source: project/wiki/http @ 10335

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

Fix http example. Use http:read-body, NOT READ-LINES

File size: 24.6 KB
Line 
1[[tags: egg]]
2
3== http
4
5[[toc:]]
6
7=== Description
8
9An easy to use HTTP client and server package. The server is fully multithreaded and
10supports persistent connections.
11
12=== Author
13
14[[Felix Winkelmann]]
15
16=== Requirements
17
18Requires the [[http://www.call-with-current-continuation.org/eggs/regex-case.html|regex-case]] egg at compile-time.
19
20{{http-client}} requires the [[http://www.call-with-current-continuation.org/eggs/url.html|url]] egg at runtime.
21
22Both {{http-client}} and {{http-server}} require the {{http-utils}} module at runtime.
23
24=== Documentation
25
26What follows is a description of the {{http}} extension, which is separated into three
27sub-extensions: {{http-client}} (HTTP client functionality), {{http-server}} (serving
28HTTP requests) and {{http-utils}} (utility functions common to client and server code).
29
30If you want to run a web-server, you should also take a look at the more featureful [[spiffy]] extension.
31
32==== http-client
33
34===== Usage
35
36{{(require-extension http-client)}}
37
38===== http:send-request
39
40 [procedure] (http:send-request REQUEST [INPUT-PORT OUTPUT-PORT])
41
42Sends an HTTP request represented by {{REQUEST}}, which may either be a HTTP
43request object, or a string that specifies an URL. The request is sent to it's destination
44and four values are returned: a string containing the first line of the response received
45from the server, an a-list that maps HTTP headers to values (strings) and the input-
46and output-port of the connection. Note that the connection is still open, and the returned
47ports can be passed in subsequent invocations of {{http:send-request}} to
48achieve a persistent connection. The ports are closed automatically, if no longer
49referenced.
50
51If an URL is given instead of a request record, a request is sent of the form
52
53 GET url HTTP/1.0
54 Connection: close
55
56===== http:GET
57
58 [procedure] (http:GET REQUEST)
59
60Sends a ''GET'' request represented by {{REQUEST}}, which may be a string (an URL)
61or a HTTP request object, and returns a string containing the body of the servers response.
62The {{REQUEST}} keeps a {{Cookie}} header that is set by {{Set-Cookie}} headers in a response,
63unsafely (hack), regardless of the storing policy. Be aware of it when reusing {{REQUEST}}.
64
65===== http:POST
66
67 [procedure] (http:POST REQUEST [ARGUMENTS] #!key [headers: HEADERS]
68                                                  [type: CTYPE]
69                                                  [delim: DELIM])
70
71Sends a '''POST''' request represented by {{REQUEST}}, which may be a string (URL)
72or a HTTP request object, and returns a string containing the body of the server response.
73{{ARGUMENTS}} may be one of several forms depending on the value of the {{Content-Type}} attribute. If {{ARGUMENTS}} is unspecified, the body will be blank (i.e., a headers-only request).
74{{DELIM}} is an arbitrary separator string defaulting to the null-string.  The behaviour of {{DELIM}} is dependent on {{Content-Type}}.
75{{HEADERS}} should be either null or a list composed of {{(ATTRIBUTE . VALUE)}} pairs.  {{Connection}} and {{Content-Type}}, if unspecified, will be added automatically.  Attributes are not case sensitive.  Any attributes explicitly given in {{HEADERS}} are used, even if normally autogenerated. 
76{{CTYPE}} is the {{Content-Type}} header attribute, and defaults to {{application/x-www-form-urlencoded}}.  {{http:POST}} has special handlers for several values of {{Content-Type}} to simplify creation of the body, as given below:
77
78<nowiki>
79<table style="table-layout: auto">
80  <tr>
81    <th><tt>Content-Type</tt></th><th>Handler</th></tr>
82
83  <tr style="vertical-align: baseline">
84    <td style="padding-top: 3em">
85      <tt>application/x-www-form-urlencoded</tt></td>
86    <td style="padding-top: 3em">
87      <tt>ARGUMENTS</tt> may be a string or a list. The list may contain either <tt>(NAME . VALUE)</tt> pairs or strings of the form <tt>"name=value"</tt>.  The message body is generated as <tt>"name1=val1&amp;name2=val2..."</tt>.  <tt>DELIM</tt> is ignored.</td></tr>
88
89  <tr style="vertical-align: baseline">
90    <td style="padding-top: 4em">
91      <tt>multipart/form-data</tt></td>
92    <td style="padding-top: 4em">
93      <tt>ARGUMENTS</tt> may be a string or a list.  <tt>DELIM</tt> is used as the boundary between multipart sections, or defaults to <tt>----chicken-scheme----</tt> if absent.  <tt>DELIM</tt> is automatically added to the <tt>Content-Type</tt> header as the value of the <tt>boundary</tt> attribute.  Each element of the <tt>ARGUMENTS</tt> top-level list generates a single multipart segment, and must be composed of elements of the following types:
94
95    <table style="inline-table; table-layout: auto">
96      <tr style="vertical-align: baseline">
97        <td style="padding-top: 1.5em">
98          <tt>NAME</tt></td>
99        <td style="padding-top: 1.5em">
100          name attribute set to <tt>NAME</tt>.  Body is empty.
101        </td></tr>
102
103      <tr style="vertical-align: baseline">
104        <td style="padding-top: 2em">
105        <tt>(NAME . VALUE)</tt></td>
106        <td style="padding-top: 2em">
107          name attribute set to <tt>NAME</tt>.  Body set to <tt>VALUE</tt>.</td></tr>
108
109      <tr style="vertical-align: baseline">
110      <td style="padding-top: 2em; padding-bottom: 1.5em">
111        <tt>(NAME (ATTRIB . AVAL)... VALUE)</tt></td>
112
113      <td style="padding-top: 2em; padding-bottom: 1.5em">
114        name attribute set to <tt>NAME</tt>.  Every <tt>(ATTRIB . AVAL)</tt> pair is added to the segment header as <tt>ATTRIB="AVAL"</tt>, separated by semicolons.  If <tt>ATTRIB</tt> ends with a colon, it is added to the body to allow metadata for file transmission.  <tt>VALUE</tt> is appended to the body after attributes are processed, and must NOT be a pair.</td></tr>
115    </table>
116    </td></tr>
117
118  <tr style="vertical-align: baseline">
119  <td style="padding-top: 4em; padding-bottom: 3em">
120    everything else</td>
121  <td style="padding-top: 4em; padding-bottom: 3em">
122    <tt>ARGUMENTS</tt> may be a string or a list of strings.  Lists of strings are concatenated with <tt>DELIM</tt> as a separator.</td></tr>
123
124</table>
125</nowiki>
126
127The above alterations are performed only when {{ARGUMENTS}} is a list.  If given as a string, the body is set to the string value without any alteration.  All values other than strings or lists generate an error.
128
129The {{REQUEST}} keeps a Cookie header, as with {{http:GET}}.
130
131
132
133===== http:close-all-connections!
134
135 [procedure] (http:close-all-connections!)
136
137Close all persistent connections kept in the current thread.
138
139===== http:read-body
140
141 [procedure] (http:read-body ARGUMENTS PORT)
142
143Read the HTTP Body from the input port {{PORT}},
144according to the {{Content-Length}} header or the {{Transfer-Encoding}} header.
145
146===== http:add-proxy!
147
148 [procedure] (http:add-proxy! PROXY-HOST PROXY-PORT [SERV-PATTERN] [HOST-PATTERN] [PORT-PATTERN] [PATH-PATTERN])
149
150Add a http proxy. {{PATTERN}}s are either a string,
151a regex, or {{#t}}. The first added proxy has the least priority.
152
153Note: {{CONNECT}} method for SSL is not supported (yet).
154
155===== http:remove-all-proxies!
156
157 [procedure] (http:remove-all-proxies!)
158
159Remove all http proxies.
160
161
162===== Examples
163
164Make a regular GET.  Returns the text resulting from the GET call:
165
166  (http:GET "http://localhost/index.html")
167
168Make an HTTP/1.1 GET:
169
170  (http:GET (http:make-request
171            'GET "http://localhost/index.html"
172            '(("Connection" . "close")
173            '() "" 'HTTP/1.1)))
174
175For complicated requests, it's worth looking at the "uri" egg to construct the URL.
176==== http-server
177
178===== Usage
179
180{{(require-extension http-server)}}
181
182===== General operation
183
184The server maps URLs to ''resource-handlers'', which are procedures that process
185incoming client-requests. A resource-handler is responsible for generating a ''response''
186by writing output to the value of {{(current-output-port)}}.
187
188The data contained in a client-request is parsed by a so-called ''content-parser'',
189which is a procedure that reads the request-body from the port given by {{(current-input-port)}}.
190Content-types are encoded as symbols.
191
192A parser for {{application/x-www-form-urlencoded}} is predefined, other content-parsers
193have to be defined by application-code using the procedure {{http:content-parser}}, or the
194default parser will be invoked (which reads the content as a plain string).
195
196The content-parser for text returns the request-body as a string. The content-parser for urlencoded
197data returns the request-body as an a-list that maps variables to strings.
198
199===== http:make-server
200
201 [procedure] (http:make-server PORTNUMBER #!key NAME PROTOCOL BACKLOG ACCEPT INIT)
202
203Creates and returns a server-procedure. {{NAME}} defaults to something silly,
204{{PROTOCOL}} to {{#f}} (ignored), {{BACKLOG}} to {{40}} and {{ACCEPT}} to {{#f}}.
205{{INIT}} should be a procedure of no arguments that will be called after the
206networking initialisation has taken place (specifically, after the invocation of
207{{tcp-listen}}).
208
209To run the server-loop, invoke the returned procedure, which takes an optional boolean argument
210(passing {{#t}} will generate debugging output). {{PORTNUMBER}}, {{BACKLOG}}, and {{ACCEPT}}
211are directly passed on to {{tcp-listen}} (see [[Unit tcp]] for more information about those parameters).
212
213===== http:content-parser
214
215 [procedure] (http:content-parser CONTENTTYPE [PROC])
216
217Returns or sets the parser-procedure (a procedure of three arguments: the size of the content
218(may be {{#f}}), the a-list of request headers and an input port) for {{CONTENTTYPE}}, which
219should be a symbol.
220
221The content-parser procedure {{PROC}} should return two values: the parsed and the unparsed (raw) request body.
222
223===== http:write-response-header
224
225 [procedure] (http:write-response-header REQ [CODE MSG [ALIST [PORT [PROTOCOL]]]])
226
227Writes a HTTP response header for request {{REQ}} to {{PORT}}, containing the server-name.
228{{CODE}} and {{MSG}} default to {{200}} and {{OK}}, respectively.
229The optional {{ALIST}} may contain pairs with header-names and -values.
230If given, {{PROTOCOL}} specifes the HTTP protocol to use for the reply, which
231should be a symbol (either {{HTTP/1.0}} or {{HTTP/1.1}}) and defaults to the
232protocol given in {{http:make-server}}.
233
234===== http:write-error-response
235
236 [procedure] (http:write-error-response CODE MESSAGE [PORT])
237
238Writes a HTTP error-response to {{PORT}}, which defaults to the value of
239{{(current-output-port)}}. Uses the result returned by the value of
240{{(http:error-response-handler)}}.
241
242===== http:request-method-handler
243
244 [procedure] (http:request-method-handler METHOD [PROC])
245
246Reads ot sets the handler procedure {{PROC}} for the request-method {{METHOD}} (which should be a symbol).
247{{PROC}} should accept one argument, a request-object. During execution of the handler,
248the current input- and output ports are bound to ports connected to the client.
249
250Method-handlers for {{GET}} and {{POST}} requests are predefined.
251
252===== http:add-resource
253
254 [procedure] (http:add-resource URL HANDLER)
255
256Defines a new resource for {{URL}} (which may be a string, a symbol or a list of strings/symbols).
257{{HANDLER}} should be a procedure of two arguments: a request structure, and an a-list
258mapping urlencoded arguments to values.
259
260During execution of the handler the current input- and an output-ports are bound to ports communicating
261with the client.
262
263===== http:remove-resource
264
265 [procedure] (http:remove-resource URL)
266
267Removes the resource defined under {{URL}} (string, symbol or list).
268
269===== http:find-resource
270
271 [procedure] (http:find-resource URL)
272
273Returns the handler-procedure for the resource defined under {{URL}} or {{#f}}
274if no such resource is registered.
275
276===== http:fallback-handler
277
278 [parameter] http:fallback-handler
279
280Contains a procedure that is is invoked on requests for resources that could not be found.
281This procedure is then called with the original request object. The default handler generates a 404 response.
282
283===== http:error-response-handler
284
285 [parameter] http:error-response-handler
286
287Contains a procedure that will be called when an HTTP error-response should be generated.
288The procedure is called with the error-code and message and should return a string containing HTML
289that will be sent in the body of the error-response.
290
291===== http:current-request-count
292
293 [procedure] (http:current-request-count)
294
295Returns the number of requests handled since startup.
296
297===== http:request-count-limit
298
299 [parameter] http:request-count-limit
300
301Maximum number of concurrently handled requests.
302
303===== http:startup-hook
304
305 [parameter] http:startup-hook
306
307A procedure that will be called on server startup, before accepting first request.
308The default procedure does nothing.
309
310===== http:error-hook
311
312 [parameter] http:error-hook
313
314A procedure that will be called when a thread triggers an unhandled exception.
315The exception is passed as an argument to the hook procedure.
316
317===== http:log-hook
318
319 [parameter] http:log-hook
320
321A procedure that will be called upon completion of a HTTP request. The procedure will be called
322with two arguments: the request object and the IP address of the client. The default value of this
323parameter does nothing.
324
325===== http:url-transformation
326
327 [parameter] http:url-transformation
328
329A procedure that allows arbitrary transformations of the URL part of each incoming request. The procedure
330is called with a single argument (the URL string) and should return the same URL, or a transformed one.
331The default transformation returns the original url unchanged.
332
333===== http:listen-procedure
334
335 [parameter] http:listen-procedure
336
337Holds a procedure that will be used to create a socket-listener - defaults to {{tcp-listen}}.
338
339===== http:accept-procedure
340
341 [parameter] http:accept-procedure
342
343Holds a procedure that will be used to accept a socket-connection - defaults to {{tcp-accept}}.
344
345===== http:get-addresses-procedure
346
347 [parameter] http:get-addresses-procedure
348
349Holds a procedure that will be used to obtain peer addresses - defaults to {{tcp-addresses}}.
350
351===== http:hard-close-procedure
352
353 [parameter] http:hard-close-procedure
354
355Holds a procedure that will be used to close a connection prematurely - defaults to {{tcp-abandon-port}}.
356
357==== http-utils
358
359
360===== Usage
361
362{{(require-extension http-utils)}}
363
364
365===== http:decode-url
366
367 [procedure] (http:decode-url URL)
368
369Canonicalizes the string passed in {{URL}} and returns two values:
370the location-path and an alist containing argument <-> value pairs.
371
372
373===== http:make-request
374
375 [procedure] (http:make-request METHOD URL [ATTRIBUTES [BODY [PROTOCOL [IP]]]])
376
377Returns a freshly created HTTP request object (see below for the meaning of the arguments).
378
379===== http:request?
380
381 [procedure] (http:request? X)
382
383Returns {{#t}} if {{X}} is a request object, or {{#f}} otherwise.
384
385
386===== http-request accessor methods
387
388 [procedure] (http:request-url REQUEST) -> URL
389 [procedure] (http:request-protocol REQUEST) -> PROTOCOL
390 [procedure] (http:request-attributes REQUEST) -> ATTRIBUTES
391 [procedure] (http:request-body REQUEST) -> X
392 [procedure] (http:request-method REQUEST) -> METHOD
393 [procedure] (http:request-ip REQUEST) -> STRING
394 [procedure] (http:request-sslctx REQUEST) -> <ssl-client-context>
395 [procedure] (http:request-url-set! REQUEST URL)
396 [procedure] (http:request-protocol-set! REQUEST PROTOCOL)
397 [procedure] (http:request-attributes-set! REQUEST ATTRIBUTES)
398 [procedure] (http:request-body-set! REQUEST X)
399 [procedure] (http:request-method-set! REQUEST METHOD)
400 [procedure] (http:request-ip-set! REQUEST STRING)
401 [procedure] (http:request-sslctx-set! REQUEST <ssl-client-context>)
402
403Accessor procedures for the components of a HTTP request structure. {{URL}} is a string,
404{{METHOD}} and {{PROTOCOL}} are symbols, {{BODY}} is either {{#f}}
405or a string and {{ATTRIBUTES}} is an a-list where each pair contains an attribute
406string and a value string.
407
408
409
410===== http:request attribute methods
411
412 [procedure] (http:request-attribute-get REQUEST ATTRIB [DEFAULT {{#f}}])
413
414Accessor procedure to get the value of {{ATTRIB}} in {{REQUEST}}.  If {{ATTRIB}} is not present in request, {{DEFAULT}} is returned.  The search is case-insensitive.  Note that this only returns the value; the attribute name is NOT returned.
415
416 [procedure] (http:request-attribute-add! REQUEST ATTRIB AVAL)
417
418Adds {{ATTRIB}} to {{REQUEST}}'s attribute list with its value set to {{AVAL}}.  If {{ATTRIB}} already appears in the list (case-insensitive), its value is set to {{AVAL}} and it retains its position in the list; otherwise, the {{(ATTRIB . AVAL)}} pair is added to the end.
419
420
421 [procedure] (http:request-attribute-del! REQUEST ATTRIB)
422
423Removes {{ATTRIB}} from the attribute list in {{REQUEST}}, if it exists (case-insensitive search).  The order of the attribute list is not altered  aside from the removal.  It is not an error for {{ATTRIB}} to not appear in the list.
424
425
426===== http:read-line-limit
427
428 [parameter] http:read-line-limit
429
430The maximum length of a header-line.
431
432===== http:read-request-attributes
433
434 [procedure] (http:read-request-attributes PORT)
435
436Reads MIME type headers from {{PORT}} until end of file is reached or a line
437is not a valid MIME header and returns an a-list where each pair holds the header
438(converted to lowercase) and the value (both strings).
439
440===== http:canonicalize-string
441
442 [procedure] (http:canonicalize-string STRING)
443
444Canonicalizes {{STRING}} by substituting {{%XX}} and {{+}} sequences.
445
446
447=== Examples
448
449==== Server example
450
451A simple "Hello, world" server:
452
453<enscript highlight=scheme>
454(require-extension http-server)
455
456(http:add-resource '("/" "/index.html")
457  (lambda (r a)
458    (let ([msg "&lt;h1>Hello, world!&lt;/h1>"])
459      (http:write-response-header
460        r
461        200
462        "OK"
463        `(("Content-type" . "test/html")
464          ("Content-length" . ,(string-length msg))))
465      (display msg) ) ) )
466
467((http:make-server 4242) #t)
468</enscript>
469
470To try it out, simply load the code into the interpreter and point your browser to
471[[http://localhost:4242/|localhost:4242]].
472
473==== Client example
474
475<enscript highlight=scheme>
476(require-extension http-client)
477
478(define-values (h a i o) (http:send-request "localhost:4242/"))
479
480(pretty-print (http:read-body a i))
481(close-input-port i)
482(close-output-port o)
483</enscript>
484
485Loading this into the interpreter will print
486
487 ("<h1>Hello, world!</h1>")
488
489(provided the hello-world server is running)
490
491
492=== Changelog
493* 2.5 Reduce GC in {{http:canonicalize-string}}, improving POST handling time. [Jim Ursetto]
494* 2.4 Changed POST method; added multipart handling; added utility functions for query and modification of attributes in request objects, changed the build order. (elf)
495* 2.3 Yet another .setup fix related to the make macro (related to SVN revision 7145).
496* 2.2 Another .setup fix (related to the make macro).
497* 2.1 .setup fix to work with chicken from SVN trunk.
498* 2.0 Move http keep-alive header management from [[spiffy]] to http. This breaks backwards-compatibility because {{http:write-response-header}} needs the request object passed to it. ([[http://trac.callcc.org/ticket/311|Ticket #311]])
499* 1.58 Compatibility upgrade: removed deprecated Chicken functions.
500* 1.57 Added keep-alive support to http-server [Daishi Kato]
501* 1.56 Fixed bug in request content processing with POST forms
502* 1.55 Remove silly default "location" header ([[http://trac.callcc.org/ticket/339|ticket #339]]) [Daishi Kato]
503* 1.54 Fix passing of POST arguments to handlers defined with {{http:add-resource}}
504* 1.53 Generation of debugging info from {{get/post-handler}} ([[http://trac.callcc.org/ticket/253|ticket #253]]) [Mario Goulart]
505* 1.52 Added requirement of [[url]] egg to meta info [thanks to Mario Goulart]
506* 1.51 Client fix for handling closed keep-alive connections [Daishi Kato]
507* 1.50 Client API for http proxies [Daishi Kato]
508* 1.49 Client API flushes output before reading to be able to work with buffered ports
509* 1.48 Bugfix in http-client.scm [Daishi Kato]
510* 1.47 Removed multipart support, added unparsed request body field, content-parsers return additional raw body
511* 1.46 Bugfix in {{url-parser}}
512* 1.45 Cookie hack for http:GET and http:POST [Daishi Kato]
513* 1.44 {{http:POST}} now handles www-form-urlencoded content-type, which is the default [Daishi Kato]
514* 1.43 Client support for chunked transfer encoding [Daishi Kato]
515* 1.42 Client support for persistent connections [Daishi Kato]
516* 1.41 Client support for https (requires openssl egg) [Daishi Kato]
517* 1.40 Client requests did finalize ports in the wrong situation [Thanks to Tim Reid]
518* 1.39 URL canonicaliation fix #2 [Thanks to Zbigniew Szadkowski]
519* 1.38 URL-canonicalization fix by Peter Busser
520* 1.37 Added hidden slot to request-structure
521* 1.36 Fixed bug in {{http:write-error-response}} [Thanks to Peter Bex]
522* 1.35 Any error-response forces closing of client connection [Suggested by Diashi Kato]
523* 1.34 Added {{-lws2_32}} to build-command for {{http-client}} on Windows [Thanks to Daishi Kato]
524* 1.33 Added parameterized socket operations to server
525* 1.32 Adapted to SRFI-69 compatible hash-tables
526* 1.31 The ports returned by {{http:send-request}}, {{http:GET}} and {{http:POST}} are finalized [Thanks to Reed Sheridan]
527* 1.30 Added {{ip}} field to request object
528* 1.29 Added {{http:url-transformation}}, debug output includes response headers
529* 1.28 Replaced use of {{(end-of-file)}} with {{#!eof}}
530* 1.27 Added {{http:request-limit}}; fixed {{http:POST}} (which didn't
531handle the second argument always correctly)
532* 1.26 Special-cased regex strings to work around pregexp bugs [Thanks to Peter Bex]
533* 1.25 Retries on failed {{tcp-accept}}, error-message output is limited
534* 1.24 Fixed bug in server example [Thanks to Graham Fawcett]
535* 1.23 Added note about SIGPIPE [Thanks Graham Fawcett]
536* 1.22 Fixed regex bug in {{http-utils.scm}} [Thanks to Patrick Brannan]
537* 1.21 Added {{http:log-hook}}
538* 1.20 Content-parser got a third argument (attribute a-list); support for {{multipart/form-data}} content type; default handler for unknown content types
539* 1.19 Added documentation for {{http:read-request-attributes}}
540* 1.18 Added {{http:GET}} and {{http:POST}}
541* 1.17 URL parsing of requests and header-generation is somewhat more robust [Thanks to Peter Bex]
542* 1.16 {{http:send-request}} assumed old meaning of request body
543* 1.15 If the content-type is not known, a request-body has the empty list ({{()}}) as the body [Thanks to Peter Bex]
544* 1.14 Urlencoded arguments without argument are handled better and escapes in the argument name are processed correctly
545* 1.13 URL parsing regex fix #394493849 [Thanks to Lars Rustemeier]
546* 1.12 Added {{http:current-request-count}}
547* 1.11 {{http:make-server}} takes keyword arguments now and accepts two additional arguments
548* 1.10 {{http:write-response-header}} accepts yet another optional argument (protocol)
549* 1.9 Fixed bug that required {{uint32_t}} which wasn't necessarily everywhere available [Thanks to Mikel Evins]
550* 1.8 Adapted to new setup scheme
551* 1.7 URL parsing in {{(http-client)}} again. Will it ever stop?
552* 1.6 URL parsing in {{(http-client)}} works now with PCRE
553* 1.5 Fixed bug in regular expression for URL parsing and another one in the regexp for HTTP headers
554* 1.4 The URL parsing in {{(http-client)}} didn't handle {{XXX.XXX.XXX.XXX}}-style URLs [Thanks to Lars Rustemeier]
555* 1.3 {{http:write-response-header}} doesn't override headers given in the alist.
556* 1.2 {{http:write-response-header}} accepts more optional arguments.
557Added default content-parser for {{application/x-www-form-urlencoded}} bodies.
558{{http:canonicalize-string}}.
559* 1.1 The {{content-type}} from a request may be followed by optional parameters.
560Fixed bug in {{canonicalize-string}}. The argument to the fallback-handler
561is now a request object.
562* 1.0 Initial release
563
564=== License
565
566 Copyright (c) 2003, Felix L. Winkelmann
567 All rights reserved.
568 
569 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
570 conditions are met:
571 
572   Redistributions of source code must retain the above copyright notice, this list of conditions and the following
573     disclaimer.
574   Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
575     disclaimer in the documentation and/or other materials provided with the distribution.
576   Neither the name of the author nor the names of its contributors may be used to endorse or promote
577     products derived from this software without specific prior written permission.
578 
579 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
580 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
581 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
582 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
583 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
584 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
585 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
586 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
587 POSSIBILITY OF SUCH DAMAGE.
Note: See TracBrowser for help on using the repository browser.