blob: e692413244463b5695d1b1de9186abc1226de4b5 [file] [log] [blame] [raw]
<!DOCTYPE html><html><head><meta charset="utf-8" /><meta content="IE=edge" http-equiv="X-UA-Compatible" /><meta content="width=device-width, initial-scale=1, maximum-scale=2.0, user-scalable=yes, minimal-ui=yes" name="viewport" /><title>facil.io - 0.7.x HTTP / WebSockets Server Documentation</title><meta content="facil.io - 0.7.x HTTP / WebSockets Server Documentation" name="description" /><link href="https://fonts.googleapis.com/css?family=Montserrat|Quicksand|Karla" rel="stylesheet" type="text/css" /><script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script><link href="/assets/styles/main.css" rel="stylesheet" type="text/css" /><script type="application/ld+json">{"@context":"http://schema.org","@type":"WebSite","url":"http://facil.io","name":"facil.io","description":"facil.io - a light web application framework in C, with support for HTTP, WebSockets and Pub/Sub out of the box.","keywords":"C, web, framework, websockets, websocket, realtime, real-time, easy","image":"http://facil.io/website/logo/facil-io.svg","author":[{"@type":"Person","name":"Bo (Myst)","url":"http://stackoverflow.com/users/4025095/myst","email":"bo(at)facil.io"}],"sourceOrganization":{"@context":"http://schema.org","@type":"Organization","name":"Plezi","url":"http://facil.io","description":"facil.io - a light web application framework in C, with support for HTTP, WebSockets and Pub/Sub out of the box.","logo":"http://facil.io/website/logo/facil-io.svg","image":"http://facil.io/website/logo/facil-io.svg","email":"bo(at)facil.io","member":[{"@type":"Person","name":"Bo (Myst)","url":"http://stackoverflow.com/users/4025095/myst","email":"bo(at)facil.io"}]}}</script><meta content="facil.io" name="apple-mobile-web-app-title" /><meta content="facil.io - the C Web Application Framework" name="application-name" /><meta content="#b91d47" name="msapplication-TileColor" /><meta content="/mstile-144x144.png" name="msapplication-TileImage" /><meta content="#ffffff" name="theme-color" /></head><body><a href="/" id="logo"></a><input id="show_nav" type="checkbox" /><nav id="top_nav"><ul><li><a href="/0.7.x/index">Latest Docs</a></li><li><a href="https://github.com/boazsegev/facil.io" target="_blank">Source Code</a></li><li><a href="javascript: change_themes();" id="theme">Night Theme</a></li></ul></nav><input id="show_sidebar" type="checkbox" /><nav id="side_bar"><h2 id="version-0-7-x"><a href="/0.7.x/index">Version 0.7.x</a></h2>
<h3 id="core-library"><a href="/0.7.x/fio">Core Library</a></h3>
<ul>
<li><a href="/0.7.x/fio#connection-protocol-management">Protocol Management</a></li>
<li><a href="/0.7.x/fio#running-facil-io">Running the IO reactor</a></li>
<li><a href="/0.7.x/fio#socket-connection-functions">Connection Functions</a></li>
<li><a href="/0.7.x/fio#event-task-scheduling">Event / Task Scheduling</a></li>
<li><a href="/0.7.x/fio#pub-sub-services">Pub/Sub Services</a></li>
<li><a href="/0.7.x/fio#the-custom-memory-allocator">Memory Allocation</a></li>
<li><a href="/0.7.x/fio#general-helpers">General Helpers</a></li>
<li><a href="/0.7.x/fio#linked-lists">Linked Lists</a></li>
<li><a href="/0.7.x/fio#string-helpers">String Helpers</a></li>
<li><a href="/0.7.x/fio#hash-maps-sets">Hash Maps / Sets</a></li>
<li><a href="/0.7.x/fio#version-and-compilation-related-macros">Compilation Macros</a></li>
<li><a href="/0.7.x/fio#weak-functions">Weak Functions</a></li>
</ul>
<h3 id="extensions"><a href="/0.7.x/extensions">Extensions</a></h3>
<ul>
<li><a href="/0.7.x/http">HTTP / WebSockets</a></li>
<li><a href="/0.7.x/redis">Redis (client)</a></li>
<li><a href="/0.7.x/fio_cli">CLI (command line)</a></li>
</ul>
<h3 id="the-fiobj-types"><a href="/0.7.x/fiobj">The FIOBJ types</a></h3>
<ul>
<li><a href="/0.7.x/fiobj_core">Core Functions</a></li>
<li><a href="/0.7.x/fiobj_primitives">Primitives</a></li>
<li><a href="/0.7.x/fiobj_numbers">Numbers</a></li>
<li><a href="/0.7.x/fiobj_str">Strings</a></li>
<li><a href="/0.7.x/fiobj_ary">Array</a></li>
<li><a href="/0.7.x/fiobj_hash">HashMap</a></li>
<li><a href="/0.7.x/fiobj_data">Data Streams</a></li>
<li><a href="/0.7.x/fiobj_json">JSON</a></li>
</ul>
</nav><div id="md_container"><div class='toc'><ul>
<li>
<a href="#facil-io-0-7-x-http-websockets-server-documentation">facil.io - 0.7.x HTTP / WebSockets Server Documentation</a>
<ul>
<li>
<a href="#listening-to-http-connections">Listening to HTTP Connections</a>
<ul>
<li>
<ul>
<li>
<a href="#http_listen"><code>http_listen</code></a>
</li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#connecting-to-http-as-a-client">Connecting to HTTP as a Client</a>
<ul>
<li>
<ul>
<li>
<a href="#http_connect"><code>http_connect</code></a>
</li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#the-http-data-handle-request-response">The HTTP Data Handle (Request / Response)</a>
<ul>
<li>
<a href="#http-handle-data-access">HTTP Handle Data Access</a>
<ul>
<li>
<a href="#h-received_at"><code>h-&gt;received_at</code></a>
</li>
<li>
<a href="#h-method"><code>h-&gt;method</code></a>
</li>
<li>
<a href="#h-status"><code>h-&gt;status</code></a>
</li>
<li>
<a href="#h-status_str"><code>h-&gt;status_str</code></a>
</li>
<li>
<a href="#h-version"><code>h-&gt;version</code></a>
</li>
<li>
<a href="#h-path"><code>h-&gt;path</code></a>
</li>
<li>
<a href="#h-query"><code>h-&gt;query</code></a>
</li>
<li>
<a href="#h-headers"><code>h-&gt;headers</code></a>
</li>
<li>
<a href="#h-cookies"><code>h-&gt;cookies</code></a>
</li>
<li>
<a href="#h-params"><code>h-&gt;params</code></a>
</li>
<li>
<a href="#h-body"><code>h-&gt;body</code></a>
</li>
<li>
<a href="#h-udata"><code>h-&gt;udata</code></a>
</li>
<li>
<a href="#h-private_data"><code>h-&gt;private_data</code></a>
</li>
</ul>
</li>
<li>
<a href="#connection-information">Connection Information</a>
<ul>
<li>
<a href="#http_settings"><code>http_settings</code></a>
</li>
<li>
<a href="#http_peer_addr"><code>http_peer_addr</code></a>
</li>
</ul>
</li>
<li>
<a href="#setting-headers-and-cookies">Setting Headers and Cookies</a>
<ul>
<li>
<a href="#http_set_header"><code>http_set_header</code></a>
</li>
<li>
<a href="#http_set_header2"><code>http_set_header2</code></a>
</li>
<li>
<a href="#http_set_cookie"><code>http_set_cookie</code></a>
</li>
</ul>
</li>
<li>
<a href="#sending-a-response-request">Sending a Response / Request</a>
<ul>
<li>
<a href="#http_finish"><code>http_finish</code></a>
</li>
<li>
<a href="#http_send_body"><code>http_send_body</code></a>
</li>
<li>
<a href="#http_sendfile"><code>http_sendfile</code></a>
</li>
<li>
<a href="#http_sendfile2"><code>http_sendfile2</code></a>
</li>
<li>
<a href="#http_send_error"><code>http_send_error</code></a>
</li>
</ul>
</li>
<li>
<a href="#push-promise-future-http-2-support">Push Promise (future HTTP/2 support)</a>
<ul>
<li>
<a href="#http_push_data"><code>http_push_data</code></a>
</li>
<li>
<a href="#http_push_file"><code>http_push_file</code></a>
</li>
</ul>
</li>
<li>
<a href="#rescheduling-the-http-event">Rescheduling the HTTP event</a>
<ul>
<li>
<a href="#http_pause"><code>http_pause</code></a>
</li>
<li>
<a href="#http_resume"><code>http_resume</code></a>
</li>
<li>
<a href="#http_paused_udata_get"><code>http_paused_udata_get</code></a>
</li>
<li>
<a href="#http_paused_udata_set"><code>http_paused_udata_set</code></a>
</li>
</ul>
</li>
<li>
<a href="#deeper-http-data-parsing">Deeper HTTP Data Parsing</a>
<ul>
<li>
<a href="#http_parse_body"><code>http_parse_body</code></a>
</li>
<li>
<a href="#http_parse_query"><code>http_parse_query</code></a>
</li>
<li>
<a href="#http_parse_cookies"><code>http_parse_cookies</code></a>
</li>
<li>
<a href="#http_add2hash"><code>http_add2hash</code></a>
</li>
<li>
<a href="#http_add2hash2"><code>http_add2hash2</code></a>
</li>
</ul>
</li>
<li>
<a href="#miscellaneous-http-helpers">Miscellaneous HTTP Helpers</a>
<ul>
<li>
<a href="#http_status2str"><code>http_status2str</code></a>
</li>
<li>
<a href="#http_hijack"><code>http_hijack</code></a>
</li>
<li>
<a href="#http_req2str"><code>http_req2str</code></a>
</li>
<li>
<a href="#http_write_log"><code>http_write_log</code></a>
</li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#websockets">WebSockets</a>
<ul>
<li>
<a href="#websocket-upgrade-from-http-server">WebSocket Upgrade From HTTP (Server)</a>
<ul>
<li>
<a href="#http_upgrade2ws"><code>http_upgrade2ws</code></a>
</li>
</ul>
</li>
<li>
<a href="#websocket-connections-client">WebSocket Connections (Client)</a>
<ul>
<li>
<a href="#websocket_connect"><code>websocket_connect</code></a>
</li>
</ul>
</li>
<li>
<a href="#websocket-connection-management-write-close">WebSocket Connection Management (write / close)</a>
<ul>
<li>
<a href="#websocket_write"><code>websocket_write</code></a>
</li>
<li>
<a href="#websocket_close"><code>websocket_close</code></a>
</li>
</ul>
</li>
<li>
<a href="#websocket-pub-sub">WebSocket Pub/Sub</a>
<ul>
<li>
<a href="#websocket_subscribe"><code>websocket_subscribe</code></a>
</li>
<li>
<a href="#websocket_unsubscribe"><code>websocket_unsubscribe</code></a>
</li>
<li>
<a href="#websocket_optimize4broadcasts"><code>websocket_optimize4broadcasts</code></a>
</li>
</ul>
</li>
<li>
<a href="#websocket-data">WebSocket Data</a>
<ul>
<li>
<a href="#websocket_udata_get"><code>websocket_udata_get</code></a>
</li>
<li>
<a href="#websocket_udata_set"><code>websocket_udata_set</code></a>
</li>
<li>
<a href="#websocket_uuid"><code>websocket_uuid</code></a>
</li>
<li>
<a href="#websocket_is_client"><code>websocket_is_client</code></a>
</li>
</ul>
</li>
<li>
<a href="#websocket-helpers">WebSocket Helpers</a>
<ul>
<li>
<a href="#websocket_attach"><code>websocket_attach</code></a>
</li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#eventsource-server-sent-events-sse">EventSource / Server Sent Events (SSE)</a>
<ul>
<li>
<a href="#eventsource-sse-connection-management">EventSource (SSE) Connection Management</a>
<ul>
<li>
<a href="#http_upgrade2sse"><code>http_upgrade2sse</code></a>
</li>
<li>
<a href="#http_sse_set_timout"><code>http_sse_set_timout</code></a>
</li>
<li>
<a href="#http_sse_close"><code>http_sse_close</code></a>
</li>
</ul>
</li>
<li>
<a href="#eventsource-sse-pub-sub">EventSource (SSE) Pub/Sub</a>
<ul>
<li>
<a href="#http_sse_subscribe"><code>http_sse_subscribe</code></a>
</li>
<li>
<a href="#http_sse_unsubscribe"><code>http_sse_unsubscribe</code></a>
</li>
</ul>
</li>
<li>
<a href="#writing-to-the-eventsource-sse-connection">Writing to the EventSource (SSE) Connection</a>
<ul>
<li>
<a href="#http_sse_write"><code>http_sse_write</code></a>
</li>
</ul>
</li>
<li>
<a href="#eventsource-sse-helpers">EventSource (SSE) Helpers</a>
<ul>
<li>
<a href="#http_sse2uuid"><code>http_sse2uuid</code></a>
</li>
<li>
<a href="#http_sse_dup"><code>http_sse_dup</code></a>
</li>
<li>
<a href="#http_sse_free"><code>http_sse_free</code></a>
</li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#miscellaneous">Miscellaneous</a>
<ul>
<li>
<a href="#mime-type-helpers">Mime-Type helpers</a>
<ul>
<li>
<a href="#http_mimetype_register"><code>http_mimetype_register</code></a>
</li>
<li>
<a href="#http_mimetype_find"><code>http_mimetype_find</code></a>
</li>
<li>
<a href="#http_mimetype_find2"><code>http_mimetype_find2</code></a>
</li>
<li>
<a href="#http_mimetype_clear"><code>http_mimetype_clear</code></a>
</li>
</ul>
</li>
<li>
<a href="#time-date-helpers">Time / Date Helpers</a>
<ul>
<li>
<a href="#http_gmtime"><code>http_gmtime</code></a>
</li>
<li>
<a href="#http_date2str"><code>http_date2str</code></a>
</li>
<li>
<a href="#http_date2rfc2109"><code>http_date2rfc2109</code></a>
</li>
<li>
<a href="#http_date2rfc2822"><code>http_date2rfc2822</code></a>
</li>
<li>
<a href="#http_time2str"><code>http_time2str</code></a>
</li>
</ul>
</li>
<li>
<a href="#url-parsing">URL Parsing</a>
<ul>
<li>
<a href="#http_url_parse"><code>http_url_parse</code></a>
</li>
</ul>
</li>
<li>
<a href="#url-string-decoding">URL String Decoding</a>
<ul>
<li>
<a href="#http_decode_url_unsafe"><code>http_decode_url_unsafe</code></a>
</li>
<li>
<a href="#http_decode_url"><code>http_decode_url</code></a>
</li>
<li>
<a href="#http_decode_path_unsafe"><code>http_decode_path_unsafe</code></a>
</li>
<li>
<a href="#http_decode_path"><code>http_decode_path</code></a>
</li>
</ul>
</li>
<li>
<a href="#commonly-used-header-constants">Commonly Used Header Constants</a>
<ul>
<li>
<a href="#http_header_accept"><code>HTTP_HEADER_ACCEPT</code></a>
</li>
<li>
<a href="#http_header_cache_control"><code>HTTP_HEADER_CACHE_CONTROL</code></a>
</li>
<li>
<a href="#http_header_connection"><code>HTTP_HEADER_CONNECTION</code></a>
</li>
<li>
<a href="#http_header_content_encoding"><code>HTTP_HEADER_CONTENT_ENCODING</code></a>
</li>
<li>
<a href="#http_header_content_length"><code>HTTP_HEADER_CONTENT_LENGTH</code></a>
</li>
<li>
<a href="#http_header_content_range"><code>HTTP_HEADER_CONTENT_RANGE</code></a>
</li>
<li>
<a href="#http_header_content_type"><code>HTTP_HEADER_CONTENT_TYPE</code></a>
</li>
<li>
<a href="#http_header_cookie"><code>HTTP_HEADER_COOKIE</code></a>
</li>
<li>
<a href="#http_header_date"><code>HTTP_HEADER_DATE</code></a>
</li>
<li>
<a href="#http_header_etag"><code>HTTP_HEADER_ETAG</code></a>
</li>
<li>
<a href="#http_header_host"><code>HTTP_HEADER_HOST</code></a>
</li>
<li>
<a href="#http_header_last_modified"><code>HTTP_HEADER_LAST_MODIFIED</code></a>
</li>
<li>
<a href="#http_header_origin"><code>HTTP_HEADER_ORIGIN</code></a>
</li>
<li>
<a href="#http_header_set_cookie"><code>HTTP_HEADER_SET_COOKIE</code></a>
</li>
<li>
<a href="#http_header_upgrade"><code>HTTP_HEADER_UPGRADE</code></a>
</li>
</ul>
</li>
<li>
<a href="#compile-time-settings">Compile Time Settings</a>
<ul>
<li>
<a href="#http_busy_unless_has_fds"><code>HTTP_BUSY_UNLESS_HAS_FDS</code></a>
</li>
<li>
<a href="#http_default_body_limit"><code>HTTP_DEFAULT_BODY_LIMIT</code></a>
</li>
<li>
<a href="#http_max_header_count"><code>HTTP_MAX_HEADER_COUNT</code></a>
</li>
<li>
<a href="#http_max_header_length"><code>HTTP_MAX_HEADER_LENGTH</code></a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div><h1 id="facil-io-0-7-x-http-websockets-server-documentation">facil.io - 0.7.x HTTP / WebSockets Server Documentation</h1>
<p>facil.io includes an HTTP/1.1 and WebSocket server / framework that could be used to author HTTP and WebSocket services, including REST applications, micro-services, etc&#39;.</p>
<p>Note that, currently, only HTTP/1.1 is supported. Support for HTTP/2 is planned for future versions and could be implemented as a custom protocol until such time.</p>
<h2 id="listening-to-http-connections">Listening to HTTP Connections</h2>
<h4 id="http_listen"><code>http_listen</code></h4>
<pre><code class='highlight'><span class="kt">intptr_t</span> <span class="n">http_listen</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">port</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">binding</span><span class="p">,</span>
<span class="k">struct</span> <span class="n">http_settings_s</span><span class="p">);</span>
<span class="n">Listens</span> <span class="n">to</span> <span class="n">HTTP</span> <span class="n">connections</span> <span class="n">at</span> <span class="n">the</span> <span class="n">specified</span> <span class="err">`</span><span class="n">port</span><span class="err">`</span> <span class="n">and</span> <span class="err">`</span><span class="n">binding</span><span class="err">`</span><span class="p">.</span>
<span class="cp">#define http_listen(port, binding, ...) \
http_listen((port), (binding), (struct http_settings_s){__VA_ARGS__})
</span></code></pre>
<p>The <code>http_listen</code> function is shadowed by the <code>http_listen</code> MACRO, which allows the function to accept &quot;named arguments&quot;, i.e.:</p>
<pre><code class='highlight'><span class="cm">/* Assuming we defined the HTTP request handler: */</span>
<span class="k">static</span> <span class="kt">void</span> <span class="n">on_http_request</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">);</span>
<span class="c1">// ... </span>
<span class="k">if</span> <span class="p">(</span><span class="n">http_listen</span><span class="p">(</span><span class="s">"3000"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span>
<span class="p">.</span><span class="n">on_request</span> <span class="o">=</span> <span class="n">on_http_request</span><span class="p">,</span>
<span class="p">.</span><span class="n">public_folder</span> <span class="o">=</span> <span class="s">"www"</span> <span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
<span class="n">perror</span><span class="p">(</span><span class="s">"No listening socket available on port 3000"</span><span class="p">);</span>
<span class="n">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
</code></pre>
<p>In addition to the <code>port</code> and <code>address</code> argument (explained in <a href="fio#fio_listen"><code>fio_listen</code></a>), the following arguments are supported:</p>
<ul>
<li><p><code>on_request</code>:</p>
<p>Callback for normal HTTP requests.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_request</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">request</span><span class="p">);</span>
</code></pre></li>
<li><p><code>on_request</code>:</p>
<p>Callback for Upgrade and EventSource (SSE) requests.</p>
<p>Server Sent Events (SSE) / EventSource requests set the <code>requested_protocol</code> string to <code>&quot;sse&quot;</code>. Other protocols (i.e., WebSockets) are represented exactly the same was as the client requested them (be aware or lower case vs. capitalized representations).</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_upgrade</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">request</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">requested_protocol</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">len</span><span class="p">);</span>
</code></pre></li>
<li><p><code>on_request</code>:</p>
<p>This callback is ignored for HTTP server mode and is only called when a response (not a request) is received. On server connections, this would normally indicate a protocol error.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_response</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">response</span><span class="p">);</span>
</code></pre></li>
<li><p><code>on_finish</code>:</p>
<p>This (optional) callback will be called when the HTTP service closes. The <code>setting</code> pointer will point to the named arguments passed to the <code>http_listen</code> function.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_finish</span><span class="p">(</span><span class="k">struct</span> <span class="n">http_settings_s</span> <span class="o">*</span><span class="n">settings</span><span class="p">);</span>
</code></pre></li>
<li><p><code>udata</code>:</p>
<p>Opaque user data. facil.io will ignore this field, but you can use it.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">;</span>
</code></pre></li>
<li><p><code>public_folder</code>:</p>
<p>A public folder for file transfers - allows to circumvent any application layer logic and simply serve static files.</p>
<p>The static file service supports automatic <code>gz</code> pre-compressed file alternatives.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">public_folder</span><span class="p">;</span>
</code></pre></li>
<li><p><code>public_folder_length</code>:</p>
<p>The length of the public_folder string.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">size_t</span> <span class="n">public_folder_length</span><span class="p">;</span>
</code></pre></li>
<li><p><code>max_header_size</code>:</p>
<p>The maximum number of bytes allowed for the request string (method, path, query), header names and fields.</p>
<p>Defaults to 32Kib (which is about 4 times more than I would recommend).</p>
<p>This reflects the total overall size. On HTTP/1.1, each header line (name + value pair) is also limited to a hard-coded HTTP_MAX_HEADER_LENGTH bytes.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">size_t</span> <span class="n">max_header_size</span><span class="p">;</span>
</code></pre></li>
<li><p><code>max_body_size</code>:</p>
<p>The maximum size, in bytes, for an HTTP request&#39;s body (posting / downloading).</p>
<p>Defaults to 50Mb (1024 * 1024 * 50).</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">size_t</span> <span class="n">max_body_size</span><span class="p">;</span>
</code></pre></li>
<li><p><code>max_clients</code>:</p>
<p>The maximum number of clients that are allowed to connect concurrently. This value&#39;s default setting is usually for the best.</p>
<p>The default value is computed according to the server&#39;s capacity, leaving some breathing room for other network and disk operations.</p>
<p>Note: clients, by the nature of socket programming, are counted according to their internal file descriptor (<code>fd</code>) value. Open files and other sockets count towards a server&#39;s limit.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">intptr_t</span> <span class="n">max_clients</span><span class="p">;</span>
</code></pre></li>
<li><p><code>ws_max_msg_size</code>:</p>
<p>The maximum WebSocket message size/buffer (in bytes) for WebSocket connections. Defaults to 250KB (250 * 1024).</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">size_t</span> <span class="n">ws_max_msg_size</span><span class="p">;</span>
</code></pre></li>
<li><p><code>timeout</code>:</p>
<p>The maximum WebSocket message size/buffer (in bytes) for WebSocket connections. Defaults to 250KB (250 * 1024).</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">uint8_t</span> <span class="n">timeout</span><span class="p">;</span>
</code></pre></li>
<li><p><code>ws_timeout</code>:</p>
<p>Timeout for the WebSocket connections, a ping will be sent whenever the timeout is reached.</p>
<p>Defaults to 40 seconds.</p>
<p>Connections are only closed when a ping cannot be sent (the network layer fails). Pongs are ignored.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">uint8_t</span> <span class="n">ws_timeout</span><span class="p">;</span>
</code></pre></li>
<li><p><code>log</code>:</p>
<p>Logging flag - set to TRUE to log HTTP requests.</p>
<p>Defaults to 0 (false).</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">uint8_t</span> <span class="n">log</span><span class="p">;</span>
</code></pre></li>
<li><p><code>is_client</code>:</p>
<p>A read only flag set automatically to indicate the protocol&#39;s mode.</p>
<p>This is ignored by the <code>http_listen</code> function but can be accessed through the <code>on_finish</code> callback and the <a href="#http_settings"><code>http_settings</code></a> function.</p></li>
<li><p><code>reserved*</code>:</p>
<p>Reserved for future use.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">intptr_t</span> <span class="n">reserved1</span><span class="p">;</span>
<span class="kt">intptr_t</span> <span class="n">reserved2</span><span class="p">;</span>
<span class="kt">intptr_t</span> <span class="n">reserved3</span><span class="p">;</span>
<span class="kt">intptr_t</span> <span class="n">reserved4</span><span class="p">;</span>
</code></pre></li>
</ul>
<p>Returns -1 on error and the socket&#39;s <code>uuid</code> on success.</p>
<p>The <code>on_finish</code> callback is always called (even on errors).</p>
<h2 id="connecting-to-http-as-a-client">Connecting to HTTP as a Client</h2>
<h4 id="http_connect"><code>http_connect</code></h4>
<pre><code class='highlight'><span class="kt">intptr_t</span> <span class="n">http_connect</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">address</span><span class="p">,</span> <span class="k">struct</span> <span class="n">http_settings_s</span><span class="p">);</span>
<span class="cp">#define http_connect(address, ...) \
http_connect((address), (struct http_settings_s){__VA_ARGS__})
</span></code></pre>
<p>Connects to an HTTP server as a client.</p>
<p>This function accepts the same arguments as the <a href="#http_listen"><code>http_listen</code></a> function (though some of hem will not be relevant for a client connection).</p>
<p>Upon a successful connection, the <code>on_response</code> callback is called with an empty <code>http_s*</code> handler (status == 0).</p>
<p>Use the HTTP Handler API to set it&#39;s content and send the request to the server. The second time the <code>on_response</code> function is called, the <code>http_s</code> handle will contain the actual response.</p>
<p>The <code>address</code> argument should contain a full URL style address for the server. i.e.:</p>
<pre><code class='highlight'> <span class="s">"http:/www.example.com:8080/"</span>
</code></pre>
<p>If an <code>address</code> includes a path or query data, they will be automatically attached (both of them) to the HTTP handle&#39;s <code>path</code> property. i.e.</p>
<pre><code class='highlight'> <span class="s">"http:/www.example.com:8080/my_path?foo=bar"</span>
<span class="c1">// will result in:</span>
<span class="n">fiobj_obj2cstr</span><span class="p">(</span><span class="n">h</span><span class="o">-&gt;</span><span class="n">path</span><span class="p">).</span><span class="n">data</span><span class="p">;</span> <span class="c1">//=&gt; "/my_path?foo=bar"</span>
</code></pre>
<p>To open a WebSocket connection, it&#39;s possible to use the <code>ws</code> protocol signature. However, it would be better to use the <a href="#websocket_connect"><code>websocket_connect</code></a> function instead.</p>
<p>Returns -1 on error and the socket&#39;s uuid on success.</p>
<p>The <code>on_finish</code> callback is always called.</p>
<h2 id="the-http-data-handle-request-response">The HTTP Data Handle (Request / Response)</h2>
<p>HTTP request and response data is manages using the <code>http_s</code> structure type, which is defined as follows:</p>
<pre><code class='highlight'><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
<span class="k">struct</span> <span class="p">{</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">vtbl</span><span class="p">;</span>
<span class="kt">uintptr_t</span> <span class="n">flag</span><span class="p">;</span>
<span class="n">FIOBJ</span> <span class="n">out_headers</span><span class="p">;</span>
<span class="p">}</span> <span class="n">private_data</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">timespec</span> <span class="n">received_at</span><span class="p">;</span>
<span class="n">FIOBJ</span> <span class="n">method</span><span class="p">;</span>
<span class="n">FIOBJ</span> <span class="n">status_str</span><span class="p">;</span>
<span class="n">FIOBJ</span> <span class="n">version</span><span class="p">;</span>
<span class="kt">uintptr_t</span> <span class="n">status</span><span class="p">;</span>
<span class="n">FIOBJ</span> <span class="n">path</span><span class="p">;</span>
<span class="n">FIOBJ</span> <span class="n">query</span><span class="p">;</span>
<span class="n">FIOBJ</span> <span class="n">headers</span><span class="p">;</span>
<span class="n">FIOBJ</span> <span class="n">cookies</span><span class="p">;</span>
<span class="n">FIOBJ</span> <span class="n">params</span><span class="p">;</span>
<span class="n">FIOBJ</span> <span class="n">body</span><span class="p">;</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">;</span>
<span class="p">}</span> <span class="n">http_s</span><span class="p">;</span>
</code></pre>
<p>The <code>http_s</code> data in NOT thread safe and can only be accessed safely from within the HTTP callbacks (<code>on_request</code>, <code>on_response</code> and the <code>http_defer</code> callback)</p>
<h3 id="http-handle-data-access">HTTP Handle Data Access</h3>
<p>HTTP data can be accessed using the HTTP handle structure fields.</p>
<p>For example:</p>
<pre><code class='highlight'><span class="cm">/* Collects a temporary reference to the Host header. Don't free the reference.*/</span>
<span class="n">FIOBJ</span> <span class="n">host</span> <span class="o">=</span> <span class="n">fiobj_hash_get</span><span class="p">(</span><span class="n">h</span><span class="o">-&gt;</span><span class="n">headers</span><span class="p">,</span> <span class="n">HTTP_HEADER_HOST</span><span class="p">);</span>
</code></pre>
<h4 id="h-received_at"><code>h-&gt;received_at</code></h4>
<pre><code class='highlight'><span class="k">struct</span> <span class="n">timespec</span> <span class="n">received_at</span><span class="p">;</span>
</code></pre>
<p>A time merker indicating when the request was received. </p>
<h4 id="h-method"><code>h-&gt;method</code></h4>
<pre><code class='highlight'><span class="n">FIOBJ</span> <span class="n">method</span><span class="p">;</span>
</code></pre>
<p>A <a href="fiobj_str">FIOBJ String</a> containing the HTTP method string.</p>
<p>facil.io accepts non-standard methods as well as the standard GET, PUT, POST, etc&#39; HTTP methods. </p>
<h4 id="h-status"><code>h-&gt;status</code></h4>
<pre><code class='highlight'><span class="kt">uintptr_t</span> <span class="n">status</span><span class="p">;</span>
</code></pre>
<p>The status used for the response (or if the object is a response).</p>
<p>When sending a request, the status should be set to 0.</p>
<h4 id="h-status_str"><code>h-&gt;status_str</code></h4>
<pre><code class='highlight'><span class="n">FIOBJ</span> <span class="n">status_str</span><span class="p">;</span>
</code></pre>
<p>A <a href="fiobj_str">FIOBJ String</a> containing the HTTP status string, for response objects (client mode response).</p>
<h4 id="h-version"><code>h-&gt;version</code></h4>
<pre><code class='highlight'><span class="n">FIOBJ</span> <span class="n">version</span><span class="p">;</span>
</code></pre>
<p>A <a href="fiobj_str">FIOBJ String</a> containing the HTTP version string, if any.</p>
<h4 id="h-path"><code>h-&gt;path</code></h4>
<pre><code class='highlight'><span class="n">FIOBJ</span> <span class="n">path</span><span class="p">;</span>
</code></pre>
<p>A <a href="fiobj_str">FIOBJ String</a> containing the request path string, if any.</p>
<h4 id="h-query"><code>h-&gt;query</code></h4>
<pre><code class='highlight'><span class="n">FIOBJ</span> <span class="n">query</span><span class="p">;</span>
</code></pre>
<p>A <a href="fiobj_str">FIOBJ String</a> containing the request query string, if any.</p>
<h4 id="h-headers"><code>h-&gt;headers</code></h4>
<pre><code class='highlight'><span class="n">FIOBJ</span> <span class="n">headers</span><span class="p">;</span>
</code></pre>
<p>A <a href="fiobj_hash">FIOBJ Hash Map</a> containing the received header data as either a <a href="fiobj_str">FIOBJ String</a> or an <a href="fiobj_ary">FIOBJ Array</a>.</p>
<p>When a header is received multiple times (such as cookie headers), an Array of Strings will be used instead of a single String.</p>
<h4 id="h-cookies"><code>h-&gt;cookies</code></h4>
<pre><code class='highlight'><span class="n">FIOBJ</span> <span class="n">cookies</span><span class="p">;</span>
</code></pre>
<p>A placeholder for a hash of cookie data.</p>
<p>The <a href="fiobj_hash">FIOBJ Hash Map</a> will be initialized when parsing the request using <a href="#http_parse_cookies"><code>http_parse_cookies</code></a>.</p>
<h4 id="h-params"><code>h-&gt;params</code></h4>
<pre><code class='highlight'><span class="n">FIOBJ</span> <span class="n">params</span><span class="p">;</span>
</code></pre>
<p>A placeholder for a hash of request data.</p>
<p>The <a href="fiobj_hash">FIOBJ Hash Map</a> will be initialized when parsing the request using <a href="#http_parse_body"><code>http_parse_body</code></a> and <a href="#http_parse_query"><code>http_parse_query</code></a>.</p>
<h4 id="h-body"><code>h-&gt;body</code></h4>
<pre><code class='highlight'><span class="n">FIOBJ</span> <span class="n">body</span><span class="p">;</span>
</code></pre>
<p>A <a href="fiobj_data">FIOBJ Data</a> reader for body data (might be a temporary file, a string or NULL).</p>
<h4 id="h-udata"><code>h-&gt;udata</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">;</span>
</code></pre>
<p>An opaque user data pointer, which can be used <strong>before</strong> calling <a href="#http_defer"><code>http_defer</code></a> in order to retain persistent application information across events.</p>
<h4 id="h-private_data"><code>h-&gt;private_data</code></h4>
<pre><code class='highlight'><span class="k">struct</span> <span class="p">{</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">vtbl</span><span class="p">;</span>
<span class="kt">uintptr_t</span> <span class="n">flag</span><span class="p">;</span>
<span class="n">FIOBJ</span> <span class="n">out_headers</span><span class="p">;</span>
<span class="p">}</span> <span class="n">private_data</span><span class="p">;</span>
</code></pre>
<p>Private data shouldn&#39;t be accessed directly. However, if you need to access the data, limit yourself to the <code>out_headers</code> field. The <code>vtbl</code> and <code>flag</code> should *<em>never</em> be altered as.</p>
<p>The out headers are set using the <a href="#http_set_header"><code>http_set_header</code></a>, <a href="#http_set_header2"><code>http_set_header2</code></a>, and <a href="#http_set_cookie"><code>http_set_cookie</code></a> functions.</p>
<p>Reading the outgoing headers is possible by directly accessing the <a href="fiobj_hash">Hash Map</a> data. However, writing data to the Hash should be avoided.</p>
<h3 id="connection-information">Connection Information</h3>
<h4 id="http_settings"><code>http_settings</code></h4>
<pre><code class='highlight'><span class="k">struct</span> <span class="n">http_settings_s</span> <span class="o">*</span><span class="n">http_settings</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">);</span>
</code></pre>
<p>Returns the settings used to setup the connection or NULL on error.</p>
<h4 id="http_peer_addr"><code>http_peer_addr</code></h4>
<pre><code class='highlight'><span class="n">fio_str_info_s</span> <span class="n">http_peer_addr</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">);</span>
</code></pre>
<p>Returns the direct address of the connected peer (most possibly an intermediary / proxy server).</p>
<p>NOTE: it is my hope that a future variation of this function will return a best guess at the actual client&#39;s address</p>
<h3 id="setting-headers-and-cookies">Setting Headers and Cookies</h3>
<h4 id="http_set_header"><code>http_set_header</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">http_set_header</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">,</span> <span class="n">FIOBJ</span> <span class="n">name</span><span class="p">,</span> <span class="n">FIOBJ</span> <span class="n">value</span><span class="p">);</span>
</code></pre>
<p>Sets an outgoing header, taking ownership of the value object, but NOT the name object (so name objects could be reused in future responses).</p>
<p>Returns -1 on error and 0 on success.</p>
<h4 id="http_set_header2"><code>http_set_header2</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">http_set_header2</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">,</span> <span class="n">fio_str_info_s</span> <span class="n">name</span><span class="p">,</span> <span class="n">fio_str_info_s</span> <span class="n">value</span><span class="p">);</span>
</code></pre>
<p>Sets an outgoing header, copying the data.</p>
<p>Returns -1 on error and 0 on success.</p>
<h4 id="http_set_cookie"><code>http_set_cookie</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">http_set_cookie</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">,</span> <span class="n">http_cookie_args_s</span><span class="p">);</span>
<span class="cp">#define http_set_cookie(http___handle, ...) \
http_set_cookie((http___handle), (http_cookie_args_s){__VA_ARGS__})
</span></code></pre>
<p>Sets an outgoing <strong>response</strong> cookie.</p>
<p>To set a <em>request</em> cookie, simply add the data to a header named <code>&quot;cookie&quot;</code>.</p>
<p>The <code>http_set_cookie</code> function is shadowed by the <code>http_set_cookie</code> MACRO, which allows the function to accept &quot;named arguments&quot;, i.e.:</p>
<pre><code class='highlight'><span class="n">http_set_cookie</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="s">"my_cookie"</span><span class="p">,</span> <span class="p">.</span><span class="n">value</span> <span class="o">=</span> <span class="s">"data"</span><span class="p">);</span>
</code></pre>
<p>In addition to the handle argument (<code>http_s *</code>), the following arguments are supported:</p>
<ul>
<li><p><code>name</code>:</p>
<p>The cookie&#39;s name (Symbol).</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">;</span>
</code></pre></li>
<li><p><code>value</code>:</p>
<p>The cookie&#39;s value. Leave the value blank (NULL) to delete cookie.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">value</span><span class="p">;</span>
</code></pre></li>
<li><p><code>domain</code>:</p>
<p>The cookie&#39;s domain (optional).</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">domain</span><span class="p">;</span>
</code></pre></li>
<li><p><code>path</code>:</p>
<p>The cookie&#39;s path (optional).</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">path</span><span class="p">;</span>
</code></pre></li>
<li><p><code>name_len</code>:</p>
<p>The cookie name&#39;s length in bytes or a terminating NUL will be assumed.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">size_t</span> <span class="n">name_len</span><span class="p">;</span>
</code></pre></li>
<li><p><code>value_len</code>:</p>
<p>The cookie value&#39;s length in bytes or a terminating NULL will be assumed.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">size_t</span> <span class="n">value_len</span><span class="p">;</span>
</code></pre></li>
<li><p><code>domain_len</code>:</p>
<p>The cookie domain&#39;s length in bytes or a terminating NULL will be assumed.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">size_t</span> <span class="n">domain_len</span><span class="p">;</span>
</code></pre></li>
<li><p><code>path_len</code>:</p>
<p>The cookie path&#39;s length in bytes or a terminating NULL will be assumed.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
</code></pre>
<p>size_t path_len;</p></li>
<li><p><code>max_age</code>:</p>
<p>Max Age (how long should the cookie persist), in seconds (0 == session).</p>
<pre><code class='highlight'><span class="c1">// type:</span>
</code></pre>
<p>int max_age;</p></li>
<li><p><code>secure</code>:</p>
<p>Limit cookie to secure connections.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
</code></pre>
<p>unsigned secure : 1;</p></li>
<li><p><code>path_len</code>:</p>
<p>Limit cookie to HTTP (intended to prevent JavaScript access/hijacking).</p>
<pre><code class='highlight'><span class="c1">// type:</span>
</code></pre>
<p>unsigned http_only : 1;</p></li>
</ul>
<p>Returns -1 on error and 0 on success.</p>
<p><strong>Note</strong>: Long cookie names and long cookie values will be considered a security violation and an error will be returned. It should be noted that most proxies and servers will refuse long cookie names or values and many impose total header lengths (including cookies) of ~8Kib.</p>
<h3 id="sending-a-response-request">Sending a Response / Request</h3>
<h4 id="http_finish"><code>http_finish</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="n">http_finish</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">);</span>
</code></pre>
<p>Sends the response headers for a header only response.</p>
<p><strong>Important</strong>: After this function is called, the <code>http_s</code> object is no longer valid.</p>
<h4 id="http_send_body"><code>http_send_body</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">http_send_body</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">uintptr_t</span> <span class="n">length</span><span class="p">);</span>
</code></pre>
<p>Sends the response headers and body.</p>
<p><strong>Note</strong>: The body is <em>copied</em> to the HTTP stream and it&#39;s memory should be
freed by the calling function.</p>
<p>Returns -1 on error and 0 on success.</p>
<p><strong>Important</strong>: After this function is called, the <code>http_s</code> object is no longer valid.</p>
<h4 id="http_sendfile"><code>http_sendfile</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">http_sendfile</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">,</span> <span class="kt">int</span> <span class="n">fd</span><span class="p">,</span> <span class="kt">uintptr_t</span> <span class="n">length</span><span class="p">,</span> <span class="kt">uintptr_t</span> <span class="n">offset</span><span class="p">);</span>
</code></pre>
<p>Sends the response headers and the specified file (the response&#39;s body).</p>
<p>The file is closed automatically.</p>
<p>Returns -1 on error and 0 on success.</p>
<p><strong>Important</strong>: After this function is called, the <code>http_s</code> object is no longer valid.</p>
<h4 id="http_sendfile2"><code>http_sendfile2</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">http_sendfile2</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">prefix</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">prefix_len</span><span class="p">,</span>
<span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">encoded</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">encoded_len</span><span class="p">);</span>
</code></pre>
<p>Sends the response headers and the specified file (the response&#39;s body).</p>
<p>The <code>local</code> and <code>encoded</code> strings will be joined into a single string that represent the file name. Either or both of these strings can be empty.</p>
<p>The <code>encoded</code> string will be URL decoded while the <code>local</code> string will used as is.</p>
<p>Returns 0 on success. A success value WILL CONSUME the <code>http_s</code> handle (it will become invalid).</p>
<p>Returns -1 on error (The <code>http_s</code> handle should still be used).</p>
<p><strong>Important</strong>: After this function is called, the <code>http_s</code> object is no longer valid.</p>
<h4 id="http_send_error"><code>http_send_error</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">http_send_error</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">error_code</span><span class="p">);</span>
</code></pre>
<p>Sends an HTTP error response.</p>
<p>Returns -1 on error and 0 on success.</p>
<p><strong>Important</strong>: After this function is called, the <code>http_s</code> object is no longer valid.</p>
<!-- The `uuid` and `settings` arguments are only required if the `http_s` handle is NULL. -->
<h3 id="push-promise-future-http-2-support">Push Promise (future HTTP/2 support)</h3>
<p><strong>Note</strong>: HTTP/2 isn&#39;t implemented yet and these functions will simply fail.</p>
<h4 id="http_push_data"><code>http_push_data</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">http_push_data</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">uintptr_t</span> <span class="n">length</span><span class="p">,</span> <span class="n">FIOBJ</span> <span class="n">mime_type</span><span class="p">);</span>
</code></pre>
<p>Pushes a data response when supported (HTTP/2 only).</p>
<p>Returns -1 on error and 0 on success.</p>
<h4 id="http_push_file"><code>http_push_file</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">http_push_file</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">,</span> <span class="n">FIOBJ</span> <span class="n">filename</span><span class="p">,</span> <span class="n">FIOBJ</span> <span class="n">mime_type</span><span class="p">);</span>
</code></pre>
<p>Pushes a file response when supported (HTTP/2 only).</p>
<p>If <code>mime_type</code> is NULL, an attempt at automatic detection using <code>filename</code> will be made.</p>
<p>Returns -1 on error and 0 on success.</p>
<h3 id="rescheduling-the-http-event">Rescheduling the HTTP event</h3>
<h4 id="http_pause"><code>http_pause</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="n">http_pause</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">,</span> <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">task</span><span class="p">)(</span><span class="n">http_pause_handle_s</span> <span class="o">*</span><span class="n">http</span><span class="p">));</span>
</code></pre>
<p>Pauses the request / response handling and INVALIDATES the current <code>http_s</code> handle (no <code>http</code> functions can be called).</p>
<p>The <code>http_resume</code> function MUST be called (at some point) using the opaque <code>http</code> pointer given to the callback <code>task</code>.</p>
<p>The opaque <code>http_pause_handle_s</code> pointer is only valid for a single call to <code>http_resume</code> and can&#39;t be used by any regular <code>http</code> function (it&#39;s a different data type).</p>
<p>Note: the current <code>http_s</code> handle will become invalid once this function is called and it&#39;s data might be deallocated, invalid or used by a different thread.</p>
<h4 id="http_resume"><code>http_resume</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="n">http_resume</span><span class="p">(</span><span class="n">http_pause_handle_s</span> <span class="o">*</span><span class="n">http</span><span class="p">,</span> <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">task</span><span class="p">)(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">),</span>
<span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">fallback</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">));</span>
</code></pre>
<p>Resumes a request / response handling within a task and INVALIDATES the current <code>http_s</code> handle.</p>
<p>The <code>task</code> MUST call one of the <code>http_send_*</code>, <code>http_finish</code>, or <code>http_pause</code>functions.</p>
<p>The (optional) <code>fallback</code> will receive the opaque <code>udata</code> that was stored in the HTTP handle and can be used for cleanup.</p>
<p>Note: <code>http_resume</code> can only be called after calling <code>http_pause</code> and entering it&#39;s task.</p>
<p>Note: the current <code>http_s</code> handle will become invalid once this function is called and it&#39;s data might be deallocated, invalidated or used by a different thread.</p>
<h4 id="http_paused_udata_get"><code>http_paused_udata_get</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="o">*</span><span class="n">http_paused_udata_get</span><span class="p">(</span><span class="n">http_pause_handle_s</span> <span class="o">*</span><span class="n">http</span><span class="p">);</span>
</code></pre>
<p>Returns the <code>udata</code> associated with the paused opaque handle </p>
<h4 id="http_paused_udata_set"><code>http_paused_udata_set</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="o">*</span><span class="n">http_paused_udata_set</span><span class="p">(</span><span class="n">http_pause_handle_s</span> <span class="o">*</span><span class="n">http</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">);</span>
</code></pre>
<p>Sets the <code>udata</code> associated with the paused opaque handle, returning the old value.</p>
<h3 id="deeper-http-data-parsing">Deeper HTTP Data Parsing</h3>
<p>The HTTP extension&#39;s initial HTTP parser parses the protocol, but not the HTTP data. This allows improved performance when parsing the data isn&#39;t necessary.</p>
<p>However, sometimes an application will want to parse a requests (or a response&#39;s) content, cookies or query parameters, converting it into a complex object.</p>
<p>This allows an application to convert a String data such as <code>&quot;user[name]=Joe&quot;</code> to a nested Hash Map, where the <code>params</code> Hash Map&#39;s key <code>user</code> maps to a nested Hash Map with the key <code>name</code> (and the value <code>&quot;Joe&quot;</code>, as described by <a href="#http_add2hash"><code>http_add2hash</code></a>)).</p>
<h4 id="http_parse_body"><code>http_parse_body</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">http_parse_body</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">);</span>
</code></pre>
<p>Attempts to decode the request&#39;s body using the <a href="#http_add2hash"><code>http_add2hash</code></a> scheme.</p>
<p>Supported body types include:</p>
<ul>
<li><p>application/x-www-form-urlencoded</p></li>
<li><p>application/json</p></li>
<li><p>multipart/form-data</p></li>
</ul>
<p>This should be called before <code>http_parse_query</code>, in order to support JSON data.</p>
<p>If the JSON data isn&#39;t an object, it will be saved under the key &quot;JSON&quot; in the <code>params</code> hash.</p>
<p>If the <code>multipart/form-data</code> type contains JSON files, they will NOT be parsed (they will behave like any other file, with <code>data</code>, <code>type</code> and <code>filename</code> keys assigned). This allows non-object JSON data (such as array) to be handled by the app.</p>
<h4 id="http_parse_query"><code>http_parse_query</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="n">http_parse_query</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">);</span>
</code></pre>
<p>Parses the query part of an HTTP request/response. Uses <a href="#http_add2hash"><code>http_add2hash</code></a>.</p>
<p>This should be called after the <code>http_parse_body</code> function, just in case the
body is a JSON object that doesn&#39;t have a Hash Map at it&#39;s root.</p>
<h4 id="http_parse_cookies"><code>http_parse_cookies</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="n">http_parse_cookies</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">,</span> <span class="kt">uint8_t</span> <span class="n">is_url_encoded</span><span class="p">);</span>
</code></pre>
<p>Parses any Cookie / Set-Cookie headers, using the <a href="#http_add2hash"><code>http_add2hash</code></a> scheme. </p>
<h4 id="http_add2hash"><code>http_add2hash</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">http_add2hash</span><span class="p">(</span><span class="n">FIOBJ</span> <span class="n">dest</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">name_len</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">value</span><span class="p">,</span>
<span class="kt">size_t</span> <span class="n">value_len</span><span class="p">,</span> <span class="kt">uint8_t</span> <span class="n">encoded</span><span class="p">);</span>
</code></pre>
<p>Adds a named parameter to the hash, converting a string to an object and resolving nesting references and URL decoding if required. i.e.:</p>
<ul>
<li><p>&quot;name[]&quot; references a nested Array (nested in the Hash).</p></li>
<li><p>&quot;name[key]&quot; references a nested Hash.</p></li>
<li><p>&quot;name[][key]&quot; references a nested Hash within an array. Hash keys will be unique (repeating a key advances the array).</p></li>
<li><p>These rules can be nested (i.e. &quot;name[][key1][][key2]...&quot;)</p></li>
<li><p>&quot;name[][]&quot; is an error (there&#39;s no way for the parser to analyze dimensions)</p></li>
</ul>
<p>Note: names can&#39;t begin with <code>&quot;[&quot;</code> or end with <code>&quot;]&quot;</code> as these are reserved characters.</p>
<h4 id="http_add2hash2"><code>http_add2hash2</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">http_add2hash2</span><span class="p">(</span><span class="n">FIOBJ</span> <span class="n">dest</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">name_len</span><span class="p">,</span> <span class="n">FIOBJ</span> <span class="n">value</span><span class="p">,</span>
<span class="kt">uint8_t</span> <span class="n">encoded</span><span class="p">);</span>
</code></pre>
<p>Same as <a href="#http_add2hash"><code>http_add2hash</code></a>, using an existing object.</p>
<h3 id="miscellaneous-http-helpers">Miscellaneous HTTP Helpers</h3>
<h4 id="http_status2str"><code>http_status2str</code></h4>
<pre><code class='highlight'><span class="n">fio_str_info_s</span> <span class="n">http_status2str</span><span class="p">(</span><span class="kt">uintptr_t</span> <span class="n">status</span><span class="p">);</span>
</code></pre>
<p>Returns a human readable string representing the HTTP status number. </p>
<h4 id="http_hijack"><code>http_hijack</code></h4>
<pre><code class='highlight'><span class="kt">intptr_t</span> <span class="n">http_hijack</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">,</span> <span class="n">fio_str_info_s</span> <span class="o">*</span><span class="n">leftover</span><span class="p">);</span>
</code></pre>
<p>Hijacks the socket away from the HTTP protocol and away from facil.io.</p>
<p>It&#39;s possible to hijack the socket and than reconnect it to a new protocol object.</p>
<p>It&#39;s possible to call <code>http_finish</code> immediately after calling <code>http_hijack</code> in order to send any outgoing headers before the hijacking is complete.</p>
<p>If any additional HTTP functions are called after the hijacking, the protocol object might attempt to continue reading data from the buffer.</p>
<p>Returns the underlining socket connection&#39;s uuid. If <code>leftover</code> isn&#39;t NULL, it will be populated with any remaining data in the HTTP buffer (the data will be automatically deallocated, so copy the data when in need).</p>
<p><strong>WARNING</strong>: this isn&#39;t a good way to handle HTTP connections, especially as HTTP/2 enters the picture. To implement Server Sent Events consider calling <a href="#http_upgrade2sse"><code>http_upgrade2sse</code></a> instead.</p>
<h4 id="http_req2str"><code>http_req2str</code></h4>
<pre><code class='highlight'><span class="n">FIOBJ</span> <span class="n">http_req2str</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">);</span>
</code></pre>
<p>Returns a String object representing the unparsed HTTP request (HTTP version
is capped at HTTP/1.1). Mostly usable for proxy usage and debugging.</p>
<h4 id="http_write_log"><code>http_write_log</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="n">http_write_log</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">);</span>
</code></pre>
<p>Writes a log line to <code>stderr</code> about the request / response object.</p>
<p>This function is called automatically if the <code>.log</code> setting is enabled.</p>
<h2 id="websockets">WebSockets</h2>
<h3 id="websocket-upgrade-from-http-server">WebSocket Upgrade From HTTP (Server)</h3>
<h4 id="http_upgrade2ws"><code>http_upgrade2ws</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">http_upgrade2ws</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">http</span><span class="p">,</span> <span class="n">websocket_settings_s</span><span class="p">);</span>
<span class="cp">#define http_upgrade2ws(http, ...) \
http_upgrade2ws((http), (websocket_settings_s){__VA_ARGS__})
</span></code></pre>
<p>Upgrades an HTTP/1.1 connection to a WebSocket connection.</p>
<p>The <code>http_upgrade2ws</code> function is shadowed by the <code>http_upgrade2ws</code> MACRO, which allows the function to accept &quot;named arguments&quot;.</p>
<p>In addition to the <code>http_s</code> argument, the following named arguments can be used:</p>
<ul>
<li><p><code>on_open</code>:</p>
<p>The (optional) <code>on_open</code> callback will be called once the WebSocket connection is established and before is is registered with <code>facil</code>, so no <code>on_message</code> events are raised before <code>on_open</code> returns.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_open</span><span class="p">(</span><span class="n">ws_s</span> <span class="o">*</span><span class="n">ws</span><span class="p">);</span>
</code></pre></li>
<li><p><code>on_message</code>:</p>
<p>The (optional) <code>on_message</code> callback will be called whenever a webSocket message is received for this connection.</p>
<p>The data received points to the WebSocket&#39;s message buffer and it will be overwritten once the function exits (it cannot be saved for later, but it can be copied).</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_message</span><span class="p">(</span><span class="n">ws_s</span> <span class="o">*</span><span class="n">ws</span><span class="p">,</span> <span class="n">fio_str_info_s</span> <span class="n">msg</span><span class="p">,</span> <span class="kt">uint8_t</span> <span class="n">is_text</span><span class="p">);</span>
</code></pre></li>
<li><p><code>on_ready</code>:</p>
<p>The (optional) <code>on_ready</code> callback will be after a the underlying socket&#39;s buffer changes it&#39;s state from full to empty.</p>
<p>If the socket&#39;s buffer is never used, the callback is never called.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_ready</span><span class="p">(</span><span class="n">ws_s</span> <span class="o">*</span><span class="n">ws</span><span class="p">);</span>
</code></pre></li>
<li><p><code>on_shutdown</code>:</p>
<p>The (optional) on_shutdown callback will be called if a WebSocket connection is still open while the server is shutting down (called before <code>on_close</code>).</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_shutdown</span><span class="p">(</span><span class="n">ws_s</span> <span class="o">*</span><span class="n">ws</span><span class="p">);</span>
</code></pre></li>
<li><p><code>on_close</code>:</p>
<p>The <code>uuid</code> is the connection&#39;s unique ID that can identify the WebSocket. A value of <code>uuid == -1</code> indicates the WebSocket connection wasn&#39;t established (an error occurred).</p>
<p>The <code>udata</code> is the user data as set during the upgrade or using the <code>websocket_udata_set</code> function.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_close</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">);</span>
</code></pre></li>
<li><p><code>udata</code>:</p>
<p>Opaque user data.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">;</span>
</code></pre></li>
</ul>
<p>This function will end the HTTP stage of the connection and attempt to &quot;upgrade&quot; to a WebSockets connection.</p>
<p>The <code>http_s</code> handle will be invalid after this call and the <code>udata</code> will be set to the new WebSocket <code>udata</code>.</p>
<p>A client connection&#39;s <code>on_finish</code> callback will be called (since the HTTP stage has finished).</p>
<p>Returns 0 on success or -1 on error.</p>
<p><strong>NOTE</strong>:</p>
<p>The type used by some of the callbacks (<code>ws_s</code>) is an opaque WebSocket handle and has no relationship with the named arguments used in this function cal. It is only used to identify a WebSocket connection.</p>
<p>Similar to an <code>http_s</code> handle, it is only valid within the scope of the specific connection (the callbacks / tasks) and shouldn&#39;t be stored or accessed otherwise.</p>
<h3 id="websocket-connections-client">WebSocket Connections (Client)</h3>
<h4 id="websocket_connect"><code>websocket_connect</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">websocket_connect</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">url</span><span class="p">,</span> <span class="n">websocket_settings_s</span> <span class="n">settings</span><span class="p">);</span>
<span class="cp">#define websocket_connect(url, ...) \
websocket_connect((address), (websocket_settings_s){__VA_ARGS__})
</span></code></pre>
<p>Connects to a WebSocket service according to the provided address.</p>
<p>This is a somewhat naive connector object, it doesn&#39;t perform any authentication or other logical handling. However, it&#39;s quire easy to author a complext authentication logic using a combination of <code>http_connect</code> and <code>http_upgrade2ws</code>.</p>
<p>In addition to the <code>url</code> address, this function accepts the same named arguments as <a href="#http_upgrade2ws"><code>http_upgrade2ws</code></a>.</p>
<p>Returns the <code>uuid</code> for the future WebSocket on success.</p>
<p>Returns -1 on error;</p>
<h3 id="websocket-connection-management-write-close">WebSocket Connection Management (write / close)</h3>
<h4 id="websocket_write"><code>websocket_write</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">websocket_write</span><span class="p">(</span><span class="n">ws_s</span> <span class="o">*</span><span class="n">ws</span><span class="p">,</span> <span class="n">fio_str_info_s</span> <span class="n">msg</span><span class="p">,</span> <span class="kt">uint8_t</span> <span class="n">is_text</span><span class="p">);</span>
</code></pre>
<p>Writes data to the WebSocket. Returns -1 on failure (0 on success).</p>
<h4 id="websocket_close"><code>websocket_close</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="n">websocket_close</span><span class="p">(</span><span class="n">ws_s</span> <span class="o">*</span><span class="n">ws</span><span class="p">);</span>
</code></pre>
<p>Closes a WebSocket connection. */</p>
<h3 id="websocket-pub-sub">WebSocket Pub/Sub</h3>
<h4 id="websocket_subscribe"><code>websocket_subscribe</code></h4>
<pre><code class='highlight'><span class="kt">uintptr_t</span> <span class="n">websocket_subscribe</span><span class="p">(</span><span class="k">struct</span> <span class="n">websocket_subscribe_s</span> <span class="n">args</span><span class="p">);</span>
<span class="cp">#define websocket_subscribe(, ...) \
websocket_subscribe((struct websocket_subscribe_s){.ws = ws_handle, __VA_ARGS__})
</span></code></pre>
<p>Subscribes to a pub/sub channel for, allowing for direct message deliverance when the <code>on_message</code> callback is missing.</p>
<p>To unsubscribe from the channel, use <a href="websocket_unsubscribe"><code>websocket_unsubscribe</code></a> (NOT
<code>fio_unsubscribe</code>).</p>
<p>The <code>websocket_subscribe</code> function is shadowed by the <code>websocket_subscribe</code> MACRO, which allows the function to accept &quot;named arguments&quot;.</p>
<p>In addition to the <code>ws_s *</code> argument, the following named arguments can be used:</p>
<ul>
<li><p><code>channel</code>:</p>
<p>The channel name used for the subscription. If missing, an empty string is assumed to be the channel name.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="n">fio_str_info_s</span> <span class="n">channel</span><span class="p">;</span>
</code></pre></li>
<li><p><code>on_message</code>:</p>
<p>An optional callback to be called when a pub/sub message is received.</p>
<p>If missing, Data is directly written to the WebSocket connection.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_message</span><span class="p">(</span><span class="n">ws_s</span> <span class="o">*</span><span class="n">ws</span><span class="p">,</span> <span class="n">fio_str_info_s</span> <span class="n">channel</span><span class="p">,</span>
<span class="n">fio_str_info_s</span> <span class="n">msg</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">);</span>
</code></pre></li>
<li><p><code>on_unsubscribe</code>:</p>
<p>An optional callback to be called after the subscription was canceled. This should be used for any required cleanup.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_unsubscribe</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">);</span>
</code></pre></li>
<li><p><code>match</code>:</p>
<p>A callback for pattern matching, as described in <a href="fio#fio_subscribe"><code>fio_subscribe</code></a>.</p>
<p>Note that only the <code>FIO_MATCH_GLOB</code> matching function (or NULL for no pattern matching) is safe to use with the Redis extension.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">int</span> <span class="n">foo_bar_match_fn</span><span class="p">(</span><span class="n">fio_str_info_s</span> <span class="n">pattern</span><span class="p">,</span> <span class="n">fio_str_info_s</span> <span class="n">channel</span><span class="p">);</span>
<span class="c1">// type:</span>
<span class="n">fio_match_fn</span> <span class="n">match</span><span class="p">;</span>
</code></pre></li>
<li><p><code>udata</code>:</p>
<p>Opaque user data.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">;</span>
</code></pre></li>
<li><p><code>force_binary</code>:</p>
<p>When using direct message forwarding (no <code>on_message</code> callback), this indicates if messages should be sent to the client as binary blobs, which is the safest approach.</p>
<p>By default, facil.io will test for UTF-8 data validity and send the data as text if it&#39;s a valid UTF-8. Messages above ~32Kb might be assumed to be binary rather than tested.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">unsigned</span> <span class="n">force_binary</span> <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
</code></pre></li>
<li><p><code>force_text</code>:</p>
<p>When using direct message forwarding (no <code>on_message</code> callback), this indicates if messages should be sent to the client as UTF-8 text.</p>
<p>By default, facil.io will test for UTF-8 data validity and send the data as text if it&#39;s a valid UTF-8. Messages above ~32Kb might be assumed to be binary rather than tested.</p>
<p><code>force_binary</code> has precedence over <code>force_text</code>.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">unsigned</span> <span class="n">force_text</span> <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
</code></pre></li>
</ul>
<p>Returns a subscription ID on success and 0 on failure.</p>
<p>All subscriptions are automatically canceled and freed once the WebSocket is closed.</p>
<h4 id="websocket_unsubscribe"><code>websocket_unsubscribe</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="n">websocket_unsubscribe</span><span class="p">(</span><span class="n">ws_s</span> <span class="o">*</span><span class="n">ws</span><span class="p">,</span> <span class="kt">uintptr_t</span> <span class="n">subscription_id</span><span class="p">);</span>
</code></pre>
<p>Unsubscribes from a channel.</p>
<p>Failures are silent.</p>
<p>All subscriptions are automatically revoked once the WebSocket is closed. So
only use this function to unsubscribe while the WebSocket is open.</p>
<h4 id="websocket_optimize4broadcasts"><code>websocket_optimize4broadcasts</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="n">websocket_optimize4broadcasts</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">type</span><span class="p">,</span> <span class="kt">int</span> <span class="n">enable</span><span class="p">);</span>
</code></pre>
<p>Enables (or disables) any of the following broadcast optimizations:</p>
<ul>
<li><p><code>WEBSOCKET_OPTIMIZE_PUBSUB</code> - Optimize generic Pub/Sub WebSocket broadcasts.</p>
<pre><code class='highlight'><span class="cp">#define WEBSOCKET_OPTIMIZE_PUBSUB (-32)
</span></code></pre></li>
<li><p><code>WEBSOCKET_OPTIMIZE_PUBSUB_TEXT</code> - Optimize text Pub/Sub WebSocket broadcasts.</p>
<pre><code class='highlight'><span class="cp">#define WEBSOCKET_OPTIMIZE_PUBSUB_TEXT (-33)
</span></code></pre></li>
<li><p><code>WEBSOCKET_OPTIMIZE_PUBSUB_BINARY</code> - Optimize binary Pub/Sub WebSocket broadcasts.</p>
<pre><code class='highlight'><span class="cp">#define WEBSOCKET_OPTIMIZE_PUBSUB_BINARY (-34)
</span></code></pre></li>
</ul>
<p>When using WebSocket pub/sub system is originally optimized for either non-direct transmission (messages are handled by callbacks) or direct transmission to 1-3 clients per channel (on average), meaning that the majority of the messages are meant for a single recipient (or multiple callback recipients) and only some are expected to be directly transmitted to a group.</p>
<p>However, when most messages are intended for direct transmission to more than 3 clients (on average), certain optimizations can be made to improve memory consumption (minimize duplication or WebSocket network data).</p>
<p><strong>Note</strong>: to disable an optimization it should be disabled the same amount of times it was enabled - multiple optimization enablements for the same type are merged, but reference counted (disabled when reference is zero).</p>
<h3 id="websocket-data">WebSocket Data</h3>
<h4 id="websocket_udata_get"><code>websocket_udata_get</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="o">*</span><span class="n">websocket_udata_get</span><span class="p">(</span><span class="n">ws_s</span> <span class="o">*</span><span class="n">ws</span><span class="p">);</span>
</code></pre>
<p>Returns the opaque user data associated with the WebSocket.</p>
<h4 id="websocket_udata_set"><code>websocket_udata_set</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="o">*</span><span class="n">websocket_udata_set</span><span class="p">(</span><span class="n">ws_s</span> <span class="o">*</span><span class="n">ws</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">);</span>
</code></pre>
<p>Sets the opaque user data associated with the WebSocket.</p>
<p>Returns the old value, if any.</p>
<h4 id="websocket_uuid"><code>websocket_uuid</code></h4>
<pre><code class='highlight'><span class="kt">intptr_t</span> <span class="n">websocket_uuid</span><span class="p">(</span><span class="n">ws_s</span> <span class="o">*</span><span class="n">ws</span><span class="p">);</span>
</code></pre>
<p>Returns the underlying socket UUID.</p>
<p>This is only relevant for collecting the protocol object from outside of WebSocket events, as the socket shouldn&#39;t be written to.</p>
<h4 id="websocket_is_client"><code>websocket_is_client</code></h4>
<pre><code class='highlight'><span class="kt">uint8_t</span> <span class="n">websocket_is_client</span><span class="p">(</span><span class="n">ws_s</span> <span class="o">*</span><span class="n">ws</span><span class="p">);</span>
</code></pre>
<p>Returns 1 if the WebSocket connection is in Client mode (connected to a remote server) and 0 if the connection is in Server mode (a connection established using facil.io&#39;s HTTP server).</p>
<h3 id="websocket-helpers">WebSocket Helpers</h3>
<h4 id="websocket_attach"><code>websocket_attach</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="n">websocket_attach</span><span class="p">(</span><span class="kt">intptr_t</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">http_settings_s</span> <span class="o">*</span><span class="n">http_settings</span><span class="p">,</span>
<span class="n">websocket_settings_s</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">length</span><span class="p">);</span>
</code></pre>
<p>Used <strong>internally</strong>: attaches the WebSocket protocol to the uuid.</p>
<h2 id="eventsource-server-sent-events-sse">EventSource / Server Sent Events (SSE)</h2>
<h3 id="eventsource-sse-connection-management">EventSource (SSE) Connection Management</h3>
<h4 id="http_upgrade2sse"><code>http_upgrade2sse</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">http_upgrade2sse</span><span class="p">(</span><span class="n">http_s</span> <span class="o">*</span><span class="n">h</span><span class="p">,</span> <span class="n">http_sse_s</span><span class="p">);</span>
<span class="cp">#define http_upgrade2sse(h, ...) \
http_upgrade2sse((h), (http_sse_s){__VA_ARGS__})
</span></code></pre>
<p>Upgrades an HTTP connection to an EventSource (SSE) connection.</p>
<p>The <code>http_s</code> handle will be invalid after this call.</p>
<p>On HTTP/1.1 connections, this will preclude future requests using the same connection.</p>
<p>The <code>http_upgrade2sse</code> function is shadowed by the <code>http_upgrade2sse</code> MACRO, which allows the function to accept &quot;named arguments&quot;, much like <code>http_listen</code>. i.e.:</p>
<pre><code class='highlight'><span class="n">on_open_sse</span><span class="p">(</span><span class="n">sse_s</span> <span class="o">*</span> <span class="n">sse</span><span class="p">)</span> <span class="p">{</span>
<span class="n">http_sse_subscribe</span><span class="p">(</span><span class="n">sse</span><span class="p">,</span> <span class="p">.</span><span class="n">channel</span> <span class="o">=</span> <span class="n">CHANNEL_NAME</span><span class="p">);</span> <span class="c1">// a simple subscription example</span>
<span class="p">}</span>
<span class="n">on_upgrade</span><span class="p">(</span><span class="n">http_s</span><span class="o">*</span> <span class="n">h</span><span class="p">)</span> <span class="p">{</span>
<span class="n">http_upgrade2sse</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="p">.</span><span class="n">on_open</span> <span class="o">=</span> <span class="n">on_open_sse</span><span class="p">);</span>
<span class="p">}</span>
</code></pre>
<p>In addition to the <code>http_s</code> argument, the following arguments are supported:</p>
<ul>
<li><p><code>on_open</code>:</p>
<p>The (optional) <code>on_open</code> callback will be called once the EventSource connection is established.</p>
<p>The <code>http_sse_s</code> pointer passed to the callback contains a copy of the named arguments passed to the <code>http_upgrade2sse</code> function.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_open</span><span class="p">(</span><span class="n">http_sse_s</span> <span class="o">*</span><span class="n">sse</span><span class="p">);</span>
</code></pre></li>
<li><p><code>on_ready</code>:</p>
<p>The (optional) <code>on_ready</code> callback will be called every time the underlying socket&#39;s buffer changes it&#39;s state to empty.</p>
<p>If the socket&#39;s buffer is never used, the callback might never get called.</p>
<p>The <code>http_sse_s</code> pointer passed to the callback contains a copy of the named arguments passed to the <code>http_upgrade2sse</code> function.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_ready</span><span class="p">(</span><span class="n">http_sse_s</span> <span class="o">*</span><span class="n">sse</span><span class="p">);</span>
</code></pre></li>
<li><p><code>on_shutdown</code>:</p>
<p>The (optional) <code>on_shutdown</code> callback will be called if a connection is still open while the server is shutting down (called before <code>on_close</code>).</p>
<p>The <code>http_sse_s</code> pointer passed to the callback contains a copy of the named arguments passed to the <code>http_upgrade2sse</code> function.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_shutdown</span><span class="p">(</span><span class="n">http_sse_s</span> <span class="o">*</span><span class="n">sse</span><span class="p">);</span>
</code></pre></li>
<li><p><code>on_close</code>:</p>
<p>The (optional) <code>on_close</code> callback will be called once a connection is terminated or failed to be established.</p>
<p>The <code>udata</code> passed to the <code>http_upgrade2sse</code> function is available through the <code>http_sse_s</code> pointer (<code>sse-&gt;udata</code>).</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_close</span><span class="p">(</span><span class="n">http_sse_s</span> <span class="o">*</span><span class="n">sse</span><span class="p">);</span>
</code></pre></li>
<li><p><code>udata</code>:</p>
<p>Opaque user data.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">;</span>
</code></pre></li>
</ul>
<h4 id="http_sse_set_timout"><code>http_sse_set_timout</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="n">http_sse_set_timout</span><span class="p">(</span><span class="n">http_sse_s</span> <span class="o">*</span><span class="n">sse</span><span class="p">,</span> <span class="kt">uint8_t</span> <span class="n">timeout</span><span class="p">);</span>
</code></pre>
<p>Sets the ping interval for SSE connections.</p>
<h4 id="http_sse_close"><code>http_sse_close</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">http_sse_close</span><span class="p">(</span><span class="n">http_sse_s</span> <span class="o">*</span><span class="n">sse</span><span class="p">);</span>
</code></pre>
<p>Closes an EventSource (SSE) connection.</p>
<h3 id="eventsource-sse-pub-sub">EventSource (SSE) Pub/Sub</h3>
<h4 id="http_sse_subscribe"><code>http_sse_subscribe</code></h4>
<pre><code class='highlight'><span class="kt">uintptr_t</span> <span class="n">http_sse_subscribe</span><span class="p">(</span><span class="n">http_sse_s</span> <span class="o">*</span><span class="n">sse</span><span class="p">,</span>
<span class="k">struct</span> <span class="n">http_sse_subscribe_args</span> <span class="n">args</span><span class="p">);</span>
<span class="cp">#define http_sse_subscribe(sse, ...) \
http_sse_subscribe((sse), (struct http_sse_subscribe_args){__VA_ARGS__})
</span></code></pre>
<p>Subscribes to a pub/sub channel for, allowing for direct message deliverance when the <code>on_message</code> callback is missing.</p>
<p>To unsubscribe from the channel, use <a href="http_sse_unsubscribe"><code>http_sse_unsubscribe</code></a> (NOT
<code>fio_unsubscribe</code>).</p>
<p>All subscriptions are automatically canceled and freed once the connection is closed.</p>
<p>The <code>http_sse_subscribe</code> function is shadowed by the <code>http_sse_subscribe</code> MACRO, which allows the function to accept &quot;named arguments&quot;.</p>
<p>In addition to the <code>sse</code> argument, the following named arguments can be used:</p>
<ul>
<li><p><code>channel</code>:</p>
<p>The channel name used for the subscription. If missing, an empty string is assumed to be the channel name.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="n">fio_str_info_s</span> <span class="n">channel</span><span class="p">;</span>
</code></pre></li>
<li><p><code>on_message</code>:</p>
<p>An optional callback to be called when a pub/sub message is received.</p>
<p>If missing, Data is directly written to the HTTP connection.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_message</span><span class="p">(</span><span class="n">http_sse_s</span> <span class="o">*</span><span class="n">sse</span><span class="p">,</span> <span class="n">fio_str_info_s</span> <span class="n">channel</span><span class="p">,</span>
<span class="n">fio_str_info_s</span> <span class="n">msg</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">);</span>
</code></pre></li>
<li><p><code>on_unsubscribe</code>:</p>
<p>An optional callback for when a subscription is fully canceled (the subscription&#39;s <code>udata</code> can be freed).</p>
<p>If missing, Data is directly written to the HTTP connection.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">void</span> <span class="n">on_unsubscribe</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">);</span>
</code></pre></li>
<li><p><code>match</code>:</p>
<p>A callback for pattern matching, as described in <a href="fio#fio_subscribe"><code>fio_subscribe</code></a>.</p>
<p>Note that only the <code>FIO_MATCH_GLOB</code> matching function (or NULL for no pattern matching) is safe to use with the Redis extension.</p>
<pre><code class='highlight'><span class="c1">// callback example:</span>
<span class="kt">int</span> <span class="n">foo_bar_match_fn</span><span class="p">(</span><span class="n">fio_str_info_s</span> <span class="n">pattern</span><span class="p">,</span> <span class="n">fio_str_info_s</span> <span class="n">channel</span><span class="p">);</span>
<span class="c1">// type:</span>
<span class="n">fio_match_fn</span> <span class="n">match</span><span class="p">;</span>
</code></pre></li>
<li><p><code>udata</code>:</p>
<p>Opaque user data.</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">udata</span><span class="p">;</span>
</code></pre></li>
</ul>
<p>Returns a subscription ID on success and 0 on failure.</p>
<h4 id="http_sse_unsubscribe"><code>http_sse_unsubscribe</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="n">http_sse_unsubscribe</span><span class="p">(</span><span class="n">http_sse_s</span> <span class="o">*</span><span class="n">sse</span><span class="p">,</span> <span class="kt">uintptr_t</span> <span class="n">subscription</span><span class="p">);</span>
</code></pre>
<p>Cancels a subscription and invalidates the subscription object.</p>
<h3 id="writing-to-the-eventsource-sse-connection">Writing to the EventSource (SSE) Connection</h3>
<h4 id="http_sse_write"><code>http_sse_write</code></h4>
<pre><code class='highlight'><span class="kt">int</span> <span class="n">http_sse_write</span><span class="p">(</span><span class="n">http_sse_s</span> <span class="o">*</span><span class="n">sse</span><span class="p">,</span> <span class="k">struct</span> <span class="n">http_sse_write_args</span><span class="p">);</span>
<span class="cp">#define http_sse_write(sse, ...) \
http_sse_write((sse), (struct http_sse_write_args){__VA_ARGS__})
</span></code></pre>
<p>Writes data to an EventSource (SSE) connection.</p>
<p>The <code>http_sse_write</code> function is shadowed by the <code>http_sse_write</code> MACRO, which allows the function to accept &quot;named arguments&quot;.</p>
<p>In addition to the <code>sse</code> argument, the following named arguments can be used:</p>
<ul>
<li><p><code>id</code>:</p>
<p>Sets the <code>id</code> event property (optional).</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="n">fio_str_info_s</span> <span class="n">id</span><span class="p">;</span>
</code></pre></li>
<li><p><code>event</code>:</p>
<p>Sets the <code>event</code> event property (optional).</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="n">fio_str_info_s</span> <span class="n">event</span><span class="p">;</span>
</code></pre></li>
<li><p><code>data</code>:</p>
<p>Sets the <code>data</code> event property (optional).</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="n">fio_str_info_s</span> <span class="n">data</span><span class="p">;</span>
</code></pre></li>
<li><p><code>retry</code>:</p>
<p>Sets the <code>retry</code> event property (optional).</p>
<pre><code class='highlight'><span class="c1">// type:</span>
<span class="n">fio_str_info_s</span> <span class="n">retry</span><span class="p">;</span>
</code></pre></li>
</ul>
<p>Event field details can be found on the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events">Mozilla developer website</a>.</p>
<h3 id="eventsource-sse-helpers">EventSource (SSE) Helpers</h3>
<h4 id="http_sse2uuid"><code>http_sse2uuid</code></h4>
<pre><code class='highlight'><span class="kt">intptr_t</span> <span class="n">http_sse2uuid</span><span class="p">(</span><span class="n">http_sse_s</span> <span class="o">*</span><span class="n">sse</span><span class="p">);</span>
</code></pre>
<p>Get the connection&#39;s UUID (for <code>fio_defer_io_task</code>, pub/sub, etc&#39;).</p>
<h4 id="http_sse_dup"><code>http_sse_dup</code></h4>
<pre><code class='highlight'><span class="n">http_sse_s</span> <span class="o">*</span><span class="n">http_sse_dup</span><span class="p">(</span><span class="n">http_sse_s</span> <span class="o">*</span><span class="n">sse</span><span class="p">);</span>
</code></pre>
<p>Duplicates an SSE handle by reference, remember to http_sse_free.</p>
<p>Returns the same object (increases a reference count, no allocation is made). </p>
<h4 id="http_sse_free"><code>http_sse_free</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="n">http_sse_free</span><span class="p">(</span><span class="n">http_sse_s</span> <span class="o">*</span><span class="n">sse</span><span class="p">);</span>
</code></pre>
<p>Frees an SSE handle by reference (decreases the reference count).</p>
<h2 id="miscellaneous">Miscellaneous</h2>
<h3 id="mime-type-helpers">Mime-Type helpers</h3>
<p>The HTTP extension allows for easy conversion between file extensions and known Mime-Types.</p>
<p>Many known file extensions are registered by the HTTP extension during startup. However, it&#39;s also possible to add/register more Mime-Types during the setup stage.</p>
<p>NOTE:</p>
<p>The Mime-Type helpers are designed to allow for concurrent read access. By design, they are <strong>not</strong> thread safe.</p>
<p>It is recommended (and assumed) that all the calls to <code>http_mimetype_register</code> are performed during the setup stage (before calling <code>fio_start</code>).</p>
<h4 id="http_mimetype_register"><code>http_mimetype_register</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="n">http_mimetype_register</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">file_ext</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">file_ext_len</span><span class="p">,</span>
<span class="n">FIOBJ</span> <span class="n">mime_type_str</span><span class="p">);</span>
</code></pre>
<p>Registers a Mime-Type to be associated with a file extension.</p>
<p>File extension names should exclude the dot (<code>&#39;.&#39;</code>) marking the beginning of the extension. i.e., use <code>&quot;jpg&quot;</code>, <code>&quot;html&quot;</code>, etc&#39; (<strong>not</strong> <code>&quot;.jpg&quot;</code>).</p>
<h4 id="http_mimetype_find"><code>http_mimetype_find</code></h4>
<pre><code class='highlight'><span class="n">FIOBJ</span> <span class="n">http_mimetype_find</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">file_ext</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">file_ext_len</span><span class="p">);</span>
</code></pre>
<p>Finds the mime-type associated with the file extension, returning a String on success and FIOBJ_INVALID on failure.</p>
<p>Remember to call <code>fiobj_free</code>.</p>
<h4 id="http_mimetype_find2"><code>http_mimetype_find2</code></h4>
<pre><code class='highlight'><span class="n">FIOBJ</span> <span class="n">http_mimetype_find2</span><span class="p">(</span><span class="n">FIOBJ</span> <span class="n">url</span><span class="p">);</span>
</code></pre>
<p>Returns the mime-type associated with the URL or the default mime-type for
HTTP.</p>
<p>Remember to call <code>fiobj_free</code>.</p>
<h4 id="http_mimetype_clear"><code>http_mimetype_clear</code></h4>
<pre><code class='highlight'><span class="kt">void</span> <span class="n">http_mimetype_clear</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
</code></pre>
<p>Clears the Mime-Type registry (it will be empty after this call). </p>
<h3 id="time-date-helpers">Time / Date Helpers</h3>
<h4 id="http_gmtime"><code>http_gmtime</code></h4>
<pre><code class='highlight'><span class="k">struct</span> <span class="n">tm</span> <span class="o">*</span><span class="n">http_gmtime</span><span class="p">(</span><span class="kt">time_t</span> <span class="n">timer</span><span class="p">,</span> <span class="k">struct</span> <span class="n">tm</span> <span class="o">*</span><span class="n">tmbuf</span><span class="p">);</span>
</code></pre>
<p>A faster (yet less localized) alternative to <code>gmtime_r</code>.</p>
<p>See the libc <code>gmtime_r</code> documentation for details.</p>
<p>Falls back to <code>gmtime_r</code> for dates before epoch.</p>
<h4 id="http_date2str"><code>http_date2str</code></h4>
<pre><code class='highlight'><span class="kt">size_t</span> <span class="n">http_date2str</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">target</span><span class="p">,</span> <span class="k">struct</span> <span class="n">tm</span> <span class="o">*</span><span class="n">tmbuf</span><span class="p">);</span>
</code></pre>
<p>Writes an HTTP date string to the <code>target</code> buffer.</p>
<p>This requires ~32 bytes of space to be available at the target buffer (unless
it&#39;s a super funky year, 32 bytes is about 3 more than you need).</p>
<p>Returns the number of bytes actually written.</p>
<h4 id="http_date2rfc2109"><code>http_date2rfc2109</code></h4>
<pre><code class='highlight'><span class="kt">size_t</span> <span class="n">http_date2rfc2109</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">target</span><span class="p">,</span> <span class="k">struct</span> <span class="n">tm</span> <span class="o">*</span><span class="n">tmbuf</span><span class="p">);</span>
</code></pre>
<p>An alternative, RFC 2109 date representation. Requires </p>
<h4 id="http_date2rfc2822"><code>http_date2rfc2822</code></h4>
<pre><code class='highlight'><span class="kt">size_t</span> <span class="n">http_date2rfc2822</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">target</span><span class="p">,</span> <span class="k">struct</span> <span class="n">tm</span> <span class="o">*</span><span class="n">tmbuf</span><span class="p">);</span>
</code></pre>
<p>An alternative, RFC 2822 date representation. </p>
<h4 id="http_time2str"><code>http_time2str</code></h4>
<pre><code class='highlight'><span class="kt">size_t</span> <span class="n">http_time2str</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">target</span><span class="p">,</span> <span class="k">const</span> <span class="kt">time_t</span> <span class="n">t</span><span class="p">);</span>
</code></pre>
<p>Prints Unix time to a HTTP time formatted string.</p>
<p>This variation implements cached results for faster processing, at the price of a less accurate string.</p>
<h3 id="url-parsing">URL Parsing</h3>
<h4 id="http_url_parse"><code>http_url_parse</code></h4>
<pre><code class='highlight'><span class="n">http_url_s</span> <span class="n">http_url_parse</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">url</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">length</span><span class="p">);</span>
</code></pre>
<p>Parses the URI returning it&#39;s components and their lengths - no decoding
performed, doesn&#39;t accept decoded URIs.</p>
<p>the result returned by <code>http_url_parse</code> is a <code>http_url_s</code> structure:</p>
<pre><code class='highlight'><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
<span class="n">fio_str_info_s</span> <span class="n">scheme</span><span class="p">;</span>
<span class="n">fio_str_info_s</span> <span class="n">user</span><span class="p">;</span>
<span class="n">fio_str_info_s</span> <span class="n">password</span><span class="p">;</span>
<span class="n">fio_str_info_s</span> <span class="n">host</span><span class="p">;</span>
<span class="n">fio_str_info_s</span> <span class="n">port</span><span class="p">;</span>
<span class="n">fio_str_info_s</span> <span class="n">path</span><span class="p">;</span>
<span class="n">fio_str_info_s</span> <span class="n">query</span><span class="p">;</span>
<span class="n">fio_str_info_s</span> <span class="n">target</span><span class="p">;</span>
<span class="p">}</span> <span class="n">http_url_s</span><span class="p">;</span>
</code></pre>
<p>The returned string are NOT NUL terminated, they are merely locations within the original string.</p>
<p>This function expects any of the following formats:</p>
<ul>
<li><p><code>/complete_path?query#target</code></p>
<p>i.e.:</p>
<ul>
<li>/index.html?page=1#list</li>
</ul></li>
<li><p><code>host:port/complete_path?query#target</code></p>
<p>i.e.:</p>
<ul>
<li>example.com</li>
<li>example.com/index.html</li>
<li>user:<a href="mailto:1234@example.com">1234@example.com</a>:8080</li>
<li>example.com:8080/index.html</li>
</ul></li>
<li><p><code>schema://user:password@host:port/path?query#target</code></p>
<p>i.e.:</p>
<ul>
<li><a href="http://example.com/index.html?page=1#list">http://example.com/index.html?page=1#list</a></li>
</ul></li>
</ul>
<p>Invalid formats might produce unexpected results. No error testing is performed.</p>
<h3 id="url-string-decoding">URL String Decoding</h3>
<h4 id="http_decode_url_unsafe"><code>http_decode_url_unsafe</code></h4>
<pre><code class='highlight'><span class="kt">ssize_t</span> <span class="n">http_decode_url_unsafe</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">dest</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">url_data</span><span class="p">);</span>
</code></pre>
<p>Decodes a URL encoded string, <strong>no</strong> buffer overflow protection. </p>
<h4 id="http_decode_url"><code>http_decode_url</code></h4>
<pre><code class='highlight'><span class="kt">ssize_t</span> <span class="n">http_decode_url</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">dest</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">url_data</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">length</span><span class="p">);</span>
</code></pre>
<p>Decodes a URL encoded string (query / form data), <strong>no</strong> buffer overflow protection.</p>
<h4 id="http_decode_path_unsafe"><code>http_decode_path_unsafe</code></h4>
<pre><code class='highlight'><span class="kt">ssize_t</span> <span class="n">http_decode_path_unsafe</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">dest</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">url_data</span><span class="p">);</span>
</code></pre>
<p>Decodes the &quot;path&quot; part of a request, <strong>no</strong> buffer overflow protection. </p>
<h4 id="http_decode_path"><code>http_decode_path</code></h4>
<pre><code class='highlight'><span class="kt">ssize_t</span> <span class="n">http_decode_path</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">dest</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">url_data</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">length</span><span class="p">);</span>
</code></pre>
<p>Decodes the &quot;path&quot; part of an HTTP request, no buffer overflow protection.</p>
<h3 id="commonly-used-header-constants">Commonly Used Header Constants</h3>
<p>Some headers are so commonly used, that the HTTP extension pre-allocates memory and objects to represent these headers.</p>
<p>Avoid freeing these headers, as the HTTP extension expects them to remain allocated until the application quits.</p>
<h4 id="http_header_accept"><code>HTTP_HEADER_ACCEPT</code></h4>
<pre><code class='highlight'><span class="k">extern</span> <span class="n">FIOBJ</span> <span class="n">HTTP_HEADER_ACCEPT</span><span class="p">;</span>
</code></pre>
<p>Represents the HTTP Header <code>&quot;Accept&quot;</code>.</p>
<h4 id="http_header_cache_control"><code>HTTP_HEADER_CACHE_CONTROL</code></h4>
<pre><code class='highlight'><span class="k">extern</span> <span class="n">FIOBJ</span> <span class="n">HTTP_HEADER_CACHE_CONTROL</span><span class="p">;</span>
</code></pre>
<p>Represents the HTTP Header <code>&quot;Cache-Control&quot;</code>.</p>
<h4 id="http_header_connection"><code>HTTP_HEADER_CONNECTION</code></h4>
<pre><code class='highlight'><span class="k">extern</span> <span class="n">FIOBJ</span> <span class="n">HTTP_HEADER_CONNECTION</span><span class="p">;</span>
</code></pre>
<p>Represents the HTTP Header <code>&quot;Connection&quot;</code>.</p>
<h4 id="http_header_content_encoding"><code>HTTP_HEADER_CONTENT_ENCODING</code></h4>
<pre><code class='highlight'><span class="k">extern</span> <span class="n">FIOBJ</span> <span class="n">HTTP_HEADER_CONTENT_ENCODING</span><span class="p">;</span>
</code></pre>
<p>Represents the HTTP Header <code>&quot;Content-Encoding&quot;</code>.</p>
<h4 id="http_header_content_length"><code>HTTP_HEADER_CONTENT_LENGTH</code></h4>
<pre><code class='highlight'><span class="k">extern</span> <span class="n">FIOBJ</span> <span class="n">HTTP_HEADER_CONTENT_LENGTH</span><span class="p">;</span>
</code></pre>
<p>Represents the HTTP Header <code>&quot;Content-Length&quot;</code>.</p>
<h4 id="http_header_content_range"><code>HTTP_HEADER_CONTENT_RANGE</code></h4>
<pre><code class='highlight'><span class="k">extern</span> <span class="n">FIOBJ</span> <span class="n">HTTP_HEADER_CONTENT_RANGE</span><span class="p">;</span>
</code></pre>
<p>Represents the HTTP Header <code>&quot;Content-Range&quot;</code>.</p>
<h4 id="http_header_content_type"><code>HTTP_HEADER_CONTENT_TYPE</code></h4>
<pre><code class='highlight'><span class="k">extern</span> <span class="n">FIOBJ</span> <span class="n">HTTP_HEADER_CONTENT_TYPE</span><span class="p">;</span>
</code></pre>
<p>Represents the HTTP Header <code>&quot;Content-Type&quot;</code>.</p>
<h4 id="http_header_cookie"><code>HTTP_HEADER_COOKIE</code></h4>
<pre><code class='highlight'><span class="k">extern</span> <span class="n">FIOBJ</span> <span class="n">HTTP_HEADER_COOKIE</span><span class="p">;</span>
</code></pre>
<p>Represents the HTTP Header <code>&quot;Cookie&quot;</code>.</p>
<h4 id="http_header_date"><code>HTTP_HEADER_DATE</code></h4>
<pre><code class='highlight'><span class="k">extern</span> <span class="n">FIOBJ</span> <span class="n">HTTP_HEADER_DATE</span><span class="p">;</span>
</code></pre>
<p>Represents the HTTP Header <code>&quot;Date&quot;</code>.</p>
<h4 id="http_header_etag"><code>HTTP_HEADER_ETAG</code></h4>
<pre><code class='highlight'><span class="k">extern</span> <span class="n">FIOBJ</span> <span class="n">HTTP_HEADER_ETAG</span><span class="p">;</span>
</code></pre>
<p>Represents the HTTP Header <code>&quot;Etag&quot;</code>.</p>
<h4 id="http_header_host"><code>HTTP_HEADER_HOST</code></h4>
<pre><code class='highlight'><span class="k">extern</span> <span class="n">FIOBJ</span> <span class="n">HTTP_HEADER_HOST</span><span class="p">;</span>
</code></pre>
<p>Represents the HTTP Header <code>&quot;Host&quot;</code>.</p>
<h4 id="http_header_last_modified"><code>HTTP_HEADER_LAST_MODIFIED</code></h4>
<pre><code class='highlight'><span class="k">extern</span> <span class="n">FIOBJ</span> <span class="n">HTTP_HEADER_LAST_MODIFIED</span><span class="p">;</span>
</code></pre>
<p>Represents the HTTP Header <code>&quot;Last-Modified&quot;</code>.</p>
<h4 id="http_header_origin"><code>HTTP_HEADER_ORIGIN</code></h4>
<pre><code class='highlight'><span class="k">extern</span> <span class="n">FIOBJ</span> <span class="n">HTTP_HEADER_ORIGIN</span><span class="p">;</span>
</code></pre>
<p>Represents the HTTP Header <code>&quot;Origin&quot;</code>.</p>
<h4 id="http_header_set_cookie"><code>HTTP_HEADER_SET_COOKIE</code></h4>
<pre><code class='highlight'><span class="k">extern</span> <span class="n">FIOBJ</span> <span class="n">HTTP_HEADER_SET_COOKIE</span><span class="p">;</span>
</code></pre>
<p>Represents the HTTP Header <code>&quot;Set-Cookie&quot;</code>.</p>
<h4 id="http_header_upgrade"><code>HTTP_HEADER_UPGRADE</code></h4>
<pre><code class='highlight'><span class="k">extern</span> <span class="n">FIOBJ</span> <span class="n">HTTP_HEADER_UPGRADE</span><span class="p">;</span>
</code></pre>
<p>Represents the HTTP Header <code>&quot;Upgrade&quot;</code>.</p>
<h3 id="compile-time-settings">Compile Time Settings</h3>
<h4 id="http_busy_unless_has_fds"><code>HTTP_BUSY_UNLESS_HAS_FDS</code></h4>
<pre><code class='highlight'><span class="cp">#define HTTP_BUSY_UNLESS_HAS_FDS 64
</span></code></pre>
<p>When a new connection is accepted, it will be immediately declined with a 503 service unavailable (server busy) response unless the following number of file descriptors is available.</p>
<h4 id="http_default_body_limit"><code>HTTP_DEFAULT_BODY_LIMIT</code></h4>
<pre><code class='highlight'><span class="cp">#define HTTP_DEFAULT_BODY_LIMIT (1024 * 1024 * 50)
</span></code></pre>
<p>The default limit on HTTP message length (in bytes). A different limit can be set during runtime as part of the <code>http_listen</code> function call.</p>
<h4 id="http_max_header_count"><code>HTTP_MAX_HEADER_COUNT</code></h4>
<pre><code class='highlight'><span class="cp">#define HTTP_MAX_HEADER_COUNT 128
</span></code></pre>
<p>The maximum (hard coded) number of headers per HTTP request, after which the request is considered malicious and the connection is abruptly closed.</p>
<h4 id="http_max_header_length"><code>HTTP_MAX_HEADER_LENGTH</code></h4>
<pre><code class='highlight'><span class="cp">#define HTTP_MAX_HEADER_LENGTH 8192
</span></code></pre>
<p>the default maximum length for a single header line </p>
</div><a href="/" id="sign"></a><div class="hidden" id="notice"><a class="notice_close" onclick="hide_notice()">X</a><div id="notice_text"></div></div><script>function change_themes() {
if(localStorage.getItem("theme") == 'dark') {
localStorage.setItem("theme", "light");
} else {
localStorage.setItem("theme", "dark");
}
$('body')[0].className = localStorage.getItem("theme");
set_theme_link();
$('#show_nav').attr('checked', false);
return false;
};
function sidebar_name() { return window.location.pathname.slice(0, window.location.pathname.lastIndexOf("/")); }
function on_sidebar_link(e) {
sessionStorage.setItem("sidebar.expect", sidebar_name());
sessionStorage.setItem("sidebar.pos", document.getElementById("side_bar").scrollTop);
}
function load_sidebar_pos() {
var e = document.getElementById("side_bar");
if(!e) {
console.warn("No sidebar detected");
return;
}
var expect = sidebar_name();
if(sessionStorage.getItem("sidebar.expect") == expect) {
e.scrollTo(0, parseInt(sessionStorage.getItem("sidebar.pos")));
} else {
sessionStorage.setItem("sidebar.expect", false);
sessionStorage.setItem("sidebar.pos", 0);
}
if(e) {
// add link callbacks
var links = document.links;
var count = links.length;
for (var i = 0; i < count; i++) {
var href = links[i].href;
if(href.startsWith(document.location.origin)) {
href = href.slice(document.location.origin.length);
}
if(href.startsWith(expect)) {
/* add link event */
links[i].addEventListener("click", on_sidebar_link);
}
}
}
};
load_sidebar_pos();
function set_theme_link() {
$("#theme").html( ( (localStorage.getItem("theme") == 'dark') ? "Day" : "Night") + " Theme" );
}
$('body')[0].className = (localStorage.getItem("theme") == 'dark') ? "dark" : "light";
set_theme_link();
function show_notice() { document.getElementById("notice").classList.remove('hidden'); };
function hide_notice() { document.getElementById("notice").classList.add('hidden'); };
$('#toc').on("touchstart", function (e) { return true; } );
$('#toc').on("hover", function (e) { return true; } );
// hljs.initHighlighting();
// Google Analytics
// if(location.hostname != "localhost") {
// (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
// (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
// m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
// })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
// ga('create', 'UA-69931401-1', 'auto');
// ga('send', 'pageview');
// }</script></body></html>