Next: , Previous: , Up: Top   [Contents][Index]


12 (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 compose-response, mouthpiece and string<-headers is formatted according to their optional style argument. By default, headers have the form:

NAME ": " VALUE CR LF

Additionally, for compose-response and mouthpiece, the first line, preceding all the headers, has the form:

"HTTP/" MAJOR "." MINOR SP NNN SP MSG

and a single CRLF pair separates the headers from the body. (Actually, mouthpiece hardcodes the protocol version to ‘1.0’, which is one reason why new code should use compose-response.) See modlisp, for another way to format this information.

Procedure: compose-response host [keyword value…]
Keywords: style, protocol-version 

Return a command-delegating closure capable of writing a properly formatted HTTP 1.1 response with Host header set to host. The actual status and header format is controlled by style, an opaque object. The actual protocol version is controlled by protocol-version, a pair of integers, such as (1 . 0) to indicate HTTP 1.0.

The returned closure r accepts commands and args:

#:set-protocol-version pair

Set the major and minor version protocol-version numbers.

#:set-reply-status number message

Set the reply status. message is a short string.

#: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.

#:entity-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! sock [flags]

Send the properly formatted response to file-port sock. It is an error to invoke #:send-reply without having first set the reply status.

Optional arg flags are the same as for send-request. See http.

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 (guile)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~%"
                 (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.

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~%" (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)

Next: , Previous: , Up: Top   [Contents][Index]