Web-unity

  1. Web-unity
    1. Description
    2. Author
    3. Requirements
    4. Download
    5. Documentation
      1. wu:set-header!
      2. wu:run-handler
      3. wu:write-headers
      4. wu:get-header
      5. wu:cookie-set!
      6. wu:cookie-delete!
      7. Request parameters
      8. Example
    6. Changelog
    7. License

Description

A unification framework for web server communications systems like CGI, SCGI or FastCGI and Spiffy.

NOTE: This documentation is a quick write-up. It needs to be improved. The egg is alpha code too.

Author

Peter Bex

Requirements

It always needs http

Extra requirements vary depending on how you want to run it; if you wish to use Spiffy, you'll need the spiffy egg, if you wish to use FastCGI you'll need the fastcgi egg, if you wish to use SCGI you'll need the scgi egg. If you only need CGI, there are no extra requirements.

Download

web-unity.egg

Documentation

Web-unity is an attempt to remove the differences between the various ways you can write web applications with Chicken. The goal is to ease professional webdevelopment by making it possible to deploy on different server architectures than you develop on, and making it easier to migrate to a different system when the need arises. This allows you to move from CGI to FastCGI if your webserver can't handle the requests any longer, or develop on Spiffy and deploy on your Lighttpd production server using SCGI.

This is done by abstracting away a couple of things, so it may mean slightly degraded performance or power.

wu:set-header!

 (wu:set-header! name value)

Sets a HTTP header in the current response by changing the value of the current-response-headers parameter. 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.

wu:run-handler

 (wu:run-handler dispatcher)

This invokes the main loop that handles requests. The dispatcher is a thunk (lambda with no args) that will be invoked whenever a request comes in on the server. This needs to be called last from whatever bootstrap code you run to set up a web application. The run-handler takes care of setting up the environment correctly so that the given dispatcher can have the information it needs to work with independently of the type of web server.

wu:write-headers

 (wu:write-headers)

Write the current headers from the wu:response-headers parameter. This must be done before emitting any output and it must be done exactly once.

wu:get-header

 (wu:get-header name [default])

Get the current value of the given header. If the optional default is given, this is returned if the header is not found, otherwise #f is returned.

wu:cookie-set!

 (wu:cookie-set! name value #!key comment max-age domain path secure)

Set the current value of the RFC2109 cookie with the given name.

Cookies will expire when the session ends (usually when the browser closes) unless MAX-AGE is supplied, which is an integer argument declaring the maximum time the cookie can be stored on the client side, in seconds. A MAX-AGE of 0 also results in the cookie being deleted when the session ends.

COMMENT is an optional comment specifying the nature of the cookie. The user will see this in his browser's cookie store, and may use this to decide wether or not to accept the cookie.

The DOMAIN string specifies for which domain the cookie is. The cookie will only be returned on subsequent requests to that domain. By default, the domain is the domain from which the cookie originates.

The PATH string specifies the topmost path from which this cookie is active. If there are multiple cookies with the same name, the value from the cookie with the most specific ("deepest") path will be passed to the server.

Finally, the boolean SECURE can be set to #t if the cookie should be treated as confidential information.

wu:cookie-delete!

 (wu:cookie-delete! name #!key domain path)

Delete the given cookie. Equivalent to calling wu:cookie-set! with a MAX-AGE of zero.

Request parameters

Most request information is available through SRFI-39 parameters.

wu:request-method (symbol)
The current request's HTTP method as a lower-cased symbol (get, post).
wu:params (alist)
The current HTTP method's parameters with their values (all strings). With GET this is equal to the query-params, with POST it contains the POST request attributes
wu:cookies (alist)
The current RFC2109 cookies, as name-value pairs (all strings).
wu:query-params (alist)
The current query parameters (URL commandline parameters), even if the method is post, for example.
wu:script-name (string)
The absolute path to the script in the URL, up to, but not including, the pathinfo.
wu:script-filename (string)
The absolute path to the script in the filesystem.
wu:path-info (string)
The pathinfo component of the URL (this is the pathname part after the actual script's filename)
wu:response-headers (alist)
The headers that will be sent when you call (wu:write-headers). Default: (("Content-Type" . "text/html))
wu:response-code (integer-string pair)
The response code that will be sent when you call (wu:write-headers). Default: (200 . "OK")
wu:headers-sent (boolean)
Whether headers have already been sent by wu:write-headers, during this request
wu:exception-handler (procedure)
Exception handler for exceptions thrown in web-unity code. Override this to get pretty error output and/or hide stack traces.

Example

TODO: Invent a better example (one that doesn't statically load one file)

Here is a really small example file that is written in web-unity:

  ;; Example.scm
  (wu:set-header! "content-type" "text/html")
  (wu:write-headers)
  (printf "params: ~A<br />\nquery args: ~A\n<br />method: ~A\n" (wu:params) (wu:query-params) (wu:request-method))
  (printf "parameter (http_)accept = ~A\n<br />" (wu:get-header "accept"))
  (printf "script-name = ~A\n<br />" (wu:script-name))
  (printf "script-filename = ~A\n<br />" (wu:script-filename))
  (printf "<form action=\"\" method=\"post\"><input name=\"foo\" /><input name=\"bar\" /><input type=\"submit\" /></form>")

You can setup lighttpd using CGI so it loads this script as follows:

 cgi.assign = ( ".scm" => "/usr/libexec/cgi-dispatcher.scm")

where the cgi-dispatcher file contains the following:

  #!/usr/pkg/bin/csi -s

  (use web-unity-cgi)
  (wu:run-handler (lambda () (load "example.scm")))

Lighttpd with FCGI works as follows:

 fastcgi.server = (
   ".scm" => (
     "localhost" => (
       "socket" => "/tmp/fastcgi-socket",
       "min-procs" => 1,
       "max-procs" => 1,
       "bin-path" => "/usr/libexec/fcgi-dispatcher.scm"
     )
   )
 )

where the cgi-dispatcher file contains the following:

  #!/usr/pkg/bin/csi -s

  (use web-unity-fcgi)
  (wu:run-handler (lambda () (load "example.scm")))

Spiffy works a little differently (the web-unity-handler comes with the web-unity egg):

  (use web-unity-handler)
  (spiffy-file-ext-handlers `(("scm" . ,(web-unity-handler "/usr/libexec/spiffy-dispatcher.scm"))))

where the spiffy-dispatcher file contains the following:

  (use web-unity-spiffy)
  (define lp ##sys#current-load-path)
  (wu:run-handler (lambda () (load (string-append lp "example.scm"))))

Changelog

License

 Copyright (c) 2007, 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.