tiny_httpd/0.9/tiny_httpd/Tiny_httpd/index.html
2021-07-18 00:10:03 -04:00

52 lines
No EOL
24 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Tiny_httpd (tiny_httpd.Tiny_httpd)</title><link rel="stylesheet" href="../../odoc.css"/><meta charset="utf-8"/><meta name="generator" content="odoc 1.5.2"/><meta name="viewport" content="width=device-width,initial-scale=1.0"/><script src="../../highlight.pack.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div class="content"><header><nav><a href="../index.html">Up</a> <a href="../index.html">tiny_httpd</a> &#x00BB; Tiny_httpd</nav><h1>Module <code>Tiny_httpd</code></h1><h2 id="tiny-http-server"><a href="#tiny-http-server" class="anchor"></a>Tiny Http Server</h2><p>This library implements a very simple, basic HTTP/1.1 server using blocking IOs and threads. Basic routing based on <code>Scanf</code> is provided for convenience, so that several handlers can be registered.</p><p>It is possible to use a thread pool, see <a href="index.html#val-create"><code>create</code></a>'s argument <code>new_thread</code>.</p><p>The <code>echo</code> example (see <code>src/examples/echo.ml</code>) demonstrates some of the features by declaring a few endpoints, including one for uploading files:</p><pre><code class="ml">module S = Tiny_httpd
let () =
let server = S.create () in
(* say hello *)
S.add_route_handler ~meth:`GET server
S.Route.(exact &quot;hello&quot; @/ string @/ return)
(fun name _req -&gt; S.Response.make_string (Ok (&quot;hello &quot; ^name ^&quot;!\n&quot;)));
(* echo request *)
S.add_route_handler server
S.Route.(exact &quot;echo&quot; @/ return)
(fun req -&gt; S.Response.make_string
(Ok (Format.asprintf &quot;echo:@ %a@.&quot; S.Request.pp req)));
(* file upload *)
S.add_route_handler ~meth:`PUT server
S.Route.(exact &quot;upload&quot; @/ string_urlencoded @/ return)
(fun path req -&gt;
try
let oc = open_out @@ &quot;/tmp/&quot; ^ path in
output_string oc req.S.Request.body;
flush oc;
S.Response.make_string (Ok &quot;uploaded file&quot;)
with e -&gt;
S.Response.fail ~code:500 &quot;couldn't upload file: %s&quot;
(Printexc.to_string e)
);
(* run the server *)
Printf.printf &quot;listening on http://%s:%d\n%!&quot; (S.addr server) (S.port server);
match S.run server with
| Ok () -&gt; ()
| Error e -&gt; raise e</code></pre><p>It is then possible to query it using curl:</p><pre><code class="ml">$ dune exec src/examples/echo.exe &amp;
listening on http://127.0.0.1:8080
# the path &quot;hello/name&quot; greets you.
$ curl -X GET http://localhost:8080/hello/quadrarotaphile
hello quadrarotaphile!
# the path &quot;echo&quot; just prints the request.
$ curl -X GET http://localhost:8080/echo --data &quot;howdy y'all&quot;
echo:
{meth=GET;
headers=Host: localhost:8080
User-Agent: curl/7.66.0
Accept: */*
Content-Length: 10
Content-Type: application/x-www-form-urlencoded;
path=&quot;/echo&quot;; body=&quot;howdy y'all&quot;}</code></pre><nav class="toc"><ul><li><a href="#tiny-buffer-implementation">Tiny buffer implementation</a></li><li><a href="#generic-stream-of-data">Generic stream of data</a></li><li><a href="#methods">Methods</a></li><li><a href="#headers">Headers</a></li><li><a href="#requests">Requests</a></li><li><a href="#response-codes">Response Codes</a></li><li><a href="#responses">Responses</a></li><li><a href="#main-server-type">Main Server type</a></li><li><a href="#request-handlers">Request handlers</a></li><li><a href="#server-sent-events">Server-sent events</a></li><li><a href="#run-the-server">Run the server</a></li></ul></nav></header><section><header><h3 id="tiny-buffer-implementation"><a href="#tiny-buffer-implementation" class="anchor"></a>Tiny buffer implementation</h3><p>These buffers are used to avoid allocating too many byte arrays when processing streams and parsing requests.</p></header><div class="spec module" id="module-Buf_"><a href="#module-Buf_" class="anchor"></a><code><span class="keyword">module</span> <a href="Buf_/index.html">Buf_</a> : <span class="keyword">sig</span> ... <span class="keyword">end</span></code></div></section><section><header><h3 id="generic-stream-of-data"><a href="#generic-stream-of-data" class="anchor"></a>Generic stream of data</h3><p>Streams are used to represent a series of bytes that can arrive progressively. For example, an uploaded file will be sent as a series of chunks.</p></header><dl><dt class="spec type" id="type-byte_stream"><a href="#type-byte_stream" class="anchor"></a><code><span class="keyword">type</span> byte_stream</code><code> = </code><code>{</code><table class="record"><tr id="type-byte_stream.bs_fill_buf" class="anchored"><td class="def field"><a href="#type-byte_stream.bs_fill_buf" class="anchor"></a><code>bs_fill_buf : unit <span>&#45;&gt;</span> bytes * int * int;</code></td><td class="doc"><p>See the current slice of the internal buffer as <code>bytes, i, len</code>, where the slice is <code>bytes[i] .. [bytes[i+len-1]]</code>. Can block to refill the buffer if there is currently no content. If <code>len=0</code> then there is no more data.</p></td></tr><tr id="type-byte_stream.bs_consume" class="anchored"><td class="def field"><a href="#type-byte_stream.bs_consume" class="anchor"></a><code>bs_consume : int <span>&#45;&gt;</span> unit;</code></td><td class="doc"><p>Consume n bytes from the buffer. This should only be called with <code>n &lt;= len</code> after a call to <code>is_fill_buf</code> that returns a slice of length <code>len</code>.</p></td></tr><tr id="type-byte_stream.bs_close" class="anchored"><td class="def field"><a href="#type-byte_stream.bs_close" class="anchor"></a><code>bs_close : unit <span>&#45;&gt;</span> unit;</code></td><td class="doc"><p>Close the stream.</p></td></tr></table><code>}</code></dt><dd><p>A buffered stream, with a view into the current buffer (or refill if empty), and a function to consume <code>n</code> bytes. See <a href="Byte_stream/index.html"><code>Byte_stream</code></a> for more details.</p></dd></dl><div class="spec module" id="module-Byte_stream"><a href="#module-Byte_stream" class="anchor"></a><code><span class="keyword">module</span> <a href="Byte_stream/index.html">Byte_stream</a> : <span class="keyword">sig</span> ... <span class="keyword">end</span></code></div></section><section><header><h3 id="methods"><a href="#methods" class="anchor"></a>Methods</h3></header><div class="spec module" id="module-Meth"><a href="#module-Meth" class="anchor"></a><code><span class="keyword">module</span> <a href="Meth/index.html">Meth</a> : <span class="keyword">sig</span> ... <span class="keyword">end</span></code></div></section><section><header><h3 id="headers"><a href="#headers" class="anchor"></a>Headers</h3><p>Headers are metadata associated with a request or response.</p></header><div class="spec module" id="module-Headers"><a href="#module-Headers" class="anchor"></a><code><span class="keyword">module</span> <a href="Headers/index.html">Headers</a> : <span class="keyword">sig</span> ... <span class="keyword">end</span></code></div></section><section><header><h3 id="requests"><a href="#requests" class="anchor"></a>Requests</h3><p>Requests are sent by a client, e.g. a web browser or cURL.</p></header><div class="spec module" id="module-Request"><a href="#module-Request" class="anchor"></a><code><span class="keyword">module</span> <a href="Request/index.html">Request</a> : <span class="keyword">sig</span> ... <span class="keyword">end</span></code></div></section><section><header><h3 id="response-codes"><a href="#response-codes" class="anchor"></a>Response Codes</h3></header><div class="spec module" id="module-Response_code"><a href="#module-Response_code" class="anchor"></a><code><span class="keyword">module</span> <a href="Response_code/index.html">Response_code</a> : <span class="keyword">sig</span> ... <span class="keyword">end</span></code></div></section><section><header><h3 id="responses"><a href="#responses" class="anchor"></a>Responses</h3><p>Responses are what a http server, such as <a href="index.html"><code>Tiny_httpd</code></a>, send back to the client to answer a <a href="Request/index.html#type-t"><code>Request.t</code></a></p></header><div class="spec module" id="module-Response"><a href="#module-Response" class="anchor"></a><code><span class="keyword">module</span> <a href="Response/index.html">Response</a> : <span class="keyword">sig</span> ... <span class="keyword">end</span></code></div><dl><dt class="spec module" id="module-Route"><a href="#module-Route" class="anchor"></a><code><span class="keyword">module</span> <a href="Route/index.html">Route</a> : <span class="keyword">sig</span> ... <span class="keyword">end</span></code></dt><dd></dd></dl></section><section><header><h3 id="main-server-type"><a href="#main-server-type" class="anchor"></a>Main Server type</h3></header><dl><dt class="spec type" id="type-t"><a href="#type-t" class="anchor"></a><code><span class="keyword">type</span> t</code></dt><dd><p>A HTTP server. See <a href="index.html#val-create"><code>create</code></a> for more details.</p></dd></dl><dl><dt class="spec value" id="val-create"><a href="#val-create" class="anchor"></a><code><span class="keyword">val</span> create : <span>?&#8288;masksigpipe:bool</span> <span>&#45;&gt;</span> <span>?&#8288;max_connections:int</span> <span>&#45;&gt;</span> <span>?&#8288;new_thread:<span>(<span>(unit <span>&#45;&gt;</span> unit)</span> <span>&#45;&gt;</span> unit)</span></span> <span>&#45;&gt;</span> <span>?&#8288;addr:string</span> <span>&#45;&gt;</span> <span>?&#8288;port:int</span> <span>&#45;&gt;</span> unit <span>&#45;&gt;</span> <a href="index.html#type-t">t</a></code></dt><dd><p>Create a new webserver.</p><p>The server will not do anything until <a href="index.html#val-run"><code>run</code></a> is called on it. Before starting the server, one can use <a href="index.html#val-add_path_handler"><code>add_path_handler</code></a> and <a href="index.html#val-set_top_handler"><code>set_top_handler</code></a> to specify how to handle incoming requests.</p><dl><dt>parameter masksigpipe</dt><dd><p>if true, block the signal <span class="xref-unresolved" title="unresolved reference to &quot;Sys.sigpipe&quot;"><code>Sys</code>.sigpipe</span> which otherwise tends to kill client threads when they try to write on broken sockets. Default: <code>true</code>.</p></dd></dl><dl><dt>parameter new_thread</dt><dd><p>a function used to spawn a new thread to handle a new client connection. By default it is <span class="xref-unresolved" title="unresolved reference to &quot;Thread.create&quot;"><code>Thread</code>.create</span> but one could use a thread pool instead.</p></dd></dl><dl><dt>parameter max_connections</dt><dd><p>maximum number of simultaneous connections.</p></dd></dl><dl><dt>parameter addr</dt><dd><p>address (IPv4 or IPv6) to listen on. Default <code>&quot;127.0.0.1&quot;</code>.</p></dd></dl><dl><dt>parameter port</dt><dd><p>to listen on. Default <code>8080</code>.</p></dd></dl></dd></dl><dl><dt class="spec value" id="val-addr"><a href="#val-addr" class="anchor"></a><code><span class="keyword">val</span> addr : <a href="index.html#type-t">t</a> <span>&#45;&gt;</span> string</code></dt><dd><p>Address on which the server listens.</p></dd></dl><dl><dt class="spec value" id="val-is_ipv6"><a href="#val-is_ipv6" class="anchor"></a><code><span class="keyword">val</span> is_ipv6 : <a href="index.html#type-t">t</a> <span>&#45;&gt;</span> bool</code></dt><dd><p><code>is_ipv6 server</code> returns <code>true</code> iff the address of the server is an IPv6 address.</p><dl><dt>since</dt><dd>0.3</dd></dl></dd></dl><dl><dt class="spec value" id="val-port"><a href="#val-port" class="anchor"></a><code><span class="keyword">val</span> port : <a href="index.html#type-t">t</a> <span>&#45;&gt;</span> int</code></dt><dd><p>Port on which the server listens.</p></dd></dl><dl><dt class="spec value" id="val-add_decode_request_cb"><a href="#val-add_decode_request_cb" class="anchor"></a><code><span class="keyword">val</span> add_decode_request_cb : <a href="index.html#type-t">t</a> <span>&#45;&gt;</span> <span>(<span>unit <a href="Request/index.html#type-t">Request.t</a></span> <span>&#45;&gt;</span> <span><span>(<span>unit <a href="Request/index.html#type-t">Request.t</a></span> * <span>(<a href="index.html#type-byte_stream">byte_stream</a> <span>&#45;&gt;</span> <a href="index.html#type-byte_stream">byte_stream</a>)</span>)</span> option</span>)</span> <span>&#45;&gt;</span> unit</code></dt><dd><p>Add a callback for every request. The callback can provide a stream transformer and a new request (with modified headers, typically). A possible use is to handle decompression by looking for a <code>Transfer-Encoding</code> header and returning a stream transformer that decompresses on the fly.</p></dd></dl><dl><dt class="spec value" id="val-add_encode_response_cb"><a href="#val-add_encode_response_cb" class="anchor"></a><code><span class="keyword">val</span> add_encode_response_cb : <a href="index.html#type-t">t</a> <span>&#45;&gt;</span> <span>(<span>unit <a href="Request/index.html#type-t">Request.t</a></span> <span>&#45;&gt;</span> <a href="Response/index.html#type-t">Response.t</a> <span>&#45;&gt;</span> <span><a href="Response/index.html#type-t">Response.t</a> option</span>)</span> <span>&#45;&gt;</span> unit</code></dt><dd><p>Add a callback for every request/response pair. Similarly to <a href="index.html#val-add_encode_response_cb"><code>add_encode_response_cb</code></a> the callback can return a new response, for example to compress it. The callback is given the query with only its headers, as well as the current response.</p></dd></dl></section><section><header><h3 id="request-handlers"><a href="#request-handlers" class="anchor"></a>Request handlers</h3></header><dl><dt class="spec value" id="val-set_top_handler"><a href="#val-set_top_handler" class="anchor"></a><code><span class="keyword">val</span> set_top_handler : <a href="index.html#type-t">t</a> <span>&#45;&gt;</span> <span>(<span>string <a href="Request/index.html#type-t">Request.t</a></span> <span>&#45;&gt;</span> <a href="Response/index.html#type-t">Response.t</a>)</span> <span>&#45;&gt;</span> unit</code></dt><dd><p>Setup a handler called by default.</p><p>This handler is called with any request not accepted by any handler installed via <a href="index.html#val-add_path_handler"><code>add_path_handler</code></a>. If no top handler is installed, unhandled paths will return a <code>404</code> not found.</p></dd></dl><dl><dt class="spec value" id="val-add_route_handler"><a href="#val-add_route_handler" class="anchor"></a><code><span class="keyword">val</span> add_route_handler : <span>?&#8288;accept:<span>(<span>unit <a href="Request/index.html#type-t">Request.t</a></span> <span>&#45;&gt;</span> <span><span>(unit, <a href="Response_code/index.html#type-t">Response_code.t</a> * string)</span> Stdlib.result</span>)</span></span> <span>&#45;&gt;</span> <span>?&#8288;meth:<a href="Meth/index.html#type-t">Meth.t</a></span> <span>&#45;&gt;</span> <a href="index.html#type-t">t</a> <span>&#45;&gt;</span> <span><span>(<span class="type-var">'a</span>, <span>string <a href="Request/index.html#type-t">Request.t</a></span> <span>&#45;&gt;</span> <a href="Response/index.html#type-t">Response.t</a>)</span> <a href="Route/index.html#type-t">Route.t</a></span> <span>&#45;&gt;</span> <span class="type-var">'a</span> <span>&#45;&gt;</span> unit</code></dt><dd><p><code>add_route_handler server Route.(exact &quot;path&quot; @/ string @/ int @/ return) f</code> calls <code>f &quot;foo&quot; 42 request</code> when a <code>request</code> with path &quot;path/foo/42/&quot; is received.</p><p>Note that the handlers are called in the reverse order of their addition, so the last registered handler can override previously registered ones.</p><dl><dt>parameter meth</dt><dd><p>if provided, only accept requests with the given method. Typically one could react to <code>`GET</code> or <code>`PUT</code>.</p></dd></dl><dl><dt>parameter accept</dt><dd><p>should return <code>Ok()</code> if the given request (before its body is read) should be accepted, <code>Error (code,message)</code> if it's to be rejected (e.g. because its content is too big, or for some permission error). See the <code>http_of_dir</code> program for an example of how to use <code>accept</code> to filter uploads that are too large before the upload even starts. The default always returns <code>Ok()</code>, i.e. it accepts all requests.</p></dd></dl><dl><dt>since</dt><dd>0.6</dd></dl></dd></dl><dl><dt class="spec value" id="val-add_route_handler_stream"><a href="#val-add_route_handler_stream" class="anchor"></a><code><span class="keyword">val</span> add_route_handler_stream : <span>?&#8288;accept:<span>(<span>unit <a href="Request/index.html#type-t">Request.t</a></span> <span>&#45;&gt;</span> <span><span>(unit, <a href="Response_code/index.html#type-t">Response_code.t</a> * string)</span> Stdlib.result</span>)</span></span> <span>&#45;&gt;</span> <span>?&#8288;meth:<a href="Meth/index.html#type-t">Meth.t</a></span> <span>&#45;&gt;</span> <a href="index.html#type-t">t</a> <span>&#45;&gt;</span> <span><span>(<span class="type-var">'a</span>, <span><a href="index.html#type-byte_stream">byte_stream</a> <a href="Request/index.html#type-t">Request.t</a></span> <span>&#45;&gt;</span> <a href="Response/index.html#type-t">Response.t</a>)</span> <a href="Route/index.html#type-t">Route.t</a></span> <span>&#45;&gt;</span> <span class="type-var">'a</span> <span>&#45;&gt;</span> unit</code></dt><dd><p>Similar to <a href="index.html#val-add_route_handler"><code>add_route_handler</code></a>, but where the body of the request is a stream of bytes that has not been read yet. This is useful when one wants to stream the body directly into a parser, json decoder (such as <code>Jsonm</code>) or into a file.</p><dl><dt>since</dt><dd>0.6</dd></dl></dd></dl><dl><dt class="spec value" id="val-add_path_handler"><a href="#val-add_path_handler" class="anchor"></a><code><span class="keyword">val</span> add_path_handler : <span>?&#8288;accept:<span>(<span>unit <a href="Request/index.html#type-t">Request.t</a></span> <span>&#45;&gt;</span> <span><span>(unit, <a href="Response_code/index.html#type-t">Response_code.t</a> * string)</span> Stdlib.result</span>)</span></span> <span>&#45;&gt;</span> <span>?&#8288;meth:<a href="Meth/index.html#type-t">Meth.t</a></span> <span>&#45;&gt;</span> <a href="index.html#type-t">t</a> <span>&#45;&gt;</span> <span><span>(<span class="type-var">'a</span>, Stdlib.Scanf.Scanning.in_channel, <span class="type-var">'b</span>, <span class="type-var">'c</span> <span>&#45;&gt;</span> <span>string <a href="Request/index.html#type-t">Request.t</a></span> <span>&#45;&gt;</span> <a href="Response/index.html#type-t">Response.t</a>, <span class="type-var">'a</span> <span>&#45;&gt;</span> <span class="type-var">'d</span>, <span class="type-var">'d</span>)</span> Stdlib.format6</span> <span>&#45;&gt;</span> <span class="type-var">'c</span> <span>&#45;&gt;</span> unit</code></dt><dd><p>Similar to <a href="index.html#val-add_route_handler"><code>add_route_handler</code></a> but based on scanf.</p><p>This uses <code>Scanf</code>'s splitting, which has some gotchas (in particular, <code>&quot;%s&quot;</code> is eager, so it's generally necessary to delimit its scope with a <code>&quot;@/&quot;</code> delimiter. The &quot;@&quot; before a character indicates it's a separator.</p><dl><dt>deprecated</dt><dd><p>use <a href="index.html#val-add_route_handler"><code>add_route_handler</code></a> instead.</p></dd></dl></dd></dl><dl><dt class="spec value" id="val-add_path_handler_stream"><a href="#val-add_path_handler_stream" class="anchor"></a><code><span class="keyword">val</span> add_path_handler_stream : <span>?&#8288;accept:<span>(<span>unit <a href="Request/index.html#type-t">Request.t</a></span> <span>&#45;&gt;</span> <span><span>(unit, <a href="Response_code/index.html#type-t">Response_code.t</a> * string)</span> Stdlib.result</span>)</span></span> <span>&#45;&gt;</span> <span>?&#8288;meth:<a href="Meth/index.html#type-t">Meth.t</a></span> <span>&#45;&gt;</span> <a href="index.html#type-t">t</a> <span>&#45;&gt;</span> <span><span>(<span class="type-var">'a</span>, Stdlib.Scanf.Scanning.in_channel, <span class="type-var">'b</span>, <span class="type-var">'c</span> <span>&#45;&gt;</span> <span><a href="index.html#type-byte_stream">byte_stream</a> <a href="Request/index.html#type-t">Request.t</a></span> <span>&#45;&gt;</span> <a href="Response/index.html#type-t">Response.t</a>, <span class="type-var">'a</span> <span>&#45;&gt;</span> <span class="type-var">'d</span>, <span class="type-var">'d</span>)</span> Stdlib.format6</span> <span>&#45;&gt;</span> <span class="type-var">'c</span> <span>&#45;&gt;</span> unit</code></dt><dd><p>Similar to <a href="index.html#val-add_path_handler"><code>add_path_handler</code></a>, but where the body of the request is a stream of bytes that has not been read yet. This is useful when one wants to stream the body directly into a parser, json decoder (such as <code>Jsonm</code>) or into a file.</p><dl><dt>since</dt><dd>0.3</dd></dl></dd></dl></section><section><header><h3 id="server-sent-events"><a href="#server-sent-events" class="anchor"></a>Server-sent events</h3><p><b>EXPERIMENTAL</b>: this API is not stable yet.</p></header><dl><dt class="spec module-type" id="module-type-SERVER_SENT_GENERATOR"><a href="#module-type-SERVER_SENT_GENERATOR" class="anchor"></a><code><span class="keyword">module</span> <span class="keyword">type</span> <a href="module-type-SERVER_SENT_GENERATOR/index.html">SERVER_SENT_GENERATOR</a> = <span class="keyword">sig</span> ... <span class="keyword">end</span></code></dt><dd><p>A server-side function to generate of Server-sent events.</p></dd></dl><dl><dt class="spec type" id="type-server_sent_generator"><a href="#type-server_sent_generator" class="anchor"></a><code><span class="keyword">type</span> server_sent_generator</code><code> = <span>(<span class="keyword">module</span> <a href="module-type-SERVER_SENT_GENERATOR/index.html">SERVER_SENT_GENERATOR</a>)</span></code></dt><dd><p>Server-sent event generator</p><dl><dt>since</dt><dd>0.9</dd></dl></dd></dl><dl><dt class="spec value" id="val-add_route_server_sent_handler"><a href="#val-add_route_server_sent_handler" class="anchor"></a><code><span class="keyword">val</span> add_route_server_sent_handler : <span>?&#8288;accept:<span>(<span>unit <a href="Request/index.html#type-t">Request.t</a></span> <span>&#45;&gt;</span> <span><span>(unit, <a href="Response_code/index.html#type-t">Response_code.t</a> * string)</span> Stdlib.result</span>)</span></span> <span>&#45;&gt;</span> <a href="index.html#type-t">t</a> <span>&#45;&gt;</span> <span><span>(<span class="type-var">'a</span>, <span>string <a href="Request/index.html#type-t">Request.t</a></span> <span>&#45;&gt;</span> <a href="index.html#type-server_sent_generator">server_sent_generator</a> <span>&#45;&gt;</span> unit)</span> <a href="Route/index.html#type-t">Route.t</a></span> <span>&#45;&gt;</span> <span class="type-var">'a</span> <span>&#45;&gt;</span> unit</code></dt><dd><p>Add a handler on an endpoint, that serves server-sent events.</p><p>The callback is given a generator that can be used to send events as it pleases. The connection is always closed by the client, and the accepted method is always <code>GET</code>. This will set the header &quot;content-type&quot; to &quot;text/event-stream&quot; automatically and reply with a 200 immediately. See <a href="index.html#type-server_sent_generator"><code>server_sent_generator</code></a> for more details.</p><p>This handler stays on the original thread (it is synchronous).</p><dl><dt>since</dt><dd>0.9</dd></dl></dd></dl></section><section><header><h3 id="run-the-server"><a href="#run-the-server" class="anchor"></a>Run the server</h3></header><dl><dt class="spec value" id="val-stop"><a href="#val-stop" class="anchor"></a><code><span class="keyword">val</span> stop : <a href="index.html#type-t">t</a> <span>&#45;&gt;</span> unit</code></dt><dd><p>Ask the server to stop. This might not have an immediate effect as <a href="index.html#val-run"><code>run</code></a> might currently be waiting on IO.</p></dd></dl><dl><dt class="spec value" id="val-run"><a href="#val-run" class="anchor"></a><code><span class="keyword">val</span> run : <a href="index.html#type-t">t</a> <span>&#45;&gt;</span> <span><span>(unit, exn)</span> Stdlib.result</span></code></dt><dd><p>Run the main loop of the server, listening on a socket described at the server's creation time, using <code>new_thread</code> to start a thread for each new client.</p><p>This returns <code>Ok ()</code> if the server exits gracefully, or <code>Error e</code> if it exits with an error.</p></dd></dl></section></div></body></html>