Outdated egg!
This is an egg for CHICKEN 3, the unsupported old release. You're almost certainly looking for the CHICKEN 4 version of this egg, if it exists.
If it does not exist, there may be equivalent functionality provided by another egg; have a look at the egg index. Otherwise, please consider porting this egg to the current version of CHICKEN.
http
- Outdated egg!
- http
- Description
- Author
- Requirements
- Documentation
- http-client
- http-server
- Usage
- General operation
- http:make-server
- http:content-parser
- http:write-response-header
- http:write-error-response
- http:request-method-handler
- http:add-resource
- http:remove-resource
- http:find-resource
- http:fallback-handler
- http:error-response-handler
- http:current-request-count
- http:request-count-limit
- http:startup-hook
- http:error-hook
- http:log-hook
- http:url-transformation
- http:restart-request
- http:listen-procedure
- http:accept-procedure
- http:get-addresses-procedure
- http:hard-close-procedure
- http-utils
- Examples
- Changelog
- License
Description
An easy to use HTTP client and server package. The server is fully multithreaded and supports persistent connections.
Author
Requirements
Requires the regex-case egg at compile-time.
http-client requires the url egg at runtime.
Both http-client and http-server require the http-utils module at runtime.
Documentation
What follows is a description of the http extension, which is separated into three sub-extensions: http-client (HTTP client functionality), http-server (serving HTTP requests) and http-utils (utility functions common to client and server code).
If you want to run a web-server, you should also take a look at the more featureful spiffy extension.
http-client
Usage
(require-extension http-client)
http:send-request
[procedure] (http:send-request REQUEST [INPUT-PORT OUTPUT-PORT])
Sends an HTTP request represented by REQUEST, which may either be a HTTP request object, or a string that specifies an URL. The request is sent to it's destination and four values are returned: a string containing the first line of the response received from the server, an a-list that maps HTTP headers to values (strings) and the input- and output-port of the connection. Note that the connection is still open, and the returned ports can be passed in subsequent invocations of http:send-request to achieve a persistent connection. The ports are closed automatically, if no longer referenced.
If an URL is given instead of a request record, a request is sent of the form
GET url HTTP/1.0 Connection: close
http:GET
[procedure] (http:GET REQUEST)
Sends a GET request represented by REQUEST, which may be a string (an URL) or a HTTP request object, and returns a string containing the body of the servers response. The REQUEST keeps a Cookie header that is set by Set-Cookie headers in a response, unsafely (hack), regardless of the storing policy. Be aware of it when reusing REQUEST.
http:POST
[procedure] (http:POST REQUEST [ARGUMENTS] #!key [headers: HEADERS] [type: CTYPE] [delim: DELIM])
Sends a POST request represented by REQUEST, which may be a string (URL) or a HTTP request object, and returns a string containing the body of the server response. 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). DELIM is an arbitrary separator string defaulting to the null-string. The behaviour of DELIM is dependent on Content-Type. 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. 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:
Content-Type | Handler | ||||||
---|---|---|---|---|---|---|---|
application/x-www-form-urlencoded | ARGUMENTS may be a string or a list. The list may contain either (NAME . VALUE) pairs or strings of the form "name=value". The message body is generated as "name1=val1&name2=val2...". DELIM is ignored. | ||||||
multipart/form-data |
ARGUMENTS may be a string or a list. DELIM is used as the boundary between multipart sections, or defaults to ----chicken-scheme---- if absent. DELIM is automatically added to the Content-Type header as the value of the boundary attribute. Each element of the ARGUMENTS top-level list generates a single multipart segment, and must be composed of elements of the following types:
| ||||||
everything else | ARGUMENTS may be a string or a list of strings. Lists of strings are concatenated with DELIM as a separator. |
The 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.
The REQUEST keeps a Cookie header, as with http:GET.
http:close-all-connections!
[procedure] (http:close-all-connections!)
Close all persistent connections kept in the current thread.
http:read-body
[procedure] (http:read-body ARGUMENTS PORT)
Read the HTTP Body from the input port PORT, according to the Content-Length header or the Transfer-Encoding header.
http:add-proxy!
[procedure] (http:add-proxy! PROXY-HOST PROXY-PORT [SERV-PATTERN] [HOST-PATTERN] [PORT-PATTERN] [PATH-PATTERN])
Add a http proxy. PATTERNs are either a string, a regex, or #t. The first added proxy has the least priority.
Note: CONNECT method for SSL is not supported (yet).
http:remove-all-proxies!
[procedure] (http:remove-all-proxies!)
Remove all http proxies.
Examples
Make a regular GET. Returns the text resulting from the GET call:
(http:GET "http://localhost/index.html")
Make an HTTP/1.1 GET:
(http:GET (http:make-request 'GET "http://localhost/index.html" '(("Connection" . "close") '() "" 'HTTP/1.1)))
For complicated requests, it's worth looking at the "uri" egg to construct the URL.
http-server
Usage
(require-extension http-server)
General operation
The server maps URLs to resource-handlers, which are procedures that process incoming client-requests. A resource-handler is responsible for generating a response by writing output to the value of (current-output-port).
The data contained in a client-request is parsed by a so-called content-parser, which is a procedure that reads the request-body from the port given by (current-input-port). Content-types are encoded as symbols.
A parser for application/x-www-form-urlencoded is predefined, other content-parsers have to be defined by application-code using the procedure http:content-parser, or the default parser will be invoked (which reads the content as a plain string).
The content-parser for text returns the request-body as a string. The content-parser for urlencoded data returns the request-body as an a-list that maps variables to strings.
http:make-server
[procedure] (http:make-server PORTNUMBER #!key NAME PROTOCOL BACKLOG ACCEPT INIT)
Creates and returns a server-procedure. NAME defaults to something silly, PROTOCOL to #f (ignored), BACKLOG to 40 and ACCEPT to #f. INIT should be a procedure of no arguments that will be called after the networking initialisation has taken place (specifically, after the invocation of tcp-listen).
To run the server-loop, invoke the returned procedure, which takes an optional boolean argument (passing #t will generate debugging output). PORTNUMBER, BACKLOG, and ACCEPT are directly passed on to tcp-listen (see Unit tcp for more information about those parameters).
http:content-parser
[procedure] (http:content-parser CONTENTTYPE [PROC])
Returns or sets the parser-procedure (a procedure of three arguments: the size of the content (may be #f), the a-list of request headers and an input port) for CONTENTTYPE, which should be a symbol.
The content-parser procedure PROC should return two values: the parsed and the unparsed (raw) request body.
http:write-response-header
[procedure] (http:write-response-header REQ [CODE MSG [ALIST [PORT [PROTOCOL]]]])
Writes a HTTP response header for request REQ to PORT, containing the server-name. CODE and MSG default to 200 and OK, respectively. The optional ALIST may contain pairs with header-names and -values. If given, PROTOCOL specifes the HTTP protocol to use for the reply, which should be a symbol (either HTTP/1.0 or HTTP/1.1) and defaults to the protocol given in http:make-server.
http:write-error-response
[procedure] (http:write-error-response CODE MESSAGE [PORT])
Writes a HTTP error-response to PORT, which defaults to the value of (current-output-port). Uses the result returned by the value of (http:error-response-handler).
http:request-method-handler
[procedure] (http:request-method-handler METHOD [PROC])
Reads ot sets the handler procedure PROC for the request-method METHOD (which should be a symbol). PROC should accept one argument, a request-object. During execution of the handler, the current input- and output ports are bound to ports connected to the client.
Method-handlers for GET and POST requests are predefined.
http:add-resource
[procedure] (http:add-resource URL HANDLER)
Defines a new resource for URL (which may be a string, a symbol or a list of strings/symbols). HANDLER should be a procedure of two arguments: a request structure, and an a-list mapping urlencoded arguments to values.
During execution of the handler the current input- and an output-ports are bound to ports communicating with the client.
http:remove-resource
[procedure] (http:remove-resource URL)
Removes the resource defined under URL (string, symbol or list).
http:find-resource
[procedure] (http:find-resource URL)
Returns the handler-procedure for the resource defined under URL or #f if no such resource is registered.
http:fallback-handler
[parameter] http:fallback-handler
Contains a procedure that is is invoked on requests for resources that could not be found. This procedure is then called with the original request object. The default handler generates a 404 response.
http:error-response-handler
[parameter] http:error-response-handler
Contains a procedure that will be called when an HTTP error-response should be generated. The procedure is called with the error-code and message and should return a string containing HTML that will be sent in the body of the error-response.
http:current-request-count
[procedure] (http:current-request-count)
Returns the number of requests handled since startup.
http:request-count-limit
[parameter] http:request-count-limit
Maximum number of concurrently handled requests.
http:startup-hook
[parameter] http:startup-hook
A procedure that will be called on server startup, before accepting first request. The default procedure does nothing.
http:error-hook
[parameter] http:error-hook
A procedure that will be called when a thread triggers an unhandled exception. The exception is passed as an argument to the hook procedure.
http:log-hook
[parameter] http:log-hook
A procedure that will be called upon completion of a HTTP request. The procedure will be called with two arguments: the request object and the IP address of the client. The default value of this parameter does nothing.
http:url-transformation
[parameter] http:url-transformation
A procedure that allows arbitrary transformations of the URL part of each incoming request. The procedure is called with a single argument (the URL string) and should return the same URL, or a transformed one. The default transformation returns the original url unchanged.
http:restart-request
[procedure] (http:restart-request REQUEST)
In case http:url-transformation is not useful (for example, when the need for a rewrite can only be discovered at a later stage in the request or when more than just the URL needs to be rewritten (for example when a header or POST data needs rewriting), you can use http:restart-request to restart the entire request processing. The REQUEST object should be the request that the http server sees as if it were sent by the client.
Be very careful: restarting requests can lead to infinite loops, so test your restart logic well.
http:listen-procedure
[parameter] http:listen-procedure
Holds a procedure that will be used to create a socket-listener - defaults to tcp-listen.
http:accept-procedure
[parameter] http:accept-procedure
Holds a procedure that will be used to accept a socket-connection - defaults to tcp-accept.
http:get-addresses-procedure
[parameter] http:get-addresses-procedure
Holds a procedure that will be used to obtain peer addresses - defaults to tcp-addresses.
http:hard-close-procedure
[parameter] http:hard-close-procedure
Holds a procedure that will be used to close a connection prematurely - defaults to tcp-abandon-port.
http-utils
Usage
(require-extension http-utils)
http:decode-url
[procedure] (http:decode-url URL)
Canonicalizes the string passed in URL and returns two values: the location-path and an alist containing argument <-> value pairs.
http:make-request
[procedure] (http:make-request METHOD URL [ATTRIBUTES [BODY [PROTOCOL [IP]]]])
Returns a freshly created HTTP request object (see below for the meaning of the arguments).
http:request?
[procedure] (http:request? X)
Returns #t if X is a request object, or #f otherwise.
http-request accessor methods
[procedure] (http:request-url REQUEST) -> URL [procedure] (http:request-protocol REQUEST) -> PROTOCOL [procedure] (http:request-attributes REQUEST) -> ATTRIBUTES [procedure] (http:request-body REQUEST) -> X [procedure] (http:request-method REQUEST) -> METHOD [procedure] (http:request-ip REQUEST) -> STRING [procedure] (http:request-sslctx REQUEST) -> <ssl-client-context> [procedure] (http:request-url-set! REQUEST URL) [procedure] (http:request-protocol-set! REQUEST PROTOCOL) [procedure] (http:request-attributes-set! REQUEST ATTRIBUTES) [procedure] (http:request-body-set! REQUEST X) [procedure] (http:request-method-set! REQUEST METHOD) [procedure] (http:request-ip-set! REQUEST STRING) [procedure] (http:request-sslctx-set! REQUEST <ssl-client-context>)
Accessor procedures for the components of a HTTP request structure. URL is a string, METHOD and PROTOCOL are symbols, BODY is either #f or a string and ATTRIBUTES is an a-list where each pair contains an attribute string and a value string.
http:request attribute methods
[procedure] (http:request-attribute-get REQUEST ATTRIB [DEFAULT {{#f}}])
Accessor 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.
[procedure] (http:request-attribute-add! REQUEST ATTRIB AVAL)
Adds 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.
[procedure] (http:request-attribute-del! REQUEST ATTRIB)
Removes 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.
http:read-line-limit
[parameter] http:read-line-limit
The maximum length of a header-line.
http:read-request-attributes
[procedure] (http:read-request-attributes PORT)
Reads MIME type headers from PORT until end of file is reached or a line is not a valid MIME header and returns an a-list where each pair holds the header (converted to lowercase) and the value (both strings).
http:canonicalize-string
[procedure] (http:canonicalize-string STRING)
Canonicalizes STRING by substituting %XX and + sequences.
Examples
Server example
A simple "Hello, world" server:
(require-extension http-server) (http:add-resource '("/" "/index.html") (lambda (r a) (let ([msg "<h1>Hello, world!</h1>"]) (http:write-response-header r 200 "OK" `(("Content-type" . "text/html") ("Content-length" . ,(string-length msg)))) (display msg) ) ) ) ((http:make-server 4242) #t)
To try it out, simply load the code into the interpreter and point your browser to localhost:4242.
Client example
(require-extension http-client) (define-values (h a i o) (http:send-request "localhost:4242/")) (pretty-print (http:read-body a i)) (close-input-port i) (close-output-port o)
Loading this into the interpreter will print
("<h1>Hello, world!</h1>")
(provided the hello-world server is running)
Changelog
- 2.8 Implemented a fix to prevent sending of the port number in Host header lines when the default port is used. This causes better interoperability with some broken webservers (reported by Drew Hess). Added error-handling to http-client for the case when remote closes connection unexpectedly. Added better handling for HTTP/1.1 server - HTTP/1.0 client interaction.
- 2.7 Implemented http:restart-request and fixed a bug that caused a 'bad rqust' when empty headers were sent (reported by Drew Hess)
- 2.5.2 Fixed HTTP version mismatch when no explicit version was set by the server and the client sent HTTP/1.0, changed Connection: keep-alive to Connection: close when http:force-close was #t and using HTTP/1.0.
- 2.5 Reduce GC in http:canonicalize-string, improving POST handling time. [Jim Ursetto]
- 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)
- 2.3 Yet another .setup fix related to the make macro (related to SVN revision 7145).
- 2.2 Another .setup fix (related to the make macro).
- 2.1 .setup fix to work with chicken from SVN trunk.
- 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. (Ticket #311)
- 1.58 Compatibility upgrade: removed deprecated Chicken functions.
- 1.57 Added keep-alive support to http-server [Daishi Kato]
- 1.56 Fixed bug in request content processing with POST forms
- 1.55 Remove silly default "location" header (ticket #339) [Daishi Kato]
- 1.54 Fix passing of POST arguments to handlers defined with http:add-resource
- 1.53 Generation of debugging info from get/post-handler (ticket #253) [Mario Goulart]
- 1.52 Added requirement of url egg to meta info [thanks to Mario Goulart]
- 1.51 Client fix for handling closed keep-alive connections [Daishi Kato]
- 1.50 Client API for http proxies [Daishi Kato]
- 1.49 Client API flushes output before reading to be able to work with buffered ports
- 1.48 Bugfix in http-client.scm [Daishi Kato]
- 1.47 Removed multipart support, added unparsed request body field, content-parsers return additional raw body
- 1.46 Bugfix in url-parser
- 1.45 Cookie hack for http:GET and http:POST [Daishi Kato]
- 1.44 http:POST now handles www-form-urlencoded content-type, which is the default [Daishi Kato]
- 1.43 Client support for chunked transfer encoding [Daishi Kato]
- 1.42 Client support for persistent connections [Daishi Kato]
- 1.41 Client support for https (requires openssl egg) [Daishi Kato]
- 1.40 Client requests did finalize ports in the wrong situation [Thanks to Tim Reid]
- 1.39 URL canonicaliation fix #2 [Thanks to Zbigniew Szadkowski]
- 1.38 URL-canonicalization fix by Peter Busser
- 1.37 Added hidden slot to request-structure
- 1.36 Fixed bug in http:write-error-response [Thanks to Peter Bex]
- 1.35 Any error-response forces closing of client connection [Suggested by Diashi Kato]
- 1.34 Added -lws2_32 to build-command for http-client on Windows [Thanks to Daishi Kato]
- 1.33 Added parameterized socket operations to server
- 1.32 Adapted to SRFI-69 compatible hash-tables
- 1.31 The ports returned by http:send-request, http:GET and http:POST are finalized [Thanks to Reed Sheridan]
- 1.30 Added ip field to request object
- 1.29 Added http:url-transformation, debug output includes response headers
- 1.28 Replaced use of (end-of-file) with #!eof
- 1.27 Added http:request-limit; fixed http:POST (which didn't handle the second argument always correctly)
- 1.26 Special-cased regex strings to work around pregexp bugs [Thanks to Peter Bex]
- 1.25 Retries on failed tcp-accept, error-message output is limited
- 1.24 Fixed bug in server example [Thanks to Graham Fawcett]
- 1.23 Added note about SIGPIPE [Thanks Graham Fawcett]
- 1.22 Fixed regex bug in http-utils.scm [Thanks to Patrick Brannan]
- 1.21 Added http:log-hook
- 1.20 Content-parser got a third argument (attribute a-list); support for multipart/form-data content type; default handler for unknown content types
- 1.19 Added documentation for http:read-request-attributes
- 1.18 Added http:GET and http:POST
- 1.17 URL parsing of requests and header-generation is somewhat more robust [Thanks to Peter Bex]
- 1.16 http:send-request assumed old meaning of request body
- 1.15 If the content-type is not known, a request-body has the empty list (()) as the body [Thanks to Peter Bex]
- 1.14 Urlencoded arguments without argument are handled better and escapes in the argument name are processed correctly
- 1.13 URL parsing regex fix #394493849 [Thanks to Lars Rustemeier]
- 1.12 Added http:current-request-count
- 1.11 http:make-server takes keyword arguments now and accepts two additional arguments
- 1.10 http:write-response-header accepts yet another optional argument (protocol)
- 1.9 Fixed bug that required uint32_t which wasn't necessarily everywhere available [Thanks to Mikel Evins]
- 1.8 Adapted to new setup scheme
- 1.7 URL parsing in (http-client) again. Will it ever stop?
- 1.6 URL parsing in (http-client) works now with PCRE
- 1.5 Fixed bug in regular expression for URL parsing and another one in the regexp for HTTP headers
- 1.4 The URL parsing in (http-client) didn't handle XXX.XXX.XXX.XXX-style URLs [Thanks to Lars Rustemeier]
- 1.3 http:write-response-header doesn't override headers given in the alist.
- 1.2 http:write-response-header accepts more optional arguments. Added default content-parser for application/x-www-form-urlencoded bodies. http:canonicalize-string.
- 1.1 The content-type from a request may be followed by optional parameters. Fixed bug in canonicalize-string. The argument to the fallback-handler is now a request object.
- 1.0 Initial release
License
Copyright (c) 2003, Felix L. Winkelmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.