4293 lines
242 KiB
HTML
4293 lines
242 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Strict//EN">
|
||
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta><title>Hunchentoot - The Common Lisp web server formerly known as TBNL</title><meta name="description" content="
|
||
A full-featured web server written in Common Lisp offering things
|
||
like HTTP/1.1 chunking, persistent connections, and SSL. Includes
|
||
a framework for building dynamic websites interactively.
|
||
"></meta><style type="text/css">
|
||
body { background-color: #ffffff }
|
||
pre { padding:5px; background-color:#e0e0e0 }
|
||
pre.none { padding:5px; background-color:#ffffff }
|
||
h3, h4, h5 { text-decoration: underline; }
|
||
.entry-type { padding-left: 1em; font-size: 60%; font-style: italic }
|
||
a { text-decoration: none; padding: 1px 2px 1px 2px; }
|
||
a:visited { text-decoration: none; padding: 1px 2px 1px 2px; }
|
||
a:hover { text-decoration: none; padding: 1px 1px 1px 1px; border: 1px solid #000000; }
|
||
a:focus { text-decoration: none; padding: 1px 2px 1px 2px; border: none; }
|
||
a.none { text-decoration: none; padding: 0; }
|
||
a.none:visited { text-decoration: none; padding: 0; }
|
||
a.none:hover { text-decoration: none; border: none; padding: 0; }
|
||
a.none:focus { text-decoration: none; border: none; padding: 0; }
|
||
a.noborder { text-decoration: none; padding: 0; }
|
||
a.noborder:visited { text-decoration: none; padding: 0; }
|
||
a.noborder:hover { text-decoration: none; border: none; padding: 0; }
|
||
a.noborder:focus { text-decoration: none; border: none; padding: 0; }
|
||
</style></head><body>
|
||
|
||
|
||
|
||
<h2>
|
||
<a href="http://www.htg1.de/hunchentoot/hunchentoot.html" title="Click here for the Hunchentoot logo" class="noborder">
|
||
<img align="top" width="93" height="45" border="0" src="hunchentoot.gif"></img>
|
||
</a>
|
||
Hunchentoot - The Common Lisp web server formerly known as TBNL
|
||
</h2>
|
||
|
||
<blockquote>
|
||
<h3 xmlns=""><a class="none" name="abstract">Abstract</a></h3>
|
||
<p>
|
||
Hunchentoot is a web server written in Common Lisp and at the
|
||
same time a toolkit for building dynamic websites. As a
|
||
stand-alone web server, Hunchentoot is capable of HTTP/1.1
|
||
chunking (both directions), persistent connections
|
||
(keep-alive), and SSL.
|
||
</p>
|
||
<p>
|
||
Hunchentoot provides facilities like automatic session
|
||
handling (with and without cookies), logging, customizable
|
||
error handling, and easy access to GET and POST parameters
|
||
sent by the client. It does <em>not</em> include functionality
|
||
to programmatically generate HTML output. For this task you
|
||
can use any library you like, e.g. (shameless self-plug)
|
||
<a href="http://weitz.de/cl-who/">CL-WHO</a> or
|
||
<a href="http://weitz.de/html-template/">HTML-TEMPLATE</a>.
|
||
</p>
|
||
<p>
|
||
Hunchentoot talks with its front-end or with the client over
|
||
TCP/IP sockets and optionally uses multiprocessing to handle
|
||
several requests at the same time. Therefore, it cannot be
|
||
implemented completely in <a href="http://www.lispworks.com/documentation/HyperSpec/Front/index.htm">portable
|
||
Common Lisp</a>. It currently works with <a href="http://www.lispworks.com/">LispWorks</a> and all Lisps
|
||
which are supported by the compatibility layers <a href="http://common-lisp.net/project/usocket/">usocket</a> and
|
||
<a href="http://common-lisp.net/project/bordeaux-threads/">Bordeaux
|
||
Threads</a>.
|
||
</p>
|
||
<p>
|
||
Hunchentoot comes with a
|
||
<a href="http://www.opensource.org/licenses/bsd-license.php">BSD-style
|
||
license</a> so you can basically do with it whatever you want.
|
||
</p>
|
||
<p>
|
||
Hunchentoot is (or was) for example used by
|
||
<a href="http://quickhoney.com/">QuickHoney</a>,
|
||
<a href="http://www.city-farming.de/">City Farming</a>,
|
||
<a href="http://heikestephan.de/">Heike Stephan</a>.
|
||
</p>
|
||
<p>
|
||
<font color="red">Download shortcut:</font>
|
||
<a href="http://weitz.de/files/hunchentoot.tar.gz">http://weitz.de/files/hunchentoot.tar.gz</a>.
|
||
</p>
|
||
|
||
</blockquote>
|
||
|
||
<h3 xmlns=""><a class="none" name="contents">Contents</a></h3>
|
||
<ol xmlns="">
|
||
<li><a href="index.html#abstract">Abstract</a></li>
|
||
<li><a href="index.html#contents">Contents</a></li>
|
||
<li>
|
||
<a href="index.html#install">Download and installation</a><ol>
|
||
<li><a href="index.html#port80">Running Hunchentoot on port 80</a></li>
|
||
<li><a href="index.html#proxy">Hunchentoot behind a proxy</a></li>
|
||
</ol>
|
||
</li>
|
||
<li><a href="index.html#support">Support</a></li>
|
||
<li><a href="index.html#teen-age">Your own webserver (the easy teen-age New York version)</a></li>
|
||
<li><a href="index.html#extras">Third party documentation and add-ons</a></li>
|
||
<li>
|
||
<a href="index.html#reference">Function and variable reference</a><ol>
|
||
<li><a href="index.html#acceptors">Acceptors</a></li>
|
||
<li><a href="index.html#acceptor-behaviour">Customizing acceptor behaviour</a></li>
|
||
<li><a href="index.html#subclassing-acceptors">An example of how to subclass ACCEPTOR</a></li>
|
||
<li><a href="index.html#taskmasters">Taskmasters</a></li>
|
||
<li><a href="index.html#request-dispatch">Request dispatch and handling</a></li>
|
||
<li><a href="index.html#easy-handlers">Using the easy-handler framework</a></li>
|
||
<li><a href="index.html#requests">Request objects</a></li>
|
||
<li><a href="index.html#replies">Reply objects</a></li>
|
||
<li><a href="index.html#sessions">Sessions</a></li>
|
||
<li><a href="index.html#session-behaviour">Customizing session behaviour</a></li>
|
||
<li><a href="index.html#cookies">Cookies</a></li>
|
||
<li><a href="index.html#logging">Logging</a></li>
|
||
<li><a href="index.html#conditions">Conditions and error handling</a></li>
|
||
<li><a href="index.html#misc">Miscellaneous</a></li>
|
||
</ol>
|
||
</li>
|
||
<li><a href="index.html#testing">Testing</a></li>
|
||
<li><a href="index.html#debugging">Debugging</a></li>
|
||
<li><a href="index.html#history">History</a></li>
|
||
<li><a href="index.html#index">Symbol index</a></li>
|
||
<li><a href="index.html#ack">Acknowledgements</a></li>
|
||
</ol>
|
||
|
||
<h3 xmlns=""><a class="none" name="install">Download and installation</a></h3>
|
||
Hunchentoot depends on a couple of other Lisp libraries which you'll need
|
||
to install first:
|
||
<ul>
|
||
<li>Pierre R. Mai's <a href="http://www.cliki.net/md5">MD5</a>,</li>
|
||
<li>Kevin Rosenberg's <a href="http://www.cliki.net/cl-base64">CL-BASE64</a>,</li>
|
||
<li>Janis Dzerins' <a href="http://common-lisp.net/project/rfc2388/">RFC2388</a>,</li>
|
||
<li>Peter Seibel's <a href="http://weitz.de/cl-fad/">CL-FAD</a>,</li>
|
||
<li>Gary King's <a href="http://common-lisp.net/project/trivial-backtrace/">trivial-backtrace</a>,</li>
|
||
<li>Erik Huelsmann's <a href="http://common-lisp.net/project/usocket">usocket</a> (unless you're using LispWorks),</li>
|
||
<li>Greg Pfeil's <a href="http://common-lisp.net/project/bordeaux-threads/">Bordeaux Threads</a> (unless you're using LispWorks),
|
||
</li>
|
||
<li>
|
||
David Lichteblau's <a href="http://common-lisp.net/project/cl-plus-ssl/">CL+SSL</a>
|
||
(unless you're using LispWorks),
|
||
</li>
|
||
<li>
|
||
and my own <a href="http://weitz.de/flexi-streams/">FLEXI-STREAMS</a> (0.12.0 or higher),
|
||
<a href="http://weitz.de/chunga/">Chunga</a> (1.0.0 or
|
||
higher), and <a href="http://weitz.de/cl-ppcre/">
|
||
CL-PPCRE</a> (plus
|
||
<a href="http://weitz.de/cl-who/">CL-WHO</a> for the <a href="index.html#teen-age">example code</a>
|
||
and <a href="http://weitz.de/drakma/">Drakma</a> for the <a href="index.html#testing">tests</a>).
|
||
</li>
|
||
</ul>
|
||
|
||
Make sure to use the <em>newest</em> versions of all of these
|
||
libraries (which might themselves depend on other libraries) - try
|
||
the repository versions if you're in doubt. Note: You can compile
|
||
Hunchentoot without SSL support - and thus without the need to
|
||
have CL+SSL - if you add <code>:HUNCHENTOOT-NO-SSL</code> to
|
||
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/v_featur.htm">
|
||
<code>*FEATURES*</code></a> <em>before</em> you compile it.
|
||
<p>
|
||
Hunchentoot will only work with Lisps where
|
||
the <a href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#character_code">character
|
||
codes</a> of
|
||
all <a href="http://en.wikipedia.org/wiki/ISO/IEC_8859-1">Latin-1</a>
|
||
characters coincide with their
|
||
Unicode <a href="http://en.wikipedia.org/wiki/Code_point">code
|
||
points</a> (which is the case for all current implementations I
|
||
know).
|
||
</p>
|
||
<p>
|
||
Hunchentoot itself together with this documentation can be
|
||
downloaded from
|
||
<a href="https://github.com/edicl/hunchentoot/archive/v1.3.0.tar.gz">https://github.com/edicl/hunchentoot/archive/v1.3.0.tar.gz</a>.
|
||
The current version is 1.3.0.
|
||
</p>
|
||
<p>
|
||
The preferred method to compile and load Hunchentoot is via <a href="http://www.cliki.net/asdf">ASDF</a>. If you want to avoid
|
||
downloading and installing all the dependencies manually, give
|
||
Zach Beane's excellent <a href="http://www.quicklisp.org/">Quicklisp</a> system a try.
|
||
</p>
|
||
<p>
|
||
Hunchentoot and its dependencies can also be installed with <a href="http://common-lisp.net/project/clbuild/">clbuild</a>.
|
||
There's also a port for <a href="http://www.gentoo.org/proj/en/lisp/common-lisp/index.xml">Gentoo
|
||
Linux</a> thanks to Matthew Kennedy.
|
||
</p>
|
||
<p>
|
||
The current development version of Hunchentoot can be found
|
||
at <a href="https://github.com/edicl/hunchentoot">https://github.com/edicl/hunchentoot</a>.
|
||
If you want to send patches, please fork the github repository and send pull requests.
|
||
</p>
|
||
|
||
<h4 xmlns=""><a name="port80">Running Hunchentoot on port 80</a></h4>
|
||
|
||
Hunchentoot does not come with code to help with running it on a
|
||
privileged port (i.e. port 80 or 443) on Unix-like operating
|
||
systems. Modern Unix-like systems have specific, non-portable
|
||
ways to allow non-root users to listen to privileged ports, so
|
||
including such functionality in Hunchentoot was considered
|
||
unnecessary. Please refer to online resources for help. At the
|
||
time of this writing, the YAWS documentation has a <a href="http://yaws.hyber.org/privbind.yaws">comprehensive
|
||
writeup</a> on the topic.
|
||
|
||
|
||
<h4 xmlns=""><a name="proxy">Hunchentoot behind a proxy</a></h4>
|
||
|
||
If you're feeling unsecure about exposing Hunchentoot to the wild,
|
||
wild Internet or if your Lisp web application is part of a larger
|
||
website, you can hide it behind a
|
||
<a href="http://en.wikipedia.org/wiki/Proxy_server">proxy server</a>.
|
||
One approach that I have used several times is to employ Apache's
|
||
<a href="http://httpd.apache.org/docs/current/mod/mod_proxy.html">mod_proxy</a>
|
||
module with a configuration that looks like this:
|
||
|
||
<pre><a href="http://httpd.apache.org/docs/current/mod/mod_proxy.html#proxypass" class="noborder">ProxyPass</a> /hunchentoot http://127.0.0.1:3000/hunchentoot
|
||
<a href="http://httpd.apache.org/docs/current/mod/mod_proxy.html#proxypassreverse" class="noborder">ProxyPassReverse</a> /hunchentoot http://127.0.0.1:3000/hunchentoot</pre>
|
||
|
||
This will tunnel all requests where the URI path begins with
|
||
<code>"/hunchentoot"</code> to a (Hunchentoot) server listening on
|
||
port 3000 on the same machine.
|
||
|
||
<p>
|
||
Of course, there are
|
||
<a href="http://www.red-bean.com/pipermail/lispweb/2006-October/001342.html">several
|
||
other</a> (more lightweight) web proxies that you could use
|
||
instead of Apache.
|
||
</p>
|
||
|
||
|
||
|
||
<h3 xmlns=""><a class="none" name="support">Support</a></h3>
|
||
<p>
|
||
The development version of Hunchentoot can be found <a href="https://github.com/edicl/hunchentoot" target="_new">on
|
||
github</a>. Please use the github issue tracking system to
|
||
submit bug reports. Patches are welcome, please use <a href="https://github.com/edicl/hunchentoot/pulls">GitHub pull
|
||
requests</a>. If you want to make a change, please <a href="http://weitz.de/patches.html" target="_new">read this
|
||
first</a>.
|
||
</p>
|
||
|
||
|
||
<h3 xmlns=""><a class="none" name="teen-age">Your own webserver (the easy teen-age New York version)</a></h3>
|
||
Starting your own web server is pretty easy. Do something like this:
|
||
<pre>(hunchentoot:<a class="noborder" href="index.html#teen-age">start</a> (make-instance 'hunchentoot:<a class="noborder" href="index.html#acceptor">easy-acceptor</a> :port 4242))</pre>
|
||
That's it. Now you should be able to enter the address
|
||
"<a href="http://127.0.0.1:4242/"><code>http://127.0.0.1:4242/</code></a>" in
|
||
your browser and see something, albeit nothing very interesting
|
||
for now.
|
||
|
||
<p>
|
||
By default, Hunchentoot serves the files from the
|
||
<code><i>www/</i></code> directory in its source tree. In the
|
||
distribution, that directory contains a HTML version of the
|
||
documentation as well as the error templates. The location of
|
||
the document root directory can be specified when creating a new
|
||
<code xmlns=""><a href="index.html#acceptor">ACCEPTOR</a></code> instance by the way of the
|
||
<code xmlns=""><a href="index.html#acceptor-document-root">ACCEPTOR-DOCUMENT-ROOT</a></code>. Likewise, the
|
||
location of the error template directory can be specified by the
|
||
<code xmlns=""><a href="index.html#acceptor-error-template-directory">ACCEPTOR-ERROR-TEMPLATE-DIRECTORY</a></code>. Both
|
||
<code xmlns=""><a href="index.html#acceptor-document-root">ACCEPTOR-DOCUMENT-ROOT</a></code> and
|
||
<code xmlns=""><a href="index.html#acceptor-error-template-directory">ACCEPTOR-ERROR-TEMPLATE-DIRECTORY</a></code> can be
|
||
specified using a logical pathname, which will be translated
|
||
once when the <code xmlns=""><a href="index.html#acceptor">ACCEPTOR</a></code> is instantiated.
|
||
</p>
|
||
|
||
<p>
|
||
The <code xmlns=""><a href="index.html#easy-acceptor">EASY-ACCEPTOR</a></code> class implements a
|
||
framework for developing web applications. Handlers are defined
|
||
using the <code xmlns=""><a href="index.html#define-easy-handler">DEFINE-EASY-HANDLER</a></code> macro.
|
||
Request dispatching is performed according to the list of
|
||
dispatch functions in <code xmlns=""><a href="index.html#*dispatch-table*">*DISPATCH-TABLE*</a></code>.
|
||
Each of the functions on that list is called to determine
|
||
whether it wants to handle the request, provided as single
|
||
argument. If a dispatcher function wants to handle the request,
|
||
it returns another function to actually create the desired page.
|
||
</p>
|
||
|
||
<p>
|
||
<code xmlns=""><a href="index.html#define-easy-handler">DEFINE-EASY-HANDLER</a></code> is accompanied by a set
|
||
of dispatcher creation functions that can be used to create
|
||
dispatchers for standard tasks. These are documented in the <a class="noborder" href="index.html#easy-handlers">subchapter on easy
|
||
handlers</a>
|
||
</p>
|
||
|
||
<p>
|
||
Now be a bit more adventurous, try this
|
||
<pre>(hunchentoot:<a class="noborder" href="index.html#define-easy-handler">define-easy-handler</a> (say-yo :uri "/yo") (name)
|
||
(setf (hunchentoot:<a class="noborder" href="index.html#content-type*">content-type*</a>) "text/plain")
|
||
(format nil "Hey~@[ ~A~]!" name))</pre>
|
||
and see what happens at "<a href="http://127.0.0.1:4242/yo"><code>http://127.0.0.1:4242/yo</code></a>" or
|
||
"<a href="http://127.0.0.1:4242/yo?name=Dude"><code>http://127.0.0.1:4242/yo?name=Dude</code></a>" .
|
||
</p>
|
||
|
||
<p>
|
||
Hunchentoot comes with a little example website which you can use
|
||
to see if it works and which should also demonstrate a couple of
|
||
the things you can do with Hunchentoot. To start the example
|
||
website, enter the following code into your listener:
|
||
|
||
<pre>(<a class="noborder" href="http://common-lisp.net/~mmommer/asdf-howto.shtml#sec11">asdf:oos</a> 'asdf:load-op :hunchentoot-test)</pre>
|
||
|
||
Now go to "<a href="http://127.0.0.1:4242/hunchentoot/test"><code>http://127.0.0.1:4242/hunchentoot/test</code></a>" and play a bit.
|
||
</p>
|
||
|
||
|
||
<h3 xmlns=""><a class="none" name="extras">Third party documentation and add-ons</a></h3>
|
||
<p>
|
||
Adam Petersen has written a book called <a href="http://www.adampetersen.se/articles/lispweb.htm">"Lisp for
|
||
the Web"</a> which explains how Hunchentoot and some other
|
||
libraries can be used to build web sites.
|
||
</p>
|
||
<p>
|
||
Here is some software which extends Hunchentoot or is based on it:
|
||
</p>
|
||
<ul>
|
||
<li>
|
||
<a href="https://github.com/fukamachi/clack">Clack</a> is a
|
||
web server abstraction layer, defaulting to Hunchentoot.
|
||
</li>
|
||
<li>
|
||
<a href="https://github.com/slyrus/hunchentoot-cgi">hunchentoot-cgi</a>
|
||
(by Cyrus Harmon) provides
|
||
<a href="http://en.wikipedia.org/wiki/Common_Gateway_Interface">CGI</a>
|
||
handlers for Hunchentoot.
|
||
</li>
|
||
<li>
|
||
<a href="http://weitz.de/cl-webdav/">CL-WEBDAV</a> is a <a href="http://webdav.org/">WebDAV</a>
|
||
server based on Hunchentoot.
|
||
</li>
|
||
<li>
|
||
<a href="http://restas.lisper.ru/">RESTAS</a> is a web
|
||
framework based on Hunchentoot.
|
||
<a href="https://github.com/fukamachi/caveman">Caveman</a>, <a href="https://github.com/Shirakumo/radiance">Radiance</a>, <a href="https://github.com/joaotavora/snooze">Snooze</a>
|
||
or again <a href="http://40ants.com/weblocks/">Weblocks</a>
|
||
are frameworks compatible with it.
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
|
||
<h3 xmlns=""><a class="none" name="reference">Function and variable reference</a></h3>
|
||
|
||
<h4 xmlns=""><a name="acceptors">Acceptors</a></h4>
|
||
|
||
If you want Hunchentoot to actually do something, you have to create and
|
||
<a href="index.html#teen-age">start</a> an <a href="index.html#acceptor">acceptor</a>.
|
||
You can also run several acceptors in one image, each one
|
||
listening on a different different port.
|
||
|
||
<p xmlns=""><a class="none" name="acceptor"></a>
|
||
[Standard class]
|
||
<br><b>acceptor</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
To create a Hunchentoot webserver, you make an instance of
|
||
this class or one of its subclasses and use the generic
|
||
function <code><a href="index.html#start">START</a></code> to start it (and
|
||
<code><a href="index.html#stop">STOP</a></code> to stop it). Use the
|
||
<code xmlns="http://www.w3.org/1999/xhtml">:port</code> initarg if you don't want to listen
|
||
on the default http port 80. If 0 is specified for the
|
||
port, the system chooses a random port to listen on. The
|
||
port number choosen can be retrieved using the
|
||
<code><a href="index.html#acceptor-port">ACCEPTOR-PORT</a></code> accessor. The port
|
||
number chosen is retained across stopping and starting the
|
||
acceptor.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
There are other initargs most of which you probably
|
||
won't need very often. They are explained in detail
|
||
in the docstrings of the slot definitions.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
Unless you are in a Lisp without MP capabilities, you can
|
||
have several active instances of
|
||
<code xmlns=""><a href="index.html#acceptor">ACCEPTOR</a></code> (listening on different
|
||
ports) at the same time.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="ssl-acceptor"></a>
|
||
[Standard class]
|
||
<br><b>ssl-acceptor</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">Create and <code><a href="index.html#start">START</a></code> an instance of this class
|
||
(instead of <code><a href="index.html#acceptor">ACCEPTOR</a></code>) if you want an https server. There are two
|
||
required initargs, <code xmlns="http://www.w3.org/1999/xhtml">:SSL-CERTIFICATE-FILE</code> and <code xmlns="http://www.w3.org/1999/xhtml">:SSL-PRIVATEKEY-FILE</code>, for
|
||
pathname designators denoting the certificate file and the key file in
|
||
PEM format. On LispWorks, you can have both in one file in which case
|
||
the second initarg is optional. You can also use the
|
||
<code xmlns="http://www.w3.org/1999/xhtml">:SSL-PRIVATEKEY-PASSWORD</code> initarg to provide a password
|
||
(as a string) for the key file (or <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>, the default, for
|
||
no password).
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
The default port for <code xmlns=""><a href="index.html#ssl-acceptor">SSL-ACCEPTOR</a></code> instances is 443 instead of 80
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="start"></a>
|
||
[Generic function]
|
||
<br><b>start</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">Starts <code><i>acceptor</i></code> so that it begins accepting
|
||
connections. Returns the acceptor.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="stop"></a>
|
||
[Generic function]
|
||
<br><b>stop</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor &key soft</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">Stops the <code><i>acceptor</i></code> so
|
||
that it no longer accepts requests. If
|
||
<code><i>soft</i></code> is true, and there are any requests
|
||
in progress, wait until all requests are fully processed, but
|
||
meanwhile do not accept new requests. Note that
|
||
<code><i>soft</i></code> must not be set when calling
|
||
<code><a href="index.html#stop">stop</a></code> from within a request handler, as
|
||
that will deadlock.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="started-p"></a>
|
||
[Generic function]
|
||
<br><b>started-p</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">generalized-boolean
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">Tells if <code><i>acceptor</i></code> has been started.
|
||
The default implementation simply queries <code><i>acceptor</i></code>
|
||
for its listening status, so if T is returned to the calling thread,
|
||
then some thread has called <code><a href="index.html#start">start</a></code> or
|
||
some thread's call to <code><a href="index.html#stop">stop</a></code> hasn't
|
||
finished. If NIL is returned either some thread has called
|
||
<code><a href="index.html#stop">stop</a></code>, or some thread's call to
|
||
<code><a href="index.html#start">start</a></code> hasn't finished or
|
||
<code><a href="index.html#start">start</a></code> was never called at all for
|
||
<code><i>acceptor</i></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*acceptor*"></a>
|
||
[Special variable]
|
||
<br><b>*acceptor*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">The current ACCEPTOR object in the context of a request.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="acceptor-listen-backlog"></a>
|
||
[Generic function]
|
||
<br><b>acceptor-listen-backlog</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">listen-backlog
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">number-of-pending-connections
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Number of pending connections allowed in the listen socket
|
||
before the kernel rejects further incoming connections.
|
||
Non-LispWorks only.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns="">
|
||
[Generic readers]<br><a class="none" name="acceptor-address"></a><b>acceptor-address</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">address
|
||
</clix:returns></i><br><a class="none" name="acceptor-port"></a><b>acceptor-port</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">port
|
||
</clix:returns></i><br><a class="none" name="acceptor-read-timeout"></a><b>acceptor-read-timeout</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">read-timeout
|
||
</clix:returns></i><br><a class="none" name="acceptor-ssl-certificate-file"></a><b>acceptor-ssl-certificate-file</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">ssl-acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">ssl-certificate-file
|
||
</clix:returns></i><br><a class="none" name="acceptor-ssl-privatekey-file"></a><b>acceptor-ssl-privatekey-file</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">ssl-acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">ssl-privatekey-file
|
||
</clix:returns></i><br><a class="none" name="acceptor-ssl-privatekey-password"></a><b>acceptor-ssl-privatekey-password</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">ssl-acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">ssl-privatekey-password
|
||
</clix:returns></i><br><a class="none" name="acceptor-write-timeout"></a><b>acceptor-write-timeout</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">write-timeout
|
||
</clix:returns></i><br><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
These are readers for various slots of <code><a href="index.html#acceptor">ACCEPTOR</a></code>
|
||
objects (and some of them obviously only make sense
|
||
for <code><a href="index.html#ssl-acceptor">SSL-ACCEPTOR</a></code> objects). See the docstrings of
|
||
these slots for more information and note that there are corresponding
|
||
initargs for all of them.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns="">
|
||
[Generic accessors]<br><a class="none" name="acceptor-access-log-destination"></a><b>acceptor-access-log-destination</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">(or pathname null)
|
||
</clix:returns></i><br><tt>(setf (</tt><b>acceptor-access-log-destination</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><br><a class="none" name="acceptor-document-root"></a><b>acceptor-document-root</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">(or pathname null)
|
||
</clix:returns></i><br><tt>(setf (</tt><b>acceptor-document-root</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><br><a class="none" name="acceptor-error-template-directory"></a><b>acceptor-error-template-directory</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">(or pathname null)
|
||
</clix:returns></i><br><tt>(setf (</tt><b>acceptor-error-template-directory</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><br><a class="none" name="acceptor-input-chunking-p"></a><b>acceptor-input-chunking-p</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">input-chunking-p
|
||
</clix:returns></i><br><tt>(setf (</tt><b>acceptor-input-chunking-p</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><br><a class="none" name="acceptor-message-log-destination"></a><b>acceptor-message-log-destination</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">(or pathname null)
|
||
</clix:returns></i><br><tt>(setf (</tt><b>acceptor-message-log-destination</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><br><a class="none" name="acceptor-name"></a><b>acceptor-name</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">name
|
||
</clix:returns></i><br><tt>(setf (</tt><b>acceptor-name</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><br><a class="none" name="acceptor-output-chunking-p"></a><b>acceptor-output-chunking-p</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">output-chunking-p
|
||
</clix:returns></i><br><tt>(setf (</tt><b>acceptor-output-chunking-p</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><br><a class="none" name="acceptor-persistent-connections-p"></a><b>acceptor-persistent-connections-p</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">persistent-connections-p
|
||
</clix:returns></i><br><tt>(setf (</tt><b>acceptor-persistent-connections-p</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><br><a class="none" name="acceptor-reply-class"></a><b>acceptor-reply-class</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">reply-class
|
||
</clix:returns></i><br><tt>(setf (</tt><b>acceptor-reply-class</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><br><a class="none" name="acceptor-request-class"></a><b>acceptor-request-class</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">request-class
|
||
</clix:returns></i><br><tt>(setf (</tt><b>acceptor-request-class</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><br><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
These are accessors for various slots of <code><a href="index.html#acceptor">ACCEPTOR</a></code>
|
||
objects. See the docstrings of these slots for more information and
|
||
note that there are corresponding initargs for all of them.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="acceptor-ssl-p"></a>
|
||
[Generic function]
|
||
<br><b>acceptor-ssl-p</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">generalized-boolean
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">Returns a true value if <code><i>acceptor</i></code> uses SSL
|
||
connections. The default is to unconditionally return <code xmlns="http://www.w3.org/1999/xhtml">NIL</code> and
|
||
subclasses of <code><a href="index.html#acceptor">ACCEPTOR</a></code> must specialize this method to signal that
|
||
they're using secure connections - see the <code><a href="index.html#ssl-acceptor">SSL-ACCEPTOR</a></code> class.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*default-connection-timeout*"></a>
|
||
[Special variable]
|
||
<br><b>*default-connection-timeout*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">The default connection timeout used when an
|
||
acceptor is reading from and writing to a socket stream. Note that
|
||
some Lisps allow you to set different timeouts for reading and writing
|
||
and you can specify both values via initargs when you create
|
||
an <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#acceptors">acceptor</a>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="acceptor-remove-session"></a>
|
||
[Generic function]
|
||
<br><b>acceptor-remove-session</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor session
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">|
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This function is called whenever a session in
|
||
<code><a href="index.html#acceptor">ACCEPTOR</a></code> is being destroyed because of
|
||
a session timout or an explicit
|
||
<code><a href="index.html#remove-session">REMOVE-SESSION</a></code> call.
|
||
</clix:description></blockquote></p>
|
||
|
||
|
||
|
||
<h4 xmlns=""><a name="acceptor-behaviour">Customizing acceptor behaviour</a></h4>
|
||
|
||
If you want to modify what acceptors do, you should subclass
|
||
<code xmlns=""><a href="index.html#acceptor">ACCEPTOR</a></code> (or <code xmlns=""><a href="index.html#ssl-acceptor">SSL-ACCEPTOR</a></code>) and
|
||
specialize the generic functions that constitute their behaviour (see
|
||
example below). The life of an acceptor looks like this: It is started
|
||
with the function <code xmlns=""><a href="index.html#start">START</a></code> which immediately calls
|
||
<code xmlns=""><a href="index.html#start-listening">START-LISTENING</a></code> and then applies the function
|
||
<code xmlns=""><a href="index.html#execute-acceptor">EXECUTE-ACCEPTOR</a></code> to its <a href="index.html#taskmasters">taskmaster</a>. This function will eventually call
|
||
<code xmlns=""><a href="index.html#accept-connections">ACCEPT-CONNECTIONS</a></code> which is responsible for setting
|
||
things up to wait for clients to connect. For each incoming connection
|
||
which comes in, <code xmlns=""><a href="index.html#handle-incoming-connection">HANDLE-INCOMING-CONNECTION</a></code> is applied
|
||
to the taskmaster which will either call
|
||
<code xmlns=""><a href="index.html#process-connection">PROCESS-CONNECTION</a></code> directly, or will create a thread
|
||
to call it. <code xmlns=""><a href="index.html#process-connection">PROCESS-CONNECTION</a></code> calls
|
||
<code xmlns=""><a href="index.html#initialize-connection-stream">INITIALIZE-CONNECTION-STREAM</a></code> before it does anything
|
||
else, then it selects and calls a function which handles the <a href="index.html#requests">request</a>, and finally it sends the <a href="index.html#replies">reply</a> to the client before it calls
|
||
<code xmlns=""><a href="index.html#reset-connection-stream">RESET-CONNECTION-STREAM</a></code>. If the connection is
|
||
persistent, this procedure is repeated (except for the intialization step)
|
||
in a loop until the connection is closed. The acceptor is stopped with
|
||
<code xmlns=""><a href="index.html#stop">STOP</a></code>.
|
||
|
||
<p>
|
||
If you just want to use the standard acceptors that come with
|
||
Hunchentoot, you don't need to know anything about the functions
|
||
listed in this section.
|
||
</p>
|
||
|
||
<p xmlns=""><a class="none" name="start-listening"></a>
|
||
[Generic function]
|
||
<br><b>start-listening</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">|
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">Sets up a listen socket for the given acceptor and
|
||
enables it to listen to incoming connections. This function is called
|
||
from the thread that starts the acceptor initially and may return
|
||
errors resulting from the listening operation (like 'address in use'
|
||
or similar).
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="accept-connections"></a>
|
||
[Generic function]
|
||
<br><b>accept-connections</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">nil
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">In a loop, accepts a connection and hands it over
|
||
to the acceptor's taskmaster for processing using
|
||
<code><a href="index.html#handle-incoming-connection">HANDLE-INCOMING-CONNECTION</a></code>. On LispWorks, this
|
||
function returns immediately, on other Lisps it returns only once the
|
||
acceptor has been stopped.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="process-connection"></a>
|
||
[Generic function]
|
||
<br><b>process-connection</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor socket
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">nil
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This function is called by the taskmaster when a new client
|
||
connection has been established. Its arguments are the
|
||
<code><a href="index.html#acceptor">ACCEPTOR</a></code> object and a LispWorks socket
|
||
handle or a usocket socket stream object in
|
||
<code><i>socket</i></code>. It reads the request headers,
|
||
sets up the <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#requests">request</a> and <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#replies">reply</a> objects, and hands over to
|
||
<code><a href="index.html#process-request">PROCESS-REQUEST</a></code> which calls
|
||
<code><a href="index.html#handle-request">HANDLE-REQUEST</a></code> to select and call a
|
||
handler for the request and sends its reply to the client.
|
||
This is done in a loop until the stream has to be closed or
|
||
until a connection timeout occurs. It is probably not a
|
||
good idea to re-implement this method until you really,
|
||
really know what you're doing.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
Handlers may call to the
|
||
<code xmlns=""><a href="index.html#detach-socket">DETACH-SOCKET</a></code> generic function to
|
||
indicate that no further requests should be handled on
|
||
the connection by Hunchentoot, and that responsibility for
|
||
the socket is assumed by third-party software. This can
|
||
be used by specialized handlers that wish to hand over
|
||
connection polling or processing to functions outside of
|
||
Hunchentoot, i.e. for connection multiplexing or
|
||
implementing specialized client protocols. Hunchentoot
|
||
will finish processing the request and the
|
||
<code xmlns=""><a href="index.html#process-connection">PROCESS-CONNECTION</a></code> function will
|
||
return without closing the connection. At that point,
|
||
the acceptor may interact with the socket in whatever
|
||
fashion required.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="detach-socket"></a>
|
||
[Generic function]
|
||
<br><b>detach-socket</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">nil
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Indicate to Hunchentoot that it should stop serving requests
|
||
on the current request's socket. Hunchentoot will finish
|
||
processing the current request and then return from
|
||
<code><a href="index.html#process-connection">PROCESS-CONNECTION</a></code> without closing the
|
||
connection to the client.
|
||
<code><a href="index.html#detach-socket">DETACH-SOCKET</a></code> can only be called from
|
||
within a request handler function.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="initialize-connection-stream"></a>
|
||
[Generic function]
|
||
<br><b>initialize-connection-stream</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor stream
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">stream
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Can be used to modify the stream which is used to
|
||
communicate between client and server before the request is
|
||
read. The default method of <code><a href="index.html#acceptor">ACCEPTOR</a></code>
|
||
does nothing, but see for example the method defined for
|
||
<code><a href="index.html#ssl-acceptor">SSL-ACCEPTOR</a></code>. All methods of this
|
||
generic function <em xmlns="http://www.w3.org/1999/xhtml">must</em> return the stream to use.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="reset-connection-stream"></a>
|
||
[Generic function]
|
||
<br><b>reset-connection-stream</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor stream
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">stream
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Resets the stream which is used to communicate
|
||
between client and server after one request has been served so that it
|
||
can be used to process the next request. This generic function is
|
||
called after a request has been processed and <em xmlns="http://www.w3.org/1999/xhtml">must</em> return the
|
||
stream.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="acceptor-log-access"></a>
|
||
[Generic function]
|
||
<br><b>acceptor-log-access</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor &key return-code</clix:lambda-list></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Function to call to log access to the acceptor. The
|
||
<code><i>return-code</i></code> keyword argument contains additional
|
||
information about the request to log. In addition, it can use the
|
||
standard request and reply accessor functions that are available to
|
||
handler functions to find out more information about the request.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="acceptor-log-message"></a>
|
||
[Generic function]
|
||
<br><b>acceptor-log-message</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor log-level format-string &rest format-arguments</clix:lambda-list></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Function to call to log messages by the <code><i>acceptor</i></code>. It must accept
|
||
a severity level for the message, which will be one of :ERROR, :INFO,
|
||
or :WARNING, a format string and an arbitary number of formatting
|
||
arguments.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="acceptor-status-message"></a>
|
||
[Generic function]
|
||
<br><b>acceptor-status-message</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor http-return-code &key &allow-other-keys</clix:lambda-list></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This function is called when a request's handler has been
|
||
called but failed to provide content to send back to the
|
||
client. It converts the
|
||
<code><i>HTTP-STATUS-CODE</i></code> to some request
|
||
contents, typically a human readable description of the
|
||
status code to be displayed to the user.
|
||
|
||
If an ERROR-TEMPLATE-DIRECTORY is set in the current
|
||
acceptor and the directory contains a file corresponding to
|
||
HTTP-STATUS-CODE named <code>.html, that file is sent
|
||
to the client after variable substitution. Variables are
|
||
referenced by ${<variable-name>}.
|
||
|
||
Additional keyword arguments may be provided which are made
|
||
available to the templating logic as substitution variables.
|
||
These variables can be interpolated into error message
|
||
templates in, which contains the current URL relative to the
|
||
server and without GET parameters.
|
||
|
||
In addition to the variables corresponding to keyword
|
||
arguments, the script-name, lisp-implementation-type,
|
||
lisp-implementation-version and hunchentoot-version
|
||
variables are available.
|
||
</clix:description></blockquote></p>
|
||
|
||
|
||
<h4 xmlns=""><a name="subclassing-acceptors">An example of how to subclass ACCEPTOR</a></h4>
|
||
|
||
This example shows how to subclass <code xmlns=""><a href="index.html#acceptor">ACCEPTOR</a></code> in order to
|
||
provide Hunchentoot with basic virtual host support. It assumes
|
||
Hunchentoot is sitting behind an Internet-facing reverse-proxy web server
|
||
that maps the host (or domain) part of incoming HTTP requests to unique
|
||
localhost ports.
|
||
|
||
<pre>(asdf:load-system "hunchentoot")
|
||
(asdf:load-system "drakma")
|
||
|
||
;;; Subclass ACCEPTOR
|
||
(defclass vhost (hunchentoot:acceptor)
|
||
;; slots
|
||
((dispatch-table
|
||
:initform '()
|
||
:accessor dispatch-table
|
||
:documentation "List of dispatch functions"))
|
||
;; options
|
||
(:default-initargs ; default-initargs must be used
|
||
:address "127.0.0.1")) ; because ACCEPTOR uses it
|
||
|
||
;;; Specialise ACCEPTOR-DISPATCH-REQUEST for VHOSTs
|
||
(defmethod hunchentoot:acceptor-dispatch-request ((vhost vhost) request)
|
||
;; try REQUEST on each dispatcher in turn
|
||
(mapc (lambda (dispatcher)
|
||
(let ((handler (funcall dispatcher request)))
|
||
(when handler ; Handler found. FUNCALL it and return result
|
||
(return-from hunchentoot:acceptor-dispatch-request (funcall handler)))))
|
||
(dispatch-table vhost))
|
||
(call-next-method))
|
||
|
||
;;; ======================================================================
|
||
;;; Now all we need to do is test it
|
||
|
||
;;; Instantiate VHOSTs
|
||
(defvar vhost1 (make-instance 'vhost :port 50001))
|
||
(defvar vhost2 (make-instance 'vhost :port 50002))
|
||
|
||
;;; Populate each dispatch table
|
||
(push
|
||
(hunchentoot:create-prefix-dispatcher "/foo" 'foo1)
|
||
(dispatch-table vhost1))
|
||
(push
|
||
(hunchentoot:create-prefix-dispatcher "/foo" 'foo2)
|
||
(dispatch-table vhost2))
|
||
|
||
;;; Define handlers
|
||
(defun foo1 () "Hello")
|
||
(defun foo2 () "Goodbye")
|
||
|
||
;;; Start VHOSTs
|
||
(hunchentoot:start vhost1)
|
||
(hunchentoot:start vhost2)
|
||
|
||
;;; Make some requests
|
||
(drakma:http-request "http://127.0.0.1:50001/foo")
|
||
;;; =|
|
||
;;; 127.0.0.1 - [2012-06-08 14:30:39] "GET /foo HTTP/1.1" 200 5 "-" "Drakma/1.2.6 (SBCL 1.0.56; Linux; 2.6.32-5-686; http://weitz.de/drakma/)"
|
||
;;; =>
|
||
;;; "Hello"
|
||
;;; 200
|
||
;;; ((:CONTENT-LENGTH . "5") (:DATE . "Fri, 08 Jun 2012 14:30:39 GMT")
|
||
;;; (:SERVER . "Hunchentoot 1.2.3") (:CONNECTION . "Close")
|
||
;;; (:CONTENT-TYPE . "text/html; charset=utf-8"))
|
||
;;; #<PURI:URI http://127.0.0.1:50001/foo>
|
||
;;; #<FLEXI-STREAMS:FLEXI-IO-STREAM {CA90059}>
|
||
;;; T
|
||
;;; "OK"
|
||
(drakma:http-request "http://127.0.0.1:50002/foo")
|
||
;;; =|
|
||
;;; 127.0.0.1 - [2012-06-08 14:30:47] "GET /foo HTTP/1.1" 200 7 "-" "Drakma/1.2.6 (SBCL 1.0.56; Linux; 2.6.32-5-686; http://weitz.de/drakma/)"
|
||
;;; =>
|
||
;;; "Goodbye"
|
||
;;; 200
|
||
;;; ((:CONTENT-LENGTH . "7") (:DATE . "Fri, 08 Jun 2012 14:30:47 GMT")
|
||
;;; (:SERVER . "Hunchentoot 1.2.3") (:CONNECTION . "Close")
|
||
;;; (:CONTENT-TYPE . "text/html; charset=utf-8"))
|
||
;;; #<PURI:URI http://127.0.0.1:50002/foo>
|
||
;;; #<FLEXI-STREAMS:FLEXI-IO-STREAM {CAE8059}>
|
||
;;; T
|
||
;;; "OK"</pre>
|
||
|
||
How to make each VHOST write to separate access log streams (or files) is
|
||
left as an exercise to the reader.
|
||
|
||
|
||
|
||
<h4 xmlns=""><a name="taskmasters">Taskmasters</a></h4>
|
||
As a "normal" Hunchentoot user, you can completely ignore
|
||
taskmasters and skip this section. But if you're still reading,
|
||
here are the dirty details: Each <a href="index.html#acceptors">acceptor</a> has a taskmaster associated with
|
||
it at creation time. It is the taskmaster's job to distribute
|
||
the work of accepting and handling incoming connections. The
|
||
acceptor calls the taskmaster if appropriate and the taskmaster
|
||
calls back into the acceptor. This is done using the generic
|
||
functions described in this and the <a href="index.html#acceptor-behaviour">previous</a> section. Hunchentoot
|
||
comes with two standard taskmaster implementations - one (which
|
||
is the default used on multi-threaded Lisps) which starts a new
|
||
thread for each incoming connection and one which handles all
|
||
requests sequentially. It should for example be relatively
|
||
straightforward to create a taskmaster which allocates threads
|
||
from a fixed pool instead of creating a new one for each
|
||
connection.
|
||
|
||
<p>
|
||
You can control the resources consumed by a threaded taskmaster via
|
||
two initargs. <code>:max-thread-count</code> lets you set the maximum
|
||
number of request threads that can be processes simultaneously. If
|
||
this is <code>nil</code>, the is no thread limit imposed.
|
||
|
||
<code>:max-accept-count</code> lets you set the maximum number of requests
|
||
that can be outstanding (i.e. being processed or queued for processing).
|
||
|
||
If <code>:max-thread-count</code> is supplied and <code>:max-accept-count</code>
|
||
is <code>NIL</code>, then a <code xmlns=""><a href="index.html#+http-service-unavailable+">+HTTP-SERVICE-UNAVAILABLE+</a></code>
|
||
error will be generated if there are more than the max-thread-count
|
||
threads processing requests. If both <code>:max-thread-count</code>
|
||
and <code>:max-accept-count</code> are supplied, then max-thread-count
|
||
must be less than max-accept-count; if more than max-thread-count
|
||
requests are being processed, then requests up to max-accept-count
|
||
will be queued until a thread becomes available. If more than
|
||
max-accept-count requests are outstanding, then a <code xmlns=""><a href="index.html#+http-service-unavailable+">+HTTP-SERVICE-UNAVAILABLE+</a></code>
|
||
error will be generated.
|
||
|
||
In a load-balanced environment with multiple Hunchentoot servers, it's
|
||
reasonable to provide <code>:max-thread-count</code> but leave
|
||
<code>:max-accept-count</code> null. This will immediately result
|
||
in <code xmlns=""><a href="index.html#+http-service-unavailable+">+HTTP-SERVICE-UNAVAILABLE+</a></code> when one server is
|
||
out of resources, so the load balancer can try to find another server.
|
||
|
||
In an environment with a single Hunchentoot server, it's reasonable
|
||
to provide both <code>:max-thread-count</code> and a somewhat larger value
|
||
for <code>:max-accept-count</code>. This will cause a server that's almost
|
||
out of resources to wait a bit; if the server is completely out of resources,
|
||
then the reply will be <code xmlns=""><a href="index.html#+http-service-unavailable+">+HTTP-SERVICE-UNAVAILABLE+</a></code>.
|
||
The default for these values is 100 and 120, respectively.
|
||
</p>
|
||
|
||
<p>
|
||
If you want to implement your own taskmasters, you should subclass
|
||
<code xmlns=""><a href="index.html#taskmaster">TASKMASTER</a></code> or one of its subclasses,
|
||
<code xmlns=""><a href="index.html#single-threaded-taskmaster">SINGLE-THREADED-TASKMASTER</a></code> or
|
||
<code xmlns=""><a href="index.html#one-thread-per-connection-taskmaster">ONE-THREAD-PER-CONNECTION-TASKMASTER</a></code>, and
|
||
specialize the generic functions in this section.
|
||
</p>
|
||
|
||
<p xmlns=""><a class="none" name="taskmaster"></a>
|
||
[Standard class]
|
||
<br><b>taskmaster</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
An instance of this class is responsible for distributing
|
||
the work of handling requests for its acceptor. This is an
|
||
"abstract" class in the sense that usually only instances of
|
||
subclasses of <code><a href="index.html#taskmaster">TASKMASTER</a></code> will be used.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="one-thread-per-connection-taskmaster"></a>
|
||
[Standard class]
|
||
<br><b>one-thread-per-connection-taskmaster</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
A taskmaster that starts one thread for listening to
|
||
incoming requests and one thread for each incoming
|
||
connection.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
This is the default taskmaster implementation for multi-threaded Lisp
|
||
implementations.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="single-threaded-taskmaster"></a>
|
||
[Standard class]
|
||
<br><b>single-threaded-taskmaster</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
A taskmaster that runs synchronously in the
|
||
thread where the <code><a href="index.html#start">START</a></code> function was invoked (or
|
||
in the case of LispWorks in the thread started
|
||
by <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.lispworks.com/documentation/lw51/LWRM/html/lwref-61.htm#marker-910861"><code>COMM:START-UP-SERVER</code></a>).
|
||
This is the simplest possible taskmaster implementation in that its
|
||
methods do nothing but calling their acceptor "sister"
|
||
methods - <code><a href="index.html#execute-acceptor">EXECUTE-ACCEPTOR</a></code> calls <code><a href="index.html#accept-connections">ACCEPT-CONNECTIONS</a></code>,
|
||
<code><a href="index.html#handle-incoming-connection">HANDLE-INCOMING-CONNECTION</a></code> calls <code><a href="index.html#process-connection">PROCESS-CONNECTION</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="multi-threaded-taskmaster"></a>
|
||
[Standard class]
|
||
<br><b>multi-threaded-taskmaster</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This is an abstract class for taskmasters that use multiple threads;
|
||
it is not a concrete class and you should not instantiate it with
|
||
<code xmlns="http://www.w3.org/1999/xhtml">MAKE-INSTANCE</code>.
|
||
Instead, you should instantiate its subclass
|
||
<code><a href="index.html#one-thread-per-connection-taskmaster">ONE-THREAD-PER-CONNECTION-TASKMASTER</a></code> described above.
|
||
<code><a href="index.html#multi-threaded-taskmaster">MULTI-THREADED-TASKMASTER</a></code>
|
||
is intended to be inherited from by extensions to Hunchentoot,
|
||
such as <a xmlns="http://www.w3.org/1999/xhtml" href="http://common-lisp.net/project/qitab/">quux-hunchentoot</a>'s
|
||
<code xmlns="http://www.w3.org/1999/xhtml">THREAD-POOLING-TASKMASTER</code>,
|
||
though at the moment, doing so only inherits one slot and one method,
|
||
on <code><a href="index.html#execute-acceptor">EXECUTE-ACCEPTOR</a></code>,
|
||
to have it start a new thread for the acceptor,
|
||
then saved in said slot.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="execute-acceptor"></a>
|
||
[Generic function]
|
||
<br><b>execute-acceptor</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">taskmaster
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">This is a callback called by the acceptor once it
|
||
has performed all initial processing to start listening for incoming
|
||
connections (see <code><a href="index.html#start-listening">START-LISTENING</a></code>). It usually calls the
|
||
<code><a href="index.html#accept-connections">ACCEPT-CONNECTIONS</a></code> method of the acceptor, but depending on the
|
||
taskmaster instance the method might be called from a new thread.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="handle-incoming-connection"></a>
|
||
[Generic function]
|
||
<br><b>handle-incoming-connection</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">taskmaster socket
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This function is called by the acceptor to start
|
||
processing of requests on a new incoming connection. <code><i>socket</i></code> is the
|
||
usocket instance that represents the new connection (or a socket
|
||
handle on LispWorks). The taskmaster starts processing requests on
|
||
the incoming connection by calling the <code><a href="index.html#process-connection">PROCESS-CONNECTION</a></code>
|
||
method of the acceptor instance. The <code><i>socket</i></code> argument is passed to
|
||
<code><a href="index.html#process-connection">PROCESS-CONNECTION</a></code> as an argument.
|
||
|
||
If the taskmaster is a multi-threaded taskmaster, <code><a href="index.html#handle-incoming-thread">HANDLE-INCOMING-THREAD</a></code>
|
||
will call <code><a href="index.html#create-request-handler-thread">CREATE-REQUEST-HANDLER-THREAD</a></code>, which will call
|
||
<code><a href="index.html#process-connection">PROCESS-CONNECTION</a></code> in a new thread.
|
||
<code><a href="index.html#handle-incoming-thread">HANDLE-INCOMING-THREAD</a></code> might issue a
|
||
<code><a href="index.html#+http-service-unavailable+">+HTTP-SERVICE-UNAVAILABLE+</a></code> error
|
||
if there are too many request threads or it might block waiting for a
|
||
request thread to finish.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="start-thread"></a>
|
||
[Generic function]
|
||
<br><b>start-thread</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">taskmaster thunk &key
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">thread
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">This function is a callback that
|
||
starts a new thread that will call the given <code><i>thunk</i></code>
|
||
in the context of the proper <code><i>taskmaster</i></code>,
|
||
with appropriate context-dependent keyword arguments.
|
||
<code><a href="index.html#one-thread-per-connection-taskmaster">ONE-THREAD-PER-CONNECTION-TASKMASTER</a></code> uses it in
|
||
<code><a href="index.html#execute-acceptor">EXECUTE-ACCEPTOR</a></code>
|
||
and <code><a href="index.html#create-request-handler-thread">CREATE-REQUEST-HANDLER-THREAD</a></code>,
|
||
but specialized taskmasters may define more functions that use it.
|
||
By default, it just creates a thread calling the thunk
|
||
with a specified <code><i>name</i></code> keyword argument.
|
||
Specialized taskmasters may wrap special bindings and condition handlers
|
||
around the thunk call, register the thread in a management table, etc.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="create-request-handler-thread"></a>
|
||
[Generic function]
|
||
<br><b>create-request-handler-thread</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">taskmaster socket
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">thread
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">This function is called by <code><a href="index.html#handle-incoming-thread">HANDLE-INCOMING-THREAD</a></code>
|
||
to create a new thread which calls <code><a href="index.html#process-connection">PROCESS-CONNECTION</a></code>.
|
||
If you specialize this function, you must be careful to have the thread
|
||
call <code><a href="index.html#decrement-taskmaster-request-count">DECREMENT-TASKMASTER-REQUEST-COUNT</a></code> before
|
||
it exits. A typical method will look like this:
|
||
|
||
<pre xmlns="http://www.w3.org/1999/xhtml">(defmethod create-request-handler-thread ((taskmaster monitor-taskmaster) socket)
|
||
(bt:make-thread
|
||
(lambda ()
|
||
(with-monitor-error-handlers
|
||
(unwind-protect
|
||
(with-monitor-variable-bindings
|
||
(process-connection (taskmaster-acceptor taskmaster) socket))
|
||
(decrement-taskmaster-request-count taskmaster))))))</pre>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="shutdown"></a>
|
||
[Generic function]
|
||
<br><b>shutdown</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">taskmaster
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">taskmaster
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">Shuts down the taskmaster, i.e. frees all resources
|
||
that were set up by it. For example, a multi-threaded taskmaster
|
||
might terminate all threads that are currently associated with it.
|
||
This function is called by the acceptor's <code><a href="index.html#stop">STOP</a></code> method.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="taskmaster-acceptor"></a>
|
||
[Generic accessor]
|
||
<br><b>taskmaster-acceptor</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">taskmaster
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:returns></i><br><tt>(setf (</tt><b>taskmaster-acceptor</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">taskmaster
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This is an accessor for the slot of a <code><a href="index.html#taskmaster">TASKMASTER</a></code>
|
||
object that links back to the <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#acceptors">acceptor</a> it is
|
||
associated with.
|
||
</clix:description></blockquote></p>
|
||
|
||
|
||
|
||
<h4 xmlns=""><a name="request-dispatch">Request dispatch and handling</a></h4>
|
||
|
||
The main job of <code xmlns=""><a href="index.html#handle-request">HANDLE-REQUEST</a></code> is to select
|
||
and call a function which handles the request, i.e. which looks
|
||
at the data the client has sent and prepares an appropriate
|
||
reply to send back. This is by default implemented as follows:
|
||
<p>
|
||
The ACCEPTOR class defines a
|
||
<code xmlns=""><a href="index.html#acceptor-dispatch-request">ACCEPTOR-DISPATCH-REQUEST</a></code> generic
|
||
function which is used to actually dispatch the request. This
|
||
function is called by the default method of
|
||
<code xmlns=""><a href="index.html#handle-request">HANDLE-REQUEST</a></code>. Each
|
||
<code xmlns=""><a href="index.html#acceptor-dispatch-request">ACCEPTOR-DISPATCH-REQUEST</a></code> method looks at
|
||
the request object and depending on its contents decides to
|
||
either handle the request or call the next method.
|
||
</p>
|
||
<p>
|
||
In order to dispatch a request, Hunchentoot calls the
|
||
<code xmlns=""><a href="index.html#acceptor-dispatch-request">ACCEPTOR-DISPATCH-REQUEST</a></code> generic
|
||
functions. The method for <code xmlns=""><a href="index.html#acceptor">ACCEPTOR</a></code> tries
|
||
to serve a static file relative to it's
|
||
<code xmlns=""><a href="index.html#acceptor-document-root">ACCEPTOR-DOCUMENT-ROOT</a></code>. Application
|
||
specific acceptor subclasses will typically perform URL
|
||
parsing and dispatching according to the policy that is
|
||
required.
|
||
</p>
|
||
<p>
|
||
The default method of <code xmlns=""><a href="index.html#handle-request">HANDLE-REQUEST</a></code> sets
|
||
up <a href="index.html#logging">standard logging and error handling</a>
|
||
before it calls the acceptor's request dispatcher.
|
||
</p>
|
||
<p>
|
||
Request handlers do their work by modifying
|
||
the <a href="index.html#replies">reply object</a> if necessary and by eventually
|
||
returning the response body in the form of a string or a binary
|
||
sequence. As an alternative, they can also
|
||
call <code xmlns=""><a href="index.html#send-headers">SEND-HEADERS</a></code> and write directly to a stream.
|
||
</p>
|
||
|
||
|
||
<h4 xmlns=""><a name="easy-handlers">Using the easy-handler framework</a></h4>
|
||
<p>
|
||
The <code xmlns=""><a href="index.html#easy-acceptor">EASY-ACCEPTOR</a></code> class defines a method
|
||
for <code xmlns=""><a href="index.html#acceptor-dispatch-request">ACCEPTOR-DISPATCH-REQUEST</a></code> that walks
|
||
through the list <code xmlns=""><a href="index.html#*dispatch-table*">*DISPATCH-TABLE*</a></code> which
|
||
consists of <em>dispatch functions</em>. Each of these
|
||
functions accepts the request object as its only argument and
|
||
either returns a request handler to handle the request or
|
||
<code>NIL</code> which means that the next dispatcher in the
|
||
list will be tried. A <em>request handler</em> is a function
|
||
of zero arguments which relies on the special variable
|
||
<code xmlns=""><a href="index.html#*request*">*REQUEST*</a></code> to access the request instance
|
||
being serviced. If all dispatch functions return
|
||
<code>NIL</code>, the next
|
||
<code xmlns=""><a href="index.html#acceptor-dispatch-request">ACCEPTOR-DISPATCH-REQUEST</a></code> will be called.
|
||
</p>
|
||
<p>
|
||
<strong>N.B.</strong> All functions and variables in this
|
||
section are related to the easy request dispatch mechanism and
|
||
are meaningless if you're using your own request dispatcher.
|
||
</p>
|
||
|
||
<p xmlns=""><a class="none" name="easy-acceptor"></a>
|
||
[Standard class]
|
||
<br><b>easy-acceptor</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This class defines no additional slots with respect to
|
||
<code><a href="index.html#acceptor">ACCEPTOR</a></code>. It only serves as an
|
||
additional type for dispatching calls to
|
||
<code><a href="index.html#acceptor-dispatch-request">ACCEPTOR-DISPATCH-REQUEST</a></code>. In order to
|
||
use the easy handler framework, acceptors of this class or
|
||
one of its subclasses must be used.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="easy-ssl-acceptor"></a>
|
||
[Standard class]
|
||
<br><b>easy-ssl-acceptor</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This class mixes the <code><a href="index.html#ssl-acceptor">SSL-ACCEPTOR</a></code> and
|
||
the <code><a href="index.html#easy-acceptor">EASY-ACCEPTOR</a></code> classes. It is used
|
||
when both ssl and the easy handler framework are required.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*dispatch-table*"></a>
|
||
[Special variable]
|
||
<br><b>*dispatch-table*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
A global list of dispatch functions. The initial value is a
|
||
list consisting of the symbol
|
||
<code><a href="index.html#dispatch-easy-handlers">DISPATCH-EASY-HANDLERS</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="create-prefix-dispatcher"></a>
|
||
[Function]
|
||
<br><b>create-prefix-dispatcher</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">prefix handler</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">dispatch-fn</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
A convenience function which will return a dispatcher that
|
||
returns <code><i>handler</i></code> whenever the path part of
|
||
the request URI starts with the
|
||
string <code><i>prefix</i></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="create-regex-dispatcher"></a>
|
||
[Function]
|
||
<br><b>create-regex-dispatcher</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">regex handler</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">dispatch-fn</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
A convenience function which will return a dispatcher that
|
||
returns <code><i>handler</i></code> whenever the path part of
|
||
the request URI matches
|
||
the <a xmlns="http://www.w3.org/1999/xhtml" href="http://weitz.de/cl-ppcre/">CL-PPCRE</a> regular
|
||
expression <code><i>regex</i></code> (which can be a string, an
|
||
s-expression, or a scanner).
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="create-folder-dispatcher-and-handler"></a>
|
||
[Function]
|
||
<br><b>create-folder-dispatcher-and-handler</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">uri-prefix base-path <tt>&optional</tt> content-type callback</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">dispatch-fn</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Creates and returns a dispatch function which will dispatch to
|
||
a handler function which emits the file relative
|
||
to <code><i>base-path</i></code> that is denoted by the URI of
|
||
the request relative
|
||
to <code><i>uri-prefix</i></code>. <code><i>uri-prefix</i></code>
|
||
must be a string ending with a
|
||
slash, <code><i>base-path</i></code> must be a pathname
|
||
designator for an existing directory.
|
||
Uses <code><a href="index.html#handle-static-file">HANDLE-STATIC-FILE</a></code> internally.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
If <code xmlns=""><i>content-type</i></code> is <em>not</em>
|
||
<code>NIL</code>, it will be used as a the content type for
|
||
all files in the folder. Otherwise (which is the default)
|
||
the content type of each file will be
|
||
determined <a href="index.html#handle-static-file">as usual</a>.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
The <code xmlns=""><i>callback</i></code> is passed on to
|
||
<code xmlns=""><a href="index.html#handle-static-file">HANDLE-STATIC-FILE</a></code>.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="create-static-file-dispatcher-and-handler"></a>
|
||
[Function]
|
||
<br><b>create-static-file-dispatcher-and-handler</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">uri path
|
||
<tt>&optional
|
||
</tt> content-type callback
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Creates and returns a request dispatch function which will
|
||
dispatch to a handler function which emits the file denoted
|
||
by the pathname designator PATH with content type
|
||
CONTENT-TYPE if the SCRIPT-NAME of the request matches the
|
||
string URI. If CONTENT-TYPE is NIL, tries to determine the
|
||
content type via the file's suffix.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
The <code xmlns=""><i>callback</i></code> is passed on to
|
||
<code xmlns=""><a href="index.html#handle-static-file">HANDLE-STATIC-FILE</a></code>.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="define-easy-handler"></a>
|
||
[Macro]
|
||
<br><b>define-easy-handler</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">description lambda-list [[declaration* | documentation]] form*</clix:lambda-list></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Defines a handler as if
|
||
by <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.lispworks.com/documentation/HyperSpec/Body/m_defun.htm">
|
||
<code>DEFUN</code></a> and optionally registers it with a
|
||
URI so that it will be found
|
||
by <code><a href="index.html#dispatch-easy-handlers">DISPATCH-EASY-HANDLERS</a></code>.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
<code xmlns=""><i>description</i></code> is either a
|
||
symbol <code xmlns=""><i>name</i></code> or a list matching the
|
||
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/03_de.htm">destructuring
|
||
lambda list</a>
|
||
</p>
|
||
<pre xmlns="http://www.w3.org/1999/xhtml">(name &key uri host acceptor-names default-parameter-type default-request-type).</pre>
|
||
<code><i>lambda-list</i></code> is a list the elements of which
|
||
are either a symbol <code><i>var</i></code> or a list matching
|
||
the destructuring lambda list
|
||
<pre xmlns="http://www.w3.org/1999/xhtml">(var &key real-name parameter-type init-form request-type).</pre>
|
||
The resulting handler will be a Lisp function with the
|
||
name <code><i>name</i></code> and keyword parameters named by
|
||
the <code><i>var</i></code> symbols.
|
||
Each <code><i>var</i></code> will be bound to the value of the
|
||
GET or POST parameter called <code><i>real-name</i></code> (a
|
||
string) before the body of the function is executed.
|
||
If <code><i>real-name</i></code> is not provided, it will be
|
||
computed
|
||
by <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.lispworks.com/documentation/HyperSpec/Body/f_stg_up.htm#string-downcase">downcasing</a>
|
||
the symbol name of <code><i>var</i></code>.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
If <code xmlns=""><i>uri</i></code> (which is evaluated) is provided,
|
||
then it must be a string or
|
||
a <a href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_f.htm#function_designator">function
|
||
designator</a> for a unary function. In this case, the
|
||
handler will be returned
|
||
by <code xmlns=""><a href="index.html#dispatch-easy-handlers">DISPATCH-EASY-HANDLERS</a></code>,
|
||
if <code xmlns=""><i>uri</i></code> is a string and
|
||
the <a href="index.html#script-name">script name</a> of the current
|
||
request is <code xmlns=""><i>uri</i></code>, or
|
||
if <code xmlns=""><i>uri</i></code> designates a function and applying
|
||
this function to
|
||
the <a href="index.html#*request*">current <code>REQUEST</code>
|
||
object</a> returns a true value.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">If <code xmlns=""><i>host</i></code> is passed in, it is compared
|
||
(via <code>STRING=</code>) to the host of the
|
||
current request, and acts as another dispatch filter. Please note
|
||
that the HTTP header sent from the browser might include the
|
||
port number, resp. will include it for ports other than 80 and 443,
|
||
so you will need to write something like
|
||
<code>"common-lisp.net:8080"</code>.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
<code xmlns=""><i>acceptor-names</i></code> (which is evaluated) can be a
|
||
list of symbols which means that the handler will only be
|
||
returned by <code xmlns=""><a href="index.html#dispatch-easy-handlers">DISPATCH-EASY-HANDLERS</a></code> in
|
||
acceptors which have one of these names
|
||
(see <code xmlns=""><a href="index.html#acceptor-name">ACCEPTOR-NAME</a></code>). <code xmlns=""><i>acceptor-names</i></code> can also be the
|
||
symbol <code>T</code> which means that the handler will be
|
||
returned by <code xmlns=""><a href="index.html#dispatch-easy-handlers">DISPATCH-EASY-HANDLERS</a></code>
|
||
in <em>every</em> acceptor.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
Whether the GET or POST parameter (or both) will be taken into
|
||
consideration, depends on <code xmlns=""><i>request-type</i></code>
|
||
which can
|
||
be <code>:GET</code>, <code>:POST</code>, <code>:BOTH</code>,
|
||
or <code>NIL</code>. In the last case, the value of
|
||
<code xmlns=""><i>default-request-type</i></code> (the default of which
|
||
is <code>:BOTH</code>) will be used.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
The value of <code xmlns=""><i>var</i></code> will usually be a string
|
||
(unless it resulted from a <a href="index.html#upload">file upload</a>
|
||
in which case it won't be converted at all), but
|
||
if <code xmlns=""><i>parameter-type</i></code> (which is evaluated) is
|
||
provided, the string will be converted to another Lisp type by
|
||
the following rules:
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
If the corresponding GET or POST parameter wasn't provided by
|
||
the client, <code xmlns=""><i>var</i></code>'s value will
|
||
be <code>NIL</code>. If <code xmlns=""><i>parameter-type</i></code>
|
||
is <code>'STRING</code>,
|
||
<code xmlns=""><i>var</i></code>'s value remains as is.
|
||
If <code xmlns=""><i>parameter-type</i></code> is <code>'INTEGER</code>
|
||
and the parameter string consists solely of decimal
|
||
digits, <code xmlns=""><i>var</i></code>'s value will be the
|
||
corresponding integer, otherwise <code>NIL</code>.
|
||
If <code xmlns=""><i>parameter-type</i></code> is
|
||
<code>'KEYWORD</code>, <code xmlns=""><i>var</i></code>'s value will be
|
||
the keyword obtained
|
||
by <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_intern.htm">interning</a>
|
||
the <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_stg_up.htm#string-upcase">upcased</a>
|
||
parameter string into
|
||
the <a href="http://www.lispworks.com/documentation/HyperSpec/Body/11_abc.htm">keyword
|
||
package</a>. If <code xmlns=""><i>parameter-type</i></code>
|
||
is <code>'CHARACTER</code> and the parameter string is of
|
||
length one, <code xmlns=""><i>var</i></code>'s value will be the single
|
||
character of this string, otherwise <code>NIL</code>.
|
||
If <code xmlns=""><i>parameter-type</i></code>
|
||
is <code>'BOOLEAN</code>, <code xmlns=""><i>var</i></code>'s value will
|
||
always be <code>T</code> (unless it is <code>NIL</code> by the
|
||
first rule above, of course).
|
||
If <code xmlns=""><i>parameter-type</i></code> is any other atom, it is
|
||
supposed to be
|
||
a <a href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_f.htm#function_designator">function
|
||
designator</a> for a unary function which will be called to
|
||
convert the string to something else.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
Those were the rules for <em>simple</em> parameter types, but
|
||
<code xmlns=""><i>parameter-type</i></code> can also be a list starting
|
||
with one of the symbols
|
||
<code>LIST</code>, <code>ARRAY</code>,
|
||
or <code>HASH-TABLE</code>. The second value of the list must
|
||
always be a simple parameter type as in the last paragraph -
|
||
we'll call it the <em>inner type</em> below.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
In the case of <code>'LIST</code>, all GET/POST parameters
|
||
called <code xmlns=""><i>real-name</i></code> will be collected,
|
||
converted to the inner type as by the rules above, and
|
||
assembled into a list which will be the value of
|
||
<code xmlns=""><i>var</i></code>.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
In the case of <code>'ARRAY</code>, all GET/POST parameters
|
||
which have a name like the result of
|
||
</p>
|
||
<pre xmlns="http://www.w3.org/1999/xhtml">(format nil "~A[~A]" real-name n)</pre>
|
||
where <code><i>n</i></code> is a non-negative integer, will be
|
||
assembled into an array where the <code><i>n</i></code>th element
|
||
will be set accordingly, after conversion to the inner type.
|
||
The array, which will become the value
|
||
of <code><i>var</i></code>, will be big enough to hold all
|
||
matching parameters, but not bigger. Array elements not set as
|
||
described above will be <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>. Note
|
||
that <code xmlns="http://www.w3.org/1999/xhtml">VAR</code> will always be bound to an array, which
|
||
may be empty, so it will never be <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>, even if no
|
||
appropriate GET/POST parameters are found.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
The full form of a <code>'HASH-TABLE</code> parameter type is
|
||
</p>
|
||
<pre xmlns="http://www.w3.org/1999/xhtml">(hash-table inner-type key-type test-function)</pre>
|
||
but <code><i>key-type</i></code>
|
||
and <code><i>test-function</i></code> can be left out in which
|
||
case they default to <code xmlns="http://www.w3.org/1999/xhtml">'STRING</code>
|
||
and <code xmlns="http://www.w3.org/1999/xhtml">'EQUAL</code>, respectively. For this parameter type,
|
||
all GET/POST parameters which have a name like the result of
|
||
<pre xmlns="http://www.w3.org/1999/xhtml">(format nil "~A{~A}" real-name key)</pre>
|
||
(where <code><i>key</i></code> is a string that doesn't contain
|
||
curly brackets) will become the values (after conversion
|
||
to <code><i>inner-type</i></code>) of a hash table with test
|
||
function <code><i>test-function</i></code>
|
||
where <code><i>key</i></code> (after conversion
|
||
to <code><i>key-type</i></code>) will be the corresponding key.
|
||
Note that <code><i>var</i></code> will always be bound to a hash
|
||
table, which may be empty, so it will never be <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>,
|
||
even if no appropriate GET/POST parameters are found.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
To make matters even more complicated, the three compound
|
||
parameter types also have an abbreviated form - just one of
|
||
the symbols <code>LIST</code>, <code>ARRAY</code>,
|
||
or <code>HASH-TABLE</code>. In this case, the inner type will
|
||
default to <code>'STRING</code>.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
If <code xmlns=""><i>parameter-type</i></code> is not provided
|
||
or <code>NIL</code>, <code xmlns=""><i>default-parameter-type</i></code>
|
||
(the default of which is <code>'STRING</code>) will be used
|
||
instead.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
If the result of the computations above would be
|
||
that <code xmlns=""><i>var</i></code> would be bound
|
||
to <code>NIL</code>, then <code xmlns=""><i>init-form</i></code> (if
|
||
provided) will be evaluated instead,
|
||
and <code xmlns=""><i>var</i></code> will be bound to the result of this
|
||
evaluation.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
Handlers built with this macro are constructed in such a way
|
||
that the resulting Lisp function is useful even outside of
|
||
Hunchentoot. Specifically, all the parameter computations
|
||
above will only happen if <code xmlns=""><a href="index.html#*request*">*REQUEST*</a></code> is
|
||
bound, i.e. if we're within a Hunchentoot request.
|
||
Otherwise, <code xmlns=""><i>var</i></code> will always be bound to the
|
||
result of evaluating <code xmlns=""><i>init-form</i></code> unless a
|
||
corresponding keyword argument is provided.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
The <a href="index.html#example">example code</a> that comes with
|
||
Hunchentoot contains an example which demonstrates some of the
|
||
features of <code xmlns=""><a href="index.html#define-easy-handler">DEFINE-EASY-HANDLER</a></code>.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="dispatch-easy-handlers"></a>
|
||
[Function]
|
||
<br><b>dispatch-easy-handlers</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">This is a dispatcher which returns the appropriate handler
|
||
defined with <code><a href="index.html#define-easy-handler">DEFINE-EASY-HANDLER</a></code>, if there is one.
|
||
</clix:description></blockquote></p>
|
||
|
||
<h4 xmlns=""><a name="requests">Request objects</a></h4>
|
||
|
||
For each incoming request, the <a href="index.html#acceptors">acceptor</a> (in
|
||
<code xmlns=""><a href="index.html#process-connection">PROCESS-CONNECTION</a></code>) creates a
|
||
<code xmlns=""><a href="index.html#request">REQUEST</a></code> object and makes it available to <a href="index.html#request-dispatch">handlers</a> via the special variable
|
||
<code xmlns=""><a href="index.html#*request*">*REQUEST*</a></code>. This object contains all relevant
|
||
information about the request and this section collects the functions
|
||
which can be used to query such an object. In all function where
|
||
<code xmlns=""><i>request</i></code> is an optional or keyword parameter, the
|
||
default is <code xmlns=""><a href="index.html#*request*">*REQUEST*</a></code>.
|
||
|
||
<p>
|
||
If you need more fine-grained control over the behaviour of request
|
||
objects, you can subclass <code xmlns=""><a href="index.html#request">REQUEST</a></code> and initialize
|
||
the <a href="index.html#acceptor-request-class"><code>REQUEST-CLASS</code></a>
|
||
slot of the <code xmlns=""><a href="index.html#acceptor">ACCEPTOR</a></code> class accordingly. The
|
||
acceptor will generate request objects of the class named by this
|
||
slot.
|
||
</p>
|
||
|
||
<p xmlns=""><a class="none" name="request"></a>
|
||
[Standard class]
|
||
<br><b>request</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Objects of this class hold all the information
|
||
about an incoming request. They are created automatically by
|
||
acceptors and can be accessed by the
|
||
corresponding <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#request-dispatch">handler</a>.
|
||
|
||
You should not mess with the slots of these objects directly, but you
|
||
can subclass <code><a href="index.html#request">REQUEST</a></code> in order to implement your
|
||
own behaviour. See
|
||
the <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#acceptor-request-class"><code>REQUEST-CLASS</code></a>
|
||
slot of the <code><a href="index.html#acceptor">ACCEPTOR</a></code> class.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*request*"></a>
|
||
[Special variable]
|
||
<br><b>*request*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">The current REQUEST object while in the context of a request.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="real-remote-addr"></a>
|
||
[Function]
|
||
<br><b>real-remote-addr</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">string{, list}
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the '<code xmlns="http://www.w3.org/1999/xhtml">X-Forwarded-For</code>' incoming http header as the
|
||
second value in the form of a list of IP addresses and the first
|
||
element of this list as the first value if this header exists.
|
||
Otherwise returns the value of <code><a href="index.html#remote-addr">REMOTE-ADDR</a></code> as the only value.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="parameter"></a>
|
||
[Function]
|
||
<br><b>parameter</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">name
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">string
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the GET or the POST parameter with name
|
||
<code><i>name</i></code> (a string) - or <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>
|
||
if there is none. If both a GET and a POST parameter with
|
||
the same name exist the GET parameter is returned. Search
|
||
is case-sensitive. See also
|
||
<code><a href="index.html#get-parameter">GET-PARAMETER</a></code> and
|
||
<code><a href="index.html#post-parameter">POST-PARAMETER</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="get-parameter"></a>
|
||
[Function]
|
||
<br><b>get-parameter</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">name <tt>&optional</tt> request</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">string</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the value of the GET parameter (as provided via the
|
||
request URI) named by the string <code><i>name</i></code> as a
|
||
string (or <code xmlns="http://www.w3.org/1999/xhtml">NIL</code> if there ain't no GET parameter
|
||
with this name). Note that only the first value will be
|
||
returned if the client provided more than one GET parameter
|
||
with the name <code><i>name</i></code>. See
|
||
also <code><a href="index.html#get-parameters*">GET-PARAMETERS*</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="post-parameter"></a>
|
||
[Function]
|
||
<br><b>post-parameter</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">name <tt>&optional</tt> request</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">string</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the value of the POST parameter (as provided in the
|
||
request's body) named by the
|
||
string <code><i>name</i></code>. Note that only the first value
|
||
will be returned if the client provided more than one POST
|
||
parameter with the name <code><i>name</i></code>. This value
|
||
will usually be a string (or <code xmlns="http://www.w3.org/1999/xhtml">NIL</code> if there ain't
|
||
no POST parameter with this name). If, however, the browser
|
||
sent a <a xmlns="http://www.w3.org/1999/xhtml" class="none" name="upload">file</a> through
|
||
a <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.faqs.org/rfcs/rfc2388.html">
|
||
<code>multipart/form-data</code>
|
||
</a> form, the value of this function is a three-element list
|
||
<pre xmlns="http://www.w3.org/1999/xhtml">(path file-name content-type)</pre>
|
||
where <code><i>path</i></code> is a pathname denoting the place
|
||
were the uploaded file was
|
||
stored, <code><i>file-name</i></code> (a string) is the file
|
||
name sent by the browser, and <code><i>content-type</i></code>
|
||
(also a string) is the content type sent by the browser. The
|
||
file denoted by <code><i>path</i></code> will be deleted after
|
||
the request has been handled - you have to move or copy it
|
||
somewhere else if you want to keep it.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
POST parameters will only be computed if the content type of
|
||
the request body was <code>multipart/form-data</code>
|
||
or <code>application/x-www-form-urlencoded</code>. Although
|
||
this function is called <code>POST-PARAMETER</code>, you can
|
||
instruct Hunchentoot to compute these parameters for other
|
||
request methods by
|
||
setting <code xmlns=""><a href="index.html#*methods-for-post-parameters*">*METHODS-FOR-POST-PARAMETERS*</a></code>.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
See also <code xmlns=""><a href="index.html#post-parameters">POST-PARAMETERS</a></code>
|
||
and <code xmlns=""><a href="index.html#*tmp-directory*">*TMP-DIRECTORY*</a></code>.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="get-parameters*"></a>
|
||
[Function]
|
||
<br><b>get-parameters*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc"><tt>&optional</tt> request</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">alist</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns
|
||
an <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_a.htm#alist">alist</a>
|
||
of all GET parameters (as provided via the request
|
||
URI). The <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#car">car</a>
|
||
of each element of this list is the parameter's name while
|
||
the <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#cdr">cdr</a>
|
||
is its value (as a string). The elements of this list are in
|
||
the same order as they were within the request URI. See
|
||
also <code><a href="index.html#get-parameter">GET-PARAMETER</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="post-parameters*"></a>
|
||
[Function]
|
||
<br><b>post-parameters*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc"><tt>&optional</tt> request</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">alist</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns
|
||
an <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_a.htm#alist">alist</a>
|
||
of all POST parameters (as provided via the request's
|
||
body). The <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#car">car</a>
|
||
of each element of this list is the parameter's name while
|
||
the <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#cdr">cdr</a>
|
||
is its value. The elements of this list are in the same order
|
||
as they were within the request's body.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
See also <code xmlns=""><a href="index.html#post-parameter">POST-PARAMETER</a></code>.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*methods-for-post-parameters*"></a>
|
||
[Special variable]
|
||
<br><b>*methods-for-post-parameters*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">A list of the request method types (as keywords) for which
|
||
Hunchentoot will try to compute <code><i>post-parameters</i></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="cookie-in"></a>
|
||
[Function]
|
||
<br><b>cookie-in</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">name
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">string
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the cookie with the name <code><i>name</i></code> (a string) as sent by the
|
||
browser - or <code xmlns="http://www.w3.org/1999/xhtml">NIL</code> if there is none.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="cookies-in*"></a>
|
||
[Function]
|
||
<br><b>cookies-in*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">alist
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">Returns an alist of all cookies associated with the <code><a href="index.html#request">REQUEST</a></code> object
|
||
<code><i>request</i></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="host"></a>
|
||
[Function]
|
||
<br><b>host</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">host
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">Returns the 'Host' incoming http header value.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="query-string*"></a>
|
||
[Function]
|
||
<br><b>query-string*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">string
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the query string of the <code><a href="index.html#request">REQUEST</a></code> object <code><i>request</i></code>. That's
|
||
the part behind the question mark (i.e. the GET parameters).
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="referer"></a>
|
||
[Function]
|
||
<br><b>referer</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the 'Referer' (sic!) http header.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="request-method*"></a>
|
||
[Function]
|
||
<br><b>request-method*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">keyword
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the request method as a Lisp keyword.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="request-uri*"></a>
|
||
[Function]
|
||
<br><b>request-uri*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">uri
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the request URI.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="server-protocol*"></a>
|
||
[Function]
|
||
<br><b>server-protocol*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">keyword
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the request protocol as a Lisp keyword.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="user-agent"></a>
|
||
[Function]
|
||
<br><b>user-agent</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the 'User-Agent' http header.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="header-in*"></a>
|
||
[Function]
|
||
<br><b>header-in*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">name
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">header
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the incoming header with name
|
||
<code><i>name</i></code>. <code><i>name</i></code> can be
|
||
a keyword (recommended) or a string.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="headers-in*"></a>
|
||
[Function]
|
||
<br><b>headers-in*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">alist
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns an alist of the incoming headers associated with the
|
||
<code><a href="index.html#request">REQUEST</a></code> object
|
||
<code><i>request</i></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="remote-addr*"></a>
|
||
[Function]
|
||
<br><b>remote-addr*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">address
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the address the current request originated from.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="remote-port*"></a>
|
||
[Function]
|
||
<br><b>remote-port*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">port
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the port the current request originated from.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="local-addr*"></a>
|
||
[Function]
|
||
<br><b>local-addr*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">address
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
The IP address of the local system that the client connected to.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="local-port*"></a>
|
||
[Function]
|
||
<br><b>local-port*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">port
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
The TCP port number of the local system that the client connected to.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="script-name*"></a>
|
||
[Function]
|
||
<br><b>script-name*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">script-name
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the file name of the <code><a href="index.html#request">REQUEST</a></code>
|
||
object <code><i>request</i></code>. That's the
|
||
requested URI without the query string (i.e the GET
|
||
parameters).
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="aux-request-value"></a>
|
||
[Accessor]
|
||
<br><b>aux-request-value</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">symbol
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">value, present-p
|
||
</clix:returns></i><br><tt>(setf (</tt><b>aux-request-value</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">symbol
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This accessor can be used to associate arbitrary
|
||
data with the the symbol <code><i>symbol</i></code> in the <code><a href="index.html#request">REQUEST</a></code> object
|
||
<code><i>request</i></code>. <code><i>present-p</i></code> is true if such data was found, otherwise <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="delete-aux-request-value"></a>
|
||
[Function]
|
||
<br><b>delete-aux-request-value</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">symbol
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">|
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Removes the value associated with <code><i>symbol</i></code> from the <code><a href="index.html#request">REQUEST</a></code> object
|
||
<code><i>request</i></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="authorization"></a>
|
||
[Function]
|
||
<br><b>authorization</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns as two values the user and password (if any) as
|
||
encoded in the 'AUTHORIZATION' header. Returns
|
||
<code xmlns="http://www.w3.org/1999/xhtml">NIL</code> if there is no such header.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*hunchentoot-default-external-format*"></a>
|
||
[Special variable]
|
||
<br><b>*hunchentoot-default-external-format*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
The external format used to compute the <code><a href="index.html#request">REQUEST</a></code> object.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*file-upload-hook*"></a>
|
||
[Special variable]
|
||
<br><b>*file-upload-hook*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
If this is not <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>, it should be a unary
|
||
function which will be called with a pathname for each file
|
||
which is <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#upload">uploaded</a> to Hunchentoot. The
|
||
pathname denotes the temporary file to which the uploaded
|
||
file is written. The hook is called directly before the
|
||
file is created. At this point,
|
||
<code><a href="index.html#*request*">*REQUEST*</a></code> is already bound to the
|
||
current <code><a href="index.html#request">REQUEST</a></code> object, but obviously
|
||
you can't access the post parameters yet.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="raw-post-data"></a>
|
||
[Function]
|
||
<br><b>raw-post-data</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&key</tt>
|
||
request external-format force-text force-binary want-stream
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">raw-body-or-stream</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the content sent by the client in the request body if
|
||
there was any (unless the content type
|
||
was <code xmlns="http://www.w3.org/1999/xhtml">multipart/form-data</code> in which
|
||
case <code xmlns="http://www.w3.org/1999/xhtml">NIL</code> is returned). By default, the result is
|
||
a string if the type of the <code xmlns="http://www.w3.org/1999/xhtml">Content-Type</code>
|
||
<a xmlns="http://www.w3.org/1999/xhtml" href="http://www.faqs.org/rfcs/rfc1590.html">media type</a>
|
||
is <code xmlns="http://www.w3.org/1999/xhtml">"text"</code>, and a vector of octets otherwise. In
|
||
the case of a string, the external format to be used to decode
|
||
the content will be determined from the <code xmlns="http://www.w3.org/1999/xhtml">charset</code>
|
||
parameter sent by the client (or
|
||
otherwise <code><a href="index.html#*hunchentoot-default-external-format*">*HUNCHENTOOT-DEFAULT-EXTERNAL-FORMAT*</a></code>
|
||
will be used).
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
You can also provide an external format explicitly (through
|
||
<code xmlns=""><i>external-format</i></code>) in which case the result
|
||
will unconditionally be a string. Likewise, you can provide
|
||
a true value for <code xmlns=""><i>force-text</i></code> which will
|
||
force Hunchentoot to act as if the type of the media type
|
||
had been <code>"text"</code>
|
||
(with <code xmlns=""><i>external-format</i></code> taking precedence
|
||
if provided). Or you can provide a true value
|
||
for <code xmlns=""><i>force-binary</i></code> which means that you
|
||
want a vector of octets at any rate. (If both
|
||
<code xmlns=""><i>force-text</i></code>
|
||
and <code xmlns=""><i>force-binary</i></code> are true, an error will
|
||
be signaled.)
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
If, however, you provide a true value
|
||
for <code xmlns=""><i>want-stream</i></code>, the other parameters are
|
||
ignored and you'll get the content (flexi) stream to read
|
||
from it yourself. It is then your responsibility to read
|
||
the correct amount of data, because otherwise you won't be
|
||
able to return a response to the client. The stream will
|
||
have
|
||
its <a href="http://weitz.de/flexi-streams/#flexi-streams">octet
|
||
position</a> set to <code>0</code>. If the client provided
|
||
a <code>Content-Length</code> header, the stream will also
|
||
have a
|
||
corresponding <a href="http://weitz.de/flexi-streams/#flexi-streams">bound</a>,
|
||
so no matter whether the client used chunked encoding or
|
||
not, you can always read until EOF.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
If the content type of the request
|
||
was <code>multipart/form-data</code>
|
||
or <code>application/x-www-form-urlencoded</code>, the
|
||
content has been read by Hunchentoot already and you can't
|
||
read from the stream anymore.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
You can call <code xmlns=""><a href="index.html#raw-post-data">RAW-POST-DATA</a></code> more than once
|
||
per request, but you can't mix calls which have different
|
||
values for <code xmlns=""><i>want-stream</i></code>.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
Note that this function is slightly misnamed because a
|
||
client can send content even if the request method is not
|
||
POST.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
|
||
<p xmlns=""><a class="none" name="recompute-request-parameters"></a>
|
||
[Function]
|
||
<br><b>recompute-request-parameters</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&key
|
||
</tt> request external-format
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">|
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Recomputes the GET and POST parameters for the <code><a href="index.html#request">REQUEST</a></code> object
|
||
<code><i>request</i></code>. This only makes sense if you're switching external formats
|
||
during the request.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="process-request"></a>
|
||
[Generic function]
|
||
<br><b>process-request</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">nil
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This function is called by <code><a href="index.html#process-connection">PROCESS-CONNECTION</a></code>
|
||
after the incoming headers have been read. It
|
||
calls <code><a href="index.html#handle-request">HANDLE-REQUEST</a></code> (and is more or less just a
|
||
thin wrapper around it) to select and call a
|
||
<a xmlns="http://www.w3.org/1999/xhtml" href="index.html#request-dispatch">handler</a> and send the output of this handler to
|
||
the client. Note that <code><a href="index.html#process-connection">PROCESS-CONNECTION</a></code> is
|
||
called once per connection and loops in case of a persistent
|
||
connection while <code><a href="index.html#process-request">PROCESS-REQUEST</a></code> is called anew
|
||
for each request.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
The return value of this function is ignored.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
Like <code xmlns=""><a href="index.html#process-connection">PROCESS-CONNECTION</a></code>, this is another function
|
||
the behaviour of which you should only modify if you really, really
|
||
know what you're doing.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="handle-request"></a>
|
||
[Generic function]
|
||
<br><b>handle-request</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">content
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This function is called by <code><a href="index.html#process-request">PROCESS-REQUEST</a></code> once
|
||
the request has been read and a <code><a href="index.html#request">REQUEST</a></code> object
|
||
has been created. Its job is to actually handle the request, i.e. to
|
||
return something to the client.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
The default method calls the
|
||
acceptor's <a href="index.html#request-dispatch">request dispatcher</a>, but you
|
||
can of course implement a different behaviour. The default method
|
||
also sets up <a href="index.html#logging">standard error handling</a> for
|
||
the <a href="index.html#request-dispatch">handler</a>.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
Might be a good place to bind or rebind special variables which can
|
||
then be accessed by your <a href="index.html#request-dispatch">handlers</a>.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="acceptor-dispatch-request"></a>
|
||
[Generic function]
|
||
<br><b>acceptor-dispatch-request</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">content
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This function is called to actually dispatch the request
|
||
once the standard logging and error handling has been set
|
||
up. <code><a href="index.html#acceptor">ACCEPTOR</a></code> subclasses implement
|
||
methods for this function in order to perform their own
|
||
request routing. If a method does not want to handle the
|
||
request, it is supposed to invoke <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.lispworks.com/documentation/HyperSpec/Body/f_call_n.htm">CALL-NEXT-METHOD</a>
|
||
so that the next <code><a href="index.html#acceptor">ACCEPTOR</a></code> in the
|
||
inheritance chain gets a chance to handle the request.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns="">
|
||
[Generic readers]<br><a class="none" name="cookies-in"></a><b>cookies-in</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">cookies
|
||
</clix:returns></i><br><a class="none" name="get-parameters"></a><b>get-parameters</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">get-parameters
|
||
</clix:returns></i><br><a class="none" name="header-in"></a><b>header-in</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">name request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><br><a class="none" name="headers-in"></a><b>headers-in</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">headers
|
||
</clix:returns></i><br><a class="none" name="post-parameters"></a><b>post-parameters</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">post-parameters
|
||
</clix:returns></i><br><a class="none" name="query-string"></a><b>query-string</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">query-string
|
||
</clix:returns></i><br><a class="none" name="remote-addr"></a><b>remote-addr</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">address
|
||
</clix:returns></i><br><a class="none" name="remote-port"></a><b>remote-port</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">port
|
||
</clix:returns></i><br><a class="none" name="local-addr"></a><b>local-addr</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">address
|
||
</clix:returns></i><br><a class="none" name="local-port"></a><b>local-port</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">port
|
||
</clix:returns></i><br><a class="none" name="request-acceptor"></a><b>request-acceptor</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:returns></i><br><a class="none" name="request-method"></a><b>request-method</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">method
|
||
</clix:returns></i><br><a class="none" name="request-uri"></a><b>request-uri</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">uri
|
||
</clix:returns></i><br><a class="none" name="server-protocol"></a><b>server-protocol</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">protocol
|
||
</clix:returns></i><br><a class="none" name="script-name"></a><b>script-name</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><br><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
These are various generic readers which are used
|
||
to read information about a <code><a href="index.html#request">REQUEST</a></code> object. If you are writing a
|
||
<a xmlns="http://www.w3.org/1999/xhtml" href="index.html#request-dispatch">handler</a>, you should <em xmlns="http://www.w3.org/1999/xhtml">not</em> use these readers but instead utilize the
|
||
corresponding functions with an asterisk at the end of their name,
|
||
also listed in this section. These generic readers are only
|
||
exported for users who want to create their own subclasses of
|
||
<code><a href="index.html#request">REQUEST</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
|
||
|
||
<h4 xmlns=""><a name="replies">Reply objects</a></h4>
|
||
|
||
For each incoming request, the <a href="index.html#acceptors">acceptor</a>
|
||
(in <code xmlns=""><a href="index.html#process-connection">PROCESS-CONNECTION</a></code>) creates
|
||
a <code xmlns=""><a href="index.html#reply">REPLY</a></code> object and makes it available
|
||
to <a href="index.html#request-dispatch">handlers</a> via the special variable
|
||
<code xmlns=""><a href="index.html#*reply*">*REPLY*</a></code>. This object contains all relevant
|
||
information (except for the content body) about the reply that will be
|
||
sent to the client and this section collects the functions which can
|
||
be used to query and modify such an object. In all function
|
||
where <code xmlns=""><i>reply</i></code> is an optional or keyword parameter,
|
||
the default is <code xmlns=""><a href="index.html#*reply*">*REPLY*</a></code>.
|
||
|
||
<p>
|
||
If you need more fine-grained control over the behaviour of reply
|
||
objects, you can subclass <code xmlns=""><a href="index.html#reply">REPLY</a></code> and initialize
|
||
the <a href="index.html#acceptor-reply-class"><code>REPLY-CLASS</code></a>
|
||
slot of the <code xmlns=""><a href="index.html#acceptor">ACCEPTOR</a></code> class accordingly. The
|
||
acceptor will generate reply objects of the class named by this
|
||
slot.
|
||
</p>
|
||
|
||
<p xmlns=""><a class="none" name="reply"></a>
|
||
[Standard class]
|
||
<br><b>reply</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Objects of this class hold all the information about an
|
||
outgoing reply. They are created automatically by
|
||
Hunchentoot and can be accessed and modified by the
|
||
corresponding <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#request-dispatch">handler</a>.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
You should not mess with the slots of these objects directly, but you
|
||
can subclass <code xmlns=""><a href="index.html#reply">REPLY</a></code> in order to implement your own behaviour. See the
|
||
<a href="index.html#acceptor-reply-class"><code>:reply-class</code></a> initarg
|
||
of the <code xmlns=""><a href="index.html#acceptor">ACCEPTOR</a></code> class.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*reply*"></a>
|
||
[Special variable]
|
||
<br><b>*reply*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
The current <code><a href="index.html#reply">REPLY</a></code> object in the context of a request.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="header-out"></a>
|
||
[Accessor]
|
||
<br><b>header-out</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">name
|
||
<tt>&optional
|
||
</tt> reply
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">string
|
||
</clix:returns></i><br><tt>(setf (</tt><b>header-out</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">name
|
||
<tt>&optional
|
||
</tt> reply
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
<code><a href="index.html#header-out">HEADER-OUT</a></code> returns the outgoing http
|
||
header named by the keyword <code><i>name</i></code> if
|
||
there is one, otherwise <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>. <code xmlns="http://www.w3.org/1999/xhtml">SETF</code>
|
||
of <code><a href="index.html#header-out">HEADER-OUT</a></code> changes the current value
|
||
of the header named <code><i>name</i></code>. If no header
|
||
named <code><i>name</i></code> exists, it is created. For
|
||
backwards compatibility, <code><i>name</i></code> can also
|
||
be a string in which case the association between a header
|
||
and its name is case-insensitive.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
Note that the header 'Set-Cookie' cannot be queried by
|
||
<code xmlns=""><a href="index.html#header-out">HEADER-OUT</a></code> and must not be set by
|
||
<code>SETF</code> of <code xmlns=""><a href="index.html#header-out">HEADER-OUT</a></code>. See
|
||
also <code xmlns=""><a href="index.html#headers-out*">HEADERS-OUT*</a></code>,
|
||
<code xmlns=""><a href="index.html#content-type*">CONTENT-TYPE*</a></code>,
|
||
<code xmlns=""><a href="index.html#content-length*">CONTENT-LENGTH*</a></code>,
|
||
<code xmlns=""><a href="index.html#cookies-out*">COOKIES-OUT*</a></code>, and
|
||
<code xmlns=""><a href="index.html#cookie-out">COOKIE-OUT</a></code>.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="headers-out*"></a>
|
||
[Function]
|
||
<br><b>headers-out*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> reply
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">alist
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">Returns an alist of the outgoing headers associated with the
|
||
<code><a href="index.html#reply">REPLY</a></code> object <code><i>reply</i></code>. See also <code><a href="index.html#header-out">HEADER-OUT</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="content-length*"></a>
|
||
[Accessor]
|
||
<br><b>content-length*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> reply
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">content-length
|
||
</clix:returns></i><br><tt>(setf (</tt><b>content-length*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> reply
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
The outgoing 'Content-Length' http header of <code><i>reply</i></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="content-type*"></a>
|
||
[Accessor]
|
||
<br><b>content-type*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> reply
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">content-type
|
||
</clix:returns></i><br><tt>(setf (</tt><b>content-type*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> reply
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
The outgoing 'Content-Type' http header of <code><i>reply</i></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="cookie-out"></a>
|
||
[Function]
|
||
<br><b>cookie-out</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">name
|
||
<tt>&optional
|
||
</tt> reply
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the current value of the outgoing <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#cookies">cookie</a> named
|
||
<code><i>name</i></code>. Search is case-sensitive.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="cookies-out*"></a>
|
||
[Accessor]
|
||
<br><b>cookies-out*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> reply
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">alist
|
||
</clix:returns></i><br><tt>(setf (</tt><b>cookies-out*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> reply
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns or sets an alist of the outgoing <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#cookies">cookies</a> associated with the
|
||
<code><a href="index.html#reply">REPLY</a></code> object
|
||
<code><i>reply</i></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="return-code*"></a>
|
||
[Accessor]
|
||
<br><b>return-code*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> reply
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">return-code
|
||
</clix:returns></i><br><tt>(setf (</tt><b>return-code*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> reply
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Gets or sets the http return code of
|
||
<code><i>reply</i></code>. The return code of each
|
||
<code><a href="index.html#reply">REPLY</a></code> object is initially set to
|
||
<code><a href="index.html#+http-ok+">+HTTP-OK+</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="send-headers"></a>
|
||
[Function]
|
||
<br><b>send-headers</b> <i></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">stream</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Sends the initial status line and all headers as determined
|
||
by the <code><a href="index.html#reply">REPLY</a></code>
|
||
object <code><a href="index.html#*reply*">*REPLY*</a></code>. Returns
|
||
a <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_b.htm#binary">binary</a>
|
||
stream to which the body of the reply can be written. Once
|
||
this function has been called, further changes
|
||
to <code><a href="index.html#*reply*">*REPLY*</a></code> don't have any effect.
|
||
Also, automatic handling of errors (i.e. sending the
|
||
corresponding status code to the browser, etc.) is turned
|
||
off for this request and functions
|
||
like <code><a href="index.html#redirect">REDIRECT</a></code> or
|
||
to <code><a href="index.html#abort-request-handler">ABORT-REQUEST-HANDLER</a></code> won't have the
|
||
desired effect once the headers are sent.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
If your handlers return the full body as a string or as an
|
||
array of octets, you should <em>not</em> call this function.
|
||
If a handler calls <code xmlns=""><a href="index.html#send-headers">SEND-HEADERS</a></code> , its
|
||
return value is ignored.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="reply-external-format*"></a>
|
||
[Accessor]
|
||
<br><b>reply-external-format*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> reply
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">external-format
|
||
</clix:returns></i><br><tt>(setf (</tt><b>reply-external-format*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> reply
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Gets or sets the external format of <code><i>reply</i></code> which is used for character output.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*default-content-type*"></a>
|
||
[Special variable]
|
||
<br><b>*default-content-type*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
The default content-type header which is returned to the client.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns="">
|
||
[Constants]<br><b>+http-continue+</b><br><b>+http-switching-protocols+</b><br><b>+http-ok+</b><br><b>+http-created+</b><br><b>+http-accepted+</b><br><b>+http-non-authoritative-information+</b><br><b>+http-no-content+</b><br><b>+http-reset-content+</b><br><b>+http-partial-content+</b><br><b>+http-multi-status+</b><br><b>+http-multiple-choices+</b><br><b>+http-moved-permanently+</b><br><b>+http-moved-temporarily+</b><br><b>+http-see-other+</b><br><b>+http-not-modified+</b><br><b>+http-use-proxy+</b><br><b>+http-temporary-redirect+</b><br><b>+http-bad-request+</b><br><b>+http-authorization-required+</b><br><b>+http-payment-required+</b><br><b>+http-forbidden+</b><br><b>+http-not-found+</b><br><b>+http-method-not-allowed+</b><br><b>+http-not-acceptable+</b><br><b>+http-proxy-authentication-required+</b><br><b>+http-request-time-out+</b><br><b>+http-conflict+</b><br><b>+http-gone+</b><br><b>+http-length-required+</b><br><b>+http-precondition-failed+</b><br><b>+http-request-entity-too-large+</b><br><b>+http-request-uri-too-large+</b><br><b>+http-unsupported-media-type+</b><br><b>+http-requested-range-not-satisfiable+</b><br><b>+http-expectation-failed+</b><br><b>+http-failed-dependency+</b><br><b>+http-internal-server-error+</b><br><b>+http-not-implemented+</b><br><b>+http-bad-gateway+</b><br><b>+http-service-unavailable+</b><br><b>+http-gateway-time-out+</b><br><b>+http-version-not-supported+</b><br><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
The values of these constants are 100, 101, 200, 201, 202,
|
||
203, 204, 205, 206, 207, 300, 301, 302, 303, 304, 305, 307,
|
||
400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411,
|
||
412, 413, 414, 415, 416, 417, 424, 500, 501, 502, 503, 504,
|
||
and 505. See <code><a href="index.html#return-code">RETURN-CODE</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns="">
|
||
[Generic readers]<br><a class="none" name="content-length"></a><b>content-length</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">reply
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">content-length
|
||
</clix:returns></i><br><a class="none" name="content-type"></a><b>content-type</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">reply
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">content-type
|
||
</clix:returns></i><br><a class="none" name="headers-out"></a><b>headers-out</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">reply
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">headers-out
|
||
</clix:returns></i><br><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
These are various generic readers which are used
|
||
to read information about a <code><a href="index.html#reply">REPLY</a></code> object. If you are writing a
|
||
<a xmlns="http://www.w3.org/1999/xhtml" href="index.html#request-dispatch">handler</a>, you should <em xmlns="http://www.w3.org/1999/xhtml">not</em> use these readers but instead utilize the
|
||
corresponding functions with an asterisk at the end of their name,
|
||
also listed in this section. These generic readers are only
|
||
exported for users who want to create their own subclasses of
|
||
<code><a href="index.html#reply">REPLY</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns="">
|
||
[Generic accessors]<br><a class="none" name="cookies-out"></a><b>cookies-out</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">reply
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><br><tt>(setf (</tt><b>cookies-out</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">reply
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><br><a class="none" name="return-code"></a><b>return-code</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">reply
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><br><tt>(setf (</tt><b>return-code</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">reply
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><br><a class="none" name="reply-external-format"></a><b>reply-external-format</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">reply
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><br><tt>(setf (</tt><b>reply-external-format</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">reply
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><br><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
These are various generic accessors which are
|
||
used to query and modify a <code><a href="index.html#reply">REPLY</a></code> objects. If
|
||
you are writing a
|
||
<a xmlns="http://www.w3.org/1999/xhtml" href="index.html#request-dispatch">handler</a>, you should <em xmlns="http://www.w3.org/1999/xhtml">not</em> use these
|
||
accessors but instead utilize the corresponding functions with an
|
||
asterisk at the end of their name, also listed in this section.
|
||
These generic accessors are only exported for users who want to
|
||
create their own subclasses of
|
||
<code><a href="index.html#reply">REPLY</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
|
||
|
||
|
||
<h4 xmlns=""><a name="sessions">Sessions</a></h4>
|
||
Hunchentoot supports <em>sessions</em>: Once a <a href="index.html#request-dispatch">request
|
||
handler</a> has called <code xmlns=""><a href="index.html#start-session">START-SESSION</a></code>, Hunchentoot
|
||
uses either cookies or (if the client doesn't send the cookies
|
||
back) <a href="index.html#*rewrite-for-session-urls*">rewrites URLs</a> to keep
|
||
track of this client, i.e. to provide a kind of 'state' for the
|
||
stateless http protocol. The session associated with the client is a
|
||
<a href="index.html#session">CLOS object</a> which can be used
|
||
to <a href="index.html#session-value">store arbitrary data</a> between requests.
|
||
<p>
|
||
Hunchentoot makes some reasonable effort to prevent eavesdroppers from
|
||
hijacking sessions (see below), but this should not be considered
|
||
really secure. Don't store sensitive data in sessions and rely solely
|
||
on the session mechanism as a safeguard against malicious users who
|
||
want to get at this data!
|
||
</p>
|
||
<p>
|
||
For each request there's one <code xmlns=""><a href="index.html#session">SESSION</a></code> object which is accessible to the
|
||
<a href="index.html#handler">handler</a> via the special
|
||
variable <code xmlns=""><a href="index.html#*session*">*SESSION*</a></code>. This object holds all the
|
||
information available about the session and can be accessed with the
|
||
functions described in this chapter. Note that the internal structure
|
||
of <code xmlns=""><a href="index.html#session">SESSION</a></code> objects should be considered opaque
|
||
and may change in future releases of Hunchentoot.
|
||
</p>
|
||
<p>
|
||
Sessions are automatically <a href="index.html#session-verify">verified</a> for
|
||
validity and age when the <code xmlns=""><a href="index.html#request">REQUEST</a></code> object is
|
||
instantiated, i.e. if <code xmlns=""><a href="index.html#*session*">*SESSION*</a></code> is not NIL then
|
||
this session is valid (as far as Hunchentoot is concerned) and
|
||
not <a href="index.html#session-too-old-p">too old</a>. Old sessions
|
||
are <a href="index.html#session-gc">automatically removed</a>.
|
||
</p>
|
||
<p>
|
||
Hunchentoot also provides a <code xmlns=""><a href="index.html#regenerate-session-cookie-value">REGENERATE-SESSION-COOKIE-VALUE</a></code>
|
||
function that creates a new cookie value. This helps to prevent against
|
||
<a href="https://www.owasp.org/index.php/Session_fixation">session fixation
|
||
attacks</a>, and should be used when a user logs in according to the application.
|
||
</p>
|
||
|
||
<p xmlns=""><a class="none" name="session"></a>
|
||
[Standard class]
|
||
<br><b>session</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
<code><a href="index.html#session">SESSION</a></code> objects are
|
||
automatically maintained by Hunchentoot. They should not be created
|
||
explicitly with <code xmlns="http://www.w3.org/1999/xhtml">MAKE-INSTANCE</code> but implicitly
|
||
with <code><a href="index.html#start-session">START-SESSION</a></code> and they should be treated as
|
||
opaque objects.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
You can ignore Hunchentoot's <code xmlns=""><a href="index.html#session">SESSION</a></code> objects and
|
||
<a href="index.html#session-behaviour">implement your own sessions</a> if you provide corresponding methods for
|
||
<code xmlns=""><a href="index.html#session-cookie-value">SESSION-COOKIE-VALUE</a></code>
|
||
and <code xmlns=""><a href="index.html#session-verify">SESSION-VERIFY</a></code>.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="start-session"></a>
|
||
[Function]
|
||
<br><b>start-session</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">session
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the current <code><a href="index.html#session">SESSION</a></code>
|
||
object. If there is no current session, creates one and updates the
|
||
corresponding data structures. In this case the function will also
|
||
send a session cookie to the browser.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="session-value"></a>
|
||
[Accessor]
|
||
<br><b>session-value</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">symbol
|
||
<tt>&optional
|
||
</tt> session
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">value, present-p
|
||
</clix:returns></i><br><tt>(setf (</tt><b>session-value</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">symbol
|
||
<tt>&optional
|
||
</tt> session
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This accessor can be used to associate arbitrary data with the the
|
||
symbol <code><i>symbol</i></code> in the <code><a href="index.html#session">SESSION</a></code>
|
||
object <code><i>session</i></code>. <code><i>present-p</i></code> is
|
||
true if such data was found, otherwise <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>. The default
|
||
value for <code><i>session</i></code> is
|
||
<code><a href="index.html#*session*">*SESSION*</a></code>.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
If <code>SETF</code> of <code xmlns=""><a href="index.html#session-value">SESSION-VALUE</a></code> is called
|
||
with <code xmlns=""><i>session</i></code> being <code>NIL</code> then a
|
||
session is automatically instantiated
|
||
with <code xmlns=""><a href="index.html#start-session">START-SESSION</a></code>.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="delete-session-value"></a>
|
||
[Function]
|
||
<br><b>delete-session-value</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">symbol
|
||
<tt>&optional
|
||
</tt> session
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">|
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Removes the value associated with
|
||
<code><i>symbol</i></code> from
|
||
<code><i>session</i></code> if there is one.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*session*"></a>
|
||
[Special variable]
|
||
<br><b>*session*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
The current session while in the context of a request, or
|
||
<code xmlns="http://www.w3.org/1999/xhtml">NIL</code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="remove-session"></a>
|
||
[Function]
|
||
<br><b>remove-session</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">session
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">|
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Completely removes the <code><a href="index.html#session">SESSION</a></code> object
|
||
<code><i>session</i></code> from Hunchentoot's
|
||
internal <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#session-db">session database</a>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="reset-sessions"></a>
|
||
[Function]
|
||
<br><b>reset-sessions</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">|
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Removes <em xmlns="http://www.w3.org/1999/xhtml">all</em> stored sessions of
|
||
<code><i>acceptor</i></code>. The default for
|
||
<code><i>acceptor</i></code> is
|
||
<code><a href="index.html#*acceptor*">*ACCEPTOR*</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="regenerate-session-cookie-value"></a>
|
||
[Function]
|
||
<br><b>regenerate-session-cookie-value</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">session
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">cookie
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Regenerates the session cookie value. This should be used
|
||
when a user logs in according to the application to prevent
|
||
against session fixation attacks. The cookie value being
|
||
dependent on ID, USER-AGENT, REMOTE-ADDR, START, and
|
||
*SESSION-SECRET*, the only value we can change is START to
|
||
regenerate a new value. Since we're generating a new cookie,
|
||
it makes sense to have the session being restarted, in
|
||
time. That said, because of this fact, calling this function
|
||
twice in the same second will regenerate twice the same
|
||
value.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*rewrite-for-session-urls*"></a>
|
||
[Special variable]
|
||
<br><b>*rewrite-for-session-urls*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Whether HTML pages should possibly be rewritten for cookie-less
|
||
session-management.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*content-types-for-url-rewrite*"></a>
|
||
[Special variable]
|
||
<br><b>*content-types-for-url-rewrite*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
The content types for which url-rewriting is OK. See
|
||
<code><a href="index.html#*rewrite-for-session-urls*">*REWRITE-FOR-SESSION-URLS*</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*use-remote-addr-for-sessions*"></a>
|
||
[Special variable]
|
||
<br><b>*use-remote-addr-for-sessions*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Whether the client's remote IP (as returned by <code><a href="index.html#real-remote-addr">REAL-REMOTE-ADDR</a></code>)
|
||
should be encoded into the session string. If this value is true, a
|
||
session will cease to be accessible if the client's remote IP changes.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
This might for example be an issue if the client uses a proxy server
|
||
which doesn't send correct 'X-Forwarded-For' headers.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="session-remote-addr"></a>
|
||
[Generic function]
|
||
<br><b>session-remote-addr</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">session
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">remote-addr
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
The remote IP address of the client when this session was started (as
|
||
returned by <code><a href="index.html#real-remote-addr">REAL-REMOTE-ADDR</a></code>).
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*use-user-agent-for-sessions*"></a>
|
||
[Special variable]
|
||
<br><b>*use-user-agent-for-sessions*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">Whether the 'User-Agent' header should
|
||
be encoded into the session string. If this value is true, a session
|
||
will cease to be accessible if the client sends a different
|
||
'User-Agent' header.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="session-user-agent"></a>
|
||
[Generic function]
|
||
<br><b>session-user-agent</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">session
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">user-agent
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
The incoming 'User-Agent' header that
|
||
was sent when this session was created.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="session-max-time"></a>
|
||
[Generic accessor]
|
||
<br><b>session-max-time</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">session
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">max-time
|
||
</clix:returns></i><br><tt>(setf (</tt><b>session-max-time</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">session
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Gets or sets the time (in seconds) after
|
||
which <code><i>session</i></code> expires if it's not used.
|
||
</clix:description></blockquote></p>
|
||
|
||
|
||
<p xmlns=""><a class="none" name="*session-max-time*"></a>
|
||
[Special variable]
|
||
<br><b>*session-max-time*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
The default time (in seconds) after which a session times out.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*session-gc-frequency*"></a>
|
||
[Special variable]
|
||
<br><b>*session-gc-frequency*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
A session GC (see function <code><a href="index.html#session-gc">SESSION-GC</a></code>) will happen every
|
||
<code><a href="index.html#*session-gc-frequency*">*SESSION-GC-FREQUENCY*</a></code> requests (counting only
|
||
requests which create a new session) if this variable is
|
||
not <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>. See <code><a href="index.html#session-created">SESSION-CREATED</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="session-gc"></a>
|
||
[Function]
|
||
<br><b>session-gc</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">|
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Removes sessions from the current session database which are
|
||
too old - see <code><a href="index.html#session-too-old-p">SESSION-TOO-OLD-P</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="session-too-old-p"></a>
|
||
[Function]
|
||
<br><b>session-too-old-p</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">session
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">generalized-boolean
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns true if the <code><a href="index.html#session">SESSION</a></code> object <code><i>session</i></code> has not been active in
|
||
the last <code xmlns="http://www.w3.org/1999/xhtml">(session-max-time session)</code> seconds.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="session-id"></a>
|
||
[Generic function]
|
||
<br><b>session-id</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">session
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">session-id
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
The unique ID (an INTEGER) of the session.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="session-start"></a>
|
||
[Generic function]
|
||
<br><b>session-start</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">session
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">universal-time
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
The time this session was started.
|
||
</clix:description></blockquote></p>
|
||
|
||
|
||
|
||
<h4 xmlns=""><a name="session-behaviour">Customizing session behaviour</a></h4>
|
||
|
||
For everyday session usage, you will probably just
|
||
use <code xmlns=""><a href="index.html#start-session">START-SESSION</a></code>,
|
||
<code xmlns=""><a href="index.html#session-value">SESSION-VALUE</a></code>,
|
||
and maybe <code xmlns=""><a href="index.html#delete-session-value">DELETE-SESSION-VALUE</a></code>
|
||
and <code xmlns=""><a href="index.html#*session*">*SESSION*</a></code>. However, there are two ways to
|
||
customize the way Hunchentoot maintains sessions.
|
||
<p>
|
||
One way is to mostly leave the session mechanism intact but to tweak
|
||
it a bit:
|
||
<ul>
|
||
<li>The publicly visible part of a session is encoded using a
|
||
<a href="index.html#*session-secret*">secret</a> which you can set yourself.</li>
|
||
<li>And it is stored using a cookie (or GET
|
||
parameter) <a href="index.html#session-cookie-name">name</a> that you can
|
||
override.</li>
|
||
<li>Each session receives a <a href="index.html#next-session-id">new ID</a> when
|
||
it is created and you can implement a more robust way to do that.</li>
|
||
<li>You can arrange to be called whenever a session
|
||
is <a href="index.html#session-created">created</a> to trigger some action. You
|
||
might also do this to invent your own
|
||
session <a href="index.html#session-gc">garbage collection</a>.</li>
|
||
<li>By default, all sessions are stored in a global alist in memory.
|
||
You can't change the alist part, but you can distribute your sessions
|
||
over different <a href="index.html#session-db">"databases"</a>.</li>
|
||
<li>By default, every operation which modifies sessions or one of the
|
||
session databases is guarded by a global lock, but you can arrange to
|
||
<a href="index.html#session-db-lock">provide</a> different locks for this.</li>
|
||
</ul>
|
||
</p>
|
||
<p>
|
||
The other way to customize Hunchentoot's sessions is to completely
|
||
replace them. This is actually pretty easy: Create your own class to
|
||
store state (which doesn't have to and probably shouldn't inherit
|
||
from <code xmlns=""><a href="index.html#session">SESSION</a></code>) and implement methods for
|
||
<code xmlns=""><a href="index.html#session-verify">SESSION-VERIFY</a></code>
|
||
and <code xmlns=""><a href="index.html#session-cookie-value">SESSION-COOKIE-VALUE</a></code> - that's it.
|
||
Hunchentoot will continue to use cookies and/or to rewrite URLs to
|
||
keep track of session state and it will store "the current session"
|
||
(whatever that is in your implementation)
|
||
in <code xmlns=""><a href="index.html#*session*">*SESSION*</a></code>. Everything else (like persisting
|
||
sessions, GC, getting and setting values) you'll have to take care of
|
||
yourself and the other session functions
|
||
(like <code xmlns=""><a href="index.html#start-session">START-SESSION</a></code> or
|
||
<code xmlns=""><a href="index.html#session-value">SESSION-VALUE</a></code>) won't work anymore. (Almost)
|
||
total freedom, but a lot of responsibility as well... :)
|
||
</p>
|
||
|
||
<p xmlns=""><a class="none" name="*session-secret*"></a>
|
||
[Special variable]
|
||
<br><b>*session-secret*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
A random ASCII string that's used to encode the public
|
||
session data. This variable is initially unbound and will
|
||
be set (using <code><a href="index.html#reset-session-secret">RESET-SESSION-SECRET</a></code>) the
|
||
first time a session is created, if necessary. You can
|
||
prevent this from happening if you set the value yourself
|
||
before starting <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#acceptors">acceptors</a>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="reset-session-secret"></a>
|
||
[Function]
|
||
<br><b>reset-session-secret</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">secret
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Sets <code><a href="index.html#*session-secret*">*SESSION-SECRET*</a></code> to a
|
||
new random value. All old sessions will cease to be valid.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="session-cookie-name"></a>
|
||
[Generic function]
|
||
<br><b>session-cookie-name</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">name
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the name (a string) of the cookie (or
|
||
the GET parameter) which is used to store a session on the client
|
||
side. The default is to use the
|
||
string <code xmlns="http://www.w3.org/1999/xhtml">"hunchentoot-session"</code>, but you can
|
||
specialize this function if you want another name.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="session-created"></a>
|
||
[Generic function]
|
||
<br><b>session-created</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor new-session
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This function is called whenever a new session
|
||
has been created. There's a default method which might trigger
|
||
a <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#session-gc">session GC</a> based on the value of
|
||
<code><a href="index.html#*session-gc-frequency*">*SESSION-GC-FREQUENCY*</a></code>.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
The return value is ignored.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="next-session-id"></a>
|
||
[Generic function]
|
||
<br><b>next-session-id</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">id
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the next sequential session ID, an
|
||
integer, which should be unique per session. The default method uses
|
||
a simple global counter and isn't guarded by a lock. For a
|
||
high-performance production environment you might consider using a
|
||
more robust implementation.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="session-db"></a>
|
||
[Generic accessor]
|
||
<br><b>session-db</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">database
|
||
</clix:returns></i><br><tt>(setf (</tt><b>session-db</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
</clix:lambda-list></i><tt>) <i>new-value</i>)</tt><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns the current session database which is an
|
||
alist where each car is a session's ID and the cdr is the
|
||
corresponding <code><a href="index.html#session">SESSION</a></code> object itself. The default
|
||
is to use a global list for all acceptors.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="session-db-lock"></a>
|
||
[Generic function]
|
||
<br><b>session-db-lock</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">acceptor
|
||
<tt>&key
|
||
</tt> whole-db-p
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">lock
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
A function which returns a lock that will be
|
||
used to prevent concurrent access to sessions. The first argument
|
||
will be the <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#acceptors">acceptor</a> that handles the
|
||
current <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#requests">request</a>, the second argument is true
|
||
if the whole (current) session database is modified. If it
|
||
is <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>, only one existing session in the database is
|
||
modified.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
This function can return <code>NIL</code> which means that sessions or
|
||
session databases will be modified without a lock held (for example
|
||
for single-threaded environments). The default is to always return a
|
||
global lock (ignoring the <code xmlns=""><i>acceptor</i></code> argument) for
|
||
Lisps that support threads and <code>NIL</code> otherwise.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="session-verify"></a>
|
||
[Generic function]
|
||
<br><b>session-verify</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">request
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">session-or-nil
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Tries to get a session identifier from the cookies
|
||
(or alternatively from the GET parameters) sent by the client (see
|
||
<code><a href="index.html#session-cookie-name">SESSION-COOKIE-NAME</a></code>
|
||
and <code><a href="index.html#session-cookie-value">SESSION-COOKIE-VALUE</a></code>). This identifier is
|
||
then checked for validity against the <code><a href="index.html#request">REQUEST</a></code>
|
||
object
|
||
<code><i>request</i></code>. On success the corresponding session object (if not too
|
||
old) is returned (and updated). Otherwise <code xmlns="http://www.w3.org/1999/xhtml">NIL</code> is returned.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
A default method is provided and you only need to write your own one
|
||
if you want to maintain your own sessions.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="session-cookie-value"></a>
|
||
[Generic function]
|
||
<br><b>session-cookie-value</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">session
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">string
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns a string which can be used to safely
|
||
restore the session <code><i>session</i></code> if as session has
|
||
already been established. This is used as the value stored in the
|
||
session cookie or in the corresponding GET parameter and verified
|
||
by <code><a href="index.html#session-verify">SESSION-VERIFY</a></code>.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
A default
|
||
method is provided and there's no reason to change it unless you
|
||
want to use your own session objects.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
|
||
|
||
<h4 xmlns=""><a name="cookies">Cookies</a></h4>
|
||
|
||
Outgoing cookies are stored in the request's <code xmlns=""><a href="index.html#reply">REPLY</a></code>
|
||
object (see <code xmlns=""><a href="index.html#cookie-out">COOKIE-OUT</a></code>
|
||
and <code xmlns=""><a href="index.html#cookies-out*">COOKIES-OUT*</a></code>). They are CLOS objects
|
||
defined like this:
|
||
|
||
<pre>(defclass cookie ()
|
||
((name :initarg :name
|
||
:reader <a class="noborder" name="cookie-name">cookie-name</a>
|
||
:type string
|
||
:documentation "The name of the cookie - a string.")
|
||
(value :initarg :value
|
||
:accessor <a class="noborder" name="cookie-value">cookie-value</a>
|
||
:initform ""
|
||
:documentation "The value of the cookie. Will be URL-encoded when sent to the browser.")
|
||
(expires :initarg :expires
|
||
:initform nil
|
||
:accessor <a class="noborder" name="cookie-expires">cookie-expires</a>
|
||
:documentation "The time (a universal time) when the cookie expires (or NIL).")
|
||
(max-age :initarg :max-age
|
||
:initform nil
|
||
:accessor <a class="noborder" name="cookie-max-age">cookie-max-age</a>
|
||
:documentation "The time delta (in seconds) after which the cookie expires (or NIL).")
|
||
(path :initarg :path
|
||
:initform nil
|
||
:accessor <a class="noborder" name="cookie-path">cookie-path</a>
|
||
:documentation "The path this cookie is valid for (or NIL).")
|
||
(domain :initarg :domain
|
||
:initform nil
|
||
:accessor <a class="noborder" name="cookie-domain">cookie-domain</a>
|
||
:documentation "The domain this cookie is valid for (or NIL).")
|
||
(secure :initarg :secure
|
||
:initform nil
|
||
:accessor <a class="noborder" name="cookie-secure">cookie-secure</a>
|
||
:documentation "A generalized boolean denoting whether this is a secure cookie.")
|
||
(http-only :initarg :http-only
|
||
:initform nil
|
||
:accessor <a class="noborder" name="cookie-http-only">cookie-http-only</a>
|
||
:documentation "A generalized boolean denoting whether this is a <a href="http://msdn2.microsoft.com/en-us/library/ms533046.aspx">HttpOnly</a> cookie.")))
|
||
</pre>
|
||
|
||
The <a href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_r.htm#reader">reader</a>
|
||
<code xmlns=""><a href="index.html#cookie-name">COOKIE-NAME</a></code> and
|
||
the <a href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_a.htm#accessor">accessors</a>
|
||
<code xmlns=""><a href="index.html#cookie-value">COOKIE-VALUE</a></code>, <code xmlns=""><a href="index.html#cookie-expires">COOKIE-EXPIRES</a></code>, <code xmlns=""><a href="index.html#cookie-max-age">COOKIE-MAX-AGE</a></code>,
|
||
<code xmlns=""><a href="index.html#cookie-path">COOKIE-PATH</a></code>, <code xmlns=""><a href="index.html#cookie-domain">COOKIE-DOMAIN</a></code>, <code xmlns=""><a href="index.html#cookie-secure">COOKIE-SECURE</a></code>,
|
||
and <code xmlns=""><a href="index.html#cookie-http-only">COOKIE-HTTP-ONLY</a></code> are all exported from
|
||
the <code>HUNCHENTOOT</code> package. For now, the class name itself is <em>not</em> exported.
|
||
|
||
<p xmlns=""><a class="none" name="set-cookie"></a>
|
||
[Function]
|
||
<br><b>set-cookie</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
name <tt>&key</tt> value expires path
|
||
domain secure http-only reply
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">cookie</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Creates a <code xmlns="http://www.w3.org/1999/xhtml">COOKIE</code> object from the parameters
|
||
provided to this function and adds it to the outgoing cookies
|
||
of the <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#replies"><code>REPLY</code> object</a>
|
||
<code><i>reply</i></code>. If a cookie with the same name
|
||
(case-sensitive) already exists, it is replaced. The default
|
||
for <code><i>reply</i></code>
|
||
is <code><a href="index.html#*reply*">*REPLY*</a></code>. The default
|
||
for <code><i>value</i></code> is the empty string.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="set-cookie*"></a>
|
||
[Function]
|
||
<br><b>set-cookie*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">cookie <tt>&optional</tt> reply</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">cookie</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Adds the <code xmlns="http://www.w3.org/1999/xhtml">COOKIE</code> object <code><i>cookie</i></code>
|
||
to the outgoing cookies of
|
||
the <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#replies"><code>REPLY</code> object</a>
|
||
<code><i>reply</i></code>. If a cookie with the same name
|
||
(case-sensitive) already exists, it is replaced. The default
|
||
for <code><i>reply</i></code> is <code><a href="index.html#*reply*">*REPLY*</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
|
||
<h4 xmlns=""><a name="logging">Logging</a></h4>
|
||
Hunchentoot can log accesses and diagnostic messages to two
|
||
separate destinations, which can be either files in the file
|
||
system or streams. Logging can also be disabled by setting the
|
||
<clix:code xmlns:clix="http://bknr.net/clixdoc">ACCESS-LOG-DESTINATION</clix:code> and
|
||
<clix:code xmlns:clix="http://bknr.net/clixdoc">MESSAGE-LOG-DESTINATION</clix:code> slots in the
|
||
<code xmlns=""><a href="index.html#acceptor">ACCEPTOR</a></code> to <code>NIL</code>. The two
|
||
slots can be initialized by providing the
|
||
:ACCESS-LOG-DESTINATION and :MESSAGE-LOG-DESTINATION
|
||
initialization arguments when creating the acceptor or set by
|
||
setting the slots through its
|
||
<code xmlns=""><a href="index.html#acceptor-message-log-destination">ACCEPTOR-MESSAGE-LOG-DESTINATION</a></code> and
|
||
<code xmlns=""><a href="index.html#acceptor-access-log-destination">ACCEPTOR-ACCESS-LOG-DESTINATION</a></code> accessors.
|
||
<p>
|
||
When the path for the message or accept log is set to a
|
||
variable holding an output stream, hunchentoots writes
|
||
corresponding log entries to that stream. By default,
|
||
Hunchentoot logs to *STANDARD-ERROR*.
|
||
</p>
|
||
<p>
|
||
Access logging is done in a format similar to what
|
||
the Apache web server can write so that logfile analysis using
|
||
standard tools is possible. Errors during request processing are
|
||
logged to a separate file.
|
||
</p>
|
||
<p>
|
||
The standard logging mechanism is deliberately simple and slow. The
|
||
log files are opened for each log entry and closed again after
|
||
writing, and access to them is protected by a global lock. Derived
|
||
acceptor classes can implement methods for the
|
||
<code xmlns=""><a href="index.html#acceptor-log-message">ACCEPTOR-LOG-MESSAGE</a></code> and
|
||
<code xmlns=""><a href="index.html#acceptor-log-access">ACCEPTOR-LOG-ACCESS</a></code> generic functions in order to
|
||
log differently (e.g. to a central logging server or in a different
|
||
file format.
|
||
</p>
|
||
<p>
|
||
Errors happening within a <a href="index.html#request-dispatch">handler</a>
|
||
which are not caught by the handler itself are handled by
|
||
Hunchentoot by logging them to the established
|
||
<code xmlns=""><a href="index.html#acceptor-message-log-destination">ACCEPTOR-MESSAGE-LOG-DESTINATION</a></code>.
|
||
</p>
|
||
|
||
<p xmlns=""><a class="none" name="log-message*"></a>
|
||
[Function]
|
||
<br><b>log-message*</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">log-level format-string
|
||
<tt>&rest
|
||
</tt> format-arguments
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Convenience function which calls the message
|
||
logger of the current acceptor (if there is one) with the same
|
||
arguments it accepts. Returns <code xmlns="http://www.w3.org/1999/xhtml">NIL</code> if there is no message
|
||
logger or whatever the message logger returns.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
This is the function which Hunchentoot itself uses to log errors it
|
||
catches during request processing.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*log-lisp-errors-p*"></a>
|
||
[Special variable]
|
||
<br><b>*log-lisp-errors-p*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Whether Lisp errors in request handlers should be logged.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*log-lisp-backtraces-p*"></a>
|
||
[Special variable]
|
||
<br><b>*log-lisp-backtraces-p*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Whether Lisp backtraces should be logged. Only
|
||
has an effect if <code><a href="index.html#*log-lisp-errors-p*">*LOG-LISP-ERRORS-P*</a></code> is true
|
||
as well.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*log-lisp-warnings-p*"></a>
|
||
[Special variable]
|
||
<br><b>*log-lisp-warnings-p*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Whether Lisp warnings in request handlers should be logged.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*lisp-errors-log-level*"></a>
|
||
[Special variable]
|
||
<br><b>*lisp-errors-log-level*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Log level for Lisp errors. Should be one
|
||
of <code xmlns="http://www.w3.org/1999/xhtml">:ERROR</code> (the default), <code xmlns="http://www.w3.org/1999/xhtml">:WARNING</code>,
|
||
or <code xmlns="http://www.w3.org/1999/xhtml">:INFO</code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*lisp-warnings-log-level*"></a>
|
||
[Special variable]
|
||
<br><b>*lisp-warnings-log-level*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Log level for Lisp warnings.
|
||
Should be one of <code xmlns="http://www.w3.org/1999/xhtml">:ERROR</code>, <code xmlns="http://www.w3.org/1999/xhtml">:WARNING</code>
|
||
(the default), or <code xmlns="http://www.w3.org/1999/xhtml">:INFO</code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
|
||
<h4 xmlns=""><a name="conditions">Conditions and error handling</a></h4>
|
||
<p>
|
||
This section describes how Hunchentoot deals with exceptional
|
||
situations. See also the secion about <a href="index.html#logging">logging</a>.
|
||
</p>
|
||
<p>
|
||
When an error occurs while processing a request, Hunchentoot's
|
||
default behavior is to catch the error, log it and
|
||
optionally display it to the client in the HTML response.
|
||
This behavior can be customized through the values of a number
|
||
of special variables, which are documented below.
|
||
</p>
|
||
|
||
<p xmlns=""><a class="none" name="*catch-errors-p*"></a>
|
||
[Special variable]
|
||
<br><b>*catch-errors-p*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
If the value of this variable is <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>
|
||
(the default is <code xmlns="http://www.w3.org/1999/xhtml">T</code>), then errors which happen while a
|
||
request is handled aren't <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#logging">caught as usual</a>, but
|
||
instead your
|
||
Lisp's <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_d.htm#debugger">debugger</a>
|
||
is <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.lispworks.com/documentation/HyperSpec/Body/f_invoke.htm">invoked</a>.
|
||
This variable should obviously always be set to a <em xmlns="http://www.w3.org/1999/xhtml">true</em> value
|
||
in a production environment.
|
||
See <code><a href="index.html#maybe-invoke-debugger">MAYBE-INVOKE-DEBUGGER</a></code>
|
||
if you want to fine-tune this behaviour.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*show-lisp-errors-p*"></a>
|
||
[Special variable]
|
||
<br><b>*show-lisp-errors-p*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Whether Lisp errors should be shown in HTML output. Note
|
||
that this only affects canned responses generated by Lisp.
|
||
If an error template is present for the "internal server
|
||
error" status code, this special variable is not used (see
|
||
<code><a href="index.html#acceptor-status-message">acceptor-status-message</a></code>).
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*show-lisp-backtraces-p*"></a>
|
||
[Special variable]
|
||
<br><b>*show-lisp-backtraces-p*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Whether Lisp backtraces should be shown in HTML output if
|
||
<code><a href="index.html#*show-lisp-errors-p*">*SHOW-LISP-ERRORS-P*</a></code> is true and an error occurs.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="maybe-invoke-debugger"></a>
|
||
[Generic function]
|
||
<br><b>maybe-invoke-debugger</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">condition
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">|
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This generic function is called whenever a
|
||
<a xmlns="http://www.w3.org/1999/xhtml" href="http://www.lispworks.com/documentation/HyperSpec/Body/09_.htm">condition</a> <code xmlns="http://www.w3.org/1999/xhtml"><i>condition</i></code>
|
||
is signaled in Hunchentoot. You might want to specialize it on
|
||
specific condition classes for debugging purposes. The default
|
||
method <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.lispworks.com/documentation/HyperSpec/Body/f_invoke.htm">invokes
|
||
the debugger</a> with <code><i>condition</i></code> if
|
||
<code><a href="index.html#*catch-errors-p*">*CATCH-ERRORS-P*</a></code> is <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="hunchentoot-condition"></a>
|
||
[Condition type]
|
||
<br><b>hunchentoot-condition</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Superclass for all conditions related to Hunchentoot.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="hunchentoot-error"></a>
|
||
[Condition type]
|
||
<br><b>hunchentoot-error</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Superclass for all errors related to Hunchentoot and a subclass of <code><a href="index.html#hunchentoot-condition">HUNCHENTOOT-CONDITION</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="parameter-error"></a>
|
||
[Condition type]
|
||
<br><b>parameter-error</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Signalled if a function was called with incosistent or illegal parameters. A subclass of <code><a href="index.html#hunchentoot-error">HUNCHENTOOT-ERROR</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="hunchentoot-warning"></a>
|
||
[Condition type]
|
||
<br><b>hunchentoot-warning</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Superclass for all warnings related to Hunchentoot and a subclass of <code><a href="index.html#hunchentoot-condition">HUNCHENTOOT-CONDITION</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
|
||
|
||
<h4 xmlns=""><a name="misc">Miscellaneous</a></h4>
|
||
|
||
Various functions and variables which didn't fit into one of the
|
||
other categories.
|
||
|
||
<p xmlns=""><a class="none" name="abort-request-handler"></a>
|
||
[Function]
|
||
<br><b>abort-request-handler</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> result
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This function can be called by a request handler
|
||
at any time to immediately abort handling the request. This works as
|
||
if the handler had returned <code><i>result</i></code>. See the
|
||
source code of <code><a href="index.html#redirect">REDIRECT</a></code> for an example.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="handle-if-modified-since"></a>
|
||
[Function]
|
||
<br><b>handle-if-modified-since</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">time <tt>&optional</tt> request</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">|</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This function is designed to be used inside
|
||
a <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#request-dispatch">handler</a>. If the client has sent an
|
||
'If-Modified-Since' header
|
||
(see <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.faqs.org/rfcs/rfc2616.html">RFC 2616</a>,
|
||
section 14.25) and the time specified matches the universal
|
||
time
|
||
<code><i>time</i></code> then the
|
||
header <code><a href="index.html#+http-not-modified+">+HTTP-NOT-MODIFIED+</a></code> with no content
|
||
is immediately returned to the client.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
Note that for this function to be useful you should usually
|
||
send 'Last-Modified' headers back to the client. See the
|
||
code
|
||
of <code xmlns=""><a href="index.html#create-static-file-dispatcher-and-handler">CREATE-STATIC-FILE-DISPATCHER-AND-HANDLER</a></code>
|
||
for an example.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
|
||
<p xmlns=""><a class="none" name="handle-static-file"></a>
|
||
[Function]
|
||
<br><b>handle-static-file</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">path <tt>&optional</tt> content-type callback</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">nil</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Sends the file denoted by the pathname designator
|
||
<code><i>path</i></code> with content type
|
||
<code><i>content-type</i></code> to the client. Sets the
|
||
necessary handlers. In particular the function employs
|
||
<code><a href="index.html#handle-if-modified-since">HANDLE-IF-MODIFIED-SINCE</a></code>.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
If <code xmlns=""><i>content-type</i></code> is <code>NIL</code>, the
|
||
function tries to determine the correct content type from
|
||
the file's suffix or falls back
|
||
to <code>"application/octet-stream"</code> as a last resort.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
The <code xmlns=""><i>callback</i></code> is run just before opening
|
||
the file; it can eg. check authorization or send caching headers.
|
||
It gets the filename and the (guessed) content-type as arguments.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
Note that this function
|
||
calls <code xmlns=""><a href="index.html#send-headers">SEND-HEADERS</a></code> internally, so after
|
||
you've called it, the headers are sent and the return value
|
||
of your handler is ignored.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="redirect"></a>
|
||
[Function]
|
||
<br><b>redirect</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">target <tt>&key</tt> host port protocol add-session-id code</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">|</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Sends back appropriate headers to redirect the client
|
||
to <code><i>target</i></code> (a string).
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
If <code xmlns=""><i>target</i></code> is a full URL starting with a
|
||
scheme, <code xmlns=""><i>host</i></code>, <code xmlns=""><i>port</i></code>,
|
||
and <code xmlns=""><i>protocol</i></code> are ignored.
|
||
Otherwise, <code xmlns=""><i>target</i></code> should denote the path
|
||
part of a URL, <code xmlns=""><i>protocol</i></code> must be one of
|
||
the keywords <code>:HTTP</code> or <code>:HTTPS</code>, and
|
||
the URL to redirect to will be constructed
|
||
from <code xmlns=""><i>host</i></code>, <code xmlns=""><i>port</i></code>, <code xmlns=""><i>protocol</i></code>,
|
||
and <code xmlns=""><i>target</i></code>.
|
||
</p>
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
<code xmlns=""><i>code</i></code> must be a 3xx HTTP redirection
|
||
status code to send to the client. It defaults to 302
|
||
("Found"). If <code xmlns=""><i>host</i></code> is not provided,
|
||
the current host (see <code xmlns=""><a href="index.html#host">HOST</a></code>) will be
|
||
used. If <code xmlns=""><i>protocol</i></code> is the keyword
|
||
<code>:HTTPS</code>, the client will be redirected to a
|
||
https URL, if it's <code>:HTTP</code> it'll be sent to a
|
||
http URL. If both <code xmlns=""><i>host</i></code> and
|
||
<code xmlns=""><i>protocol</i></code> aren't provided, then the
|
||
value of <code xmlns=""><i>protocol</i></code> will match the
|
||
current request.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="require-authorization"></a>
|
||
[Function]
|
||
<br><b>require-authorization</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc"><tt>&optional</tt> realm</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">|</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Sends back appropriate headers to require basic HTTP
|
||
authentication
|
||
(see <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.faqs.org/rfcs/rfc2617.html">RFC 2617</a>)
|
||
for the realm <code><i>realm</i></code>. The default value
|
||
for <code><i>realm</i></code> is <code xmlns="http://www.w3.org/1999/xhtml">"Hunchentoot"</code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="no-cache"></a>
|
||
[Function]
|
||
<br><b>no-cache</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">|
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Adds appropriate headers to completely prevent caching on most browsers.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="ssl-p"></a>
|
||
[Function]
|
||
<br><b>ssl-p</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> acceptor
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">generalized-boolean
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Whether the current connection to the client is secure. See <code><a href="index.html#acceptor-ssl-p">ACCEPTOR-SSL-P</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="ssl-get-peer-certificate"></a>
|
||
[Function]
|
||
<br><b>ssl-get-peer-certificate</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">system-area-pointer
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns a SAP to the certificate the peer used to authenticate itself, or NIL.
|
||
Can be used with <code xmlns="http://www.w3.org/1999/xhtml">CL+SSL:CERTIFICATE-SUBJECT-COMMON-NAMES</code> and the other certificate functions.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="reason-phrase"></a>
|
||
[Function]
|
||
<br><b>reason-phrase</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">return-code
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">string
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns a reason phrase for the HTTP return code <code><i>return-code</i></code>
|
||
(which should be an integer) or <code xmlns="http://www.w3.org/1999/xhtml">NIL</code> for return codes Hunchentoot
|
||
doesn't know.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="rfc-1123-date"></a>
|
||
[Function]
|
||
<br><b>rfc-1123-date</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
<tt>&optional
|
||
</tt> time
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">string
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Generates a time string according to <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.faqs.org/rfcs/rfc1123.html">RFC 1123</a>. Default is current time.
|
||
This can be used to send a 'Last-Modified' header - see <code><a href="index.html#handle-if-modified-since">HANDLE-IF-MODIFIED-SINCE</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="url-encode"></a>
|
||
[Function]
|
||
<br><b>url-encode</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">string
|
||
<tt>&optional
|
||
</tt> external-format
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">string
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
URL-encodes a string using the external format <code><i>external-format</i></code>. The default for <code><i>external-format</i></code> is the value of <code><a href="index.html#*hunchentoot-default-external-format*">*HUNCHENTOOT-DEFAULT-EXTERNAL-FORMAT*</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="url-decode"></a>
|
||
[Function]
|
||
<br><b>url-decode</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">string
|
||
<tt>&optional
|
||
</tt> external-format
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">string
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Decodes a URL-encoded string which is assumed to
|
||
be encoded using the external
|
||
format <code><i>external-format</i></code>, i.e. this is the inverse
|
||
of <code><a href="index.html#url-encode">URL-ENCODE</a></code>. It is assumed that you'll rarely
|
||
need this function, if ever. But just in case - here it is. The
|
||
default for <code><i>external-format</i></code> is the value
|
||
of <code><a href="index.html#*hunchentoot-default-external-format*">*HUNCHENTOOT-DEFAULT-EXTERNAL-FORMAT*</a></code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="escape-for-html"></a>
|
||
[Function]
|
||
<br><b>escape-for-html</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">string
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Escapes the characters #\<, #\>, #\', #\", and #\& for HTML output.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="http-token-p"></a>
|
||
[Function]
|
||
<br><b>http-token-p</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">object</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">generalized-boolean</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This function tests whether <code><i>object</i></code> is a
|
||
non-empty string which is a <em xmlns="http://www.w3.org/1999/xhtml">token</em> according
|
||
to <a xmlns="http://www.w3.org/1999/xhtml" href="http://www.faqs.org/rfcs/rfc2068.html">RFC
|
||
2068</a> (i.e. whether it may be used for, say, cookie names).
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="mime-type"></a>
|
||
[Function]
|
||
<br><b>mime-type</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">pathspec
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">result
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Given a pathname designator <code><i>pathspec</i></code> returns the <a xmlns="http://www.w3.org/1999/xhtml" href="http://en.wikipedia.org/wiki/Internet_media_type">MIME type</a>
|
||
(as a string) corresponding to the suffix of the file denoted by
|
||
<code><i>pathspec</i></code> (or <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>).
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="within-request-p"></a>
|
||
[Function]
|
||
<br><b>within-request-p</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">
|
||
</clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">generalized-boolean
|
||
</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Returns true if in the context of a request. Otherwise, <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*tmp-directory*"></a>
|
||
[Special variable]
|
||
<br><b>*tmp-directory*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
This should be a pathname denoting a directory where temporary
|
||
files can be stored. It is used for <a xmlns="http://www.w3.org/1999/xhtml" href="index.html#upload">file
|
||
uploads</a>.
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*header-stream*"></a>
|
||
[Special variable]
|
||
<br><b>*header-stream*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
If this variable is not <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>, it should be bound to a stream to
|
||
which incoming and outgoing headers will be written for debugging
|
||
purposes.
|
||
</clix:description></blockquote></p>
|
||
|
||
|
||
<p xmlns=""><a class="none" name="*cleanup-function*"></a>
|
||
[Special variable]
|
||
<br><b>*cleanup-function*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
A designator for a function without arguments which is called on a
|
||
regular basis if <code><a href="index.html#*cleanup-interval*">*CLEANUP-INTERVAL*</a></code> is not <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>. The initial value is
|
||
the name of a function which invokes a garbage collection on 32-bit
|
||
versions of LispWorks.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
This variable is only available on LispWorks.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
<p xmlns=""><a class="none" name="*cleanup-interval*"></a>
|
||
[Special variable]
|
||
<br><b>*cleanup-interval*</b><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Should be <code xmlns="http://www.w3.org/1999/xhtml">NIL</code> or a positive integer. The system calls
|
||
<code><a href="index.html#*cleanup-function*">*CLEANUP-FUNCTION*</a></code>
|
||
whenever <code><a href="index.html#*cleanup-interval*">*CLEANUP-INTERVAL*</a></code> new worker threads
|
||
(counted globally across all acceptors) have been created unless the
|
||
value is <code xmlns="http://www.w3.org/1999/xhtml">NIL</code>. The initial value is 100.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
This variable is only available on LispWorks.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
|
||
|
||
<h3 xmlns=""><a class="none" name="testing">Testing</a></h3>
|
||
Hunchentoot comes with a test script which verifies that the
|
||
example web server responds as expected. This test script uses the
|
||
<a href="http://weitz.de/drakma/">Drakma</a> HTTP client library
|
||
and thus shares a significant amount of its base code with
|
||
Hunchentoot itself. Still, running the test script is a useful
|
||
confidence test, and it is also possible to run the script across
|
||
machines in order to verify a new Hunchentoot (or, for that matter
|
||
Drakma) port.
|
||
<p>
|
||
To run the confidence test, <a href="index.html#teen-age">start
|
||
the example web server</a>. Then, in your Lisp
|
||
listener, type
|
||
<pre>(<a class="noborder" href="hunchentoot-test:test-hunchentoot">hunchentoot-test:test-hunchentoot</a> "http://localhost:4242")</pre>
|
||
You will see some diagnostic output and a summary line that
|
||
reports whether any tests have failed. (You can also use the
|
||
example certificate and key files in the test directory and
|
||
start and test an https server instead.)
|
||
</p>
|
||
|
||
<p xmlns=""><a class="none" name="hunchentoot-test:test-hunchentoot"></a>
|
||
[Function]
|
||
<br><b>hunchentoot-test:test-hunchentoot</b> <i><clix:lambda-list xmlns:clix="http://bknr.net/clixdoc">base-url <tt>&key</tt></clix:lambda-list></i>
|
||
=>
|
||
<i><clix:returns xmlns:clix="http://bknr.net/clixdoc">|</clix:returns></i><blockquote><clix:description xmlns:clix="http://bknr.net/clixdoc">
|
||
Runs the built-in confidence
|
||
test. <code><i>base-url</i></code> is the base URL to use
|
||
for testing, it should not have a trailing slash. The keyword
|
||
arguments accepted are for future extension and should not
|
||
currently be used.
|
||
<p xmlns="http://www.w3.org/1999/xhtml">
|
||
The script expects the Hunchentoot example test server to be
|
||
running at the given <code xmlns=""><i>base-url</i></code> and
|
||
retrieves various pages from that server, expecting certain
|
||
responses.
|
||
</p>
|
||
</clix:description></blockquote></p>
|
||
|
||
|
||
<h3 xmlns=""><a class="none" name="debugging">Debugging</a></h3>
|
||
By default, Hunchentoot intercepts all errors that occur while
|
||
executing request handlers, logs them to the log file and displays
|
||
a static error page to the user. While developing applications,
|
||
you may want to change that behavior so that the debugger is
|
||
invoked when an error occurs. You can set
|
||
the <code xmlns=""><a href="index.html#*catch-errors-p*">*CATCH-ERRORS-P*</a></code> to <code>NIL</code> to
|
||
make that happen. Alternatively, you may want to have Hunchentoot
|
||
display detailed error information in the error response page.
|
||
You can set the <code xmlns=""><a href="index.html#*show-lisp-errors-p*">*SHOW-LISP-ERRORS-P*</a></code> to a
|
||
true value to make that happen. If you don't want to see Lisp
|
||
backtraces in these error pages, you can
|
||
set <code xmlns=""><a href="index.html#*show-lisp-backtraces-p*">*SHOW-LISP-BACKTRACES-P*</a></code>
|
||
to <code>NIL</code>.
|
||
|
||
|
||
<h3 xmlns=""><a class="none" name="history">History</a></h3>
|
||
|
||
Hunchentoot's predecessor <a href="http://weitz.de/tbnl/">TBNL</a>
|
||
(which is short for "To Be Named Later") grew over the years as a
|
||
toolkit that I used for various commercial and private
|
||
projects. In August 2003, Daniel Barlow started
|
||
a <a href="http://article.gmane.org/gmane.lisp.web/148">review of
|
||
web APIs</a> on
|
||
the <a href="http://www.red-bean.com/lispweb/">lispweb</a> mailing
|
||
list and
|
||
I <a href="http://article.gmane.org/gmane.lisp.web/153">described</a>
|
||
the API of my hitherto-unreleased bunch of code (and christened it
|
||
"TBNL").
|
||
<p>
|
||
It turned out that
|
||
<a href="http://www.jeffcaldwell.com/">Jeff Caldwell</a> had
|
||
worked on something similar so he emailed me and proposed to
|
||
join our efforts. As I had no immediate plans to release my code
|
||
(which was poorly organized, undocumented, and mostly
|
||
CMUCL-specific), I gave it to Jeff and he worked towards a
|
||
release. He added docstrings, refactored, added some stuff, and
|
||
based it on KMRCL to make it portable across several Lisp
|
||
implementations.
|
||
</p>
|
||
<p>
|
||
Unfortunately, Jeff is at least as busy as I am so he didn't
|
||
find the time to finish a full release. But in spring 2004 I
|
||
needed a documented version of the code for a client of mine who
|
||
thought it would be good if the toolkit were publicly available
|
||
under an open source license. So I took Jeff's code, refactored
|
||
again (to sync with the changes I had done in the meantime), and
|
||
added documentation. This resulted in TBNL 0.1.0 (which
|
||
initially required mod_lisp as its front-end).
|
||
</p>
|
||
<p>
|
||
In March 2005, Bob Hutchinson sent patches which enabled TBNL to
|
||
use other front-ends than mod_lisp. This made me aware that
|
||
TBNL was already <em>almost</em> a full web server, so
|
||
eventually I wrote Hunchentoot which <em>was</em> a full web
|
||
server, implemented as a wrapper around TBNL. Hunchentoot 0.1.0
|
||
was released at the end of 2005 and was originally
|
||
LispWorks-only.
|
||
</p>
|
||
<p>
|
||
Hunchentoot 0.4.0, released in October 2006, was the first
|
||
release which also worked with other Common Lisp
|
||
implementations. It is a major rewrite and also incorporates
|
||
most of TBNL and replaces it completely.
|
||
</p>
|
||
<p>
|
||
Hunchentoot 1.0.0, released in February 2009, is again a major
|
||
rewrite and should be considered work in progress. It moved to
|
||
using
|
||
the <a href="http://common-lisp.net/project/usocket/">usocket</a>
|
||
and <a href="http://common-lisp.net/project/bordeaux-threads/">Bordeaux
|
||
Threads</a> libraries for non-LispWorks Lisps, thereby removing most of
|
||
the platform dependent code. Threading behaviour was made
|
||
controllable through the introduction of
|
||
taskmasters. <a href="http://www.cliki.net/mod_lisp">mod_lisp</a>
|
||
support and several other things were removed in this release to
|
||
simplify the code base (and partly due to the lack of interest).
|
||
Several architectural changes (lots of them not
|
||
backwards-compatible) were made to ease customization of
|
||
Hunchentoot's behaviour. A significant part of the 1.0.0
|
||
redesign was done
|
||
by <a href="http://netzhansa.blogspot.com/">Hans Hübner</a>.
|
||
</p>
|
||
|
||
|
||
<h3 xmlns=""><a class="none" name="index">Symbol index</a></h3>
|
||
|
||
Here are all exported symbols of the <code>HUNCHENTOOT</code>
|
||
package in alphabetical order linked to their corresponding
|
||
documentation entries:
|
||
|
||
<ul xmlns="">
|
||
<li>
|
||
<code><a href="index.html#*acceptor*">*acceptor*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*catch-errors-p*">*catch-errors-p*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*cleanup-function*">*cleanup-function*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*cleanup-interval*">*cleanup-interval*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*content-types-for-url-rewrite*">*content-types-for-url-rewrite*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*default-connection-timeout*">*default-connection-timeout*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*default-content-type*">*default-content-type*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*dispatch-table*">*dispatch-table*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*file-upload-hook*">*file-upload-hook*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*header-stream*">*header-stream*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*hunchentoot-default-external-format*">*hunchentoot-default-external-format*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*lisp-errors-log-level*">*lisp-errors-log-level*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*lisp-warnings-log-level*">*lisp-warnings-log-level*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*log-lisp-backtraces-p*">*log-lisp-backtraces-p*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*log-lisp-errors-p*">*log-lisp-errors-p*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*log-lisp-warnings-p*">*log-lisp-warnings-p*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*methods-for-post-parameters*">*methods-for-post-parameters*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*reply*">*reply*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*request*">*request*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*rewrite-for-session-urls*">*rewrite-for-session-urls*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*session*">*session*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*session-gc-frequency*">*session-gc-frequency*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*session-max-time*">*session-max-time*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*session-secret*">*session-secret*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*show-lisp-backtraces-p*">*show-lisp-backtraces-p*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*show-lisp-errors-p*">*show-lisp-errors-p*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*tmp-directory*">*tmp-directory*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*use-remote-addr-for-sessions*">*use-remote-addr-for-sessions*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#*use-user-agent-for-sessions*">*use-user-agent-for-sessions*</a></code><span class="entry-type">Special variable</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-accepted+">+http-accepted+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-authorization-required+">+http-authorization-required+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-bad-gateway+">+http-bad-gateway+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-bad-request+">+http-bad-request+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-conflict+">+http-conflict+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-continue+">+http-continue+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-created+">+http-created+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-expectation-failed+">+http-expectation-failed+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-failed-dependency+">+http-failed-dependency+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-forbidden+">+http-forbidden+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-gateway-time-out+">+http-gateway-time-out+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-gone+">+http-gone+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-internal-server-error+">+http-internal-server-error+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-length-required+">+http-length-required+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-method-not-allowed+">+http-method-not-allowed+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-moved-permanently+">+http-moved-permanently+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-moved-temporarily+">+http-moved-temporarily+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-multi-status+">+http-multi-status+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-multiple-choices+">+http-multiple-choices+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-no-content+">+http-no-content+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-non-authoritative-information+">+http-non-authoritative-information+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-not-acceptable+">+http-not-acceptable+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-not-found+">+http-not-found+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-not-implemented+">+http-not-implemented+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-not-modified+">+http-not-modified+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-ok+">+http-ok+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-partial-content+">+http-partial-content+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-payment-required+">+http-payment-required+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-precondition-failed+">+http-precondition-failed+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-proxy-authentication-required+">+http-proxy-authentication-required+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-request-entity-too-large+">+http-request-entity-too-large+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-request-time-out+">+http-request-time-out+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-request-uri-too-large+">+http-request-uri-too-large+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-requested-range-not-satisfiable+">+http-requested-range-not-satisfiable+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-reset-content+">+http-reset-content+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-see-other+">+http-see-other+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-service-unavailable+">+http-service-unavailable+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-switching-protocols+">+http-switching-protocols+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-temporary-redirect+">+http-temporary-redirect+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-unsupported-media-type+">+http-unsupported-media-type+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-use-proxy+">+http-use-proxy+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#+http-version-not-supported+">+http-version-not-supported+</a></code><span class="entry-type">Constant</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#abort-request-handler">abort-request-handler</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#accept-connections">accept-connections</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor">acceptor</a></code><span class="entry-type">Standard class</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-access-log-destination">acceptor-access-log-destination</a></code><span class="entry-type">Generic accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-address">acceptor-address</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-dispatch-request">acceptor-dispatch-request</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-document-root">acceptor-document-root</a></code><span class="entry-type">Generic accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-error-template-directory">acceptor-error-template-directory</a></code><span class="entry-type">Generic accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-input-chunking-p">acceptor-input-chunking-p</a></code><span class="entry-type">Generic accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-listen-backlog">acceptor-listen-backlog</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-log-access">acceptor-log-access</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-log-message">acceptor-log-message</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-message-log-destination">acceptor-message-log-destination</a></code><span class="entry-type">Generic accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-name">acceptor-name</a></code><span class="entry-type">Generic accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-output-chunking-p">acceptor-output-chunking-p</a></code><span class="entry-type">Generic accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-persistent-connections-p">acceptor-persistent-connections-p</a></code><span class="entry-type">Generic accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-port">acceptor-port</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-read-timeout">acceptor-read-timeout</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-remove-session">acceptor-remove-session</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-reply-class">acceptor-reply-class</a></code><span class="entry-type">Generic accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-request-class">acceptor-request-class</a></code><span class="entry-type">Generic accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-ssl-certificate-file">acceptor-ssl-certificate-file</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-ssl-p">acceptor-ssl-p</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-ssl-privatekey-file">acceptor-ssl-privatekey-file</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-ssl-privatekey-password">acceptor-ssl-privatekey-password</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-status-message">acceptor-status-message</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#acceptor-write-timeout">acceptor-write-timeout</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#authorization">authorization</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#aux-request-value">aux-request-value</a></code><span class="entry-type">Accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#content-length">content-length</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#content-length*">content-length*</a></code><span class="entry-type">Accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#content-type">content-type</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#content-type*">content-type*</a></code><span class="entry-type">Accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#cookie-in">cookie-in</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#cookie-out">cookie-out</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#cookies-in">cookies-in</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#cookies-in*">cookies-in*</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#cookies-out">cookies-out</a></code><span class="entry-type">Generic accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#cookies-out*">cookies-out*</a></code><span class="entry-type">Accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#create-folder-dispatcher-and-handler">create-folder-dispatcher-and-handler</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#create-prefix-dispatcher">create-prefix-dispatcher</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#create-regex-dispatcher">create-regex-dispatcher</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#create-request-handler-thread">create-request-handler-thread</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#create-static-file-dispatcher-and-handler">create-static-file-dispatcher-and-handler</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#define-easy-handler">define-easy-handler</a></code><span class="entry-type">Macro</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#delete-aux-request-value">delete-aux-request-value</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#delete-session-value">delete-session-value</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#detach-socket">detach-socket</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#dispatch-easy-handlers">dispatch-easy-handlers</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#easy-acceptor">easy-acceptor</a></code><span class="entry-type">Standard class</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#easy-ssl-acceptor">easy-ssl-acceptor</a></code><span class="entry-type">Standard class</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#escape-for-html">escape-for-html</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#execute-acceptor">execute-acceptor</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#get-parameter">get-parameter</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#get-parameters">get-parameters</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#get-parameters*">get-parameters*</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#handle-if-modified-since">handle-if-modified-since</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#handle-incoming-connection">handle-incoming-connection</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#handle-request">handle-request</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#handle-static-file">handle-static-file</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#header-in">header-in</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#header-in*">header-in*</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#header-out">header-out</a></code><span class="entry-type">Accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#headers-in">headers-in</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#headers-in*">headers-in*</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#headers-out">headers-out</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#headers-out*">headers-out*</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#host">host</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#http-token-p">http-token-p</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#hunchentoot-condition">hunchentoot-condition</a></code><span class="entry-type">Condition type</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#hunchentoot-error">hunchentoot-error</a></code><span class="entry-type">Condition type</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#hunchentoot-test:test-hunchentoot">hunchentoot-test:test-hunchentoot</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#hunchentoot-warning">hunchentoot-warning</a></code><span class="entry-type">Condition type</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#initialize-connection-stream">initialize-connection-stream</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#local-addr">local-addr</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#local-addr*">local-addr*</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#local-port">local-port</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#local-port*">local-port*</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#log-message*">log-message*</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#maybe-invoke-debugger">maybe-invoke-debugger</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#mime-type">mime-type</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#multi-threaded-taskmaster">multi-threaded-taskmaster</a></code><span class="entry-type">Standard class</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#next-session-id">next-session-id</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#no-cache">no-cache</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#one-thread-per-connection-taskmaster">one-thread-per-connection-taskmaster</a></code><span class="entry-type">Standard class</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#parameter">parameter</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#parameter-error">parameter-error</a></code><span class="entry-type">Condition type</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#post-parameter">post-parameter</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#post-parameters">post-parameters</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#post-parameters*">post-parameters*</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#process-connection">process-connection</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#process-request">process-request</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#query-string">query-string</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#query-string*">query-string*</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#raw-post-data">raw-post-data</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#real-remote-addr">real-remote-addr</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#reason-phrase">reason-phrase</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#recompute-request-parameters">recompute-request-parameters</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#redirect">redirect</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#referer">referer</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#regenerate-session-cookie-value">regenerate-session-cookie-value</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#remote-addr">remote-addr</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#remote-addr*">remote-addr*</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#remote-port">remote-port</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#remote-port*">remote-port*</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#remove-session">remove-session</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#reply">reply</a></code><span class="entry-type">Standard class</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#reply-external-format">reply-external-format</a></code><span class="entry-type">Generic accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#reply-external-format*">reply-external-format*</a></code><span class="entry-type">Accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#request">request</a></code><span class="entry-type">Standard class</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#request-acceptor">request-acceptor</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#request-method">request-method</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#request-method*">request-method*</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#request-uri">request-uri</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#request-uri*">request-uri*</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#require-authorization">require-authorization</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#reset-connection-stream">reset-connection-stream</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#reset-session-secret">reset-session-secret</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#reset-sessions">reset-sessions</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#return-code">return-code</a></code><span class="entry-type">Generic accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#return-code*">return-code*</a></code><span class="entry-type">Accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#rfc-1123-date">rfc-1123-date</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#script-name">script-name</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#script-name*">script-name*</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#send-headers">send-headers</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#server-protocol">server-protocol</a></code><span class="entry-type">Generic reader</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#server-protocol*">server-protocol*</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#session">session</a></code><span class="entry-type">Standard class</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#session-cookie-name">session-cookie-name</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#session-cookie-value">session-cookie-value</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#session-created">session-created</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#session-db">session-db</a></code><span class="entry-type">Generic accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#session-db-lock">session-db-lock</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#session-gc">session-gc</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#session-id">session-id</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#session-max-time">session-max-time</a></code><span class="entry-type">Generic accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#session-remote-addr">session-remote-addr</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#session-start">session-start</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#session-too-old-p">session-too-old-p</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#session-user-agent">session-user-agent</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#session-value">session-value</a></code><span class="entry-type">Accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#session-verify">session-verify</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#set-cookie">set-cookie</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#set-cookie*">set-cookie*</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#shutdown">shutdown</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#single-threaded-taskmaster">single-threaded-taskmaster</a></code><span class="entry-type">Standard class</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#ssl-acceptor">ssl-acceptor</a></code><span class="entry-type">Standard class</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#ssl-get-peer-certificate">ssl-get-peer-certificate</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#ssl-p">ssl-p</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#start">start</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#start-listening">start-listening</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#start-session">start-session</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#start-thread">start-thread</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#stop">stop</a></code><span class="entry-type">Generic function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#taskmaster">taskmaster</a></code><span class="entry-type">Standard class</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#taskmaster-acceptor">taskmaster-acceptor</a></code><span class="entry-type">Generic accessor</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#url-decode">url-decode</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#url-encode">url-encode</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#user-agent">user-agent</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
<li>
|
||
<code><a href="index.html#within-request-p">within-request-p</a></code><span class="entry-type">Function</span>
|
||
</li>
|
||
</ul>
|
||
|
||
|
||
|
||
<h3 xmlns=""><a class="none" name="ack">Acknowledgements</a></h3>
|
||
|
||
Thanks to Jeff Caldwell - TBNL would not have been released
|
||
without his efforts. Thanks
|
||
to <a href="http://www.cliki.net/Stefan%20Scholl">Stefan
|
||
Scholl</a> and Travis Cross for various additions and fixes to
|
||
TBNL, to <a href="http://www.foldr.org/~michaelw/">Michael
|
||
Weber</a> for initial file upload code, and
|
||
to <a href="http://www.ltn.lv/~jonis/">Janis Dzerins</a> for
|
||
his <a href="http://common-lisp.net/project/rfc2388/">RFC 2388
|
||
code</a>. Thanks to Bob Hutchison for his code for multiple
|
||
front-ends (which made me realize that TBNL was already pretty
|
||
close to a "real" web server) and the initial UTF-8 example.
|
||
Thanks to <a href="http://netzhansa.blogspot.com/">Hans Hübner</a>
|
||
for a lot of architectural and implementation enhancements for the
|
||
1.0.0 release and also for transferring the documentation to sane
|
||
XHTML. Thanks to John
|
||
Foderaro's <a href="http://opensource.franz.com/aserve/index.html">AllegroServe</a>
|
||
for inspiration. Thanks to <a href="http://www.htg1.de/">Uwe von
|
||
Loh</a> for
|
||
the <a href="http://www.htg1.de/hunchentoot/hunchentoot.html">Hunchentoot
|
||
logo</a>.
|
||
|
||
<p>
|
||
Hunchentoot originally used code
|
||
from <a href="http://www.cliki.net/ACL-COMPAT">ACL-COMPAT</a>,
|
||
specifically the chunking code from Jochen Schmidt. (This has been
|
||
replaced by <a href="http://weitz.de/chunga/">Chunga</a>.) When I ported
|
||
Hunchentoot to other Lisps than LispWorks, I stole code from
|
||
ACL-COMPAT, <a href="http://www.cliki.net/kmrcl">KMRCL</a>,
|
||
and <a href="http://www.cliki.net/trivial-sockets">trivial-sockets</a> for
|
||
implementation-dependent stuff like sockets and MP. (This has been replaced by
|
||
<a href="http://common-lisp.net/project/bordeaux-threads/">Bordeaux
|
||
Threads</a>
|
||
and <a href="http://common-lisp.net/project/usocket/">usocket</a>.)
|
||
</p>
|
||
<p>
|
||
Parts of this documentation were prepared
|
||
with <a href="http://weitz.de/documentation-template/">DOCUMENTATION-TEMPLATE</a>,
|
||
no animals were harmed.
|
||
</p>
|
||
|
||
<p>
|
||
<a href="http://weitz.de/index.html">BACK TO MY HOMEPAGE
|
||
</a>
|
||
</p>
|
||
</body></html>
|