Changeset 12036 in project


Ignore:
Timestamp:
09/29/08 21:56:24 (12 years ago)
Author:
sjamaan
Message:

add docs for spiffy 4, move old docs to spiffy 3 file

Location:
wiki
Files:
1 edited
1 copied

Legend:

Unmodified
Added
Removed
  • wiki/spiffy

    r10771 r12036  
    99A small web-server written in [[http://www.call-with-current-continuation.org|Chicken]].
    1010
     11This is the documentation for Spiffy 4, a rewrite from scratch.
     12For information on Spiffy 3, please see [[spiffy 3]].
     13
    1114=== Author
    1215
     
    1417
    1518=== Requirements
    16 Requires the [[http]] and [[sendfile]] extensions.
     19
     20Requires the [[intarweb]], [[matchable]] and [[sendfile]] extensions.
    1721
    1822=== Download
     23
    1924[[http://www.call-with-current-continuation.org/eggs/spiffy.egg|spiffy.egg]]
    2025
    2126=== Documentation
    2227
    23 Spiffy is a simple web-server for the Chicken Scheme system. It's
    24 quite easy to set up and use and it can be customized in numerous
    25 ways.
    26 
    27 Note that only very basic functionality is provided, there is no
    28 support for encoding styles.
    29 
    30  (start-server location: [string: host name] init: [procedure])
    31 
    32 Starts the web server. The arguments provided default as follows:
    33 
    34 <enscript highlight=scheme>
    35   (start-server location: (get-host-name)
    36                 init: noop)
    37 </enscript>
    38 
    39 The {{location}} argument is directly passed on to {{http:make-server}}.
    40 The {{init}} argument should be a procedure of zero arguments.
    41 This procedure will be called after setting up the connection and changing the user ID.
    42 Any other configuration is done via standard SRFI-39 parameters.  See the next section
    43 for configuration options.
    44 
    45 Note that there is currently no way of terminating the server manually; you have to terminate the whole process.
    46 
    47 === Server configuration
    48 
    49 The following SRFI-39 parameters determine configuration of Spiffy.  To save you the trouble of reading SRFI-39, you read this by treating them as regular variables, and set them by treating them as functions of one argument, i.e. (spiffy-tcp-port "8080").
    50 
    51 ; spiffy-tcp-port (integer) : The port (as in the {{--port}} option). Default: 8080
    52 
    53 ; spiffy-debug-mode (boolean) : Whether debugging information should be printed. Default: {{#f}}
    54 
    55 ; spiffy-access-log (string or port) : Filename (string) or port to append access log output to.  Default: {{#f}} (disabled)
    56 
    57 ; spiffy-error-log (string or port) : Filename (string) or port which error messages from evaluated code should be output. Default: {{(current-error-port)}}
    58 
    59 ; spiffy-server-name (string) : The name of the server as given in HTTP responses. Default: {{(Silly)}}
    60 
    61 ; spiffy-accept-incoming-host (string) : If given, restricts incoming requests to this hostname. Default: {{#f}}
    62 
    63 ; spiffy-user-name (string) : If given, changes to given user after setting up listening port. Default: {{#f}}
    64 
    65 ; spiffy-root-path (string) : The path containing the served files. Default: {{./web}}
    66 
    67 ; spiffy-access-denied? (lambda) : A procedure of two arguments that returns #t if access is to be denied.  The arguments are the path and filename which is to be served. The procedure is invoked on every step along the way of going from spiffy-root-path up to the actual file.  Defaults to a procedure which checks if the file is a dotfile, has the {{.sspx}} extension or the path includes {{..}} or {{~}}.
    68 
    69 ; spiffy-vhost-map (alist of string<->lambda pairs)  : Maps hosts to lambdas of virtual servers.  See the section "Virtual hosts" below.  Default: {{#f}}
    70 
    71 ; spiffy-index-pages (list of strings) : List of filenames that should be tried in case a request references a directory. Default: {{'("index.html" "index.ssp" "index.ws")}}
    72 
    73 ; spiffy-file-type-map (alist of string <-> symbol pairs) : Maps file-extensions to MIME types. Default:
    74 
    75 <enscript highlight=scheme>
    76  '(("txt" . text/plain)
    77    ("xml" . text/xml)
    78    ("js"  . text/javascript)
    79    ("xul" . application/vnd.mozilla.xul+xml)
    80    ("htm" . text/html)
    81    ("html" . text/html)
    82    ("pdf" . application/pdf)
    83    ("css" . text/css)
    84    ("bmp" . image/bmp)
    85    ("ico" . image/x-icon)
    86    ("gif" . image/gif)
    87    ("jpg" . image/jpeg)
    88    ("jpeg" . image/jpeg)
    89    ("png" . image/png))
    90 </enscript>
    91 
    92 ; spiffy-default-mime-type (symbol) : The default mime type used if the extension of the file was not found in {{spiffy-file-type-map}}. Default: {{application/octet-stream}}
    93 
    94 ; spiffy-read-block-size (integer) : The size of chunks in which files should be loaded and transferred to the client. Default: {{100000}}
    95 
    96 ; spiffy-cache-limit (integer) : The maximum size of the cache for static file-based resources. Default: {{0}}
    97 
    98 ; spiffy-access-file (filename) : The name of directory-local access-permission files. Default: {{#f}}
    99 
    100 ; spiffy-config-file (filename) : The name of the configuration file to load at startup. Default: {{#f}}
    101 
    102 ; spiffy-handle-directory (lambda) : A procedure that accepts one parameter (the requested path), which gets invoked when a directory which has no index-file is requested.  Default: a lambda which returns a {{403 Forbidden}} status.
    103 
    104 ; spiffy-not-found-handler (lambda) : A procedure of zero parameters that will handle all requests for files that were not found.  Default: A lambda which calls the previous {{http:fallback-handler}} (returns a 404 status).
    105 
    106 ; spiffy-error-css (string) : The CSS to be used on error pages.
    107 
    108 ; spiffy-exception-handler (lambda) : A procedure of one argument (the exception) that gets invoked to produce an error page when an exception is raised.  Defaults to a procedure which displays a default error page which uses spiffy-error-css and shows a backtrace.  An error is always logged to the error log before calling this procedure.
    109 
    110 ==== Module support
    111 
    112 Starting at version 3.0, Spiffy's functionality has become large enough to split out into modules.  Currently it has modules for:
    113 
    114 ; Web-scheme : [[http://www.call-with-current-continuation.org/eggs/web-scheme.html|Web-scheme]], a functional web programming language on top of Scheme.
    115 
    116 ; CGI : An implementation of the Common Gateway Interface, version 1.1.  Use this to run legacy PHP scripts, if you have them.
    117 
    118 ; SSP (Scheme Server Pages) : Spiffy provides a way to embed Scheme code in web pages the way it's usually done for PHP, Embedded Ruby or ASP.  You just type your HTML with bits of code sprinkled through it delimited by special "code tags".
    119 
    120 ; Simple-directory-handler : A directory handler that displays a rather simple directory listing, for use with {{spiffy-handle-directory}}.
    121 
    122 You can run a module simply by adding a <code>use</code> statement to your program and then hooking a file extension handler for that module's handler.  Here's an example on how to do this:
    123 
    124 <enscript highlight=scheme>
    125  (spiffy-file-ext-handlers `(("ssp" . ,ssp-handler)
    126                              ("ws" . ,web-scheme-handler)
    127                              ("php" . ,(cgi-handler* "/usr/pkg/libexec/cgi-bin/php"))))
    128 </enscript>
    129 
    130 During execution of file extension handlers (which modules basically are), the following parameters are available, which hold some useful data for the currently handled request:
    131 
    132 ; (current-request) : Holds an object representing the current HTTP. See [[http://chicken.wiki.br/http#http-request-accessor-methods|HTTP request accessor methods]] for more information.
    133 
    134 ; (current-urlencoded-arguments) : Holds an a-list containing pairs of strings, which contains URL-encoded arguments. So a request for {{/foo.html?bar=baz}} would result in this parameter containing {{(("bar" . "baz"))}}.
    135 
    136 ; (current-response-code) : A pair containing the status code and the status message sent in the reply. Defaults to (200 . "OK").
    137 
    138 ; (current-response-headers) : An a-list holding the HTTP headers which are sent before the body of the current response. By default this parameter contains {{(("content-type" . "text/html"))}}. You can modify the existing value, or assign a different one by calling the parameter with a new a-list.
    139 
    140 ; (current-hostname) : The current vhost's hostname.
    141 
    142 ; (current-pathinfo) : The pathinfo -- the part of the URL ''after'' a filename (Only available at directory-level, not at vhost level)
    143 
    144 ; (current-path) : The complete URL (including pathinfo, but excluding URL parameters) Mostly useful for {{not-found-handler}}s.
    145 
    146 
    147 === Example With Dynamic Resources
    148 
    149 You can add URL resources by invoking the procedure
    150 {{define-http-resource}}. Procedures can be registered that are
    151 invoked when a request refers to a given path. See the documentation
    152 [[http://chicken.wiki.br/spiffy#convenience-macros|below]].
    153 
    154 The example below is a fairly general example of Spiffy usage, to
    155 get you started. It is somewhat contrived, in that it is not
    156 necessary to set the content-type to text/html, as that is the
    157 default for resources.  It can't hurt, though.
    158 
    159 To use this example, run "csi -s [file]".  You will then see Spiffy
    160 debugging output to stdout.  To see it in action, connect to
    161 <code>http://localhost:8080/index.html?userid=1</code>, and
    162 also try <code>userid=2</code>.
    163 
    164 Note that user-information uses strings; all http arguments are
    165 passed to your code as strings.
    166 
    167 <enscript highlight=scheme>
    168 (use spiffy)
    169 
    170 (spiffy-debug-mode #t)
    171 (spiffy-tcp-port 8080)
    172 
    173 (define user-information
    174   '(("1" . "Alice")
    175     ("2" . "Bob")))
    176 
    177 (define-http-resource
    178   ; "/index.html" is the URI/resource to respond to with this code
    179   ("/index.html"
    180    ; userid will be bound to the value of GET or POST argument
    181    ; with that name.  You can also specify defaults here
    182    userid)
    183   (let ([name (alist-ref userid user-information string=)])
    184     (let ([s (sprintf "<h1>Hello, ~A</h1>" name userid)])
    185       (set-header! "Content-type: text/html")
    186       s)))
    187 
    188 (start-server location: (get-host-name) init: noop)
    189 </enscript>
    190 === Content transporters
    191 
    192 The content of a served file is read and transmitted using a {{content-transporter}} procedure. The default content-transporter reads in the data and forwards it to the client with appropriate {{Content-length}} and {{Content-type}} headers.
    193 
    194 User-defined content-transporters allow customized retrieval and processing of resources, depending on file-type.
    195 
    196 ; (content-transporter TYPE [PROC]) : If called with a single argument, this procedure returns the content-transporter procedure for the given TYPE, which should be a symbol like {{text/html}}. If the optional argument PROC is given, then the content-transporter for the given type is set to PROC. PROC should accept two arguments: the type TYPE and the filename of the requested resource. Any output generated by PROC is transmitted to the client.
    197 
    198 === Access to the cache
    199 
    200 ; (cache-read PATH) : Reads a string from the cache, stored under the string PATH and returns it if found, or #f otherwise.
    201 
    202 ; (cache-write PATH STRING) : Writes a string into the cache, stored under PATH. If the cache-limit is not sufficient (see {{spiffy-cache-limit}} the data is not stored.
    203 
    204 Note that the cache is by default not enabled ({{spiffy-cache-limit}} is 0).
    205 
    206 ; (invalidate-cache [PATH]) : If the optional argument PATH is given, remove the associated item from the cache. If no argument is given, clear the whole cache.
    207 
    208 === Logging
    209 
    210 If logging is enabled by setting the parameter {{spiffy-access-log}} to the pathname of a log-file or a port,
    211 then each request will be logged by appending a line of the following format:
    212 
    213   CLIENT-IP DATE-AND-TIME REQUEST-LINE USER-AGENT
     28Spiffy is a web-server library for the Chicken Scheme system. It's
     29quite easy to set up and use (whether as a library or a standalone
     30server application) and it can be customized in numerous ways.
     31
     32=== Starting the server
     33
     34<procedure>(start-server [port: port-number])</procedure>
     35
     36Starts the server, to listen on the given port. Other configuration
     37can be tweaked through SRFI-39 parameters. These are listed below.
     38Once the server is started, server behaviour can be controlled through
     39these parameters as well. By default, Spiffy will only serve static
     40files. On directories, it will give a "403 forbidden", unless there
     41is an index-file. If there is, that file's contents will be shown.
     42
     43All arguments directly supplied to {{start-server}} override the
     44configuration parameter values.
     45
     46{{Port-number}} defaults to 8080.
     47
     48=== Configuration parameters
     49
     50The following parameters can be used to control spiffy's behaviour.
     51Besides these parameters, you can also influence spiffy's behaviour by
     52tweaking the [[intarweb]] parameters.
     53
     54<parameter>(root-path [path])</parameter>
     55
     56The path to the document root. Defaults to {{"./web"}}.
     57
     58<parameter>(server-port [port-number])</parameter>
     59
     60The port number on which to listen. Defaults to 8080.
     61
     62<parameter>(index-files [file-list])</parameter>
     63
     64A list of filenames which are to be used as index files to serve when
     65the requested URL identifies a directory.  Defaults to
     66{{'("index.html" "index.xhtml")}}
     67
     68<parameter>(mime-type-map [extension->mimetype-list])</parameter>
     69
     70An alist of extensions (strings) to mime-types (symbols), to use
     71for the content-type header when serving up a static file. Defaults to
     72{{
     73(("xml" . text/xml)
     74 ("html" . text/html)
     75 ("xhtml" . text/xhtml+xml)
     76 ("js"  . text/javascript)
     77 ("pdf" . application/pdf)
     78 ("css" . text/css)
     79 ("png" . image/png)
     80 ("ico" . image/x-icon)
     81 ("gif" . image/gif)
     82 ("jpeg" . image/jpeg)
     83 ("jpg" . image/jpeg)
     84 ("svg" . image/svg+xml)
     85 ("bmp" . image/bmp)
     86 ("txt" . text/plain))
     87}}
     88
     89<parameter>(default-mime-type [mime-type])</parameter>
     90
     91The mime-type (a symbol) to use if none was found in the
     92{{mime-type-map}}. Defaults to {{'application/octet-stream}}
     93
     94<parameter>(default-host [hostname])</parameter>
     95
     96The host name to use when no virtual host could be determined from the
     97request.  See the section on virtual hosts below.
     98
     99<parameter>(vhost-map [host-regex->vhost-handler])</parameter>
     100
     101A mapping of virtual hosts (regex) to handlers (procedures of one
     102argument; a continuation thunk). See the section on virtual hosts
     103below. Defaults to {{`((".*" . ,(lambda (continue) (continue))))}}
     104
     105<parameter>(file-extension-handlers [extension->handler-list])</parameter>
     106
     107An alist mapping file extensions (strings) to handler procedures
     108(lambdas of one argument; the file name relative to the webroot).
     109Defaults to {{'()}}. If no handler was found, defaults to just sending
     110a static file.
     111
     112=== Handlers
     113
     114Besides "static" configuration, Spiffy also has several handlers for
     115when something is to be served.
     116
     117<parameter>(handle-directory [proc])</parameter>
     118
     119The handler for directory entries. If the requested URL points to a
     120directory which has no index file, this handler is invoked. It is a
     121procedure of one argument, the path (a string) relative to the
     122webroot. Defaults to a procedure which returns a "403 forbidden".
     123
     124<parameter>(handle-file [proc])</parameter>
     125
     126The handler for files. If the requested URL points to a file, this
     127handler is invoked to serve the file. It is a procedure of one
     128argument, the path (a string) relative to the webroot. Defaults to a
     129procedure which sets the content-type and determines a handler based
     130on the {{file-extension-handlers}}, or {{send-static-file}} if none
     131was found.
     132
     133<parameter>(handle-not-found [proc])</parameter>
     134
     135The handler for nonexisting files. If the requested URL does not point
     136to an existing file or directory, this procedure is called. It is a
     137procedure of one argument, the path (a string) that were
     138requested. This path should be interpreted as being relative to the
     139webroot (even though it points to no existing file). Defaults to a
     140procedure which returns a "404 Not found".
     141
     142=== Runtime information
     143
     144During the handling of a request, Spiffy adds more information to the
     145environment by parameterizing the following parameters whenever the
     146information becomes available:
     147
     148<parameter>(current-request [request])</parameter>
     149
     150An intarweb request-object that defines the current request. Available
     151from the moment the request comes in and is parsed. Contains, among
     152other things, the query parameters and the request-headers, in fully
     153parsed form (as intarweb returns them).
     154
     155<parameter>(current-response [request])</parameter>
     156
     157An intarweb response-object that defines the current
     158response. Available from the same time current-request is available.
     159This keeps getting updated along the way, while the response data is
     160being refined (like when headers are being added).
     161
     162<parameter>(current-file [path])</parameter>
     163
     164The path to the requested file (a string). Available from the moment
     165Spiffy determined the requested URL points to a file (just before the
     166{{handle-file}} procedure is called).
     167
     168<parameter>(current-pathinfo [path])</parameter>
     169
     170The trailing path ''fragments'' (a list of strings) that were passed
     171in the URL after the requested filename. Available from the moment
     172Spiffy determined the requested URL points to a file (just before the
     173{{handle-file}} procedure is called).
    214174
    215175=== Virtual hosts
    216176
    217 You can set up virtual hosting by defining a vhost-map like so:
    218 
    219 <enscript highlight=scheme>
    220  (spiffy-vhost-map `(("foo\\.bar\\.com" .
    221                          ,(lambda (continue)
    222                             (parameterize ((spiffy-file-ext-handlers `(("ssp" . ,ssp-handler) ("ws" . ,web-scheme-handler)))
    223                                            (spiffy-root-path "/var/www/domains/foo.bar.com"))
    224                               (continue))))
    225                      (,(glob->regexp "*.domain.com") .
    226                          ,(lambda (continue)
    227                             (parameterize ((spiffy-file-ext-handlers `(("php" . ,(cgi-handler* "/usr/pkg/bin/php"))))
    228                                            (spiffy-root-path "/var/www/domains/domain.com"))
    229                               (continue))))))
    230 </enscript>
    231 
    232 In this example, if a client accesses {{foo.bar.com/mumble/blah.html}}, the file {{/var/www/domains/foo.bar.com/mumble/blah.html}}
    233 will be served.  Any files ending in {{.ssp}} or {{.ws}} will be served by the corresponding file type handler.  If there's
    234 any PHP file, its source will simply be displayed.
    235 In case of {{my.domain.com/something/bar.html}}, the file {{/var/www/domains/domain.com/something/bar.html}} will be served.
    236 If there's a {{.ssp}} or {{.ws}} file there, it will not be interpreted.  Its source will be displayed instead.  A {{.php}} file,
    237 on the other hand, will be passed via CGI to the program {{/usr/pkg/bin/php}}.
    238 
    239 Domain names are mapped to a lambda that sets up any parameters it wants to override from the defaults.
    240 The host names are matched using {{string-match}}.  If the host name is not yet a regexp, it will be converted to a ''case-insensitive'' regexp.
    241 
    242 Virtual hosting is a HTTP/1.1 feature, so this will only work with HTTP/1.1 clients.
    243 Actually, it also works with HTTP/1.0 clients which insert an additional Host: line in the request headers since Spiffy ignores
    244 the HTTP version the client sends.
    245 
    246 === Access files
    247 
    248 Fine-grained access-control can be implemented by using so-called access files.
    249 When a request for a specific file is made and a file with the name given in the {{spiffy-access-file}} parameter
    250 exists in any directory between the {{spiffy-root-dir}} of that vhost and the directory in which the file resides,
    251 then the access file is loaded as an s-expression containing a function and is evaluated with a single argument,
    252 the function that should be called to continue processing the request.
    253 
    254 This works just like vhosting.  The function that gets called can call {{parameterize}} to set additional
    255 constraints on the code that handles deeper directories.
    256 
    257 For example, if we evaluate {{(spiffy-access-file ".access")}} before starting the server, and we put the following
    258 code in a file named .access into the root-directory, then all accesses from localhost to any file in the
    259 root-directory or any subdirectory will be denied:
    260 
    261 <enscript highlight=scheme>
    262  (lambda (continue)
    263    (if (string=? (http:request-ip (current-request)) "127.0.0.1")
    264        (continue)
    265        (http:write-error-response 403 "Forbidden")))
    266 </enscript>
    267 
    268 If we only want to deny access to files that start with an X, put this in the {{.access}} file:
    269 
    270 <enscript highlight=scheme>
    271  (lambda (continue)
    272    (parameterize ((spiffy-access-denied?
    273                     (lambda (path file) (string-prefix? "X" file))))
    274      (continue)))
    275 </enscript>
    276 
    277 Of course, access files can be used for much more than just access checks.  One can put anything in them that could be put in vhost configuration or in top-level configuration.
    278 
    279 They are very useful for making deployable web applications, so you can just drop a directory on your server which has its own configuration embedded in an access file in the root directory of the application, without having to edit the server's main configuration files.
    280 === Some useful procedures
    281 
    282 ; (write-fragment-response . FRAGMENTS) : Generates a HTTP response and writes the elements of all the FRAGMENTS you pass to it as the contents of the body. A fragment may be a #f or the empty list (which are ignored), a string, character, number, symbol or a list of other fragments.  Uses write-response-header internally, so uses the same parameters to determine headers and status code.
    283 
    284 ; (send-static-file FILENAME) : Generates a HTTP response and writes the contents of the given file.  Remember to set the {{Content-Type}} header if {{current-response-headers}} do not set a {{text/html}} content-type.
    285 
    286 ; (redirect PATH) : Changes the current value of (current-response-code) and (current-response-headers) to return a redirection response. This is basically the same as redirect-page but is usable in {{.ssp}} pages.
    287 
    288 ; (redirect-page PATH) : Generates a {{303 See Other}} HTTP response that redirects the client to PATH.  It also outputs a small note that the page was moved.  This procedure should be used from vhost configurations or other places where there is no output to send (ie, as a replacement for a call to {{(continue)}}).
    289 
    290 ; (spiffy-debug FORMATSTRING ARG ...) : When debugging output has been turned on (via the debug argument to start-server, or by (spiffy-debug-mode #t)), then this is equivalent to {{(fprintf (current-error-port) FORMATSTRING ARG ...)}}.
    291 
    292 ; (write-response-header) : Writes a HTTP response header to the current output port. This largely equivalent to {{http:write-response-header}}, but handles persistent connections properly by checking the HTTP version any Connection request headers and it obeys arguments {{current-response-code}} and {{current-response-headers}} instead of using keyword arguments.
    293 
    294 ; (current-workdir) : A parameter that holds the current include path, relative to {{spiffy-root-path}}. File loading operations like {{load-once}}, {{load-ssp}} or {{include-ssp}} set this parameter, so that nested load/include operations always take place relative the the containing source file.
    295 
    296 ; (htmlize STRING) : Makes STRING suitable for embedding in HTML by replacing {{<}}, {{>}}, {{&}} and {{"}} with {{&lt;}}, {{&gt;}}, {{&amp;}} and {{&quot;}}.
    297 
    298 ; (load-once FILENAME) : If no file with this name has been loaded, or if the file has been modified since the last time it has been loaded, then it is loaded and evaluated and #t is returned. Otherwise nothing is done and load-once returns {{#f}}.
    299 
    300 Note that this works only reliable for source files, not for compiled code.
    301 
    302 ; (get-header STRING [DEFAULT]) : Retrieves the value of a HTTP header in the current request. STRING should name the header and will be compared (case-insensitive) with any headers passed in the current request object (as given in {{(current-request)}}). If no header with this name can be found DEFAULT will be returned (or {{#f}} if DEFAULT is not specified).
    303 
    304 ; (set-header! STRING) : Sets a HTTP header in the current response by changing the value of the current-response-headers parameter. STRING should be a valid HTTP header of the form {{<header-name>: <header-value>}}. If the header was already set it will be overwritten except in the case of Set-Cookie.  In this case, it will just output an additional Set-Cookie header.
    305 === Convenience macros
    306 
    307 ; (syntax) (define-http-resource (URL ARGUMENT ...) BODY ...) : Defines a resource-handler (as with {{http:add-resource}}) for URL, which should be a string or symbol. the ARGUMENTs should be symbols, which will be bound to URL-encoded or POSTed arguments or they should be of the form (IDENTIFIER DEFAULT) to bind them to a default value, if not provided. The result of BODY ... will be returned as the response, it should be a string containing (X)HTML or XML.
    308 
    309 To exit prematurly from the body, or to customize the returned response, the procedure {{respond}} will be lexically visible inside the body, and can be called, for example, like this:
    310 
    311 <enscript highlight=scheme>
    312   (parameterize ((current-response-code '(200 . "OK")))
    313     (respond "<html><body>Hello, world</body></html>"))
    314 </enscript>
    315 
    316 Calling {{(respond RESULT)}} is identical to returning RESULT in the body.
    317 
    318 
    319 === Modules
    320 
    321 This section will describe what the various modules that come with Spiffy are and how they work.
    322 
    323 ==== ssp-handler
    324 
    325 SSP, or Scheme Server Pages, are a way to embed Scheme in HTML pages. Files with an extension of {{.ssp}}
    326 are handled specifically, by replacing occurrences of certain reserved tags with Scheme code.
    327 There are two possible forms, either the long version, where all output is redirected to the HTTP response
    328 port, or the short, where the result of the embedded expression is displayed in the response.
    329 The tags default to {{<?scheme}} and {{<?}}, see Configuration for how to change them.
    330 
    331 <enscript highlight=scheme>
    332    <html><body>
    333    <ol><?scheme (for-each (lambda (i) (printf "<li>~S~%" i)) (iota 5))?></ol>
    334    <br />
    335    <b><?(call-with-values (lambda () (user-information (current-user-id))) (lambda (name . _) name))?><b>
    336    </body></html>
    337 </enscript>
    338 
    339 would generate for example something like this:
    340 
    341      1. 0
    342      2. 1
    343      3. 2
    344      4. 3
    345      5. 4
    346 
    347   (felix x 500 100 /home/felix /bin/bash)
    348 
    349 When a {{.ssp}} file is loaded the first time, or when it has been modified, then a translation
    350 takes place that generates a loadable Scheme source file (with the extension {{.sspx}}, in the
    351 same directory as the original file) from the original data, so in the above example something
    352 like this would be generated:
    353 
    354 <enscript highlight=scheme>
    355   (let ()
    356     (display "<html><body>\n<ol>")
    357     (for-each (lambda (i) (printf "<li>~S~%" i)) (iota 5))
    358     (display "</ol>\n<br />\n<b>")
    359     (display (call-with-values (lambda () (user-information (current-user-id))) (lambda (name . _) name)))
    360     (display "<b>\n</body></html>\n") )
    361 </enscript>
    362 
    363 Note that the body is evaluated in a {{(let () ...)}} form.
    364 
    365 Note: each request runs in a separate thread, so code in {{.ssp}} pages should take care when using global variables.
    366 
    367 ===== Configuration
    368 
    369 The SSP handler can be configured with the following options:
    370 
    371 ; ssp-close-tag (regexp) :  The closing tag for Scheme fragments in {{.ssp}} files. Default: {{?>}}
    372 
    373 ; ssp-short-open-tag (regexp) : The opening tag for short fragments. Default: {{<?}}
    374 
    375 ; ssp-long-open-tag (regexp) : The opening tag for long fragments. Default: {{<?scheme}}
    376 
    377 ; ssp-eval-environment (environment) : The environment passed to {{eval}} when evaluating Scheme code inside {{.ssp}}-pages.  Default: {{interaction-environment}}
    378 
    379 ===== Procedures
    380 
    381 The ssp-handler module adds the following procedures to the environment:
    382 
    383 ; (include-ssp FILENAME) : Translates the file FILENAME into Scheme by replacing {{<?scheme ... ?>}} and {{<? ... ?>}} sequences (if needed) and writes the translated contents to the current output-port.
    384 
    385 ; (ssp-stringize FILENAME) : Similar to {{include-ssp}}, but instead of writing the translated text, the text is returned as a string.
    386 
    387 ; (exit-handler) : During execution of an ssp page, {{exit-handler}} is bound to a procedure that will finish the current page, ignoring any further content or code.
    388 ==== web-scheme-handler
    389 
    390 Another way of executing Scheme code to produce content are {{.ws}} files: these should contain a Scheme
    391 expression that is expected to evaluate to a string which will be directly written as the response to the
    392 current request. This facility is intended for Scheme code that uses
    393 the [[http://www.call-with-current-continuation.org/eggs/web-scheme.html|web-scheme]] extension.
    394 
    395 You can use the {{web-scheme-handler}} for any Scheme file which returns HTML as a string or
    396 which has a side-effect of outputting the HTML. If it's the latter, make sure the final statement
    397 in your file does not return a string or it will be appended to the output (just like in the {{csi}} REPL).
    398 
    399 '''Tip''' This handler type is perfect not only for web-scheme but also for when you're using SRV:send-reply with SXML or for example a wiki-to-string translator.
    400 
    401 Note: each request runs in a separate thread, so code in {{.ws}} pages should take care when using global variables.
    402 
    403 ===== Configuration
    404 
    405 The Web-scheme handler can be configured with the following options:
    406 
    407 ; web-scheme-eval-environment (environment) : The environment passed to {{eval}} when evaluating Scheme code inside {{.ws}}-pages.  Default: {{interaction-environment}}
    408 
    409 ==== cgi-handler
    410 
    411 Spiffy supports a subset of the [[http://hoohoo.ncsa.uiuc.edu/cgi/interface.html|CGI/1.1 spec]]. All request headers will be passed as
    412 environment variables to the CGI program, prefixed with {{"HTTP_"}}, and converted to uppercase, with hyphens ("-") replaced by an underscore ("_"). The CGI program will receive the request body in unparsed form from stdin and should write a complete HTTP response to stdout.  Any headers that are missing but required for HTTP will be added by Spiffy.
    413 
    414 The following environment variables are currently not set during invocation of CGI subprocesses:
    415 
    416    AUTH_TYPE
    417    PATH_TRANSLATED
    418    REMOTE_HOST
    419    REMOTE_IDENT
    420    REMOTE_USER
    421 
    422 The {{cgi-handler}} procedure will simply execute the cgi binary directly.  This is useful if you have files with a special extension or in a directory on your server than can be run directly.
    423 
    424 The {{cgi-handler*}} procedure is usually more useful.  It allows you to define an interpreter to use for files and returns a file handler.  See the example above for {{spiffy-file-ext-handlers}}.
    425 
    426 ===== Configuration
    427 
    428 CGI handler can be configured with the following parameters:
    429 
    430 ; spiffy-cgi-default-environment (alist of string->string) : The environment variables that should be in the default environnment of every CGI program.  Variables like {{SCRIPT_NAME}} will be added dynamically to the end of this alist. Default:
    431 
    432 <enscript highlight=scheme>
    433 (("SERVER_SOFTWARE" . ,(spiffy-server-name))
    434  ("GATEWAY_INTERFACE" . "CGI/1.1")
    435  ("REDIRECT_STATUS" . "200"))
    436 </enscript>
    437 ==== simple-directory-handler
    438 
    439 In order to get directory listings, you can use {{simple-directory-handler}}.  Just assign the {{simple-directory-handler}} to {{spiffy-handle-directory}} and you're set.
    440 
    441 ===== Configuration
    442 
    443 The simple directory handler has a few configuration options:
    444 
    445 ; simple-directory-css (string) : The CSS which is included in every page to style it.  Defaults to a simple CSS string that adds some padding to the table and gives the page a mustard-colored background.
    446 ; simple-directory-dotfiles? (bool) : Determines if dotfiles should show up in the directory listings.  Default: {{#f}}
    447 ; simple-directory-display-file (lambda) : A lambda that accepts three arguments: the remote filename, the local filename and a boolean that says if the file is a directory.  This lambda should output a table row with the desired information.  Defaults to a lambda that prints the name, size and date when the file was last modified.
    448 
     177Spiffy has support for virtual hosting, using the HTTP/1.1 Host
     178header.  This allows you to use one Spiffy instance running on one IP
     179address/port number to serve multiple webpages, as determined by the
     180hostname that was requested.
     181
     182The virtual host is defined by a procedure, which can set arbitrary
     183parameters on-the-fly. It is passed a continuation thunk, which it
     184should explicitly call if it wants the processing to continue.  The
     185most used parameter in virtual host setups is the {{root-path}}
     186parameter, so that another docroot can be selected based on the
     187requested hostname, showing different websites for different hosts:
     188
     189<example>
     190(vhost-map `(("foo\\.bar\\.com" .
     191               ,(lambda (continue)
     192                  (parameterize ((file-extension-handlers
     193                                   `(("ssp" . ,ssp-handler) ("ws" . ,web-scheme-handler)))
     194                                 (root-path "/var/www/domains/foo.bar.com"))
     195                     (continue))))
     196             (,(glob->regexp "*.domain.com") .
     197                ,(lambda (continue)
     198                   (parameterize ((file-extension-handlers
     199                                    `(("php" . ,(cgi-handler* "/usr/pkg/bin/php"))))
     200                                  (root-path "/var/www/domains/domain.com"))
     201                     (continue))))))
     202</example>
     203
     204In this example, if a client accesses
     205{{foo.bar.com/mumble/blah.html}}, the file
     206{{/var/www/domains/foo.bar.com/mumble/blah.html}} will be served.  Any
     207files ending in {{.ssp}} or {{.ws}} will be served by the
     208corresponding file type handler.  If there's any PHP file, its source
     209will simply be displayed.  In case of
     210{{my.domain.com/something/bar.html}}, the file
     211{{/var/www/domains/domain.com/something/bar.html}} will be served.  If
     212there's a {{.ssp}} or {{.ws}} file there, it will not be interpreted.
     213Its source will be displayed instead.  A {{.php}} file, on the other
     214hand, will be passed via CGI to the program {{/usr/pkg/bin/php}}.
     215
     216Domain names are mapped to a lambda that sets up any parameters it
     217wants to override from the defaults.  The host names are matched using
     218{{string-match}}.  If the host name is not yet a regexp, it will be
     219converted to a ''case-insensitive'' regexp.
     220
     221=== Procedures and macros
     222
     223The following procedures and macros can be used in dynamic web
     224programs, or dynamic server configuration:
     225
     226<procedure>(with-headers new-headers thunk)</procedures>
     227
     228Call {{thunk}} with the header list {{new-headers}}. This
     229parameterizes the current response to contain the new headers.  The
     230existing headers are extended with {{new-headers}} through intarweb's
     231{{headers}} procedure.
     232
     233<procedure>(send-status code reason [message])</procedure>
     234
     235Easy way to send a page and a status code to the client.  The optional
     236message is a string containing HTML to add in the body of the
     237response. Example:
     238
     239<example>
     240<expr>
     241(send-status 404 "Not found"
     242 "Sorry, page not found! Please try <a href='/search.ws'>our search page</a>")
     243</expr>
     244</example>
     245
     246<procedure>(send-static-file filename)</procedure>
     247
     248Send a file to the client. This sets the {{content-length}} header and
     249tries to send the file as quickly as possible to the client. The
     250filename is interpreted relative to {{root-path}}.
     251
     252<procedure>(restart-request request)</procedure>
     253
     254Restart the entire request-handling starting at the point where the
     255request was just parsed. The argument is the new request to use.
     256Be careful, this makes it very easy to introduce unwanted endless loops!
    449257
    450258=== Changelog
    451259
    452 * trunk Add text/javascript to default content types. Removed procedures that don't belong in Spiffy: {{escape-chars}}, {{strip-tags}}, {{htmlize-with-spaces}}
    453 * 3.9 Fix bugs in resource handlers and add regression tests for them (thanks to Robin Lee Powell), streamline directory normalization, add 301 redirect on directory requests so all index pages end with a / (this makes relative hyperlinks work properly), add initial test for web-scheme-handler.  Change the way current-workdir works.
    454 * 3.8 Fix bug in resources handling and add test for it
    455 * 3.7 Plug file descriptor leak in {{send-static-file}}. [zb], fix bug in ssp-handler that caused it to fail on all pages, fix difference in {{include-ssp}} versus {{ssp-stringize}}'s way of handling the current workdir.  Add tests for SSP handler.
    456 * 3.6 Clean up header handling a little bit, update for latest sendfile and http eggs. Add {{spiffy-default-mime-type}}. Change the default MIME-type to {{application/octet-stream}} instead of {{text/plain}}.
    457 * 3.5 Remove remaining superfluous REQUEST and response-code arguments from procedures and simplify content-transporters.  Improve exception handling. Use the sendfile egg for transfer of static files.
    458 * 3.4 Add support for pathinfo, add support for stacked access-files, change access-files to be similar to vhost-handlers.  Fix the way path is handed to directory handlers to be the same as file handlers.  Add spiffy-access-denied? and remove spiffy-deny-paths and spiffy-deny-access (which makes it a lot cleaner and much more powerful). Automatically convert non-regexes to case insensitive regexes, making vhosting a little cleaner to set up.  Implement regression tests.
    459 * 3.3 Add handler ability for directory listings and extract existing handler to simple-directory-handler.  Fix relative directory handling for spiffy-root-path.  Fix directory links in directory listings for vhosts.
    460 * 3.2 Make all configuration options SRFI-39 parameters, so vhost configuration is much more flexible.  Normalize logfile handling.
    461 * 3.1 Improve CGI handling so it will work with PHP.
    462 * 3.0 Introduce modules for SSP, web-scheme and CGI.
    463 * 2.43 Program name was wrongly passed as argument to CGI subprocess.
    464 * 2.42 Fix small typo (thanks to Mario Domenech Goulart)
    465 * 2.41 Fixed bug in webscheme where any output would be injected in the HTTP response. {{.ws}} files can now be used for any pure scheme code to be evaled, as an alternative to {{.ssp}}. Fixed generate-directory-listing as per ticket #15.
    466 * 2.40 {{write-sxml}} generates improved output [Thanks to Peter Wright]
    467 * 2.39 Renamed {{sxml->html}} to {{write-sxml}} (kept the old name for backwards compatibility), also changed newline behaviour subtly [thanks to Peter Wright and Zbigniew Szadkowski]
    468 * 2.38 CGI "Status" header is recognized now
    469 * 2.37 Added handling for {{.htm}} extension [Thanks to Mario Goulart]
    470 * 2.36 Added {{spiffy-eval-environment}} and more error output
    471 * 2.35 Added {{spiffy-error-port}} [suggested by Daishi Kato]
    472 * 2.34 Bugfix in {{load-web-scheme}} by Mario Domenech Goulart
    473 * 2.33 More complete CGI support (needs http 1.47)
    474 * 2.32 Preliminary CGI support
    475 * 2.31 Disabled keep-alive connections on MSVC until its problems have been investigated [Suggested by Graham Fawcett]
    476 * 2.3 Disabled {{signal-handler}} setup on MSVC [Thanks to Graham Fawcett]
    477 * 2.2 {{htmlize}} shouldn't have replaced newlines with {{br}} tag
    478 * 2.1 Didn't cd to root dir on startup
    479 * 2.0 Support dynamic reconfiguration [by Peter Bex]
    480 * 1.53 Supports default {{"ws"}} page and small bugfix [Thanks to Mario Domenech Goulart]
    481 * 1.52 Add virtual hosting support [by Peter Bex]
    482 * 1.51 {{set-header!}} uses different regexp for non-pregexp platforms
    483 * 1.50 Direct loading of Scheme source code files with the {{".ws"}} extension [by Mario Goulart]
    484 * 1.49 Yet another bugfix by Hans Bulfone
    485 * 1.48 Better error-output
    486 * 1.47 Removed {{SIGPIPE}} handler (is done by tcp unit); added pregexp-compatibility hack [by Daishi Kato]
    487 * 1.46 Adapted to SRFI-69 compatible hash-tables
    488 * 1.45 The code in {{.ssp}} pages is evaluated in a lexically scoped body; added files beginning with a dot to files denied by default; added access-files
    489 * 1.44 {{define-http-resource}} automatically prefixes url with {{/}} if needed
    490 * 1.43 {{define-http-resource}} didn't pass headers and code back to responder [Thanks to Michele Simionato]
    491 * 1.42 {{define-http-resource}} binds some important parameters [Thanks to Michele Simionato]
    492 * 1.41 Link in directory listing to parent directory was broken [Thanks to Guy Banay]
    493 * 1.40 Added {{define-http-resource}} and reorganized code a tiny bit
    494 * 1.39 Serving files with no extension failed
    495 * 1.38 File-extension mapping was broken (argh)
    496 * 1.37 File-extension mapping is case-insensitive [Thanks to Peter Bex]
    497 * 1.36 Peter Bex added htmlize-with-spaces.
    498 * 1.35 Peter Bex added current-workdir and relative load/include paths
    499 * 1.34 Fixed a bug in {{load-scheme}} (uncaught exceptions triggered an unbound variable error)
    500 * 1.33 Directory-listing ignores broken links and displays footer; {{spiffy-program-pattern} is matched with full pathname
    501 * 1.32 Some bugfixes and cosmectic changes
    502 * 1.31 Removed {{spiffy-program-path}} and {{spiffy-log}}
    503 * 1.30 Spiffy is now a library; removed all command-line processing and {{spiffy-monitor}}; added {{start-server}} and support for exit in {{.ssp}} pages; directory listings; programs ({{spiffy-program-path}} and {{spiffy-program-pattern}}); {{get-header}}
    504 * 1.29 {{translate-file}} opened {{input-file}} twice; the default location is set to the result of {{get-host-name}}; {{set-header!}} used broken regular expression; errors during redirection are properly caught [Thanks to Peter Bex]
    505 * 1.28 The fallback page-handler didn't work with relative root-paths [Thanks to Gian Paolo Ciceri]
    506 * 1.27 Added optional argument to {{set-header!}}, removed {{load-ssp}} and added {{include-ssp}} and {{ssp-stringize}} [Thanks to Peter Bex]
    507 * 1.26 Added {{current-response-code}} and {{redirect}} (and renamed the old one to {{redirect-page}}). {{set-header!}} handles spaces in the header value [Thanks to Peter Bex]
    508 * 1.25 Changing to root path was done too early
    509 * 1.24 Fixed documentation; added text/css to list of content-types; on startup current directory is changed to root path; changing to user sets supplementary groups [Thanks to Peter Bex]
    510 * 1.22 Changed {{"root"}} directory to {{"web"}}
    511 * 1.21 argument needs no default value; {{set-header!}} wasn't exported
    512 * 1.20 Removed sill startup message, spiffy-monitor uses HEAD request, added several new helper procedures
    513 * 1.19 preliminary HEAD support
    514 * 1.18 {{spiffy-log}} was broken
    515 * 1.17 changed {{.shp}} and {{.shp.2}} extensions to {{.ssp}} and {{.sspx}}, respectively; several new API routines and improvements
    516 * 1.16 Updated for http extension (version 1.11), added support for restriction of incoming requests and changing user ID.
    517 * 1.15 fixed bug in startup code for daemonized spiffy
    518 * 1.14 reply protocol uses the one given in request
    519 * 1.13
     260* 4.0 Rewrite from scratch, using Intarweb
     261* pre-4.0 See the changelog for [[spiffy 3]]
    520262
    521263=== License
Note: See TracChangeset for help on using the changeset viewer.