You are looking at historical revision 12039 of this page. It may differ significantly from its current revision.

Spiffy

Description

A small web-server written in Chicken.

This is the documentation for Spiffy 4, a rewrite from scratch. For information on Spiffy 3, please see spiffy 3.

Author

Felix Winkelmann. Currently maintained by Peter Bex.

Requirements

Requires the intarweb, matchable and sendfile extensions.

Download

spiffy.egg

Documentation

Spiffy is a web-server library for the Chicken Scheme system. It's quite easy to set up and use (whether as a library or a standalone server application) and it can be customized in numerous ways.

Starting the server

[procedure] (start-server [port: port-number])

Starts the server, to listen on the given port. Other configuration can be tweaked through SRFI-39 parameters. These are listed below. Once the server is started, server behaviour can be controlled through these parameters as well. By default, Spiffy will only serve static files. On directories, it will give a "403 forbidden", unless there is an index-file. If there is, that file's contents will be shown.

All arguments directly supplied to start-server override the configuration parameter values.

Port-number defaults to 8080.

Configuration parameters

The following parameters can be used to control spiffy's behaviour. Besides these parameters, you can also influence spiffy's behaviour by tweaking the intarweb parameters.

[parameter] (root-path [path])

The path to the document root. Defaults to "./web".

[parameter] (server-port [port-number])

The port number on which to listen. Defaults to 8080.

[parameter] (index-files [file-list])

A list of filenames which are to be used as index files to serve when the requested URL identifies a directory. Defaults to '("index.html" "index.xhtml")

[parameter] (mime-type-map [extension->mimetype-list])

An alist of extensions (strings) to mime-types (symbols), to use for the content-type header when serving up a static file. Defaults to

 (("xml" . text/xml)
  ("html" . text/html)
  ("xhtml" . text/xhtml+xml)
  ("js"  . text/javascript)
  ("pdf" . application/pdf)
  ("css" . text/css)
  ("png" . image/png)
  ("ico" . image/x-icon)
  ("gif" . image/gif)
  ("jpeg" . image/jpeg)
  ("jpg" . image/jpeg)
  ("svg" . image/svg+xml)
  ("bmp" . image/bmp)
  ("txt" . text/plain))
[parameter] (default-mime-type [mime-type])

The mime-type (a symbol) to use if none was found in the mime-type-map. Defaults to 'application/octet-stream

[parameter] (default-host [hostname])

The host name to use when no virtual host could be determined from the request. See the section on virtual hosts below.

[parameter] (vhost-map [host-regex->vhost-handler])

A mapping of virtual hosts (regex) to handlers (procedures of one argument; a continuation thunk). See the section on virtual hosts below. Defaults to `((".*" . ,(lambda (continue) (continue))))

[parameter] (file-extension-handlers [extension->handler-list])

An alist mapping file extensions (strings) to handler procedures (lambdas of one argument; the file name relative to the webroot). Defaults to '(). If no handler was found, defaults to just sending a static file.

Handlers

Besides "static" configuration, Spiffy also has several handlers for when something is to be served.

[parameter] (handle-directory [proc])

The handler for directory entries. If the requested URL points to a directory which has no index file, this handler is invoked. It is a procedure of one argument, the path (a string) relative to the webroot. Defaults to a procedure which returns a "403 forbidden".

[parameter] (handle-file [proc])

The handler for files. If the requested URL points to a file, this handler is invoked to serve the file. It is a procedure of one argument, the path (a string) relative to the webroot. Defaults to a procedure which sets the content-type and determines a handler based on the file-extension-handlers, or send-static-file if none was found.

[parameter] (handle-not-found [proc])

The handler for nonexisting files. If the requested URL does not point to an existing file or directory, this procedure is called. It is a procedure of one argument, the path (a string) that was requested. This path should be interpreted as being relative to the webroot (even though it points to no existing file). Defaults to a procedure which returns a "404 Not found".

Runtime information

During the handling of a request, Spiffy adds more information to the environment by parameterizing the following parameters whenever the information becomes available:

[parameter] (current-request [request])

An intarweb request-object that defines the current request. Available from the moment the request comes in and is parsed. Contains, among other things, the query parameters and the request-headers, in fully parsed form (as intarweb returns them).

[parameter] (current-response [request])

An intarweb response-object that defines the current response. Available from the same time current-request is available. This keeps getting updated along the way, while the response data is being refined (like when headers are being added).

[parameter] (current-file [path])

The path to the requested file (a string). Available from the moment Spiffy determined the requested URL points to a file (just before the handle-file procedure is called).

[parameter] (current-pathinfo [path])

The trailing path fragments (a list of strings) that were passed in the URL after the requested filename. Available from the moment Spiffy determined the requested URL points to a file (just before the handle-file procedure is called).

Virtual hosts

Spiffy has support for virtual hosting, using the HTTP/1.1 Host header. This allows you to use one Spiffy instance running on one IP address/port number to serve multiple webpages, as determined by the hostname that was requested.

The virtual host is defined by a procedure, which can set arbitrary parameters on-the-fly. It is passed a continuation thunk, which it should explicitly call if it wants the processing to continue. The most used parameter in virtual host setups is the root-path parameter, so that another docroot can be selected based on the requested hostname, showing different websites for different hosts:

<example> <expr> (vhost-map `(("foo\\.bar\\.com" .

              ,(lambda (continue)
                 (parameterize ((file-extension-handlers
                                  `(("ssp" . ,ssp-handler) ("ws" . ,web-scheme-handler)))
                                (root-path "/var/www/domains/foo.bar.com"))
                    (continue))))
            (,(glob->regexp "*.domain.com") .
               ,(lambda (continue)
                  (parameterize ((file-extension-handlers
                                   `(("php" . ,(cgi-handler* "/usr/pkg/bin/php"))))
                                 (root-path "/var/www/domains/domain.com"))
                    (continue))))))

</expr> </example>

In this example, if a client accesses foo.bar.com/mumble/blah.html, the file /var/www/domains/foo.bar.com/mumble/blah.html will be served. Any files ending in .ssp or .ws will be served by the corresponding file type handler. If there's any PHP file, its source will simply be displayed. In case of my.domain.com/something/bar.html, the file /var/www/domains/domain.com/something/bar.html will be served. If there's a .ssp or .ws file there, it will not be interpreted. Its source will be displayed instead. A .php file, on the other hand, will be passed via CGI to the program /usr/pkg/bin/php.

Domain names are mapped to a lambda that sets up any parameters it wants to override from the defaults. 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.

Procedures and macros

The following procedures and macros can be used in dynamic web programs, or dynamic server configuration:

<procedure>(with-headers new-headers thunk)</procedures>

Call thunk with the header list new-headers. This parameterizes the current response to contain the new headers. The existing headers are extended with new-headers through intarweb's headers procedure.

[procedure] (send-status code reason [message])

Easy way to send a page and a status code to the client. The optional message is a string containing HTML to add in the body of the response. Example:

<example> <expr> (send-status 404 "Not found"

"Sorry, page not found! Please try <a href='/search.ws'>our search page</a>")

</expr> </example>

[procedure] (send-static-file filename)

Send a file to the client. This sets the content-length header and tries to send the file as quickly as possible to the client. The filename is interpreted relative to root-path.

[procedure] (restart-request request)

Restart the entire request-handling starting at the point where the request was just parsed. The argument is the new request to use. Be careful, this makes it very easy to introduce unwanted endless loops!

Changelog

License

 Copyright (c) 2005-2008, Felix L. Winkelmann and Peter Bex
 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.