
<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>Sun, 05 Apr 2026 14:22:04 GMT</lastBuildDate>
        <item>
            <title><![CDATA[Trailblazing a Development Environment for Workers]]></title>
            <link>https://blog.cloudflare.com/trailblazing-a-development-environment-for-workers/</link>
            <pubDate>Fri, 03 Apr 2020 11:03:00 GMT</pubDate>
            <description><![CDATA[ When I arrived at Cloudflare for an internship in the summer of 2018, I was taken on a tour, introduced to my mentor who took me out for coffee (shoutout to Preston), and given a quick whiteboard overview of how Cloudflare works. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>When I arrived at Cloudflare for an internship in the summer of 2018, I was taken on a tour, introduced to my mentor who took me out for coffee (shoutout to Preston), and given a quick whiteboard overview of how Cloudflare works. Each of the interns would work on a small project of their own and they’d try to finish them by the end of the summer. The description of the project I was given on my very first day read something along the lines of “<a href="/real-urls-for-amp-cached-content-using-cloudflare-workers/">implementing signed exchanges in a Cloudflare Worker to fix the AMP URL attribution problem</a>,” which was a lot to take in at once. I asked so many questions those first couple of weeks. What are signed exchanges? Can I put these stickers on my laptop? What’s a Cloudflare Worker? Is there a limit to how much Topo Chico I can take from the fridge? What’s the <a href="https://blog.amp.dev/2017/02/06/whats-in-an-amp-url/">AMP URL attribution problem</a>? Where’s the bathroom?</p><p>I got the answers to all of those questions (and more!) and eventually landed a full-time job at Cloudflare. Here’s the story of my internship and working on the Workers Developer Experience team at Cloudflare.</p>
    <div>
      <h3>Getting Started with Workers in 2018</h3>
      <a href="#getting-started-with-workers-in-2018">
        
      </a>
    </div>
    <p>After doing a lot of reading, and asking a lot more questions, it was time to start coding. I set up a Cloudflare account with a Workers subscription, and was greeted with a page that looked something like this:</p><p>I was able to change the code in the text area on the left, click “Update”, and the changes would be reflected on the right — fairly self-explanatory. There was also a testing tab which allowed me to handcraft HTTP requests with different methods and custom headers. So far so good.</p><p>As my project evolved, it became clear that I needed to leave the Workers editor behind. Anything more than a one-off script tends to require JavaScript modules and multiple files. I spent some time setting up a local development environment for myself with <a href="https://npmjs.com">npm</a> and <a href="https://webpack.js.org/">webpack</a> (see, purgatory: a place or state of temporary suffering. <a href="https://www.merriam-webster.com/dictionary/purgatory">merriam-webster.com</a>).</p><p>After I finally got everything working, my iteration cycle looked a bit like this:</p><ol><li><p>Make a change to my code</p></li><li><p>Run <code>npm run build</code> (which ran webpack and bundled my code in a single script)</p></li><li><p>Open <code>./dist/worker.min.js</code> (the output from my build step)</p></li><li><p>Copy the entire contents of the built Worker to my clipboard</p></li><li><p>Switch to the Cloudflare Workers Dashboard</p></li><li><p>Paste my script into the Workers editor</p></li><li><p>Click update</p></li><li><p>Investigate the behavior of my recently modified script</p></li><li><p>Rinse and repeat</p></li></ol><p>There were two main things here that were decidedly <b>not</b> a fantastic developer experience:</p><ol><li><p>Inspecting the value of a variable by adding a console.log statement would take me ~2-3 minutes and involved lots of manual steps to perform a full rebuild.</p></li><li><p>I was unable to use familiar HTTP clients such as cURL and Postman without deploying to production. This was because the Workers Preview UI was an iframe nested in the dashboard.</p></li></ol><p>Luckily for me, Cloudflare Workers deploy globally incredibly quickly, so I could push the latest iteration of my Worker, wait just a few seconds for it to go live, and cURL away.</p>
    <div>
      <h3>A Better Workers Developer Experience in 2019</h3>
      <a href="#a-better-workers-developer-experience-in-2019">
        
      </a>
    </div>
    <p>Shortly after we shipped <a href="/announcing-amp-real-url/">AMP Real URL</a>, Cloudflare released <a href="https://github.com/cloudflare/wrangler">Wrangler</a>, the official CLI tool for developing Workers, and I was hired full time to work on it. Wrangler came with a feature that automated steps 2-7 of my workflow by running the command <code>wrangler preview</code>, which was a <i>significant</i> improvement. Running the command would build my Worker and open the browser automatically for me so I could see log messages and test out HTTP requests. That summer, our intern Matt Alonso created <code>wrangler preview --watch</code>. This command automatically updates the Workers preview window when changes are made to your code. You can read more about that <a href="/live-preview-build-and-test-workers-faster-with-wrangler-cli-1-2-0/">here</a>. This was, yet again, another improvement over my old friend <i>Build and Open and Copy and Switch Windows and Paste Forever and Ever, Amen</i>. But there was still no way that I could test my Worker with any HTTP client I wanted without deploying to production — I was still locked in to using the nested iframe.</p><p>A few months ago we decided it was time to do something about it. To the whiteboard!</p>
    <div>
      <h3>Enter <code>wrangler dev</code></h3>
      <a href="#enter-wrangler-dev">
        
      </a>
    </div>
    <p>Most web developers are familiar with developing their applications on <code>localhost</code>, and since Wrangler is written in Rust, it means we could start up a server on localhost that would handle requests to a Worker. The idea was to somehow start a server on <code>localhost</code> and then transform incoming requests and send them off to a preview session running on a Cloudflare server.</p>
    <div>
      <h3>Proof of Concept</h3>
      <a href="#proof-of-concept">
        
      </a>
    </div>
    <p>What we came up with ended up looking a little something like this — when a developer runs <code>wrangler dev</code>, do the following:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4REMjenya1591p3JRN44k7/09277c65ef8e5084b580f8876ef73149/wrangler.dev-flowchart_2x.png" />
            
            </figure><ol><li><p>Build the Worker</p></li><li><p>Upload the Worker via the Cloudflare API as a previewable Worker</p></li><li><p>The Cloudflare API takes the uploaded script and creates a preview session, and returns an access token</p></li><li><p>Start listening for incoming HTTP requests at <code>localhost:8787</code></p></li></ol><p>   <i>Top secret fact: 8787 spells out Rust on a phone numpad</i> — <i>Happy Easter!</i></p><ol><li><p>All incoming requests to <code>localhost:8787</code> are modified:</p></li></ol><ul><li><p>All headers are prepended with <code>cf-ew-raw-</code> (for instance, <code>X-Auth-Header</code> would become <code>cf-ew-raw-X-Auth-Header</code>)</p></li><li><p>The URL is changed to <code>https://rawhttp.cloudflareworkers.com/${path}</code></p></li><li><p>The Host header is changed to <code>rawhttp.cloudflareworkers.com</code></p></li><li><p>The <code>cf-ew-preview</code> header is added with the access token returned from the API in step 3</p></li></ul><ol><li><p>After sending this request, the response is modified</p></li></ol><ul><li><p>All headers not prefixed with <code>cf-ew-raw-</code> are discarded and headers with the prefix have it removed (for instance, <code>cf-ew-raw-X-Auth-Success</code> would become <code>X-Auth-Success</code>)</p></li></ul><p>The hard part here was already done — the Workers Core team had already implemented the API to support the Preview UI. We just needed to gently nudge Wrangler and the API to be the best of friends. After some investigation into Rust’s HTTP ecosystem, we settled on using the HTTP library <a href="https://hyper.rs/">hyper</a>, which I highly recommend if you’re in need of a low level HTTP library — it’s fast, correct, and the ergonomics are constantly improving. After a bit of work, we got a prototype working and carved Wrangler ❤️ Cloudflare API into the old oak tree down by <a href="https://en.wikipedia.org/wiki/Lady_Bird_Lake">Lady Bird Lake</a>.</p>
    <div>
      <h3>Usage</h3>
      <a href="#usage">
        
      </a>
    </div>
    <p>Let’s say I have a Workers script that looks like this:</p>
            <pre><code>addEventListener('fetch', event =&gt; {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  let message = "Hello, World!"
  return new Response(message)
}</code></pre>
            <p>If I created a Wrangler project with this code and ran <code>wrangler dev</code>, this is what it looked like:</p>
            <pre><code>$ wrangler dev
?  Listening on http://127.0.0.1:8787</code></pre>
            <p>In another terminal session, I could run the following:</p>
            <pre><code>$ curl localhost:8787
Hello, World!</code></pre>
            <p>It worked! Hooray!</p>
    <div>
      <h3>Just the Right Amount of Scope Creep</h3>
      <a href="#just-the-right-amount-of-scope-creep">
        
      </a>
    </div>
    <p>At this point, our initial goal was complete: any HTTP client could test out a Worker before it was deployed. However, <code>wrangler dev</code> was still missing crucial functionality. When running <code>wrangler preview</code>, it’s possible to view <code>console.log</code> output in the browser editor. This is incredibly useful for debugging Workers applications, and something with a name like <code>wrangler dev</code> should include a way to view those logs as well. “This will be easy,” I said, not yet knowing what I was signing up for. Buckle up!</p>
    <div>
      <h3>console.log, V8, and the Chrome Devtools Protocol, Oh My!</h3>
      <a href="#console-log-v8-and-the-chrome-devtools-protocol-oh-my">
        
      </a>
    </div>
    <p>My first goal was to get a <code>Hello, World!</code> message streamed to my terminal session so that developers can debug their applications using <code>wrangler dev</code>. Let’s take the script from earlier and add a <code>console.log</code> statement to it:</p>
            <pre><code>addEventListener('fetch', event =&gt; {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  let message = "Hello, World!"
  console.log(message) // this line is new
  return new Response(message)
}</code></pre>
            <p>If you’d like to follow along, you can paste that script into the editor at <a href="https://cloudflareworkers.com">cloudflareworkers.com</a> using Google Chrome.</p><p>This is what the Preview editor looks like when that script is run:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3z1nKvt6MrXFlNLph2b7kS/7180183ce4e2de323c1d6c5246f0b742/image2-4.png" />
            
            </figure><p>You can see that <code>Hello, World!</code> has been printed to the console. This may not be the most useful example, but in more complex applications logging different variables is helpful for debugging. If you’re following along, try changing <code>console.log(message)</code> to something more interesting, like <code>console.log(request.url)</code>.</p><p>The console may look familiar to you if you’re a web developer because it’s the same interface you see when you open the Developer Tools in Google Chrome. Since Cloudflare Workers is built on top of <a href="https://v8.dev/">V8</a> (more info about that <a href="https://developers.cloudflare.com/workers/about/how-it-works/">here</a> and <a href="/cloud-computing-without-containers/">here</a>), the Workers runtime is able to create a <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API">WebSocket</a> that speaks the <a href="https://chromedevtools.github.io/devtools-protocol/">Chrome Devtools Protocol</a>. This protocol allows the client (your browser, Wrangler, or anything else that supports WebSockets) to send and receive messages that contain information about the script that is running.</p><p>In order to see the messages that are being sent back and forth between our browser and the Workers runtime:</p><ol><li><p><a href="https://developers.google.com/web/tools/chrome-devtools/open">Open Chrome Devtools</a></p></li><li><p>Click the Network tab at the top of the inspector</p></li><li><p>Click the filter icon underneath the Network tab (it looks like a funnel and is nested between the cancel icon and the search icon)</p></li><li><p>Click WS to filter out all requests but WebSocket connections</p></li></ol><p>Your inspector should look like this:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3wvIrTdVQF1TzfZBc5BkRZ/783589719e14255621f7d60239049ac6/image1-4.png" />
            
            </figure><p>Then, reload the page, and select the <code>/inspect</code> item to view its messages. It should look like this:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3AX9JjU5mwVt9LvEQ4T05m/ab69695521afe2599e670d73ac625729/image4-4.png" />
            
            </figure><p>Hey look at that! We can see messages that our browser sent to the Workers runtime to enable different portions of the developer tools for this Worker, and we can see that the runtime sent back our <code>Hello, World!</code> Pretty cool!</p><p>On the Wrangler side of things, all we had to do to get started was initialize a WebSocket connection for the current Worker, and send a message with the method <code>Runtime.enable</code> so the Workers runtime would enable the <a href="https://chromedevtools.github.io/devtools-protocol/v8/Runtime">Runtime domain</a> and start sending <code>console.log</code> messages from our script.</p><p>After those initial steps, it quickly became clear that a lot more work was needed to get to a useful developer tool. There’s a lot that goes into the Chrome Devtools Inspector and most of the libraries for interacting with it are written in languages other than Rust (which we use for Wrangler). We spent a lot of time switching WebSocket libraries due to incompatibilities across operating systems (turns out TLS is hard) and <a href="https://github.com/EverlastingBugstopper/chrome-devtools-rs">implementing</a> the part of the Chrome Devtools Protocol in Rust that we needed to. There’s a lot of work that still needs to be done in order to make <code>wrangler dev</code> a top notch developer tool, but we wanted to get it into the hands of developers as quickly as possible.</p>
    <div>
      <h3>Try it Out!</h3>
      <a href="#try-it-out">
        
      </a>
    </div>
    <p><code>wrangler dev</code> is currently in alpha, and we’d love it if you could try it out! You should first check out the <a href="https://developers.cloudflare.com/workers/quickstart">Quick Start</a> and then move on to <a href="https://developers.cloudflare.com/workers/tooling/wrangler/commands/#dev-alpha-">wrangler dev</a>. If you run into issues or have any feedback, please <a href="https://github.com/cloudflare/wrangler/issues/1047">let us know</a>!</p>
    <div>
      <h3>Signing Off</h3>
      <a href="#signing-off">
        
      </a>
    </div>
    <p>I’ve come a long way from where I started in 2018 and so has the Workers ecosystem. It’s been awesome helping to improve the developer experience of Workers for future interns, internal Cloudflare teams, and of course our customers. I can’t wait to see what we do next. I have <a href="https://github.com/cloudflare/wrangler/milestone/29">some ideas</a> for <a href="https://github.com/cloudflare/wrangler/milestone/18">what’s next</a> with Wrangler, so stay posted!</p><p>P.S. Wrangler is also <a href="https://github.com/cloudflare/wrangler">open source</a>, and we are more than happy to field bug reports, feedback, and community PRs. Check out our <a href="https://github.com/cloudflare/wrangler/blob/master/CONTRIBUTING.md">Contribution Guide</a> if you want to help out!</p> ]]></content:encoded>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Internship Experience]]></category>
            <category><![CDATA[Serverless]]></category>
            <guid isPermaLink="false">5HJePHWveXoMEt1AC448LW</guid>
            <dc:creator>Avery Harnish</dc:creator>
        </item>
        <item>
            <title><![CDATA[Real URLs for AMP Cached Content Using Cloudflare Workers]]></title>
            <link>https://blog.cloudflare.com/real-urls-for-amp-cached-content-using-cloudflare-workers/</link>
            <pubDate>Tue, 13 Nov 2018 19:33:00 GMT</pubDate>
            <description><![CDATA[ As Cloudflare Workers matures, we continue to push ourselves to develop and deploy important features using them. Today, we’re excited to announce support for HTTP signed exchanges, generated by Cloudflare Workers! ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5zK61KytdjS5NqmHTcWfrX/25a160e62d1bf1058ef6b61558fe9f60/amp-share-copy_4x.png" />
            
            </figure><p>Today, we’re excited to announce our solution for arguably the biggest issue affecting Accelerated Mobile Pages (AMP): the inability to use real origin URLs when serving AMP-cached content. To allow AMP caches to serve content under its origin URL, we implemented HTTP signed exchanges, which extend authenticity and integrity to content cached and served on behalf of a publisher. This logic lives on <a href="https://www.cloudflare.com/products/cloudflare-workers/">Cloudflare Workers</a>, meaning that adding HTTP signed exchanges to your content is just a simple Workers application away. Publishers on Cloudflare can now take advantage of AMP performance and have AMP caches serve content with their origin URLs. We're thrilled to use Workers as a core component of this solution.</p><p>HTTP signed exchanges are a crucial component of the emerging Web Packaging standard, a set of protocols used to package websites for distribution through optimized delivery systems like Google AMP. This announcement comes just in time for Chrome Dev Summit 2018, where our colleague Rustam Lalkaka spoke about our efforts to advance the Web Packaging standard.</p>
    <div>
      <h3>What is Web Packaging and Why Does it Matter?</h3>
      <a href="#what-is-web-packaging-and-why-does-it-matter">
        
      </a>
    </div>
    <p>You may already see the need for Web Packaging on a daily basis. On your smartphone, perhaps you’ve searched for Christmas greens, visited 1-800-Flowers directly from Google, and have been surprised to see content served under the URL <a href="https://google.com/amp/1800flowers.com/blog/flower-facts/types-of-christmas-greens/amp">https://google.com/amp/1800flowers.com/blog/flower-facts/types-of-christmas-greens/amp</a>. This is an instance of AMP in action, where Google serves cached content so your desired web page loads faster.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6kgYK09foa4H185JC2AaO4/26c0a7ef1039fd33516c1653bb7d2f70/ezgif-noAMP.gif" />
            
            </figure><p>Visiting 1-800 Flowers through AMP without HTTP signed exchange</p><p>Google cannot serve cached content under publisher URLs for clear security reasons. To securely present content from a URL, a <a href="https://www.cloudflare.com/application-services/products/ssl/">TLS certificate</a> for its domain is required. Google cannot provide 1-800-Flowers’ certificate on the vendor’s behalf, because it does not have the corresponding private key. Additionally, Google cannot, and should not be able to, sign content using the private key that corresponds to 1-800-Flowers’ certificate.</p><p>The inability to use original content URLs with AMP posed some serious issues. First, the google.com/amp URL prefix can strip URLs of their meaning. To the frustration of publishers, their content is no longer directly attributed to them by a URL (let alone a certificate). The publisher can no longer prove the integrity and authenticity of content served on their behalf.</p><p>Second, for web browsers the lack of a publisher’s URL can call the integrity and authenticity of a cached webpage into question. Namely, there’s no clear way to prove that this response is a cached version of an actual page published by 1-800-Flowers. Additionally, cookies are managed by third-party providers like Google instead of the publisher.</p><p>Enter Web Packaging, a <a href="https://github.com/WICG/webpackage">collection of specifications</a> for “packaging” website content with information like certificates and their validity. The <a href="https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html">HTTP signed exchanges specification</a> allows third-party caches to cache and service HTTPS requests with proof of integrity and authenticity.</p>
    <div>
      <h3>HTTP Signed Exchanges: Extending Trust with Cryptography</h3>
      <a href="#http-signed-exchanges-extending-trust-with-cryptography">
        
      </a>
    </div>
    <p>In the pre-AMP days, people expected to find a webpage’s content at one definitive URL. The publisher, who owns the domain of the definitive URL, would present a visitor with a certificate that corresponds to this domain and contains a public key.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6GeUoh4OBPc3gUuywTcGAE/651a5a6638d6eef794fc9bf6462983db/step-one_4x.png" />
            
            </figure><p>The publisher would use the corresponding private key to sign a cryptographic handshake, which is used to derive shared symmetric keys that are used to encrypt the content and protect its integrity.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/39tMMzRKPaWwXidW4fxyDw/edaf20ec675376ec08c0a9069a794d02/step-2_4x.png" />
            
            </figure><p>The visitor would then receive content encrypted and signed by the shared key.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2rOJWcnNjs0ps5CFQIDvZI/60fb1846557c2f9587e4d555ce03151a/step-3_4x.png" />
            
            </figure><p>The visitor’s browser then uses the shared key to verify the response’s signature and, in turn, the authenticity and integrity of the content received.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/17OtcMYs9DYkDblDZVcQj5/54cda01c719370ebf2546ca0d3652f2d/step-4_4x.png" />
            
            </figure><p>With services like AMP, however, online content may correspond to more than one URL. This introduces a problem: while only one domain actually corresponds to the webpage’s publisher, multiple domains can be responsible for serving a webpage. If a publisher allows AMP services to cache and serve their webpages, they must be able to sign their content even when AMP caches serve it for them. Only then can AMP-cached content prove its legitimacy.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/70Tx1Lvaj6AIDzjWUJPuXi/c1d9d474af8f2e1bb50aa0a6a145a9c5/step-4-copy-4_4x.png" />
            
            </figure><p>HTTP signed exchanges directly address the problem of extending publisher signatures to services like AMP. This <a href="https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html">IETF draft</a> specifies how publishers may sign an HTTP request/response pair (an exchange). With a signed exchange, the publisher can assure the integrity and authenticity of a response to a specific request even before the client makes the request. Given a signed exchange, the publisher authorizes intermediates (like Google’s AMP Cache) to forward the exchanges; the intermediate responds to a given request with the corresponding response in the signed HTTP request/response pair. A browser can then verify the exchange signature to assert the intermediate response’s integrity and authenticity.</p><p>This is like handing out an answer key to a quiz signed by the instructor. Having a signed answer sheet is just as good as getting the answer from the teacher in real time.</p>
    <div>
      <h3>The Technical Details</h3>
      <a href="#the-technical-details">
        
      </a>
    </div>
    <p>An HTTP signed exchange is generated by the following steps.First, the publisher uses <a href="https://tools.ietf.org/id/draft-thomson-http-mice-03.txt">MICE</a> (Merkle Integrity Content Encoding) to provide a concise proof of integrity for the response included in the exchange. To start, the response is split into blocks of some record size bits long. Take, for example, a message ABCD, which is divided into record-size blocks A, B, C, and D. The first step to constructing a proof of integrity is to take the last block, D, and compute the following:</p>
            <pre><code>proof(D) = SHA-256(D || 0x0)</code></pre>
            <p>This produces proof(D). Then, all consequent proof values for blocks are computed as follows:</p>
            <pre><code>proof(C) = SHA-256(C || proof(D) || 0x1)
proof(B) = SHA-256(B || proof(C) || 0x1)
proof(A) = SHA-256(A || proof(B) || 0x1)</code></pre>
            <p>The generation of these proofs build the following tree:</p>
            <pre><code>      proof(A)
         /\
        /  \
       /    \
      A    proof(B)
            /\
           /  \
          /    \
         B    proof(C)
                /\
               /  \
              /    \
             C    proof(D)
                    |
                    |
                    D</code></pre>
            <p>As such, proof(A) is a 256-bit digest that a person who receives the real response should be able to recompute for themselves. If a recipient can recompute a tree head value identical to proof(A), they can verify the integrity of the response they received. In fact, this digest plays a similar role to the tree head of a <a href="/introducing-certificate-transparency-and-nimbus/">Merkle Tree</a>, which is recomputed and compared to the presented tree head to verify the membership of a particular node. The MICE-generated digest is stored in the Digest header of the response.</p><p>Next, the publisher serializes the headers and payloads of a request/response pair into <a href="https://tools.ietf.org/html/rfc7049">CBOR</a> (Concise Binary Object Representation). CBOR’s key-value storage is structurally similar to JSON, but creates smaller message sizes.</p><p>Finally, the publisher signs the CBOR-encoded request/response pair using the private key associated with the publisher’s certificate. This becomes the value of the sig parameter in the HTTP signed exchange.</p><p>The final HTTP signed exchange appears like the following:</p>
            <pre><code>sig=*MEUCIQDXlI2gN3RNBlgFiuRNFpZXcDIaUpX6HIEwcZEc0cZYLAIga9DsVOMM+g5YpwEBdGW3sS+bvnmAJJiSMwhuBdqp5UY=*;  
integrity="digest/mi-sha256";  
validity-url="https://example.com/resource.validity.1511128380";  
cert-url="https://example.com/oldcerts";  
cert-sha256=*W7uB969dFW3Mb5ZefPS9Tq5ZbH5iSmOILpjv2qEArmI=*;  
date=1511128380; expires=1511733180</code></pre>
            <p>Services like AMP can send signed exchanges by using a new HTTP response format that includes the signature above in addition to the original response.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/30wTgi8lZo4TnZN0nsg73U/6de57d124bdd34b656633929962221b0/step-4-copy-3_4x.png" />
            
            </figure><p>When this signature is included in an AMP-cached response, a browser can verify the legitimacy of this response. First, the browser confirms that the certificate provided in cert-url corresponds to the request’s domain and is still valid. It next uses the certificate’s public key, as well as the headers and body values of request/response pair, to check the authenticity of the signature, sig. The browser then checks the integrity of the response using the given integrity algorithm, digest/mi-sha256 (aka MICE), and the contents of the Digest header. Now the browser can confirm that a response provided by a third party has the integrity and authenticity of the content’s original publisher.</p><p>After all this behind-the-scenes work, the browser can now present the original URL of the content instead of one prefixed by google.com/amp. Yippee to solving one of AMP’s most substantial pain points!</p>
    <div>
      <h3>Generating HTTP Signed Exchanges with Workers</h3>
      <a href="#generating-http-signed-exchanges-with-workers">
        
      </a>
    </div>
    <p>From the overview above, the process of generating an HTTP signed exchange is clearly involved. What if there were a way to automate the generation of HTTP signed exchanges and have services like AMP automatically pick them up? With Cloudflare Workers… we found a way you could have your HTTP origin exchange cake and eat it too!</p><p>We have already implemented HTTP signed exchanges for one of our customers, <a href="https://www.1800flowers.com/">1-800-Flowers</a>. Code deployed in a Cloudflare Worker is responsible for fetching and generating information necessary to create this HTTP signed exchange.</p><p>This Worker works with Google AMP’s automatic caching. When Google’s search crawler crawls a site, it will ask for a signed exchange from the same URL if it initially responds with Vary: AMP-Cache-Transform. Our HTTP signed exchange Worker checks if we can generate a signed exchange and if the current document is valid AMP. If it is, that Vary header is returned. After Google’s crawler sees this Vary header in the response, it will send another request with the following two headers:</p>
            <pre><code>AMP-Cache-Transform: google
Accept: application/signed-exchange;v=b2</code></pre>
            <p>When our implementation sees these header values, it will attempt to generate and return an HTTP response with Content-Type: application/signed-exchange;v=b2.</p><p>Now that Google has cached this page with the signed exchange produced by our Worker, the requested page will appear with the publisher’s URL instead of Google’s AMP Cache URL. Success!</p><p>If you’d like to see HTTP signed exchanges in action on 1-800-Flowers, follow these steps:</p><ol><li><p>Install/open Chrome Beta for Android. (It should be version 71+).</p></li><li><p>Go to <a href="https://goo.gl/webpackagedemo">goo.gl/webpackagedemo</a>.</p></li><li><p>Search for “Christmas greens.”</p></li><li><p>Click on the 1-800-Flowers link -- it should be about 3 spots down with the AMP icon next to it. Along the way to getting there you should see a blue box that says "Results with the AMP icon use web packaging technology." If you see a different message, double check that you are using the correct Chrome Beta.An example of AMP in action for 1-800-Flowers:</p></li></ol>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5j6PfikkSSKXgrgSRmvYFh/9af3b955be231c64435517d2466af692/ezgif-w-amp.gif" />
            
            </figure><p>Visiting 1-800 Flowers through AMP with HTTP signed exchange</p>
    <div>
      <h3>The Future: Deploying HTTP Signed Exchanges as a Worker App</h3>
      <a href="#the-future-deploying-http-signed-exchanges-as-a-worker-app">
        
      </a>
    </div>
    <p>Phew. There’s clearly a lot of infrastructure for publishers to build for distributing AMP content. Thankfully Cloudflare has <a href="https://www.cloudflare.com/network/">one of the largest networks in the world</a>, and we now have the ability to execute JavaScript at the edge with <a href="https://www.cloudflare.com/network/">Cloudflare Workers</a>. We have developed a prototype Worker that generates these exchanges, on the fly, for any domain. If you’d like to start experimenting with signed exchanges, <a href="https://www.cloudflare.com/website-optimization/ampersand/">we’d love to talk</a>!</p><p>Soon, we will release this as a Cloudflare Worker application to our AMP customers. We’re excited to bring a better AMP experience to internet users and advance the Web Packaging standard. Stay tuned!</p>
    <div>
      <h3>The Big Picture</h3>
      <a href="#the-big-picture">
        
      </a>
    </div>
    <p>Web Packaging is not simply a technology that helps fix the URL for AMP pages, it’s a fundamental shift in the way that publishing works online. For the entire history of the web up until this point, publishers have relied on transport layer security (TLS) to ensure that the content that they send to readers is authentic. TLS is great for protecting communication from attackers but it does not provide any public verifiability. This means that if a website serves a specific piece of content to a specific user, that user has no way of proving that to the outside world. This is problematic when it comes to efforts to archive the web.</p><p>Services like the Internet Archive crawl websites and keep a copy of what the website returns, but who’s to say they haven’t modified it? And who’s to say that the site didn’t serve a different version of the site to the crawler than it did to a set of readers? Web Packaging fixes this issue by allowing sites to digitally sign the actual content, not just the cryptographic keys used to transport data. This subtle change enables a profoundly new ability that we never knew we needed: the ability to record and archive content on the Internet in a trustworthy way. This ability is something that is lacking in the field of online publishing. If Web Packaging takes off as a general technology, it could be the first step in creating a trusted digital record for future generations to look back on.</p><p>Excited about the future of Web Packaging and AMP? Check out <a href="https://www.cloudflare.com/website-optimization/ampersand/">Cloudflare Ampersand</a> to see how we're implementing this future.</p> ]]></content:encoded>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[JavaScript]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[AMP]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[HTTPS]]></category>
            <category><![CDATA[Mobile]]></category>
            <category><![CDATA[Programming]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">2vBadQs4BUhz2xKzJQ5Bll</guid>
            <dc:creator>Gabbi Fisher</dc:creator>
            <dc:creator>Avery Harnish</dc:creator>
        </item>
    </channel>
</rss>