
<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 08:58:56 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[DDoS threat report for 2023 Q3]]></title>
            <link>https://blog.cloudflare.com/ddos-threat-report-2023-q3/</link>
            <pubDate>Thu, 26 Oct 2023 13:00:58 GMT</pubDate>
            <description><![CDATA[ In the past quarter, DDoS attacks surged by 65%. Gaming and Gambling companies were the most attacked and Cloudflare mitigated thousands of hyper-volumetric DDoS attacks. The largest attacks we saw peaked at 201 million rps and 2.6 Tbps. ]]></description>
            <content:encoded><![CDATA[ <p></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7vJM3Cw70UHjDC2hq8rRqv/7d62354485355a253d2b997d3249df82/image19.png" />
            
            </figure><p>Welcome to the third DDoS threat report of 2023. DDoS attacks, or <a href="https://www.cloudflare.com/learning/ddos/what-is-a-ddos-attack/">distributed denial-of-service attacks</a>, are a type of cyber attack that aims to disrupt websites (and other types of Internet properties) to make them unavailable for legitimate users by overwhelming them with more traffic than they can handle — similar to a driver stuck in a traffic jam on the way to the grocery store.</p><p>We see a lot of DDoS attacks of all types and sizes, and our <a href="https://www.cloudflare.com/network/">network</a> is one of the largest in the world spanning more than 300 cities in over 100 countries. Through this network we serve over 64 million HTTP requests per second at peak and about 2.3 billion DNS queries every day. On average, we mitigate 140 billion cyber threats each day. This colossal amount of data gives us a unique vantage point to understand the threat landscape and provide the community access to insightful and actionable DDoS trends.</p><p>In recent weeks, we've also observed a surge in DDoS attacks and other cyber attacks against Israeli newspaper and media websites, as well as financial institutions and government websites. Palestinian websites have also seen a significant increase in DDoS attacks. View the full coverage <a href="/cyber-attacks-in-the-israel-hamas-war/">here</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6ZyOmncoxhr4spfWrvzu4I/fb65af9e3364a5c9c10551e622f6acb2/pasted-image-0--7--1.png" />
            
            </figure><p>HTTP DDoS attacks against Israeli websites using Cloudflare</p>
    <div>
      <h2>The global DDoS threat landscape</h2>
      <a href="#the-global-ddos-threat-landscape">
        
      </a>
    </div>
    <p>In the third quarter of 2023, Cloudflare faced one of the most sophisticated and persistent DDoS attack campaigns in recorded history.</p><ol><li><p>Cloudflare mitigated thousands of hyper-volumetric HTTP DDoS attacks, 89 of which exceeded 100 million requests per second (rps) and with the largest peaking at 201 million rps — a figure three times higher than the previous <a href="/cloudflare-mitigates-record-breaking-71-million-request-per-second-ddos-attack/?">largest attack on record</a> (71M rps).</p></li><li><p>The campaign contributed to an overall increase of 65% in HTTP DDoS attack traffic in Q3 compared to the previous quarter. Similarly, L3/4 DDoS attacks also increased by 14% alongside numerous attacks in the terabit-per-second range — the largest attack targeted Cloudflare’s free DNS resolver <a href="https://www.cloudflare.com/learning/dns/what-is-1.1.1.1/">1.1.1.1</a> and peaked at 2.6 Tbps.</p></li><li><p>Gaming and Gambling companies were bombarded with the largest volume of HTTP DDoS attack traffic, overtaking the Cryptocurrency industry from last quarter.</p></li></ol><p><i>Reminder: an interactive version of this report is also available as a</i> <a href="https://radar.cloudflare.com/reports/ddos-2023-q3"><i>Cloudflare Radar Report</i></a><i>. On</i> <a href="https://radar.cloudflare.com/"><i>Radar</i></a><i>, you can also dive deeper and explore traffic trends, attacks, outages and many more insights for your specific industry, network and country.</i></p>
    <div>
      <h3>HTTP DDoS attacks and hyper-volumetric attacks</h3>
      <a href="#http-ddos-attacks-and-hyper-volumetric-attacks">
        
      </a>
    </div>
    <p>An <a href="https://www.cloudflare.com/learning/ddos/http-flood-ddos-attack/">HTTP DDoS attack</a> is a DDoS attack over the <a href="https://www.cloudflare.com/learning/ddos/glossary/hypertext-transfer-protocol-http/">Hypertext Transfer Protocol (HTTP)</a>. It targets HTTP Internet properties such as mobile application servers, ecommerce websites, and API gateways.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4MzFZZekp5KTt2jQlOoG0M/69a332e07a45dcb6c922f7d7f7cc82c0/Untitled.png" />
            
            </figure><p>Illustration of an HTTP DDoS attack</p><p><a href="https://developers.cloudflare.com/support/network/understanding-cloudflare-http2-and-http3-support/#http2">HTTP/2</a>, which accounts for 62% of HTTP traffic, is a version of the protocol that’s meant to improve application performance. The downside is that HTTP/2 can also help <i>improve</i> a botnet’s performance.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7gt0Zfq2TByTxHFxMJe6BP/ccba571bf7ffb3e37782e64ebaa5e0cf/pasted-image-0-1.png" />
            
            </figure><p>Distribution of HTTP versions by Radar</p>
    <div>
      <h3>Campaign of hyper-volumetric DDoS attacks exploiting HTTP/2 Rapid Resets</h3>
      <a href="#campaign-of-hyper-volumetric-ddos-attacks-exploiting-http-2-rapid-resets">
        
      </a>
    </div>
    <p>Starting in late August 2023, Cloudflare and various other vendors were subject to a sophisticated and persistent DDoS attack campaign that exploited the <a href="/zero-day-rapid-reset-http2-record-breaking-ddos-attack/">HTTP/2 Rapid Reset</a> vulnerability (<a href="https://www.cve.org/CVERecord?id=CVE-2023-44487">CVE-2023-44487</a>).</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1zfCtXueNXLlsmlk7A8coq/84f13ed42f5dc510dfc9bad46ed7b8b3/pasted-image-0--1--1.png" />
            
            </figure><p>Illustration of an HTTP/2 Rapid Reset DDoS attack</p><p>The DDoS campaign included thousands of hyper-volumetric DDoS attacks over HTTP/2 that peaked in the range of millions of requests per second. The average attack rate was 30M rps. Approximately 89 of the attacks peaked above 100M rps and the largest one we saw hit 201M rps.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6WoXAia8UYzUqUvdwsxuXW/eccf1cdae4f0cb46d709b89395004e6a/pasted-image-0--2--1.png" />
            
            </figure><p>HTTP/2 Rapid Reset campaign of hyper-volumetric DDoS attacks</p><p>Cloudflare’s systems automatically detected and mitigated the vast majority of attacks. We deployed emergency countermeasures and improved our mitigation systems’ efficacy and efficiency to ensure the availability of our network and of our customers’.</p><p>Check out our engineering blog that <a href="/technical-breakdown-http2-rapid-reset-ddos-attack/">dives deep into the land of HTTP/2</a>, what we learned and what actions we took to make the Internet safer.</p>
    <div>
      <h3>Hyper-volumetric DDoS attacks enabled by VM-based botnets</h3>
      <a href="#hyper-volumetric-ddos-attacks-enabled-by-vm-based-botnets">
        
      </a>
    </div>
    <p>As we’ve seen in this campaign and previous <a href="/ddos-threat-report-2023-q1/">ones</a>, botnets that leverage cloud computing platforms and exploit HTTP/2 are able to generate up to <b>x5,000</b> more force per botnet node. This allowed them to launch hyper-volumetric DDoS attacks with a small botnet ranging 5-20 thousand nodes alone. To put that into perspective, in the past, IoT based botnets consisted of fleets of millions of nodes and barely managed to reach a few million requests per second.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6aY3QDbXwT06ndT5ruv6Ms/4acf652835acec7f5bd28b0aca80bf32/pasted-image-0--3--1.png" />
            
            </figure><p>Comparison of an Internet of Things (IoT) based botnet and a Virtual Machine (VM) based botnet</p><p>When analyzing the two-month-long DDoS campaign, we can see that Cloudflare infrastructure was the main target of the attacks. More specifically, 19% of all attacks targeted Cloudflare websites and infrastructure. Another 18% targeted Gaming companies, and 10% targeted well known VoIP providers.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5TsjdpB4iSwOB0brlTf454/b0dbbad2c5d475fc719d76423328337a/pasted-image-0--4--1.png" />
            
            </figure><p>Top industries targeted by the HTTP/2 Rapid Reset DDoS attacks</p>
    <div>
      <h3>HTTP DDoS attack traffic increased by 65%</h3>
      <a href="#http-ddos-attack-traffic-increased-by-65">
        
      </a>
    </div>
    <p>The attack campaign contributed to an overall increase in the amount of attack traffic. Last quarter, the volume of HTTP DDoS attacks increased by 15% QoQ. This quarter, it grew even more. Attacks volume increased by 65% QoQ to a total staggering figure of 8.9 trillion HTTP DDoS requests that Cloudflare systems automatically detected and mitigated.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3GZPXFg1uZKMn9HLpcTQSS/cb9d2cd146b5a2d68baa1b94651f315e/Untitled9.png" />
            
            </figure><p>Aggregated volume of HTTP DDoS attack requests by quarter</p><p>Alongside the 65% increase in HTTP DDoS attacks, we also saw a minor increase of 14% in L3/4 DDoS attacks — similar to the figures we saw in the first quarter of this year.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/60R9Zo2MFYlW9w8KfNge4C/78c978588db6977529abebcfbb8221d3/pasted-image-0--5--1.png" />
            
            </figure><p>L3/4 DDoS attack by quarter</p><p>A rise in large volumetric DDoS attacks contributing to this increase. In Q3, our DDoS defenses automatically detected and mitigated numerous DDoS attacks in the terabit-per-second range. The largest attacks we saw peaked at 2.6 Tbps. This attack was part of a broader campaign that targeted Cloudflare’s free DNS resolver <a href="https://www.cloudflare.com/learning/dns/what-is-1.1.1.1/">1.1.1.1</a>. It was a <a href="https://www.cloudflare.com/learning/ddos/udp-flood-ddos-attack/">UDP flood</a> that was launched by a <a href="https://www.cloudflare.com/learning/ddos/glossary/mirai-botnet/">Mirai-variant botnet</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5Uxn6gNTYNEWO9KACtfKpN/8cc96fb699be51869db0691269335008/pasted-image-007.png" />
            
            </figure>
    <div>
      <h2>Top sources of HTTP DDoS attacks</h2>
      <a href="#top-sources-of-http-ddos-attacks">
        
      </a>
    </div>
    <p>When comparing the global and country-specific HTTP DDoS attack request volume, we see that the US remains the largest source of HTTP DDoS attacks. One out of every 25 HTTP DDoS requests originated from the US. China remains in second place. Brazil replaced Germany as the third-largest source of HTTP DDoS attacks, as Germany fell to fourth place.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/50dCj8uTPa6ovls8JnBbeV/0e84a5263c930cb59616544d82bc91fd/pasted-image-0--6-.png" />
            
            </figure><p>HTTP DDoS attacks: Top sources compared to all attack traffic</p><p>Some countries naturally receive more traffic due to various factors such as the population and Internet usage, and therefore also receive/generate more attacks. So while it’s interesting to understand the total amount of attack traffic originating from or targeting a given country, it is also helpful to remove that bias by normalizing the attack traffic by all traffic to a given country.</p><p>When doing so, we see a different pattern. The US doesn’t even make it into the top ten. Instead, Mozambique is in first place (again). One out of every five HTTP requests that originated from Mozambique was part of an HTTP DDoS attack traffic.</p><p>Egypt remains in second place — approximately 13% of requests originating from Egypt were part of an HTTP DDoS attack. Libya and China follow as the third and fourth-largest source of HTTP DDoS attacks.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/wuw45dUbZjsMYTpxcaFrv/b065d46bbfcbff8466a570a97d3c022b/pasted-image-0--8-.png" />
            
            </figure><p>HTTP DDoS attacks: Top sources compared to their own traffic</p>
    <div>
      <h2>Top sources of L3/4 DDoS attacks</h2>
      <a href="#top-sources-of-l3-4-ddos-attacks">
        
      </a>
    </div>
    <p>When we look at the origins of L3/4 DDoS attacks, we ignore the source IP address because it can be <a href="https://www.cloudflare.com/learning/ddos/glossary/ip-spoofing/">spoofed</a>. Instead, we rely on the location of Cloudflare’s data center where the traffic was ingested. Thanks to our large network and global coverage, we’re able to achieve geographical accuracy to understand where attacks come from.</p><p>In Q3, approximately 36% of all <a href="https://www.cloudflare.com/learning/ddos/layer-3-ddos-attacks/">L3/4 DDoS attack</a> traffic that we saw originated from the US. Far behind, Germany came in second place with 8% and the UK followed in third place with almost 5%.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/RrBJ1xpV90NhBGOAmP3Au/bb3251e7566f5715b2e70737569efc75/pasted-image-0--9-.png" />
            
            </figure><p>L3/4 DDoS attacks: Top sources compared to all attack traffic</p><p>When normalizing the data, we see that Vietnam dropped to the second-largest source of L3/4 DDoS attacks after being first for two consecutive quarters. New Caledonia, a French territory comprising dozens of islands in the South Pacific, grabbed the first place. Two out of every four bytes ingested in Cloudflare’s data centers in New Caledonia were attacks.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2m7OrC60ttRI190S1ripAi/acc86e9508f687fbb4e1d7afb2199994/pasted-image-0--10-.png" />
            
            </figure><p>L3/4 DDoS attacks: Top sources compared to their own traffic</p>
    <div>
      <h2>Top attacked industries by HTTP DDoS attacks</h2>
      <a href="#top-attacked-industries-by-http-ddos-attacks">
        
      </a>
    </div>
    <p>In terms of absolute volume of HTTP DDoS attack traffic, the Gaming and Gambling industry jumps to first place overtaking the Cryptocurrency industry. Over 5% of all HTTP DDoS attack traffic that Cloudflare saw targeted the Gaming and Gambling industry.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4g1US6Pgze6K9cktcoxExV/356942816a4b30030ba953059f5462e3/pasted-image-0--11--2.png" />
            
            </figure><p>HTTP DDoS attacks: Top attacked industries compared to all attack traffic</p><p>The Gaming and Gambling industry has long been one of the most attacked industries compared to others. But when we look at the HTTP DDoS attack traffic relative to each specific industry, we see a different picture. The Gaming and Gambling industry has so much user traffic that, despite being the most attacked industry <i>by volume</i>, it doesn’t even make it into the top ten when we put it into the per-industry context.</p><p>Instead, what we see is that the Mining and Metals industry was targeted by the most attacks compared to its total traffic — 17.46% of all traffic to Mining and Metals companies were DDoS attack traffic.</p><p>Following closely in second place, 17.41% of all traffic to Non-profits were HTTP DDoS attacks. Many of these attacks are directed at more than 2,400 Non-profit and independent media organizations in 111 countries that Cloudflare protects for free as part of Project Galileo, which celebrated its <a href="/nine-years-of-project-galileo-and-how-the-last-year-has-changed-it/">ninth anniversary</a> this year. Over the past quarter alone, Cloudflare mitigated an average of 180.5 million cyber threats against Galileo-protected websites every day.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4IdazsRvY8JcFF5ByZprTK/e7d3886bde7415b9ebca9509dc0d5b91/pasted-image-0--12--2.png" />
            
            </figure><p>HTTP DDoS attacks: Top attacked industries compared to their own traffic</p><p>Pharmaceuticals, Biotechnology and Health companies came in third, and US Federal Government websites in fourth place. Almost one out of every 10 HTTP requests to US Federal Government Internet properties were part of an attack. In fifth place, Cryptocurrency and then Farming and Fishery not far behind.</p>
    <div>
      <h3>Top attacked industries by region</h3>
      <a href="#top-attacked-industries-by-region">
        
      </a>
    </div>
    <p>Now let’s dive deeper to understand which industries were targeted the most in each region.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1SgX9S1bbrxWXAQHtWECiz/ec7a1d4c2cfc8c65aa82943d721249e2/Top-Attacked-Industry-by-Region-Q3-2023.png" />
            
            </figure><p>HTTP DDoS attacks: Top industries targeted by HTTP DDoS attacks by region</p>
    <div>
      <h2>Regional deepdives</h2>
      <a href="#regional-deepdives">
        
      </a>
    </div>
    
    <div>
      <h3>Africa</h3>
      <a href="#africa">
        
      </a>
    </div>
    <p>After two consecutive quarters as the most attacked industry, the Telecommunications industry dropped from first place to fourth. Media Production companies were the most attacked industry in Africa. The Banking, Financial Services and Insurance (BFSI) industry follows as the second most attacked. Gaming and Gambling companies in third.</p>
    <div>
      <h3>Asia</h3>
      <a href="#asia">
        
      </a>
    </div>
    <p>The Cryptocurrency industry remains the most attacked in APAC for the second consecutive quarter. Gaming and Gambling came in second place. Information Technology and Services companies in third.</p>
    <div>
      <h3>Europe</h3>
      <a href="#europe">
        
      </a>
    </div>
    <p>For the fourth consecutive quarter, the Gaming and Gambling industry remains the most attacked industry in Europe. Retail companies came in second, and Computer Software companies in third.</p>
    <div>
      <h3>Latin America</h3>
      <a href="#latin-america">
        
      </a>
    </div>
    <p>Farming was the most targeted industry in Latin America in Q3. It accounted for a whopping 53% of all attacks towards Latin America. Far behind, Gaming and Gambling companies were the second most targeted. Civic and Social Organizations were in third.</p>
    <div>
      <h3>Middle East</h3>
      <a href="#middle-east">
        
      </a>
    </div>
    <p>Retail companies were the most targeted in the Middle East in Q3. Computer Software companies came in second and the Gaming and Gambling industry in third.</p>
    <div>
      <h3>North America</h3>
      <a href="#north-america">
        
      </a>
    </div>
    <p>After two consecutive quarters, the Marketing and Advertising industry dropped from the first place to the second. Computer Software took the lead. In third place, Telecommunications companies.</p>
    <div>
      <h3>Oceania</h3>
      <a href="#oceania">
        
      </a>
    </div>
    <p>The Telecommunications industry was, by far, the most targeted in Oceania in Q3 — over 45% of all attacks to Oceania. Cryptocurrency and Computer Software companies came in second and third places respectively.</p>
    <div>
      <h2>Top attacked industries by L3/4 DDoS attacks</h2>
      <a href="#top-attacked-industries-by-l3-4-ddos-attacks">
        
      </a>
    </div>
    <p>When descending the layers of the <a href="https://www.cloudflare.com/learning/ddos/glossary/open-systems-interconnection-model-osi/">OSI model</a>, the Internet networks and services that were most targeted belonged to the Information Technology and Services industry. Almost 35% of all L3/4 DDoS attack traffic (in bytes) targeted the Information Technology and Internet industry.</p><p>Far behind, Telecommunication companies came in second with a mere share of 3%. Gaming and Gambling came in third, Banking, Financial Services and Insurance companies (BFSI) in fourth.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2MfrOUrxk9nvOVu3UJz4VN/f8297c3bb90969df2b1a5530621c0fd5/pasted-image-0--13--1.png" />
            
            </figure><p>L3/4 DDoS attacks: Top attacked industries compared to all attack traffic</p><p>When comparing the attacks on industries to all traffic for that specific industry, we see that the Music industry jumps to the first place, followed by Computer and Network Security companies, Information Technology and Internet companies and Aviation and Aerospace.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3DfOZGUxDtZjNG32es9K4K/ecb5f8a71a998a896dfd71592c6f4896/pasted-image-0--14--1.png" />
            
            </figure><p>L3/4 DDoS attacks: Top attacked industries compared to their own traffic</p>
    <div>
      <h2>Top attacked countries by HTTP DDoS attacks</h2>
      <a href="#top-attacked-countries-by-http-ddos-attacks">
        
      </a>
    </div>
    <p>When examining the total volume of attack traffic, the US remains the main target of HTTP DDoS attacks. Almost 5% of all HTTP DDoS attack traffic targeted the US. Singapore came in second and China in third.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6UGa4GWaTX9dLLMudmE8x8/c781750cd8b72074946581454d350ed0/pasted-image-0--15--2.png" />
            
            </figure><p>HTTP DDoS attacks: Top attacked countries compared to all traffic</p><p>If we normalize the data per country and region and divide the attack traffic by the total traffic, we get a different picture. The top three most attacked countries are Island nations.</p><p>Anguilla, a small set of islands east of Puerto Rico, jumps to the first place as the most attacked country. Over 75% of all traffic to Anguilla websites were HTTP DDoS attacks. In second place, American Samoa, a group of islands east of Fiji. In third, the British Virgin Islands.</p><p>In fourth place, Algeria, and then Kenya, Russia, Vietnam, Singapore, Belize, and Japan.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4dKlIvgbduDoug2Zlxn49q/2f8fdf78b30024ddb05e7b2aedef3da3/pasted-image-0--16-.png" />
            
            </figure><p>HTTP DDoS attacks: Top attacked countries compared to their own traffic</p>
    <div>
      <h3>Top attacked countries by L3/4 DDoS attacks</h3>
      <a href="#top-attacked-countries-by-l3-4-ddos-attacks">
        
      </a>
    </div>
    <p>For the second consecutive quarter, Chinese Internet networks and services remain the most targeted by L3/4 DDoS attacks. These China-bound attacks account for 29% of all attacks we saw in Q3.</p><p>Far, far behind, the US came in second place (3.5%) and Taiwan in third place (3%).</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1MliH893yCW3CV3jqpjZmw/0ca7b37530fc93682052961774b52c19/pasted-image-0--17-.png" />
            
            </figure><p>L3/4 DDoS attacks: Top attacked countries compared to all traffic</p><p>When normalizing the amount of attack traffic compared to all traffic to a country, China remains in first place and the US disappears from the top ten. Cloudflare saw that 73% of traffic to China Internet networks were attacks. However, the normalized ranking changes from second place on, with the Netherlands receiving the second-highest proportion of attack traffic (representing 35% of the country’s overall traffic), closely followed by Thailand, Taiwan and Brazil.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2m9M6zzn5dSwaubzw5PXQG/a3b6cdff495954f94a9173206142d8c3/pasted-image-0--18-.png" />
            
            </figure><p>L3/4 DDoS attacks: Top attacked countries compared to their own traffic</p>
    <div>
      <h2>Top attack vectors</h2>
      <a href="#top-attack-vectors">
        
      </a>
    </div>
    <p>The Domain Name System, or <a href="https://www.cloudflare.com/learning/dns/what-is-dns/">DNS</a>, serves as the phone book of the Internet. DNS helps translate the human-friendly website address (e.g., <a href="https://www.cloudflare.com/">www.cloudflare.com</a>) to a machine-friendly IP address (e.g., 104.16.124.96). By disrupting DNS servers, attackers impact the machines’ ability to connect to a website, and by doing so making websites unavailable to users.</p><p>For the second consecutive quarter, <a href="https://www.cloudflare.com/learning/ddos/dns-flood-ddos-attack/">DNS-based DDoS attacks</a> were the most common. Almost 47% of all attacks were DNS-based. This represents a 44% increase compared to the previous quarter. <a href="https://www.cloudflare.com/learning/ddos/syn-flood-ddos-attack/">SYN floods</a> remain in second place, followed by RST floods, <a href="https://www.cloudflare.com/learning/ddos/udp-flood-ddos-attack/">UDP floods</a>, and <a href="https://www.cloudflare.com/learning/ddos/glossary/mirai-botnet/">Mirai attacks</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5YGOLx5BKnhvVEXB8awpxU/2b651344c3572a0c0aa2e5fdf3dbf9f2/pasted-image-0--19-.png" />
            
            </figure><p>Top attack vectors</p>
    <div>
      <h3>Emerging threats - <i>reduced, reused and recycled</i></h3>
      <a href="#emerging-threats-reduced-reused-and-recycled">
        
      </a>
    </div>
    <p>Aside from the most common attack vectors, we also saw significant increases in lesser known attack vectors. These tend to be very volatile as threat actors try to <i>“reduce, reuse and recycle”</i> older attack vectors. These tend to be UDP-based protocols that can be exploited to launch amplification and reflection DDoS attacks.</p><p>One well-known tactic that we continue to see is the use of amplification/reflection attacks. In this attack method, the attacker bounces traffic off of servers, and aims the responses towards their victim. Attackers are able to aim the bounced traffic to their victim by various methods such as <a href="https://www.cloudflare.com/learning/ddos/glossary/ip-spoofing/">IP spoofing</a>.</p><p>Another form of reflection can be achieved differently in an attack named ‘DNS Laundering attack’. In a DNS Laundering attack, the attacker will query subdomains of a domain that is managed by the victim’s DNS server. The prefix that defines the subdomain is randomized and is never used more than once or twice in such an attack. Due to the randomization element, recursive DNS servers will never have a cached response and will need to forward the query to the victim’s authoritative DNS server. The authoritative DNS server is then bombarded by so many queries until it cannot serve legitimate queries or even crashes all together.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7sMVuA99lvODrsKQNBXFqs/e67a7b2cc1c7f07ba0642b25768a7142/pasted-image-0--20-.png" />
            
            </figure><p>Illustration of a reflection and amplification attack</p><p>Overall in Q3, Multicast DNS (mDNS) based DDoS attacks was the attack method that increased the most. In second place were attacks that exploit the Constrained Application Protocol (CoAP), and in third, the Encapsulating Security Payload (ESP). Let’s get to know those attack vectors a little better.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7zpAljr3yzAfQXITi9rSnX/83db014c34690385fa4f09f15171b0af/pasted-image-0--21-.png" />
            
            </figure><p>Main emerging threats</p>
    <div>
      <h3>mDNS DDoS attacks increased by 456%</h3>
      <a href="#mdns-ddos-attacks-increased-by-456">
        
      </a>
    </div>
    <p>Multicast DNS (mDNS) is a UDP-based protocol that is used in local networks for service/device discovery. Vulnerable mDNS servers respond to unicast queries originating outside the local network, which are ‘spoofed’ (altered) with the victim's source address. This results in amplification attacks. In Q3, we noticed a large increase of mDNS attacks; a 456% increase compared to the previous quarter.</p>
    <div>
      <h3>CoAP DDoS attacks increased by 387%</h3>
      <a href="#coap-ddos-attacks-increased-by-387">
        
      </a>
    </div>
    <p>The Constrained Application Protocol (CoAP) is designed for use in simple electronics and enables communication between devices in a low-power and lightweight manner. However, it can be abused for DDoS attacks via <a href="https://www.cloudflare.com/learning/ddos/glossary/ip-spoofing/">IP spoofing</a> or amplification, as malicious actors exploit its multicast support or leverage poorly configured CoAP devices to generate large amounts of unwanted network traffic. This can lead to service disruption or overloading of the targeted systems, making them unavailable to legitimate users.</p>
    <div>
      <h3>ESP DDoS attacks increased by 303%</h3>
      <a href="#esp-ddos-attacks-increased-by-303">
        
      </a>
    </div>
    <p>The Encapsulating Security Payload (<a href="https://www.cloudflare.com/learning/network-layer/what-is-ipsec/#:~:text=Encapsulating%20Security%20Protocol%20(ESP)">ESP</a>) protocol is part of <a href="https://www.cloudflare.com/learning/network-layer/what-is-ipsec/">IPsec</a> and provides confidentiality, authentication, and integrity to network communications. However, it could potentially be abused in DDoS attacks if malicious actors exploit misconfigured or vulnerable systems to reflect or amplify traffic towards a target, leading to service disruption. Like with other protocols, securing and properly configuring the systems using ESP is crucial to mitigate the risks of DDoS attacks.</p>
    <div>
      <h2>Ransom DDoS attacks</h2>
      <a href="#ransom-ddos-attacks">
        
      </a>
    </div>
    <p>Occasionally, DDoS attacks are carried out to extort ransom payments. We’ve been surveying Cloudflare customers over three years now, and have been tracking the occurrence of <a href="https://www.cloudflare.com/learning/ddos/ransom-ddos-attack/">Ransom DDoS attack</a> events.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/78OHC3lsv0ffsK9Yul14GD/d7006d3f770e766373d0c334204f668b/Untitled--1--1.png" />
            
            </figure><p>Comparison of Ransomware and Ransom DDoS attacks</p><p>Unlike <a href="https://www.cloudflare.com/learning/security/ransomware/what-is-ransomware/">Ransomware</a> attacks, where victims typically fall prey to downloading a malicious file or clicking on a compromised email link which locks, deletes, or leaks their files until a ransom is paid, <a href="https://www.cloudflare.com/learning/ddos/ransom-ddos-attack/">Ransom DDoS attacks</a> can be much simpler for threat actors to execute. Ransom DDoS attacks bypass the need for deceptive tactics such as luring victims into opening dubious emails or clicking on fraudulent links, and they don't necessitate a breach into the network or access to corporate resources.</p><p>Over the past quarter, reports of Ransom DDoS attacks continue to decrease. Approximately 8% of respondents reported being threatened or subject to Random DDoS attacks, which continues a decline we've been tracking throughout the year. Hopefully it is because threat actors have realized that organizations will not pay them (which is our <a href="https://www.cloudflare.com/ransom-ddos/">recommendation</a>).</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/19HOqqLzAWDtf28tnsQg5w/03bb32015896bb211edcb3f63e142e09/pasted-image-0--22-.png" />
            
            </figure><p>Ransom DDoS attacks by quarter</p><p>However, keep in mind that this is also very seasonal, and we can expect an increase in ransom DDoS attacks during the months of November and December. If we look at Q4 numbers from the past three years, we can see that Ransom DDoS attacks have been significantly increasing YoY in November. In previous Q4s, it reached a point where one out of every four respondents reported being subject to Ransom DDoS attacks.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5ch5GcIORAOzfXzBwd8XsM/3d881a3b619861bb82bb1d93d11f01f4/pasted-image-0--23-.png" />
            
            </figure>
    <div>
      <h2>Improving your defenses in the era of hyper-volumetric DDoS attacks</h2>
      <a href="#improving-your-defenses-in-the-era-of-hyper-volumetric-ddos-attacks">
        
      </a>
    </div>
    <p>In the past quarter, we saw an unprecedented surge in DDoS attack traffic. This surge was largely driven by the hyper-volumetric HTTP/2 DDoS attack campaign.</p><p>Cloudflare customers using our HTTP reverse proxy, i.e. our CDN/WAF services, are <a href="https://www.cloudflare.com/h2/">already protected</a> from these and other HTTP DDoS attacks. Cloudflare customers that are using non-HTTP services and organizations that are not using Cloudflare at all are strongly encouraged to use an automated, always-on HTTP DDoS Protection service for their HTTP applications.</p><p>It’s important to remember that security is a process, not a single product or flip of a switch. Atop of our automated DDoS protection systems, we offer comprehensive bundled features such as <a href="https://developers.cloudflare.com/firewall/cf-firewall-rules/">firewall</a>, <a href="https://developers.cloudflare.com/bots/">bot detection</a>, <a href="https://www.cloudflare.com/application-services/solutions/api-security/">API protection</a>, and <a href="https://developers.cloudflare.com/cache/">caching</a> to bolster your defenses. Our multi-layered approach optimizes your security posture and minimizes potential impact. We’ve also put together a <a href="https://developers.cloudflare.com/ddos-protection/best-practices/respond-to-ddos-attacks/">list of recommendations</a> to help you optimize your defenses against DDoS attacks, and you can follow our step-by-step wizards to <a href="https://developers.cloudflare.com/learning-paths/application-security/">secure your applications</a> and <a href="https://developers.cloudflare.com/learning-paths/prevent-ddos-attacks/">prevent DDoS attacks</a>.</p><p>...<b>Report methodologies</b>Learn more about our methodologies and how we generate these insights: <a href="https://developers.cloudflare.com/radar/reference/quarterly-ddos-reports">https://developers.cloudflare.com/radar/reference/quarterly-ddos-reports</a></p> ]]></content:encoded>
            <category><![CDATA[DDoS]]></category>
            <category><![CDATA[Attacks]]></category>
            <category><![CDATA[Radar]]></category>
            <category><![CDATA[DDoS Reports]]></category>
            <category><![CDATA[Insights]]></category>
            <category><![CDATA[Trends]]></category>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[Rapid Reset]]></category>
            <guid isPermaLink="false">M67SmSyk26u5hjiQgLBKv</guid>
            <dc:creator>Omer Yoachimik</dc:creator>
            <dc:creator>Jorge Pacheco</dc:creator>
        </item>
        <item>
            <title><![CDATA[Connection coalescing with ORIGIN Frames: fewer DNS queries, fewer connections]]></title>
            <link>https://blog.cloudflare.com/connection-coalescing-with-origin-frames-fewer-dns-queries-fewer-connections/</link>
            <pubDate>Mon, 04 Sep 2023 13:00:51 GMT</pubDate>
            <description><![CDATA[ In this blog we’re going to take a closer look at “connection coalescing”, with specific focus on manage it at a large scale ]]></description>
            <content:encoded><![CDATA[ <p><i>This blog reports and summarizes the contents of a Cloudflare </i><a href="https://research.cloudflare.com/publications/Singanamalla2022/"><i>research paper</i></a><i> which appeared at the ACM </i><a href="https://conferences.sigcomm.org/imc/2022/program/"><i>Internet Measurement Conference</i></a><i>, that measures and prototypes connection coalescing with ORIGIN Frames.</i></p><p>Some readers might be surprised to hear that a single visit to a web page can cause a browser to make tens, sometimes even hundreds, of web connections. Take this very blog as an example. If it is your first visit to the Cloudflare blog, or it has been a while since your last visit, your browser will make multiple connections to render the page. The browser will make DNS queries to find IP addresses corresponding to blog.cloudflare.com and then subsequent requests to retrieve any necessary subresources on the web page needed to successfully render the complete page. How many? Looking below, at the time of writing, there are 32 different hostnames used to load the Cloudflare Blog. That means 32 DNS queries and <i>at least</i> 32 TCP (or QUIC) connections, unless the client is able to reuse (or coalesce) some of those connections.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5iVEUq8ZQ8HsPbg1FAP5jq/de5899ea338a7628e732558caf2f8710/Screenshot-2023-09-03-at-18.34.41.png" />
            
            </figure><p>Each new web connection not only introduces additional load on a server's processing capabilities – potentially leading to scalability challenges during peak usage hours – but also exposes client metadata to the network, such as the plaintext hostnames being accessed by an individual. Such meta information can potentially reveal a user’s online activities and browsing behaviors to on-path network adversaries and eavesdroppers!</p><p>In this blog we’re going to take a closer look at “connection coalescing”. Since our initial look at <a href="/connection-coalescing-experiments/">IP-based coalescing in 2021</a>, we have done further large-scale measurements and modeling across the Internet, to understand and predict if and where coalescing would work best. Since IP coalescing is difficult to manage at large scale, last year we implemented and experimented with a promising standard called the <a href="https://datatracker.ietf.org/doc/rfc8336/">HTTP/2 ORIGIN Frame extension</a> that we leveraged to coalesce connections to our edge without worrying about managing IP addresses.</p><p>All told, there are opportunities being missed by many large providers. We hope that this blog (and our <a href="https://research.cloudflare.com/publications/Singanamalla2022/">publication</a> at ACM IMC 2022 with full details) offers a first step that helps servers and clients take advantage of the ORIGIN Frame standard.</p>
    <div>
      <h3>Setting the stage</h3>
      <a href="#setting-the-stage">
        
      </a>
    </div>
    <p>At a high level, as a user navigates the web, the browser renders web pages by retrieving dependent subresources to construct the complete web page. This process bears a striking resemblance to the way physical products are assembled in a factory. In this sense, a modern web page can be considered like an assembly plant. It relies on a ‘supply chain’ of resources that are needed to produce the final product.</p><p>An assembly plant in the physical world can place a single order for different parts and get a single shipment from the supplier (similar to the <a href="https://www.sciencedirect.com/science/article/abs/pii/092552739290109K">kitting process</a> for maximizing value and minimizing response time); no matter the manufacturer of those parts or where they are made -- one ‘connection’ to the supplier is all that is needed. Any single truck from a supplier to an assembly plant can be filled with parts from multiple manufacturers.</p><p>The design of the web causes browsers to typically do the opposite in nature. To retrieve the images, JavaScript, and other resources on a web page (the parts), web clients (assembly plants) have to make <i>at least</i> one connection to every hostname (the manufacturers) defined in the HTML that is returned by the server (the supplier). It makes no difference if the connections to those hostnames go to the same server or not, for example they could go to a <a href="https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/">reverse proxy</a> like Cloudflare. For each manufacturer a ‘new’ truck would be needed to transfer the materials to the assembly plant from the same supplier, or more formally, a new connection would need to be made to request a subresource from a hostname on the same web page.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3jdJ2PTbkKJKMFxbWD6RgD/40b366c9315d9c55e2409e1654bc0a3d/pasted-image-0--4-.png" />
            
            </figure><p>Without connection coalescing</p><p>The number of connections used to load a web page can be surprisingly high. It is also common for the subresources to need yet other sub-subresources, and so new connections emerge as a result of earlier ones. Remember, too, that HTTP connections to hostnames are often preceded by DNS queries! Connection coalescing allows us to use fewer connections_, or ‘reuse’ the same set of trucks to carry parts from multiple manufacturers from a single supplier._</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/jJx6aGfQCngN6w6D4jpeE/1dcfe2b5e3f8128d8837512ec1a959c9/pasted-image-0--5-.png" />
            
            </figure><p>With connection coalescing </p>
    <div>
      <h3>Connection coalescing in principle</h3>
      <a href="#connection-coalescing-in-principle">
        
      </a>
    </div>
    <p>Connection coalescing was <a href="https://datatracker.ietf.org/doc/html/rfc7540">introduced in HTTP/2</a>, and carried over into <a href="https://www.rfc-editor.org/rfc/rfc9114.html#name-connection-reuse">HTTP/3</a>. We’ve blogged about connection coalescing <a href="/connection-coalescing-experiments/">previously</a> (for a detailed primer we encourage going over that blog). While the idea is simple, implementing it can present a number of engineering challenges. For example, recall from above that there are 32 hostnames (at the time of writing) to load the web page you are reading right now. Among the 32 hostnames are 16 unique domains (defined as “Effective <a href="https://www.cloudflare.com/learning/dns/top-level-domain/">TLD+1</a>”). Can we create fewer connections or ‘coalesce’ existing connections for each unique domain? The answer is ‘<i>Yes, but it depends</i>’.</p><p>The exact number of connections to load the blog page is not at all obvious, and hard to know. There may be 32 hostnames attached to 16 domains but, counter-intuitively, this does not mean the answer to “how many unique connections?” is 16. The true answer could be as few as <i>one</i> connection if all the hostnames are reachable at a single server; or as many as 32 independent connections if a different and distinct server is needed to access each individual hostname.</p><p>Connection reuse comes in many forms, so it’s important to define “connection coalescing” in the HTTP space. For example, the reuse of an existing <a href="https://www.cloudflare.com/learning/ddos/glossary/tcp-ip/">TCP</a> or TLS connection to a hostname to make multiple requests for subresources from that <b><i>same</i></b> hostname is connection reuse, but not coalescing.</p><p>Coalescing occurs when an existing TLS channel for some hostname can be repurposed or used for connecting to a <b><i>different</i></b> hostname. For example, upon visiting blog.cloudflare.com, the HTML points to subresources at cdnjs.cloudflare.com. To reuse the same TLS connection for the subresources, it is necessary for both hostnames to appear together in the TLS certificate's <a href="https://en.wikipedia.org/wiki/Subject_Alternative_Name">“Server Alternative Name (SAN)</a>” list, but this step alone is not sufficient to convince browsers to coalesce. After all, the cdnjs.cloudflare.com service may or may not be reachable at the same server as blog.cloudflare.com, despite being on the same certificate. So how can the browser know? Coalescing only works if servers set up the right conditions, but clients have to decide whether to coalesce or not – thus, browsers require a signal to coalesce beyond the SANs list on the certificate. Revisiting our analogy, the assembly plant may order a part from a manufacturer directly, not knowing that the supplier already has the same part in its warehouse.</p><p>There are two explicit signals a browser can use to decide whether connections can be coalesced: one is IP-based, the other ORIGIN Frame-based. The former requires the server operators to tightly bind DNS records to the HTTP resources available on the server. This is difficult to manage and deploy, and actually creates a risky dependency, because you have to place all the resources behind a specific set or a single IP address. The way IP addresses influence coalescing decisions <a href="https://daniel.haxx.se/blog/2016/08/18/http2-connection-coalescing/">varies among browsers</a>, with some choosing to be more conservative and others more permissive. Alternatively, the HTTP ORIGIN Frame is an easier signal for the servers to orchestrate; it’s also flexible and has graceful failure with no interruption to service (for a specification compliant implementation).</p><p>A foundational difference between both these coalescing signals is: IP-based coalescing signals are implicit, even accidental, and force clients to infer coalescing possibilities that may exist, or not. None of this is surprising since IP addresses are designed to <a href="/addressing-agility/">have no real relationship with names!</a> In contrast, ORIGIN Frame is an explicit signal from servers to clients that coalescing is available no matter what DNS says for any particular hostname.</p><p>We have experimented with <a href="/connection-coalescing-experiments/">IP-based coalescing previously</a>; for the purpose of this blog we will take a deeper look at ORIGIN Frame-based coalescing.</p>
    <div>
      <h3>What is the ORIGIN Frame standard?</h3>
      <a href="#what-is-the-origin-frame-standard">
        
      </a>
    </div>
    <p>The ORIGIN Frame is an extension to the <a href="https://www.rfc-editor.org/rfc/rfc8336">HTTP/2</a> and <a href="https://www.rfc-editor.org/rfc/rfc9412">HTTP/3</a> specification, a special Frame sent on stream 0 or the control stream of the connection respectively. The Frame allows the servers to send an ‘origin-set’ to the clients on an <i>existing</i> established TLS connection, which includes hostnames that it is authorized for and will not incur any <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/421">HTTP 421 errors</a>. Hostnames in the origin-set MUST also appear in the certificate SAN list for the server, even if those hostnames are announced on different IP addresses via DNS.</p><p>Specifically, two different steps are required:</p><ol><li><p>Web servers must send a list enumerating the Origin Set (the hostnames that a given connection might be used for) in the ORIGIN Frame extension.</p></li><li><p>The TLS certificate returned by the web server must cover the additional hostnames being returned in the ORIGIN Frame in the DNS names SAN entries.</p></li></ol><p>At a high-level ORIGIN Frames are a supplement to the TLS certificate that operators can attach to say, “Psst! Hey, client, here are the names in the SANs that are available on this connection -- you can coalesce!” Since the ORIGIN Frame is not part of the certificate itself, its contents can be made to change independently. No new certificate is required. There is also no dependency on IP addresses. For a coalesceable hostname, existing TCP/QUIC+TLS connections can be reused without requiring new connections or DNS queries.</p><p><a href="https://w3techs.com/technologies/overview/proxy">Many websites today</a> rely on content which is served by CDNs, like Cloudflare CDN service. The practice of using external CDN services offers websites the advantages of speed, reliability, and reduces the load of content served by their <a href="https://www.cloudflare.com/learning/cdn/glossary/origin-server/">origin servers</a>. When both the website, and the resources are served by the same CDN, despite being different hostnames, owned by different entities, it opens up some very interesting opportunities for CDN operators to allow connections to be reused and coalesced since they can control both the certificate management and connection requests for sending ORIGIN frames on behalf of the real origin server.</p><p>Unfortunately, there has been no way to turn the possibilities enabled by ORIGIN Frame into practice. To the best of our knowledge, until today, there has been no server implementation that supports ORIGIN Frames. Among browsers, only Firefox supports ORIGIN Frames. Since IP coalescing is challenging and ORIGIN Frame has no deployed support, is the engineering time and energy to better support coalescing worth the investment? We decided to find out with a large-scale Internet-wide measurement to understand the opportunities and predict the possibilities, and then implemented the ORIGIN Frame to experiment on production traffic.</p>
    <div>
      <h3>Experiment #1: What is the scale of required changes?</h3>
      <a href="#experiment-1-what-is-the-scale-of-required-changes">
        
      </a>
    </div>
    <p>In February 2021, <a href="/connection-coalescing-experiments/">we collected data</a> for 500K of the <a href="https://radar.cloudflare.com/domains">most popular websites</a> on the Internet, using a modified <a href="https://github.com/WPO-Foundation/webpagetest">Web Page Test</a> on 100 virtual machines. An automated Chrome (v88) browser instance was launched for every visit to a web page to eliminate caching effects (because we wanted to understand coalescing, not caching). On successful completion of each session, Chrome developer tools were used to retrieve and write the page load data as an HTTP Archive format (HAR) file with a full timeline of events, as well as additional information about certificates and their validation. Additionally, we parsed the certificate chains for the root web page and new TLS connections triggered by subresource requests to (i) identify certificate issuers for the hostnames, (ii) inspect the presence of the Subject Alternative Name (SAN) extension, and (iii) validate that DNS names resolve to the IP address used. Further details about our methodology and results can be found in the technical <a href="https://research.cloudflare.com/publications/Singanamalla2022/">paper</a>.</p><p>The first step was to understand what resources are requested by web pages to successfully render the page contents, and where these resources were present on the Internet. Connection coalescing becomes possible when subresource domains are ideally co-located. We approximated the location of a domain by finding its corresponding autonomous system (AS). For example, the domain attached to <a href="https://cdnjs.cloudflare.com/https://cdnjs.cloudflare.com/">cdnjs</a> is reachable via AS 13335 in the BGP routing table, and that AS number belongs to Cloudflare. The figure below describes the percentage of web pages and the number of unique ASes needed to fully load a web page.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3H188I6GyYxiqZEYxBPMPp/4bde6b40a523d0e66207c87cee40755c/Screenshot-2023-08-31-at-1.39.16-PM.png" />
            
            </figure><p>Around 14% of the web pages need two ASes to fully load i.e. pages that have a dependency on one additional AS for subresources. More than 50% of the web pages need to contact no more than six ASes to obtain all the necessary subresources. This finding as shown in the plot above implies that a relatively small number of operators serve the sub-resource content necessary for a majority (~50%) of the websites, and any usage of ORIGIN Frames would need only a few changes to have its intended impact. The potential for connection coalescing can therefore be optimistically approximated to the number of unique ASes needed to retrieve all subresources in a web page. In practice however, this may be superseded by operational factors such as SLAs or helped by flexible mappings between sockets, names, and IP addresses which we worked on <a href="https://research.cloudflare.com/publications/Fayed2021/">previously at Cloudflare</a>.</p><p>We then tried to understand the impact of coalescing on connection metrics. The measured and ideal number of DNS queries and TLS connections needed to load a web page are summarized by their CDFs in the figure below.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7aCaLsYdjNqeuQAuVSfQ6c/beae2aeaf3e96830f9562c09aeb0a2cd/Screenshot-2023-08-31-at-1.39.02-PM.png" />
            
            </figure><p>Through modeling and extensive analysis, we identify that connection coalescing through ORIGIN Frames could reduce the number of DNS and TLS connections made by browsers by over 60% at the median. We performed this modeling by identifying the number of times the clients requested DNS records, and combined them with the ideal ORIGIN Frames to serve.</p><p>Many multi-origin servers such as those operated by <a href="https://www.cloudflare.com/learning/cdn/what-is-a-cdn/">CDNs</a> tend to reuse certificates and serve the same certificate with multiple DNS SAN entries. This allows the operators to manage fewer certificates through their creation and renewal cycles. While theoretically one can have millions of names in the certificate, creating such certificates is unreasonable and a challenge to manage effectively. By continuing to rely on existing certificates, our modeling measurements bring to light the volume of changes required to enable perfect coalescing, while presenting information about the scale of changes needed, as highlighted in the figure below.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5rIcRVeD6UEGNCW9dj3MYM/187f0bc53e9afedf3baca072410eb4db/Screenshot-2023-08-31-at-1.38.35-PM.png" />
            
            </figure><p>We identify that over 60% of the certificates served by websites do not need any modifications and could benefit from ORIGIN Frames, while with no more than 10 additions to the DNS SAN names in certificates we’re able to successfully coalesce connections to over 92% of the websites in our measurement. The most effective changes could be made by CDN providers by adding three or four of their most popular requested hostnames into each certificate.</p>
    <div>
      <h3>Experiment #2: ORIGIN Frames in action</h3>
      <a href="#experiment-2-origin-frames-in-action">
        
      </a>
    </div>
    <p>In order to validate our modeling expectations, we then took a more active approach in early 2022. Our next experiment focused on 5,000 websites that make extensive use of <i>cdnjs.cloudflare.com</i> as a subresource. By modifying our experimental TLS termination endpoint we deployed HTTP/2 ORIGIN Frame support as defined in the <a href="https://datatracker.ietf.org/doc/rfc8336/">RFC standard</a>. This involved changing the internal fork of <i>net</i> and <i>http</i> dependency modules of Golang which we have open sourced (<a href="https://github.com/cloudflare/go-originframe">see here</a>, and <a href="https://github.com/cloudflare/net-originframe">here</a>).</p><p>During the experiments, connecting to a website in the experiment set would return <i>cdnjs.cloudflare.com</i> in the ORIGIN frame, while the control set returned an arbitrary (unused) hostname. All existing edge certificates for the 5000 websites were also modified. For the experimental group, the corresponding certificates were renewed with <i>cdnjs.cloudflare.com</i> added to the SAN. To ensure integrity between control and experimental sets, control group domains certificates were also renewed with a valid and identical size third party domain used by none of the control domains. This is done to ensure that the relative size changes to the certificates is kept constant avoiding potential biases due to different certificate sizes. Our results were striking!</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2jGJXHliykd9CGh3lNujpq/bc1b9faf871d7d4c6ecf7041966078cb/Screenshot-2023-08-31-at-1.38.47-PM.png" />
            
            </figure><p>Sampling 1% of the requests we received from Firefox to the websites in the experiment, we identified over <b>50% reduction in new TLS connections per second</b> indicating a lesser number of cryptographic verification operations done by both the client and reduced server compute overheads. As expected there were no differences in the control set indicating the effectiveness of connection re-use as seen by the CDN or server operators.</p>
    <div>
      <h3>Discussion and insights</h3>
      <a href="#discussion-and-insights">
        
      </a>
    </div>
    <p>While our modeling measurements indicated that we could anticipate some performance improvements, in practice it was not significantly better suggesting that ‘no-worse’ is the appropriate mental model regarding performance. The subtle interplay between resource object sizes, competing connections, and congestion control is subject to network conditions. Bottleneck-share capacity, for example, diminishes as fewer connections compete for bottleneck resources on network links. It would be interesting to revisit these measurements as more operators deploy support on their servers for ORIGIN Frames.</p><p>Apart from performance, one major benefit of ORIGIN frames is in terms of privacy. How? Well, each coalesced connection hides client metadata that is otherwise leaked from non-coalesced connections. Certain resources on a web page are loaded depending on how one is interacting with the website. This means for every new connection for retrieving some resource from the server, TLS plaintext metadata like <a href="https://www.cloudflare.com/learning/ssl/what-is-sni/">SNI</a> (in the absence of <a href="/encrypted-client-hello/">Encrypted Client Hello</a>) and at least one plaintext DNS query, if transmitted over UDP or TCP on port 53, is exposed to the network. Coalescing connections helps remove the need for browsers to open new TLS connections, and the need to do extra DNS queries. This prevents metadata leakage from anyone listening on the network. ORIGIN Frames help minimize those signals from the network path, improving privacy by reducing the amount of cleartext information leaked on path to network eavesdroppers.</p><p>While the browsers benefit from reduced cryptographic computations needed to verify multiple certificates, a major advantage comes from the fact that it opens up very interesting future opportunities for resource scheduling at the endpoints (the browsers, and the origin servers) such as <a href="/better-http-3-prioritization-for-a-faster-web/">prioritization</a>, or recent proposals like <a href="/early-hints/">HTTP early hints</a> to provide clients experiences where connections are not overloaded or competing for those resources. When coupled with <a href="https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-http2-secondary-certs-06#section-3.4">CERTIFICATE Frames</a> IETF draft, we can further eliminate the need for manual certificate modifications as a server can prove its authority of hostnames after connection establishment without any additional SAN entries on the website’s TLS certificate.</p>
    <div>
      <h3>Conclusion and call to action</h3>
      <a href="#conclusion-and-call-to-action">
        
      </a>
    </div>
    <p>In summary, the current Internet ecosystem has a lot of opportunities for connection coalescing with only a few changes to certificates and their server infrastructure. Servers can significantly reduce the number of TLS handshakes by roughly 50%, while reducing the number of render blocking DNS queries by over 60%. Clients additionally reap these benefits in privacy by reducing cleartext DNS exposure to network on-lookers.</p><p>To help make this a reality we are currently planning to add support for both HTTP/2 and HTTP/3 ORIGIN Frames for our customers. We also encourage other operators that manage third party resources to adopt support of ORIGIN Frame to improve the Internet ecosystem.Our paper submission was accepted to the ACM Internet Measurement Conference 2022 and is <a href="https://research.cloudflare.com/publications/Singanamalla2022/">available for download</a>. If you’d like to work on projects like this, where you get to see the rubber meet the road for new standards, visit our <a href="https://www.cloudflare.com/careers/">careers page</a>!</p> ]]></content:encoded>
            <category><![CDATA[DNS]]></category>
            <category><![CDATA[Internship Experience]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[TLS]]></category>
            <category><![CDATA[Research]]></category>
            <guid isPermaLink="false">QjYiQB1Bf6uRL71yURBMi</guid>
            <dc:creator>Suleman Ahmad</dc:creator>
            <dc:creator>Jonathan Hoyland</dc:creator>
            <dc:creator>Sudheesh Singanamalla</dc:creator>
        </item>
        <item>
            <title><![CDATA[The state of HTTP in 2022]]></title>
            <link>https://blog.cloudflare.com/the-state-of-http-in-2022/</link>
            <pubDate>Fri, 30 Dec 2022 14:00:00 GMT</pubDate>
            <description><![CDATA[ So what happened at all of those working group meetings, specification documents, and side events in 2022? What are implementers and deployers of the web’s protocol doing? And what’s coming next? ]]></description>
            <content:encoded><![CDATA[ <p></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6YG57TW3Ue3Z2iGZU7dO4u/853a3d2f76588ca638c4e24727f5eca5/http3-tube_2x-2.png" />
            
            </figure><p>At over thirty years old, HTTP is still the foundation of the web and one of the Internet’s most popular protocols—not just for browsing, watching videos and listening to music, but also for apps, machine-to-machine communication, and even as a basis for building other protocols, forming what some refer to as a “second waist” in the classic Internet hourglass diagram.</p><p>What makes HTTP so successful? One answer is that it hits a “sweet spot” for most applications that need an application protocol. “<a href="https://httpwg.org/specs/rfc9205.html">Building Protocols with HTTP</a>” (published in 2022 as a Best Current Practice RFC by the <a href="https://httpwg.org/">HTTP Working Group</a>) argues that HTTP’s success can be attributed to factors like:</p><p>- familiarity by implementers, specifiers, administrators, developers, and users;- availability of a variety of client, server, and proxy implementations;- ease of use;- availability of web browsers;- reuse of existing mechanisms like authentication and encryption;- presence of HTTP servers and clients in target deployments; and- its ability to traverse firewalls.</p><p>Another important factor is the community of people using, implementing, and standardising HTTP. We work together to maintain and develop the protocol actively, to assure that it’s interoperable and meets today’s needs. If HTTP stagnates, another protocol will (justifiably) replace it, and we’ll lose all the community’s investment, shared understanding and interoperability.</p><p>Cloudflare and many others do this by sending engineers to <a href="/cloudflare-and-the-ietf/">participate in the IETF</a>, where most Internet protocols are discussed and standardised. We also attend and sponsor community events like the <a href="https://httpwork.shop">HTTP Workshop</a> to have conversations about what problems people have, what they need, and understand what changes might help them.</p><p>So what happened at all of those working group meetings, specification documents, and side events in 2022? What are implementers and deployers of the web’s protocol doing? And what’s coming next?</p>
    <div>
      <h3>New Specification: HTTP/3</h3>
      <a href="#new-specification-http-3">
        
      </a>
    </div>
    <p>Specification-wise, the biggest thing to happen in 2022 was the publication of <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a>, because it was an enormous step towards keeping up with the requirements of modern applications and sites by using the network more efficiently to unblock web performance.</p><p>Way back in the 90s, HTTP/0.9 and HTTP/1.0 used a new TCP connection for each request—an astoundingly inefficient use of the network. HTTP/1.1 introduced persistent connections (which were backported to HTTP/1.0 with the `Connection: Keep-Alive` header). This was an improvement that helped servers and the network cope with the explosive popularity of the web, but even back then, the community knew it had significant limitations—in particular, head-of-line blocking (where one outstanding request on a connection blocks others from completing).</p><p>That didn’t matter so much in the 90s and early 2000s, but today’s web pages and applications place demands on the network that make these limitations performance-critical. Pages often have hundreds of assets that all compete for network resources, and HTTP/1.1 wasn’t up to the task. After some <a href="https://www.w3.org/Protocols/HTTP-NG/">false starts</a>, the community finally <a href="/http-2-for-web-developers/">addressed these issues with HTTP/2 in 2015</a>.</p><p>However, removing head-of-line blocking in HTTP exposed the same problem one layer lower, in TCP. Because TCP is an in-order, reliable delivery protocol, loss of a single packet in a flow can block access to those after it—even if they’re sitting in the operating system’s buffers. This turns out to be a real issue for HTTP/2 deployment, especially on less-than-optimal networks.</p><p>The answer, of course, was to replace TCP—the venerable transport protocol that so much of the Internet is built upon. After much discussion and many drafts in the <a href="https://quicwg.org/">QUIC Working Group</a>, <a href="/quic-version-1-is-live-on-cloudflare/">QUIC version 1 was published as that replacement</a> in 2021.</p><p>HTTP/3 is the version of HTTP that uses QUIC. While the working group effectively finished it in 2021 along with QUIC, its publication was held until 2022 to synchronise with the publication of other documents (see below). 2022 was also a <a href="/cloudflare-view-http3-usage/">milestone year for HTTP/3 deployment</a>; Cloudflare saw <a href="https://radar.cloudflare.com/adoption-and-usage?range=28d">increasing adoption and confidence</a> in the new protocol.</p><p>While there was only a brief gap of a few years between HTTP/2 and HTTP/3, there isn’t much appetite for working on HTTP/4 in the community soon. QUIC and HTTP/3 are both new, and the world is still learning how best to implement the protocols, operate them, and build sites and applications using them. While we can’t rule out a limitation that will force a new version in the future, the IETF built these protocols based upon broad industry experience with modern networks, and have significant extensibility available to ease any necessary changes.</p>
    <div>
      <h3>New specifications: HTTP “core”</h3>
      <a href="#new-specifications-http-core">
        
      </a>
    </div>
    <p>The other headline event for HTTP specs in 2022 was the publication of its “core” documents -- the heart of HTTP’s specification. The core comprises: <a href="https://httpwg.org/specs/rfc9110.html">HTTP Semantics</a> - things like methods, headers, status codes, and the message format; <a href="https://httpwg.org/specs/rfc9111.html">HTTP Caching</a> - how HTTP caches work; <a href="https://httpwg.org/specs/rfc9112.html">HTTP/1.1</a> - mapping semantics to the wire, using the format everyone knows and loves.</p><p>Additionally, <a href="https://httpwg.org/specs/rfc9113.html">HTTP/2 was republished</a> to properly integrate with the Semantics document, and to fix a few outstanding issues.</p><p>This is the latest in a long series of revisions for these documents—in the past, we’ve had the RFC 723x series, the (perhaps most well-known) RFC 2616, RFC 2068, and the grandparent of them all, RFC 1945. Each revision has aimed to improve readability, fix errors, explain concepts better, and clarify protocol operation. Poorly specified (or implemented) features are deprecated; new features that improve protocol operation are added. See the ‘Changes from...’ appendix in each document for the details. And, importantly, always refer to the latest revisions linked above; the older RFCs are now obsolete.</p>
    <div>
      <h3>Deploying Early Hints</h3>
      <a href="#deploying-early-hints">
        
      </a>
    </div>
    <p>HTTP/2 included <i>server push</i>, a feature designed to allow servers to “push” a request/response pair to clients when they knew the client was going to need something, so it could avoid the latency penalty of making a request and waiting for the response.</p><p>After HTTP/2 was finalised in 2015, Cloudflare and many other HTTP implementations soon <a href="/announcing-support-for-http-2-server-push-2/">rolled out server push</a> in anticipation of big performance wins. Unfortunately, it turned out that’s harder than it looks; server push effectively requires the server to predict the future—not only what requests the client will send but also what the network conditions will be. And, when the server gets it wrong (“over-pushing”), the pushed requests directly compete with the real requests that the browser is making, representing a significant opportunity cost with real potential for harming performance, rather than helping it. The impact is even worse when the browser already has a copy in cache, so it doesn’t need the push at all.</p><p>As a result, <a href="https://developer.chrome.com/blog/removing-push/">Chrome removed HTTP/2 server push in 2022</a>. Other browsers and servers might still support it, but the community seems to agree that it’s only suitable for specialised uses currently, like the browser notification-specific <a href="https://www.rfc-editor.org/rfc/rfc8030.html">Web Push Protocol</a>.</p><p>That doesn’t mean that we’re giving up, however. The <a href="https://httpwg.org/specs/rfc8297.html">103 (Early Hints)</a> status code was published as an Experimental RFC by the HTTP Working Group in 2017. It allows a server to send <i>hints</i> to the browser in a non-final response, before the “real” final response. That’s useful if you know that the content is going to include some links to resources that the browser will fetch, but need more time to get the response to the client (because it will take more time to generate, or because the server needs to fetch it from somewhere else, like a CDN does).</p><p>Early Hints can be used in many situations that server push was designed for -- for example, when you have CSS and JavaScript that a page is going to need to load. In theory, they’re not as optimal as server push, because they only allow hints to be sent when there’s an outstanding request, and because getting the hints to the client and acted upon adds some latency.</p><p>In practice, however, Cloudflare and our partners (like Shopify and Google) spent 2022 experimenting with Early Hints and finding them much safer to use, with <a href="/early-hints-performance/">promising performance benefits</a> that include significant reductions in key web performance metrics.</p><p>We’re excited about the potential that Early Hints show; so excited that we’ve <a href="/early-hints-on-cloudflare-pages/">integrated them into Cloudflare Pages</a>. We’re also evaluating new ways to improve performance using this new capability in the protocol.</p>
    <div>
      <h3>Privacy-focused intermediation</h3>
      <a href="#privacy-focused-intermediation">
        
      </a>
    </div>
    <p>For many, the most exciting HTTP protocol extensions in 2022 focused on intermediation—the ability to insert proxies, gateways, and similar components into the protocol to achieve specific goals, often focused on improving privacy.</p><p>The <a href="https://ietf-wg-masque.github.io">MASQUE Working Group</a>, for example, is an effort to add new tunneling capabilities to HTTP, so that an intermediary can pass the tunneled traffic along to another server.</p><p>While CONNECT has enabled TCP tunnels for a long time, MASQUE enabled <a href="https://datatracker.ietf.org/doc/html/rfc9298">UDP tunnels</a>, allowing more protocols to be tunneled more efficiently–including QUIC and HTTP/3.</p><p>At Cloudflare, we’re enthusiastic to be working with Apple to use MASQUE to implement <a href="/icloud-private-relay/">iCloud Private Relay</a> and enhance their customers’ privacy without relying solely on one company. We’re also very interested in the Working Group’s future work, including <a href="/unlocking-quic-proxying-potential/">IP tunneling</a> that will enable MASQUE-based VPNs.Another intermediation-focused specification is <a href="https://www.ietf.org/archive/id/draft-ietf-ohai-ohttp-06.html">Oblivious HTTP</a> (or OHTTP). OHTTP uses sets of intermediaries to prevent the server from using connections or IP addresses to track clients, giving greater privacy assurances for things like collecting telemetry or other sensitive data. This specification is just finishing the standards process, and we’re using it to build an important new product, <a href="/building-privacy-into-internet-standards-and-how-to-make-your-app-more-private-today/">Privacy Gateway</a>, to protect the privacy of our customers’ customers.</p><p>We and many others in the Internet community believe that this is just the start, because intermediation can partition communication, a <a href="https://intarchboard.github.io/draft-obliviousness/draft-kpw-iab-privacy-partitioning.html">valuable tool for improving privacy</a>.</p>
    <div>
      <h3>Protocol security</h3>
      <a href="#protocol-security">
        
      </a>
    </div>
    <p>Finally, 2022 saw a lot of work on security-related aspects of HTTP. The <a href="https://httpwg.org/http-extensions/draft-ietf-httpbis-digest-headers.html">Digest Fields</a> specification is an update to the now-ancient `Digest` header field, allowing integrity digests to be added to messages. The <a href="https://httpwg.org/http-extensions/draft-ietf-httpbis-message-signatures.html">HTTP Message Signatures</a> specification enables cryptographic signatures on requests and responses -- something that has widespread ad hoc deployment, but until now has lacked a standard. Both specifications are in the final stages of standardisation.</p><p>A <a href="https://httpwg.org/http-extensions/draft-ietf-httpbis-rfc6265bis.html">revision of the Cookie specification</a> also saw a lot of progress in 2022, and should be final soon. Since it’s not possible to get rid of them completely soon, much work has taken place to limit how they operate to improve privacy and security, including a new `SameSite` attribute.</p><p>Another set of security-related specifications that Cloudflare has <a href="/cloudflare-supports-privacy-pass/">invested in for many years</a> is <a href="https://www.ietf.org/archive/id/draft-ietf-privacypass-architecture-09.html">Privacy Pass</a> also known as “Private Access Tokens.” These are cryptographic tokens that can assure clients are real people, not bots, without using an intrusive CAPTCHA, and without tracking the user’s activity online. In HTTP, they take the form of a <a href="https://www.ietf.org/archive/id/draft-ietf-privacypass-auth-scheme-07.html">new authentication scheme</a>.</p><p>While Privacy Pass is still not quite through the standards process, 2022 saw its <a href="/eliminating-captchas-on-iphones-and-macs-using-new-standard/">broad deployment by Apple</a>, a huge step forward. And since <a href="/turnstile-private-captcha-alternative/">Cloudflare uses it in Turnstile</a>, our CAPTCHA alternative, your users can have a better experience today.</p>
    <div>
      <h3>What about 2023?</h3>
      <a href="#what-about-2023">
        
      </a>
    </div>
    <p>So, what’s next? Besides, the specifications above that aren’t quite finished, the HTTP Working Group has a few other works in progress, including a <a href="https://httpwg.org/http-extensions/draft-ietf-httpbis-safe-method-w-body.html">QUERY method</a> (think GET but with a body), <a href="https://httpwg.org/http-extensions/draft-ietf-httpbis-resumable-upload.html">Resumable Uploads</a> (based on <a href="https://tus.io">tus</a>), <a href="https://httpwg.org/http-extensions/draft-ietf-httpbis-variants.html">Variants</a> (an improved Vary header for caching), <a href="https://httpwg.org/http-extensions/draft-ietf-httpbis-sfbis.html">improvements to Structured Fields</a> (including a new Date type), and a way to <a href="https://httpwg.org/http-extensions/draft-ietf-httpbis-retrofit.html">retrofit existing headers into Structured Fields</a>. We’ll write more about these as they progress in 2023.</p><p>At the <a href="https://github.com/HTTPWorkshop/workshop2022/blob/main/report.md">2022 HTTP Workshop</a>, the community also talked about what new work we can take on to improve the protocol. Some ideas discussed included improving our shared protocol testing infrastructure (right now we have a <a href="https://github.com/httpwg/wiki/wiki/HTTP-Testing-Resources">few resources</a>, but it could be much better), improving (or replacing) <a href="https://httpwg.org/specs/rfc7838.html">Alternative Services</a> to allow more intelligent and correct connection management, and more radical changes, like <a href="https://mnot.github.io/I-D/draft-nottingham-binary-structured-headers.html">alternative, binary serialisations of headers</a>.</p><p>There’s also a continuing discussion in the community about whether HTTP should accommodate pub/sub, or whether it should be standardised to work over WebSockets (and soon, WebTransport). Although it’s hard to say now, adjacent work on <a href="https://datatracker.ietf.org/group/moq/about/">Media over QUIC</a> that just started <i>might</i> provide an opportunity to push this forward.</p><p>Of course, that’s not everything, and what happens to HTTP in 2023 (and beyond) remains to be seen. HTTP is still evolving, even as it stays compatible with the largest distributed hypertext system ever conceived—the World Wide Web.</p> ]]></content:encoded>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[HTTP3]]></category>
            <category><![CDATA[Privacy]]></category>
            <category><![CDATA[Performance]]></category>
            <guid isPermaLink="false">2ChQ8N8Cg6LwDWafsFjWJN</guid>
            <dc:creator>Mark Nottingham</dc:creator>
        </item>
        <item>
            <title><![CDATA[Moving k8s communication to gRPC]]></title>
            <link>https://blog.cloudflare.com/moving-k8s-communication-to-grpc/</link>
            <pubDate>Sat, 20 Mar 2021 14:00:00 GMT</pubDate>
            <description><![CDATA[ How we use gRPC in combination with Kubernetes to improve the performance and usability of internal APIs. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Over the past year and a half, Cloudflare has been hard at work moving our back-end services running in our non-edge locations from bare metal solutions and Mesos Marathon to a more unified approach using <a href="https://kubernetes.io/">Kubernetes(K8s)</a>. We chose Kubernetes because it allowed us to split up our monolithic application into many different microservices with granular control of communication.</p><p>For example, a <a href="https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/">ReplicaSet</a> in Kubernetes can provide high availability by ensuring that the correct number of pods are always available. A <a href="https://kubernetes.io/docs/concepts/workloads/pods/">Pod</a> in Kubernetes is similar to a container in <a href="https://www.docker.com/">Docker</a>. Both are responsible for running the actual application. These pods can then be exposed through a Kubernetes <a href="https://kubernetes.io/docs/concepts/services-networking/service/">Service</a> to abstract away the number of replicas by providing a single endpoint that load balances to the pods behind it. The services can then be exposed to the Internet via an <a href="https://kubernetes.io/docs/concepts/services-networking/ingress/">Ingress</a>. Lastly, a network policy can protect against unwanted communication by ensuring the correct policies are applied to the application. These policies can include L3 or L4 rules.</p><p>The diagram below shows a simple example of this setup.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/33zWCqFZw2iuXfhllsHgdk/e290742e17a975a98a195bccc283297f/2-3.png" />
            
            </figure><p>Though Kubernetes does an excellent job at providing the tools for communication and traffic management, it does not help the developer decide the best way to communicate between the applications running on the pods. Throughout this blog we will look at some of the decisions we made and why we made them to discuss the pros and cons of two commonly used API architectures, REST and gRPC.</p>
    <div>
      <h3>Out with the old, in with the new</h3>
      <a href="#out-with-the-old-in-with-the-new">
        
      </a>
    </div>
    <p>When the DNS team first moved to Kubernetes, all of our pod-to-pod communication was done through REST APIs and in many cases also included Kafka. The general communication flow was as follows:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3GQIkngkqEYcBJNFzv1xNU/fe13bc8911a11a9c26dc5925b4fe6a19/1-5.png" />
            
            </figure><p>We use Kafka because it allows us to handle large spikes in volume without losing information. For example, during a Secondary DNS Zone zone transfer, Service A tells Service B that the zone is ready to be published to the edge. Service B then calls Service A’s REST API, generates the zone, and pushes it to the edge. If you want more information about how this works, I wrote an entire blog post about the <a href="/secondary-dns-deep-dive/">Secondary DNS pipeline</a> at Cloudflare.</p><p>HTTP worked well for most communication between these two services. However, as we scaled up and added new endpoints, we realized that as long as we control both ends of the communication, we could improve the usability and performance of our communication. In addition, sending large DNS zones over the network using HTTP often caused issues with sizing constraints and compression.</p><p>In contrast, gRPC can easily stream data between client and server and is commonly used in microservice architecture. These qualities made gRPC the obvious replacement for our REST APIs.</p>
    <div>
      <h3>gRPC Usability</h3>
      <a href="#grpc-usability">
        
      </a>
    </div>
    <p>Often overlooked from a developer’s perspective, HTTP client libraries are clunky and require code that defines paths, handles parameters, and deals with responses in bytes. gRPC abstracts all of this away and makes network calls feel like any other function calls defined for a struct.</p><p>The example below shows a very basic schema to set up a GRPC client/server system. As a result of gRPC using <a href="https://developers.google.com/protocol-buffers">protobuf</a> for serialization, it is largely language agnostic. Once a schema is defined, the <i>protoc</i> command can be used to generate code for <a href="https://grpc.io/docs/languages/">many languages</a>.</p><p>Protocol Buffer data is structured as <i>messages,</i> with each <i>message</i> containing information stored in the form of fields. The fields are strongly typed, providing type safety unlike JSON or XML. Two messages have been defined, <i>Hello</i> and <i>HelloResponse</i>. Next we define a service called <i>HelloWorldHandler</i> which contains one RPC function called <i>SayHello</i> that must be implemented if any object wants to call themselves a <i>HelloWorldHandler</i>.</p><p>Simple Proto:</p>
            <pre><code>message Hello{
   string Name = 1;
}

message HelloResponse{}

service HelloWorldHandler {
   rpc SayHello(Hello) returns (HelloResponse){}
}</code></pre>
            <p>Once we run our <i>protoc</i> command, we are ready to write the server-side code. In order to implement the <i>HelloWorldHandler</i>, we must define a struct that implements all of the RPC functions specified in the protobuf schema above_._ In this case, the struct <i>Server</i> defines a function <i>SayHello</i> that takes in two parameters, context and <i>*pb.Hello</i>. <i>*pb.Hello</i> was previously specified in the schema and contains one field, <i>Name. SayHello</i> must also return the <i>*pbHelloResponse</i> which has been defined without fields for simplicity.</p><p>Inside the main function, we create a TCP listener, create a new gRPC server, and then register our handler as a <i>HelloWorldHandlerServer</i>. After calling <i>Serve</i> on our gRPC server, clients will be able to communicate with the server through the function <i>SayHello</i>.</p><p>Simple Server:</p>
            <pre><code>type Server struct{}

func (s *Server) SayHello(ctx context.Context, in *pb.Hello) (*pb.HelloResponse, error) {
    fmt.Println("%s says hello\n", in.Name)
    return &amp;pb.HelloResponse{}, nil
}

func main() {
    lis, err := net.Listen("tcp", ":8080")
    if err != nil {
        panic(err)
    }
    gRPCServer := gRPC.NewServer()
    handler := Server{}
    pb.RegisterHelloWorldHandlerServer(gRPCServer, &amp;handler)
    if err := gRPCServer.Serve(lis); err != nil {
        panic(err)
    }
}</code></pre>
            <p>Finally, we need to implement the gRPC Client. First, we establish a TCP connection with the server. Then, we create a new <i>pb.HandlerClient</i>. The client is able to call the server's <i>SayHello</i> function by passing in a *<i>pb.Hello</i> object.</p><p>Simple Client:</p>
            <pre><code>conn, err := gRPC.Dial("127.0.0.1:8080", gRPC.WithInsecure())
if err != nil {
    panic(err)
}
client := pb.NewHelloWorldHandlerClient(conn)
client.SayHello(context.Background(), &amp;pb.Hello{Name: "alex"})</code></pre>
            <p>Though I have removed some code for simplicity, these <i>services</i> and <i>messages</i> can become quite complex if needed. The most important thing to understand is that when a server attempts to announce itself as a <i>HelloWorldHandlerServer</i>, it is required to implement the RPC functions as specified within the protobuf schema. This agreement between the client and server makes cross-language network calls feel like regular function calls.</p><p>In addition to the basic Unary server described above, gRPC lets you decide between four types of service methods:</p><ul><li><p><b>Unary</b> (example above): client sends a single request to the server and gets a single response back, just like a normal function call.</p></li><li><p><b>Server Streaming:</b> server returns a stream of messages in response to a client's request.</p></li><li><p><b>Client Streaming:</b> client sends a stream of messages to the server and the server replies in a single message, usually once the client has finished streaming.</p></li><li><p><b>Bi-directional Streaming:</b> the client and server can both send streams of messages to each other asynchronously.</p></li></ul>
    <div>
      <h3>gRPC Performance</h3>
      <a href="#grpc-performance">
        
      </a>
    </div>
    <p>Not all HTTP connections are created equal. Though Golang natively supports HTTP/2, the HTTP/2 transport must be set by the client and the server must also support HTTP/2. Before moving to gRPC, we were still using HTTP/1.1 for client connections. We could have switched to HTTP/2 for performance gains, but we would have lost some of the benefits of native protobuf compression and usability changes.</p><p>The best option available in HTTP/1.1 is pipelining. Pipelining means that although requests can share a connection, they must queue up one after the other until the request in front completes. HTTP/2 improved pipelining by using connection multiplexing. Multiplexing allows for multiple requests to be sent on the same connection and at the same time.</p><p>HTTP REST APIs generally use JSON for their request and response format. Protobuf is the native request/response format of gRPC because it has a standard schema agreed upon by the client and server during registration. In addition, protobuf is known to be significantly faster than JSON due to its serialization speeds. I’ve run some benchmarks on my laptop, source code can be found <a href="https://github.com/Fattouche/protobuf-benchmark">here</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/23TkQ80Iruo8IYflqIuobN/f7323dd5817ca47f9b203b8b63a3a980/image1-26.png" />
            
            </figure><p>As you can see, protobuf performs better in small, medium, and large data sizes. It is faster per operation, smaller after marshalling, and scales well with input size. This becomes even more noticeable when unmarshaling very large data sets. Protobuf takes 96.4ns/op but JSON takes 22647ns/op, a 235X reduction in time! For large DNS zones, this efficiency makes a massive difference in the time it takes us to go from record change in our API to serving it at the edge.</p><p>Combining the benefits of HTTP/2 and protobuf showed almost no performance change from our application’s point of view. This is likely due to the fact that our pods were already so close together that our connection times were already very low. In addition, most of our gRPC calls are done with small amounts of data where the difference is negligible. One thing that we did notice <b>—</b> likely related to the multiplexing of HTTP/2 <b>—</b> was greater efficiency when writing newly created/edited/deleted records to the edge. Our latency spikes dropped in both amplitude and frequency.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6PDR6bZkh8zzVVv2j6tmE5/9ce516e00daa832135964246eaf7b95c/image2-19.png" />
            
            </figure>
    <div>
      <h3>gRPC Security</h3>
      <a href="#grpc-security">
        
      </a>
    </div>
    <p>One of the best features in Kubernetes is the NetworkPolicy. This allows developers to control what goes in and what goes out.</p>
            <pre><code>apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978</code></pre>
            <p>In this example, taken from the <a href="https://kubernetes.io/docs/concepts/services-networking/network-policies/">Kubernetes docs</a>, we can see that this will create a network policy called test-network-policy. This policy controls both ingress and egress communication to or from any pod that matches the role <i>db</i> and enforces the following rules:</p><p>Ingress connections allowed:</p><ul><li><p>Any pod in default namespace with label “role=frontend”</p></li><li><p>Any pod in any namespace that has a label “project=myproject”</p></li><li><p>Any source IP address in 172.17.0.0/16 except for 172.17.1.0/24</p></li></ul><p>Egress connections allowed:</p><ul><li><p>Any dest IP address in 10.0.0.0/24</p></li></ul><p>NetworkPolicies do a fantastic job of protecting APIs at the network level, however, they do nothing to protect APIs at the application level. If you wanted to control which endpoints can be accessed within the API, you would need k8s to be able to not only distinguish between pods, but also endpoints within those pods. These concerns led us to <a href="https://grpc.io/docs/guides/auth/">per RPC credentials</a>. Per RPC credentials are easy to set up on top of the pre-existing gRPC code. All you need to do is add interceptors to both your stream and unary handlers.</p>
            <pre><code>func (s *Server) UnaryAuthInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    // Get the targeted function
    functionInfo := strings.Split(info.FullMethod, "/")
    function := functionInfo[len(functionInfo)-1]
    md, _ := metadata.FromIncomingContext(ctx)

    // Authenticate
    err := authenticateClient(md.Get("username")[0], md.Get("password")[0], function)
    // Blocked
    if err != nil {
        return nil, err
    }
    // Verified
    return handler(ctx, req)
}</code></pre>
            <p>In this example code snippet, we are grabbing the username, password, and requested function from the info object. We then authenticate against the client to make sure that it has correct rights to call that function. This interceptor will run before any of the other functions get called, which means one implementation protects all functions. The client would initialize its secure connection and send credentials like so:</p>
            <pre><code>transportCreds, err := credentials.NewClientTLSFromFile(certFile, "")
if err != nil {
    return nil, err
}
perRPCCreds := Creds{Password: grpcPassword, User: user}
conn, err := grpc.Dial(endpoint, grpc.WithTransportCredentials(transportCreds), grpc.WithPerRPCCredentials(perRPCCreds))
if err != nil {
    return nil, err
}
client:= pb.NewRecordHandlerClient(conn)
// Can now start using the client</code></pre>
            <p>Here the client first verifies that the server matches with the certFile. This step ensures that the client does not accidentally send its password to a bad actor. Next, the client initializes the <i>perRPCCreds</i> struct with its username and password and dials the server with that information. Any time the client makes a call to an rpc defined function, its credentials will be verified by the server.</p>
    <div>
      <h3>Next Steps</h3>
      <a href="#next-steps">
        
      </a>
    </div>
    <p>Our next step is to remove the need for many applications to access the database and ultimately DRY up our codebase by pulling all DNS-related code into a single API, accessed from one gRPC interface. This removes the potential for mistakes in individual applications and makes updating our database schema easier. It also gives us more granular control over which functions can be accessed rather than which tables can be accessed.</p><p>So far, the DNS team is very happy with the results of our gRPC migration. However, we still have a long way to go before we can move entirely away from REST. We are also patiently waiting for <a href="https://github.com/grpc/grpc/issues/19126">HTTP/3 support</a> for gRPC so that we can take advantage of those super <a href="https://en.wikipedia.org/wiki/QUIC">quic</a> speeds!</p> ]]></content:encoded>
            <category><![CDATA[DNS]]></category>
            <category><![CDATA[gRPC]]></category>
            <category><![CDATA[Kubernetes]]></category>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[QUIC]]></category>
            <guid isPermaLink="false">6oeh7RRYqhqnS7vtJ2BpwP</guid>
            <dc:creator>Alex Fattouche</dc:creator>
        </item>
        <item>
            <title><![CDATA[Delivering HTTP/2 upload speed improvements]]></title>
            <link>https://blog.cloudflare.com/delivering-http-2-upload-speed-improvements/</link>
            <pubDate>Mon, 24 Aug 2020 11:00:00 GMT</pubDate>
            <description><![CDATA[ Cloudflare recently shipped improved upload speeds across our network for clients using HTTP/2. This post describes our journey from troubleshooting an issue to fixing it and delivering faster upload speeds to the global Internet. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Cloudflare recently shipped improved <i>upload</i> speeds across our network for clients using HTTP/2. This post describes our journey from troubleshooting an issue to fixing it and delivering faster upload speeds to the global Internet.</p><p>We <a href="/test-your-home-network-performance/">launched</a> <a href="/test-your-home-network-performance/">speed.cloudflare.com</a> in May 2020 to give our users insight into how well their networks perform. The test provides download, upload and latency tests. Soon after release, we received reports from a small number of users that sometimes upload speeds were underreported. Our investigation determined that it seemed to happen with end users that had high upload bandwidth available (several hundreds Mbps class cable modem or fiber service). Our speed tests are performed via browser JavaScript, and most browsers use HTTP/2 by default. We found that HTTP/2 upload speeds were sometimes much slower than HTTP/1.1 (assuming all TLS) when the user had high available upload bandwidth.</p><p>Upload speed is more important than ever, especially for people using home broadband connections. As many people have been forced to work from home they’re using their broadband connections differently than before. Prior to the pandemic broadband traffic was very asymmetric (you downloaded way more than you uploaded… think listening to music, or streaming a movie), but now we’re seeing an increase in uploading as people video conference from home or create content from their home office.</p>
    <div>
      <h3>Initial Tests</h3>
      <a href="#initial-tests">
        
      </a>
    </div>
    <p>User reports were focused on particularly fast home networks. I set up a <code>dummynet</code> network simulator to test upload speed in a controlled environment. I launched a linux VM running our code inside my Macbook Pro and set up a <a href="https://www.saturnsoft.net/tech/2020/06/07/macosx-dummynet/">dummynet between the VM and Mac host</a>.  Measuring upload speed is simple – create a file and upload using curl to an endpoint which accepts a request body. I ran the same test 20 times and took a median upload speed (Mbps).</p>
            <pre><code>% dd if=/dev/urandom of=test.dat bs=1M count=10
% curl --http1.1 -w '%{speed_upload}\n' -sf -o/dev/null --data-binary @test.dat https://edge/upload-endpoint
% curl --http2 -w '%{speed_upload}\n' -sf -o/dev/null --data-binary @test.dat https://edge/upload-endpoint</code></pre>
            <p>Stepping up to uploading a 10MB object over a network which has 200Mbps available bandwidth and 40ms <a href="https://www.cloudflare.com/learning/cdn/glossary/round-trip-time-rtt/">RTT</a>, the result was surprising. Using our production configuration, HTTP/2 upload speed tested at almost half of the same test conditions using HTTP/1.1 (higher is better).</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5MPf14YbzqYkqUtiu4lNyH/a869cff834ea16aeb7d8ce659b7b352c/Screen-Shot-2020-08-18-at-4.44.56-PM.png" />
            
            </figure><p>The result may differ depending on your network, but the gap is bigger when the network is fast. On a slow network, like my home cable connection (5Mbps upload and 20ms RTT), HTTP/2 upload speed was almost identical to the performance observed with HTTP/1.1.</p>
    <div>
      <h3>Receiver Flow Control</h3>
      <a href="#receiver-flow-control">
        
      </a>
    </div>
    <p>Before we get into more detail on this topic, my intuition suggested the issue was related to receiver flow control. Usually the client (browser or any HTTP client) is the receiver of data, but in the case the client is uploading content to the server, the server is the receiver of data. And the receiver needs some type of flow control of the receive buffer.</p><p>How we handle receiver flow control differs between HTTP/1.1 and HTTP/2. For example, HTTP/1.1 doesn’t define protocol-level receiver flow control since there is no multiplexing of requests in the connection and it’s up to the TCP layer which handles receiving data. Note that most of the modern OS TCP stacks have auto tuning of the receive buffer (we will revisit that later) and they tune based on the current <a href="https://en.wikipedia.org/wiki/Bandwidth-delay_product">BDP (bandwidth-delay product)</a>.</p><p>In the case of HTTP/2, there is a <a href="https://tools.ietf.org/html/rfc7540#section-5.2">stream-level flow control</a> mechanism because the protocol supports multiplexing of streams. Each HTTP/2 stream has its own flow control window and there is connection level flow control for all streams in the connection. If it’s too tight, the sender will be blocked by the flow control. If it’s too loose we may end up wasting memory for buffering. So keeping it optimal is important when implementing flow control and the most optimal strategy is to keep the receive buffer matching the current BDP. BDP represents the maximum bytes in flight in the given network and can be used as an optimal buffer size.</p>
    <div>
      <h3>How NGINX handles the request body buffer</h3>
      <a href="#how-nginx-handles-the-request-body-buffer">
        
      </a>
    </div>
    <p>Initially I tried to find a parameter which controls NGINX upload buffering and tried to see if tuning the values improved the result. There are a couple of parameters which are related to uploading a request body.</p><ul><li><p><code>[proxy_buffering](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering)</code></p></li><li><p><code>[client_body_buffer_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size)</code></p></li></ul><p>And this is HTTP/2 specific:</p><ul><li><p><code>[http2_body_preread_size](http://nginx.org/en/docs/http/ngx_http_v2_module.html#http2_body_preread_size)</code></p></li></ul><p>Cloudflare does not use the <code>proxy_request_buffering</code> directive, so it can be immediately discounted.  <code>client_body_buffer_size</code> is the size of the request body buffer which is used regardless of the protocol, so this one applies to HTTP/1.1 and HTTP/2 as well.</p><p>When looking into the code, here is how it works:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5FFejc0ITjeuf1tZChITtW/21d23eb449794b824c944062dea9d087/Screen-Shot-2020-08-10-at-3.51.05-PM.png" />
            
            </figure><ul><li><p>HTTP/1.1: use <code>client_body_buffer_size</code> buffer as a buffer between upstream and the client, simply repeating reading and writing using this buffer.</p></li><li><p>HTTP/2: since we need a flow control window update for the HTTP/2 DATA frame, there are two parameters:</p><ul><li><p><code>http2_body_preread_size</code>: it specifies the size of the initial request body read before it starts to send to the upstream.</p></li><li><p><code>client_body_buffer_size</code>: it specifies the size of the request body buffer.</p></li><li><p>Those two parameters are used for allocating a request body buffer during uploading. Here is a brief summary of how unbuffered upload works:</p><ul><li><p>Allocate a single request body buffer which size is a maximum of <code>http2_body_preread_size</code> and <code>client_body_buffer_size</code>. This means if <code>http2_body_preread_size</code> is 64KB and <code>client_body_buffer_size</code> is 128KB, then a 128KB buffer is allocated. We use 128KB for <code>client_body_buffer_size</code>.</p></li><li><p>HTTP/2 Settings <code>INITIAL_WINDOW_SIZE</code> of the stream is set to <code>http2_body_preread_size</code> and we use 64KB as a default (<a href="https://tools.ietf.org/html/rfc7540#section-6.9.2">the RFC7540 default value</a>).</p></li><li><p>HTTP/2 module reads up to <code>http2_body_preread_size</code> before sending it to upstream.</p></li><li><p>After flushing the preread buffer, keep reading from the client and write to upstream and send <code>WINDOW_UPDATE</code> frame back to the client when necessary until the request body is fully received.</p></li></ul></li></ul></li></ul><p>To summarise what this means: HTTP/1.1 simply uses a single buffer, so TCP socket buffers do the flow control. However with HTTP/2, the application layer also has receiver flow control and NGINX uses a fixed size buffer for the receiver. This limits upload speed when the current link has a BDP larger than the current request body buffer size. So the bottleneck is HTTP/2 flow control when the buffer size is too tight.</p>
    <div>
      <h3>We're going to need a bigger buffer?</h3>
      <a href="#were-going-to-need-a-bigger-buffer">
        
      </a>
    </div>
    <p>In theory, bigger buffer sizes should avoid upload bottlenecks, so I tried a few out by running my tests again. The previous chart result is now labelled "prod" and plotted alongside HTTP/2 tests with <code>client_body_buffer_size</code> set to 256KB, 512KB and 1024KB:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3ViLVb0T1Ku13wI6wjCicy/3c722510d2eb466c5685f698cf66a73c/10MB-1.png" />
            
            </figure><p>It appears 512KB is an optimal value for <code>client_body_buffer_size</code>.</p><p>What if I test with some other network parameter? Here is when RTT is 10ms, in this case, 256KB looks optimal.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5nxstBv8ApAJdbBCOhXFSQ/5d33c532b593beb759fcece97843ec5c/10MB-2.png" />
            
            </figure><p>Both cases look much better than current 128KB and get a similar performance to HTTP/1.1 or even better. However, it seems like the optimal buffer size is a moving target and furthermore having too large a buffer size can hurt the performance: we need a smart way to find the optimal buffer size.</p>
    <div>
      <h2>Autotuning request body buffer size</h2>
      <a href="#autotuning-request-body-buffer-size">
        
      </a>
    </div>
    <p>One of the ideas that can help this kind of situation is autotuning. For example, modern TCP stacks autotune their receive buffers automatically. In production, our edge also has <a href="https://sysctl-explorer.net/net/ipv4/tcp_moderate_rcvbuf/">TCP receiver buffer autotuning</a> enabled by default.</p>
            <pre><code>net.ipv4.tcp_moderate_rcvbuf = 1</code></pre>
            <p>But in case of HTTP/2, TCP buffer autotuning is not very effective because the HTTP/2 layer is doing its own flow control and the existing 128KB was too small for a high BDP link. At this point, I decided to pursue autotuning HTTP/2 receive buffer sizing as well, similar to what TCP does.</p><p>The basic idea is that NGINX doubles the size of HTTP/2 request body buffer size based on its BDP. Here is an algorithm currently implemented in our version of NGINX:</p><ul><li><p>Allocate a request body buffer as explained above.</p></li><li><p>For every RTT (using linux <code>tcp_info</code>), update the current BDP.</p></li><li><p>Double the request body buffer size when the current BDP &gt; (receiver window / 4).</p></li></ul>
    <div>
      <h2>Test Result</h2>
      <a href="#test-result">
        
      </a>
    </div>
    
    <div>
      <h3><b>Lab Test</b></h3>
      <a href="#lab-test">
        
      </a>
    </div>
    <p>Here is a test result when HTTP/2 autotune upload is enabled (still using <code>client_body_buffer_size</code> 128KB). You can see "h2 autotune" is doing pretty well – similar or even slightly faster than HTTP/1.1 speed (that's the initial goal). It might be slightly worse than a hand-picked optimal buffer size for given conditions, but you can see now NGINX picks up optimal buffer size automatically based on network conditions.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3Sl1rRUKOPiCoT5YeDqU6g/19231407e0b61e6b0ddbc8a2790a772d/10MB-3.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3keSehjT2WOcQVXA4QmDiy/bad3fdb88497492a7c4bd21ac5e8cb87/10MB-4.png" />
            
            </figure>
    <div>
      <h3>Production test</h3>
      <a href="#production-test">
        
      </a>
    </div>
    <p>After we deployed this feature, I ran similar tests against our production edge, uploading a 10MB file from well connected client nodes to our edge. I created a Linux VM instance in Google Cloud and ran the upload test where the network is very fast (a few Gbps) and low latency (&lt;10ms).</p><p>Here is when I run the test in the Google Cloud Belgium region to our CDG (Paris) PoP which has 7ms RTT. This looks very good with almost 3x improvement.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/MgWAhBWB91UiGKOWULns6/5faa240c54fd96fbc8d1b0c8ba7dd5c5/10MB-5.png" />
            
            </figure><p>I also tested between the Google Cloud Tokyo region and our NRT (Tokyo) PoP, which had a 2.3ms RTT. Although this is not realistic for home users, the results are interesting. A 128KB fixed buffer performs well, but HTTP/2 with buffer autotune outperforms even HTTP/1.1.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/33aKI4Dguh46tXuIV9INyv/c6e7a8146e32c70a2cb09cf1c009d664/10MB-6.png" />
            
            </figure>
    <div>
      <h2>Summary</h2>
      <a href="#summary">
        
      </a>
    </div>
    <p>HTTP/2 upload buffer autotuning is now fully deployed in the Cloudflare edge. Customers should now benefit from improved upload performance for all HTTP/2 connections, including speed tests on speed.cloudflare.com. Autotuning upload buffer size logic works well for most cases, and now HTTP/2 upload is much faster than before! When we think about the performance we usually tend to think about download speed or latency reduction, but faster uploading can also help users working from home when they need a large amount of upload, such as photo/video sharing apps, content creation, video conferencing or self broadcasting.</p><p>Many thanks to <a href="/author/lucas/">Lucas Pardue</a> and <a href="/author/rustam-lalkaka/">Rustam Lalkaka</a> for great feedback and suggestions on the article.</p><p>Update: we made this patch available to public and sent to NGINX upstream. You can find it <a href="http://mailman.nginx.org/pipermail/nginx-devel/2020-August/013436.html">here</a>.</p> ]]></content:encoded>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[Cloudflare Network]]></category>
            <category><![CDATA[Network]]></category>
            <guid isPermaLink="false">77KoGnJkqSvxBbUjDx9PhH</guid>
            <dc:creator>Junho Choi</dc:creator>
        </item>
        <item>
            <title><![CDATA[Comparing HTTP/3 vs. HTTP/2 Performance]]></title>
            <link>https://blog.cloudflare.com/http-3-vs-http-2/</link>
            <pubDate>Tue, 14 Apr 2020 11:00:00 GMT</pubDate>
            <description><![CDATA[ We announced support for HTTP/3, the successor to HTTP/2, during Cloudflare’s birthday week last year. Our goal is and has always been to help build a better Internet. Even though HTTP/3 is still in draft status, we've seen a lot of interest from our users. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>We announced <a href="/http3-the-past-present-and-future/">support for HTTP/3</a>, the successor to HTTP/2 during Cloudflare’s <a href="/birthday-week-2019/">birthday week</a> last year. Our goal is and has always been to help build a better Internet. Collaborating on standards is a big part of that, and we're very fortunate to do that here.</p><p>Even though <a href="https://www.cloudflare.com/learning/performance/what-is-http3/">HTTP/3</a> is still in draft status, we've seen a lot of interest from our users. So far, over 113,000 zones have activated HTTP/3 and, if you are using an experimental browser those zones can be accessed using the new protocol! It's been great seeing so many people enable HTTP/3: having real websites accessible through HTTP/3 means browsers have more diverse properties to test against.</p><p>When we <a href="/http3-the-past-present-and-future/">launched support</a> for HTTP/3, we did so in partnership with Google, who simultaneously launched experimental support in Google Chrome. Since then, we've seen more browsers add experimental support: Firefox to their nightly <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1581637">builds</a>, other Chromium-based browsers such as Opera and Microsoft Edge through the underlying Chrome browser engine, and Safari via their <a href="https://developer.apple.com/safari/technology-preview/release-notes/">technology preview</a>. We closely follow these developments and partner wherever we can help; having a large network with many sites that have HTTP/3 enabled gives browser implementers an excellent testbed against which to try out code.</p>
    <div>
      <h3>So, what's the status and where are we now?</h3>
      <a href="#so-whats-the-status-and-where-are-we-now">
        
      </a>
    </div>
    <p>The IETF standardization process develops protocols as a series of document draft versions with the ultimate aim of producing a final draft version that is ready to be marked as an RFC. The members of the QUIC Working Group collaborate on analyzing, implementing and interoperating the specification in order to find things that don't work quite right. We launched with support for <a href="https://tools.ietf.org/html/draft-ietf-quic-http-23">Draft-23 for HTTP/3</a> and have since kept up with each new draft, with <a href="https://tools.ietf.org/html/draft-ietf-quic-http-27">27</a> being the latest at time of writing. With each draft the group improves the quality of the QUIC definition and gets closer to "rough consensus" about how it behaves. In order to avoid a perpetual state of analysis paralysis and endless tweaking, the bar for proposing changes to the specification has been increasing with each new draft. This means that changes between versions are smaller, and that a final RFC should closely match the protocol that we've been running in production.</p>
    <div>
      <h3>Benefits</h3>
      <a href="#benefits">
        
      </a>
    </div>
    <p>One of the main touted advantages of HTTP/3 is increased performance, specifically around fetching multiple objects simultaneously. With HTTP/2, any interruption (packet loss) in the TCP connection blocks all streams (Head of line blocking). Because HTTP/3 is UDP-based, if a packet gets dropped that only interrupts that one stream, not all of them.</p><p>In addition, HTTP/3 offers <a href="/even-faster-connection-establishment-with-quic-0-rtt-resumption/">0-RTT</a> support, which means that subsequent connections can start up much faster by eliminating the TLS acknowledgement from the server when setting up the connection. This means the client can start requesting data much faster than with a full TLS negotiation, meaning the website starts loading earlier.</p><p>The following illustrates the packet loss and its impact: HTTP/2 multiplexing two requests . A request comes over HTTP/2 from the client to the server requesting two resources (we’ve colored the requests and their associated responses green and yellow). The responses are broken up into multiple packets and, alas, a packet is lost so both requests are held up.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5MQCKq4WKwM4fCqDGYJ8Ui/1f9306b608618fe78e3e57a1392a9b11/image1-1.gif" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6DSF88gTgVSsmiVExIa3Ry/5e26b2b32f6bd00dda851caa4c9c46e6/image4-1.gif" />
            
            </figure><p>The above shows HTTP/3 multiplexing 2 requests. A packet is lost that affects the yellow response but the green one proceeds just fine.</p><p>Improvements in session startup mean that ‘connections’ to servers start much faster, which means the browser starts to see data more quickly. We were curious to see how much of an improvement, so we ran some tests. To measure the improvement resulting from 0-RTT support, we ran some benchmarks measuring <i>time to first byte</i> (TTFB). On average, with HTTP/3 we see the first byte appearing after 176ms. With HTTP/2 we see 201ms, meaning HTTP/3 is already performing 12.4% better!</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5slXFJulfUbmW5NsZqm8r/f7087c07f55ab903735524e70dd04bb0/image5-6.png" />
            
            </figure><p>Interestingly, not every aspect of the protocol is governed by the drafts or RFC. Implementation choices can affect performance, such as efficient <a href="/accelerating-udp-packet-transmission-for-quic/">packet transmission</a> and choice of congestion control algorithm. Congestion control is a technique your computer and server use to adapt to overloaded networks: by dropping packets, transmission is subsequently throttled. Because QUIC is a new protocol, getting the congestion control design and implementation right requires experimentation and tuning.</p><p>In order to provide a safe and simple starting point, the Loss Detection and Congestion Control specification recommends the <a href="https://en.wikipedia.org/wiki/TCP_congestion_control#TCP_Tahoe_and_Reno">Reno</a> algorithm but allows endpoints to choose any algorithm they might like.  We started with <a href="https://en.wikipedia.org/wiki/TCP_congestion_control#TCP_New_Reno">New Reno</a> but we know from experience that we can get better performance with something else. We have recently moved to <a href="https://en.wikipedia.org/wiki/CUBIC_TCP">CUBIC</a> and on our network with larger size transfers and packet loss, CUBIC shows improvement over New Reno. Stay tuned for more details in future.</p><p>For our existing HTTP/2 stack, we currently support <a href="https://github.com/google/bbr">BBR v1</a> (TCP). This means that in our tests, we’re not performing an exact apples-to-apples comparison as these congestion control algorithms will behave differently for smaller vs larger transfers. That being said, we can already see a speedup in smaller websites using HTTP/3 when compared to HTTP/2. With larger zones, the improved congestion control of our tuned HTTP/2 stack shines in performance.</p><p>For a small test page of 15KB, HTTP/3 takes an average of 443ms to load compared to 458ms for HTTP/2. However, once we increase the page size to 1MB that advantage disappears: HTTP/3 is just slightly slower than HTTP/2 on our network today, taking 2.33s to load versus 2.30s.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2UrCQVwplKQxT7aSzqwMl6/4ff62d1bdb67e54c29b553d260f11aa8/image2-11.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2KPuZxBl9m6TOyvrGZfMFw/5d22e954c62325af32c99c5783f62560/image6-4.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/JDw2bdaT0Vcmd4Jyg7Yhl/af2af92b3bdc2dd1891062844027fe70/image3-11.png" />
            
            </figure><p>Synthetic benchmarks are interesting, but we wanted to know how HTTP/3 would perform in the real world.</p><p>To measure, we wanted a third party that could load websites on our network, mimicking a browser. WebPageTest is a common framework that is used to measure the page load time, with nice waterfall charts. For analyzing the backend, we used our in-house <a href="https://support.cloudflare.com/hc/en-us/articles/360033929991-Cloudflare-Browser-Insights">Browser Insights</a>, to capture timings as our edge sees it. We then tied both pieces together with bits of automation.</p><p>As a test case we decided to use <a href="/">this very blog</a> for our <a href="https://www.cloudflare.com/application-services/solutions/app-performance-monitoring/">performance monitoring</a>. We configured our own instances of WebPageTest spread over the world to load these sites over both HTTP/2 and HTTP/3. We also enabled HTTP/3 and Browser Insights. So, every time our test scripts kickoff a webpage test with an HTTP/3 supported browser loading the page, browser analytics report the data back. Rinse and repeat for HTTP/2 to be able to compare.</p><p>The following graph shows the page load time for a real world page -- <a href="/">blog.cloudflare.com</a>, to compare the performance of HTTP/3 and HTTP/2. We have these performance measurements running from different geographical locations.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2Xwp5YGAE5hCP7m0TQeGeE/52a42c9ad4a53be01e22fba4888c27de/image7-5.png" />
            
            </figure><p>As you can see, HTTP/3 performance still trails HTTP/2 performance, by about 1-4% on average in North America and similar results are seen in Europe, Asia and South America. We suspect this could be due to the difference in congestion algorithms: HTTP/2 on BBR v1 vs. HTTP/3 on CUBIC. In the future, we’ll work to support the same congestion algorithm on both to get a more accurate apples-to-apples comparison.</p>
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>Overall, we’re very excited to be allowed to help push this standard forward. Our implementation is holding up well, offering better performance in some cases and at worst similar to HTTP/2. As the standard finalizes, we’re looking forward to seeing browsers add support for HTTP/3 in mainstream versions. As for us, we continue to support the latest drafts while at the same time looking for more ways to leverage HTTP/3 to get even better performance, be it congestion tuning, <a href="/adopting-a-new-approach-to-http-prioritization/">prioritization</a> or system capacity (CPU and raw network throughput).</p><p>In the meantime, if you’d like to try it out, just enable HTTP/3 on our dashboard and download a nightly version of one of the major browsers. Instructions on how to enable HTTP/3 can be found on our <a href="https://developers.cloudflare.com/http3/intro/">developer documentation</a>.</p> ]]></content:encoded>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[HTTP3]]></category>
            <category><![CDATA[Better Internet]]></category>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[Performance]]></category>
            <guid isPermaLink="false">7uJaKjNWQi13PNs4O9ylJB</guid>
            <dc:creator>Sreeni Tellakula</dc:creator>
        </item>
        <item>
            <title><![CDATA[On the recent HTTP/2 DoS attacks]]></title>
            <link>https://blog.cloudflare.com/on-the-recent-http-2-dos-attacks/</link>
            <pubDate>Tue, 13 Aug 2019 17:00:00 GMT</pubDate>
            <description><![CDATA[ Today, multiple Denial of Service (DoS) vulnerabilities were disclosed for a number of HTTP/2 server implementations. Cloudflare uses NGINX for HTTP/2. Customers using Cloudflare are already protected against these attacks. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Today, multiple Denial of Service (DoS) vulnerabilities were disclosed for a number of HTTP/2 server implementations. Cloudflare uses NGINX for HTTP/2. <b>Customers using Cloudflare are already protected against these attacks.</b></p><p>The individual vulnerabilities, originally discovered by Netflix and are included in <a href="https://github.com/Netflix/security-bulletins/blob/master/advisories/third-party/2019-002.md">this</a> announcement are:</p><ul><li><p><a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-9511">CVE-2019-9511</a> HTTP/2 Data Dribble</p></li><li><p><a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-9512">CVE-2019-9512</a> HTTP/2 Ping Flood</p></li><li><p><a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-9513">CVE-2019-9513</a> HTTP/2 Resource Loop</p></li><li><p><a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-9514">CVE-2019-9514</a> HTTP/2 Reset Flood</p></li><li><p><a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-9515">CVE-2019-9515</a> HTTP/2 Settings Flood</p></li><li><p><a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-9516">CVE-2019-9516</a> HTTP/2 0-Length Headers Leak</p></li><li><p><a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-9518">CVE-2019-9518</a> HTTP/2 Request Data/Header Flood</p></li></ul><p>As soon as we became aware of these vulnerabilities, Cloudflare’s Protocols team started working on fixing them. We first pushed a patch to detect any attack attempts and to see if any normal traffic would be affected by our mitigations. This was followed up with work to mitigate these vulnerabilities; we pushed the changes out few weeks ago and continue to monitor similar attacks on our stack.</p><p>If any of our customers host web services over HTTP/2 on an alternative, publicly accessible path that is not behind Cloudflare, we recommend you apply the latest security updates to your origin servers in order to protect yourselves from these HTTP/2 vulnerabilities.</p><p>We will soon follow up with more details on these vulnerabilities and how we mitigated them.</p><p>Full credit for the discovery of these vulnerabilities goes to Jonathan Looney of Netflix and Piotr Sikora of Google and the Envoy Security Team.</p> ]]></content:encoded>
            <category><![CDATA[Vulnerabilities]]></category>
            <category><![CDATA[DDoS]]></category>
            <category><![CDATA[HTTP2]]></category>
            <guid isPermaLink="false">1RNROMoG90Eth3X6fVPj6v</guid>
            <dc:creator>Nafeez</dc:creator>
        </item>
        <item>
            <title><![CDATA[NGINX structural enhancements for HTTP/2 performance]]></title>
            <link>https://blog.cloudflare.com/nginx-structural-enhancements-for-http-2-performance/</link>
            <pubDate>Wed, 22 May 2019 17:14:56 GMT</pubDate>
            <description><![CDATA[ My team: the Cloudflare PROTOCOLS team is responsible for termination of HTTP traffic at the edge of the Cloudflare network. We deal with features related to: TCP, QUIC, TLS and Secure Certificate management, HTTP/1 and HTTP/2. ]]></description>
            <content:encoded><![CDATA[ <p></p>
    <div>
      <h3>Introduction</h3>
      <a href="#introduction">
        
      </a>
    </div>
    <p>My team: the Cloudflare PROTOCOLS team is responsible for termination of HTTP traffic at the edge of the Cloudflare network. We deal with features related to: TCP, QUIC, TLS and Secure Certificate management, HTTP/1 and HTTP/2. Over Q1, we were responsible for implementing the <a href="/better-http-2-prioritization-for-a-faster-web/">Enhanced HTTP/2 Prioritization</a> product that Cloudflare announced during Speed Week.</p><p>This is a very exciting project to be part of, and doubly exciting to see the results of, but during the course of the project, we had a number of interesting realisations about NGINX: the HTTP oriented server onto which Cloudflare currently deploys its software infrastructure. We quickly became certain that our Enhanced HTTP/2 Prioritization project could not achieve even moderate success if the internal workings of NGINX were not changed.</p><p>Due to these realisations we embarked upon a number of significant changes to the internal structure of NGINX in parallel to the work on the core prioritization product. This blog post describes the motivation behind the structural changes, how we approached them, and what impact they had. We also identify additional changes that we plan to add to our roadmap, which we hope will improve performance further.</p>
    <div>
      <h3>Background</h3>
      <a href="#background">
        
      </a>
    </div>
    <p>Enhanced HTTP/2 Prioritization aims to do one thing to web traffic flowing between a client and a server: it provides a means to shape the many HTTP/2 streams as they flow from upstream (server or origin side) into a single HTTP/2 connection that flows downstream (client side).</p><p>Enhanced HTTP/2 Prioritization allows site owners and the Cloudflare edge systems to dictate the rules about how various objects should combine into the single HTTP/2 connection: whether a particular object should have priority and dominate that connection and reach the client as soon as possible, or whether a group of objects should evenly share the capacity of the connection and put more emphasis on parallelism.</p><p>As a result, Enhanced HTTP/2 Prioritization allows site owners to tackle two problems that exist between a client and a server: how to control precedence and ordering of objects, and: how to make the best use of a limited connection resource, which may be constrained by a number of factors such as bandwidth, volume of traffic and CPU workload at the various stages on the path of the connection.</p>
    <div>
      <h3>What did we see?</h3>
      <a href="#what-did-we-see">
        
      </a>
    </div>
    <p>The key to prioritisation is being able to compare two or more HTTP/2 streams in order to determine which one’s frame is to go down the pipe next. The Enhanced HTTP/2 Prioritization project necessarily drew us into the core NGINX codebase, as our intention was to fundamentally alter the way that NGINX compared and queued HTTP/2 data frames as they were written back to the client.</p><p>Very early in the analysis phase, as we rummaged through the NGINX internals to survey the site of our proposed features, we noticed a number of shortcomings in the structure of NGINX itself, in particular: how it moved data from upstream (server side) to downstream (client side) and how it temporarily stored (buffered) that data in its various internal stages. The main conclusion of our early analysis of NGINX was that it largely failed to give the stream data frames any 'proximity'. Either streams were processed in the NGINX HTTP/2 layer in isolated succession or frames of different streams spent very little time in the same place: a shared queue for example. The net effect was a reduction in the opportunities for useful comparison.</p><p>We coined a new, barely scientific but useful measurement: <b>Potential</b>, to describe how effectively the Enhanced HTTP/2 Prioritization strategies (or even the default NGINX prioritization) can be applied to queued data streams. Potential is not so much a measurement of the effectiveness of prioritization per se, that metric would be left for later on in the project, it is more a measurement of the levels of participation during the application of the algorithm. In simple terms, it considers the number of streams and frames thereof that are included in an iteration of prioritization, with more streams and more frames leading to higher Potential.</p><p>What we could see from early on was that by default, NGINX displayed low Potential: rendering prioritization instructions from either the browser, as is the case in the traditional HTTP/2 prioritization model, or from our Enhanced HTTP/2 Prioritization product, fairly useless.</p>
    <div>
      <h3>What did we do?</h3>
      <a href="#what-did-we-do">
        
      </a>
    </div>
    <p>With the goal of improving the specific problems related to Potential, and also improving general throughput of the system, we identified some key pain points in NGINX. These points, which will be described below, have either been worked on and improved as part of our initial release of Enhanced HTTP/2 Prioritization, or have now branched out into meaningful projects of their own that we will put engineering effort into over the course of the next few months.</p>
    <div>
      <h3>HTTP/2 frame write queue reclamation</h3>
      <a href="#http-2-frame-write-queue-reclamation">
        
      </a>
    </div>
    <p>Write queue reclamation was successfully shipped with our release of Enhanced HTTP/2 Prioritization and ironically, it wasn’t a change made to the original NGINX, it was in fact a change made against our Enhanced HTTP/2 Prioritization implementation when we were part way through the project, and it serves as a good example of something one may call: conservation of data, which is a good way to increase Potential.</p><p>Similar to the original NGINX, our Enhanced HTTP/2 Prioritization algorithm will place a cohort of HTTP/2 data frames into a write queue as a result of an iteration of the prioritization strategies being applied to them. The contents of the write queue would be destined to be written the downstream TLS layer.  Also similar to the original NGINX, the write queue may only be partially written to the TLS layer due to back-pressure from the network connection that has temporarily reached write capacity.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5bBa68J0uK2BJvMi5ouTD5/92ce87c4a134c046206f2ac46ba55d2c/Write-Queue-Construction-Without-Reclamation.png" />
            
            </figure><p>Early on in our project, if the write queue was only partially written to the TLS layer, we would simply leave the frames in the write queue until the backlog was cleared, then we would re-attempt to write that data to the network in a future write iteration, just like the original NGINX.</p><p>The original NGINX takes this approach because the write queue is the <b>only</b> place that waiting data frames are stored. However, in our NGINX modified for Enhanced HTTP/2 Prioritization, we have a unique structure that the original NGINX lacks: per-stream data frame queues where we temporarily store data frames before our prioritization algorithms are applied to them.</p><p>We came to the realisation that in the event of a partial write, we were able to restore the unwritten frames back into their per-stream queues. If it was the case that a subsequent data cohort arrived behind the partially unwritten one, then the previously unwritten frames could participate in an additional round of prioritization comparisons, thus raising the Potential of our algorithms.</p><p>The following diagram illustrates this process:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7uEXuMETgrrFmtN84ZlQEL/52b63e9fd2401ec0c7c56cd442f1c14e/Write-Queue-Construction-With-Reclamation.png" />
            
            </figure><p>We were very pleased to ship Enhanced HTTP/2 Prioritization with the reclamation feature included as this single enhancement greatly increased Potential and made up for the fact that we had to withhold the next enhancement for speed week due to its delicacy.</p>
    <div>
      <h3>HTTP/2 frame write event re-ordering</h3>
      <a href="#http-2-frame-write-event-re-ordering">
        
      </a>
    </div>
    <p>In Cloudflare infrastructure, we map the many streams of a single HTTP/2 connection from the eyeball to multiple HTTP/1.1 connections to the upstream Cloudflare control plane.</p><p>As a note: it may seem counterintuitive that we downgrade protocols like this, and it may seem doubly counterintuitive when I reveal that we also disable HTTP keepalive on these upstream connections, resulting in only one transaction per connection, however this arrangement offers a number of advantages, particularly in the form of improved CPU workload distribution.</p><p>When NGINX monitors its upstream HTTP/1.1 connections for read activity, it may detect readability on many of those connections and process them all in a batch. However, within that batch, each of the upstream connections is processed sequentially, one at a time, from start to finish: from HTTP/1.1 connection read, to framing in the HTTP/2 stream, to HTTP/2 connection write to the TLS layer.</p><p>The existing NGINX workflow is illustrated in this diagram:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/69wml2jrdBLGZW1nMImkL4/9583420328f40b1e521d0f0a8412614e/Upstream-Read-Event.png" />
            
            </figure><p>By committing each streams’ frames to the TLS layer one stream at a time, many frames may pass entirely through the NGINX system before backpressure on the downstream connection allows the queue of frames to build up, providing an opportunity for these frames to be in proximity and allowing prioritization logic to be applied.  This negatively impacts Potential and reduces the effectiveness of prioritization.</p><p>The Cloudflare Enhanced HTTP/2 Prioritization modified NGINX aims to re-arrange the internal workflow described above into the following model:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4d0xrrRBO4J3C1HCe4Hy8M/43b971a2a8592e5708f930b1c6bfddfb/Upstream-Read-Reordered.png" />
            
            </figure><p>Although we continue to frame upstream data into HTTP/2 data frames in the separate iterations for each upstream connection, we no longer commit these frames to a single write queue within each iteration, instead we arrange the frames into the per-stream queues described earlier. We then post a single event to the end of the per-connection iterations, and perform the prioritization, queuing and writing of the HTTP/2 data frames of all streams in that single event.</p><p>This single event finds the cohort of data conveniently stored in their respective per-stream queues, all in close proximity, which greatly increases the Potential of the Edge Prioritization algorithms.</p><p>In a form closer to actual code, the core of this modification looks a bit like this:</p>
            <pre><code>ngx_http_v2_process_data(ngx_http_v2_connection *h2_conn,
                         ngx_http_v2_stream *h2_stream,
                         ngx_buffer *buffer)
{
    while ( ! ngx_buffer_empty(buffer) {
        ngx_http_v2_frame_data(h2_conn,
                               h2_stream-&gt;frames,
                               buffer);
    }

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

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

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

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

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

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

    ngx_http_v2_write_queue(h2_conn-&gt;queue);
}</code></pre>
            <p>There is a high level of risk in this modification, for even though it is remarkably small, we are taking the well established and debugged event flow in NGINX and switching it around to a significant degree. Like taking a number of Jenga pieces out of the tower and placing them in another location, we risk: race conditions, event misfires and event blackholes leading to lockups during transaction processing.</p><p>Because of this level of risk, we did <b>not</b> release this change in its entirety during Speed Week, but we will continue to test and refine it for future release.</p>
    <div>
      <h3>Upstream buffer partial re-use</h3>
      <a href="#upstream-buffer-partial-re-use">
        
      </a>
    </div>
    <p>Nginx has an internal buffer region to store connection data it reads from upstream. To begin with, the entirety of this buffer is <b>Ready</b> for use. When data is read from upstream into the Ready buffer, the part of the buffer that holds the data is passed to the downstream HTTP/2 layer. Since HTTP/2 takes responsibility for that data, that portion of the buffer is marked as: <b>Busy</b> and it will remain Busy for as long as it takes for the HTTP/2 layer to write the data into the TLS layer, which is a process that may take some time (in computer terms!).</p><p>During this gulf of time, the upstream layer may continue to read more data into the remaining Ready sections of the buffer and continue to pass that incremental data to the HTTP/2 layer until there are no Ready sections available.</p><p>When Busy data is finally finished in the HTTP/2 layer, the buffer space that contained that data is then marked as: <b>Free</b></p><p>The process is illustrated in this diagram:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/rpLV7aUoGwAE6KcQmEts5/9bfa13e2ef08845172e915f01354dc63/Upstream-Buffer-Current-1.png" />
            
            </figure><p>You may ask: When the leading part of the upstream buffer is marked as Free (in blue in the diagram), even though the trailing part of the upstream buffer is still Busy, can the Free part be re-used for reading more data from upstream?</p><p>The answer to that question is: <b>NO</b></p><p>Because just a small part of the buffer is still Busy, NGINX will refuse to allow any of the entire buffer space to be re-used for reads. Only when the entirety of the buffer is Free, can the buffer be returned to the Ready state and used for another iteration of upstream reads. So in summary, data can be read from upstream into Ready space at the tail of the buffer, but not into Free space at the head of the buffer.</p><p>This is a shortcoming in NGINX and is clearly undesirable as it interrupts the flow of data into the system. We asked: what if we could cycle through this buffer region and re-use parts at the head as they became Free? We seek to answer that question in the near future by testing the following buffering model in NGINX:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5WkYGqHYhndsb6dYFqM7TT/6cf0dfe91b09ce205f512347d3427255/Upstream-Buffer-Improved.png" />
            
            </figure>
    <div>
      <h3>TLS layer Buffering</h3>
      <a href="#tls-layer-buffering">
        
      </a>
    </div>
    <p>On a number of occasions in the above text, I have mentioned the TLS layer, and how the HTTP/2 layer writes data into it. In the OSI network model, TLS sits just below the protocol (HTTP/2) layer, and in many consciously designed networking software systems such as NGINX, the software interfaces are separated in a way that mimics this layering.</p><p>The NGINX HTTP/2 layer will collect the current cohort of data frames and place them in priority order into an output queue, then submit this queue to the TLS layer. The TLS layer makes use of a per-connection buffer to collect HTTP/2 layer data before performing the actual cryptographic transformations on that data.</p><p>The purpose of the buffer is to give the TLS layer a more meaningful quantity of data to encrypt, for if the buffer was too small, or the TLS layer simply relied on the units of data from the HTTP/2 layer, then the overhead of encrypting and transmitting the multitude of small blocks may negatively impact system throughput.</p><p>The following diagram illustrates this undersize buffer situation:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/21JR00rWD6FPowvk2nMNRs/79712a865fa021954e8c37f187dac002/TLS-Layer-Buffering-Undersize.png" />
            
            </figure><p>If the TLS buffer is too big, then an excessive amount of HTTP/2 data will be committed to encryption and if it failed to write to the network due to backpressure, it would be locked into the TLS layer and not be available to return to the HTTP/2 layer for the reclamation process, thus reducing the effectiveness of reclamation. The following diagram illustrates this oversize buffer situation:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7wwWnqkWaJ0CpbGLCQWp1l/7e18f9e66c0a7ee9ed83357f52db9398/TLS-Layer-Buffering-Oversize.png" />
            
            </figure><p>In the coming months, we will embark on a process to attempt to find the ‘goldilocks’ spot for TLS buffering: To size the TLS buffer so it is big enough to maintain efficiency of encryption and network writes, but not so big as to reduce the responsiveness to incomplete network writes and the efficiency of reclamation.</p>
    <div>
      <h3>Thank you - Next!</h3>
      <a href="#thank-you-next">
        
      </a>
    </div>
    <p>The Enhanced HTTP/2 Prioritization project has the lofty goal of fundamentally re-shaping how we send traffic from the Cloudflare edge to clients, and as results of our testing and feedback from some of our customers shows, we have certainly achieved that! However, one of the most important aspects that we took away from the project was the critical role the internal data flow within our NGINX software infrastructure plays in the outlook of the traffic observed by our end users. We found that changing a few lines of (albeit critical) code, could have significant impacts on the effectiveness and performance of our prioritization algorithms. Another positive outcome is that in addition to improving HTTP/2, we are looking forward to carrying our newfound skills and lessons learned and apply them to HTTP/3 over QUIC.</p><p>We are eager to share our modifications to NGINX with the community, so we have opened <a href="https://trac.nginx.org/nginx/ticket/1763">this</a> ticket, through which we will discuss upstreaming the event re-ordering change and the buffer partial re-use change with the NGINX team.</p><p>As Cloudflare continues to grow, our requirements on our software infrastructure also shift. Cloudflare has already moved beyond proxying of HTTP/1 over TCP to support termination and Layer 3 and 4 protection for any UDP and TCP traffic. Now we are moving on to other technologies and protocols such as QUIC and HTTP/3, and full proxying of a wide range of other protocols such as messaging and streaming media.</p><p>For these endeavours we are looking at new ways to answer questions on topics such as: scalability, localised performance, wide scale performance, introspection and debuggability, release agility, maintainability.</p><p>If you would like to help us answer these questions and know a bit about: hardware and software scalability, network programming, asynchronous event and futures based software design, TCP, TLS, QUIC, HTTP, RPC protocols, Rust or maybe something else?, then have a look <a href="https://www.cloudflare.com/careers/">here</a>.</p> ]]></content:encoded>
            <category><![CDATA[Speed Week]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[NGINX]]></category>
            <category><![CDATA[HTTP2]]></category>
            <guid isPermaLink="false">tzpAmDnnJeZ1Iu6R6B9KN</guid>
            <dc:creator>Nick Jones</dc:creator>
        </item>
        <item>
            <title><![CDATA[One more thing... new Speed Page]]></title>
            <link>https://blog.cloudflare.com/new-speed-page/</link>
            <pubDate>Mon, 20 May 2019 13:00:00 GMT</pubDate>
            <description><![CDATA[ With the Speed Page redesign, we are emphasizing the performance benefits of using Cloudflare and the additional improvements possible from our features. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/XqOoxFvK0VJ3KVmpQ12uk/12abe99caca7f6677cde4f88b1c38748/new-speed-page_3x.png" />
            
            </figure><p>Congratulations on making it through Speed Week. In the last week, Cloudflare has: described how <a href="/argo-and-the-cloudflare-global-private-backbone">our global network</a> speeds up the Internet, launched a <a href="/better-http-2-prioritization-for-a-faster-web">HTTP/2 prioritisation model</a> that will improve web experiences on all browsers, launched an <a href="/announcing-cloudflare-image-resizing-simplifying-optimal-image-delivery">image resizing service</a> which will deliver the optimal image to every device, <a href="/introducing-concurrent-streaming-acceleration">optimized live video delivery</a>, detailed how to <a href="/parallel-streaming-of-progressive-images">stream progressive images</a> so that they render twice as fast - using the flexibility of our new HTTP/2 prioritisation model and finally, prototyped a new <a href="/binary-ast">over-the-wire format for JavaScript</a> that could improve application start-up performance especially on mobile devices. As a bonus, we’re also rolling out one more new feature: “TCP Turbo” automatically chooses the TCP settings to further accelerate your website.</p><p>As a company, we want to help every one of our customers improve web experiences. The growth of Cloudflare, along with the increase in features, has often made simple questions difficult to answer:</p><ul><li><p>How fast is my website?</p></li><li><p>How should I be thinking about performance features?</p></li><li><p>How much faster would the site be if I were to enable a particular feature?</p></li></ul><p>This post will describe the exciting changes we have made to the Speed Page on the Cloudflare dashboard to give our customers a much clearer understanding of how their websites are performing and how they can be made even faster. The new Speed Page consists of :</p><ul><li><p>A visual comparison of your website loading on Cloudflare, with caching enabled, compared to connecting directly to the origin.</p></li><li><p>The measured improvement expected if any performance feature is enabled.</p></li><li><p>A report describing how fast your website is on desktop and mobile.</p></li></ul><p>We want to simplify the complexity of making web experiences fast and give our customers control.  Take a look - We hope you like it.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7HG9zZiFbLdNOXolin2M33/a463e5a1537c803fe5467ad2808a859e/SpeedPage--1-.png" />
            
            </figure>
    <div>
      <h3>Why do fast web experiences matter?</h3>
      <a href="#why-do-fast-web-experiences-matter">
        
      </a>
    </div>
    <p><b>Customer experience :</b> No one likes slow service. Imagine if you go to a restaurant and the service is slow, especially when you arrive; you are not likely to go back or recommend it to your friends. It turns out the web works in the same way and Internet customers are even more demanding. As many as <a href="https://blog.hubspot.com/marketing/page-load-time-conversion-rates">79% of customers</a> who are “dissatisfied” with a website’s performance are less likely to buy from that site again.</p><p><b>Engagement and Revenue :</b> There are many studies explaining how speed affects customer engagement, bounce rates and revenue.</p><p><b>Reputation :</b> There is also brand reputation to consider as customers associate an online experience to the brand. A study found that for <a href="https://www.singlestoneconsulting.com/articles/patience-is-a-virtue">66%</a> of the sample website performance influences their impression of the company.</p><p><b>Diversity :</b> Mobile traffic has grown to be larger than its desktop counterpart over the last few years. Mobile customers' expectations have become increasingly demanding and expect seamless Internet access regardless of location.</p><p>Mobile provides a new set of challenges that includes the diversity of device specifications. When testing, be aware that the average mobile device is significantly less capable than the top-of-the-range models. For example, there can be orders-of-magnitude disparity in the time different mobile devices take to run JavaScript. Another challenge is the variance in mobile performance, as customers move from a strong, high quality office network to mobile networks of different speeds (3G/5G), and quality within the same browsing session.</p>
    <div>
      <h3>New Speed Page</h3>
      <a href="#new-speed-page">
        
      </a>
    </div>
    <p>There is compelling evidence that a faster web experience is important for anyone online. Most of the major studies involve the largest tech companies, who have whole teams dedicated to measuring and improving web experiences for their own services. At Cloudflare we are on a mission to help build a better and faster Internet for everyone - not just the selected few.</p><p>Delivering fast web experiences is not a simple matter. That much is clear.To know what to send and when requires a deep understanding of every layer of the stack, from TCP tuning, protocol level prioritisation, content delivery formats through to the intricate mechanics of browser rendering.  You will also need a global network that strives to be within 10 ms of every Internet user. The intrinsic value of such a network, should be clear to everyone. Cloudflare <i>has</i> this network, but it also offers many additional performance features.</p><p>With the Speed Page redesign, we are emphasizing the performance benefits of using Cloudflare and the additional improvements possible from our features.</p><p>The de facto standard for measuring website performance has been <a href="https://www.webpagetest.org/">WebPageTest</a>. Having its creator in-house at Cloudflare encouraged us to use it as the basis for website performance measurement. So, what is the easiest way to understand how a web page loads? A list of statistics do not paint a full picture of actual user experience. One of the cool features of WebPageTest is that it can generate a filmstrip of screen snapshots taken during a web page load, enabling us to quantify how a page loads, visually. This view makes it significantly easier to determine how long the page is blank for, and how long it takes for the most important content to render. Being able to look at the results in this way, provides the ability to empathise with the user.</p>
    <div>
      <h3>How fast on Cloudflare ?</h3>
      <a href="#how-fast-on-cloudflare">
        
      </a>
    </div>
    <p>After moving your website to Cloudflare, you may have asked: How fast did this decision make my website? Well, now we provide the answer:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/ul30Mk0yn4elSNrAodrkg/2428b0205cf0c82f2cc812f04fad3638/OnlyFilmstrip-1.png" />
            
            </figure><p>Comparison of website performance using Cloudflare. </p><p>As well as the increase in speed, we provide filmstrips of before and after, so that it is easy to compare and understand how differently a user will experience the website. If our tests are unable to reach your origin and you are already setup on Cloudflare, we will test with development mode enabled, which disables caching and minification.</p><p><b>Site performance statistics</b></p><p>How can we measure the user experience of a website?</p><p>Traditionally, <i>page load</i> was the important metric. Page load is a technical measurement used by browser vendors that has no bearing on the presentation or usability of a page. The metric reports on how long it takes not only to load the important content but also all of the 3rd party content (social network widgets, advertising, tracking scripts etc.). A user may very well not see anything until after all the page content has loaded, or they may be able to interact with a page immediately, while content continues to load.</p><p>A user will not decide whether a page is fast by a single measure or moment. A user will perceive how fast a website is from a combination of factors:</p><ul><li><p>when they <i>see</i> any response</p></li><li><p>when they see the <i>content</i> they expect</p></li><li><p>when they can <i>interact</i> with the page</p></li><li><p>when they can <i>perform</i> the task they intended</p></li></ul><p>Experience has shown that if you focus on one measure, it will likely be to the detriment of the others.</p><p><b>Importance of Visual response</b></p><p>If an impatient user navigates to your site and sees no content for several seconds or no valuable content, they are likely to get frustrated and leave. The <a href="https://w3c.github.io/paint-timing/">paint timing spec</a> defines a set of <a href="https://docs.google.com/document/d/1BR94tJdZLsin5poeet0XoTW60M0SjvOJQttKT-JK8HI/view">paint metrics</a>, when content appears on a page, to measure the key moments in how a user perceives performance.</p><p><b>First Contentful Paint</b> (FCP) is the time when the browser first renders any DOM content.</p><p><b>First Meaningful Paint</b> (FMP) is the point in time when the page’s “primary” content appears on the screen. This metric should relate to what the user has come to the site to see and is designed as the point in time when the largest visible layout change happens.</p><p><b>Speed Index</b> attempts to quantify the value of the filmstrip rather than using a single paint timing. The <a href="https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/metrics/speed-index">speed index</a> measures the rate at which content is displayed - essentially the area above the curve. In the chart below from our progressive image feature you can see reaching 80% happens much earlier for the parallelized (red) load rather than the regular (blue).</p><img src="http://staging.blog.mrk.cfdata.org/content/images/2019/05/speedindex-1.png" />

    <div>
      <h3>Importance of interactivity</h3>
      <a href="#importance-of-interactivity">
        
      </a>
    </div>
    <p>The same impatient user is now happy that the content they want to see has appeared. They will still become frustrated if they are unable to interact with the site.<b>Time to Interactive</b> is the time it takes for content to be rendered and the page is ready to receive input from the user. Technically this is defined as when the browser’s main processing thread has been idle for several seconds after first meaningful paint.</p><p>The Speed Tab displays these key metrics for mobile and desktop.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/50EYtQgFSjMevEDSsIk4CG/c327d48e0b7b24fe8d650de11fd88834/CriticalLoadingTime-5.png" />
            
            </figure>
    <div>
      <h3>How much faster on Cloudflare ?</h3>
      <a href="#how-much-faster-on-cloudflare">
        
      </a>
    </div>
    <p>The Cloudflare Dashboard provides a list of performance features which can, admittedly, be both confusing and daunting. What would be the benefit of turning on Rocket Loader and on which performance metrics will it have the most impact ? If you upgrade to Pro what will be the value of the enhanced HTTP/2 prioritisation ? The optimization section answers these questions.</p><p>Tests are run with each performance feature turned on and off. The values for the tests for the appropriate performance metrics are displayed, along with the improvement. You can enable or upgrade the feature from this view. Here are a few examples :</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6LkuEkCNY8bloX9JvJEAOS/1c067dbce64927affb3e4420044dd4af/RocketLoader.png" />
            
            </figure><p>If Rocket Loader were enabled for this website, the render-blocking JavaScript would be deferred causing first paint time to drop from 1.25s to 0.81s - an improvement of 32% on desktop.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/kyJrVQRTpGxQb3HuFBIJn/82475df75c20123ec9d81a7ed2631c3f/Mirage.png" />
            
            </figure><p>Image heavy sites do not perform well on slow mobile connections. If you enable Mirage, your customers on 3G connections would see meaningful content 1s sooner - an improvement of 29.4%.</p><p>So how about our new features?</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5erNk1iTWG0gx7vm8dwITX/288529be98b01aa378dc4489a8c690fd/H2.png" />
            
            </figure><p>We tested the enhanced HTTP/2 prioritisation feature on an Edge browser on desktop and saw meaningful content display 2s sooner - an improvement of 64%.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5DSkRUoK50wHoHsUtWHcc1/32099750c650930c1d9c89e7a40033bb/ProImgStreaming.png" />
            
            </figure><p>This is a more interesting result taken from the blog example used to illustrate the progressive image streaming. At first glance the improvement of 29% in speed index is good. The filmstrip comparison shows a more significant difference. In this case the page with no images shown is already 43% visually complete for both scenarios after 1.5s. At 2.5s the difference is 77% compared to 50%.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2tf37dOPAwHL1lKPQNkxVq/6fd8cc88184349c12f57bec4adeba5e0/filmstrip.png" />
            
            </figure><p>This is a great example of how metrics do not tell the full story. They cannot completely replace viewing the page loading flow and understanding what is important for your site.</p>
    <div>
      <h3>How to try</h3>
      <a href="#how-to-try">
        
      </a>
    </div>
    <p>This is our first iteration of the new Speed Page and we are eager to get your feedback. We will be rolling this out to beta customers who are interested in seeing how their sites perform. To be added to the queue for activation of the new Speed Page please click on the banner on the overview page,</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1eHf4V1lYUprNu6EuYGVLc/fa2b5e64ed05508e9139cdd37e180596/BannerOverview.png" />
            
            </figure><p>or click on the banner on the existing Speed Page.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5sJqPyA2OJDHOkxRDiIwvB/de77d2e82ab87960f06c3385e3accda5/BannerSpeed.png" />
            
            </figure> ]]></content:encoded>
            <category><![CDATA[Speed Week]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Dashboard]]></category>
            <guid isPermaLink="false">24ufNjE5kwbiozkOO2zlWM</guid>
            <dc:creator>Andrew Galloni</dc:creator>
        </item>
        <item>
            <title><![CDATA[Better HTTP/2 Prioritization for a Faster Web]]></title>
            <link>https://blog.cloudflare.com/better-http-2-prioritization-for-a-faster-web/</link>
            <pubDate>Tue, 14 May 2019 13:00:00 GMT</pubDate>
            <description><![CDATA[ Advancing the state of the art of HTTP/2 to deliver a faster user experience. See why it matters and how much of a differenc ]]></description>
            <content:encoded><![CDATA[ <p>HTTP/2 promised a much faster web and Cloudflare rolled out HTTP/2 access for all our customers long, long ago. But one feature of HTTP/2, Prioritization, didn’t live up to the hype. Not because it was fundamentally broken but because of the way browsers implemented it.</p><p>Today Cloudflare is pushing out a change to HTTP/2 Prioritization that gives our servers control of prioritization decisions that truly make the web much faster.</p><p>Historically the browser has been in control of deciding how and when web content is loaded. Today we are introducing a radical change to that model for all paid plans that puts control into the hands of the site owner directly. Customers can enable “Enhanced HTTP/2 Prioritization” in the Speed tab of the Cloudflare dashboard: this overrides the browser defaults with an improved scheduling scheme that results in a significantly faster visitor experience (we have seen 50% faster on multiple occasions). With <a href="https://www.cloudflare.com/developer-platform/workers/">Cloudflare Workers</a>, site owners can take this a step further and fully customize the experience to their specific needs.</p>
    <div>
      <h3>Background</h3>
      <a href="#background">
        
      </a>
    </div>
    <p>Web pages are made up of <a href="https://discuss.httparchive.org/t/whats-the-distribution-of-requests-per-page/21/10?u=patmeenan">dozens (sometimes hundreds)</a> of separate resources that are loaded and assembled by the browser into the final displayed content. This includes the visible content the user interacts with (HTML, CSS, images) as well as the application logic (JavaScript) for the site itself, ads, analytics for tracking site usage and marketing tracking beacons. The sequencing of how those resources are loaded can have a significant impact on how long it takes for the user to see the content and interact with the page.</p><p>A browser is basically an HTML processing engine that goes through the HTML document and follows the instructions in order from the start of the HTML to the end, building the page as it goes along. References to stylesheets (CSS) tell the browser how to style the page content and the browser will delay displaying content until it has loaded the stylesheet (so it knows how to style the content it is going to display). Scripts referenced in the document can have several different behaviors. If the script is tagged as “async” or “defer” the browser can keep processing the document and just run the script code whenever the scripts are available. If the scripts are not tagged as async or defer then the browser <a href="https://html.spec.whatwg.org/">MUST</a> stop processing the document until the script has downloaded and executed before continuing. These are referred to as “blocking” scripts because they block the browser from continuing to process the document until they have been loaded and executed.</p><p>The HTML document is split into two parts. The <code>&lt;head&gt;</code> of the document is at the beginning and contains stylesheets, scripts and other instructions for the browser that are needed to display the content. The <code>&lt;body&gt;</code> of the document comes after the head and contains the actual page content that is displayed in the browser window (though scripts and stylesheets are allowed to be in the body as well). Until the browser gets to the body of the document there is nothing to display to the user and the page will remain blank so getting through the head of the document as quickly as possible is important. “HTML5 rocks” has a <a href="https://www.html5rocks.com/en/tutorials/internals/howbrowserswork/">great tutorial</a> on how browsers work if you want to dive deeper into the details.</p><p>The browser is generally in charge of determining the order of loading the different resources it needs to build the page and to continue processing the document. In the case of HTTP/1.x, the browser is limited in how many things it can request from any one server at a time (generally 6 connections and only one resource at a time per connection) so the ordering is strictly controlled by the browser by how things are requested. With HTTP/2 <a href="https://www.cloudflare.com/learning/performance/http2-vs-http1.1/">things change pretty significantly</a>. The browser can request all of the resources at once (at least as soon as it knows about them) and it provides <a href="https://hpbn.co/http2/#stream-prioritization">detailed instructions</a> to the server for how the resources should be delivered.</p>
    <div>
      <h3>Optimal Resource Ordering</h3>
      <a href="#optimal-resource-ordering">
        
      </a>
    </div>
    <p>For most parts of the page loading cycle there is an optimal ordering of the resources that will result in the fastest user experience (and the difference between optimal and not can be significant - as much as a 50% improvement or more).</p><p>As described above, early in the page load cycle before the browser can render any content it is blocked on the CSS and blocking JavaScript in the <code>&lt;head&gt;</code> section of the HTML. During that part of the loading cycle it is best for 100% of the connection bandwidth to be used to download the blocking resources and for them to be downloaded one at a time in the order they are defined in the HTML. That lets the browser parse and execute each item while it is downloading the next blocking resource, allowing the download and execution to be pipelined.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/s20F4kV70i7sqhrMifCLU/588f1954891895eedbc46df730d8afdc/pipeline-1.png" />
            
            </figure><p>The scripts take the same amount of time to download when downloaded in parallel or one after the other but by downloading them sequentially the first script can be processed and execute while the second script is downloading.</p><p>Once the render-blocking content has loaded things get a little more interesting and the optimal loading may depend on the specific site or even business priorities (user content vs ads vs analytics, etc). Fonts in particular can be difficult as the browser only discovers what fonts it needs after the stylesheets have been applied to the content that is about to be displayed so by the time the browser knows about a font, it is needed to display text that is already ready to be drawn to the screen. Any delays in getting the font loaded end up as periods with blank text on the screen (or text displayed using the wrong font).</p><p>Generally there are some tradeoffs that need to be considered:</p><ul><li><p>Custom fonts and visible images in the visible part of the page (viewport) should be loaded as quickly as possible. They directly impact the user’s visual experience of the page loading.</p></li><li><p>Non-blocking JavaScript should be downloaded serially relative to other JavaScript resources so the execution of each can be pipelined with the downloads. The JavaScript may include user-facing application logic as well as analytics tracking and marketing beacons and delaying them can cause a drop in the metrics that the business tracks.</p></li><li><p>Images benefit from downloading in parallel. The first few bytes of an image file contain the image dimensions which may be necessary for browser layout, and progressive images downloading in parallel can look visually complete with around 50% of the bytes transferred.</p></li></ul><p>Weighing the tradeoffs, one strategy that works well in most cases is:</p><ul><li><p>Custom fonts download sequentially and split the available bandwidth with visible images.</p></li><li><p>Visible images download in parallel, splitting the “images” share of the bandwidth among them.</p></li><li><p>When there are no more fonts or visible images pending:</p><ul><li><p>Non-blocking scripts download sequentially and split the available bandwidth with non-visible images</p></li><li><p>Non-visible images download in parallel, splitting the “images” share of the bandwidth among them.</p></li></ul></li></ul><p>That way the content visible to the user is loaded as quickly as possible, the application logic is delayed as little as possible and the non-visible images are loaded in such a way that layout can be completed as quickly as possible.</p>
    <div>
      <h3>Example</h3>
      <a href="#example">
        
      </a>
    </div>
    <p>For illustrative purposes, we will use a simplified product category page from a typical <a href="https://www.cloudflare.com/ecommerce/">e-commerce site</a>. In this example the page has:</p><p><img src="https://images.ctfassets.net/zkvhlag99gkb/145sNNiiOcM6IHvlHCPrKN/2bf1eda5852c3cbef911230fa4c5b327/html-1.png?h=50" /> The HTML file for the page itself, represented by a blue box.</p>
<p><img src="https://images.ctfassets.net/zkvhlag99gkb/4BsBnjaP0Lf79mAiFfAecf/1270b865cbc581082352c89f8c1ecef4/css-1.png?h=50" /> 1 external stylesheet (CSS file), represented by a green box.</p>
<p><img src="https://images.ctfassets.net/zkvhlag99gkb/hpncpQ52hkS4CtiZuIs05/98953dd0e08b5c8d0bbb4d4cba5aa731/script-1.png" /> 4 external scripts (JavaScript), represented by orange boxes. 2 of the scripts are blocking at the beginning of the page and 2 are asynchronous. The blocking script boxes use a darker shade of orange.</p>
<p><img src="https://images.ctfassets.net/zkvhlag99gkb/59Odb7qJYEVNtcMILE7V1l/a59365e9c52bae8607237513e4b6f583/font-1.png" /> 1 custom web font, represented by a red box.</p>
<p><img src="https://images.ctfassets.net/zkvhlag99gkb/6Vu0MFw5Jmo9DKkBiNhTq4/dafbe4485dee9aeec87685728ec7b926/image-1.png" /> 13 images, represented by purple boxes. The page logo and 4 of the product images are visible in the viewport and 8 of the product images require scrolling to see. The 5 visible images use a darker shade of purple.</p><p>For simplicity, we will assume that all the resources are the same size and each takes 1 second to download on the visitor’s connection. Loading everything takes a total of 20 seconds, but HOW it is loaded can have a huge <a href="https://www.cloudflare.com/solutions/ecommerce/optimization/">impact</a> to the experience.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6ZDzhZm88h13LKAQAlmJ3W/0283bd74ba6c85042717a096a1aa00ba/optimal-1.png" />
            
            </figure><p>This is what the described optimal loading would look like in the browser as the resources load:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6VglYMpZ814iSoMmiDEoLz/a5e4849cf69b7adeb7be5bba7cb863cd/Optimal_loading-1.gif" />
            
            </figure><ul><li><p>The page is blank for the first 4 seconds while the HTML, CSS and blocking scripts load, all using 100% of the connection.</p></li><li><p>At the 4-second mark the background and structure of the page is displayed with no text or images.</p></li><li><p>One second later, at 5 seconds, the text for the page is displayed.</p></li><li><p>From 5-10 seconds the images load, starting out as blurry but sharpening very quickly. By around the 7-second mark it is almost indistinguishable from the final version.</p></li><li><p>At the 10 second mark all of the visual content in the viewport has completed loading.</p></li><li><p>Over the next 2 seconds the asynchronous JavaScript is loaded and executed, running any non-critical logic (analytics, marketing tags, etc).</p></li><li><p>For the final 8 seconds the rest of the product images load so they are ready for when the user scrolls.</p></li></ul>
    <div>
      <h3>Current Browser Prioritization</h3>
      <a href="#current-browser-prioritization">
        
      </a>
    </div>
    <p>All of the current browser engines implement <a href="https://calendar.perfplanet.com/2018/http2-prioritization/">different prioritization strategies</a>, none of which are optimal.</p><p><b>Microsoft Edge and Internet Explorer</b> <a href="https://calendar.perfplanet.com/2018/http2-prioritization/#microsoft_edge_internet_explorer">do not support prioritization</a> so everything falls back to the HTTP/2 default which is to load everything in parallel, splitting the bandwidth evenly among everything. Microsoft Edge is moving to use the Chromium browser engine in future Windows releases which will help improve the situation. In our example page this means that the browser is stuck in the head for the majority of the loading time since the images are slowing down the transfer of the blocking scripts and stylesheets.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/ERv7hb1NYBHy60aJuy5jD/04cd8f5947317252fa17648d4d227216/edge-1.png" />
            
            </figure><p>Visually that results in a pretty painful experience of staring at a blank screen for 19 seconds before most of the content displays, followed by a 1-second delay for the text to display. Be patient when watching the animated progress because for the 19 seconds of blank screen it may feel like nothing is happening (even though it is):</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3UcgquIFWREMgbBsEJNQk2/5caa49f6d98a28bc407bd1d6773670f8/Edge_loading-1.gif" />
            
            </figure><p><b>Safari</b> <a href="https://calendar.perfplanet.com/2018/http2-prioritization/#safari">loads all resources in parallel</a>, splitting the bandwidth between them based on how important Safari believes they are (with render-blocking resources like scripts and stylesheets being more important than images). Images load in parallel but also load at the same time as the render-blocking content.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2L8xcpZEdYQJstyuI5ORRR/45220b046032cb8ffd1f2ce85cc1f0cd/safari-1.png" />
            
            </figure><p>While similar to Edge in that everything downloads at the same time, by allocating more bandwidth to the render-blocking resources Safari can display the content much sooner:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5bN7ouLtrKcl2dWQ2fESJ5/f7fd9768b20b76deb0dcee3488fa0296/Safari_loading-1.gif" />
            
            </figure><ul><li><p>At around 8 seconds the stylesheet and scripts have finished loading so the page can start to be displayed. Since the images were loading in parallel, they can also be rendered in their partial state (blurry for progressive images). This is still twice as slow as the optimal case but much better than what we saw with Edge.</p></li><li><p>At around 11 seconds the font has loaded so the text can be displayed and more image data has been downloaded so the images will be a little sharper. This is comparable to the experience around the 7-second mark for the optimal loading case.</p></li><li><p>For the remaining 9 seconds of the load the images get sharper as more data for them downloads until it is finally complete at 20 seconds.</p></li></ul><p><b>Firefox</b> builds a dependency tree that <a href="https://calendar.perfplanet.com/2018/http2-prioritization/#firefox">groups resources</a> and then schedules the groups to either load one after another or to share bandwidth between the groups. Within a given group the resources share bandwidth and download concurrently. The images are scheduled to load after the render-blocking stylesheets and to load in parallel but the render-blocking scripts and stylesheets also load in parallel and do not get the benefits of pipelining.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3mnypoOho1hKfUiSl834Cf/7aeef99c40884ea1c4807f7ba3cfdbc3/firefox-1.png" />
            
            </figure><p>In our example case this ends up being a slightly faster experience than with Safari since the images are delayed until after the stylesheets complete:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2yjKwptC34WE2GigxNdo0R/7a7616f2c1876d62765649bd768b698a/Firefox_loading-1.gif" />
            
            </figure><ul><li><p>At the 6 second mark the initial page content is rendered with the background and blurry versions of the product images (compared to 8 seconds for Safari and 4 seconds for the optimal case).</p></li><li><p>At 8 seconds the font has loaded and the text can be displayed along with slightly sharper versions of the product images (compared to 11 seconds for Safari and 7 seconds in the Optimal case).</p></li><li><p>For the remaining 12 seconds of the loading the product images get sharper as the remaining content loads.</p></li></ul><p><b>Chrome</b> (and all Chromium-based browsers) prioritizes resources into a <a href="https://calendar.perfplanet.com/2018/http2-prioritization/#chrome">list</a>. This works really well for the render-blocking content that benefits from loading in order but works less well for images. Each image loads to 100% completion before starting the next image.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4VAHVWx6bngx7CK2px6qAe/08da953608a3d887b8ae59d68db633be/chrome-1.png" />
            
            </figure><p>In practice this is almost as good as the optimal loading case with the only difference being that the images load one at a time instead of in parallel:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4WxB31Ov3jzmpNmPRjH0A5/8e23e517276c6a13e7c7f0087f23bd65/Chrome_loading-1.gif" />
            
            </figure><ul><li><p>Up until the 5 second mark the Chrome experience is identical to the optimal case, displaying the background at 4 seconds and the text content at 5.</p></li><li><p>For the next 5 seconds the visible images load one at a time until they are all complete at the 10 second mark (compared to the optimal case where they are just slightly blurry at 7 seconds and sharpen up for the remaining 3 seconds).</p></li><li><p>After the visual part of the page is complete at 10 seconds (identical to the optimal case), the remaining 10 seconds are spent running the async scripts and loading the hidden images (just like with the optimal loading case).</p></li></ul>
    <div>
      <h3>Visual Comparison</h3>
      <a href="#visual-comparison">
        
      </a>
    </div>
    <p>Visually, the impact can be quite dramatic, even though they all take the same amount of time to technically load all of the content:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/67CSkIvoirmEfMIUAo4y07/ed87a8f8ce29a212c1cd09c2c69ec95a/compare.gif" />
            
            </figure>
    <div>
      <h3>Server-Side Prioritization</h3>
      <a href="#server-side-prioritization">
        
      </a>
    </div>
    <p>HTTP/2 prioritization is requested by the client (browser) and it is up to the server to decide what to do based on the request. A <a href="https://github.com/andydavies/http2-prioritization-issues">good number of servers don’t support doing anything at all with the prioritization</a> but for those that do, they all honor the client’s request. Another option would be to decide on the best prioritization to use on the server-side, taking into account the client’s request.</p><p>Per the <a href="https://httpwg.org/specs/rfc9113.html#StreamPriority">specification</a>, HTTP/2 prioritization is a dependency tree that requires full knowledge of all of the in-flight requests to be able to prioritize resources against each other. That allows for incredibly complex strategies but is difficult to implement well on either the browser or server side (as evidenced by the different browser strategies and varying levels of server support). To make prioritization easier to manage we have developed a simpler prioritization scheme that still has all of the flexibility needed for optimal scheduling.</p><p>The Cloudflare prioritization scheme consists of 64 priority “levels” and within each priority level there are groups of resources that determine how the connection is shared between them:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/245bFqwfOBgQvwwRLWGNGE/6898590819dedda5cf30444e7014c059/priorities.png" />
            
            </figure><p>All of the resources at a higher priority level are transferred before moving on to the next lower priority level.</p><p>Within a given priority level, there are 3 different “concurrency” groups:</p><ul><li><p><b>0</b> : All of the resources in the concurrency “0” group are sent sequentially in the order they were requested, using 100% of the bandwidth. Only after all of the concurrency “0” group resources have been downloaded are other groups at the same level considered.</p></li><li><p><b>1</b> : All of the resources in the concurrency “1” group are sent sequentially in the order they were requested. The available bandwidth is split evenly between the concurrency “1” group and the concurrency “n” group.</p></li><li><p><b>n</b> : The resources in the concurrency “n” group are sent in parallel, splitting the bandwidth available to the group between them.</p></li></ul><p>Practically speaking, the concurrency “0” group is useful for critical content that needs to be processed sequentially (scripts, CSS, etc). The concurrency “1” group is useful for less-important content that can share bandwidth with other resources but where the resources themselves still benefit from processing sequentially (async scripts, non-progressive images, etc). The concurrency “n” group is useful for resources that benefit from processing in parallel (progressive images, video, audio, etc).</p>
    <div>
      <h3>Cloudflare Default Prioritization</h3>
      <a href="#cloudflare-default-prioritization">
        
      </a>
    </div>
    <p>When enabled, the enhanced prioritization implements the “optimal” scheduling of resources described above. The specific prioritizations applied look like this:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/36JhpUvPcpYATKuUcb0HQm/5588ef0b814df225b2f1d934f34c4638/defaults.png" />
            
            </figure><p>This prioritization scheme allows sending the render-blocking content serially, followed by the visible images in parallel and then the rest of the page content with some level of sharing to balance application and content loading. The “* If Detectable” caveat is that not all browsers differentiate between the different types of stylesheets and scripts but it will still be significantly faster in all cases. 50% faster by default, particularly for Edge and Safari visitors is not unusual:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3br9uRCejjByZGW4mVxQyp/d4755f71f3b5432373244dbe1ac7e89d/filmstrip2.png" />
            
            </figure>
    <div>
      <h3>Customizing Prioritization with Workers</h3>
      <a href="#customizing-prioritization-with-workers">
        
      </a>
    </div>
    <p>Faster-by-default is great but where things get really interesting is that the ability to configure the prioritization is also exposed to Cloudflare Workers so sites can override the default prioritization for resources or implement their own complete prioritization schemes.</p><p>If a Worker adds a “cf-priority” header to the response, Cloudflare edge servers will use the specified priority and concurrency for that response. The format of the header is <code>&lt;priority&gt;/&lt;concurrency&gt;</code> so something like <code>response.headers.set('cf-priority', “30/0”);</code> would set the priority to 30 with a concurrency of 0 for the given response. Similarly, “30/1” would set concurrency to 1 and “30/n” would set concurrency to n.</p><p>With this level of flexibility a site can tweak resource prioritization to meet their needs. Boosting the priority of some critical async scripts for example or increasing the priority of hero images before the browser has identified that they are in the viewport.</p><p>To help inform any prioritization decisions, the Workers runtime also exposes the browser-requested prioritization information in the request object passed in to the Worker’s fetch event listener (request.cf.requestPriority). The incoming requested priority is a semicolon-delimited list of attributes that looks something like this: “weight=192;exclusive=0;group=3;group-weight=127”.</p><ul><li><p><b>weight</b>: The browser-requested weight for the HTTP/2 prioritization.</p></li><li><p><b>exclusive</b>: The browser-requested HTTP/2 exclusive flag (1 for Chromium-based browsers, 0 for others).</p></li><li><p><b>group</b>: HTTP/2 stream ID for the request group (only non-zero for Firefox).</p></li><li><p><b>group-weight</b>: HTTP/2 weight for the request group (only non-zero for Firefox).</p></li></ul>
    <div>
      <h3>This is Just the Beginning</h3>
      <a href="#this-is-just-the-beginning">
        
      </a>
    </div>
    <p>The ability to tune and control the prioritization of responses is the basic building block that a lot of future work will benefit from. We will be implementing our own <a href="https://www.cloudflare.com/application-services/products/website-optimization/">advanced optimizations</a> on top of it but by exposing it in Workers we have also opened it up to sites and researchers to experiment with different prioritization strategies. With the Apps Marketplace it is also possible for companies to build new optimization services on top of the Workers platform and make it available to other sites to use.</p><p>If you are on a <a href="https://www.cloudflare.com/plans/pro/">Pro plan</a> or above, head over to the speed tab in the Cloudflare dashboard and turn on “Enhanced HTTP/2 Prioritization” to accelerate your site.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/36yaMZfdrrrZlYjivB5xnY/8730346008c9a991586a91b61754fd1c/speed-week-copy-2_2x.png" />
            
            </figure><p></p> ]]></content:encoded>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[Speed Week]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[Product News]]></category>
            <guid isPermaLink="false">14X39RjlgOpBoyWcVxeYGf</guid>
            <dc:creator>Patrick Meenan (Guest Author)</dc:creator>
        </item>
        <item>
            <title><![CDATA[Fast Google Fonts with Cloudflare Workers]]></title>
            <link>https://blog.cloudflare.com/fast-google-fonts-with-cloudflare-workers/</link>
            <pubDate>Thu, 22 Nov 2018 07:58:00 GMT</pubDate>
            <description><![CDATA[ Code walkthrough on using Cloudflare workers to improve the performance of sites using Google Fonts. The improvements can be quite dramatic and the sample provides a real-world use case of doing streaming HTML modification in a Cloudflare Worker. ]]></description>
            <content:encoded><![CDATA[ <p>Google Fonts is one of the most common third-party resources on the web, but carries with it significant user-facing performance issues. Cloudflare Workers running at the edge is a great solution for fixing these performance issues, without having to modify the publishing system for every site using Google Fonts.</p><p>This post walks through the implementation details for how to fix the performance of Google Fonts with Cloudflare Workers. More importantly, it also provides code for doing high-performance content modification at the edge using Cloudflare Workers.</p>
    <div>
      <h3>Google fonts are SLOW</h3>
      <a href="#google-fonts-are-slow">
        
      </a>
    </div>
    <p>First, some background. <a href="https://fonts.google.com/">Google Fonts</a> provides a rich selection of royalty-free fonts for sites to use. You select the fonts you want to use, and end up with a simple stylesheet URL to include on your pages, as well as styles to use for applying the fonts to parts of the page:</p>
            <pre><code>&lt;link href="https://fonts.googleapis.com/css?family=Open+Sans|Roboto+Slab"
      rel="stylesheet"&gt;
&lt;style&gt;
body {
 font-family: 'Open Sans', sans-serif;
}
h1 {
 font-family: 'Roboto Slab', serif;
}</code></pre>
            <p>Your visitor’s browser fetches the CSS file as soon as the HTML for the page is available. The browser will request the underlying font files when the browser does layout for the page and discovers that it needs fonts for different sections of text.</p><p>The way Google fonts are served, the CSS is on one domain (fonts.googleapis.com) and the font files are on a different domain (fonts.gstatic.com). Since they are on separate domains, the fetch for each resource takes a minimum of four round trips back and forth to the server: One each for the DNS lookup, establishing the socket connection, negotiating TLS encryption (for https) and a final round trip for the request itself.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2emQRH8SC0mYJpSOJ58FUK/34a15d2f34fe2782706f04d3ecc78d98/before-round-trips.png" />
            
            </figure><p>4 round trips each for the font css and font file.</p><p>The requests can’t be done in parallel because the fonts aren’t known about until after the CSS has been downloaded and the styles applied to the page. In a best-case scenario, this translates to eight round-trips before the text can be displayed (the text which was already available in the browser as soon as the HTML was available). On a slower 3G connection with a 300ms round-trip time, this adds up to a 2.4 second delay. Best case!</p><p>There is also a problem with resource prioritization. When you have all of the requests coming from the same domain on the same HTTP/2 connection they can be scheduled against each other. Critical resources (like CSS and fonts) can be pushed ahead in the queue and delivered before lower priority resources (like images). Since Google Fonts (and most third-party resources) are served from a different domain than the main page resources, they cannot be prioritized and end up competing with each other for download bandwidth. This can cause the actual fetch times to be much longer than the best-case of 8 round trips.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/hYNUX0ngMLAKMUqN8jQhj/de35321957316e751a8411df7068f851/before-competing.png" />
            
            </figure><p>CSS and font download competing with low-priority images for bandwidth.</p><p>Users will see the images and skeleton for the page <a href="https://www.webpagetest.org/video/view.php?id=181016_befafeb79a563c08a7c4012ec10379ccb1c2f755">long before</a> the actual text is displayed:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7tAfGVsUZxzYE99QUHQTlr/44bfe9947e72383443afb6f29b88e343/b1-image-paint.png" />
            
            </figure><p>The page starts painting at 3.3 seconds with partial images and no text.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1c2TrfVScCtSgq6uAquxOC/242f0831bdc00aebaca98af15e1f285e/b2-text.png" />
            
            </figure><p>The text finally displays at 6.2 seconds into the page load.</p>
    <div>
      <h3>Fixing Google Fonts performance</h3>
      <a href="#fixing-google-fonts-performance">
        
      </a>
    </div>
    <p>The paths to fixing performance issues and making fonts lightning-fast is different for the CSS and the font files themselves. We can reduce the total number of round trips to one:</p><ol><li><p>Embed the CSS directly in the HTML.</p></li><li><p>Proxy the Google Font files through the page origin.</p></li></ol>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7ImYCsOuIuMBm24oD75ZfA/89877f802875de7e320691f7464125eb/Fonts.png" />
            
            </figure><p>The embedded CSS loads immediately as part of the HTML and the fonts load before the images.</p>
    <div>
      <h4>Optimizing CSS delivery</h4>
      <a href="#optimizing-css-delivery">
        
      </a>
    </div>
    <p>For CSS, the easy answer is to just download the CSS file that Google hosts and either serve it yourself directly or place it into the HTML as an embedded stylesheet. The problem with this is that Google fonts serves a browser-specific CSS file that is different for each browser so it can serve newer formats and use newer features, when supported, while still providing custom font support for older browsers.</p><p>With Cloudflare Workers, we can dynamically replace the external CSS reference with the browser-specific stylesheet content at fetch time when the HTML is requested by the browser. This way, the embedded CSS will always be up to date and support the capabilities of whichever browser is making the request. This completely eliminates any round trips for fetching the CSS for the fonts.</p>
    <div>
      <h4>Optimizing font file delivery</h4>
      <a href="#optimizing-font-file-delivery">
        
      </a>
    </div>
    <p>For the font files themselves, we can eliminate all of the round trips except for the fetch itself by serving the font files directly from the same domain as the HTML. This brings with it the added benefit of serving fonts over the same HTTP/2 connection as the rest of the page resources, allowing them to be prioritized correctly and not compete for bandwidth.</p><p>Specifically, when we embed the CSS into the HTML response, we rewrite all of the font URLs to use the same domain as the HTML. When those rewritten requests arrive at the worker the URL is transformed back to the original URL served by Google and fetched by the worker (as a proxy). The worker fetches are routed through Cloudflare’s caching infrastructure so they will be cached automatically at the edge. The actual URL rewriting is pretty simple but effective. We take font URLs that look like this:</p>
            <pre><code>https://fonts.gstatic.com/s/...</code></pre>
            <p>and we just prepend the page domain to the front of the URL:</p>
            <pre><code>https://www.example.com/fonts.gstatic.com/s/...</code></pre>
            <p>That way, when they arrive at the edge, the worker can look at the path of a request and know right away that it is a proxy request for a Google font. At this point, rewriting the original URL is trivial. On the extremely odd chance that a page on your site actually has a path that starts with /fonts.gstatic.com/, those resources would break and something else should be appended to the URL to make sure they are unique.</p>
    <div>
      <h4>Optimization Results</h4>
      <a href="#optimization-results">
        
      </a>
    </div>
    <p>In practice, the results can be quite dramatic. On <a href="https://www.perftests.com/googlefonts/">this test page</a> for example, the wait time for fonts to become available dropped from 5.5 seconds to 1 second (an 81% improvement!):</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6c3mWxyg3E5LclNnSBxdCy/6c0aea538a3c2b7d7c5ecb383ec5bfe0/after.png" />
            
            </figure><p>The fonts load immediately after the HTML.</p><p>Visually, the improvement to the user experience is also <a href="https://www.webpagetest.org/video/view.php?id=181016_040e1e2365d95c4c7836281c9cf713ccc8aed3f5">quite dramatic</a>. Instead of seeing a skeleton page of images followed by the text eventually appearing, the text is available (and correctly styled) immediately and the user can start consuming the content right away:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5kWjTwTLDvAES4n8TJg2IH/e94c6635c0ba15d43b61a1a17f249efc/1-initial-text.png" />
            
            </figure><p>The first paint happens much sooner at 2.5 seconds with all of the text displayed while the original page is still blank.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/56RnWXmU9RV9zXzpCFn97p/abaf9c451e0adcec1dfdb6d2cafcefce/2-image-paint.png" />
            
            </figure><p>At 3.3 seconds the original page finally starts to paint, displaying part of the images and no text.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7A9zYZNkzElNgOPRuxYkXe/8751b7c01ef3861c72f12aefe8df056e/2.5-text.png" />
            
            </figure><p>At 4.4 seconds the optimized page is visibly complete while the original page still has not displayed any text.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7qfU3rpfQedLhVuUjE4QTg/68190f6af1b60232997dced05a70d955/3-text-complete.png" />
            
            </figure><p>At 6.2 seconds the original page finally displays the text content.</p><p>One thing that I didn’t notice in the initial testing and only discovered when looking at the side-by-side video is that the fonts are only correctly styled in the optimized case. In the original case it took longer than Chrome’s 3-second timeout for the fonts to load and it fell back to the system fonts. Not only was the experience much faster; it was also styled correctly with the custom fonts right from the beginning.</p>
    <div>
      <h3>Optimizing Google fonts with a Cloudflare worker</h3>
      <a href="#optimizing-google-fonts-with-a-cloudflare-worker">
        
      </a>
    </div>
    <p>The full Cloudflare worker code for implementing the font optimization is available on <a href="https://github.com/cloudflare/worker-examples/tree/master/examples/fast-google-fonts">GitHub here</a>. Buckle-in because this is quite a bit more involved than most of the samples in the documentation.</p><p>At a high level this code:</p><ul><li><p>Filters all requests and determines if a request is for a proxied font or HTML (and passes all other requests through unmodified).</p></li><li><p>Rewrites the URL and passes the fetch request through for Font requests.</p></li><li><p>For HTML requests:</p><ul><li><p>Passes the request through unmodified to the origin server.</p></li><li><p>Returns non-UTF-8 content unmodified..</p></li><li><p>Processes the HTML response in streaming chunks as it is available.</p></li><li><p>Replaces Google font stylesheet link tags with style tags containing the CSS and the font URLs rewritten to proxy through the origin.</p></li></ul></li></ul><p>The code here is slightly simplified to make it clearer to understand the flow. The full code on GitHub adds support for an in-memory worker cache for the CSS (in addition to the persistent cache API) and provides query parameters for toggling the HTML rewriting on and off (for testing).</p><p>The content modification is all done by operating on the HTML as strings (with a combination of regular expressions and string matches). This is much faster and lighter weight than parsing the HTML into a virtual DOM, operating on it and converting back to HTML. It also allows for incremental processing of the HTML as a stream.</p>
    <div>
      <h4>Entry Point</h4>
      <a href="#entry-point">
        
      </a>
    </div>
    <p>The addEventListener(“fetch”) call is the main entry point for any worker and houses the JavaScript for intercepting inbound requests. If the handler does nothing, then the requests will be passed through normally and the worker will be out of the path in processing the response. Our goal it to minimize the amount of work that the worker has to do to determine if it is a request that it is interested in.</p><p>In the case of the proxied font requests, we can just look at the request URL and see that the path starts with /fonts.gstatic.com/. To identify requests for HTML content we can look at the “accept” header on the request. Every major browser I have tested includes text/html on the list of content types that it will accept when requesting a document. On the off chance that there is a browser that doesn’t include it as an accept header, the HTML will just be passed through and returned unmodified. The goal with everything here is to fail-safe and just return unoptimized content for any edge cases that aren’t covered. This way nothing breaks; it just doesn’t get the added performance boost.</p>
            <pre><code>addEventListener("fetch", event =&gt; {
 
 const url = new URL(event.request.url);
 const accept = event.request.headers.get('accept');
 if (event.request.method === 'GET' &amp;&amp;
     url.pathname.startsWith('/fonts.gstatic.com/')) {
 
   // Proxy the font file requests
   event.respondWith(proxyRequest('https:/' + url.pathname,
                                  event.request));
 
 } else if (accept &amp;&amp; accept.indexOf("text/html") !== -1) {
 
   // Process the HTML
   event.respondWith(processHtmlRequest(event.request, event));
 
 }
})</code></pre>
            
    <div>
      <h4>Request Proxy</h4>
      <a href="#request-proxy">
        
      </a>
    </div>
    <p>The proxying of the font requests is pretty straightforward. Since we are crossing origins it is generally a bad idea to just reuse the existing request object with a new URL. That can leak user data like cookies to a Third-party. Instead, we make a new request, clone a subset of the headers and pass the new fetch request back for the Worker runtime to handle.</p><p>The fetch path between workers and the outside Internet goes through the Cloudflare cache so the actual font files will only be fetched from Google if they aren’t already in the cache. Even in that case, the connection from Cloudflare’s edge to Google’s font servers is much faster (and more reliable) than the end-user’s connection from the browser. Even on a cache miss, it is an insignificant delay.</p>
            <pre><code>async function proxyRequest(url, request) {
 
 // Only pass through a subset of request headers
 let init = {
   method: request.method,
   headers: {}
 };
 const proxyHeaders = ["Accept",
                       "Accept-Encoding",
                       "Accept-Language",
                       "Referer",
                       "User-Agent"];
 for (let name of proxyHeaders) {
   let value = request.headers.get(name);
   if (value) {
     init.headers[name] = value;
   }
 }
 const clientAddr = request.headers.get('cf-connecting-ip');
 if (clientAddr) {
   init.headers['X-Forwarded-For'] = clientAddr;
 }
 
 // Only include a strict subset of response headers
 const response = await fetch(url, init);
 if (response) {
   const responseHeaders = ["Content-Type",
                            "Cache-Control",
                            "Expires",
                            "Accept-Ranges",
                            "Date",
                            "Last-Modified",
                            "ETag"];
   let responseInit = {status: response.status,
                       statusText: response.statusText,
                       headers: {}};
   for (let name of responseHeaders) {
     let value = response.headers.get(name);
     if (value) {
       responseInit.headers[name] = value;
     }
   }
   const newResponse = new Response(response.body, responseInit);
   return newResponse;
 }
 
 return response;
}</code></pre>
            <p>In addition to filtering the request headers we also filter the response headers sent back to the browser. If you’re not careful you could end up in a situation where a third-party is setting cookies on your origin or even turning on something like <a href="https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security">HTTP Strict Transport Security</a> for your site.</p>
    <div>
      <h4>Streaming HTML Processing</h4>
      <a href="#streaming-html-processing">
        
      </a>
    </div>
    <p>The HTML path is more complicated because we are going to intercept and modify the content itself.</p><p>In processing the HTML request, the first thing we want to do is make sure it is actually an HTML response. If it is something else, then we should get out of the way and let the response stream back to the browser as it does normally. It is very possible that a PDF document, file download, or even a directly opened image, has a Accept of text/html. It is critical to check the actual content that is being responded with to make sure it is something we want to inspect and possibly modify.</p><p>The easiest way to modify a response is to just wait for the response to be fully complete, process it as a single block of HTML, and then pass the modified HTML back to the browser:</p>
            <pre><code> async function processHtmlRequest(request) {
 
 // Fetch from origin server.
 const response = await fetch(request)
 if (response.headers.get("content-type").indexOf("text/html") !== -1) {
  
   let content = await response.text();
   content = await modifyHtmlChunk(content, request);
 
   // Create a cloned response with our modified HTML
   return new Response(content, response);
 }
 return response;
}</code></pre>
            <p>This works reasonably well if you are sure that all of the HTML is UTF-8 (or ascii), and the server returns all of the HTML at once, but there are some pretty serious concerns with doing it this way:</p><ul><li><p>The memory use can be unbounded and only limited by the size of the largest HTML response (possibly causing the worker to be terminated for using too much memory).</p></li><li><p>Significant delay will be added to any pages where the server <a href="https://www.stevesouders.com/blog/2009/05/18/flushing-the-document-early/">flushes the initial content early</a> and then does some expensive/slow work before returning the rest of the HTML.</p></li><li><p>This only works if the text content uses an encoding that JavaScript can decode directly as UTF-8. Any other character encodings will fail to decode.</p></li></ul><p>For our worker we are going to process the HTML stream incrementally as it arrives from the server and pass it through to the browser as soon as possible (and pass-through any content that isn’t utf-8 unmodified).</p>
    <div>
      <h5>Processing HTML as a stream</h5>
      <a href="#processing-html-as-a-stream">
        
      </a>
    </div>
    <p>First we are going to look at what it takes to process the HTML stream incrementally. We will leave the character encoding changes out for now to keep things (relatively) simple.</p><p>To process the stream incrementally, we need to generate a new fetch response to pass back from the worker that uses a TransformStream for its content. That will allow us to pass the response itself back immediately and write to the stream as soon as we have content to add. We pass all of the other headers through unmodified.</p>
            <pre><code>async function processHtmlRequest(request) {
 
 // Fetch from origin server.
 const response = await fetch(request)
 if (response.headers.get("content-type").indexOf("text/html") !== -1) {
  
   // Create an identity TransformStream (a.k.a. a pipe).
   // The readable side will become our new response body.
   const { readable, writable } = new TransformStream();
 
   // Create a cloned response with our modified stream
   const newResponse = new Response(readable, response);
 
   // Start the async processing of the response stream (NO await!)
   modifyHtmlStream(response.body, writable, request);
 
   // Return the in-process response so it can be streamed.
   return newResponse;
 }
 return response;
}</code></pre>
            <p>The key thing here is to not wait for the async modifyHtmlStream async function to complete before passing the new response back from the worker. This way the initial headers can be sent immediately and the response will continue to stream anything written into the TransformStream until it is closed.</p><p>Processing the HTML stream in chunks as it arrives is a little tricky. The HTML stream will arrive in chunks of arbitrary sizes as strings. We need to add some protection to make sure that a chunk boundary doesn’t split a link tag. If it does, and we don’t account for it, we can miss a stylesheet link (or worse, process a partial link URL with the wrong style type). To make sure we don’t split link tags, we search from the end of the string for “&lt;link “ and from the start of the last link tag we search forward for a closing “&gt;” tag. If we don’t find one, then there is a partial link tag and we split the string just before the link tag starts. We process everything up to the split link tag and keep the partial tag to prepend it to the next chunk of data that arrives.</p><p>An alternative would be to keep accumulating data and only process it when there is no split link tag at the end, but this way we can return more data to the browser sooner.</p><p>When the incoming stream is complete, we process any partial data left over from the previous chunk and close the output stream (ending the response to the browser).</p>
            <pre><code>async function modifyHtmlStream(readable, writable, request) {
 const reader = readable.getReader();
 const writer = writable.getWriter();
 const encoder = new TextEncoder();
 let decoder = new TextDecoder();
 
 let partial = '';
 let content = '';
 
 for(;;) {
   // Read the next chunk of HTML from the fetch request.
   const { done, value } = await reader.read()
 
   if (done) {
 
     // Send any remaining fragment and complete the request.
     if (partial.length) {
       partial = await modifyHtmlChunk(partial, request);
       await writer.write(encoder.encode(partial));
       partial = '';
     }
     break;
 
   }
  
   try {
     let chunk = decoder.decode(value, {stream:true});
 
     // Add the inbound chunk to the the remaining partial chunk
     // from the previous read.
     content = partial + chunk;
     partial = '';
 
     // See if there is an unclosed link tag at the end (and if so,
     // carve it out to complete when the remainder comes in).
     const linkPos = content.lastIndexOf('&lt;link');
     if (linkPos &gt;= 0) {
       const linkClose = content.indexOf('/&gt;', linkPos);
       if (linkClose === -1) {
         partial = content.slice(linkPos);
         content = content.slice(0, linkPos);
       }
     }
 
     if (content.length) {
       // Do the actual HTML modifications on the current chunk.
       content = await modifyHtmlChunk(content, request);
     }
   } catch (e) {
     // Ignore the exception
   }
 
   // Send the processed HTML chunk to the requesting browser.
   if (content.length) {
     await writer.write(encoder.encode(content));
     content = '';
   }
 }
 
 await writer.close()
}</code></pre>
            <p>One thing I was initially worried about was having to modify the “content-length” response header from the original response since we are modifying the content. Luckily, the worker takes care of that automatically and it isn’t something you have to implement.</p><p>There is a try/catch handler around the processing in case something goes horribly wrong with the decode.</p><p>The actual HTML rewriting is handled in “modifyHtmlChunk”. This is just the logic for processing the incoming data as incremental chunks.</p>
    <div>
      <h5>Dealing with character encodings other than UTF-8</h5>
      <a href="#dealing-with-character-encodings-other-than-utf-8">
        
      </a>
    </div>
    <p>We intentionally skipped over handling character encodings other than UTF-8 up until now. To handle arbitrary pages you will need to be able to process other character encodings. The Worker runtime only supports decoding UTF-8 but we need to make sure that we don’t break any content that isn’t UTF-8 (or similar). To do this, we detect the current encoding if it is specified and anything that isn’t UTF-8 is passed through unmodified. In the case that the content type can not be detected we also detect decode errors and pass content through unmodified when they occur.</p><p>The HTML charset can be specified in the content-type response header or as a <code>&lt;meta charset&gt;</code> tag in the HTML itself.</p><p>For the response headers it is pretty simple. When we get the original response, see if there is a charset in the content-type header. If there is, extract the current value and if it isn’t a supported charset just pass the response through unmodified.</p>
            <pre><code>   // Workers can only decode utf-8. If it is anything else, pass the
   // response through unmodified
   const VALID_CHARSETS = ['utf-8', 'utf8', 'iso-8859-1', 'us-ascii'];
   const charsetRegex = /charset\s*=\s*([^\s;]+)/mgi;
   const match = charsetRegex.exec(contentType);
   if (match !== null) {
     let charset = match[1].toLowerCase();
     if (!VALID_CHARSETS.includes(charset)) {
       return response;
     }
   }
  
   // Create an identity TransformStream (a.k.a. a pipe).
   // The readable side will become our new response body.
   const { readable, writable } = new TransformStream();
 
   // Create a cloned response with our modified stream
   const newResponse = new Response(readable, response);
 
   // Start the async processing of the response stream
   modifyHtmlStream(response.body, writable, request, event);</code></pre>
            <p>For the cases where there is a “” tag in the HTML (and possibly no header) things get a bit more complicated. If at any point an unsupported charset is detected then we pipe the incoming byte stream directly into the output stream unmodified. We first decode the first chunk of HTML response using the default decoder. Then, if a ” tag is found in the html we extract the charset. If it isn’t a supported charset then we enter passthrough mode. If at any point the input stream can’t be decoded (likely because of an invalid charset) we also enter passthrough mode and pipe the remaining content through unprocessed.</p>
            <pre><code>async function modifyHtmlStream(readable, writable, request, event) {
 const reader = readable.getReader();
 const writer = writable.getWriter();
 const encoder = new TextEncoder();
 let decoder = new TextDecoder("utf-8", {fatal: true});
 
 let firstChunk = true;
 let unsupportedCharset = false;
 
 let partial = '';
 let content = '';
 
 try {
   for(;;) {
     const { done, value } = await reader.read();
     if (done) {
       if (partial.length) {
         partial = await modifyHtmlChunk(partial, request, event);
         await writer.write(encoder.encode(partial));
         partial = '';
       }
       break;
     }
 
     let chunk = null;
     if (unsupportedCharset) {
       // Pass the data straight through
       await writer.write(value);
       continue;
     } else {
       try {
         chunk = decoder.decode(value, {stream:true});
       } catch (e) {
         // Decoding failed, switch to passthrough
         unsupportedCharset = true;
         if (partial.length) {
           await writer.write(encoder.encode(partial));
           partial = '';
         }
         await writer.write(value);
         continue;
       }
     }
 
     try {
       // Look inside of the first chunk for a HTML charset or
       // content-type meta tag.
       if (firstChunk) {
         firstChunk = false;
         if (chunkContainsInvalidCharset(chunk)) {
           // switch to passthrough
           unsupportedCharset = true;
           if (partial.length) {
             await writer.write(encoder.encode(partial));
             partial = '';
           }
           await writer.write(value);
           continue;
         }
       }
 
       content = partial + chunk;
       partial = '';
 
       // See if there is an unclosed link tag at the end (and if so,
       // carve it out to complete when the remainder comes in).
       const linkPos = content.lastIndexOf('&lt;link');
       if (linkPos &gt;= 0) {
         const linkClose = content.indexOf('/&gt;', linkPos);
         if (linkClose === -1) {
           partial = content.slice(linkPos);
           content = content.slice(0, linkPos);
         }
       }
 
       if (content.length) {
         content = await modifyHtmlChunk(content, request, event);
       }
     } catch (e) {
       // Ignore the exception
     }
     if (content.length) {
       await writer.write(encoder.encode(content));
       content = '';
     }
   }
 } catch(e) {
   // Ignore the exception
 }
 
 try {
   await writer.close();
 } catch(e) {
   // Ignore the exception
 }
}</code></pre>
            <p>There is a helper that scans for the charset in both meta tags that support setting the charset:</p>
            <pre><code>function chunkContainsInvalidCharset(chunk) {
 let invalid = false;
 const VALID_CHARSETS = ['utf-8', 'utf8', 'iso-8859-1', 'us-ascii'];
 
 // meta charset
 const charsetRegex = /&lt;\s*meta[^&gt;]+charset\s*=\s*['"]([^'"]*)['"][^&gt;]*&gt;/mgi;
 const charsetMatch = charsetRegex.exec(chunk);
 if (charsetMatch) {
   const docCharset = charsetMatch[1].toLowerCase();
   if (!VALID_CHARSETS.includes(docCharset)) {
     invalid = true;
   }
 }
 // content-type
 const contentTypeRegex = /&lt;\s*meta[^&gt;]+http-equiv\s*=\s*['"]\s*content-type[^&gt;]*&gt;/mgi;
 const contentTypeMatch = contentTypeRegex.exec(chunk);
 if (contentTypeMatch) {
   const metaTag = contentTypeMatch[0];
   const metaRegex = /charset\s*=\s*([^\s"]*)/mgi;
   const metaMatch = metaRegex.exec(metaTag);
   if (metaMatch) {
     const charset = metaMatch[1].toLowerCase();
     if (!VALID_CHARSETS.includes(charset)) {
       invalid = true;
     }
   }
 }
 return invalid;
}</code></pre>
            
    <div>
      <h4>HTML Business Logic</h4>
      <a href="#html-business-logic">
        
      </a>
    </div>
    <p>Finally, we can start the actual logic for embedding the font CSS. The basic logic is:</p><ul><li><p>Use a regex to find link tags for Google fonts css.</p></li><li><p>Fetch the browser-specific version of the CSS (from cache if possible).</p><ul><li><p>The fetch logic (discussed later) modifies the font URLs in the CSS to proxy through the worker.</p></li></ul></li><li><p>Replace the link tag with a style block with the CSS content.</p></li></ul>
            <pre><code>async function modifyHtmlChunk(content, request, event) {
 const fontCSSRegex = /&lt;link\s+[^&gt;]*href\s*=\s*['"]((https?:)?\/\/fonts.googleapis.com\/css[^'"]+)[^&gt;]*&gt;/mgi;
 let match = fontCSSRegex.exec(content);
 while (match !== null) {
   const matchString = match[0];
   if (matchString.indexOf('stylesheet') &gt;= 0) {
     const fontCSS = await fetchCSS(match[1], request, event);
     if (fontCSS.length) {
       // See if there is a media type on the link tag
       let mediaStr = '';
       const mediaMatch = matchString.match(/media\s*=\s*['"][^'"]*['"]/mig);
       if (mediaMatch) {
         mediaStr = ' ' + mediaMatch[0];
       }
       // Replace the actual css
       let cssString = "&lt;style" + mediaStr + "&gt;\n";
       cssString += fontCSS;
       cssString += "\n&lt;/style&gt;\n";
       content = content.split(matchString).join(cssString);
     }
     match = fontCSSRegex.exec(content);
   }
 }
 
 return content;
}</code></pre>
            <p>The fetching (and modifying) of the CSS is a little more complicated than a straight passthrough because we want to cache the result when possible. We cache the responses locally using the worker’s <a href="https://developers.cloudflare.com/workers/reference/cache-api/">Cache API</a>. Since the response is browser-specific, and we don’t want to fragment the cache too crazily, we create a custom cache key based on the browser user agent string that is basically browser+version+mobile.</p><p>Some plans have access to named cache storage, but to work with all plans it is easiest if we just modify the font URL that gets stored in cache and append the cache key to the end of the URL as a query parameter. The cache URL never gets sent to a server but is useful for local caching of different content that shares the same URL. For example:</p>
            <pre><code>https://fonts.googleapis.com/css?family=Roboto&amp;chrome71</code></pre>
            <p>If the CSS isn’t available in the cache then we create a fetch request for the original URL from the Google servers, passing through the HTML url as the referer, the correct browser user agent string and the client’s IP address in a standard proxy X-Forwarded-For header. Once the response is available we store it in the cache for future requests.</p><p>For browsers that can’t be identified by user agent string a generic request for css is sent with the user agent string from Internet Explorer 8 to get the lowest common denominator fallback CSS.</p><p>The actual modification of the CSS just uses a regex to look for font URLs, replaces them with the HTML origin as a prefix.</p>
            <pre><code>async function fetchCSS(url, request) {
 let fontCSS = "";
 if (url.startsWith('/'))
   url = 'https:' + url;
 const userAgent = request.headers.get('user-agent');
 const clientAddr = request.headers.get('cf-connecting-ip');
 const browser = getCacheKey(userAgent);
 const cacheKey = browser ? url + '&amp;' + browser : url;
 const cacheKeyRequest = new Request(cacheKey);
 let cache = null;
 
 let foundInCache = false;
 // Try pulling it from the cache API (wrap it in case it's not implemented)
 try {
   cache = caches.default;
   let response = await cache.match(cacheKeyRequest);
   if (response) {
     fontCSS = response.text();
     foundInCache = true;
   }
 } catch(e) {
   // Ignore the exception
 }
 
 if (!foundInCache) {
   let headers = {'Referer': request.url};
   if (browser) {
     headers['User-Agent'] = userAgent;
   } else {
     headers['User-Agent'] =
       "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)";
   }
   if (clientAddr) {
     headers['X-Forwarded-For'] = clientAddr;
   }
 
   try {
     const response = await fetch(url, {headers: headers});
     fontCSS = await response.text();
 
     // Rewrite all of the font URLs to come through the worker
     fontCSS = fontCSS.replace(/(https?:)?\/\/fonts\.gstatic\.com\//mgi,
                               '/fonts.gstatic.com/');
 
     // Add the css info to the font caches
     FONT_CACHE[cacheKey] = fontCSS;
     try {
       if (cache) {
         const cacheResponse = new Response(fontCSS, {ttl: 86400});
         event.waitUntil(cache.put(cacheKeyRequest, cacheResponse));
       }
     } catch(e) {
       // Ignore the exception
     }
   } catch(e) {
     // Ignore the exception
   }
 }
 
 return fontCSS;
}</code></pre>
            <p>Generating the browser-specific cache key is a little sensitive since browsers tend to clone each other’s user agent strings and add their own information to them. For example, Edge includes a Chrome identifier and Chrome includes a Safari identifier, etc. We don’t necessarily have to handle every browser string since it will fallback to the least common denominator (ttf files without unicode range support) but it is helpful to catch as many of the large mainstream browser engines as possible.</p>
            <pre><code>function getCacheKey(userAgent) {
 let os = '';
 const osRegex = /^[^(]*\(\s*(\w+)/mgi;
 let match = osRegex.exec(userAgent);
 if (match) {
   os = match[1];
 }
 
 let mobile = '';
 if (userAgent.match(/Mobile/mgi)) {
   mobile = 'Mobile';
 }
 
 // Detect Edge first since it includes Chrome and Safari
 const edgeRegex = /\s+Edge\/(\d+)/mgi;
 match = edgeRegex.exec(userAgent);
 if (match) {
   return 'Edge' + match[1] + os + mobile;
 }
 
 // Detect Chrome next (and browsers using the Chrome UA/engine)
 const chromeRegex = /\s+Chrome\/(\d+)/mgi;
 match = chromeRegex.exec(userAgent);
 if (match) {
   return 'Chrome' + match[1] + os + mobile;
 }
 
 // Detect Safari and Webview next
 const webkitRegex = /\s+AppleWebKit\/(\d+)/mgi;
 match = webkitRegex.exec(userAgent.match);
 if (match) {
   return 'WebKit' + match[1] + os + mobile;
 }
 
 // Detect Firefox
 const firefoxRegex = /\s+Firefox\/(\d+)/mgi;
 match = firefoxRegex.exec(userAgent);
 if (match) {
   return 'Firefox' + match[1] + os + mobile;
 }
  return null;
}</code></pre>
            
    <div>
      <h3>Profit!</h3>
      <a href="#profit">
        
      </a>
    </div>
    <p>Any site served through Cloudflare can implement workers to rewrite their content but for something like Google fonts or other third-party resources it gets much more interesting when someone implements it once and everyone else can benefit. With <a href="https://www.cloudflare.com/apps/developer/docs/getting-started">Cloudflare Apps’</a> new <a href="/introducing-apps-with-workers/">worker support</a> you can bundle up and deliver complex worker logic for anyone else to consume and publish it to the Apps marketplace.</p><p>If you are a third-party content provider for sites, think about what you might be able to do to leverage workers for your content for sites that are served through Cloudflare.</p><p>I get excited thinking about the performance implications of something like a tag manager running entirely on the edge without the sites having to change their published pages and without browsers having to fetch heavy JavaScript to do the page modifications. It can be done dynamically for every request directly on the edge!</p> ]]></content:encoded>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Programming]]></category>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">4UYfaU3hSHYBAmqQgVZm0v</guid>
            <dc:creator>Patrick Meenan (Guest Author)</dc:creator>
        </item>
        <item>
            <title><![CDATA[Optimizing HTTP/2 prioritization with BBR and tcp_notsent_lowat]]></title>
            <link>https://blog.cloudflare.com/http-2-prioritization-with-nginx/</link>
            <pubDate>Fri, 12 Oct 2018 12:00:00 GMT</pubDate>
            <description><![CDATA[ Getting the best end-user performance from HTTP/2 requires good support for resource prioritization.  While most web servers support HTTP/2 prioritization, getting it to work well all the way to the browser requires a fair bit of coordination across the networking stack. ]]></description>
            <content:encoded><![CDATA[ <p>Getting the best end-user performance from HTTP/2 requires good support for resource prioritization. While most web servers support HTTP/2 prioritization, getting it to work well all the way to the browser requires a fair bit of coordination across the networking stack. This article will expose some of the interactions between the web server, Operating System and network and how to tune a server to optimize performance for end users.</p>
    <div>
      <h3>tl;dr</h3>
      <a href="#tl-dr">
        
      </a>
    </div>
    <p>On Linux 4.9 kernels and later, enable BBR congestion control and set tcp_notsent_lowat to 16KB for HTTP/2 prioritization to work reliably. This can be done in /etc/sysctl.conf:</p>
            <pre><code>    net.core.default_qdisc = fq
    net.ipv4.tcp_congestion_control = bbr
    net.ipv4.tcp_notsent_lowat = 16384</code></pre>
            
    <div>
      <h3>Browsers and Request Prioritization</h3>
      <a href="#browsers-and-request-prioritization">
        
      </a>
    </div>
    <p>A single web page is made up of <a href="https://httparchive.org/reports/state-of-the-web#reqTotal">dozens</a> to hundreds of separate pieces of content that a web browser pulls together to create and present to the user. The main content (HTML) for the page you are visiting is a list of instructions on how to construct the page and the browser goes through the instructions from beginning to end to figure out everything it needs to load and how to put it all together. Each piece of content requires a separate HTTP request from the browser to the server responsible for that content (or if it has been loaded before, it can be loaded from a local cache in the browser).</p><p>In a simple implementation, the web browser could wait until everything is loaded and constructed and then show the result but that would be pretty slow. Not all of the content is critical to the user and can include things such as images way down in the page, analytics for tracking usage, ads, like buttons, etc. All the browsers work more incrementally where they display the content as it becomes available. This results in a much faster user experience. The visible part of the page can be displayed while the rest of the content is being loaded in the background. Deciding on the best order to request the content in is where browser request prioritization comes into play. Done correctly the visible content can display significantly faster than a naive implementation.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2XMGHLI8Lg4iw7DBN7mNAS/b1c65f7a021f93e5c81d47f1304b50de/Parser-web.png" />
            
            </figure><p>HTML Parser blocking page render for styles and scripts in the head of the document.</p><p>Most modern browsers use similar prioritization schemes which generally look like:</p><ol><li><p>Load similar resources (scripts, images, styles) in the order they were listed in the HTML.</p></li><li><p>Load styles/CSS before anything else because content cannot be displayed until styles are complete.</p></li><li><p>Load blocking scripts/JavaScript next because blocking scripts stop the browser from moving on to the next instruction in the HTML until they have been loaded and executed.</p></li><li><p>Load images and non-blocking scripts (async/defer).</p></li></ol><p>Fonts are a bit of a special case in that they are needed to draw the text on the screen but the browser won’t know that it needs to load a font until it is actually ready to draw the text to the screen. So they are discovered pretty late. As a result they are generally given a very high priority once they are discovered but aren’t known about until fairly late in the loading process.</p><p>Chrome also applies some special treatment to images that are visible in the current browser viewport (part of the page visible on the screen). Once the styles have been applied and the page has been laid out it will give visible images a much higher priority and load them in order from largest to smallest.</p>
    <div>
      <h4>HTTP/1.x prioritization</h4>
      <a href="#http-1-x-prioritization">
        
      </a>
    </div>
    <p>With HTTP/1.x, each connection to a server can support one request at a time (practically anyway as no browser supports <a href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.1.2.2">pipelining</a>) and most browsers will open up to 6 connections at a time to each server. The browser maintains a prioritized list of the content it needs and makes the requests to each server as a connection becomes available. When a high-priority piece of content is discovered it is moved to the front of a list and when the next connection becomes available it is requested.</p>
    <div>
      <h4>HTTP/2 prioritization</h4>
      <a href="#http-2-prioritization">
        
      </a>
    </div>
    <p>With HTTP/2, the browser uses a single connection and the requests are multiplexed over the connection as separate “streams”. The requests are all sent to the server as soon as they are discovered along with some prioritization information to let the server know the preferred ordering of the responses. It is then up to the server to do its best to deliver the most important responses first, followed by lower priority responses. When a high priority request comes in to the server, it should immediately jump ahead of the lower priority responses, even mid-response. The actual priority scheme implemented by HTTP/2 allows for parallel downloads with weighting between them and more complicated schemes. For now it is easiest to just think about it as a priority ordering of the resources.</p><p>Most servers that support prioritization will send data for the highest priority responses for which it has data available. But if the most important response takes longer to generate than lower priority responses, the server may end up starting to send data for a lower priority response and then interrupt its stream when the higher priority response becomes available. That way it can avoid wasting available bandwidth and head-of-line blocking where a slow response holds everything else up.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/59eyWItYTFdeYfulcnJGgn/80c68b2bc82e445e1c5685f602ed235d/H2Prioritization.gif" />
            
            </figure><p>Browser requesting a high-priority resource after several low-priority resources.</p><p><b>In an optimal configuration, the time to retrieve a top-priority resource on a busy connection with lots of other streams will be identical to the time to retrieve it on an empty connection.</b> Effectively that means that the server needs to be able to interrupt the response streams of all of the other responses immediately with no additional buffering to delay the high-priority response (beyond the minimal amount of data in-flight on the network to keep the connection fully utilized).</p>
    <div>
      <h3>Buffers on the Internet</h3>
      <a href="#buffers-on-the-internet">
        
      </a>
    </div>
    <p>Excessive buffering is pretty much the nemesis for HTTP/2 because it directly impacts the ability for a server to be nimble in responding to priority shifts. It is not unusual for there to be megabytes-worth of buffering between the server and the browser which is larger than most websites. Practically that means that the responses will get delivered in whatever order they become available on the server. It is not unusual to have a critical resource (like a font or a render-blocking script in the <code>&lt;head&gt;</code> of a document) delayed by megabytes of lower priority images. For the end-user this translates to seconds or even minutes of delay rendering the page.</p>
    <div>
      <h4>TCP send buffers</h4>
      <a href="#tcp-send-buffers">
        
      </a>
    </div>
    <p>The first layer of buffering between the server and the browser is in the server itself. The operating system maintains a TCP send buffer that the server writes data into. Once the data is in the buffer then the operating system takes care of delivering the data as-needed (pulling from the buffer as data is sent and signaling to the server when the buffer needs more data). A large buffer also reduces CPU load because it reduces the amount of writing that the server has to do to the connection.</p><p>The actual size of the send buffer needs to be big enough to keep a copy of all of the data that has been sent to the browser but has yet to be acknowledged in case a packet gets dropped and some data needs to be retransmitted. Too small of a buffer will prevent the server from being able to max-out the connection bandwidth to the client (and is a common cause of slow downloads over long distances). In the case of HTTP/1.x (and a lot of other protocols), the data is delivered in bulk in a known-order and tuning the buffers to be as big as possible has no downside other than the increase in memory use (trading off memory for CPU). Increasing the TCP send buffer sizes is an effective way to increase the throughput of a web server.</p><p>For HTTP/2, the problem with large send buffers is that it limits the nimbleness of the server to adjust the data it is sending on a connection as high priority responses become available. Once the response data has been written into the TCP send buffer it is beyond the server’s control and has been committed to be delivered in the order it is written.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1AqTAsnXSJ1q1TQpRZh0pm/86f7438dcd64c932fe96921e811b5a95/Lowat-buff-web.png" />
            
            </figure><p>High-priority resource queued behind low-priority resources in the TCP send buffer.</p><p><b>The optimal send buffer size for HTTP/2 is the minimal amount of data required to fully utilize the available bandwidth to the browser</b> (which is different for every connection and changes over time even for a single connection). Practically you’d want the buffer to be slightly bigger to allow for some time between when the server is signaled that more data is needed and when the server writes the additional data.</p>
    <div>
      <h4>TCP_NOTSENT_LOWAT</h4>
      <a href="#tcp_notsent_lowat">
        
      </a>
    </div>
    <p><a href="https://lwn.net/Articles/560082/">TCP_NOTSENT_LOWAT</a> is a socket option that allows configuration of the send buffer so that it is always the optimal size plus a fixed additional buffer. You provide a buffer size (X) which is the additional amount of size you’d like in addition to the minimal needed to fully utilize the connection and it dynamically adjusts the TCP send buffer to always be X bytes larger than the current connection congestion window. The congestion window is the TCP stack’s estimate of the amount of data that needs to be in-flight on the network to fully utilize the connection.</p><p>TCP_NOTSENT_LOWAT can be configured in code on a socket-by-socket basis if the web server software supports it or system-wide using the net.ipv4.tcp_notsent_lowat sysctl:</p>
            <pre><code>    net.ipv4.tcp_notsent_lowat = 16384</code></pre>
            <p>We have a patch we are preparing to upstream for NGINX to make it configurable but it isn’t quite ready yet so configuring it system-wide is required. Experimentally, the value 16,384 (16K) has proven to be a good balance where the connections are kept fully-utilized with negligible additional CPU overhead. That will mean that at most 16KB of lower priority data will be buffered before a higher priority response can interrupt it and be delivered. As always, your mileage may vary and it is worth experimenting with.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/r0NmKQUjLYjXThiREdchj/37a90992b93c43d8a31563f27c46c349/Lowat-web.png" />
            
            </figure><p>High-priority resource ready to send with minimal TCP buffering.</p>
    <div>
      <h4>Bufferbloat</h4>
      <a href="#bufferbloat">
        
      </a>
    </div>
    <p>Beyond buffering on the server, the network connection between the server and the browser can act as a buffer. It is increasingly common for networking gear to have large buffers that absorb data that is sent faster than the receiving side can consume it. This is generally referred to as <a href="https://www.bufferbloat.net/projects/bloat/wiki/Introduction/">Bufferbloat</a>. I hedged my explanation of the effectiveness of tcp_notsent_lowat a little bit in that it is based on the current congestion window which is an estimate of the optimal amount of in-flight data needed but not necessarily the actual optimal amount of in-flight data.</p><p>The buffers in the network can be quite large at times (megabytes) and they interact very poorly with the congestion control algorithms usually used by TCP. Most classic congestion-control algorithms determine the congestion window by watching for packet loss. Once a packet is dropped then it knows there was too much data on the network and it scales back from there. With Bufferbloat that limit is raised artificially high because the buffers are absorbing the extra packets beyond what is needed to saturate the connection. As a result, the TCP stack ends up calculating a congestion window that spikes to much larger than the actual size needed, then drops to significantly smaller once the buffers are saturated and a packet is dropped and the cycle repeats.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5yp3yoEG0uBWlPowSVbKLm/e6fdd79c824709f41e2993698d2f8155/h2_tcp_sawtooth_web.png" />
            
            </figure><p>Loss-based congestion control congestion window graph.</p><p>TCP_NOTSENT_LOWAT uses the calculated congestion window as a baseline for the size of the send buffer it needs to use so when the underlying calculation is wrong, the server ends up with send buffers much larger (or smaller) than it actually needs.</p><p>I like to think about Bufferbloat as being like a line for a ride at an amusement park. Specifically, one of those lines where it’s a straight shot to the ride when there are very few people in line but once the lines start to build they can divert you through a maze of zig-zags. Approaching the ride it looks like a short distance from the entrance to the ride but things can go horribly wrong.</p><p>Bufferbloat is very similar. When the data is coming into the network slower than the links can support, everything is nice and fast:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1IpqZY4r070iJKdzCndFAU/1e039adf8d8ea8f00238794b6eea0191/Bb-fast-web.png" />
            
            </figure><p>Response traveling through the network with no buffering.</p><p>Once the data comes in faster than it can go out the gates are flipped and the data gets routed through the maze of buffers to hold it until it can be sent. From the entrance to the line it still looks like everything is going fine since the network is absorbing the extra data but it also means there is a long queue of the low-priority data already absorbed when you want to send the high-priority data and it has no choice but to follow at the back of the line:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1iqGmNvNY0pOG3CJZRHT0w/4f65ec518eff246284d8f2bca373b7da/Bb-slow-web.png" />
            
            </figure><p>Responses queued in network buffers.</p>
    <div>
      <h4>BBR congestion control</h4>
      <a href="#bbr-congestion-control">
        
      </a>
    </div>
    <p><a href="https://cloud.google.com/blog/products/gcp/tcp-bbr-congestion-control-comes-to-gcp-your-internet-just-got-faster">BBR</a> is a new congestion control algorithm from Google that uses changes in packet delays to model the congestion instead of waiting for packets to drop. Once it sees that packets are taking longer to be acknowledged it assumes it has saturated the connection and packets have started to buffer. As a result the congestion window is often very close to the optimal needed to keep the connection fully utilized while also avoiding Bufferbloat. BBR was merged into the Linux kernel in version 4.9 and can be configured through sysctl:</p>
            <pre><code>    net.core.default_qdisc = fq
    net.ipv4.tcp_congestion_control = bbr</code></pre>
            <p>BBR also tends to perform better overall since it doesn’t require packet loss as part of probing for the correct congestion window and also tends to react better to random packet loss.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4t9tjuLzOCF7CbuCLicM5G/a350fcbdafc39f865ac34e90f5778fce/h2_bbr_sawtooth.png" />
            
            </figure><p>BBR congestion window graph.</p><p>Back to the amusement park line, BBR is like having each person carry one of the RFID cards they use to measure the wait time. Once the wait time looks like it is getting slower the people at the entrance slow down the rate that they let people enter the line.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/lAoZDM2jP8XYw9SyS5OMx/f040d3c07ff4b97eefc65cad5f89ab39/Bb-detect-web.png" />
            
            </figure><p>BBR detecting network congestion early.</p><p>This way BBR essentially keeps the line moving as fast as possible and prevents the maze of lines from being used. When a guest with a fast pass arrives (the high-priority request) they can jump into the fast-moving line and hop right onto the ride.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1PIseBoVZR55F9yEe71pya/75c406b6b42272f3d02a761f7b6a7047/Bb-bbr-web.png" />
            
            </figure><p>BBR delivering responses without network buffering.</p><p>Technically, any congestion control that keeps Bufferbloat in check and maintains an accurate congestion window will work for keeping the TCP send buffers in check, BBR just happens to be one of them (with lots of good properties).</p>
    <div>
      <h3>Putting it all together</h3>
      <a href="#putting-it-all-together">
        
      </a>
    </div>
    <p><b><i>The combination of TCP_NOTSENT_LOWAT and BBR reduces the amount of buffering on the network to the absolute minimum and is CRITICAL for good end-user performance with HTTP/2.</i></b> This is particularly true for NGINX and other HTTP/2 servers that don’t implement their own buffer throttling.</p><p>The end-user impact of correct prioritization is huge and may not show up in most of the metrics you are used to watching (particularly any server-side metrics like requests-per-second, request response time, etc).</p><p>Even on a 5Mbps cable connection proper resource ordering can result in rendering a page significantly faster (and the difference can explode to dozens of seconds or even minutes on a slower connection). <a href="https://www.webpagetest.org/video/view.php?id=180927_1b80249b8e1a7619300d2a51533c07438e4fa5ea">Here</a> is a relatively common case of a WordPress blog served over HTTP/2:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/42hSIcWY4c4t5AlEDYa1Sl/eaacdf916bba0264aa90549411b8fc22/h2_render_1.png" />
            
            </figure><p>The page from the tuned server (After) starts to render at 1.8 seconds.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7DbdYJbZ12so4x2jDmnx3W/a9bb2f54dedd07bb752dddb8fcc11667/h2_render_2.png" />
            
            </figure><p>The page from the tuned server (After) is completely done rendering at 4.5 seconds, well before the default configuration (Before) even started to render.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2DFgPFFYHWh7yoPDVPvzD8/a9788b5de09169f0d9113b8255fee060/h2_render_3.png" />
            
            </figure><p>Finally, at 10.2 seconds the default configuration started to render (8.4 seconds later or 5.6 times slower than the tuned server).</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7Mi9As6BWT0lq9HCITHwJ5/fbd8ebf3a553691da6b53d266286652e/h2_render_4.png" />
            
            </figure><p>Visually complete on the default configuration arrives at 10.7 seconds (6.2 seconds or 2.3 times slower than the tuned server).</p><p>Both configurations served the exact same content using the exact same servers with “After” being tuned for TCP_NOTSENT_LOWAT of 16KB (both configurations used BBR).</p>
    <div>
      <h3>Identifying Prioritization Issues In The Wild</h3>
      <a href="#identifying-prioritization-issues-in-the-wild">
        
      </a>
    </div>
    <p>If you look at a network waterfall diagram of a page loading prioritization issues will show up as high-priority requests completing much later than lower-priority requests from the same origin. Usually that will also push metrics like <a href="https://w3c.github.io/paint-timing/#sec-terminology">First Paint</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded">DOM Content Loaded</a> (the vertical purple bar below) much later.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2Ed4mofSgwlJ77sJ46qcWf/4fa3f82440f6df9a1cab240d02c1ce4f/h2_waterfall_delayed.png" />
            
            </figure><p>Network waterfall showing critical CSS and JavaScript delayed by images.</p><p>When prioritization is working correctly you will see critical resources all completing much earlier and not be blocked by the lower-priority requests. You may still see SOME low-priority data download before the higher-priority data starts downloading because there is still some buffering even under ideal conditions but it should be minimal.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1xpPBVSGpsy1byCuc6vGy7/2c2fe0e20129d3ce23304886674c8ef0/h2_waterfall_fast.png" />
            
            </figure><p>Network waterfall showing critical CSS and JavaScript loading quickly.</p><p>Chrome 69 and later may hide the problem a bit. Chrome holds back lower-priority requests even on HTTP/2 connections until after it has finished processing the head of the document. In a waterfall it will look like a delayed block of requests that all start at the same time after the critical requests have completed. That doesn’t mean that it isn’t a problem for Chrome, just that it isn’t as obvious. Even with the staggering of requests there are still high-priority requests outside of the head of the document that can be delayed by lower-priority requests. Most notable are any blocking scripts in the body of the page and any external fonts that were not preloaded.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/35PouKEd6DjgpSylNzuGp6/1081ad9271d8cb9acd89d1d5cce75c17/h2_waterfall_chrome.png" />
            
            </figure><p>Network waterfall showing Chrome delaying the requesting of low-priority resources.</p><p>Hopefully this post gives you the tools to be able to identify HTTP/2 prioritization issues when they happen, a deeper understanding of how HTTP/2 prioritization works and some tools to fix the issues when they appear.</p> ]]></content:encoded>
            <category><![CDATA[NGINX]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[TCP]]></category>
            <guid isPermaLink="false">7zRny2MvKKFGt3vBHIyM5c</guid>
            <dc:creator>Patrick Meenan (Guest Author)</dc:creator>
        </item>
        <item>
            <title><![CDATA[The Road to QUIC]]></title>
            <link>https://blog.cloudflare.com/the-road-to-quic/</link>
            <pubDate>Thu, 26 Jul 2018 15:04:36 GMT</pubDate>
            <description><![CDATA[ QUIC (Quick UDP Internet Connections) is a new encrypted-by-default Internet transport protocol, that provides a number of improvements designed to accelerate HTTP traffic as well as make it more secure, with the intended goal of eventually replacing TCP and TLS on the web. ]]></description>
            <content:encoded><![CDATA[ <p>QUIC (Quick UDP Internet Connections) is a new encrypted-by-default Internet transport protocol, that provides a number of improvements designed to accelerate HTTP traffic as well as make it more secure, with the intended goal of eventually replacing TCP and TLS on the web. In this blog post we are going to outline some of the key features of QUIC and how they benefit the web, and also some of the challenges of supporting this radical new protocol.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3XUtUi1ckk243XN0PWk2zo/68dcab940f1bcbb37cb3d3b7f10d1ddb/QUIC-Badge-Dark-RGB-Horiz.png" />
            
            </figure><p>There are in fact two protocols that share the same name: “Google QUIC” (“gQUIC” for short), is the original protocol that was designed by Google engineers several years ago, which, after years of experimentation, has now been adopted by the <a href="https://ietf.org/">IETF</a> (Internet Engineering Task Force) for standardization.</p><p>“IETF QUIC” (just “QUIC” from now on) has already diverged from gQUIC quite significantly such that it can be considered a separate protocol. From the wire format of the packets, to the handshake and the mapping of HTTP, QUIC has improved the original gQUIC design thanks to open collaboration from many organizations and individuals, with the shared goal of making the Internet faster and more secure.</p><p>So, what are the improvements QUIC provides?</p>
    <div>
      <h3>Built-in security (and performance)</h3>
      <a href="#built-in-security-and-performance">
        
      </a>
    </div>
    <p>One of QUIC’s more radical deviations from the now venerable TCP, is the stated design goal of providing a secure-by-default transport protocol. QUIC accomplishes this by providing security features, like authentication and encryption, that are typically handled by a higher layer protocol (like TLS), from the transport protocol itself.</p><p>The initial QUIC handshake combines the typical three-way handshake that you get with TCP, with the TLS 1.3 handshake, which provides authentication of the end-points as well as negotiation of cryptographic parameters. For those familiar with the TLS protocol, QUIC replaces the TLS record layer with its own framing format, while keeping the same TLS handshake messages.</p><p>Not only does this ensure that the connection is always authenticated and encrypted, but it also makes the initial connection establishment faster as a result: the typical QUIC handshake only takes a single round-trip between client and server to complete, compared to the two round-trips required for the TCP and TLS 1.3 handshakes combined.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1CWL4LYn5pKIq6nJjHfPeK/0683aa058799594bf35d41605e05b4c1/http-request-over-tcp-tls_2x.png" />
            
            </figure><p> </p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5rT3ge707TKiFEIiyEL4IW/3588b3d9d434ca9b705d75c2a72de090/http-request-over-quic_2x.png" />
            
            </figure><p>But QUIC goes even further, and also encrypts additional connection metadata that could be abused by middle-boxes to interfere with connections. For example packet numbers could be used by passive on-path attackers to correlate users activity over multiple network paths when connection migration is employed (see below). By encrypting packet numbers QUIC ensures that they can't be used to correlate activity by any entity other than the end-points in the connection.</p><p>Encryption can also be an effective remedy to ossification, which makes flexibility built into a protocol (like for example being able to negotiate different versions of that protocol) impossible to use in practice due to wrong assumptions made by implementations (ossification is what <a href="/why-tls-1-3-isnt-in-browsers-yet/">delayed deployment of TLS 1.3</a> for so long, which <a href="/you-get-tls-1-3-you-get-tls-1-3-everyone-gets-tls-1-3">was only possible</a> after several changes, designed to prevent ossified middle-boxes from incorrectly blocking the new revision of the TLS protocol, were adopted).</p>
    <div>
      <h3>Head-of-line blocking</h3>
      <a href="#head-of-line-blocking">
        
      </a>
    </div>
    <p>One of the main improvements delivered by <a href="/introducing-http2/">HTTP/2</a> was the ability to multiplex different HTTP requests onto the same TCP connection. This allows HTTP/2 applications to process requests concurrently and better utilize the network bandwidth available to them.</p><p>This was a big improvement over the then status quo, which required applications to initiate multiple TCP+TLS connections if they wanted to process multiple HTTP/1.1 requests concurrently (e.g. when a browser needs to fetch both CSS and Javascript assets to render a web page). Creating new connections requires repeating the initial handshakes multiple times, as well as going through the initial congestion window ramp-up, which means that rendering of web pages is slowed down. Multiplexing HTTP exchanges avoids all that.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5FcudeYzlfQKPqRI8YXk45/d271d04cc9150d0debd301c6481157d5/multiplexing.svg" />
            
            </figure><p>This however has a downside: since multiple requests/responses are transmitted over the same TCP connection, they are all equally affected by packet loss (e.g. due to network congestion), even if the data that was lost only concerned a single request. This is called “head-of-line blocking”.</p><p>QUIC goes a bit deeper and provides first class support for multiplexing such that different HTTP streams can in turn be mapped to different QUIC transport streams, but, while they still share the same QUIC connection so no additional handshakes are required and congestion state is shared, QUIC streams are delivered independently, such that in most cases packet loss affecting one stream doesn't affect others.</p><p>This can dramatically reduce the time required to, for example, render complete web pages (with CSS, Javascript, images, and other kinds of assets) particularly when crossing highly congested networks, with high packet loss rates.</p>
    <div>
      <h3>That easy, uh?</h3>
      <a href="#that-easy-uh">
        
      </a>
    </div>
    <p>In order to deliver on its promises, the QUIC protocol needs to break some of the assumptions that were taken for granted by many network applications, potentially making implementations and deployment of QUIC more difficult.</p><p>QUIC is designed to be delivered on top of UDP datagrams, to ease deployment and avoid problems coming from network appliances that drop packets from unknown protocols, since most appliances already support UDP. This also allows QUIC implementations to live in user-space, so that, for example, browsers will be able to implement new protocol features and ship them to their users without having to wait for operating systems updates.</p><p>However despite the intended goal of avoiding breakage, it also makes preventing abuse and correctly routing packets to the correct end-points more challenging.</p>
    <div>
      <h3>One NAT to bring them all and in the darkness bind them</h3>
      <a href="#one-nat-to-bring-them-all-and-in-the-darkness-bind-them">
        
      </a>
    </div>
    <p>Typical NAT routers can keep track of TCP connections passing through them by using the traditional 4-tuple (source IP address and port, and destination IP address and port), and by observing TCP SYN, ACK and FIN packets transmitted over the network, they can detect when a new connection is established and when it is terminated. This allows them to precisely manage the lifetime of NAT bindings, the association between the internal IP address and port, and the external ones.</p><p>With QUIC this is not yet possible, since NAT routers deployed in the wild today do not understand QUIC yet, so they typically fallback to the default and less precise handling of UDP flows, which usually involves using <a href="https://conferences.sigcomm.org/imc/2010/papers/p260.pdf">arbitrary, and at times very short, timeouts</a>, which could affect long-running connections.</p><p>When a NAT rebinding happens (due to a timeout for example), the end-point on the outside of the NAT perimeter will see packets coming from a different source port than the one that was observed when the connection was originally established, which makes it impossible to track connections by only using the 4-tuple.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2nozSxNZ6rsrj02Tb1IACy/fa90467738d8e89865b59be3ee4e5cf6/NAT-timeout-_2x.png" />
            
            </figure><p>And it's not just NAT! One of the features QUIC is intended to deliver is called “connection migration” and will allow QUIC end-points to migrate connections to different IP addresses and network paths at will. For example, a mobile client will be able to migrate QUIC connections between cellular data networks and WiFi when a known WiFi network becomes available (like when its user enters their favorite coffee shop).</p><p>QUIC tries to address this problem by introducing the concept of a connection ID: an arbitrary opaque blob of variable length, carried by QUIC packets, that can be used to identify a connection. End-points can use this ID to track connections that they are responsible for without the need to check the 4-tuple (in practice there might be multiple IDs identifying the same connection, for example to avoid linking different paths when connection migration is used, but that behavior is controlled by the end-points not the middle-boxes).</p><p>However this also poses a problem for network operators that use anycast addressing and <a href="/path-mtu-discovery-in-practice/">ECMP routing</a>, where a single destination IP address can potentially identify hundreds or even thousands of servers. Since edge routers used by these networks also don't yet know how to handle QUIC traffic, it might happen that UDP packets belonging to the same QUIC connection (that is, with the same connection ID) but with different 4-tuple (due to NAT rebinding or connection migration) might end up being routed to different servers, thus breaking the connection.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3y7Ae7Hm6zUy6SyL315Oxa/366eee8f4d5a89458556b77c53aacecb/anycast-cdn.png" />
            
            </figure><p>In order to address this, network operators might need to employ smarter layer 4 load balancing solutions, which can be implemented in software and deployed without the need to touch edge routers (see for example Facebook's <a href="https://github.com/facebookincubator/katran">Katran</a> project).</p>
    <div>
      <h3>QPACK</h3>
      <a href="#qpack">
        
      </a>
    </div>
    <p>Another benefit introduced by HTTP/2 was <a href="/hpack-the-silent-killer-feature-of-http-2/">header compression (or HPACK)</a> which allows HTTP/2 end-points to reduce the amount of data transmitted over the network by removing redundancies from HTTP requests and responses.</p><p>In particular, among other techniques, HPACK employs dynamic tables populated with headers that were sent (or received) from previous HTTP requests (or responses), allowing end-points to reference previously encountered headers in new requests (or responses), rather than having to transmit them all over again.</p><p>HPACK's dynamic tables need to be synchronized between the encoder (the party that sends an HTTP request or response) and the decoder (the one that receives them), otherwise the decoder will not be able to decode what it receives.</p><p>With HTTP/2 over TCP this synchronization is transparent, since the transport layer (TCP) takes care of delivering HTTP requests and responses in the same order they were sent in, the instructions for updating the tables can simply be sent by the encoder as part of the request (or response) itself, making the encoding very simple. But for QUIC this is more complicated.</p><p>QUIC can deliver multiple HTTP requests (or responses) over different streams independently, which means that while it takes care of delivering data in order as far as a single stream is concerned, there are no ordering guarantees across multiple streams.</p><p>For example, if a client sends HTTP request A over QUIC stream A, and request B over stream B, it might happen, due to packet reordering or loss in the network, that request B is received by the server before request A, and if request B was encoded such that it referenced a header from request A, the server will be unable to decode it since it didn't yet see request A.</p><p>In the gQUIC protocol this problem was solved by simply serializing all HTTP request and response headers (but not the bodies) over the same gQUIC stream, which meant headers would get delivered in order no matter what. This is a very simple scheme that allows implementations to reuse a lot of their existing HTTP/2 code, but on the other hand it increases the head-of-line blocking that QUIC was designed to reduce. The IETF QUIC working group thus designed a new mapping between HTTP and QUIC (“HTTP/QUIC”) as well as a new header compression scheme called “QPACK”.</p><p>In the latest draft of the HTTP/QUIC mapping and the QPACK spec, each HTTP request/response exchange uses its own bidirectional QUIC stream, so there's no head-of-line blocking. In addition, in order to support QPACK, each peer creates two additional unidirectional QUIC streams, one used to send QPACK table updates to the other peer, and one to acknowledge updates received by the other side. This way, a QPACK encoder can use a dynamic table reference only after it has been explicitly acknowledged by the decoder.</p>
    <div>
      <h3>Deflecting Reflection</h3>
      <a href="#deflecting-reflection">
        
      </a>
    </div>
    <p>A common problem among <a href="/ssdp-100gbps/">UDP-based</a> <a href="/memcrashed-major-amplification-attacks-from-port-11211/">protocols</a> is their susceptibility to <a href="/reflections-on-reflections/">reflection attacks</a>, where an attacker tricks an otherwise innocent server into sending large amounts of data to a third-party victim, by spoofing the source IP address of packets targeted to the server to make them look like they came from the victim.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7LfQICIemcnM4AgyhDb6kD/0649164a476896ca3a58de5390c08f09/ip-spoofing.png" />
            
            </figure><p>This kind of attack can be very effective when the response sent by the server happens to be larger than the request it received, in which case we talk of “amplification”.</p><p>TCP is not usually used for this kind of attack due to the fact that the initial packets transmitted during its handshake (SYN, SYN+ACK, …) have the same length so they don’t provide any amplification potential.</p><p>QUIC’s handshake on the other hand is very asymmetrical: like for TLS, in its first flight the QUIC server generally sends its own certificate chain, which can be very large, while the client only has to send a few bytes (the TLS ClientHello message embedded into a QUIC packet). For this reason, the initial QUIC packet sent by a client has to be padded to a specific minimum length (even if the actual content of the packet is much smaller). However this mitigation is still not sufficient, since the typical server response spans multiple packets and can thus still be far larger than the padded client packet.</p><p>The QUIC protocol also defines an explicit source-address verification mechanism, in which the server, rather than sending its long response, only sends a much smaller “retry” packet which contains a unique cryptographic token that the client will then have to echo back to the server inside a new initial packet. This way the server has a higher confidence that the client is not spoofing its own source IP address (since it received the retry packet) and can complete the handshake. The downside of this mitigation is that it increases the initial handshake duration from a single round-trip to two.</p><p>An alternative solution involves reducing the server's response to the point where a reflection attack becomes less effective, for example by using <a href="/ecdsa-the-digital-signature-algorithm-of-a-better-internet/">ECDSA certificates</a> (which are typically much smaller than their RSA counterparts). We have also been experimenting with a mechanism for <a href="https://tools.ietf.org/html/draft-ietf-tls-certificate-compression">compressing TLS certificates</a> using off-the-shelf compression algorithms like zlib and brotli, which is a feature originally introduced by gQUIC but not currently available in TLS.</p>
    <div>
      <h3>UDP performance</h3>
      <a href="#udp-performance">
        
      </a>
    </div>
    <p>One of the recurring issues with QUIC involves existing hardware and software deployed in the wild not being able to understand it. We've already looked at how QUIC tries to address network middle-boxes like routers, but another potentially problematic area is the performance of sending and receiving data over UDP on the QUIC end-points themselves. Over the years a lot of work has gone into optimizing TCP implementations as much as possible, including building off-loading capabilities in both software (like in operating systems) and hardware (like in network interfaces), but none of that is currently available for UDP.</p><p>However it’s only a matter of time until QUIC implementations can take advantage of these capabilities as well. Look for example at the recent efforts to implement <a href="https://lwn.net/Articles/752184/">Generic Segmentation Offloading for UDP on LInux</a>, which would allow applications to bundle and transfer multiple UDP segments between user-space and the kernel-space networking stack at the cost of a single one (or close enough), as well as the one to add <a href="https://lwn.net/Articles/655299/">zerocopy socket support also on Linux</a> which would allow applications to avoid the cost of copying user-space memory into kernel-space.</p>
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>Like HTTP/2 and TLS 1.3, QUIC is set to deliver a lot of new features designed to improve performance and security of web sites, as well as other Internet-based properties. The IETF working group is currently set to deliver the first version of the QUIC specifications by the end of the year and Cloudflare engineers are already hard at work to provide the benefits of QUIC to all of our customers.</p> ]]></content:encoded>
            <category><![CDATA[TLS]]></category>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[QUIC]]></category>
            <category><![CDATA[IETF]]></category>
            <guid isPermaLink="false">4ZyUVtsRDEiNCkr2iwov88</guid>
            <dc:creator>Alessandro Ghedini</dc:creator>
        </item>
        <item>
            <title><![CDATA[Deprecating SPDY]]></title>
            <link>https://blog.cloudflare.com/deprecating-spdy/</link>
            <pubDate>Thu, 18 Jan 2018 15:58:00 GMT</pubDate>
            <description><![CDATA[ Participating in the Internet democracy occasionally means that technologies that were once popular lose their utility as newer technologies emerge. SPDY is one such technology.  As a result, we're announcing our intention to deprecate the use of SPDY for connections made to Cloudflare's edge. ]]></description>
            <content:encoded><![CDATA[ <p>Democratizing the Internet and making new features available to all Cloudflare customers is a core part of what we do. We're proud to be early adopters and have a long record of adopting new standards early, such as <a href="/introducing-http2/">HTTP/2</a>, as well as features that are experimental or not yet final, like <a href="/introducing-tls-1-3/">TLS 1.3</a> and <a href="/introducing-spdy/">SPDY</a>.</p><p>Participating in the Internet democracy occasionally means that ideas and technologies that were once popular or ubiquitous on the net lose their utility as newer technologies emerge. SPDY is one such technology. Several years ago, Google drafted a <a href="http://www.chromium.org/spdy/spdy-whitepaper">proprietary and experimental new protocol called SPDY</a>. SPDY offered many performance improvements over the aging HTTP/1.1 standard and these improvements resulted in significantly faster page load times for real-world websites. Stemming from its success, SPDY became the starting point for HTTP/2 and, when the new HTTP standard was finalized, the SPDY experiment came to an end where it gradually fell into disuse.</p><p>As a result, we're announcing our intention to deprecate the use of SPDY for connections made to Cloudflare's edge by February 21st, 2018.</p>
    <div>
      <h3>Remembering 2012</h3>
      <a href="#remembering-2012">
        
      </a>
    </div>
    <p>Five and a half years ago, when the majority of the web was unencrypted and web developers were resorting to creative tricks to improve performance (such as domain sharding to download resources in parallel) to get around the limitations of the then thirteen-year-old HTTP/1.1 standard, Cloudflare launched support for an exciting new protocol called SPDY.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/GcM2v0PkiVsXMHYMcNMFd/d4450ed0bde7202c91677354c4e0c486/0910152_02-A4-at-144-dpi.jpg" />
            
            </figure><p><a href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a> by <a href="https://cds.cern.ch/record/1211045">Maximilien Brice</a></p><p>SPDY aimed to remove many of the bottlenecks present in HTTP/1.1 by changing the way HTTP requests were sent over the wire. Using header compression, request prioritization, and multiplexing, SPDY was able to provide significant performance gains while remaining compatible with the existing HTTP/1.1 standard. This meant that server operators could place a SPDY layer, such as Cloudflare, in front of their web application and gain the performance benefits of SPDY without modifying any of their existing code. SPDY effectively became a fast tunnel for HTTP traffic.</p>
    <div>
      <h3>2015: An ever-changing landscape</h3>
      <a href="#2015-an-ever-changing-landscape">
        
      </a>
    </div>
    <p>As the HTTPbis Working Group submitted SPDY for <a href="https://tools.ietf.org/html/draft-ietf-httpbis-http2-00">standardization</a>, the protocol underwent some changes (e.g.— Using <a href="https://tools.ietf.org/html/rfc7541">HPACK</a> for compression), but retained its core performance optimizations and came to be known as HTTP/2 in May 2015.</p><p>With the standardization of HTTP/2, Google announced that they would cease supporting SPDY with the public release of Chrome 51 in May 2016. This signaled to other software providers that they too should abandon support for the experimental SPDY protocol in favor of the newly standardized HTTP/2. Mozilla did so with the release of Firefox 51 in January 2017 and NGINX built their HTTP/2 module so that either it or the SPDY module could be used to terminate HTTPS connections, but not both.</p><p>Cloudflare announced support for HTTP/2 in December of 2015. It was at this point that we deviated from our peers in the industry. We knew that adoption of this new standard and the migration away from SPDY would take longer than the 1-2 year timeline put forth by Google and others, so we created our own patch for NGINX so that we could support terminating both SPDY and HTTP/2. This allowed Cloudflare customers who had yet to upgrade their clients to continue to receive the performance benefits of SPDY until they were able to support HTTP/2.</p><p>When we made this decision, SPDY was used for 53.59% of TLS connections to our edge and HTTP/2 for 26.79%. Had we only adopted the standard NGINX HTTP/2 module, we would've made the internet around 20% slower for more than half of all visitors to sites on Cloudflare— definitely not a performance compromise we were willing to make!</p>
    <div>
      <h3>To 2018 and Beyond</h3>
      <a href="#to-2018-and-beyond">
        
      </a>
    </div>
    <p>Two years after we began supporting HTTP/2 (and nearly three years after standardization), the majority of web browsers now support HTTP/2 where the notable exceptions are the UC Browser for Android and Opera Mini. This results in SPDY being used for only 3.83% of TLS connections to Cloudflare's edge whereas HTTP/2 accounts for 66.88%. At this point, and for several reasons, now is the time to stop supporting SPDY.</p><p><a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a> by <a href="https://pixabay.com/en/users/JanBaby-3005373/">JanBaby</a></p><p>Looking closer at the low percentage of clients connecting with SPDY in 2018, 65% of these connections are made by older iOS and macOS apps compiled against HTTP and TLS libraries which only support SPDY and not HTTP/2. This means that these app developers need to publish an update with HTTP/2 support to enable support for this protocol. We worked closely with Apple to assess the impact of deprecating SPDY for these clients and determined that the impact of deprecation is minimal.</p><p>We mentioned earlier that we applied our own patch to NGINX in order to be able to continue to support both SPDY and HTTP/2 for TLS connections. What we didn't mention was the engineering cost associated with maintaining this patch. Every time we want to update NGINX, we also need to update and test our patch, which makes each upgrade more difficult. Further, no active development is being done to SPDY so in the event that security issues arise, we would incur the cost of developing our own security patches.</p><p>Finally, when we do disable SPDY this February, the less than 4% of traffic that currently uses SPDY will still be able to connect to Cloudflare's edge by gracefully falling back to using HTTP/1.1.</p>
    <div>
      <h3>Moving Forward While Looking Back</h3>
      <a href="#moving-forward-while-looking-back">
        
      </a>
    </div>
    <p>Part of being an innovator is knowing when it is time to move forward and put older innovations in the rear view mirror. By seeing 10% of HTTP requests made on the internet, Cloudflare is in a unique position to analyze overall adoption trends of new technologies, allowing us to make informed decisions on when to launch new features or deprecate legacy ones.</p><p>SPDY has been extraordinarily beneficial to clients connecting to Cloudflare over the years, but now that the protocol is largely abandoned and superseded by newer technologies, we recognize that 2018 is time to say goodbye to an aging legacy protocol.</p> ]]></content:encoded>
            <category><![CDATA[SSL]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[spdy]]></category>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <guid isPermaLink="false">3PXXT92K6072DYydBkCKiN</guid>
            <dc:creator>Max Nystrom</dc:creator>
        </item>
        <item>
            <title><![CDATA[How to make your site HTTPS-only]]></title>
            <link>https://blog.cloudflare.com/how-to-make-your-site-https-only/</link>
            <pubDate>Thu, 06 Jul 2017 13:35:00 GMT</pubDate>
            <description><![CDATA[ The Internet is getting more secure every day as people enable HTTPS, the secure version of HTTP, on their sites and services. ]]></description>
            <content:encoded><![CDATA[ <p>The Internet is getting more secure every day as people enable HTTPS, the secure version of HTTP, on their sites and services. Last year, Mozilla reported that the percentage of requests made by Firefox using encrypted HTTPS passed <a href="https://twitter.com/0xjosh/status/78697141295942042">50% for the first time</a>. HTTPS has numerous benefits that are not available over unencrypted HTTP, including improved performance with <a href="https://www.cloudflare.com/website-optimization/http2/">HTTP/2</a>, <a href="http://searchengineland.com/google-starts-giving-ranking-boost-secure-httpsssl-sites-199446">SEO benefits</a> for search engines like Google and the reassuring lock icon in the address bar.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2mExGu34GTxoBejOt9ef1Y/a173ce5dfc0b61d2213238afab253abe/image1.jpg" />
            
            </figure><p>So how do you add HTTPS to your site or service? That’s simple, Cloudflare offers free and automatic HTTPS support for all customers with no configuration. Sign up for any plan and Cloudflare will issue an SSL certificate for you and serve your site over HTTPS.</p>
    <div>
      <h3>HTTPS-only</h3>
      <a href="#https-only">
        
      </a>
    </div>
    <p>Enabling HTTPS does not mean that all visitors are protected. If a visitor types your website’s name into the address bar of a browser or follows an HTTP link, it will bring them to the insecure HTTP version of your website. In order to make your site HTTPS-only, you need to redirect visitors from the HTTP to the HTTPS version of your site.</p><p>Going HTTPS-only should be as easy as a click of a button, so we literally added one to the Cloudflare dashboard. Enable the “Always Use HTTPS” feature and all visitors of the HTTP version of your website will be redirected to the HTTPS version. You’ll find this option just above the HTTP Strict Transport Security setting and it is of course also available through our <a href="https://api.cloudflare.com/#zone-settings-change-always-use-https-setting">API</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/19twvdqDrUtYthZ88NZCG1/9b888300f8ed08e480adfbcaad1c1ee0/image2-1.png" />
            
            </figure><p>In case you would like to redirect only some subset of your requests you can still do this by creating a <a href="https://www.cloudflare.com/features-page-rules/">Page Rule</a>. Simply use the “Always Use HTTPS” setting on any URL pattern.</p>
    <div>
      <h3>Securing your site: next steps</h3>
      <a href="#securing-your-site-next-steps">
        
      </a>
    </div>
    <p>Once you have confirmed that your site is fully functional with HTTPS-only enabled, you can take it a step further and enable HTTP Strict Transport Security (<a href="/enforce-web-policy-with-hypertext-strict-transport-security-hsts/">HSTS</a>). HSTS is a header that tells browsers that your site is available over HTTPS and will be for a set period of time. Once a browser sees an HSTS header for a site, it will automatically fetch the HTTPS version of HTTP pages without needing to follow redirects. HSTS can be enabled in the crypto app right under the Always Use HTTPS toggle.</p><p>It's also important to secure the connection between Cloudflare and your site. To do that, you can use Cloudflare's <a href="/cloudflare-ca-encryption-origin/">Origin CA</a> to get a free certificate for your origin server. Once your origin server is set up with HTTPS and a valid certificate, change your SSL mode to Full (strict) to get the highest level of security.</p> ]]></content:encoded>
            <category><![CDATA[HTTPS]]></category>
            <category><![CDATA[SSL]]></category>
            <category><![CDATA[Automatic HTTPS]]></category>
            <category><![CDATA[Certificate Authority]]></category>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Cryptography]]></category>
            <guid isPermaLink="false">2XThcNAZoHfneQaKkn6XXC</guid>
            <dc:creator>Nick Sullivan</dc:creator>
        </item>
        <item>
            <title><![CDATA[So you want to expose Go on the Internet]]></title>
            <link>https://blog.cloudflare.com/exposing-go-on-the-internet/</link>
            <pubDate>Mon, 26 Dec 2016 14:59:01 GMT</pubDate>
            <description><![CDATA[ Back when crypto/tls was slow and net/http young, the general wisdom was to always put Go servers behind a reverse proxy like NGINX. That's not necessary anymore! ]]></description>
            <content:encoded><![CDATA[ <p><i>This piece was </i><a href="https://blog.gopheracademy.com/advent-2016/exposing-go-on-the-internet/"><i>originally written</i></a><i> for the Gopher Academy advent series. We are grateful to them for allowing us to republish it here.</i></p><p>Back when <code>crypto/tls</code> was slow and <code>net/http</code> young, the general wisdom was to always put Go servers behind a reverse proxy like NGINX. That's not necessary anymore!</p><p>At Cloudflare we recently experimented with exposing pure Go services to the hostile wide area network. With the Go 1.8 release, <code>net/http</code> and <code>crypto/tls</code> proved to be stable, performant and flexible.</p><p>However, the defaults are tuned for local services. In this articles we'll see how to tune and harden a Go server for Internet exposure.</p>
    <div>
      <h3><code>crypto/tls</code></h3>
      <a href="#crypto-tls">
        
      </a>
    </div>
    <p>You're not running an insecure HTTP server on the Internet in 2016. So you need <code>crypto/tls</code>. The good news is that it's <a href="/go-crypto-bridging-the-performance-gap/">now really fast</a> (as you've seen in a <a href="https://blog.gopheracademy.com/advent-2016/tls-termination-bench/">previous advent article</a>), and its security track record so far is excellent.</p><p>The default settings resemble the <i>Intermediate</i> recommended configuration of the <a href="https://wiki.mozilla.org/Security/Server_Side_TLS">Mozilla guidelines</a>. However, you should still set <code>PreferServerCipherSuites</code> to ensure safer and faster cipher suites are preferred, and <code>CurvePreferences</code> to avoid unoptimized curves: a client using <code>CurveP384</code> would cause up to a second of CPU to be consumed on our machines.</p>
            <pre><code>&amp;tls.Config{
	// Causes servers to use Go's default ciphersuite preferences,
	// which are tuned to avoid attacks. Does nothing on clients.
	PreferServerCipherSuites: true,
	// Only use curves which have assembly implementations
	CurvePreferences: []tls.CurveID{
		tls.CurveP256,
		tls.X25519, // Go 1.8 only
	},
}</code></pre>
            <p>If you can take the compatibility loss of the <i>Modern</i> configuration, you should then also set <code>MinVersion</code> and <code>CipherSuites</code>.</p>
            <pre><code>	MinVersion: tls.VersionTLS12,
	CipherSuites: []uint16{
		tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
		tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
		tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, // Go 1.8 only
		tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,   // Go 1.8 only
		tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
		tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,

		// Best disabled, as they don't provide Forward Secrecy,
		// but might be necessary for some clients
		// tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
		// tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
	},</code></pre>
            <p>Be aware that the Go implementation of the CBC cipher suites (the ones we disabled in <i>Modern</i> mode above) is vulnerable to the <a href="https://www.imperialviolet.org/2013/02/04/luckythirteen.html">Lucky13 attack</a>, even if <a href="https://github.com/golang/go/commit/f28cf8346c4ce7cb74bf97c7c69da21c43a78034">partial countermeasures were merged in 1.8</a>.</p><p>Final caveat, all these recommendations apply only to the amd64 architecture, for which <a href="/go-crypto-bridging-the-performance-gap/">fast, constant time implementations</a> of the crypto primitives (AES-GCM, ChaCha20-Poly1305, P256) are available. Other architectures are probably not fit for production use.</p><p>Since this server will be exposed to the Internet, it will need a publicly trusted certificate. You can get one easily and for free thanks to Let's Encrypt and the <a href="https://godoc.org/golang.org/x/crypto/acme/autocert"><code>golang.org/x/crypto/acme/autocert</code></a> package’s <code>GetCertificate</code> function.</p><p>Don't forget to redirect HTTP page loads to HTTPS, and consider <a href="https://www.owasp.org/index.php/HTTP_Strict_Transport_Security_Cheat_Sheet">HSTS</a> if your clients are browsers.</p>
            <pre><code>srv := &amp;http.Server{
	ReadTimeout:  5 * time.Second,
	WriteTimeout: 5 * time.Second,
	Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		w.Header().Set("Connection", "close")
		url := "https://" + req.Host + req.URL.String()
		http.Redirect(w, req, url, http.StatusMovedPermanently)
	}),
}
go func() { log.Fatal(srv.ListenAndServe()) }()</code></pre>
            <p>You can use the <a href="https://www.ssllabs.com/ssltest/">SSL Labs test</a> to check that everything is configured correctly.</p>
    <div>
      <h3><code>net/http</code></h3>
      <a href="#net-http">
        
      </a>
    </div>
    <p><code>net/http</code> is a mature HTTP/1.1 and HTTP/2 stack. You probably know how (and have opinions about how) to use the Handler side of it, so that's not what we'll talk about. We will instead talk about the Server side and what goes on behind the scenes.</p>
    <div>
      <h3>Timeouts</h3>
      <a href="#timeouts">
        
      </a>
    </div>
    <p>Timeouts are possibly the most dangerous edge case to overlook. Your service might get away with it on a controlled network, but it will not survive on the open Internet, especially (but not only) if maliciously attacked.</p><p>Applying timeouts is a matter of resource control. Even if goroutines are cheap, file descriptors are always limited. A connection that is stuck, not making progress or is maliciously stalling should not be allowed to consume them.</p><p>A server that ran out of file descriptors will fail to accept new connections with errors like</p>
            <pre><code>http: Accept error: accept tcp [::]:80: accept: too many open files; retrying in 1s</code></pre>
            <p>A zero/default <code>http.Server</code>, like the one used by the package-level helpers <code>http.ListenAndServe</code> and <code>http.ListenAndServeTLS</code>, comes with no timeouts. You don't want that.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/12k30eO5eG5vdJG4C7Yk6J/89cc5b4dc27bff41da1259bde71b278d/Timeouts.png" />
            
            </figure><p>There are three main timeouts exposed in <code>http.Server</code>: <code>ReadTimeout</code>, <code>WriteTimeout</code> and <code>IdleTimeout</code>. You set them by explicitly using a Server:</p>
            <pre><code>srv := &amp;http.Server{
    ReadTimeout:  5 * time.Second,
    WriteTimeout: 10 * time.Second,
    IdleTimeout:  120 * time.Second,
    TLSConfig:    tlsConfig,
    Handler:      serveMux,
}
log.Println(srv.ListenAndServeTLS("", ""))</code></pre>
            <p><code>ReadTimeout</code> covers the time from when the connection is accepted to when the request body is fully read (if you do read the body, otherwise to the end of the headers). It's implemented in <code>net/http</code> by calling <code>SetReadDeadline</code> <a href="https://github.com/golang/go/blob/3ba31558d1bca8ae6d2f03209b4cae55381175b3/src/net/http/server.go#L750">immediately after Accept</a>.</p><p>The problem with a <code>ReadTimeout</code> is that it doesn't allow a server to give the client more time to stream the body of a request based on the path or the content. Go 1.8 introduces <code>ReadHeaderTimeout</code>, which only covers up to the request headers. However, there's still no clear way to do reads with timeouts from a Handler. Different designs are being discussed in issue <a href="https://golang.org/issue/16100">#16100</a>.</p><p><code>WriteTimeout</code> normally covers the time from the end of the request header read to the end of the response write (a.k.a. the lifetime of the ServeHTTP), by calling <code>SetWriteDeadline</code> <a href="https://github.com/golang/go/blob/3ba31558d1bca8ae6d2f03209b4cae55381175b3/src/net/http/server.go#L753-L755">at the end of readRequest</a>.</p><p>However, when the connection is over HTTPS, <code>SetWriteDeadline</code> is called <a href="https://github.com/golang/go/blob/3ba31558d1bca8ae6d2f03209b4cae55381175b3/src/net/http/server.go#L1477-L1483">immediately after Accept</a> so that it also covers the packets written as part of the TLS handshake. Annoyingly, this means that (in that case only) <code>WriteTimeout</code> ends up including the header read and the first byte wait.</p><p>Similarly to <code>ReadTimeout</code>, <code>WriteTimeout</code> is absolute, with no way to manipulate it from a Handler (<a href="https://golang.org/issue/16100">#16100</a>).</p><p>Finally, Go 1.8 <a href="https://github.com/golang/go/issues/14204">introduces <code>IdleTimeout</code></a> which limits server-side the amount of time a Keep-Alive connection will be kept idle before being reused. Before Go 1.8, the <code>ReadTimeout</code> would start ticking again immediately after a request completed, making it very hostile to Keep-Alive connections: the idle time would consume time the client should have been allowed to send the request, causing unexpected timeouts also for fast clients.</p><p>You should set <code>Read</code>, <code>Write</code> and <code>Idle</code> timeouts when dealing with untrusted clients and/or networks, so that a client can't hold up a connection by being slow to write or read.</p><p>For detailed background on HTTP/1.1 timeouts (up to Go 1.7) read <a href="/the-complete-guide-to-golang-net-http-timeouts/">my post on the Cloudflare blog</a>.</p>
    <div>
      <h4>HTTP/2</h4>
      <a href="#http-2">
        
      </a>
    </div>
    <p>HTTP/2 is enabled automatically on any Go 1.6+ server if:</p><ul><li><p>the request is served over TLS/HTTPS</p></li><li><p><code>Server.TLSNextProto</code> is <code>nil</code> (setting it to an empty map is how you disable HTTP/2)</p></li><li><p><code>Server.TLSConfig</code> is set and <code>ListenAndServeTLS</code> is used <b>or</b></p></li><li><p><code>Serve</code> is used and <code>tls.Config.NextProtos</code> includes <code>"h2"</code> (like <code>[]string{"h2", "http/1.1"}</code>, since <code>Serve</code> is called <a href="https://github.com/golang/go/issues/15908">too late to auto-modify the TLS Config</a>)</p></li></ul><p>HTTP/2 has a slightly different meaning since the same connection can be serving different requests at the same time, however, they are abstracted to the same set of Server timeouts in Go.</p><p>Sadly, <code>ReadTimeout</code> breaks HTTP/2 connections in Go 1.7. Instead of being reset for each request it's set once at the beginning of the connection and never reset, breaking all HTTP/2 connections after the <code>ReadTimeout</code> duration. <a href="https://github.com/golang/go/issues/16450">It's fixed in 1.8</a>.</p><p>Between this and the inclusion of idle time in <code>ReadTimeout</code>, my recommendation is to <b>upgrade to 1.8 as soon as possible</b>.</p>
    <div>
      <h4>TCP Keep-Alives</h4>
      <a href="#tcp-keep-alives">
        
      </a>
    </div>
    <p>If you use <code>ListenAndServe</code> (as opposed to passing a <code>net.Listener</code> to <code>Serve</code>, which offers zero protection by default) a TCP Keep-Alive period of three minutes <a href="https://github.com/golang/go/blob/61db2e4efa2a8f558fd3557958d1c86dbbe7d3cc/src/net/http/server.go#L3023-L3039">will be set automatically</a>. That <i>will</i> help with clients that disappear completely off the face of the earth leaving a connection open forever, but I’ve learned not to trust that, and to set timeouts anyway.</p><p>To begin with, three minutes might be too high, which you can solve by implementing your own <a href="https://github.com/golang/go/blob/61db2e4efa2a8f558fd3557958d1c86dbbe7d3cc/src/net/http/server.go#L3023-L3039"><code>tcpKeepAliveListener</code></a>.</p><p>More importantly, a Keep-Alive only makes sure that the client is still responding, but does not place an upper limit on how long the connection can be held. A single malicious client can just open as many connections as your server has file descriptors, hold them half-way through the headers, respond to the rare keep-alives, and effectively take down your service.</p><p>Finally, in my experience connections tend to leak anyway until <a href="https://github.com/FiloSottile/Heartbleed/commit/4a3332ca1dc07aedf24b8540857792f72624cdf7">timeouts are in place</a>.</p>
    <div>
      <h3>ServeMux</h3>
      <a href="#servemux">
        
      </a>
    </div>
    <p>Package level functions like <code>http.Handle[Func]</code> (and maybe your web framework) register handlers on the global <code>http.DefaultServeMux</code> which is used if <code>Server.Handler</code> is nil. You should avoid that.</p><p>Any package you import, directly or through other dependencies, has access to <code>http.DefaultServeMux</code> and might register routes you don't expect.</p><p>For example, if any package somewhere in the tree imports <code>net/http/pprof</code> clients will be able to get CPU profiles for your application. You can still use <code>net/http/pprof</code> by registering <a href="https://github.com/golang/go/blob/1106512db54fc2736c7a9a67dd553fc9e1fca742/src/net/http/pprof/pprof.go#L67-L71">its handlers</a> manually.</p><p>Instead, instantiate an <code>http.ServeMux</code> yourself, register handlers on it, and set it as <code>Server.Handler</code>. Or set whatever your web framework exposes as <code>Server.Handler</code>.</p>
    <div>
      <h3>Logging</h3>
      <a href="#logging">
        
      </a>
    </div>
    <p><code>net/http</code> does a number of things before yielding control to your handlers: <a href="https://github.com/golang/go/blob/1106512db54fc2736c7a9a67dd553fc9e1fca742/src/net/http/server.go#L2631-L2653"><code>Accept</code>s the connections</a>, <a href="https://github.com/golang/go/blob/1106512db54fc2736c7a9a67dd553fc9e1fca742/src/net/http/server.go#L1718-L1728">runs the TLS Handshake</a>, ...</p><p>If any of these go wrong a line is written directly to <code>Server.ErrorLog</code>. Some of these, like timeouts and connection resets, are expected on the open Internet. It's not clean, but you can intercept most of those and turn them into metrics by matching them with regexes from the Logger Writer, thanks to this guarantee:</p><blockquote><p>Each logging operation makes a single call to the Writer's Write method.</p></blockquote><p>To abort from inside a Handler without logging a stack trace you can either <code>panic(nil)</code> or in Go 1.8 <code>panic(http.ErrAbortHandler)</code>.</p>
    <div>
      <h3>Metrics</h3>
      <a href="#metrics">
        
      </a>
    </div>
    <p>A metric you'll want to monitor is the number of open file descriptors. <a href="https://github.com/prometheus/client_golang/blob/575f371f7862609249a1be4c9145f429fe065e32/prometheus/process_collector.go">Prometheus does that by using the <code>proc</code> filesystem</a>.</p><p>If you need to investigate a leak, you can use the <code>Server.ConnState</code> hook to get more detailed metrics of what stage the connections are in. However, note that there is no way to keep a correct count of <code>StateActive</code> connections without keeping state, so you'll need to maintain a <code>map[net.Conn]ConnState</code>.</p>
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>The days of needing NGINX in front of all Go services are gone, but you still need to take a few precautions on the open Internet, and probably want to upgrade to the shiny, new Go 1.8.</p><p>Happy serving!</p> ]]></content:encoded>
            <category><![CDATA[TLS]]></category>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Programming]]></category>
            <category><![CDATA[Cryptography]]></category>
            <guid isPermaLink="false">5x4k8xtfrkPyeHS7HcYbF7</guid>
            <dc:creator>Filippo Valsorda</dc:creator>
        </item>
        <item>
            <title><![CDATA[HPACK: the silent killer (feature) of HTTP/2]]></title>
            <link>https://blog.cloudflare.com/hpack-the-silent-killer-feature-of-http-2/</link>
            <pubDate>Mon, 28 Nov 2016 14:10:41 GMT</pubDate>
            <description><![CDATA[ If you have experienced HTTP/2 for yourself, you are probably aware of the visible performance gains possible with HTTP/2 due to features like stream multiplexing, explicit stream dependencies, and Server Push.

 ]]></description>
            <content:encoded><![CDATA[ <p>If you have <a href="https://www.cloudflare.com/website-optimization/http2/">experienced HTTP/2</a> for yourself, you are probably aware of the visible performance gains possible with <a href="https://www.cloudflare.com/website-optimization/http2/">HTTP/2</a> due to features like stream multiplexing, explicit stream dependencies, and <a href="/announcing-support-for-http-2-server-push-2/">Server Push</a>.</p><p>There is however one important feature that is not obvious to the eye. This is the HPACK header compression. Current implementation of nginx, as well edge networks and <a href="https://www.cloudflare.com/learning/cdn/what-is-a-cdn/">CDNs</a> using it, do not support the full HPACK implementation. We have, however, implemented the full HPACK in nginx, and <a href="http://mailman.nginx.org/pipermail/nginx-devel/2015-December/007682.html">upstreamed</a> the part that performs Huffman encoding.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4wGvQogXUWstwB5ETJPpyr/5423d3e1f23daed6c17cc8d79a25ac8d/6129093355_9434beed25_z.jpg" />
            
            </figure><p><a href="https://creativecommons.org/licenses/by/2.0/">CC BY 2.0</a> <a href="https://www.flickr.com/photos/conchur/6129093355/in/photolist-akBcVn-6eEtUq-d9Xi2T-c8MwzA-mGVr3z-aVezji-mGVxov-acMJmz-6nvbCJ-6a6DGQ-5uwrr9-rRtCCp-acMKsk-cKeuXY-9F6N13-9GSuHh-acMDBk-cJYes5-cijtcj-akFua9-cK1iqS-fiAHkE-acMCDt-cJZ9Fq-5qtfNv-cJWFiw-e4pfTd-6fzyLV-8RNMTo-p7jJLQ-524dkf-dw52qG-mVDttF-duUbYU-dvXt3Z-c8NkYG-6e6K2S-duKJjZ-5DbaqV-duBiR3-dvGTsM-dvLst4-dvPfJ1-ezYL1J-7f1cMC-bqi5WN-5MMGkV-9F3C7c-eWASXx-cJXsW9">image</a> by <a href="https://www.flickr.com/photos/conchur/">Conor Lawless</a></p><p>This blog post gives an overview of the reasons for the development of HPACK, and the hidden bandwidth and latency benefits it brings.</p>
    <div>
      <h3>Some Background</h3>
      <a href="#some-background">
        
      </a>
    </div>
    <p>As you probably know, a regular HTTPS connection is in fact an overlay of several connections in the multi-layer model. The most basic connection you usually care about is the TCP connection (the transport layer), on top of that you have the TLS connection (mix of transport/application layers), and finally the HTTP connection (application layer).</p><p>In the the days of yore, HTTP compression was performed in the TLS layer, using gzip. Both headers and body were compressed indiscriminately, because the lower TLS layer was unaware of the transferred data type. In practice it meant both were compressed with the <a href="/results-experimenting-brotli/">DEFLATE</a> algorithm.</p><p>Then came SPDY with a new, dedicated, header compression algorithm. Although specifically designed for headers, including the use of a preset <a href="/improving-compression-with-preset-deflate-dictionary/">dictionary</a>, it was still using DEFLATE, including dynamic Huffman codes and string matching.</p><p>Unfortunately both were found to be vulnerable to the <a href="https://www.ekoparty.org/archive/2012/CRIME_ekoparty2012.pdf">CRIME</a> attack, that can extract secret authentication cookies from compressed headers: because DEFLATE uses backward string matches and dynamic Huffman codes, an attacker that can control part of the request headers, can gradually recover the full cookie by modifying parts of the request and seeing how the total size of the request changes during compression.</p><p>Most edge networks, including Cloudflare, disabled header compression because of CRIME. That’s until HTTP/2 came along.</p>
    <div>
      <h3>HPACK</h3>
      <a href="#hpack">
        
      </a>
    </div>
    <p>HTTP/2 supports a new dedicated header compression algorithm, called HPACK. HPACK was developed with attacks like CRIME in mind, and is therefore considered safe to use.</p><p>HPACK is resilient to CRIME, because it does not use partial backward string matches and dynamic Huffman codes like DEFLATE. Instead, it uses these three methods of compression:</p><ul><li><p>Static Dictionary: A <a href="https://http2.github.io/http2-spec/compression.html#static.table.definition">predefined dictionary</a> of 61 commonly used header fields, some with predefined values.</p></li><li><p>Dynamic Dictionary: A list of actual headers that were encountered during the connection. This dictionary has limited size, and when new entries are added, old entries might be evicted.</p></li><li><p>Huffman Encoding: A <a href="https://http2.github.io/http2-spec/compression.html#huffman.code">static Huffman code</a> can be used to encode any string: name or value. This code was computed specifically for HTTP Response/Request headers - ASCII digits and lowercase letters are given shorter encodings. The shortest encoding possible is 5 bits long, therefore the highest compression ratio achievable is 8:5 (or 37.5% smaller).</p></li></ul>
    <div>
      <h4>HPACK flow</h4>
      <a href="#hpack-flow">
        
      </a>
    </div>
    <p>When HPACK needs to encode a header in the format <b><i>name:value</i></b>, it will first look in the static and dynamic dictionaries. If the <b><i>full</i></b> <b>name:value</b> is present, it will simply reference the entry in the dictionary. This will usually take one byte, and in most cases two bytes will suffice! A whole header encoded in a single byte! How crazy is that?</p><p>Since many headers are repetitive, this strategy has a very high success rate. For example, headers like <b>:authority:</b><a href="http://www.cloudflare.com"><b>www.cloudflare.com</b></a> or the sometimes huge <b>cookie</b> headers are the usual suspects in this case.</p><p>When HPACK can't match a whole header in a dictionary, it will attempt to find a header with the same <b><i>name</i></b>. Most of the popular header names are present in the static table, for example: <b>content-encoding</b>, <b>cookie</b>, <b>etag</b>. The rest are likely to be repetitive and therefore present in the dynamic table. For example, Cloudflare assigns a unique <b>cf-ray</b> header to each response, and while the value of this field is always different, the name can be reused!</p><p>If the name was found, it can again be expressed in one or two bytes in most cases, otherwise the name will be encoded using either raw encoding or the Huffman encoding: the shorter of the two. The same goes for the value of the header.</p><p>We found that the Huffman encoding alone saves almost 30% of header size.</p><p>Although HPACK does string matching, for the attacker to find the value of a header, they must guess the entire value, instead of a gradual approach that was possible with DEFLATE matching, and was vulnerable to CRIME.</p>
    <div>
      <h4>Request Headers</h4>
      <a href="#request-headers">
        
      </a>
    </div>
    <p>The gains HPACK provides for HTTP request headers are more significant than for response headers. Request headers get better compression, due to much higher duplication in the headers. For example, here are two requests for our own blog, using Chrome:</p><h6>Request #1:</h6><p>**:authority:**blog.cloudflare.com**:method:**GET<b>:path:</b> /**:scheme:**https**accept:**text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,<i>/</i>;q=0.8**accept-encoding:**gzip, deflate, sdch, br**accept-language:**en-US,en;q=0.8<b>cookie:</b> 297 byte cookie**upgrade-insecure-requests:**1**user-agent:**Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2853.0 Safari/537.36</p><p>I marked in red the headers that can be compressed with the use of the static dictionary. Three fields: <b>:method:GET</b>, <b>:path:/</b> and <b>:scheme:https</b> are always present in the static dictionary, and will each be encoded in a single byte. Then some fields will only have their names compressed in a byte: <b>:authority</b>, <b>accept</b>, <b>accept-encoding</b>, <b>accept-language</b>, <b>cookie</b> and <b>user-agent</b> are present in the static dictionary.</p><p>Everything else, marked in green will be Huffman encoded.</p><p>Headers that were not matched, will be inserted into the dynamic dictionary for the following requests to use.</p><p>Let's take a look at a later request:</p><h6>Request #2:</h6><p><b>:authority:</b><b><b>blog.cloudflare.com</b></b>****<b>:method:</b><b><b>GET</b></b><b>:path:</b>/assets/images/cloudflare-sprite-small.png**:scheme:**https**accept:**image/webp,image/<i>,</i>/*;q=0.8**accept-encoding:**gzip, deflate, sdch, br**accept-language:**en-US,en;q=0.8**cookie:**same 297 byte cookie<b>referer:</b><a href="/assets/css/screen.css?v=2237be22c2">http://blog.cloudflare.com/assets/css/screen.css?v=2237be22c2</a>**user-agent:**Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2853.0 Safari/537.36</p><p>Here I added blue encoded fields. Those indicate fields that were matched from the dynamic dictionary. It is clear that most fields repeat between requests. In this case two fields are again present in the static dictionary and five more are repeated and therefore present in the dynamic dictionary, that means they can be encoded in one or two bytes each. One of those is the ~300 byte <b>cookie</b> header, and ~130 byte <b>user-agent</b>. That is 430 bytes encoded into mere 4 bytes, 99% compression!</p><p>All in all for the repeat request, only three short strings will be Huffman encoded.</p><p>This is how ingress header traffic appears on the Cloudflare edge network during a six hour period:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5hRafOHVmAAbUcHkXmB41S/1f601ca581a9f94fb0d8f08f2966bbc7/headers-ingress-1.png" />
            
            </figure><p>On average we are seeing a 76% compression for ingress headers. As the headers represent the majority of ingress traffic, it also provides substantial savings in the total ingress traffic:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/8J76zioOehggfZXNukjGQ/3e99553a7156092babe86efa68713333/headers-ingress-2-1.png" />
            
            </figure><p>We can see that the total ingress traffic is reduced by 53% as the result of HPACK compression!</p><p>In fact today, we process about the same number of requests for HTTP/1 and HTTP/2 over HTTPS, yet the ingress traffic for HTTP/2 is only half that of HTTP/1.</p>
    <div>
      <h3>Response Headers</h3>
      <a href="#response-headers">
        
      </a>
    </div>
    <p>For the response headers (egress traffic) the gains are more modest, but still spectacular:</p><h6>Response #1:</h6><p>**cache-control:**public, max-age=30**cf-cache-status:**HIT<b>cf-h2-pushed:</b>&lt;/assets/css/screen.css?v=2237be22c2&gt;,&lt;/assets/js/jquery.fitvids.js?v=2237be22c2&gt;**cf-ray:**2ded53145e0c1ffa-DFW**content-encoding:**gzip**content-type:**text/html; charset=utf-8**date:**Wed, 07 Sep 2016 21:41:23 GMT**expires:**Wed, 07 Sep 2016 21:41:53 GMT<b>link:</b> &lt;//cdn.bizible.com/scripts/bizible.js&gt;; rel=preload; as=script,&lt;<a href="https://code.jquery.com/jquery-1.11.3.min.js">https://code.jquery.com/jquery-1.11.3.min.js</a>&gt;; rel=preload; as=script**server:**cloudflare-nginx<b>status:200</b>**vary:**Accept-Encoding**x-ghost-cache-status:**From Cache**x-powered-by:**Express</p><p>The majority of the first response will be Huffman encoded, with some of the field names being matched from the static dictionary.</p><h6>Response #2:</h6><p>**cache-control:**public, max-age=31536000**cf-bgj:imgq:**100**cf-cache-status:**HIT<b>cf-ray</b>:2ded53163e241ffa-DFW**content-type:**image/png**date:**Wed, 07 Sep 2016 21:41:23 GMT**expires:**Thu, 07 Sep 2017 21:41:23 GMT**server:**cloudflare-nginx**status:**200**vary:**Accept-Encoding**x-ghost-cache-status:**From Cache<b>x-powered-by:Express</b></p><p>Again, the blue color indicates matches from the dynamic table, red indicate matches from the static table, and the green ones represent Huffman encoded strings.</p><p>On the second response it is possible to fully match seven of twelve headers. For four of the remaining five, the name can be fully matched, and six strings will be efficiently encoded using the static Huffman encoding.</p><p>Although the two <b>expires</b> headers are almost identical, they can only be Huffman compressed, because they can't be matched in full.</p><p>The more requests are being processed, the bigger the dynamic table becomes, and more headers can be matched, leading to increased compression ratio.</p><p>This is how egress header traffic appears on the Cloudflare edge:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7GxMxHoPdJGWpyZmqzw6lL/75874c72c47944a121e98517fba5b78b/headers-egress-1.png" />
            
            </figure><p>On average egress headers are compressed by 69%. The savings for the total egress traffic are not that significant however:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7MibXK42BowSlnSdhPGZZx/9e82b02d6c1eac9474cbb4d4e55ac919/headers-egress-2-1.png" />
            
            </figure><p>It is difficult to see, but we get 1.4% savings in the total egress HTTP/2 traffic. While it does not look like much, it is still more than <a href="/results-experimenting-brotli/">increasing the compression level for data would give</a> in many cases. This number is also significantly skewed by websites that serve very large files: we measured savings of well over 15% for some websites.</p>
    <div>
      <h3>Test your HPACK</h3>
      <a href="#test-your-hpack">
        
      </a>
    </div>
    <p>If you have nghttp2 installed, you can test the efficiency of HPACK compression on your website with a bundled tool called h2load.</p><p>For example:</p>
            <pre><code>h2load https://blog.cloudflare.com | tail -6 |head -1
traffic: 18.27KB (18708) total, 538B (538) headers (space savings 27.98%), 17.65KB (18076) data</code></pre>
            <p>We see 27.98% space savings in the headers. That is for a single request, and the gains are mostly due to the Huffman encoding. To test if the website utilizes the full power of HPACK, we need to issue two requests, for example:</p>
            <pre><code>h2load https://blog.cloudflare.com -n 2 | tail -6 |head -1
traffic: 36.01KB (36873) total, 582B (582) headers (space savings 61.15%), 35.30KB (36152) data</code></pre>
            <p>If for two similar requests the savings are 50% or more then it is very likely full HPACK compression is utilized.</p><p>Note that compression ratio improves with additional requests:</p>
            <pre><code>h2load https://blog.cloudflare.com -n 4 | tail -6 |head -1
traffic: 71.46KB (73170) total, 637B (637) headers (space savings 78.68%), 70.61KB (72304) data</code></pre>
            
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>By implementing HPACK compression for HTTP response headers we've seen a significant drop in egress bandwidth. HPACK has been enabled for all Cloudflare customers using HTTP/2, all of whom benefit from faster, smaller HTTP responses.</p> ]]></content:encoded>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[TLS]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[NGINX]]></category>
            <guid isPermaLink="false">5PbF7N0blz31qVAU014p8U</guid>
            <dc:creator>Vlad Krasnov</dc:creator>
        </item>
        <item>
            <title><![CDATA[How we brought HTTPS Everywhere to the cloud (part 1)]]></title>
            <link>https://blog.cloudflare.com/how-we-brought-https-everywhere-to-the-cloud-part-1/</link>
            <pubDate>Sat, 24 Sep 2016 15:46:26 GMT</pubDate>
            <description><![CDATA[ CloudFlare's mission is to make HTTPS accessible for all our customers. It provides security for their websites, improved ranking on search engines, better performance with HTTP/2, and access to browser features such as geolocation that are being deprecated for plaintext HTTP. ]]></description>
            <content:encoded><![CDATA[ <p>CloudFlare's mission is to make HTTPS accessible for all our customers. It provides security for their websites, <a href="https://webmasters.googleblog.com/2014/08/https-as-ranking-signal.html">improved ranking on search engines</a>, <a href="/introducing-http2/">better performance with HTTP/2</a>, and access to browser features such as geolocation that are being deprecated for plaintext HTTP. With <a href="https://www.cloudflare.com/ssl/">Universal SSL</a> or similar features, a simple button click can now enable encryption for a website.</p><p>Unfortunately, as described in a <a href="/fixing-the-mixed-content-problem-with-automatic-https-rewrites/">previous blog post</a>, this is only half of the problem. To make sure that a page is secure and can't be controlled or eavesdropped by third-parties, browsers must ensure that not only the page itself but also all its dependencies are loaded via secure channels. Page elements that don't fulfill this requirement are called mixed content and can either result in the entire page being reported as insecure or even completely blocked, thus breaking the page for the end user.</p>
    <div>
      <h2>What can we do about it?</h2>
      <a href="#what-can-we-do-about-it">
        
      </a>
    </div>
    <p>When we conceived the Automatic HTTPS Rewrites project, we aimed to automatically reduce the amount of mixed content on customers' web pages without breaking their websites and without any delay noticeable by end users while receiving a page that is being rewritten on the fly.</p><p>A naive way to do this would be to just rewrite <code>http://</code> links to <code>https://</code> or let browsers do that with <a href="https://www.w3.org/TR/upgrade-insecure-requests/"><code>Upgrade-Insecure-Requests</code></a> directive.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6YhZ5thm7SrTbeJ65wiYoT/7428a3a42d5a26fe18a57c2558012046/tumblr_inline_nyupi1faxM1qkjeen_500-1.gif" />
            
            </figure><p>Unfortunately, such approach is very fragile and unsafe unless you're sure that</p><ol><li><p>Each single HTTP sub-resource is also available via HTTPS.</p></li><li><p>It's available at the exact same domain and path after protocol upgrade (more often than you might think that's <i>not</i> the case).</p></li></ol><p>If either of these conditions is unmet, you end up rewriting resources to non-existing URLs and breaking important page dependencies.</p><p>Thus we decided to take a look at the existing solutions.</p>
    <div>
      <h2>How are these problems solved already?</h2>
      <a href="#how-are-these-problems-solved-already">
        
      </a>
    </div>
    <p>Many security aware people use the <a href="https://www.eff.org/https-everywhere">HTTPS Everywhere</a> browser extension to avoid those kinds of issues. HTTPS Everywhere contains a well-maintained database from the <a href="https://www.eff.org/">Electronic Frontier Foundation</a> that contains all sorts of mappings for popular websites that safely rewrite HTTP versions of resources to HTTPS only when it can be done without breaking the page.</p><p>However, most users are either not aware of it or are not even able to use it, for example, on mobile browsers.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4nhcIelWSXtuEWz07ilh04/054f2fc8ad7d51fea105f1778e6ccbe7/4542048705_25a394a2f3_b.jpg" />
            
            </figure><p><a href="https://creativecommons.org/licenses/by/2.0/">CC BY 2.0</a> <a href="https://www.flickr.com/photos/generated/4542048705/in/photolist-7VnbQz-9sd2LW-4EEoZv-d2T6A7-5hKfKu-8UcLHh-pBjRDg-5gCYKG-8vS5Gw-8vP6yc-bj9pgX-qaSiZi-951EJW-75Xuvx-5pft8J-eyebR1-8dyjPV-r9csMz-991WwM-a3aW4T-3JAiSH-6fGqt7-cs2ud1-nEDWYQ-bLR6yz-4JKM5j-6KMths-4eWtLa-5iij6Z-bQSzaP-dKY18j-8SU3Vr-8nGQmE-bwPWoF-323VBR-FuKadJ-p8VD7-x9knmA-hJG7Bc-3KHP4m-8YmLDZ-6CmJme-ngT44v-7ThvBy-4m9A3n-7AGkE-ogJ97T-yCChfV-ok7E25-8Nkr9w">image</a> by <a href="https://www.flickr.com/photos/generated/">Jared Tarbell</a></p><p>So we decided to flip the model around. Instead of re-writing URLs in the browser, we would re-write them inside the CloudFlare reverse proxy. By taking advantage of the existing database on the server-side, website owners could turn it on and all their users would instantly benefit from HTTPS rewriting. The fact that it’s automatic is especially useful for websites with user-generated content where it's not trivial to find and fix all the cases of inserted insecure third-party content.</p><p>At our scale, we obviously couldn't use the existing JavaScript rewriter. The performance challenges for a browser extension which can find, match and cache rules lazily as a user opens websites, are very different from those of a CDN server that handles millions of requests per second. We usually don't get a chance to rewrite them before they hit the cache either, as many pages are dynamically generated on the origin server and go straight through us to the client.</p><p>That means, to take advantage of the database, we needed to learn how the existing implementation works and create our own in the form of a native library that could work without delays under our load. Let's do the same here.</p>
    <div>
      <h2>How does HTTPS Everywhere know what to rewrite?</h2>
      <a href="#how-does-https-everywhere-know-what-to-rewrite">
        
      </a>
    </div>
    <p>HTTPS Everywhere rulesets can be found in <a href="https://github.com/EFForg/https-everywhere/tree/master/src/chrome/content/rules"><code>src/chrome/content/rules</code></a> folder of the <a href="https://github.com/EFForg/https-everywhere">official repository</a>. They are organized as XML files, each for their own set of hosts (with few exclusions). This allows users with basic technical skills to write and contribute missing rules to the database on their own.</p><p>Each ruleset is an XML file of the following structure:</p>
            <pre><code>&lt;ruleset name="example.org"&gt;
  &lt;!-- Target domains --&gt;
  &lt;target host="*.example.org" /&gt;
 
  &lt;!-- Exclusions --&gt;
  &lt;exclusion pattern="^http://example\.org/i-am-http-only" /&gt;
 
  &lt;!-- Rewrite rules --&gt;
  &lt;rule from="^http://(www\.)?example\.org/" to="https://$1example.org/" /&gt;
&lt;/ruleset&gt;</code></pre>
            <p>At the moment of writing, the HTTPS Everywhere database consists of ~22K such rulesets covering ~113K domain wildcards with ~32K rewrite rules and exclusions.</p><p>For performance reasons, we can't keep all those ruleset XMLs in memory, go through nodes, check each wildcard, perform replacements based on specific string format and so on. All that work would introduce significant delays in page processing and increase memory consumption on our servers. That's why we had to perform some compile-time tricks for each type of node to ensure that rewriting is smooth and fast for any user from the very first request.</p><p>Let's walk through those nodes and see what can be done in each specific case.</p>
    <div>
      <h3>Target domains</h3>
      <a href="#target-domains">
        
      </a>
    </div>
    <p>First of all, we get target elements which describe domain wildcards that current ruleset potentially covers.</p>
            <pre><code>&lt;target host="*.example.org" /&gt;</code></pre>
            <p>If a wildcard is used, it can be <a href="https://www.eff.org/https-everywhere/rulesets#wildcard-targets">either left-side or right-side</a>.</p><p>Left-side wildcard like <code>*.example.org</code> covers any hostname which has example.org as a suffix - no matter how many subdomain levels you have.</p><p>Right-side wildcard like <code>example.*</code> covers only one level instead so that subdomains with the same beginning but one unexpected domain level are not accidentally caught. For example, the Google ruleset, among others, uses the <code>google.*</code> wildcard and it should match <code>google.com</code>, <code>google.ru</code>, <code>google.es</code> etc. but not <code>google.mywebsite.com</code>.</p><p>Note that a single host can be covered by several different rulesets as wildcards can overlap, so the rewriter should be given entire database in order to find a correct replacement. Still, matching hostname allows to instantly reduce all ~22,000 rulesets to only 3-5 which we can deal with more easily.</p><p>Matching wildcards at runtime one-by-one is, of course, possible, but very inefficient with ~113K domain wildcards (and, as we noted above, one domain can match several rulesets, so we can't even bail out early). We need to find a better way.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/018PMe56SuXGqrCUnghAoJ/a864c686c92348249d570b30b35419f9/3901819627_c3908690a0_b.jpg" />
            
            </figure><p><a href="https://creativecommons.org/licenses/by/2.0/">CC BY 2.0</a> <a href="https://www.flickr.com/photos/vige/3901819627/in/photolist-6WMR3c-qqw1zU-7Gsyt1-4mQ6Sr-7GxrjW-bZTMQs-6HAcEr-58J6-pJb9qT-55o5bP-4c2bxs-4MEcWm-6yf4xg-dkdJkY-crpQwG-br8o3Y-4tXRcD-a3DzL7-nAYdFT-729Vjb-d5qcf-a59ugi-AKFWW-d2g9e5-3LQJEe-fqMVts-762EoB-4Lreh9-57pKGy-wnqcdN-99jyGb-6oAMor-8U28ub-9bYp3-92DYLM-6x8aZg-4MEcLQ-7n2QqA-8pydBi-ocFj72-fAyhG7-7B9Qwt-xxknG-d3Tk63-axF8dU-o4ALKi-grY52F-9bXtY-8KRwXd-a2syrf">image</a> by <a href="https://www.flickr.com/photos/vige/">vige</a></p><p>We use <a href="http://www.colm.net/open-source/ragel/">Ragel</a> to build fast lexers in other pieces of our code. Ragel is a state machine compiler which takes grammars and actions described with its own syntax and generates source code in a given programming language as an output. We decided to use it here too and wrote a script that generates a Ragel grammar from our set of wildcards. In turn, Ragel converts it into C code of a state machine capable of going through characters of URLs, matching hosts and invoking custom handler on each found ruleset.</p><p>This leads us to another interesting problem. At the moment of writing among 113K domain wildcards we have 4.7K that have a left wildcard and less than 200 which have a right wildcard. Left wildcards are expensive in state machines (including regular expressions) as they cause <a href="https://en.wikipedia.org/wiki/Combinatorial_explosion">DFA space explosion</a> during compilation so Ragel got stuck for more than 10 minutes without giving any result - trying to analyze all the <code>*.</code> prefixes and merge all the possible states where they can go, resulting in a complex tree.</p><p>Instead, if we choose to look from the end of the host, we can significantly simplify the state tree (as only 200 wildcards need to be checked separately now instead of 4.7K), thus reducing compile time to less than 20 seconds.</p><p>Let's take an oversimplified example to understand the difference. Say, we have following target wildcards (3 left-wildcards against 1 right-wildcard and 1 simple host):</p>
            <pre><code>&lt;target host="*.google.com" /&gt;
&lt;target host="*.google.co.uk" /&gt;
&lt;target host="*.google.es" /&gt;
&lt;target host="google.*" /&gt;
&lt;target host="google.com" /&gt;</code></pre>
            <p>If we build Ragel state machine directly from those:</p>
            <pre><code>%%{
    machine hosts;
 
    host_part = (alnum | [_\-])+;
 
    main := (
        any+ '.google.com' |
        any+ '.google.co.uk' |
        any+ '.google.es' |
        'google.' host_part |
        'google.com.ua'
    );
}%%</code></pre>
            <p>We will get the following state graph:</p>
            <figure>
            <a href="http://staging.blog.mrk.cfdata.org/content/images/2016/09/1.png">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1sykJ6ByovKV68tzpCF5zn/7fe8636ec9e22c152e6e8e83e007509a/1.png" />
            </a>
            </figure><p>You can see that the graph is already pretty complex as each starting character, even <code>g</code> which is an explicit starting character of <code>'google.'</code> and <code>'google.com'</code> strings, still needs to simultaneously go also into <code>any+</code> matches. Even when you have already parsed the <code>google.</code> part of the host name, it can still correctly match any of the given wildcards whether as <code>google.google.com</code>, <code>google.google.co.uk</code>, <code>google.google.es</code>, <code>google.tech</code> or <code>google.com.ua</code>. This already blows up the complexity of the state machine, and we only took an oversimplified example with three left wildcards here.</p><p>However, if we simply reverse each rule in order to feed the string starting from the end:</p>
            <pre><code>%%{
    machine hosts;
 
    host_part = (alnum | [_\-])+;
 
    main := (
        'moc.elgoog.' |
        'ku.oc.elgoog.' |
        'se.elgoog.' |
        host_part '.elgoog' |
        'au.moc.elgoog'
    );
}%%</code></pre>
            <p>we can get much simpler graph and, consequently, significantly reduced graph build and matching times:</p>
            <figure>
            <a href="http://staging.blog.mrk.cfdata.org/content/images/2016/09/2.png">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6NfYuIYypMQPvlSOkk40so/e44c0007f0c2d621e5d755cb2e3ad099/2.png" />
            </a>
            </figure><p>So now, all that we need is to do is to go through the host part in the URL, stop on <code>/</code> right after and start the machine backwards from this point. There is no need to waste time with in-memory string reversal as Ragel provides the <code>getkey</code> instruction for custom data access expressions which we can use for accessing characters in reverse order after we match the ending slash.</p><p>Here is animation of the full process:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5dcX7Zc8OH98Y9SDAIAu5E/a2cb285821563467d2ae59f365402099/third.gif" />
            
            </figure><p>After we've matched the host name and found potentially applicable rulesets, we need to ensure that we're not rewriting URLs which are not available via HTTPS.</p>
    <div>
      <h3>Exclusions</h3>
      <a href="#exclusions">
        
      </a>
    </div>
    <p>Exclusion elements serve exactly this goal.</p>
            <pre><code>&lt;exclusion pattern="^http://(www\.)?google\.com/analytics/" /&gt;
&lt;exclusion pattern="^http://(www\.)?google\.com/imgres/" /&gt;</code></pre>
            <p>The rewriter needs to test against all the exclusion patterns before applying any actual rules. Otherwise, paths that have issues or can't be served over HTTPS will be incorrectly rewritten and will potentially break the website.</p><p>We don't care about matched groups nor do we care even which particular regular expression was matched, so as an extra optimization, instead of going through them one-by-one, we merge all the exclusion patterns in the ruleset into one regular expression that can be internally optimized by a regexp engine.</p><p>For example, for the exclusions above we can create the following regular expression, common parts of which can be merged internally by a regexp engine:</p>
            <pre><code>(^http://(www\.)?google\.com/analytics/)|(^http://(www\.)?google\.com/imgres/)</code></pre>
            <p>After that, in our action we just need to call <code>pcre_exec</code> without a match data destination – we don't care about matched groups, but only about completion status. If a URL matches a regular expression, we bail out of this action as following rewrites shouldn't be applied. After this, Ragel will automatically call another matched action (another ruleset) on its own until one is found.</p><p>Finally, after we both matched the host name and ensured that our URL is not covered by any exclusion patterns, we can go to the actual rewrite rules.</p>
    <div>
      <h3>Rewrite rules</h3>
      <a href="#rewrite-rules">
        
      </a>
    </div>
    <p>These rules are presented as JavaScript regular expressions and replacement patterns. The rewriter matches the URL against each of those regular expressions as soon as a host matches and a URL is not an exclusion.</p>
            <pre><code>&lt;rule from="^http://(\w{2})\.wikipedia\.org/wiki/" to="https://secure.wikimedia.org/wikipedia/$1/wiki/" /&gt;</code></pre>
            <p>As soon as a match is found, the replacement is performed and the search can be stopped. Note: while exclusions cover dangerous replacements, it's totally possible and valid for the URL to not match any of actual rules - in that case it should be just left intact.</p><p>After the previous steps we are usually reduced only to couple of rules, so unlike in the case with exclusions, we don't apply any clever merging techniques for them. It turned out to be easier to go through them one-by-one rather than create a regexp engine specifically optimized for the case of multi-regexp replacements.</p><p>However, we don't want to waste time on regexp analysis and compilation on our edge server. This requires extra time during initialization and memory for carrying unnecessary text sources of regular expressions around. PCRE allows regular expressions to be precompiled into its own format using pcre_compile. Then, we gather all these compiled regular expressions into one binary file and link it using <code>ld --format=binary</code> - a neat option that tells linker to attach any given binary file as a named data resource available to the application.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4oBelLGyvi8KGq7mQmTvFK/e5356dd36c37b29aa1fefccca167e43a/15748968831_9d97f7167f_z.jpg" />
            
            </figure><p><a href="https://creativecommons.org/licenses/by/2.0/">CC BY 2.0</a> <a href="https://www.flickr.com/photos/sidelong/15748968831/in/photolist-pZFzKn-nCgsND-5kmFQB-bm5Ny4-3qR9NP-NfYDG-e7AwCH-eqqc2o-e3DgoN-6ZcGVn-pkmTXn-3oT9Nj-8y4HB7-H93FUT-6pSxvu-aukZ2w-2yo3n-2fTgn7-dXH6No-nBzysU-nsnMR1-dHoz6o-zXDcxE-9G5ydk-HJPTCt-qoQnCi-zmKYcs-4vwvyV-ygPe2Q-rUH8dy-dSbR9U-sc8NEN-htr2XH-uDEHXF-ehnr4K-xDLoGG-gMbuTr-bygmuu-r26oQx-bDJmuS-7WHeZ7-o5V5nL-bn3PNf-9Fr7nQ-dbbuB6-4sGsph-77HwTg-gbA7WS-27jJRy-7xGShs">image</a> by <a href="https://www.flickr.com/photos/sidelong/">DaveBleasdale</a></p><p>The second part of the rule is the replacement pattern which uses the simplest feature of JavaScript regex replacement - number-based groups and has the form of <code>https://www.google.com.$1/</code> which means that the resulting string should be concatenation of <code>"https://www.google.com."</code> with the matched group at position <code>1</code>, and a <code>"/"</code>.</p><p>Once again, we don't want to waste time performing repetitive analysis looking for dollar signs and converting string indexes to numeric representation at runtime. Instead, it's more efficient to split this pattern at compile-time into <code>{ "https://www.google.com.", "/" }</code> static substrings plus an array of indexes which need to be inserted in between - in our case just <code>{ 1 }</code>. Then, at runtime, we simply build a string going through both arrays one-by-one and concatenating strings with found matches.</p><p>Finally, after such string is built, it's inserted in place of the previous attribute value and sent to the client.</p>
    <div>
      <h3>Wait, but what about testing?</h3>
      <a href="#wait-but-what-about-testing">
        
      </a>
    </div>
    <p>Glad you asked.</p><p>The HTTPS Everywhere extension uses an automated checker that checks the validity of rewritten URLs on any change in ruleset. In order to do that, rulesets are required to contain special test elements that cover all the rewrite rules.</p>
            <pre><code>&lt;test url="http://maps.google.com/" /&gt;</code></pre>
            <p>What we need to do on our side is to collect those test URLs, combined with our own auto-generated tests from wildcards, and to invoke both the HTTPS Everywhere built-in JavaScript rewriter and our own side-by-side to ensure that we're getting same results — URLs that should be left intact, are left intact with our implementation and URLs that are rewritten, are rewritten identically.</p>
    <div>
      <h2>Can we fix even more mixed content?</h2>
      <a href="#can-we-fix-even-more-mixed-content">
        
      </a>
    </div>
    <p>After all this was done and tested, we decided to look around for other potential sources of guaranteed rewrites to extend our database.</p><p>And one such is <a href="https://hstspreload.appspot.com/">HSTS preload list</a> maintained by Google and used by all the major browsers. This list allows website owners who want to ensure that their website is never loaded via <code>http://</code>, to submit their hosts (optionally together with subdomains) and this way opt-in to auto-rewrite of any <code>http://</code> references to <code>https://</code> by a modern browser before even hitting the origin.</p><p>This means, the origin guarantees that the HTTPS version will be always available and will serve just the same content as HTTP - otherwise any resources referenced from it will simply break as the browser won't attempt to fallback to HTTP after domain is in the list. A perfect match for another ruleset!</p><p>As we already have a working solution and don't have any complexities around regular expressions in this list, we can download the JSON version of it <a href="https://chromium.googlesource.com/chromium/src/net/+/master/http/transport_security_state_static.json">directly from the Chromium source</a> and convert to the same XML ruleset with wildcards and exclusions that our system already understands and handles, as part of the build process.</p><p>This way, both databases are merged and work together, rewriting even more URLs on customer websites without any major changes to the code.</p>
    <div>
      <h2>That was quite a trip</h2>
      <a href="#that-was-quite-a-trip">
        
      </a>
    </div>
    <p>It was... but it's not really the end of the story. You see, in order to provide safe and fast rewrites for everyone, and after analyzing the alternatives, we decided to write a new streaming HTML5 parser that became the core of this feature. We intend to use it for even more tasks in future to ensure that we can improve security and performance of our customers websites in even more ways.</p><p>However, it deserves a separate blog post, so stay tuned.</p><p>And remember - if you're into web performance, security or just excited about the possibility of working on features that do not break millions of pages every second - we're <a href="https://www.cloudflare.com/join-our-team/">hiring</a>!</p><p>P.S. We are incredibly grateful to the folks at the EFF who created the HTTPS Everywhere extension and worked with us on this project.</p> ]]></content:encoded>
            <category><![CDATA[HTTPS]]></category>
            <category><![CDATA[Mixed Content Errors]]></category>
            <category><![CDATA[SSL]]></category>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Crypto Week]]></category>
            <guid isPermaLink="false">3Zps5SYwGYawkTGZfKjlfn</guid>
            <dc:creator>Ingvar Stepanyan</dc:creator>
        </item>
        <item>
            <title><![CDATA[Opportunistic Encryption: Bringing HTTP/2 to the unencrypted web]]></title>
            <link>https://blog.cloudflare.com/opportunistic-encryption-bringing-http-2-to-the-unencrypted-web/</link>
            <pubDate>Wed, 21 Sep 2016 15:51:28 GMT</pubDate>
            <description><![CDATA[ Encrypting the web is not an easy task. Various complexities prevent websites from migrating from HTTP to HTTPS, including mixed content, which can prevent sites from functioning with HTTPS.  ]]></description>
            <content:encoded><![CDATA[ <p>Encrypting the web is not an easy task. Various complexities prevent websites from migrating from HTTP to HTTPS, including mixed content, which can prevent sites from functioning with HTTPS.</p><p>Opportunistic Encryption provides an additional level of security to websites that have not yet moved to HTTPS and the performance benefits of HTTP/2. Users will not see a security indicator for HTTPS in the address bar when visiting a site using Opportunistic Encryption, but the connection from the browser to the server is encrypted.</p><p>In December 2015, CloudFlare introduced <a href="https://www.cloudflare.com/http2/">HTTP/2</a>, the latest version of HTTP, that can result in improved performance for websites. HTTP/2 can’t be used without encryption, and before now, that meant HTTPS. Opportunistic Encryption, based on an <a href="http://httpwg.org/http-extensions/draft-ietf-httpbis-http2-encryption.html">IETF draft</a>, enables servers to accept HTTP requests over an encrypted connection, allowing HTTP/2 connections for non-HTTPS sites. This is a first.</p><p>Combined with <a href="/introducing-tls-1-3/">TLS 1.3</a> and <a href="/announcing-support-for-http-2-server-push-2/">HTTP/2 Server Push</a>, Opportunistic Encryption can result in significant performance gains, while also providing security benefits.</p><p>Opportunistic Encryption is now available to all CloudFlare customers, enabled by default for Free and Pro plans. The option is available in the Crypto tab of the CloudFlare dashboard:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/53Z7Qo7rd4AQlJC0kikjXS/6323937c3bdbbe82b69abf176dc467fb/Screen-Shot-2016-09-21-at-16.19.03.png" />
            
            </figure>
    <div>
      <h3>How it works</h3>
      <a href="#how-it-works">
        
      </a>
    </div>
    <p>Opportunistic Encryption uses <a href="http://httpwg.org/http-extensions/alt-svc.html">HTTP Alternative Services</a>, a mechanism that allows servers to tell clients that the service they are accessing is available at another network location or over another protocol. When a supporting browser makes a request to a CloudFlare site with Opportunistic Encryption enabled, CloudFlare adds an Alternative Service header to indicate that the site is available over HTTP/2 (or SPDY) on port 443.</p><p>For customers with HTTP/2 enabled:</p>
            <pre><code>Alt-Svc: h2=”:443”; ma=60</code></pre>
            <p>For customers with HTTP/2 disabled:</p>
            <pre><code>Alt-Svc: spdy/3.1=”:443”; ma=60</code></pre>
            <p>This header simply states that the domain can be authoritatively accessed using HTTP/2 (“h2”) or SPDY 3.1 (“spdy/3.1”) at the same network address, over port 443 (the standard HTTPS port). The field “ma” (max-age) indicates how long in seconds the client should remember the existence of the alternative service.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2QNLkeEtnUSqIk1sg0yDZn/3eb1c11409ba9f950127ffaba673447e/2829700354_4cb63ac45e_b.jpg" />
            
            </figure><p><a href="https://creativecommons.org/licenses/by-sa/2.0/">CC BY-SA 2.0</a> <a href="https://www.flickr.com/photos/jabberwocky381/2829700354/in/photolist-5j3Xk9-9ozwgL-CyXzMW-b9NypP-af3UAc-c5VG2j-7tCoKg-8iRnKw-4F2xWk-4F6MDS-g5xKwj-6t8Gpg-e7gmMh-ahbP86-aheB15-aheAzE-8ucqdq-aheBcf-DETnGc-8ogV2T-9PNooC-9PKwkx-9PNots-2hpkp-F3qYFL-xdQqLr-9PKwe2-9PKwhT-Fe87Tv-Fe88gK-GnUy7Z-HigQiP-H9VVcS-HigRaP-H9VUFw-HigQPZ-H9VVdy-H9VUA1-H9VV9W-HigPYR-H9VULm-HigRat-HigQUt-H9VVRC-HigQXV-HigQxg-H9VV6u-H9VUuQ-frEFs1-HfkgMN">image</a> by <a href="https://www.flickr.com/photos/jabberwocky381/">Evan Jackson</a></p><p>When Firefox (or any other browser that supports Opportunistic Encryption) receives an “h2” Alt-Svc header, it knows that the site is available using HTTP/2 over TLS on port 443. For any subsequent HTTP requests to that domain, the browser will connect using TLS on port 443, where the server will present a certificate for the domain signed by a trusted certificate authority. The browser will then validate the certificate. If the connection succeeds, the browser will send the requests over that connection using HTTP/2.</p><p>Opportunistically requests will contain “http” in the<a href="https://http2.github.io/http2-spec/#HttpRequest"><code>:scheme</code> pseudo-header</a> instead of “https”. From a bit-on-the-wire perspective, this pseudo-header is the only difference between HTTP requests with Opportunistic Encryption over TLS and HTTPS. However, there is a big difference between how browsers treat assets fetched using HTTP vs. HTTPS URLs (as discussed below). </p><p>HTTP Alternative Services is a relatively new but widely used mechanism. For example, Alt-Svc is used by Google to advertise support for their experimental transport protocol, <a href="https://www.chromium.org/quic">QUIC</a>, to browsers in much the same way as we use it to advertise support for Opportunistic Encryption.</p>
    <div>
      <h2>Why not just use HTTPS?</h2>
      <a href="#why-not-just-use-https">
        
      </a>
    </div>
    <p>CloudFlare enables HTTPS by default for customers on <a href="https://www.cloudflare.com/plans/">all plans</a> using Universal SSL. However, some sites choose to continue to allow access to their sites via unencrypted HTTP. The main reason for this is mixed content. If a site contains references to HTTP images, or makes requests to HTTP URLs via embedded scripts, browsers will present warnings or even block requests outright, often breaking the functionality of the site.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/53q02AwHvDVUSNdgdmG2eX/2927aaaf2f4df9cebf7a6fcf4549c837/16467022408_789bc66bfb_z.jpg" />
            
            </figure><p><a href="https://creativecommons.org/licenses/by/2.0/">CC BY 2.0</a> <a href="https://www.flickr.com/photos/blondinrikard/16467022408/in/photolist-r68N4s-wdqoLL-wL6trG-vTynKb-vTyjDm-wbh17E-wawCrA-vw2iz8-wbofNT-w8RLP5-wboR8p-wscuys-wbgUu9-wPHQUT-wtmaGV-wsdj2U-wbo7Fv-wbgW9m-wtm9RM-wbgfb3-wqyuDm-wboXM6-wbp7jX-wsTgrP-wbALUc-wujVgK-vea2uj-wscmum-veiEag-vea12j-veiFGV-wbgLWS-wbaXWX-veiH66-wqznYf-vea193-vTyvb1-wucvcL-AKwG91-wbaZmk-vTFwsg-vTynJC-wucAZE-wawzEJ-AKCQWi-wawoMm-wbaWhV-wbaVVH-wbb8hv-wujW96">image</a> by <a href="https://www.flickr.com/photos/blondinrikard/">Blondinrikard Fröberg</a></p><p>Making sure a site can be fully migrated to HTTPS can be a manual and time-consuming process. It can require someone to manually inspect every page on a site or set up a <a href="https://content-security-policy.com/">Content Security Policy (CSP)</a> reporting infrastructure, a complex task. Even after all this work, fixing mixed content issues may require changes in middleware or content management software that can’t be easily updated. Later this week, we’ll introduce Automatic HTTPS Rewrites, which helps fix mixed content for many sites, but not all. Some mixed content can’t be fixed because the included third party resources (such as ads) that are not available over HTTPS. Websites that can’t update fully to HTTPS will benefit most from Opportunistic Encryption.</p><p>With Opportunistic Encryption, supporting browsers can choose to access an HTTP site using HTTP/2 over an encrypted connection instead of HTTP/1.1 over plaintext (the default).</p>
    <div>
      <h2>Security Benefits</h2>
      <a href="#security-benefits">
        
      </a>
    </div>
    <p>It’s no secret that network operators have access to the data that travels through their equipment. This access can be used to modify data: ISPs have been caught injecting unwanted data (<a href="http://arstechnica.com/tech-policy/2013/04/how-a-banner-ad-for-hs-ok/">such as advertisements</a> and <a href="http://www.theverge.com/2016/3/7/11173010/verizon-supercookie-fine-1-3-million-fcc">tracking cookies</a>) into unencrypted requests. Countries <a href="https://en.wikipedia.org/wiki/Internet_censorship_in_India">routinely filter content</a> by inspecting HTTP headers in unencrypted traffic, and <a href="https://citizenlab.org/2015/04/chinas-great-cannon/">China’s Great Cannon</a> injected malicious code into unencrypted websites. Access to data in transit can also be used to perform dragnet surveillance, where vast swaths of data is collected and then <a href="https://www.theguardian.com/commentisfree/2013/jul/15/crux-nsa-collect-it-all">shipped to a central location for analysis</a>.</p><p>Opportunistic Encryption does not fully protect against attackers who can simply remove the header that signals support for Opportunistic Encryption to the browser. However, once an opportunistically encrypted connection is established all requests sent over the connection are encrypted and cannot be read (or modified) by prying eyes.</p>
    <div>
      <h2>Terminology is hard</h2>
      <a href="#terminology-is-hard">
        
      </a>
    </div>
    <p>Tim Berners-Lee initiated the development of HTTP in the late 1980s to facilitate the transfer of documents from servers to clients. Both websites and browsers were rudimentary compared to the today’s web ecosystem. The concept of web security was practically non-existent.</p><p>From <a href="https://www.w3.org/History/1989/proposal.html">the original 1989 paper</a>:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2HwLp3ipQLBPQrABrqkM2/35384da5c3bdc5791949e85c1e5cb50c/Screen-Shot-2016-09-21-at-16.47.03.png" />
            
            </figure><p>As the use cases of the web expanded to include sensitive data transactions, some security was needed. Multiple encryption schemes were developed to help secure HTTP, including <a href="http://www.homeport.org/~adam/shttp.html">S-HTTP</a> and the eventual winner, HTTPS.</p><p>Originally, the difference between HTTP and HTTPS was one of layering. In HTTP, messages were written to the network directly, and in HTTPS, a secure connection was established between the client and server using SSL (an encryption and authentication protocol), and standard HTTP messages were written to the encrypted connection. Browsers signaled HTTP websites with an open lock icon, whereas HTTPS websites received a closed lock. Later, SSL evolved into TLS, although people sometimes <a href="https://www.google.com/trends/explore?q=ssl,tls,https">still refer to it as SSL</a>.</p><p>As websites became much more complex, embedded scripts and dynamic content became commonplace. Serving insecure content on a secure web page was identified as a risk and HTTPS started to take on a more nuanced meaning. Rather than just HTTP on an encrypted connection, HTTPS meant secure HTTP. For example, cookies became a popular way to store state in the client for managing web sessions. Cookies obtained over a secure connection were not allowed to be sent over insecure HTTP or modified by data obtained over HTTP. New privacy-sensitive features now require HTTPS (such as the <a href="https://developers.google.com/web/updates/2016/04/geolocation-on-secure-contexts-only">Location API</a>). This distinction between HTTP and HTTPS has been further codified by the W3C, the standards body in charge of the web, in their <a href="https://w3c.github.io/webappsec-secure-contexts/">Secure Contexts</a> document.</p><p>To break it down:</p><ul><li><p>HTTP is a protocol for transferring hypertext</p></li><li><p>TLS/SSL is a protocol for encrypted communication</p></li><li><p>HTTPS is a protocol for transferring secure hypertext</p></li></ul><table><tr><td><p></p></td><td><p><b>HTTP</b></p></td><td><p><b>HTTPS</b></p></td></tr><tr><td><p>Unencrypted</p></td><td><p><b>✔️</b></p></td><td><p>❌</p></td></tr><tr><td><p>Encrypted with TLS</p></td><td><p>✔️</p></td><td><p>✔️</p></td></tr></table><p>Opportunistic Encryption is the bottom left ✔️. While only HTTPS sites are treated as secure by the browser (as indicated by a green lock security indicator), encrypted HTTP is preferable to unencrypted HTTP.</p>
    <div>
      <h2>Browser support</h2>
      <a href="#browser-support">
        
      </a>
    </div>
    <p>All versions of Firefox since Firefox 38 (May 2015) have supported Opportunistic Encryption in its original form (without certificate validation). Firefox has recently added support for certificate validation in Firefox Nightly and will support it in an upcoming official release. We believe that Opportunistic Encryption is a meaningful advance in web security. We hope that other browsers follow Firefox’s lead and enable Opportunistic Encryption.</p><p>To be clear, Opportunistic Encryption is not a replacement for HTTPS. HTTPS should always be used when both strong encryption and authentication are required. For sites that don’t have the resources to fully move to HTTPS, Opportunistic Encryption can help, providing both added security and performance. Every bit counts.</p> ]]></content:encoded>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[HTTPS]]></category>
            <category><![CDATA[TLS]]></category>
            <category><![CDATA[TLS 1.3]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Crypto Week]]></category>
            <guid isPermaLink="false">4H5mFEHNBeu1B8biX0q6UO</guid>
            <dc:creator>Nick Sullivan</dc:creator>
        </item>
    </channel>
</rss>