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

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

Document build-error-message

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