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

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

Document remaining exported procedures, parameters etc

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