Wiki
Download
Manual
Eggs
API
Tests
Bugs
show
edit
history
You can edit this page using
wiki syntax
for markup.
Article contents:
== Outdated egg! This is an egg for CHICKEN 4, the unsupported old release. You're almost certainly looking for [[/eggref/5/spiffy|the CHICKEN 5 version of this egg]], if it exists. If it does not exist, there may be equivalent functionality provided by another egg; have a look at the [[https://wiki.call-cc.org/chicken-projects/egg-index-5.html|egg index]]. Otherwise, please consider porting this egg to the current version of CHICKEN. [[tags: egg]] == Spiffy [[toc:]] === Description A small web-server written in [[http://www.call-cc.org|Chicken]]. === Author [[/users/felix-winkelmann|Felix Winkelmann]]. Currently maintained by [[/users/peter-bex|Peter Bex]]. === Requirements Requires the [[intarweb]], [[uri-common]], [[uri-generic]] and [[sendfile]] extensions. === Documentation Spiffy is a web-server library for the Chicken Scheme system. It's quite easy to set up and use (whether as a library or a standalone server application) and it can be customized in numerous ways. To test it out immediately, try the following command after installing: $ csi -e "(use spiffy) (start-server)" This starts up a spiffy server which listens on port 8080, and serves documents from the default docroot, which is a directory called {{web}} underneath the current working directory. A typical httpd would be a more complete program which first configures a few things like the {{port-number}} and {{root-path}} parameters and set up some logging through {{access-log}} and {{error-log}}. It could also configure some extensions (like {{simple-directory-handler}}) and register some user-defined path handlers by adding them to {{vhost-map}}. Finally it could daemonize by forking and exiting. The mentioned parameters are explained below. === Starting the server <procedure>(start-server [port: port-number] [bind-address: address] [listen: listen-procedure] [accept: accept-procedure] [addresses: addresses-procedure])</procedure> This is the most convenient way to get a server up and running quickly. It starts the server to listen on the given port. Other configuration can be tweaked through SRFI-39 parameters. These are listed below. Once the server is started, server behaviour can be controlled through these parameters as well. After the listener is started, when {{spiffy-user}} and/or {{spiffy-group}} are provided, this procedure will drop privileges before starting the accept loop. By default, Spiffy will only serve static files. On directories, it will give a "403 forbidden", unless there is an index-file. If there is, that file's contents will be shown. All arguments directly supplied to {{start-server}} override the configuration parameter values and will be parameterized to reflect this new setting. {{port-number}} defaults to the value of {{server-port}} (see below). {{bind-address}} defaults to the value of {{server-bind-address}} (see below). {{listen}} defaults to {{tcp-listen}} and should accept a port number, backlog and bind address. {{accept}} defaults to {{tcp-accept}}, and is passed on as-is to {{accept-loop}}. {{addresses-procedure}} defaults to a procedure which works like {{tcp-addresses}} but can also detect SSL ports and return the addresses of the underlying TCP connection. <procedure>(accept-loop listener accept [addresses])</procedure> This procedure starts the loop which accepts incoming connections and fires off threads to handle requests on those connections. You can use it if you need more control over the startup process than {{start-server}} offers. The listener object should be an object which is accepted by the {{accept}} procedure, which should return two values; an input and an output port which represent an incoming connection from a client. The optional {{addresses}} procedure should accept the input port returned by the {{accept}} procedure and return two strings; the local and remote addresses of the server and client, respectively. For example, you can set up an SSL context and drop privileges, and possibly load extra code before starting the accept loop (Spiffy contains the required code to detect SSL ports, and will handle those more-or-less transparently): <enscript highlight="scheme"> (use chicken-syntax) ; This must done at the very toplevel so that it is available in the interaction-environment. (use spiffy openssl) (server-port 443) (spiffy-user "www") (spiffy-group "www") ;; Bind the port as root, before we drop privileges (define listener (ssl-listen (server-port))) ;; Load the certificate files as root so we can secure their permissions (ssl-load-certificate-chain! listener "server.pem") (ssl-load-private-key! listener "server.key") ;; Drop root privileges (switch-user/group (spiffy-user) (spiffy-group)) ;; We don't want to load this extra code as root! (load "extra-code.scm") ;; Done! Start listening for connections. (accept-loop listener ssl-accept) </enscript> <procedure>(switch-user/group user group)</procedure> This is a helper procedure which allows you to easily drop privileges before running the accept loop. The user and group must be either strings or UID/GID numbers which indicate the username and groupname to which you want to switch. Either is also allowed to be {{#f}}, if you don't want to switch that aspect of the process. === Configuration parameters The following parameters can be used to control spiffy's behaviour. Besides these parameters, you can also influence spiffy's behaviour by tweaking the [[intarweb]] parameters. <parameter>(server-software [product])</parameter> The server software product description. This should be a valid product value as used in the server and user-agent headers by intarweb; this is a list of lists. The inner lists contain the product name, the product version and a comment, all either a string or {{#f}}. Default: {{(("Spiffy" "a.b" "Running on Chicken x.y"))}}, with {{a.b}} being the Spiffy major/minor version and {{x.y}} being Chicken's. <parameter>(root-path [path])</parameter> The path to the document root, for the current vhost. Defaults to {{"./web"}}. <parameter>(server-port [port-number])</parameter> The port number on which to listen. Defaults to 8080. <parameter>(server-bind-address [address])</parameter> The IP address on which to listen, or all addresses if {{#f}}. Defaults to {{#f}}. <parameter>(max-connections [number])</parameter> The maximum number of simultaneously active connections. Defaults to 1024. Any new connection that comes in when this number is reached must wait until one of the active connections is closed. <parameter>(spiffy-user [name-or-uid])</parameter> The name or UID of a user to switch to just after binding the port. This only works if you start Spiffy as root, so it can bind port 80 and then drop privileges. If {{#f}}, no switch will occur. Defaults to {{#f}}. <parameter>(spiffy-group [name-or-gid])</parameter> The name or GID of a group to switch to just after binding the port. This only works if you start Spiffy as root, so it can bind port 80 and then drop privileges. If {{#f}}, it will be set to the primary group of {{spiffy-user}} if the user was selected. Otherwise, no change will occur. Defaults to {{#f}}. <parameter>(index-files [file-list])</parameter> A list of filenames which are to be used as index files to serve when the requested URL identifies a directory. Defaults to {{'("index.html" "index.xhtml")}} <parameter>(mime-type-map [extension->mimetype-list])</parameter> An alist of extensions (strings) to mime-types (symbols), to use for the content-type header when serving up a static file. Defaults to '(("html" . text/html) ("xhtml" . application/xhtml+xml) ("js" . application/javascript) ("css" . text/css) ("png" . image/png) ("xml" . application/xml) ("pdf" . application/pdf) ("jpeg" . image/jpeg) ("jpg" . image/jpeg) ("gif" . image/gif) ("ico" . image/vnd.microsoft.icon) ("svg" . image/svg+xml) ("txt" . text/plain)) See also {{file-extension->mime-type}} for a procedure which can look up file extensions for you. <parameter>(default-mime-type [mime-type])</parameter> The mime-type (a symbol) to use if none was found in the {{mime-type-map}}. Defaults to {{'application/octet-stream}} <parameter>(default-host [hostname])</parameter> The host name to use when no virtual host could be determined from the request. See the section on virtual hosts below. <parameter>(vhost-map [host-regex->vhost-handler])</parameter> A mapping of virtual hosts (regex) to handlers (procedures of one argument; a continuation thunk). See the section on virtual hosts below. Defaults to {{`((".*" . ,(lambda (continue) (continue))))}} <parameter>(file-extension-handlers [extension->handler-list])</parameter> An alist mapping file extensions (strings) to handler procedures (lambdas of one argument; the file name relative to the webroot). Defaults to {{'()}}. If no handler was found, defaults to just sending a static file. <parameter>(access-log [log-file-or-port])</parameter> Filename (string) or port to append access log output to. Default: {{#f}} (disabled) <parameter>(error-log [log-file-or-port])</parameter> Filename (string) or port to which error messages from evaluated code should be output. Default: {{(current-error-port)}} <parameter>(debug-log [log-file-or-port])</parameter> Filename (string) or port to write debugging messages to. Default: {{#f}} (disabled) <parameter>(access-file [string])</parameter> The name of an access file, or {{#f}} if not applicable. This file is read when the directory is entered by the directory traversal system, and allows you to write dynamic handlers that can assign new values for parameters only for resources below that directory, very much like adding parameters in code before calling a procedure. See the section "Access files" for more information. <parameter>(trusted-proxies [list-of-strings])</parameter> When an incoming request is first accepted, the {{remote-address}} is initialized to the IP address of the remote peer. When this peer is a reverse proxy in an internal network, that value is not so useful because all requests would seem to come from there. If you want to have a more meaningful value, you can add the IP addresses of proxies to this list, and {{X-Forwarded-For}} entries from these proxies will be stripped, and the first entry just before the most-distant trusted proxy will be used. Be careful: all IP addresses in this list will be trusted on their word. Default: {{()}} (trust no one) === Handlers Besides "static" configuration, Spiffy also has several handlers for when something is to be served. <parameter>(handle-directory [proc])</parameter> The handler for directory entries. If the requested URL points to a directory which has no index file, this handler is invoked. It is a procedure of one argument, the path (a string) relative to the webroot. Defaults to a procedure which returns a "403 forbidden". <parameter>(handle-file [proc])</parameter> The handler for files. If the requested URL points to a file, this handler is invoked to serve the file. It is a procedure of one argument, the path (a string) relative to the webroot. Defaults to a procedure which sets the content-type and determines a handler based on the {{file-extension-handlers}}, or {{send-static-file}} if none was found and the method was {{HEAD}} or {{GET}} (otherwise it replies with 405 "Method Not Allowed"). <parameter>(handle-not-found [proc])</parameter> The handler for nonexistent files. If the requested URL does not point to an existing file or directory, this procedure is called. It is a procedure of one argument, the path (a string) to the first missing file in the request path. Defaults to a procedure which returns a "404 Not found". The path path which is passed to the handler is handled in a particular way: It contains all the components that exist, and the final component is the file or directory which does not exist. That means this path may differ from the concatenated URI path; this can be seen as "pathinfo" for the would-be file, if it had existed. The path should be interpreted as relative to {{root-path}}. '''Important security note:''' If you are going to resolve the URI's path in the file system, please remember to check that it doesn't contain slashes in any of the components, as that could be used in a path traversal attack. Alternatively (and possibly even safer), try to ensure that the final path lies under the desired root directory. <parameter>(handle-exception [proc])</parameter> The handler for when an exception occurs. This defaults to a procedure that logs the error to the error log. While debugging or developing, it may be more convenient to use a procedure that sends the error back to the client: <enscript highlight=scheme> (handle-exception (lambda (exn chain) (send-status 'internal-server-error (build-error-message exn chain)))) </enscript> <parameter>(handle-access-logging [proc])</parameter> The handler for access logging. This is a procedure of zero arguments which should write a line to the access log. Defaults to a procedure which writes a line to {{access-log}} which looks like this: 127.0.0.1 [Sun Nov 16 15:16:01 2008] "GET http://localhost:8080/foo?bar HTTP/1.1" 200 "http://localhost:8080/referer" "Links (2.2; NetBSD 5.99.01 macppc; x)" === Runtime information During the handling of a request, Spiffy adds more information to the environment by parameterizing the following parameters whenever the information becomes available: <parameter>(current-request [request])</parameter> An intarweb request-object that defines the current request. Available from the moment the request comes in and is parsed. Contains, among other things, the query parameters and the request-headers, in fully parsed form (as intarweb returns them). The URI is automatically augmented with the host, scheme and port if it is not an absolute URI. <parameter>(current-response [response])</parameter> An intarweb response-object that defines the current response. Available from the same time current-request is available. This keeps getting updated along the way, while the response data is being refined (like when headers are being added). <parameter>(current-file [path])</parameter> The path to the requested file (a string). Available from the moment Spiffy determined the requested URL points to a file (just before the {{handle-file}} procedure is called). This file is relative to the {{root-path}}. <parameter>(current-pathinfo [path])</parameter> The trailing path ''fragments'' (a list of strings) that were passed in the URL after the requested filename. Available from the moment Spiffy determined the requested URL points to a file (just before the {{handle-file}} procedure is called). <parameter>(remote-address [address])</parameter> The IP address (a string) of the user-agent performing the current request. See also {{trusted-proxies}}. <parameter>(local-address [address])</parameter> The IP address (a string) on which the current request came in. <parameter>(secure-connection? [boolean])</parameter> {{#t}} when the current connection is a secure one (SSL), {{#f}} if it isn't (regular HTTP). This pertains only to the direct connection itself, so if Spiffy is behind a proxy this will be {{#f}} even if the proxy itself is connected to the client over SSL. One way to get around this is to ''always'' add a custom header to your reverse proxy's configuration file. Then you can read this out in Spiffy and set secure-connection? to {{#t}} or {{#f}}, as well as updating the request URI's scheme. There is no standardized header for this, so the default Spiffy won't do this. An easier way around this is to set up two spiffies listening on different ports and configure one to have {{secure-connection?}} set to {{#t}}, which you redirect incoming HTTPS requests to. '''This parameter may disappear or change in the future''', when there are more smart people using Spiffy who know how to deal with this or the Spiffy maintainer has a moment of clarity and decides how to do this cleanly. === Virtual hosts Spiffy has support for virtual hosting, using the HTTP/1.1 Host header. This allows you to use one Spiffy instance running on one IP address/port number to serve multiple webpages, as determined by the hostname that was requested. The virtual host is defined by a procedure, which can set arbitrary parameters on-the-fly. It is passed a continuation thunk, which it should explicitly call if it wants the processing to continue. The most used parameter in virtual host setups is the {{root-path}} parameter, so that another docroot can be selected based on the requested hostname, showing different websites for different hosts: <enscript highlight="scheme"> (vhost-map `(("foo\\.bar\\.com" . ,(lambda (continue) ;; Requires the spiffy-dynamic-handlers egg... (parameterize ((file-extension-handlers `(("ssp" . ,ssp-handler) ("ws" . ,web-scheme-handler))) (root-path "/var/www/domains/foo.bar.com")) (continue)))) (,(glob->regexp "*.domain.com") . ,(lambda (continue) ;; Requires the spiffy-cgi-handlers egg... (parameterize ((file-extension-handlers `(("php" . ,(cgi-handler* "/usr/pkg/libexec/cgi-bin/php")))) ;; You can also change PHP's arg_separator.input ;; to be ";&" instead of this parameter (form-urlencoded-separator "&") (root-path "/var/www/domains/domain.com")) (continue)))))) </enscript> In this example, if a client accesses {{foo.bar.com/mumble/blah.html}}, the file {{/var/www/domains/foo.bar.com/mumble/blah.html}} will be served. Any files ending in {{.ssp}} or {{.ws}} will be served by the corresponding file type handler. If there's any PHP file, its source will simply be displayed. In case of {{my.domain.com/something/bar.html}}, the file {{/var/www/domains/domain.com/something/bar.html}} will be served. If there's a {{.ssp}} or {{.ws}} file there, it will not be interpreted. Its source will be displayed instead. A {{.php}} file, on the other hand, will be passed via CGI to the program {{/usr/pkg/libexec/cgi-bin/php}}. Domain names are mapped to a lambda that can set up any parameters it wants to override from the defaults. The host names are matched using {{irregex-match}}. If the host name is not yet a regexp, it will be converted to a ''case-insensitive'' regexp. '''Important security note:''' If you are going to resolve the URI's path in the file system, please remember to check that it doesn't contain slashes in any of the components, as that could be used in a path traversal attack. Alternatively (and possibly even safer), try to ensure that the final path lies under the desired root directory. === Access files Fine-grained access-control can be implemented by using so-called access files. When a request for a specific file is made and a file with the name given in the {{access-file}} parameter exists in any directory between the {{root-path}} of that vhost and the directory in which the file resides, then the access file is loaded as an s-expression containing a function and is evaluated with a single argument, the function that should be called to continue processing the request. This works just like vhosting. The function that gets called can call {{parameterize}} to set additional constraints on the code that handles deeper directories. For example, if we evaluate {{(access-file ".access")}} before starting the server, and we put the following code in a file named {{.access}} into the root-directory, then all accesses to any file in the root-directory or any subdirectory will be denied unless the request comes from localhost: <enscript highlight=scheme> (lambda (continue) (if (string=? (remote-address) "127.0.0.1") (continue) (send-status 'forbidden "Sorry, you're not allowed here"))) </enscript> If we only want to deny access to files that start with an X, put this in the {{.access}} file: <enscript highlight=scheme> (lambda (continue) (let ((old-handler (handle-file))) (parameterize ((handle-file (lambda (path) (if (not (string-prefix? "X" (pathname-file path))) (send-status 'forbidden "No X-files allowed!") (old-handler path))))) (continue)))) </enscript> Of course, access files can be used for much more than just access checks. One can put anything in them that could be put in vhost configuration or in top-level configuration. They are very useful for making deployable web applications, so you can just drop a directory on your server which has its own configuration embedded in an access file in the root directory of the application, without having to edit the server's main configuration files. '''Warning:''' Be very careful when using this. The full Scheme language is available from access files. That means that a small mistake in your web application's file permissions might result in a complete breach of your server's security. This feature will be removed in a future version, because it is much too dangerous. === Procedures and macros The following procedures and macros can be used in dynamic web programs, or dynamic server configuration: <procedure>(with-headers new-headers thunk)</procedure> Call {{thunk}} with the header list {{new-headers}}. This parameterizes the current response to contain the new headers. The existing headers are extended with {{new-headers}} through intarweb's {{headers}} procedure. <procedure>(write-logged-response)</procedure> This procedure simply writes {{current-response}} after calling {{handle-access-logging}}. Responses should always go through this procedure instead of directly using {{write-response}} from intarweb. If you have a response body to write, you still need to remember to call {{finish-response-body}} (from intarweb) after doing so. <procedure>(log-to log format . rest)</procedure> Write a printf-style format string to the specified log (one of {{access-log}}, {{error-log}} or {{debug-log}}). {{format}} is a {{printf}}-style format string, and rest arguments should match the arguments one would pass to printf. A newline is appended to the end of the log message automatically. <procedure>(send-response #!key status code reason body headers)</procedure> Easy way to send string data to the client, with additional headers. It will add appropriate headers and will automatically detect {{HEAD}} requests. If BODY is {{#f}}, no body is sent and the {{content-length}} header is set to zero. The status is a symbol describing the response status, which is looked up in [[intarweb]]'s {{http-status-code}} parameter. If {{code}} and/or {{reason}} are supplied, these take precedence. If {{status}} and {{code}} are missing, the default status is {{ok}}. <procedure>(send-status code reason [message])</procedure><br> <procedure>(send-status status [message])</procedure> Easy way to send a page and a status code to the client. The optional {{message}} is a string containing HTML to add in the body of the response. Some structure will be added around the message, so message should only be the actual message you want to send. This can be called either with a numeric code, string reason and optional message or with a symbolic status and optional message. Example: <enscript highight="scheme"> (send-status 404 "Not found" "Sorry, page not found! Please try <a href='/search.ws'>our search page</a>") ;; Alternative way of doing this: (send-status 'not-found "Sorry, page not found! Please try <a href='/search.ws'>our search page</a>") </enscript> <procedure>(send-static-file filename)</procedure> Send a file to the client. This sets the {{content-length}} header and tries to send the file as quickly as possible to the client. The filename is interpreted relative to {{root-path}}. <procedure>(file-extension->mime-type EXT)</procedure> Looks up the file extension {{EXT}} (without a leading dot) in {{mime-type-map}}, or uses {{default-mime-type}} when the extension can't be found. If {{EXT}} is {{#f}}, it'll look up the extension that is the empty string. This returns a symbol which indicates the mime-type which is matched to the extension (for example {{text/html}}). <procedure>(restart-request request)</procedure> Restart the entire request-handling starting at the point where the request was just parsed. The argument is the new request to use. Be careful, this makes it very easy to introduce unwanted endless loops! <procedure>(htmlize string) => string</procedure> Encode "special" html symbols like tag and attribute characters so they will not be interpreted by the browser. <procedure>(build-error-message exn chain [raw-output])</procedure> Build an error message for the exception {{exn}}, with call chain {{chain}}. Defaults to HTML output, unless {{raw-output}} is given and nonfalse. === Modules This section will describe what the various modules that come with Spiffy are and how they work. ==== ssp-handler This was moved to the [[spiffy-dynamic-handlers]] egg. ==== web-scheme-handler This was moved to the [[spiffy-dynamic-handlers]] egg. ==== cgi-handler This was moved to the [[spiffy-cgi-handlers]] egg. ==== simple-directory-handler In order to get directory listings, you can use {{simple-directory-handler}}. Just parameterize {{handle-directory}}'s value with the {{simple-directory-handler}} procedure and you're set. This directory handler truly is very simple and limited in what you can customize. For a more flexible directory handler, see the [[spiffy-directory-listing]] egg. ===== Configuration The simple directory handler has a few configuration options: <procedure>(simple-directory-dotfiles? [dotfiles?])</procedure> Determines if dotfiles should show up in the directory listings. Default: {{#f}} <procedure>(simple-directory-display-file [displayer])</procedure> A lambda that accepts three arguments: the remote filename, the local filename and a boolean that says if the file is a directory. This lambda should output a table row with the desired information. Defaults to a lambda that prints the name, size and date when the file was last modified. ===== Procedures The simple-directory handler adds only one procedure to the environment: <procedure>(simple-directory-handler pathname)</procedure> The handler itself, which should be used in the {{handle-directory}} parameter. === Examples ==== Quick config for serving up a docroot Spiffy is very easy to use for simple cases: <enscript highlight=scheme> (use spiffy) (server-port 80) (root-path "/var/www") ;; When dropping privileges, switch to this user (spiffy-user "httpd") (spiffy-group "httpd") (start-server) </enscript> One could also use parameterize (according to taste): <enscript highlight=scheme> (use spiffy) (parameterize ((server-port 80) (spiffy-user "httpd") (spiffy-group "httpd") (root-path "/var/www")) (start-server)) </enscript> If you put this in {{/usr/local/libexec/spiffy.scm}} you can use [[/spiffy-init-script|this example init.d script]] or [[/spiffy-systemd-scripts|these example systemd scripts]] as-is, to launch Spiffy. ==== A simple dynamic web page example If you would like to dynamically serve content, you can use a custom handler in the vhost-map for the host on which you want to serve this content: <enscript highlight="scheme"> (use spiffy intarweb uri-common) (define (handle-greeting continue) (let* ((uri (request-uri (current-request)))) (if (equal? (uri-path uri) '(/ "greeting")) (send-response status: 'ok body: "<h1>Hello!</h1>") (continue)))) (vhost-map `(("localhost" . ,handle-greeting))) (start-server) </enscript> It's not advised to use string concatenation for building HTML, as it is rather unsafe and easy to get wrong. For a slightly larger example, see [[http://bugs.call-cc.org/browser/project/demonstrations/spiffy|this demonstration of Spiffy with SXML]]. ==== Network tweaks Spiffy does not activate Chicken's TCP buffering, which results in extra traffic: one packet sent per header line. With a TCP buffer size greater than the total header length, all headers will be coalesced into a single write; generally the response body will be coalesced as well. For example: (tcp-buffer-size 2048) ; from unit tcp (start-server) ==== Redirecting to another domain When you have a domain you want to canonicalize so that it will always have {{www}} in front of it, you can set up a conditional redirect in your {{vhosts}} section: <enscript highlight=scheme> (use spiffy intarweb uri-common) (vhost-map `(("example.com" . ,(lambda (continue) (let* ((old-u (request-uri (current-request))) (new-u (update-uri old-u host: "www.example.com"))) (with-headers `((location ,new-u)) (lambda () (send-status 'moved-permanently)))))) ("www.example.com" . ,(lambda (continue) (continue))))) (start-server) </enscript> Alternatively the following version can be used to generate appropriate handlers for several domains: <enscript highlight=scheme> (use spiffy intarweb uri-common) ; Generates a handler that can be used in vhost-map that will cause all requests to that URL to be rewritten to the domain specified in 'to'. (define (canonicalise-domain to) (let ((to (uri-reference to))) (assert (equal? '(/ "") (uri-path to))) (assert (null? (uri-query to))) ; We don't see fragments on the server and choose not to care about usernames and password fields. (lambda (continue) (let* ((old-u (request-uri (current-request))) (new-u (update-uri old-u scheme: (or (uri-scheme to) (uri-scheme old-u)) port: (or (uri-port to) (uri-port old-u)) host: (or (uri-host to) (uri-host old-u))))) (with-headers `((location ,new-u)) (lambda () (send-status 'moved-permanently))))))) (vhost-map `(("example.com" . ,(canonicalise-domain "http://www.example.com")) ("www.example.com" . ,(lambda (continue) (continue))))) </enscript> The above code hooks a handler for the regular expression {{"example.com"}}, checks the request's URI and then updates only the host component, keeping all other components (like port and path) intact. Then it sends a simple status response that indicates a 301 "Moved Permanently" response, using the new URI in the {{Location:}} header. The second entry just tells Spiffy to continue serving the request when it's made to {{www.example.com}}. A request on any other host will receive a 404 not found response due to not having a vhost entry. More elaborate setups can parameterize some other aspects for each host before calling {{continue}}. === Changelog * 5.4.2: Use proper 2-element vectors for {{date}} and {{last-modified}} headers, for compatibility with intarwebs newer than 1.6.1. * 5.4.1: Once again allow backslashes in paths on UNIX-like platforms in CHICKENs where {{make-pathname}} was fixed. Improve request handling performance. Remove over-reliance on undocumented {{alist-ref}} comparison procedure's argument order (which will be changed in CHICKEN 4.11). * 5.4: Fix critical security vulnerability (path traversal, CVE-2015-8235) by disallowing backslashes in request paths (thanks to Benedikt Rosenau for reporting the vulnerability). Use {{spiffy}} in the gensym'ed name of spiffy's threads, for easier debugging. Thanks to Evan Hanson. * 5.3.2 Fix tests so they still function correctly when {{SPIFFY_TEST_PORT}} is overridden. Thanks to Kon Lovett for pointing this out. * 5.3.1 Don't try to handle another request when the input or output ports are closed (thanks to Thomas Hintz. This makes [[/egg/websockets|websocket]] support work properly!) * 5.3 Improved presentation and correctness of HTML in simple-directory-handler (thanks to Roel van der Hoorn). Fixed serving of static files on Windows due to missing {{#:binary}} option (thanks to "Jubjub"). * 5.2.1 Handle disconnections more gracefully (as per intarweb 1.2), and improved debugging some more.. * 5.2 Log prematurely broken connections to the debug-log, to aid in... debugging (thanks to Andy Bennett). Fix locking bug in tests, and disable the "unreadable file is 403" check when run as root. * 5.1 Fix static file handling of files which cannot be read by Spiffy (thanks to Andy Bennett). Use intarweb's new {{finish-response-body}} procedure where needed. Add image/svg+xml to the default mime-type lists. * 5.0 Work around race conditions in {{simple-directory-handler}} related to deleted files or self-referential symlinks (reported by [[/users/mario-domenech-goulart|Mario]]). Move deprecated dynamic content handlers into separate [[spiffy-dynamic-handlers]] egg. Move cgi handler into separate [[spiffy-cgi-handlers]] egg. * 4.15 Disallow non-{{GET}}/{{HEAD}} requests for normal files in {{handle-file}}. Remove dependencies on [[/eggref/4/matchable|matchable]] and [[/eggref/4/regex|regex]] eggs. Allow request-uri overrides in user lambdas to affect the default handler (Thanks to [[/users/mario-domenech-goulart|Mario]]). * 4.14 Fix ssp-handler's pathname construction so it doesn't error on files in the rootdirectory. Fix incompatibility with version 1.6.1 of the OpenSSL egg [Thanks to [[/users/mario-domenech-goulart|Mario]] and [[/users/thomas-chust|Thomas]].] * 4.13 Add trusted-proxies parameter so remote-address can have a meaningful value in the presence of reverse proxies [thanks to John J Foerch]. Allow cgi scripts to be outside the docroot. Pass on query-strings to CGI scripts as-is, if possible, to avoid breaking scripts that rely on a particular variable-separator (reported by Felix Winkelmann). Refactor to use symbolic response codes from Intarweb. * 4.12 Make Spiffy optionally fully independent of Unit tcp [thanks to [[/users/jim-ursetto|Jim Ursetto]]] Tests now also work with Chickens greater than 4.6.0 (removed deprecated {{getenv}} calls) * 4.11 Drop openssl requirement (suggested by Felix Winkelmann); split up listening and accept loop invocation to allow loading code after dropping root privileges (suggested by Mario Goulart). * 4.10 Fix serious bug which caused Spiffy to exit after handling N requests. Fix handling of empty path components now that uri-generic preserves them. * 4.9 Export {{file-extension->mime-type}}. Add more info about exceptional situations to the debugging logs when enabled. * 4.8 Fix ssl support. Get rid of {{spiffy-root-uri}}. Add timestamp and request info to error log. * 4.7 Fix redirects for directories again (thanks to [[/users/mario-domenech-goulart|Mario]]). NO TESTCASE (possibly to be fixed in [[uri-generic]]) * 4.6 Fix redirects for directories with special URI characters in them (thanks to [[/users/felix-winkelmann|Felix]]) * 4.5 Add {{send-response}} procedure; flush output after request is handled; use proper IANA-assigned MIME types in default {{mime-type-map}}; fix {{server-root-uri}} when spiffy is behind a proxy [thanks to zbigniew] * 4.4 Fix a problem with 304 "not modified", for which Safari incorrectly tries to read a content-body when a content-length is present. * 4.3 Fix crash with extensionless files and nonempty extension handlers * 4.2 Add support for caching headers and proper If-Modified-Since support * 4.1 Make cgi-handler cope with missing pathinfo. Fix statuscode related crash in cgi-handler. Make ssp handler's open/close tags parameters, so it actually matches what the documentation says. Add {{ssp-cache-dir}}. Update for latest intarweb changes (0.2) * 4.0 Rewrite from scratch, using Intarweb * pre-4.0 See the changelog for the [[/eggref/3/spiffy|old spiffy]] === License Copyright (c) 2005-2017, Felix L. Winkelmann and Peter Bex All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Description of your changes:
I would like to authenticate
Authentication
Username:
Password:
Spam control
What do you get when you subtract 21 from 20?