#lang scribble/doc @; THIS FILE IS GENERATED @(require scribble/manual) @(require (for-label (planet neil/scgi:1:=3))) @(require (for-label racket)) @title[#:version "0.4"]{@bold{scgi}: Web Server HTTP SCGI and CGI in Racket} @author{Neil Van Dyke} License: @seclink["Legal" #:underline? #f]{LGPL 3} @(hspace 1) Web: @link["http://www.neilvandyke.org/racket-scgi/" #:underline? #f]{http://www.neilvandyke.org/racket-scgi/} @defmodule[(planet neil/scgi:1:=3)] @section{Introduction} The @bold{scgi} library implements fast Web CGI using the SCGI protocol. This library is used in conjunction with an HTTP server supporting SCGI, such as Apache Server with the @tt{mod_scgi} module. The @bold{scgi} library also supports running as normal Web CGI without any change to the source code of the app, such as during development of an application intended to be deployed using SCGI. This also gives flexibility in deployment, allowing a system administrator to switch between either mode just by editing the HTTP server configuration. The SCGI protocol was specified by Neil Schemenauer in ``SCGI: A Simple Common Gateway Interface alternative,'' dated 2008-06-23 (@link["http://python.ca/scgi/protocol.txt"]{http://python.ca/scgi/protocol.txt}). An example usage of this library: @SCHEMEBLOCK[ (require (planet neil/scgi)) (cgi (lambda () (and (eq? (cgi-type) 'scgi) (my-do-some-init-only-for-scgi))) (lambda () (display "Content-type: text/html\r\n\r\n") (display "

Hello, world

")) (lambda () (my-shutdown-stuff))) ] @subsection{Apache mod_scgi} Note that your Apache Server installation might not have @tt{mod_scgi} module installed or enabled by default. If you happen to be running Debian Lenny (@tt{stable}) or similar, this module can be installed via the Debian package @tt{libapache2-mod-scgi}. Once you've installed @tt{mod_scgi}, you need some standard SCGI directives to end up in your Apache config files, whether you accomplish that by editing config files manually, making symbolic links in a @tt{mods-enabled} directory, or clicking in a GUI. For example, the following loads @tt{mod_scgi}, maps URL paths under @tt{/mypath} to the SCGI server on the local machine at the standard SCGI TCP port, and sets a 60-second timeout for the SCGI server to respond to a request before Apache drops the connection: @verbatim["LoadModule scgi_module /usr/lib/apache2/modules/mod_scgi.so\nSCGIMount /mypath 127.0.0.1:4000\nSCGIServerTimeout 60"] There are additional @tt{mod_scgi} Apache config directives, including @tt{SCGIHandler} and @tt{SCGIServer}. @section{Interface} @defproc[ (cgi (startup-proc any/c) (request-proc any/c) (shutdown-proc any/c)) any/c]{ Implement CGI. Normal CGI is used if the @tt{REQUEST_URI} environment variable is defined (which suggests that the code is being called in a CGI context); otherwise, SCGI is used. @schemevarfont{startup-proc} is a thunk that is evaluated once (before listener starts). @schemevarfont{request-proc} is evaluated once for each request (which, in normal CGI, is once). @schemevarfont{shutdown-proc} is evaluated once, as processing of all CGI requests has finished. For evaluation of @schemevarfont{request-proc}, the default input and output ports are as with normal CGI, regardless of whether normal CGI or SCGI is in use. This procedure also accepts a few optional keyword arguments, all of which apply to SCGI mode only: @SCHEMEBLOCK[ #:scgi-hostname (scgi-hostname "127.0.0.1") #:scgi-portnum (scgi-portnum 4000) #:scgi-max-allow-wait (scgi-max-allow-wait 4) #:reuse-scgi-port? (reuse-scgi-port? #t) ] @tt{scgi-hostname} is the hostname or IP address (as a string) for the interface on which to listen. @tt{scgi-portnum} is the TCP port number on that interface. @tt{scgi-max-allow-wait} is the maximum number of unaccepted connections to permit waiting. @tt{reuse-scgi-port?} is whether or not to reuse the TCP port number, such as if a previous server exited and the port is in a @tt{TIME_WAIT} state. } @defproc[ (cgi-content-length) any/c]{ In a CGI request context, returns the CGI content length -- the number of bytes that can be read from the default input port -- as integer. } @defproc[ (make-cgi-variable-proc (sym any/c) (name-bytes any/c)) any/c]{ Produces a procedure for getting a CGI environment variable value as a string. Works whether in normal CGI or SCGI. This is useful for accessing non-standard variables, such as might be provided by an unusual Apache module. Argument @schemevarfont{sym} is a symbol for the name of the procedure, which is used in error reporting. Argument @schemevarfont{name-bytes} is the name of the environment variable, as a byte string. For example, the @tt{cgi-remote-user} procedure could be defined as: @SCHEMEBLOCK[ (define cgi-remote-user (%make-cgi-variable-proc 'cgi-remote-user #"REMOTE_USER")) ] } @defproc[ (cgi-content-type) any/c]{} @defproc[ (cgi-document-root) any/c]{} @defproc[ (cgi-http-cookie) any/c]{} @defproc[ (cgi-http-host) any/c]{} @defproc[ (cgi-http-referer) any/c]{} @defproc[ (cgi-http-user-agent) any/c]{} @defproc[ (cgi-https) any/c]{} @defproc[ (cgi-path-info) any/c]{} @defproc[ (cgi-path-translated) any/c]{} @defproc[ (cgi-query-string) any/c]{} @defproc[ (cgi-remote-addr) any/c]{} @defproc[ (cgi-remote-host) any/c]{} @defproc[ (cgi-remote-user) any/c]{} @defproc[ (cgi-request-method) any/c]{} @defproc[ (cgi-request-uri) any/c]{} @defproc[ (cgi-script-name) any/c]{} @defproc[ (cgi-server-name) any/c]{} @defproc[ (cgi-server-port) any/c]{ In a CGI request context, returns the corresponding CGI value as a string. Note that @tt{cgi-content-length} is @emph{not} in this list, and it returns a number rather than a string. } @defproc[ (scgi-variables) any/c]{ When called in SCGI mode, this procedure yields an alist of SCGI variables with both the key and value of each pair being byte strings. Calling this procedure in normal CGI mode is an error. Note that normally you will not need to use this procedure, and will instead use procedures like @tt{cgi-request-uri}, which work in both SCGI and normal CGI modes. } @defproc[ (cgi-type) any/c]{ Returns a symbol indicating the CGI type: @tt{normal} or @tt{scgi}. Behavior outside of the @tt{cgi} form is undefined. } @defproc[ (cgi-request-id) any/c]{ In CGI request context, yields a printable identifying object for the current request that is unique at least for the current requests being handled. This identifying object is intended to be used in debugging messages. } @defproc[ (stop-cgi-service-immediately) any/c]{ Stops processing all CGI requests. This works only within the @schemevarfont{request-proc} of the @tt{cgi} form. } @section{Troubleshooting} This section has some troubleshooting tips. Currently, these come from use with @tt{mod_scgi} atop Apache 2.2.9 atop Debian GNU/Linux. @itemize[ @item{ Racket error ``tcp-write: error writing (Broken pipe; errno=32)'' or ``tcp-write: error writing (Connection reset by peer; errno=104)'' is likely due to the HTTP request having been dropped by the HTTP client (e.g., user stops a page load in their browser before page finishes loading) or by Apache hitting @tt{SCGIServerTimeout} for the request. Note that buffered I/O means that you won't necessarily get this error even if the request is aborted this way. } @item{ Apache error log entry ``Premature end of script headers: @emph{PATH}'' followed by ``(500)Unknown error 500: scgi: Unknown error 500: error reading response headers'' can mean that @tt{SCGIServerTimeout} was hit before any HTTP headers from the SCGI request handler were started or completed. Note that buffered I/O can mean that some of the Racket code of the handler wrote some text, but it was not yet flushed to the SCGI client. } @item{ Apache error log entry ``(70007)The timeout specified has expired: ap_content_length_filter: apr_bucket_read() failed'' followed by ``(70007)The timeout specified has expired: scgi: The timeout specified has expired: ap_pass_brigade()'' can mean that @tt{SCGIServerTimeout} was hit after HTTP headers from the request handler had been received by the SCGI client. } ] @section{History} @itemize[ @item{Version 0.4 --- 2011-05-16 --- PLaneT @tt{(1 3)} Added @tt{#:reuse-scgi-port?} argument to procedure @tt{cgi}. Added several new CGI environment variable procedures. Added @tt{make-cgi-variable-proc}. The @tt{cgi} procedure now uses @tt{tcp-accept/enable-break} rather than @tt{tcp-accept}. Added more @tt{log-debug}. Added documentation about @tt{mod_scgi} configuration, troubleshooting, and the keyword arguments to the @tt{cgi} procedure. Removed documentation placeholders for @tt{end-cgi-request} for now. Various additional quality assurance testing has been done, and more is the works. } @item{Version 0.3 --- 2010-11-14 --- PLaneT @tt{(1 2)} Added @tt{cgi-http-user-agent}. } @item{Version 0.2 --- 2010-10-11 --- PLaneT @tt{(1 1)} Documentation changes to reflect that it is successfully in use in a real system, and some work remains. } @item{Version 0.1 --- 2010-05-25 --- PLaneT @tt{(1 0)} Initial release. Preliminary. } ] @section[#:tag "Legal"]{Legal} Copyright (c) 2010--2011 Neil Van Dyke. This program is Free Software; Software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License (LGPL 3), or (at your option) any later version. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. See http://www.gnu.org/licenses/ for details. For other licenses and consulting, please contact the author. @italic{@smaller{Standard Documentation Format Note: The API signatures in this documentation are likely incorrect in some regards, such as indicating type @tt{any/c} for things that are not, and not indicating when arguments are optional. This is due to a transitioning from the Texinfo documentation format to Scribble, which the author intends to finish someday.}}