277 lines
16 KiB
HTML
277 lines
16 KiB
HTML
|
<!DOCTYPE html>
|
||
|
<html>
|
||
|
<!-- Created by GNU Texinfo 7.1, https://www.gnu.org/software/texinfo/ -->
|
||
|
<head>
|
||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||
|
<!-- This manual documents Guile version 3.0.10.
|
||
|
|
||
|
Copyright (C) 1996-1997, 2000-2005, 2009-2023 Free Software Foundation,
|
||
|
Inc.
|
||
|
|
||
|
Copyright (C) 2021 Maxime Devos
|
||
|
|
||
|
Copyright (C) 2024 Tomas Volf
|
||
|
|
||
|
|
||
|
Permission is granted to copy, distribute and/or modify this document
|
||
|
under the terms of the GNU Free Documentation License, Version 1.3 or
|
||
|
any later version published by the Free Software Foundation; with no
|
||
|
Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A
|
||
|
copy of the license is included in the section entitled "GNU Free
|
||
|
Documentation License." -->
|
||
|
<title>Web Server (Guile Reference Manual)</title>
|
||
|
|
||
|
<meta name="description" content="Web Server (Guile Reference Manual)">
|
||
|
<meta name="keywords" content="Web Server (Guile Reference Manual)">
|
||
|
<meta name="resource-type" content="document">
|
||
|
<meta name="distribution" content="global">
|
||
|
<meta name="Generator" content=".texi2any-real">
|
||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
|
|
||
|
<link href="index.html" rel="start" title="Top">
|
||
|
<link href="Concept-Index.html" rel="index" title="Concept Index">
|
||
|
<link href="index.html#SEC_Contents" rel="contents" title="Table of Contents">
|
||
|
<link href="Web.html" rel="up" title="Web">
|
||
|
<link href="Web-Examples.html" rel="next" title="Web Examples">
|
||
|
<link href="Web-Client.html" rel="prev" title="Web Client">
|
||
|
<style type="text/css">
|
||
|
<!--
|
||
|
a.copiable-link {visibility: hidden; text-decoration: none; line-height: 0em}
|
||
|
div.example {margin-left: 3.2em}
|
||
|
span:hover a.copiable-link {visibility: visible}
|
||
|
strong.def-name {font-family: monospace; font-weight: bold; font-size: larger}
|
||
|
-->
|
||
|
</style>
|
||
|
<link rel="stylesheet" type="text/css" href="https://www.gnu.org/software/gnulib/manual.css">
|
||
|
|
||
|
|
||
|
</head>
|
||
|
|
||
|
<body lang="en">
|
||
|
<div class="subsection-level-extent" id="Web-Server">
|
||
|
<div class="nav-panel">
|
||
|
<p>
|
||
|
Next: <a href="Web-Examples.html" accesskey="n" rel="next">Web Examples</a>, Previous: <a href="Web-Client.html" accesskey="p" rel="prev">Web Client</a>, Up: <a href="Web.html" accesskey="u" rel="up"><abbr class="acronym">HTTP</abbr>, the Web, and All That</a> [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Concept-Index.html" title="Index" rel="index">Index</a>]</p>
|
||
|
</div>
|
||
|
<hr>
|
||
|
<h4 class="subsection" id="Web-Server-1"><span>7.3.9 Web Server<a class="copiable-link" href="#Web-Server-1"> ¶</a></span></h4>
|
||
|
|
||
|
<p><code class="code">(web server)</code> is a generic web server interface, along with a main
|
||
|
loop implementation for web servers controlled by Guile.
|
||
|
</p>
|
||
|
<div class="example">
|
||
|
<pre class="example-preformatted">(use-modules (web server))
|
||
|
</pre></div>
|
||
|
|
||
|
<p>The lowest layer is the <code class="code"><server-impl></code> object, which defines a set
|
||
|
of hooks to open a server, read a request from a client, write a
|
||
|
response to a client, and close a server. These hooks – <code class="code">open</code>,
|
||
|
<code class="code">read</code>, <code class="code">write</code>, and <code class="code">close</code>, respectively – are bound
|
||
|
together in a <code class="code"><server-impl></code> object. Procedures in this module take a
|
||
|
<code class="code"><server-impl></code> object, if needed.
|
||
|
</p>
|
||
|
<p>A <code class="code"><server-impl></code> may also be looked up by name. If you pass the
|
||
|
<code class="code">http</code> symbol to <code class="code">run-server</code>, Guile looks for a variable
|
||
|
named <code class="code">http</code> in the <code class="code">(web server http)</code> module, which should
|
||
|
be bound to a <code class="code"><server-impl></code> object. Such a binding is made by
|
||
|
instantiation of the <code class="code">define-server-impl</code> syntax. In this way the
|
||
|
run-server loop can automatically load other backends if available.
|
||
|
</p>
|
||
|
<p>The life cycle of a server goes as follows:
|
||
|
</p>
|
||
|
<ol class="enumerate">
|
||
|
<li> The <code class="code">open</code> hook is called, to open the server. <code class="code">open</code> takes
|
||
|
zero or more arguments, depending on the backend, and returns an opaque
|
||
|
server socket object, or signals an error.
|
||
|
|
||
|
</li><li> The <code class="code">read</code> hook is called, to read a request from a new client.
|
||
|
The <code class="code">read</code> hook takes one argument, the server socket. It should
|
||
|
return three values: an opaque client socket, the request, and the
|
||
|
request body. The request should be a <code class="code"><request></code> object, from
|
||
|
<code class="code">(web request)</code>. The body should be a string or a bytevector, or
|
||
|
<code class="code">#f</code> if there is no body.
|
||
|
|
||
|
<p>If the read failed, the <code class="code">read</code> hook may return #f for the client
|
||
|
socket, request, and body.
|
||
|
</p>
|
||
|
</li><li> 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 class="code"><response></code> record from <code class="code">(web response)</code>, and the
|
||
|
response body as bytevector, or <code class="code">#f</code> if not present.
|
||
|
|
||
|
<p>The respose and response body are run through <code class="code">sanitize-response</code>,
|
||
|
documented below. This allows the handler writer to take some
|
||
|
convenient shortcuts: for example, instead of a <code class="code"><response></code>, 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 class="code">sanitize-response</code> documentation, for more.
|
||
|
</p>
|
||
|
</li><li> The <code class="code">write</code> hook is called with three arguments: the client
|
||
|
socket, the response, and the body. The <code class="code">write</code> hook returns no
|
||
|
values.
|
||
|
|
||
|
</li><li> At this point the request handling is complete. For a loop, we
|
||
|
loop back and try to read a new request.
|
||
|
|
||
|
</li><li> If the user interrupts the loop, the <code class="code">close</code> hook is called on
|
||
|
the server socket.
|
||
|
</li></ol>
|
||
|
|
||
|
<p>A user may define a server implementation with the following form:
|
||
|
</p>
|
||
|
<dl class="first-deffn">
|
||
|
<dt class="deffn" id="index-define_002dserver_002dimpl"><span class="category-def">Scheme Syntax: </span><span><strong class="def-name">define-server-impl</strong> <var class="def-var-arguments">name open read write close</var><a class="copiable-link" href="#index-define_002dserver_002dimpl"> ¶</a></span></dt>
|
||
|
<dd><p>Make a <code class="code"><server-impl></code> object with the hooks <var class="var">open</var>,
|
||
|
<var class="var">read</var>, <var class="var">write</var>, and <var class="var">close</var>, and bind it to the symbol
|
||
|
<var class="var">name</var> in the current module.
|
||
|
</p></dd></dl>
|
||
|
|
||
|
<dl class="first-deffn">
|
||
|
<dt class="deffn" id="index-lookup_002dserver_002dimpl"><span class="category-def">Scheme Procedure: </span><span><strong class="def-name">lookup-server-impl</strong> <var class="def-var-arguments">impl</var><a class="copiable-link" href="#index-lookup_002dserver_002dimpl"> ¶</a></span></dt>
|
||
|
<dd><p>Look up a server implementation. If <var class="var">impl</var> is a server
|
||
|
implementation already, it is returned directly. If it is a symbol, the
|
||
|
binding named <var class="var">impl</var> in the <code class="code">(web server <var class="var">impl</var>)</code> module is
|
||
|
looked up. Otherwise an error is signaled.
|
||
|
</p>
|
||
|
<p>Currently a server implementation is a somewhat opaque type, useful only
|
||
|
for passing to other procedures in this module, like <code class="code">read-client</code>.
|
||
|
</p></dd></dl>
|
||
|
|
||
|
<p>The <code class="code">(web server)</code> module defines a number of routines that use
|
||
|
<code class="code"><server-impl></code> objects to implement parts of a web server. Given
|
||
|
that we don’t expose the accessors for the various fields of a
|
||
|
<code class="code"><server-impl></code>, indeed these routines are the only procedures with
|
||
|
any access to the impl objects.
|
||
|
</p>
|
||
|
<dl class="first-deffn">
|
||
|
<dt class="deffn" id="index-open_002dserver"><span class="category-def">Scheme Procedure: </span><span><strong class="def-name">open-server</strong> <var class="def-var-arguments">impl open-params</var><a class="copiable-link" href="#index-open_002dserver"> ¶</a></span></dt>
|
||
|
<dd><p>Open a server for the given implementation. Return one value, the new
|
||
|
server object. The implementation’s <code class="code">open</code> procedure is applied to
|
||
|
<var class="var">open-params</var>, which should be a list.
|
||
|
</p></dd></dl>
|
||
|
|
||
|
<dl class="first-deffn">
|
||
|
<dt class="deffn" id="index-read_002dclient"><span class="category-def">Scheme Procedure: </span><span><strong class="def-name">read-client</strong> <var class="def-var-arguments">impl server</var><a class="copiable-link" href="#index-read_002dclient"> ¶</a></span></dt>
|
||
|
<dd><p>Read a new client from <var class="var">server</var>, by applying the implementation’s
|
||
|
<code class="code">read</code> 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, return <code class="code">#f</code> for all three
|
||
|
values.
|
||
|
</p></dd></dl>
|
||
|
|
||
|
<dl class="first-deffn">
|
||
|
<dt class="deffn" id="index-handle_002drequest"><span class="category-def">Scheme Procedure: </span><span><strong class="def-name">handle-request</strong> <var class="def-var-arguments">handler request body state</var><a class="copiable-link" href="#index-handle_002drequest"> ¶</a></span></dt>
|
||
|
<dd><p>Handle a given request, returning the response and body.
|
||
|
</p>
|
||
|
<p>The response and response body are produced by calling the given
|
||
|
<var class="var">handler</var> with <var class="var">request</var> and <var class="var">body</var> as arguments.
|
||
|
</p>
|
||
|
<p>The elements of <var class="var">state</var> are also passed to <var class="var">handler</var> as
|
||
|
arguments, and may be returned as additional values. The new
|
||
|
<var class="var">state</var>, collected from the <var class="var">handler</var>’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.
|
||
|
</p></dd></dl>
|
||
|
|
||
|
<dl class="first-deffn">
|
||
|
<dt class="deffn" id="index-sanitize_002dresponse"><span class="category-def">Scheme Procedure: </span><span><strong class="def-name">sanitize-response</strong> <var class="def-var-arguments">request response body</var><a class="copiable-link" href="#index-sanitize_002dresponse"> ¶</a></span></dt>
|
||
|
<dd><p>“Sanitize” the given response and body, making them appropriate for
|
||
|
the given request.
|
||
|
</p>
|
||
|
<p>As a convenience to web handler authors, <var class="var">response</var> 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 class="var">body</var> is a string, encodes the string to a bytevector,
|
||
|
in an encoding appropriate for <var class="var">response</var>. Adds a
|
||
|
<code class="code">content-length</code> and <code class="code">content-type</code> header, as necessary.
|
||
|
</p>
|
||
|
<p>If <var class="var">body</var> is a procedure, it is called with a port as an argument,
|
||
|
and the output collected as a bytevector. In the future we might try to
|
||
|
instead use a compressing, chunk-encoded port, and call this procedure
|
||
|
later, in the write-client procedure. Authors are advised not to rely on
|
||
|
the procedure being called at any particular time.
|
||
|
</p></dd></dl>
|
||
|
|
||
|
<dl class="first-deffn">
|
||
|
<dt class="deffn" id="index-write_002dclient"><span class="category-def">Scheme Procedure: </span><span><strong class="def-name">write-client</strong> <var class="def-var-arguments">impl server client response body</var><a class="copiable-link" href="#index-write_002dclient"> ¶</a></span></dt>
|
||
|
<dd><p>Write an HTTP response and body to <var class="var">client</var>. 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 class="var">server</var> argument somehow.
|
||
|
</p></dd></dl>
|
||
|
|
||
|
<dl class="first-deffn">
|
||
|
<dt class="deffn" id="index-close_002dserver"><span class="category-def">Scheme Procedure: </span><span><strong class="def-name">close-server</strong> <var class="def-var-arguments">impl server</var><a class="copiable-link" href="#index-close_002dserver"> ¶</a></span></dt>
|
||
|
<dd><p>Release resources allocated by a previous invocation of
|
||
|
<code class="code">open-server</code>.
|
||
|
</p></dd></dl>
|
||
|
|
||
|
<p>Given the procedures above, it is a small matter to make a web server:
|
||
|
</p>
|
||
|
<dl class="first-deffn">
|
||
|
<dt class="deffn" id="index-serve_002done_002dclient"><span class="category-def">Scheme Procedure: </span><span><strong class="def-name">serve-one-client</strong> <var class="def-var-arguments">handler impl server state</var><a class="copiable-link" href="#index-serve_002done_002dclient"> ¶</a></span></dt>
|
||
|
<dd><p>Read one request from <var class="var">server</var>, call <var class="var">handler</var> on the request
|
||
|
and body, and write the response to the client. Return the new state
|
||
|
produced by the handler procedure.
|
||
|
</p></dd></dl>
|
||
|
|
||
|
<dl class="first-deffn">
|
||
|
<dt class="deffn" id="index-run_002dserver-1"><span class="category-def">Scheme Procedure: </span><span><strong class="def-name">run-server</strong> <var class="def-var-arguments">handler [impl=’http] [open-params=’()] arg …</var><a class="copiable-link" href="#index-run_002dserver-1"> ¶</a></span></dt>
|
||
|
<dd><p>Run Guile’s built-in web server.
|
||
|
</p>
|
||
|
<p><var class="var">handler</var> 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.
|
||
|
</p>
|
||
|
<p>For examples, skip ahead to the next section, <a class="ref" href="Web-Examples.html">Web Examples</a>.
|
||
|
</p>
|
||
|
<p>The response and body will be run through <code class="code">sanitize-response</code>
|
||
|
before sending back to the client.
|
||
|
</p>
|
||
|
<p>Additional arguments to <var class="var">handler</var> are taken from <var class="var">arg</var>
|
||
|
<small class="enddots">...</small>. These arguments comprise a <em class="dfn">state</em>. 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.
|
||
|
</p></dd></dl>
|
||
|
|
||
|
<p>The default web server implementation is <code class="code">http</code>, which binds to a
|
||
|
socket, listening for request on that port.
|
||
|
</p>
|
||
|
<dl class="first-deffn">
|
||
|
<dt class="deffn" id="index-http"><span class="category-def">HTTP Implementation: </span><span><strong class="def-name">http</strong> <var class="def-var-arguments">[#:host=#f] [#:family=AF_INET] [#:addr=INADDR_LOOPBACK] [#:port 8080] [#:socket]</var><a class="copiable-link" href="#index-http"> ¶</a></span></dt>
|
||
|
<dd><p>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 class="var">open-params</var> to <code class="code">run-server</code> get passed to the
|
||
|
implementation’s open function.
|
||
|
</p>
|
||
|
<div class="example">
|
||
|
<pre class="example-preformatted">;; 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)))
|
||
|
</pre></div>
|
||
|
</dd></dl>
|
||
|
|
||
|
</div>
|
||
|
<hr>
|
||
|
<div class="nav-panel">
|
||
|
<p>
|
||
|
Next: <a href="Web-Examples.html">Web Examples</a>, Previous: <a href="Web-Client.html">Web Client</a>, Up: <a href="Web.html"><abbr class="acronym">HTTP</abbr>, the Web, and All That</a> [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Concept-Index.html" title="Index" rel="index">Index</a>]</p>
|
||
|
</div>
|
||
|
|
||
|
|
||
|
|
||
|
</body>
|
||
|
</html>
|