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

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

Document user/group switching

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