[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
7.3.9 Web Server
(web server)
is a generic web server interface, along with a main
loop implementation for web servers controlled by Guile.
(use-modules (web server))
The lowest layer is the <server-impl>
object, which defines a set
of hooks to open a server, read a request from a client, write a
response to a client, and close a server. These hooks – open
,
read
, write
, and close
, respectively – are bound
together in a <server-impl>
object. Procedures in this module take a
<server-impl>
object, if needed.
A <server-impl>
may also be looked up by name. If you pass the
http
symbol to run-server
, Guile looks for a variable
named http
in the (web server http)
module, which should
be bound to a <server-impl>
object. Such a binding is made by
instantiation of the define-server-impl
syntax. In this way the
run-server loop can automatically load other backends if available.
The life cycle of a server goes as follows:
-
The
open
hook is called, to open the server.open
takes zero or more arguments, depending on the backend, and returns an opaque server socket object, or signals an error. -
The
read
hook is called, to read a request from a new client. Theread
hook takes one argument, the server socket. It should return three values: an opaque client socket, the request, and the request body. The request should be a<request>
object, from(web request)
. The body should be a string or a bytevector, or#f
if there is no body.If the read failed, the
read
hook may return #f for the client socket, request, and body. -
A user-provided handler procedure is called, with the request and body
as its arguments. The handler should return two values: the response,
as a
<response>
record from(web response)
, and the response body as bytevector, or#f
if not present.The respose and response body are run through
sanitize-response
, documented below. This allows the handler writer to take some convenient shortcuts: for example, instead of a<response>
, the handler can simply return an alist of headers, in which case a default response object is constructed with those headers. Instead of a bytevector for the body, the handler can return a string, which will be serialized into an appropriate encoding; or it can return a procedure, which will be called on a port to write out the data. See thesanitize-response
documentation, for more. -
The
write
hook is called with three arguments: the client socket, the response, and the body. Thewrite
hook returns no values. - At this point the request handling is complete. For a loop, we loop back and try to read a new request.
-
If the user interrupts the loop, the
close
hook is called on the server socket.
A user may define a server implementation with the following form:
- Scheme Syntax: define-server-impl name open read write close
Make a
<server-impl>
object with the hooks open, read, write, and close, and bind it to the symbol name in the current module.
- Scheme Procedure: lookup-server-impl impl
Look up a server implementation. If impl is a server implementation already, it is returned directly. If it is a symbol, the binding named impl in the
(web server impl)
module is looked up. Otherwise an error is signaled.Currently a server implementation is a somewhat opaque type, useful only for passing to other procedures in this module, like
read-client
.
The (web server)
module defines a number of routines that use
<server-impl>
objects to implement parts of a web server. Given
that we don’t expose the accessors for the various fields of a
<server-impl>
, indeed these routines are the only procedures with
any access to the impl objects.
- Scheme Procedure: open-server impl open-params
Open a server for the given implementation. Return one value, the new server object. The implementation’s
open
procedure is applied to open-params, which should be a list.
- Scheme Procedure: read-client impl server
Read a new client from server, by applying the implementation’s
read
procedure to the server. If successful, return three values: an object corresponding to the client, a request object, and the request body. If any exception occurs, return#f
for all three values.
- Scheme Procedure: handle-request handler request body state
Handle a given request, returning the response and body.
The response and response body are produced by calling the given handler with request and body as arguments.
The elements of state are also passed to handler as arguments, and may be returned as additional values. The new state, collected from the handler’s return values, is then returned as a list. The idea is that a server loop receives a handler from the user, along with whatever state values the user is interested in, allowing the user’s handler to explicitly manage its state.
- Scheme Procedure: sanitize-response request response body
“Sanitize” the given response and body, making them appropriate for the given request.
As a convenience to web handler authors, response may be given as an alist of headers, in which case it is used to construct a default response. Ensures that the response version corresponds to the request version. If body is a string, encodes the string to a bytevector, in an encoding appropriate for response. Adds a
content-length
andcontent-type
header, as necessary.If body is a procedure, it is called with a port as an argument, and the output collected as a bytevector. In the future we might try to instead use a compressing, chunk-encoded port, and call this procedure later, in the write-client procedure. Authors are advised not to rely on the procedure being called at any particular time.
- Scheme Procedure: write-client impl server client response body
Write an HTTP response and body to client. If the server and client support persistent connections, it is the implementation’s responsibility to keep track of the client thereafter, presumably by attaching it to the server argument somehow.
- Scheme Procedure: close-server impl server
Release resources allocated by a previous invocation of
open-server
.
Given the procedures above, it is a small matter to make a web server:
- Scheme Procedure: serve-one-client handler impl server state
Read one request from server, call handler on the request and body, and write the response to the client. Return the new state produced by the handler procedure.
- Scheme Procedure: run-server handler [impl='http] [open-params='()] arg …
Run Guile’s built-in web server.
handler should be a procedure that takes two or more arguments, the HTTP request and request body, and returns two or more values, the response and response body.
For examples, skip ahead to the next section, Web Examples.
The response and body will be run through
sanitize-response
before sending back to the client.Additional arguments to handler are taken from arg .... These arguments comprise a state. Additional return values are accumulated into a new state, which will be used for subsequent requests. In this way a handler can explicitly manage its state.
The default web server implementation is http
, which binds to a
socket, listening for request on that port.
- HTTP Implementation: http [#:host=#f] [#:family=AF_INET] [#:addr=INADDR_LOOPBACK] [#:port 8080] [#:socket]
The default HTTP implementation. We document it as a function with keyword arguments, because that is precisely the way that it is – all of the open-params to
run-server
get passed to the implementation’s open function.;; The defaults: localhost:8080 (run-server handler) ;; Same thing (run-server handler 'http '()) ;; On a different port (run-server handler 'http '(#:port 8081)) ;; IPv6 (run-server handler 'http '(#:family AF_INET6 #:port 8081)) ;; Custom socket (run-server handler 'http `(#:socket ,(sudo-make-me-a-socket)))
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated on April 20, 2013 using texi2html 5.0.