* HTTP Headers:: How Guile represents specific header values.
* Requests:: HTTP requests.
* Responses:: HTTP responses.
+* Web Client:: Accessing web resources over HTTP.
* Web Server:: Serving HTTP to the internet.
* Web Examples:: How to use this thing.
@end menu
dates, occurs on the boundary in which we produce a SRFI 19 date record
from other types, like strings.
-With regards to the web, data types are help in the two broad phases of
-HTTP messages: parsing and generation.
+With regards to the web, data types are helpful in the two broad phases
+of HTTP messages: parsing and generation.
Consider a server, which has to parse a request, and produce a response.
Guile will parse the request into an HTTP request object
elements of the HTTP protocol.
If you are want to skip the low-level details for now and move on to web
-pages, @pxref{Web Server}. Otherwise, load the HTTP module, and read
-on.
+pages, @pxref{Web Client}, and @pxref{Web Server}. Otherwise, load the
+HTTP module, and read on.
@example
(use-modules (web http))
(string->header "FOO")
@result{} foo
-(header->string 'foo
+(header->string 'foo)
@result{} "Foo"
@end example
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"
(lambda (str)
(inet-aton str))
(parse-header 'accept "text/html,text/plain;charset=utf-8")
@result{} ((text/html) (text/plain (charset . "utf-8")))
@end example
-Preference is expressed with qualitiy values:
+Preference is expressed with quality values:
@example
(parse-header 'accept "text/html;q=0.8,text/plain;q=0.6")
@result{} ((text/html (q . 800)) (text/plain (q . 600)))
Indicates that a response should proceed if and only if the resource has
been modified since the given date.
@example
-(parse-header if-modified-since "Tue, 15 Nov 1994 08:12:31 GMT")
+(parse-header 'if-modified-since "Tue, 15 Nov 1994 08:12:31 GMT")
@result{} #<date ...>
@end example
@end deftypevr
@deftypevr {HTTP Header} *|List vary
A set of request headers that were used in computing this response.
-Used to indicate that server-side content negotation was performed, for
+Used to indicate that server-side content negotiation was performed, for
example in response to the @code{accept-language} header. Can also be
the symbol @code{*}, indicating that all headers were considered.
@example
@end deffn
+@node Web Client
+@subsection Web Client
+
+@code{(web client)} provides a simple, synchronous HTTP client, built on
+the lower-level HTTP, request, and response modules.
+
+@deffn {Scheme Procedure} open-socket-for-uri uri
+@end deffn
+
+@deffn {Scheme Procedure} http-get uri [#:port=(open-socket-for-uri uri)] [#:version='(1 . 1)] [#:keep-alive?=#f] [#:extra-headers='()] [#:decode-body=#t]
+Connect to the server corresponding to @var{uri} and ask for the
+resource, using the @code{GET} method. If you already have a port open,
+pass it as @var{port}. The port will be closed at the end of the
+request unless @var{keep-alive?} is true. Any extra headers in the
+alist @var{extra-headers} will be added to the request.
+
+If @var{decode-body?} is true, as is the default, the body of the
+response will be decoded to string, if it is a textual content-type.
+Otherwise it will be returned as a bytevector.
+@end deffn
+
+@code{http-get} is useful for making one-off requests to web sites. If
+you are writing a web spider or some other client that needs to handle a
+number of requests in parallel, it's better to build an event-driven URL
+fetcher, similar in structure to the web server (@pxref{Web Server}).
+
+Another option, good but not as performant, would be to use threads,
+possibly via par-map or futures.
+
+More helper procedures for the other common HTTP verbs would be a good
+addition to this module. Send your code to
+@email{guile-user@@gnu.org}.
+
+
@node Web Server
@subsection Web Server
socket, request, and body.
@item
-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
-@code{#f} 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.
+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 bytevector, or @code{#f} if not present.
+
+The respose and response body are run through @code{sanitize-response},
+documented below. This allows the handler writer to take some
+convenient shortcuts: for example, instead of a @code{<response>}, the
+handler can simply return an alist of headers, in which case a default
+response object is constructed with those headers. Instead of a
+bytevector for the body, the handler can return a string, which will be
+serialized into an appropriate encoding; or it can return a procedure,
+which will be called on a port to write out the data. See the
+@code{sanitize-response} documentation, for more.
@item
The @code{write} hook is called with three arguments: the client
(define (not-found request)
(values (build-response #:code 404)
(string-append "Resource not found: "
- (unparse-uri (request-uri request)))))
+ (uri->string (request-uri request)))))
;; Now paste this to let the web server keep going:
,continue