
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Sat, 04 Apr 2026 11:56:16 GMT</lastBuildDate>
        <item>
            <title><![CDATA[NGINX structural enhancements for HTTP/2 performance]]></title>
            <link>https://blog.cloudflare.com/nginx-structural-enhancements-for-http-2-performance/</link>
            <pubDate>Wed, 22 May 2019 17:14:56 GMT</pubDate>
            <description><![CDATA[ My team: the Cloudflare PROTOCOLS team is responsible for termination of HTTP traffic at the edge of the Cloudflare network. We deal with features related to: TCP, QUIC, TLS and Secure Certificate management, HTTP/1 and HTTP/2. ]]></description>
            <content:encoded><![CDATA[ <p></p>
    <div>
      <h3>Introduction</h3>
      <a href="#introduction">
        
      </a>
    </div>
    <p>My team: the Cloudflare PROTOCOLS team is responsible for termination of HTTP traffic at the edge of the Cloudflare network. We deal with features related to: TCP, QUIC, TLS and Secure Certificate management, HTTP/1 and HTTP/2. Over Q1, we were responsible for implementing the <a href="/better-http-2-prioritization-for-a-faster-web/">Enhanced HTTP/2 Prioritization</a> product that Cloudflare announced during Speed Week.</p><p>This is a very exciting project to be part of, and doubly exciting to see the results of, but during the course of the project, we had a number of interesting realisations about NGINX: the HTTP oriented server onto which Cloudflare currently deploys its software infrastructure. We quickly became certain that our Enhanced HTTP/2 Prioritization project could not achieve even moderate success if the internal workings of NGINX were not changed.</p><p>Due to these realisations we embarked upon a number of significant changes to the internal structure of NGINX in parallel to the work on the core prioritization product. This blog post describes the motivation behind the structural changes, how we approached them, and what impact they had. We also identify additional changes that we plan to add to our roadmap, which we hope will improve performance further.</p>
    <div>
      <h3>Background</h3>
      <a href="#background">
        
      </a>
    </div>
    <p>Enhanced HTTP/2 Prioritization aims to do one thing to web traffic flowing between a client and a server: it provides a means to shape the many HTTP/2 streams as they flow from upstream (server or origin side) into a single HTTP/2 connection that flows downstream (client side).</p><p>Enhanced HTTP/2 Prioritization allows site owners and the Cloudflare edge systems to dictate the rules about how various objects should combine into the single HTTP/2 connection: whether a particular object should have priority and dominate that connection and reach the client as soon as possible, or whether a group of objects should evenly share the capacity of the connection and put more emphasis on parallelism.</p><p>As a result, Enhanced HTTP/2 Prioritization allows site owners to tackle two problems that exist between a client and a server: how to control precedence and ordering of objects, and: how to make the best use of a limited connection resource, which may be constrained by a number of factors such as bandwidth, volume of traffic and CPU workload at the various stages on the path of the connection.</p>
    <div>
      <h3>What did we see?</h3>
      <a href="#what-did-we-see">
        
      </a>
    </div>
    <p>The key to prioritisation is being able to compare two or more HTTP/2 streams in order to determine which one’s frame is to go down the pipe next. The Enhanced HTTP/2 Prioritization project necessarily drew us into the core NGINX codebase, as our intention was to fundamentally alter the way that NGINX compared and queued HTTP/2 data frames as they were written back to the client.</p><p>Very early in the analysis phase, as we rummaged through the NGINX internals to survey the site of our proposed features, we noticed a number of shortcomings in the structure of NGINX itself, in particular: how it moved data from upstream (server side) to downstream (client side) and how it temporarily stored (buffered) that data in its various internal stages. The main conclusion of our early analysis of NGINX was that it largely failed to give the stream data frames any 'proximity'. Either streams were processed in the NGINX HTTP/2 layer in isolated succession or frames of different streams spent very little time in the same place: a shared queue for example. The net effect was a reduction in the opportunities for useful comparison.</p><p>We coined a new, barely scientific but useful measurement: <b>Potential</b>, to describe how effectively the Enhanced HTTP/2 Prioritization strategies (or even the default NGINX prioritization) can be applied to queued data streams. Potential is not so much a measurement of the effectiveness of prioritization per se, that metric would be left for later on in the project, it is more a measurement of the levels of participation during the application of the algorithm. In simple terms, it considers the number of streams and frames thereof that are included in an iteration of prioritization, with more streams and more frames leading to higher Potential.</p><p>What we could see from early on was that by default, NGINX displayed low Potential: rendering prioritization instructions from either the browser, as is the case in the traditional HTTP/2 prioritization model, or from our Enhanced HTTP/2 Prioritization product, fairly useless.</p>
    <div>
      <h3>What did we do?</h3>
      <a href="#what-did-we-do">
        
      </a>
    </div>
    <p>With the goal of improving the specific problems related to Potential, and also improving general throughput of the system, we identified some key pain points in NGINX. These points, which will be described below, have either been worked on and improved as part of our initial release of Enhanced HTTP/2 Prioritization, or have now branched out into meaningful projects of their own that we will put engineering effort into over the course of the next few months.</p>
    <div>
      <h3>HTTP/2 frame write queue reclamation</h3>
      <a href="#http-2-frame-write-queue-reclamation">
        
      </a>
    </div>
    <p>Write queue reclamation was successfully shipped with our release of Enhanced HTTP/2 Prioritization and ironically, it wasn’t a change made to the original NGINX, it was in fact a change made against our Enhanced HTTP/2 Prioritization implementation when we were part way through the project, and it serves as a good example of something one may call: conservation of data, which is a good way to increase Potential.</p><p>Similar to the original NGINX, our Enhanced HTTP/2 Prioritization algorithm will place a cohort of HTTP/2 data frames into a write queue as a result of an iteration of the prioritization strategies being applied to them. The contents of the write queue would be destined to be written the downstream TLS layer.  Also similar to the original NGINX, the write queue may only be partially written to the TLS layer due to back-pressure from the network connection that has temporarily reached write capacity.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5bBa68J0uK2BJvMi5ouTD5/92ce87c4a134c046206f2ac46ba55d2c/Write-Queue-Construction-Without-Reclamation.png" />
            
            </figure><p>Early on in our project, if the write queue was only partially written to the TLS layer, we would simply leave the frames in the write queue until the backlog was cleared, then we would re-attempt to write that data to the network in a future write iteration, just like the original NGINX.</p><p>The original NGINX takes this approach because the write queue is the <b>only</b> place that waiting data frames are stored. However, in our NGINX modified for Enhanced HTTP/2 Prioritization, we have a unique structure that the original NGINX lacks: per-stream data frame queues where we temporarily store data frames before our prioritization algorithms are applied to them.</p><p>We came to the realisation that in the event of a partial write, we were able to restore the unwritten frames back into their per-stream queues. If it was the case that a subsequent data cohort arrived behind the partially unwritten one, then the previously unwritten frames could participate in an additional round of prioritization comparisons, thus raising the Potential of our algorithms.</p><p>The following diagram illustrates this process:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7uEXuMETgrrFmtN84ZlQEL/52b63e9fd2401ec0c7c56cd442f1c14e/Write-Queue-Construction-With-Reclamation.png" />
            
            </figure><p>We were very pleased to ship Enhanced HTTP/2 Prioritization with the reclamation feature included as this single enhancement greatly increased Potential and made up for the fact that we had to withhold the next enhancement for speed week due to its delicacy.</p>
    <div>
      <h3>HTTP/2 frame write event re-ordering</h3>
      <a href="#http-2-frame-write-event-re-ordering">
        
      </a>
    </div>
    <p>In Cloudflare infrastructure, we map the many streams of a single HTTP/2 connection from the eyeball to multiple HTTP/1.1 connections to the upstream Cloudflare control plane.</p><p>As a note: it may seem counterintuitive that we downgrade protocols like this, and it may seem doubly counterintuitive when I reveal that we also disable HTTP keepalive on these upstream connections, resulting in only one transaction per connection, however this arrangement offers a number of advantages, particularly in the form of improved CPU workload distribution.</p><p>When NGINX monitors its upstream HTTP/1.1 connections for read activity, it may detect readability on many of those connections and process them all in a batch. However, within that batch, each of the upstream connections is processed sequentially, one at a time, from start to finish: from HTTP/1.1 connection read, to framing in the HTTP/2 stream, to HTTP/2 connection write to the TLS layer.</p><p>The existing NGINX workflow is illustrated in this diagram:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/69wml2jrdBLGZW1nMImkL4/9583420328f40b1e521d0f0a8412614e/Upstream-Read-Event.png" />
            
            </figure><p>By committing each streams’ frames to the TLS layer one stream at a time, many frames may pass entirely through the NGINX system before backpressure on the downstream connection allows the queue of frames to build up, providing an opportunity for these frames to be in proximity and allowing prioritization logic to be applied.  This negatively impacts Potential and reduces the effectiveness of prioritization.</p><p>The Cloudflare Enhanced HTTP/2 Prioritization modified NGINX aims to re-arrange the internal workflow described above into the following model:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4d0xrrRBO4J3C1HCe4Hy8M/43b971a2a8592e5708f930b1c6bfddfb/Upstream-Read-Reordered.png" />
            
            </figure><p>Although we continue to frame upstream data into HTTP/2 data frames in the separate iterations for each upstream connection, we no longer commit these frames to a single write queue within each iteration, instead we arrange the frames into the per-stream queues described earlier. We then post a single event to the end of the per-connection iterations, and perform the prioritization, queuing and writing of the HTTP/2 data frames of all streams in that single event.</p><p>This single event finds the cohort of data conveniently stored in their respective per-stream queues, all in close proximity, which greatly increases the Potential of the Edge Prioritization algorithms.</p><p>In a form closer to actual code, the core of this modification looks a bit like this:</p>
            <pre><code>ngx_http_v2_process_data(ngx_http_v2_connection *h2_conn,
                         ngx_http_v2_stream *h2_stream,
                         ngx_buffer *buffer)
{
    while ( ! ngx_buffer_empty(buffer) {
        ngx_http_v2_frame_data(h2_conn,
                               h2_stream-&gt;frames,
                               buffer);
    }

    ngx_http_v2_prioritise(h2_conn-&gt;queue,
                           h2_stream-&gt;frames);

    ngx_http_v2_write_queue(h2_conn-&gt;queue);
}</code></pre>
            <p>To this:</p>
            <pre><code>ngx_http_v2_process_data(ngx_http_v2_connection *h2_conn,
                         ngx_http_v2_stream *h2_stream,
                         ngx_buffer *buffer)
{
    while ( ! ngx_buffer_empty(buffer) {
        ngx_http_v2_frame_data(h2_conn,
                               h2_stream-&gt;frames,
                               buffer);
    }

    ngx_list_add(h2_conn-&gt;active_streams, h2_stream);

    ngx_call_once_async(ngx_http_v2_write_streams, h2_conn);
}</code></pre>
            
            <pre><code>ngx_http_v2_write_streams(ngx_http_v2_connection *h2_conn)
{
    ngx_http_v2_stream *h2_stream;

    while ( ! ngx_list_empty(h2_conn-&gt;active_streams)) {
        h2_stream = ngx_list_pop(h2_conn-&gt;active_streams);

        ngx_http_v2_prioritise(h2_conn-&gt;queue,
                               h2_stream-&gt;frames);
    }

    ngx_http_v2_write_queue(h2_conn-&gt;queue);
}</code></pre>
            <p>There is a high level of risk in this modification, for even though it is remarkably small, we are taking the well established and debugged event flow in NGINX and switching it around to a significant degree. Like taking a number of Jenga pieces out of the tower and placing them in another location, we risk: race conditions, event misfires and event blackholes leading to lockups during transaction processing.</p><p>Because of this level of risk, we did <b>not</b> release this change in its entirety during Speed Week, but we will continue to test and refine it for future release.</p>
    <div>
      <h3>Upstream buffer partial re-use</h3>
      <a href="#upstream-buffer-partial-re-use">
        
      </a>
    </div>
    <p>Nginx has an internal buffer region to store connection data it reads from upstream. To begin with, the entirety of this buffer is <b>Ready</b> for use. When data is read from upstream into the Ready buffer, the part of the buffer that holds the data is passed to the downstream HTTP/2 layer. Since HTTP/2 takes responsibility for that data, that portion of the buffer is marked as: <b>Busy</b> and it will remain Busy for as long as it takes for the HTTP/2 layer to write the data into the TLS layer, which is a process that may take some time (in computer terms!).</p><p>During this gulf of time, the upstream layer may continue to read more data into the remaining Ready sections of the buffer and continue to pass that incremental data to the HTTP/2 layer until there are no Ready sections available.</p><p>When Busy data is finally finished in the HTTP/2 layer, the buffer space that contained that data is then marked as: <b>Free</b></p><p>The process is illustrated in this diagram:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/rpLV7aUoGwAE6KcQmEts5/9bfa13e2ef08845172e915f01354dc63/Upstream-Buffer-Current-1.png" />
            
            </figure><p>You may ask: When the leading part of the upstream buffer is marked as Free (in blue in the diagram), even though the trailing part of the upstream buffer is still Busy, can the Free part be re-used for reading more data from upstream?</p><p>The answer to that question is: <b>NO</b></p><p>Because just a small part of the buffer is still Busy, NGINX will refuse to allow any of the entire buffer space to be re-used for reads. Only when the entirety of the buffer is Free, can the buffer be returned to the Ready state and used for another iteration of upstream reads. So in summary, data can be read from upstream into Ready space at the tail of the buffer, but not into Free space at the head of the buffer.</p><p>This is a shortcoming in NGINX and is clearly undesirable as it interrupts the flow of data into the system. We asked: what if we could cycle through this buffer region and re-use parts at the head as they became Free? We seek to answer that question in the near future by testing the following buffering model in NGINX:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5WkYGqHYhndsb6dYFqM7TT/6cf0dfe91b09ce205f512347d3427255/Upstream-Buffer-Improved.png" />
            
            </figure>
    <div>
      <h3>TLS layer Buffering</h3>
      <a href="#tls-layer-buffering">
        
      </a>
    </div>
    <p>On a number of occasions in the above text, I have mentioned the TLS layer, and how the HTTP/2 layer writes data into it. In the OSI network model, TLS sits just below the protocol (HTTP/2) layer, and in many consciously designed networking software systems such as NGINX, the software interfaces are separated in a way that mimics this layering.</p><p>The NGINX HTTP/2 layer will collect the current cohort of data frames and place them in priority order into an output queue, then submit this queue to the TLS layer. The TLS layer makes use of a per-connection buffer to collect HTTP/2 layer data before performing the actual cryptographic transformations on that data.</p><p>The purpose of the buffer is to give the TLS layer a more meaningful quantity of data to encrypt, for if the buffer was too small, or the TLS layer simply relied on the units of data from the HTTP/2 layer, then the overhead of encrypting and transmitting the multitude of small blocks may negatively impact system throughput.</p><p>The following diagram illustrates this undersize buffer situation:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/21JR00rWD6FPowvk2nMNRs/79712a865fa021954e8c37f187dac002/TLS-Layer-Buffering-Undersize.png" />
            
            </figure><p>If the TLS buffer is too big, then an excessive amount of HTTP/2 data will be committed to encryption and if it failed to write to the network due to backpressure, it would be locked into the TLS layer and not be available to return to the HTTP/2 layer for the reclamation process, thus reducing the effectiveness of reclamation. The following diagram illustrates this oversize buffer situation:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7wwWnqkWaJ0CpbGLCQWp1l/7e18f9e66c0a7ee9ed83357f52db9398/TLS-Layer-Buffering-Oversize.png" />
            
            </figure><p>In the coming months, we will embark on a process to attempt to find the ‘goldilocks’ spot for TLS buffering: To size the TLS buffer so it is big enough to maintain efficiency of encryption and network writes, but not so big as to reduce the responsiveness to incomplete network writes and the efficiency of reclamation.</p>
    <div>
      <h3>Thank you - Next!</h3>
      <a href="#thank-you-next">
        
      </a>
    </div>
    <p>The Enhanced HTTP/2 Prioritization project has the lofty goal of fundamentally re-shaping how we send traffic from the Cloudflare edge to clients, and as results of our testing and feedback from some of our customers shows, we have certainly achieved that! However, one of the most important aspects that we took away from the project was the critical role the internal data flow within our NGINX software infrastructure plays in the outlook of the traffic observed by our end users. We found that changing a few lines of (albeit critical) code, could have significant impacts on the effectiveness and performance of our prioritization algorithms. Another positive outcome is that in addition to improving HTTP/2, we are looking forward to carrying our newfound skills and lessons learned and apply them to HTTP/3 over QUIC.</p><p>We are eager to share our modifications to NGINX with the community, so we have opened <a href="https://trac.nginx.org/nginx/ticket/1763">this</a> ticket, through which we will discuss upstreaming the event re-ordering change and the buffer partial re-use change with the NGINX team.</p><p>As Cloudflare continues to grow, our requirements on our software infrastructure also shift. Cloudflare has already moved beyond proxying of HTTP/1 over TCP to support termination and Layer 3 and 4 protection for any UDP and TCP traffic. Now we are moving on to other technologies and protocols such as QUIC and HTTP/3, and full proxying of a wide range of other protocols such as messaging and streaming media.</p><p>For these endeavours we are looking at new ways to answer questions on topics such as: scalability, localised performance, wide scale performance, introspection and debuggability, release agility, maintainability.</p><p>If you would like to help us answer these questions and know a bit about: hardware and software scalability, network programming, asynchronous event and futures based software design, TCP, TLS, QUIC, HTTP, RPC protocols, Rust or maybe something else?, then have a look <a href="https://www.cloudflare.com/careers/">here</a>.</p> ]]></content:encoded>
            <category><![CDATA[Speed Week]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[NGINX]]></category>
            <category><![CDATA[HTTP2]]></category>
            <guid isPermaLink="false">tzpAmDnnJeZ1Iu6R6B9KN</guid>
            <dc:creator>Nick Jones</dc:creator>
        </item>
        <item>
            <title><![CDATA[Get a head start with QUIC]]></title>
            <link>https://blog.cloudflare.com/head-start-with-quic/</link>
            <pubDate>Tue, 25 Sep 2018 12:01:00 GMT</pubDate>
            <description><![CDATA[ Today Cloudflare opened the door on our beta deployment of QUIC with the announcement of our test site: cloudflare-quic.com.  ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Today Cloudflare opened the door on our beta deployment of QUIC with the <a href="/the-quicening">announcement</a> of our test site: cloudflare-quic.com. It supports the latest draft of the IETF Working Group’s <a href="https://datatracker.ietf.org/doc/draft-ietf-quic-transport/">draft standard for QUIC</a>, which at this time is at: <a href="https://datatracker.ietf.org/doc/draft-ietf-quic-transport/14/">draft 14</a>.</p><p>The Cloudflare Systems Engineering Team has a long history of investing time and effort to trial new technologies, often before these technologies are standardised or adopted elsewhere. We deployed early experiments in standards such as: <a href="/introducing-http2/">HTTP/2</a>,<a href="/why-tls-1-3-isnt-in-browsers-yet/">TLS1.3</a>, <a href="/dnssec-an-introduction/">DNSSEC</a>, <a href="/dns-resolver-1-1-1-1/">DNS over HTTP</a>, <a href="/esni">Encrypted SNI</a>, when they were still in incubation. We committed to these technologies in their very early stages because we believed that they made for a safer, faster, better internet. And now we’re excited to do the same with QUIC.</p><p>In this blog post, we will show you how you can unlock the <b>cloudflare-quic.com</b> achievement and be some of the first people in the world to perform a HTTP transaction over the global internet using QUIC. This will be a moment that you can tell your grandkids about - if they can stop laughing at your stories of cars with wheels and use of antiquated words like: “meme” and “phone”.</p><p>But before we begin, let’s take a little bit of time to review what QUIC is. Our previous blog post <a href="/the-road-to-quic/">The Road to QUIC</a> by my colleague <a href="/author/alessandro-ghedini/">Alessandro Ghedini</a>, gives an excellent introduction to QUIC; its goals, its challenges, and many of the technical advantages that will come with it. It is good background reading for this article and a great introduction to the topic of QUIC in general.</p><p>If you visit <a href="https://cloudflare-quic.com">cloudflare-quic.com</a> with your regular web browser, you will be presented with an informative landing page. However, what you see will not be delivered using QUIC, because at the time this blog is posted, your browser doesn’t support IETF QUIC. No graphical browser does.</p><p>Some may point out that Google Chrome has had support for QUIC for many years, but we must re-iterate that the protocol supported by Chrome is Google’s own UDP based transport layer protocol. That protocol was once called QUIC but has forfeited that label and now goes by the name gQUIC, and what’s more, the mechanics of gQUIC are now significantly different to IETF QUIC.</p>
    <div>
      <h3>Getting QUIC</h3>
      <a href="#getting-quic">
        
      </a>
    </div>
    <p>The only way to access <b>cloudflare-quic.com</b> using the QUIC protocol is to use a command line client from one of the various implementations of QUIC that are actively evolving alongside the IETF standard. Most of these implementations can be found <a href="https://github.com/quicwg/base-drafts/wiki/Implementations">here</a>. If you are familiar with any of these, you are welcome to try them against <b>cloudflare-quic.com</b> however please note that your client of choice must support <a href="https://datatracker.ietf.org/doc/draft-ietf-quic-transport/14/"><b>draft 14</b></a> of the IETF QUIC standard.</p><p>Our preferred QUIC client, and the one whose output we will be analysing in this blog, comes as part of the ngtcp2 project. The original project is located here: <a href="https://github.com/ngtcp2/ngtcp2">github.com/ngtcp2/ngtcp2</a>, but we are hosting our own copy here: <a href="https://github.com/cloudflare/ngtcp2/tree/quic-draft-14">github.com/cloudflare/ngtcp2/tree/quic-draft-14</a> so that we may be sure you get the exact resources you need for this demonstration.</p><p>Before proceeding please be aware that the following instructions will require you to build software from source code. ngtcp2 and its dependencies are buildable on multiple Operating System platforms, however, the processes described below are more likely to succeed on Linux. To start with, you will need:</p><ul><li><p>A POSIX-flavoured operating system, for example: Ubuntu Linux</p></li><li><p>To install core software development tools: gcc or clang, libc development packages, make, autoconf, automake, autotools-dev, libtool, pkg-config, git</p></li><li><p>To install some additional software dependencies: C Unit tester: (cunit &gt;=2.1), libev development packages. Check the homepage of Cloudflare ngtcp2 copy if you are unsure.</p></li></ul><p>Once you are confident with your setup, run the following commands to retrieve and build the ngtcp2 client and its major dependency OpenSSL:</p>
            <pre><code>$ git clone --depth 1 -b quic-draft-14 https://github.com/tatsuhiro-t/openssl
$ cd openssl
$ ./config enable-tls1_3 --prefix=$PWD/build
$ make
$ make install_sw
$ cd ..
$ git clone -b quic-draft-14 https://github.com/cloudflare/ngtcp2
$ cd ngtcp2
$ autoreconf -i
$ ./configure PKG_CONFIG_PATH=$PWD/../openssl/build/lib/pkgconfig LDFLAGS="-Wl,-rpath,$PWD/../openssl/build/lib"
$ make check</code></pre>
            
    <div>
      <h3>Testing QUIC</h3>
      <a href="#testing-quic">
        
      </a>
    </div>
    <p>If you are still with me, congratulations! The next step is to pre-fabricate a HTTP/1.1 request that we can pass to our QUIC client, in order to avoid typing it out repeatedly. From your ngtcp2 directory, invoke the command:</p>
            <pre><code>$ echo -ne "GET / HTTP/1.1\r\nHost: cloudflare-quic.com\r\n\r\n" &gt; cloudflare-quic.req</code></pre>
            <p>One of the promises of QUIC is the new <a href="https://datatracker.ietf.org/doc/draft-ietf-quic-http/">QUIC HTTP</a> protocol, which is another IETF standard being developed in conjunction with the QUIC transport layer. It is a re-engineering of the HTTP/2 protocol to allow it to benefit from the many advantages of QUIC.</p><p>The design of QUIC HTTP is in a high state of flux at this time and is an elusive target for software implementors, but it is clearly on the Cloudflare product roadmap. For now, <b>cloudflare-quic.com</b> will use HTTP/1.1 for utility and simplicity.</p><p>Now it’s time to invoke the ngtcp2 command line client and establish your QUIC connection to <b>cloudflare-quic.com</b>:</p>
            <pre><code>$ examples/client cloudflare-quic.com 443 -d cloudflare-quic.req</code></pre>
            <p>To be perfectly honest, the debugging output of the ngtcp2 client is not particularly pretty, but who cares! You are now a QUIC pioneer, riding the crest of a new technological wave! Your reward will be the eye-rolls of the teenagers of 2050.</p>
    <div>
      <h3>The HANDSHAKE</h3>
      <a href="#the-handshake">
        
      </a>
    </div>
    <p>Let’s go over some of the ngtcp2 debugging output that you hopefully can see after invoking your HTTP request over QUIC, and at the same time, let’s relate this output back to some important features of the QUIC protocol.</p>
    <div>
      <h4>Client HELLO</h4>
      <a href="#client-hello">
        
      </a>
    </div>
    
            <pre><code>01 I00000000 0x07ff706cb107568ef7116f5f58a9ed9010 pkt tx pkt 0 dcid=0xba006470cf7c05009e219ff201e4adbef8a3 scid=0x07ff706cb107568ef7116f5f58a9ed9010 type=Initial(0x7f) len=0
02 I00000000 0x07ff706cb107568ef7116f5f58a9ed9010 frm tx 0 Initial(0x7f) CRYPTO(0x18) offset=0 len=309
03 I00000000 0x07ff706cb107568ef7116f5f58a9ed9010 frm tx 0 Initial(0x7f) PADDING(0x00) len=878
04 I00000000 0x07ff706cb107568ef7116f5f58a9ed9010 rcv loss_detection_timer=1537267827966896128 last_hs_tx_pkt_ts=1537267827766896128 timeout=200</code></pre>
            <p>Above is what the QUIC protocol calls the client initial packet. It is the packet that is sent to establish a completely new connection between the client and the QUIC server.</p><p>The element: <code>scid</code> on line <code>01</code> is an example of a source connection ID. This is the unique number that the client chooses for itself when sending an initial packet. In the example output above, the value of the client scid is: <code>0x07ff706cb107568ef7116f5f58a9ed9010</code> but you will see a different value. In the ngtcp2 client utility, this number is purely random, as the QUIC connection will only last as long as the command runs, and therefore doesn’t need to carry much meaning. In future, more complex QUIC clients (such as web browsers) will likely choose their source connection IDs more carefully. Future QUIC servers will certainly do this, as connection IDs are a good place to encode information.</p><p>Encoding information in source connection ids is of particular interest to an organisation like Cloudflare, where a single IP address can represent thousands of physical servers. To support QUIC in an infrastructure like ours, routing of UDP QUIC packets will need to be done to a greater level of precision than can be represented in an IP address, and large, data packed connection IDs will be very useful for this. But enough about us, this blog is about you!</p><p>The element: <code>dcid</code>, also on line <code>01</code>, is the destination connection ID. In the client initial phase, this is always random as per the QUIC specification, because the client wants to be sure that it is treated as ‘new’ by the QUIC server. A random <code>dcid</code>, particularly one that is the maximum allowed length of 144bits, combined with a large source connection id, has a sufficiently high statistical chance of being unique so as to not clash with a connection id that the QUIC server has already registered. Later we will see what the QUIC server does with the random destination connection ID that the client has chosen.</p><p>On line <code>02</code>, we see that the client initial packet includes a <code>CRYPTO</code> frame that contains the TLS client hello message. This clearly demonstrates one of the significant advantages in the design of QUIC: the overlapping of transport layer connection establishment and TLS layer negotiation. Both of these processes necessitate some back and forth between a client and server for both TLS over TCP and for QUIC.</p><p>In TLS over TCP the two processes happen one after the other:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/jQj08SwyYXo7i4TGtxaBE/abe44f4a66d3387d6ce55f8e59d40f5a/http-request-over-tcp-tls_2x.png" />
            
            </figure><p>You can count a total of FOUR round trips between the client &amp; the server before a HTTP request can be made! Now compare that with QUIC, where they happen at the same time:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2Pm2yZff9Su7CHqm6l4gXC/17270e669d16f0261cbdbdc2e1d86b7a/http-request-over-quic_2x.png" />
            
            </figure><p>That’s a 50% reduction! With just TWO round trips before you can start making HTTP requests.</p><p>Returning to the analysis of the ngtcp2 debug output, we can see the client initial packet adds a <code>PADDING</code> frame in order to bring the packet to a minimum size mandated by the QUIC specification. The reason for this is twofold:</p><p>Firstly, to ensure that the network between the QUIC client and server can support satisfactorily large UDP packets. Sadly UDP is a second class citizen on the wide internet, generally only being used to transmit single, small, unrelated packets. QUIC counters all three of these patterns, so the rationale here is: if it’s going to get stuck, better to find out early. The quality of network support for streams of UDP will hopefully evolve alongside QUIC.</p><p>Secondly, to reduce the effectiveness of amplification attacks. This type of attack is where bad actors take advantage of network services that produce server responses vastly greater in size than the barely-validated request that solicited them. By spoofing the address of a victim, a bad actor can bombard the victim with large volumes of server responses given a relatively small volume of requests to the server. By requiring that an initial request be large, QUIC helps to make the amplification value much lower. UDP based amplification attacks are a very real issue, and you can read Cloudflare's account of a such an attack <a href="/memcrashed-major-amplification-attacks-from-port-11211/">here</a>.</p><p>QUIC defines a number of other mechanisms to protect against amplification attacks as well as DDoS attacks and you will see some of these a bit later.</p>
    <div>
      <h4>Server HELLO</h4>
      <a href="#server-hello">
        
      </a>
    </div>
    <p>Further down you will see the first packet returned from the server, which is the server initial packet:</p>
            <pre><code>01 I00000160 0x07ff706cb107568ef7116f5f58a9ed9010 pkt rx pkt 0 dcid=0x07ff706cb107568ef7116f5f58a9ed9010 scid=0x3afafde2c24248817832ffe545d874a2a01f type=Initial(0x7f) len=111
02 I00000160 0x07ff706cb107568ef7116f5f58a9ed9010 frm rx 0 Initial(0x7f) CRYPTO(0x18) offset=0 len=90
…
03 I00000314 0x07ff706cb107568ef7116f5f58a9ed9010 cry remote transport_parameters negotiated_version=0xff00000e
04 I00000314 0x07ff706cb107568ef7116f5f58a9ed9010 cry remote transport_parameters supported_version[0]=0xff00000e
…
05 I00000314 0x07ff706cb107568ef7116f5f58a9ed9010 frm tx 3 Initial(0x7f) ACK(0x0d) largest_ack=1 ack_delay=0(0) ack_block_count=0
06 I00000314 0x07ff706cb107568ef7116f5f58a9ed9010 frm tx 3 Initial(0x7f) ACK(0x0d) block=[1..0] block_count=1</code></pre>
            <p>The response destination connection id (<code>dcid</code> on line <code>01</code>) is the client’s original source connection ID (<code>scid</code>) which in this example is: <code>0x07ff706cb107568ef7116f5f58a9ed9010</code>.</p><p>The server has now discarded the client’s randomly-chosen <code>dcid</code> after finding that the client is ‘new’, and replaced it with its own connection ID which you can see as the packet source connection ID <code>scid</code> on line <code>01</code>, which in this example is: <code>0x3afafde2c24248817832ffe545d874a2a01</code>.</p><p>Starting from this point, both the QUIC client and server recognise each other’s connection IDs, opening the door to a powerful feature of QUIC: connection migration. Connection migration will allow QUIC clients and servers to change their IP addresses and ports, but still maintain the QUIC connection. QUIC packets arriving from or to the new IP/port can continue to be handled because the connection ID, which has not changed, will act as the primary identifier of the connection context. For our first <b>cloudflare-quic.com</b> demonstration, connection migration is not supported, but we’ll be working on this as we develop our QUIC offerings.</p><p>The server initial packet contains the next part of the TLS handshake, found in the <code>CRYPTO</code> frame on line <code>01</code>, which is the first part of the TLS server hello and may contain elements such as handshake key material and the beginning of the server’s certificate chain.</p><p>Lines <code>03</code> and <code>04</code> show the exchange of <code>transport parameters</code>, which are QUIC specific configuration values declared by one side to the other and used to control various aspects of the connection. These parameters are encoded and transmitted within the TLS handshake. This not only reiterates the close relationship between the TLS and transport layers in QUIC, but also demonstrates QUIC’s focus on security, as the exchange of these parameters will be protected against outside tampering as part of the TLS handshake.</p><p>Lines <code>05</code> and <code>06</code> show an example of some acknowledgement frames being sent from the client to the server. Acknowledgements are part of the QUIC loss detection mechanism that deals with data losses that inevitably happen on large networks, however during the handshake phase, acknowledgements also have another use: to hint at the validity of the client by proving to the server that a client is truly interested in communicating with the server and is not at a spoofed address.</p><p>Without any form of source validation, QUIC servers will severely limit the amount of data that they send to clients. This protects helpless, spoofed victims of amplification attacks (in conjunction with the client initial packet minimum size requirement described above), and also helps protect the QUIC server from the equivalent of a TCP SYN attack, by constraining the commitment that the QUIC server will make to an unvalidated client.</p><p>For Cloudflare, there are vast unknowns in regard to DDoS and SYN style attacks against QUIC and it is a subject we are supremely interested in. While these threat models remain unknown, our protections around <b>cloudflare-quic.com</b> will be effective but… remorseless.</p>
    <div>
      <h4>The REQUEST</h4>
      <a href="#the-request">
        
      </a>
    </div>
    <p>Once the TLS handshake is complete, we can see the transmission of the first layer 7 data:</p>
            <pre><code>01 I00000315 0xac791937b009b7a61927361d9d453b48e0 pkt tx pkt 0 dcid=0x3afafde2c24248817832ffe545d874a2a01f scid=0x07ff706cb107568ef7116f5f58a9ed9010 type=Short(0x00) len=0
02 I00000315 0xac791937b009b7a61927361d9d453b48e0 frm tx 0 Short(0x00) STREAM(0x13) id=0x0 fin=1 offset=0 len=45 uni=0
03 Ordered STREAM data stream_id=0x0
04 00000000  47 45 54 20 2f 20 48 54  54 50 2f 31 2e 31 0d 0a  |GET / HTTP/1.1..|
05 00000010  48 6f 73 74 3a 20 63 6c  6f 75 64 66 6c 61 72 65  |Host: cloudflare|
06 00000020  2d 71 75 69 63 2e 63 6f  6d 0d 0a 0d 0a           |-quic.com....|</code></pre>
            <p>This fragment of the HTTP transaction is transmitted inside what is called a QUIC <code>STREAM</code>, seen on line <code>02</code>. QUIC streams are one or more communication channels multiplexed within a QUIC connection. QUIC streams are analogous to discrete TCP connections in that they provide data ordering and reliability guarantees, as well as data exchange that is independent from one another. But QUIC streams have some other advantages:</p><p>Firstly, QUIC streams are extremely fast to create as they rely on the authenticated client server relationship previously established by the QUIC connection. Evidence of this can be seen in the example above where a stream’s data is transmitted in the same packet that the stream was established.</p><p>Secondly, because ordering and reliability are independent for each QUIC stream, the loss of data belonging to one stream will not affect any other streams, providing a solution to the head of line blocking problem that affects protocols that multiplex over TCP, like HTTP/2.</p>
    <div>
      <h4>The RESPONSE</h4>
      <a href="#the-response">
        
      </a>
    </div>
    <p>Now you should be able to see the fruit of your QUIC toil: the HTTP response!</p>
            <pre><code>01 I00001755 0x07ff706cb107568ef7116f5f58a9ed9010 con recv packet len=719
02 I00001755 0x07ff706cb107568ef7116f5f58a9ed9010 pkt rx pkt 3 dcid=0x07ff706cb107568ef7116f5f58a9ed9010 scid=0x type=Short(0x00) len=0
03 I00001755 0x07ff706cb107568ef7116f5f58a9ed9010 frm rx 3 Short(0x00) MAX_DATA(0x04) max_data=1048621
04 I00001755 0x07ff706cb107568ef7116f5f58a9ed9010 frm rx 3 Short(0x00) STREAM(0x12) id=0x0 fin=0 offset=0 len=675 uni=0
Ordered STREAM data stream_id=0x0
05 00000000  48 54 54 50 2f 31 2e 31  20 32 30 30 20 4f 4b 0d  |HTTP/1.1 200 OK.|
…
06 I00001755 0x07ff706cb107568ef7116f5f58a9ed9010 con recv packet len=45
07 I00001755 0x07ff706cb107568ef7116f5f58a9ed9010 pkt rx pkt 4 dcid=0x07ff706cb107568ef7116f5f58a9ed9010 scid=0x type=Short(0x00) len=0
08 I00001755 0x07ff706cb107568ef7116f5f58a9ed9010 frm rx 4 Short(0x00) STREAM(0x16) id=0x0 fin=0 offset=675 len=5 uni=0
Ordered STREAM data stream_id=0x0
09 00000000  31 63 65 0d 0a                                    |1ce..|
…
10 I00001755 0x07ff706cb107568ef7116f5f58a9ed9010 con recv packet len=503
11 I00001755 0x07ff706cb107568ef7116f5f58a9ed9010 pkt rx pkt 5 dcid=0x07ff706cb107568ef7116f5f58a9ed9010 scid=0x type=Short(0x00) len=0
12 I00001755 0x07ff706cb107568ef7116f5f58a9ed9010 frm rx 5 Short(0x00) STREAM(0x16) id=0x0 fin=0 offset=680 len=462 uni=0
Ordered STREAM data stream_id=0x0
13 00000000  3c 21 44 4f 43 54 59 50  45 20 68 74 6d 6c 3e 0a  |&lt;!DOCTYPE html&gt;.|
…</code></pre>
            <p>As can be seen on line <code>04</code>, the response arrives on the same QUIC <code>STREAM</code> on which it was sent: (<code>0x0</code>).</p><p>Many other familiar faces can be seen: line <code>05</code>: the start of the response headers, line <code>09</code>: the chunked encoding header and line <code>13</code>: the start of the response body. It looks almost… normal!</p>
    <div>
      <h3>Summary</h3>
      <a href="#summary">
        
      </a>
    </div>
    <p>Thank you for following us on this QUIC odyssey! We understand that the process of building the ngtcp2 example client may be new for some people, but we urge you to keep trying and make use of online resources to help you if you come up against anything unexpected.</p><p>But if all went well, and you managed to see the HTTP response from <b>cloudflare-quic.com</b>, then: <b>Congratulations!</b> You and your screen full of debugging gibberish are on the crest of a new wave of internet communication.</p><ul><li><p>Please take a screenshot or a selfie!</p></li><li><p>Please tell us about it in the comments below!</p></li><li><p>Please take some time to compare the output you see with the points of interest that I have highlighted above.</p></li><li><p>And...please visit our blog again to keep up with our developments with QUIC, as support for this exciting new protocol develops.</p></li></ul><p><a href="/subscribe/"><i>Subscribe to the blog</i></a><i> for daily updates on all our Birthday Week announcements.</i></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6BZ9rEJyb66k1IrkNjZ0UI/8fb7f6701c466c0ea5d69aff12c17f3e/Cloudflare-Birthday-Week-6.png" />
            
            </figure> ]]></content:encoded>
            <category><![CDATA[Birthday Week]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[Programming]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <guid isPermaLink="false">1vieZP33jay319dEsR26y8</guid>
            <dc:creator>Nick Jones</dc:creator>
        </item>
    </channel>
</rss>