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

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

Add info about logging support

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