Description

SCGI server library

Author

Thomas Chust

Version

Usage

(require-extension scgi)

Download

scgi.egg

Requires

Documentation

This egg provides a simple interface to create an SCGI server, a server application providing similar functionality as CGI to a web server, which connects to it, but is a persistent program.

Global parameters

parameter: scgi:max-request-length

Examined by the default "POST" request method handler to determine whether the request is accepted. See scgi:request-method-handler

procedure: (scgi:request-method-handler (name <string>)) => <procedure-class>
procedure: (scgi:request-method-handler (name <string>) (proc <procedure-class>)) => <void>

Gets or sets an entry in the global hash table of request method handlers. name is a string identifying the request method and proc, if given, is a procedure of two arguments, the hash table containing the environment variables passed from the server and the response handler to call, which has no significant return value. The procedure is called with input and output ports connected to the webserver.

Handlers for the "GET" and "POST" methods are already registered, so you will probably seldomly register additional ones.

The default "POST" handler calls on methods registered by scgi:request-parameter-parser to parse the request parameters. Before it does so, it checks the content length of the request against (scgi:max-request-length). The request is rejected with an appropriate HTTP error status, if (scgi:max-request-length) is not #f and the content length is either not specified by the client or less than (scgi:max-request-length).

Modifications made to the table of request method handlers are thread safe, but the table is global.

procedure: (scgi:request-parameter-parser (name <string>)) => <procedure-class>
procedure: (scgi:request-parameter-parser (name <string>) (proc <procedure-class>)) => <void>

Gets or sets an entry in the global hash table of request parameter parsers. name is a string identifying the MIME-type to parse and proc, if given, is a procedure of two arguments, the hash table containing the environment variables passed from the server and the content length to read (which may be #f if no content length was sent by the client), which should return a hash table of decoded request parameters. The procedure is called with input and output ports connected to the webserver.

A handler for the "application/x-www-form-urlencoded" type is already registered. You may want to register one for multipart formdata if you want to use file uploads.

Modifications made to the table of request parameter parsers are thread safe, but the table is global.

parameter: scgi:resources

This parameter stores a hash table mapping PATH_INFO values passed in the environment to your SCGI application to response handler procedures. The hash table is wrapped up in a mutex and access to it is synchronized. You can initialize the parameter directly with a mutex, a hash table or with an association list, but it is recommended that you use the methods below to access it.

The handler procedures are procedures of two arguments, the server environment and the parsed request parameters as hash tables, and their return value has no meaning. The procedures are called with input and output ports connected to the webserver.

procedure: (scgi:add-resource (name <string>) (proc <procedure-class>)) => <void>
procedure: (scgi:add-resource (names <list of strings>) (proc <procedure-class>)) => <void>

Adds a response handler for the given resource(s) to the hash table in scgi:resources.

procedure: (scgi:find-resource (name <string>) (proc <procedure-class>)) => <procedure-class>

Returns the response handler for the given resource or #f if no handler exists for it.

procedure: (scgi:remove-resource (name <string>) (proc <procedure-class>)) => <void>
procedure: (scgi:remove-resource (names <list of strings>) (proc <procedure-class>)) => <void>

Removes the response handler(s) for the given resource(s) from the hash table in scgi:resources.

Assistance for output of content

procedure: (scgi:write-response-header (content-type <string>) #!optional (content-length <integer>) ((more-headers <list>) '()) ((status-code <integer>) 200) ((status-message <string>) "OK")) => <void>

Writes the response headers in the correct format to the current output stream. more-headers may contain an association list of header and value strings that are output in addition to the Status, Content-type and optionally Content-length headers.

procedure: (scgi:write-error-response (status-code <integer>) (status-message <string>) (long-message <string>) #!optional ((more-headers <list>) '())) => <void>

Writes the headers and a full explanatory HTML page containing the long-message in addition to the short status message to the current output port.

Creating and running the server

procedure: (scgi:make-server (listener <tcp-listener>) #!optional (max-requests <exact>)) => <procedure-class>

Calls on make-tcp-server to create a procedure that will start the SCGI server when called.

Examples

Here is the SCGI variant of the always popular server side application example: A program that echoes the environment and query parameters back to the client.

#!/usr/local/bin/csi -s
;;;; scgi-demo.scm
;;;; Environment and parameter echo SCGI server

(require-extension (srfi 69) tcp scgi htmlprag)

(define (hash-table->table ht)
  `(table
    (tr (th "Key") (th "Value"))
    ,@(hash-table-fold
       ht
       (lambda (key value seed)
	 (cons
	  `(tr (td (tt ,(->string key)))
	       (td (tt ,(call-with-output-string (cut write value <>)))))
	  seed))
       '())))

(scgi:add-resource '("" "/" "/index.html")
  (lambda (env params)
    (scgi:write-response-header "text/html")
    (for-each
     write-shtml-as-html
     `((*PI* xml "version=\"1.0\" encoding=\"US-ASCII\"")
       (*DECL* DOCTYPE html
	       PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
	       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd")
       (html (@ (xmlns "http://www.w3.org/1999/xhtml"))
	(head
	 (meta (@ (http-equiv "content-type")
		  (content "text/html; charset=US-ASCII")))
	 (title "scgi-demo.scm"))
	(body
	 (h1 "scgi-demo.scm")
	 (h2 "Environment")
	 ,(hash-table->table env)
	 (h2 "Query parameters")
	 ,(hash-table->table params)))))))

(define scgi-server
  (scgi:make-server
   (tcp-listen
    (string->number (car (command-line-arguments)))
    4
    "localhost")))

(scgi-server #t)

License

Copyright (c) 2006, Thomas Chust <chust@web.de>.  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

  Redistributions of source code must retain the above copyright notice,
  this list of conditions and the following disclaimer. Redistributions in
  binary form must reproduce the above copyright notice, this list of
  conditions and the following disclaimer in the documentation and/or
  other materials provided with the distribution. Neither the name of the
  author nor the names of its contributors may be used to endorse or
  promote products derived from this software without specific prior
  written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.