The (www http)
module includes module-configuration fluids,
procedures for high-level HTTP
operation, low-level HTTP message object access, and common messages.
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
Return a TCP stream socket connected to the location specified by protocol proto, addrfam and address. proto is
PF_INET
orPF_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
andAF_foo
are names of variables that have constant values, not symbols.
Return an HTTP connection (a socket) to host (a string) on TCP port port (default 80 if unspecified).
Keywords: headers, body, flags, protocol-versionSubmit 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 CRLFand body, which may be
#f
(which means no body), a string or list of them, au8
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 symbolchunked
, send the body with “chunked”Transfer-Encoding
. Otherwise, compute and add to the headers its totalContent-Length
.If
flags
contains the symbolclose
, addConnection: 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 addchunked
to flags as well as the headers:TE: trailers Connection: TEReturn an unspecified object pending that can be passed to
receive-response
.
Keywords: s2s, intervene, flagsReceive 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 tostring-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.
- If intervene is specified, it should be a procedure that takes two args, hget and flags and returns two values, new-headers and new-flags. It is called after the headers are parsed but before the body is received so that its returned values may influence the body processing.
hget is a procedure that takes one arg sel.
#f
- Return the headers (alist).
#t
- Return the name normalization procedure (involving s2s, described above).
- string
- Normalize it; return the associated header value.
- symbol
- Return the associated header value.
A
#f
value for new-headers means “don't change the headers”. Likewise, for new-flags. Otherwise, the respective items are replaced (NB: not just added!).- If flags is null (the default), the body is a string.
- If flags contains the symbol
u8
, the body is au8
vector.- If flags contains the symbol
custom
, the following item in flags should be a thunk that returns four values (all procedures) that support the chunk transfer protocol. These are:
(mkx
len)
- Create and return a container capable of holding len bytes.
(r!
x sock)
- Fill x, reading from sock. Return the number of bytes read (positive integer), or zero on EOF.
(cat-r
list)
- Return a new container formed by reversing list and concatenating its elements.
(subseq
x len)
- Return a new container that holds the first len bytes of container x.
The message body is a single container, either constructed from multiple exact chunks (“chunked”
Transfer-Encoding
), or read in one swoop (ifContent-Length
is given), or from multiple inexact chunks (the default).For backward compatability, instead of a thunk returning four values, you can also specify the four values directly. NB: Support for specifying four values directly will NO LONGER BE AVAILABLE after 2013-05-15.1
- If flags contains the symbol
no-cat
, then all multi-chunk transfers are not “concatenated”; instead, the message body is the list of chunk data (string,u8
orcustom
), in order of reception.
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).
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
orPOST
. It may also be a string. url is a url object returned byurl: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).
Return
#t
iff status code of msg indicates a successful request.
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.
Return the header field named header from HTTP message msg, or
#f
if no such header is present in the message.
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
isapplication/x-www-form-urlencoded
, and furthermore all the fkey and fvalue are transformed byurl-coding:encode
(see url-coding) with the additional reserved characters#\&
(ampersand) and#\=
(equal sign).Otherwise, the
Content-Type
ismultipart/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.
Submit an http request using the
HEAD
method on the url. TheHost
header is automatically included.
Submit an http request using the
GET
method on the url. TheHost
header is automatically included.
[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.