mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-23 20:05:32 +02:00
syncronize web module docstrings with manual
* doc/ref/web.texi: Fix spacing. Update with a few missing function descriptions. * module/web/client.scm: * module/web/http.scm: * module/web/request.scm: * module/web/server.scm: * module/web/uri.scm: Update docstrings from manual (reworked by Ludovic Courtès).
This commit is contained in:
parent
e8772a9ede
commit
06883ae000
7 changed files with 170 additions and 144 deletions
|
@ -431,8 +431,8 @@ from @code{header-writer}.
|
|||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} read-headers port
|
||||
Read the headers of an HTTP message from @var{port}, returning the
|
||||
headers as an ordered alist.
|
||||
Read the headers of an HTTP message from @var{port}, returning them
|
||||
as an ordered alist.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} write-headers headers port
|
||||
|
@ -1368,6 +1368,7 @@ Return the given response header, or @var{default} if none was present.
|
|||
the lower-level HTTP, request, and response modules.
|
||||
|
||||
@deffn {Scheme Procedure} open-socket-for-uri uri
|
||||
Return an open input/output port for a connection to URI.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} http-get uri [#:port=(open-socket-for-uri uri)] [#:version='(1 . 1)] [#:keep-alive?=#f] [#:extra-headers='()] [#:decode-body?=#t]
|
||||
|
@ -1470,7 +1471,7 @@ the server socket.
|
|||
|
||||
A user may define a server implementation with the following form:
|
||||
|
||||
@deffn {Scheme Procedure} define-server-impl name open read write close
|
||||
@deffn {Scheme Syntax} 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.
|
||||
|
|
|
@ -115,6 +115,15 @@
|
|||
(define* (http-get uri #:key (port (open-socket-for-uri uri))
|
||||
(version '(1 . 1)) (keep-alive? #f) (extra-headers '())
|
||||
(decode-body? #t))
|
||||
"Connect to the server corresponding to URI and ask for the
|
||||
resource, using the ‘GET’ method. If you already have a port open,
|
||||
pass it as PORT. The port will be closed at the end of the
|
||||
request unless KEEP-ALIVE? is true. Any extra headers in the
|
||||
alist EXTRA-HEADERS will be added to the request.
|
||||
|
||||
If DECODE-BODY? is true, as is the default, the body of the
|
||||
response will be decoded to string, if it is a textual content-type.
|
||||
Otherwise it will be returned as a bytevector."
|
||||
(let ((req (build-request uri #:version version
|
||||
#:headers (if keep-alive?
|
||||
extra-headers
|
||||
|
|
|
@ -77,7 +77,7 @@
|
|||
|
||||
|
||||
(define (string->header name)
|
||||
"Parse @var{name} to a symbolic header name."
|
||||
"Parse NAME to a symbolic header name."
|
||||
(string->symbol (string-downcase name)))
|
||||
|
||||
(define-record-type <header-decl>
|
||||
|
@ -100,12 +100,7 @@
|
|||
validator
|
||||
writer
|
||||
#:key multiple?)
|
||||
"Define a parser, validator, and writer for the HTTP header, @var{name}.
|
||||
|
||||
@var{parser} 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."
|
||||
"Declare a parser, validator, and writer for a given header."
|
||||
(if (and (string? name) parser validator writer)
|
||||
(let ((decl (make-header-decl name parser validator writer multiple?)))
|
||||
(hashq-set! *declared-headers* (string->header name) decl)
|
||||
|
@ -113,34 +108,40 @@ port, and writes the value to the port."
|
|||
(error "bad header decl" name parser validator writer multiple?)))
|
||||
|
||||
(define (header->string sym)
|
||||
"Return the string form for the header named @var{sym}."
|
||||
"Return the string form for the header named SYM."
|
||||
(let ((decl (lookup-header-decl sym)))
|
||||
(if decl
|
||||
(header-decl-name decl)
|
||||
(string-titlecase (symbol->string sym)))))
|
||||
|
||||
(define (known-header? sym)
|
||||
"Return @code{#t} if there are parsers and writers registered for this
|
||||
header, otherwise @code{#f}."
|
||||
"Return ‘#t’ iff SYM is a known header, with associated
|
||||
parsers and serialization procedures."
|
||||
(and (lookup-header-decl sym) #t))
|
||||
|
||||
(define (header-parser sym)
|
||||
"Returns a procedure to parse values for the given header."
|
||||
"Return the value parser for headers named 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."
|
||||
(let ((decl (lookup-header-decl sym)))
|
||||
(if decl
|
||||
(header-decl-parser decl)
|
||||
(lambda (x) x))))
|
||||
|
||||
(define (header-validator sym)
|
||||
"Returns a procedure to validate values for the given header."
|
||||
"Return a predicate which returns ‘#t’ if the given value is valid
|
||||
for headers named SYM. The default validator for unknown headers
|
||||
is ‘string?’."
|
||||
(let ((decl (lookup-header-decl sym)))
|
||||
(if decl
|
||||
(header-decl-validator decl)
|
||||
string?)))
|
||||
|
||||
(define (header-writer sym)
|
||||
"Returns a procedure to write values for the given header to a given
|
||||
port."
|
||||
"Return a procedure that writes values for headers named SYM to a
|
||||
port. The resulting procedure takes two arguments: a value and a port.
|
||||
The default writer is ‘display’."
|
||||
(let ((decl (lookup-header-decl sym)))
|
||||
(if decl
|
||||
(header-decl-writer decl)
|
||||
|
@ -173,7 +174,7 @@ port."
|
|||
(define *eof* (call-with-input-string "" read))
|
||||
|
||||
(define (read-header port)
|
||||
"Reads one HTTP header from @var{port}. Returns two values: the header
|
||||
"Reads one HTTP header from 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.
|
||||
|
||||
|
@ -195,32 +196,28 @@ body was reached (i.e., a blank line)."
|
|||
(string-trim-both line char-set:whitespace (1+ delim)))))))))
|
||||
|
||||
(define (parse-header sym val)
|
||||
"Parse @var{val}, a string, with the parser registered for the header
|
||||
named @var{sym}.
|
||||
|
||||
Returns the parsed value. If a parser was not found, the value is
|
||||
returned as a string."
|
||||
"Parse VAL, a string, with the parser registered for the header
|
||||
named SYM. Returns the parsed value."
|
||||
((header-parser sym) 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}."
|
||||
"Returns a true value iff VAL is a valid Scheme value for the
|
||||
header with name SYM."
|
||||
(if (symbol? sym)
|
||||
((header-validator sym) val)
|
||||
(error "header name not a symbol" sym)))
|
||||
|
||||
(define (write-header sym val port)
|
||||
"Writes the given header name and value to @var{port}. If @var{sym}
|
||||
is a known header, uses the specific writer registered for that header.
|
||||
Otherwise the value is written using @code{display}."
|
||||
"Write the given header name and value to PORT, using the writer
|
||||
from ‘header-writer’."
|
||||
(display (header->string sym) port)
|
||||
(display ": " port)
|
||||
((header-writer sym) val port)
|
||||
(display "\r\n" port))
|
||||
|
||||
(define (read-headers port)
|
||||
"Read an HTTP message from @var{port}, returning the headers as an
|
||||
ordered alist."
|
||||
"Read the headers of an HTTP message from PORT, returning them
|
||||
as an ordered alist."
|
||||
(let lp ((headers '()))
|
||||
(call-with-values (lambda () (read-header port))
|
||||
(lambda (k v)
|
||||
|
@ -229,8 +226,8 @@ ordered alist."
|
|||
(lp (acons k v headers)))))))
|
||||
|
||||
(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."
|
||||
"Write the given header alist to PORT. Doesn't write the final
|
||||
@samp{\\r\\n}, as the user might want to add another header."
|
||||
(let lp ((headers headers))
|
||||
(if (pair? headers)
|
||||
(begin
|
||||
|
@ -981,9 +978,9 @@ ordered alist."
|
|||
(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,
|
||||
@code{(1 . 1)}."
|
||||
"Parse an HTTP version from STR, returning it as a major-minor
|
||||
pair. For example, ‘HTTP/1.1’ parses as the pair of integers,
|
||||
‘(1 . 1)’."
|
||||
(or (let lp ((known *known-versions*))
|
||||
(and (pair? known)
|
||||
(if (string= str (caar known) start end)
|
||||
|
@ -998,7 +995,7 @@ pair. For example, @code{HTTP/1.1} parses as the pair of integers,
|
|||
(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}."
|
||||
"Write the given major-minor version pair to PORT."
|
||||
(display "HTTP/" port)
|
||||
(display (car val) port)
|
||||
(display #\. port)
|
||||
|
@ -1019,8 +1016,8 @@ pair. For example, @code{HTTP/1.1} parses as the pair of integers,
|
|||
;; 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}."
|
||||
"Parse an HTTP method from STR. The result is an upper-case
|
||||
symbol, like ‘GET’."
|
||||
(cond
|
||||
((string= str "GET" start end) 'GET)
|
||||
((string= str "HEAD" start end) 'HEAD)
|
||||
|
@ -1052,7 +1049,7 @@ not have to have a scheme or host name. The result is a URI object."
|
|||
(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
|
||||
"Read the first line of an HTTP request from PORT, returning
|
||||
three values: the method, the URI, and the version."
|
||||
(let* ((line (read-line* port))
|
||||
(d0 (string-index line char-set:whitespace)) ; "delimiter zero"
|
||||
|
@ -1093,7 +1090,7 @@ three values: the method, the URI, and the version."
|
|||
(display (uri-query uri) port))))
|
||||
|
||||
(define (write-request-line method uri version port)
|
||||
"Write the first line of an HTTP request to @var{port}."
|
||||
"Write the first line of an HTTP request to PORT."
|
||||
(display method port)
|
||||
(display #\space port)
|
||||
(let ((path (uri-path uri))
|
||||
|
@ -1113,7 +1110,7 @@ three values: the method, the URI, and the version."
|
|||
(display "\r\n" port))
|
||||
|
||||
(define (read-response-line port)
|
||||
"Read the first line of an HTTP response from @var{port}, returning
|
||||
"Read the first line of an HTTP response from PORT, returning
|
||||
three values: the HTTP version, the response code, and the \"reason
|
||||
phrase\"."
|
||||
(let* ((line (read-line* port))
|
||||
|
@ -1128,7 +1125,7 @@ phrase\"."
|
|||
(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 the first line of an HTTP response to PORT."
|
||||
(write-http-version version port)
|
||||
(display #\space port)
|
||||
(display code port)
|
||||
|
@ -1833,10 +1830,10 @@ treated specially, and is just returned as a plain string."
|
|||
|
||||
(define* (make-chunked-input-port port #:key (keep-alive? #f))
|
||||
"Returns a new port which translates HTTP chunked transfer encoded
|
||||
data from @var{port} into a non-encoded format. Returns eof when it has
|
||||
read the final chunk from @var{port}. This does not necessarily mean
|
||||
that there is no more data on @var{port}. When the returned port is
|
||||
closed it will also close @var{port}, unless the KEEP-ALIVE? is true."
|
||||
data from PORT into a non-encoded format. Returns eof when it has
|
||||
read the final chunk from PORT. This does not necessarily mean
|
||||
that there is no more data on PORT. When the returned port is
|
||||
closed it will also close PORT, unless the KEEP-ALIVE? is true."
|
||||
(define (next-chunk)
|
||||
(read-chunk port))
|
||||
(define finished? #f)
|
||||
|
@ -1872,11 +1869,11 @@ closed it will also close @var{port}, unless the KEEP-ALIVE? is true."
|
|||
|
||||
(define* (make-chunked-output-port port #:key (keep-alive? #f))
|
||||
"Returns a new port which translates non-encoded data into a HTTP
|
||||
chunked transfer encoded data and writes this to @var{port}. Data
|
||||
chunked transfer encoded data and writes this to PORT. Data
|
||||
written to this port is buffered until the port is flushed, at which
|
||||
point it is all sent as one chunk. Take care to close the port when
|
||||
done, as it will output the remaining data, and encode the final zero
|
||||
chunk. When the port is closed it will also close @var{port}, unless
|
||||
chunk. When the port is closed it will also close PORT, unless
|
||||
KEEP-ALIVE? is true."
|
||||
(define (q-for-each f q)
|
||||
(while (not (q-empty? q))
|
||||
|
|
|
@ -160,7 +160,7 @@
|
|||
(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,
|
||||
"Construct an HTTP request object. If VALIDATE-HEADERS? is true,
|
||||
the headers are each run through their respective validators."
|
||||
(let ((needs-host? (and (equal? version '(1 . 1))
|
||||
(not (assq-ref headers 'host)))))
|
||||
|
@ -189,13 +189,17 @@ the headers are each run through their respective validators."
|
|||
meta port)))
|
||||
|
||||
(define* (read-request port #:optional (meta '()))
|
||||
"Read an HTTP request from @var{port}, optionally attaching the given
|
||||
metadata, @var{meta}.
|
||||
"Read an HTTP request from PORT, optionally attaching the given
|
||||
metadata, META.
|
||||
|
||||
As a side effect, sets the encoding on @var{port} to
|
||||
As a side effect, sets the encoding on 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."
|
||||
more information.
|
||||
|
||||
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."
|
||||
(set-port-encoding! port "ISO-8859-1")
|
||||
(call-with-values (lambda () (read-request-line port))
|
||||
(lambda (method uri version)
|
||||
|
@ -203,10 +207,10 @@ more information."
|
|||
|
||||
;; FIXME: really return a new request?
|
||||
(define (write-request r port)
|
||||
"Write the given HTTP request to @var{port}.
|
||||
"Write the given HTTP request to PORT.
|
||||
|
||||
Returns a new request, whose @code{request-port} will continue writing
|
||||
on @var{port}, perhaps using some transfer encoding."
|
||||
Return a new request, whose ‘request-port’ will continue writing
|
||||
on 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)
|
||||
|
@ -217,8 +221,8 @@ on @var{port}, perhaps using some transfer encoding."
|
|||
(request-headers r) (request-meta r) port)))
|
||||
|
||||
(define (read-request-body r)
|
||||
"Reads the request body from @var{r}, as a bytevector. Returns
|
||||
@code{#f} if there was no request body."
|
||||
"Reads the request body from R, as a bytevector. Return ‘#f’
|
||||
if there was no request body."
|
||||
(let ((nbytes (request-content-length r)))
|
||||
(and nbytes
|
||||
(let ((bv (get-bytevector-n (request-port r) nbytes)))
|
||||
|
@ -228,8 +232,8 @@ on @var{port}, perhaps using some transfer encoding."
|
|||
(bytevector-length bv) nbytes))))))
|
||||
|
||||
(define (write-request-body r bv)
|
||||
"Write @var{bv}, a bytevector, to the port corresponding to the HTTP
|
||||
request @var{r}."
|
||||
"Write BV, a bytevector, to the port corresponding to the HTTP
|
||||
request R."
|
||||
(put-bytevector (request-port r) bv))
|
||||
|
||||
(define-syntax define-request-accessor
|
||||
|
@ -297,6 +301,8 @@ request @var{r}."
|
|||
|
||||
;; Misc accessors
|
||||
(define* (request-absolute-uri r #:optional default-host default-port)
|
||||
"A helper routine to determine the absolute URI of a request, using the
|
||||
‘host’ header and the default host and port."
|
||||
(let ((uri (request-uri r)))
|
||||
(if (uri-host uri)
|
||||
uri
|
||||
|
|
|
@ -107,7 +107,7 @@
|
|||
|
||||
(define* (build-response #:key (version '(1 . 1)) (code 200) reason-phrase
|
||||
(headers '()) port (validate-headers? #t))
|
||||
"Construct an HTTP response object. If @var{validate-headers?} is true,
|
||||
"Construct an HTTP response object. If VALIDATE-HEADERS? is true,
|
||||
the headers are each run through their respective validators."
|
||||
(cond
|
||||
((not (and (pair? version)
|
||||
|
@ -170,15 +170,15 @@ the headers are each run through their respective validators."
|
|||
"(Unknown)"))
|
||||
|
||||
(define (response-reason-phrase response)
|
||||
"Return the reason phrase given in @var{response}, or the standard
|
||||
"Return the reason phrase given in 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}.
|
||||
"Read an HTTP response from PORT.
|
||||
|
||||
As a side effect, sets the encoding on @var{port} to
|
||||
As a side effect, sets the encoding on 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."
|
||||
|
@ -202,10 +202,10 @@ the version field."
|
|||
#:port (response-port response)))
|
||||
|
||||
(define (write-response r port)
|
||||
"Write the given HTTP response to @var{port}.
|
||||
"Write the given HTTP response to PORT.
|
||||
|
||||
Returns a new response, whose @code{response-port} will continue writing
|
||||
on @var{port}, perhaps using some transfer encoding."
|
||||
Returns a new response, whose ‘response-port’ will continue writing
|
||||
on 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)
|
||||
|
@ -216,7 +216,7 @@ on @var{port}, perhaps using some transfer encoding."
|
|||
(response-reason-phrase r) (response-headers r) port)))
|
||||
|
||||
(define (response-must-not-include-body? r)
|
||||
"Returns @code{#t} if the response @var{r} is not permitted to have a body.
|
||||
"Returns ‘#t’ if the response R is not permitted to have a body.
|
||||
|
||||
This is true for some response types, like those with code 304."
|
||||
;; RFC 2616, section 4.3.
|
||||
|
@ -225,8 +225,8 @@ This is true for some response types, like those with code 304."
|
|||
(= (response-code r) 304)))
|
||||
|
||||
(define (read-response-body r)
|
||||
"Reads the response body from @var{r}, as a bytevector. Returns
|
||||
@code{#f} if there was no response body."
|
||||
"Reads the response body from R, as a bytevector. Returns
|
||||
‘#f’ if there was no response body."
|
||||
(if (member '(chunked) (response-transfer-encoding r))
|
||||
(let ((chunk-port (make-chunked-input-port (response-port r)
|
||||
#:keep-alive? #t)))
|
||||
|
@ -240,8 +240,8 @@ This is true for some response types, like those with code 304."
|
|||
(bytevector-length bv) nbytes)))))))
|
||||
|
||||
(define (write-response-body r bv)
|
||||
"Write @var{bv}, a bytevector, to the port corresponding to the HTTP
|
||||
response @var{r}."
|
||||
"Write BV, a bytevector, to the port corresponding to the HTTP
|
||||
response R."
|
||||
(put-bytevector (response-port r) bv))
|
||||
|
||||
(define-syntax define-response-accessor
|
||||
|
|
|
@ -123,14 +123,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
|
||||
"Look up a server implementation. If 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
|
||||
binding named IMPL in the ‘(web server 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}."
|
||||
‘read-client’."
|
||||
(cond
|
||||
((server-impl? impl) impl)
|
||||
((symbol? impl)
|
||||
|
@ -143,17 +143,17 @@ for passing to other procedures in this module, like
|
|||
|
||||
;; -> 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."
|
||||
"Open a server for the given implementation. Return one value, the
|
||||
new server object. The implementation's ‘open’ procedure is
|
||||
applied to 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
|
||||
@code{read} procedure to the server. If successful, returns three
|
||||
"Read a new client from SERVER, by applying the implementation's
|
||||
‘read’ 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 ‘#f’ for all three
|
||||
values."
|
||||
(call-with-error-handling
|
||||
(lambda ()
|
||||
|
@ -213,14 +213,14 @@ values."
|
|||
"\"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
|
||||
As a convenience to web handler authors, 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
|
||||
@code{content-length} and @code{content-type} header, as necessary.
|
||||
version. If BODY is a string, encodes the string to a bytevector,
|
||||
in an encoding appropriate for RESPONSE. Adds a
|
||||
‘content-length’ and ‘content-type’ header, as necessary.
|
||||
|
||||
If @var{body} is a procedure, it is called with a port as an argument,
|
||||
If 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
|
||||
|
@ -290,11 +290,11 @@ on the procedure being called at any particular time."
|
|||
"Handle a given request, returning the response and body.
|
||||
|
||||
The response and response body are produced by calling the given
|
||||
@var{handler} with @var{request} and @var{body} as arguments.
|
||||
HANDLER with REQUEST and BODY as arguments.
|
||||
|
||||
The elements of @var{state} are also passed to @var{handler} as
|
||||
The elements of STATE are also passed to HANDLER as
|
||||
arguments, and may be returned as additional values. The new
|
||||
@var{state}, collected from the @var{handler}'s return values, is then
|
||||
STATE, collected from the 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."
|
||||
|
@ -318,10 +318,10 @@ in, allowing the user's handler to explicitly manage its state."
|
|||
|
||||
;; -> unspecified values
|
||||
(define (write-client impl server client response body)
|
||||
"Write an HTTP response and body to @var{client}. If the server and
|
||||
"Write an HTTP response and body to 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."
|
||||
attaching it to the SERVER argument somehow."
|
||||
(call-with-error-handling
|
||||
(lambda ()
|
||||
((server-impl-write impl) server client response body))
|
||||
|
@ -332,7 +332,7 @@ attaching it to the @var{server} argument somehow."
|
|||
;; -> unspecified values
|
||||
(define (close-server impl server)
|
||||
"Release resources allocated by a previous invocation of
|
||||
@code{open-server}."
|
||||
‘open-server’."
|
||||
((server-impl-close impl) server))
|
||||
|
||||
(define call-with-sigint
|
||||
|
@ -363,8 +363,8 @@ attaching it to the @var{server} argument somehow."
|
|||
|
||||
;; -> 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
|
||||
"Read one request from SERVER, call HANDLER on the request
|
||||
and body, and write the response to the client. Return the new state
|
||||
produced by the handler procedure."
|
||||
(debug-elapsed 'serve-again)
|
||||
(call-with-values
|
||||
|
@ -387,7 +387,7 @@ produced by the handler procedure."
|
|||
. state)
|
||||
"Run Guile's built-in web server.
|
||||
|
||||
@var{handler} should be a procedure that takes two or more arguments,
|
||||
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.
|
||||
|
||||
|
@ -400,16 +400,16 @@ For example, here is a simple \"Hello, World!\" server:
|
|||
(run-server handler)
|
||||
@end example
|
||||
|
||||
The response and body will be run through @code{sanitize-response}
|
||||
The response and body will be run through ‘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
|
||||
Additional arguments to HANDLER are taken from
|
||||
STATE. Additional return values are accumulated into a new
|
||||
STATE, which will be used for subsequent requests. In this way a
|
||||
handler can explicitly manage its state.
|
||||
|
||||
The default server implementation is @code{http}, which accepts
|
||||
@var{open-params} like @code{(#:port 8081)}, among others. See \"Web
|
||||
The default server implementation is ‘http’, which accepts
|
||||
OPEN-PARAMS like ‘(#: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)))
|
||||
|
|
|
@ -79,8 +79,10 @@
|
|||
|
||||
(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."
|
||||
"Construct a URI object. SCHEME should be a symbol, and the rest
|
||||
of the fields are either strings or ‘#f’. If 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))
|
||||
|
@ -168,7 +170,7 @@ consistency checks to make sure that the constructed URI is valid."
|
|||
(make-regexp uri-pat))
|
||||
|
||||
(define (string->uri string)
|
||||
"Parse @var{string} into a URI object. Returns @code{#f} if the string
|
||||
"Parse STRING into a URI object. Return ‘#f’ if the string
|
||||
could not be parsed."
|
||||
(% (let ((m (regexp-exec uri-regexp string)))
|
||||
(if (not m) (abort))
|
||||
|
@ -191,10 +193,7 @@ could not be parsed."
|
|||
(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."
|
||||
"Declare a default port for the given URI scheme."
|
||||
(hashq-set! *default-ports* scheme port))
|
||||
|
||||
(define (default-port? scheme port)
|
||||
|
@ -205,7 +204,9 @@ printed."
|
|||
(declare-default-port! 'https 443)
|
||||
|
||||
(define (uri->string uri)
|
||||
"Serialize @var{uri} to a string."
|
||||
"Serialize 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."
|
||||
(let* ((scheme-str (string-append
|
||||
(symbol->string (uri-scheme uri)) ":"))
|
||||
(userinfo (uri-userinfo uri))
|
||||
|
@ -285,26 +286,32 @@ printed."
|
|||
;; characters in other character sets.
|
||||
;;
|
||||
|
||||
;; Return a new string made from uri-decoding @var{str}. Specifically,
|
||||
;; turn @code{+} into space, and hex-encoded @code{%XX} strings into
|
||||
;; Return a new string made from uri-decoding STR. Specifically,
|
||||
;; turn ‘+’ into space, and hex-encoded ‘%XX’ strings into
|
||||
;; their eight-bit characters.
|
||||
;;
|
||||
(define hex-chars
|
||||
(string->char-set "0123456789abcdefABCDEF"))
|
||||
|
||||
(define* (uri-decode str #:key (encoding "utf-8"))
|
||||
"Percent-decode the given @var{str}, according to @var{encoding}.
|
||||
"Percent-decode the given STR, according to ENCODING,
|
||||
which should be the name of a character encoding.
|
||||
|
||||
Note that this function should not generally be applied to a full URI
|
||||
string. For paths, use split-and-decode-uri-path instead. For query
|
||||
strings, split the query on @code{&} and @code{=} boundaries, and decode
|
||||
strings, split the query on ‘&’ and ‘=’ 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
|
||||
@var{encoding} if you want decoded bytes as a bytevector directly."
|
||||
Note also 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 ‘#f’ for
|
||||
ENCODING if you want decoded bytes as a bytevector directly.
|
||||
@xref{Ports, ‘set-port-encoding!’}, for more information on
|
||||
character encodings.
|
||||
|
||||
Returns a string of the decoded characters, or a bytevector if
|
||||
ENCODING was ‘#f’."
|
||||
(let* ((len (string-length str))
|
||||
(bv
|
||||
(call-with-output-bytevector*
|
||||
|
@ -353,16 +360,19 @@ bytes are not valid for the given encoding. Pass @code{#f} for
|
|||
(char-set-union ascii-alnum-chars
|
||||
(string->char-set "-._~")))
|
||||
|
||||
;; Return a new string made from uri-encoding @var{str}, unconditionally
|
||||
;; transforming any characters not in @var{unescaped-chars}.
|
||||
;; Return a new string made from uri-encoding STR, unconditionally
|
||||
;; transforming any characters not in UNESCAPED-CHARS.
|
||||
;;
|
||||
(define* (uri-encode str #:key (encoding "utf-8")
|
||||
(unescaped-chars unreserved-chars))
|
||||
"Percent-encode any character not in the character set, @var{unescaped-chars}.
|
||||
"Percent-encode any character not in the character set,
|
||||
UNESCAPED-CHARS.
|
||||
|
||||
Percent-encoding first writes out the given character to a bytevector
|
||||
within the given @var{encoding}, then encodes each byte as
|
||||
@code{%@var{HH}}, where @var{HH} is the hexadecimal representation of
|
||||
The default character set includes alphanumerics from ASCII, as well as
|
||||
the special characters @samp{-}, @samp{.}, @samp{_}, and @samp{~}. Any
|
||||
other character will be percent-encoded, by writing out the character to
|
||||
a bytevector within the given ENCODING, then encoding each byte as
|
||||
‘%HH’, where HH is the hexadecimal representation of
|
||||
the byte."
|
||||
(define (needs-escaped? ch)
|
||||
(not (char-set-contains? unescaped-chars ch)))
|
||||
|
@ -387,15 +397,18 @@ the byte."
|
|||
str))
|
||||
|
||||
(define (split-and-decode-uri-path path)
|
||||
"Split @var{path} into its components, and decode each
|
||||
component, removing empty components.
|
||||
"Split PATH into its components, and decode each component,
|
||||
removing empty components.
|
||||
|
||||
For example, @code{\"/foo/bar/\"} decodes to the two-element list,
|
||||
@code{(\"foo\" \"bar\")}."
|
||||
For example, ‘\"/foo/bar%20baz/\"’ decodes to the two-element list,
|
||||
‘(\"foo\" \"bar baz\")’."
|
||||
(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."
|
||||
"URI-encode each element of PARTS, which should be a list of
|
||||
strings, and join the parts together with ‘/’ as a delimiter.
|
||||
|
||||
For example, the list ‘(\"scrambled eggs\" \"biscuits&gravy\")’
|
||||
encodes as ‘\"scrambled%20eggs/biscuits%26gravy\"’."
|
||||
(string-join (map uri-encode parts) "/"))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue