Sophie

Sophie

distrib > Mageia > 7 > armv7hl > media > core-release > by-pkgid > 63d08e0672e8e21a61288844222458a9 > files > 229

nghttp2-1.38.0-1.mga7.armv7hl.rpm



<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <title>Tutorial: HTTP/2 server &mdash; nghttp2 1.38.0 documentation</title>
  

  
  

  

  
  
    

  

  
  
    <link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
  

  

  
        <link rel="index" title="Index"
              href="genindex.html"/>
        <link rel="search" title="Search" href="search.html"/>
    <link rel="top" title="nghttp2 1.38.0 documentation" href="index.html"/>
        <link rel="next" title="Tutorial: HPACK API" href="tutorial-hpack.html"/>
        <link rel="prev" title="Tutorial: HTTP/2 client" href="tutorial-client.html"/> 

  
  <script src="_static/js/modernizr.min.js"></script>

</head>

<body class="wy-body-for-nav" role="document">

   
  <div class="wy-grid-for-nav">

    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-scroll">
        <div class="wy-side-nav-search">
          

          
            <a href="index.html" class="icon icon-home"> nghttp2
          

          
          </a>

          
            
            
              <div class="version">
                1.38.0
              </div>
            
          

          
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>

          
        </div>

        <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
          
            
            
                <ul class="current">
<li class="toctree-l1"><a class="reference internal" href="package_README.html">nghttp2 - HTTP/2 C Library</a></li>
<li class="toctree-l1"><a class="reference internal" href="contribute.html">Contribution Guidelines</a></li>
<li class="toctree-l1"><a class="reference internal" href="building-android-binary.html">Building Android binary</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-client.html">Tutorial: HTTP/2 client</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Tutorial: HTTP/2 server</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#libevent-server-c">libevent-server.c</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-hpack.html">Tutorial: HPACK API</a></li>
<li class="toctree-l1"><a class="reference internal" href="nghttp.1.html">nghttp(1)</a></li>
<li class="toctree-l1"><a class="reference internal" href="nghttpd.1.html">nghttpd(1)</a></li>
<li class="toctree-l1"><a class="reference internal" href="nghttpx.1.html">nghttpx(1)</a></li>
<li class="toctree-l1"><a class="reference internal" href="h2load.1.html">h2load(1)</a></li>
<li class="toctree-l1"><a class="reference internal" href="nghttpx-howto.html">nghttpx - HTTP/2 proxy - HOW-TO</a></li>
<li class="toctree-l1"><a class="reference internal" href="h2load-howto.html">h2load - HTTP/2 benchmarking tool - HOW-TO</a></li>
<li class="toctree-l1"><a class="reference internal" href="programmers-guide.html">Programmers’ Guide</a></li>
<li class="toctree-l1"><a class="reference internal" href="apiref.html">API Reference</a></li>
<li class="toctree-l1"><a class="reference internal" href="libnghttp2_asio.html">libnghttp2_asio: High level HTTP/2 C++ library</a></li>
<li class="toctree-l1"><a class="reference internal" href="python-apiref.html">Python API Reference</a></li>
<li class="toctree-l1"><a class="reference internal" href="nghttp2.h.html">nghttp2.h</a></li>
<li class="toctree-l1"><a class="reference internal" href="nghttp2ver.h.html">nghttp2ver.h</a></li>
<li class="toctree-l1"><a class="reference internal" href="asio_http2_server.h.html">asio_http2_server.h</a></li>
<li class="toctree-l1"><a class="reference internal" href="asio_http2_client.h.html">asio_http2_client.h</a></li>
<li class="toctree-l1"><a class="reference internal" href="asio_http2.h.html">asio_http2.h</a></li>
<li class="toctree-l1"><a class="reference external" href="https://github.com/nghttp2/nghttp2">Source</a></li>
<li class="toctree-l1"><a class="reference external" href="https://github.com/nghttp2/nghttp2/issues">Issues</a></li>
<li class="toctree-l1"><a class="reference external" href="https://nghttp2.org/">nghttp2.org</a></li>
</ul>

            
          
        </div>
      </div>
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">

      
      <nav class="wy-nav-top" role="navigation" aria-label="top navigation">
        <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
        <a href="index.html">nghttp2</a>
      </nav>


      
      <div class="wy-nav-content">
        <div class="rst-content">
          

 



<div role="navigation" aria-label="breadcrumbs navigation">
  <ul class="wy-breadcrumbs">
    <li><a href="index.html">Docs</a> &raquo;</li>
      
    <li>Tutorial: HTTP/2 server</li>
    <li class="wy-breadcrumbs-aside">
      
        
      
    </li>
  </ul>
  <hr/>
</div>
          <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
           <div itemprop="articleBody">
            
  <div class="section" id="tutorial-http-2-server">
<h1>Tutorial: HTTP/2 server<a class="headerlink" href="#tutorial-http-2-server" title="Permalink to this headline">¶</a></h1>
<p>In this tutorial, we are going to write a single-threaded, event-based
HTTP/2 web server, which supports HTTPS only. It can handle concurrent
multiple requests, but only the GET method is supported. The complete
source code, <a class="reference internal" href="#libevent-server-c">libevent-server.c</a>, is attached at the end of this
page.  The source also resides in the examples directory in the
archive or repository.</p>
<p>This simple server takes 3 arguments: The port number to listen on,
the path to your SSL/TLS private key file, and the path to your
certificate file.  The synopsis is:</p>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ libevent-server PORT /path/to/server.key /path/to/server.crt
</pre></div>
</div>
<p>We use libevent in this tutorial to handle networking I/O.  Please
note that nghttp2 itself does not depend on libevent.</p>
<p>The server starts with some libevent and OpenSSL setup in the
<code class="docutils literal notranslate"><span class="pre">main()</span></code> and <code class="docutils literal notranslate"><span class="pre">run()</span></code> functions. This setup isn’t specific to
nghttp2, but one thing you should look at is setup of the NPN
callback. The NPN callback is used by the server to advertise which
application protocols the server supports to a client.  In this
example program, when creating the <code class="docutils literal notranslate"><span class="pre">SSL_CTX</span></code> object, we store the
application protocol name in the wire format of NPN in a statically
allocated buffer. This is safe because we only create one <code class="docutils literal notranslate"><span class="pre">SSL_CTX</span></code>
object in the program’s entire lifetime.</p>
<p>If you are following TLS related RFC, you know that NPN is not the
standardized way to negotiate HTTP/2.  NPN itself is not even
published as RFC.  The standard way to negotiate HTTP/2 is ALPN,
Application-Layer Protocol Negotiation Extension, defined in <a class="reference external" href="https://tools.ietf.org/html/rfc7301">RFC 7301</a>.  The one caveat of ALPN is
that OpenSSL &gt;= 1.0.2 is required.  We use macro to enable/disable
ALPN support depending on OpenSSL version.  In ALPN, client sends the
list of supported application protocols, and server selects one of
them.  We provide the callback for it:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">next_proto_list</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span>
<span class="k">static</span> <span class="kt">size_t</span> <span class="n">next_proto_list_len</span><span class="p">;</span>

<span class="k">static</span> <span class="kt">int</span> <span class="nf">next_proto_cb</span><span class="p">(</span><span class="n">SSL</span> <span class="o">*</span><span class="n">s</span> <span class="n">_U_</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">**</span><span class="n">data</span><span class="p">,</span>
                         <span class="kt">unsigned</span> <span class="kt">int</span> <span class="o">*</span><span class="n">len</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">arg</span> <span class="n">_U_</span><span class="p">)</span> <span class="p">{</span>
  <span class="o">*</span><span class="n">data</span> <span class="o">=</span> <span class="n">next_proto_list</span><span class="p">;</span>
  <span class="o">*</span><span class="n">len</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span><span class="n">next_proto_list_len</span><span class="p">;</span>
  <span class="k">return</span> <span class="n">SSL_TLSEXT_ERR_OK</span><span class="p">;</span>
<span class="p">}</span>

<span class="cp">#if OPENSSL_VERSION_NUMBER &gt;= 0x10002000L</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">alpn_select_proto_cb</span><span class="p">(</span><span class="n">SSL</span> <span class="o">*</span><span class="n">ssl</span> <span class="n">_U_</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">**</span><span class="n">out</span><span class="p">,</span>
                                <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">outlen</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">in</span><span class="p">,</span>
                                <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">inlen</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">arg</span> <span class="n">_U_</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">rv</span><span class="p">;</span>

  <span class="n">rv</span> <span class="o">=</span> <span class="n">nghttp2_select_next_protocol</span><span class="p">((</span><span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">**</span><span class="p">)</span><span class="n">out</span><span class="p">,</span> <span class="n">outlen</span><span class="p">,</span> <span class="n">in</span><span class="p">,</span> <span class="n">inlen</span><span class="p">);</span>

  <span class="k">if</span> <span class="p">(</span><span class="n">rv</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">SSL_TLSEXT_ERR_NOACK</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="k">return</span> <span class="n">SSL_TLSEXT_ERR_OK</span><span class="p">;</span>
<span class="p">}</span>
<span class="cp">#endif </span><span class="c1">// OPENSSL_VERSION_NUMBER &gt;= 0x10002000L</span>

<span class="k">static</span> <span class="n">SSL_CTX</span> <span class="o">*</span><span class="nf">create_ssl_ctx</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">key_file</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">cert_file</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">SSL_CTX</span> <span class="o">*</span><span class="n">ssl_ctx</span><span class="p">;</span>
  <span class="n">EC_KEY</span> <span class="o">*</span><span class="n">ecdh</span><span class="p">;</span>

  <span class="n">ssl_ctx</span> <span class="o">=</span> <span class="n">SSL_CTX_new</span><span class="p">(</span><span class="n">SSLv23_server_method</span><span class="p">());</span>

  <span class="p">...</span>

  <span class="n">next_proto_list</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">NGHTTP2_PROTO_VERSION_ID_LEN</span><span class="p">;</span>
  <span class="n">memcpy</span><span class="p">(</span><span class="o">&amp;</span><span class="n">next_proto_list</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">NGHTTP2_PROTO_VERSION_ID</span><span class="p">,</span>
         <span class="n">NGHTTP2_PROTO_VERSION_ID_LEN</span><span class="p">);</span>
  <span class="n">next_proto_list_len</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="n">NGHTTP2_PROTO_VERSION_ID_LEN</span><span class="p">;</span>

  <span class="n">SSL_CTX_set_next_protos_advertised_cb</span><span class="p">(</span><span class="n">ssl_ctx</span><span class="p">,</span> <span class="n">next_proto_cb</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>

<span class="cp">#if OPENSSL_VERSION_NUMBER &gt;= 0x10002000L</span>
  <span class="n">SSL_CTX_set_alpn_select_cb</span><span class="p">(</span><span class="n">ssl_ctx</span><span class="p">,</span> <span class="n">alpn_select_proto_cb</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="cp">#endif </span><span class="c1">// OPENSSL_VERSION_NUMBER &gt;= 0x10002000L</span>

  <span class="k">return</span> <span class="n">ssl_ctx</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>The wire format of NPN is a sequence of length prefixed strings, with
exactly one byte used to specify the length of each protocol
identifier.  In this tutorial, we advertise the specific HTTP/2
protocol version the current nghttp2 library supports, which is
exported in the identifier <a class="reference internal" href="macros.html#c.NGHTTP2_PROTO_VERSION_ID" title="NGHTTP2_PROTO_VERSION_ID"><code class="xref c c-macro docutils literal notranslate"><span class="pre">NGHTTP2_PROTO_VERSION_ID</span></code></a>. The
<code class="docutils literal notranslate"><span class="pre">next_proto_cb()</span></code> function is the server-side NPN callback. In the
OpenSSL implementation, we just assign the pointer to the NPN buffers
we filled in earlier. The NPN callback function is set to the
<code class="docutils literal notranslate"><span class="pre">SSL_CTX</span></code> object using <code class="docutils literal notranslate"><span class="pre">SSL_CTX_set_next_protos_advertised_cb()</span></code>.</p>
<p>In <code class="docutils literal notranslate"><span class="pre">alpn_select_proto_cb()</span></code>, we use <a class="reference internal" href="nghttp2_select_next_protocol.html#c.nghttp2_select_next_protocol" title="nghttp2_select_next_protocol"><code class="xref c c-func docutils literal notranslate"><span class="pre">nghttp2_select_next_protocol()</span></code></a>
to select application protocol.  The <a class="reference internal" href="nghttp2_select_next_protocol.html#c.nghttp2_select_next_protocol" title="nghttp2_select_next_protocol"><code class="xref c c-func docutils literal notranslate"><span class="pre">nghttp2_select_next_protocol()</span></code></a>
returns 1 only if it selected h2 (ALPN identifier for HTTP/2), and out
parameters were assigned accordingly.</p>
<p>Next, let’s take a look at the main structures used by the example
application:</p>
<p>We use the <code class="docutils literal notranslate"><span class="pre">app_context</span></code> structure to store application-wide data:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="n">app_context</span> <span class="p">{</span>
  <span class="n">SSL_CTX</span> <span class="o">*</span><span class="n">ssl_ctx</span><span class="p">;</span>
  <span class="k">struct</span> <span class="n">event_base</span> <span class="o">*</span><span class="n">evbase</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>We use the <code class="docutils literal notranslate"><span class="pre">http2_session_data</span></code> structure to store session-level
(which corresponds to one HTTP/2 connection) data:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">typedef</span> <span class="k">struct</span> <span class="n">http2_session_data</span> <span class="p">{</span>
  <span class="k">struct</span> <span class="n">http2_stream_data</span> <span class="n">root</span><span class="p">;</span>
  <span class="k">struct</span> <span class="n">bufferevent</span> <span class="o">*</span><span class="n">bev</span><span class="p">;</span>
  <span class="n">app_context</span> <span class="o">*</span><span class="n">app_ctx</span><span class="p">;</span>
  <span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">;</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">client_addr</span><span class="p">;</span>
<span class="p">}</span> <span class="n">http2_session_data</span><span class="p">;</span>
</pre></div>
</div>
<p>We use the <code class="docutils literal notranslate"><span class="pre">http2_stream_data</span></code> structure to store stream-level data:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">typedef</span> <span class="k">struct</span> <span class="n">http2_stream_data</span> <span class="p">{</span>
  <span class="k">struct</span> <span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">prev</span><span class="p">,</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">request_path</span><span class="p">;</span>
  <span class="kt">int32_t</span> <span class="n">stream_id</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">fd</span><span class="p">;</span>
<span class="p">}</span> <span class="n">http2_stream_data</span><span class="p">;</span>
</pre></div>
</div>
<p>A single HTTP/2 session can have multiple streams.  To manage them, we
use a doubly linked list:  The first element of this list is pointed
to by the <code class="docutils literal notranslate"><span class="pre">root-&gt;next</span></code> in <code class="docutils literal notranslate"><span class="pre">http2_session_data</span></code>.  Initially,
<code class="docutils literal notranslate"><span class="pre">root-&gt;next</span></code> is <code class="docutils literal notranslate"><span class="pre">NULL</span></code>.</p>
<p>libevent’s bufferevent structure is used to perform network I/O, with
the pointer to the bufferevent stored in the <code class="docutils literal notranslate"><span class="pre">http2_session_data</span></code>
structure.  Note that the bufferevent object is kept in
<code class="docutils literal notranslate"><span class="pre">http2_session_data</span></code> and not in <code class="docutils literal notranslate"><span class="pre">http2_stream_data</span></code>. This is
because <code class="docutils literal notranslate"><span class="pre">http2_stream_data</span></code> is just a logical stream multiplexed
over the single connection managed by the bufferevent in
<code class="docutils literal notranslate"><span class="pre">http2_session_data</span></code>.</p>
<p>We first create a listener object to accept incoming connections.
libevent’s <code class="docutils literal notranslate"><span class="pre">struct</span> <span class="pre">evconnlistener</span></code> is used for this purpose:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">void</span> <span class="nf">start_listen</span><span class="p">(</span><span class="k">struct</span> <span class="n">event_base</span> <span class="o">*</span><span class="n">evbase</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">service</span><span class="p">,</span>
                         <span class="n">app_context</span> <span class="o">*</span><span class="n">app_ctx</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">rv</span><span class="p">;</span>
  <span class="k">struct</span> <span class="n">addrinfo</span> <span class="n">hints</span><span class="p">;</span>
  <span class="k">struct</span> <span class="n">addrinfo</span> <span class="o">*</span><span class="n">res</span><span class="p">,</span> <span class="o">*</span><span class="n">rp</span><span class="p">;</span>

  <span class="n">memset</span><span class="p">(</span><span class="o">&amp;</span><span class="n">hints</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">hints</span><span class="p">));</span>
  <span class="n">hints</span><span class="p">.</span><span class="n">ai_family</span> <span class="o">=</span> <span class="n">AF_UNSPEC</span><span class="p">;</span>
  <span class="n">hints</span><span class="p">.</span><span class="n">ai_socktype</span> <span class="o">=</span> <span class="n">SOCK_STREAM</span><span class="p">;</span>
  <span class="n">hints</span><span class="p">.</span><span class="n">ai_flags</span> <span class="o">=</span> <span class="n">AI_PASSIVE</span><span class="p">;</span>
<span class="cp">#ifdef AI_ADDRCONFIG</span>
  <span class="n">hints</span><span class="p">.</span><span class="n">ai_flags</span> <span class="o">|=</span> <span class="n">AI_ADDRCONFIG</span><span class="p">;</span>
<span class="cp">#endif </span><span class="cm">/* AI_ADDRCONFIG */</span><span class="cp"></span>

  <span class="n">rv</span> <span class="o">=</span> <span class="n">getaddrinfo</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="n">service</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">hints</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">res</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">rv</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">errx</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">for</span> <span class="p">(</span><span class="n">rp</span> <span class="o">=</span> <span class="n">res</span><span class="p">;</span> <span class="n">rp</span><span class="p">;</span> <span class="n">rp</span> <span class="o">=</span> <span class="n">rp</span><span class="o">-&gt;</span><span class="n">ai_next</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">evconnlistener</span> <span class="o">*</span><span class="n">listener</span><span class="p">;</span>
    <span class="n">listener</span> <span class="o">=</span> <span class="n">evconnlistener_new_bind</span><span class="p">(</span>
        <span class="n">evbase</span><span class="p">,</span> <span class="n">acceptcb</span><span class="p">,</span> <span class="n">app_ctx</span><span class="p">,</span> <span class="n">LEV_OPT_CLOSE_ON_FREE</span> <span class="o">|</span> <span class="n">LEV_OPT_REUSEABLE</span><span class="p">,</span>
        <span class="mi">16</span><span class="p">,</span> <span class="n">rp</span><span class="o">-&gt;</span><span class="n">ai_addr</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">rp</span><span class="o">-&gt;</span><span class="n">ai_addrlen</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">listener</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">freeaddrinfo</span><span class="p">(</span><span class="n">res</span><span class="p">);</span>

      <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="n">errx</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">&quot;Could not start listener&quot;</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>We specify the <code class="docutils literal notranslate"><span class="pre">acceptcb</span></code> callback, which is called when a new connection is
accepted:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">void</span> <span class="nf">acceptcb</span><span class="p">(</span><span class="k">struct</span> <span class="n">evconnlistener</span> <span class="o">*</span><span class="n">listener</span> <span class="n">_U_</span><span class="p">,</span> <span class="kt">int</span> <span class="n">fd</span><span class="p">,</span>
                     <span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="n">addr</span><span class="p">,</span> <span class="kt">int</span> <span class="n">addrlen</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">arg</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">app_context</span> <span class="o">*</span><span class="n">app_ctx</span> <span class="o">=</span> <span class="p">(</span><span class="n">app_context</span> <span class="o">*</span><span class="p">)</span><span class="n">arg</span><span class="p">;</span>
  <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">;</span>

  <span class="n">session_data</span> <span class="o">=</span> <span class="n">create_http2_session_data</span><span class="p">(</span><span class="n">app_ctx</span><span class="p">,</span> <span class="n">fd</span><span class="p">,</span> <span class="n">addr</span><span class="p">,</span> <span class="n">addrlen</span><span class="p">);</span>

  <span class="n">bufferevent_setcb</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">bev</span><span class="p">,</span> <span class="n">readcb</span><span class="p">,</span> <span class="n">writecb</span><span class="p">,</span> <span class="n">eventcb</span><span class="p">,</span> <span class="n">session_data</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Here we create the <code class="docutils literal notranslate"><span class="pre">http2_session_data</span></code> object. The connection’s
bufferevent is initialized at the same time. We specify three
callbacks for the bufferevent: <code class="docutils literal notranslate"><span class="pre">readcb</span></code>, <code class="docutils literal notranslate"><span class="pre">writecb</span></code>, and
<code class="docutils literal notranslate"><span class="pre">eventcb</span></code>.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">eventcb()</span></code> callback is invoked by the libevent event loop when an event
(e.g. connection has been established, timeout, etc.) occurs on the
underlying network socket:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">void</span> <span class="nf">eventcb</span><span class="p">(</span><span class="k">struct</span> <span class="n">bufferevent</span> <span class="o">*</span><span class="n">bev</span> <span class="n">_U_</span><span class="p">,</span> <span class="kt">short</span> <span class="n">events</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">ptr</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span> <span class="o">=</span> <span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="p">)</span><span class="n">ptr</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">events</span> <span class="o">&amp;</span> <span class="n">BEV_EVENT_CONNECTED</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">alpn</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">alpnlen</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">SSL</span> <span class="o">*</span><span class="n">ssl</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">&quot;%s connected</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">client_addr</span><span class="p">);</span>

    <span class="n">ssl</span> <span class="o">=</span> <span class="n">bufferevent_openssl_get_ssl</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">bev</span><span class="p">);</span>

    <span class="n">SSL_get0_next_proto_negotiated</span><span class="p">(</span><span class="n">ssl</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">alpn</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">alpnlen</span><span class="p">);</span>
<span class="cp">#if OPENSSL_VERSION_NUMBER &gt;= 0x10002000L</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">alpn</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">SSL_get0_alpn_selected</span><span class="p">(</span><span class="n">ssl</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">alpn</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">alpnlen</span><span class="p">);</span>
    <span class="p">}</span>
<span class="cp">#endif </span><span class="c1">// OPENSSL_VERSION_NUMBER &gt;= 0x10002000L</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">alpn</span> <span class="o">==</span> <span class="nb">NULL</span> <span class="o">||</span> <span class="n">alpnlen</span> <span class="o">!=</span> <span class="mi">2</span> <span class="o">||</span> <span class="n">memcmp</span><span class="p">(</span><span class="s">&quot;h2&quot;</span><span class="p">,</span> <span class="n">alpn</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</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">&quot;%s h2 is not negotiated</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">client_addr</span><span class="p">);</span>
      <span class="n">delete_http2_session_data</span><span class="p">(</span><span class="n">session_data</span><span class="p">);</span>
      <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">initialize_nghttp2_session</span><span class="p">(</span><span class="n">session_data</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">send_server_connection_header</span><span class="p">(</span><span class="n">session_data</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span> <span class="o">||</span>
        <span class="n">session_send</span><span class="p">(</span><span class="n">session_data</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">delete_http2_session_data</span><span class="p">(</span><span class="n">session_data</span><span class="p">);</span>
      <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">events</span> <span class="o">&amp;</span> <span class="n">BEV_EVENT_EOF</span><span class="p">)</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">&quot;%s EOF</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">client_addr</span><span class="p">);</span>
  <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">events</span> <span class="o">&amp;</span> <span class="n">BEV_EVENT_ERROR</span><span class="p">)</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">&quot;%s network error</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">client_addr</span><span class="p">);</span>
  <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">events</span> <span class="o">&amp;</span> <span class="n">BEV_EVENT_TIMEOUT</span><span class="p">)</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">&quot;%s timeout</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">client_addr</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="n">delete_http2_session_data</span><span class="p">(</span><span class="n">session_data</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Here we validate that HTTP/2 is negotiated, and if not, drop
connection.</p>
<p>For the <code class="docutils literal notranslate"><span class="pre">BEV_EVENT_EOF</span></code>, <code class="docutils literal notranslate"><span class="pre">BEV_EVENT_ERROR</span></code>, and
<code class="docutils literal notranslate"><span class="pre">BEV_EVENT_TIMEOUT</span></code> events, we just simply tear down the connection.
The <code class="docutils literal notranslate"><span class="pre">delete_http2_session_data()</span></code> function destroys the
<code class="docutils literal notranslate"><span class="pre">http2_session_data</span></code> object and its associated bufferevent member.
As a result, the underlying connection is closed.</p>
<p>The
<code class="docutils literal notranslate"><span class="pre">BEV_EVENT_CONNECTED</span></code> event is invoked when SSL/TLS handshake has
completed successfully. After this we are ready to begin communicating
via HTTP/2.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">initialize_nghttp2_session()</span></code> function initializes the nghttp2
session object and several callbacks:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">void</span> <span class="nf">initialize_nghttp2_session</span><span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">nghttp2_session_callbacks</span> <span class="o">*</span><span class="n">callbacks</span><span class="p">;</span>

  <span class="n">nghttp2_session_callbacks_new</span><span class="p">(</span><span class="o">&amp;</span><span class="n">callbacks</span><span class="p">);</span>

  <span class="n">nghttp2_session_callbacks_set_send_callback</span><span class="p">(</span><span class="n">callbacks</span><span class="p">,</span> <span class="n">send_callback</span><span class="p">);</span>

  <span class="n">nghttp2_session_callbacks_set_on_frame_recv_callback</span><span class="p">(</span><span class="n">callbacks</span><span class="p">,</span>
                                                       <span class="n">on_frame_recv_callback</span><span class="p">);</span>

  <span class="n">nghttp2_session_callbacks_set_on_stream_close_callback</span><span class="p">(</span>
      <span class="n">callbacks</span><span class="p">,</span> <span class="n">on_stream_close_callback</span><span class="p">);</span>

  <span class="n">nghttp2_session_callbacks_set_on_header_callback</span><span class="p">(</span><span class="n">callbacks</span><span class="p">,</span>
                                                   <span class="n">on_header_callback</span><span class="p">);</span>

  <span class="n">nghttp2_session_callbacks_set_on_begin_headers_callback</span><span class="p">(</span>
      <span class="n">callbacks</span><span class="p">,</span> <span class="n">on_begin_headers_callback</span><span class="p">);</span>

  <span class="n">nghttp2_session_server_new</span><span class="p">(</span><span class="o">&amp;</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">session</span><span class="p">,</span> <span class="n">callbacks</span><span class="p">,</span> <span class="n">session_data</span><span class="p">);</span>

  <span class="n">nghttp2_session_callbacks_del</span><span class="p">(</span><span class="n">callbacks</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Since we are creating a server, we use <a class="reference internal" href="nghttp2_session_server_new.html#c.nghttp2_session_server_new" title="nghttp2_session_server_new"><code class="xref c c-func docutils literal notranslate"><span class="pre">nghttp2_session_server_new()</span></code></a>
to initialize the nghttp2 session object.  We also setup 5 callbacks
for the nghttp2 session, these are explained later.</p>
<p>The server now begins by sending the server connection preface, which
always consists of a SETTINGS frame.
<code class="docutils literal notranslate"><span class="pre">send_server_connection_header()</span></code> configures and submits it:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">send_server_connection_header</span><span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">nghttp2_settings_entry</span> <span class="n">iv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
      <span class="p">{</span><span class="n">NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS</span><span class="p">,</span> <span class="mi">100</span><span class="p">}};</span>
  <span class="kt">int</span> <span class="n">rv</span><span class="p">;</span>

  <span class="n">rv</span> <span class="o">=</span> <span class="n">nghttp2_submit_settings</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">session</span><span class="p">,</span> <span class="n">NGHTTP2_FLAG_NONE</span><span class="p">,</span> <span class="n">iv</span><span class="p">,</span>
                               <span class="n">ARRLEN</span><span class="p">(</span><span class="n">iv</span><span class="p">));</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">rv</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">warnx</span><span class="p">(</span><span class="s">&quot;Fatal error: %s&quot;</span><span class="p">,</span> <span class="n">nghttp2_strerror</span><span class="p">(</span><span class="n">rv</span><span class="p">));</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>In the example SETTINGS frame we’ve set
SETTINGS_MAX_CONCURRENT_STREAMS to 100. <a class="reference internal" href="nghttp2_submit_settings.html#c.nghttp2_submit_settings" title="nghttp2_submit_settings"><code class="xref c c-func docutils literal notranslate"><span class="pre">nghttp2_submit_settings()</span></code></a>
is used to queue the frame for transmission, but note it only queues
the frame for transmission, and doesn’t actually send it. All
functions in the <code class="docutils literal notranslate"><span class="pre">nghttp2_submit_*()</span></code> family have this property. To
actually send the frame, <a class="reference internal" href="nghttp2_session_send.html#c.nghttp2_session_send" title="nghttp2_session_send"><code class="xref c c-func docutils literal notranslate"><span class="pre">nghttp2_session_send()</span></code></a> should be used, as
described later.</p>
<p>Since bufferevent may buffer more than the first 24 bytes from the client, we
have to process them here since libevent won’t invoke callback functions for
this pending data. To process the received data, we call the
<code class="docutils literal notranslate"><span class="pre">session_recv()</span></code> function:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">session_recv</span><span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">ssize_t</span> <span class="n">readlen</span><span class="p">;</span>
  <span class="k">struct</span> <span class="n">evbuffer</span> <span class="o">*</span><span class="n">input</span> <span class="o">=</span> <span class="n">bufferevent_get_input</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">bev</span><span class="p">);</span>
  <span class="kt">size_t</span> <span class="n">datalen</span> <span class="o">=</span> <span class="n">evbuffer_get_length</span><span class="p">(</span><span class="n">input</span><span class="p">);</span>
  <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">data</span> <span class="o">=</span> <span class="n">evbuffer_pullup</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">);</span>

  <span class="n">readlen</span> <span class="o">=</span> <span class="n">nghttp2_session_mem_recv</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">session</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">datalen</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">readlen</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">warnx</span><span class="p">(</span><span class="s">&quot;Fatal error: %s&quot;</span><span class="p">,</span> <span class="n">nghttp2_strerror</span><span class="p">((</span><span class="kt">int</span><span class="p">)</span><span class="n">readlen</span><span class="p">));</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">evbuffer_drain</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="p">(</span><span class="kt">size_t</span><span class="p">)</span><span class="n">readlen</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">warnx</span><span class="p">(</span><span class="s">&quot;Fatal error: evbuffer_drain failed&quot;</span><span class="p">);</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">session_send</span><span class="p">(</span><span class="n">session_data</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>In this function, we feed all unprocessed but already received data to
the nghttp2 session object using the <a class="reference internal" href="nghttp2_session_mem_recv.html#c.nghttp2_session_mem_recv" title="nghttp2_session_mem_recv"><code class="xref c c-func docutils literal notranslate"><span class="pre">nghttp2_session_mem_recv()</span></code></a>
function. The <a class="reference internal" href="nghttp2_session_mem_recv.html#c.nghttp2_session_mem_recv" title="nghttp2_session_mem_recv"><code class="xref c c-func docutils literal notranslate"><span class="pre">nghttp2_session_mem_recv()</span></code></a> function processes the data
and may both invoke the previously setup callbacks and also queue
outgoing frames. To send any pending outgoing frames, we immediately
call <code class="docutils literal notranslate"><span class="pre">session_send()</span></code>.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">session_send()</span></code> function is defined as follows:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">session_send</span><span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">rv</span><span class="p">;</span>
  <span class="n">rv</span> <span class="o">=</span> <span class="n">nghttp2_session_send</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">session</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">rv</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">warnx</span><span class="p">(</span><span class="s">&quot;Fatal error: %s&quot;</span><span class="p">,</span> <span class="n">nghttp2_strerror</span><span class="p">(</span><span class="n">rv</span><span class="p">));</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>The <a class="reference internal" href="nghttp2_session_send.html#c.nghttp2_session_send" title="nghttp2_session_send"><code class="xref c c-func docutils literal notranslate"><span class="pre">nghttp2_session_send()</span></code></a> function serializes the frame into wire
format and calls the <code class="docutils literal notranslate"><span class="pre">send_callback()</span></code>, which is of type
<a class="reference internal" href="types.html#c.nghttp2_send_callback" title="nghttp2_send_callback"><code class="xref c c-type docutils literal notranslate"><span class="pre">nghttp2_send_callback</span></code></a>.  The <code class="docutils literal notranslate"><span class="pre">send_callback()</span></code> is defined as
follows:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">ssize_t</span> <span class="nf">send_callback</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span> <span class="n">_U_</span><span class="p">,</span> <span class="k">const</span> <span class="kt">uint8_t</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> <span class="kt">int</span> <span class="n">flags</span> <span class="n">_U_</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">user_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span> <span class="o">=</span> <span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="p">)</span><span class="n">user_data</span><span class="p">;</span>
  <span class="k">struct</span> <span class="n">bufferevent</span> <span class="o">*</span><span class="n">bev</span> <span class="o">=</span> <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">bev</span><span class="p">;</span>
  <span class="cm">/* Avoid excessive buffering in server side. */</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">evbuffer_get_length</span><span class="p">(</span><span class="n">bufferevent_get_output</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">bev</span><span class="p">))</span> <span class="o">&gt;=</span>
      <span class="n">OUTPUT_WOULDBLOCK_THRESHOLD</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">NGHTTP2_ERR_WOULDBLOCK</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">bufferevent_write</span><span class="p">(</span><span class="n">bev</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">length</span><span class="p">);</span>
  <span class="k">return</span> <span class="p">(</span><span class="kt">ssize_t</span><span class="p">)</span><span class="n">length</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Since we use bufferevent to abstract network I/O, we just write the
data to the bufferevent object. Note that <a class="reference internal" href="nghttp2_session_send.html#c.nghttp2_session_send" title="nghttp2_session_send"><code class="xref c c-func docutils literal notranslate"><span class="pre">nghttp2_session_send()</span></code></a>
continues to write all frames queued so far. If we were writing the
data to a non-blocking socket directly using the <code class="docutils literal notranslate"><span class="pre">write()</span></code> system
call in the <code class="docutils literal notranslate"><span class="pre">send_callback()</span></code>, we’d soon receive an  <code class="docutils literal notranslate"><span class="pre">EAGAIN</span></code> or
<code class="docutils literal notranslate"><span class="pre">EWOULDBLOCK</span></code> error since sockets have a limited send buffer. If
that happens, it’s possible to return <a class="reference internal" href="enums.html#c.NGHTTP2_ERR_WOULDBLOCK" title="NGHTTP2_ERR_WOULDBLOCK"><code class="xref c c-macro docutils literal notranslate"><span class="pre">NGHTTP2_ERR_WOULDBLOCK</span></code></a>
to signal the nghttp2 library to stop sending further data. But here,
when writing to the bufferevent, we have to regulate the amount data
to buffered ourselves to avoid using huge amounts of memory. To
achieve this, we check the size of the output buffer and if it reaches
more than or equal to <code class="docutils literal notranslate"><span class="pre">OUTPUT_WOULDBLOCK_THRESHOLD</span></code> bytes, we stop
writing data and return <a class="reference internal" href="enums.html#c.NGHTTP2_ERR_WOULDBLOCK" title="NGHTTP2_ERR_WOULDBLOCK"><code class="xref c c-macro docutils literal notranslate"><span class="pre">NGHTTP2_ERR_WOULDBLOCK</span></code></a>.</p>
<p>The next bufferevent callback is <code class="docutils literal notranslate"><span class="pre">readcb()</span></code>, which is invoked when
data is available to read in the bufferevent input buffer:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">void</span> <span class="nf">readcb</span><span class="p">(</span><span class="k">struct</span> <span class="n">bufferevent</span> <span class="o">*</span><span class="n">bev</span> <span class="n">_U_</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">ptr</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span> <span class="o">=</span> <span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="p">)</span><span class="n">ptr</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">session_recv</span><span class="p">(</span><span class="n">session_data</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">delete_http2_session_data</span><span class="p">(</span><span class="n">session_data</span><span class="p">);</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>In this function, we just call <code class="docutils literal notranslate"><span class="pre">session_recv()</span></code> to process incoming
data.</p>
<p>The third bufferevent callback is <code class="docutils literal notranslate"><span class="pre">writecb()</span></code>, which is invoked when all
data in the bufferevent output buffer has been sent:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">void</span> <span class="nf">writecb</span><span class="p">(</span><span class="k">struct</span> <span class="n">bufferevent</span> <span class="o">*</span><span class="n">bev</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">ptr</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span> <span class="o">=</span> <span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="p">)</span><span class="n">ptr</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">evbuffer_get_length</span><span class="p">(</span><span class="n">bufferevent_get_output</span><span class="p">(</span><span class="n">bev</span><span class="p">))</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">nghttp2_session_want_read</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">session</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span>
      <span class="n">nghttp2_session_want_write</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">session</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">delete_http2_session_data</span><span class="p">(</span><span class="n">session_data</span><span class="p">);</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">session_send</span><span class="p">(</span><span class="n">session_data</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">delete_http2_session_data</span><span class="p">(</span><span class="n">session_data</span><span class="p">);</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>First we check whether we should drop the connection or not. The
nghttp2 session object keeps track of reception and transmission of
GOAWAY frames and other error conditions as well. Using this
information, the nghttp2 session object can state whether the
connection should be dropped or not. More specifically, if both
<a class="reference internal" href="nghttp2_session_want_read.html#c.nghttp2_session_want_read" title="nghttp2_session_want_read"><code class="xref c c-func docutils literal notranslate"><span class="pre">nghttp2_session_want_read()</span></code></a> and <a class="reference internal" href="nghttp2_session_want_write.html#c.nghttp2_session_want_write" title="nghttp2_session_want_write"><code class="xref c c-func docutils literal notranslate"><span class="pre">nghttp2_session_want_write()</span></code></a>
return 0, the connection is no-longer required and can be closed.
Since we are using bufferevent and its deferred callback option, the
bufferevent output buffer may still contain pending data when the
<code class="docutils literal notranslate"><span class="pre">writecb()</span></code> is called. To handle this, we check whether the output
buffer is empty or not. If all of these conditions are met, we drop
connection.</p>
<p>Otherwise, we call <code class="docutils literal notranslate"><span class="pre">session_send()</span></code> to process the pending output
data. Remember that in <code class="docutils literal notranslate"><span class="pre">send_callback()</span></code>, we must not write all data to
bufferevent to avoid excessive buffering. We continue processing pending data
when the output buffer becomes empty.</p>
<p>We have already described the nghttp2 callback <code class="docutils literal notranslate"><span class="pre">send_callback()</span></code>.  Let’s
learn about the remaining nghttp2 callbacks setup in
<code class="docutils literal notranslate"><span class="pre">initialize_nghttp2_setup()</span></code> function.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">on_begin_headers_callback()</span></code> function is invoked when the reception of
a header block in HEADERS or PUSH_PROMISE frame is started:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">on_begin_headers_callback</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span>
                                     <span class="k">const</span> <span class="n">nghttp2_frame</span> <span class="o">*</span><span class="n">frame</span><span class="p">,</span>
                                     <span class="kt">void</span> <span class="o">*</span><span class="n">user_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span> <span class="o">=</span> <span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="p">)</span><span class="n">user_data</span><span class="p">;</span>
  <span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">stream_data</span><span class="p">;</span>

  <span class="k">if</span> <span class="p">(</span><span class="n">frame</span><span class="o">-&gt;</span><span class="n">hd</span><span class="p">.</span><span class="n">type</span> <span class="o">!=</span> <span class="n">NGHTTP2_HEADERS</span> <span class="o">||</span>
      <span class="n">frame</span><span class="o">-&gt;</span><span class="n">headers</span><span class="p">.</span><span class="n">cat</span> <span class="o">!=</span> <span class="n">NGHTTP2_HCAT_REQUEST</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">stream_data</span> <span class="o">=</span> <span class="n">create_http2_stream_data</span><span class="p">(</span><span class="n">session_data</span><span class="p">,</span> <span class="n">frame</span><span class="o">-&gt;</span><span class="n">hd</span><span class="p">.</span><span class="n">stream_id</span><span class="p">);</span>
  <span class="n">nghttp2_session_set_stream_user_data</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">frame</span><span class="o">-&gt;</span><span class="n">hd</span><span class="p">.</span><span class="n">stream_id</span><span class="p">,</span>
                                       <span class="n">stream_data</span><span class="p">);</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>We are only interested in the HEADERS frame in this function. Since
the HEADERS frame has several roles in the HTTP/2 protocol, we check
that it is a request HEADERS, which opens new stream. If the frame is
a request HEADERS, we create a <code class="docutils literal notranslate"><span class="pre">http2_stream_data</span></code> object to store
the stream related data. We associate the created
<code class="docutils literal notranslate"><span class="pre">http2_stream_data</span></code> object with the stream in the nghttp2 session
object using <code class="xref c c-func docutils literal notranslate"><span class="pre">nghttp2_set_stream_user_data()</span></code>. The
<code class="docutils literal notranslate"><span class="pre">http2_stream_data</span></code> object can later be easily retrieved from the
stream, without searching through the doubly linked list.</p>
<p>In this example server, we want to serve files relative to the current working
directory in which the program was invoked. Each header name/value pair is
emitted via <code class="docutils literal notranslate"><span class="pre">on_header_callback</span></code> function, which is called after
<code class="docutils literal notranslate"><span class="pre">on_begin_headers_callback()</span></code>:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">on_header_callback</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span>
                              <span class="k">const</span> <span class="n">nghttp2_frame</span> <span class="o">*</span><span class="n">frame</span><span class="p">,</span> <span class="k">const</span> <span class="kt">uint8_t</span> <span class="o">*</span><span class="n">name</span><span class="p">,</span>
                              <span class="kt">size_t</span> <span class="n">namelen</span><span class="p">,</span> <span class="k">const</span> <span class="kt">uint8_t</span> <span class="o">*</span><span class="n">value</span><span class="p">,</span>
                              <span class="kt">size_t</span> <span class="n">valuelen</span><span class="p">,</span> <span class="kt">uint8_t</span> <span class="n">flags</span> <span class="n">_U_</span><span class="p">,</span>
                              <span class="kt">void</span> <span class="o">*</span><span class="n">user_data</span> <span class="n">_U_</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">stream_data</span><span class="p">;</span>
  <span class="k">const</span> <span class="kt">char</span> <span class="n">PATH</span><span class="p">[]</span> <span class="o">=</span> <span class="s">&quot;:path&quot;</span><span class="p">;</span>
  <span class="k">switch</span> <span class="p">(</span><span class="n">frame</span><span class="o">-&gt;</span><span class="n">hd</span><span class="p">.</span><span class="n">type</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">case</span> <span class="nl">NGHTTP2_HEADERS</span><span class="p">:</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">frame</span><span class="o">-&gt;</span><span class="n">headers</span><span class="p">.</span><span class="n">cat</span> <span class="o">!=</span> <span class="n">NGHTTP2_HCAT_REQUEST</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">break</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">stream_data</span> <span class="o">=</span>
        <span class="n">nghttp2_session_get_stream_user_data</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">frame</span><span class="o">-&gt;</span><span class="n">hd</span><span class="p">.</span><span class="n">stream_id</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">stream_data</span> <span class="o">||</span> <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">request_path</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">break</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">namelen</span> <span class="o">==</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">PATH</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="n">memcmp</span><span class="p">(</span><span class="n">PATH</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">namelen</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="kt">size_t</span> <span class="n">j</span><span class="p">;</span>
      <span class="k">for</span> <span class="p">(</span><span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">valuelen</span> <span class="o">&amp;&amp;</span> <span class="n">value</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">!=</span> <span class="sc">&#39;?&#39;</span><span class="p">;</span> <span class="o">++</span><span class="n">j</span><span class="p">)</span>
        <span class="p">;</span>
      <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">request_path</span> <span class="o">=</span> <span class="n">percent_decode</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">j</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">break</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>We search for the <code class="docutils literal notranslate"><span class="pre">:path</span></code> header field among the request headers and
store the requested path in the <code class="docutils literal notranslate"><span class="pre">http2_stream_data</span></code> object. In this
example program, we ignore the <code class="docutils literal notranslate"><span class="pre">:method</span></code> header field and always
treat the request as a GET request.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">on_frame_recv_callback()</span></code> function is invoked when a frame is
fully received:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">on_frame_recv_callback</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span>
                                  <span class="k">const</span> <span class="n">nghttp2_frame</span> <span class="o">*</span><span class="n">frame</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">user_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span> <span class="o">=</span> <span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="p">)</span><span class="n">user_data</span><span class="p">;</span>
  <span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">stream_data</span><span class="p">;</span>
  <span class="k">switch</span> <span class="p">(</span><span class="n">frame</span><span class="o">-&gt;</span><span class="n">hd</span><span class="p">.</span><span class="n">type</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">case</span> <span class="nl">NGHTTP2_DATA</span><span class="p">:</span>
  <span class="k">case</span> <span class="nl">NGHTTP2_HEADERS</span><span class="p">:</span>
    <span class="cm">/* Check that the client request has finished */</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">frame</span><span class="o">-&gt;</span><span class="n">hd</span><span class="p">.</span><span class="n">flags</span> <span class="o">&amp;</span> <span class="n">NGHTTP2_FLAG_END_STREAM</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">stream_data</span> <span class="o">=</span>
          <span class="n">nghttp2_session_get_stream_user_data</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">frame</span><span class="o">-&gt;</span><span class="n">hd</span><span class="p">.</span><span class="n">stream_id</span><span class="p">);</span>
      <span class="cm">/* For DATA and HEADERS frame, this callback may be called after</span>
<span class="cm">         on_stream_close_callback. Check that stream still alive. */</span>
      <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">stream_data</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
      <span class="p">}</span>
      <span class="k">return</span> <span class="n">on_request_recv</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">session_data</span><span class="p">,</span> <span class="n">stream_data</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">break</span><span class="p">;</span>
  <span class="k">default</span><span class="o">:</span>
    <span class="k">break</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>First we retrieve the <code class="docutils literal notranslate"><span class="pre">http2_stream_data</span></code> object associated with the
stream in <code class="docutils literal notranslate"><span class="pre">on_begin_headers_callback()</span></code> using
<a class="reference internal" href="nghttp2_session_get_stream_user_data.html#c.nghttp2_session_get_stream_user_data" title="nghttp2_session_get_stream_user_data"><code class="xref c c-func docutils literal notranslate"><span class="pre">nghttp2_session_get_stream_user_data()</span></code></a>. If the requested path
cannot be served for some reason (e.g. file is not found), we send a
404 response using <code class="docutils literal notranslate"><span class="pre">error_reply()</span></code>.  Otherwise, we open
the requested file and send its content. We send the header field
<code class="docutils literal notranslate"><span class="pre">:status</span></code> as a single response header.</p>
<p>Sending the file content is performed by the <code class="docutils literal notranslate"><span class="pre">send_response()</span></code> function:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">send_response</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">stream_id</span><span class="p">,</span>
                         <span class="n">nghttp2_nv</span> <span class="o">*</span><span class="n">nva</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">nvlen</span><span class="p">,</span> <span class="kt">int</span> <span class="n">fd</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">rv</span><span class="p">;</span>
  <span class="n">nghttp2_data_provider</span> <span class="n">data_prd</span><span class="p">;</span>
  <span class="n">data_prd</span><span class="p">.</span><span class="n">source</span><span class="p">.</span><span class="n">fd</span> <span class="o">=</span> <span class="n">fd</span><span class="p">;</span>
  <span class="n">data_prd</span><span class="p">.</span><span class="n">read_callback</span> <span class="o">=</span> <span class="n">file_read_callback</span><span class="p">;</span>

  <span class="n">rv</span> <span class="o">=</span> <span class="n">nghttp2_submit_response</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">stream_id</span><span class="p">,</span> <span class="n">nva</span><span class="p">,</span> <span class="n">nvlen</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">data_prd</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">rv</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">warnx</span><span class="p">(</span><span class="s">&quot;Fatal error: %s&quot;</span><span class="p">,</span> <span class="n">nghttp2_strerror</span><span class="p">(</span><span class="n">rv</span><span class="p">));</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>nghttp2 uses the <a class="reference internal" href="types.html#c.nghttp2_data_provider" title="nghttp2_data_provider"><code class="xref c c-type docutils literal notranslate"><span class="pre">nghttp2_data_provider</span></code></a> structure to send the
entity body to the remote peer. The <code class="docutils literal notranslate"><span class="pre">source</span></code> member of this
structure is a union, which can be either a void pointer or an int
(which is intended to be used as file descriptor). In this example
server, we use it as a file descriptor. We also set the
<code class="docutils literal notranslate"><span class="pre">file_read_callback()</span></code> callback function to read the contents of the
file:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">ssize_t</span> <span class="nf">file_read_callback</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span> <span class="n">_U_</span><span class="p">,</span>
                                  <span class="kt">int32_t</span> <span class="n">stream_id</span> <span class="n">_U_</span><span class="p">,</span> <span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span>
                                  <span class="kt">size_t</span> <span class="n">length</span><span class="p">,</span> <span class="kt">uint32_t</span> <span class="o">*</span><span class="n">data_flags</span><span class="p">,</span>
                                  <span class="n">nghttp2_data_source</span> <span class="o">*</span><span class="n">source</span><span class="p">,</span>
                                  <span class="kt">void</span> <span class="o">*</span><span class="n">user_data</span> <span class="n">_U_</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">fd</span> <span class="o">=</span> <span class="n">source</span><span class="o">-&gt;</span><span class="n">fd</span><span class="p">;</span>
  <span class="kt">ssize_t</span> <span class="n">r</span><span class="p">;</span>
  <span class="k">while</span> <span class="p">((</span><span class="n">r</span> <span class="o">=</span> <span class="n">read</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">buf</span><span class="p">,</span> <span class="n">length</span><span class="p">))</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="n">errno</span> <span class="o">==</span> <span class="n">EINTR</span><span class="p">)</span>
    <span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">r</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">r</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="o">*</span><span class="n">data_flags</span> <span class="o">|=</span> <span class="n">NGHTTP2_DATA_FLAG_EOF</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="n">r</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>If an error occurs while reading the file, we return
<a class="reference internal" href="enums.html#c.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE" title="NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE"><code class="xref c c-macro docutils literal notranslate"><span class="pre">NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE</span></code></a>.  This tells the
library to send RST_STREAM to the stream.  When all data has been
read, the <a class="reference internal" href="enums.html#c.NGHTTP2_DATA_FLAG_EOF" title="NGHTTP2_DATA_FLAG_EOF"><code class="xref c c-macro docutils literal notranslate"><span class="pre">NGHTTP2_DATA_FLAG_EOF</span></code></a> flag is set to signal nghttp2
that we have finished reading the file.</p>
<p>The <a class="reference internal" href="nghttp2_submit_response.html#c.nghttp2_submit_response" title="nghttp2_submit_response"><code class="xref c c-func docutils literal notranslate"><span class="pre">nghttp2_submit_response()</span></code></a> function is used to send the response to the
remote peer.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">on_stream_close_callback()</span></code> function is invoked when the stream
is about to close:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">on_stream_close_callback</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">stream_id</span><span class="p">,</span>
                                    <span class="kt">uint32_t</span> <span class="n">error_code</span> <span class="n">_U_</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">user_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span> <span class="o">=</span> <span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="p">)</span><span class="n">user_data</span><span class="p">;</span>
  <span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">stream_data</span><span class="p">;</span>

  <span class="n">stream_data</span> <span class="o">=</span> <span class="n">nghttp2_session_get_stream_user_data</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">stream_id</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">stream_data</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">remove_stream</span><span class="p">(</span><span class="n">session_data</span><span class="p">,</span> <span class="n">stream_data</span><span class="p">);</span>
  <span class="n">delete_http2_stream_data</span><span class="p">(</span><span class="n">stream_data</span><span class="p">);</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Lastly, we destroy the <code class="docutils literal notranslate"><span class="pre">http2_stream_data</span></code> object in this function,
since the stream is about to close and we no longer need the object.</p>
<div class="section" id="libevent-server-c">
<h2>libevent-server.c<a class="headerlink" href="#libevent-server-c" title="Permalink to this headline">¶</a></h2>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cm">/*</span>
<span class="cm"> * nghttp2 - HTTP/2 C Library</span>
<span class="cm"> *</span>
<span class="cm"> * Copyright (c) 2013 Tatsuhiro Tsujikawa</span>
<span class="cm"> *</span>
<span class="cm"> * Permission is hereby granted, free of charge, to any person obtaining</span>
<span class="cm"> * a copy of this software and associated documentation files (the</span>
<span class="cm"> * &quot;Software&quot;), to deal in the Software without restriction, including</span>
<span class="cm"> * without limitation the rights to use, copy, modify, merge, publish,</span>
<span class="cm"> * distribute, sublicense, and/or sell copies of the Software, and to</span>
<span class="cm"> * permit persons to whom the Software is furnished to do so, subject to</span>
<span class="cm"> * the following conditions:</span>
<span class="cm"> *</span>
<span class="cm"> * The above copyright notice and this permission notice shall be</span>
<span class="cm"> * included in all copies or substantial portions of the Software.</span>
<span class="cm"> *</span>
<span class="cm"> * THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND,</span>
<span class="cm"> * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF</span>
<span class="cm"> * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND</span>
<span class="cm"> * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE</span>
<span class="cm"> * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION</span>
<span class="cm"> * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION</span>
<span class="cm"> * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</span>
<span class="cm"> */</span>
<span class="cp">#ifdef __sgi</span>
<span class="cp">#  define errx(exitcode, format, args...)                                      \</span>
<span class="cp">    {                                                                          \</span>
<span class="cp">      warnx(format, ##args);                                                   \</span>
<span class="cp">      exit(exitcode);                                                          \</span>
<span class="cp">    }</span>
<span class="cp">#  define warn(format, args...) warnx(format &quot;: %s&quot;, ##args, strerror(errno))</span>
<span class="cp">#  define warnx(format, args...) fprintf(stderr, format &quot;\n&quot;, ##args)</span>
<span class="cp">#endif</span>

<span class="cp">#ifdef HAVE_CONFIG_H</span>
<span class="cp">#  include &lt;config.h&gt;</span>
<span class="cp">#endif </span><span class="cm">/* HAVE_CONFIG_H */</span><span class="cp"></span>

<span class="cp">#include</span> <span class="cpf">&lt;sys/types.h&gt;</span><span class="cp"></span>
<span class="cp">#ifdef HAVE_SYS_SOCKET_H</span>
<span class="cp">#  include &lt;sys/socket.h&gt;</span>
<span class="cp">#endif </span><span class="cm">/* HAVE_SYS_SOCKET_H */</span><span class="cp"></span>
<span class="cp">#ifdef HAVE_NETDB_H</span>
<span class="cp">#  include &lt;netdb.h&gt;</span>
<span class="cp">#endif </span><span class="cm">/* HAVE_NETDB_H */</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;signal.h&gt;</span><span class="cp"></span>
<span class="cp">#ifdef HAVE_UNISTD_H</span>
<span class="cp">#  include &lt;unistd.h&gt;</span>
<span class="cp">#endif </span><span class="cm">/* HAVE_UNISTD_H */</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;sys/stat.h&gt;</span><span class="cp"></span>
<span class="cp">#ifdef HAVE_FCNTL_H</span>
<span class="cp">#  include &lt;fcntl.h&gt;</span>
<span class="cp">#endif </span><span class="cm">/* HAVE_FCNTL_H */</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;ctype.h&gt;</span><span class="cp"></span>
<span class="cp">#ifdef HAVE_NETINET_IN_H</span>
<span class="cp">#  include &lt;netinet/in.h&gt;</span>
<span class="cp">#endif </span><span class="cm">/* HAVE_NETINET_IN_H */</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;netinet/tcp.h&gt;</span><span class="cp"></span>
<span class="cp">#ifndef __sgi</span>
<span class="cp">#  include &lt;err.h&gt;</span>
<span class="cp">#endif</span>
<span class="cp">#include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;errno.h&gt;</span><span class="cp"></span>

<span class="cp">#include</span> <span class="cpf">&lt;openssl/ssl.h&gt;</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;openssl/err.h&gt;</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;openssl/conf.h&gt;</span><span class="cp"></span>

<span class="cp">#include</span> <span class="cpf">&lt;event.h&gt;</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;event2/event.h&gt;</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;event2/bufferevent_ssl.h&gt;</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf">&lt;event2/listener.h&gt;</span><span class="cp"></span>

<span class="cp">#include</span> <span class="cpf">&lt;nghttp2/nghttp2.h&gt;</span><span class="cp"></span>

<span class="cp">#define OUTPUT_WOULDBLOCK_THRESHOLD (1 &lt;&lt; 16)</span>

<span class="cp">#define ARRLEN(x) (sizeof(x) / sizeof(x[0]))</span>

<span class="cp">#define MAKE_NV(NAME, VALUE)                                                   \</span>
<span class="cp">  {                                                                            \</span>
<span class="cp">    (uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1,    \</span>
<span class="cp">        NGHTTP2_NV_FLAG_NONE                                                   \</span>
<span class="cp">  }</span>

<span class="k">struct</span> <span class="n">app_context</span><span class="p">;</span>
<span class="k">typedef</span> <span class="k">struct</span> <span class="n">app_context</span> <span class="n">app_context</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="n">http2_stream_data</span> <span class="p">{</span>
  <span class="k">struct</span> <span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">prev</span><span class="p">,</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">request_path</span><span class="p">;</span>
  <span class="kt">int32_t</span> <span class="n">stream_id</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">fd</span><span class="p">;</span>
<span class="p">}</span> <span class="n">http2_stream_data</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span> <span class="n">http2_session_data</span> <span class="p">{</span>
  <span class="k">struct</span> <span class="n">http2_stream_data</span> <span class="n">root</span><span class="p">;</span>
  <span class="k">struct</span> <span class="n">bufferevent</span> <span class="o">*</span><span class="n">bev</span><span class="p">;</span>
  <span class="n">app_context</span> <span class="o">*</span><span class="n">app_ctx</span><span class="p">;</span>
  <span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">;</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">client_addr</span><span class="p">;</span>
<span class="p">}</span> <span class="n">http2_session_data</span><span class="p">;</span>

<span class="k">struct</span> <span class="n">app_context</span> <span class="p">{</span>
  <span class="n">SSL_CTX</span> <span class="o">*</span><span class="n">ssl_ctx</span><span class="p">;</span>
  <span class="k">struct</span> <span class="n">event_base</span> <span class="o">*</span><span class="n">evbase</span><span class="p">;</span>
<span class="p">};</span>

<span class="k">static</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">next_proto_list</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span>
<span class="k">static</span> <span class="kt">size_t</span> <span class="n">next_proto_list_len</span><span class="p">;</span>

<span class="cp">#ifndef OPENSSL_NO_NEXTPROTONEG</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">next_proto_cb</span><span class="p">(</span><span class="n">SSL</span> <span class="o">*</span><span class="n">ssl</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">**</span><span class="n">data</span><span class="p">,</span>
                         <span class="kt">unsigned</span> <span class="kt">int</span> <span class="o">*</span><span class="n">len</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">arg</span><span class="p">)</span> <span class="p">{</span>
  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">ssl</span><span class="p">;</span>
  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">arg</span><span class="p">;</span>

  <span class="o">*</span><span class="n">data</span> <span class="o">=</span> <span class="n">next_proto_list</span><span class="p">;</span>
  <span class="o">*</span><span class="n">len</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span><span class="n">next_proto_list_len</span><span class="p">;</span>
  <span class="k">return</span> <span class="n">SSL_TLSEXT_ERR_OK</span><span class="p">;</span>
<span class="p">}</span>
<span class="cp">#endif </span><span class="cm">/* !OPENSSL_NO_NEXTPROTONEG */</span><span class="cp"></span>

<span class="cp">#if OPENSSL_VERSION_NUMBER &gt;= 0x10002000L</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">alpn_select_proto_cb</span><span class="p">(</span><span class="n">SSL</span> <span class="o">*</span><span class="n">ssl</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">**</span><span class="n">out</span><span class="p">,</span>
                                <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">outlen</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">in</span><span class="p">,</span>
                                <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">inlen</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">arg</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">rv</span><span class="p">;</span>
  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">ssl</span><span class="p">;</span>
  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">arg</span><span class="p">;</span>

  <span class="n">rv</span> <span class="o">=</span> <span class="n">nghttp2_select_next_protocol</span><span class="p">((</span><span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">**</span><span class="p">)</span><span class="n">out</span><span class="p">,</span> <span class="n">outlen</span><span class="p">,</span> <span class="n">in</span><span class="p">,</span> <span class="n">inlen</span><span class="p">);</span>

  <span class="k">if</span> <span class="p">(</span><span class="n">rv</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">SSL_TLSEXT_ERR_NOACK</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="k">return</span> <span class="n">SSL_TLSEXT_ERR_OK</span><span class="p">;</span>
<span class="p">}</span>
<span class="cp">#endif </span><span class="cm">/* OPENSSL_VERSION_NUMBER &gt;= 0x10002000L */</span><span class="cp"></span>

<span class="cm">/* Create SSL_CTX. */</span>
<span class="k">static</span> <span class="n">SSL_CTX</span> <span class="o">*</span><span class="nf">create_ssl_ctx</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">key_file</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">cert_file</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">SSL_CTX</span> <span class="o">*</span><span class="n">ssl_ctx</span><span class="p">;</span>
  <span class="n">EC_KEY</span> <span class="o">*</span><span class="n">ecdh</span><span class="p">;</span>

  <span class="n">ssl_ctx</span> <span class="o">=</span> <span class="n">SSL_CTX_new</span><span class="p">(</span><span class="n">SSLv23_server_method</span><span class="p">());</span>
  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">ssl_ctx</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">errx</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">&quot;Could not create SSL/TLS context: %s&quot;</span><span class="p">,</span>
         <span class="n">ERR_error_string</span><span class="p">(</span><span class="n">ERR_get_error</span><span class="p">(),</span> <span class="nb">NULL</span><span class="p">));</span>
  <span class="p">}</span>
  <span class="n">SSL_CTX_set_options</span><span class="p">(</span><span class="n">ssl_ctx</span><span class="p">,</span>
                      <span class="n">SSL_OP_ALL</span> <span class="o">|</span> <span class="n">SSL_OP_NO_SSLv2</span> <span class="o">|</span> <span class="n">SSL_OP_NO_SSLv3</span> <span class="o">|</span>
                          <span class="n">SSL_OP_NO_COMPRESSION</span> <span class="o">|</span>
                          <span class="n">SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION</span><span class="p">);</span>

  <span class="n">ecdh</span> <span class="o">=</span> <span class="n">EC_KEY_new_by_curve_name</span><span class="p">(</span><span class="n">NID_X9_62_prime256v1</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">ecdh</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">errx</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">&quot;EC_KEY_new_by_curv_name failed: %s&quot;</span><span class="p">,</span>
         <span class="n">ERR_error_string</span><span class="p">(</span><span class="n">ERR_get_error</span><span class="p">(),</span> <span class="nb">NULL</span><span class="p">));</span>
  <span class="p">}</span>
  <span class="n">SSL_CTX_set_tmp_ecdh</span><span class="p">(</span><span class="n">ssl_ctx</span><span class="p">,</span> <span class="n">ecdh</span><span class="p">);</span>
  <span class="n">EC_KEY_free</span><span class="p">(</span><span class="n">ecdh</span><span class="p">);</span>

  <span class="k">if</span> <span class="p">(</span><span class="n">SSL_CTX_use_PrivateKey_file</span><span class="p">(</span><span class="n">ssl_ctx</span><span class="p">,</span> <span class="n">key_file</span><span class="p">,</span> <span class="n">SSL_FILETYPE_PEM</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">errx</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">&quot;Could not read private key file %s&quot;</span><span class="p">,</span> <span class="n">key_file</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">SSL_CTX_use_certificate_chain_file</span><span class="p">(</span><span class="n">ssl_ctx</span><span class="p">,</span> <span class="n">cert_file</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">errx</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">&quot;Could not read certificate file %s&quot;</span><span class="p">,</span> <span class="n">cert_file</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="n">next_proto_list</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">NGHTTP2_PROTO_VERSION_ID_LEN</span><span class="p">;</span>
  <span class="n">memcpy</span><span class="p">(</span><span class="o">&amp;</span><span class="n">next_proto_list</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">NGHTTP2_PROTO_VERSION_ID</span><span class="p">,</span>
         <span class="n">NGHTTP2_PROTO_VERSION_ID_LEN</span><span class="p">);</span>
  <span class="n">next_proto_list_len</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="n">NGHTTP2_PROTO_VERSION_ID_LEN</span><span class="p">;</span>

<span class="cp">#ifndef OPENSSL_NO_NEXTPROTONEG</span>
  <span class="n">SSL_CTX_set_next_protos_advertised_cb</span><span class="p">(</span><span class="n">ssl_ctx</span><span class="p">,</span> <span class="n">next_proto_cb</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="cp">#endif </span><span class="cm">/* !OPENSSL_NO_NEXTPROTONEG */</span><span class="cp"></span>

<span class="cp">#if OPENSSL_VERSION_NUMBER &gt;= 0x10002000L</span>
  <span class="n">SSL_CTX_set_alpn_select_cb</span><span class="p">(</span><span class="n">ssl_ctx</span><span class="p">,</span> <span class="n">alpn_select_proto_cb</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="cp">#endif </span><span class="cm">/* OPENSSL_VERSION_NUMBER &gt;= 0x10002000L */</span><span class="cp"></span>

  <span class="k">return</span> <span class="n">ssl_ctx</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/* Create SSL object */</span>
<span class="k">static</span> <span class="n">SSL</span> <span class="o">*</span><span class="nf">create_ssl</span><span class="p">(</span><span class="n">SSL_CTX</span> <span class="o">*</span><span class="n">ssl_ctx</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">SSL</span> <span class="o">*</span><span class="n">ssl</span><span class="p">;</span>
  <span class="n">ssl</span> <span class="o">=</span> <span class="n">SSL_new</span><span class="p">(</span><span class="n">ssl_ctx</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">ssl</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">errx</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">&quot;Could not create SSL/TLS session object: %s&quot;</span><span class="p">,</span>
         <span class="n">ERR_error_string</span><span class="p">(</span><span class="n">ERR_get_error</span><span class="p">(),</span> <span class="nb">NULL</span><span class="p">));</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="n">ssl</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">void</span> <span class="nf">add_stream</span><span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">,</span>
                       <span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">stream_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">root</span><span class="p">.</span><span class="n">next</span><span class="p">;</span>
  <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">root</span><span class="p">.</span><span class="n">next</span> <span class="o">=</span> <span class="n">stream_data</span><span class="p">;</span>
  <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">prev</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">root</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">next</span><span class="o">-&gt;</span><span class="n">prev</span> <span class="o">=</span> <span class="n">stream_data</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">void</span> <span class="nf">remove_stream</span><span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">,</span>
                          <span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">stream_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">session_data</span><span class="p">;</span>

  <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">prev</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">next</span><span class="o">-&gt;</span><span class="n">prev</span> <span class="o">=</span> <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">prev</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">http2_stream_data</span> <span class="o">*</span>
<span class="nf">create_http2_stream_data</span><span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">stream_id</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">stream_data</span><span class="p">;</span>
  <span class="n">stream_data</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">http2_stream_data</span><span class="p">));</span>
  <span class="n">memset</span><span class="p">(</span><span class="n">stream_data</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">http2_stream_data</span><span class="p">));</span>
  <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">stream_id</span> <span class="o">=</span> <span class="n">stream_id</span><span class="p">;</span>
  <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">fd</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>

  <span class="n">add_stream</span><span class="p">(</span><span class="n">session_data</span><span class="p">,</span> <span class="n">stream_data</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">stream_data</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">void</span> <span class="nf">delete_http2_stream_data</span><span class="p">(</span><span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">stream_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">fd</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">close</span><span class="p">(</span><span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">fd</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="n">free</span><span class="p">(</span><span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">request_path</span><span class="p">);</span>
  <span class="n">free</span><span class="p">(</span><span class="n">stream_data</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">http2_session_data</span> <span class="o">*</span><span class="nf">create_http2_session_data</span><span class="p">(</span><span class="n">app_context</span> <span class="o">*</span><span class="n">app_ctx</span><span class="p">,</span>
                                                     <span class="kt">int</span> <span class="n">fd</span><span class="p">,</span>
                                                     <span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="n">addr</span><span class="p">,</span>
                                                     <span class="kt">int</span> <span class="n">addrlen</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">rv</span><span class="p">;</span>
  <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">;</span>
  <span class="n">SSL</span> <span class="o">*</span><span class="n">ssl</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">host</span><span class="p">[</span><span class="n">NI_MAXHOST</span><span class="p">];</span>
  <span class="kt">int</span> <span class="n">val</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

  <span class="n">ssl</span> <span class="o">=</span> <span class="n">create_ssl</span><span class="p">(</span><span class="n">app_ctx</span><span class="o">-&gt;</span><span class="n">ssl_ctx</span><span class="p">);</span>
  <span class="n">session_data</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">http2_session_data</span><span class="p">));</span>
  <span class="n">memset</span><span class="p">(</span><span class="n">session_data</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">http2_session_data</span><span class="p">));</span>
  <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">app_ctx</span> <span class="o">=</span> <span class="n">app_ctx</span><span class="p">;</span>
  <span class="n">setsockopt</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">IPPROTO_TCP</span><span class="p">,</span> <span class="n">TCP_NODELAY</span><span class="p">,</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">val</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">val</span><span class="p">));</span>
  <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">bev</span> <span class="o">=</span> <span class="n">bufferevent_openssl_socket_new</span><span class="p">(</span>
      <span class="n">app_ctx</span><span class="o">-&gt;</span><span class="n">evbase</span><span class="p">,</span> <span class="n">fd</span><span class="p">,</span> <span class="n">ssl</span><span class="p">,</span> <span class="n">BUFFEREVENT_SSL_ACCEPTING</span><span class="p">,</span>
      <span class="n">BEV_OPT_CLOSE_ON_FREE</span> <span class="o">|</span> <span class="n">BEV_OPT_DEFER_CALLBACKS</span><span class="p">);</span>
  <span class="n">bufferevent_enable</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">bev</span><span class="p">,</span> <span class="n">EV_READ</span> <span class="o">|</span> <span class="n">EV_WRITE</span><span class="p">);</span>
  <span class="n">rv</span> <span class="o">=</span> <span class="n">getnameinfo</span><span class="p">(</span><span class="n">addr</span><span class="p">,</span> <span class="p">(</span><span class="kt">socklen_t</span><span class="p">)</span><span class="n">addrlen</span><span class="p">,</span> <span class="n">host</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">host</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>
                   <span class="n">NI_NUMERICHOST</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">rv</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">client_addr</span> <span class="o">=</span> <span class="n">strdup</span><span class="p">(</span><span class="s">&quot;(unknown)&quot;</span><span class="p">);</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">client_addr</span> <span class="o">=</span> <span class="n">strdup</span><span class="p">(</span><span class="n">host</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="k">return</span> <span class="n">session_data</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">void</span> <span class="nf">delete_http2_session_data</span><span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">stream_data</span><span class="p">;</span>
  <span class="n">SSL</span> <span class="o">*</span><span class="n">ssl</span> <span class="o">=</span> <span class="n">bufferevent_openssl_get_ssl</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">bev</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">&quot;%s disconnected</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">client_addr</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">ssl</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">SSL_shutdown</span><span class="p">(</span><span class="n">ssl</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="n">bufferevent_free</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">bev</span><span class="p">);</span>
  <span class="n">nghttp2_session_del</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">session</span><span class="p">);</span>
  <span class="k">for</span> <span class="p">(</span><span class="n">stream_data</span> <span class="o">=</span> <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">root</span><span class="p">.</span><span class="n">next</span><span class="p">;</span> <span class="n">stream_data</span><span class="p">;)</span> <span class="p">{</span>
    <span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">next</span> <span class="o">=</span> <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
    <span class="n">delete_http2_stream_data</span><span class="p">(</span><span class="n">stream_data</span><span class="p">);</span>
    <span class="n">stream_data</span> <span class="o">=</span> <span class="n">next</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">free</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">client_addr</span><span class="p">);</span>
  <span class="n">free</span><span class="p">(</span><span class="n">session_data</span><span class="p">);</span>
<span class="p">}</span>

<span class="cm">/* Serialize the frame and send (or buffer) the data to</span>
<span class="cm">   bufferevent. */</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">session_send</span><span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">rv</span><span class="p">;</span>
  <span class="n">rv</span> <span class="o">=</span> <span class="n">nghttp2_session_send</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">session</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">rv</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">warnx</span><span class="p">(</span><span class="s">&quot;Fatal error: %s&quot;</span><span class="p">,</span> <span class="n">nghttp2_strerror</span><span class="p">(</span><span class="n">rv</span><span class="p">));</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/* Read the data in the bufferevent and feed them into nghttp2 library</span>
<span class="cm">   function. Invocation of nghttp2_session_mem_recv() may make</span>
<span class="cm">   additional pending frames, so call session_send() at the end of the</span>
<span class="cm">   function. */</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">session_recv</span><span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">ssize_t</span> <span class="n">readlen</span><span class="p">;</span>
  <span class="k">struct</span> <span class="n">evbuffer</span> <span class="o">*</span><span class="n">input</span> <span class="o">=</span> <span class="n">bufferevent_get_input</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">bev</span><span class="p">);</span>
  <span class="kt">size_t</span> <span class="n">datalen</span> <span class="o">=</span> <span class="n">evbuffer_get_length</span><span class="p">(</span><span class="n">input</span><span class="p">);</span>
  <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">data</span> <span class="o">=</span> <span class="n">evbuffer_pullup</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">);</span>

  <span class="n">readlen</span> <span class="o">=</span> <span class="n">nghttp2_session_mem_recv</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">session</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">datalen</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">readlen</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">warnx</span><span class="p">(</span><span class="s">&quot;Fatal error: %s&quot;</span><span class="p">,</span> <span class="n">nghttp2_strerror</span><span class="p">((</span><span class="kt">int</span><span class="p">)</span><span class="n">readlen</span><span class="p">));</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">evbuffer_drain</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="p">(</span><span class="kt">size_t</span><span class="p">)</span><span class="n">readlen</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">warnx</span><span class="p">(</span><span class="s">&quot;Fatal error: evbuffer_drain failed&quot;</span><span class="p">);</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">session_send</span><span class="p">(</span><span class="n">session_data</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">ssize_t</span> <span class="nf">send_callback</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span> <span class="k">const</span> <span class="kt">uint8_t</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> <span class="kt">int</span> <span class="n">flags</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">user_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span> <span class="o">=</span> <span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="p">)</span><span class="n">user_data</span><span class="p">;</span>
  <span class="k">struct</span> <span class="n">bufferevent</span> <span class="o">*</span><span class="n">bev</span> <span class="o">=</span> <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">bev</span><span class="p">;</span>
  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">session</span><span class="p">;</span>
  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">flags</span><span class="p">;</span>

  <span class="cm">/* Avoid excessive buffering in server side. */</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">evbuffer_get_length</span><span class="p">(</span><span class="n">bufferevent_get_output</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">bev</span><span class="p">))</span> <span class="o">&gt;=</span>
      <span class="n">OUTPUT_WOULDBLOCK_THRESHOLD</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">NGHTTP2_ERR_WOULDBLOCK</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">bufferevent_write</span><span class="p">(</span><span class="n">bev</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">length</span><span class="p">);</span>
  <span class="k">return</span> <span class="p">(</span><span class="kt">ssize_t</span><span class="p">)</span><span class="n">length</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/* Returns nonzero if the string |s| ends with the substring |sub| */</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">ends_with</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">sub</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">size_t</span> <span class="n">slen</span> <span class="o">=</span> <span class="n">strlen</span><span class="p">(</span><span class="n">s</span><span class="p">);</span>
  <span class="kt">size_t</span> <span class="n">sublen</span> <span class="o">=</span> <span class="n">strlen</span><span class="p">(</span><span class="n">sub</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">slen</span> <span class="o">&lt;</span> <span class="n">sublen</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="n">memcmp</span><span class="p">(</span><span class="n">s</span> <span class="o">+</span> <span class="n">slen</span> <span class="o">-</span> <span class="n">sublen</span><span class="p">,</span> <span class="n">sub</span><span class="p">,</span> <span class="n">sublen</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/* Returns int value of hex string character |c| */</span>
<span class="k">static</span> <span class="kt">uint8_t</span> <span class="nf">hex_to_uint</span><span class="p">(</span><span class="kt">uint8_t</span> <span class="n">c</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span><span class="sc">&#39;0&#39;</span> <span class="o">&lt;=</span> <span class="n">c</span> <span class="o">&amp;&amp;</span> <span class="n">c</span> <span class="o">&lt;=</span> <span class="sc">&#39;9&#39;</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">(</span><span class="kt">uint8_t</span><span class="p">)(</span><span class="n">c</span> <span class="o">-</span> <span class="sc">&#39;0&#39;</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="sc">&#39;A&#39;</span> <span class="o">&lt;=</span> <span class="n">c</span> <span class="o">&amp;&amp;</span> <span class="n">c</span> <span class="o">&lt;=</span> <span class="sc">&#39;F&#39;</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">(</span><span class="kt">uint8_t</span><span class="p">)(</span><span class="n">c</span> <span class="o">-</span> <span class="sc">&#39;A&#39;</span> <span class="o">+</span> <span class="mi">10</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="sc">&#39;a&#39;</span> <span class="o">&lt;=</span> <span class="n">c</span> <span class="o">&amp;&amp;</span> <span class="n">c</span> <span class="o">&lt;=</span> <span class="sc">&#39;f&#39;</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">(</span><span class="kt">uint8_t</span><span class="p">)(</span><span class="n">c</span> <span class="o">-</span> <span class="sc">&#39;a&#39;</span> <span class="o">+</span> <span class="mi">10</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/* Decodes percent-encoded byte string |value| with length |valuelen|</span>
<span class="cm">   and returns the decoded byte string in allocated buffer. The return</span>
<span class="cm">   value is NULL terminated. The caller must free the returned</span>
<span class="cm">   string. */</span>
<span class="k">static</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">percent_decode</span><span class="p">(</span><span class="k">const</span> <span class="kt">uint8_t</span> <span class="o">*</span><span class="n">value</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">valuelen</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">res</span><span class="p">;</span>

  <span class="n">res</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="n">valuelen</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">valuelen</span> <span class="o">&gt;</span> <span class="mi">3</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">size_t</span> <span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">valuelen</span> <span class="o">-</span> <span class="mi">2</span><span class="p">;)</span> <span class="p">{</span>
      <span class="k">if</span> <span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">!=</span> <span class="sc">&#39;%&#39;</span> <span class="o">||</span> <span class="o">!</span><span class="n">isxdigit</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">])</span> <span class="o">||</span>
          <span class="o">!</span><span class="n">isxdigit</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]))</span> <span class="p">{</span>
        <span class="n">res</span><span class="p">[</span><span class="n">j</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span><span class="p">)</span><span class="n">value</span><span class="p">[</span><span class="n">i</span><span class="o">++</span><span class="p">];</span>
        <span class="k">continue</span><span class="p">;</span>
      <span class="p">}</span>
      <span class="n">res</span><span class="p">[</span><span class="n">j</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span>
          <span class="p">(</span><span class="kt">char</span><span class="p">)((</span><span class="n">hex_to_uint</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">])</span> <span class="o">&lt;&lt;</span> <span class="mi">4</span><span class="p">)</span> <span class="o">+</span> <span class="n">hex_to_uint</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]));</span>
      <span class="n">i</span> <span class="o">+=</span> <span class="mi">3</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">memcpy</span><span class="p">(</span><span class="o">&amp;</span><span class="n">res</span><span class="p">[</span><span class="n">j</span><span class="p">],</span> <span class="o">&amp;</span><span class="n">value</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="mi">2</span><span class="p">);</span>
    <span class="n">res</span><span class="p">[</span><span class="n">j</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="sc">&#39;\0&#39;</span><span class="p">;</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="n">memcpy</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">valuelen</span><span class="p">);</span>
    <span class="n">res</span><span class="p">[</span><span class="n">valuelen</span><span class="p">]</span> <span class="o">=</span> <span class="sc">&#39;\0&#39;</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="n">res</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">ssize_t</span> <span class="nf">file_read_callback</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">stream_id</span><span class="p">,</span>
                                  <span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">length</span><span class="p">,</span>
                                  <span class="kt">uint32_t</span> <span class="o">*</span><span class="n">data_flags</span><span class="p">,</span>
                                  <span class="n">nghttp2_data_source</span> <span class="o">*</span><span class="n">source</span><span class="p">,</span>
                                  <span class="kt">void</span> <span class="o">*</span><span class="n">user_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">fd</span> <span class="o">=</span> <span class="n">source</span><span class="o">-&gt;</span><span class="n">fd</span><span class="p">;</span>
  <span class="kt">ssize_t</span> <span class="n">r</span><span class="p">;</span>
  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">session</span><span class="p">;</span>
  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">stream_id</span><span class="p">;</span>
  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">user_data</span><span class="p">;</span>

  <span class="k">while</span> <span class="p">((</span><span class="n">r</span> <span class="o">=</span> <span class="n">read</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">buf</span><span class="p">,</span> <span class="n">length</span><span class="p">))</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="n">errno</span> <span class="o">==</span> <span class="n">EINTR</span><span class="p">)</span>
    <span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">r</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">r</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="o">*</span><span class="n">data_flags</span> <span class="o">|=</span> <span class="n">NGHTTP2_DATA_FLAG_EOF</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="n">r</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">int</span> <span class="nf">send_response</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">stream_id</span><span class="p">,</span>
                         <span class="n">nghttp2_nv</span> <span class="o">*</span><span class="n">nva</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">nvlen</span><span class="p">,</span> <span class="kt">int</span> <span class="n">fd</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">rv</span><span class="p">;</span>
  <span class="n">nghttp2_data_provider</span> <span class="n">data_prd</span><span class="p">;</span>
  <span class="n">data_prd</span><span class="p">.</span><span class="n">source</span><span class="p">.</span><span class="n">fd</span> <span class="o">=</span> <span class="n">fd</span><span class="p">;</span>
  <span class="n">data_prd</span><span class="p">.</span><span class="n">read_callback</span> <span class="o">=</span> <span class="n">file_read_callback</span><span class="p">;</span>

  <span class="n">rv</span> <span class="o">=</span> <span class="n">nghttp2_submit_response</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">stream_id</span><span class="p">,</span> <span class="n">nva</span><span class="p">,</span> <span class="n">nvlen</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">data_prd</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">rv</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">warnx</span><span class="p">(</span><span class="s">&quot;Fatal error: %s&quot;</span><span class="p">,</span> <span class="n">nghttp2_strerror</span><span class="p">(</span><span class="n">rv</span><span class="p">));</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">ERROR_HTML</span><span class="p">[]</span> <span class="o">=</span> <span class="s">&quot;&lt;html&gt;&lt;head&gt;&lt;title&gt;404&lt;/title&gt;&lt;/head&gt;&quot;</span>
                                 <span class="s">&quot;&lt;body&gt;&lt;h1&gt;404 Not Found&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;&quot;</span><span class="p">;</span>

<span class="k">static</span> <span class="kt">int</span> <span class="nf">error_reply</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span>
                       <span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">stream_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">rv</span><span class="p">;</span>
  <span class="kt">ssize_t</span> <span class="n">writelen</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">pipefd</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
  <span class="n">nghttp2_nv</span> <span class="n">hdrs</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="n">MAKE_NV</span><span class="p">(</span><span class="s">&quot;:status&quot;</span><span class="p">,</span> <span class="s">&quot;404&quot;</span><span class="p">)};</span>

  <span class="n">rv</span> <span class="o">=</span> <span class="n">pipe</span><span class="p">(</span><span class="n">pipefd</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">rv</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">warn</span><span class="p">(</span><span class="s">&quot;Could not create pipe&quot;</span><span class="p">);</span>
    <span class="n">rv</span> <span class="o">=</span> <span class="n">nghttp2_submit_rst_stream</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">NGHTTP2_FLAG_NONE</span><span class="p">,</span>
                                   <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">stream_id</span><span class="p">,</span>
                                   <span class="n">NGHTTP2_INTERNAL_ERROR</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">rv</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">warnx</span><span class="p">(</span><span class="s">&quot;Fatal error: %s&quot;</span><span class="p">,</span> <span class="n">nghttp2_strerror</span><span class="p">(</span><span class="n">rv</span><span class="p">));</span>
      <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="n">writelen</span> <span class="o">=</span> <span class="n">write</span><span class="p">(</span><span class="n">pipefd</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">ERROR_HTML</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">ERROR_HTML</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">close</span><span class="p">(</span><span class="n">pipefd</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>

  <span class="k">if</span> <span class="p">(</span><span class="n">writelen</span> <span class="o">!=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">ERROR_HTML</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">close</span><span class="p">(</span><span class="n">pipefd</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">fd</span> <span class="o">=</span> <span class="n">pipefd</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>

  <span class="k">if</span> <span class="p">(</span><span class="n">send_response</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">stream_id</span><span class="p">,</span> <span class="n">hdrs</span><span class="p">,</span> <span class="n">ARRLEN</span><span class="p">(</span><span class="n">hdrs</span><span class="p">),</span>
                    <span class="n">pipefd</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">close</span><span class="p">(</span><span class="n">pipefd</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/* nghttp2_on_header_callback: Called when nghttp2 library emits</span>
<span class="cm">   single header name/value pair. */</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">on_header_callback</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span>
                              <span class="k">const</span> <span class="n">nghttp2_frame</span> <span class="o">*</span><span class="n">frame</span><span class="p">,</span> <span class="k">const</span> <span class="kt">uint8_t</span> <span class="o">*</span><span class="n">name</span><span class="p">,</span>
                              <span class="kt">size_t</span> <span class="n">namelen</span><span class="p">,</span> <span class="k">const</span> <span class="kt">uint8_t</span> <span class="o">*</span><span class="n">value</span><span class="p">,</span>
                              <span class="kt">size_t</span> <span class="n">valuelen</span><span class="p">,</span> <span class="kt">uint8_t</span> <span class="n">flags</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">user_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">stream_data</span><span class="p">;</span>
  <span class="k">const</span> <span class="kt">char</span> <span class="n">PATH</span><span class="p">[]</span> <span class="o">=</span> <span class="s">&quot;:path&quot;</span><span class="p">;</span>
  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">flags</span><span class="p">;</span>
  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">user_data</span><span class="p">;</span>

  <span class="k">switch</span> <span class="p">(</span><span class="n">frame</span><span class="o">-&gt;</span><span class="n">hd</span><span class="p">.</span><span class="n">type</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">case</span> <span class="nl">NGHTTP2_HEADERS</span><span class="p">:</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">frame</span><span class="o">-&gt;</span><span class="n">headers</span><span class="p">.</span><span class="n">cat</span> <span class="o">!=</span> <span class="n">NGHTTP2_HCAT_REQUEST</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">break</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">stream_data</span> <span class="o">=</span>
        <span class="n">nghttp2_session_get_stream_user_data</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">frame</span><span class="o">-&gt;</span><span class="n">hd</span><span class="p">.</span><span class="n">stream_id</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">stream_data</span> <span class="o">||</span> <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">request_path</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">break</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">namelen</span> <span class="o">==</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">PATH</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="n">memcmp</span><span class="p">(</span><span class="n">PATH</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">namelen</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="kt">size_t</span> <span class="n">j</span><span class="p">;</span>
      <span class="k">for</span> <span class="p">(</span><span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">valuelen</span> <span class="o">&amp;&amp;</span> <span class="n">value</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">!=</span> <span class="sc">&#39;?&#39;</span><span class="p">;</span> <span class="o">++</span><span class="n">j</span><span class="p">)</span>
        <span class="p">;</span>
      <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">request_path</span> <span class="o">=</span> <span class="n">percent_decode</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">j</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">break</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">int</span> <span class="nf">on_begin_headers_callback</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span>
                                     <span class="k">const</span> <span class="n">nghttp2_frame</span> <span class="o">*</span><span class="n">frame</span><span class="p">,</span>
                                     <span class="kt">void</span> <span class="o">*</span><span class="n">user_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span> <span class="o">=</span> <span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="p">)</span><span class="n">user_data</span><span class="p">;</span>
  <span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">stream_data</span><span class="p">;</span>

  <span class="k">if</span> <span class="p">(</span><span class="n">frame</span><span class="o">-&gt;</span><span class="n">hd</span><span class="p">.</span><span class="n">type</span> <span class="o">!=</span> <span class="n">NGHTTP2_HEADERS</span> <span class="o">||</span>
      <span class="n">frame</span><span class="o">-&gt;</span><span class="n">headers</span><span class="p">.</span><span class="n">cat</span> <span class="o">!=</span> <span class="n">NGHTTP2_HCAT_REQUEST</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">stream_data</span> <span class="o">=</span> <span class="n">create_http2_stream_data</span><span class="p">(</span><span class="n">session_data</span><span class="p">,</span> <span class="n">frame</span><span class="o">-&gt;</span><span class="n">hd</span><span class="p">.</span><span class="n">stream_id</span><span class="p">);</span>
  <span class="n">nghttp2_session_set_stream_user_data</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">frame</span><span class="o">-&gt;</span><span class="n">hd</span><span class="p">.</span><span class="n">stream_id</span><span class="p">,</span>
                                       <span class="n">stream_data</span><span class="p">);</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/* Minimum check for directory traversal. Returns nonzero if it is</span>
<span class="cm">   safe. */</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">check_path</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">path</span><span class="p">)</span> <span class="p">{</span>
  <span class="cm">/* We don&#39;t like &#39;\&#39; in url. */</span>
  <span class="k">return</span> <span class="n">path</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="n">path</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="sc">&#39;/&#39;</span> <span class="o">&amp;&amp;</span> <span class="n">strchr</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="sc">&#39;\\&#39;</span><span class="p">)</span> <span class="o">==</span> <span class="nb">NULL</span> <span class="o">&amp;&amp;</span>
         <span class="n">strstr</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s">&quot;/../&quot;</span><span class="p">)</span> <span class="o">==</span> <span class="nb">NULL</span> <span class="o">&amp;&amp;</span> <span class="n">strstr</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s">&quot;/./&quot;</span><span class="p">)</span> <span class="o">==</span> <span class="nb">NULL</span> <span class="o">&amp;&amp;</span>
         <span class="o">!</span><span class="n">ends_with</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s">&quot;/..&quot;</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">ends_with</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s">&quot;/.&quot;</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">int</span> <span class="nf">on_request_recv</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span>
                           <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">,</span>
                           <span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">stream_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">fd</span><span class="p">;</span>
  <span class="n">nghttp2_nv</span> <span class="n">hdrs</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="n">MAKE_NV</span><span class="p">(</span><span class="s">&quot;:status&quot;</span><span class="p">,</span> <span class="s">&quot;200&quot;</span><span class="p">)};</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">rel_path</span><span class="p">;</span>

  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">request_path</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">error_reply</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">stream_data</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">return</span> <span class="n">NGHTTP2_ERR_CALLBACK_FAILURE</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</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">&quot;%s GET %s</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">client_addr</span><span class="p">,</span>
          <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">request_path</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">check_path</span><span class="p">(</span><span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">request_path</span><span class="p">))</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">error_reply</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">stream_data</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">return</span> <span class="n">NGHTTP2_ERR_CALLBACK_FAILURE</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">for</span> <span class="p">(</span><span class="n">rel_path</span> <span class="o">=</span> <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">request_path</span><span class="p">;</span> <span class="o">*</span><span class="n">rel_path</span> <span class="o">==</span> <span class="sc">&#39;/&#39;</span><span class="p">;</span> <span class="o">++</span><span class="n">rel_path</span><span class="p">)</span>
    <span class="p">;</span>
  <span class="n">fd</span> <span class="o">=</span> <span class="n">open</span><span class="p">(</span><span class="n">rel_path</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">fd</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">error_reply</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">stream_data</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">return</span> <span class="n">NGHTTP2_ERR_CALLBACK_FAILURE</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">fd</span> <span class="o">=</span> <span class="n">fd</span><span class="p">;</span>

  <span class="k">if</span> <span class="p">(</span><span class="n">send_response</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">stream_data</span><span class="o">-&gt;</span><span class="n">stream_id</span><span class="p">,</span> <span class="n">hdrs</span><span class="p">,</span> <span class="n">ARRLEN</span><span class="p">(</span><span class="n">hdrs</span><span class="p">),</span> <span class="n">fd</span><span class="p">)</span> <span class="o">!=</span>
      <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">close</span><span class="p">(</span><span class="n">fd</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">NGHTTP2_ERR_CALLBACK_FAILURE</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">int</span> <span class="nf">on_frame_recv_callback</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span>
                                  <span class="k">const</span> <span class="n">nghttp2_frame</span> <span class="o">*</span><span class="n">frame</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">user_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span> <span class="o">=</span> <span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="p">)</span><span class="n">user_data</span><span class="p">;</span>
  <span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">stream_data</span><span class="p">;</span>
  <span class="k">switch</span> <span class="p">(</span><span class="n">frame</span><span class="o">-&gt;</span><span class="n">hd</span><span class="p">.</span><span class="n">type</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">case</span> <span class="nl">NGHTTP2_DATA</span><span class="p">:</span>
  <span class="k">case</span> <span class="nl">NGHTTP2_HEADERS</span><span class="p">:</span>
    <span class="cm">/* Check that the client request has finished */</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">frame</span><span class="o">-&gt;</span><span class="n">hd</span><span class="p">.</span><span class="n">flags</span> <span class="o">&amp;</span> <span class="n">NGHTTP2_FLAG_END_STREAM</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">stream_data</span> <span class="o">=</span>
          <span class="n">nghttp2_session_get_stream_user_data</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">frame</span><span class="o">-&gt;</span><span class="n">hd</span><span class="p">.</span><span class="n">stream_id</span><span class="p">);</span>
      <span class="cm">/* For DATA and HEADERS frame, this callback may be called after</span>
<span class="cm">         on_stream_close_callback. Check that stream still alive. */</span>
      <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">stream_data</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
      <span class="p">}</span>
      <span class="k">return</span> <span class="n">on_request_recv</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">session_data</span><span class="p">,</span> <span class="n">stream_data</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">break</span><span class="p">;</span>
  <span class="k">default</span><span class="o">:</span>
    <span class="k">break</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">int</span> <span class="nf">on_stream_close_callback</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">stream_id</span><span class="p">,</span>
                                    <span class="kt">uint32_t</span> <span class="n">error_code</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">user_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span> <span class="o">=</span> <span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="p">)</span><span class="n">user_data</span><span class="p">;</span>
  <span class="n">http2_stream_data</span> <span class="o">*</span><span class="n">stream_data</span><span class="p">;</span>
  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">error_code</span><span class="p">;</span>

  <span class="n">stream_data</span> <span class="o">=</span> <span class="n">nghttp2_session_get_stream_user_data</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">stream_id</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">stream_data</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">remove_stream</span><span class="p">(</span><span class="n">session_data</span><span class="p">,</span> <span class="n">stream_data</span><span class="p">);</span>
  <span class="n">delete_http2_stream_data</span><span class="p">(</span><span class="n">stream_data</span><span class="p">);</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">void</span> <span class="nf">initialize_nghttp2_session</span><span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">nghttp2_session_callbacks</span> <span class="o">*</span><span class="n">callbacks</span><span class="p">;</span>

  <span class="n">nghttp2_session_callbacks_new</span><span class="p">(</span><span class="o">&amp;</span><span class="n">callbacks</span><span class="p">);</span>

  <span class="n">nghttp2_session_callbacks_set_send_callback</span><span class="p">(</span><span class="n">callbacks</span><span class="p">,</span> <span class="n">send_callback</span><span class="p">);</span>

  <span class="n">nghttp2_session_callbacks_set_on_frame_recv_callback</span><span class="p">(</span><span class="n">callbacks</span><span class="p">,</span>
                                                       <span class="n">on_frame_recv_callback</span><span class="p">);</span>

  <span class="n">nghttp2_session_callbacks_set_on_stream_close_callback</span><span class="p">(</span>
      <span class="n">callbacks</span><span class="p">,</span> <span class="n">on_stream_close_callback</span><span class="p">);</span>

  <span class="n">nghttp2_session_callbacks_set_on_header_callback</span><span class="p">(</span><span class="n">callbacks</span><span class="p">,</span>
                                                   <span class="n">on_header_callback</span><span class="p">);</span>

  <span class="n">nghttp2_session_callbacks_set_on_begin_headers_callback</span><span class="p">(</span>
      <span class="n">callbacks</span><span class="p">,</span> <span class="n">on_begin_headers_callback</span><span class="p">);</span>

  <span class="n">nghttp2_session_server_new</span><span class="p">(</span><span class="o">&amp;</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">session</span><span class="p">,</span> <span class="n">callbacks</span><span class="p">,</span> <span class="n">session_data</span><span class="p">);</span>

  <span class="n">nghttp2_session_callbacks_del</span><span class="p">(</span><span class="n">callbacks</span><span class="p">);</span>
<span class="p">}</span>

<span class="cm">/* Send HTTP/2 client connection header, which includes 24 bytes</span>
<span class="cm">   magic octets and SETTINGS frame */</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">send_server_connection_header</span><span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">nghttp2_settings_entry</span> <span class="n">iv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
      <span class="p">{</span><span class="n">NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS</span><span class="p">,</span> <span class="mi">100</span><span class="p">}};</span>
  <span class="kt">int</span> <span class="n">rv</span><span class="p">;</span>

  <span class="n">rv</span> <span class="o">=</span> <span class="n">nghttp2_submit_settings</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">session</span><span class="p">,</span> <span class="n">NGHTTP2_FLAG_NONE</span><span class="p">,</span> <span class="n">iv</span><span class="p">,</span>
                               <span class="n">ARRLEN</span><span class="p">(</span><span class="n">iv</span><span class="p">));</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">rv</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">warnx</span><span class="p">(</span><span class="s">&quot;Fatal error: %s&quot;</span><span class="p">,</span> <span class="n">nghttp2_strerror</span><span class="p">(</span><span class="n">rv</span><span class="p">));</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="cm">/* readcb for bufferevent after client connection header was</span>
<span class="cm">   checked. */</span>
<span class="k">static</span> <span class="kt">void</span> <span class="nf">readcb</span><span class="p">(</span><span class="k">struct</span> <span class="n">bufferevent</span> <span class="o">*</span><span class="n">bev</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">ptr</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span> <span class="o">=</span> <span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="p">)</span><span class="n">ptr</span><span class="p">;</span>
  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">bev</span><span class="p">;</span>

  <span class="k">if</span> <span class="p">(</span><span class="n">session_recv</span><span class="p">(</span><span class="n">session_data</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">delete_http2_session_data</span><span class="p">(</span><span class="n">session_data</span><span class="p">);</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="cm">/* writecb for bufferevent. To greaceful shutdown after sending or</span>
<span class="cm">   receiving GOAWAY, we check the some conditions on the nghttp2</span>
<span class="cm">   library and output buffer of bufferevent. If it indicates we have</span>
<span class="cm">   no business to this session, tear down the connection. If the</span>
<span class="cm">   connection is not going to shutdown, we call session_send() to</span>
<span class="cm">   process pending data in the output buffer. This is necessary</span>
<span class="cm">   because we have a threshold on the buffer size to avoid too much</span>
<span class="cm">   buffering. See send_callback(). */</span>
<span class="k">static</span> <span class="kt">void</span> <span class="nf">writecb</span><span class="p">(</span><span class="k">struct</span> <span class="n">bufferevent</span> <span class="o">*</span><span class="n">bev</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">ptr</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span> <span class="o">=</span> <span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="p">)</span><span class="n">ptr</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">evbuffer_get_length</span><span class="p">(</span><span class="n">bufferevent_get_output</span><span class="p">(</span><span class="n">bev</span><span class="p">))</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">nghttp2_session_want_read</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">session</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span>
      <span class="n">nghttp2_session_want_write</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">session</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">delete_http2_session_data</span><span class="p">(</span><span class="n">session_data</span><span class="p">);</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">session_send</span><span class="p">(</span><span class="n">session_data</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">delete_http2_session_data</span><span class="p">(</span><span class="n">session_data</span><span class="p">);</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="cm">/* eventcb for bufferevent */</span>
<span class="k">static</span> <span class="kt">void</span> <span class="nf">eventcb</span><span class="p">(</span><span class="k">struct</span> <span class="n">bufferevent</span> <span class="o">*</span><span class="n">bev</span><span class="p">,</span> <span class="kt">short</span> <span class="n">events</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">ptr</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span> <span class="o">=</span> <span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="p">)</span><span class="n">ptr</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">events</span> <span class="o">&amp;</span> <span class="n">BEV_EVENT_CONNECTED</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">alpn</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">alpnlen</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">SSL</span> <span class="o">*</span><span class="n">ssl</span><span class="p">;</span>
    <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">bev</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">&quot;%s connected</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">client_addr</span><span class="p">);</span>

    <span class="n">ssl</span> <span class="o">=</span> <span class="n">bufferevent_openssl_get_ssl</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">bev</span><span class="p">);</span>

<span class="cp">#ifndef OPENSSL_NO_NEXTPROTONEG</span>
    <span class="n">SSL_get0_next_proto_negotiated</span><span class="p">(</span><span class="n">ssl</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">alpn</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">alpnlen</span><span class="p">);</span>
<span class="cp">#endif </span><span class="cm">/* !OPENSSL_NO_NEXTPROTONEG */</span><span class="cp"></span>
<span class="cp">#if OPENSSL_VERSION_NUMBER &gt;= 0x10002000L</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">alpn</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">SSL_get0_alpn_selected</span><span class="p">(</span><span class="n">ssl</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">alpn</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">alpnlen</span><span class="p">);</span>
    <span class="p">}</span>
<span class="cp">#endif </span><span class="cm">/* OPENSSL_VERSION_NUMBER &gt;= 0x10002000L */</span><span class="cp"></span>

    <span class="k">if</span> <span class="p">(</span><span class="n">alpn</span> <span class="o">==</span> <span class="nb">NULL</span> <span class="o">||</span> <span class="n">alpnlen</span> <span class="o">!=</span> <span class="mi">2</span> <span class="o">||</span> <span class="n">memcmp</span><span class="p">(</span><span class="s">&quot;h2&quot;</span><span class="p">,</span> <span class="n">alpn</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</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">&quot;%s h2 is not negotiated</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">client_addr</span><span class="p">);</span>
      <span class="n">delete_http2_session_data</span><span class="p">(</span><span class="n">session_data</span><span class="p">);</span>
      <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">initialize_nghttp2_session</span><span class="p">(</span><span class="n">session_data</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">send_server_connection_header</span><span class="p">(</span><span class="n">session_data</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span> <span class="o">||</span>
        <span class="n">session_send</span><span class="p">(</span><span class="n">session_data</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">delete_http2_session_data</span><span class="p">(</span><span class="n">session_data</span><span class="p">);</span>
      <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">events</span> <span class="o">&amp;</span> <span class="n">BEV_EVENT_EOF</span><span class="p">)</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">&quot;%s EOF</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">client_addr</span><span class="p">);</span>
  <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">events</span> <span class="o">&amp;</span> <span class="n">BEV_EVENT_ERROR</span><span class="p">)</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">&quot;%s network error</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">client_addr</span><span class="p">);</span>
  <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">events</span> <span class="o">&amp;</span> <span class="n">BEV_EVENT_TIMEOUT</span><span class="p">)</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">&quot;%s timeout</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">session_data</span><span class="o">-&gt;</span><span class="n">client_addr</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="n">delete_http2_session_data</span><span class="p">(</span><span class="n">session_data</span><span class="p">);</span>
<span class="p">}</span>

<span class="cm">/* callback for evconnlistener */</span>
<span class="k">static</span> <span class="kt">void</span> <span class="nf">acceptcb</span><span class="p">(</span><span class="k">struct</span> <span class="n">evconnlistener</span> <span class="o">*</span><span class="n">listener</span><span class="p">,</span> <span class="kt">int</span> <span class="n">fd</span><span class="p">,</span>
                     <span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="n">addr</span><span class="p">,</span> <span class="kt">int</span> <span class="n">addrlen</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">arg</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">app_context</span> <span class="o">*</span><span class="n">app_ctx</span> <span class="o">=</span> <span class="p">(</span><span class="n">app_context</span> <span class="o">*</span><span class="p">)</span><span class="n">arg</span><span class="p">;</span>
  <span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">;</span>
  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">listener</span><span class="p">;</span>

  <span class="n">session_data</span> <span class="o">=</span> <span class="n">create_http2_session_data</span><span class="p">(</span><span class="n">app_ctx</span><span class="p">,</span> <span class="n">fd</span><span class="p">,</span> <span class="n">addr</span><span class="p">,</span> <span class="n">addrlen</span><span class="p">);</span>

  <span class="n">bufferevent_setcb</span><span class="p">(</span><span class="n">session_data</span><span class="o">-&gt;</span><span class="n">bev</span><span class="p">,</span> <span class="n">readcb</span><span class="p">,</span> <span class="n">writecb</span><span class="p">,</span> <span class="n">eventcb</span><span class="p">,</span> <span class="n">session_data</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">void</span> <span class="nf">start_listen</span><span class="p">(</span><span class="k">struct</span> <span class="n">event_base</span> <span class="o">*</span><span class="n">evbase</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">service</span><span class="p">,</span>
                         <span class="n">app_context</span> <span class="o">*</span><span class="n">app_ctx</span><span class="p">)</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">rv</span><span class="p">;</span>
  <span class="k">struct</span> <span class="n">addrinfo</span> <span class="n">hints</span><span class="p">;</span>
  <span class="k">struct</span> <span class="n">addrinfo</span> <span class="o">*</span><span class="n">res</span><span class="p">,</span> <span class="o">*</span><span class="n">rp</span><span class="p">;</span>

  <span class="n">memset</span><span class="p">(</span><span class="o">&amp;</span><span class="n">hints</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">hints</span><span class="p">));</span>
  <span class="n">hints</span><span class="p">.</span><span class="n">ai_family</span> <span class="o">=</span> <span class="n">AF_UNSPEC</span><span class="p">;</span>
  <span class="n">hints</span><span class="p">.</span><span class="n">ai_socktype</span> <span class="o">=</span> <span class="n">SOCK_STREAM</span><span class="p">;</span>
  <span class="n">hints</span><span class="p">.</span><span class="n">ai_flags</span> <span class="o">=</span> <span class="n">AI_PASSIVE</span><span class="p">;</span>
<span class="cp">#ifdef AI_ADDRCONFIG</span>
  <span class="n">hints</span><span class="p">.</span><span class="n">ai_flags</span> <span class="o">|=</span> <span class="n">AI_ADDRCONFIG</span><span class="p">;</span>
<span class="cp">#endif </span><span class="cm">/* AI_ADDRCONFIG */</span><span class="cp"></span>

  <span class="n">rv</span> <span class="o">=</span> <span class="n">getaddrinfo</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="n">service</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">hints</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">res</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">rv</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">errx</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">&quot;Could not resolve server address&quot;</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">for</span> <span class="p">(</span><span class="n">rp</span> <span class="o">=</span> <span class="n">res</span><span class="p">;</span> <span class="n">rp</span><span class="p">;</span> <span class="n">rp</span> <span class="o">=</span> <span class="n">rp</span><span class="o">-&gt;</span><span class="n">ai_next</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">evconnlistener</span> <span class="o">*</span><span class="n">listener</span><span class="p">;</span>
    <span class="n">listener</span> <span class="o">=</span> <span class="n">evconnlistener_new_bind</span><span class="p">(</span>
        <span class="n">evbase</span><span class="p">,</span> <span class="n">acceptcb</span><span class="p">,</span> <span class="n">app_ctx</span><span class="p">,</span> <span class="n">LEV_OPT_CLOSE_ON_FREE</span> <span class="o">|</span> <span class="n">LEV_OPT_REUSEABLE</span><span class="p">,</span>
        <span class="mi">16</span><span class="p">,</span> <span class="n">rp</span><span class="o">-&gt;</span><span class="n">ai_addr</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">rp</span><span class="o">-&gt;</span><span class="n">ai_addrlen</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">listener</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">freeaddrinfo</span><span class="p">(</span><span class="n">res</span><span class="p">);</span>

      <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="n">errx</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">&quot;Could not start listener&quot;</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">void</span> <span class="nf">initialize_app_context</span><span class="p">(</span><span class="n">app_context</span> <span class="o">*</span><span class="n">app_ctx</span><span class="p">,</span> <span class="n">SSL_CTX</span> <span class="o">*</span><span class="n">ssl_ctx</span><span class="p">,</span>
                                   <span class="k">struct</span> <span class="n">event_base</span> <span class="o">*</span><span class="n">evbase</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">memset</span><span class="p">(</span><span class="n">app_ctx</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">app_context</span><span class="p">));</span>
  <span class="n">app_ctx</span><span class="o">-&gt;</span><span class="n">ssl_ctx</span> <span class="o">=</span> <span class="n">ssl_ctx</span><span class="p">;</span>
  <span class="n">app_ctx</span><span class="o">-&gt;</span><span class="n">evbase</span> <span class="o">=</span> <span class="n">evbase</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">void</span> <span class="nf">run</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">service</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">key_file</span><span class="p">,</span>
                <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">cert_file</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">SSL_CTX</span> <span class="o">*</span><span class="n">ssl_ctx</span><span class="p">;</span>
  <span class="n">app_context</span> <span class="n">app_ctx</span><span class="p">;</span>
  <span class="k">struct</span> <span class="n">event_base</span> <span class="o">*</span><span class="n">evbase</span><span class="p">;</span>

  <span class="n">ssl_ctx</span> <span class="o">=</span> <span class="n">create_ssl_ctx</span><span class="p">(</span><span class="n">key_file</span><span class="p">,</span> <span class="n">cert_file</span><span class="p">);</span>
  <span class="n">evbase</span> <span class="o">=</span> <span class="n">event_base_new</span><span class="p">();</span>
  <span class="n">initialize_app_context</span><span class="p">(</span><span class="o">&amp;</span><span class="n">app_ctx</span><span class="p">,</span> <span class="n">ssl_ctx</span><span class="p">,</span> <span class="n">evbase</span><span class="p">);</span>
  <span class="n">start_listen</span><span class="p">(</span><span class="n">evbase</span><span class="p">,</span> <span class="n">service</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">app_ctx</span><span class="p">);</span>

  <span class="n">event_base_loop</span><span class="p">(</span><span class="n">evbase</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>

  <span class="n">event_base_free</span><span class="p">(</span><span class="n">evbase</span><span class="p">);</span>
  <span class="n">SSL_CTX_free</span><span class="p">(</span><span class="n">ssl_ctx</span><span class="p">);</span>
<span class="p">}</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="o">**</span><span class="n">argv</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">struct</span> <span class="n">sigaction</span> <span class="n">act</span><span class="p">;</span>

  <span class="k">if</span> <span class="p">(</span><span class="n">argc</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="p">)</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">&quot;Usage: libevent-server PORT KEY_FILE CERT_FILE</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">);</span>
    <span class="n">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="n">memset</span><span class="p">(</span><span class="o">&amp;</span><span class="n">act</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">sigaction</span><span class="p">));</span>
  <span class="n">act</span><span class="p">.</span><span class="n">sa_handler</span> <span class="o">=</span> <span class="n">SIG_IGN</span><span class="p">;</span>
  <span class="n">sigaction</span><span class="p">(</span><span class="n">SIGPIPE</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">act</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>

  <span class="n">SSL_load_error_strings</span><span class="p">();</span>
  <span class="n">SSL_library_init</span><span class="p">();</span>

  <span class="n">run</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">argv</span><span class="p">[</span><span class="mi">3</span><span class="p">]);</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
</div>


           </div>
          </div>
          <footer>
  
    <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
      
        <a href="tutorial-hpack.html" class="btn btn-neutral float-right" title="Tutorial: HPACK API" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
      
      
        <a href="tutorial-client.html" class="btn btn-neutral" title="Tutorial: HTTP/2 client" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
      
    </div>
  

  <hr/>

  <div role="contentinfo">
    <p>
        &copy; Copyright 2012, 2015, 2016, Tatsuhiro Tsujikawa.

    </p>
  </div>
  Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. 

</footer>

        </div>
      </div>

    </section>

  </div>
  


  

    <script type="text/javascript">
        var DOCUMENTATION_OPTIONS = {
            URL_ROOT:'./',
            VERSION:'1.38.0',
            COLLAPSE_INDEX:false,
            FILE_SUFFIX:'.html',
            HAS_SOURCE:  false
        };
    </script>
      <script type="text/javascript" src="_static/jquery.js"></script>
      <script type="text/javascript" src="_static/underscore.js"></script>
      <script type="text/javascript" src="_static/doctools.js"></script>
      <script type="text/javascript" src="_static/language_data.js"></script>

  

  
  
    <script type="text/javascript" src="_static/js/theme.js"></script>
  

  
  
  <script type="text/javascript">
      jQuery(function () {
          SphinxRtdTheme.StickyNav.enable();
      });
  </script>
   

</body>
</html>