The occam web-server OGI HOWTO


Contents


1: What is an OGI ?

OGI is an acronym for "occam Gateway Interface". Functionally, it's much like a CGI (Common Gateway Interface), but instead of being an OS process (script, executable, whatever) it's an occam process network. When a request is made to the occam web-server for a CGI, it sets up an OS environment and runs that CGI. When a request is made for an OGI, the relevant file (shared library) is loaded into the running web-server and the new process attached and run. The web-server and the OGI communicate using occam channels (with a well-defined protocol).


2: What's the interface ?

Two occam protocols are defined for communicating with an OGI:

    PROTOCOL OGI.LINK.IN IS CONNECTION; INT::[]BYTE:
    PROTOCOL OGI.LINK.OUT
      CASE
        persist; BOOL
        conn; CONNECTION
    :
		
The OGI itself is defined with the following header:
    PROC ogimain (VAL DPROCESS me, []CHAN OF ANY x.in, x.out)
		
This is the standard interface for all dynamic processes in occam. That is, a process desciptor (which OGIs will never need to use), an array of input channels and an array of output channels. The "actual" interface transported in this is extracted with the following re-typings:
    CHAN OF OGI.LINK.IN in RETYPES x.in[0]:
    CHAN OF OGI.LINK.OUT out RETYPES x.out[0]:
		
The incomming data is always a new request, held in the CONNECTION type, followed by any query-string passed (stuff after the ? in the URI). The outgoing link has two CASEs. The `persist' case should be sent as soon as possible, and indicates whether this OGI should remain loaded. For most simple things, this is probably best left as FALSE since there are a finite number of OGI handling processes in the web-server itself (to which OGIs attach). Once the request has been processed and results sent to the client, etc., the OGI should pass the CONNECTION back to the web-server with the `conn' output case.


3: So, writing a simple one ?

Here is the complete code for the simple test OGI:

    #INCLUDE "socklib.inc"
    #USE "sock.lib"
    #INCLUDE "httplib.inc"
    #USE "http.lib"
    #INCLUDE "dynproc.inc"
    #INCLUDE "../connection.inc"


    PROC ogimain (VAL DPROCESS me, []CHAN OF ANY x.in, x.out)
      CONNECTION conn:
      [256]BYTE q.str:
      INT q.size:
      CHAN OF OGI.LINK.IN in RETYPES x.in[0]:
      CHAN OF OGI.LINK.OUT out RETYPES x.out[0]:
      INT res:
      SEQ
        in ? conn; q.size::q.str
        out ! persist; FALSE
        CHAN OF HTTP.PROTO c:
        PAR
          http.process (c, conn[sock])
          SEQ
            c ! init.ok
            VAL []BYTE ct IS "text/html":
            c ! content.type; (SIZE ct)::ct
            c ! end.headers
            c ! begin.html
            c ! begin.head
            VAL []BYTE ct IS "testing the OGI stuff":
            c ! title; (SIZE ct)::ct
            c ! end.head
            c ! begin.body
            VAL []BYTE ct IS "hello world!":
            c ! html; HTML.H2; (SIZE ct)::ct
            c ! line.break
            VAL []BYTE ct IS "The query string was [":
            c ! html; HTML.NONE; (SIZE ct)::ct
            IF
              q.size > 0
                c ! html; HTML.TT; q.size::q.str
              TRUE
                SKIP
            c ! html; HTML.NONE; 3::"]*c*n"
            c ! end.body
            c ! end.html
            c ! finish
        out ! conn; conn
    :
		
Most of this program is communicating with the `http.process', which provides a fairly simple way of generating HTML down a socket.