Next: , Previous: Top, Up: Top


1 (www http)

The (www http) module includes module-configuration fluids, procedures for high-level HTTP operation, low-level HTTP message object access, and common messages.

1.1 Dynamic Configuration

— Fluid: protocol-version

A pair of integers representing the major and minor portions of the protocol version this module should support. The default value is (1 . 0). Users:

          http:request
          http:head        ; via http:request
          http:get         ; likewise
          http:post-form   ; likewise

1.2 High-Level HTTP Operation

— Procedure: http:connect proto addrfam address [address-rest...]

Return a TCP stream socket connected to the location specified by protocol proto, addrfam and address. proto is PF_INET or PF_UNIX, and the other args take corresponding forms:

PF_INET
(AF_INET ipaddr portno), where ipaddr is an integer. Use (car (hostent:addr-list (gethost host))) to compute the ipaddr of host (a string).
PF_UNIX
(AF_UNIX filename), made, for example, by
(list AF_UNIX "/tmp/foo-control").

Note that PF_foo and AF_foo are names of variables that have constant values, not symbols.

— Procedure: http:open host [port]

Return an HTTP connection (a socket) to host (a string) on TCP port port (default 80 if unspecified).

— Procedure: send-request sock method url [keyword value...]

          Keywords: headers, body, flags, protocol-version

Submit to socket sock an HTTP request using method (a symbol) and url, an object returned by url:parse, forming the message with additional headers, a list of strings, each of which should have one of the forms:

          NAME ": " VALUE
          NAME ": " VALUE CRLF

and body, which may be #f (which means no body), a string or list of them, a u8 vector or list of them, or a procedure m which manages the transmission of the body data by supporting the body transmission protocol. This means m takes one arg, command (symbol):

content-length
This is called if the transfer is not “chunked” (see below). m returns the total length (in bytes) of the data.
next-chunk
Return two values: the length (in bytes) of the next chunk of data to send, and either a string, or a procedure w that does the actual writing to its port arg (which will be sock). If there is no more data, both values should be #f, i.e., m should return (values #f #f).

If flags contains the symbol chunked, send the body with “chunked” Transfer-Encoding. Otherwise, compute and add to the headers its total Content-Length.

If flags contains the symbol close, add Connection: close to the headers.

The protocol-version is a pair specifying the major and minor version numbers of HTTP to send as. It defaults to (1 . 1). For HTTP 1.x (x >= 1), automatically add chunked to flags as well as the headers:

          TE: trailers
          Connection: TE

Return an unspecified object pending that can be passed to receive-response.

— Procedure: receive-response pending [keyword value...]

          Keywords: s2s, intervene, flags

Receive the pending (from send-request) response. Return an HTTP message object. The header names are symbols made by (string->symbol (s2s orig)), where s2s defaults to string-titlecase. The status code is a 3-digit integer. The body of the message may be #f if there is no body possible (per HTTP). Otherwise, its value depends on intervene and flags.

Here is an example that uses receive-response argument intervene to arrange for the message body to be a u8 vector if the Content-Type is not “text/*”.

     (use-modules
      (srfi srfi-13)   ; string-prefix?
      (www url))       ; url:parse
     
     (define (text? type)
       (string-prefix? "text/" type))
     
     (define (u8-maybe hget flags)
       (cond ((hget 'Content-Type)
              => (lambda (type)
                   (values #f (and (not (text? type))
                                   (cons 'u8 flags)))))
             (else
              (values #f #f))))
     
     (define SOCK (http:open ...))
     
     (define (gimme string)
       (send-request SOCK 'GET (url:parse string)))
     
     (define (ok pending)
       (receive-response pending #:intervene u8-maybe))
     
     (define ICO (ok (gimme "http://localhost/favicon.ico")))
     (define IDX (ok (gimme "http://localhost/index.html")))
     
     (http:message-body ICO)
     ⇒ #u8(0 0 1 0 1 0 46 ...)
     
     (http:message-body IDX)
     ⇒ "<?xml version=\"1.0\" ..."

Note that to find the content type in u8-maybe, we rely on the default header-name normalization of string-titlecase, since we know ok does not specify #:s2s s2s in its call to receive-response. To enable u8-maybe to work with any pending response, you can instead use (hget "Content-Type") (i.e., a string name).

— Procedure: http:request method url [headers [body]]

Submit an HTTP request using method and url, wait for a response, and return the response as an HTTP message object. The field types and values of this message object are as described in receive-response, with two exceptions (for backward compatability): the status code is a string; the header names are symbols, all lower-case.

method is the symbolic name of some HTTP method, e.g., GET or POST. It may also be a string. url is a url object returned by url:parse. Optional args headers and body are lists of strings that comprise the lines of an HTTP message. The header strings should not end with ‘CR’ or ‘LF’ or ‘CRLF’; http:request handles that. Also, the Content-Length header and Host header are calculated automatically and should not be supplied. Here are two examples:

          (http:request 'GET parsed-url
            (list "User-Agent: Anonymous/0.1"
                  "Content-Type: text/plain"))
          
          (http:request 'POST parsed-url
            (list "User-Agent: Fred/0.1"
                  "Content-Type: application/x-www-form-urlencoded")
            (list "search=Gosper"
                  "&case=no"
                  "&max_hits=50"))

In the second example, the Content-Length header is computed to have value 33 (the sum of 13, 8 and 12).

1.3 Low-Level HTTP Message Object Access

— Procedure: http:message-version msg

Return the HTTP version in use in HTTP message msg.

— Procedure: http:message-status-code msg

Return the status code returned in HTTP message msg.

— Procedure: http:message-status-text msg

Return the text of the status line from HTTP message msg.

— Procedure: http:message-status-ok? msg

Return #t iff status code of msg indicates a successful request.

— Procedure: http:status-ok? status

Return #t iff status (string or integer) is 2xx.

— Procedure: http:message-body msg

Return the body of the HTTP message msg.

An HTTP message header is represented by a pair. The car is a symbol representing the header name, and the cdr is a string containing the header text. E.g.:

     '((date . "Thu, 29 May 1997 23:48:27 GMT")
       (server . "NCSA/1.5.1")
       (last-modified . "Tue, 06 May 1997 18:32:03 GMT")
       (content-type . "text/html")
       (content-length . "8097"))

Note: these symbols are all lowercase, although the original headers may be mixed-case. Clients using this library should keep this in mind, since Guile symbols are case-sensitive.

— Procedure: http:message-headers msg

Return a list of the headers from HTTP message msg.

— Procedure: http:message-header header msg

Return the header field named header from HTTP message msg, or #f if no such header is present in the message.

1.4 Common Messages

— Procedure: http:post-form url extra-headers fields

Submit an http request using the POST method on the url. extra-headers is a list of extra headers, each a string of form "name: value ...".

The "Content-Type" and "Host" headers are sent automatically and do not need to be specified. fields is a list of elements of the form (fkey . fvalue), where fkey is a symbol and fvalue is normally a string.

fvalue can also be a list of file-upload specifications, each of which has the form (source name mime-type transfer-encoding). source can be a string or a thunk that returns a string.

The rest of the elements are strings or symbols: name is the filename (only the non-directory part is used); mime-type is a type/subtype pair such as "image/jpeg", or #f to mean "text/plain". transfer-encoding is one of the tokens specified by RFC 1521, or #f to mean "binary". File-upload spec elements with invalid types result in a "bad upload spec" error prior to the http request.

Note that source is used directly without further processing; it is the caller's responsibility to ensure that the MIME type and transfer encoding specified describe source accurately.

If there are no file-upload specifications in fields, the Content-Type is application/x-www-form-urlencoded, and furthermore all the fkey and fvalue are transformed by url-coding:encode (see url-coding) with the additional reserved characters #\& (ampersand) and #\= (equal sign).

Otherwise, the Content-Type is multipart/form-data, with each field in fields formatted as a MIME sub-part.

NB: The following two procedures will NO LONGER BE AVAILABLE after 2013-02-28. Using send-request and receive-reply directly is more flexible and featureful.

— Procedure: http:head url

Submit an http request using the HEAD method on the url. The Host header is automatically included.

— Procedure: http:get url

Submit an http request using the GET method on the url. The Host header is automatically included.


Footnotes

[1] Out of an explicit call-with-values context, Guile 2.x will silently discard all values following the “expected number” (one, in this case):

     (list 'custom (values P1 P2 P3 P4))
     ⇒ (custom P1)

This is apparently allowed under R5RS and R6RS.