| <!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 - a mini-framework for C web applications</title><meta content="facil.io - a mini-framework for C web applications" 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><link href="/assets/logo/facil-io-logo.svg" rel="icon" sizes="350x350" type="image/svg" /><link href="/assets/logo/facil-io-logo.png" rel="icon" sizes="350x350" type="image/png" /><link href="/assets/logo/facil-io-logo.svg" rel="shortcut icon" sizes="350x350" type="image/svg" /><link href="/assets/logo/facil-io-logo.png" rel="shortcut icon" sizes="350x350" type="image/png" /><link href="/assets/logo/facil-io-logo.svg" rel="apple-touch-icon" sizes="350x350" type="image/svg" /><link href="/assets/logo/facil-io-logo.png" rel="apple-touch-icon" sizes="350x350" type="image/png" /><link href="/assets/logo/facil-io-logo.svg" rel="fluid-icon" sizes="350x350" type="image/svg" /><link href="/assets/logo/facil-io-logo.png" rel="fluid-icon" sizes="350x350" type="image/png" /><link href="/manifest.json" rel="manifest" /><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-6-x"><a href="/0.6.x/index">Version 0.6.x</a></h2> |
| |
| <ul> |
| <li><a href="/0.6.x/api">API Overview</a></li> |
| <li><a href="/0.6.x/modules">The Modules</a></li> |
| </ul> |
| |
| <h3 id="core-api"><a href="/0.6.x/facil">Core API</a></h3> |
| |
| <ul> |
| <li><a href="/0.6.x/defer">Event scheduling</a></li> |
| <li><a href="/0.6.x/evio">Low Level Polling</a></li> |
| <li><a href="/0.6.x/sock">Low Level Sockets</a></li> |
| <li><a href="/0.6.x/fio_mem">Memory Allocation</a></li> |
| </ul> |
| |
| <h3 id="extensions">Extensions</h3> |
| |
| <ul> |
| <li><a href="/0.6.x/http">HTTP</a></li> |
| <li><a href="/0.6.x/websockets">WebSockets</a></li> |
| <li><a href="/0.6.x/pubsub">Pub/Sub</a></li> |
| <li><a href="/0.6.x/fio_cli">CLI (command line)</a></li> |
| </ul> |
| |
| <h3 id="the-fiobj-types"><a href="/0.6.x/fiobj">The FIOBJ types</a></h3> |
| |
| <ul> |
| <li><a href="/0.6.x/fiobj_primitives">Primitives</a></li> |
| <li><a href="/0.6.x/fiobj_numbers">Numbers</a></li> |
| <li><a href="/0.6.x/fiobj_str">Strings</a></li> |
| <li><a href="/0.6.x/fiobj_ary">Array</a></li> |
| <li><a href="/0.6.x/fiobj_hash">HashMap</a></li> |
| <li><a href="/0.6.x/fiobj_json">JSON</a></li> |
| </ul> |
| |
| <h3 id="core-types"><a href="/0.6.x/types">Core Types</a></h3> |
| |
| <ul> |
| <li><a href="/0.6.x/fio_ary">C Arrays</a></li> |
| <li><a href="/0.6.x/fio_hashmap">C HashMap</a></li> |
| <li><a href="/0.6.x/fio_llist">Linked Lists</a></li> |
| </ul> |
| </nav><div id="md_container"><div class='toc'><ul> |
| <li> |
| <a href="#facil-io-a-mini-framework-for-c-web-applications">facil.io - a mini-framework for C web applications</a> |
| <ul> |
| <li> |
| <a href="#facil-io-more-than-a-powerful-http-websockets-server-library">facil.io - more than a powerful HTTP/Websockets server library.</a> |
| </li> |
| <li> |
| <a href="#an-easy-chatroom-example">An easy chatroom example</a> |
| </li> |
| <li> |
| <a href="#further-reading">Further reading</a> |
| </li> |
| <li> |
| <a href="#forking-contributing-and-all-that-jazz">Forking, Contributing and all that Jazz</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </div><h1 id="facil-io-a-mini-framework-for-c-web-applications">facil.io - a mini-framework for C web applications</h1> |
| |
| <p>A Web application in C? It's as easy as:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#include "http.h" </span><span class="cm">/* the HTTP facil.io extension */</span><span class="cp"> |
| </span> |
| <span class="c1">// We'll use this callback in `http_listen`, to handles HTTP requests</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> |
| |
| <span class="c1">// These will contain pre-allocated values that we will use often</span> |
| <span class="n">FIOBJ</span> <span class="n">HTTP_HEADER_X_DATA</span><span class="p">;</span> |
| |
| <span class="c1">// Listen to HTTP requests and start facil.io</span> |
| <span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="k">const</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span> <span class="p">{</span> |
| <span class="c1">// allocating values we use often</span> |
| <span class="n">HTTP_HEADER_X_DATA</span> <span class="o">=</span> <span class="n">fiobj_str_static</span><span class="p">(</span><span class="s">"X-Data"</span><span class="p">,</span> <span class="mi">6</span><span class="p">);</span> |
| <span class="c1">// listen on port 3000 and any available network binding (NULL == 0.0.0.0)</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_request</span><span class="p">,</span> <span class="p">.</span><span class="n">log</span> <span class="o">=</span> <span class="mi">1</span><span class="p">);</span> |
| <span class="c1">// start the server</span> |
| <span class="n">facil_run</span><span class="p">(.</span><span class="n">threads</span> <span class="o">=</span> <span class="mi">1</span><span class="p">);</span> |
| <span class="c1">// deallocating the common values</span> |
| <span class="n">fiobj_free</span><span class="p">(</span><span class="n">HTTP_HEADER_X_DATA</span><span class="p">);</span> |
| <span class="p">}</span> |
| |
| <span class="c1">// Easy HTTP handling</span> |
| <span class="kt">void</span> <span class="nf">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> <span class="p">{</span> |
| <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">name_len</span> <span class="o">=</span> <span class="mi">9</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> |
| <span class="p">.</span><span class="n">value_len</span> <span class="o">=</span> <span class="mi">4</span><span class="p">);</span> |
| <span class="n">http_set_header</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">HTTP_HEADER_CONTENT_TYPE</span><span class="p">,</span> |
| <span class="n">http_mimetype_find</span><span class="p">(</span><span class="s">"txt"</span><span class="p">,</span> <span class="mi">3</span><span class="p">));</span> |
| <span class="n">http_set_header</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">HTTP_HEADER_X_DATA</span><span class="p">,</span> <span class="n">fiobj_str_new</span><span class="p">(</span><span class="s">"my data"</span><span class="p">,</span> <span class="mi">7</span><span class="p">));</span> |
| <span class="n">http_send_body</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s">"Hello World!</span><span class="se">\r\n</span><span class="s">"</span><span class="p">,</span> <span class="mi">14</span><span class="p">);</span> |
| <span class="p">}</span> |
| </code></pre></div> |
| <h2 id="facil-io-more-than-a-powerful-http-websockets-server-library">facil.io - more than a powerful HTTP/Websockets server library.</h2> |
| |
| <p><a href="http://facil.io">facil.io</a> is a C mini-framework for web applications and includes a fast HTTP and Websocket server, a <a href="pubsub.md">native Pub/Sub solution</a>, an optional Redis pub/sub engine, support for custom protocols and some nifty tidbits.</p> |
| |
| <p><a href="http://facil.io">facil.io</a> powers the <a href="https://github.com/boazsegev/iodine">HTTP/Websockets Ruby Iodine server</a> and it can easily power your application as well.</p> |
| |
| <p><a href="http://facil.io">facil.io</a> provides high performance TCP/IP network services to Linux / BSD (and macOS) by using an evented design that was tested to provide an easy solution to <a href="http://www.kegel.com/c10k.html">the C10K problem</a>.</p> |
| |
| <p><a href="http://facil.io">facil.io</a> prefers a TCP/IP specialized solution over a generic one (although it can be easily adopted for Unix sockets, UDP and other approaches).</p> |
| |
| <p><a href="http://facil.io">facil.io</a> includes a number of libraries that work together for a common goal. Some of the libraries (i.e., some <a href="api/types.md">core types</a> the thread-pool library <code>defer</code>, the socket library <code>sock</code>, the evented IO core <code>evio</code> and the <a href="">parsers</a> can be used independently while others are designed to work together using a modular approach.</p> |
| |
| <p>I used this library (including the HTTP server) on Linux, Mac OS X and FreeBSD (I had to edit the <code>makefile</code> for each environment).</p> |
| |
| <h2 id="an-easy-chatroom-example">An easy chatroom example</h2> |
| |
| <p>Here's a simple Websocket chatroom example:</p> |
| <div class="highlight"><pre class="highlight c"><code><span class="cp">#include "http.h" |
| #include "pubsub.h" |
| #include <string.h> |
| </span> |
| <span class="cm">/* ***************************************************************************** |
| Nicknames |
| ***************************************************************************** */</span> |
| |
| <span class="k">struct</span> <span class="n">nickname</span> <span class="p">{</span> |
| <span class="kt">size_t</span> <span class="n">len</span><span class="p">;</span> |
| <span class="kt">char</span> <span class="n">nick</span><span class="p">[];</span> |
| <span class="p">};</span> |
| |
| <span class="cm">/* This initalization requires GNU gcc / clang ... |
| * ... it's a default name for unimaginative visitors. |
| */</span> |
| <span class="k">static</span> <span class="k">struct</span> <span class="n">nickname</span> <span class="n">MISSING_NICKNAME</span> <span class="o">=</span> <span class="p">{.</span><span class="n">len</span> <span class="o">=</span> <span class="mi">7</span><span class="p">,</span> <span class="p">.</span><span class="n">nick</span> <span class="o">=</span> <span class="s">"unknown"</span><span class="p">};</span> |
| <span class="k">static</span> <span class="n">FIOBJ</span> <span class="n">CHAT_CHANNEL</span><span class="p">;</span> |
| <span class="cm">/* ***************************************************************************** |
| Websocket callbacks |
| ***************************************************************************** */</span> |
| |
| <span class="cm">/* We'll subscribe to the channel's chat channel when a new connection opens */</span> |
| <span class="k">static</span> <span class="kt">void</span> <span class="nf">on_open_websocket</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="p">{</span> |
| <span class="cm">/* subscription - easy as pie */</span> |
| <span class="n">websocket_subscribe</span><span class="p">(</span><span class="n">ws</span><span class="p">,</span> <span class="p">.</span><span class="n">channel</span> <span class="o">=</span> <span class="n">CHAT_CHANNEL</span><span class="p">,</span> <span class="p">.</span><span class="n">force_text</span> <span class="o">=</span> <span class="mi">1</span><span class="p">);</span> |
| <span class="cm">/* notify everyone about new (named) visitors */</span> |
| <span class="k">struct</span> <span class="n">nickname</span> <span class="o">*</span><span class="n">n</span> <span class="o">=</span> <span class="n">websocket_udata</span><span class="p">(</span><span class="n">ws</span><span class="p">);</span> |
| <span class="k">if</span> <span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="p">{</span> |
| <span class="n">FIOBJ</span> <span class="n">msg</span> <span class="o">=</span> <span class="n">fiobj_str_new</span><span class="p">(</span><span class="n">n</span><span class="o">-></span><span class="n">nick</span><span class="p">,</span> <span class="n">n</span><span class="o">-></span><span class="n">len</span><span class="p">);</span> |
| <span class="n">fiobj_str_write</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="s">" joined the chat."</span><span class="p">,</span> <span class="mi">17</span><span class="p">);</span> |
| <span class="n">pubsub_publish</span><span class="p">(.</span><span class="n">channel</span> <span class="o">=</span> <span class="n">CHAT_CHANNEL</span><span class="p">,</span> <span class="p">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">msg</span><span class="p">);</span> |
| <span class="cm">/* cleanup */</span> |
| <span class="n">fiobj_free</span><span class="p">(</span><span class="n">msg</span><span class="p">);</span> |
| <span class="p">}</span> |
| <span class="p">}</span> |
| |
| <span class="cm">/* Free the nickname, if any. */</span> |
| <span class="k">static</span> <span class="kt">void</span> <span class="nf">on_close_websocket</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="p">{</span> |
| <span class="k">struct</span> <span class="n">nickname</span> <span class="o">*</span><span class="n">n</span> <span class="o">=</span> <span class="n">websocket_udata</span><span class="p">(</span><span class="n">ws</span><span class="p">);</span> |
| <span class="k">if</span> <span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="p">{</span> |
| <span class="cm">/* send notification */</span> |
| <span class="n">FIOBJ</span> <span class="n">msg</span> <span class="o">=</span> <span class="n">fiobj_str_new</span><span class="p">(</span><span class="n">n</span><span class="o">-></span><span class="n">nick</span><span class="p">,</span> <span class="n">n</span><span class="o">-></span><span class="n">len</span><span class="p">);</span> |
| <span class="n">fiobj_str_write</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="s">" left the chat."</span><span class="p">,</span> <span class="mi">15</span><span class="p">);</span> |
| <span class="n">pubsub_publish</span><span class="p">(.</span><span class="n">channel</span> <span class="o">=</span> <span class="n">CHAT_CHANNEL</span><span class="p">,</span> <span class="p">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">msg</span><span class="p">);</span> |
| <span class="cm">/* cleanup */</span> |
| <span class="n">fiobj_free</span><span class="p">(</span><span class="n">msg</span><span class="p">);</span> |
| <span class="n">free</span><span class="p">(</span><span class="n">n</span><span class="p">);</span> |
| <span class="p">}</span> |
| <span class="p">}</span> |
| |
| <span class="cm">/* Received a message from a client, format message for chat . */</span> |
| <span class="k">static</span> <span class="kt">void</span> <span class="nf">handle_websocket_messages</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">char</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">size</span><span class="p">,</span> |
| <span class="kt">uint8_t</span> <span class="n">is_text</span><span class="p">)</span> <span class="p">{</span> |
| <span class="k">struct</span> <span class="n">nickname</span> <span class="o">*</span><span class="n">n</span> <span class="o">=</span> <span class="n">websocket_udata</span><span class="p">(</span><span class="n">ws</span><span class="p">);</span> |
| <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">n</span><span class="p">)</span> |
| <span class="n">n</span> <span class="o">=</span> <span class="o">&</span><span class="n">MISSING_NICKNAME</span><span class="p">;</span> |
| |
| <span class="cm">/* allocates a dynamic string. knowing the buffer size is faster */</span> |
| <span class="n">FIOBJ</span> <span class="n">msg</span> <span class="o">=</span> <span class="n">fiobj_str_buf</span><span class="p">(</span><span class="n">n</span><span class="o">-></span><span class="n">len</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">size</span><span class="p">);</span> |
| <span class="n">fiobj_str_write</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">n</span><span class="o">-></span><span class="n">nick</span><span class="p">,</span> <span class="n">n</span><span class="o">-></span><span class="n">len</span><span class="p">);</span> |
| <span class="n">fiobj_str_write</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="s">": "</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span> |
| <span class="n">fiobj_str_write</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span> |
| <span class="k">if</span> <span class="p">(</span><span class="n">pubsub_publish</span><span class="p">(.</span><span class="n">channel</span> <span class="o">=</span> <span class="n">CHAT_CHANNEL</span><span class="p">,</span> <span class="p">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">msg</span><span class="p">))</span> |
| <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Failed to publish</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> |
| <span class="n">fiobj_free</span><span class="p">(</span><span class="n">msg</span><span class="p">);</span> |
| <span class="p">(</span><span class="kt">void</span><span class="p">)(</span><span class="n">ws</span><span class="p">);</span> |
| <span class="p">(</span><span class="kt">void</span><span class="p">)(</span><span class="n">is_text</span><span class="p">);</span> |
| <span class="p">}</span> |
| |
| <span class="cm">/* ***************************************************************************** |
| HTTP Handling (Upgrading to Websocket) |
| ***************************************************************************** */</span> |
| |
| <span class="cm">/* Answers simple HTTP requests */</span> |
| <span class="k">static</span> <span class="kt">void</span> <span class="nf">answer_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="p">{</span> |
| <span class="n">http_set_header2</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="p">(</span><span class="n">fio_cstr_s</span><span class="p">){.</span><span class="n">name</span> <span class="o">=</span> <span class="s">"Server"</span><span class="p">,</span> <span class="p">.</span><span class="n">len</span> <span class="o">=</span> <span class="mi">6</span><span class="p">},</span> |
| <span class="p">(</span><span class="n">fio_cstr_s</span><span class="p">){.</span><span class="n">value</span> <span class="o">=</span> <span class="s">"facil.example"</span><span class="p">,</span> <span class="p">.</span><span class="n">len</span> <span class="o">=</span> <span class="mi">13</span><span class="p">});</span> |
| <span class="n">http_set_header</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="n">HTTP_HEADER_CONTENT_TYPE</span><span class="p">,</span> <span class="n">http_mimetype_find</span><span class="p">(</span><span class="s">"txt"</span><span class="p">,</span> <span class="mi">3</span><span class="p">));</span> |
| <span class="cm">/* this both sends the response and frees the http handler. */</span> |
| <span class="n">http_send_body</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="s">"This is a simple Websocket chatroom example."</span><span class="p">,</span> <span class="mi">44</span><span class="p">);</span> |
| <span class="p">}</span> |
| |
| <span class="cm">/* tests that the target protocol is "websockets" and upgrades the connection */</span> |
| <span class="k">static</span> <span class="kt">void</span> <span class="nf">answer_http_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="kt">char</span> <span class="o">*</span><span class="n">target</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">len</span><span class="p">)</span> <span class="p">{</span> |
| <span class="cm">/* test for target protocol name */</span> |
| <span class="k">if</span> <span class="p">(</span><span class="n">len</span> <span class="o">!=</span> <span class="mi">9</span> <span class="o">||</span> <span class="n">memcmp</span><span class="p">(</span><span class="n">target</span><span class="p">,</span> <span class="s">"websocket"</span><span class="p">,</span> <span class="mi">9</span><span class="p">))</span> <span class="p">{</span> |
| <span class="n">http_send_error</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="mi">400</span><span class="p">);</span> |
| <span class="k">return</span><span class="p">;</span> |
| <span class="p">}</span> |
| <span class="k">struct</span> <span class="n">nickname</span> <span class="o">*</span><span class="n">n</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> |
| <span class="n">fio_cstr_s</span> <span class="n">path</span> <span class="o">=</span> <span class="n">fiobj_obj2cstr</span><span class="p">(</span><span class="n">h</span><span class="o">-></span><span class="n">path</span><span class="p">);</span> |
| <span class="k">if</span> <span class="p">(</span><span class="n">path</span><span class="p">.</span><span class="n">len</span> <span class="o">></span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span> |
| <span class="n">n</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="n">path</span><span class="p">.</span><span class="n">len</span> <span class="o">+</span> <span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">n</span><span class="p">));</span> |
| <span class="n">n</span><span class="o">-></span><span class="n">len</span> <span class="o">=</span> <span class="n">path</span><span class="p">.</span><span class="n">len</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> |
| <span class="n">memcpy</span><span class="p">(</span><span class="n">n</span><span class="o">-></span><span class="n">nick</span><span class="p">,</span> <span class="n">path</span><span class="p">.</span><span class="n">data</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">path</span><span class="p">.</span><span class="n">len</span><span class="p">);</span> <span class="cm">/* will copy the NUL byte */</span> |
| <span class="p">}</span> |
| <span class="c1">// Websocket upgrade will use our existing response.</span> |
| <span class="k">if</span> <span class="p">(</span><span class="n">http_upgrade2ws</span><span class="p">(.</span><span class="n">http</span> <span class="o">=</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_websocket</span><span class="p">,</span> |
| <span class="p">.</span><span class="n">on_close</span> <span class="o">=</span> <span class="n">on_close_websocket</span><span class="p">,</span> |
| <span class="p">.</span><span class="n">on_message</span> <span class="o">=</span> <span class="n">handle_websocket_messages</span><span class="p">,</span> <span class="p">.</span><span class="n">udata</span> <span class="o">=</span> <span class="n">n</span><span class="p">))</span> |
| <span class="n">free</span><span class="p">(</span><span class="n">n</span><span class="p">);</span> |
| <span class="p">}</span> |
| |
| <span class="cm">/* Our main function, we'll start up the server */</span> |
| <span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</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="o">=</span> <span class="s">"3000"</span><span class="p">;</span> |
| <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">public_folder</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> |
| <span class="kt">uint32_t</span> <span class="n">threads</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> |
| <span class="kt">uint32_t</span> <span class="n">workers</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> |
| <span class="kt">uint8_t</span> <span class="n">print_log</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> |
| <span class="n">CHAT_CHANNEL</span> <span class="o">=</span> <span class="n">fiobj_sym_new</span><span class="p">(</span><span class="s">"chat"</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span> |
| |
| <span class="k">if</span> <span class="p">(</span><span class="n">http_listen</span><span class="p">(</span><span class="n">port</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">answer_http_request</span><span class="p">,</span> |
| <span class="p">.</span><span class="n">on_upgrade</span> <span class="o">=</span> <span class="n">answer_http_upgrade</span><span class="p">,</span> <span class="p">.</span><span class="n">log</span> <span class="o">=</span> <span class="n">print_log</span><span class="p">,</span> |
| <span class="p">.</span><span class="n">public_folder</span> <span class="o">=</span> <span class="n">public_folder</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> |
| <span class="n">perror</span><span class="p">(</span><span class="s">"Couldn't initiate Websocket service"</span><span class="p">),</span> <span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> |
| <span class="n">facil_run</span><span class="p">(.</span><span class="n">threads</span> <span class="o">=</span> <span class="n">threads</span><span class="p">,</span> <span class="p">.</span><span class="n">processes</span> <span class="o">=</span> <span class="n">workers</span><span class="p">);</span> |
| |
| <span class="n">fiobj_free</span><span class="p">(</span><span class="n">CHAT_CHANNEL</span><span class="p">);</span> |
| <span class="p">}</span> |
| </code></pre></div> |
| <h2 id="further-reading">Further reading</h2> |
| |
| <p>The code in this project is heavily commented and the header files could (and probably should) be used as the actual documentation.</p> |
| |
| <p>However, experience shows that a quick reference guide is immensely helpful and that Doxygen documentation is ... well ... less helpful and harder to navigate (I'll leave it at that for now).</p> |
| |
| <p>The documentation in this folder includes:</p> |
| |
| <ul> |
| <li><p>A <a href="getting_started.md">Getting Started Guide</a> with example for WebApps utilizing the HTTP / Websocket protocols as well as a custom protocol.</p></li> |
| <li><p>A <a href="fiobj.md">quick guide to <code>facil.io</code>'s dynamic type library</a> with quick examples get you started.</p></li> |
| <li><p>The core <a href="facil.md"><code>facil.io</code> API documentation</a>.</p> |
| |
| <p>This documents the main library API and should be used when writing custom protocols. This API is (mostly) redundant when using the <code>http</code> or <code>websockets</code> protocol extensions.</p></li> |
| <li><p>The <a href=""><code>http</code> extension API documentation</a> (Please help me write this).</p> |
| |
| <p>The <code>http</code> protocol extension allows quick access to the HTTP protocol necessary for writing web applications.</p> |
| |
| <p>Although the <code>libserver</code> API is still accessible, the <code>http_request_s</code> and <code>http_response_s</code> objects and API provide abstractions for the higher level HTTP protocol and should be preferred.</p></li> |
| <li><p>The <a href=""><code>websockets</code> extension API documentation</a> (Please help me write this).</p> |
| |
| <p>The <code>websockets</code> protocol extension allows quick access to the HTTP and Websockets protocols necessary for writing real-time web applications.</p> |
| |
| <p>Although the <code>libserver</code> API is still accessible, the <code>http_request_s</code>, <code>http_response_s</code> and <code>ws_s</code> objects and API provide abstractions for the higher level HTTP and Websocket protocols and should be preferred.</p></li> |
| <li><p>Core documentation that documents the libraries used internally.</p> |
| |
| <p>The core documentation can be safely ignored by anyone using the <code>facil.io</code>, <code>http</code> or <code>websockets</code> frameworks.</p> |
| |
| <p>The core libraries include (coming soon):</p> |
| |
| <ul> |
| <li><a href="./defer.md"><code>defer</code></a> - A simple event-loop with the added functionality of a thread pool and <code>fork</code>ing support.</li> |
| <li><a href="./sock.md"><code>sock</code></a> - A sockets library that resolves common issues such as fd collisions and user land buffer.</li> |
| <li><a href="./evio.md"><code>evio</code></a> - an edge triggered <code>kqueue</code> / <code>epoll</code> abstraction / wrapper with an overridable callback design, allowing fast access to these APIs while maintaining portability enhancing ease of use (at the expense of complexity).</li> |
| </ul></li> |
| </ul> |
| |
| <hr> |
| |
| <h2 id="forking-contributing-and-all-that-jazz">Forking, Contributing and all that Jazz</h2> |
| |
| <p>Sure, why not. If you can add Solaris or Windows support to <code>evio</code>, that could mean <code>facil.io</code> would become available for use on these platforms as well (as well as the HTTP protocol implementation and all the niceties that implies).</p> |
| |
| <p>If you encounter any issues, open an issue (or, even better, a pull request with a fix) - that would be great :-)</p> |
| |
| <p>Hit me up if you want to:</p> |
| |
| <ul> |
| <li><p>Help me write HPACK / HTTP2 protocol support.</p></li> |
| <li><p>Help me design / write a generic HTTP routing helper library for the <code>http_s</code> struct.</p></li> |
| <li><p>If you want to help integrate an SSL/TLS library into <code>facil</code>, that would be great.</p></li> |
| </ul> |
| </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> |