[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Guile-commits] GNU Guile branch, master, updated. release_1-9-14-55-g2e
From: |
Andy Wingo |
Subject: |
[Guile-commits] GNU Guile branch, master, updated. release_1-9-14-55-g2e6f5ea |
Date: |
Tue, 11 Jan 2011 06:41:11 +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=2e6f5ea4cdd96bdc46ac579b1731e73ba3ae6024
The branch, master has been updated
via 2e6f5ea4cdd96bdc46ac579b1731e73ba3ae6024 (commit)
via f4ec6877bbb6c0e6b99a5648a97c8c08795433ba (commit)
via de54fb6d5e719a87bd04ccdd80d97776a75b3593 (commit)
via f944ee8f23f03f2ec62ed8b421281ef9b451f4b2 (commit)
via 3475fbb5722fb53a413a89db231ed543cc27c05d (commit)
from ff8339db69811ef9c736379b9127e60a3ff74b05 (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 2e6f5ea4cdd96bdc46ac579b1731e73ba3ae6024
Author: Andy Wingo <address@hidden>
Date: Mon Jan 10 22:40:43 2011 -0800
web.texi defun -> deffn
* doc/ref/web.texi (URIs): Change instances of @defun to @deffn with
{Scheme Procedure}.
commit f4ec6877bbb6c0e6b99a5648a97c8c08795433ba
Author: Andy Wingo <address@hidden>
Date: Mon Jan 10 22:35:39 2011 -0800
more web.texi foo
* doc/ref/web.texi (Web Server, Web Examples): Update.
commit de54fb6d5e719a87bd04ccdd80d97776a75b3593
Author: Andy Wingo <address@hidden>
Date: Mon Jan 10 22:23:38 2011 -0800
update web.text documentation for requests and responses
* doc/ref/web.texi (Requests, Responses): Update, and add a note on
character encodings.
commit f944ee8f23f03f2ec62ed8b421281ef9b451f4b2
Author: Andy Wingo <address@hidden>
Date: Mon Jan 10 22:22:56 2011 -0800
request and response cleanups
* module/web/request.scm (build-request): Make URI a positional
argument.
* module/web/response.scm: Remove extend-response.
(read-response): Fix a docstring.
* module/web/server.scm (extend-response): Include extend-response here,
but not exported.
commit 3475fbb5722fb53a413a89db231ed543cc27c05d
Author: Andy Wingo <address@hidden>
Date: Mon Jan 10 22:09:57 2011 -0800
(web response) and (web request): bodies are bytevectors
* module/web/request.scm (read-request-body, write-request-body): Rename
from read-request-body/bytevector and
write-request-body/bytevector. Remove the /latin-1 variants, as they
were unused and a bad idea.
* module/web/response.scm (read-response-body, write-response-body):
Likewise.
* module/web/server/http.scm (http-read, http-write): Adapt to
request/response change.
* test-suite/tests/web-request.test:
* test-suite/tests/web-response.test: Update tests.
-----------------------------------------------------------------------
Summary of changes:
doc/ref/web.texi | 541 ++++++++++++++++++------------------
module/web/request.scm | 50 +---
module/web/response.scm | 66 +----
module/web/server.scm | 11 +
module/web/server/http.scm | 10 +-
test-suite/tests/web-request.test | 7 +-
test-suite/tests/web-response.test | 13 +-
7 files changed, 307 insertions(+), 391 deletions(-)
diff --git a/doc/ref/web.texi b/doc/ref/web.texi
index 56b9720..3c7e0cd 100644
--- a/doc/ref/web.texi
+++ b/doc/ref/web.texi
@@ -204,44 +204,44 @@ The following procedures can be found in the @code{(web
uri)}
module. Load it into your Guile, using a form like the above, to have
access to them.
address@hidden build-uri scheme [#:address@hidden [#:address@hidden @
address@hidden {Scheme Procedure} build-uri scheme [#:address@hidden
[#:address@hidden @
[#:address@hidden [#:address@hidden""}] [#:address@hidden @
[#:address@hidden [#:address@hidden
Construct a URI object. @var{scheme} should be a symbol, and the rest
of the fields are either strings or @code{#f}. If @var{validate?} is
true, also run some consistency checks to make sure that the constructed
URI is valid.
address@hidden defun
-
address@hidden uri? x
address@hidden uri-scheme uri
address@hidden uri-userinfo uri
address@hidden uri-host uri
address@hidden uri-port uri
address@hidden uri-path uri
address@hidden uri-query uri
address@hidden uri-fragment uri
address@hidden deffn
+
address@hidden {Scheme Procedure} uri? x
address@hidden {Scheme Procedure} uri-scheme uri
address@hidden {Scheme Procedure} uri-userinfo uri
address@hidden {Scheme Procedure} uri-host uri
address@hidden {Scheme Procedure} uri-port uri
address@hidden {Scheme Procedure} uri-path uri
address@hidden {Scheme Procedure} uri-query uri
address@hidden {Scheme Procedure} uri-fragment uri
A predicate and field accessors for the URI record type. The URI scheme
will be a symbol, and the rest either strings or @code{#f} if not
present.
address@hidden defun
address@hidden deffn
address@hidden string->uri string
address@hidden {Scheme Procedure} string->uri string
Parse @var{string} into a URI object. Return @code{#f} if the string
could not be parsed.
address@hidden defun
address@hidden deffn
address@hidden uri->string uri
address@hidden {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
serialization.
address@hidden defun
address@hidden deffn
address@hidden declare-default-port! scheme port
address@hidden {Scheme Procedure} declare-default-port! scheme port
Declare a default port for the given URI scheme.
address@hidden defun
address@hidden deffn
address@hidden uri-decode str [#:address@hidden"utf-8"}]
address@hidden {Scheme Procedure} uri-decode str [#:address@hidden"utf-8"}]
Percent-decode the given @var{str}, according to @var{encoding}, which
should be the name of a character encoding.
@@ -260,12 +260,12 @@ character encodings.
Returns a string of the decoded characters, or a bytevector if
@var{encoding} was @code{#f}.
address@hidden defun
address@hidden deffn
Fixme: clarify return type. indicate default values. type of
unescaped-chars.
address@hidden uri-encode str [#:address@hidden"utf-8"}] [#:unescaped-chars]
address@hidden {Scheme Procedure} uri-encode str [#:address@hidden"utf-8"}]
[#:unescaped-chars]
Percent-encode any character not in the character set,
@var{unescaped-chars}.
@@ -275,23 +275,23 @@ other character will be percent-encoded, by writing out
the character to
a bytevector within the given @var{encoding}, then encoding each byte as
@address@hidden, where @var{HH} is the hexadecimal representation of
the byte.
address@hidden defun
address@hidden deffn
address@hidden split-and-decode-uri-path path
address@hidden {Scheme Procedure} split-and-decode-uri-path path
Split @var{path} into its components, and decode each component,
removing empty components.
For example, @code{"/foo/bar%20baz/"} decodes to the two-element list,
@code{("foo" "bar baz")}.
address@hidden defun
address@hidden deffn
address@hidden encode-and-join-uri-path parts
address@hidden {Scheme Procedure} 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.
For example, the list @code{("scrambled eggs" "biscuits&gravy")} encodes
as @code{"scrambled%20eggs/biscuits%26gravy"}.
address@hidden defun
address@hidden deffn
@node HTTP
@subsection The Hyper-Text Transfer Protocol
@@ -321,13 +321,13 @@ not-too-divergent texts.
Header names are represented as lower-case symbols.
address@hidden string->header name
address@hidden {Scheme Procedure} string->header name
Parse @var{name} to a symbolic header name.
address@hidden defun
address@hidden deffn
address@hidden header->string sym
address@hidden {Scheme Procedure} header->string sym
Return the string form for the header named @var{sym}.
address@hidden defun
address@hidden deffn
For example:
@@ -347,37 +347,37 @@ Guile keeps a registry of known headers, their string
names, and some
parsing and serialization procedures. If a header is unknown, its
string name is simply its symbol name in title-case.
address@hidden known-header? sym
address@hidden {Scheme Procedure} known-header? sym
Return @code{#t} iff @var{sym} is a known header, with associated
parsers and serialization procedures.
address@hidden defun
address@hidden deffn
address@hidden header-parser sym
address@hidden {Scheme Procedure} header-parser sym
Return the value parser for headers named @var{sym}. The result is a
procedure that takes one argument, a string, and returns the parsed
value. If the header isn't known to Guile, a default parser is returned
that passes through the string unchanged.
address@hidden defun
address@hidden deffn
address@hidden header-validator sym
address@hidden {Scheme Procedure} header-validator sym
Return a predicate which returns @code{#t} if the given value is valid
for headers named @var{sym}. The default validator for unknown headers
is @code{string?}.
address@hidden defun
address@hidden deffn
address@hidden header-writer sym
address@hidden {Scheme Procedure} header-writer sym
Return a procedure that writes values for headers named @var{sym} to a
port. The resulting procedure takes two arguments: a value and a port.
The default writer is @code{display}.
address@hidden defun
address@hidden deffn
For more on the set of headers that Guile knows about out of the box,
@pxref{HTTP Headers}. To add your own, use the @code{declare-header!}
procedure:
address@hidden declare-header! name parser validator writer [#:address@hidden
address@hidden {Scheme Procedure} declare-header! name parser validator writer
[#:address@hidden
Declare a parser, validator, and writer for a given header.
address@hidden defun
address@hidden deffn
For example, let's say you are running a web server behind some sort of
proxy, and your proxy adds an @code{X-Client-Address} header, indicating
@@ -402,79 +402,79 @@ HTTP stack like this:
(display (inet-ntoa ip) port)))
@end example
address@hidden valid-header? sym val
address@hidden {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}.
address@hidden defun
address@hidden deffn
Now that we have a generic interface for reading and writing headers, we
do just that.
address@hidden read-header port
address@hidden {Scheme Procedure} read-header port
Read one HTTP header from @var{port}. Return 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 the end-of-file object for both values if the end of the message
body was reached (i.e., a blank line).
address@hidden defun
address@hidden deffn
address@hidden parse-header name val
address@hidden {Scheme Procedure} parse-header name val
Parse @var{val}, a string, with the parser for the header named
@var{name}. Returns the parsed value.
address@hidden defun
address@hidden deffn
address@hidden write-header name val port
address@hidden {Scheme Procedure} write-header name val port
Write the given header name and value to @var{port}, using the writer
from @code{header-writer}.
address@hidden defun
address@hidden deffn
address@hidden read-headers port
address@hidden {Scheme Procedure} read-headers port
Read the headers of an HTTP message from @var{port}, returning the
headers as an ordered alist.
address@hidden defun
address@hidden deffn
address@hidden write-headers headers port
address@hidden {Scheme Procedure} write-headers headers port
Write the given header alist to @var{port}. Doesn't write the final
@samp{\r\n}, as the user might want to add another header.
address@hidden defun
address@hidden deffn
The @code{(web http)} module also has some utility procedures to read
and write request and response lines.
address@hidden parse-http-method str [start] [end]
address@hidden {Scheme Procedure} 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 deffn
address@hidden parse-http-version str [start] [end]
address@hidden {Scheme Procedure} 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,
@code{(1 . 1)}.
address@hidden defun
address@hidden deffn
address@hidden parse-request-uri str [start] [end]
address@hidden {Scheme Procedure} 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 deffn
address@hidden read-request-line port
address@hidden {Scheme Procedure} 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 deffn
address@hidden write-request-line method uri version port
address@hidden {Scheme Procedure} write-request-line method uri version port
Write the first line of an HTTP request to @var{port}.
address@hidden defun
address@hidden deffn
address@hidden read-response-line port
address@hidden {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".
address@hidden defun
address@hidden deffn
address@hidden write-response-line version code reason-phrase port
address@hidden {Scheme Procedure} write-response-line version code
reason-phrase port
Write the first line of an HTTP response to @var{port}.
address@hidden defun
address@hidden deffn
@node HTTP Headers
@@ -1033,23 +1033,43 @@ A list of challenges to a user, indicating the need for
authentication.
(use-modules (web request))
@end example
-The request module contains a data type for HTTP requests. Note that
-the body is not part of the request, but the port is. Once you have
-read a request, you may read the body separately, and likewise for
-writing requests.
+The request module contains a data type for HTTP requests.
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 request?
address@hidden request-method
address@hidden request-uri
address@hidden request-version
address@hidden request-headers
address@hidden request-meta
address@hidden request-port
address@hidden An Important Note on Character Sets
+
+HTTP requests consist of two parts: the request proper, consisting of a
+request line and a set of headers, and (optionally) a body. The body
+might have a binary content-type, and even in the textual case its
+length is specified in bytes, not characters.
+
+Therefore, HTTP is a fundamentally binary protocol. However the request
+line and headers are specified to be in a subset of ASCII, so they can
+be treated as text, provided that the port's encoding is set to an
+ASCII-compatible one-byte-per-character encoding. ISO-8859-1 (latin-1)
+is just such an encoding, and happens to be very efficient for Guile.
+
+So what Guile does when reading requests from the wire, or writing them
+out, is to set the port's encoding to latin-1, and treating the request
+headers as text.
+
+The request body is another issue. For binary data, the data is
+probably in a bytevector, so we use the R6RS binary output procedures to
+write out the binary payload. Textual data usually has to be written
+out to some character encoding, usually UTF-8, and then the resulting
+bytevector is written out to the port.
+
+In summary, Guile reads and writes HTTP over latin-1 sockets, without
+any loss of generality.
+
address@hidden Request API
+
address@hidden {Scheme Procedure} request?
address@hidden {Scheme Procedure} request-method
address@hidden {Scheme Procedure} request-uri
address@hidden {Scheme Procedure} request-version
address@hidden {Scheme Procedure} request-headers
address@hidden {Scheme Procedure} request-meta
address@hidden {Scheme Procedure} request-port
A predicate and field accessors for the request type. The fields are as
follows:
@table @code
@@ -1068,99 +1088,92 @@ Communication}).
@item port
The port on which to read or write a request body, if any.
@end table
address@hidden defun
address@hidden deffn
address@hidden read-request port [meta]
address@hidden {Scheme Procedure} 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
+discussion of character sets above, for more information.
address@hidden write-request r port
-Write the given HTTP request to @var{port}.
+Note that the body is not part of the request. Once you have read a
+request, you may read the body separately, and likewise for writing
+requests.
address@hidden deffn
-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.
address@hidden {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.
address@hidden deffn
-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 {Scheme Procedure} write-request r port
+Write the given HTTP request to @var{port}.
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
+Return a new request, whose @code{request-port} will continue writing
+on @var{port}, perhaps using some transfer encoding.
address@hidden deffn
address@hidden read-request-body/bytevector r
-Reads the request body from @var{r}, as a bytevector. Returns @code{#f}
address@hidden {Scheme Procedure} read-request-body r
+Reads the request body from @var{r}, as a bytevector. Return @code{#f}
if there was no request body.
address@hidden defun
address@hidden deffn
address@hidden write-request-body/bytevector r bv
address@hidden {Scheme Procedure} write-request-body r bv
Write @var{body}, a bytevector, to the port corresponding to the HTTP
request @var{r}.
address@hidden defun
address@hidden deffn
The various headers that are typically associated with HTTP requests may
be accessed with these dedicated accessors. @xref{HTTP Headers}, for
more information on the format of parsed headers.
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 {Scheme Procedure} request-accept request [default='()]
address@hidden {Scheme Procedure} request-accept-charset request [default='()]
address@hidden {Scheme Procedure} request-accept-encoding request [default='()]
address@hidden {Scheme Procedure} request-accept-language request [default='()]
address@hidden {Scheme Procedure} request-allow request [default='()]
address@hidden {Scheme Procedure} request-authorization request [default=#f]
address@hidden {Scheme Procedure} request-cache-control request [default='()]
address@hidden {Scheme Procedure} request-connection request [default='()]
address@hidden {Scheme Procedure} request-content-encoding request [default='()]
address@hidden {Scheme Procedure} request-content-language request [default='()]
address@hidden {Scheme Procedure} request-content-length request [default=#f]
address@hidden {Scheme Procedure} request-content-location request [default=#f]
address@hidden {Scheme Procedure} request-content-md5 request [default=#f]
address@hidden {Scheme Procedure} request-content-range request [default=#f]
address@hidden {Scheme Procedure} request-content-type request [default=#f]
address@hidden {Scheme Procedure} request-date request [default=#f]
address@hidden {Scheme Procedure} request-expect request [default='()]
address@hidden {Scheme Procedure} request-expires request [default=#f]
address@hidden {Scheme Procedure} request-from request [default=#f]
address@hidden {Scheme Procedure} request-host request [default=#f]
address@hidden {Scheme Procedure} request-if-match request [default=#f]
address@hidden {Scheme Procedure} request-if-modified-since request [default=#f]
address@hidden {Scheme Procedure} request-if-none-match request [default=#f]
address@hidden {Scheme Procedure} request-if-range request [default=#f]
address@hidden {Scheme Procedure} request-if-unmodified-since request
[default=#f]
address@hidden {Scheme Procedure} request-last-modified request [default=#f]
address@hidden {Scheme Procedure} request-max-forwards request [default=#f]
address@hidden {Scheme Procedure} request-pragma request [default='()]
address@hidden {Scheme Procedure} request-proxy-authorization request
[default=#f]
address@hidden {Scheme Procedure} request-range request [default=#f]
address@hidden {Scheme Procedure} request-referer request [default=#f]
address@hidden {Scheme Procedure} request-te request [default=#f]
address@hidden {Scheme Procedure} request-trailer request [default='()]
address@hidden {Scheme Procedure} request-transfer-encoding request
[default='()]
address@hidden {Scheme Procedure} request-upgrade request [default='()]
address@hidden {Scheme Procedure} request-user-agent request [default=#f]
address@hidden {Scheme Procedure} request-via request [default='()]
address@hidden {Scheme Procedure} request-warning request [default='()]
Return the given request header, or @var{default} if none was present.
address@hidden defun
address@hidden deffn
address@hidden request-absolute-uri r [default-host] [default-port]
address@hidden {Scheme Procedure} request-absolute-uri r [default-host=#f]
[default-port=#f]
A helper routine to determine the absolute URI of a request, using the
@code{host} header and the default host and port.
address@hidden defun
-
address@hidden deffn
@node Responses
@@ -1173,12 +1186,12 @@ A helper routine to determine the absolute URI of a
request, using the
As with requests (@pxref{Requests}), Guile offers a data type for HTTP
responses. Again, the body is represented separately from the request.
address@hidden response?
address@hidden response-version
address@hidden response-code
address@hidden response-reason-phrase response
address@hidden response-headers
address@hidden response-port
address@hidden {Scheme Procedure} response?
address@hidden {Scheme Procedure} response-version
address@hidden {Scheme Procedure} response-code
address@hidden {Scheme Procedure} response-reason-phrase response
address@hidden {Scheme Procedure} response-headers
address@hidden {Scheme Procedure} response-port
A predicate and field accessors for the response type. The fields are as
follows:
@table @code
@@ -1194,30 +1207,23 @@ The response headers, as an alist of parsed values.
@item port
The port on which to read or write a response body, if any.
@end table
address@hidden defun
address@hidden deffn
address@hidden read-response port
-Read an HTTP response from @var{port}, optionally attaching the given
-metadata, @var{meta}.
address@hidden {Scheme Procedure} read-response port
+Read an HTTP response from @var{port}.
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
+discussion of character sets in @ref{Responses}, for more information.
address@hidden deffn
address@hidden build-response [#:version] [#:code] [#:reason-phrase]
[#:headers] [#:port]
address@hidden {Scheme Procedure} build-response [#:version='(1 . 1)]
[#:code=200] [#:reason-phrase=#f] [#:headers='()] [#:port=#f]
[#:validate-headers=#t]
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 deffn
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
address@hidden {Scheme Procedure} adapt-response-version response version
+Adapt the given response to a different HTTP version. Return a new HTTP
response.
The idea is that many applications might just build a response for the
@@ -1225,74 +1231,60 @@ 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 deffn
address@hidden write-response r port
address@hidden {Scheme Procedure} write-response r port
Write the given HTTP response to @var{port}.
-Returns a new response, whose @code{response-port} will continue writing
+Return 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 deffn
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}
address@hidden {Scheme Procedure} read-response-body r
+Read the response body from @var{r}, as a bytevector. Returns @code{#f}
if there was no response body.
address@hidden defun
address@hidden deffn
address@hidden write-response-body/bytevector r bv
address@hidden {Scheme Procedure} write-response-body r bv
Write @var{body}, a bytevector, to the port corresponding to the HTTP
response @var{r}.
address@hidden defun
address@hidden deffn
As with requests, the various headers that are typically associated with
HTTP responses may be accessed with these dedicated accessors.
@xref{HTTP Headers}, for more information on the format of parsed
headers.
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]
-Return the given request header, or @var{default} if none was present.
address@hidden defun
address@hidden {Scheme Procedure} response-accept-ranges response [default=#f]
address@hidden {Scheme Procedure} response-age response [default='()]
address@hidden {Scheme Procedure} response-allow response [default='()]
address@hidden {Scheme Procedure} response-cache-control response [default='()]
address@hidden {Scheme Procedure} response-connection response [default='()]
address@hidden {Scheme Procedure} response-content-encoding response
[default='()]
address@hidden {Scheme Procedure} response-content-language response
[default='()]
address@hidden {Scheme Procedure} response-content-length response [default=#f]
address@hidden {Scheme Procedure} response-content-location response
[default=#f]
address@hidden {Scheme Procedure} response-content-md5 response [default=#f]
address@hidden {Scheme Procedure} response-content-range response [default=#f]
address@hidden {Scheme Procedure} response-content-type response [default=#f]
address@hidden {Scheme Procedure} response-date response [default=#f]
address@hidden {Scheme Procedure} response-etag response [default=#f]
address@hidden {Scheme Procedure} response-expires response [default=#f]
address@hidden {Scheme Procedure} response-last-modified response [default=#f]
address@hidden {Scheme Procedure} response-location response [default=#f]
address@hidden {Scheme Procedure} response-pragma response [default='()]
address@hidden {Scheme Procedure} response-proxy-authenticate response
[default=#f]
address@hidden {Scheme Procedure} response-retry-after response [default=#f]
address@hidden {Scheme Procedure} response-server response [default=#f]
address@hidden {Scheme Procedure} response-trailer response [default='()]
address@hidden {Scheme Procedure} response-transfer-encoding response
[default='()]
address@hidden {Scheme Procedure} response-upgrade response [default='()]
address@hidden {Scheme Procedure} response-vary response [default='()]
address@hidden {Scheme Procedure} response-via response [default='()]
address@hidden {Scheme Procedure} response-warning response [default='()]
address@hidden {Scheme Procedure} response-www-authenticate response
[default=#f]
+Return the given response header, or @var{default} if none was present.
address@hidden deffn
@node Web Server
@@ -1343,7 +1335,7 @@ 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
address@hidden if not present. We also allow the response to be simply an
alist of headers, in which case a default response object is
constructed with those headers.
@@ -1363,13 +1355,13 @@ the server socket.
A user may define a server implementation with the following form:
address@hidden define-server-impl name open read write close
address@hidden {Scheme Procedure} define-server-impl name open read write close
Make a @code{<server-impl>} object with the hooks @var{open},
@var{read}, @var{write}, and @var{close}, and bind it to the symbol
@var{name} in the current module.
address@hidden defun
address@hidden deffn
address@hidden lookup-server-impl impl
address@hidden {Scheme Procedure} 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
@@ -1377,7 +1369,7 @@ 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 deffn
The @code{(web server)} module defines a number of routines that use
@code{<server-impl>} objects to implement parts of a web server. Given
@@ -1385,21 +1377,21 @@ that we don't expose the accessors for the various
fields of a
@code{<server-impl>}, indeed these routines are the only procedures with
any access to the impl objects.
address@hidden open-server impl open-params
-Open a server for the given implementation. Returns one value, the new
address@hidden {Scheme Procedure} open-server impl open-params
+Open a server for the given implementation. Return one value, the new
server object. The implementation's @code{open} procedure is applied to
@var{open-params}, which should be a list.
address@hidden defun
address@hidden deffn
address@hidden read-client impl server
address@hidden {Scheme Procedure} 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
address@hidden procedure to the server. If successful, return 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
+request body. If any exception occurs, return @code{#f} for all three
values.
address@hidden defun
address@hidden deffn
address@hidden handle-request handler request body state
address@hidden {Scheme Procedure} 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
@@ -1411,9 +1403,9 @@ arguments, and may be returned as additional values. The
new
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 deffn
address@hidden sanitize-response request response body
address@hidden {Scheme Procedure} sanitize-response request response body
"Sanitize" the given response and body, making them appropriate for the
given request.
@@ -1429,43 +1421,36 @@ 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 deffn
address@hidden write-client impl server client response body
address@hidden {Scheme Procedure} 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 deffn
address@hidden close-server impl server
address@hidden {Scheme Procedure} close-server impl server
Release resources allocated by a previous invocation of
@code{open-server}.
address@hidden defun
address@hidden deffn
Given the procedures above, it is a small matter to make a web server:
address@hidden serve-one-client handler impl server state
address@hidden {Scheme Procedure} 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
+and body, and write the response to the client. Return the new state
produced by the handler procedure.
address@hidden defun
address@hidden deffn
address@hidden run-server handler [impl] [open-params] . state
address@hidden {Scheme Procedure} run-server handler [impl='http]
[open-params='()] . state
Run Guile's built-in web server.
@var{handler} 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
+For examples, skip ahead to the next section, @ref{Web Examples}.
The response and body will be run through @code{sanitize-response}
before sending back to the client.
@@ -1474,12 +1459,30 @@ 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.
address@hidden deffn
-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
+The default web server implementation is @code{http}, which binds to a
+socket, listening for request on that port.
address@hidden {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
+implementation's open function.
+
address@hidden
+;; The defaults: localhost:8080
+(run-server handler)
+;; Same thing
+(run-server handler 'http '())
+;; On a different port
+(run-server handler 'http '(#:port 8081))
+;; IPv6
+(run-server handler 'http '(#:family AF_INET6 #:port 8081))
+;; Custom socket
+(run-server handler 'http `(#:socket ,(sudo-make-me-a-socket)))
address@hidden example
address@hidden deffn
@node Web Examples
@subsection Web Examples
@@ -1506,7 +1509,7 @@ is our payload:
@example
(define (hello-world-handler request request-body)
- (values '((content-type . ("text/plain")))
+ (values '((content-type . (text/plain)))
"Hello World!"))
@end example
@@ -1542,7 +1545,7 @@ the request, response, and URI modules, and do just that.
(define (hello-hacker-handler request body)
(if (equal? (request-path-components request)
'("hacker"))
- (values '((content-type . ("text/plain")))
+ (values '((content-type . (text/plain)))
"Hello hacker!")
(not-found request)))
@@ -1630,8 +1633,8 @@ strings. Now we define a little response helper:
(status 200)
(title "Hello hello!")
(doctype "<!DOCTYPE html>\n")
- (content-type-params '(("charset" . "utf-8")))
- (content-type "text/html")
+ (content-type-params '((charset . "utf-8")))
+ (content-type 'text/html)
(extra-headers '())
(sxml (and body (templatize title body))))
(values (build-response
@@ -1650,9 +1653,9 @@ Here we see the power of keyword arguments with default
initializers. By
the time the arguments are fully parsed, the @code{sxml} local variable
will hold the templated SXML, ready for sending out to the client.
-Instead of returning the body as a string, here we give a procedure,
-which will be called by the web server to write out the response to the
-client.
+Also, instead of returning the body as a string, @code{respond} gives a
+procedure, which will be called by the web server to write out the
+response to the client.
Now, a simple example using this responder, which lays out the incoming
headers in an HTML table.
diff --git a/module/web/request.scm b/module/web/request.scm
index 84bc36e..91cc59d 100644
--- a/module/web/request.scm
+++ b/module/web/request.scm
@@ -38,11 +38,8 @@
build-request
write-request
- read-request-body/latin-1
- write-request-body/latin-1
-
- read-request-body/bytevector
- write-request-body/bytevector
+ read-request-body
+ write-request-body
;; General headers
;;
@@ -149,7 +146,7 @@
(if (not (null? headers))
(bad-request "Headers not a list: ~a" headers))))
-(define* (build-request #:key (method 'GET) uri (version '(1 . 1))
+(define* (build-request uri #:key (method 'GET) (version '(1 . 1))
(headers '()) port (meta '())
(validate-headers? #t))
"Construct an HTTP request object. If @var{validate-headers?} is true,
@@ -198,44 +195,7 @@ on @var{port}, perhaps using some transfer encoding."
(make-request (request-method r) (request-uri r) (request-version r)
(request-headers r) (request-meta r) port)))
-;; Probably not what you want to use "in production". Relies on one byte
-;; 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)
- (let ((buf (make-string nbytes))
- (port (request-port r)))
- (let lp ((i 0))
- (cond
- ((< i nbytes)
- (let ((c (read-char port)))
- (cond
- ((eof-object? c)
- (bad-request "EOF while reading request body: ~a bytes of ~a"
- i nbytes))
- (else
- (string-set! buf i c)
- (lp (1+ i))))))
- (else buf))))))
- (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.
-;;
-(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)
+(define (read-request-body r)
"Reads the request body from @var{r}, as a bytevector. Returns
@code{#f} if there was no request body."
(let ((nbytes (request-content-length r)))
@@ -246,7 +206,7 @@ corresponding to the HTTP request @var{r}."
(bad-request "EOF while reading request body: ~a bytes of ~a"
(bytevector-length bv) nbytes))))))
-(define (write-request-body/bytevector r bv)
+(define (write-request-body r bv)
"Write @var{body}, a bytevector, to the port corresponding to the HTTP
request @var{r}."
(put-bytevector (request-port r) bv))
diff --git a/module/web/response.scm b/module/web/response.scm
index f8a87a2..2cabd4f 100644
--- a/module/web/response.scm
+++ b/module/web/response.scm
@@ -33,15 +33,11 @@
response-port
read-response
build-response
- extend-response
adapt-response-version
write-response
- read-response-body/latin-1
- write-response-body/latin-1
-
- read-response-body/bytevector
- write-response-body/bytevector
+ read-response-body
+ write-response-body
;; General headers
;;
@@ -126,20 +122,6 @@ the headers are each run through their respective
validators."
(validate-headers headers))))
(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)
- #:headers
- (assoc-set! (copy-tree (response-headers r))
- k v)
- #:port (response-port r))))
- (if (null? additional)
- r
- (apply extend-response r additional))))
-
(define *reason-phrases*
'((100 . "Continue")
(101 . "Switching Protocols")
@@ -193,8 +175,7 @@ reason phrase for the response's code."
(code->reason-phrase (response-code response))))
(define (read-response port)
- "Read an HTTP response from @var{port}, optionally attaching the given
-metadata, @var{meta}.
+ "Read an HTTP response from @var{port}.
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
@@ -233,44 +214,7 @@ on @var{port}, perhaps using some transfer encoding."
(make-response (response-version r) (response-code r)
(response-reason-phrase r) (response-headers r) port)))
-;; Probably not what you want to use "in production". Relies on one byte
-;; 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)
- (let ((buf (make-string nbytes))
- (port (response-port r)))
- (let lp ((i 0))
- (cond
- ((< i nbytes)
- (let ((c (read-char port)))
- (cond
- ((eof-object? c)
- (bad-response "EOF while reading response body: ~a bytes of ~a"
- i nbytes))
- (else
- (string-set! buf i c)
- (lp (1+ i))))))
- (else buf))))))
- (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 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)
+(define (read-response-body r)
"Reads the response body from @var{r}, as a bytevector. Returns
@code{#f} if there was no response body."
(let ((nbytes (response-content-length r)))
@@ -281,7 +225,7 @@ corresponding to the HTTP response @var{r}."
(bad-response "EOF while reading response body: ~a bytes of ~a"
(bytevector-length bv) nbytes))))))
-(define (write-response-body/bytevector r bv)
+(define (write-response-body r bv)
"Write @var{body}, a bytevector, to the port corresponding to the HTTP
response @var{r}."
(put-bytevector (response-port r) bv))
diff --git a/module/web/server.scm b/module/web/server.scm
index 02d01b0..4715cae 100644
--- a/module/web/server.scm
+++ b/module/web/server.scm
@@ -187,6 +187,17 @@ values."
(lambda (port)
(display str port)))))
+(define (extend-response r k v . additional)
+ (let ((r (build-response #:version (response-version r)
+ #:code (response-code r)
+ #:headers
+ (assoc-set! (copy-tree (response-headers r))
+ k v)
+ #:port (response-port r))))
+ (if (null? additional)
+ r
+ (apply extend-response r additional))))
+
;; -> response body
(define (sanitize-response request response body)
"\"Sanitize\" the given response and body, making them appropriate for
diff --git a/module/web/server/http.scm b/module/web/server/http.scm
index e9d612b..a9a9049 100644
--- a/module/web/server/http.scm
+++ b/module/web/server/http.scm
@@ -1,6 +1,6 @@
;;; Web I/O: HTTP
-;; Copyright (C) 2010 Free Software Foundation, Inc.
+;; Copyright (C) 2010, 2011 Free Software Foundation, Inc.
;; This library is free software; you can redistribute it and/or
;; modify it under the terms of the GNU Lesser General Public
@@ -121,7 +121,7 @@
(let ((req (read-request port)))
(values port
req
- (read-request-body/bytevector req))))
+ (read-request-body req))))
(lambda (k . args)
(false-if-exception (close-port port)))))))))))))
@@ -142,12 +142,10 @@
(port (response-port response)))
(cond
((not body)) ; pass
- ((string? body)
- (write-response-body/latin-1 response body))
((bytevector? body)
- (write-response-body/bytevector response body))
+ (write-response-body response body))
(else
- (error "Expected a string or bytevector for body" body)))
+ (error "Expected a bytevector for body" body)))
(cond
((keep-alive? response)
(force-output port)
diff --git a/test-suite/tests/web-request.test
b/test-suite/tests/web-request.test
index 32b99dd..e1eec2f 100644
--- a/test-suite/tests/web-request.test
+++ b/test-suite/tests/web-request.test
@@ -51,11 +51,8 @@ Accept-Language: en-gb, en;q=0.9\r
(pass-if (equal? (request-uri r) (build-uri 'http #:path "/qux")))
- (pass-if (equal? (read-request-body/latin-1 r) #f))
- ;; Since it's #f, should be an idempotent read, so we can try
- ;; bytevectors too
- (pass-if (equal? (read-request-body/bytevector r) #f))
-
+ (pass-if (equal? (read-request-body r) #f))
+
(pass-if "checking all headers"
(equal?
(request-headers r)
diff --git a/test-suite/tests/web-response.test
b/test-suite/tests/web-response.test
index 7e7331e..a21a702 100644
--- a/test-suite/tests/web-response.test
+++ b/test-suite/tests/web-response.test
@@ -20,6 +20,7 @@
(define-module (test-suite web-response)
#:use-module (web uri)
#:use-module (web response)
+ #:use-module (rnrs bytevectors)
#:use-module (srfi srfi-19)
#:use-module (test-suite lib))
@@ -53,9 +54,9 @@ abcdefghijklmnopqrstuvwxyz0123456789")
(set! r (read-response (open-input-string example-1)))
(response? r)))
- (pass-if "read-response-body/latin-1"
+ (pass-if "read-response-body"
(begin
- (set! body (read-response-body/latin-1 r))
+ (set! body (read-response-body r))
#t))
(pass-if (equal? (response-version r) '(1 . 1)))
@@ -64,7 +65,9 @@ abcdefghijklmnopqrstuvwxyz0123456789")
(pass-if (equal? (response-reason-phrase r) "OK"))
- (pass-if (equal? body "abcdefghijklmnopqrstuvwxyz0123456789"))
+ (pass-if (equal? body
+ (string->utf8
+ "abcdefghijklmnopqrstuvwxyz0123456789")))
(pass-if "checking all headers"
(equal?
@@ -88,10 +91,10 @@ abcdefghijklmnopqrstuvwxyz0123456789")
(with-output-to-string
(lambda ()
(let ((r (write-response r (current-output-port))))
- (write-response-body/latin-1 r body))))
+ (write-response-body r body))))
(lambda ()
(let ((r (read-response (current-input-port))))
- (values r (read-response-body/latin-1 r))))))
+ (values r (read-response-body r))))))
(lambda (r* body*)
(responses-equal? r body r* body*))))
hooks/post-receive
--
GNU Guile
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Guile-commits] GNU Guile branch, master, updated. release_1-9-14-55-g2e6f5ea,
Andy Wingo <=