guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] GNU Guile branch, master, updated. release_1-9-13-192-g8


From: Andy Wingo
Subject: [Guile-commits] GNU Guile branch, master, updated. release_1-9-13-192-g8db7e09
Date: Thu, 16 Dec 2010 13:48:45 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Guile".

http://git.savannah.gnu.org/cgit/guile.git/commit/?id=8db7e0947d7d6ac7e85ca45fa4d58e94794bb5c4

The branch, master has been updated
       via  8db7e0947d7d6ac7e85ca45fa4d58e94794bb5c4 (commit)
       via  43d6659ae2a23686d9a8e9397da99c1c9c1d2bd0 (commit)
       via  cc1e26c2cd015fe17a9c581ba3c0f523508f897a (commit)
       via  92c5c0b67c873a38ba0884b0199ac43f7edfaf1e (commit)
       via  277bbe96244e647dc63ce0695474fd3aac14e581 (commit)
      from  76ebf23fcefcac1af10df239a3c592eead58b51b (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 8db7e0947d7d6ac7e85ca45fa4d58e94794bb5c4
Author: Andy Wingo <address@hidden>
Date:   Tue Dec 14 23:26:41 2010 +0100

    add web.texi to manual
    
    * doc/ref/web.texi: New file, here to document the various (web ...)
      modules.  Quite a rough beginning, but it is a start...
    
    * doc/ref/guile.texi:
    * doc/ref/Makefile.am: Add to manual.

commit 43d6659ae2a23686d9a8e9397da99c1c9c1d2bd0
Author: Andy Wingo <address@hidden>
Date:   Thu Dec 16 12:52:03 2010 +0100

    (web server) docstrings
    
    * module/web/server.scm: Docstrings in the house.

commit cc1e26c2cd015fe17a9c581ba3c0f523508f897a
Author: Andy Wingo <address@hidden>
Date:   Thu Dec 16 12:21:56 2010 +0100

    docstrings in (web request) and (web response)
    
    * module/web/request.scm:
    * module/web/response.scm: Add docstrings.

commit 92c5c0b67c873a38ba0884b0199ac43f7edfaf1e
Author: Andy Wingo <address@hidden>
Date:   Thu Dec 16 12:02:53 2010 +0100

    (web http) docstrings
    
    * module/web/http.scm: Add docstrings all around.

commit 277bbe96244e647dc63ce0695474fd3aac14e581
Author: Andy Wingo <address@hidden>
Date:   Thu Dec 16 11:35:02 2010 +0100

    document (web uri), and simplify uri-encode
    
    * module/web/uri.scm: Add docstrings.
      (uri-encode): Simplify. Not sure what I was thinking before.

-----------------------------------------------------------------------

Summary of changes:
 doc/ref/Makefile.am     |    1 +
 doc/ref/guile.texi      |    2 +
 doc/ref/web.texi        |  685 +++++++++++++++++++++++++++++++++++++++++++++++
 module/web/http.scm     |   47 +++-
 module/web/request.scm  |   25 ++
 module/web/response.scm |   39 +++-
 module/web/server.scm   |   77 ++++++
 module/web/uri.scm      |   91 ++++---
 8 files changed, 931 insertions(+), 36 deletions(-)
 create mode 100644 doc/ref/web.texi

diff --git a/doc/ref/Makefile.am b/doc/ref/Makefile.am
index d54ec14..ee36654 100644
--- a/doc/ref/Makefile.am
+++ b/doc/ref/Makefile.am
@@ -57,6 +57,7 @@ guile_TEXINFOS = preface.texi                 \
                 scheme-indices.texi            \
                 slib.texi                      \
                 posix.texi                     \
+                web.texi                       \
                 expect.texi                    \
                 scsh.texi                      \
                 sxml-match.texi                \
diff --git a/doc/ref/guile.texi b/doc/ref/guile.texi
index 3fbc1d7..1e7a277 100644
--- a/doc/ref/guile.texi
+++ b/doc/ref/guile.texi
@@ -348,6 +348,7 @@ available through both Scheme and C interfaces.
 @menu
 * SLIB::                        Using the SLIB Scheme library.
 * POSIX::                       POSIX system calls and networking.
+* Web::                         HTTP, the web, and all that.
 * getopt-long::                 Command line handling.
 * SRFI Support::                Support for various SRFIs.
 * R6RS Support::                Modules defined by the R6RS.
@@ -366,6 +367,7 @@ available through both Scheme and C interfaces.
 
 @include slib.texi
 @include posix.texi
address@hidden web.texi
 @include mod-getopt-long.texi
 @include srfi-modules.texi
 @include r6rs.texi
diff --git a/doc/ref/web.texi b/doc/ref/web.texi
new file mode 100644
index 0000000..e59e1a1
--- /dev/null
+++ b/doc/ref/web.texi
@@ -0,0 +1,685 @@
address@hidden -*-texinfo-*-
address@hidden This is part of the GNU Guile Reference Manual.
address@hidden Copyright (C) 2010 Free Software Foundation, Inc.
address@hidden See the file guile.texi for copying conditions.
+
address@hidden Web
address@hidden @acronym{HTTP}, the Web, and All That
address@hidden Web
address@hidden WWW
address@hidden HTTP
+
+When Guile started back in the mid-nineties, the GNU system was still
+focused on producing a good POSIX implementation.  This is why Guile's
+POSIX support is good, and has been so for a while.
+
+But times change, and in a way these days the web is the new POSIX: a
+standard and a motley set of implementations on which much computing is
+done.  So today's Guile also supports the web at the programming
+language level, by defining common data types and operations for the
+technologies underpinning the web: URIs, HTTP, and XML.
+
+It is particularly important to define native web data types.  Though
+the web is text in motion, programming the web in text is like
+programming with @code{goto}: muddy, and error-prone.  Most current
+security problems on the web are due to treating the web as text instead
+of as instances of the proper data types.
+
+In addition, common web data types help programmers to share code.
+
+Well.  That's all very nice and opinionated and such, but how do I use
+the thing?  Read on!
+
address@hidden
+* URIs::                        Universal Resource Identifiers.
+* HTTP::                        The Hyper-Text Transfer Protocol.
+* Requests::                    HTTP requests.
+* Responses::                   HTTP responses.
+* Web Handlers::                A simple web application interface.
+* Web Server::                  Serving HTTP to the internet.
address@hidden menu
+
address@hidden URIs
address@hidden Universal Resource Identifiers
+
address@hidden
+(use-modules (web uri))
address@hidden example
+
address@hidden 
+ A data type for Universal Resource Identifiers, as defined in RFC
+ 3986. 
address@hidden verbatim
+
address@hidden uri? 
address@hidden defspec
+
address@hidden uri-scheme 
address@hidden defspec
+
address@hidden uri-userinfo 
address@hidden defspec
+
address@hidden uri-host 
address@hidden defspec
+
address@hidden uri-port 
address@hidden defspec
+
address@hidden uri-path 
address@hidden defspec
+
address@hidden uri-query 
address@hidden defspec
+
address@hidden uri-fragment 
address@hidden defspec
+
address@hidden build-uri scheme [#:userinfo] [#:host] [#:port] [#:path] 
[#:query] [#:fragment] [#:validate?]
+Construct a URI object. If @var{validate?} is true, also run some
+consistency checks to make sure that the constructed URI is valid.
address@hidden defun
+
address@hidden declare-default-port! scheme port
+Declare a default port for the given URI scheme.
+
+Default ports are for printing URI objects: a default port is not
+printed.
address@hidden defun
+
address@hidden parse-uri string
+Parse @var{string} into a URI object. Returns @code{#f} if the string
+could not be parsed.
address@hidden defun
+
address@hidden unparse-uri uri
+Serialize @var{uri} to a string.
address@hidden defun
+
address@hidden uri-decode str [#:charset]
+Percent-decode the given @var{str}, according to @var{charset}.
+
+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.
+
+Note that percent-encoded strings encode @emph{bytes}, not characters.
+There is no guarantee that a given byte sequence is a valid string
+encoding. Therefore this routine may signal an error if the decoded
+bytes are not valid for the given encoding. Pass @code{#f} for
address@hidden if you want decoded bytes as a bytevector directly.
address@hidden defun
+
address@hidden uri-encode str [#:charset] [#:unescaped-chars]
+Percent-encode any character not in @var{unescaped-chars}.
+
+Percent-encoding first writes out the given character to a bytevector
+within the given @var{charset}, then encodes each byte as
address@hidden@var{HH}}, where @var{HH} is the hexadecimal representation of
+the byte.
address@hidden defun
+
address@hidden split-and-decode-uri-path path
+Split @var{path} into its components, and decode each component,
+removing empty components.
+
+For example, @code{"/foo/bar/"} decodes to the two-element list,
address@hidden("foo" "bar")}.
address@hidden defun
+
address@hidden encode-and-join-uri-path parts
+URI-encode each element of @var{parts}, which should be a list of
+strings, and join the parts together with @code{/} as a delimiter.
address@hidden defun
+
address@hidden HTTP
address@hidden The Hyper-Text Transfer Protocol
+
address@hidden
+(use-modules (web http))
address@hidden example
+
+This module has a number of routines to parse textual
+representations of HTTP data into native Scheme data structures.
+
+It tries to follow RFCs fairly strictly---the road to perdition
+being paved with compatibility hacks---though some allowances are
+made for not-too-divergent texts (like a quality of .2 which should
+be 0.2, etc).
+
address@hidden header-decl? 
address@hidden defspec
+
address@hidden make-header-decl 
address@hidden defspec
+
address@hidden header-decl-sym 
address@hidden defspec
+
address@hidden header-decl-name 
address@hidden defspec
+
address@hidden header-decl-multiple? 
address@hidden defspec
+
address@hidden header-decl-parser 
address@hidden defspec
+
address@hidden header-decl-validator 
address@hidden defspec
+
address@hidden header-decl-writer 
address@hidden defspec
+
address@hidden lookup-header-decl name
+Return the @var{header-decl} object registered for the given @var{name}.
+
address@hidden may be a symbol or a string. Strings are mapped to headers in
+a case-insensitive fashion.
address@hidden defun
+
address@hidden declare-header! sym name [#:multiple?] [#:parser] [#:validator] 
[#:writer]
+Define a parser, validator, and writer for the HTTP header, @var{name}.
+
address@hidden should be a procedure that takes a string and returns a
+Scheme value. @var{validator} is a predicate for whether the given
+Scheme value is valid for this header. @var{writer} takes a value and a
+port, and writes the value to the port.
address@hidden defun
+
address@hidden read-header port
+Reads one HTTP header from @var{port}. Returns two values: the header
+name and the parsed Scheme value. May raise an exception if the header
+was known but the value was invalid.
+
+Returns @var{#f} for both values if the end of the message body was
+reached (i.e., a blank line).
address@hidden defun
+
address@hidden parse-header name val
+Parse @var{val}, a string, with the parser for the header named
address@hidden
+
+Returns two values, the header name and parsed value. If a parser was
+found, the header name will be returned as a symbol. If a parser was not
+found, both the header name and the value are returned as strings.
address@hidden defun
+
address@hidden valid-header? sym val
+Returns a true value iff @var{val} is a valid Scheme value for the
+header with name @var{sym}.
address@hidden defun
+
address@hidden write-header name val port
+Writes the given header name and value to @var{port}. If @var{name} is a
+symbol, looks up a declared header and uses that writer. Otherwise the
+value is written using @var{display}.
address@hidden defun
+
address@hidden read-headers port
+Read an HTTP message from @var{port}, returning the headers as an
+ordered alist.
address@hidden defun
+
address@hidden write-headers headers port
+Write the given header alist to @var{port}. Doesn't write the final
+\r\n, as the user might want to add another header.
address@hidden defun
+
address@hidden parse-http-method str [start] [end]
+Parse an HTTP method from @var{str}. The result is an upper-case symbol,
+like @code{GET}.
address@hidden defun
+
address@hidden parse-http-version str [start] [end]
+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,
address@hidden(1 . 1)}.
address@hidden defun
+
address@hidden parse-request-uri str [start] [end]
+Parse a URI from an HTTP request line. Note that URIs in requests do not
+have to have a scheme or host name. The result is a URI object.
address@hidden defun
+
address@hidden read-request-line port
+Read the first line of an HTTP request from @var{port}, returning three
+values: the method, the URI, and the version.
address@hidden defun
+
address@hidden write-request-line method uri version port
+Write the first line of an HTTP request to @var{port}.
address@hidden defun
+
address@hidden 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".
address@hidden defun
+
address@hidden write-response-line version code reason-phrase port
+Write the first line of an HTTP response to @var{port}.
address@hidden defun
+
+
address@hidden Requests
address@hidden HTTP Requests
+
address@hidden
+(use-modules (web request))
address@hidden example
+
address@hidden request? 
address@hidden defspec
+
address@hidden request-method 
address@hidden defspec
+
address@hidden request-uri 
address@hidden defspec
+
address@hidden request-version 
address@hidden defspec
+
address@hidden request-headers 
address@hidden defspec
+
address@hidden request-meta 
address@hidden defspec
+
address@hidden request-port 
address@hidden defspec
+
address@hidden read-request port [meta]
+Read an HTTP request from @var{port}, optionally attaching the given
+metadata, @var{meta}.
+
+As a side effect, sets the encoding on @var{port} to ISO-8859-1
+(latin-1), so that reading one character reads one byte. See the
+discussion of character sets in "HTTP Requests" in the manual, for more
+information.
address@hidden defun
+
address@hidden build-request [#:method] [#:uri] [#:version] [#:headers] 
[#:port] [#:meta] [#:validate-headers?]
+Construct an HTTP request object. If @var{validate-headers?} is true,
+the headers are each run through their respective validators.
address@hidden defun
+
address@hidden write-request r port
+Write the given HTTP request to @var{port}.
+
+Returns a new request, whose @code{request-port} will continue writing
+on @var{port}, perhaps using some transfer encoding.
address@hidden defun
+
address@hidden read-request-body/latin-1 r
+Reads the request body from @var{r}, as a string.
+
+Assumes that the request port has ISO-8859-1 encoding, so that the
+number of characters to read is the same as the
address@hidden Returns @code{#f} if there was no request
+body.
address@hidden defun
+
address@hidden write-request-body/latin-1 r body
+Write @var{body}, a string encodable in ISO-8859-1, to the port
+corresponding to the HTTP request @var{r}.
address@hidden defun
+
address@hidden read-request-body/bytevector r
+Reads the request body from @var{r}, as a bytevector. Returns @code{#f}
+if there was no request body.
address@hidden defun
+
address@hidden write-request-body/bytevector r bv
+Write @var{body}, a bytevector, to the port corresponding to the HTTP
+request @var{r}.
address@hidden defun
+
address@hidden request-accept request [default='()]
address@hidden request-accept-charset request [default='()]
address@hidden request-accept-encoding request [default='()]
address@hidden request-accept-language request [default='()]
address@hidden request-allow request [default='()]
address@hidden request-authorization request [default=#f]
address@hidden request-cache-control request [default='()]
address@hidden request-connection request [default='()]
address@hidden request-content-encoding request [default='()]
address@hidden request-content-language request [default='()]
address@hidden request-content-length request [default=#f]
address@hidden request-content-location request [default=#f]
address@hidden request-content-md5 request [default=#f]
address@hidden request-content-range request [default=#f]
address@hidden request-content-type request [default=#f]
address@hidden request-date request [default=#f]
address@hidden request-expect request [default='()]
address@hidden request-expires request [default=#f]
address@hidden request-from request [default=#f]
address@hidden request-host request [default=#f]
address@hidden request-if-match request [default=#f]
address@hidden request-if-modified-since request [default=#f]
address@hidden request-if-none-match request [default=#f]
address@hidden request-if-range request [default=#f]
address@hidden request-if-unmodified-since request [default=#f]
address@hidden request-last-modified request [default=#f]
address@hidden request-max-forwards request [default=#f]
address@hidden request-pragma request [default='()]
address@hidden request-proxy-authorization request [default=#f]
address@hidden request-range request [default=#f]
address@hidden request-referer request [default=#f]
address@hidden request-te request [default=#f]
address@hidden request-trailer request [default='()]
address@hidden request-transfer-encoding request [default='()]
address@hidden request-upgrade request [default='()]
address@hidden request-user-agent request [default=#f]
address@hidden request-via request [default='()]
address@hidden request-warning request [default='()]
address@hidden defun
+
address@hidden request-absolute-uri r [default-host] [default-port]
address@hidden defun
+
+
+
address@hidden Responses
address@hidden HTTP Responses
+
address@hidden
+(use-modules (web response))
address@hidden example
+
+
address@hidden response? 
address@hidden defspec
+
address@hidden response-version 
address@hidden defspec
+
address@hidden response-code 
address@hidden defspec
+
address@hidden response-reason-phrase response
+Return the reason phrase given in @var{response}, or the standard reason
+phrase for the response's code.
address@hidden defun
+
address@hidden response-headers 
address@hidden defspec
+
address@hidden response-port 
address@hidden defspec
+
address@hidden read-response port
+Read an HTTP response from @var{port}, optionally attaching the given
+metadata, @var{meta}.
+
+As a side effect, sets the encoding on @var{port} to ISO-8859-1
+(latin-1), so that reading one character reads one byte. See the
+discussion of character sets in "HTTP Responses" in the manual, for more
+information.
address@hidden defun
+
address@hidden build-response [#:version] [#:code] [#:reason-phrase] 
[#:headers] [#:port]
+Construct an HTTP response object. If @var{validate-headers?} is true,
+the headers are each run through their respective validators.
address@hidden defun
+
address@hidden extend-response r k v . additional
+Extend an HTTP response by setting additional HTTP headers @var{k},
address@hidden Returns a new HTTP response.
address@hidden defun
+
address@hidden adapt-response-version response version
+Adapt the given response to a different HTTP version. Returns a new HTTP
+response.
+
+The idea is that many applications might just build a response for the
+default HTTP version, and this method could handle a number of
+programmatic transformations to respond to older HTTP versions (0.9 and
+1.0). But currently this function is a bit heavy-handed, just updating
+the version field.
address@hidden defun
+
address@hidden write-response r port
+Write the given HTTP response to @var{port}.
+
+Returns a new response, whose @code{response-port} will continue writing
+on @var{port}, perhaps using some transfer encoding.
address@hidden defun
+
address@hidden read-response-body/latin-1 r
+Reads the response body from @var{r}, as a string.
+
+Assumes that the response port has ISO-8859-1 encoding, so that the
+number of characters to read is the same as the
address@hidden Returns @code{#f} if there was no
+response body.
address@hidden defun
+
address@hidden write-response-body/latin-1 r body
+Write @var{body}, a string encodable in ISO-8859-1, to the port
+corresponding to the HTTP response @var{r}.
address@hidden defun
+
address@hidden read-response-body/bytevector r
+Reads the response body from @var{r}, as a bytevector. Returns @code{#f}
+if there was no response body.
address@hidden defun
+
address@hidden write-response-body/bytevector r bv
+Write @var{body}, a bytevector, to the port corresponding to the HTTP
+response @var{r}.
address@hidden defun
+
address@hidden response-accept-ranges response [default=#f]
address@hidden response-age response [default='()]
address@hidden response-allow response [default='()]
address@hidden response-cache-control response [default='()]
address@hidden response-connection response [default='()]
address@hidden response-content-encoding response [default='()]
address@hidden response-content-language response [default='()]
address@hidden response-content-length response [default=#f]
address@hidden response-content-location response [default=#f]
address@hidden response-content-md5 response [default=#f]
address@hidden response-content-range response [default=#f]
address@hidden response-content-type response [default=#f]
address@hidden response-date response [default=#f]
address@hidden response-etag response [default=#f]
address@hidden response-expires response [default=#f]
address@hidden response-last-modified response [default=#f]
address@hidden response-location response [default=#f]
address@hidden response-pragma response [default='()]
address@hidden response-proxy-authenticate response [default=#f]
address@hidden response-retry-after response [default=#f]
address@hidden response-server response [default=#f]
address@hidden response-trailer response [default='()]
address@hidden response-transfer-encoding response [default='()]
address@hidden response-upgrade response [default='()]
address@hidden response-vary response [default='()]
address@hidden response-via response [default='()]
address@hidden response-warning response [default='()]
address@hidden response-www-authenticate response [default=#f]
address@hidden defun
+
+
address@hidden Web Handlers
address@hidden Web Handlers
+
+from request to response
+
address@hidden Web Server
address@hidden Web Server
+
address@hidden(web server)} is a generic web server interface, along with a main
+loop implementation for web servers controlled by Guile.
+
+The lowest layer is the <server-impl> object, which defines a set of
+hooks to open a server, read a request from a client, write a
+response to a client, and close a server.  These hooks -- open,
+read, write, and close, respectively -- are bound together in a
+<server-impl> object.  Procedures in this module take a
+<server-impl> object, if needed.
+
+A <server-impl> may also be looked up by name.  If you pass the
address@hidden symbol to @code{run-server}, Guile looks for a variable named
address@hidden in the @code{(web server http)} module, which should be bound to 
a
+<server-impl> object.  Such a binding is made by instantiation of
+the @code{define-server-impl} syntax.  In this way the run-server loop can
+automatically load other backends if available.
+
+The life cycle of a server goes as follows:
+
address@hidden
address@hidden
+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
+server socket object, or signals an error.
+
address@hidden
+The @code{read} hook is called, to read a request from a new client.
+The @code{read} hook takes one arguments, the server socket.  It
+should return three values: an opaque client socket, the
+request, and the request body. The request should be a
address@hidden<request>} object, from @code{(web request)}.  The body should be 
a
+string or a bytevector, or @code{#f} if there is no body.
+
+If the read failed, the @code{read} hook may return #f for the client
+socket, request, and body.
+
address@hidden
+A user-provided handler procedure is called, with the request
+and body as its arguments.  The handler should return two
+values: the response, as a @code{<response>} record from @code{(web
+response)}, and the response body as a string, bytevector, or
address@hidden if not present.  We also allow the reponse to be simply an
+alist of headers, in which case a default response object is
+constructed with those headers.
+
address@hidden
+The @code{write} hook is called with three arguments: the client
+socket, the response, and the body.  The @code{write} hook returns no
+values.
+
address@hidden
+At this point the request handling is complete. For a loop, we
+loop back and try to read a new request.
+
address@hidden
+If the user interrupts the loop, the @code{close} hook is called on
+the server socket.
address@hidden enumerate
+
address@hidden define-server-impl name open read write close
address@hidden defspec
+
address@hidden lookup-server-impl impl
+Look up a server implementation. If @var{impl} is a server
+implementation already, it is returned directly. If it is a symbol, the
+binding named @var{impl} in the @code{(web server @var{impl})} module is
+looked up. Otherwise an error is signaled.
+
+Currently a server implementation is a somewhat opaque type, useful only
+for passing to other procedures in this module, like @code{read-client}.
address@hidden defun
+
address@hidden open-server impl open-params
+Open a server for the given implementation. Returns one value, the new
+server object. The implementation's @code{open} procedure is applied to
address@hidden, which should be a list.
address@hidden defun
+
address@hidden read-client impl server
+Read a new client from @var{server}, by applying the implementation's
address@hidden procedure to the server. If successful, returns three
+values: an object corresponding to the client, a request object, and the
+request body. If any exception occurs, returns @code{#f} for all three
+values.
address@hidden defun
+
address@hidden handle-request handler request body state
+Handle a given request, returning the response and body.
+
+The response and response body are produced by calling the given
address@hidden with @var{request} and @var{body} as arguments.
+
+The elements of @var{state} are also passed to @var{handler} as
+arguments, and may be returned as additional values. The new
address@hidden, collected from the @var{handler}'s return values, is then
+returned as a list. The idea is that a server loop receives a handler
+from the user, along with whatever state values the user is interested
+in, allowing the user's handler to explicitly manage its state.
address@hidden defun
+
address@hidden sanitize-response request response body
+"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
+response. Ensures that the response version corresponds to the request
+version. If @var{body} is a string, encodes the string to a bytevector,
+in an encoding appropriate for @var{response}. Adds a
address@hidden and @code{content-type} header, as necessary.
+
+If @var{body} is a procedure, it is called with a port as an argument,
+and the output collected as a bytevector. In the future we might try to
+instead use a compressing, chunk-encoded port, and call this procedure
+later, in the write-client procedure. Authors are advised not to rely on
+the procedure being called at any particular time.
address@hidden defun
+
address@hidden write-client impl server client response body
+Write an HTTP response and body to @var{client}. If the server and
+client support persistent connections, it is the implementation's
+responsibility to keep track of the client thereafter, presumably by
+attaching it to the @var{server} argument somehow.
address@hidden defun
+
address@hidden close-server impl server
+Release resources allocated by a previous invocation of
address@hidden
address@hidden defun
+
address@hidden serve-one-client handler impl server state
+Read one request from @var{server}, call @var{handler} on the request
+and body, and write the response to the client. Returns the new state
+produced by the handler procedure.
address@hidden defun
+
address@hidden run-server handler [impl] [open-params] . state
+Run Guile's built-in web server.
+
address@hidden should be a procedure that takes two or more arguments,
+the HTTP request and request body, and returns two or more values, the
+response and response body.
+
+For example, here is a simple "Hello, World!" server:
+
address@hidden 
+ (define (handler request body)
+   (values '((content-type . ("text/plain")))
+           "Hello, World!"))
+ (run-server handler)
address@hidden example
+
+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.
+
+The default server implementation is @code{http}, which accepts
address@hidden like @code{(#:port 8081)}, among others. See "Web
+Server" in the manual, for more information.
address@hidden defun
+
address@hidden
+(use-modules (web server))
address@hidden example
+
+
address@hidden Local Variables:
address@hidden TeX-master: "guile.texi"
address@hidden End:
diff --git a/module/web/http.scm b/module/web/http.scm
index 6416b1b..d02b336 100644
--- a/module/web/http.scm
+++ b/module/web/http.scm
@@ -92,6 +92,12 @@
                           parser
                           validator
                           writer)
+  "Define a parser, validator, and writer for the HTTP header, @var{name}.
+
address@hidden should be a procedure that takes a string and returns a
+Scheme value.  @var{validator} is a predicate for whether the given
+Scheme value is valid for this header.  @var{writer} takes a value and a
+port, and writes the value to the port."
   (if (and (symbol? sym) (string? name) parser validator writer)
       (let ((decl (make-header-decl sym name
                                     multiple? parser validator writer)))
@@ -125,6 +131,12 @@
       val))
 
 (define (read-header port)
+  "Reads one HTTP header from @var{port}. Returns two values: the header
+name and the parsed Scheme value. May raise an exception if the header
+was known but the value was invalid.
+
+Returns @var{#f} for both values if the end of the message body was
+reached (i.e., a blank line)."
   (let ((line (read-line* port)))
     (if (or (string-null? line)
             (string=? line "\r"))
@@ -138,11 +150,20 @@
             (string-trim-both line char-whitespace? (1+ delim))))))))
 
 (define (lookup-header-decl name)
+  "Return the @var{header-decl} object registered for the given @var{name}.
+
address@hidden may be a symbol or a string.  Strings are mapped to headers
+in a case-insensitive fashion."
   (if (string? name)
       (hash-ref *declared-headers-by-name* (string-downcase name))
       (hashq-ref *declared-headers* name)))
 
 (define (parse-header name val)
+  "Parse @var{val}, a string, with the parser for the header named @var{name}.
+
+Returns two values, the header name and parsed value.  If a parser was
+found, the header name will be returned as a symbol.  If a parser was
+not found, both the header name and the value are returned as strings."
   (let* ((down (string-downcase name))
          (decl (hash-ref *declared-headers-by-name* down)))
     (if decl
@@ -151,12 +172,17 @@
         (values down val))))
 
 (define (valid-header? sym val)
+  "Returns a true value iff @var{val} is a valid Scheme value for the
+header with name @var{sym}."
   (let ((decl (hashq-ref *declared-headers* sym)))
     (if (not decl)
         (error "Unknown header" sym)
         ((header-decl-validator decl) val))))
 
 (define (write-header name val port)
+  "Writes the given header name and value to @var{port}.  If @var{name}
+is a symbol, looks up a declared header and uses that writer. Otherwise
+the value is written using @var{display}."
   (if (string? name)
       ;; assume that it's a header we don't know about...
       (begin
@@ -174,6 +200,8 @@
               (display "\r\n" port))))))
 
 (define (read-headers port)
+  "Read an HTTP message from @var{port}, returning the headers as an
+ordered alist."
   (let lp ((headers '()))
     (call-with-values (lambda () (read-header port))
       (lambda (k v)
@@ -181,9 +209,9 @@
             (lp (acons k v headers))
             (reverse! headers))))))
 
-;; Doesn't write the final \r\n, as the user might want to add another
-;; header.
 (define (write-headers headers port)
+  "Write the given header alist to @var{port}.  Doesn't write the final
+\\r\\n, as the user might want to add another header."
   (let lp ((headers headers))
     (if (pair? headers)
         (begin
@@ -637,6 +665,9 @@
 (define *known-versions* '())
 
 (define* (parse-http-version str #:optional (start 0) (end (string-length 
str)))
+  "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,
address@hidden(1 . 1)}."
   (or (let lp ((known *known-versions*))
         (and (pair? known)
              (if (string= str (caar known) start end)
@@ -651,6 +682,7 @@
             (bad-header-component 'http-version (substring str start end))))))
 
 (define (write-http-version val port)
+  "Write the given major-minor version pair to @var{port}."
   (display "HTTP/" port)
   (display (car val) port)
   (display #\. port)
@@ -671,6 +703,8 @@
 ;; ourselves the trouble of that case, and disallow the CONNECT method.
 ;;
 (define* (parse-http-method str #:optional (start 0) (end (string-length str)))
+  "Parse an HTTP method from @var{str}.  The result is an upper-case
+symbol, like @code{GET}."
   (cond
    ((string= str "GET" start end) 'GET)
    ((string= str "HEAD" start end) 'HEAD)
@@ -682,6 +716,8 @@
    (else (bad-request "Invalid method: ~a" (substring str start end)))))
 
 (define* (parse-request-uri str #:optional (start 0) (end (string-length str)))
+  "Parse a URI from an HTTP request line.  Note that URIs in requests do
+not have to have a scheme or host name.  The result is a URI object."
   (cond
    ((= start end)
     (bad-request "Missing Request-URI"))
@@ -700,6 +736,8 @@
         (bad-request "Invalid URI: ~a" (substring str start end))))))
 
 (define (read-request-line port)
+  "Read the first line of an HTTP request from @var{port}, returning
+three values: the method, the URI, and the version."
   (let* ((line (read-line* port))
          (d0 (string-index line char-whitespace?)) ; "delimiter zero"
          (d1 (string-rindex line char-whitespace?)))
@@ -739,6 +777,7 @@
         (display (uri-query uri) port))))
 
 (define (write-request-line method uri version port)
+  "Write the first line of an HTTP request to @var{port}."
   (display method port)
   (display #\space port)
   (write-uri uri port)
@@ -747,6 +786,9 @@
   (display "\r\n" port))
 
 (define (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\"."
   (let* ((line (read-line* port))
          (d0 (string-index line char-whitespace?)) ; "delimiter zero"
          (d1 (and d0 (string-index line char-whitespace?
@@ -759,6 +801,7 @@
         (bad-response "Bad Response-Line: ~s" line))))
 
 (define (write-response-line version code reason-phrase port)
+  "Write the first line of an HTTP response to @var{port}."
   (write-http-version version port)
   (display #\space port)
   (display code port)
diff --git a/module/web/request.scm b/module/web/request.scm
index da91c40..adf1dd2 100644
--- a/module/web/request.scm
+++ b/module/web/request.scm
@@ -156,6 +156,8 @@
 (define* (build-request #:key (method 'GET) uri (version '(1 . 1))
                         (headers '()) port (meta '())
                         (validate-headers? #t))
+  "Construct an HTTP request object. If @var{validate-headers?} is true,
+the headers are each run through their respective validators."
   (cond
    ((not (and (pair? version)
               (non-negative-integer? (car version))
@@ -173,6 +175,13 @@
   (make-request method uri version headers meta port))
 
 (define* (read-request port #:optional (meta '()))
+  "Read an HTTP request from @var{port}, optionally attaching the given
+metadata, @var{meta}.
+
+As a side effect, sets the encoding on @var{port} to
+ISO-8859-1 (latin-1), so that reading one character reads one byte.  See
+the discussion of character sets in \"HTTP Requests\" in the manual, for
+more information."
   (set-port-encoding! port "ISO-8859-1")
   (call-with-values (lambda () (read-request-line port))
     (lambda (method uri version)
@@ -180,6 +189,10 @@
 
 ;; FIXME: really return a new request?
 (define (write-request r port)
+  "Write the given HTTP request to @var{port}.
+
+Returns a new request, whose @code{request-port} will continue writing
+on @var{port}, perhaps using some transfer encoding."
   (write-request-line (request-method r) (request-uri r)
                       (request-version r) port)
   (write-headers (request-headers r) port)
@@ -193,6 +206,12 @@
 ;; per char because we are in latin-1 encoding.
 ;;
 (define (read-request-body/latin-1 r)
+  "Reads the request body from @var{r}, as a string.
+
+Assumes that the request port has ISO-8859-1 encoding, so that the
+number of characters to read is the same as the
address@hidden Returns @code{#f} if there was no request
+body."
   (cond 
    ((request-content-length r) =>
     (lambda (nbytes)
@@ -216,9 +235,13 @@
 ;; and that the latin-1 encoding is what is expected by the server.
 ;;
 (define (write-request-body/latin-1 r body)
+  "Write @var{body}, a string encodable in ISO-8859-1, to the port
+corresponding to the HTTP request @var{r}."
   (display body (request-port r)))
 
 (define (read-request-body/bytevector r)
+  "Reads the request body from @var{r}, as a bytevector.  Returns
address@hidden if there was no request body."
   (let ((nbytes (request-content-length r)))
     (and nbytes
          (let ((bv (get-bytevector-n (request-port r) nbytes)))
@@ -228,6 +251,8 @@
                             (bytevector-length bv) nbytes))))))
 
 (define (write-request-body/bytevector r bv)
+  "Write @var{body}, a bytevector, to the port corresponding to the HTTP
+request @var{r}."
   (put-bytevector (request-port r) bv))
 
 (define-syntax define-request-accessor
diff --git a/module/web/response.scm b/module/web/response.scm
index c3c69cd..295b2f4 100644
--- a/module/web/response.scm
+++ b/module/web/response.scm
@@ -95,9 +95,13 @@
 
 (define* (build-response #:key (version '(1 . 1)) (code 200) reason-phrase
                          (headers '()) port)
+  "Construct an HTTP response object. If @var{validate-headers?} is true,
+the headers are each run through their respective validators."
   (make-response version code reason-phrase headers port))
 
 (define (extend-response r k v . additional)
+  "Extend an HTTP response by setting additional HTTP headers @var{k},
address@hidden  Returns a new HTTP response."
   (let ((r (build-response #:version (response-version r)
                            #:code (response-code r)
                            #:reason-phrase (%response-reason-phrase r)
@@ -156,22 +160,43 @@
       "(Unknown)"))
 
 (define (response-reason-phrase response)
+  "Return the reason phrase given in @var{response}, or the standard
+reason phrase for the response's code."
   (or (%response-reason-phrase response)
       (code->reason-phrase (response-code response))))
 
 (define (read-response port)
+  "Read an HTTP response from @var{port}, optionally attaching the given
+metadata, @var{meta}.
+
+As a side effect, sets the encoding on @var{port} to
+ISO-8859-1 (latin-1), so that reading one character reads one byte.  See
+the discussion of character sets in \"HTTP Responses\" in the manual,
+for more information."
   (set-port-encoding! port "ISO-8859-1")
   (call-with-values (lambda () (read-response-line port))
     (lambda (version code reason-phrase)
       (make-response version code reason-phrase (read-headers port) port))))
 
 (define (adapt-response-version response version)
+  "Adapt the given response to a different HTTP version.  Returns a new
+HTTP response.
+
+The idea is that many applications might just build a response for the
+default HTTP version, and this method could handle a number of
+programmatic transformations to respond to older HTTP versions (0.9 and
+1.0).  But currently this function is a bit heavy-handed, just updating
+the version field."
   (build-response #:code (response-code response)
                   #:version version
                   #:headers (response-headers response)
                   #:port (response-port response)))
 
 (define (write-response r port)
+  "Write the given HTTP response to @var{port}.
+
+Returns a new response, whose @code{response-port} will continue writing
+on @var{port}, perhaps using some transfer encoding."
   (write-response-line (response-version r) (response-code r)
                        (response-reason-phrase r) port)
   (write-headers (response-headers r) port)
@@ -185,6 +210,12 @@
 ;; per char because we are in latin-1 encoding.
 ;;
 (define (read-response-body/latin-1 r)
+  "Reads the response body from @var{r}, as a string.
+
+Assumes that the response port has ISO-8859-1 encoding, so that the
+number of characters to read is the same as the
address@hidden Returns @code{#f} if there was no
+response body."
   (cond 
    ((response-content-length r) =>
     (lambda (nbytes)
@@ -205,12 +236,16 @@
    (else #f)))
 
 ;; Likewise, assumes that body can be written in the latin-1 encoding,
-;; and that the latin-1 encoding is what is expected by the server.
+;; and that the latin-1 encoding is what is expected by the client.
 ;;
 (define (write-response-body/latin-1 r body)
+  "Write @var{body}, a string encodable in ISO-8859-1, to the port
+corresponding to the HTTP response @var{r}."
   (display body (response-port r)))
 
 (define (read-response-body/bytevector r)
+  "Reads the response body from @var{r}, as a bytevector.  Returns
address@hidden if there was no response body."
   (let ((nbytes (response-content-length r)))
     (and nbytes
          (let ((bv (get-bytevector-n (response-port r) nbytes)))
@@ -220,6 +255,8 @@
                             (bytevector-length bv) nbytes))))))
 
 (define (write-response-body/bytevector r bv)
+  "Write @var{body}, a bytevector, to the port corresponding to the HTTP
+response @var{r}."
   (put-bytevector (response-port r) bv))
 
 (define-syntax define-response-accessor
diff --git a/module/web/server.scm b/module/web/server.scm
index 6d3d941..042e4f1 100644
--- a/module/web/server.scm
+++ b/module/web/server.scm
@@ -125,6 +125,14 @@
        (make-server-impl 'name open read write close)))))
 
 (define (lookup-server-impl impl)
+  "Look up a server implementation.  If @var{impl} is a server
+implementation already, it is returned directly.  If it is a symbol, the
+binding named @var{impl} in the @code{(web server @var{impl})} module is
+looked up.  Otherwise an error is signaled.
+
+Currently a server implementation is a somewhat opaque type, useful only
+for passing to other procedures in this module, like
address@hidden"
   (cond
    ((server-impl? impl) impl)
    ((symbol? impl)
@@ -137,10 +145,18 @@
 
 ;; -> server
 (define (open-server impl open-params)
+  "Open a server for the given implementation.  Returns one value, the
+new server object.  The implementation's @code{open} procedure is
+applied to @var{open-params}, which should be a list."
   (apply (server-impl-open impl) open-params))
 
 ;; -> (client request body | #f #f #f)
 (define (read-client impl server)
+  "Read a new client from @var{server}, by applying the implementation's
address@hidden procedure to the server.  If successful, returns three
+values: an object corresponding to the client, a request object, and the
+request body.  If any exception occurs, returns @code{#f} for all three
+values."
   (call-with-error-handling
    (lambda ()
      ((server-impl-read impl) server))
@@ -173,6 +189,21 @@
 
 ;; -> response body
 (define (sanitize-response request response body)
+  "\"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
+response.  Ensures that the response version corresponds to the request
+version.  If @var{body} is a string, encodes the string to a bytevector,
+in an encoding appropriate for @var{response}.  Adds a
address@hidden and @code{content-type} header, as necessary.
+
+If @var{body} is a procedure, it is called with a port as an argument,
+and the output collected as a bytevector.  In the future we might try to
+instead use a compressing, chunk-encoded port, and call this procedure
+later, in the write-client procedure.  Authors are advised not to rely
+on the procedure being called at any particular time."
   (cond
    ((list? response)
     (sanitize-response request
@@ -226,6 +257,17 @@
 
 ;; -> response body state
 (define (handle-request handler request body state)
+  "Handle a given request, returning the response and body.
+
+The response and response body are produced by calling the given
address@hidden with @var{request} and @var{body} as arguments.
+
+The elements of @var{state} are also passed to @var{handler} as
+arguments, and may be returned as additional values.  The new
address@hidden, collected from the @var{handler}'s return values, is then
+returned as a list.  The idea is that a server loop receives a handler
+from the user, along with whatever state values the user is interested
+in, allowing the user's handler to explicitly manage its state."
   (call-with-error-handling
    (lambda ()
      (call-with-values (lambda ()
@@ -248,6 +290,10 @@
 
 ;; -> unspecified values
 (define (write-client impl server client response body)
+  "Write an HTTP response and body to @var{client}.  If the server and
+client support persistent connections, it is the implementation's
+responsibility to keep track of the client thereafter, presumably by
+attaching it to the @var{server} argument somehow."
   (call-with-error-handling
    (lambda ()
      ((server-impl-write impl) server client response body))
@@ -260,6 +306,8 @@
 
 ;; -> unspecified values
 (define (close-server impl server)
+  "Release resources allocated by a previous invocation of
address@hidden"
   ((server-impl-close impl) server))
 
 (define call-with-sigint
@@ -290,6 +338,9 @@
   
 ;; -> new-state
 (define (serve-one-client handler impl server state)
+  "Read one request from @var{server}, call @var{handler} on the request
+and body, and write the response to the client.  Returns the new state
+produced by the handler procedure."
   (debug-elapsed 'serve-again)
   (call-with-values
       (lambda ()
@@ -309,6 +360,32 @@
 
 (define* (run-server handler #:optional (impl 'http) (open-params '())
                      . state)
+  "Run Guile's built-in web server.
+
address@hidden should be a procedure that takes two or more arguments,
+the HTTP request and request body, and returns two or more values, the
+response and response body.
+
+For example, here is a simple \"Hello, World!\" server:
+
address@hidden
+ (define (handler request body)
+   (values '((content-type . (\"text/plain\")))
+           \"Hello, World!\"))
+ (run-server handler)
address@hidden example
+
+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
address@hidden Additional return values are accumulated into a new
address@hidden, which will be used for subsequent requests.  In this way a
+handler can explicitly manage its state.
+
+The default server implementation is @code{http}, which accepts
address@hidden like @code{(#:port 8081)}, among others.  See \"Web
+Server\" in the manual, for more information."
   (let* ((impl (lookup-server-impl impl))
          (server (open-server impl open-params)))
     (call-with-sigint
diff --git a/module/web/uri.scm b/module/web/uri.scm
index 7a82f0f..a7c4f2e 100644
--- a/module/web/uri.scm
+++ b/module/web/uri.scm
@@ -19,11 +19,18 @@
 
 ;;; Commentary:
 
-;; Based on (www url). To be documented.
+;; A data type for Universal Resource Identifiers, as defined in RFC
+;; 3986. 
 
 ;;; Code:
 
 (define-module (web uri)
+  #:use-module (srfi srfi-9)
+  #:use-module (ice-9 regex)
+  #:use-module (ice-9 rdelim)
+  #:use-module (ice-9 control)
+  #:use-module (rnrs bytevectors)
+  #:use-module (rnrs io ports)
   #:export (uri?
             uri-scheme uri-userinfo uri-host uri-port
             uri-path uri-query uri-fragment
@@ -33,13 +40,7 @@
             parse-uri unparse-uri
             uri-decode uri-encode
             split-and-decode-uri-path
-            encode-and-join-uri-path)
-  #:use-module (srfi srfi-9)
-  #:use-module (ice-9 regex)
-  #:use-module (ice-9 rdelim)
-  #:use-module (ice-9 control)
-  #:use-module (rnrs bytevectors)
-  #:use-module (rnrs io ports))
+            encode-and-join-uri-path))
 
 (define-record-type <uri>
   (make-uri scheme userinfo host port path query fragment)
@@ -78,6 +79,8 @@
 
 (define* (build-uri scheme #:key userinfo host port (path "") query fragment
                     (validate? #t))
+  "Construct a URI object. If @var{validate?} is true, also run some
+consistency checks to make sure that the constructed URI is valid."
   (if validate?
       (validate-uri scheme userinfo host port path query fragment))
   (make-uri scheme userinfo host port path query fragment))
@@ -158,6 +161,8 @@
   (make-regexp uri-pat))
 
 (define (parse-uri string)
+  "Parse @var{string} into a URI object. Returns @code{#f} if the string
+could not be parsed."
   (% (let ((m (regexp-exec uri-regexp string)))
        (if (not m) (abort))
        (let ((scheme (string->symbol
@@ -179,6 +184,10 @@
 (define *default-ports* (make-hash-table))
 
 (define (declare-default-port! scheme port)
+  "Declare a default port for the given URI scheme.
+
+Default ports are for printing URI objects: a default port is not
+printed."
   (hashq-set! *default-ports* scheme port))
 
 (define (default-port? scheme port)
@@ -189,6 +198,7 @@
 (declare-default-port! 'https 443)
 
 (define (unparse-uri uri)
+  "Serialize @var{uri} to a string."
   (let* ((scheme-str (string-append
                       (symbol->string (uri-scheme uri)) ":"))
          (userinfo (uri-userinfo uri))
@@ -257,6 +267,18 @@
   (string->char-set "0123456789abcdefABCDEF"))
 
 (define* (uri-decode str #:key (charset "utf-8"))
+  "Percent-decode the given @var{str}, according to @var{charset}.
+
+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.
+
+Note that percent-encoded strings encode @emph{bytes}, not characters.
+There is no guarantee that a given byte sequence is a valid string
+encoding. Therefore this routine may signal an error if the decoded
+bytes are not valid for the given encoding. Pass @code{#f} for
address@hidden if you want decoded bytes as a bytevector directly."
   (let ((len (string-length str)))
     (call-with-values open-bytevector-output-port
       (lambda (port get-bytevector)
@@ -308,35 +330,38 @@
 ;;
 (define* (uri-encode str #:key (charset "utf-8")
                      (unescaped-chars unreserved-chars))
-  (define (put-utf8 binary-port str)
-    (put-bytevector binary-port (string->utf8 str)))
-
-  ((cond
-    ((string-ci=? charset "utf-8") utf8->string)
-    ((not charset) (lambda (x) x)) ; raw bytevector
-    (else (uri-error "Unimplemented charset: ~s" charset)))
-   (call-with-values open-bytevector-output-port
-     (lambda (port get-bytevector)
-       (string-for-each
-        (lambda (ch)
-          (if (char-set-contains? unescaped-chars ch)
-              (put-utf8 port (string ch))
-              (let* ((utf8 (string->utf8 (string ch)))
-                     (len (bytevector-length utf8)))
-                ;; Encode each byte.
-                (let lp ((i 0))
-                  (if (< i len)
-                      (begin
-                        (put-utf8 port (string #\%))
-                        (put-utf8 port
-                                  (number->string (bytevector-u8-ref utf8 i) 
16))
-                        (lp (1+ i))))))))
-        str)
-       (get-bytevector)))))
+  "Percent-encode any character not in @var{unescaped-chars}.
+
+Percent-encoding first writes out the given character to a bytevector
+within the given @var{charset}, then encodes each byte as
address@hidden@var{HH}}, where @var{HH} is the hexadecimal representation of
+the byte."
+  (call-with-output-string
+   (lambda (port)
+     (string-for-each
+      (lambda (ch)
+        (if (char-set-contains? unescaped-chars ch)
+            (display ch port)
+            (let* ((bv (encode-string (string ch) charset))
+                   (len (bytevector-length bv)))
+              (let lp ((i 0))
+                (if (< i len)
+                    (let ((byte (bytevector-u8-ref bv i)))
+                      (display #\% port)
+                      (display (number->string byte 16) port)
+                      (lp (1+ i))))))))
+      str))))
 
 (define (split-and-decode-uri-path path)
+  "Split @var{path} into its components, and decode each
+component, removing empty components.
+
+For example, @code{\"/foo/bar/\"} decodes to the two-element list,
address@hidden(\"foo\" \"bar\")}."
   (filter (lambda (x) (not (string-null? x)))
           (map uri-decode (string-split path #\/))))
 
 (define (encode-and-join-uri-path parts)
+  "URI-encode each element of @var{parts}, which should be a list of
+strings, and join the parts together with @code{/} as a delimiter."
   (string-join (map uri-encode parts) "/"))


hooks/post-receive
-- 
GNU Guile



reply via email to

[Prev in Thread] Current Thread [Next in Thread]