source: project/wiki/eggref/4/spiffy @ 12521

Last change on this file since 12521 was 12521, checked in by sjamaan, 12 years ago

Document the spiffy modules now that they've been ported

File size: 18.7 KB
Line 
1[[tags: egg]]
2
3== Spiffy
4
5[[toc:]]
6
7=== Description
8
9A small web-server written in [[http://www.call-with-current-continuation.org|Chicken]].
10
11=== Author
12
13[[Felix Winkelmann]].  Currently maintained by [[Peter Bex]].
14
15=== Requirements
16
17Requires the [[intarweb]], [[matchable]] and [[sendfile]] extensions.
18
19=== Download
20
21[[http://www.call-with-current-continuation.org/eggs/spiffy.egg|spiffy.egg]]
22
23=== Documentation
24
25Spiffy is a web-server library for the Chicken Scheme system. It's
26quite easy to set up and use (whether as a library or a standalone
27server application) and it can be customized in numerous ways.
28
29=== Starting the server
30
31<procedure>(start-server [port: port-number])</procedure>
32
33Starts the server, to listen on the given port. Other configuration
34can be tweaked through SRFI-39 parameters. These are listed below.
35Once the server is started, server behaviour can be controlled through
36these parameters as well. By default, Spiffy will only serve static
37files. On directories, it will give a "403 forbidden", unless there
38is an index-file. If there is, that file's contents will be shown.
39
40All arguments directly supplied to {{start-server}} override the
41configuration parameter values.
42
43{{Port-number}} defaults to 8080.
44
45=== Configuration parameters
46
47The following parameters can be used to control spiffy's behaviour.
48Besides these parameters, you can also influence spiffy's behaviour by
49tweaking the [[intarweb]] parameters.
50
51<parameter>(root-path [path])</parameter>
52
53The path to the document root. Defaults to {{"./web"}}.
54
55<parameter>(server-port [port-number])</parameter>
56
57The port number on which to listen. Defaults to 8080.
58
59<parameter>(index-files [file-list])</parameter>
60
61A list of filenames which are to be used as index files to serve when
62the requested URL identifies a directory.  Defaults to
63{{'("index.html" "index.xhtml")}}
64
65<parameter>(mime-type-map [extension->mimetype-list])</parameter>
66
67An alist of extensions (strings) to mime-types (symbols), to use
68for the content-type header when serving up a static file. Defaults to
69  (("xml" . text/xml)
70   ("html" . text/html)
71   ("xhtml" . text/xhtml+xml)
72   ("js"  . text/javascript)
73   ("pdf" . application/pdf)
74   ("css" . text/css)
75   ("png" . image/png)
76   ("ico" . image/x-icon)
77   ("gif" . image/gif)
78   ("jpeg" . image/jpeg)
79   ("jpg" . image/jpeg)
80   ("svg" . image/svg+xml)
81   ("bmp" . image/bmp)
82   ("txt" . text/plain))
83
84<parameter>(default-mime-type [mime-type])</parameter>
85
86The mime-type (a symbol) to use if none was found in the
87{{mime-type-map}}. Defaults to {{'application/octet-stream}}
88
89<parameter>(default-host [hostname])</parameter>
90
91The host name to use when no virtual host could be determined from the
92request.  See the section on virtual hosts below.
93
94<parameter>(vhost-map [host-regex->vhost-handler])</parameter>
95
96A mapping of virtual hosts (regex) to handlers (procedures of one
97argument; a continuation thunk). See the section on virtual hosts
98below. Defaults to {{`((".*" . ,(lambda (continue) (continue))))}}
99
100<parameter>(file-extension-handlers [extension->handler-list])</parameter>
101
102An alist mapping file extensions (strings) to handler procedures
103(lambdas of one argument; the file name relative to the webroot).
104Defaults to {{'()}}. If no handler was found, defaults to just sending
105a static file.
106
107=== Handlers
108
109Besides "static" configuration, Spiffy also has several handlers for
110when something is to be served.
111
112<parameter>(handle-directory [proc])</parameter>
113
114The handler for directory entries. If the requested URL points to a
115directory which has no index file, this handler is invoked. It is a
116procedure of one argument, the path (a string) relative to the
117webroot. Defaults to a procedure which returns a "403 forbidden".
118
119<parameter>(handle-file [proc])</parameter>
120
121The handler for files. If the requested URL points to a file, this
122handler is invoked to serve the file. It is a procedure of one
123argument, the path (a string) relative to the webroot. Defaults to a
124procedure which sets the content-type and determines a handler based
125on the {{file-extension-handlers}}, or {{send-static-file}} if none
126was found.
127
128<parameter>(handle-not-found [proc])</parameter>
129
130The handler for nonexisting files. If the requested URL does not point
131to an existing file or directory, this procedure is called. It is a
132procedure of one argument, the path (a string) that was
133requested. This path should be interpreted as being relative to the
134webroot (even though it points to no existing file). Defaults to a
135procedure which returns a "404 Not found".
136
137=== Runtime information
138
139During the handling of a request, Spiffy adds more information to the
140environment by parameterizing the following parameters whenever the
141information becomes available:
142
143<parameter>(current-request [request])</parameter>
144
145An intarweb request-object that defines the current request. Available
146from the moment the request comes in and is parsed. Contains, among
147other things, the query parameters and the request-headers, in fully
148parsed form (as intarweb returns them).
149
150<parameter>(current-response [request])</parameter>
151
152An intarweb response-object that defines the current
153response. Available from the same time current-request is available.
154This keeps getting updated along the way, while the response data is
155being refined (like when headers are being added).
156
157<parameter>(current-file [path])</parameter>
158
159The path to the requested file (a string). Available from the moment
160Spiffy determined the requested URL points to a file (just before the
161{{handle-file}} procedure is called).
162
163<parameter>(current-pathinfo [path])</parameter>
164
165The trailing path ''fragments'' (a list of strings) that were passed
166in the URL after the requested filename. Available from the moment
167Spiffy determined the requested URL points to a file (just before the
168{{handle-file}} procedure is called).
169
170=== Virtual hosts
171
172Spiffy has support for virtual hosting, using the HTTP/1.1 Host
173header.  This allows you to use one Spiffy instance running on one IP
174address/port number to serve multiple webpages, as determined by the
175hostname that was requested.
176
177The virtual host is defined by a procedure, which can set arbitrary
178parameters on-the-fly. It is passed a continuation thunk, which it
179should explicitly call if it wants the processing to continue.  The
180most used parameter in virtual host setups is the {{root-path}}
181parameter, so that another docroot can be selected based on the
182requested hostname, showing different websites for different hosts:
183
184<example>
185<expr>
186(vhost-map `(("foo\\.bar\\.com" .
187               ,(lambda (continue)
188                  (parameterize ((file-extension-handlers
189                                   `(("ssp" . ,ssp-handler) ("ws" . ,web-scheme-handler)))
190                                 (root-path "/var/www/domains/foo.bar.com"))
191                     (continue))))
192             (,(glob->regexp "*.domain.com") .
193                ,(lambda (continue)
194                   (parameterize ((file-extension-handlers
195                                    `(("php" . ,(cgi-handler* "/usr/pkg/bin/php"))))
196                                  (root-path "/var/www/domains/domain.com"))
197                     (continue))))))
198</expr>
199</example>
200
201In this example, if a client accesses
202{{foo.bar.com/mumble/blah.html}}, the file
203{{/var/www/domains/foo.bar.com/mumble/blah.html}} will be served.  Any
204files ending in {{.ssp}} or {{.ws}} will be served by the
205corresponding file type handler.  If there's any PHP file, its source
206will simply be displayed.  In case of
207{{my.domain.com/something/bar.html}}, the file
208{{/var/www/domains/domain.com/something/bar.html}} will be served.  If
209there's a {{.ssp}} or {{.ws}} file there, it will not be interpreted.
210Its source will be displayed instead.  A {{.php}} file, on the other
211hand, will be passed via CGI to the program {{/usr/pkg/bin/php}}.
212
213Domain names are mapped to a lambda that sets up any parameters it
214wants to override from the defaults.  The host names are matched using
215{{string-match}}.  If the host name is not yet a regexp, it will be
216converted to a ''case-insensitive'' regexp.
217
218=== Procedures and macros
219
220The following procedures and macros can be used in dynamic web
221programs, or dynamic server configuration:
222
223<procedure>(with-headers new-headers thunk)</procedure>
224
225Call {{thunk}} with the header list {{new-headers}}. This
226parameterizes the current response to contain the new headers.  The
227existing headers are extended with {{new-headers}} through intarweb's
228{{headers}} procedure.
229
230<procedure>(send-status code reason [message])</procedure>
231
232Easy way to send a page and a status code to the client.  The optional
233message is a string containing HTML to add in the body of the
234response. Example:
235
236<example>
237<expr>
238(send-status 404 "Not found"
239 "Sorry, page not found! Please try <a href='/search.ws'>our search page</a>")
240</expr>
241</example>
242
243<procedure>(send-static-file filename)</procedure>
244
245Send a file to the client. This sets the {{content-length}} header and
246tries to send the file as quickly as possible to the client. The
247filename is interpreted relative to {{root-path}}.
248
249<procedure>(restart-request request)</procedure>
250
251Restart the entire request-handling starting at the point where the
252request was just parsed. The argument is the new request to use.
253Be careful, this makes it very easy to introduce unwanted endless loops!
254
255=== Modules
256
257This section will describe what the various modules that come with
258Spiffy are and how they work.
259
260==== ssp-handler
261
262SSP, or Scheme Server Pages, are a way to embed Scheme in HTML
263pages. Files with an extension of {{.ssp}} are handled specifically,
264by replacing occurrences of certain reserved tags with Scheme code.
265There are two possible forms, either the long version, where all
266output is redirected to the HTTP response port, or the short, where
267the result of the embedded expression is displayed in the response.
268The tags default to {{<?scheme}} and {{<?}}, see Configuration for how
269to change them.
270
271<enscript highlight=scheme>
272   <html><body>
273   <ol><?scheme (for-each (lambda (i) (printf "<li>~S~%" i)) (iota 5))?></ol>
274   <br />
275   <b><?(call-with-values (lambda () (user-information (current-user-id))) (lambda (name . _) name))?><b>
276   </body></html>
277</enscript>
278
279would generate for example something like this:
280
281     1. 0
282     2. 1
283     3. 2
284     4. 3
285     5. 4
286
287  (felix x 500 100 /home/felix /bin/bash)
288
289When a {{.ssp}} file is loaded the first time, or when it has been
290modified, then a translation takes place that generates a loadable
291Scheme source file (with the extension {{.sspx}}, in the same
292directory as the original file) from the original data, so in the
293above example something like this would be generated:
294
295<enscript highlight=scheme>
296  (let ()
297    (display "<html><body>\n<ol>")
298    (for-each (lambda (i) (printf "<li>~S~%" i)) (iota 5))
299    (display "</ol>\n<br />\n<b>")
300    (display (call-with-values (lambda () (user-information (current-user-id))) (lambda (name . _) name)))
301    (display "<b>\n</body></html>\n") )
302</enscript>
303
304Note that the body is evaluated in a {{(let () ...)}} form.
305
306Note: each request runs in a separate thread, so code in {{.ssp}}
307pages should take care when using global variables.
308
309===== Configuration
310
311The SSP handler can be configured with the following options:
312
313<parameter>(ssp-short-open-tag [tag-regexp])</parameter>
314
315The opening tag for short fragments. Default: {{<?}}
316
317<parameter>(ssp-long-open-tag [tag-regexp])</parameter>
318
319The opening tag for long fragments. Default: {{<?scheme}}
320
321<parameter>(ssp-close-tag [tag-regexp])</parameter>
322
323The closing tag for Scheme fragments in {{.ssp}} files. Default: {{?>}}
324
325<parameter>(ssp-eval-environment [environment])</parameter>
326
327The environment passed to {{eval}} when evaluating Scheme code inside
328{{.ssp}}-pages.  Default: {{interaction-environment}}
329
330===== Runtime information
331
332For the duration of evaluating a SSP page, the following parameters
333will have a value assigned to them:
334
335<parameter>(current-workdir [path])</parameter>
336
337During execution, the current working directory of the SSP handler.
338Any of the "include" procedures (ssp-include, ssp-stringize) will
339interpret their file arguments to be relative to this directory.
340
341<parameter>(exit-handler [handler])</parameter>
342
343During execution of an ssp page, {{exit-handler}} is bound to a
344procedure that will finish the current page, ignoring any further
345content or code.
346
347===== Procedures
348
349The ssp-handler module adds the following procedures to the environment:
350
351<procedure>(ssp-handler filename)</procedure>
352
353The handler itself, which should be used in the {{file-extension-handlers}}
354parameter list.
355
356<procedure>(ssp-include filename)</procedure>
357
358Translates the file {{filename}} into Scheme by replacing {{<?scheme ... ?>}}
359and {{<? ... ?>}} sequences (if needed) and writes the translated contents
360to the current output-port.
361
362<procedure>(ssp-stringize FILENAME)</procedure>
363
364Similar to {{ssp-include}}, but instead of writing the translated
365text, the text is returned as a string.
366
367==== web-scheme-handler
368
369Another way of executing Scheme code to produce content are {{.ws}}
370files: these should contain a Scheme expression that is expected to
371evaluate to a string which will be directly written as the response to
372the current request. This facility is intended for Scheme code that
373uses the [[web-scheme]] extension.
374
375You can use the {{web-scheme-handler}} for any Scheme file which
376returns HTML as a string or which has a side-effect of outputting the
377HTML. If it's the latter, make sure the final statement in your file
378does not return a string or it will be appended to the output (just
379like in the {{csi}} REPL).
380
381'''Tip''' This handler type is perfect not only for web-scheme but
382also for when you're using {{SRV:send-reply}} with SXML or for example a
383wiki-to-string translator.
384
385Note: each request runs in a separate thread, so code in {{.ws}} pages
386should take care when using global variables.
387
388Note: web-scheme-handler is a separate extension and must be imported
389as such.
390
391<enscript highlight=scheme>
392(require-extension web-scheme-handler)
393</enscript>
394
395===== Configuration
396
397The Web-scheme handler can be configured with the following options:
398
399<parameter>(web-scheme-eval-environment [environment])</parameter>
400
401The environment passed to {{eval}} when evaluating Scheme code inside
402{{.ws}}-pages.  Default: {{interaction-environment}}
403
404===== Procedures
405
406The Web-scheme handler adds only one procedure to the environment:
407
408<procedure>(web-scheme-handler filename)</procedure>
409
410The handler itself, which should be used in the {{file-extension-handlers}}
411parameter list.
412
413
414==== cgi-handler
415
416Spiffy supports [[http://www.ietf.org/rfc/rfc3875|CGI/1.1 as specified by RFC 3875]].
417
418All request headers will be passed as environment variables to the CGI
419program, prefixed with {{"HTTP_"}}, and converted to uppercase, with
420hyphens ("-") replaced by an underscore ("_"). The CGI program will
421receive the request body in unparsed form from stdin and should write
422a complete HTTP response to stdout.  Any headers that are missing but
423required for HTTP will be added by Spiffy.  For more info on how a CGI
424script is called, consult the spec.
425
426The {{AUTH_TYPE}} and {{REMOTE_USER}} environment variables are
427currently not set during invocation of CGI subprocesses.
428The {{REMOTE_IDENT}} environment variable is not and never will be supported.
429
430===== Configuration
431
432CGI handler can be configured with the following parameters:
433
434<procedure>(cgi-default-environment [env-alist])</procedure>
435
436The environment variables that should be in the default environnment
437of every CGI program.  Variables like {{SCRIPT_NAME}} will be added
438dynamically to the end of this alist.
439
440Default:
441<enscript highlight=scheme>
442(("SERVER_SOFTWARE" . ,(server-software))
443 ("GATEWAY_INTERFACE" . "CGI/1.1")
444 ("REDIRECT_STATUS" . "200"))
445</enscript>
446
447===== Procedures
448
449CGI-handler adds two procedures to the environment:
450
451<procedure>(cgi-handler filename [interpreter])</procedure>
452
453The {{cgi-handler}} procedure is called by {{cgi-handler*}} with the
454filename. It's not very useful on its own.
455
456<procedure>(cgi-handler* [interpreter])</procedure>
457
458The {{cgi-handler*}} procedure is usually more useful.  It allows you
459to define an interpreter to use for files and returns a file handler.
460See the example above for {{file-extension-handlers}}.
461
462
463==== simple-directory-handler
464
465In order to get directory listings, you can use
466{{simple-directory-handler}}.  Just assign the
467{{simple-directory-handler}} to {{handle-directory}} and you're set.
468
469===== Configuration
470
471The simple directory handler has a few configuration options:
472
473<procedure>(simple-directory-dotfiles? [dotfiles?])</procedure>
474
475Determines if dotfiles should show up in the directory listings.
476Default: {{#f}}
477
478<procedure>(simple-directory-display-file [displayer])</procedure>
479
480A lambda that accepts three arguments: the remote filename, the local
481filename and a boolean that says if the file is a directory.  This
482lambda should output a table row with the desired information.
483Defaults to a lambda that prints the name, size and date when the file
484was last modified.
485
486===== Procedures
487
488The simple-directory handler adds only one procedure to the environment:
489
490<procedure>(simple-directory-handler pathname)</procedure>
491
492The handler itself, which should be used in the {{handle-directory}}
493parameter.
494
495
496=== Changelog
497
498* 4.0 Rewrite from scratch, using Intarweb
499* pre-4.0 See the changelog for the old [[spiffy]]
500
501=== License
502
503  Copyright (c) 2005-2008, Felix L. Winkelmann and Peter Bex
504  All rights reserved.
505 
506  Redistribution and use in source and binary forms, with or without
507  modification, are permitted provided that the following conditions are
508  met:
509 
510  Redistributions of source code must retain the above copyright
511  notice, this list of conditions and the following disclaimer.
512 
513  Redistributions in binary form must reproduce the above copyright
514  notice, this list of conditions and the following disclaimer in the
515  documentation and/or other materials provided with the distribution.
516 
517  Neither the name of the author nor the names of its contributors may
518  be used to endorse or promote products derived from this software
519  without specific prior written permission.
520 
521  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
522  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
523  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
524  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
525  COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
526  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
527  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
528  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
529  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
530  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
531  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
532  OF THE POSSIBILITY OF SUCH DAMAGE.
Note: See TracBrowser for help on using the repository browser.