mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-20 11:40:18 +02:00
read-header returns EOF at end, update (web http) docs
* doc/ref/web.texi (HTTP): Add an example for declaring a header, and adapt to read-header change. * module/web/http.scm (read-header): Return EOF for both values if there are no more headers, instead of #f. (read-headers): Adapt.
This commit is contained in:
parent
569269b4b2
commit
929ccf48fc
2 changed files with 43 additions and 16 deletions
|
@ -352,11 +352,36 @@ A writer, which writes a value to the port given in the second argument.
|
|||
@end table
|
||||
@end defun
|
||||
|
||||
@defun declare-header! sym name [#:multiple?] [#:parser] [#:validator] [#:writer]
|
||||
@defun declare-header! sym name [#:multiple?=@code{#f}] [#:parser] [#:validator] [#:writer]
|
||||
Make a header declaration, as above, and register it by symbol and by
|
||||
name.
|
||||
name. The @var{parser}, @var{validator}, and @var{writer} arguments are
|
||||
all mandatory.
|
||||
@end defun
|
||||
|
||||
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
|
||||
the IPv4 address of the original client. You would like for the HTTP
|
||||
request record to parse out this header to a Scheme value, instead of
|
||||
leaving it as a string. You could register this header with Guile's
|
||||
HTTP stack like this:
|
||||
|
||||
@example
|
||||
(define (parse-ip str)
|
||||
(inet-aton str)
|
||||
(define (validate-ip ip)
|
||||
(define (write-ip ip port)
|
||||
(display (inet-ntoa ip) port))
|
||||
|
||||
(declare-header! 'x-client-address
|
||||
"X-Client-Address"
|
||||
#:parser (lambda (str)
|
||||
(inet-aton str))
|
||||
#:validator (lambda (ip)
|
||||
(and (integer? ip) (exact? ip) (<= 0 ip 4294967295)))
|
||||
#:writer (lambda (ip port)
|
||||
(display (inet-ntoa ip) port)))
|
||||
@end example
|
||||
|
||||
@defun lookup-header-decl name
|
||||
Return the @var{header-decl} object registered for the given @var{name}.
|
||||
|
||||
|
@ -365,27 +390,27 @@ a case-insensitive fashion.
|
|||
@end defun
|
||||
|
||||
@defun valid-header? sym val
|
||||
Returns a true value iff @var{val} is a valid Scheme value for the
|
||||
header with name @var{sym}.
|
||||
Return a true value iff @var{val} is a valid Scheme value for the header
|
||||
with name @var{sym}.
|
||||
@end defun
|
||||
|
||||
Now that we have a generic interface for reading and writing headers, we
|
||||
do just that.
|
||||
|
||||
@defun read-header port
|
||||
Reads one HTTP header from @var{port}. Returns two values: the header
|
||||
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 @var{#f} for both values if the end of the message body was
|
||||
reached (i.e., a blank line).
|
||||
Returns the end-of-file object for both values if the end of the message
|
||||
body was reached (i.e., a blank line).
|
||||
@end defun
|
||||
|
||||
@defun 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
|
||||
Return 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.
|
||||
@end defun
|
||||
|
@ -397,8 +422,8 @@ value is written using @var{display}.
|
|||
@end defun
|
||||
|
||||
@defun 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 @var{port}, returning the
|
||||
headers as an ordered alist.
|
||||
@end defun
|
||||
|
||||
@defun write-headers headers port
|
||||
|
|
|
@ -130,17 +130,19 @@ port, and writes the value to the port."
|
|||
(read-line* port))))
|
||||
val))
|
||||
|
||||
(define *eof* (call-with-input-string "" read))
|
||||
|
||||
(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)."
|
||||
Returns the end-of-file object 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"))
|
||||
(values #f #f)
|
||||
(values *eof* *eof*)
|
||||
(let ((delim (or (string-index line #\:)
|
||||
(bad-header '%read line))))
|
||||
(parse-header
|
||||
|
@ -205,9 +207,9 @@ ordered alist."
|
|||
(let lp ((headers '()))
|
||||
(call-with-values (lambda () (read-header port))
|
||||
(lambda (k v)
|
||||
(if k
|
||||
(lp (acons k v headers))
|
||||
(reverse! headers))))))
|
||||
(if (eof-object? k)
|
||||
(reverse! headers)
|
||||
(lp (acons k v headers)))))))
|
||||
|
||||
(define (write-headers headers port)
|
||||
"Write the given header alist to @var{port}. Doesn't write the final
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue