@c -*-texinfo-*-
@c This is part of the GNU Guile Reference Manual.
-@c Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc.
+@c Copyright (C) 2010, 2011, 2012, 2013, 2015 Free Software Foundation, Inc.
@c See the file guile.texi for copying conditions.
@node Web
@cindex HTTP
It has always been possible to connect computers together and share
-information between them, but the rise of the World-Wide Web over the
+information between them, but the rise of the World Wide Web over the
last couple of decades has made it much easier to do so. The result is
a richly connected network of computation, in which Guile forms a part.
element, represented as a tagged list. So @samp{foo} becomes
@samp{"foo"}, and @samp{<b>foo</b>} becomes @samp{(b "foo")}.
Attributes, if present, go in a tagged list headed by @samp{@@}, like
-@samp{(img (@@ (src "http://example.com/foo.png")))}. @xref{sxml
-simple}, for more information.
+@samp{(img (@@ (src "http://example.com/foo.png")))}. @xref{SXML}, for
+more information.
The good thing about SXML is that HTML elements cannot be confused with
text. Let's make a new definition of @code{para}:
URIs have a host, and some of those have ports and userinfo. Any URI
might have a query part or a fragment.
+There is also a ``URI-reference'' data type, which is the same as a URI
+but where the scheme is optional. In this case, the scheme is taken to
+be relative to some other related URI. A common use of URI references
+is when you want to be vague regarding the choice of HTTP or HTTPS --
+serving a web page referring to @code{/foo.css} will use HTTPS if loaded
+over HTTPS, or HTTP otherwise.
+
Userinfo is something of an abstraction, as some legacy URI schemes
allowed userinfo of the form @code{@var{username}:@var{passwd}}. But
since passwords do not belong in URIs, the RFC does not want to condone
module. Load it into your Guile, using a form like the above, to have
access to them.
-@deffn {Scheme Procedure} build-uri scheme [#:userinfo=@code{#f}] [#:host=@code{#f}] @
- [#:port=@code{#f}] [#:path=@code{""}] [#:query=@code{#f}] @
- [#:fragment=@code{#f}] [#:validate?=@code{#t}]
+@deffn {Scheme Procedure} build-uri scheme @
+ [#:userinfo=@code{#f}] [#:host=@code{#f}] [#:port=@code{#f}] @
+ [#:path=@code{""}] [#:query=@code{#f}] [#:fragment=@code{#f}] @
+ [#:validate?=@code{#t}]
Construct a URI object. @var{scheme} should be a symbol, @var{port}
either a positive, exact integer or @code{#f}, and the rest of the
fields are either strings or @code{#f}. If @var{validate?} is true,
is valid.
@end deffn
-@deffn {Scheme Procedure} uri? x
+@deffn {Scheme Procedure} build-uri-reference [#:scheme=@code{#f}]@
+ [#:userinfo=@code{#f}] [#:host=@code{#f}] [#:port=@code{#f}] @
+ [#:path=@code{""}] [#:query=@code{#f}] [#:fragment=@code{#f}] @
+ [#:validate?=@code{#t}]
+Like @code{build-uri}, but with an optional scheme.
+@end deffn
+
+In Guile, both URI and URI reference data types are represented in the
+same way, as URI objects.
+
+@deffn {Scheme Procedure} uri? obj
@deffnx {Scheme Procedure} uri-scheme uri
@deffnx {Scheme Procedure} uri-userinfo uri
@deffnx {Scheme Procedure} uri-host uri
@deffnx {Scheme Procedure} uri-query uri
@deffnx {Scheme Procedure} uri-fragment uri
A predicate and field accessors for the URI record type. The URI scheme
-will be a symbol, the port either a positive, exact integer or @code{#f},
-and the rest either strings or @code{#f} if not present.
+will be a symbol, or @code{#f} if the object is a URI reference but not
+a URI. The port will be either a positive, exact integer or @code{#f},
+and the rest of the fields will be either strings or @code{#f} if not
+present.
@end deffn
@deffn {Scheme Procedure} string->uri string
could not be parsed.
@end deffn
+@deffn {Scheme Procedure} string->uri-reference string
+Parse @var{string} into a URI object, while not requiring a scheme.
+Return @code{#f} if the string could not be parsed.
+@end deffn
+
@deffn {Scheme Procedure} uri->string uri
Serialize @var{uri} to a string. If the URI has a port that is the
default port for its scheme, the port is not included in the
should be the name of a character encoding.
Note that this function should not generally be applied to a full URI
-string. For paths, use split-and-decode-uri-path instead. For query
-strings, split the query on @code{&} and @code{=} boundaries, and decode
-the components separately.
+string. For paths, use @code{split-and-decode-uri-path} instead. For
+query strings, split the query on @code{&} and @code{=} boundaries, and
+decode the components separately.
Note also that percent-encoded strings encode @emph{bytes}, not
characters. There is no guarantee that a given byte sequence is a valid
@var{encoding} was @code{#f}.
@end deffn
-Fixme: clarify return type. indicate default values. type of
-unescaped-chars.
-
@deffn {Scheme Procedure} uri-encode str [#:encoding=@code{"utf-8"}] [#:unescaped-chars]
Percent-encode any character not in the character set,
@var{unescaped-chars}.
string name is simply its symbol name in title-case.
@deffn {Scheme Procedure} known-header? sym
-Return @code{#t} iff @var{sym} is a known header, with associated
-parsers and serialization procedures.
+Return @code{#t} if @var{sym} is a known header, with associated
+parsers and serialization procedures, or @code{#f} otherwise.
@end deffn
@deffn {Scheme Procedure} header-parser sym
@pxref{HTTP Headers}. To add your own, use the @code{declare-header!}
procedure:
-@deffn {Scheme Procedure} declare-header! name parser validator writer [#:multiple?=@code{#f}]
+@deffn {Scheme Procedure} declare-header! name parser validator writer @
+ [#:multiple?=@code{#f}]
Declare a parser, validator, and writer for a given header.
@end deffn
@end deffn
@deffn {Scheme Procedure} valid-header? sym val
-Return a true value iff @var{val} is a valid Scheme value for the header
-with name @var{sym}.
+Return a true value if @var{val} is a valid Scheme value for the header
+with name @var{sym}, or @code{#f} otherwise.
@end deffn
Now that we have a generic interface for reading and writing headers, we
@end deffn
@deffn {Scheme Procedure} parse-http-version str [start] [end]
-Parse an HTTP version from @var{str}, returning it as a major-minor
+Parse an HTTP version from @var{str}, returning it as a major--minor
pair. For example, @code{HTTP/1.1} parses as the pair of integers,
@code{(1 . 1)}.
@end deffn
@deffn {Scheme Procedure} read-response-line port
Read the first line of an HTTP response from @var{port}, returning three
-values: the HTTP version, the response code, and the "reason phrase".
+values: the HTTP version, the response code, and the ``reason phrase''.
@end deffn
@deffn {Scheme Procedure} write-response-line version code reason-phrase port
@end example
@end deftypevr
-@deftypevr {HTTP Header} URI location
-A URI on which a request may be completed. Used in combination with a
-redirecting status code to perform client-side redirection.
+@deftypevr {HTTP Header} URI-reference location
+A URI reference on which a request may be completed. Used in
+combination with a redirecting status code to perform client-side
+redirection.
@example
(parse-header 'location "http://example.com/other")
@result{} #<uri ...>
@subsubsection Request API
-@deffn {Scheme Procedure} request?
-@deffnx {Scheme Procedure} request-method
-@deffnx {Scheme Procedure} request-uri
-@deffnx {Scheme Procedure} request-version
-@deffnx {Scheme Procedure} request-headers
-@deffnx {Scheme Procedure} request-meta
-@deffnx {Scheme Procedure} request-port
+@deffn {Scheme Procedure} request? obj
+@deffnx {Scheme Procedure} request-method request
+@deffnx {Scheme Procedure} request-uri request
+@deffnx {Scheme Procedure} request-version request
+@deffnx {Scheme Procedure} request-headers request
+@deffnx {Scheme Procedure} request-meta request
+@deffnx {Scheme Procedure} request-port request
A predicate and field accessors for the request type. The fields are as
follows:
@table @code
requests.
@end deffn
-@deffn {Scheme Procedure} build-request uri [#:method='GET] [#:version='(1 . 1)] [#:headers='()] [#:port=#f] [#:meta='()] [#:validate-headers?=#t]
+@deffn {Scheme Procedure} build-request uri [#:method='GET] @
+ [#:version='(1 . 1)] [#:headers='()] [#:port=#f] [#:meta='()] @
+ [#:validate-headers?=#t]
Construct an HTTP request object. If @var{validate-headers?} is true,
the headers are each run through their respective validators.
@end deffn
Return the given request header, or @var{default} if none was present.
@end deffn
-@deffn {Scheme Procedure} request-absolute-uri r [default-host=#f] [default-port=#f]
+@deffn {Scheme Procedure} request-absolute-uri r [default-host=#f] @
+ [default-port=#f] [default-scheme=#f]
A helper routine to determine the absolute URI of a request, using the
-@code{host} header and the default host and port.
+@code{host} header and the default scheme, host and port. If there is
+no default scheme and the URI is not itself absolute, an error is
+signalled.
@end deffn
-
@node Responses
@subsection HTTP Responses
As with requests (@pxref{Requests}), Guile offers a data type for HTTP
responses. Again, the body is represented separately from the request.
-@deffn {Scheme Procedure} response?
-@deffnx {Scheme Procedure} response-version
-@deffnx {Scheme Procedure} response-code
+@deffn {Scheme Procedure} response? obj
+@deffnx {Scheme Procedure} response-version response
+@deffnx {Scheme Procedure} response-code response
@deffnx {Scheme Procedure} response-reason-phrase response
-@deffnx {Scheme Procedure} response-headers
-@deffnx {Scheme Procedure} response-port
+@deffnx {Scheme Procedure} response-headers response
+@deffnx {Scheme Procedure} response-port response
A predicate and field accessors for the response type. The fields are as
follows:
@table @code
@code{(web client)} provides a simple, synchronous HTTP client, built on
the lower-level HTTP, request, and response modules.
+@example
+(use-modules (web client))
+@end example
+
@deffn {Scheme Procedure} open-socket-for-uri uri
Return an open input/output port for a connection to URI.
@end deffn
-@deffn {Scheme Procedure} http-get uri [#:port=(open-socket-for-uri uri)] [#:version='(1 . 1)] [#:keep-alive?=#f] [#:extra-headers='()] [#:decode-body?=#t]
-Connect to the server corresponding to @var{uri} and ask for the
-resource, using the @code{GET} method. If you already have a port open,
-pass it as @var{port}. The port will be closed at the end of the
-request unless @var{keep-alive?} is true. Any extra headers in the
-alist @var{extra-headers} will be added to the request.
+@deffn {Scheme Procedure} http-get uri arg...
+@deffnx {Scheme Procedure} http-head uri arg...
+@deffnx {Scheme Procedure} http-post uri arg...
+@deffnx {Scheme Procedure} http-put uri arg...
+@deffnx {Scheme Procedure} http-delete uri arg...
+@deffnx {Scheme Procedure} http-trace uri arg...
+@deffnx {Scheme Procedure} http-options uri arg...
+
+Connect to the server corresponding to @var{uri} and make a request over
+HTTP, using the appropriate method (@code{GET}, @code{HEAD}, etc.).
+
+All of these procedures have the same prototype: a URI followed by an
+optional sequence of keyword arguments. These keyword arguments allow
+you to modify the requests in various ways, for example attaching a body
+to the request, or setting specific headers. The following table lists
+the keyword arguments and their default values.
+
+@table @code
+@item #:body #f
+@item #:port (open-socket-for-uri @var{uri})]
+@item #:version '(1 . 1)
+@item #:keep-alive? #f
+@item #:headers '()
+@item #:decode-body? #t
+@item #:streaming? #f
+@end table
+
+If you already have a port open, pass it as @var{port}. Otherwise, a
+connection will be opened to the server corresponding to @var{uri}. Any
+extra headers in the alist @var{headers} will be added to the request.
+
+If @var{body} is not @code{#f}, a message body will also be sent with
+the HTTP request. If @var{body} is a string, it is encoded according to
+the content-type in @var{headers}, defaulting to UTF-8. Otherwise
+@var{body} should be a bytevector, or @code{#f} for no body. Although a
+message body may be sent with any request, usually only @code{POST} and
+@code{PUT} requests have bodies.
If @var{decode-body?} is true, as is the default, the body of the
response will be decoded to string, if it is a textual content-type.
Otherwise it will be returned as a bytevector.
+
+However, if @var{streaming?} is true, instead of eagerly reading the
+response body from the server, this function only reads off the headers.
+The response body will be returned as a port on which the data may be
+read.
+
+Unless @var{keep-alive?} is true, the port will be closed after the full
+response body has been read.
+
+Returns two values: the response read from the server, and the response
+body as a string, bytevector, #f value, or as a port (if
+@var{streaming?} is true).
@end deffn
@code{http-get} is useful for making one-off requests to web sites. If
Another option, good but not as performant, would be to use threads,
possibly via par-map or futures.
-More helper procedures for the other common HTTP verbs would be a good
-addition to this module. Send your code to
-@email{guile-user@@gnu.org}.
+@deffn {Scheme Parameter} current-http-proxy
+Either @code{#f} or a non-empty string containing the URL of the HTTP
+proxy server to be used by the procedures in the @code{(web client)}
+module, including @code{open-socket-for-uri}. Its initial value is
+based on the @env{http_proxy} environment variable.
+
+@example
+(current-http-proxy) @result{} "http://localhost:8123/"
+(parameterize ((current-http-proxy #f))
+ (http-get "http://example.com/")) ; temporarily bypass proxy
+(current-http-proxy) @result{} "http://localhost:8123/"
+@end example
+@end deffn
@node Web Server
@enumerate
@item
-The @code{open} hook is called, to open the server. @code{open} takes 0 or
-more arguments, depending on the backend, and returns an opaque
+The @code{open} hook is called, to open the server. @code{open} takes
+zero or more arguments, depending on the backend, and returns an opaque
server socket object, or signals an error.
@item
@end deffn
@deffn {Scheme Procedure} sanitize-response request response body
-"Sanitize" the given response and body, making them appropriate for the
-given request.
+``Sanitize'' the given response and body, making them appropriate for
+the given request.
As a convenience to web handler authors, @var{response} may be given as
an alist of headers, in which case it is used to construct a default
produced by the handler procedure.
@end deffn
-@deffn {Scheme Procedure} run-server handler [impl='http] [open-params='()] . state
+@deffn {Scheme Procedure} run-server handler @
+ [impl='http] [open-params='()] @
+ arg @dots{}
Run Guile's built-in web server.
@var{handler} should be a procedure that takes two or more arguments,
The response and body will be run through @code{sanitize-response}
before sending back to the client.
-Additional arguments to @var{handler} are taken from @var{state}.
-Additional return values are accumulated into a new @var{state}, which
-will be used for subsequent requests. In this way a handler can
-explicitly manage its state.
+Additional arguments to @var{handler} are taken from @var{arg}
+@enddots{}. These arguments comprise a @dfn{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.
@end deffn
The default web server implementation is @code{http}, which binds to a
socket, listening for request on that port.
-@deffn {HTTP Implementation} http [#:host=#f] [#:family=AF_INET] [#:addr=INADDR_LOOPBACK] [#:port 8080] [#:socket]
+@deffn {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 @var{open-params} to @code{run-server} get passed to the
The web handler interface is a common baseline that all kinds of Guile
web applications can use. You will usually want to build something on
top of it, however, especially when producing HTML. Here is a simple
-example that builds up HTML output using SXML (@pxref{sxml simple}).
+example that builds up HTML output using SXML (@pxref{SXML}).
First, load up the modules: