
<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 06:35:37 GMT</lastBuildDate>
        <item>
            <title><![CDATA[Go and enhance your calm: demolishing an HTTP/2 interop problem]]></title>
            <link>https://blog.cloudflare.com/go-and-enhance-your-calm/</link>
            <pubDate>Fri, 31 Oct 2025 13:00:00 GMT</pubDate>
            <description><![CDATA[ HTTP/2 implementations often respond to suspected attacks by closing the connection with an ENHANCE_YOUR_CALM error code. Learn how a common pattern of using Go's HTTP/2 client can lead to unintended errors and the solution to avoiding them. ]]></description>
            <content:encoded><![CDATA[ <p>In September 2025, a thread popped up in our internal engineering chat room asking, "Which part of our stack would be responsible for sending <code>ErrCode=ENHANCE_YOUR_CALM</code> to an HTTP/2 client?" Two internal microservices were experiencing a critical error preventing their communication and the team needed a timely answer.</p><p>In this blog post, we describe the background to well-known HTTP/2 attacks that trigger Cloudflare defences, which close connections. We then document an easy-to-make mistake using Go's standard library that can cause clients to send PING flood attacks and how you can avoid it.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2OL6xA151F9JNR4S0wE0DG/f6ae4b0a261da5d189d82ccfa401104e/image1.png" />
          </figure>
    <div>
      <h3>HTTP/2 is powerful – but it can be easy to misuse</h3>
      <a href="#http-2-is-powerful-but-it-can-be-easy-to-misuse">
        
      </a>
    </div>
    <p><a href="https://www.rfc-editor.org/rfc/rfc9113"><u>HTTP/2</u></a> defines a binary wire format for encoding <a href="https://www.rfc-editor.org/rfc/rfc9110.html"><u>HTTP semantics</u></a>. Request and response messages are encoded as a series of HEADERS and DATA frames, each associated with a logical stream, sent over a TCP connection using TLS. There are also control frames that relate to the management of streams or the connection as a whole. For example, SETTINGS frames advertise properties of an endpoint, WINDOW_UPDATE frames provide flow control credit to a peer so that it can send data, RST_STREAM can be used to cancel or reject a request or response, while GOAWAY can be used to signal graceful or immediate connection closure.</p><p>HTTP/2 provides many powerful features that have legitimate uses. However, with great power comes responsibility and opportunity for accidental or intentional misuse. The specification details a number of <a href="https://datatracker.ietf.org/doc/html/rfc9113#section-10.5"><u>denial-of-service considerations</u></a>. Implementations are advised to harden themselves: "An endpoint that doesn't monitor use of these features exposes itself to a risk of denial of service. Implementations SHOULD track the use of these features and set limits on their use."</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/71AXf477FP8u9znjdqXIh9/d6d22049a3f5f5488b8b7e9ac7f832a9/image3.png" />
          </figure><p>Cloudflare implements many different HTTP/2 defenses, developed over years in order to protect our systems and our customers. Some notable examples include mitigations added in 2019 to address "<a href="https://blog.cloudflare.com/on-the-recent-http-2-dos-attacks/"><u>Netflix vulnerabilities</u></a>" and in 2023 to mitigate <a href="https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/"><u>Rapid Reset</u></a> and <a href="https://blog.cloudflare.com/madeyoureset-an-http-2-vulnerability-thwarted-by-rapid-reset-mitigations/"><u>similar</u></a> style attacks.</p><p>When Cloudflare detects that HTTP/2 client behaviour is likely malicious, we close the connection using the GOAWAY frame and include the error code <a href="https://www.rfc-editor.org/rfc/rfc9113#ENHANCE_YOUR_CALM"><code><u>ENHANCE_YOUR_CALM</u></code></a>.</p><p>One of the well-known and common attacks is <a href="https://www.cve.org/CVERecord?id=CVE-2019-9512"><u>CVE-2019-9512</u></a>, aka PING flood: "The attacker sends continual pings to an HTTP/2 peer, causing the peer to build an internal queue of responses. Depending on how efficiently this data is queued, this can consume excess CPU, memory, or both." Sending a <a href="https://www.rfc-editor.org/rfc/rfc9113#section-6.7"><u>PING frame</u></a> causes the peer to respond with a PING acknowledgement (indicated by an ACK flag). This allows for checking the liveness of the HTTP connection, along with measuring the layer 7 round-trip time – both useful things. The requirement to acknowledge a PING, however, provides the potential attack vector since it generates work for the peer.</p><p>A client that PINGs the Cloudflare edge too frequently will trigger our <a href="https://www.cve.org/CVERecord?id=CVE-2019-9512"><u>CVE-2019-9512</u></a> mitigations, causing us to close the connection. Shortly after we <a href="https://blog.cloudflare.com/road-to-grpc/"><u>launched support for gRPC</u></a> in 2020, we encountered interoperability issues with some gRPC clients that sent many PINGs as part of a <a href="https://grpc.io/blog/grpc-go-perf-improvements/#bdp-estimation-and-dynamic-flow-control-window"><u>performance optimization for window tuning</u></a>. We also discovered that the Rust Hyper crate had a feature called Adaptive Window that emulated the design and triggered a similar <a href="https://github.com/hyperium/hyper/issues/2526"><u>problem</u></a> until Hyper made a <a href="https://github.com/hyperium/hyper/pull/2550"><u>fix</u></a>.</p>
    <div>
      <h3>Solving a microservice miscommunication mystery</h3>
      <a href="#solving-a-microservice-miscommunication-mystery">
        
      </a>
    </div>
    <p>When that thread popped up asking which part of our stack was responsible for sending the <code>ENHANCE_YOUR_CALM</code> error code, it was regarding a client communicating over HTTP/2 between two internal microservices.</p><p>We suspected that this was an HTTP/2 mitigation issue and confirmed it was a PING flood mitigation in our logs. But taking a step back, you may wonder why two internal microservices are communicating over the Cloudflare edge at all, and therefore hitting our mitigations. In this case, communicating over the edge provides us with several advantages:</p><ol><li><p>We get to dogfood our edge infrastructure and discover issues like this!</p></li><li><p>We can use Cloudflare Access for authentication. This allows our microservices to be accessed securely by both other services (using service tokens) and engineers (which is invaluable for debugging).</p></li><li><p>Internal services that are written with Cloudflare Workers can easily communicate with services that are accessible at the edge.</p></li></ol>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6v9oBdn5spdqw1BjDW1bS3/a9b36ef9252d580a79c978eb366f7a7a/image2.png" />
          </figure><p>The question remained: Why was this client behaving this way? We traded some ideas as we attempted to get to the bottom of the issue.</p><p>The client had a configuration that would indicate that it didn't need to PING very frequently:</p>
            <pre><code>t2.PingTimeout = 2 * time.Second
t2.ReadIdleTimeout = 5 * time.Second</code></pre>
            <p>However, in situations like this it is generally a good idea to establish ground truth about what is really happening "on the wire." For instance, grabbing a packet capture that can be dissected and explored in Wireshark can provide unequivocal evidence of precisely what was sent over the network. The next best option is detailed/trace logging at the sender or receiver, although sometimes logging can be misleading, so caveat emptor.</p><p>In our particular case, it was simpler to use logging with <code>GODEBUG=http2debug=2</code>. We built a simplified minimal reproduction of the client that triggered the error, helping to eliminate other potential variables. We did some group log analysis, combined with diving into some of the Go standard library code to understand what it was really doing. Issac Asimov is commonly credited with the quote "The most exciting phrase to hear in science, the one that heralds new discoveries, is not 'Eureka!' but 'That's funny...'" and sure enough, within the hour someone declared–

<i>the funny part I see is this:</i></p>
            <pre><code>2025/09/02 17:33:18 http2: Framer 0x14000624540: wrote RST_STREAM stream=9 len=4 ErrCode=CANCEL
2025/09/02 17:33:18 http2: Framer 0x14000624540: wrote PING len=8 ping="j\xe7\xd6R\xdaw\xf8+"</code></pre>
            <p><i>every ping seems to be preceded by a RST_STREAM</i></p><p>Observant readers will recall the earlier mention of Rapid Reset. However, our logs clearly indicated ENHANCE_YOUR_CALM being triggered due to the PING flood. A bit of searching landed us on this <a href="https://groups.google.com/g/grpc-io/c/sWYYQJXHCAQ/m/SWFHxw9IAgAJ"><u>mailing list thread</u></a> and the comment "Sending a PING frame along with an RST_STREAM allows a client to distinguish between an unresponsive server and a slow response." That seemed quite relevant. We also found <a href="https://go-review.googlesource.com/c/net/+/632995"><u>a change that was committed</u></a> related to this topic. This partly answered why there were so many PINGs, but it also raised a new question: Why so many stream resets?

So we went back to the logs and built up a little more context about the interaction:</p>
            <pre><code>2025/09/02 17:33:18 http2: Transport received DATA flags=END_STREAM stream=47 len=0 data=""
2025/09/02 17:33:18 http2: Framer 0x14000624540: wrote RST_STREAM stream=47 len=4 ErrCode=CANCEL
2025/09/02 17:33:18 http2: Framer 0x14000624540: wrote PING len=8 ping="\x97W\x02\xfa&gt;\xa8\xabi"</code></pre>
            <p>The interesting thing here is that the server had sent a DATA frame with the END_STREAM flag set. Per the HTTP/2 stream <a href="https://www.rfc-editor.org/rfc/rfc9113#section-5.1"><u>state machine</u></a>, the stream should have transitioned to <b>closed</b> when a frame with END_STREAM was processed. The client doesn't need to do anything in this state – sending a RST_STREAM is entirely unnecessary.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/R0Bbw1SFYwcyb280RdwjY/578628489c97f67a5ac877a55f4f3e3b/image6.png" />
          </figure><p>A little more digging and noodling and an engineer proclaimed:

<i>I noticed that the reset+ping only happens when you call r</i><code><i>esp.Body.Close()</i></code></p><p><i>I believe Go's HTTP library doesn't actually read the response body automatically, but keeps the stream open for you to use until you call r</i><code><i>esp.Body.Close()</i></code><i>, which you can do at any point you like.</i></p><p>The hilarious thing in our example was that there wasn't actually any HTTP body to read. From the earlier example: <code>received DATA flags=END_STREAM stream=47 len=0 data=""</code>.</p><p>Science and engineering are at times weird and counterintuitive. We decided to tweak our client to read the (absent) body via <code>io.Copy(io.Discard, resp.Body)</code> before closing it. </p><p>Sure enough, this immediately stopped the client sending both a useless RST_STREAM and, by association, a PING frame. </p><p>Mystery solved?</p><p>To prove we had fixed the root cause, the production client was updated with a similar fix. A few hours later, all the ENHANCE_YOUR_CALM closures were eliminated.</p>
    <div>
      <h3>Reading bodies in Go can be unintuitive</h3>
      <a href="#reading-bodies-in-go-can-be-unintuitive">
        
      </a>
    </div>
    <p>It’s worth noting that in some situations, ensuring the response body is always read can sometimes be unintuitive in Go. For example, at first glance it appears that the response body will always be read in the following example:</p>
            <pre><code>resp, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer resp.Body.Close()

if err := json.NewDecoder(resp.Body).Decode(&amp;respBody); err != nil {
	return err
}</code></pre>
            <p>However, <code>json.Decoder</code> stops reading as soon as it finds a complete JSON document or errors. If the response body contains multiple JSON documents or invalid JSON, then the entire response body may still not be read.</p><p>Therefore, in our clients, we’ve started replacing <code>defer response.Body.Close()</code> with the following pattern to ensure that response bodies are always fully read:</p>
            <pre><code>resp, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer func() {
	io.Copy(io.Discard, resp.Body)
	resp.Body.Close()
}()

if err := json.NewDecoder(resp.Body).Decode(&amp;respBody); err != nil {
	return err
}</code></pre>
            
    <div>
      <h2>Actions to take if you encounter ENHANCE_YOUR_CALM</h2>
      <a href="#actions-to-take-if-you-encounter-enhance_your_calm">
        
      </a>
    </div>
    <p>HTTP/2 is a protocol with several features. Many implementations have implemented hardening to protect themselves from misuse of features, which can trigger a connection to be closed. The recommended error code for closing connections in such conditions is ENHANCE_YOUR_CALM. There are numerous HTTP/2 implementations and APIs, which may drive the use of HTTP/2 features in unexpected ways that could appear like attacks.</p><p>If you have an HTTP/2 client that encounters closures with ENHANCE_YOUR_CALM, we recommend that you try to establish ground truth with packet captures (including TLS decryption keys via mechanisms like <a href="https://wiki.wireshark.org/TLS#using-the-pre-master-secret"><u>SSLKEYLOGFILE</u></a>) and/or detailed trace logging. Look for patterns of frequent or repeated frames that might be similar to malicious traffic. Adjusting your client may help avoid it getting misclassified as an attacker.</p><p>If you use Go, we recommend always reading HTTP/2 response bodies (even if empty) in order to avoid sending unnecessary RST_STREAM and PING frames. This is especially important if you use a single connection for multiple requests, which can cause a high frequency of these frames.</p><p>This was also a great reminder of the advantages of dogfooding our own products within our internal services. When we run into issues like this one, our learnings can benefit our customers with similar setups.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6doWYOkW3zbafkANt31knv/b00387716b1971d61eb8b4915ee58783/image5.png" />
          </figure><p></p> ]]></content:encoded>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[DDoS]]></category>
            <guid isPermaLink="false">sucWiZHlaWXeLFddHtkk1</guid>
            <dc:creator>Lucas Pardue</dc:creator>
            <dc:creator>Zak Cutner</dc:creator>
        </item>
        <item>
            <title><![CDATA[MadeYouReset: An HTTP/2 vulnerability thwarted by Rapid Reset mitigations]]></title>
            <link>https://blog.cloudflare.com/madeyoureset-an-http-2-vulnerability-thwarted-by-rapid-reset-mitigations/</link>
            <pubDate>Thu, 14 Aug 2025 22:03:00 GMT</pubDate>
            <description><![CDATA[ A new HTTP/2 denial-of-service (DoS) vulnerability called MadeYouReset was recently disclosed by security researchers. Cloudflare HTTP DDoS mitigation, already protects from MadeYouReset. ]]></description>
            <content:encoded><![CDATA[ <p><i><sub>(Correction on August 19, 2025: This post was updated to correct and clarify details about the vulnerability and the HTTP/2 protocol.)</sub></i></p><p>On August 13, security researchers at Tel Aviv University disclosed a new HTTP/2 denial-of-service (DoS) vulnerability that they are calling MadeYouReset (<a href="https://www.kb.cert.org/vuls/id/767506"><u>CVE-2025-8671</u></a>). This vulnerability exists in a limited number of unpatched HTTP/2 server implementations that do not accurately track use of server-sent stream resets, which can lead to resource consumption. <b>If you’re using Cloudflare for HTTP DDoS mitigation, you’re already protected from MadeYouReset</b>.</p><p>Cloudflare was informed of this vulnerability in May through a coordinated disclosure process, and we were able to confirm that our systems were not susceptible. We foresaw this sort of attack while mitigating the "<a href="https://blog.cloudflare.com/on-the-recent-http-2-dos-attacks/"><u>Netflix vulnerabilities</u></a>" in 2019, and added even stronger defenses in response to <a href="https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/"><u>Rapid Reset</u></a> (<a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-44487"><u>CVE-2023-44487</u></a>) in 2023. MadeYouReset and Rapid Reset are two conceptually similar attacks that exploit a fundamental feature within <a href="https://datatracker.ietf.org/doc/html/rfc9113#RST_STREAM"><u>the HTTP/2 specification</u></a> (RFC 9113): stream resets. In the HTTP/2 protocol, a client initiates a bidirectional stream that carries an HTTP request/response exchange, represented as frames sent between the client and server. Typically, HEADERS and DATA frames are used for a complete exchange.  Endpoints can use the RST_STREAM frame to prematurely terminate a stream, essentially cancelling operations and signalling that it won’t process any more request or response data. Furthermore, HTTP/2 requires that RST_STREAM is sent when there are protocol errors related to the stream. For example, <a href="http://datatracker.ietf.org/doc/html/rfc9113#section-6.1-10"><u>section 6.1 of RFC 9113</u></a> requires that when a DATA frame is received under the wrong circumstances, "...<i>the recipient MUST respond with a stream error (</i><a href="https://datatracker.ietf.org/doc/html/rfc9113#section-5.4.2"><i><u>Section 5.4.2</u></i></a><i>) of type STREAM_CLOSED</i>". </p><p>The vulnerability exploited by both MadeYouReset and Rapid Reset lies in the potential for malicious actors to abuse this stream reset mechanism. By repeatedly causing stream resets, attackers can overwhelm a server's resources. While the server is attempting to process and respond to a multitude of requests, the rapid succession of resets forces it to expend computational effort on starting and then immediately discarding these operations. This can lead to resource exhaustion and impact the availability of the targeted server for legitimate users; <a href="https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/#impact-on-customers"><u>as described previously</u></a>, the main difference between the two attacks is that Rapid Reset exploits client-sent resets, while MadeYouReset exploits server-sent resets. It works by using a client to persuade a server into resetting streams via intentionally sending frames that trigger protocol violations, which in turn trigger stream errors.</p><p>RFC 9113 details a number of <a href="https://datatracker.ietf.org/doc/html/rfc9113#section-10.5"><u>denial-of-service considerations</u></a>. Fundamentally, the protocol provides many features with legitimate uses that can be exploited by attackers with nefarious intent. Implementations are advised to harden themselves: "An endpoint that doesn't monitor use of these features exposes itself to a risk of denial of service. Implementations SHOULD track the use of these features and set limits on their use."</p><p>Fortunately, the MadeYouReset vulnerability only impacts a relatively small number of HTTP/2 implementations. In most major HTTP/2 implementations already in widespread use today, the proactive measures taken to implement RFC 9113 guidance and counter Rapid Reset in 2023 have also provided substantial protection against MadeYouReset, limiting its potential impact and preventing a similarly disruptive event.</p><blockquote><p><b>A note about Cloudflare’s Pingora and its users:
</b>Our <a href="https://blog.cloudflare.com/pingora-open-source/"><u>open-sourced Pingora framework</u></a> uses the popular Rust-language h2 library for its HTTP/2 support. Versions of h2 prior to 0.4.11 were <a href="https://seanmonstar.com/blog/hyper-http2-didnt-madeyoureset/"><u>potentially susceptible to MadeYouReset</u></a>. Users of Pingora can patch their applications by updating their h2 crate version using the cargo update command. Pingora does not itself terminate inbound HTTP connections to Cloudflare’s network, meaning this vulnerability could not be exploited against Cloudflare’s infrastructure.</p></blockquote><p>We would like to credit researchers <a href="https://galbarnahum.com/posts/made-you-reset-intro"><u>Gal Bar Nahum</u></a>, Anat Bremler-Barr, and Yaniv Harel of Tel Aviv University for discovering this vulnerability and thank them for their leadership in the coordinated disclosure process. Cloudflare always encourages security researchers to submit vulnerabilities like this to our <a href="https://hackerone.com/cloudflare?type=team"><u>HackerOne Bug Bounty program</u></a>.</p> ]]></content:encoded>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Vulnerabilities]]></category>
            <category><![CDATA[Attacks]]></category>
            <category><![CDATA[DDoS]]></category>
            <guid isPermaLink="false">707qJXBfSyXWBe0ziAnp8G</guid>
            <dc:creator>Alex Forster</dc:creator>
            <dc:creator>Noah Maxwell Kennedy</dc:creator>
            <dc:creator>Lucas Pardue</dc:creator>
            <dc:creator>Evan Rittenhouse</dc:creator>
        </item>
        <item>
            <title><![CDATA[QUIC action: patching a broadcast address amplification vulnerability]]></title>
            <link>https://blog.cloudflare.com/mitigating-broadcast-address-attack/</link>
            <pubDate>Mon, 10 Feb 2025 14:00:00 GMT</pubDate>
            <description><![CDATA[ Cloudflare was recently contacted by researchers who discovered a broadcast amplification vulnerability through their QUIC Internet measurement research. We've implemented a mitigation. ]]></description>
            <content:encoded><![CDATA[ <p>Cloudflare was recently contacted by a group of anonymous security researchers who discovered a broadcast amplification vulnerability through their <a href="https://blog.cloudflare.com/tag/quic"><u>QUIC</u></a> Internet measurement research. Our team collaborated with these researchers through our Public Bug Bounty program, and worked to fully patch a dangerous vulnerability that affected our infrastructure.</p><p>Since being notified about the vulnerability, we've implemented a mitigation to help secure our infrastructure. According to our analysis, we have fully patched this vulnerability and the amplification vector no longer exists. </p>
    <div>
      <h3>Summary of the amplification attack</h3>
      <a href="#summary-of-the-amplification-attack">
        
      </a>
    </div>
    <p>QUIC is an Internet transport protocol that is encrypted by default. It offers equivalent features to <a href="https://www.cloudflare.com/learning/ddos/glossary/tcp-ip/"><u>TCP</u></a> (Transmission Control Protocol) and <a href="https://www.cloudflare.com/learning/ssl/transport-layer-security-tls/"><u>TLS</u></a> (Transport Layer Security), while using a shorter handshake sequence that helps reduce connection establishment times. QUIC runs over <a href="https://www.cloudflare.com/en-gb/learning/ddos/glossary/user-datagram-protocol-udp/"><u>UDP</u></a> (User Datagram Protocol).</p><p>The researchers found that a single client QUIC <a href="https://datatracker.ietf.org/doc/html/rfc9000#section-17.2.2"><u>Initial packet</u></a> targeting a broadcast IP destination address could trigger a large response of initial packets. This manifested as both a server CPU amplification attack and a reflection amplification attack.</p>
    <div>
      <h3>Transport and security handshakes</h3>
      <a href="#transport-and-security-handshakes">
        
      </a>
    </div>
    <p>When using TCP and TLS there are two handshake interactions. First, is the TCP 3-way transport handshake. A client sends a SYN packet to a server, it responds with a SYN-ACK to the client, and the client responds with an ACK. This process validates the client IP address. Second, is the TLS security handshake. A client sends a ClientHello to a server, it carries out some cryptographic operations and responds with a ServerHello containing a server certificate. The client verifies the certificate, confirms the handshake and sends application traffic such as an HTTP request.</p><p><a href="https://datatracker.ietf.org/doc/html/rfc9000#section-7"><u>QUIC</u></a> follows a similar process, however the sequence is shorter because the transport and security handshake is combined. A client sends an Initial packet containing a ClientHello to a server, it carries out some cryptographic operations and responds with an Initial packet containing a ServerHello with a server certificate. The client verifies the certificate and then sends application data.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7wsMcFwy8xMRYwQyFNm6oC/5d131543e7704794776dfc3ed89c1693/image2.png" />
          </figure><p>The QUIC handshake does not require client IP address validation before starting the security handshake. This means there is a risk that an attacker could spoof a client IP and cause a server to do cryptographic work and send data to a target victim IP (aka a <a href="https://blog.cloudflare.com/reflections-on-reflections/"><u>reflection attack</u></a>). <a href="https://datatracker.ietf.org/doc/html/rfc9000"><u>RFC 9000</u></a> is careful to describe the risks this poses and provides mechanisms to reduce them (for example, see Sections <a href="https://datatracker.ietf.org/doc/html/rfc9000#section-8"><u>8</u></a> and <a href="https://datatracker.ietf.org/doc/html/rfc9000#section-9.3.1"><u>9.3.1</u></a>). Until a client address is verified, a server employs an anti-amplification limit, sending a maximum of 3x as many bytes as it has received. Furthermore, a server can initiate address validation before engaging in the cryptographic handshake by responding with a <a href="https://datatracker.ietf.org/doc/html/rfc9000#section-8.1.2"><u>Retry packet</u></a>. The retry mechanism, however, adds an additional round-trip to the QUIC handshake sequence, negating some of its benefits compared to TCP. Real-world QUIC deployments use a range of strategies and heuristics to detect traffic loads and enable different mitigations.</p><p>In order to understand how the researchers triggered an amplification attack despite these QUIC guardrails, we first need to dive into how IP broadcast works.</p>
    <div>
      <h3>Broadcast addresses</h3>
      <a href="#broadcast-addresses">
        
      </a>
    </div>
    <p>In Internet Protocol version 4 (IPv4) addressing, the final address in any given <a href="https://www.cloudflare.com/learning/network-layer/what-is-a-subnet/"><u>subnet</u></a> is a special broadcast IP address used to send packets to every node within the IP address range. Every node that is within the same subnet receives any packet that is sent to the broadcast address, enabling one sender to send a message that can be “heard” by potentially hundreds of adjacent nodes. This behavior is enabled by default in most network-connected systems and is critical for discovery of devices within the same IPv4 network.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/49zGjFbeIv7RxZMM6W2i5V/9e9e5f2f3bd8401467887d488930f476/image3.png" />
          </figure><p>The broadcast address by nature poses a risk of DDoS amplification; for every one packet sent, hundreds of nodes have to process the traffic. </p>
    <div>
      <h3>Dealing with the expected broadcast</h3>
      <a href="#dealing-with-the-expected-broadcast">
        
      </a>
    </div>
    <p>To combat the risk posed by broadcast addresses, by default most routers reject packets originating from outside their IP subnet which are targeted at the broadcast address of networks for which they are locally connected. Broadcast packets are only allowed to be forwarded within the same IP subnet, preventing attacks from the Internet from targeting servers across the world.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5TU3GO26KOJgzLHcS9Uxiu/6cd334afc3925b1713b7e706decc7269/image1.png" />
          </figure><p>The same techniques are not generally applied when a given router is not directly connected to a given subnet. So long as an address is not locally treated as a broadcast address, <a href="https://www.cloudflare.com/learning/security/glossary/what-is-bgp/"><u>Border Gateway Protocol</u></a> (BGP) or other routing protocols will continue to route traffic from external IPs toward the last IPv4 address in a subnet. Essentially, this means a “broadcast address” is only relevant within a local scope of routers and hosts connected together via Ethernet. To routers and hosts across the Internet, a broadcast IP address is routed in the same way as any other IP.</p>
    <div>
      <h3>Binding IP address ranges to hosts</h3>
      <a href="#binding-ip-address-ranges-to-hosts">
        
      </a>
    </div>
    <p>Each Cloudflare server is expected to be capable of serving content from every website on the Cloudflare network. Because our network utilizes <a href="https://www.cloudflare.com/learning/cdn/glossary/anycast-network/"><u>Anycast</u></a> routing, each server necessarily needs to be listening on (and capable of returning traffic from) every Anycast IP address in use on our network.</p><p>To do so, we take advantage of the loopback interface on each server. Unlike a physical network interface, all IP addresses within a given IP address range are made available to the host (and will be processed locally by the kernel) when bound to the loopback interface.</p><p>The mechanism by which this works is straightforward. In a traditional routing environment, <a href="https://en.wikipedia.org/wiki/Longest_prefix_match"><u>longest prefix matching</u></a> is employed to select a route. Under longest prefix matching, routes towards more specific blocks of IP addresses (such as 192.0.2.96/29, a range of 8 addresses) will be selected over routes to less specific blocks of IP addresses (such as 192.0.2.0/24, a range of 256 addresses).</p><p>While Linux utilizes longest prefix matching, it consults an additional step — the Routing Policy Database (RPDB) — before immediately searching for a match. The RPDB contains a list of routing tables which can contain routing information and their individual priorities. The default RPDB looks like this:</p>
            <pre><code>$ ip rule show
0:	from all lookup local
32766:	from all lookup main
32767:	from all lookup default</code></pre>
            <p>Linux will consult each routing table in ascending numerical order to try and find a matching route. Once one is found, the search is terminated and the route immediately used.</p><p>If you’ve previously worked with routing rules on Linux, you are likely familiar with the contents of the main table. Contrary to the existence of the table named “default”, “main” generally functions as the default lookup table. It is also the one which contains what we traditionally associate with route table information:</p>
            <pre><code>$ ip route show table main
default via 192.0.2.1 dev eth0 onlink
192.0.2.0/24 dev eth0 proto kernel scope link src 192.0.2.2</code></pre>
            <p>This is, however, not the first routing table that will be consulted for a given lookup. Instead, that task falls to the local table:</p>
            <pre><code>$ ip route show table local
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
local 192.0.2.2 dev eth0 proto kernel scope host src 192.0.2.2
broadcast 192.0.2.255 dev eth0 proto kernel scope link src 192.0.2.2</code></pre>
            <p>Looking at the table, we see two new types of routes — local and broadcast. As their names would suggest, these routes dictate two distinctly different functions: routes that are handled locally and routes that will result in a packet being broadcast. Local routes provide the desired functionality — any prefix with a local route will have all IP addresses in the range processed by the kernel. Broadcast routes will result in a packet being broadcast to all IP addresses within the given range. Both types of routes are added automatically when an IP address is bound to an interface (and, when a range is bound to the loopback (lo) interface, the range itself will be added as a local route).</p>
    <div>
      <h3>Vulnerability discovery</h3>
      <a href="#vulnerability-discovery">
        
      </a>
    </div>
    <p>Deployments of QUIC are highly dependent on the load-balancing and packet forwarding infrastructure that they sit on top of. Although QUIC’s RFCs describe risks and mitigations, there can still be attack vectors depending on the nature of server deployments. The reporting researchers studied QUIC deployments across the Internet and discovered that sending a QUIC Initial packet to one of Cloudflare’s broadcast addresses triggered a flood of responses. The aggregate amount of response data exceeded the RFC's 3x amplification limit.</p><p>Taking a look at the local routing table of an example Cloudflare system, we see a potential culprit:</p>
            <pre><code>$ ip route show table local
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
local 192.0.2.2 dev eth0 proto kernel scope host src 192.0.2.2
broadcast 192.0.2.255 dev eth0 proto kernel scope link src 192.0.2.2
local 203.0.113.0 dev lo proto kernel scope host src 203.0.113.0
local 203.0.113.0/24 dev lo proto kernel scope host src 203.0.113.0
broadcast 203.0.113.255 dev lo proto kernel scope link src 203.0.113.0</code></pre>
            <p>On this example system, the anycast prefix 203.0.113.0/24 has been bound to the loopback interface (lo) through the use of standard tooling. Acting dutifully under the standards of IPv4, the tooling has assigned both special types of routes — a local one for the IP range itself and a broadcast one for the final address in the range — to the interface.</p><p>While traffic to the broadcast address of our router’s directly connected subnet is filtered as expected, broadcast traffic targeting our routed anycast prefixes still arrives at our servers themselves. Normally, broadcast traffic arriving at the loopback interface does little to cause problems. Services bound to a specific port across an entire range will receive data sent to the broadcast address and continue as normal. Unfortunately, this relatively simple trait breaks down when normal expectations are broken.</p><p>Cloudflare’s frontend consists of several worker processes, each of which independently binds to the entire anycast range on UDP port 443. In order to enable multiple processes to bind to the same port, we use the SO_REUSEPORT socket option. While SO_REUSEPORT <a href="https://blog.cloudflare.com/the-sad-state-of-linux-socket-balancing/"><u>has additional benefits</u></a>, it also causes traffic sent to the broadcast address to be copied to every listener.</p><p>Each individual QUIC server worker operates in isolation. Each one reacted to the same client Initial, duplicating the work on the server side and generating response traffic to the client's IP address. Thus, a single packet could trigger a significant amplification. While specifics will vary by implementation, a typical one-listener-per-core stack (which sends retries in response to presumed timeouts) on a 128-core system could result in 384 replies being generated and sent for each packet sent to the broadcast address.</p><p>Although the researchers demonstrated this attack on QUIC, the underlying vulnerability can affect other UDP request/response protocols that use sockets in the same way.</p>
    <div>
      <h3>Mitigation</h3>
      <a href="#mitigation">
        
      </a>
    </div>
    <p>As a communication methodology, broadcast is not generally desirable for anycast prefixes. Thus, the easiest method to mitigate the issue was simply to disable broadcast functionality for the final address in each range.</p><p>Ideally, this would be done by modifying our tooling to only add the local routes in the local routing table, skipping the inclusion of the broadcast ones altogether. Unfortunately, the only practical mechanism to do so would involve patching and maintaining our own internal fork of the iproute2 suite, a rather heavy-handed solution for the problem at hand.</p><p>Instead, we decided to focus on removing the route itself. Similar to any other route, it can be removed using standard tooling:</p>
            <pre><code>$ sudo ip route del 203.0.113.255 table local</code></pre>
            <p>To do so at scale, we made a relatively minor change to our deployment system:</p>
            <pre><code>  {%- for lo_route in lo_routes %}
    {%- if lo_route.type == "broadcast" %}
        # All broadcast addresses are implicitly ipv4
        {%- do remove_route({
        "dev": "lo",
        "dst": lo_route.dst,
        "type": "broadcast",
        "src": lo_route.src,
        }) %}
    {%- endif %}
  {%- endfor %}</code></pre>
            <p>In doing so, we effectively ensure that all broadcast routes attached to the loopback interface are removed, mitigating the risk by ensuring that the specification-defined broadcast address is treated no differently than any other address in the range.</p>
    <div>
      <h3>Next steps </h3>
      <a href="#next-steps">
        
      </a>
    </div>
    <p>While the vulnerability specifically affected broadcast addresses within our anycast range, it likely expands past our infrastructure. Anyone with infrastructure that meets the relatively narrow criteria (a multi-worker, multi-listener UDP-based service that is bound to all IP addresses on a machine with routable IP prefixes attached in such a way as to expose the broadcast address) will be affected unless mitigations are in place. We encourage network administrators and security professionals to assess their systems for configurations that may present a local amplification attack vector.</p> ]]></content:encoded>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Network]]></category>
            <category><![CDATA[Edge]]></category>
            <category><![CDATA[DDoS]]></category>
            <category><![CDATA[HTTP3]]></category>
            <category><![CDATA[Bug Bounty]]></category>
            <guid isPermaLink="false">6ZaxgQxDACeIF6MZAquLPV</guid>
            <dc:creator>Josephine Chow</dc:creator>
            <dc:creator>June Slater</dc:creator>
            <dc:creator>Bryton Herdes</dc:creator>
            <dc:creator>Lucas Pardue</dc:creator>
        </item>
        <item>
            <title><![CDATA[Open sourcing h3i: a command line tool and library for low-level HTTP/3 testing and debugging]]></title>
            <link>https://blog.cloudflare.com/h3i/</link>
            <pubDate>Mon, 30 Dec 2024 14:00:00 GMT</pubDate>
            <description><![CDATA[ h3i is a command line tool and Rust library designed for low-level testing and debugging of HTTP/3, which runs over QUIC. ]]></description>
            <content:encoded><![CDATA[ <p>Have you ever built a piece of IKEA furniture, or put together a LEGO set, by following the instructions closely and only at the end realized at some point you didn't <i>quite</i> follow them correctly? The final result might be close to what was intended, but there's a nagging thought that maybe, just maybe, it's not as rock steady or functional as it could have been.</p><p>Internet protocol specifications are instructions designed for engineers to build things. Protocol designers take great care to ensure the documents they produce are clear. The standardization process gathers consensus and review from experts in the field, to further ensure document quality. Any reasonably skilled engineer should be able to take a specification and produce a performant, reliable, and secure implementation. The Internet is central to everyone's lives, and we depend on these implementations. Any deviations from the specification can put us at risk. For example, mishandling of malformed requests can allow attacks such as <a href="https://en.wikipedia.org/wiki/HTTP_request_smuggling"><u>request smuggling</u></a>.</p><p>h3i is a binary command line tool and Rust library designed for low-level testing and debugging of HTTP/3, which runs over QUIC. <a href="https://crates.io/crates/h3i"><u>h3i</u></a> is free and open source as part of Cloudflare's <a href="https://github.com/cloudflare/quiche"><u>quiche</u></a> project. In this post we'll explain the motivation behind developing h3i, how we use it to help develop robust and safe standards-compliant software and production systems, and how you can similarly use it to test your own software or services. If you just want to jump into how to use h3i, go to the <a href="#the-h3i-command-line-tool"><u>h3i command line tool</u></a> section.</p>
    <div>
      <h2>A recap of QUIC and HTTP/3</h2>
      <a href="#a-recap-of-quic-and-http-3">
        
      </a>
    </div>
    <p><a href="https://blog.cloudflare.com/http3-the-past-present-and-future/"><u>QUIC</u></a> is a secure-by-default transport protocol that provides performance advantages compared to TCP and TLS via a more efficient handshake, along with stream multiplexing that provides <a href="https://en.wikipedia.org/wiki/Head-of-line_blocking"><u>head-of-line blocking</u></a> avoidance. <a href="https://www.cloudflare.com/en-gb/learning/performance/what-is-http3/"><u>HTTP/3</u></a> is an application protocol that maps HTTP semantics to QUIC, such as defining how HTTP requests and responses are assigned to individual QUIC streams.</p><p>Cloudflare has supported QUIC on our global network in some shape or form <a href="https://blog.cloudflare.com/http3-the-past-present-and-future/"><u>since 2018</u></a>. We started while the <a href="https://ietf.org/"><u>Internet Engineering Task Force (IETF)</u></a> was earnestly standardizing the protocol, working through early iterations and using interoperability testing and experience to help provide feedback for the standards process. We <a href="https://blog.cloudflare.com/quic-version-1-is-live-on-cloudflare/"><u>launched support</u></a> for QUIC version 1 and HTTP/3 as soon as <a href="https://datatracker.ietf.org/doc/html/rfc9000"><u>RFC 9000</u></a> (and its accompanying specifications) were published in 2021.</p><p>We work on the Protocols team, who own the ingress proxy into the Cloudflare network. This is essentially Cloudflare’s “front door” — HTTP requests that come to Cloudflare from the Internet pass through us first. The majority of requests are passed onwards to things like rulesets, workers, caches, or a customer origin. However, you might be surprised that many requests don't ever make it that far because they are, in some way, invalid or malformed. Servers listening on the Internet have to be robust to traffic that is not RFC compliant, whether caused by accident or malicious intent.</p><p>The Protocols team actively participates in IETF standardization work and has also helped build and maintain other Cloudflare services that leverage quiche for QUIC and HTTP/3, from the proxies that help <a href="https://blog.cloudflare.com/icloud-private-relay/"><u>iCloud Private Relay</u></a> via <a href="https://blog.cloudflare.com/unlocking-quic-proxying-potential/"><u>MASQUE proxying</u></a>, to replacing <a href="https://blog.cloudflare.com/zero-trust-warp-with-a-masque/"><u>WARP's use of Wireguard with MASQUE</u></a>, and beyond.</p><p>Throughout all of these different use cases, it is important for us to extensively test all aspects of the protocols. A deep dive into protocol details is a blog post (or three) in its own right. So let's take a thin slice across HTTP to help illustrate the concepts.</p><p><a href="https://www.rfc-editor.org/rfc/rfc9110.html"><u>HTTP Semantics</u></a> are common to all versions of HTTP — the overall architecture, terminology, and protocol aspects such as request and response messages, methods, status codes, header and trailer fields, message content, and much more. Each individual HTTP version defines how semantics are transformed into a "wire format" for exchange over the Internet. You can read more about HTTP/1.1 and HTTP/2 in some of our previous <a href="https://blog.cloudflare.com/a-primer-on-proxies/"><u>blog</u></a> <a href="https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/"><u>posts</u></a>.</p><p>With HTTP/3, HTTP request and response messages are split into a series of binary frames. <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-7.2.2"><u>HEADERS</u></a> frames carry a representation of HTTP metadata (method, path, status code, field lines). The payload of the frame is the encoded <a href="https://datatracker.ietf.org/doc/html/rfc9204"><u>QPACK</u></a> compression output. <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-7.2.1"><u>DATA</u></a> frames carry <a href="https://datatracker.ietf.org/doc/html/rfc9110#section-6.4.1"><u>HTTP content</u></a> (aka "message body"). In order to exchange these frames, HTTP/3 relies on QUIC <a href="https://datatracker.ietf.org/doc/html/rfc9000#section-2"><u>streams</u></a>. These provide an ordered and reliable byte stream and each have an identifier (ID) that is unique within the scope of a connection. There are <a href="https://datatracker.ietf.org/doc/html/rfc9000#section-2.1"><u>four different stream types</u></a>, denominated by the two least significant bits of the ID.</p><p>As a simple example, assuming a QUIC connection has already been established, a client can make a GET request and receive a 200 OK response with an HTML body using the follow sequence:</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7vVfQ5CYaaVPVmGloRUnkI/88bd727c3526e540bd493bc15fbe904a/unnamed.png" />
          </figure><ol><li><p>Client allocates the first available client-initiated bidirectional QUIC stream. (The IDs start at 0, then 4, 8, 12 and so on)</p></li><li><p>Client sends the request HEADERS frame on the stream and sets the stream's <a href="https://datatracker.ietf.org/doc/html/rfc9000#section-19.8"><u>FIN bit</u></a> to mark the end of stream.</p></li><li><p>Server receives the request HEADERS frame and validates it against <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-4.1.2"><u>RFC 9114 rules</u></a>. If accepted, it processes the request and prepares the response.</p></li><li><p>Server sends the response HEADERS frame on the same stream.</p></li><li><p>Server sends the response DATA frame on the same stream and sets the FIN bit.</p></li><li><p>Client receives the response frames and validates them. If accepted, the content is presented to the user.</p></li></ol><p>At the QUIC layer, stream data is split into STREAM frames, which are sent in QUIC packets over UDP. QUIC deals with any loss detection and recovery, helping to ensure stream data is reliable. The layer cake diagram below provides a handy comparison of how HTTP/1.1, HTTP/2 and HTTP/3 use TCP, UDP and IP.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4049UpKGn4BJcYcEXSFgWz/32143a5ba3672786639908ad96851225/image2.png" />
          </figure>
    <div>
      <h2>Background on testing QUIC and HTTP/3 at Cloudflare</h2>
      <a href="#background-on-testing-quic-and-http-3-at-cloudflare">
        
      </a>
    </div>
    <p>The Protocols team has a diverse set of automated test tools that exercise our ingress proxy software in order to ensure it can stand up to the deluge that the Internet can throw at it. Just like a bouncer at a nightclub front door, we need to prevent as much bad traffic as possible before it gets inside and potentially causes damage.</p><p>HTTP/2 and HTTP/3 share several concepts. When we started developing early HTTP/3 support, we'd already learned a lot from production experience with HTTP/2. While HTTP/2 addressed many issues with HTTP/1.1 (especially problems like <a href="https://www.cgisecurity.com/lib/HTTP-Request-Smuggling.pdf"><u>request smuggling</u></a>, caused by its ASCII-based message delineation), HTTP/2 also added complexity and new avenues for attack. Security is an ongoing process, and the Protocols team continually hardens our software and systems to threats. For example, mitigating the range of <a href="https://blog.cloudflare.com/on-the-recent-http-2-dos-attacks/"><u>denial-of-service attacks</u></a> identified by Netflix in 2019, or the <a href="https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/"><u>HTTP/2 Rapid Reset</u></a> attacks of 2023.</p><p>For testing HTTP/2, we rely on the Python <a href="https://pypi.org/project/requests/"><u>Requests</u></a> library for testing conventional HTTP exchanges. However, that mostly only exercises HEADERS and DATA frames. There are eight other frame types and a plethora of ways that they can interact (hence the new attack vectors mentioned above). In order to get full testing coverage, we have to break down into the lower layer <a href="https://pypi.org/project/h2/"><u>h2</u></a> library, which allows exact frame-by-frame control. However, even that is not always enough. Libraries tend to want to follow the RFC rules and prevent their users from doing "the wrong thing". This is entirely logical for most purposes. For our needs though, we need to take off the safety guards just like any potential attackers might do. We have a few cases where the best way to exercise certain traffic patterns is to handcraft HTTP/2 frames in a hex editor, store that as binary, and replay it with a tool such as <a href="https://docs.openssl.org/1.0.2/man1/s_client/"><u>OpenSSL s_client</u></a>.</p><p>We knew we'd need similar testing approaches for HTTP/3. However, when we started in 2018, there weren't many other suitable client implementations. The rate of iteration on the specifications also meant it was hard to always keep in sync. So we built tests on quiche, using a mix of our <a href="https://github.com/cloudflare/quiche/blob/master/apps/src/client.rs"><u>quiche-client</u></a> and <a href="https://github.com/cloudflare/quiche/tree/master/tools/http3_test"><u>http3_test</u></a>. Over time, the python library <a href="https://github.com/aiortc/aioquic"><u>aioquic</u></a> has matured, and we have used it to add a range of lower-layer tests that break or bend HTTP/3 rules, in order to prove our proxies are robust.</p><p>Finally, we would be remiss not to mention that all the tests in our ingress proxy are <b>in addition to </b>the suite of over 500 integration tests that run on the quiche project itself.</p>
    <div>
      <h2>Making HTTP/3 testing more accessible and maintainable with h3i</h2>
      <a href="#making-http-3-testing-more-accessible-and-maintainable-with-h3i">
        
      </a>
    </div>
    <p>While we are happy with the coverage of our current tests, the smorgasbord of test tools makes it hard to know what to reach for when adding new tests. For example, we've had cases where aioquic's safety guards prevent us from doing something, and it has needed a patch or workaround. This sort of thing requires a time investment just to debug/develop the tests.</p><p>We believe it shouldn't take a protocol or code expert to develop what are often very simple to describe tests. While it is important to provide guide rails for the majority of conventional use cases, it is also important to provide accessible methods for taking them off.</p><p>Let's consider a simple example. In HTTP/3 there is something called the control stream. It's used to exchange frames such as SETTINGS, which affect the HTTP/3 connection. RFC 9114 <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-6.2.1"><u>Section 6.2.1</u></a> states:</p><blockquote><p><i>Each side MUST initiate a single control stream at the beginning of the connection and send its SETTINGS frame as the first frame on this stream. If the first frame of the control stream is any other frame type, this MUST be treated as a connection error of type H3_MISSING_SETTINGS. Only one control stream per peer is permitted; receipt of a second stream claiming to be a control stream MUST be treated as a connection error of type H3_STREAM_CREATION_ERROR. The sender MUST NOT close the control stream, and the receiver MUST NOT request that the sender close the control stream. If either control stream is closed at any point, this MUST be treated as a connection error of type H3_CLOSED_CRITICAL_STREAM. Connection errors are described in Section 8.</i></p></blockquote><p>There are many tests we can conjure up just from that paragraph:</p><ol><li><p>Send a non-SETTINGS frame as the first frame on the control stream.</p></li><li><p>Open two control streams.</p></li><li><p>Open a control stream and then close it with a FIN bit.</p></li><li><p>Open a control stream and then reset it with a RESET_STREAM QUIC frame.</p></li><li><p>Wait for the peer to open a control stream and then ask for it to be reset with a STOP_SENDING QUIC frame.</p></li></ol><p>All of the above actions should cause a remote peer that has implemented the RFC properly to close the connection. Therefore, it is not in the interest of the local client or server applications to ever do these actions.</p><p>Many QUIC and HTTP/3 implementations are developed as libraries that are integrated into client or server applications. There may be an extensive set of unit or integration tests of the library checking RFC rules. However, it is also important to run the same tests on the integrated assembly of library and application, since it's all too common that an unhandled/mishandled library error can cascade to cause issues in upper layers. For instance, the HTTP/2 Rapid Reset attacks affected Cloudflare due to their <a href="https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/#impact-on-customers"><u>impact on how one service spoke to another</u></a>.</p><p>We've developed h3i, a command line tool and library, to make testing more accessible and maintainable for all. We started with a client that can exercise servers, since that's what our focus has been. Future developments could support the opposite, a server that behaves in unusual ways in order to exercise clients.</p><p><b>Note: </b>h3i is <i>not</i> intended to be a production client! Its flexibility may cause issues that are not observed in other production-oriented clients. It is also not intended to be used for any type of performance testing and measurement.</p>
    <div>
      <h2>The h3i command line tool</h2>
      <a href="#the-h3i-command-line-tool">
        
      </a>
    </div>
    <p>The primary purpose of the h3i command line tool is quick low-level debugging and exploratory testing. Rather than worrying about writing code or a test script, users can quickly run an ad-hoc client test against a target, guided by interactive prompts.</p><p>In the simplest case, you can think of h3i a bit like <a href="https://curl.se/"><u>curl</u></a> but with access to some extra HTTP/3 parameters. In the example below, we issue a request to <a href="https://cloudflare-quic.com"><u>https://cloudflare-quic.com</u></a>/ and receive a response.</p><div>
  
</div><p>Walking through a simple GET with h3i step-by-step:</p><ol><li><p>Grab a copy of the h3i binary either by running <code>cargo install h3i</code> or cloning the quiche source repo at <a href="https://github.com/cloudflare/quiche/"><u>https://github.com/cloudflare/quiche/</u></a>. Both methods assume you have some familiarity with Rust and Cargo. See the cargo <a href="https://doc.rust-lang.org/book/ch14-04-installing-binaries.html"><u>documentation</u></a> for more information.</p><ol><li><p><code>cargo install</code> will place the binary on your path, so you can then just run it by executing <code>h3i</code>.</p></li><li><p>If running from source, navigate to the quiche/h3i directory and then use <code>cargo run</code>.</p></li></ol></li><li><p>Run the binary and provide the name and port of the target server. If the port is omitted, the default value 443 is assumed. E.g, <code>cargo run cloudflare-quic.com</code></p></li><li><p>h3i then enters the action prompting phase. A series of one or more HTTP/3 actions can be queued up, such as sending frames, opening or terminating streams, or waiting on data from the server. The full set of options is documented in the <a href="https://github.com/cloudflare/quiche/blob/master/h3i/README.md#command-line-tool"><u>readme</u></a>.</p><ol><li><p>The prompting interface adapts to keyboard inputs and supports tab completion.</p></li><li><p>In the example above, the <code>headers</code> action is selected, which walks through populating the fields in a HEADERS frame. It includes <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-4.3.1"><u>mandatory fields</u></a> from RFC 9114 for convenience. If a test requires omitting these, the <code>headers_no_pseudo</code> can be used instead.</p></li></ol></li><li><p>The <code>commit</code> prompt choice finalizes the action list and moves to the connection phase. h3i initiates a QUIC connection to the server identified in step 2. Once connected, actions are executed in order.</p></li><li><p>By default, h3i reports some limited information about the frames the server sent. To get more detailed information, the <code>RUST_LOG</code> environment can be set with either <code>debug</code> or <code>trace</code> levels.</p></li></ol>
    <div>
      <h2>Instant record and replay, powered by qlog</h2>
      <a href="#instant-record-and-replay-powered-by-qlog">
        
      </a>
    </div>
    <p>It can be fun to play around with the h3i command line tool to see how different servers respond to different combinations or sequences of actions. Occasionally, you'll find a certain set that you want to run over and over again, or share with a friend or colleague. Having to manually enter the prompts repeatedly, or share screenshots of the h3i input can turn tedious. Fortunately, h3i records all the actions in a log file by default — the file path is printed immediately after h3i starts. The format of this file is based on <a href="https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-main-schema"><u>qlog</u></a>, an in-progress standard in development at the IETF for network protocol logging. It’s a perfect fit for our low-level needs.</p><p>Here's an example h3i qlog file:</p>
            <pre><code>{"qlog_version":"0.3","qlog_format":"JSON-SEQ","title":"h3i","description":"h3i","trace":{"vantage_point":{"type":"client"},"title":"h3i","description":"h3i","configuration":{"time_offset":0.0}}}
{
  "time": 0.172783,
  "name": "http:frame_created",
  "data": {
    "stream_id": 0,
    "frame": {
      "frame_type": "headers",
      "headers": [
        {
          "name": ":method",
          "value": "GET"
        },
        {
          "name": ":authority",
          "value": "cloudflare-quic.com"
        },
        {
          "name": ":path",
          "value": "/"
        },
        {
          "name": ":scheme",
          "value": "https"
        },
        {
          "name": "user-agent",
          "value": "h3i"
        }
      ]
    }
  },
  "fin_stream": true
}</code></pre>
            <p>h3i logs can be replayed using the <code>--qlog-input</code> option. You can change the target server host and port, and keep all the same actions. However, most servers will validate the :authority pseudo-header or Host header contained in a HEADERS frame. The --replay-host-override option allows changing these fields without needing to modify the file by hand.</p><p>And yes, qlog files are human-readable text in the JSON-SEQ format. So you can also just write these by hand in the first place if you like! However, if you're going to start writing things, maybe Rust is your preferred option…</p>
    <div>
      <h2>Using the h3i library to send a malformed request with Rust</h2>
      <a href="#using-the-h3i-library-to-send-a-malformed-request-with-rust">
        
      </a>
    </div>
    <p>In our previous example, we just sent a valid request so there wasn't anything interesting to observe. Where h3i really shines is in generating traffic that isn't RFC compliant, such as malformed HTTP messages, invalid frame sequences, or other actions on streams. This helps determine if a server is acting robustly and defensively.</p><p>Let's explore this more with an example of HTTP content-length mismatch. RFC 9114 <a href="https://datatracker.ietf.org/doc/html/rfc9114#section-4.1.2"><u>section 4.1.2</u></a> specifies:</p><blockquote><p><i>A request or response that is defined as having content when it contains a Content-Length header field (Section 8.6 of [HTTP]) is malformed if the value of the Content-Length header field does not equal the sum of the DATA frame lengths received. A response that is defined as never having content, even when a Content-Length is present, can have a non-zero Content-Length header field even though no content is included in DATA frames.</i></p><p><i>Intermediaries that process HTTP requests or responses (i.e., any intermediary not acting as a tunnel) MUST NOT forward a malformed request or response. Malformed requests or responses that are detected MUST be treated as a stream error of type H3_MESSAGE_ERROR.</i></p><p><i>For malformed requests, a server MAY send an HTTP response indicating the error prior to closing or resetting the stream.</i></p></blockquote><p>There are good reasons that the RFC is so strict about handling mismatched content lengths. They can be a vector for <a href="https://portswigger.net/research/http2"><u>desynchronization attacks</u></a> (similar to request smuggling), especially when a proxy is converting inbound HTTP/3 to outbound HTTP/1.1.</p><p>We've provided an <a href="https://github.com/cloudflare/quiche/blob/master/h3i/examples/content_length_mismatch.rs"><u>example</u></a> of how to use the h3i Rust library to write a tailor-made test client that sends a mismatched content length request. It sends a Content-Length header of 5, but its body payload is “test”, which is only 4 bytes. It then waits for the server to respond, after which it explicitly closes the connection by sending a QUIC CONNECTION_CLOSE frame.</p><p>When running low-level tests, it can be interesting to also take a packet capture (<a href="https://en.wikipedia.org/wiki/Pcap"><u>pcap</u></a>) and observe what is happening on the wire. Since QUIC is an encrypted transport, we'll need to use the SSLKEYLOG environment variable to capture the session keys so that tools like Wireshark can <a href="https://wiki.wireshark.org/TLS#using-the-pre-master-secret"><u>decrypt and dissect</u></a>.</p><p>To follow along at home, clone a copy of the quiche repository, start a packet capture on the appropriate network interface and then run:</p>
            <pre><code>cd quiche/h3i
SSLKEYLOGFILE="h3i-example.keys" cargo run --example content_length_mismatch</code></pre>
            <p>In our decrypted capture, we see the expected sequence of handshake, request, response, and then closure.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6Qkdd3h0x826tH95S61u92/5de829e018b9d3ef409a2452362fa81e/image1.png" />
          </figure>
    <div>
      <h2>Surveying the example code</h2>
      <a href="#surveying-the-example-code">
        
      </a>
    </div>
    <p>The <a href="https://github.com/cloudflare/quiche/blob/master/h3i/examples/content_length_mismatch.rs"><u>example</u></a> is a simple binary app with a <code>main()</code> entry point. Let's survey the key elements.</p><p>First, we set up an h3i configuration to a target server:</p>
            <pre><code>let config = Config::new()
        .with_host_port("cloudflare-quic.com".to_string())
        .with_idle_timeout(2000)
        .build()
        .unwrap();</code></pre>
            <p>The idle timeout is a QUIC concept which tells each endpoint when it should close the connection if the connection has been idle. This prevents endpoints from spinning idly if the peer hasn’t closed the connection. h3i’s default is 30 seconds, which can be too long for tests, so we set ours to 2 seconds here.</p><p>Next, we define a set of request headers and encode them with QPACK compression, ready to put in a HEADERS frame. Note that h3i does provide a <a href="https://docs.rs/h3i/latest/h3i/actions/h3/fn.send_headers_frame.html"><u>send_headers_frame</u></a> helper method which does this for you, but the example does it manually for clarity:</p>
            <pre><code>let headers = vec![
        Header::new(b":method", b"POST"),
        Header::new(b":scheme", b"https"),
        Header::new(b":authority", b"cloudflare-quic.com"),
        Header::new(b":path", b"/"),
        // We say that we're going to send a body with 5 bytes...
        Header::new(b"content-length", b"5"),
    ];

    let header_block = encode_header_block(&amp;headers).unwrap();</code></pre>
            <p>Then, we define the set of h3i actions that we want to execute in order: send HEADERS, send a too-short DATA frame, wait for the server's HEADERS, then close the connection.</p>
            <pre><code>let actions = vec![
        Action::SendHeadersFrame {
            stream_id: STREAM_ID,
            fin_stream: false,
            headers,
            frame: Frame::Headers { header_block },
        },
        Action::SendFrame {
            stream_id: STREAM_ID,
            fin_stream: true,
            frame: Frame::Data {
                // ...but, in actuality, we only send 4 bytes. This should yield a
                // 400 Bad Request response from an RFC-compliant
                // server: https://datatracker.ietf.org/doc/html/rfc9114#section-4.1.2-3
                payload: b"test".to_vec(),
            },
        },
        Action::Wait {
            wait_type: WaitType::StreamEvent(StreamEvent {
                stream_id: STREAM_ID,
                event_type: StreamEventType::Headers,
            }),
        },
        Action::ConnectionClose {
            error: quiche::ConnectionError {
                is_app: true,
                error_code: quiche::h3::WireErrorCode::NoError as u64,
                reason: vec![],
            },
        },
    ];</code></pre>
            <p>Finally, we'll set things in motion with <code>connect()</code>, which sets up the QUIC connection, executes the actions list and collects the summary.</p>
            <pre><code>let summary =
        sync_client::connect(config, &amp;actions).expect("connection failed");

    println!(
        "=== received connection summary! ===\n\n{}",
        serde_json::to_string_pretty(&amp;summary).unwrap_or_else(|e| e.to_string())
    );</code></pre>
            <p><a href="https://docs.rs/h3i/latest/h3i/client/connection_summary/struct.ConnectionSummary.html"><u>ConnectionSummary</u></a>  provides data about the connection, including the frames h3i received, details about why the connection closed, and connection statistics. The example prints the summary out. However, you can programmatically check it. We do this to write our own internal automation tests.</p><p>If you're running the example, it should print something like the following:</p>
            <pre><code>=== received connection summary! ===

{
  "stream_map": {
    "0": [
      {
        "UNKNOWN": {
          "raw_type": 2471591231244749708,
          "payload": ""
        }
      },
      {
        "UNKNOWN": {
          "raw_type": 2031803309763646295,
          "payload": "4752454153452069732074686520776f7264"
        }
      },
      {
        "enriched_headers": {
          "header_block_len": 75,
          "headers": [
            {
              "name": ":status",
              "value": "400"
            },
            {
              "name": "server",
              "value": "cloudflare"
            },
            {
              "name": "date",
              "value": "Sat, 07 Dec 2024 00:34:12 GMT"
            },
            {
              "name": "content-type",
              "value": "text/html"
            },
            {
              "name": "content-length",
              "value": "155"
            },
            {
              "name": "cf-ray",
              "value": "8ee06dbe2923fa17-ORD"
            }
          ]
        }
      },
      {
        "DATA": {
          "payload_len": 104
        }
      },
      {
        "DATA": {
          "payload_len": 51
        }
      }
    ]
  },
  "stats": {
    "recv": 10,
    "sent": 5,
    "lost": 0,
    "retrans": 0,
    "sent_bytes": 1712,
    "recv_bytes": 4178,
    "lost_bytes": 0,
    "stream_retrans_bytes": 0,
    "paths_count": 1,
    "reset_stream_count_local": 0,
    "stopped_stream_count_local": 0,
    "reset_stream_count_remote": 0,
    "stopped_stream_count_remote": 0,
    "path_challenge_rx_count": 0
  },
  "path_stats": [
    {
      "local_addr": "0.0.0.0:64418",
      "peer_addr": "104.18.29.7:443",
      "active": true,
      "recv": 10,
      "sent": 5,
      "lost": 0,
      "retrans": 0,
      "rtt": 0.008140072,
      "min_rtt": 0.004645536,
      "rttvar": 0.004238173,
      "cwnd": 13500,
      "sent_bytes": 1712,
      "recv_bytes": 4178,
      "lost_bytes": 0,
      "stream_retrans_bytes": 0,
      "pmtu": 1350,
      "delivery_rate": 247720
    }
  ],
  "error": {
    "local_error": {
      "is_app": true,
      "error_code": 256,
      "reason": ""
    },
    "timed_out": false
  }
}
</code></pre>
            <p>Let’s walk through the output. Up first is the <a href="https://docs.rs/h3i/latest/h3i/client/connection_summary/struct.StreamMap.html"><u>StreamMap</u></a>, which is a record of all frames received on each stream. We can see that we received 5 frames on stream 0: 2 UNKNOWNs, one <a href="https://docs.rs/h3i/latest/h3i/frame/struct.EnrichedHeaders.html"><u>EnrichedHeaders</u></a> frame, and two DATA frames.</p><p>The UNKNOWN frames are extension frames that are unknown to h3i; the server under test is sending what are known as <a href="https://datatracker.ietf.org/doc/draft-edm-protocol-greasing/"><u>GREASE</u></a> frames to help exercise the protocol and ensure clients are not erroring when they receive something unexpected per <a href="https://datatracker.ietf.org/doc/html/rfc9114#extensions"><u>RFC 9114 requirements</u></a>.</p><p>The EnrichedHeaders frame is essentially an HTTP/3 HEADERS frame, but with some small helpers, like one to get the response status code. The server under test sent a 400 as expected.</p><p>The DATA frames carry response body bytes. In this case, the body is the HTML required to render the Cloudflare Bad Request page (you can peek at the HTML yourself in Wireshark). We chose to omit the raw bytes from the ConnectionSummary since they may not be representable safely as text. A future improvement could be to encode the bytes in base64 or hex, in order to support tests that need to check response content.</p>
    <div>
      <h2>h3i for test automation</h2>
      <a href="#h3i-for-test-automation">
        
      </a>
    </div>
    <p>We believe h3i is a great library for building automated tests on. You can take the above example and modify it to fit within various types of (continuous) integration tests.</p><p>We outlined earlier how the Protocols team HTTP/3 testing has organically grown to use three different frameworks. Even within those, we still didn't have much flexibility and ease of use. Over the last year we've been building h3i itself and reimplementing our suite of ingress proxy test cases using the Rust library. This has helped us improve test coverage with a range of new tests not previously possible. It also surprisingly identified some problems with the old tests, particularly for some edge cases where it wasn't clear how the old test code implementation was running under the hood.</p>
    <div>
      <h2>Bake offs, interop, and wider testing of HTTP</h2>
      <a href="#bake-offs-interop-and-wider-testing-of-http">
        
      </a>
    </div>
    <p><a href="https://datatracker.ietf.org/doc/html/rfc1025"><u>RFC 1025</u></a> was published in 1987. Authored by <a href="https://icannwiki.org/Jon_Postel"><u>Jon Postel</u></a>, it discusses bake offs:</p><blockquote><p><i>In the early days of the development of TCP and IP, when there were very few implementations and the specifications were still evolving, the only way to determine if an implementation was "correct" was to test it against other implementations and argue that the results showed your own implementation to have done the right thing.  These tests and discussions could, in those early days, as likely change the specification as change the implementation.</i></p><p><i>There were a few times when this testing was focused, bringing together all known implementations and running through a set of tests in hopes of demonstrating the N squared connectivity and correct implementation of the various tricky cases.  These events were called "Bake Offs".</i></p></blockquote><p>While nearly 4 decades old, the concept of exercising Internet protocol implementations and seeing how they compare to the specification still holds true. The QUIC WG made heavy use of interoperability testing through its standardization process. We started off sitting in a room and running tests manually by hand (or with some help from scripts). Then <a href="https://seemann.io/"><u>Marten Seemann</u></a> developed the <a href="https://interop.seemann.io/"><u>QUIC Interop Runner</u></a>, which runs regular automated testing and collects and renders all the results. This has proven to be incredibly useful.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2OGnVUbatoX8Ya2IO5RdCl/754316e004a8e658ac089e10e70b72ca/image6.png" />
          </figure><p>The state of HTTP/3 interoperability testing is not quite as mature. Although there are tools such as <a href="https://kazu-yamamoto.hatenablog.jp/"><u>Kazu Yamamoto's</u></a> excellent <a href="https://github.com/kazu-yamamoto/h3spec"><u>h3spec</u></a> (in Haskell) for testing conformance, there isn't a similar continuous integration process of collection and rendering of results. While h3i shares similarities with h3spec, we felt it important to focus on the framework capabilities rather than creating a corpus of tests and assertions. Cloudflare is a big fan of Rust and as several teams move to Rust-based proxies, having a consistent ecosystem provides advantages (such as developer velocity).</p><p>We certainly feel there is a great opportunity for continued collaboration and cross-pollination between projects in the QUIC and HTTP space. For example, h3i might provide a suitable basis to build another tool (or set of scripts) to run bake offs or interop tests. Perhaps it even makes sense to have a common collection of test cases owned by the community, that can be specialized to the most appropriate or preferred tooling. This topic was recently presented at the <a href="https://github.com/HTTPWorkshop/workshop2024/blob/main/talks/5.%20Testing/testing.pdf"><u>HTTP Workshop 2024</u></a> by Mohammed Al-Sahaf, and it excites us to see <a href="https://www.caffeinatedwonders.com/2024/12/18/towards-validated-http-implementation/"><u>new potential directions</u></a> of testing improvements.</p><p>When using any tools or methods for protocol testing, we encourage responsible handling of security-related matters. If you believe you may have identified a vulnerability in an IETF Internet protocol itself, please follow the IETF's <a href="https://www.ietf.org/standards/rfcs/vulnerabilities/"><u>reporting guidance</u></a>. If you believe you may have discovered an implementation vulnerability in a product, open source project, or service using QUIC or HTTP, then you should report these directly to the responsible party. Implementers or operators often provide their own publicly-available guidance and contact details to send reports. For example, the Cloudflare quiche <a href="https://github.com/cloudflare/quiche/security/policy"><u>security policy</u></a> is available in the Security tab of the GitHub repository.</p>
    <div>
      <h2>Summary and outlook</h2>
      <a href="#summary-and-outlook">
        
      </a>
    </div>
    <p>Cloudflare takes testing very seriously. While h3i has a limited feature set as a test HTTP/3 client, we believe it provides a strong framework that can be extended to a wider range of different cases and different protocols. For example, we'd like to add support for low-level HTTP/2.</p><p>We've designed h3i to integrate into a wide range of testing methodologies, from manual ad-hoc testing, to native Rust tests, to conformance testbenches built with scripting languages. We've had great success migrating our existing zoo of test tools to a single one that is more accessible and easier to maintain.</p><p>Now that you've read about h3i's capabilities, it's left as an exercise to the reader to go back to the example of HTTP/3 control streams and consider how you could write tests to exercise a server.</p><p>We encourage the community to experiment with h3i and provide feedback, and propose ideas or contributions to the <a href="https://github.com/cloudflare/quiche"><u>GitHub repository</u></a> as issues or Pull Requests.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5rp4YDTbXm37OxK7dtjiKF/816c0eed08926b7d34842f4769808277/image4.png" />
          </figure><p></p> ]]></content:encoded>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[HTTP3]]></category>
            <category><![CDATA[Testing]]></category>
            <category><![CDATA[Protocols]]></category>
            <category><![CDATA[Rust]]></category>
            <guid isPermaLink="false">2yX9ADcaKBprzyI9BaBoqN</guid>
            <dc:creator>Lucas Pardue</dc:creator>
            <dc:creator>Evan Rittenhouse</dc:creator>
        </item>
        <item>
            <title><![CDATA[HTTP/2 Rapid Reset: deconstructing the record-breaking attack]]></title>
            <link>https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/</link>
            <pubDate>Tue, 10 Oct 2023 12:02:28 GMT</pubDate>
            <description><![CDATA[ This post dives into the details of the HTTP/2 protocol, the feature that attackers exploited to generate the massive Rapid Reset attacks ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Starting on Aug 25, 2023, we started to notice some unusually big HTTP attacks hitting many of our customers. These attacks were detected and mitigated by our automated DDoS system. It was not long however, before they started to reach record-breaking sizes — and eventually peaked just above 201 million requests per second. This was nearly 3x bigger than our <a href="/cloudflare-mitigates-record-breaking-71-million-request-per-second-ddos-attack/">previous biggest attack on record</a>.</p><em><small>Under attack or need additional protection? <a href="https://www.cloudflare.com/h2/">Click here to get help</a>.</small></em><br /><p>Concerning is the fact that the attacker was able to generate such an attack with a botnet of merely 20,000 machines. There are botnets today that are made up of hundreds of thousands or millions of machines. Given that the entire web typically sees only between 1–3 billion requests per second, it's not inconceivable that using this method could focus an entire web’s worth of requests on a small number of targets.</p>
    <div>
      <h2>Detecting and Mitigating</h2>
      <a href="#detecting-and-mitigating">
        
      </a>
    </div>
    <p>This was a novel attack vector at an unprecedented scale, but Cloudflare's existing protections were largely able to absorb the brunt of the attacks. While initially we saw some impact to customer traffic — affecting roughly 1% of requests during the initial wave of attacks — today we’ve been able to refine our mitigation methods to stop the attack for any Cloudflare customer without it impacting our systems.</p><p>We noticed these attacks at the same time two other major industry players — Google and AWS — were seeing the same. We worked to harden Cloudflare’s systems to ensure that, today, all our customers are protected from this new DDoS attack method without any customer impact. We’ve also participated with Google and AWS in a coordinated disclosure of the attack to impacted vendors and critical infrastructure providers.</p><p>This attack was made possible by abusing some features of the HTTP/2 protocol and server implementation details (see  <a href="https://www.cve.org/CVERecord?id=CVE-2023-44487">CVE-2023-44487</a> for details). Because the attack abuses an underlying weakness in the HTTP/2 protocol, we believe any vendor that has implemented HTTP/2 will be subject to the attack. This included every modern web server. We, along with Google and AWS, have disclosed the attack method to web server vendors who we expect will implement patches. In the meantime, the best defense is using a DDoS mitigation service like Cloudflare’s in front of any web-facing web or API server.</p><p>This post dives into the details of the HTTP/2 protocol, the feature that attackers exploited to generate these massive attacks, and the mitigation strategies we took to ensure all our customers are protected. Our hope is that by publishing these details other impacted web servers and services will have the information they need to implement mitigation strategies. And, moreover, the HTTP/2 protocol standards team, as well as teams working on future web standards, can better design them to <a href="https://www.cloudflare.com/learning/ddos/how-to-prevent-ddos-attacks/">prevent such attacks</a>.</p>
    <div>
      <h2>RST attack details</h2>
      <a href="#rst-attack-details">
        
      </a>
    </div>
    <p>HTTP is the application protocol that powers the Web. <a href="https://www.rfc-editor.org/rfc/rfc9110.html">HTTP Semantics</a> are common to all versions of HTTP — the overall architecture, terminology, and protocol aspects such as request and response messages, methods, status codes, header and trailer fields, message content, and much more. Each individual HTTP version defines how semantics are transformed into a "wire format" for exchange over the Internet. For example, a client has to serialize a request message into binary data and send it, then the server parses that back into a message it can process.</p><p><a href="https://www.rfc-editor.org/rfc/rfc9112.html">HTTP/1.1</a> uses a textual form of serialization. Request and response messages are exchanged as a stream of ASCII characters, sent over a reliable transport layer like TCP, using the following <a href="https://www.rfc-editor.org/rfc/rfc9112.html#section-2.1">format</a> (where CRLF means carriage-return and linefeed):</p>
            <pre><code> HTTP-message   = start-line CRLF
                   *( field-line CRLF )
                   CRLF
                   [ message-body ]</code></pre>
            <p>For example, a very simple GET request for <code>https://blog.cloudflare.com/</code> would look like this on the wire:</p><p><code>GET / HTTP/1.1 CRLFHost: blog.cloudflare.comCRLFCRLF</code></p><p>And the response would look like:</p><p><code>HTTP/1.1 200 OK CRLFServer: cloudflareCRLFContent-Length: 100CRLFtext/html; charset=UTF-8CRLFCRLF&lt;100 bytes of data&gt;</code></p><p>This format <b>frames</b> messages on the wire, meaning that it is possible to use a single TCP connection to exchange multiple requests and responses. However, the format requires that each message is sent whole. Furthermore, in order to correctly correlate requests with responses, strict ordering is required; meaning that messages are exchanged serially and can not be multiplexed. Two GET requests, for <code>https://blog.cloudflare.com/</code> and <code>https://blog.cloudflare.com/page/2/</code>, would be:</p><p><code>GET / HTTP/1.1 CRLFHost: blog.cloudflare.comCRLFCRLFGET /page/2/ HTTP/1.1 CRLFHost: blog.cloudflare.comCRLFCRLF</code></p><p>With the responses:</p><p><code>HTTP/1.1 200 OK CRLFServer: cloudflareCRLFContent-Length: 100CRLFtext/html; charset=UTF-8CRLFCRLF&lt;100 bytes of data&gt;CRLFHTTP/1.1 200 OK CRLFServer: cloudflareCRLFContent-Length: 100CRLFtext/html; charset=UTF-8CRLFCRLF&lt;100 bytes of data&gt;</code></p><p>Web pages require more complicated HTTP interactions than these examples. When visiting the Cloudflare blog, your browser will load multiple scripts, styles and media assets. If you visit the front page using HTTP/1.1 and decide quickly to navigate to page 2, your browser can pick from two options. Either wait for all of the queued up responses for the page that you no longer want before page 2 can even start, or cancel in-flight requests by closing the TCP connection and opening a new connection. Neither of these is very practical. Browsers tend to work around these limitations by managing a pool of TCP connections (up to 6 per host) and implementing complex request dispatch logic over the pool.</p><p><a href="https://www.rfc-editor.org/rfc/rfc9113">HTTP/2</a> addresses many of the issues with HTTP/1.1. Each HTTP message is serialized into a set of <b>HTTP/2 frames</b> that have type, length, flags, stream identifier (ID) and payload. The stream ID makes it clear which bytes on the wire apply to which message, allowing safe multiplexing and concurrency. Streams are bidirectional. Clients send frames and servers reply with frames using the same ID.</p><p>In HTTP/2 our GET request for <code>https://blog.cloudflare.com</code> would be exchanged across stream ID 1, with the client sending one <a href="https://www.rfc-editor.org/rfc/rfc9113#name-headers">HEADERS</a> frame, and the server responding with one HEADERS frame, followed by one or more <a href="https://www.rfc-editor.org/rfc/rfc9113#name-data">DATA</a> frames. Client requests always use odd-numbered stream IDs, so subsequent requests would use stream ID 3, 5, and so on. Responses can be served in any order, and frames from different streams can be interleaved.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/UgsMj35BXBaxK2dKVIvC2/8b6db7d94e03f2a0f9f0f9a2c2a55df6/Screenshot-2023-10-09-at-2.13.29-PM.png" />
            
            </figure><p>Stream multiplexing and concurrency are powerful features of HTTP/2. They enable more efficient usage of a single TCP connection. HTTP/2 optimizes resources fetching especially when coupled with <a href="/better-http-2-prioritization-for-a-faster-web/">prioritization</a>. On the flip side, making it easy for clients to launch large amounts of parallel work can increase the peak demand for server resources when compared to HTTP/1.1. This is an obvious vector for denial-of-service.</p><p>In order to provide some guardrails, HTTP/2 provides a notion of maximum active <a href="https://www.rfc-editor.org/rfc/rfc9113#section-5.1.2">concurrent streams</a>. The <a href="https://www.rfc-editor.org/rfc/rfc9113#SETTINGS_MAX_FRAME_SIZE">SETTINGS_MAX_CONCURRENT_STREAMS</a> parameter allows a server to advertise its limit of concurrency. For example, if the server states a limit of 100, then only 100 requests can be active at any time. If a client attempts to open a stream above this limit, it must be rejected by the server using a <a href="https://www.rfc-editor.org/rfc/rfc9113#section-6.4">RST_STREAM</a> frame. Stream rejection does not affect the other in-flight streams on the connection.</p><p>The true story is a little more complicated. Streams have a <a href="https://www.rfc-editor.org/rfc/rfc9113#section-5.1">lifecycle</a>. Below is a diagram of the HTTP/2 stream state machine. Client and server manage their own views of the state of a stream. HEADERS, DATA and RST_STREAM frames trigger transitions when they are sent or received. Although the views of the stream state are independent, they are synchronized.</p><p>HEADERS and DATA frames include an END_STREAM flag, that when set to the value 1 (true), can trigger a state transition.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2iRGsrf6eBGkrJ0rpqZtSx/a4c47fc7f29ec562660aa75c3e26e13c/Request-stream-states.png" />
            
            </figure><p>Let's work through this with an example of a GET request that has no message content. The client sends the request as a HEADERS frame with the END_STREAM flag set to 1. The client first transitions the stream from <b>idle</b> to <b>open</b> state, then immediately transitions into <b>half-closed</b> state. The client half-closed state means that it can no longer send HEADERS or DATA, only <a href="https://www.rfc-editor.org/rfc/rfc9113.html#section-6.9">WINDOW_UPDATE</a>, <a href="https://www.rfc-editor.org/rfc/rfc9113.html#section-6.3">PRIORITY</a> or RST_STREAM frames. It can receive any frame however.</p><p>Once the server receives and parses the HEADERS frame, it transitions the stream state from idle to open and then half-closed, so it matches the client. The server half-closed state means it can send any frame but receive only WINDOW_UPDATE, PRIORITY or RST_STREAM frames.</p><p>The response to the GET contains message content, so the server sends HEADERS with END_STREAM flag set to 0, then DATA with END_STREAM flag set to 1. The DATA frame triggers the transition of the stream from <b>half-closed</b> to <b>closed</b> on the server. When the client receives it, it also transitions to closed. Once a stream is closed, no frames can be sent or received.</p><p>Applying this lifecycle back into the context of concurrency, HTTP/2 <a href="https://www.rfc-editor.org/rfc/rfc9113#section-5.1.2-2">states</a>:</p><p><i>Streams that are in the "open" state or in either of the "half-closed" states count toward the maximum number of streams that an endpoint is permitted to open. Streams in any of these three states count toward the limit advertised in the</i> <a href="https://www.rfc-editor.org/rfc/rfc9113#SETTINGS_MAX_CONCURRENT_STREAMS"><i>SETTINGS_MAX_CONCURRENT_STREAMS</i></a> <i>setting.</i></p><p>In theory, the concurrency limit is useful. However, there are practical factors that hamper its effectiveness— which we will cover later in the blog.</p>
    <div>
      <h3>HTTP/2 request cancellation</h3>
      <a href="#http-2-request-cancellation">
        
      </a>
    </div>
    <p>Earlier, we talked about client cancellation of in-flight requests. HTTP/2 supports this in a much more efficient way than HTTP/1.1. Rather than needing to tear down the whole connection, a client can send a RST_STREAM frame for a single stream. This instructs the server to stop processing the request and to abort the response, which frees up server resources and avoids wasting bandwidth.</p><p>Let's consider our previous example of 3 requests. This time the client cancels the request on stream 1 after all of the HEADERS have been sent. The server parses this RST_STREAM frame before it is ready to serve the response and instead only responds to stream 3 and 5:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7dnYO0saZeIgGlocFRxKLb/45b3c1197559ee9f5547efad0a88b00a/Screenshot-2023-10-09-at-2.12.04-PM.png" />
            
            </figure><p>Request cancellation is a useful feature. For example, when scrolling a webpage with multiple images, a web browser can cancel images that fall outside the viewport, meaning that images entering it can load faster. HTTP/2 makes this behaviour a lot more efficient compared to HTTP/1.1.</p><p>A request stream that is canceled, rapidly transitions through the stream lifecycle. The client's HEADERS with END_STREAM flag set to 1 transitions the state from <b>idle</b> to <b>open</b> to <b>half-closed</b>, then RST_STREAM immediately causes a transition from <b>half-closed</b> to <b>closed.</b></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4XHuuWwKaQkVyDclt2ktaT/983c5d5531c2987a90382548e8618f50/Request-stream-states-reset.png" />
            
            </figure><p>Recall that only streams that are in the open or half-closed state contribute to the stream concurrency limit. When a client cancels a stream, it instantly gets the ability to open another stream in its place and can send another request immediately. This is the crux of what makes <a href="https://www.cve.org/CVERecord?id=CVE-2023-44487">CVE-2023-44487</a> work.</p>
    <div>
      <h3>Rapid resets leading to denial of service</h3>
      <a href="#rapid-resets-leading-to-denial-of-service">
        
      </a>
    </div>
    <p>HTTP/2 request cancellation can be abused to rapidly reset an unbounded number of streams. When an HTTP/2 server is able to process client-sent RST_STREAM frames and tear down state quickly enough, such rapid resets do not cause a problem. Where issues start to crop up is when there is any kind of delay or lag in tidying up. The client can churn through so many requests that a backlog of work accumulates, resulting in excess consumption of resources on the server.</p><p>A common HTTP deployment architecture is to run an HTTP/2 proxy or load-balancer in front of other components. When a client request arrives it is quickly dispatched and the actual work is done as an asynchronous activity somewhere else. This allows the proxy to handle client traffic very efficiently. However, this separation of concerns can make it hard for the proxy to tidy up the in-process jobs. Therefore, these deployments are more likely to encounter issues from rapid resets.</p><p>When Cloudflare's <a href="https://www.rfc-editor.org/rfc/rfc9110#section-3.7-6">reverse proxies</a> process incoming HTTP/2 client traffic, they copy the data from the connection’s socket into a buffer and process that buffered data in order. As each request is read (HEADERS and DATA frames) it is dispatched to an upstream service. When RST_STREAM frames are read, the local state for the request is torn down and the upstream is notified that the request has been canceled. Rinse and repeat until the entire buffer is consumed. However, this logic can be abused: when a malicious client started sending an enormous chain of requests and resets at the start of a connection, our servers would eagerly read them all and create stress on the upstream servers to the point of being unable to process any new incoming request.</p><p>Something that is important to highlight is that stream concurrency on its own cannot mitigate rapid reset. The client can churn requests to create high request rates no matter the server's chosen value of <a href="https://www.rfc-editor.org/rfc/rfc9113#SETTINGS_MAX_CONCURRENT_STREAMS">SETTINGS_MAX_CONCURRENT_STREAMS</a>.</p>
    <div>
      <h3>Rapid Reset dissected</h3>
      <a href="#rapid-reset-dissected">
        
      </a>
    </div>
    Here's an example of rapid reset reproduced using a proof-of-concept client attempting to make a total of 1000 requests. I've used an off-the-shelf server without any mitigations; listening on port 443 in a test environment. The traffic is dissected using Wireshark and filtered to show only HTTP/2 traffic for clarity. <a href="http://staging.blog.mrk.cfdata.org/content/images/rapidreset.pcapng">Download the pcap</a> to follow along.
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3wv6U0bsO7wQ2Ofw0qp5f9/9d974117608d62c9eef6e276890f336b/Untitled--2-.png" />
            
            </figure><p>It's a bit difficult to see, because there are a lot of frames. We can get a quick summary via Wireshark's Statistics &gt; HTTP2 tool:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1STsop3XklVVe7phIL1mg0/69bb1269474936146e529c969aaecd18/Screenshot-2023-10-09-at-10.50.42-PM.png" />
            
            </figure><p>The first frame in this trace, in packet 14, is the server's SETTINGS frame, which advertises a maximum stream concurrency of 100. In packet 15, the client sends a few control frames and then starts making requests that are rapidly reset. The first HEADERS frame is 26 bytes long, all subsequent HEADERS are only 9 bytes. This size difference is due to a compression technology called <a href="/hpack-the-silent-killer-feature-of-http-2/">HPACK</a>. In total, packet 15 contains 525 requests, going up to stream 1051.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/JkezErQ90qEV2L0JuKNuK/c75695ef3a2b192eb1cb7a93a546cb7f/Untitled--3-.png" />
            
            </figure><p>Interestingly, the RST_STREAM for stream 1051 doesn't fit in packet 15, so in packet 16 we see the server respond with a 404 response.  Then in packet 17 the client does send the RST_STREAM, before moving on to sending the remaining 475 requests.</p><p>Note that although the server advertised 100 concurrent streams, both packets sent by the client sent a lot more HEADERS frames than that. The client did not have to wait for any return traffic from the server, it was only limited by the size of the packets it could send. No server RST_STREAM frames are seen in this trace, indicating that the server did not observe a concurrent stream violation.</p>
    <div>
      <h2>Impact on customers</h2>
      <a href="#impact-on-customers">
        
      </a>
    </div>
    <p>As mentioned above, as requests are canceled, upstream services are notified and can abort requests before wasting too many resources on it. This was the case with this attack, where most malicious requests were never forwarded to the origin servers. However, the sheer size of these attacks did cause some impact.</p><p>First, as the rate of incoming requests reached peaks never seen before, we had reports of increased levels of 502 errors seen by clients. This happened on our most impacted data centers as they were struggling to process all the requests. While our network is meant to deal with large attacks, this particular vulnerability exposed a weakness in our infrastructure. Let's dig a little deeper into the details, focusing on how incoming requests are handled when they hit one of our data centers:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2FNw47et7A6A8yQ8FTJWeB/4a244ae8faed2fca1afc45de7ccb2600/Untitled-2023-10-04-1953.png" />
            
            </figure><p>We can see that our infrastructure is composed of a chain of different proxy servers with different responsibilities. In particular, when a client connects to Cloudflare to send HTTPS traffic, it first hits our TLS decryption proxy: it decrypts TLS traffic, processes HTTP 1, 2 or 3 traffic, then forwards it to our "business logic" proxy. This one is responsible for loading all the settings for each customer, then routing the requests correctly to other upstream services — and more importantly in our case, <b>it is also responsible for security features</b>. This is where L7 attack mitigation is processed.</p><p>The problem with this attack vector is that it manages to send a lot of requests very quickly in every single connection. Each of them had to be forwarded to the business logic proxy before we had a chance to block it. As the request throughput became higher than our proxy capacity, the pipe connecting these two services reached its saturation level in some of our servers.</p><p>When this happens, the TLS proxy cannot connect anymore to its upstream proxy, this is why some clients saw a bare "502 Bad Gateway" error during the most serious attacks. It is important to note that, as of today, the logs used to create HTTP analytics are also emitted by our business logic proxy. The consequence of that is that these errors are not visible in the Cloudflare dashboard. Our internal dashboards show that about 1% of requests were impacted during the initial wave of attacks (before we implemented mitigations), with peaks at around 12% for a few seconds during the most serious one on August 29th. The following graph shows the ratio of these errors over a two hours while this was happening:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/lNZyUoAWzVfyQ66xIPJ9i/d9907d299155b8b6e80c9de3f4a4f032/imageLikeEmbed.png" />
            
            </figure><p>We worked to reduce this number dramatically in the following days, as detailed later on in this post. Both thanks to changes in our stack and to our mitigation that reduce the size of these attacks considerably, this number today is effectively zero.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6PDIKg6O07UYWjQk30YkIH/e542a06392b680737ec2256c0919a33e/imageLikeEmbed--2-.png" />
            
            </figure>
    <div>
      <h3>499 errors and the challenges for HTTP/2 stream concurrency</h3>
      <a href="#499-errors-and-the-challenges-for-http-2-stream-concurrency">
        
      </a>
    </div>
    <p>Another symptom reported by some customers is an increase in 499 errors. The reason for this is a bit different and is related to the maximum stream concurrency in a HTTP/2 connection detailed earlier in this post.</p><p>HTTP/2 settings are exchanged at the start of a connection using SETTINGS frames. In the absence of receiving an explicit parameter, default values apply. Once a client establishes an HTTP/2 connection, it can wait for a server's SETTINGS (slow) or it can assume the default values and start making requests (fast). For SETTINGS_MAX_CONCURRENT_STREAMS, the default is effectively unlimited (stream IDs use a 31-bit number space, and requests use odd numbers, so the actual limit is 1073741824). The specification recommends that a server offer no fewer than 100 streams. Clients are generally biased towards speed, so don't tend to wait for server settings, which creates a bit of a race condition. Clients are taking a gamble on what limit the server might pick; if they pick wrong the request will be rejected and will have to be retried. Gambling on 1073741824 streams is a bit silly. Instead, a lot of clients decide to limit themselves to issuing 100 concurrent streams, with the hope that servers followed the specification recommendation. Where servers pick something below 100, this client gamble fails and streams are reset.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3ZdAxnNVz1PsuG1BCE3wsT/d4b02d4d1b8f6cf8ecebdddbed194c74/Untitled-2023-10-04-1953--1-.png" />
            
            </figure><p>There are many reasons a server might reset a stream beyond concurrency limit overstepping. HTTP/2 is strict and requires a stream to be closed when there are parsing or logic errors. In 2019, Cloudflare developed several mitigations in response to <a href="/on-the-recent-http-2-dos-attacks/">HTTP/2 DoS vulnerabilities</a>. Several of those vulnerabilities were caused by a client misbehaving, leading the server to reset a stream. A very effective strategy to clamp down on such clients is to count the number of server resets during a connection, and when that exceeds some threshold value, close the connection with a <a href="https://www.rfc-editor.org/rfc/rfc9113#section-6.8">GOAWAY</a> frame. Legitimate clients might make one or two mistakes in a connection and that is acceptable. A client that makes too many mistakes is probably either broken or malicious and closing the connection addresses both cases.</p><p>While responding to DoS attacks enabled by <a href="https://www.cve.org/CVERecord?id=CVE-2023-44487">CVE-2023-44487</a>, Cloudflare reduced maximum stream concurrency to 64. Before making this change, we were unaware that clients don't wait for SETTINGS and instead assume a concurrency of 100. Some web pages, such as an image gallery, do indeed cause a browser to send 100 requests immediately at the start of a connection. Unfortunately, the 36 streams above our limit all needed to be reset, which triggered our counting mitigations. This meant that we closed connections on legitimate clients, leading to a complete page load failure. As soon as we realized this interoperability issue, we changed the maximum stream concurrency to 100.</p>
    <div>
      <h2>Actions from the Cloudflare side</h2>
      <a href="#actions-from-the-cloudflare-side">
        
      </a>
    </div>
    <p>In 2019 several <a href="/on-the-recent-http-2-dos-attacks/">DoS vulnerabilities</a> were uncovered related to implementations of HTTP/2. Cloudflare developed and deployed a series of detections and mitigations in response.  <a href="https://www.cve.org/CVERecord?id=CVE-2023-44487">CVE-2023-44487</a> is a different manifestation of HTTP/2 vulnerability. However, to mitigate it we were able to extend the existing protections to monitor client-sent RST_STREAM frames and close connections when they are being used for abuse. Legitimate client uses for RST_STREAM are unaffected.</p><p>In addition to a direct fix, we have implemented several improvements to the server's HTTP/2 frame processing and request dispatch code. Furthermore, the business logic server has received improvements to queuing and scheduling that reduce unnecessary work and improve cancellation responsiveness. Together these lessen the impact of various potential abuse patterns as well as giving more room to the server to process requests before saturating.</p>
    <div>
      <h3>Mitigate attacks earlier</h3>
      <a href="#mitigate-attacks-earlier">
        
      </a>
    </div>
    <p>Cloudflare already had systems in place to efficiently mitigate very large attacks with less expensive methods. One of them is named "IP Jail". For hyper volumetric attacks, this system collects the client IPs participating in the attack and stops them from connecting to the attacked property, either at the IP level, or in our TLS proxy. This system however needs a few seconds to be fully effective; during these precious seconds, the origins are already protected but our infrastructure still needs to absorb all HTTP requests. As this new botnet has effectively no ramp-up period, we need to be able to neutralize attacks before they can become a problem.</p><p>To achieve this we expanded the IP Jail system to protect our entire infrastructure: once an IP is "jailed", not only it is blocked from connecting to the attacked property, we also forbid the corresponding IPs from using HTTP/2 to any other domain on Cloudflare for some time. As such protocol abuses are not possible using HTTP/1.x, this limits the attacker's ability to run large attacks, while any legitimate client sharing the same IP would only see a very small performance decrease during that time. IP based mitigations are a very blunt tool — this is why we have to be extremely careful when using them at that scale and seek to avoid false positives as much as possible. Moreover, the lifespan of a given IP in a botnet is usually short so any long term mitigation is likely to do more harm than good. The following graph shows the churn of IPs in the attacks we witnessed:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3tsViCTkDispBbBmIY57vy/3c49903f3c4a1ac60f98efae6c1e3fb4/ip-churn.png" />
            
            </figure><p>As we can see, many new IPs spotted on a given day disappear very quickly afterwards.</p><p>As all these actions happen in our TLS proxy at the beginning of our HTTPS pipeline, this saves considerable resources compared to our regular L7 mitigation system. This allowed us to weather these attacks much more smoothly and now the number of random 502 errors caused by these botnets is down to zero.</p>
    <div>
      <h3>Observability improvements</h3>
      <a href="#observability-improvements">
        
      </a>
    </div>
    <p>Another front on which we are making change is <a href="https://www.cloudflare.com/learning/performance/what-is-observability/">observability</a>. Returning errors to clients without being visible in customer analytics is unsatisfactory. Fortunately, a project has been underway to overhaul these systems since long before the recent attacks. It will eventually allow each service within our infrastructure to log its own data, instead of relying on our business logic proxy to consolidate and emit log data. This incident underscored the importance of this work, and we are redoubling our efforts.</p><p>We are also working on better connection-level logging, allowing us to spot such protocol abuses much more quickly to improve our DDoS mitigation capabilities.</p>
    <div>
      <h2>Conclusion</h2>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>While this was the latest record-breaking attack, we know it won’t be the last. As attacks continue to become more sophisticated, Cloudflare works relentlessly to proactively identify new threats — deploying countermeasures to our global network so that our millions of customers are immediately and automatically protected.</p><p>Cloudflare has provided free, unmetered and unlimited DDoS protection to all of our customers since 2017. In addition, we offer a range of additional security features to suit the needs of organizations of all sizes. <a href="https://www.cloudflare.com/h2">Contact us</a> if you’re unsure whether you’re protected or want to understand how you can be.</p> ]]></content:encoded>
            <category><![CDATA[DDoS]]></category>
            <category><![CDATA[Vulnerabilities]]></category>
            <category><![CDATA[Trends]]></category>
            <category><![CDATA[Attacks]]></category>
            <category><![CDATA[Security]]></category>
            <guid isPermaLink="false">3WjbDYiA84ghLhFzgsMfYp</guid>
            <dc:creator>Lucas Pardue</dc:creator>
            <dc:creator>Julien Desgats</dc:creator>
        </item>
        <item>
            <title><![CDATA[Introducing HTTP/3 Prioritization]]></title>
            <link>https://blog.cloudflare.com/better-http-3-prioritization-for-a-faster-web/</link>
            <pubDate>Tue, 20 Jun 2023 13:00:46 GMT</pubDate>
            <description><![CDATA[ Today, Cloudflare is very excited to announce full support for HTTP/3 Extensible Priorities, a new standard that speeds the loading of webpages by up to 37% ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5WMquEFDro1TjSvsKvdb2X/1ebf5bacb443b2c7c611b2600cfe1352/image4-9.png" />
            
            </figure><p>Today, Cloudflare is very excited to announce full support for HTTP/3 Extensible Priorities, a new standard that speeds the loading of webpages by up to 37%. Cloudflare worked closely with standards builders to help form the specification for HTTP/3 priorities and is excited to help push the web forward. HTTP/3 Extensible Priorities is available on all plans on Cloudflare. For paid users, there is an enhanced version available that improves performance even more.</p><p>Web pages are made up of many objects that must be downloaded before they can be processed and presented to the user. Not all objects have equal importance for web performance. The role of HTTP prioritization is to load the right bytes at the most opportune time, to achieve the best results. Prioritization is most important when there are multiple objects all competing for the same constrained resource. In <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a>, this resource is the QUIC connection. In most cases, bandwidth is the bottleneck from server to client. Picking what objects to dedicate bandwidth to, or share bandwidth amongst, is a critical foundation to web performance. When it goes askew, the other optimizations we build on top can suffer.</p><p>Today, we're announcing support for prioritization in HTTP/3, using the full capabilities of the HTTP Extensible Priorities (<a href="https://www.rfc-editor.org/rfc/rfc9218.html">RFC 9218)</a> standard, augmented with Cloudflare's knowledge and experience of enhanced HTTP/2 prioritization. This change is compatible with all mainstream web browsers and can improve key metrics such as <a href="https://web.dev/lcp/">Largest Contentful Paint</a> (LCP) by up to 37% in our test. Furthermore, site owners can apply server-side overrides, using Cloudflare Workers or directly from an origin, to customize behavior for their specific needs.</p>
    <div>
      <h3>Looking at a real example</h3>
      <a href="#looking-at-a-real-example">
        
      </a>
    </div>
    <p>The ultimate question when it comes to features like HTTP/3 Priorities is: how well does this work and should I turn it on? The details are interesting and we'll explain all of those shortly but first lets see some demonstrations.</p><p>In order to evaluate prioritization for HTTP/3, we have been running many simulations and tests. Each web page is unique. Loading a web page can require many TCP or QUIC connections, each of them idiosyncratic. These all affect how prioritization works and how effective it is.</p><p>To evaluate the effectiveness of priorities, we ran a set of tests measuring Largest Contentful Paint (LCP). As an example, we benchmarked blog.cloudflare.com to see how much we could improve performance:</p><div></div>
<p></p><p>As a film strip, this is what it looks like:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1nUzro5TRNUdT66D48SAX9/eea3706754ab1adcdcf2de1520b4e8b2/unnamed.png" />
            
            </figure><p>In terms of actual numbers, we see Largest Contentful Paint drop from 2.06 seconds down to 1.29 seconds. Let’s look at why that is. To analyze exactly what’s going on we have to look at a waterfall diagram of how this web page is loading. A waterfall diagram is a way of visualizing how assets are loading. Some may be loaded in parallel whilst some might be loaded sequentially. Without smart prioritization, the waterfall for loading assets for this web page looks as follows:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7GEe1xRnxvauMVfOKy5KH2/ab43c1561d3d512589a6de0b063419a1/BLOG-1879-waterfall-analysis-2.png" />
            
            </figure><p>There are several interesting things going on here so let's break it down. The LCP image at request 21 is for 1937-1.png, weighing 30.4 KB. Although it is the LCP image, the browser requests it as priority u=3,i, which informs the server to put it in the same round-robin bandwidth-sharing bucket with all of the other images. Ahead of the LCP image is index.js, a JavaScript file that is loaded with a "defer" attribute. This JavaScript is non-blocking and shouldn't affect key aspects of page layout.</p><p>What appears to be happening is that the browser gives index.js the priority u=3,i=?0, which places it ahead of the images group on the server-side. Therefore, the 217 KB of index.js is sent in preference to the LCP image. Far from ideal. Not only that, once the script is delivered, it needs to be processed and executed. This saturates the CPU and prevents the LCP image from being painted, for about 300 milliseconds, even though it was delivered already.</p><p>The waterfall with prioritization looks much better:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3Y2mU3vMrf4DVgI6Cq7CSv/980f93870fee27984d40dd310ee38c8d/BLOG-1879-waterfall-analysis-1.png" />
            
            </figure><p>We used a server-side override to promote the priority of the LCP image 1937-1.png from u=3,i to u=2,i. This has the effect of making it leapfrog the "defer" JavaScript. We can see at around 1.2 seconds, transmission of index.js is halted while the image is delivered in full. And because it takes another couple of hundred milliseconds to receive the remaining JavaScript, there is no CPU competition for the LCP image paint. These factors combine together to drastically improve LCP times.</p>
    <div>
      <h3>How Extensible Priorities actually works</h3>
      <a href="#how-extensible-priorities-actually-works">
        
      </a>
    </div>
    <p>First of all, you don't need to do anything yourselves to make it work. Out of the box, browsers will send Extensible Priorities signals alongside HTTP/3 requests, which we'll feed into our priority scheduling decision making algorithms. We'll then decide the best way to send HTTP/3 response data to ensure speedy page loads.</p><p>Extensible Priorities has a similar interaction model to HTTP/2 priorities, client send priorities and servers act on them to schedule response data, we'll explain exactly how that works in a bit.</p><p>HTTP/2 priorities used a dependency tree model. While this was very powerful it turned out hard to implement and use. When the IETF came to try and port it to HTTP/3 during the standardization process, we hit major issues. If you are interested in all that background, go and read my blog post describing why we adopted a <a href="/adopting-a-new-approach-to-http-prioritization/">new approach to HTTP/3 prioritization</a>.</p><p>Extensible Priorities is a far simpler scheme. HTTP/2's dependency tree with 255 weights and dependencies (that can be mutual or exclusive) is complex, hard to use as a web developer and could not work for HTTP/3. Extensible Priorities has just two parameters: urgency and incremental, and these are capable of achieving exactly the same web performance goals.</p><p>Urgency is an integer value in the range 0-7. It indicates the importance of the requested object, with 0 being most important and 7 being the least. The default is 3. Urgency is comparable to HTTP/2 weights. However, it's simpler to reason about 8 possible urgencies rather than 255 weights. This makes developer's lives easier when trying to pick a value and predicting how it will work in practice.</p><p>Incremental is a boolean value. The default is false. A true value indicates the requested object can be processed as parts of it are received and read - commonly referred to as streaming processing. A false value indicates the object must be received in whole before it can be processed.</p><p>Let's consider some example web objects to put these parameters into perspective:</p><ul><li><p>An HTML document is the most important piece of a webpage. It can be processed as parts of it arrive. Therefore, urgency=0 and incremental=true is a good choice.</p></li><li><p>A CSS style is important for page rendering and could block visual completeness. It needs to be processed in whole. Therefore, urgency=1 and incremental=false is suitable, this would mean it doesn't interfere with the HTML.</p></li><li><p>An image file that is outside the browser viewport is not very important and it can be processed and painted as parts arrive. Therefore, urgency=3 and incremental=true is appropriate to stop it interfering with sending other objects.</p></li><li><p>An image file that is the "hero image" of the page, making it the Largest Contentful Pain element. An urgency of 1 or 2 will help it avoid being mixed in with other images. The choice of incremental value is a little subjective and either might be appropriate.</p></li></ul><p>When making an HTTP request, clients decide the Extensible Priority value composed of the urgency and incremental parameters. These are sent either as an HTTP header field in the request (meaning inside the HTTP/3 HEADERS frame on a request stream), or separately in an HTTP/3 PRIORITY_UPDATE frame on the control stream. HTTP headers are sent once at the start of a request; a client might change its mind so the PRIORITY_UPDATE frame allows it to reprioritize at any point in time.</p><p>For both the header field and PRIORITY_UPDATE, the parameters are exchanged using the Structured Fields Dictionary format (<a href="https://www.rfc-editor.org/info/rfc8941">RFC 8941</a>) and serialization rules. In order to save bytes on the wire, the parameters are shortened – urgency to 'u', and incremental to 'i'.</p><p>Here's how the HTTP header looks alongside a GET request for important HTML, using HTTP/3 style notation:</p>
            <pre><code>HEADERS:
    :method = GET
    :scheme = https
    :authority = example.com
    :path = /index.html
     priority = u=0,i</code></pre>
            <p>The PRIORITY_UPDATE frame only carries the serialized Extensible Priority value:</p>
            <pre><code>PRIORITY_UPDATE:
    u=0,i</code></pre>
            <p>Structured Fields has some other neat tricks. If you want to indicate the use of a default value, then that can be done via omission. Recall that the urgency default is 3, and incremental default is false. A client could send "u=1" alongside our important CSS request (urgency=1, incremental=false). For our lower priority image it could send just "i=?1" (urgency=3, incremental=true). There's even another trick, where boolean true dictionary parameters are sent as just "i". You should expect all of these formats to be used in practice, so it pays to be mindful about their meaning.</p><p>Extensible Priority servers need to decide how best to use the available connection bandwidth to schedule the response data bytes. When servers receive priority client signals, they get one form of input into a decision making process. RFC 9218 provides a set of <a href="https://www.rfc-editor.org/rfc/rfc9218.html#name-server-scheduling">scheduling recommendations</a> that are pretty good at meeting a board set of needs. These can be distilled down to some golden rules.</p><p>For starters, the order of requests is crucial. Clients are very careful about asking for things at the moment they want it. Serving things in request order is good. In HTTP/3, because there is no strict ordering of stream arrival, servers can use stream IDs to determine this. Assuming the order of the requests is correct, the next most important thing is urgency ordering. Serving according to urgency values is good.</p><p>Be wary of non-incremental requests, as they mean the client needs the object in full before it can be used at all. An incremental request means the client can process things as and when they arrive.</p><p>With these rules in mind, the scheduling then becomes broadly: for each urgency level, serve non-incremental requests in whole serially, then serve incremental requests in round robin fashion in parallel. What this achieves is dedicated bandwidth for very important things, and shared bandwidth for less important things that can be processed or rendered progressively.</p><p>Let's look at some examples to visualize the different ways the scheduler can work. These are generated by using <a href="https://github.com/cloudflare/quiche">quiche's</a> <a href="https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-main-schema/">qlog</a> support and running it via the <a href="https://qvis.quictools.info/">qvis</a> analysis tool. These diagrams are similar to a waterfall chart; the y-dimension represents stream IDs (0 at the top, increasing as we move down) and the x-dimension shows reception of stream data.</p><p>Example 1: all streams have the same urgency and are non-incremental so get served in serial order of stream ID.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2mzTrM4iI9h7uEJXa2TOuT/40d1ba7c1d13949107d68a2e1fb5398f/u-same.png" />
            
            </figure><p>Example 2: the streams have the same urgency and are incremental so get served in round-robin fashion.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1V44aLuoHvqxR4gpETKJ2x/fdb8ddb148353333b4aaceff11858ff6/u-same-i.png" />
            
            </figure><p>Example 3: the streams have all different urgency, with later streams being more important than earlier streams. The data is received serially but in a reverse order compared to example 1.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2koT4ij8bzGMc06OVNIFGZ/26572e5bffa63b588860050e005fe64e/u-reversed.png" />
            
            </figure><p>Beyond the Extensible Priority signals, a server might consider other things when scheduling, such as file size, content encoding, how the application vs content origins are configured etc.. This was true for HTTP/2 priorities but Extensible Priorities introduces a new neat trick, a priority signal can also be sent as a response header to override the client signal.</p><p>This works especially well in a proxying scenario where your HTTP/3 terminating proxy is sat in front of some backend such as Workers. The proxy can pass through the request headers to the backend, it can inspect these and if it wants something different, return response headers to the proxy. This allows powerful tuning possibilities and because we operate on a semantic request basis (rather than HTTP/2 priorities dependency basis) we don't have all the complications and dangers. Proxying isn't the only use case. Often, one form of "API" to your local server is via setting response headers e.g., via configuration. Leveraging that approach means we don't have to invent new APIs.</p><p>Let's consider an example where server overrides are useful. Imagine we have a webpage with multiple images that are referenced via  tags near the top of the HTML. The browser will process these quite early in the page load and want to issue requests. At this point, <b>it might not know enough</b> about the page structure to determine if an image is in the viewport or outside the viewport. It can guess, but that might turn out to be wrong if the page is laid out a certain way. Guessing wrong means that something is misprioritized and might be taking bandwidth away from something that is more important. While it is possible to reprioritize things mid-flight using the PRIORITY_UPDATE frame, this action is "laggy" and by the time the server realizes things, it might be too late to make much difference.</p><p>Fear not, the web developer who built the page knows exactly how it is supposed to be laid out and rendered. They can overcome client uncertainty by overriding the Extensible Priority when they serve the response. For instance, if a client guesses wrong and requests the LCP image at a low priority in a shared bandwidth bucket, the image will load slower and web performance metrics will be adversely affected. Here's how it might look and how we can fix it:</p>
            <pre><code>Request HEADERS:
    :method = GET
    :scheme = https
    :authority = example.com
    :path = /lcp-image.jpg
     priority = u=3,i</code></pre>
            
            <pre><code>Response HEADERS:
:status = 200
content-length: 10000
content-type: image/jpeg
priority = u=2</code></pre>
            <p>Priority response headers are one tool to tweak client behavior and they are complementary to other web performance techniques. Methods like efficiently ordering elements in HTML, using attributes like "async" or "defer", augmenting HTML links with Link headers, or using more descriptive link relationships like “<a href="https://html.spec.whatwg.org/multipage/links.html#link-type-preload">preload</a>” all help to improve a browser's understanding of the resources comprising a page. A website that optimizes these things provides a better chance for the browser to make the best choices for prioritizing requests.</p><p>More recently, a new attribute called “<a href="https://web.dev/fetch-priority/">fetchpriority</a>” has emerged that allows developers to tune some of the browser behavior, by boosting or dropping the priority of an element relative to other elements of the same type. The attribute can help the browser do two important things for Extensible priorities: first, the browser might send the request earlier or later, helping to satisfy our golden rule #1 - ordering. Second, the browser might pick a different urgency value, helping to satisfy rule #2. However, "fetchpriority" is a nudge mechanism and it doesn't allow for directly setting a desired priority value. The nudge can be a bit opaque. Sometimes the circumstances benefit greatly from just knowing plainly what the values are and what the server will do, and that's where the response header can help.</p>
    <div>
      <h3>Conclusions</h3>
      <a href="#conclusions">
        
      </a>
    </div>
    <p>We’re excited about bringing this new standard into the world. Working with standards bodies has always been an amazing partnership and we’re very pleased with the results. We’ve seen great results with HTTP/3 priorities, reducing Largest Contentful Paint by up to 37% in our test. We’ll be rolling this feature out over the next few weeks as part of the HTTP Priorities feature for HTTP/2 that’s already available today.</p> ]]></content:encoded>
            <category><![CDATA[Speed Week]]></category>
            <category><![CDATA[HTTP3]]></category>
            <category><![CDATA[QUIC]]></category>
            <guid isPermaLink="false">3sxwiYeGEwXXvE9ltToeUB</guid>
            <dc:creator>Lucas Pardue</dc:creator>
            <dc:creator>Achiel van der Mandele</dc:creator>
        </item>
        <item>
            <title><![CDATA[Examining HTTP/3 usage one year on]]></title>
            <link>https://blog.cloudflare.com/http3-usage-one-year-on/</link>
            <pubDate>Tue, 06 Jun 2023 13:00:20 GMT</pubDate>
            <description><![CDATA[ With the HTTP/3 RFC celebrating its 1st birthday, we examined HTTP version usage trends between May 2022 - May 2023. We found that HTTP/3 usage by browsers continued to grow, but that search engine and social media bots continued to effectively ignore the latest version of the web’s core protocol ]]></description>
            <content:encoded><![CDATA[ <p></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3fGsSPUCSxABWlwpC5HfdV/ca7cf03337e600bd768b8acc7d06de36/image11-1.png" />
            
            </figure><p>In June 2022, after the publication of a set of HTTP-related Internet standards, including the <a href="https://www.rfc-editor.org/rfc/rfc9114.html">RFC that formally defined HTTP/3</a>, we published <a href="/cloudflare-view-http3-usage/"><i>HTTP RFCs have evolved: A Cloudflare view of HTTP usage trends</i></a>. One year on, as the RFC reaches its first birthday, we thought it would be interesting to look back at how these trends have evolved over the last year.</p><p>Our previous post reviewed usage trends for <a href="https://datatracker.ietf.org/doc/html/rfc9112">HTTP/1.1</a>, <a href="https://datatracker.ietf.org/doc/html/rfc9113">HTTP/2</a>, and <a href="https://datatracker.ietf.org/doc/html/rfc9114">HTTP/3</a> observed across Cloudflare’s network between May 2021 and May 2022, broken out by version and browser family, as well as for search engine indexing and social media bots. At the time, we found that browser-driven traffic was overwhelmingly using HTTP/2, although HTTP/3 usage was showing signs of growth. Search and social bots were mixed in terms of preference for <a href="https://www.cloudflare.com/learning/performance/http2-vs-http1.1/">HTTP/1.1 vs. HTTP/2</a>, with little-to-no HTTP/3 usage seen.</p><p>Between May 2022 and May 2023, we found that HTTP/3 usage in browser-retrieved content continued to grow, but that search engine indexing and social media bots continued to effectively ignore the latest version of the web’s core protocol. (Having said that, <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">the benefits of HTTP/3</a> are very user-centric, and arguably offer minimal benefits to bots designed to asynchronously crawl and index content. This may be a key reason that we see such low adoption across these automated user agents.) In addition, HTTP/3 usage across API traffic is still low, but doubled across the year. Support for HTTP/3 is on by default for zones using Cloudflare’s free tier of service, while paid customers have the option to activate support.</p><p>HTTP/1.1 and HTTP/2 use TCP as a transport layer and add security via <a href="https://www.cloudflare.com/learning/ssl/transport-layer-security-tls/">TLS</a>. HTTP/3 uses QUIC to provide both the transport layer and security. Due to the difference in transport layer, user agents usually require learning that an origin is accessible using HTTP/3 before they'll try it. One method of discovery is <a href="https://httpwg.org/specs/rfc7838.html">HTTP Alternative Services</a>, where servers return an Alt-Svc response header containing a list of supported <a href="https://developer.mozilla.org/en-US/docs/Glossary/ALPN">Application-Layer Protocol Negotiation Identifiers (ALPN IDs)</a>. Another method is the <a href="/speeding-up-https-and-http-3-negotiation-with-dns/">HTTPS record type</a>, where clients query the DNS to learn the supported ALPN IDs. The ALPN ID for HTTP/3 is "h3" but while the specification was in development and iteration, we added a suffix to identify the particular draft version e.g., "h3-29" identified <a href="https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-29">draft 29</a>. In order to maintain compatibility for a wide range of clients, Cloudflare advertised both "h3" and "h3-29". However, draft 29 was published close to three years ago and clients have caught up with support for the final RFC. As of late May 2023, Cloudflare no longer advertises h3-29 for zones that have HTTP/3 enabled, helping to save several bytes on each HTTP response or <a href="https://www.cloudflare.com/learning/dns/dns-records/">DNS record</a> that would have included it. Because a browser and web server typically automatically negotiate the highest HTTP version available, HTTP/3 takes precedence over HTTP/2.</p><p>In the sections below, “likely automated” and “automated” traffic based on <a href="https://developers.cloudflare.com/bots/concepts/bot-score/">Cloudflare bot score</a> has been filtered out for desktop and mobile browser analysis to restrict analysis to “likely human” traffic, but it is included for the search engine and social media bot analysis. In addition, references to HTTP requests or HTTP traffic below include requests made over both HTTP and HTTPS.</p>
    <div>
      <h3>Overall request distribution by HTTP version</h3>
      <a href="#overall-request-distribution-by-http-version">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/BD7nhUhMqEAKHE3lw7Ucs/1230d8393a90c5a431398edccac2b6c2/download-3.png" />
            
            </figure><p>Aggregating global web traffic to Cloudflare on a daily basis, we can observe usage trends for HTTP/1.1, HTTP/2, and HTTP/3 across the surveyed one year period. The share of traffic over HTTP/1.1 declined from 8% to 7% between May and the end of September, but grew rapidly to over 11% through October. It stayed elevated into the new year and through January, dropping back down to 9% by May 2023. Interestingly, the weekday/weekend traffic pattern became more pronounced after the October increase, and remained for the subsequent six months. HTTP/2 request share saw nominal change over the year, beginning around 68% in May 2022, but then starting to decline slightly in June. After that, its share didn’t see a significant amount of change, ending the period just shy of 64%. No clear weekday/weekend pattern was visible for HTTP/2. Starting with just over 23% share in May 2022, the percentage of requests over HTTP/3 grew to just over 30% by August and into September, but dropped to around 26% by November. After some nominal loss and growth, it ended the surveyed time period at 28% share. (Note that this graph begins in late May due to data retention limitations encountered when generating the graph in early June.)</p>
    <div>
      <h3>API request distribution by HTTP version</h3>
      <a href="#api-request-distribution-by-http-version">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1iKB6A5jGKVMBcaRAYckjv/47b7777093a2cad492060224a8257601/download--1--2.png" />
            
            </figure><p>Although <a href="/application-security-2023/">API traffic</a> makes up a significant amount of Cloudflare’s request volume, only a small fraction of those requests are made over HTTP/3. Approximately half of such requests are made over HTTP/1.1, with another third over HTTP/2. However, HTTP/3 usage for APIs grew from around 6% in May 2022 to over 12% by May 2023. HTTP/3’s smaller share of traffic is likely due in part to support for HTTP/3 in key tools like <a href="https://curl.se/docs/http3.html">curl</a> still being considered as “experimental”. Should this change in the future, with HTTP/3 gaining first-class support in such tools, we expect that this will accelerate growth in HTTP/3 usage, both for <a href="https://www.cloudflare.com/learning/security/api/what-is-an-api/">APIs</a> and overall as well.</p>
    <div>
      <h3>Mitigated request distribution by HTTP version</h3>
      <a href="#mitigated-request-distribution-by-http-version">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4J6wSXALudeaeZNzxvgRBo/6614895278f32528664d3f1444402350/download--2--2.png" />
            
            </figure><p>The analyses presented above consider all HTTP requests made to Cloudflare, but we also thought that it would be interesting to look at HTTP version usage by potentially malicious traffic, so we broke out just those requests that were mitigated by one of Cloudflare’s application security solutions. The graph above shows that the vast majority of mitigated requests are made over HTTP/1.1 and HTTP/2, with generally less than 5% made over HTTP/3. Mitigated requests appear to be most frequently made over HTTP/1.1, although HTTP/2 accounted for a larger share between early August and late November. These observations suggest that attackers don’t appear to be investing the effort to upgrade their tools to take advantage of the newest version of HTTP, finding the older versions of the protocol sufficient for their needs. (Note that this graph begins in late May 2022 due to data retention limitations encountered when generating the graph in early June 2023.)</p>
    <div>
      <h3>HTTP/3 use by desktop browser</h3>
      <a href="#http-3-use-by-desktop-browser">
        
      </a>
    </div>
    <p>As we noted last year, <a href="https://caniuse.com/http3">support for HTTP/3 in the stable release channels of major browsers</a> came in November 2020 for Google Chrome and Microsoft Edge, and April 2021 for Mozilla Firefox. We also noted that in Apple Safari, HTTP/3 support needed to be <a href="https://developer.apple.com/forums/thread/660516">enabled</a> in the “Experimental Features” developer menu in production releases. However, in the most recent releases of Safari, it appears that this step is no longer necessary, and that HTTP/3 is now natively supported.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/46nLEn3t41yyWfhZkznaEa/29c5b7bfa59b34f55977cc65ad67c2bf/download--3--2.png" />
            
            </figure><p>Looking at request shares by browser, Chrome started the period responsible for approximately 80% of HTTP/3 request volume, but the continued growth of Safari dropped it to around 74% by May 2023. A year ago, Safari represented less than 1% of HTTP/3 traffic on Cloudflare, but grew to nearly 7% by May 2023, likely as a result of support graduating from experimental to production.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7L26q8bA4sjcNlx7Vh0ohL/667061d148ccbaa0043cd3fd1e38a879/download--4--2.png" />
            
            </figure><p>Removing Chrome from the graph again makes trends across the other browsers more visible. As noted above, Safari experienced significant growth over the last year, while Edge saw a bump from just under 10% to just over 11% in June 2022. It stayed around that level through the new year, and then gradually dropped below 10% over the next several months. Firefox dropped slightly, from around 10% to just under 9%, while reported HTTP/3 traffic from Internet Explorer was near zero.</p><p>As we did in last year’s post, we also wanted to look at how the share of HTTP versions has changed over the last year across each of the leading browsers. The relative stability of HTTP/2 and HTTP/3 seen over the last year is in some contrast to the observations made in last year’s post, which saw some noticeable shifts during the May 2021 - May 2022 timeframe.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3bt30ch54tIJHXIcA4xzNo/ae9bf1593781da888f4c4843ac379465/download--5--1.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/CRgOGynraOznE7gu7AFjM/ec94e0c8be1b4ec2fb4f9f8f0a715cb0/download--6--1.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3AbRtdFXbJ43Xli6w0jVJN/ad597050da4a948d41a9b275c3752d96/download--7-.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/GgWSo7NP45FZffpsqScv1/e269f55f5b59402ad771a065196b3d59/download--8-.png" />
            
            </figure><p>In looking at request share by protocol version across the major desktop browser families, we see that across all of them, HTTP/1.1 share grows in late October. Further analysis indicates that this growth was due to significantly higher HTTP/1.1 request volume across several large customer zones, but it isn’t clear <b>why</b> this influx of traffic using an older version of HTTP occurred. It is clear that HTTP/2 remains the dominant protocol used for content requests by the major browsers, consistently accounting for 50-55% of request volume for Chrome and Edge, and ~60% for Firefox. However, for Safari, HTTP/2’s share dropped from nearly 95% in May 2022 to around 75% a year later, thanks to the growth in HTTP/3 usage.</p><p>HTTP/3 share on Safari grew from under 3% to nearly 18% over the course of the year, while its share on the other browsers was more consistent, with Chrome and Edge hovering around 40% and Firefox around 35%, and both showing pronounced weekday/weekend traffic patterns. (That pattern is arguably the most pronounced for Edge.) Such a pattern becomes more, yet still barely, evident with Safari in late 2022, although it tends to vary by less than a percent.</p>
    <div>
      <h3>HTTP/3 usage by mobile browser</h3>
      <a href="#http-3-usage-by-mobile-browser">
        
      </a>
    </div>
    <p>Mobile devices are responsible for <a href="https://radar.cloudflare.com/traffic?range=28d">over half</a> of request volume to Cloudflare, with Chrome Mobile <a href="https://radar.cloudflare.com/adoption-and-usage?range=28d">generating</a> more than 25% of all requests, and Mobile Safari more than 10%. Given this, we decided to explore HTTP/3 usage across these two key mobile platforms.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6gEIDgm3aTtDYNZj0GD5bS/3728f1ff9a6790b44f66deec6101871c/download--9-.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6a0By0cXENGpNbqV1BQB7G/5ddbdae331642235f4395c0972e8121e/download--10-.png" />
            
            </figure><p>Looking at Chrome Mobile and Chrome Mobile Webview (an embeddable version of Chrome that applications can use to display Web content), we find HTTP/1.1 usage to be minimal, topping out at under 5% of requests. HTTP/2 usage dropped from 60% to just under 55% between May and mid-September, but then bumped back up to near 60%, remaining essentially flat to slightly lower through the rest of the period. In a complementary fashion, HTTP/3 traffic increased from 37% to 45%, before falling just below 40% in mid-September, hovering there through May. The usage patterns ultimately look very similar to those seen with desktop Chrome, albeit without the latter’s clear weekday/weekend traffic pattern.</p><p>Perhaps unsurprisingly, the usage patterns for Mobile Safari and Mobile Safari Webview closely mirror those seen with desktop Safari. HTTP/1.1 share increases in October, and HTTP/3 sees strong growth, from under 3% to nearly 18%.</p>
    <div>
      <h3>Search indexing bots</h3>
      <a href="#search-indexing-bots">
        
      </a>
    </div>
    <p>Exploring usage of the various versions of HTTP by <a href="https://www.cloudflare.com/learning/bots/what-is-a-web-crawler/">search engine crawlers/bots</a>, we find that last year’s trend continues, and that there remains little-to-no usage of HTTP/3. (As mentioned above, this is somewhat expected, as HTTP/3 is optimized for browser use cases.) Graphs for Bing &amp; Baidu here are trimmed to a period ending April 1, 2023 due to anomalous data during April that is being investigated.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2zpXgMRgxrsctpJHrIShZC/ca5830878f4a328f0ee98ea5afdd883b/download--11-.png" />
            
            </figure><p>GoogleBot continues to rely primarily on HTTP/1.1, which generally comprises 55-60% of request volume. The balance is nearly all HTTP/2, although some nominal growth in HTTP/3 usage sees it peaking at just under 2% in March.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/415sWhtv1TxuyQJgW95wq4/a4340af637f9dbc42f25b3d81f61f356/download--12-.png" />
            
            </figure><p>Through January 2023, around 85% of requests from Microsoft’s BingBot were made via HTTP/2, but dropped to closer to 80% in late January. The balance of the requests were made via HTTP/1.1, as HTTP/3 usage was negligible.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2EP2wiznT1eIlRB7rwDQZB/6a2ffcda96dbc4a77f85d4866453aea0/download--13-.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7BxyzvnZnL8rWgIpIcEh9D/63cd123faeb6e9795b3766082b918b1a/download--14-.png" />
            
            </figure><p>Looking at indexing bots from search engines based outside of the United States, Russia’s YandexBot appears to use HTTP/1.1 almost exclusively, with HTTP/2 usage generally around 1%, although there was a period of increased usage between late August and mid-November. It isn’t clear what ultimately caused this increase. There was no meaningful request volume seen over HTTP/3. The indexing bot used by Chinese search engine Baidu also appears to strongly prefer HTTP/1.1, generally used for over 85% of requests. However, the percentage of requests over HTTP/2 saw a number of spikes, briefly reaching over 60% on days in July, November, and December 2022, as well as January 2023, with several additional spikes in the 30% range. Again, it isn’t clear what caused this spiky behavior. HTTP/3 usage by BaiduBot is effectively non-existent as well.</p>
    <div>
      <h3>Social media bots</h3>
      <a href="#social-media-bots">
        
      </a>
    </div>
    <p>Similar to Bing &amp; Baidu above, the graphs below are also trimmed to a period ending April 1.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6JuMhjbBKR1azrJ0zgZfeM/7c765cdc40f70ddbdec16aa447585e0f/download--15-.png" />
            
            </figure><p>Facebook’s use of HTTP/3 for site crawling and indexing over the last year remained near zero, similar to what we observed over the previous year. HTTP/1.1 started the period accounting for under 60% of requests, and except for a brief peak above it in late May, usage of HTTP/1.1 steadily declined over the course of the year, dropping to around 30% by April 2023. As such, use of HTTP/2 increased from just over 40% in May 2022 to over 70% in April 2023. Meta engineers confirmed that this shift away from HTTP/1.1 usage is an expected gradual change in their infrastructure's use of HTTP, and that they are slowly working towards removing HTTP/1.1 from their infrastructure entirely.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6Gq43pPPIHZuV6L8gqwHCv/1bb85f1d4eb42551a64e41e943678e7f/download--16-.png" />
            
            </figure><p>In last year’s blog post, we noted that “TwitterBot clearly has a strong and consistent preference for HTTP/2, accounting for 75-80% of its requests, with the balance over HTTP/1.1.” This preference generally remained the case through early October, at which point HTTP/2 usage began a gradual decline to just above 60% by April 2023. It isn’t clear what drove the week-long HTTP/2 drop and HTTP/1.1 spike in late May 2022. And as we noted last year, TwitterBot’s use of HTTP/3 remains non-existent.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4fb6YfpvO1LgDfHmQ9ExXh/5c999b0cf8ced8ca0c7a64b9788c3fb5/download--17-.png" />
            
            </figure><p>In contrast to Facebook’s and Twitter’s site crawling bots, HTTP/3 actually accounts for a noticeable, and growing, volume of requests made by LinkedIn’s bot, increasing from just under 1% in May 2022 to just over 10% in April 2023. We noted last year that LinkedIn’s use of HTTP/2 began to take off in March 2022, growing to approximately 5% of requests. Usage of this version gradually increased over this year’s surveyed period to 15%, although the growth was particularly erratic and spiky, as opposed to a smooth, consistent increase. HTTP/1.1 remained the dominant protocol used by LinkedIn’s bots, although its share dropped from around 95% in May 2022 to 75% in April 2023.</p>
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>On the whole, we are excited to see that usage of HTTP/3 has generally increased for browser-based consumption of traffic, and recognize that there is opportunity for significant further growth if and when it starts to be used more actively for API interactions through production support in key tools like curl. And though disappointed to see that search engine and social media bot usage of HTTP/3 remains minimal to non-existent, we also recognize that the real-time benefits of using the newest version of the web’s foundational protocol may not be completely applicable for asynchronous automated content retrieval.</p><p>You can follow these and other trends in the “Adoption and Usage” section of Cloudflare Radar at <a href="https://radar.cloudflare.com/adoption-and-usage">https://radar.cloudflare.com/adoption-and-usage</a>, as well as by following <a href="https://twitter.com/cloudflareradar">@CloudflareRadar</a> on Twitter or <a href="https://cloudflare.social/@radar">https://cloudflare.social/@radar</a> on Mastodon.</p> ]]></content:encoded>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[IETF]]></category>
            <guid isPermaLink="false">7Dpg4lAaYLKzXNozcyuxdv</guid>
            <dc:creator>David Belson</dc:creator>
            <dc:creator>Lucas Pardue</dc:creator>
        </item>
        <item>
            <title><![CDATA[HTTP RFCs have evolved: A Cloudflare view of HTTP usage trends]]></title>
            <link>https://blog.cloudflare.com/cloudflare-view-http3-usage/</link>
            <pubDate>Mon, 06 Jun 2022 20:49:17 GMT</pubDate>
            <description><![CDATA[ HTTP/3 is now RFC 9114. We explore Cloudflare's view of how it is being used ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Today, a cluster of Internet standards were published that rationalize and modernize the definition of HTTP - the application protocol that underpins the web. This work includes updates to, and <a href="https://www.cloudflare.com/learning/cloud/how-to-refactor-applications/">refactoring</a> of, HTTP semantics, HTTP caching, HTTP/1.1, HTTP/2, and the brand-new <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a>. Developing these specifications has been no mean feat and today marks the culmination of efforts far and wide, in the Internet Engineering Task Force (IETF) and beyond. We thought it would be interesting to celebrate the occasion by sharing some analysis of Cloudflare's view of HTTP traffic over the last 12 months.</p><p>However, before we get into the traffic data, for quick reference, here are the new RFCs that you should make a note of and start using:</p><ul><li><p>HTTP Semantics - <a href="https://www.rfc-editor.org/rfc/rfc9110.html">RFC 9110</a></p><ul><li><p>HTTP's overall architecture, common terminology and shared protocol aspects such as request and response messages, methods, status codes, header and trailer fields, message content, representation data, content codings and much more. Obsoletes RFCs <a href="https://www.rfc-editor.org/rfc/rfc2818.html">2818</a>, <a href="https://www.rfc-editor.org/rfc/rfc7231.html">7231</a>, <a href="https://www.rfc-editor.org/rfc/rfc7232.html">7232</a>, <a href="https://www.rfc-editor.org/rfc/rfc7233.html">7233</a>, <a href="https://www.rfc-editor.org/rfc/rfc7235.html">7235</a>, <a href="https://www.rfc-editor.org/rfc/rfc7538.html">7538</a>, <a href="https://www.rfc-editor.org/rfc/rfc7615.html">7615</a>, <a href="https://www.rfc-editor.org/rfc/rfc7694.html">7694</a>, and portions of <a href="https://www.rfc-editor.org/rfc/rfc7230.html">7230</a>.</p></li></ul></li><li><p>HTTP Caching - <a href="https://www.rfc-editor.org/rfc/rfc9111.html">RFC 9111</a></p><ul><li><p>HTTP caches and related header fields to control the behavior of response caching. Obsoletes RFC <a href="https://www.rfc-editor.org/rfc/rfc7234.html">7234</a>.</p></li></ul></li><li><p>HTTP/1.1 - <a href="https://www.rfc-editor.org/rfc/rfc9112.html">RFC 9112</a></p><ul><li><p>A syntax, aka "wire format", of HTTP that uses a text-based format. Typically used over TCP and TLS. Obsolete portions of RFC <a href="https://www.rfc-editor.org/rfc/rfc7230.html">7230</a>.</p></li></ul></li><li><p>HTTP/2 - RFC <a href="https://www.rfc-editor.org/rfc/rfc9113.html">9113</a></p><ul><li><p>A syntax of HTTP that uses a binary framing format, which provides streams to support concurrent requests and responses. Message fields can be compressed using HPACK. Typically used over TCP and TLS. Obsoletes RFCs <a href="https://www.rfc-editor.org/rfc/rfc7540.html">7540</a> and <a href="https://www.rfc-editor.org/rfc/rfc8740.html">8740</a>.</p></li></ul></li><li><p>HTTP/3 - RFC <a href="https://www.rfc-editor.org/rfc/rfc9114.html">9114</a></p><ul><li><p>A syntax of HTTP that uses a binary framing format optimized for the QUIC transport protocol. Message fields can be compressed using QPACK.</p></li></ul></li><li><p>QPACK - RFC <a href="https://www.rfc-editor.org/rfc/rfc9204.html">9204</a></p><ul><li><p>A variation of HPACK field compression that is optimized for the QUIC transport protocol.</p></li></ul></li></ul><p>On May 28, 2021, we <a href="/quic-version-1-is-live-on-cloudflare/">enabled</a> QUIC version 1 and HTTP/3 for all Cloudflare customers, using the final "h3" identifier that matches RFC 9114. So although today's publication is an occasion to celebrate, for us nothing much has changed, and it's business as usual.</p><p><a href="https://caniuse.com/http3">Support for HTTP/3 in the stable release channels of major browsers</a> came in November 2020 for Google Chrome and Microsoft Edge and April 2021 for Mozilla Firefox. In Apple Safari, HTTP/3 support currently needs to be <a href="https://developer.apple.com/forums/thread/660516">enabled</a> in the “Experimental Features” developer menu in production releases.</p><p>A browser and web server typically automatically negotiate the highest HTTP version available. Thus, HTTP/3 takes precedence over HTTP/2. We looked back over the last year to understand HTTP/3 usage trends across the Cloudflare network, as well as analyzing HTTP versions used by traffic from leading browser families (Google Chrome, Mozilla Firefox, Microsoft Edge, and Apple Safari), major search engine indexing bots, and bots associated with some popular social media platforms. The graphs below are based on aggregate HTTP(S) traffic seen globally by the Cloudflare network, and include requests for website and application content across the Cloudflare customer base between May 7, 2021, and May 7, 2022. We used <a href="https://developers.cloudflare.com/bots/concepts/bot-score/">Cloudflare bot scores</a> to restrict analysis to “likely human” traffic for the browsers, and to “likely automated” and “automated” for the search and social bots.</p>
    <div>
      <h3>Traffic by HTTP version</h3>
      <a href="#traffic-by-http-version">
        
      </a>
    </div>
    <p>Overall, HTTP/2 still comprises the majority of the request traffic for Cloudflare customer content, as clearly seen in the graph below. After remaining fairly consistent through 2021, HTTP/2 request volume increased by approximately 20% heading into 2022. HTTP/1.1 request traffic remained fairly flat over the year, aside from a slight drop in early December. And while HTTP/3 traffic initially trailed HTTP/1.1, it surpassed it in early July, growing steadily and  roughly doubling in twelve months.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2UKNCgWJPAocsCrvTmqKOG/6c1d9ff45b8c4430f4663f4fe8a41964/image13-1.png" />
            
            </figure>
    <div>
      <h3>HTTP/3 traffic by browser</h3>
      <a href="#http-3-traffic-by-browser">
        
      </a>
    </div>
    <p>Digging into just HTTP/3 traffic, the graph below shows the trend in daily aggregate request volume over the last year for HTTP/3 requests made by the surveyed browser families. Google Chrome (orange line) is far and away the leading browser, with request volume far outpacing the others.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6fOBxNVQis3KRP9qMJtN0h/07df569e787dcfd3b918124a9c324b30/image6-21.png" />
            
            </figure><p>Below, we remove Chrome from the graph to allow us to more clearly see the trending across other browsers. Likely because it is also based on the Chromium engine, the trend for Microsoft Edge closely mirrors Chrome. As noted above, Mozilla Firefox first enabled production support in <a href="https://hacks.mozilla.org/2021/04/quic-and-http-3-support-now-in-firefox-nightly-and-beta/">version 88</a> in April 2021, making it available by default by the end of May. The increased adoption of that updated version during the following month is clear in the graph as well, as HTTP/3 request volume from Firefox grew rapidly. HTTP/3 traffic from Apple Safari increased gradually through April, suggesting growth in the number of users enabling the experimental feature or running a Technology Preview version of the browser. However, Safari’s HTTP/3 traffic has subsequently dropped over the last couple of months. We are not aware of any specific reasons for this decline, but our most recent observations indicate HTTP/3 traffic is recovering.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7Mupv6iXQ195JfJkFLJQjX/cb0cc4153c043740e92e93fb2e041626/image2-57.png" />
            
            </figure><p>Looking at the lines in the graph for Chrome, Edge, and Firefox, a weekly cycle is clearly visible in the graph, suggesting greater usage of these browsers during the work week. This same pattern is absent from Safari usage.</p><p>Across the surveyed browsers, Chrome ultimately accounts for approximately 80% of the HTTP/3 requests seen by Cloudflare, as illustrated in the graphs below. Edge is responsible for around another 10%, with Firefox just under 10%, and Safari responsible for the balance.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3Yph7V9e1W31PWkSry6pCy/6c874447bfa49392244e587dfb3d35fe/image1-64.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1zPj3TMsZuiirtoljldJYy/12f92447d2d0b3c26afd0b5754c510f1/image8-10.png" />
            
            </figure><p>We also wanted to look at how the mix of HTTP versions has changed over the last year across each of the leading browsers. Although the percentages vary between browsers, it is interesting to note that the trends are very similar across Chrome, Firefox and Edge. (After Firefox turned on default HTTP/3 support in May 2021, of course.)  These trends are largely customer-driven – that is, they are likely due to changes in Cloudflare customer configurations.</p><p>Most notably we see an increase in HTTP/3 during the last week of September, and a decrease in HTTP/1.1 at the beginning of December. For Safari, the HTTP/1.1 drop in December is also visible, but the HTTP/3 increase in September is not. We expect that over time, once Safari supports HTTP/3 by default that its trends will become more similar to those seen for the other browsers.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4P1m2PJH7GBq9kBUL4vH0/fd19391109337e16a255967b54120392/image7-12.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5Fj8pBr6Z5tpMV9XUTC1lJ/68b10faf3b1f840844d1cf97f8204b64/image9-6.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6iMw3Aj3IXWpjn4LyxBAsG/7b59629b937fb39d352a126a5bd178d3/image12-1.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2dtxJLKq2N23CBwcZlEz8s/64bdc5275320e16bd0b8780db49e0ffc/image11-2.png" />
            
            </figure>
    <div>
      <h3>Traffic by search indexing bot</h3>
      <a href="#traffic-by-search-indexing-bot">
        
      </a>
    </div>
    <p>Back in 2014, Google <a href="https://developers.google.com/search/blog/2014/08/https-as-ranking-signal">announced</a> that it would start to consider HTTPS usage as a ranking signal as it indexed websites. However, it does not appear that Google, or any of the other major search engines, currently consider support for the latest versions of HTTP as a ranking signal. (At least not directly – the performance improvements associated with newer versions of HTTP could theoretically influence rankings.) Given that, we wanted to understand which versions of HTTP the indexing bots themselves were using.</p><p>Despite leading the charge around the development of QUIC, and integrating HTTP/3 support into the Chrome browser early on, it appears that on the indexing/crawling side, Google still has quite a long way to go. The graph below shows that requests from GoogleBot are still predominantly being made over HTTP/1.1, although use of HTTP/2 has grown over the last six months, gradually approaching HTTP/1.1 request volume. (A <a href="https://developers.google.com/search/blog/2020/09/googlebot-will-soon-speak-http2">blog post</a> from Google provides some potential insights into this shift.) Unfortunately, the volume of requests from GoogleBot over HTTP/3 has remained extremely limited over the last year.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3gTr2C26AB8SF6aK0CaiK/9b555a912b3428ad9e15572936bf4fb1/image4-32.png" />
            
            </figure><p>Microsoft’s BingBot also fails to use HTTP/3 when indexing sites, with near-zero request volume. However, in contrast to GoogleBot, BingBot prefers to use HTTP/2, with a wide margin developing in mid-May 2021 and remaining consistent across the rest of the past year.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/444sdNtnh5h0LNsGtUWmuV/b4d3a2f76ec4a5b8fc579371c9f005a2/image10-5.png" />
            
            </figure>
    <div>
      <h3>Traffic by social media bot</h3>
      <a href="#traffic-by-social-media-bot">
        
      </a>
    </div>
    <p>Major social media platforms use custom bots to retrieve metadata for shared content, <a href="https://developers.facebook.com/docs/sharing/bot/">improve language models for speech recognition technology</a>, or otherwise index website content. We also surveyed the HTTP version preferences of the bots deployed by three of the leading social media platforms.</p><p>Although <a href="https://http3check.net/?host=www.facebook.com">Facebook supports HTTP/3</a> on their main website (and presumably their mobile applications as well), their back-end FacebookBot crawler does not appear to support it. Over the last year, on the order of 60% of the requests from FacebookBot have been over HTTP/1.1, with the balance over HTTP/2. Heading into 2022, it appeared that HTTP/1.1 preference was trending lower, with request volume over the 25-year-old protocol dropping from near 80% to just under 50% during the fourth quarter. However, that trend was abruptly reversed, with HTTP/1.1 growing back to over 70% in early February. The reason for the reversal is unclear.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6upA1FtAbR6TWhexL8CkxT/87b3f1d676e1f9189ad5b7dc1d869e4a/image3-44.png" />
            
            </figure><p>Similar to FacebookBot, it appears TwitterBot’s use of HTTP/3 is, unfortunately, pretty much non-existent. However, TwitterBot clearly has a strong and consistent preference for HTTP/2, accounting for 75-80% of its requests, with the balance over HTTP/1.1.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2c9sz97ViywLHaRd4vxCwE/9c981e7c39f8c894957447b4a3337c1a/image14-1.png" />
            
            </figure><p>In contrast, LinkedInBot has, over the last year, been firmly committed to making requests over HTTP/1.1, aside from the apparently brief anomalous usage of HTTP/2 last June. However, in mid-March, it appeared to tentatively start exploring the use of other HTTP versions, with around 5% of requests now being made over HTTP/2, and around 1% over HTTP/3, as seen in the upper right corner of the graph below.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1ozCJpCXILw6ulzIAxDyXn/70f9a1c95d76f4fd1f6f9e70e4d3e270/image5-23.png" />
            
            </figure>
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>We're happy that HTTP/3 has, at long last, been published as <a href="https://www.rfc-editor.org/rfc/rfc9114.html">RFC 9114</a>. More than that, we're super pleased to see that regardless of the wait, browsers have steadily been enabling support for the protocol by default. This allows end users to seamlessly gain the advantages of HTTP/3 whenever it is available. On Cloudflare's global network, we've seen continued growth in the share of traffic speaking HTTP/3, demonstrating continued interest from customers in enabling it for their sites and services. In contrast, we are disappointed to see bots from the major search and social platforms continuing to rely on aging versions of HTTP. We'd like to build a better understanding of how these platforms chose particular HTTP versions and welcome collaboration in exploring the advantages that HTTP/3, in particular, could provide.</p><p>Current statistics on HTTP/3 and QUIC adoption at a country and autonomous system (ASN) level can be found on <a href="https://radar.cloudflare.com/">Cloudflare Radar</a>.</p><p>Running HTTP/3 and QUIC on the edge for everyone has allowed us to monitor a wide range of aspects related to interoperability and performance across the Internet. Stay tuned for future blog posts that explore some of the technical developments we've been making.</p><p>And this certainly isn't the end of protocol innovation, as HTTP/3 and QUIC provide many exciting new opportunities. The IETF and wider community are already underway building new capabilities on top, such as <a href="/unlocking-quic-proxying-potential/">MASQUE</a> and <a href="https://datatracker.ietf.org/wg/webtrans/documents/">WebTransport</a>. Meanwhile, in the last year, the QUIC Working Group has adopted new work such as <a href="https://datatracker.ietf.org/doc/draft-ietf-quic-v2/">QUIC version 2</a>, and the <a href="https://datatracker.ietf.org/doc/draft-ietf-quic-multipath/">Multipath Extension to QUIC</a>.</p>
    <div>
      <h3>Watch on Cloudflare TV</h3>
      <a href="#watch-on-cloudflare-tv">
        
      </a>
    </div>
    <div></div><p></p> ]]></content:encoded>
            <category><![CDATA[HTTP3]]></category>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[IETF]]></category>
            <guid isPermaLink="false">4Dd2QedroFWYvUMb5Ba3ha</guid>
            <dc:creator>Lucas Pardue</dc:creator>
            <dc:creator>David Belson</dc:creator>
        </item>
        <item>
            <title><![CDATA[Unlocking QUIC’s proxying potential with MASQUE]]></title>
            <link>https://blog.cloudflare.com/unlocking-quic-proxying-potential/</link>
            <pubDate>Sun, 20 Mar 2022 16:58:37 GMT</pubDate>
            <description><![CDATA[ We continue our technical deep dive into traditional TCP proxying over HTTP ]]></description>
            <content:encoded><![CDATA[ <p></p><p>In the last post on <a href="/a-primer-on-proxies/">proxy TCP-based applications</a>, we discussed how HTTP CONNECT can be used to proxy TCP-based applications, including DNS-over-HTTPS and generic HTTPS traffic, between a client and target server. This provides significant benefits for those applications, but it doesn’t lend itself to non-TCP applications. And if you’re wondering whether or not we care about these, the answer is an affirmative yes!</p><p>For instance, <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a> is based on QUIC, which runs on top of UDP. What if we wanted to speak HTTP/3 to a target server? That requires two things: (1) the means to encapsulate a UDP payload between client and proxy (which the proxy decapsulates and forward to the target in an actual UDP datagram), and (2) a way to instruct the proxy to open a UDP association to a target so that it knows where to forward the decapsulated payload. In this post, we’ll discuss answers to these two questions, starting with encapsulation.</p>
    <div>
      <h3>Encapsulating datagrams</h3>
      <a href="#encapsulating-datagrams">
        
      </a>
    </div>
    <p>While TCP provides a reliable and ordered byte stream for applications to use, UDP instead provides unreliable messages called datagrams. Datagrams sent or received on a connection are loosely associated, each one is independent from a transport perspective. Applications that are built on top of UDP can leverage the unreliability for good. For example, low-latency media streaming often does so to avoid lost packets getting retransmitted. This makes sense, on a live teleconference it is better to receive the most recent audio or video rather than starting to lag behind while you're waiting for stale data</p><p>QUIC is designed to run on top of an unreliable protocol such as UDP. QUIC provides its own layer of security, packet loss detection, methods of data recovery, and congestion control. If the layer underneath QUIC duplicates those features, they can cause wasted work or worse create destructive interference. For instance, QUIC <a href="https://www.rfc-editor.org/rfc/rfc9002.html#section-7">congestion control</a> defines a number of signals that provide input to sender-side algorithms. If layers underneath QUIC affect its packet flows (loss, timing, pacing, etc), they also affect the algorithm output. Input and output run in a feedback loop, so perturbation of signals can get amplified. All of this can cause congestion control algorithms to be more conservative in the data rates they use.</p><p>If we could speak HTTP/3 to a proxy, and leverage a reliable QUIC stream to carry encapsulated datagrams payload, then everything <i>can</i> work. However, the reliable stream interferes with expectations. The most likely outcome being slower end-to-end UDP throughput than we could achieve without tunneling. Stream reliability runs counter to our goals.</p><p>Fortunately, QUIC's <a href="https://datatracker.ietf.org/doc/draft-ietf-quic-datagram/">unreliable datagram extension</a> adds a new <a href="https://datatracker.ietf.org/doc/html/draft-ietf-quic-datagram-07#section-4">DATAGRAM frame</a> that, as its name plainly says, is unreliable. It has several uses; the one we care about is that it provides a building block for performant UDP tunneling. In particular, this extension has the following properties:</p><ul><li><p>DATAGRAM frames are individual messages, unlike a long QUIC stream.</p></li><li><p>DATAGRAM frames do not contain a multiplexing identifier, unlike QUIC's stream IDs.</p></li><li><p>Like all QUIC frames, DATAGRAM frames must fit completely inside a QUIC packet.</p></li><li><p>DATAGRAM frames are subject to congestion control, helping senders to avoid overloading the network.</p></li><li><p>DATAGRAM frames are acknowledged by the receiver but, importantly, if the sender detects a loss, QUIC does not retransmit the lost data.</p></li></ul><p>The Datagram "Unreliable Datagram Extension to QUIC" specification will be published as an RFC soon. Cloudflare's <a href="https://github.com/cloudflare/quiche">quiche</a> library has supported it since October 2020.</p><p>Now that QUIC has primitives that support sending unreliable messages, we have a standard way to effectively tunnel UDP inside it. QUIC provides the STREAM and DATAGRAM transport primitives that support our proxying goals. Now it is the application layer responsibility to describe <b>how</b> to use them for proxying. Enter MASQUE.</p>
    <div>
      <h3>MASQUE: Unlocking QUIC’s potential for proxying</h3>
      <a href="#masque-unlocking-quics-potential-for-proxying">
        
      </a>
    </div>
    <p>Now that we’ve described how encapsulation works, let’s now turn our attention to the second question listed at the start of this post: How does an application initialize an end-to-end tunnel, informing a proxy server where to send UDP datagrams to, and where to receive them from? This is the focus of the <a href="https://datatracker.ietf.org/wg/masque/about/">MASQUE Working Group</a>, which was formed in June 2020 and has been designing answers since. Many people across the Internet ecosystem have been contributing to the standardization activity. At Cloudflare, that includes Chris (as co-chair), Lucas (as co-editor of one WG document) and several other colleagues.</p><p>MASQUE started solving the UDP tunneling problem with a pair of specifications: a definition for how <a href="https://datatracker.ietf.org/doc/draft-ietf-masque-h3-datagram/">QUIC datagrams are used with HTTP/3</a>, and <a href="https://datatracker.ietf.org/doc/draft-ietf-masque-connect-udp/">a new kind of HTTP request</a> that initiates a UDP socket to a target server. These have built on the concept of extended CONNECT, which was first introduced for HTTP/2 in <a href="https://datatracker.ietf.org/doc/html/rfc8441">RFC 8441</a> and has now been <a href="https://datatracker.ietf.org/doc/draft-ietf-httpbis-h3-websockets/">ported to HTTP/3</a>. Extended CONNECT defines the :protocol pseudo-header that can be used by clients to indicate the intention of the request. The initial use case was WebSockets, but we can repurpose it for UDP and it looks like this:</p>
            <pre><code>:method = CONNECT
:protocol = connect-udp
:scheme = https
:path = /target.example.com/443/
:authority = proxy.example.com</code></pre>
            <p>A client sends an extended CONNECT request to a proxy server, which identifies a target server in the :path. If the proxy succeeds in opening a UDP socket, it responds with a 2xx (Successful) status code. After this, an end-to-end flow of unreliable messages between the client and target is possible; the client and proxy exchange QUIC DATAGRAM frames with an encapsulated payload, and the proxy and target exchange UDP datagrams bearing that payload.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3BXgtvSVPvNMa3CkKqqioK/1530306e4007e30b6d7b995c2b01f823/image3-34.png" />
            
            </figure>
    <div>
      <h3>Anatomy of Encapsulation</h3>
      <a href="#anatomy-of-encapsulation">
        
      </a>
    </div>
    <p>UDP tunneling has a constraint that TCP tunneling does not – namely, the size of messages and how that relates to path MTU (Maximum Transmission Unit; for more background see our <a href="https://www.cloudflare.com/learning/network-layer/what-is-mtu/">Learning Center article</a>). The path MTU is the maximum size that is allowed on the path between client and server. The actual maximum is the smallest maximum across all elements at every hop and at every layer, from the network up to application. All it takes is for one component with a small MTU to reduce the path MTU entirely. On the Internet, <a href="https://www.cloudflare.com/learning/network-layer/what-is-mtu/">1,500 bytes</a> is a common practical MTU. When considering tunneling using QUIC, we need to appreciate the anatomy of QUIC packets and frames in order to understand how they add bytes of overheard. This consumes bytes and subtracts from our theoretical maximum.</p><p>We've been talking in terms of HTTP/3 which normally has its own frames (HEADERS, DATA, etc) that have a common type and length overhead. However, there is no HTTP/3 framing when it comes to DATAGRAM, instead the bytes are placed directly into the QUIC frame. This frame is composed of two fields. The first field is a variable number of bytes, called the <a href="https://datatracker.ietf.org/doc/html/draft-ietf-masque-h3-datagram-05#section-3">Quarter Stream ID</a> field, which is an encoded identifier that supports independent multiplexed DATAGRAM flows. It does so by binding each DATAGRAM to the HTTP request stream ID. In QUIC, stream IDs use two bits to encode four types of stream. Since request streams are always of one type (client-initiated bidirectional, to be exact), we can divide their ID by four to save space on the wire. Hence the name Quarter Stream ID. The second field is payload, which contains the end-to-end message payload. Here's how it might look on the wire.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7fzMrcBgH540C9SizGskfh/2107ffe432c189ec089e5663615bc814/image2-75.png" />
            
            </figure><p>If you recall our lesson from the <a href="/a-primer-on-proxies/">last post</a>, DATAGRAM frames (like all frames) must fit completely inside a QUIC packet. Moreover, since QUIC requires that <a href="https://www.rfc-editor.org/rfc/rfc9000.html#section-14-7">fragmentation is disabled</a>, QUIC packets must fit completely inside a UDP datagram. This all combines to limit the maximum size of things that we can actually send: the path MTU determines the size of the UDP datagram, then we need to subtract the overheads of the UDP datagram header, QUIC packet header, and QUIC DATAGRAM frame header. For a better understanding of QUIC's wire image and overheads, see <a href="https://www.rfc-editor.org/rfc/rfc8999.html#section-5">Section 5 of RFC 8999</a> and <a href="https://www.rfc-editor.org/rfc/rfc9000.html#section-12.4">Section 12.4 of RFC 9000</a>.</p><p>If a sender has a message that is too big to fit inside the tunnel, there are only two options: discard the message or fragment it. Neither of these are good options. Clients create the UDP tunnel and are more likely to accurately calculate the real size of encapsulated UDP datagram payload, thus avoiding the problem. However, a target server is most likely unaware that a client is behind a proxy, so it cannot accommodate the tunneling overhead. It might send a UDP datagram payload that is too big for the proxy to encapsulate. This conundrum is common to all proxy protocols! There's an art in picking the right MTU size for UDP-based traffic in the face of tunneling overheads. While approaches like path MTU discovery can help, they are <a href="/path-mtu-discovery-in-practice/">not a silver bullet</a>. Choosing conservative maximum sizes can reduce the chances of tunnel-related problems. However, this needs to be weighed against being too restrictive. Given a theoretical path MTU of 1,500, once we consider QUIC encapsulation overheads, tunneled messages with a limit between 1,200 and 1,300 bytes can be effective.This is especially important when we think about tunneling QUIC itself. <a href="https://datatracker.ietf.org/doc/html/rfc9000#section-8.1">RFC 9000 Section 8.1</a> details how clients that initiate new QUIC connections must send UDP datagrams of at least 1,200 bytes. If a proxy can't support that, then QUIC will not work in a tunnel.</p>
    <div>
      <h3>Nested tunneling for Improved Privacy Proxying</h3>
      <a href="#nested-tunneling-for-improved-privacy-proxying">
        
      </a>
    </div>
    <p>MASQUE gives us the application layer building blocks to support efficient tunneling of TCP or UDP traffic. What's cool about this is that we can combine these blocks into different deployment architectures for different scenarios or different needs.</p><p>One example of this case is nested tunneling via multiple proxies, which can minimize the connection metadata available to each individual proxy or server (one example of this type of deployment is described in our recent post on <a href="/icloud-private-relay/">iCloud Private Relay)</a>. In this kind of setup, a client might manage at least three logical connections. First, a QUIC connection between Client and Proxy 1. Second, a QUIC connection between Client and Proxy 2, which runs via a CONNECT tunnel in the first connection. Third, an end-to-end byte stream between Client and Server, which runs via a CONNECT tunnel in the second connection. A real TCP connection only exists between Proxy 2 and Server. If additional Client to Server logical connections are needed, they can be created inside the existing pair of QUIC connections.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3zIR70pmMrWlgjGongXqkH/9409a30dfba8a603d9a917b20e8a3d3a/image4-16.png" />
            
            </figure>
    <div>
      <h3>Towards a full tunnel with IP tunneling</h3>
      <a href="#towards-a-full-tunnel-with-ip-tunneling">
        
      </a>
    </div>
    <p>Proxy support for UDP and TCP already unblocks a huge assortment of use cases, including TLS, QUIC, HTTP, DNS, and so on. But it doesn’t help protocols that use different <a href="https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml">IP protocols</a>, like <a href="https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol">ICMP</a> or IPsec <a href="https://en.wikipedia.org/wiki/IPsec#Encapsulating_Security_Payload">Encapsulating Security Payload</a> (ESP). Fortunately, the MASQUE Working Group has also been working on IP tunneling. This is a lot more complex than UDP tunneling, so they first spent some time defining a common set of <a href="https://datatracker.ietf.org/doc/draft-ietf-masque-ip-proxy-reqs/">requirements</a>. The group has recently adopted a new specification to support <a href="https://datatracker.ietf.org/doc/draft-ietf-masque-connect-ip/">IP proxying over HTTP</a>. This behaves similarly to the other CONNECT designs we've discussed but with a few differences. Indeed, IP proxying support using HTTP as a substrate would unlock many applications that existing protocols like IPsec and WireGuard enable.</p><p>At this point, it would be reasonable to ask: “A complete HTTP/3 stack is a bit excessive when all I need is a simple end-to-end tunnel, right?” Our answer is, it depends! CONNECT-based IP proxies use TLS and rely on well established PKIs for creating secure channels between endpoints, whereas protocols like WireGuard use a simpler cryptographic protocol for key establishment and defer authentication to the application. WireGuard does not support proxying over TCP but <a href="https://www.wireguard.com/known-limitations/">can be adapted to work over TCP</a> transports, if necessary. In contrast, CONNECT-based proxies do support TCP and UDP transports, depending on what version of HTTP is used. Despite these differences, these protocols do share similarities. In particular, the actual framing used by both protocols – be it the TLS record layer or QUIC packet protection for CONNECT-based proxies, or WireGuard encapsulation – are not interoperable but only slightly differ in wire format. Thus, from a performance perspective, there’s not really much difference.</p><p>In general, comparing these protocols is like comparing apples and oranges – they’re fit for different purposes, have different implementation requirements, and assume different ecosystem participants and threat models. At the end of the day, CONNECT-based proxies are better suited to an ecosystem and environment that is already heavily invested in TLS and the existing WebPKI, so we expect CONNECT-based solutions for IP tunnels to become the norm in the future. Nevertheless, it's early days, so be sure to watch this space if you’re interested in learning more!</p>
    <div>
      <h3>Looking ahead</h3>
      <a href="#looking-ahead">
        
      </a>
    </div>
    <p>The IETF has chartered the MASQUE Working Group to help design an HTTP-based solution for UDP and IP that complements the existing CONNECT method for TCP tunneling. Using HTTP semantics allows us to use features like request methods, response statuses, and header fields to enhance tunnel initialization. For example, allowing for reuse of existing authentication mechanisms or the <a href="https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-proxy-status">Proxy-Status</a> field. By using HTTP/3, UDP and IP tunneling can benefit from QUIC's secure transport native unreliable datagram support, and other features. Through a flexible design, older versions of HTTP can also be supported, which helps widen the potential deployment scenarios. Collectively, this work brings proxy protocols to the masses.</p><p>While the design details of MASQUE specifications continue to be iterated upon, so far several implementations have been developed, some of which have been interoperability tested during IETF hackathons. This running code helps inform the continued development of the specifications. Details are likely to continue changing before the end of the process, but we should expect the overarching approach to remain similar. Join us during the MASQUE WG meeting in <a href="https://www.ietf.org/how/meetings/113/">IETF 113</a> to learn more!</p> ]]></content:encoded>
            <category><![CDATA[Proxying]]></category>
            <category><![CDATA[Deep Dive]]></category>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[QUIC]]></category>
            <guid isPermaLink="false">7uf0jVn0IMKFbqLxWODDNM</guid>
            <dc:creator>Lucas Pardue</dc:creator>
            <dc:creator>Christopher Wood</dc:creator>
        </item>
        <item>
            <title><![CDATA[A Primer on Proxies]]></title>
            <link>https://blog.cloudflare.com/a-primer-on-proxies/</link>
            <pubDate>Sat, 19 Mar 2022 17:01:15 GMT</pubDate>
            <description><![CDATA[ A technical dive into traditional TCP proxying over HTTP ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4icLjzJ8inC97t9zh3LiWw/e0e75625752de444e0fd2a32f627112e/image2-73.png" />
            
            </figure><p>Traffic proxying, the act of encapsulating one flow of data inside another, is a valuable privacy tool for establishing boundaries on the Internet. Encapsulation has an overhead, Cloudflare and our Internet peers strive to avoid turning it into a performance cost. MASQUE is the latest collaboration effort to design efficient proxy protocols based on IETF standards. We're already running these at scale in production; see our recent blog post about Cloudflare's role in <a href="/icloud-private-relay/">iCloud Private Relay</a> for an example.</p><p>In this blog post series, we’ll dive into proxy protocols.</p><p>To begin, let’s start with a simple question: what is proxying? In this case, we are focused on <b>forward</b> proxying — a client establishes an end-to-end tunnel to a target server via a proxy server. This contrasts with the Cloudflare CDN, which operates as a <a href="https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/"><b>reverse</b></a> <a href="https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/">proxy</a> that terminates client connections and then takes responsibility for actions such as caching, security including <a href="https://www.cloudflare.com/learning/ddos/glossary/web-application-firewall-waf/">WAF</a>, load balancing, etc. With forward proxying, the details about the tunnel, such as how it is established and used, whether it provides confidentiality via authenticated encryption, and so on, vary by proxy protocol. Before going into specifics, let’s start with one of the most common tunnels used on the Internet: TCP.</p>
    <div>
      <h3>Transport basics: TCP provides a reliable byte stream</h3>
      <a href="#transport-basics-tcp-provides-a-reliable-byte-stream">
        
      </a>
    </div>
    <p>The TCP transport protocol is a rich topic. For the purposes of this post, we will focus on one aspect: TCP provides a readable and writable, reliable, and ordered byte stream. Some protocols like HTTP and TLS require reliable transport underneath them and TCP's single byte stream is an ideal fit. The application layer reads or writes to this byte stream, but the details about how TCP sends this data "on the wire" are typically abstracted away.</p><p>Large application objects are written into a stream, then they are split into many small packets, and they are sent in order to the network. At the receiver, packets are read from the network and combined back into an identical stream. Networks are not perfect and packets can be lost or reordered. TCP is clever at dealing with this and not worrying the application with details. It just works. A way to visualize this is to imagine a magic paper shredder that can both shred documents and convert shredded papers back to whole documents. Then imagine you and your friend bought a pair of these and decided that it would be fun to send each other shreds.</p><p>The one problem with TCP is that when a lost packet is detected at a receiver, the sender needs to retransmit it. This takes time to happen and can mean that the byte stream reconstruction gets delayed. This is known as TCP head-of-line blocking. Applications regularly use TCP via a socket API that abstracts away protocol details; they often can't tell if there are delays because the other end is slow at sending or if the network is slowing things down via packet loss.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/xnUbBQnb4droA0xmJMJ69/c07b46a941cdc3a7cbb75dc696050f38/image1-84.png" />
            
            </figure>
    <div>
      <h3>Proxy Protocols</h3>
      <a href="#proxy-protocols">
        
      </a>
    </div>
    <p>Proxying TCP is immensely useful for many applications, including, though certainly not limited to HTTPS, <a href="https://www.cloudflare.com/learning/access-management/what-is-ssh/">SSH</a>, and RDP. In fact, <a href="/oblivious-dns/">Oblivious DoH</a>, which is a proxy protocol for DNS messages, could very well be implemented using a TCP proxy, though there are reasons <a href="https://datatracker.ietf.org/doc/html/draft-pauly-dprive-oblivious-doh-11#appendix-A">why this may not be desirable</a>. Today, there are a number of different options for proxying TCP end-to-end, including:</p><ul><li><p>SOCKS, which runs in cleartext and requires an expensive connection establishment step.</p></li><li><p>Transparent TCP proxies, commonly referred to as performance enhancing proxies (PEPs), which must be on path and offer no additional transport security, and, definitionally, are limited to TCP protocols.</p></li><li><p>Layer 4 proxies such as Cloudflare <a href="https://developers.cloudflare.com/spectrum/">Spectrum</a>, which might rely on side carriage metadata via something like the <a href="https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt">PROXY protocol</a>.</p></li><li><p>HTTP CONNECT, which transforms HTTPS connections into opaque byte streams.</p></li></ul><p>While SOCKS and PEPs are viable options for some use cases, when choosing which proxy protocol to build future systems upon, it made most sense to choose a reusable and general-purpose protocol that provides well-defined and standard abstractions. As such, the IETF chose to focus on using HTTP as a substrate via the CONNECT method.</p><p>The concept of using HTTP as a substrate for proxying is not new. Indeed, HTTP/1.1 and HTTP/2 have supported proxying TCP-based protocols for a long time. In the following sections of this post, we’ll explain in detail how CONNECT works across different versions of HTTP, including HTTP/1.1, HTTP/2, and the <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">recently standardized HTTP/3</a>.</p>
    <div>
      <h3>HTTP/1.1 and CONNECT</h3>
      <a href="#http-1-1-and-connect">
        
      </a>
    </div>
    <p>In HTTP/1.1, the <a href="https://www.rfc-editor.org/rfc/rfc7231#section-4.3.6">CONNECT method</a> can be used to establish an end-to-end TCP tunnel to a target server via a proxy server. This is commonly applied to use cases where there is a benefit of protecting the traffic between the client and the proxy, or where the proxy can provide access control at network boundaries. For example, a Web browser can be configured to issue all of its HTTP requests via an HTTP proxy.</p><p>A client sends a CONNECT request to the proxy server, which requests that it opens a TCP connection to the target server and desired port. It looks something like this:</p>
            <pre><code>CONNECT target.example.com:80 HTTP/1.1
Host: target.example.com</code></pre>
            <p>If the proxy succeeds in opening a TCP connection to the target, it responds with a 2xx range status code. If there is some kind of problem, an error status in the 5xx range can be returned. Once a tunnel is established there are two independent TCP connections; one on either side of the proxy. If a flow needs to stop, you can simply terminate them.</p><p>HTTP CONNECT proxies forward data between the client and the target server. The TCP packets themselves are not tunneled, only the data on the logical byte stream. Although the proxy is supposed to forward data and not process it, if the data is plaintext there would be nothing to stop it. In practice, CONNECT is often used to create an end-to-end TLS connection where only the client and target server have access to the protected content; the proxy sees only TLS records and can't read their content because it doesn't have access to the keys.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1ParPDOxCyJFT2m3UYsLtR/d76fbce62a99c53fa68bc86773c231bd/image8-1.png" />
            
            </figure><p>Finally, it's worth noting that after a successful CONNECT request, the HTTP connection (and the TCP connection underpinning it) has been converted into a tunnel. There is no more possibility of issuing other HTTP messages, to the proxy itself, on the connection.</p>
    <div>
      <h3>HTTP/2 and CONNECT</h3>
      <a href="#http-2-and-connect">
        
      </a>
    </div>
    <p><a href="https://www.rfc-editor.org/rfc/rfc7540.html">HTTP/2</a> adds logical streams above the TCP layer in order to support concurrent requests and responses on a single connection. Streams are also reliable and ordered byte streams, operating on top of TCP. Returning to our magic shredder analogy: imagine you wanted to send a book. Shredding each page one after another and rebuilding the book one page at a time is slow, but handling multiple pages at the same time might be faster. HTTP/2 streams allow us to do that. But, as we all know, trying to put too much into a shredder can sometimes cause it to jam.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/37F1LF53K2Plk0vYbcdmgg/d7d57e19b13ebce0aabb910568f4d9f6/image3-33.png" />
            
            </figure><p>In HTTP/2, each request and response is sent on a different stream. To support this, HTTP/2 defines frames that contain the stream identifier that they are associated with. Requests and responses are composed of HEADERS and DATA frames which contain HTTP header fields and HTTP content, respectively. Frames can be large. When they are sent on the wire they might span multiple TLS records or TCP segments. Side note: the HTTP WG has been working on a new revision of the document that defines HTTP semantics that are common to all HTTP versions. The terms message, header fields, and content all come from <a href="https://www.ietf.org/archive/id/draft-ietf-httpbis-semantics-19.html#name-message-abstraction">this description</a>.</p><p>HTTP/2 concurrency allows applications to read and write multiple objects at different rates, which can improve HTTP application performance, such as web browsing. HTTP/1.1 traditionally dealt with this concurrency by opening multiple TCP connections in parallel and striping requests across these connections. In contrast, HTTP/2 multiplexes frames belonging to different streams onto the single byte stream provided by one TCP connection. Reusing a single connection has benefits, but it still leaves HTTP/2 at risk of TCP head-of-line blocking. For more details, refer to <a href="https://calendar.perfplanet.com/2020/head-of-line-blocking-in-quic-and-http-3-the-details/">Perf Planet blog</a>.</p><p><a href="https://datatracker.ietf.org/doc/html/rfc7540#section-8.3">HTTP/2 also supports the CONNECT method</a>. In contrast to HTTP/1.1, CONNECT requests do not take over an entire HTTP/2 connection. Instead, they convert a single stream into an end-to-end tunnel. It looks something like this:</p>
            <pre><code>:method = CONNECT
:authority = target.example.com:443</code></pre>
            <p>If the proxy succeeds in opening a TCP connection, it responds with a 2xx (Successful) status code. After this, the client sends DATA frames to the proxy, and the content of these frames are put into TCP packets sent to the target. In the return direction, the proxy reads from the TCP byte stream and populates DATA frames. If a tunnel needs to stop, you can simply terminate the stream; there is no need to terminate the HTTP/2 connection.</p><p>By using HTTP/2, a client can create multiple CONNECT tunnels in a single connection. This can help reduce resource usage (saving the global count of TCP connections) and allows related tunnels to be logically grouped together, ensuring that they "share fate" when either client or proxy need to gracefully close. On the proxy-to-server side there are still multiple independent TCP connections.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2zNstK2cYrqJKofOIiOeII/2c4bda54b181ce6c171b264589511421/image7.png" />
            
            </figure><p>One challenge of multiplexing tunnels on concurrent streams is how to effectively prioritize them. We've talked in the past about <a href="/better-http-2-prioritization-for-a-faster-web/">prioritization for web pages</a>, but the story is a bit different for CONNECT. We've been thinking about this and captured <a href="https://httpwg.org/http-extensions/draft-ietf-httpbis-priority.html#name-scheduling-and-the-connect-">considerations</a> in the new <a href="/adopting-a-new-approach-to-http-prioritization/">Extensible Priorities</a> draft.</p>
    <div>
      <h3>QUIC, HTTP/3 and CONNECT</h3>
      <a href="#quic-http-3-and-connect">
        
      </a>
    </div>
    <p>QUIC is a new secure and multiplexed transport protocol from the IETF. QUIC version 1 was published as <a href="https://www.rfc-editor.org/rfc/rfc9000.html">RFC 9000</a> in May 2021 and, <a href="/quic-version-1-is-live-on-cloudflare/">the next day</a>, we enabled it for all Cloudflare customers.</p><p>QUIC is composed of several foundational features. You can think of these like individual puzzle pieces that interlink to form a transport service. This service needs one more piece, an application mapping, to bring it all together.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7gGK0LOkLSU64zmxkd9gVd/d02d3a3f1f7e13d7c2819342f61f6a4a/image4-15.png" />
            
            </figure><p>Similar to HTTP/2, QUIC version 1 provides reliable and ordered streams. But QUIC streams live at the transport layer and they are the only type of QUIC primitive that can carry application data. QUIC has no opinion on how streams get used. Applications that wish to use QUIC must define that themselves.</p><p>QUIC streams can be long (up to 2^62 - 1 bytes). Stream data is sent on the wire in the form of <a href="https://www.rfc-editor.org/rfc/rfc9000.html#name-stream-frames">STREAM frames</a>. All QUIC frames must fit completely inside a QUIC packet. QUIC packets must fit entirely in a UDP datagram; fragmentation is prohibited. These requirements mean that a long stream is serialized to a series of QUIC packets sized roughly to the path <a href="https://en.wikipedia.org/wiki/Maximum_transmission_unit">MTU</a> (Maximum Transmission Unit). STREAM frames provide reliability via QUIC loss detection and recovery. Frames are acknowledged by the receiver and if the sender detects a loss (via missing acknowledgments), QUIC will retransmit the lost data. In contrast, TCP retransmits packets. This difference is an important feature of QUIC, letting implementations decide how to repacketize and reschedule lost data.</p><p>When multiplexing streams, different packets can contain <a href="https://www.rfc-editor.org/rfc/rfc9000.html#name-stream-frames">STREAM frames</a> belonging to different stream identifiers. This creates independence between streams and helps avoid the head-of-line blocking caused by packet loss that we see in TCP. If a UDP packet containing data for one stream is lost, other streams can continue to make progress without being blocked by retransmission of the lost stream.</p><p>To use our magic shredder analogy one more time: we're sending a book again, but this time we parallelise our task by using independent shredders. We need to logically associate them together so that the receiver knows the pages and shreds are all for the same book, but otherwise they can progress with less chance of jamming.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2KPS4I6E6zvfPnrY4zNlxB/912d09cf787fa46d6dc77140919ba607/image6-5.png" />
            
            </figure><p><a href="https://datatracker.ietf.org/doc/draft-ietf-quic-http/">HTTP/3</a> is an example of an application mapping that describes how streams are used to exchange: HTTP settings, <a href="https://datatracker.ietf.org/doc/html/draft-ietf-quic-qpack-21">QPACK</a> state, and request and response messages. HTTP/3 still defines its own frames like HEADERS and DATA, but it is overall simpler than HTTP/2 because QUIC deals with the hard stuff. Since HTTP/3 just sees a logical byte stream, its frames can be arbitrarily sized. The QUIC layer handles segmenting HTTP/3 frames over STREAM frames for sending in packets. HTTP/3 <a href="https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#section-4.2">also supports the CONNECT method</a>. It functions identically to CONNECT in HTTP/2, each request stream converting to an end-to-end tunnel.</p>
    <div>
      <h3>HTTP packetization comparison</h3>
      <a href="#http-packetization-comparison">
        
      </a>
    </div>
    <p>We've talked about HTTP/1.1, HTTP/2 and HTTP/3. The diagram below is a convenient way to summarize how HTTP requests and responses get serialized for transmission over a secure transport. The main difference is that with TLS, protected records are split across several TCP segments. While with QUIC there is no record layer, each packet has its own protection.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2Ixri8ytJ113sldUVNplLm/47ffbc388a4a45ae481a78e39b2986a0/image5-18.png" />
            
            </figure>
    <div>
      <h3>Limitations and looking ahead</h3>
      <a href="#limitations-and-looking-ahead">
        
      </a>
    </div>
    <p>HTTP CONNECT is a simple and elegant protocol that has a tremendous number of application use cases, especially for privacy-enhancing technology. In particular, applications can use it to proxy <a href="https://www.cloudflare.com/learning/dns/dns-over-tls/">DNS-over-HTTPS</a> similar to what’s been done for Oblivious DoH, or more generic HTTPS traffic (based on HTTP/1.1 or HTTP/2), and many more.</p><p>However, what about non-TCP traffic? Recall that HTTP/3 is an application mapping for QUIC, and therefore runs over UDP as well. What if we wanted to proxy QUIC? What if we wanted to proxy entire IP datagrams, similar to VPN technologies like IPsec or WireGuard? This is where <a href="/unlocking-quic-proxying-potential/">MASQUE</a> comes in. In the next post, we’ll discuss how the <a href="https://datatracker.ietf.org/wg/masque/about/">MASQUE Working Group</a> is standardizing technologies to enable proxying for datagram-based protocols like UDP and IP.</p> ]]></content:encoded>
            <category><![CDATA[Deep Dive]]></category>
            <category><![CDATA[TCP]]></category>
            <category><![CDATA[Proxying]]></category>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[iCloud Private Relay]]></category>
            <guid isPermaLink="false">2YU980GMLipuAmzDuDgrTc</guid>
            <dc:creator>Lucas Pardue</dc:creator>
            <dc:creator>Christopher Wood</dc:creator>
        </item>
        <item>
            <title><![CDATA[QUIC Version 1 is live on Cloudflare]]></title>
            <link>https://blog.cloudflare.com/quic-version-1-is-live-on-cloudflare/</link>
            <pubDate>Fri, 28 May 2021 21:06:55 GMT</pubDate>
            <description><![CDATA[ QUIC is a new fast and secure transport protocol. Version 1 has just been published as RFC 9000 and today Cloudflare has enabled support for all customers, come try it out.    ]]></description>
            <content:encoded><![CDATA[ <p></p><p>On May 27, 2021, the Internet Engineering Task Force published RFC 9000 - the standardized version of the QUIC transport protocol. The QUIC Working Group declared themselves done by issuing a <a href="/last-call-for-quic/">Last Call</a> 7 months ago. The i's have been dotted and the t's crossed, RFC 8999 - RFC 9002 are a suite of documents that capture years of engineering design and testing of QUIC. This marks a big occasion.</p><p>And today, one day later, we’ve made the standardized version of QUIC available to Cloudflare customers.</p><p>Transport protocols have a history of being hard to deploy on the Internet. QUIC overcomes this challenge by basing itself on top of UDP. Compared to TCP, QUIC has security by default, protecting almost all bytes from prying eyes or "helpful" middleboxes that can end up making things worse. It has designed-in features that speed up connection handshakes and mitigate the performance perils that can strike on networks that suffer loss or delays. It is pluggable, providing clear standardised extensions point that will allow smooth, iterative development and deployment of new features or performance enhancements for years to come.</p><p>The killer feature of QUIC, however, is that it is deployable in reality. We are excited to announce that QUIC version 1, <a href="https://www.rfc-editor.org/rfc/rfc9000.html">RFC 9000</a>, is available to all Cloudflare customers.  We started with a <a href="/the-quicening/">limited beta in 2018</a>, we made it <a href="/http3-the-past-present-and-future/">general availability in 2019</a>, and we've been tracking new document revisions every step of the way. In that time we've seen User-Agents like browsers join us in this merry march and prove that this thing works on the Internet.</p><p>QUIC is just a transport protocol. To make it do anything you need an application protocol to be mapped onto it. In parallel to the QUIC specification, the Working Group has defined an HTTP mapping called <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a>. The design is all done, but we're waiting for a few more i's to be crossed before it too is published as an RFC. That doesn't prevent people from testing it though, and for the 3+ years that we've supported QUIC, we have supported HTTP on the top of it.</p><p>According to <a href="https://radar.cloudflare.com/">Cloudflare Radar</a>, we're seeing around 12% of Internet traffic using QUIC with HTTP/3 already. We look forward to this increasing now that RFC 9000 is out and raising awareness of the stability of things.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/44hkcMdHbgfl5XZk42hRUv/328f93d4e472216c75880da4db50b60a/image3-8.png" />
            
            </figure>
    <div>
      <h2>How do I enable QUIC and HTTP/3 for my domain?</h2>
      <a href="#how-do-i-enable-quic-and-http-3-for-my-domain">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4CC9znbBgFKJGTw6QN8YOL/094c27a60a4b9c4271d4b6cc6b610dcb/image4-12.png" />
            
            </figure><p>HTTP/3 and QUIC are controlled from the "Network" tab of your dashboard. Turn it on and start testing.</p>
    <div>
      <h2>But what does that actually do?</h2>
      <a href="#but-what-does-that-actually-do">
        
      </a>
    </div>
    <p>Cloudflare servers sit and listen for QUIC traffic on UDP port 443. Clients send an Initial QUIC packet in a UDP datagram which kicks off the handshake process. The Initial packet contains a version identifier, which the server checks and selects from. The client also provides, via the TLS Application Layer Negotiation Protocol extension, a list of application protocols it speaks. Today Cloudflare supports clients that directly connect to us and attempt to speak QUIC version 1 using the ALPN identifier "h3".</p><p>Over the years, as the draft wire format of the protocol has changed, new version and ALPN identifiers have been coined, helping to ensure the client and server pick something they can agree on. RFC 9000 coins the version 0x00000001. Since it's so new, we expect clients to continue sending some of the old ones as it takes time to support. These look like 0xff00001d, 0xff00001c, and 0xff00001b, which mark draft 29, 28, and 27 respectively. Version identifiers are 32-bits, which is conspicuous because a lot of other fields use QUICs <i>variable-length integer encoding</i> (<a href="https://www.rfc-editor.org/rfc/rfc9000.html#name-variable-length-integer-enc">see here</a>).</p><p>Before a client can even send an Initial QUIC packet however, it needs to know we're sat here listening for them! In the old days, HTTP relied on the URL to determine which TCP port to speak to. By default, it picked 80 for an http scheme, 443 for an https scheme, or used the value supplied in the authority component e.g. <a href="https://example.com:1234">https://example.com:1234</a>. Nobody wanted to change the URL schemes to support QUIC; that would have added tremendous friction to deployment.</p><p>While developing QUIC and HTTP/3, the Working Group generally relied on prior knowledge that a server would talk QUIC. And if something went wrong, we'd just ping each other directly on Slack. This kind of model obviously doesn't scale. For widespread real-world deployment we instead rely on HTTP Alternative Services (RFC 7838) to tell TCP-based clients that HTTP/3 is available. This is the method that web browsers will use to determine what protocols to use.When a client makes HTTP requests to a zone that has Cloudflare QUIC and HTTP/3 support enabled, we return an Alt-Svc header that tells it about all the QUIC versions we support. Here's an example:</p>
            <pre><code>$ curl -sI https://www.cloudflare.com/ | grep alt-svc
alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400</code></pre>
            <p>The entry "h3-29" tells clients that we support HTTP/3 over QUIC draft version 29 on UDP port 443. If they support that they might just send us a QUIC Initial with the single version <b>0xff00001</b> and identifier "h3-29". Or to hedge their bets, they might send an initial with all versions that they support. Whichever type of Initial Cloudflare receives, we'll pick the highest version. They also might choose _not_ to use QUIC, for whatever reason they like, in which case they can just carry on as normal.</p><p>Previously, you needed to <a href="/how-to-test-http-3-and-quic-with-firefox-nightly/">enable experimental support</a> if you wanted to test it out in browsers. But now many of them have QUIC enabled by default and we expect them to start enabling QUIC v1 support soon. So today we've begun rolling out changes to our Alt-Svc advertisements to also include the "h3" identifier and we'll have complete world-wide support early next week. All of these protocol upgrade behaviours are done behind the scenes, hopefully your browsing experiences just appear to get magically faster. If you want to check what's happening, you can, for example, use a browser's network tools - just be sure to enable the Protocol column. Here's how it looks in Firefox:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/40t2IICcOJjpNbYclJVm3N/9b3390d0b88137917610abeb140e56da/image2-8.png" />
            
            </figure>
    <div>
      <h2>All powered by delicious Quiche!</h2>
      <a href="#all-powered-by-delicious-quiche">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4uiSku4MIBNz7VHzAR1H5B/e28eb3e55adb5be7f6d204168662db98/image5-5.png" />
            
            </figure><p>Cloudflare's QUIC and HTTP/3 support is powered by quiche, <a href="/enjoy-a-slice-of-quic-and-rust/">our own open-source implementation written in Rust</a>. You can find it on GitHub at <a href="https://github.com/cloudflare/quiche">github.com/cloudflare/quiche</a>.</p><p>Quiche is a Rust library that exposes a C API. We've designed it from day one to be easily integratable into many types of projects. Our <a href="/experiment-with-http-3-using-nginx-and-quiche/">edge servers</a> use it, <a href="https://developers.cloudflare.com/http3/curl-brew">curl uses it</a>, Mozilla uses our <a href="https://crates.io/crates/qlog">qlog</a> sub-crate in <a href="https://github.com/mozilla/neqo">neqo</a> (which powers Firefox's QUIC), <a href="https://github.com/netty/netty-incubator-codec-quic">netty uses it</a>, the list is quite long. We're excited to support this project and grow support for QUIC and HTTP/3 wherever we can. And it won't surprise you to hear that we have built some of our own tools to help us during development. quiche-client is a tool we use to get detailed information on all the nitty gritty details of QUIC connections. It also integrates into the <a href="https://interop.seemann.io/">interoperability testing matrix</a> that lets us continually assess interoperability and performance.</p><p>You can find <a href="https://developers.cloudflare.com/http3/quiche-http3-client">quiche-client</a> in the <a href="https://github.com/cloudflare/quiche/tree/master/tools">/tools folder</a> of the quiche repository. Here's an example of running it with all trace information turned on, I've highlighted the Initial version and selected ALPN. A corresponding client-{connection ID}.qlog file will be written out.</p>
            <pre><code>RUST_LOG=trace QLOG_DIR=$PWD cargo run --manifest-path tools/apps/Cargo.toml --bin quiche-client -- --wire-version 00000001  https://www.cloudflare.com

[2021-05-28T18:59:30.506616991Z INFO  quiche_apps::client] connecting to 104.16.123.96:443 from 192.168.0.50:41238 with scid 5875ecd13154429e5c618eee35b6bbd9ecfe8c6b
[2021-05-28T18:59:30.506842369Z TRACE quiche::tls] 5875ecd13154429e5c618eee35b6bbd9ecfe8c6b write message lvl=Initial len=310
[2021-05-28T18:59:30.506891348Z TRACE quiche] 5875ecd13154429e5c618eee35b6bbd9ecfe8c6b tx pkt Initial version=1 dcid=ed8de2d33a2e830279dfeaae8a7ad674 scid=5875ecd13154429e5c618eee35b6bbd9ecfe8c6b len=330 pn=0
[2021-05-28T18:59:30.506982912Z TRACE quiche] 5875ecd13154429e5c618eee35b6bbd9ecfe8c6b tx frm CRYPTO off=0 len=310
[2021-05-28T18:59:30.507044916Z TRACE quiche::recovery] 5875ecd13154429e5c618eee35b6bbd9ecfe8c6b timer=998.815785ms latest_rtt=0ns srtt=None min_rtt=0ns rttvar=166.5ms loss_time=[None, None, None] loss_probes=[0, 0, 0] cwnd=13500 ssthresh=18446744073709551615 bytes_in_flight=377 app_limited=true congestion_recovery_start_time=None delivered=0 delivered_time=204.765µs recent_delivered_packet_sent_time=206.283µs app_limited_at_pkt=0  pacing_rate=0 last_packet_scheduled_time=Some(Instant { tv_sec: 620877, tv_nsec: 428024928 }) hystart=window_end=None last_round_min_rtt=None current_round_min_rtt=None rtt_sample_count=0 lss_start_time=None  
[2021-05-28T18:59:30.507160963Z TRACE quiche_apps::client] written 1200
[2021-05-28T18:59:30.537123997Z TRACE quiche_apps::client] got 1200 bytes
[2021-05-28T18:59:30.537194566Z TRACE quiche] 5875ecd13154429e5c618eee35b6bbd9ecfe8c6b rx pkt Initial version=1 dcid=5875ecd13154429e5c618eee35b6bbd9ecfe8c6b scid=017022e8618952fd8c7177e863894eb0447b85f4 token= len=117 pn=0
&lt;snip&gt;
[2021-05-28T18:59:30.542581460Z TRACE quiche] 5875ecd13154429e5c618eee35b6bbd9ecfe8c6b connection established: proto=Ok("h3") cipher=Some(AES128_GCM) curve=Some("X25519") sigalg=Some("ecdsa_secp256r1_sha256") resumed=false TransportParams { original_destination_connection_id: Some(ed8de2d33a2e830279dfeaae8a7ad674), max_idle_timeout: 180000, stateless_reset_token: None, max_udp_payload_size: 65527, initial_max_data: 10485760, initial_max_stream_data_bidi_local: 0, initial_max_stream_data_bidi_remote: 1048576, initial_max_stream_data_uni: 1048576, initial_max_streams_bidi: 256, initial_max_streams_uni: 3, ack_delay_exponent: 3, max_ack_delay: 25, disable_active_migration: false, active_conn_id_limit: 2, initial_source_connection_id: Some(017022e8618952fd8c7177e863894eb0447b85f4), retry_source_connection_id: None, max_datagram_frame_size: None }</code></pre>
            
    <div>
      <h2>So if QUIC is done, what's next?</h2>
      <a href="#so-if-quic-is-done-whats-next">
        
      </a>
    </div>
    <p>The road has been long, and we should celebrate the success of the community's efforts over many years to dream big and deliver something.  But as far as we're concerned, we're far from done. We've learned a lot from our early QUIC deployments - a big thank you to everyone in the wider Cloudflare team that supported the Protocols team getting here today. We'll continue to invest that back into our implementation and standardisation activities. <a href="/author/alessandro-ghedini/">Alessandro</a>, <a href="/author/junho/">Junho</a>, <a href="/author/lohith/">Lohith</a> and I will continue to participate in our respective areas of expertise in the IETF. Speaking for myself, I'll be continuing to co-chair the QUIC Working Group and help guide it through a new chapter focused on maintenance, operations, extensibility and… QUIC version 2. And I'll be moonlighting in other places like the <a href="https://datatracker.ietf.org/wg/httpbis/about/">HTTP</a> WG to push Prioritization over the line, and the <a href="https://datatracker.ietf.org/wg/masque/about/">MASQUE</a> WG to help define how we can use <a href="https://datatracker.ietf.org/doc/html/draft-ietf-masque-h3-datagram-02">unreliable DATAGRAMS</a> to tunnel almost anything over QUIC and HTTP/3.</p>
    <div>
      <h2>A weekend riddle</h2>
      <a href="#a-weekend-riddle">
        
      </a>
    </div>
    <p>If you've made it this far, you are obviously very interested in QUIC. My colleague, Chris Wood, is like that too. He was very excited about the RFCs being shipped. So excited that he sent me this cryptic message:</p><p><i>"QUIC is finally here -- RFC </i><b><i>8999</i></b><i>, 9000, </i><b><i>9001</i></b><i>, and 9002. Are we and the rest of the Internet ready to turn it on? 0404d3f63f040214574904010a5735!</i></p><p>I have no clue what this means, can you help me out?</p> ]]></content:encoded>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[IETF]]></category>
            <guid isPermaLink="false">jMlsubMfOLintHjT8HGts</guid>
            <dc:creator>Lucas Pardue</dc:creator>
        </item>
        <item>
            <title><![CDATA[A Last Call for QUIC, a giant leap for the Internet]]></title>
            <link>https://blog.cloudflare.com/last-call-for-quic/</link>
            <pubDate>Thu, 22 Oct 2020 14:08:51 GMT</pubDate>
            <description><![CDATA[ QUIC and HTTP/3 are open standards that have been under development in the IETF for almost exactly 4 years. On October 21, 2020, following two rounds of Working Group Last Call, draft 32 of the family of documents that describe QUIC and HTTP/3 were put into IETF Last Call. ]]></description>
            <content:encoded><![CDATA[ <p>QUIC is a new Internet transport protocol for secure, reliable and multiplexed communications. <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a> builds on top of QUIC, leveraging the new features to fix performance problems such as Head-of-Line blocking. This enables web pages to load faster, especially over troublesome networks.</p><p>QUIC and HTTP/3 are open standards that have been under development in the IETF <a href="/http-3-from-root-to-tip">for almost exactly 4 years</a>. On October 21, 2020, following two rounds of Working Group Last Call, draft 32 of the family of documents that describe QUIC and HTTP/3 were put into <a href="https://mailarchive.ietf.org/arch/msg/quic/ye1LeRl7oEz898RxjE6D3koWhn0/">IETF Last Call</a>. This is an important milestone for the group. We are now telling the entire IETF community that we think we're almost done and that we'd welcome their final review.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/78vaeSkXoriOtIbPyOU5rw/8ce2942b6542d94b5d0d42fc9e91d7b7/image2-24.png" />
            
            </figure><p>Speaking personally, I've been involved with QUIC in some shape or form for many years now. Earlier this year I was honoured to be asked to help co-chair the Working Group. I'm pleased to help shepherd the documents through this important phase, and grateful for the efforts of everyone involved in getting us there, especially the editors. I'm also excited about future opportunities to evolve on top of QUIC v1 to help build a better Internet.</p><p>There are two aspects to protocol development. One aspect involves writing and iterating upon the documents that describe the protocols themselves. Then, there's implementing, deploying and testing libraries, clients and/or servers. These aspects operate hand in hand, helping the Working Group move towards satisfying the goals listed in its charter. IETF Last Call marks the point that the group and their responsible Area Director (in this case Magnus Westerlund) believe the job is almost done. Now is the time to solicit feedback from the wider IETF community for review. At the end of the Last Call period, the stakeholders will take stock, address feedback as needed and, fingers crossed, go onto the next step of requesting the documents be published as RFCs on the Standards Track.</p><p>Although specification and implementation work hand in hand, they often progress at different rates, and that is totally fine. The QUIC specification has been mature and deployable for a long time now. HTTP/3 has been <a href="/http3-the-past-present-and-future/">generally available</a> on the Cloudflare edge since September 2019, and we've been delighted to see support roll out in user agents such as Chrome, Firefox, Safari, curl and so on. Although draft 32 is the latest specification, the community has for the time being settled on draft 29 as a solid basis for interoperability. This shouldn't be surprising, as foundational aspects crystallize the scope of changes between iterations decreases. For the average person in the street, there's not really much difference between 29 and 32.</p><p>So today, if you visit a website with HTTP/3 enabled—such as <a href="https://cloudflare-quic.com">https://cloudflare-quic.com</a>—you’ll probably see response headers that contain Alt-Svc: h3-29="… . And in a while, once Last Call completes and the RFCs ship, you'll start to see websites simply offer Alt-Svc: h3="… (note, no draft version!).</p>
    <div>
      <h3>Need a deep dive?</h3>
      <a href="#need-a-deep-dive">
        
      </a>
    </div>
    <p>We've collected a bunch of resource links at <a href="https://cloudflare-quic.com">https://cloudflare-quic.com</a>. If you're more of an interactive visual learner, you might be pleased to hear that I've also been hosting a series on <a href="https://cloudflare.tv/live">Cloudflare TV</a> called "Levelling up Web Performance with HTTP/3". There are over 12 hours of content including the basics of QUIC, ways to measure and debug the protocol in action using tools like Wireshark, and several deep dives into specific topics. I've also been lucky to have some guest experts join me along the way. The table below gives an overview of the episodes that are available on demand.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/41Oavd19lBk474V1BOr1ZQ/3b6d0466c42b3940e6329c754c63863d/image1-36.png" />
            
            </figure><p>Episode</p><p>Description</p><p><a href="https://cloudflare.tv/event/6jJjzbBoFwvARsoaNiUt9i">1</a></p><p>Introduction to QUIC.</p><p><a href="https://cloudflare.tv/event/5rcGVibHCKs9l9xUUMdJqg">2</a></p><p>Introduction to HTTP/3.</p><p><a href="https://cloudflare.tv/event/3OM7upT7p3vpAdzphFdhnx">3</a></p><p>QUIC &amp; HTTP/3 logging and analysis using qlog and qvis. Featuring Robin Marx.</p><p><a href="https://cloudflare.tv/event/45tQd4UPkZGULg59BZPl1p">4</a></p><p>QUIC &amp; HTTP/3 packet capture and analysis using Wireshark. Featuring Peter Wu.</p><p><a href="https://cloudflare.tv/event/4YgvMrif2yma7pM6Srv6wi">5</a></p><p>The roles of Server Push and Prioritization in HTTP/2 and HTTP/3. Featuring Yoav Weiss.</p><p><a href="https://cloudflare.tv/event/7ufIyfjZfn2aQ2K635EH3t">6</a></p><p>"After dinner chat" about curl and QUIC. Featuring Daniel Stenberg.</p><p><a href="https://cloudflare.tv/event/6vMyFU2jyx2iKXZVp7YjHW">7</a></p><p>Qlog vs. Wireshark. Featuring Robin Marx and Peter Wu.</p><p><a href="https://cloudflare.tv/event/3miIPtXnktpzjslJlnkD9c">8</a></p><p>Understanding protocol performance using WebPageTest. Featuring Pat Meenan and Andy Davies.</p><p><a href="https://cloudflare.tv/event/6Qv7zmY2oi6j28M5HZNZmV">9</a></p><p>Handshake deep dive.</p><p><a href="https://cloudflare.tv/event/3gqUUBcl40LvThxO7UQH0T">10</a></p><p>Getting to grips with quiche, Cloudflare's QUIC and HTTP/3 library.</p><p><a href="https://cloudflare.tv/event/3Mrq6DHoA9fy4ATT3Wigrv">11</a></p><p>A review of SIGCOMM's EPIQ workshop on evolving QUIC.</p><p><a href="https://cloudflare.tv/event/CHrSpig5nqKeFGFA3fzLq">12</a></p><p>Understanding the role of congestion control in QUIC. Featuring Junho Choi.</p><p></p>
    <div>
      <h3>Whither QUIC?</h3>
      <a href="#whither-quic">
        
      </a>
    </div>
    <p>So does Last Call mean QUIC is "done"? Not by a long shot. The new protocol is a giant leap for the Internet, because it enables new opportunities and innovation. QUIC v1 is basically the set of documents that have gone into Last Call. We'll continue to see people gain experience deploying and testing this, and no doubt cool blog posts about tweaking parameters for efficiency and performance are on the radar. But QUIC and HTTP/3 are extensible, so we'll see people interested in trying new things like multipath, different congestion control approaches, or new ways to carry data unreliably such as the <a href="https://datatracker.ietf.org/doc/draft-ietf-quic-datagram/">DATAGRAM frame</a>.</p><p>We're also seeing people interested in using QUIC for other use cases. Mapping other application protocols like DNS to QUIC is a rapid way to get its improvements. We're seeing people that want to use QUIC as a substrate for carrying other transport protocols, hence the formation of the <a href="https://datatracker.ietf.org/wg/masque/about/">MASQUE Working Group</a>. There's folks that want to use QUIC and HTTP/3 as a "supercharged WebSocket", hence the formation of the <a href="https://datatracker.ietf.org/wg/webtrans/documents/">WebTransport Working Group</a>.</p><p>Whatever the future holds for QUIC, we're just getting started, and I'm excited.</p> ]]></content:encoded>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[HTTP3]]></category>
            <category><![CDATA[Speed]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[IETF]]></category>
            <guid isPermaLink="false">4kkjRctgxi0uvF46ddKnp6</guid>
            <dc:creator>Lucas Pardue</dc:creator>
        </item>
        <item>
            <title><![CDATA[How to test HTTP/3 and QUIC with Firefox Nightly]]></title>
            <link>https://blog.cloudflare.com/how-to-test-http-3-and-quic-with-firefox-nightly/</link>
            <pubDate>Tue, 30 Jun 2020 11:00:00 GMT</pubDate>
            <description><![CDATA[ Now that Firefox Nightly supports HTTP/3 we thought we'd share some instructions to help you enable and test it yourselves. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6LFuqXEde60ewdAIKCGpBU/bf9372291e6c9ed483d3df9b8d1c2018/HTTP3-partnership-nightly-_3x-1.png" />
            
            </figure><p><a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a> is the third major version of the Hypertext Transfer Protocol, which takes the bold step of moving away from TCP to the new transport protocol QUIC in order to provide performance and security improvements.</p><p>During Cloudflare's Birthday Week 2019, we were <a href="/http3-the-past-present-and-future/">delighted to announce</a> that we had enabled QUIC and HTTP/3 support on the Cloudflare edge network. This was joined by support from Google Chrome and Mozilla Firefox, two of the leading browser vendors and partners in our effort to make the web faster and more reliable for all. A big part of developing new standards is interoperability, which typically means different people analysing, implementing and testing a written specification in order to prove that it is precise, unambiguous, and actually implementable.</p><p>At the time of our announcement, Chrome Canary had experimental HTTP/3 support and we were eagerly awaiting a release of Firefox Nightly. Now that Firefox supports HTTP/3 we thought we'd share some instructions to help you enable and test it yourselves.</p>
    <div>
      <h3>How do I enable HTTP/3 for my domain?</h3>
      <a href="#how-do-i-enable-http-3-for-my-domain">
        
      </a>
    </div>
    <p>Simply go to the Cloudflare dashboard and flip the switch from the "Network" tab manually:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/zkM5pyAf9MD0HhWqueVP3/e4d9d2d8ae7a37b5da5c0bda7e9447e5/http3-toggle-1.png" />
            
            </figure>
    <div>
      <h3>Using Firefox Nightly as an HTTP/3 client</h3>
      <a href="#using-firefox-nightly-as-an-http-3-client">
        
      </a>
    </div>
    <p>Firefox Nightly has experimental support for HTTP/3. In our experience things are pretty good but be aware that you might experience some teething issues, so bear that in mind if you decide to enable and experiment with HTTP/3. If you're happy with that responsibility, you'll first need to download and install the <a href="https://www.mozilla.org/firefox/channel/desktop/">latest Firefox Nightly build</a>. Then open Firefox and enable HTTP/3 by visiting "about:config" and setting "network.http.http3.enabled" to true. There are some other parameters that can be tweaked but the defaults should suffice.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4UGnSGsahi5Qm5bqtL5qho/dfa340c0825d974ae1164bc1e6eaedda/firefox-h3-about-config.png" />
            
            </figure><p>about:config can be filtered by using a search term like "http3".</p><p>Once HTTP/3 is enabled, you can visit your site to test it out. A straightforward way to check if HTTP/3 was negotiated is to check the Developer Tools "Protocol" column in the "Network" tab (on Windows and Linux the Developer Tools keyboard shortcut is Ctrl+Shift+I, on macOS it's Command+Option+I). This "Protocol" column might not be visible at first, so to enable it right-click one of the column headers and check "Protocol" as shown below.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/61omvb6CpN2nUSd6mFvqiB/c0a23a5a0551f5583efa1a5d76f7a94f/firefox-h3-protocol-column.png" />
            
            </figure><p>Then reload the page and you should see that "HTTP/3" is reported.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1Q8evveLC4cyU0PGHISWmJ/58930682b8a9751208a2a6c3845db588/firefox-h3-success.png" />
            
            </figure><p>The aforementioned teething issues might cause HTTP/3 not to show up initially. When you enable HTTP/3 on a zone, we add a header field such as <code><i>alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400</i></code> to all responses for that zone. Clients see this as an advertisement to try HTTP/3 out and will take up the offer on the <b>next</b> request. So to make this happen you can reload the page but make sure that you bypass the local browser cache (via the "Disable Cache" checkbox, or use the Shift-F5 key combo) or else you'll just see the protocol used to fetch the resource the first time around. Finally, Firefox provides the "about:networking" page which provides a list of visited zones and the HTTP version that was used to load them; for example, this very blog.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/72pladWtRSe3QS38rhRR0F/59b97837d711a7f5bad8cf94f1d9cb43/firefox-h3-about-networking.png" />
            
            </figure><p>about:networking contains a table of all visited zones and the connection properties.</p><p>Sometimes browsers can get sticky to an existing HTTP connection and will refuse to start an HTTP/3 connection, this is hard to detect by humans, so sometimes the best option is to close the app completely and reopen it. Finally, we've also seen some interactions with Service Workers that make it appear that a resource was fetched from the network using HTTP/1.1, when in fact it was fetched from the local Service Worker cache. In such cases if you're keen to see HTTP/3 in action then you'll need to deregister the Service Worker. If you're in doubt about what is happening on the network it is often useful to verify things independently, for example capturing a packet trace and dissecting it with Wireshark.</p>
    <div>
      <h2>What’s next?</h2>
      <a href="#whats-next">
        
      </a>
    </div>
    <p>The QUIC Working Group recently <a href="https://mailarchive.ietf.org/arch/msg/quic/F7wvKGnA1FJasmaE35XIxsc2Tno/">announced a "Working Group Last Call"</a>, which marks an important milestone in the continued maturity of the standards. From the announcement:</p><blockquote><p><i>After more than three and a half years and substantial discussion, all 845 of the design issues raised against the QUIC protocol drafts have gained consensus or have a proposed resolution. In that time the protocol has been considerably transformed; it has become more secure, much more widely implemented, and has been shown to be interoperable. Both the Chairs and the Editors feel that it is ready to proceed in standardisation.</i></p></blockquote><p>The coming months will see the specifications settle and we anticipate that implementations will continue to improve their QUIC and HTTP/3 support, eventually enabling it in their stable channels. We're pleased to continue working with <a href="https://www.cloudflare.com/case-studies/mozilla/">industry partners such as Mozilla</a> to help build a better Internet together.</p><p>In the meantime, you might want to <a href="https://developers.cloudflare.com/http3/intro">check out our guides</a> to testing with other implementations such as Chrome Canary or curl. As compatibility becomes proven, implementations will shift towards optimizing their performance; you can read about Cloudflare's efforts on <a href="/http-3-vs-http-2/">comparing HTTP/3 to HTTP/2</a> and the work we've done to improve performance by <a href="/cubic-and-hystart-support-in-quiche/">adding support for CUBIC and HyStart++</a> to our congestion control module.</p> ]]></content:encoded>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[HTTP3]]></category>
            <guid isPermaLink="false">3vxyDdvWdI550GPFsqj0D5</guid>
            <dc:creator>Lucas Pardue</dc:creator>
        </item>
        <item>
            <title><![CDATA[Adopting a new approach to HTTP prioritization]]></title>
            <link>https://blog.cloudflare.com/adopting-a-new-approach-to-http-prioritization/</link>
            <pubDate>Tue, 31 Dec 2019 19:13:58 GMT</pubDate>
            <description><![CDATA[ HTTP prioritization is important for web performance. This is the story behind a new approach recently adopted for further work in the IETF. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Friday the 13th is a lucky day for Cloudflare for <a href="https://twitter.com/eastdakota/status/566276309433602048">many reasons</a>. On December 13, 2019 Tommy Pauly, co-chair of the IETF HTTP Working Group, <a href="https://lists.w3.org/Archives/Public/ietf-http-wg/2019OctDec/0181.html">announced</a> the adoption of the "Extensible Prioritization Scheme for HTTP" - a new approach to HTTP prioritization.</p><p>Web pages are made up of many resources that must be downloaded before they can be presented to the user. The role of HTTP prioritization is to load the right bytes at the right time in order to achieve the best performance. This is a collaborative process between client and server, a client sends priority signals that the server can use to schedule the delivery of response data. In HTTP/1.1 the signal is basic, clients order requests smartly across a pool of about 6 connections. In HTTP/2 a single connection is used and clients send a signal per request, as a frame, which describes the <i>relative dependency and weighting</i> of the response. HTTP/3 tried to use the same approach but dependencies don't work well when signals can be delivered out of order.</p><p><a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a> is being standardised as part of the <a href="/the-road-to-quic/">QUIC</a> effort. As a Working Group (WG) we've been trying to fix the problems that non-deterministic ordering poses for HTTP priorities. However, in parallel some of us have been working on an alternative solution, the Extensible Prioritization Scheme, which fixes problems by dropping dependencies and using an <i>absolute weighting</i>. This is signalled in an HTTP header field meaning it can be backported to work with HTTP/2 or carried over HTTP/1.1 hops. The alternative proposal is documented in the Individual-Draft <a href="https://tools.ietf.org/html/draft-kazuho-httpbis-priority-04">draft-kazuho-httpbis-priority-04</a>, co-authored by Kazuho Oku (Fastly) and myself. This has now been adopted by the IETF HTTP WG as the basis of further work; It's adopted name will be draft-ietf-httpbis-priority-00.</p><p>To some extent document adoption is the end of one journey and the start of the next; sometimes the authors of the original work are not the best people to oversee the next phase. However, I'm pleased to say that Kazuho and I have been selected as co-editors of this new document. In this role we will reflect the consensus of the WG and help steward the next chapter of HTTP prioritization standardisation. Before the next journey begins in earnest, I wanted to take the opportunity to share my thoughts on the story of developing the alternative prioritization scheme through 2019.</p><p>I'd love to explain all the details of this new approach to HTTP prioritization but the truth is I expect the standardization process to refine the design and for things to go stale quickly. However, it doesn't hurt to give a taste of what's in store, just be aware that it is all subject to change.</p>
    <div>
      <h2>A recap on priorities</h2>
      <a href="#a-recap-on-priorities">
        
      </a>
    </div>
    <p>The essence of HTTP prioritization comes down to trying to download many things over constrained connectivity. To borrow some text from Pat Meenan: <i>Web pages are made up of</i> <a href="https://discuss.httparchive.org/t/whats-the-distribution-of-requests-per-page/21/10?u=patmeenan"><i>dozens (sometimes hundreds)</i></a> <i>of separate resources that are loaded and assembled by a browser into the final displayed content.</i> Since it is not possible to download everything immediately, we prefer to fetch more important things before less important ones. The challenge comes in signalling the importance from client to server.</p><p>In HTTP/2, every connection has a priority tree that expresses the relative importance between requests. Servers use this to determine how to schedule sending response data. The tree starts with a single root node and as requests are made they either depend on the root or each other. Servers may use the tree to decide how to schedule sending resources but clients cannot force a server to behave in any particular way.</p><p>To illustrate, imagine a client that makes three simple GET requests that all depend on root. As the server receives each request it grows its view of the priority tree:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2eAdxmuUQxOJLbtqnmP0BS/2379ea92642242d027465218bc39d0bc/treebuilding1.png" />
            
            </figure><p>The server starts with only the root node of the priority tree. As requests arrive, the tree grows. In this case all requests depend on the root, so the requests are priority siblings.</p><p>Once all requests are received, the server determines all requests have equal priority and that it should send response data using <a href="https://en.wikipedia.org/wiki/Round-robin_scheduling">round-robin scheduling</a>: send some fraction of response 1, then a fraction of response 2, then a fraction of response 3, and repeat until all responses are complete.</p><p>A single HTTP/2 request-response exchange is made up of frames that are sent on a stream. A simple GET request would be sent using a single <a href="https://tools.ietf.org/html/rfc7540#section-6.2">HEADERS</a> frame:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/76uj7WpKKMF0lczd3FfkSY/b49c96761908edf66d482859b3cfa62f/H2_HEADERS_frame.png" />
            
            </figure><p>HTTP/2 HEADERS frame, Each region of a frame is a named field</p><p>Each region of a frame is a named field, a '?' indicates the field is optional and the value in parenthesis is the length in bytes with '*' meaning variable length. The <i>Header Block Fragment</i> field holds compressed HTTP header fields (using <a href="/hpack-the-silent-killer-feature-of-http-2/">HPACK</a>), <i>Pad Length</i> and <i>Padding</i> relate to optional padding, and <i>E</i>, <i>Stream Dependency</i> and <i>Weight</i> combined are the priority signal that controls the priority tree.</p><p>The <i>Stream Dependency</i> and <i>Weight</i> fields are optional but their absence is interpreted as a signal to use the default values; dependency on the root with a weight of 16 meaning that the default priority scheduling strategy is round-robin . However, this is often a bad choice because important resources like HTML, CSS and JavaScript are tied up with things like large images. The following animation demonstrates this in the Edge browser, causing the page to be blank for 19 seconds. Our <a href="/better-http-2-prioritization-for-a-faster-web/">deep dive blog post</a> explains the problem further.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/WHsjjksenLoE7ocl8SgRI/d2f8dab33a3688f4357b12b6646cb593/Edge_loading-1.gif" />
            
            </figure><p>The HEADERS frame <i>E</i> field is the interesting bit (pun intended). A request with the field set to 1 (true) means that the dependency is exclusive and nothing else can depend on the indicated node. To illustrate, imagine a client that sends three requests which set the <i>E</i> field to 1. As the server receives each request, it interprets this as an exclusive dependency on the root node. Because all requests have the same dependency on root, the tree has to be shuffled around to satisfy the exclusivity rules.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/i6NA77FtHzckq638a42kh/25013c743bff2c0279d4324f69ee9a64/treebuilding2.png" />
            
            </figure><p>Each request has an exclusive dependency on the root node. The tree is shuffled as each request is received by the server.</p><p>The final version of the tree looks very different from our previous example. The server would schedule all of response 3, then all of response 2, then all of response 1. This could help load all of an HTML file before an image and thus improve the visual load behaviour.</p><p>In reality, clients load a lot more than three resources and use a mix of priority signals. To understand the priority of any single request, we need to understand all requests. That presents some technological challenges, especially for servers that act like proxies such as the Cloudflare edge network. Some servers have <a href="https://github.com/andydavies/http2-prioritization-issues">problems</a> applying prioritization effectively.</p><p>Because not all clients send the most optimal priority signals we were motivated to develop <a href="/better-http-2-prioritization-for-a-faster-web/">Cloudflare's Enhanced HTTP/2 Prioritization</a>, announced last May during <a href="/tag/speed-week/">Speed Week</a>. This was a joint project between the Speed team (Andrew Galloni, Pat Meenan, Kornel Lesiński) and Protocols team (Nick Jones, Shih-Chiang Chien) and others. It replaces the complicated priority tree with a simpler scheme that is well suited to web resources. Because the feature is implemented on the server side, we avoid requiring any modification of clients or the HTTP/2 protocol itself. Be sure to check out my colleague Nick's blog post that details some of the <a href="/nginx-structural-enhancements-for-http-2-performance/">technical challenges and changes</a> needed to let our servers deliver smarter priorities.</p>
    <div>
      <h2>The Extensible Prioritization Scheme proposal</h2>
      <a href="#the-extensible-prioritization-scheme-proposal">
        
      </a>
    </div>
    <p>The scheme specified in <a href="https://tools.ietf.org/html/draft-kazuho-httpbis-priority-04">draft-kazuho-httpbis-priority-04</a>, defines a way for priorities to be expressed in absolute terms. It replaces HTTP/2's dependency-based relative prioritization, the priority of a request is independent of others, which makes it easier to reason about and easier to schedule.</p><p>Rather than send the priority signal in a frame, the scheme defines an HTTP header - tentatively named "Priority" - that can carry an urgency on a scale of 0 (highest) to 7 (lowest). For example, a client could express the priority of an important resource by sending a request with:</p><p><code>Priority: u=0</code></p><p>And a less important background resource could be requested with:</p><p><code>Priority: u=7</code></p><p>While Kazuho and I are the main authors of this specification, we were inspired by several ideas in the Internet community, and we have incorporated feedback or direct input from many of our peers in the Internet community over several drafts. The text today reflects the efforts-so-far of cross-industry work involving many engineers and researchers including organizations such Adobe, Akamai, Apple, Cloudflare, Fastly, Facebook, Google, Microsoft, Mozilla and UHasselt. Adoption in the HTTP Working Group means that we can help improve the design and specification by spending some IETF time and resources for broader discussion, feedback and implementation experience.</p>
    <div>
      <h2>The backstory</h2>
      <a href="#the-backstory">
        
      </a>
    </div>
    <p>I work in Cloudflare's Protocols team which is responsible for terminating HTTP at the edge. We deal with things like TCP, TLS, QUIC, HTTP/1.x, HTTP/2 and HTTP/3 and since joining the company I've worked with Alessandro Ghedini, Junho Choi and Lohith Bellad to make <a href="/http3-the-past-present-and-future/">QUIC and HTTP/3 generally available</a> last September.</p><p>Working on emerging standards is fun. It involves an eclectic mix of engineering, meetings, document review, specification writing, time zones, personalities, and organizational boundaries. So while working on the codebase of <a href="https://github.com/cloudflare/quiche">quiche</a>, our open source implementation of QUIC and HTTP/3, I am also mulling over design details of the protocols and discussing them in cross-industry venues like the IETF.</p><p>Because of <a href="/http-3-from-root-to-tip/">HTTP/3's lineage</a>, it carries over a lot of features from HTTP/2 including the priority signals and tree described earlier in the post.</p><p>One of the key benefits of HTTP/3 is that it is more resilient to the effect of lossy network conditions on performance; head-of-line blocking is limited because requests and responses can progress independently. This is, however, a double-edged sword because sometimes ordering is important. In HTTP/3 there is no guarantee that the requests are received in the same order that they were sent, so the priority tree can get out of sync between client and server. Imagine a client that makes two requests that include priority signals stating request 1 depends on root, request 2 depends on request 1. If request 2 arrives before request 1, the dependency cannot be resolved and becomes dangling. In such a case what is the best thing for a server to do? Ambiguity in behaviour leads to assumptions and disappointment. We should try to avoid that.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/68BpLWmGQLImEc9Bj4BczY/d37a2841eca4bb18f80c473db2e7440f/h3tree.png" />
            
            </figure><p>Request 1 depends on root and request 2 depends on request 1. If an HTTP/3 server receives request 2 first, the dependency cannot be resolved.</p><p>This is just one example where things get tricky quickly. Unfortunately the WG kept finding edge case upon edge case with the priority tree model. We tried to find solutions but each additional fix seemed to create further complexity to the HTTP/3 design. This is a problem because it makes it hard to implement a server that handles priority correctly.</p><p>In parallel to Cloudflare's work on implementing a <a href="/better-http-2-prioritization-for-a-faster-web/">better prioritization for HTTP/2</a>, in January 2019 Pat posted his proposal for an <a href="https://github.com/pmeenan/http3-prioritization-proposal/blob/master/README.md">alternative prioritization scheme for HTTP/3</a> in a <a href="https://lists.w3.org/Archives/Public/ietf-http-wg/2019JanMar/0073.html">message to the IETF HTTP WG</a>.</p><p>Arguably HTTP/2 prioritization never lived up to its hype. However, replacing it with something else in HTTP/3 is a challenge because the QUIC WG charter required us to try and maintain parity between the protocols. Mark Nottingham, co-chair of the HTTP and QUIC WGs <a href="https://lists.w3.org/Archives/Public/ietf-http-wg/2019JanMar/0074.html">responded with</a> a good summary of the situation. To quote part of that response:</p><blockquote><p>My sense is that people know that we need to do something about prioritisation, but we're not yet confident about any particular solution. Experimentation with new schemes as HTTP/2 extensions would be very helpful, as it would give us some data to work with. If you'd like to propose such an extension, this is the right place to do it.</p></blockquote><p>And so started a very interesting year of cross-industry discussion on the future of HTTP prioritization.</p>
    <div>
      <h2>A year of prioritization</h2>
      <a href="#a-year-of-prioritization">
        
      </a>
    </div>
    <p>The following is an account of my personal experiences during 2019. It's been a busy year and there may be unintentional errors or omissions, please let me know if you think that is the case. But I hope it gives you a taste of the standardization process and a look behind the scenes of how new Internet protocols that benefit everyone come to life.</p>
    <div>
      <h3>January</h3>
      <a href="#january">
        
      </a>
    </div>
    <p>Pat's email came at the same time that I was attending the QUIC WG Tokyo interim meeting hosted at Akamai (thanks to Mike Bishop for arrangements). So I was able to speak to a few people face-to-face on the topic. There was a bit of mailing list chatter but it tailed off after a few days.</p>
    <div>
      <h3>February to April</h3>
      <a href="#february-to-april">
        
      </a>
    </div>
    <p>Things remained quiet in terms of prioritization discussion. I knew the next best opportunity to get the ball rolling would be the <a href="https://httpwork.shop/">HTTP Workshop 2019</a> held in April. The workshop is a multi-day event not associated with a standards-defining-organization (even if many of the attendees also go to meetings such as the IETF or W3C). It is structured in a way that allows the agenda to be more fluid than a typical standards meeting and gives plenty of time for organic conversation. This sometimes helps overcome gnarly problems, such as the community finding a path forward for <a href="https://tools.ietf.org/html/rfc8441">WebSockets over HTTP/2</a> due to a productive discussion during the 2017 workshop. HTTP prioritization is a gnarly problem, so I was inspired to pitch it as a talk idea. It was selected and you can find the <a href="https://github.com/HTTPWorkshop/workshop2019/blob/master/talks/pardue-jones-priorities.pdf">full slide deck here</a>.</p><p>During the presentation I recounted the history of HTTP prioritization. The great thing about working on open standards is that many email threads, presentation materials and meeting materials are publicly archived. It's fun digging through this history. Did you know: HTTP/2 is based on SPDY and inherited its weight-based prioritization scheme, the tree-based scheme we are familiar with today was only introduced in <a href="https://tools.ietf.org/html/draft-ietf-httpbis-http2-11">draft-ietf-httpbis-http2-11</a>? One of the reasons for the more-complicated tree was to help HTTP intermediaries (a.k.a. proxies) implement clever resource management. However, it became clear during the discussion that no intermediaries implement this, and none seem to plan to. I also explained a bit more about Pat's alternative scheme and Nick described his implementation experiences. Despite some interesting discussion around the topic however, we didn't come to any definitive solution. There were a lot of other <a href="https://github.com/HTTPWorkshop/workshop2019/blob/master/talks/pardue-pcaps.pdf">interesting topics</a> to discover <a href="https://daniel.haxx.se/blog/2019/04/02/the-http-workshop-2019-begins/">that week</a>.</p>
    <div>
      <h3>May</h3>
      <a href="#may">
        
      </a>
    </div>
    <p>In early May, Ian Swett (Google) <a href="https://lists.w3.org/Archives/Public/ietf-http-wg/2019AprJun/0107.html">restarted interest</a> in Pat's mailing list thread. Unfortunately he was not present at the HTTP Workshop so had some catching up to do. A little while later Ian submitted a <a href="https://github.com/quicwg/base-drafts/pull/2700">Pull Request to the HTTP/3 specification</a> called "Strict Priorities". This incorporated Pat's proposal and attempted to fix a number of those prioritization edge cases that I mentioned earlier.</p><p>In late May, another QUIC WG interim meeting was held in London at the new Cloudflare offices, here is the view from the meeting room window. Credit to Alessandro for handling the meeting arrangements.</p><blockquote><p>Thanks to <a href="https://twitter.com/Cloudflare?ref_src=twsrc%5Etfw">@cloudflare</a> for hosting our interop and interim meetings in London this week! <a href="https://t.co/LIOA3OqEjr">pic.twitter.com/LIOA3OqEjr</a></p><p>— IETF QUIC WG (@quicwg) <a href="https://twitter.com/quicwg/status/1131467406059212801?ref_src=twsrc%5Etfw">May 23, 2019</a></p></blockquote><p>Mike, the editor of the HTTP/3 specification <a href="https://github.com/quicwg/wg-materials/blob/master/interim-19-05/h3issues.pdf">presented some of the issues</a> with prioritization and we attempted to solve them with the conventional tree-based scheme. Ian, with contribution from Robin Marx (UHasselt), also <a href="https://github.com/quicwg/wg-materials/blob/master/interim-19-05/priorities.pdf">presented</a> an explanation about his "Strict Priorities" proposal. I recommend taking a look at Robin's priority tree visualisations which do a great job of explaining things. From that presentation I particularly liked "The prioritization spectrum", it's a concise snapshot of the state of things at that time:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1JveyeZmmt60QOPXKbnZym/dc50d185e0c9f3afc0e077961050b1ae/priotizationspectrum.png" />
            
            </figure><p>An overview of HTTP/3 prioritization issues, fixes and possible alternatives. Presented by Ian Swett at the QUIC Interim Meeting May 2019.</p>
    <div>
      <h3>June and July</h3>
      <a href="#june-and-july">
        
      </a>
    </div>
    <p>Following the interim meeting, the prioritization "debate" continued electronically across GitHub and email. Some time in June Kazuho started work on a proposal that would use a scheme similar to Pat and Ian's absolute priorities. The major difference was that rather than send the priority signal in an HTTP frame, it would use a header field. This isn't a new concept, <a href="https://tools.ietf.org/agenda/83/slides/slides-83-httpbis-5.pdf">Roy Fielding proposed</a> something similar at IETF 83.</p><p>In HTTP/2 and HTTP/3 requests are made up of frames that are sent on streams. Using a simple GET request as an example: a client sends a HEADERS frame that contains the scheme, method, path, and other request header fields. A server responds with a HEADERS frame that contains the status and response header fields, followed by DATA frame(s) that contain the payload.</p><p>To signal priority, a client could also send a PRIORITY frame. In the tree-based scheme the frame carries several fields that express dependencies and weights. Pat and Ian's proposals changed the contents of the PRIORITY frame. Kazuho's proposal encodes the priority as a header field that can be carried in the HEADERS frame as normal metadata, removing the need for the PRIORITY frame altogether.</p><p>I liked the simplification of Kazuho's approach and the new opportunities it might create for application developers. HTTP/2 and HTTP/3 implementations (in particular browsers) abstract away a lot of connection-level details such as stream or frames. That makes it hard to understand what is happening or to tune it.</p><p>The lingua franca of the Web is HTTP requests and responses, which are formed of header fields and payload data. In browsers, APIs such as <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">Service Worker</a> allow handling of these primitives. In servers, there may be ways to interact with the primitives via configuration or programming languages. As part of <a href="/better-http-2-prioritization-for-a-faster-web/">Enhanced HTTP/2 Prioritization</a>, we have exposed prioritization to Cloudflare Workers to allow rich behavioural customization. If a Worker adds the "cf-priority" header to a response, Cloudflare’s edge servers use the specified priority to serve the response. This might be used to boost the priority of a resource that is important to the load time of a page. To help inform this decision making, the incoming browser priority signal is encapsulated in the request object passed to a Worker's fetch event listener (request.cf.requestPriority).</p><p>Standardising approaches to problems is part of helping to build a better Internet. Because of the resonance between Cloudflare's work and Kazuho's proposal, I asked if he would consider letting me come aboard as a co-author. He kindly accepted and on July 8th we published the <a href="https://tools.ietf.org/html/draft-kazuho-httpbis-priority-00">first version</a> as an Internet-Draft.</p><p>Meanwhile, Ian was helping to drive the overall prioritization discussion and proposed that we use time during IETF 105 in Montreal to speak to a wider group of people. We kicked off the week with a short <a href="https://github.com/httpwg/wg-materials/blob/gh-pages/ietf105/priorities.pdf">presentation to the HTTP WG</a> from Ian, and Kazuho and I <a href="https://lists.w3.org/Archives/Public/ietf-http-wg/2019JulSep/0095.html">presented</a> our draft in a side-meeting that saw a healthy discussion. There was a realization that the concepts of prioritization scheme, priority signalling and server resource scheduling (enacting prioritization) were conflated and made effective communication and progress difficult. HTTP/2's model was seen as one aspect, and two different I-Ds were created to deprecate it in some way (<a href="https://tools.ietf.org/html/draft-lassey-priority-setting-00">draft-lassey-priority-setting</a>, <a href="https://tools.ietf.org/html/draft-peon-httpbis-h2-priority-one-less-00">draft-peon-httpbis-h2-priority-one-less</a>). Martin Thomson (Mozilla) also created a Pull Request that simply <a href="https://github.com/quicwg/base-drafts/pull/2922">removed the PRIORITY frame from HTTP/3</a>.</p><p>To round off the week, in the second HTTP session it was decided that there was sufficient interest in resolving the prioritization debate via the creation of a design team. I joined the team led by Ian Swett along with others from Adobe, Akamai, Apple, Cloudflare, Fastly, Facebook, Google, Microsoft, and UHasselt.</p>
    <div>
      <h3>August to October</h3>
      <a href="#august-to-october">
        
      </a>
    </div>
    <p>Martin's PR generated a lot of conversation. It was merged under proviso that <i>some</i> solution be found before the HTTP/3 specification was finalized. Between May and August we went from something very complicated (e.g. <i>Orphan placeholder, with PRIORITY only on control stream, plus exclusive priorities</i>) to a blank canvas. The pressure was now on!</p><p>The design team held several teleconference meetings across the months. Logistics are a bit difficult when you have team members distributed across West Coast America, East Coast America, Western Europe, Central Europe, and Japan. However, thanks to some late nights and early mornings we managed to all get on the call at the same time.</p><p>In October most of us travelled to Cupertino, CA to attend another QUIC interim meeting hosted at Apple's Infinite Loop (Eric Kinnear helping with arrangements).  The first two days of the meeting were used for interop testing and were loosely structured, so the design team took the opportunity to hold the first face-to-face meeting. We made some progress and helped Ian to form up some <a href="https://github.com/quicwg/wg-materials/blob/master/interim-19-10/HTTP%20Priorities%20Update.pdf">new slides to present</a> later in the week. Again, there was some useful discussion and signs that we should put some time in the agenda in IETF 106.</p>
    <div>
      <h3>November</h3>
      <a href="#november">
        
      </a>
    </div>
    <p>The design team came to agreement that draft-kazuho-httpbis-priority was a good basis for a new prioritization scheme. We decided to consolidate the various I-Ds that had sprung up during IETF 105 into the document, making it a single source that was easier for people to track progress and open issues if required. This is why, even though Kazuho and I are the named authors, the document reflects a broad input from the community. We published <a href="https://tools.ietf.org/html/draft-kazuho-httpbis-priority-03">draft 03</a> in November, just ahead of the deadline for IETF 106 in Singapore.</p><p>Many of us travelled to Singapore ahead of the actual start of IETF 106. This wasn't to squeeze in some sightseeing (sadly) but rather to attend the IETF Hackathon. These are events where engineers and researchers can really put the concept of "running code" to the test. I really enjoy attending and I'm grateful to Charles Eckel and the team that organised it. If you'd like to read more about the event, Charles wrote up a nice blog post that, through some strange coincidence, features a picture of me, Kazuho and Robin talking at the QUIC table.</p><blockquote><p>Link: <a href="https://t.co/8qP78O6cPS">https://t.co/8qP78O6cPS</a></p><p>— Lucas Pardue (@SimmerVigor) <a href="https://twitter.com/SimmerVigor/status/1207049013301796864?ref_src=twsrc%5Etfw">December 17, 2019</a></p></blockquote><p>The design team held another face-to-face during a Hackathon lunch break and decided that we wanted to make some tweaks to the design written up in draft 03. Unfortunately the freeze was still in effect so we could not issue a new draft. Instead, we presented the most recent thinking to the HTTP session on Monday where Ian put forward draft-kazuho-httpbis-priority as the group's proposed design solution. Ian and Robin also shared results of <a href="https://github.com/httpwg/wg-materials/blob/gh-pages/ietf106/priorities.pdf">prioritization experiments</a>. We received some great feedback in the meeting and during the week pulled out all the stops to issue a new draft <a href="https://tools.ietf.org/html/draft-kazuho-httpbis-priority-04">04</a> before the next HTTP session on Thursday. The question now was: Did the WG think this was suitable to adopt as the basis of an alternative prioritization scheme? I think we addressed a lot of the feedback in this draft and there was a general feeling of support in the room. However, in the IETF consensus is declared via mailing lists and so Tommy Pauly, co-chair of the HTTP WG, put out a <a href="https://lists.w3.org/Archives/Public/ietf-http-wg/2019OctDec/0125.html">Call for Adoption</a> on November 21st.</p>
    <div>
      <h3>December</h3>
      <a href="#december">
        
      </a>
    </div>
    <p>In the Cloudflare London office, preparations begin for mince pie <a href="/imdb-2017/">acquisition</a> and <a href="/internet-mince-pie-database/">assessment</a>.</p><p>The HTTP priorities team played the waiting game and watched the mailing list discussion. On the whole people supported the concept but there was one topic that divided opinion. Some people loved the use of headers to express priorities, some people didn't and wanted to stick to frames.</p><p>On December 13th Tommy <a href="https://lists.w3.org/Archives/Public/ietf-http-wg/2019OctDec/0181.html">announced</a> that the group had decided to adopt our document and assign Kazuho and I as editors. The header/frame divide was noted as something that needed to be resolved.</p>
    <div>
      <h2>The next step of the journey</h2>
      <a href="#the-next-step-of-the-journey">
        
      </a>
    </div>
    <p>Just because the document has been adopted does not mean we are done. In some ways we are just getting started. Perfection is often the enemy of getting things done and so sometimes adoption occurs at the first incarnation of a "good enough" proposal.</p><p>Today HTTP/3 has no prioritization signal. Without priority information there is a small danger that servers pick a scheduling strategy that is not optimal, that could cause the web performance of HTTP/3 to be worse than HTTP/2. To avoid that happening we'll refine and complete the design of the Extensible Priority Scheme. To do so there are open issues that we have to resolve, we'll need to square the circle on headers vs. frames, and we'll no doubt hit unknown unknowns. We'll need the input of the WG to make progress and their help to document the design that fits the need, and so I look forward to continued collaboration across the Internet community.</p><p>2019 was quite a ride and I'm excited to see what 2020 brings.</p><p>If working on protocols is your interest and you like what Cloudflare is doing, please visit our <a href="https://www.cloudflare.com/careers/">careers page</a>. Our journey isn’t finished, in fact far from it.</p> ]]></content:encoded>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[IETF]]></category>
            <guid isPermaLink="false">7FCWckuesFb3p3M4fjhJy</guid>
            <dc:creator>Lucas Pardue</dc:creator>
        </item>
        <item>
            <title><![CDATA[HTTP/3: From root to tip]]></title>
            <link>https://blog.cloudflare.com/http-3-from-root-to-tip/</link>
            <pubDate>Thu, 24 Jan 2019 17:57:09 GMT</pubDate>
            <description><![CDATA[ Explore HTTP/3 from root to tip and discover the backstory of this new HTTP syntax that works on top of the IETF QUIC transport. ]]></description>
            <content:encoded><![CDATA[ <p>HTTP is the application protocol that powers the Web. It began life as the so-called HTTP/0.9 protocol in 1991, and by 1999 had evolved to HTTP/1.1, which was standardised within the IETF (Internet Engineering Task Force). HTTP/1.1 was good enough for a long time but the ever changing needs of the Web called for a better suited protocol, and HTTP/2 emerged in 2015. More recently it was announced that the IETF is intending to deliver a new version - <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a>. To some people this is a surprise and has caused a bit of confusion. If you don't track IETF work closely it might seem that HTTP/3 has come out of the blue. However,  we can trace its origins through a lineage of experiments and evolution of Web protocols; specifically the QUIC transport protocol.</p><p>If you're not familiar with QUIC, my colleagues have done a great job of tackling different angles. John's <a href="/the-quicening/">blog</a> describes some of the real-world annoyances of today's HTTP, Alessandro's <a href="/the-road-to-quic/">blog</a> tackles the nitty-gritty transport layer details, and Nick's blog covers <a href="/head-start-with-quic/">how to get hands on</a> with some testing. We've collected these and more at <a href="https://cloudflare-quic.com">https://cloudflare-quic.com</a>. And if that tickles your fancy, be sure to check out <a href="/enjoy-a-slice-of-quic-and-rust/">quiche</a>, our own open-source implementation of the QUIC protocol written in Rust.</p><p>HTTP/3 is the HTTP application mapping to the QUIC transport layer. This name was made official in the recent draft version 17 (<a href="https://tools.ietf.org/html/draft-ietf-quic-http-17">draft-ietf-quic-http-17</a>), which was proposed in late October 2018, with discussion and rough consensus being formed during the IETF 103 meeting in Bangkok in November. HTTP/3 was previously known as HTTP over QUIC, which itself was previously known as HTTP/2 over QUIC. Before that we had HTTP/2 over gQUIC, and way back we had SPDY over gQUIC. The fact of the matter, however, is that HTTP/3 is just a new HTTP syntax that works on IETF QUIC, a UDP-based multiplexed and secure transport.</p><p>In this blog post we'll explore the history behind some of HTTP/3's previous names and present the motivation behind the most recent name change. We'll go back to the early days of HTTP and touch on all the good work that has happened along the way. If you're keen to get the full picture you can jump to the end of the article or open this <a href="/content/images/2019/01/web_timeline_large1.svg">highly detailed SVG version</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1rKByCE0o19Q1zSD9Huliu/7f3540be1ff8f02da311c4df909def42/http3-stack.png" />
            
            </figure><p>An HTTP/3 layer cake</p>
    <div>
      <h2>Setting the scene</h2>
      <a href="#setting-the-scene">
        
      </a>
    </div>
    <p>Just before we focus on HTTP, it is worth reminding ourselves that there are two protocols that share the name QUIC. As we explained <a href="/the-road-to-quic/">previously</a>, gQUIC is commonly used to identify Google QUIC (the original protocol), and QUIC is commonly used to represent the IETF standard-in-progress version that diverges from gQUIC.</p><p>Since its early days in the 90s, the web’s needs have changed. We've had new versions of HTTP and added user security in the shape of Transport Layer Security (TLS). We'll only touch on TLS in this post, our other <a href="/tag/tls/">blog posts</a> are a great resource if you want to explore that area in more detail.</p><p>To help me explain the history of HTTP and TLS, I started to collate details of protocol specifications and dates. This information is usually presented in a textual form such as a list of bullets points stating document titles, ordered by date. However, there are branching standards, each overlapping in time and a simple list cannot express the real complexity of relationships. In HTTP, there has been parallel work that refactors core protocol definitions for easier consumption, extends the protocol for new uses, and redefines how the protocol exchanges data over the Internet for performance. When you're trying to join the dots over nearly 30 years of Internet history across different branching work streams you need a visualisation. So I made one -  the Cloudflare Secure Web Timeline. (NB: Technically it is a <a href="https://en.wikipedia.org/wiki/Cladogram">Cladogram</a>, but the term timeline is more widely known).</p><p>I have applied some artistic license when creating this, choosing to focus on the successful branches in the IETF space. Some of the things not shown include efforts in the W3 Consortium <a href="https://www.w3.org/Protocols/HTTP-NG/">HTTP-NG</a> working group, along with some exotic ideas that their authors are keen on explaining how to pronounce:  <a href="https://blog.jgc.org/2012/12/speeding-up-http-with-minimal-protocol.html">HMURR (pronounced 'hammer')</a> and <a href="https://github.com/HTTPWorkshop/workshop2017/blob/master/talks/waka.pdf">WAKA (pronounced “wah-kah”)</a>.</p><p>In the next few sections I'll walk this timeline to explain critical chapters in the history of HTTP. To enjoy the takeaways from this post, it helps to have an appreciation of why standardisation is beneficial, and how the IETF approaches it. Therefore we'll start with a very brief overview of that topic before returning to the timeline itself. Feel free to skip the next section if you are already familiar with the IETF.</p>
    <div>
      <h2>Types of Internet standard</h2>
      <a href="#types-of-internet-standard">
        
      </a>
    </div>
    <p>Generally, standards define common terms of reference, scope, constraint, applicability, and other considerations. Standards exist in many shapes and sizes, and can be informal (aka de facto) or formal (agreed/published by a Standards Defining Organisation such as IETF, ISO or MPEG). Standards are used in many fields, there is even a formal British Standard for making tea - BS 6008.</p><p>The early Web used HTTP and SSL protocol definitions that were published outside the IETF, these are marked as <b>red lines</b> on the Secure Web Timeline. The uptake of these protocols by clients and servers made them de facto standards.</p><p>At some point, it was decided to formalise these protocols (some motivating reasons are described in a later section). Internet standards are commonly defined in the IETF, which is guided by the informal principle of "rough consensus and running code". This is grounded in experience of developing and deploying things on the Internet. This is in contrast to a "clean room" approach of trying to develop perfect protocols in a vacuum.</p><p>IETF Internet standards are commonly known as RFCs. This is a complex area to explain so I recommend reading the blog post "<a href="https://www.ietf.org/blog/how-read-rfc/">How to Read an RFC</a>" by the QUIC Working Group Co-chair Mark Nottingham. A Working Group, or WG, is more or less just a mailing list.</p><p>Each year the IETF hold three meetings that provide the time and facilities for all WGs to meet in person if they wish. The agenda for these weeks can become very congested, with limited time available to discuss highly technical areas in depth. To overcome this, some WGs choose to also hold interim meetings in the months between the the general IETF meetings. This can help to maintain momentum on specification development. The QUIC WG has held several interim meetings since 2017, a full list is available on their <a href="https://datatracker.ietf.org/wg/quic/meetings/">meeting page</a>.</p><p>These IETF meetings also provide the opportunity for other IETF-related collections of people to meet, such as the <a href="https://www.iab.org/">Internet Architecture Board</a> or <a href="https://irtf.org/">Internet Research Task Force</a>. In recent years, an <a href="https://www.ietf.org/how/runningcode/hackathons/">IETF Hackathon</a> has been held during the weekend preceding the IETF meeting. This provides an opportunity for the community to develop running code and, importantly, to carry out interoperability testing in the same room with others. This helps to find issues in specifications that can be discussed in the following days.</p><p>For the purposes of this blog, the important thing to understand is that RFCs don't just spring into existence. Instead, they go through a process that usually starts with an IETF Internet Draft (I-D) format that is submitted for consideration of adoption. In the case where there is already a published specification, preparation of an I-D might just be a simple reformatting exercise. I-Ds have a 6 month active lifetime from the date of publish. To keep them active, new versions need to be published. In practice, there is not much consequence to letting an I-D elapse and it happens quite often. The documents continue to be hosted on the <a href="https://datatracker.ietf.org/doc/recent">IETF document’s website</a> for anyone that wants to read them.</p><p>I-Ds are represented on the Secure Web Timeline as <b>purple lines</b>. Each one has a unique name that takes the form of <i>draft-{author name}-{working group}-{topic}-{version}</i>. The working group field is optional, it might predict IETF WG that will work on the piece and sometimes this changes. If an I-D is adopted by the IETF, or if the I-D was initiated directly within the IETF, the name is <i>draft-ietf-{working group}-{topic}-{version}</i>. I-Ds may branch, merge or die on the vine. The version starts at 00 and increases by 1 each time a new draft is released. For example, the 4th draft of an I-D will have the version 03. Any time that an I-D changes name, its version resets back to 00.</p><p>It is important to note that anyone can submit an I-D to the IETF; you should not consider these as standards. But, if the IETF standardisation process of an I-D does reach consensus, and the final document passes review, we finally get an RFC. The name changes again at this stage. Each RFC gets a unique number e.g. <a href="https://tools.ietf.org/html/rfc7230">RFC 7230</a>. These are represented as <b>blue lines</b> on the Secure Web Timeline.</p><p>RFCs are immutable documents. This means that changes to the RFC require a completely new number. Changes might be done in order to incorporate fixes for errata (editorial or technical errors that were found and reported) or simply to refactor the specification to improve layout. RFCs may <b>obsolete</b> older versions (complete replacement), or just <b>update</b> them (substantively change).</p><p>All IETF documents are openly available on <a href="http://tools.ietf.org">http://tools.ietf.org</a>. Personally I find the <a href="https://datatracker.ietf.org">IETF Datatracker</a> a little more user friendly because it provides a visualisation of a documents progress from I-D to RFC.</p><p>Below is an example that shows the development of <a href="https://tools.ietf.org/html/rfc1945">RFC 1945</a> - HTTP/1.0 and it is a clear source of inspiration for the Secure Web Timeline.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5SlEeIaoaU7r9PkklUSIOj/c24f0ba70885244920a29bea1daffd68/RFC-1945-datatracker.png" />
            
            </figure><p>IETF Datatracker view of RFC 1945</p><p>Interestingly, in the course of my work I found that the above visualisation is incorrect. It is missing <a href="https://tools.ietf.org/html/draft-ietf-http-v10-spec-05">draft-ietf-http-v10-spec-05</a> for some reason. Since the I-D lifetime is 6 months, there appears to be a gap before it became an RFC, whereas in reality draft 05 was still active through until August 1996.</p>
    <div>
      <h2>Exploring the Secure Web Timeline</h2>
      <a href="#exploring-the-secure-web-timeline">
        
      </a>
    </div>
    <p>With a small appreciation of how Internet standards documents come to fruition, we can start to walk the the Secure Web Timeline. In this section are a number of excerpt diagrams that show an important part of the timeline. Each dot represents the date that a document or capability was made available. For IETF documents, draft numbers are omitted for clarity. However, if you want to see all that detail please check out the <a href="/content/images/2019/01/web_timeline_large1.svg">complete timeline</a>.</p><p>HTTP began life as the so-called HTTP/0.9 protocol in 1991, and in 1994 the I-D <a href="https://tools.ietf.org/html/draft-fielding-http-spec-00">draft-fielding-http-spec-00</a> was published. This was adopted by the IETF soon after, causing the name change to <a href="https://tools.ietf.org/html/draft-ietf-http-v10-spec-00">draft-ietf-http-v10-spec-00</a>. The I-D went through 6 draft versions before being published as <a href="https://tools.ietf.org/html/rfc1945">RFC 1945</a> - HTTP/1.0 in 1996.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6fSsHSEtXc1HA38jJorxhO/d1a86966735f27d3b2ccfbcc1c8ec38d/http11-standardisation.png" />
            
            </figure><p>However, even before the HTTP/1.0 work completed, a separate activity started on HTTP/1.1. The I-D <a href="https://tools.ietf.org/html/draft-ietf-http-v11-spec-00">draft-ietf-http-v11-spec-00</a> was published in November 1995 and was formally published as <a href="https://tools.ietf.org/html/rfc2068">RFC 2068</a> in 1997. The keen eyed will spot that the Secure Web Timeline doesn't quite capture that sequence of events, this is an unfortunate side effect of the tooling used to generate the visualisation. I tried to minimise such problems where possible.</p><p>An HTTP/1.1 revision exercise was started in mid-1997 in the form of <a href="https://tools.ietf.org/html/draft-ietf-http-v11-spec-rev-00">draft-ietf-http-v11-spec-rev-00</a>. This completed in 1999 with the publication of <a href="https://tools.ietf.org/html/rfc2616">RFC 2616</a>. Things went quiet in the IETF HTTP world until 2007. We'll come back to that shortly.</p>
    <div>
      <h2>A History of SSL and TLS</h2>
      <a href="#a-history-of-ssl-and-tls">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6pnAQiXiXCFpQpSkznYI1T/80a5516f4dafa64d1a5b60733b14c913/ssl-tls-standardisation.png" />
            
            </figure><p>Switching tracks to SSL. We see that the SSL 2.0 specification was released sometime around 1995, and that SSL 3.0 was released in November 1996. Interestingly, SSL 3.0 is described by <a href="https://tools.ietf.org/html/rfc6101">RFC 6101</a>, which was released in August 2011. This sits in <b>Historic</b> category, which "is usually done to document ideas that were considered and discarded, or protocols that were already historic when it was decided to document them." according to the <a href="https://www.ietf.org/blog/iesg-statement-designating-rfcs-historic/?primary_topic=7&amp;">IETF</a>. In this case it is advantageous to have an IETF-owned document that describes SSL 3.0 because it can be used as a canonical reference elsewhere.</p><p>Of more interest to us is how SSL inspired the development of TLS, which began life as <a href="https://tools.ietf.org/html/draft-ietf-tls-protocol-00">draft-ietf-tls-protocol-00</a> in November 1996. This went through 6 draft versions and was published as <a href="https://tools.ietf.org/html/rfc2246">RFC 2246</a> - TLS 1.0 at the start of 1999.</p><p>Between 1995 and 1999, the SSL and TLS protocols were used to secure HTTP communications on the Internet. This worked just fine as a de facto standard. It wasn't until January 1998 that the formal standardisation process for HTTPS was started with the publication of I-D <a href="https://tools.ietf.org/html/draft-ietf-tls-https-00">draft-ietf-tls-https-00</a>. That work concluded in May 2000 with the publication of <a href="https://tools.ietf.org/html/rfc2616">RFC 2616</a> - HTTP over TLS.</p><p>TLS continued to evolve between 2000 and 2007, with the standardisation of TLS 1.1 and 1.2. There was a gap of 7 years until work began on the next version of TLS, which was adopted as <a href="https://tools.ietf.org/html/draft-ietf-tls-tls13-00">draft-ietf-tls-tls13-00</a> in April 2014 and, after 28 drafts, completed as <a href="https://tools.ietf.org/html/rfc8446">RFC 8446</a> - TLS 1.3 in August 2018.</p>
    <div>
      <h2>Internet standardisation process</h2>
      <a href="#internet-standardisation-process">
        
      </a>
    </div>
    <p>After taking a small look at the timeline, I hope you can build a sense of how the IETF works. One generalisation for the way that Internet standards take shape is that researchers or engineers design experimental protocols that suit their specific use case. They experiment with protocols, in public or private, at various levels of scale. The data helps to identify improvements or issues. The work may be published to explain the experiment, to gather wider input or to help find other implementers. Take up of this early work by others may make it a de facto standard; eventually there may be sufficient momentum that formal standardisation becomes an option.</p><p>The status of a protocol can be an important consideration for organisations that may be thinking about implementing, deploying or in some way using it. A formal standardisation process can make a de facto standard more attractive because it tends to provide stability. The stewardship and guidance is provided by an organisation, such as the IETF, that reflects a wider range of experiences. However, it is worth highlighting that not all all formal standards succeed.</p><p>The process of creating a final standard is almost as important as the standard itself. Taking an initial idea and inviting contribution from people with wider knowledge, experience and use cases can to help produce something that will be of more use to a wider population. However, the standardisation process is not always easy. There are pitfalls and hurdles. Sometimes the process takes so long that the output is no longer relevant.</p><p>Each Standards Defining Organisation tends to have its own process that is geared around its field and participants. Explaining all of the details about how the IETF works is well beyond the scope of this blog. The IETF's "<a href="https://www.ietf.org/how/">How we work</a>" page is an excellent starting point that covers many aspects. The best method to forming understanding, as usual, is to get involved yourself. This can be as easy as joining an email list or adding to discussion on a relevant GitHub repository.</p>
    <div>
      <h2>Cloudflare's running code</h2>
      <a href="#cloudflares-running-code">
        
      </a>
    </div>
    <p>Cloudflare is proud to be early an adopter of new and evolving protocols. We have a long record of adopting new standards early, such as <a href="/introducing-http2/">HTTP/2</a>. We also test  features that are experimental or yet to be final, like <a href="/introducing-tls-1-3/">TLS 1.3</a> and <a href="/introducing-spdy/">SPDY</a>.</p><p>In relation to the IETF standardisation process, deploying this running code on real networks across a diverse body of websites helps us understand how well the protocol will work in practice. We combine our existing expertise with experimental information to help improve the running code and, where it makes sense, feedback issues or improvements to the WG that is standardising a protocol.</p><p>Testing new things is not the only priority. Part of being an innovator is knowing when it is time to move forward and put older innovations in the rear view mirror. Sometimes this relates to security-oriented protocols, for example, Cloudflare <a href="/sslv3-support-disabled-by-default-due-to-vulnerability/">disabled SSLv3 by default</a> due of the POODLE vulnerability. In other cases, protocols become superseded by a more technologically advanced one; Cloudflare <a href="/deprecating-spdy/">deprecated SPDY</a> support in favour of HTTP/2.</p><p>The introduction and deprecation of relevant protocols are represented on the Secure Web Timeline as <b>orange lines</b>. Dotted vertical lines help correlate Cloudflare events to relevant IETF documents. For example, Cloudflare introduced TLS 1.3 support in September 2016, with the final document, <a href="https://tools.ietf.org/html/rfc8446">RFC 8446</a>, being published almost two years later in August 2018.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/ptcxVRf8P4wmKMz6uSzAk/4d37f0581a865bc4f120282e7d9d5ebf/cf-events.png" />
            
            </figure>
    <div>
      <h2>Refactoring in HTTPbis</h2>
      <a href="#refactoring-in-httpbis">
        
      </a>
    </div>
    <p>HTTP/1.1 is a very successful protocol and the timeline shows that there wasn't much activity in the IETF after 1999. However, the true reflection is that years of active use gave implementation experience that unearthed latent issues with <a href="https://tools.ietf.org/html/rfc2616">RFC 2616</a>, which caused some interoperability issues. Furthermore, the protocol was extended by other RFCs like 2817 and 2818. It was decided in 2007 to kickstart a new activity to improve the HTTP protocol specification. This was called HTTPbis (where "bis" stems from Latin meaning "two", "twice" or "repeat") and it took the form of a new Working Group. The original <a href="https://tools.ietf.org/wg/httpbis/charters?item=charter-httpbis-2007-10-23.txt">charter</a> does a good job of describing the problems that were trying to be solved.</p><p>In short, HTTPbis decided to refactor <a href="https://tools.ietf.org/html/rfc2616">RFC 2616</a>. It would incorporate errata fixes and buy in some aspects of other specifications that had been published in the meantime. It was decided to split the document up into parts. This resulted in 6 I-Ds published in December 2007:</p><ul><li><p>draft-ietf-httpbis-p1-messaging</p></li><li><p>draft-ietf-httpbis-p2-semantics</p></li><li><p>draft-ietf-httpbis-p4-conditional</p></li><li><p>draft-ietf-httpbis-p5-range</p></li><li><p>draft-ietf-httpbis-p6-cache</p></li><li><p>draft-ietf-httpbis-p7-auth</p></li></ul>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5cCDzKbc2DBLJgD1cdLCor/c928470939df5acd6112503c41c78db3/http11-refactor.png" />
            
            </figure><p>The diagram shows how this work progressed through a lengthy drafting process of 7 years, with 27 draft versions being released, before final standardisation. In June 2014, the so-called RFC 723x series was released (where x ranges from 0 to 5). The Chair of the HTTPbis WG celebrated this achievement with the acclimation "<a href="https://www.mnot.net/blog/2014/06/07/rfc2616_is_dead">RFC2616 is Dead</a>". If it wasn't clear, these new documents obsoleted the older <a href="https://tools.ietf.org/html/rfc2616">RFC 2616</a>.</p>
    <div>
      <h2>What does any of this have to do with HTTP/3?</h2>
      <a href="#what-does-any-of-this-have-to-do-with-http-3">
        
      </a>
    </div>
    <p>While the IETF was busy working on the RFC 723x series the world didn't stop. People continued to enhance, extend and experiment with HTTP on the Internet. Among them were Google, who had started to experiment with something called SPDY (pronounced speedy). This protocol was touted as improving the performance of web browsing, a principle use case for HTTP. At the end of 2009 SPDY v1 was announced, and it was quickly followed by SPDY v2 in 2010.</p><p>I want to avoid going into the technical details of SPDY. That's a topic for another day. What is important, is to understand that SPDY took the core paradigms of HTTP and modified the interchange format slightly in order to gain improvements. With hindsight, we can see that HTTP has clearly delimited semantics and syntax. Semantics describe the concept of request and response exchanges including: methods, status codes, header fields (metadata) and bodies (payload). Syntax describe how to map semantics to bytes on the wire.</p><p>HTTP/0.9, 1.0 and 1.1 share many semantics. They also share syntax in the form of character strings that are sent over TCP connections. SPDY took HTTP/1.1 semantics and changed the syntax from strings to binary. This is a really interesting topic but we will go no further down that rabbit hole today.</p><p>Google's experiments with SPDY showed that there was promise in changing HTTP syntax, and value in keeping the existing HTTP semantics. For example, keeping the format of URLs to use  https:// avoided many problems that could have affected adoption.</p><p>Having seen some of the positive outcomes, the IETF decided it was time to consider what HTTP/2.0 might look like. The <a href="https://github.com/httpwg/wg-materials/blob/gh-pages/ietf83/HTTP2.pdf">slides</a> from the HTTPbis session held during IETF 83 in March 2012 show the requirements, goals and measures of success that were set out. It is also clearly states that "HTTP/2.0 only signifies that the wire format isn't compatible with that of HTTP/1.x".</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3EQMui9QKRGR8Vzcu5wMZA/229e6a1cb1cc1fa78da96dc34f59c220/http2-standardisation.png" />
            
            </figure><p>During that meeting the community was invited to share proposals. I-Ds that were submitted for consideration included <a href="https://tools.ietf.org/html/draft-mbelshe-httpbis-spdy-00">draft-mbelshe-httpbis-spdy-00</a>, <a href="https://tools.ietf.org/html/draft-montenegro-httpbis-speed-mobility-00">draft-montenegro-httpbis-speed-mobility-00</a> and <a href="https://tools.ietf.org/html/draft-tarreau-httpbis-network-friendly-00">draft-tarreau-httpbis-network-friendly-00</a>. Ultimately, the SPDY draft was adopted and in November 2012 work began on <a href="https://tools.ietf.org/html/draft-ietf-httpbis-http2-00">draft-ietf-httpbis-http2-00</a>. After 18 drafts across a period of just over 2 years, <a href="https://tools.ietf.org/html/rfc7540">RFC 7540</a> - HTTP/2 was published in 2015. During this specification period, the precise syntax of HTTP/2 diverged just enough to make HTTP/2 and SPDY incompatible.</p><p>These years were a very busy period for the HTTP-related work at the IETF, with the HTTP/1.1 refactor and HTTP/2 standardisation taking place in parallel. This is in stark contrast to the many years of quiet in the early 2000s. Be sure to check out the full timeline to really appreciate the amount of work that took place.</p><p>Although HTTP/2 was in the process of being standardised, there was still benefit to be had from using and experimenting with SPDY. Cloudflare <a href="/spdy-now-one-click-simple-for-any-website/">introduced support for SPDY</a> in August 2012 and only deprecated it in February 2018 when our statistics showed that less than 4% of Web clients continued to want SPDY. Meanwhile, we <a href="/introducing-http2/">introduced HTTP/2</a> support in December 2015, not long after the RFC was published, when our analysis indicated that a meaningful proportion of Web clients could take advantage of it.</p><p>Web client support of the SPDY and HTTP/2 protocols preferred the secure option of using TLS. The introduction of <a href="/introducing-universal-ssl/">Universal SSL</a> in September 2014 helped ensure that all websites signed up to Cloudflare were able to take advantage of these new protocols as we introduced them.</p>
    <div>
      <h3>gQUIC</h3>
      <a href="#gquic">
        
      </a>
    </div>
    <p>Google continued to experiment between 2012 and 2015 they released SPDY v3 and v3.1. They also started working on gQUIC (pronounced, at the time, as quick) and the initial public specification was made available in early 2012.</p><p>The early versions of gQUIC made use of the SPDY v3 form of HTTP syntax. This choice made sense because HTTP/2 was not yet finished. The SPDY binary syntax was packaged into QUIC packets that could sent in UDP datagrams. This was a departure from the TCP transport that HTTP traditionally relied on. When stacked up all together this looked like:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/40oAdMSmePG37lMEb8Odfi/b5cf02bbe9256889bd0cc103a34484a9/gquic-stack.png" />
            
            </figure><p>SPDY over gQUIC layer cake</p><p>gQUIC used clever tricks to achieve performance. One of these was to break the clear layering between application and transport. What this meant in practice was that gQUIC only ever supported HTTP. So much so that gQUIC, termed "QUIC" at the time, was synonymous with being the next candidate version of HTTP. Despite the continued changes to QUIC over the last few years, which we'll touch on momentarily, to this day, the term QUIC is understood by people to mean that initial HTTP-only variant. Unfortunately this is a regular source of confusion when discussing the protocol.</p><p>gQUIC continued to experiment and eventually switched over to a syntax much closer to HTTP/2. So close in fact that most people simply called it "HTTP/2 over QUIC". However, because of technical constraints there were some very subtle differences. One example relates to how the HTTP headers were serialized and exchanged. It is a minor difference but in effect means that HTTP/2 over gQUIC was incompatible with the IETF's HTTP/2.</p><p>Last but not least, we always need to consider the security aspects of Internet protocols. gQUIC opted not to use TLS to provide security. Instead Google developed a different approach called QUIC Crypto. One of the interesting aspects of this was a new method for speeding up security handshakes. A client that had previously established a secure session with a server could reuse information to do a "zero <a href="https://www.cloudflare.com/learning/cdn/glossary/round-trip-time-rtt/">round-trip time</a>", or 0-RTT, handshake. 0-RTT was later incorporated into TLS 1.3.</p>
    <div>
      <h2>Are we at the point where you can tell me what HTTP/3 is yet?</h2>
      <a href="#are-we-at-the-point-where-you-can-tell-me-what-http-3-is-yet">
        
      </a>
    </div>
    <p>Almost.</p><p>By now you should be familiar with how standardisation works and gQUIC is not much different. There was sufficient interest that the Google specifications were written up in I-D format. In June 2015 <a href="https://tools.ietf.org/html/draft-tsvwg-quic-protocol-00">draft-tsvwg-quic-protocol-00</a>, entitled "QUIC: A UDP-based Secure and Reliable Transport for HTTP/2" was submitted. Keep in mind my earlier statement that the syntax was almost-HTTP/2.</p><p>Google <a href="https://groups.google.com/a/chromium.org/forum/#!topic/proto-quic/otGKB4ytAyc">announced</a> that a Bar BoF would be held at IETF 93 in Prague. For those curious about what a "Bar BoF" is, please consult <a href="https://tools.ietf.org/html/rfc6771">RFC 6771</a>. Hint: BoF stands for Birds of a Feather.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/364tlrFLOtgAYBYxHrOXy8/18f5cebace8c29778e06109fe878c3b8/quic-standardisation.png" />
            
            </figure><p>The outcome of this engagement with the IETF was, in a nutshell, that QUIC seemed to offer many advantages at the transport layer and that it should be decoupled from HTTP. The clear separation between layers should be re-introduced. Furthermore, there was a preference for returning back to a TLS-based handshake (which wasn't so bad since TLS 1.3 was underway at this stage, and it was incorporating 0-RTT handshakes).</p><p>About a year later, in 2016, a new set of I-Ds were submitted:</p><ul><li><p><a href="https://tools.ietf.org/html/draft-hamilton-quic-transport-protocol-00">draft-hamilton-quic-transport-protocol-00</a></p></li><li><p><a href="https://tools.ietf.org/html/draft-thomson-quic-tls-00">draft-thomson-quic-tls-00</a></p></li><li><p><a href="https://tools.ietf.org/html/draft-iyengar-quic-loss-recovery-00">draft-iyengar-quic-loss-recovery-00</a></p></li><li><p><a href="https://tools.ietf.org/html/draft-shade-quic-http2-mapping-00">draft-shade-quic-http2-mapping-00</a></p></li></ul><p>Here's where another source of confusion about HTTP and QUIC enters the fray. <a href="https://tools.ietf.org/html/draft-shade-quic-http2-mapping-00">draft-shade-quic-http2-mapping-00</a> is entitled "HTTP/2 Semantics Using The QUIC Transport Protocol" and it describes itself as "a mapping of HTTP/2 semantics over QUIC". However, this is a misnomer. HTTP/2 was about changing syntax while maintaining semantics. Furthermore, "HTTP/2 over gQUIC" was never an accurate description of the syntax either, for the reasons I outlined earlier. Hold that thought.</p><p>This IETF version of QUIC was to be an entirely new transport protocol. That's a large undertaking and before diving head-first into such commitments, the IETF likes to gauge actual interest from its members. To do this, a formal <a href="https://www.ietf.org/how/bofs/">Birds of a Feather</a> meeting was held at the IETF 96 meeting in Berlin in 2016. I was lucky enough to attend the session in person and the <a href="https://datatracker.ietf.org/meeting/96/materials/slides-96-quic-0">slides</a> don't give it justice. The meeting was attended by hundreds, as shown by Adam Roach's <a href="https://www.flickr.com/photos/adam-roach/28343796722/in/photostream/">photograph</a>. At the end of the session consensus was reached; QUIC would be adopted and standardised at the IETF.</p><p>The first IETF QUIC I-D for mapping HTTP to QUIC, <a href="https://tools.ietf.org/html/draft-ietf-quic-http-00">draft-ietf-quic-http-00</a>, took the Ronseal approach and simplified its name to "HTTP over QUIC". Unfortunately, it didn't finish the job completely and there were many instances of the term HTTP/2 throughout the body. Mike Bishop, the I-Ds new editor, identified this and started to fix the HTTP/2 misnomer. In the 01 draft, the description changed to "a mapping of HTTP semantics over QUIC".</p><p>Gradually, over time and versions, the use of the term "HTTP/2" decreased and the instances became mere references to parts of <a href="https://tools.ietf.org/html/rfc7540">RFC 7540</a>. Roll forward two years to October 2018 and the I-D is now at version 16. While HTTP over QUIC bares similarity to HTTP/2 it ultimately is an independent, non-backwards compatible HTTP syntax. However, to those that don't track IETF development very closely (a very very large percentage of the Earth's population), the document name doesn't capture this difference. One of the main points of standardisation is to aid communication and interoperability. Yet a simple thing like naming is a major contributor to confusion in the community.</p><p>Recall what was said in 2012, "HTTP/2.0 only signifies that the wire format isn't compatible with that of HTTP/1.x". The IETF followed that existing cue. After much deliberation in the lead up to, and during, IETF 103, consensus was reached to rename "HTTP over QUIC" to HTTP/3. The world is now in a better place and we can move on to more important debates.</p>
    <div>
      <h2>But RFC 7230 and 7231 disagree with your definition of semantics and syntax!</h2>
      <a href="#but-rfc-7230-and-7231-disagree-with-your-definition-of-semantics-and-syntax">
        
      </a>
    </div>
    <p>Sometimes document titles can be confusing. The present HTTP documents that describe syntax and semantics are:</p><ul><li><p><a href="https://tools.ietf.org/html/rfc7230">RFC 7230</a> - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing</p></li><li><p><a href="https://tools.ietf.org/html/rfc7231">RFC 7231</a> - Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content</p></li></ul><p>It is possible to read too much into these names and believe that fundamental HTTP semantics are specific for versions of HTTP i.e. HTTP/1.1. However, this is an unintended side effect of the HTTP family tree. The good news is that the HTTPbis Working Group are trying to address this. Some brave members are going through another round of document revision, as Roy Fielding put it, "one more time!". This work is underway right now and is known as the HTTP Core activity (you may also have heard of this under the moniker HTTPtre or HTTPter; naming things is hard). This will condense the six drafts down to three:</p><ul><li><p>HTTP Semantics (draft-ietf-httpbis-semantics)</p></li><li><p>HTTP Caching (draft-ietf-httpbis-caching)</p></li><li><p>HTTP/1.1 Message Syntax and Routing (draft-ietf-httpbis-messaging)</p></li></ul><p>Under this new structure, it becomes more evident that HTTP/2 and HTTP/3 are syntax definitions for the common HTTP semantics. This doesn't mean they don't have their own features beyond syntax but it should help frame discussion going forward.</p>
    <div>
      <h2>Pulling it all together</h2>
      <a href="#pulling-it-all-together">
        
      </a>
    </div>
    <p>This blog post has taken a shallow look at the standardisation process for HTTP in the IETF across the last three decades. Without touching on many technical details, I've tried to explain how we have ended up with HTTP/3 today. If you skipped the good bits in the middle and are looking for a one liner here it is: HTTP/3 is just a new HTTP syntax that works on IETF QUIC, a UDP-based multiplexed and secure transport. There are many interesting technical areas to explore further but that will have to wait for another day.</p><p>In the course of this post, we explored important chapters in the development of HTTP and TLS but did so in isolation. We close out the blog by pulling them all together into the complete Secure Web Timeline presented below. You can use this to investigate the detailed history at your own comfort. And for the super sleuths, be sure to check out the <a href="/content/images/2019/01/web_timeline_large1.svg">full version including draft numbers</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3eL8vJkYylVmR4T5Aa1Zdf/2f2929308ee42e450917639874835c1d/cf-secure-web-timeline-1.png" />
            
            </figure> ]]></content:encoded>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[TLS]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[HTTP3]]></category>
            <category><![CDATA[IETF]]></category>
            <guid isPermaLink="false">1upTpaZ3pXyoDXxMvZoEC8</guid>
            <dc:creator>Lucas Pardue</dc:creator>
        </item>
    </channel>
</rss>