Next: , Previous: cookies, Up: Top


13 (www server-utils answer)

The (www server-utils answer) module provides a simple wrapper around the formatting/accounting requirements of a standard HTTP response. Additionally, the #:rechunk-content facility allows some degree of performance tuning; a server may be able to achieve better throughput with certain chunk sizes than with others.

The output from mouthpiece and string<-headers is formatted according to their optional style argument. By default, headers have the form:

     NAME #\: #\space VALUE #\cr #\lf

Additionally, for mouthpiece, the first line, preceding all the headers, has the form:

     HTTP/1.0 nnn msg

and a single #\cr #\lf pair separates the headers from the body. See modlisp, for another way to format this information.

— Procedure: mouthpiece out-port [status-box [style]]

Return a command-delegating closure capable of writing a properly formatted HTTP 1.0 response to out-port. Optional arg status-box is a list whose car is set to the numeric status code given to a #:set-reply-status command. If status-box has length of two or more, its cadr is set to the content-length on #:send-reply. A content-length value of #f means there have been no calls to #:add-content. The commands and their args are:

#:reset-protocol!
Reset internal state, including reply status, headers and content. This is called automatically by #:send-reply.


#:set-reply-status number message
Set the reply status. message is a short string.


#:set-reply-status:success
This is equivalent to #:set-reply-status 200 "OK".


#:add-header name value
name may be #f, #t, a string, symbol or keyword. value is a string. If name is #f or #t, value is taken to be a pre-formatted string, "A: B" or "A: B\r\n", respectively. If name is not a boolean, value may also be a tree of strings or a number.


#:add-content [tree ...]
tree may be a string, a nested list of strings, or a series of such. Subsequent calls to #:add-content append their trees to the collected content tree thus far.


#:add-formatted format-string [args ...]
format-string may be #f to mean ~S, #t to mean ~A, or a normal format string. It is used to format args, and the result passed to #:add-content.


#:add-direct-writer len write
len is the number of bytes that procedure write will output to its arg, out-port (passed back), when called during #:send-reply. This is to allow sendfile(2) and related hackery.


#:content-length
Return the total number of bytes in the content added thus far.


#:rechunk-content chunk
chunk may be #f, in which case a list of the string lengths collected thus far is returned; #t which means to use the content length as the chunk size (effectively producing one chunk); or a number specifying the maximum size of a chunk. The return value is a list of the chunk sizes.

It is an error to use #:rechunk-content with a non-#f chunk in the presence of a previous #:add-direct-writer.


#:inhibit-content! bool
Non-#f bool arranges for #:send-reply (below) to compute content length and add the appropriate header, as usual, but no content is actually sent. This is useful, e.g., when answering a HEAD request. If bool is #f, #:send-reply acts normally (i.e., sends both headers and content).


#:send-reply [close]
Send the properly formatted response to out-port, and reset all internal state (status reset, content discarded, etc). It is an error to invoke #:send-reply without having first set the reply status.

Optional arg close means do a shutdown on out-port using close — directly, if an integer, or called with no arguments, if a thunk — as the shutdown how argument. (Note: If out-port is not a socket, this does nothing silently.) See Network Sockets and Communication.

If close is specified, the closure forgets about out-port internally; it is an error to call other mouthpiece commands, subsequently.

example

Here is an example that uses most of the mouthpiece commands:

     (use-modules (www server-utils filesystem) (scripts slurp))
     
     (define SERVER-NAME "Guile-WWW-example-server")
     (define SERVER-VERSION "1.0")
     (define STATUS (list #f #f))
     (define M (mouthpiece (open-output-file "fake") STATUS))
     
     (define (transmit-file filename)
       (M #:set-reply-status:success)
       (M #:add-header #:Server (string-append SERVER-NAME " "
                                               SERVER-VERSION))
       (M #:add-header #:Connection "close")
       (M #:add-header #:Content-Type (filename->content-type
                                       filename "text/plain"))
       (M #:add-content (slurp filename))
       (simple-format #t "rechunked: ~A\n"
                      (M #:rechunk-content (* 8 1024)))
       ;; We don't shutdown because this is a file port;
       ;; if it were a socket, we might specify 2 to
       ;; stop both reception and transmission.
       (M #:send-reply))
     
     (transmit-file "COPYING")
     -| rechunked: (8192 8192 1605)
     STATUS
     ⇒ (200 17989)

For higher performance, you can preformat parts of the response, using CRLF, and some lower-level convenience procedures. If preformatting is not possible (or desirable), you can still declare a nested list of strings (aka tree) to have a flat length, i.e., the size in bytes a tree would occupy once flattened, thus enabling internal optimizations. (The flat length of a string is its string-length.)

— Constant String: CRLF

The string “\r\n”.

— Object Property: flat-length object

Return the flat length of object, or #f if not yet computed.

— Procedure: fs s [args...]

Return a new string made by using format string s on args. As in simple-format (which this procedure uses), ~A expands as with display, while ~S expands as with write.

— Procedure: walk-tree proc tree

Call proc for each recursively-visited leaf in tree, excluding empty lists. It is an error for tree to contain improper lists.

— Procedure: tree-flat-length! tree

If tree is a string, return its string-length. If tree already has a flat-length, return that. Otherwise, recursively compute, set, and return the flat-length of tree.

— Procedure: string<-tree tree

Return a new string made from flattening tree. Set the flat-length (using tree-flat-length!) of tree by side effect.

— Procedure: string<-headers alist [style]

Return a string made from formatting name/value pairs in alist, according to the optional style argument. If unspecified or specified as #f, the default is to format headers like so:

          NAME #\: #\space VALUE #\cr #\lf

Each name may be a string, symbol or keyword. Each value may be a string, number, symbol, or a tree.

— Procedure: string<-header-components n v [n1 v1...]

Return a string made from formatting header name n and value v. Additional headers can be specified as alternating name and value args. Each header is formatted like so: “name: value\r\n”.

Each n may be a string, symbol or keyword. Each v may be a string, number, symbol, or a tree.

NOTE: This proc will be removed after 2011-12-31. Use string<-headers instead.

example

Here is transmit-file from the above example, slightly modified to use preformatted headers and fs:

     (define CONSTANT-HEADERS
       (string<-headers
        `((#:Server     . ,(fs "~A ~A" SERVER-NAME SERVER-VERSION))
          (#:Connection . "close"))))
     
     (define (transmit-file filename)
       (M #:set-reply-status:success)
       (M #:add-header #t CONSTANT-HEADERS)
       (M #:add-header #:Content-Type (filename->content-type
                                       filename "text/plain"))
       (M #:add-content (slurp filename))
       (display (fs "rechunked: ~A\n" (M #:rechunk-content (* 8 1024))))
       (M #:send-reply))

Note that mouthpiece accepts trees for both #:add-header and #:add-content commands. Thus, the following two fragments give the same result, although the latter is both more elegant and more efficient:

     ;; Doing things "manually".
     (walk-tree (lambda (string)
                  (M #:add-content string))
                tree)
     
     ;; Letting the mouthpiece handle things.
     (M #:add-content tree)