
<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>Mon, 13 Apr 2026 18:07:20 GMT</lastBuildDate>
        <item>
            <title><![CDATA[A History of HTML Parsing at Cloudflare: Part 1]]></title>
            <link>https://blog.cloudflare.com/html-parsing-1/</link>
            <pubDate>Thu, 28 Nov 2019 08:44:00 GMT</pubDate>
            <description><![CDATA[ To coincide with the launch of streaming HTML rewriting functionality for Cloudflare Workers we are open sourcing the Rust HTML rewriter (LOL  HTML) used to back the Workers HTMLRewriter API. We also thought it was about time to review the history of HTML rewriting at Cloudflare. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/30jkHPpVT3WDwbmxy2U4P4/b7c107bdf8240fa50da653f3eed806bd/HTML-rewrriter_1_3x.png" />
            
            </figure><p>To coincide with the launch of streaming HTML rewriting functionality for <a href="https://workers.cloudflare.com/">Cloudflare Workers</a> we are open sourcing the Rust HTML rewriter (<a href="https://github.com/cloudflare/lol-html">LOL HTML</a>) used to back the Workers <a href="https://developers.cloudflare.com/workers/reference/apis/html-rewriter/">HTMLRewriter API</a>. We also thought it was about time to review the history of HTML rewriting at Cloudflare.</p><p>The first blog post will explain the basics of a streaming HTML rewriter and our particular requirements. We start around 8 years ago by describing the group of ‘ad-hoc’ parsers that were created with specific functionality such as to rewrite e-mail addresses or minify HTML. By 2016 the state machine defined in the HTML5 specification could be used to build a single spec-compliant HTML pluggable rewriter, to replace the existing collection of parsers. The source code for this rewriter is now public and available here: <a href="https://github.com/cloudflare/lazyhtml">https://github.com/cloudflare/lazyhtml</a>.</p><p>The second blog post will describe the next iteration of rewriter. With the launch of the edge compute platform <a href="https://workers.cloudflare.com/">Cloudflare Workers</a> we came to realise that developers wanted the same HTML rewriting capabilities with a JavaScript API. The post describes the thoughts behind a low latency streaming HTML rewriter with a CSS-selector based API. We open-sourced the Rust library as it can also be used as a stand-alone HTML rewriting/parsing library.</p>
    <div>
      <h3>What is a streaming HTML rewriter ?</h3>
      <a href="#what-is-a-streaming-html-rewriter">
        
      </a>
    </div>
    <p>A streaming HTML rewriter takes either a HTML string or byte stream input, parses it into tokens or any other structured <a href="https://en.wikipedia.org/wiki/Intermediate_representation">intermediate representation</a> (IR) - such as an <a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">Abstract Syntax Tree</a> (AST). It then performs transformations on the tokens before converting back to HTML. This provides the ability to modify, extract or add to an existing HTML document as the bytes are being processed. Compare this with a standard HTML tree parser which needs to retrieve the entire file to generate a full DOM tree. The tree-based rewriter will both take longer to deliver the first processed bytes and require significantly more memory.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/REe13uX61XBtlevdzEg50/b1398b68b2024b5a5c65f5c84d2c8589/image8.png" />
            
            </figure><p>HTML rewriter</p><p>For example; consider you own a large site with a lot of historical content that you want to now serve over HTTPS. You will quickly run into the problem of resources (images, scripts, videos) being served over HTTP. This ‘mixed content’ opens a security hole and browsers will warn or block these resources. It can be difficult or even impossible to update every link on every page of a website. With a streaming HTML rewriter you can select the URI attribute of any HTML tag and change any HTTP links to HTTPS. We built this very feature <a href="/fixing-the-mixed-content-problem-with-automatic-https-rewrites/">Automatic HTTPS rewrites</a> back in 2016 to solve mixed content issues for our customers.</p><p>The reader may already be wondering: “Isn’t this a solved problem, aren’t there many widely used open-source browsers out there with HTML parsers that can be used for this purpose?”. The reality is that writing code to run in 190+ PoPs around the world with a strict low latency requirement turns even seemingly trivial problems into complex engineering challenges.</p><p>The following blog posts will detail the journey of how starting with a simple idea of finding email addresses within an HTML page led to building an almost spec compliant HTML parser and then on to a CSS selector matching Virtual Machine. We learned a lot on this journey. I hope you find some of this as interesting as we did.</p>
    <div>
      <h2>Rewriting at the edge</h2>
      <a href="#rewriting-at-the-edge">
        
      </a>
    </div>
    <p>When rewriting content through Cloudflare we do not want to impact site performance. The balance in designing a streaming HTML rewriter is to minimise the pause in response byte flow by holding onto as little information as possible whilst retaining the ability to rewrite matching tokens.</p><p>The difference in requirements compared to an HTML parser used in a browser include:</p>
    <div>
      <h4>Output latency</h4>
      <a href="#output-latency">
        
      </a>
    </div>
    <p>For browsers, the Document Object Model (DOM) is the end product of the parsing process but in our case we have to parse, rewrite and serialize back to HTML. In the case of Cloudflare’s reverse proxy any content processing on the edge server results in latency between the server and an eyeball. It is desirable to minimize the latency impact of HTML handling, which involves parsing, rewriting and serializing back to HTML. In all of these stages we want to be as fast as possible to minimize latency.</p>
    <div>
      <h4>Parser throughput</h4>
      <a href="#parser-throughput">
        
      </a>
    </div>
    <p>Let’s assume that usually browsers rarely need to deal with HTML pages bigger than 1Mb in size and an average page load time is somewhere around 3s at best. HTML parsing is not the main bottleneck of the page loading process as the browser will be blocked on running scripts and loading other render-critical resources. We can roughly estimate that ~3Mbps is an acceptable throughput for browser’s HTML parser. At Cloudflare we have hundreds of megabytes of traffic per CPU, so we need a parser that is faster by an order of magnitude.</p>
    <div>
      <h4>Memory limitations</h4>
      <a href="#memory-limitations">
        
      </a>
    </div>
    <p>As most users must realise, browsers have the luxury of being able to consume memory. For example, this simple HTML markup when opened in a browser will consume a significant chunk of your system memory before eventually halting a browser tab (and all this memory will be consumed by the parser) :</p>
            <pre><code>&lt;script&gt;
   document.write('&lt;');
   while(true) {
      document.write('aaaaaaaaaaaaaaaaaaaaaaaa');
   }
&lt;/script&gt;</code></pre>
            <p>Unfortunately, buffering of some fraction of the input is inevitable even for streaming HTML rewriting. Consider these 2 HTML snippets:</p>
            <pre><code>&lt;div foo="bar" qux="qux"&gt;</code></pre>
            
            <pre><code>&lt;div foo="bar" qux="qux"</code></pre>
            <p>These seemingly similar fragments of HTML will be treated completely differently when encountered at the end of an HTML page. The first fragment will be parsed as a start tag and the second one will be ignored. By just seeing a `&lt;` character followed by a tag name, the parser can’t determine if it has found a start tag or not. It needs to traverse the input in the search of the closing `&gt;` to make a decision, buffering all content in between, so it can later be emitted to the consumer as a start tag token.</p><p>This requirement forces browsers to indefinitely buffer content before eventually giving up with the out-of-memory error.</p><p>In our case, we can’t afford to spend hundreds of megabytes of memory parsing a single HTML file (actual constraints are even tighter - even using a dozen kilobytes for each request would be unacceptable). We need to be much more sophisticated than other implementations in terms of memory usage and gracefully handle all the situations where provided memory capacity is insufficient to accomplish parsing.</p>
    <div>
      <h2>v0 : “Ad-hoc parsers”</h2>
      <a href="#v0-ad-hoc-parsers">
        
      </a>
    </div>
    <p>As usual with big projects, it all started pretty innocently.</p>
    <div>
      <h4>Find and obfuscate an email</h4>
      <a href="#find-and-obfuscate-an-email">
        
      </a>
    </div>
    <p>In 2010, Cloudflare decided to provide a feature that would stop popular email scrapers. The basic idea of this protection was to find and obfuscate emails on pages and later decode them back in the browser with injected JavaScript code. Sounds easy, right? You search for anything that looks like an email, encode it and then decode it with some JavaScript magic and present the result to the end-user.</p><p>However, even such a seemingly simple task already requires solving several issues. First of all, we need to define what an email is, and there is no simple answer. Even the infamous <a href="http://www.ex-parrot.com/~pdw/Mail-RFC822-Address.html">regex</a> supposedly covering the entire RFC is, in fact, outdated and incomplete as the new RFC added lots of valid email constructions, including Unicode support. Let’s not go down that rabbit hole for now and instead focus on a higher-level issue: transforming streaming content.</p><p>Content from the network comes in packets, which have to be buffered and parsed as HTTP by our servers. You can’t predict how the content will be split, which means you always need to buffer some of it because content that is going to be replaced can be present in multiple input chunks.</p><p>Let’s say we decided to go with a simple regex like `[\w.]+@[\w.]+`. If the content that comes through contains the email “<a>test@example.org</a>”, it might be split in the following chunks:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4SbMCSfBNwSI7ctqCY8ko0/ffd823fb60c086753d7d0c34f0c16a1e/image3.png" />
            
            </figure><p>In order to keep good Time To First Byte (TTFB) and consistent speed, we want to ensure that the preceding chunk is emitted as soon as we determine that it’s not interesting for replacement purposes.</p><p>The easiest way to do that is to transform our regex into a state machine, or a finite automata. While you could do that by hand, you will end up with hard-to-maintain and error-prone code. Instead, <a href="http://www.colm.net/open-source/ragel/">Ragel</a> was chosen to transform regular expressions into efficient native state machine code. Ragel doesn’t try to take care of buffering or anything other than traversing the state machine. It provides a syntax that not only describes patterns, but can also associate custom actions (code in a host language) with any given state.</p><p>In our case we can pass through buffers until we match the beginning of an email. If we subsequently find out the pattern is not an email we can bail out from buffering as soon as the pattern stops matching. Otherwise, we can retrieve the matched email and replace it with new content.</p><p>To turn our pattern into a streaming parser we can remember the position of the potential start of an email and, unless it was already discarded or replaced by the end of the current input, store the unhandled part in a permanent buffer. Then, when a new chunk comes, we can process it separately, resuming from a state Ragel remembers itself, but then use both the buffered chunk and a new one to either emit or obfuscate.</p><p>Now that we have solved the problem of matching email patterns in text, we need to deal with the fact that they need to be obfuscated on pages. This is when the first hints of HTML “parsing” were introduced.</p><p>I’ve put “parsing” in quotes because, rather than implementing the whole parser, the email filter (as the module was called) didn’t attempt to replicate the whole HTML grammar, but rather added custom Ragel patterns just for skipping over comments and tags where emails should not be obfuscated.</p><p>This was a reasonable approach, especially back in 2010 - four years before the HTML5 specification, when all browsers had their own quirks handling of HTML. However, as you can imagine, this approach did not scale well. If you’re trying to work around quirks in other parsers, you start gaining more and more quirks in your own, and then work around these too. Simultaneously, new features started to be added, which also required modifying HTML on the fly (like automatic insertion of Google Analytics script), and an existing module seemed to be the best place for that. It grew to handle more and more tags, operations and syntactic edge cases.</p>
    <div>
      <h4>Now let’s minify..</h4>
      <a href="#now-lets-minify">
        
      </a>
    </div>
    <p>In 2011, Cloudflare decided to also add minification to allow customers to speed up their websites even if they had not employed minification themselves. For that, we decided to use an existing streaming minifier - <a href="https://github.com/brianpane/jitify-core">jitify</a>. It already had NGINX bindings, which made it a great candidate for integration into the existing pipeline.</p><p>Unfortunately, just like most other parsers from that time as well as ours described above, it had its own processing rules for HTML, JavaScript and CSS, which weren’t precise but rather tried to parse content on a best-effort basis. This led to us having two independent streaming parsers that were incompatible and could produce bugs either individually or only in combination.</p>
    <div>
      <h2>v1 : "(Almost) HTML5 Spec compliant parser"</h2>
      <a href="#v1-almost-html5-spec-compliant-parser">
        
      </a>
    </div>
    <p>Over the years engineers kept adding new features to the ever-growing state machines, while fixing new bugs arising from imprecise syntax implementations, conflicts between various parsers, and problems in features themselves.</p><p>By 2016, it was time to get out of the multiple ad hoc parsers business and do things ‘the right way’.</p><p>The next section(s) will describe how we built our HTML5 compliant parser starting from the specification state machine. Using only this state machine it should have been straight-forward to build a parser. You may be aware that historically the parsing of HTML had not been entirely strict which meant to not break existing implementations the building of an actual DOM was required for parsing. This is not possible for a streaming rewriter so a simulator of the parser feedback was developed. In terms of performance, it is always better not to do something. We then describe why the rewriter can be ‘lazy’ and not perform the expensive encoding and decoding of text when rewriting HTML. The surprisingly difficult problem of deciding if a response is HTML is then detailed.</p>
    <div>
      <h4>HTML5</h4>
      <a href="#html5">
        
      </a>
    </div>
    <p>By 2016, HTML5 had defined precise syntax rules for parsing and compatibility with legacy content and custom browser implementations. It was already implemented by all browsers and many 3rd-party implementations.</p><p>The <a href="https://html.spec.whatwg.org/multipage/parsing.html">HTML5 parsing specification</a> defines basic HTML syntax in the form of a state machine. We already had experience with <a href="http://www.colm.net/open-source/ragel/">Ragel</a> for similar use cases, so there was no question about what to use for the new streaming parser. Despite the complexity of the grammar, the translation of the specification to Ragel syntax was straightforward. The code looks simpler than the formal description of the state machine, thanks to the ability to mix regex syntax with explicit transitions.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3lfOyfSPrShxKNNEw5OoF1/7c70383207caeb3741f265725bc5bbf1/image6-1.png" />
            
            </figure><p>A visualisation of a small fraction of the HTML state machine. Source: <a href="https://twitter.com/RReverser/status/715937136520916992">https://twitter.com/RReverser/status/715937136520916992</a></p>
    <div>
      <h3>HTML5 parsing requires a ‘DOM’</h3>
      <a href="#html5-parsing-requires-a-dom">
        
      </a>
    </div>
    <p>However, HTML has a history. To not break existing implementations HTML5 is specified with recovery procedures for incorrect tag nesting, ordering, unclosed tags, missing attributes and all the other possible quirks that used to work in older browsers. In order to resolve these issues, the specification expects a tree builder to drive the lexer, essentially meaning you can’t correctly tokenize HTML (split into separate tags) without a DOM.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6WiV28d2K2jxXL3TbpNJJk/2468b04ab896d5ab46721b3446ac8680/image2-2.png" />
            
            </figure><p>HTML parsing flow as defined by the specification</p><p>For this reason, most parsers don’t even try to perform streaming parsing and instead take the input as a whole and produce a document tree as an output. This is not something we could do for streaming transformation without adding significant delays to page loading.</p><p>An existing HTML5 JavaScript parser - <a href="https://github.com/inikulin/parse5">parse5</a> - had already implemented spec-compliant tree parsing using a streaming tokenizer and rewriter. To avoid having to create a full DOM the concept of a “parser feedback simulator” was introduced.</p>
    <div>
      <h4>Tree builder feedback</h4>
      <a href="#tree-builder-feedback">
        
      </a>
    </div>
    <p>As you can guess from the name, this is a module that aims to simulate a full parser’s feedback to the tokenizer, without actually building the whole DOM, but instead preserving only the required information and context necessary for correctly driving the state machine.</p><p>After rigorous testing and upstreaming a test runner to parse5, we found this technique to be suitable for the majority of even poorly written pages on the Internet, and employed it in LazyHTML.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7156cYXNTDlDNGfLV8YCrq/7edc57eb142f4daded43a653d66460fa/image7-1.png" />
            
            </figure><p>LazyHTML architecture</p>
    <div>
      <h3>Avoiding decoding - everything is ASCII</h3>
      <a href="#avoiding-decoding-everything-is-ascii">
        
      </a>
    </div>
    <p>Now that we had a streaming tokenizer working, we wanted to make sure that it was fast enough so that users didn’t notice any slowdowns to their pages as they go through the parser and transformations. Otherwise it would completely circumvent any optimisations we’d want to attempt on the fly.</p><p>It would not only cause a performance hit due to decoding and re-encoding any modified HTML content, but also significantly complicates our implementation due to multiple sources of potential encoding information required to <a href="https://html.spec.whatwg.org/multipage/parsing.html#determining-the-character-encoding">determine the character encoding</a>, including sniffing of the first 1 KB of the content.</p><p>The “living” HTML Standard specification permits only encodings defined in the <a href="https://encoding.spec.whatwg.org/">Encoding Standard</a>. If we look carefully through those encodings, as well as a remark on Character encodings section of the HTML spec, we find that all of them are ASCII-compatible with the exception of UTF-16 and ISO-2022-JP.</p><p>This means that any ASCII text will be represented in such encodings exactly as it would be in ASCII, and any non-ASCII text will be represented by bytes outside of the ASCII range. This property allows us to safely tokenize, compare and even modify original HTML without decoding or even knowing which particular encoding it contains. It is possible as all the token boundaries in HTML grammar are represented by an ASCII character.</p><p>We need to detect UTF-16 by sniffing and either decode or skip such documents without modification. We chose the latter to avoid potential security-sensitive bugs which are common with UTF-16, and because the character encoding is seen in less than 0.1% of known character encodings luckily.</p><p>The only issue left with this approach is that in most places the <a href="https://html.spec.whatwg.org/multipage/parsing.html#tokenization">HTML tokenization</a> specification requires you to replace U+0000 (NUL) characters with U+FFFD (replacement character) during parsing. Presumably, this was added as a security precaution against bugs in C implementations of old engines which could treat NUL character, encoded in ASCII / UTF-8 / ... as a 0x00 byte, as the end of the string (yay, null-terminated strings…). It’s problematic for us because U+FFFD is outside of the ASCII range, and will be represented by different sequences of bytes in different encodings. We don’t know the encoding of the document, so this will lead to corruption of the output.</p><p>Luckily, we’re not in the same business as browser vendors, and don’t worry about NUL characters in strings as much - we use “fat pointer” string representation, in which the length of the string is determined not by the position of the NUL character, but stored along with the data pointer as an integer field:</p>
            <pre><code>typedef struct {
   const char *data;
   size_t length;
} lhtml_string_t;</code></pre>
            <p>Instead, we can quietly ignore these parts of the spec (sorry!), and keep U+0000 characters as-is and add them as such to tag, attribute names, and other strings, and later re-emit to the document. This is safe to do, because it doesn’t affect any state machine transitions, but merely preserves original 0x00 bytes and delegates their replacement to the parser in the end user’s browser.</p>
    <div>
      <h3>Content type madness</h3>
      <a href="#content-type-madness">
        
      </a>
    </div>
    <p>We want to be lazy and minimise false positives. We only want to spend time parsing, decoding and rewriting actual HTML rather than breaking images or JSON. So the question is how do you decide if something is a HTML document. Can you just use the Content-Type for example ? A comment left in the source code best describes the reality.</p>
            <pre><code>/*
Dear future generations. I didn't like this hack either and hoped
we could do the right thing instead. Unfortunately, the Internet
was a bad and scary place at the moment of writing. If this
ever changes and websites become more standards compliant,
please do remove it just like I tried.
Many websites use PHP which sets Content-Type: text/html by
default. There is no error or warning if you don't provide own
one, so most websites don't bother to change it and serve
JSON API responses, private keys and binary data like images
with this default Content-Type, which we would happily try to
parse and transforms. This not only hurts performance, but also
easily breaks response data itself whenever some sequence inside
it happens to look like a valid HTML tag that we are interested
in. It gets even worse when JSON contains valid HTML inside of it
and we treat it as such, and append random scripts to the end
breaking APIs critical for popular web apps.
This hack attempts to mitigate the risk by ensuring that the
first significant character (ignoring whitespaces and BOM)
is actually `&lt;` - which increases the chances that it's indeed HTML.
That way we can potentially skip some responses that otherwise
could be rendered by a browser as part of AJAX response, but this
is still better than the opposite situation.
*/</code></pre>
            <p>The reader might think that it’s a rare edge case, however, our observations show that almost 25% of the traffic served through Cloudflare with the “text/html” content type is unlikely to be HTML.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/a7BORxQP4K6bUBa06Mr4z/fc6f1596815a90154d35f4d2bcc6b958/image9-1.png" />
            
            </figure><p>The trouble doesn’t end there: it turns out that there is a considerable amount of XML content served with the “text/html” content type which can’t be always processed correctly when treated as HTML.</p><p>Over time bailouts for binary data, JSON, AMP and correctly identifying HTML fragments leads to the content sniffing logic which can be described by the following diagram:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2aEUXB2iTqRDZIlMxwBZKQ/12b43668197625afce880c56603a7516/image4-1.png" />
            
            </figure><p>This is a good example of divergence between formal specifications and reality.</p>
    <div>
      <h3>Tag name comparison optimisation</h3>
      <a href="#tag-name-comparison-optimisation">
        
      </a>
    </div>
    <p>But just having fast parsing is not enough - we have functionality that consumes the output of the parser, rewrites it and feeds it back for the serialization. And all the memory and time constraints that we have for the parser are applicable for this code as well, as it is a part of the same content processing pipeline.</p><p>It’s a common requirement to compare parsed HTML tag names, e.g. to determine if the current tag should be rewritten or not. A naive implementation will use regular per-byte comparison which can require traversing the whole tag name. We were able to narrow this operation to a single integer comparison instruction in the majority of cases by using specially designed hashing algorithm.</p><p>The tag names of all <a href="https://html.spec.whatwg.org/multipage/semantics.html#semantics">standard HTML elements</a> contain only alphabetical ASCII characters and digits from 1 to 6 (in numbered header tags, i.e.  - ). Comparison of tag names is case-insensitive, so we only need 26 characters to represent alphabetical characters. Using the same basic idea as <a href="https://en.wikipedia.org/wiki/Arithmetic_coding">arithmetic coding</a>, we can represent each of the possible 32 characters of a tag name using just 5 bits and, thus, fit up to <i>floor(64 / 5) = 12</i> characters in a 64-bit integer which is enough for all the standard tag names and any other tag names that satisfy the same requirements! The great part is that we don’t even need to additionally traverse a tag name to hash it - we can do that as we parse the tag name consuming the input byte by byte.</p><p>However, there is one problem with this hashing algorithm and the culprit is not so obvious: to fit all 32 characters in 5 bits we need to use all possible bit combinations including 00000. This means that if the leading character of the tag name is represented with 00000 then we will not be able to differentiate between a varying number of consequent repetitions of this character.</p><p>For example, considering that ‘a’ is encoded as 00000 and ‘b’ as 00001 :</p><table>
    <tr>
    <th>Tag name</th>
    <th>Bit representation</th>
    <th>Encoded value</th>
    </tr>
    <tr>
        <td>ab</td>
        <td>00000 00001</td>
        <td>1</td>
    </tr>
    <tr>
        <td>aab</td>
        <td>00000 00000 00001</td>
        <td>1</td>
    </tr>
</table><p>Luckily, we know that HTML grammar <a href="https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state">doesn’t allow</a> the first character of a tag name to be anything except an ASCII alphabetical character, so reserving numbers from 0 to 5 (00000b-00101b) for digits and numbers from 6 to 31 (00110b - 11111b) for ASCII alphabetical characters solves the problem.</p>
    <div>
      <h3>LazyHTML</h3>
      <a href="#lazyhtml">
        
      </a>
    </div>
    <p>After taking everything mentioned above into consideration the LazyHTML (<a href="https://github.com/cloudflare/lazyhtml">https://github.com/cloudflare/lazyhtml</a>) library was created. It is a fast streaming HTML parser and serializer with a token based C-API derived from the HTML5 lexer written in Ragel. It provides a pluggable transformation pipeline to allow multiple transformation handlers to be chained together.</p><p>An example of a function that transforms `href` property of links:</p>
            <pre><code>// define static string to be used for replacements
static const lhtml_string_t REPLACEMENT = {
   .data = "[REPLACED]",
   .length = sizeof("[REPLACED]") - 1
};

static void token_handler(lhtml_token_t *token, void *extra /* this can be your state */) {
  if (token-&gt;type == LHTML_TOKEN_START_TAG) { // we're interested only in start tags
    const lhtml_token_starttag_t *tag = &amp;token-&gt;start_tag;
    if (tag-&gt;type == LHTML_TAG_A) { // check whether tag is of type &lt;a&gt;
      const size_t n_attrs = tag-&gt;attributes.count;
      const lhtml_attribute_t *attrs = tag-&gt;attributes.items;
      for (size_t i = 0; i &lt; n_attrs; i++) { // iterate over attributes
        const lhtml_attribute_t *attr = &amp;attrs[i];
        if (lhtml_name_equals(attr-&gt;name, "href")) { // match the attribute name
          attr-&gt;value = REPLACEMENT; // set the attribute value
        }
      }
    }
  }
  lhtml_emit(token, extra); // pass transformed token(s) to next handler(s)
}</code></pre>
            
    <div>
      <h3>So, is it correct and how fast is it?</h3>
      <a href="#so-is-it-correct-and-how-fast-is-it">
        
      </a>
    </div>
    <p>It is HTML5 compliant as tested against the official test suites. As part of the work several contributions were sent to the specification itself for clarification / simplification of the spec language.</p><p>Unlike the previous parser(s), it didn't bail out on any of the 2,382,625 documents from HTTP Archive, although 0.2% of documents exceeded expected bufferization limits as they were in fact JavaScript or RSS or other types of content incorrectly served with Content-Type: text/html, and since anything is valid HTML5, the parser tried to parse e.g. a&lt;b; x=3; y=4 as incomplete tag with attributes. This is very rare (and goes to even lower amount of 0.03% when two error-prone advertisement networks are excluded from those results), but still needs to be accounted for and is a valid case for bailing out.</p><p>As for the benchmarks, In September 2016 using an example which transforms the HTML spec itself (7.9 MB HTML file) by replacing every  (only that property only in those tags) to a static value. It was compared against the few existing and popular HTML parsers (only tokenization mode was used for the fair comparison, so that they don't need to build AST and so on), and timings in milliseconds for 100 iterations are the following (lazy mode means that we're using raw strings whenever possible, the other one serializes each token just for comparison):</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7BUi5lG0xlZjW0jjZuSL6S/68b1cccd68c8fe5fec844de53e80dbee/image5-1.png" />
            
            </figure><p>The results show that LazyHTML parser speeds are around an order of magnitude faster.</p><p>That concludes the first post in our series on HTML rewriters at Cloudflare. The next post describes how we built a new streaming rewriter on top of the ideas of LazyHTML. The major update was to provide an easier to use CSS selector API. It provides the back-end for the Cloudflare workers HTMLRewriter JavaScript API.</p> ]]></content:encoded>
            <category><![CDATA[Rust]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Workers Sites]]></category>
            <category><![CDATA[JavaScript]]></category>
            <guid isPermaLink="false">6ME5A32CsufvgVgNpOie59</guid>
            <dc:creator>Andrew Galloni</dc:creator>
            <dc:creator>Ingvar Stepanyan</dc:creator>
        </item>
        <item>
            <title><![CDATA[Faster script loading with BinaryAST?]]></title>
            <link>https://blog.cloudflare.com/binary-ast/</link>
            <pubDate>Fri, 17 May 2019 13:00:00 GMT</pubDate>
            <description><![CDATA[ BinaryAST is a new over-the-wire format for JavaScript that aims to speed up parsing while keeping the semantics of the original JavaScript intact. ]]></description>
            <content:encoded><![CDATA[ <p></p>
    <div>
      <h3>JavaScript Cold starts</h3>
      <a href="#javascript-cold-starts">
        
      </a>
    </div>
    <p>The <a href="https://www.cloudflare.com/application-services/products/">performance of applications</a> on the web platform is becoming increasingly bottle necked by the startup (load) time. Large amounts of JavaScript code are required to create rich web experiences that we’ve become used to. When we look at the total size of JavaScript requested on mobile devices from <a href="https://httparchive.org/reports/state-of-javascript#bytesJs">HTTPArchive</a>, we see that an average page loads 350KB of JavaScript, while 10% of pages go over the 1MB threshold. The rise of more complex applications can push these numbers even higher.</p><p>While caching helps, popular websites regularly release new code, which makes cold start (first load) times particularly important. With browsers moving to separate caches for different domains to <a href="https://sirdarckcat.blogspot.com/2019/03/http-cache-cross-site-leaks.html">prevent cross-site leaks</a>, the importance of cold starts is growing even for popular subresources served from CDNs, as they can no longer be safely shared.</p><p>Usually, when talking about the cold start performance, the primary factor considered is a raw download speed. However, on modern interactive pages one of the other big contributors to cold starts is JavaScript parsing time. This might seem surprising at first, but makes sense - before starting to execute the code, the engine has to first parse the fetched JavaScript, make sure it doesn’t contain any syntax errors and then compile it to the initial bytecode. As networks become faster, parsing and compilation of JavaScript could become the dominant factor.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5CNQyY1zmsuXVJTSwcPTWp/29c4b25ac370568c9946dfb03be196b4/desktop-without-BinJS.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7u0b1HDtALk80vk2bAnizO/b633b495ee777e1107a2a34fe62ad6d5/LowEnd-device-without-BinJS.png" />
            
            </figure><p>The device capability (CPU or memory performance) is the most important factor in the variance of JavaScript parsing times and correspondingly the time to application start. A 1MB JavaScript file <a href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/javascript-startup-optimization/">will take an order</a> of a 100 ms to parse on a modern desktop or high-end mobile device but can take over a second on an average phone  (Moto G4).</p><p><a href="https://medium.com/@addyosmani/the-cost-of-javascript-in-2018-7d8950fbb5d4">A more detailed post</a> on the overall cost of parsing, compiling and execution of JavaScript shows how the JavaScript boot time can vary on different mobile devices. For example, in the case of <a href="https://news.google.com/">news.google.com</a>, it can range from 4s on a Pixel 2 to 28s on a low-end device.</p><p>While engines continuously improve raw parsing performance, with V8 in particular <a href="https://twitter.com/mathias/status/1125096214641254400">doubling it</a> over the past year, as well as moving more things off the main thread, parsers still have to do lots of potentially unnecessary work that consumes memory, battery and might delay the processing of the useful resources.</p>
    <div>
      <h3>The “BinaryAST” Proposal</h3>
      <a href="#the-binaryast-proposal">
        
      </a>
    </div>
    <p>This is where BinaryAST comes in. BinaryAST is a new over-the-wire format for JavaScript proposed and actively developed by Mozilla that aims to speed up parsing while keeping the semantics of the original JavaScript intact. It does so by using an efficient binary representation for code and data structures, as well as by storing and providing extra information to guide the parser ahead of time.</p><p>The name comes from the fact that the format stores the JavaScript source as an AST encoded into a binary file. The specification lives at <a href="https://tc39.github.io/proposal-binary-ast/">tc39.github.io/proposal-binary-ast</a> and is being worked on by engineers from Mozilla, Facebook, Bloomberg and Cloudflare.</p><blockquote><p>“Making sure that web applications start quickly is one of the most important, but also one of the most challenging parts of web development. We know that BinaryAST can radically reduce startup time, but we need to collect real-world data to demonstrate its impact. Cloudflare's work on enabling use of BinaryAST with Cloudflare Workers is an important step towards gathering this data at scale.”</p><p>Till Schneidereit, Senior Engineering Manager, Developer TechnologiesMozilla</p></blockquote>
    <div>
      <h3>Parsing JavaScript</h3>
      <a href="#parsing-javascript">
        
      </a>
    </div>
    <p>For regular JavaScript code to execute in a browser the source is parsed into an intermediate representation known as an <a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">AST</a> that describes the syntactic structure of the code. This representation can then be compiled into a byte code or a native machine code for execution.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3DIWPcDgNpOEH6BhW3GrO5/487a787830d0b3fb4017a72a1135aaba/without-binAST.png" />
            
            </figure><p>A simple example of adding two numbers can be represented in an AST as:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4EIAsDST7S6TpVAT8F4WFU/c0d3acf3dc8971dbd3607f95329d37ce/orpmdqtF-udYY2MUOSzd8gJdsSxdABJMSubMUMfTtI47GMBNFYayHWBZH3gKf70ElJPGXBkDvIQOCmcJbGvrbsD4YKDxa8bsonVFpVOJxMZC6w0noCDH82pCMyjq.jpg" />
            
            </figure><p>Parsing JavaScript is not an easy task; no matter which optimisations you apply, it still requires reading the entire text file char by char, while tracking extra context for syntactic analysis.</p><p>The goal of the BinaryAST is to reduce the complexity and the amount of work the browser parser has to do overall by providing additional information and context by the time and place where the parser needs it.</p><p>To execute JavaScript delivered as BinaryAST the only steps required are:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6eomG3q2K9lSST6Hzsxq2R/870db1cfa20c98105a04ee4dc222e313/With-BinAST.png" />
            
            </figure><p>Another benefit of BinaryAST is that it makes possible to only parse the critical code necessary for start-up, completely skipping over the unused bits. This can dramatically improve the initial loading time.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1b2b1rL6qXh2czmgHxaxR3/06b3936abfb6b8c4b94068349d4ed131/desktop-without-BinJS-1.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3h7xWlH4bIj2DEcG9EXKSO/fd214ce71f10e2591e82d5dbc2b32af9/desktop-with-BinJS.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5QU4tWZEOZIhC534xVp9Bs/a69c99362a2881857e3a2689f0394961/LowEnd-device-without-BinJS-1.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/x0v3uvopVvmibsIJVBTXJ/5500ef41ad596746da51c2e5c6c2aabb/LowEnd-device-with-BinJS-1.png" />
            
            </figure><p>This post will now describe some of the challenges of parsing JavaScript in more detail, explain how the proposed format addressed them, and how we made it possible to run its encoder in Workers.</p>
    <div>
      <h3>Hoisting</h3>
      <a href="#hoisting">
        
      </a>
    </div>
    <p>JavaScript relies on hoisting for all declarations - variables, functions, classes. Hoisting is a property of the language that allows you to declare items after the point they’re syntactically used.</p><p>Let's take the following example:</p>
            <pre><code>function f() {
	return g();
}

function g() {
	return 42;
}</code></pre>
            <p>Here, when the parser is looking at the body of <code>f</code>, it doesn’t know yet what <code>g</code> is referring to - it could be an already existing global function or something declared further in the same file - so it can’t finalise parsing of the original function and start the actual compilation.</p><p>BinaryAST fixes this by storing all the scope information and making it available upfront before the actual expressions.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1Gfo2bgKDwFzYt4UDUAEbn/f91e9b797c2e5c8b16546e4d8fa79d73/global-scope_2x-1.png" />
            
            </figure><p>As shown by the difference between the initial AST and the enhanced AST in a JSON representation:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/73zazZkCUkmjWppTBdWMIq/00cb51447f344a037eb44cefcbc89e87/1T5U7zKHwc_PuZ7heYpDuQ5HMTQpFiqO-wmz6Vncm7ycWNe65Xvm3PvlFKAtj89vqesgymqj-H9_6-kohc6TLrRkyLwJ5PNIAEOIZSypZpQGAFWFpAIHjsAhLegG.png" />
            
            </figure>
    <div>
      <h3>Lazy parsing</h3>
      <a href="#lazy-parsing">
        
      </a>
    </div>
    <p>One common technique used by modern engines to improve parsing times is lazy parsing. It utilises the fact that lots of websites include more JavaScript than they actually need, especially for the start-up.</p><p>Working around this involves a set of heuristics that try to guess when any given function body in the code can be safely skipped by the parser initially and delayed for later. A common example of such heuristic is immediately running the full parser for any function that is wrapped into parentheses:</p>
            <pre><code>(function(...</code></pre>
            <p>Such prefix usually indicates that a following function is going to be an IIFE (immediately-invoked function expression), and so the parser can assume that it will be compiled and executed ASAP, and wouldn’t benefit from being skipped over and delayed for later.</p>
            <pre><code>(function() {
	…
})();</code></pre>
            <p>These heuristics significantly improve the performance of the initial parsing and cold starts, but they’re not completely reliable or trivial to implement.</p><p>One of the reasons is the same as in the previous section - even with lazy parsing, you still need to read the contents, analyse them and store an additional scope information for the declarations.</p><p>Another reason is that the JavaScript specification requires reporting any syntax errors immediately during load time, and not when the code is actually executed. A class of these errors, called early errors, is checking for mistakes like usage of the reserved words in invalid contexts, strict mode violations, variable name clashes and more. All of these checks require not only lexing JavaScript source, but also tracking extra state even during the lazy parsing.</p><p>Having to do such extra work means you need to be careful about marking functions as lazy too eagerly, especially if they actually end up being executed during the page load. Otherwise, you’re making cold start costs even worse, as now every function that is erroneously marked as lazy, needs to be parsed twice - once by the lazy parser and then again by the full one.</p><p>Because BinaryAST is meant to be an output format of other tools such as Babel, TypeScript and bundlers such as Webpack, the browser parser can rely on the JavaScript being already analysed and verified by the initial parser. This allows it to skip function bodies completely, making lazy parsing essentially free.</p><p>It reduces the cost of a completely unused code - while including it is still a problem in terms of the network bandwidth (don’t do this!), at least it’s not affecting parsing times any more. These benefits apply equally to the code that is used later in the page lifecycle (for example, invoked in response to user actions), but is not required during the startup.</p><p>Last but not the least important benefit of such approach is that BinaryAST encodes lazy annotations as part of the format, giving tools and developers direct and full control over the heuristics. For example, a tool targeting the Web platform or a framework CLI can use its domain-specific knowledge to mark some event handlers as lazy or eager depending on the context and the event type.</p>
    <div>
      <h3>Avoiding ambiguity in parsing</h3>
      <a href="#avoiding-ambiguity-in-parsing">
        
      </a>
    </div>
    <p>Using a text format for a programming language is great for readability and debugging, but it's not the most efficient representation for parsing and execution.</p><p>For example, parsing low-level types like numbers, booleans and even strings from text requires extra analysis and computation, which is unnecessary when you can just store and read them as native binary-encoded values in the first place and read directly on the other side.</p><p>Another problem is an ambiguity in the grammar itself. It was already an issue in the ES5 world, but could usually be resolved with some extra bookkeeping based on the previously seen tokens. However, in ES6+ there are productions that can be ambiguous all the way through until they’re parsed completely.</p><p>For example, a token sequence like:</p>
            <pre><code>(a, {b: c, d}, [e = 1])...</code></pre>
            <p>can start either a parenthesized comma expression with nested object and array literals and an assignment:</p>
            <pre><code>(a, {b: c, d}, [e = 1]); // it was an expression</code></pre>
            <p>or a parameter list of an arrow expression function with nested object and array patterns and a default value:</p>
            <pre><code>(a, {b: c, d}, [e = 1]) =&gt; … // it was a parameter list</code></pre>
            <p>Both representations are perfectly valid, but have completely different semantics, and you can’t know which one you’re dealing with until you see the final token.</p><p>To work around this, parsers usually have to either backtrack, which can easily get exponentially slow, or to parse contents into intermediate node types that are capable of holding both expressions and patterns, with following conversion. The latter approach preserves linear performance, but makes the implementation more complicated and requires preserving more state.</p><p>In the BinaryAST format this issue doesn't exist in the first place because the parser sees the type of each node before it even starts parsing its contents.</p>
    <div>
      <h3>Cloudflare Implementation</h3>
      <a href="#cloudflare-implementation">
        
      </a>
    </div>
    <p>Currently, the format is still in flux, but the very first version of the client-side implementation was released under a flag in Firefox Nightly several months ago. Keep in mind this is only an initial unoptimised prototype, and there are already several experiments changing the format to provide improvements to both size and parsing performance.</p><p>On the producer side, the reference implementation lives at <a href="https://github.com/binast/binjs-ref">github.com/binast/binjs-ref</a>. Our goal was to take this reference implementation and consider how we would deploy it at Cloudflare scale.</p><p>If you dig into the codebase, you will notice that it currently consists of two parts.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1hO4rh3KiWnZt9MSyLXmqU/2755ce821df08853758c8e8e34cc7b35/cf-implementation.png" />
            
            </figure><p>One is the encoder itself, which is responsible for taking a parsed AST, annotating it with scope and other relevant information, and writing out the result in one of the currently supported formats. This part is written in Rust and is fully native.</p><p>Another part is what produces that initial AST - the parser. Interestingly, unlike the encoder, it's implemented in JavaScript.</p><p>Unfortunately, there is currently no battle-tested native JavaScript parser with an open API, let alone implemented in Rust. There have been a few attempts, but, given the complexity of JavaScript grammar, it’s better to wait a bit and make sure they’re well-tested before incorporating it into the production encoder.</p><p>On the other hand, over the last few years the JavaScript ecosystem grew to extensively rely on developer tools implemented in JavaScript itself. In particular, this gave a push to rigorous parser development and testing. There are several JavaScript parser implementations that have been proven to work on thousands of real-world projects.</p><p>With that in mind, it makes sense that the BinaryAST implementation chose to use one of them - in particular, <a href="https://shift-ast.org">Shift</a> - and integrated it with the Rust encoder, instead of attempting to use a native parser.</p>
    <div>
      <h3>Connecting Rust and JavaScript</h3>
      <a href="#connecting-rust-and-javascript">
        
      </a>
    </div>
    <p>Integration is where things get interesting.</p><p>Rust is a native language that can compile to an executable binary, but JavaScript requires a separate engine to be executed. To connect them, we need some way to transfer data between the two without sharing the memory.</p><p>Initially, the reference implementation generated JavaScript code with an embedded input on the fly, passed it to Node.js and then read the output when the process had finished. That code contained a call to the Shift parser with an inlined input string and produced the AST back in a JSON format.</p><p>This doesn’t scale well when parsing lots of JavaScript files, so the first thing we did is transformed the Node.js side into a long-living daemon. Now Rust could spawn a required Node.js process just once and keep passing inputs into it and getting responses back as individual messages.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3rCs07kw5ldmfRx8zpvgHM/d1f258228fb9e1e6e7e4a57bdf4e47a2/Connecting-rust-java_2x.png" />
            
            </figure>
    <div>
      <h3>Running in the cloud</h3>
      <a href="#running-in-the-cloud">
        
      </a>
    </div>
    <p>While the Node.js solution worked fairly well after these optimisations, shipping both a Node.js instance and a native bundle to production requires some effort. It's also potentially risky and requires manual sandboxing of both processes to make sure we don’t accidentally start executing malicious code.</p><p>On the other hand, the only thing we needed from Node.js is the ability to run the JavaScript parser code. And we already have an isolated JavaScript engine running in the cloud - <a href="https://www.cloudflare.com/developer-platform/workers/">Cloudflare Workers</a>! By additionally compiling the native Rust encoder to Wasm (which is quite easy with the native toolchain and <a href="https://rustwasm.github.io/docs/wasm-bindgen/">wasm-bindgen</a>), we can even run both parts of the code in the same process, making cold starts and communication much faster than in a previous model.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7dMlhjj8rPxs3pjUScdbFJ/59d8373896f17b68c628416ddfa15741/V8-isolate-01_2x.png" />
            
            </figure>
    <div>
      <h3>Optimising data transfer</h3>
      <a href="#optimising-data-transfer">
        
      </a>
    </div>
    <p>The next logical step is to reduce the overhead of data transfer. JSON worked fine for communication between separate processes, but with a single process we should be able to retrieve the required bits directly from the JavaScript-based AST.</p><p>To attempt this, first, we needed to move away from the direct JSON usage to something more generic that would allow us to support various import formats. The Rust ecosystem already has an amazing serialisation framework for that - <a href="https://serde.rs/">Serde</a>.</p><p>Aside from allowing us to be more flexible in regard to the inputs, rewriting to Serde helped an existing native use case too. Now, instead of parsing JSON into an intermediate representation and then walking through it, all the native typed AST structures can be deserialized directly from the stdout pipe of the Node.js process in a streaming manner. This significantly improved both the CPU usage and memory pressure.</p><p>But there is one more thing we can do: instead of serializing and deserializing from an intermediate format (let alone, a text format like JSON), we should be able to operate [almost] directly on JavaScript values, saving memory and repetitive work.</p><p>How is this possible? wasm-bindgen provides a type called <code>JsValue</code> that stores a handle to an arbitrary value on the JavaScript side. This handle internally contains an index into a predefined array.</p><p>Each time a JavaScript value is passed to the Rust side as a result of a function call or a property access, it’s stored in this array and an index is sent to Rust. The next time Rust wants to do something with that value, it passes the index back and the JavaScript side retrieves the original value from the array and performs the required operation.</p><p>By reusing this mechanism, we could implement a Serde deserializer that requests only the required values from the JS side and immediately converts them to their native representation. It’s now open-sourced under <a href="https://github.com/cloudflare/serde-wasm-bindgen">https://github.com/cloudflare/serde-wasm-bindgen</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2KCuxugOCOU8NjfZopkygl/3933c96b0b558b48bd90bcc368f20c7b/V8-isolate-01-copy_2x.png" />
            
            </figure><p>At first, we got a much worse performance out of this due to the overhead of more frequent calls between 1) Wasm and JavaScript - SpiderMonkey has improved these recently, but other engines still lag behind and 2) JavaScript and C++, which also can’t be optimised well in most engines.</p><p>The JavaScript ↔ C++ overhead comes from the usage of <code>TextEncoder</code> to pass strings between JavaScript and Wasm in wasm-bindgen, and, indeed, it showed up as the highest in the benchmark profiles. This wasn’t surprising - after all, strings can appear not only in the value payloads, but also in property names, which have to be serialized and sent between JavaScript and Wasm over and over when using a generic JSON-like structure.</p><p>Luckily, because our deserializer doesn’t have to be compatible with JSON any more, we can use our knowledge of Rust types and cache all the serialized property names as JavaScript value handles just once, and then keep reusing them for further property accesses.</p><p>This, combined with some changes to wasm-bindgen which we have up streamed, allows our deserializer to be up to 3.5x faster in benchmarks than the original Serde support in wasm-bindgen, while saving ~33% off the resulting code size. Note that for string-heavy data structures it might still be slower than the current JSON-based integration, but situation is expected to improve over time when <a href="https://github.com/WebAssembly/reference-types">reference types</a> proposal lands natively in Wasm.</p><p>After implementing and integrating this deserializer, we used the <a href="https://github.com/wasm-tool/wasm-pack-plugin">wasm-pack plugin for Webpack</a> to build a Worker with both Rust and JavaScript parts combined and shipped it to some test zones.</p>
    <div>
      <h3>Show me the numbers</h3>
      <a href="#show-me-the-numbers">
        
      </a>
    </div>
    <p>Keep in mind that this proposal is in very early stages, and current benchmarks and demos are not representative of the final outcome (which should improve numbers much further).</p><p>As mentioned earlier, BinaryAST can mark functions that should be parsed lazily ahead of time. By using different levels of lazification in the encoder (<a href="https://github.com/binast/binjs-ref/blob/b72aff7dac7c692a604e91f166028af957cdcda5/crates/binjs_es6/src/lazy.rs#L43">https://github.com/binast/binjs-ref/blob/b72aff7dac7c692a604e91f166028af957cdcda5/crates/binjs_es6/src/lazy.rs#L43</a>) and running tests against some popular JavaScript libraries, we found following speed-ups.</p>
    <div>
      <h4>Level 0 (no functions are lazified)</h4>
      <a href="#level-0-no-functions-are-lazified">
        
      </a>
    </div>
    <p>With lazy parsing disabled in both parsers we got a raw parsing speed improvement of between 3 and 10%.</p><table><tr><td><p><b>Name</b></p></td><td><p><b>Source size (kb)</b></p></td><td><p><b>JavaScript Parse time (average ms)</b></p></td><td><p><b>BinaryAST parse time (average ms)</b></p></td><td><p><b>Diff (%)</b></p></td></tr><tr><td><p>React</p></td><td><p>20</p></td><td><p>0.403</p></td><td><p>0.385</p></td><td><p>-4.56</p></td></tr><tr><td><p>D3 (v5)</p></td><td><p>240</p></td><td><p>11.178</p></td><td><p>10.525</p></td><td><p>-6.018</p></td></tr><tr><td><p>Angular</p></td><td><p>180</p></td><td><p>6.985</p></td><td><p>6.331</p></td><td><p>-9.822</p></td></tr><tr><td><p>Babel</p></td><td><p>780</p></td><td><p>21.255</p></td><td><p>20.599</p></td><td><p>-3.135</p></td></tr><tr><td><p>Backbone</p></td><td><p>32</p></td><td><p>0.775</p></td><td><p>0.699</p></td><td><p>-10.312</p></td></tr><tr><td><p>wabtjs</p></td><td><p>1720</p></td><td><p>64.836</p></td><td><p>59.556</p></td><td><p>-8.489</p></td></tr><tr><td><p>Fuzzball (1.2)</p></td><td><p>72</p></td><td><p>3.165</p></td><td><p>2.768</p></td><td><p>-13.383</p></td></tr></table>
    <div>
      <h4>Level 3 (functions up to 3 levels deep are lazified)</h4>
      <a href="#level-3-functions-up-to-3-levels-deep-are-lazified">
        
      </a>
    </div>
    <p>But with the lazification set to skip nested functions of up to 3 levels we see much more dramatic improvements in parsing time between 90 and 97%. As mentioned earlier in the post, BinaryAST makes lazy parsing essentially free by completely skipping over the marked functions.</p><table><tr><td><p><b>Name</b></p></td><td><p><b>Source size (kb)</b></p></td><td><p><b>Parse time (average ms)</b></p></td><td><p><b>BinaryAST parse time (average ms)</b></p></td><td><p><b>Diff (%)</b></p></td></tr><tr><td><p>React</p></td><td><p>20</p></td><td><p>0.407</p></td><td><p>0.032</p></td><td><p>-92.138</p></td></tr><tr><td><p>D3 (v5)</p></td><td><p>240</p></td><td><p>11.623</p></td><td><p>0.224</p></td><td><p>-98.073</p></td></tr><tr><td><p>Angular</p></td><td><p>180</p></td><td><p>7.093</p></td><td><p>0.680</p></td><td><p>-90.413</p></td></tr><tr><td><p>Babel</p></td><td><p>780</p></td><td><p>21.100</p></td><td><p>0.895</p></td><td><p>-95.758</p></td></tr><tr><td><p>Backbone</p></td><td><p>32</p></td><td><p>0.898</p></td><td><p>0.045</p></td><td><p>-94.989</p></td></tr><tr><td><p>wabtjs</p></td><td><p>1720</p></td><td><p>59.802</p></td><td><p>1.601</p></td><td><p>-97.323</p></td></tr><tr><td><p>Fuzzball (1.2)</p></td><td><p>72</p></td><td><p>2.937</p></td><td><p>0.089</p></td><td><p>-96.970</p></td></tr></table><p>All the numbers are from manual tests on a Linux x64 Intel i7 with 16Gb of ram.</p><p>While these synthetic benchmarks are impressive, they are not representative of real-world scenarios. Normally you will use at least some of the loaded JavaScript during the startup. To check this scenario, we decided to test some realistic pages and demos on desktop and mobile Firefox and found speed-ups in page loads too.</p><p>For a sample application (<a href="https://github.com/cloudflare/binjs-demo">https://github.com/cloudflare/binjs-demo</a>, <a href="https://serve-binjs.that-test.site/">https://serve-binjs.that-test.site/</a>) which weighed in at around 1.2 MB of JavaScript we got the following numbers for initial script execution:</p><table><tr><td><p><b>Device</b></p></td><td><p><b>JavaScript</b></p></td><td><p><b>BinaryAST</b></p></td></tr><tr><td><p>Desktop</p></td><td><p>338ms</p></td><td><p>314ms</p></td></tr><tr><td><p>Mobile (HTC One M8)</p></td><td><p>2019ms</p></td><td><p>1455ms</p></td></tr></table><p>Here is a video that will give you an idea of the improvement as seen by a user on mobile Firefox (in this case showing the entire page startup time):</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6EpLne9c9yziJOCzYLUAe6/e2e1f52cece43d6557d4728a17463a2e/binast.gif" />
            
            </figure><p>Next step is to start gathering data on real-world websites, while improving the underlying format.</p>
    <div>
      <h3>How do I test BinaryAST on my website?</h3>
      <a href="#how-do-i-test-binaryast-on-my-website">
        
      </a>
    </div>
    <p>We’ve open-sourced our Worker so that it could be installed on any Cloudflare zone: <a href="https://github.com/binast/binjs-ref/tree/cf-wasm">https://github.com/binast/binjs-ref/tree/cf-wasm</a>.</p><p>One thing to be currently wary of is that, even though the result gets stored in the cache, the initial encoding is still an expensive process, and might easily hit CPU limits on any non-trivial JavaScript files and fall back to the un-encoded variant. We are working to improve this situation by releasing BinaryAST encoder as a separate feature with more relaxed limits in the following few days.</p><p>Meanwhile, if you want to play with BinaryAST on larger real-world scripts, an alternative option is to use a static <code>binjs_encode</code> tool from <a href="https://github.com/binast/binjs-ref">https://github.com/binast/binjs-ref</a> to pre-encode JavaScript files ahead of time. Then, you can use a Worker from <a href="https://github.com/cloudflare/binast-cf-worker">https://github.com/cloudflare/binast-cf-worker</a> to serve the resulting BinaryAST assets when supported and requested by the browser.</p><p>On the client side, you’ll currently need to download <a href="https://www.mozilla.org/en-US/firefox/channel/desktop/#nightly">Firefox Nightly</a>, go to <code>about:config</code> and enable unrestricted BinaryAST support via the following options:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6HbSv4S41klPC6XblrjxEd/cb9d147f349a29cd84e9d6127327efb2/sFlcLvgSb04T7bAtR8cF7Blnkn7pvQhswCjynrLIpUDtVBBnY0VVg3Bu5v1CCWG_dvjHcGXUvMyJpGr2Nf4wag1Kd381l1OQbZpQmFZmvNq15vsieMC4m5ShEZU8.png" />
            
            </figure><p>Now, when opening a website with either of the Workers installed, Firefox will get BinaryAST instead of JavaScript automatically.</p>
    <div>
      <h3>Summary</h3>
      <a href="#summary">
        
      </a>
    </div>
    <p>The amount of JavaScript in modern apps is presenting performance challenges for all consumers. Engine vendors are experimenting with different ways to improve the situation - some are focusing on raw decoding performance, some on parallelizing operations to reduce overall latency, some are researching new optimised formats for data representation, and some are inventing and improving protocols for the network delivery.</p><p>No matter which one it is, we all have a shared goal of making the Web better and faster. On Cloudflare's side, we're always excited about collaborating with all the vendors and combining various approaches to make that goal closer with every step.</p> ]]></content:encoded>
            <category><![CDATA[Speed Week]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[JavaScript]]></category>
            <guid isPermaLink="false">5WBO0SkrdMzVGxax4hM6pS</guid>
            <dc:creator>Ingvar Stepanyan</dc:creator>
        </item>
        <item>
            <title><![CDATA[Building fast interpreters in Rust]]></title>
            <link>https://blog.cloudflare.com/building-fast-interpreters-in-rust/</link>
            <pubDate>Mon, 04 Mar 2019 16:00:00 GMT</pubDate>
            <description><![CDATA[ In the previous post we described the Firewall Rules architecture and how the different components are integrated together. We created a configurable Rust library for writing and executing Wireshark®-like filters in different parts of our stack written in Go, Lua, C, C++ and JavaScript Workers. ]]></description>
            <content:encoded><![CDATA[ <p>In the <a href="/how-we-made-firewall-rules/">previous post</a> we described the Firewall Rules architecture and how the different components are integrated together. We also mentioned that we created a configurable Rust library for writing and executing <a href="https://www.wireshark.org/">Wireshark</a>®-like filters in different parts of our stack written in Go, Lua, C, C++ and JavaScript Workers.</p><blockquote><p>With a mixed set of requirements of performance, memory safety, low memory use, and the capability to be part of other products that we’re working on like Spectrum, Rust stood out as the strongest option.</p></blockquote>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3emjeRzzAw9z6ipj1FIjoD/fbfb5538cf10d6a5f0c096676dabfa63/Langs.png" />
            
            </figure><p>We have now open-sourced this library under our Github account: <a href="https://github.com/cloudflare/wirefilter">https://github.com/cloudflare/wirefilter</a>. This post will dive into its design, explain why we didn’t use a parser generator and how our execution engine balances security, runtime performance and compilation cost for the generated filters.</p>
    <div>
      <h3>Parsing Wireshark syntax</h3>
      <a href="#parsing-wireshark-syntax">
        
      </a>
    </div>
    <p>When building a custom Domain Specific Language (DSL), the first thing we need to be able to do is parse it. This should result in an intermediate representation (usually called an Abstract Syntax Tree) that can be inspected, traversed, analysed and, potentially, serialised.</p><p>There are different ways to perform such conversion, such as:</p><ol><li><p>Manual char-by-char parsing using state machines, regular expression and/or native string APIs.</p></li><li><p>Parser combinators, which use higher-level functions to combine different parsers together (in Rust-land these are represented by <a href="https://github.com/Geal/nom">nom</a>, <a href="https://github.com/m4rw3r/chomp">chomp</a>, <a href="https://github.com/Marwes/combine">combine</a> and <a href="https://crates.io/keywords/parser-combinators">others</a>).</p></li><li><p>Fully automated generators which, provided with a grammar, can generate a fully working parser for you (examples are <a href="https://github.com/kevinmehall/rust-peg">peg</a>, <a href="https://github.com/pest-parser/pest">pest</a>, <a href="https://github.com/lalrpop/lalrpop">LALRPOP</a>, etc.).</p></li></ol>
    <div>
      <h4>Wireshark syntax</h4>
      <a href="#wireshark-syntax">
        
      </a>
    </div>
    <p>But before trying to figure out which approach would work best for us, let’s take a look at some of the simple <a href="https://wiki.wireshark.org/DisplayFilters">official Wireshark examples</a>, to understand what we’re dealing with:</p><ul><li><p><code>ip.len le 1500</code></p></li><li><p><code>udp contains 81:60:03</code></p></li><li><p><code>sip.To contains "a1762"</code></p></li><li><p><code>http.request.uri matches "gl=se$"</code></p></li><li><p><code>eth.dst == ff:ff:ff:ff:ff:ff</code></p></li><li><p><code>ip.addr == 192.168.0.1</code></p></li><li><p><code>ipv6.addr == ::1</code></p></li></ul><p>You can see that the right hand side of a comparison can be a number, an IPv4 / IPv6 address, a set of bytes or a string. They are used interchangeably, without any special notion of a type, which is fine given that they are easily distinguishable… or are they?</p><p>Let’s take a look at some <a href="https://en.wikipedia.org/wiki/IPv6#Address_representation">IPv6 forms</a> on Wikipedia:</p><ul><li><p><code>2001:0db8:0000:0000:0000:ff00:0042:8329</code></p></li><li><p><code>2001:db8:0:0:0:ff00:42:8329</code></p></li><li><p><code>2001:db8::ff00:42:8329</code></p></li></ul><p>So IPv6 can be written as a set of up to 8 colon-separated hexadecimal numbers, each containing up to 4 digits with leading zeros omitted for convenience. This appears suspiciously similar to the syntax for byte sequences. Indeed, if we try writing out a sequence like <code>2f:31:32:33:34:35:36:37</code>, it’s simultaneously a valid IPv6 and a byte sequence in terms of Wireshark syntax.</p><p>There is no way of telling what this sequence actually represents without looking at the type of the field it’s being compared with, and if you try using this sequence in Wireshark, you’ll notice that it does just that:</p><ul><li><p><code>ipv6.addr == 2f:31:32:33:34:35:36:37</code>: right hand side is parsed and used as an IPv6 address</p></li><li><p><code>http.request.uri == 2f:31:32:33:34:35:36:37</code>: right hand side is parsed and used as a byte sequence (will match a URL <code>"/1234567"</code>)</p></li></ul><p>Are there other examples of such ambiguities? Yup - for example, we can try using a single number with two decimal digits:</p><ul><li><p><code>tcp.port == 80</code>: matches any traffic on the port 80 (HTTP)</p></li><li><p><code>http.file_data == 80</code>: matches any HTTP request/response with body containing a single byte (0x80)</p></li></ul><p>We could also do the same with ethernet address, defined as a separate type in Wireshark, but, for simplicity, we represent it as a regular byte sequence in our implementation, so there is no ambiguity here.</p>
    <div>
      <h4>Choosing a parsing approach</h4>
      <a href="#choosing-a-parsing-approach">
        
      </a>
    </div>
    <p>This is an interesting syntax design decision. It means that we need to store a mapping between field names and types ahead of time - a Scheme, as we call it - and use it for contextual parsing. This restriction also immediately rules out many if not most parser generators.</p><p>We could still use one of the more sophisticated ones (like LALRPOP) that allow replacing the default regex-based lexer with your own custom code, but at that point we’re so close to having a full parser for our DSL that the complexity outweighs any benefits of using a black-box parser generator.</p><p>Instead, we went with a manual parsing approach. While (for a good reason) this might sound scary in unsafe languages like C / C++, in Rust all strings are bounds checked by default. Rust also provides a rich string manipulation API, which we can use to build more complex helpers, eventually ending up with a full parser.</p><p>This approach is, in fact, pretty similar to parser combinators in that the parser doesn’t have to keep state and only passes the unprocessed part of the input down to smaller, narrower scoped functions. Just as in parser combinators, the absence of mutable state also allows to easily test and maintain each of the parsers for different parts of the syntax independently of the others.</p><p>Compared with popular parser combinator libraries in Rust, one of the differences is that our parsers are not standalone functions but rather types that implement common traits:</p>
            <pre><code>pub trait Lex&lt;'i&gt;: Sized {
   fn lex(input: &amp;'i str) -&gt; LexResult&lt;'i, Self&gt;;
}
pub trait LexWith&lt;'i, E&gt;: Sized {
   fn lex_with(input: &amp;'i str, extra: E) -&gt; LexResult&lt;'i, Self&gt;;
}</code></pre>
            <p>The <code>lex</code> method or its contextual variant <code>lex_with</code> can either return a successful pair of <code>(instance of the type, rest of input)</code> or a pair of <code>(error kind, relevant input span)</code>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5L9MIL21iug4jVm8Eo1bGM/a4996c058b046ea785ff40d315772c53/parse.png" />
            
            </figure><p>The <code>Lex</code> trait is used for target types that can be parsed independently of the context (like field names or literals), while <code>LexWith</code> is used for types that need a <code>Scheme</code> or a part of it to be parsed unambiguously.</p><p>A bigger difference is that, instead of relying on higher-level functions for parser combinators, we use the usual imperative function call syntax. For example, when we want to perform sequential parsing, all we do is call several parsers in a row, using tuple destructuring for intermediate results:</p>
            <pre><code>let input = skip_space(input);
let (op, input) = CombinedExpr::lex_with(input, scheme)?;
let input = skip_space(input);
let input = expect(input, ")")?;</code></pre>
            <p>And, when we want to try different alternatives, we can use native pattern matching and ignore the errors:</p>
            <pre><code>if let Ok(input) = expect(input, "(") {
   ...
   (SimpleExpr::Parenthesized(Box::new(op)), input)
} else if let Ok((op, input)) = UnaryOp::lex(input) {
   ...
} else {
   ...
}</code></pre>
            <p>Finally, when we want to automate parsing of some more complicated common cases - say, enums - Rust provides a powerful macro syntax:</p>
            <pre><code>lex_enum!(#[repr(u8)] OrderingOp {
   "eq" | "==" =&gt; Equal = EQUAL,
   "ne" | "!=" =&gt; NotEqual = LESS | GREATER,
   "ge" | "&gt;=" =&gt; GreaterThanEqual = GREATER | EQUAL,
   "le" | "&lt;=" =&gt; LessThanEqual = LESS | EQUAL,
   "gt" | "&gt;" =&gt; GreaterThan = GREATER,
   "lt" | "&lt;" =&gt; LessThan = LESS,
});</code></pre>
            <p>This gives an experience similar to parser generators, while still using native language syntax and keeping us in control of all the implementation details.</p>
    <div>
      <h3>Execution engine</h3>
      <a href="#execution-engine">
        
      </a>
    </div>
    <p>Because our grammar and operations are fairly simple, initially we used direct AST interpretation by requiring all nodes to implement a trait that includes an <code>execute</code> method.</p>
            <pre><code>trait Expr&lt;'s&gt; {
    fn execute(&amp;self, ctx: &amp;ExecutionContext&lt;'s&gt;) -&gt; bool;
}</code></pre>
            <p>The <code>ExecutionContext</code> is pretty similar to a <code>Scheme</code>, but instead of mapping arbitrary field names to their types, it maps them to the runtime input values provided by the caller.</p><p>As with <code>Scheme</code>, initially <code>ExecutionContext</code> used an internal <code>HashMap</code> for registering these arbitrary <code>String</code> -&gt; <code>RhsValue</code> mappings. During the <code>execute</code> call, the AST implementation would evaluate itself recursively, and look up each field reference in this map, either returning a value or raising an error on missing slots and type mismatches.</p><p>This worked well enough for an initial implementation, but using a <code>HashMap</code> has a non-trivial cost which we would like to eliminate. We already used a more efficient hasher - <code>[Fnv](https://github.com/servo/rust-fnv)</code> - because we are in control of all keys and so are not worried about hash DoS attacks, but there was still more we could do.</p>
    <div>
      <h4>Speeding up field access</h4>
      <a href="#speeding-up-field-access">
        
      </a>
    </div>
    <p>If we look at the data structures involved, we can see that the scheme is always well-defined in advance, and all our runtime values in the execution engine are expected to eventually match it, even if the order or a precise set of fields is not guaranteed:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/mMOLvyXxOj9FxO3dIbYwr/6b308db1a7860c67f52209a689226b56/fieldaccess.png" />
            
            </figure><p>So what if we ditch the second map altogether and instead use a fixed-size array of values? Array indexing should be much cheaper than looking up in a map, so it might be well worth the effort.</p><p>How can we do it? We already know the number of items (thanks to the predefined scheme) so we can use that for the size of the backing storage, and, in order to simulate <code>HashMap</code> “holes” for unset values, we can wrap each item an <code>Option&lt;...&gt;</code>:</p>
            <pre><code>pub struct ExecutionContext&lt;'e&gt; {
    scheme: &amp;'e Scheme,
    values: Box&lt;[Option&lt;LhsValue&lt;'e&gt;&gt;]&gt;,
}</code></pre>
            <p>The only missing piece is an index that could map both structures to each other. As you might remember, <code>Scheme</code> still uses a <code>HashMap</code> for field registration, and a <code>HashMap</code> is normally expected to be randomised and indexed only by the predefined key.</p><p>While we could wrap a value and an auto-incrementing index together into a custom struct, there is already a better solution: <code>[IndexMap](https://github.com/bluss/indexmap)</code>. <code>IndexMap</code> is a drop-in replacement for a <code>HashMap</code> that preserves ordering and provides a way to get an index of any element and vice versa - exactly what we needed.</p><p>After replacing a <code>HashMap</code> in the Scheme with <code>IndexMap</code>, we can change parsing to resolve all the parsed field names to their indices in-place and store that in the AST:</p>
            <pre><code>impl&lt;'i, 's&gt; LexWith&lt;'i, &amp;'s Scheme&gt; for Field&lt;'s&gt; {
   fn lex_with(mut input: &amp;'i str, scheme: &amp;'s Scheme) -&gt; LexResult&lt;'i, Self&gt; {
       ...
       let field = scheme
           .get_field_index(name)
           .map_err(|err| (LexErrorKind::UnknownField(err), name))?;
       Ok((field, input))
   }
}</code></pre>
            <p>After that, in the <code>ExecutionContext</code> we allocate a fixed-size array and use these indices for resolving values during runtime:</p>
            <pre><code>impl&lt;'e&gt; ExecutionContext&lt;'e&gt; {
   /// Creates an execution context associated with a given scheme.
   ///
   /// This scheme will be used for resolving any field names and indices.
   pub fn new&lt;'s: 'e&gt;(scheme: &amp;'s Scheme) -&gt; Self {
       ExecutionContext {
           scheme,
           values: vec![None; scheme.get_field_count()].into(),
       }
   }
   ...
}</code></pre>
            <p>This gave significant (~2x) speed ups on our standard benchmarks:</p><p><i>Before:</i></p>
            <pre><code>test matching ... bench:       2,548 ns/iter (+/- 98)
test parsing  ... bench:     192,037 ns/iter (+/- 21,538)</code></pre>
            <p><i>After**:**</i></p>
            <pre><code>test matching ... bench:       1,227 ns/iter (+/- 29)
test parsing  ... bench:     197,574 ns/iter (+/- 16,568)</code></pre>
            <p>This change also improved the usability of our API, as any type errors are now detected and reported much earlier, when the values are just being set on the context, and not delayed until filter execution.</p>
    <div>
      <h4>[not] JIT compilation</h4>
      <a href="#not-jit-compilation">
        
      </a>
    </div>
    <p>Of course, as with any respectable DSL, one of the other ideas we had from the beginning was “...at some point we’ll add native compilation to make everything super-fast, it’s just a matter of time...”.</p><p>In practice, however, native compilation is a complicated matter, but not due to lack of tools.</p><p>First of all, there is question of storage for the native code. We could compile each filter statically into some sort of a library and publish to a key-value store, but that would not be easy to maintain:</p><ul><li><p>We would have to compile each filter to several platforms (x86-64, ARM, WASM, …).</p></li><li><p>The overhead of native library formats would significantly outweigh the useful executable size, as most filters tend to be small.</p></li><li><p>Each time we’d like to change our execution logic, whether to optimise it or to fix a bug, we would have to recompile and republish all the previously stored filters.</p></li><li><p>Finally, even if/though we’re sure of the reliability of the chosen store, executing dynamically retrieved native code on the edge as-is is not something that can be taken lightly.</p></li></ul><p>The usual flexible alternative that addresses most of these issues is Just-in-Time (JIT) compilation.</p><p>When you compile code directly on the target machine, you get to re-verify the input (still expressed as a restricted DSL), you can compile it just for the current platform in-place, and you never need to republish the actual rules.</p><p>Looks like a perfect fit? Not quite. As with any technology, there are tradeoffs, and you only get to choose those that make more sense for your use cases. JIT compilation is no exception.</p><p>First of all, even though you’re not loading untrusted code over the network, you still need to generate it into the memory, mark that memory as executable and trust that it will always contain valid code and not garbage or something worse. Depending on your choice of libraries and complexity of the DSL, you might be willing to trust it or put heavy sandboxing around, but, either way, it’s a risk that one must explicitly be willing to take.</p><p>Another issue is the cost of compilation itself. Usually, when measuring the speed of native code vs interpretation, the cost of compilation is not taken into the account because it happens out of the process.</p><p>With JIT compilers though, it’s different as you’re now compiling things the moment they’re used and cache the native code only for a limited time. Turns out, generating native code can be rather expensive, so you must be absolutely sure that the compilation cost doesn’t offset any benefits you might gain from the native execution speedup.</p><p>I’ve talked a bit more about this at <a href="https://www.meetup.com/rust-atx/">Rust Austin meetup</a> and, I believe, this topic deserves a separate blog post so won’t go into much more details here, but feel free to check out the slides: <a href="https://www.slideshare.net/RReverser/building-fast-interpreters-in-rust">https://www.slideshare.net/RReverser/building-fast-interpreters-in-rust</a>. Oh, and if you’re in Austin, you should pop into our office for the next meetup!</p><p>Let’s get back to our original question: is there anything else we can do to get the best balance between security, runtime performance and compilation cost? Turns out, there is.</p>
    <div>
      <h4>Dynamic dispatch and closures to the rescue</h4>
      <a href="#dynamic-dispatch-and-closures-to-the-rescue">
        
      </a>
    </div>
    <p>Introducing <code>Fn</code> trait!</p><p>In Rust, the <code>Fn</code> trait and friends (<code>FnMut</code>, <code>FnOnce</code>) are automatically implemented on eligible functions and closures. In case of a simple <code>Fn</code> case the restriction is that they must not modify their captured environment and can only borrow from it.</p><p>Normally, you would want to use it in generic contexts to support arbitrary callbacks with given argument and return types. This is important because in Rust, each function and closure implements a unique type and any generic usage would compile down to a specific call just to that function.</p>
            <pre><code>fn just_call(me: impl Fn(), maybe: bool) {
  if maybe {
    me()
  }
}</code></pre>
            <p>Such behaviour (called static dispatch) is the default in Rust and is preferable for performance reasons.</p><p>However, if we don’t know all the possible types at compile-time, Rust allows us to opt-in for a dynamic dispatch instead:</p>
            <pre><code>fn just_call(me: &amp;dyn Fn(), maybe: bool) {
  if maybe {
    me()
  }
}</code></pre>
            <p>Dynamically dispatched objects don't have a statically known size, because it depends on the implementation details of particular type being passed. They need to be passed as a reference or stored in a heap-allocated <code>Box</code>, and then used just like in a generic implementation.</p><p>In our case, this allows to create, return and store arbitrary closures, and later call them as regular functions:</p>
            <pre><code>trait Expr&lt;'s&gt; {
    fn compile(self) -&gt; CompiledExpr&lt;'s&gt;;
}

pub(crate) struct CompiledExpr&lt;'s&gt;(Box&lt;dyn 's + Fn(&amp;ExecutionContext&lt;'s&gt;) -&gt; bool&gt;);

impl&lt;'s&gt; CompiledExpr&lt;'s&gt; {
   /// Creates a compiled expression IR from a generic closure.
   pub(crate) fn new(closure: impl 's + Fn(&amp;ExecutionContext&lt;'s&gt;) -&gt; bool) -&gt; Self {
       CompiledExpr(Box::new(closure))
   }

   /// Executes a filter against a provided context with values.
   pub fn execute(&amp;self, ctx: &amp;ExecutionContext&lt;'s&gt;) -&gt; bool {
       self.0(ctx)
   }
}</code></pre>
            <p>The closure (an <code>Fn</code> box) will also automatically include the environment data it needs for the execution.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7x17xAapCcN3PjapVfoIyh/89ca29faa4b157fc2dcd7af0179eacb6/box.png" />
            
            </figure><p>This means that we can optimise the runtime data representation as part of the “compile” process without changing the AST or the parser. For example, when we wanted to optimise IP range checks by splitting them for different IP types, we could do that without having to modify any existing structures:</p>
            <pre><code>RhsValues::Ip(ranges) =&gt; {
   let mut v4 = Vec::new();
   let mut v6 = Vec::new();
   for range in ranges {
       match range.clone().into() {
           ExplicitIpRange::V4(range) =&gt; v4.push(range),
           ExplicitIpRange::V6(range) =&gt; v6.push(range),
       }
   }
   let v4 = RangeSet::from(v4);
   let v6 = RangeSet::from(v6);
   CompiledExpr::new(move |ctx| {
       match cast!(ctx.get_field_value_unchecked(field), Ip) {
           IpAddr::V4(addr) =&gt; v4.contains(addr),
           IpAddr::V6(addr) =&gt; v6.contains(addr),
       }
   })
}</code></pre>
            <p>Moreover, boxed closures can be part of that captured environment, too. This means that we can convert each simple comparison into a closure, and then combine it with other closures, and keep going until we end up with a single top-level closure that can be invoked as a regular function to evaluate the entire filter expression.</p><p>It’s turtles closures all the way down:</p>
            <pre><code>let items = items
   .into_iter()
   .map(|item| item.compile())
   .collect::&lt;Vec&lt;_&gt;&gt;()
   .into_boxed_slice();

match op {
   CombiningOp::And =&gt; {
       CompiledExpr::new(move |ctx| items.iter().all(|item| item.execute(ctx)))
   }
   CombiningOp::Or =&gt; {
       CompiledExpr::new(move |ctx| items.iter().any(|item| item.execute(ctx)))
   }
   CombiningOp::Xor =&gt; CompiledExpr::new(move |ctx| {
       items
           .iter()
           .fold(false, |acc, item| acc ^ item.execute(ctx))
   }),
}</code></pre>
            <p>What’s nice about this approach is:</p><ul><li><p>Our execution is no longer tied to the AST, and we can be as flexible with optimising the implementation and data representation as we want without affecting the parser-related parts of code or output format.</p></li><li><p>Even though we initially “compile” each node to a single closure, in future we can pretty easily specialise certain combinations of expressions into their own closures and so improve execution speed for common cases. All that would be required is a separate <code>match</code> branch returning a closure optimised for just that case.</p></li><li><p>Compilation is very cheap compared to real code generation. While it might seem that allocating many small objects (one <code>Box</code>ed closure per expression) is not very efficient and that it would be better to replace it with some sort of a memory pool, in practice we saw a negligible performance impact.</p></li><li><p>No native code is generated at runtime, which means that we execute only code that was statically verified by Rust at compile-time and compiled down to a static function. All that we do at the runtime is call existing functions with different values.</p></li><li><p>Execution turns out to be faster too. This initially came as a surprise, because dynamic dispatch is widely believed to be costly and we were worried that it would get slightly worse than AST interpretation. However, it showed an immediate ~10-15% runtime improvement in benchmarks and on real examples.</p></li></ul><p>The only obvious downside is that each level of AST requires a separate dynamically-dispatched call instead of a single inlined code for the entire expression, like you would have even with a basic template JIT.</p><p>Unfortunately, such output could be achieved only with real native code generation, and, for our case, the mentioned downsides and risks would outweigh runtime benefits, so we went with the safe &amp; flexible closure approach.</p>
    <div>
      <h3>Bonus: WebAssembly support</h3>
      <a href="#bonus-webassembly-support">
        
      </a>
    </div>
    <p>As was mentioned earlier, we chose Rust as a safe high-level language that allows easy integration with other parts of our stack written in Go, C and Lua via C FFI. But Rust has one more target it invests in and supports exceptionally well: WebAssembly.</p><p>Why would we be interested in that? Apart from the parts of the stack where our rules would run, and the API that publishes them, we also have users who like to write their own rules. To do that, they use a UI editor that allows either writing raw expressions in Wireshark syntax or as a WYSIWYG builder.</p><p>We thought it would be great to expose the parser - the same one as we use on the backend - to the frontend JavaScript for a consistent real-time editing experience. And, honestly, we were just looking for an excuse to play with WASM support in Rust.</p><p>WebAssembly could be targeted via regular C FFI, but in that case you would need to manually provide all the glue for the JavaScript side to hold and convert strings, arrays and objects forth and back.</p><p>In Rust, this is all handled by <a href="https://github.com/rustwasm/wasm-bindgen">wasm-bindgen</a>. While it provides various attributes and methods for direct conversions, the simplest way to get started is to activate the “serde” feature which will automatically convert types using <code>JSON.parse</code>, <code>JSON.stringify</code> and <code>[serde_json](https://docs.serde.rs/serde_json/)</code> under the hood.</p><p>In our case, creating a wrapper for the parser with only 20 lines of code was enough to get started and have all the WASM code + JavaScript glue required:</p>
            <pre><code>#[wasm_bindgen]
pub struct Scheme(wirefilter::Scheme);

fn into_js_error(err: impl std::error::Error) -&gt; JsValue {
   js_sys::Error::new(&amp;err.to_string()).into()
}

#[wasm_bindgen]
impl Scheme {
   #[wasm_bindgen(constructor)]
   pub fn try_from(fields: &amp;JsValue) -&gt; Result&lt;Scheme, JsValue&gt; {
       fields.into_serde().map(Scheme).map_err(into_js_error)
   }

   pub fn parse(&amp;self, s: &amp;str) -&gt; Result&lt;JsValue, JsValue&gt; {
       let filter = self.0.parse(s).map_err(into_js_error)?;
       JsValue::from_serde(&amp;filter).map_err(into_js_error)
   }
}</code></pre>
            <p>And by using a higher-level tool called <a href="https://github.com/rustwasm/wasm-pack">wasm-pack</a>, we also got automated npm package generation and publishing, for free.</p><p>This is not used in the production UI yet because we still need to figure out some details for unsupported browsers, but it’s great to have all the tooling and packages ready with minimal efforts. Extending and reusing the same package, it should be even possible to run filters in Cloudflare Workers too (which <a href="/webassembly-on-cloudflare-workers/">also support WebAssembly</a>).</p>
    <div>
      <h3>The future</h3>
      <a href="#the-future">
        
      </a>
    </div>
    <p>The code in the current state is already doing its job well in production and we’re happy to share it with the open-source Rust community.</p><p>This is definitely not the end of the road though - we have many more fields to add, features to implement and planned optimisations to explore. If you find this sort of work interesting and would like to help us by working on firewalls, parsers or just any Rust projects at scale, give us a shout!</p> ]]></content:encoded>
            <category><![CDATA[Rust]]></category>
            <category><![CDATA[JavaScript]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[IPv4]]></category>
            <category><![CDATA[IPv6]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Programming]]></category>
            <category><![CDATA[API]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">2IkqAbjbvhsOMUuOPkvsnL</guid>
            <dc:creator>Ingvar Stepanyan</dc:creator>
            <dc:creator>Andrew Galloni</dc:creator>
        </item>
        <item>
            <title><![CDATA[Improving request debugging in Cloudflare Workers]]></title>
            <link>https://blog.cloudflare.com/better-workers-debugging-with-a-network-panel/</link>
            <pubDate>Fri, 28 Dec 2018 14:18:11 GMT</pubDate>
            <description><![CDATA[ As some of you might have already noticed either from our public release notes, on cloudflareworkers.com or in your Cloudflare Workers dashboard, there was a small but important change in the look of the inspector. ]]></description>
            <content:encoded><![CDATA[ <p>At Cloudflare, we are constantly looking into ways to improve development experience for Workers and make it the most convenient platform for writing serverless code.</p><p>As some of you might have already noticed either from our public release notes, on <a href="https://cloudflareworkers.com/">cloudflareworkers.com</a> or in your Cloudflare Workers dashboard, there recently was a small but important change in the look of the inspector.</p><p>But before we go into figuring out what it is, let's take a look at our standard example on <a href="https://cloudflareworkers.com/">cloudflareworkers.com</a>:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/457ro5RNFewcfSnhPPwFA8/62939086d77edc6181ed5e5ba13f6433/image-16.png" />
            
            </figure><p>The example worker code featured here acts as a transparent proxy, while printing requests / responses to the console.</p><p>Commonly, when debugging Workers, all you could see from the client-side devtools is the interaction between your browser and the Cloudflare Worker runtime. However, like in most other server-side runtimes, the interaction between your code and the actual origin has been hidden.</p><p>This is where <code>console.log</code> comes in. Although not the most convenient, printing random things out is a fairly popular debugging technique.</p><p>Unfortunately, its default output doesn't help much with debugging network interactions. If you try to expand either of request or response objects, all you can see is just a bunch of lazy accessors:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5K8RNMUh2epL4Swl7M9eso/5f28631909bffda10f3f5e66a5ec1cf2/screenshot-storage.googleapis.com-2018.12.14-11-59-22.png" />
            
            </figure><p>You could expand them one-by-one, getting some properties back, but, when it comes to important parts like headers, that doesn't help much either:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3NG4RcXiD3KK8N9U53DAJL/9df91e9705f0bda09a06e2d865153ad3/screenshot-storage.googleapis.com-2018.12.14-12-00-37.png" />
            
            </figure><p>So, since the launch of Workers, what we have been able to suggest instead is certain JS tricks to convert headers to a more readable format:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/583U9GfftSUcqzY54HX8yT/a39d9d63dd253ae1a577cf594874b48c/screenshot-cloudflareworkers.com-2018.12.14-12-03-57.png" />
            
            </figure><p>This works somewhat better, but doesn't scale well, especially if you're trying to debug complex interactions between various requests on a page and subrequests coming from a worker. So we thought: how can we do better?</p><p>If you're familiar with Chrome DevTools, you might have noticed before that we were already offering its trimmed-down version in our UI with basic Console and Sources panels. The obvious solution is: why not expose the existing Network panel in addition to these? And we did just* that.</p><p>* Unfortunately, this is easier said than done. If you're already faimilar with the Network tab and are interested in the technical implementation details, feel free to <a href="#how-did-we-do-this">skip the next section</a>.</p>
    <div>
      <h3>What can you do with the new panel?</h3>
      <a href="#what-can-you-do-with-the-new-panel">
        
      </a>
    </div>
    <p>You should be able to use most of the things available in regular Chrome DevTools Network panel, but instead of inspecting the interaction between browser and Cloudflare (which is as much as browser devtools can give you), you are now able to peek into the interaction between your Worker and the origin as well.</p><p>This means you're able to view request and response headers, including both those internal to your worker and the ones provided by Cloudflare:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3uV34bLhMdZxNY3Gbo3dQG/4b6606ff56ad8ebe3e309c37c75626a8/image-22.png" />
            
            </figure><p>Check the original response to verify content modifications:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2PGAymDgcq0ZfPTe4eESyd/7c200054b1efe875b4cf717fc50d2434/screenshot-cloudflareworkers.com-2018.12.14-17-37-19.png" />
            
            </figure><p>Same goes for raw responses:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7BUBV00klumZq2Xz8rOOhI/e2143e6ef19c6b9088126a0214438c0c/screenshot-cloudflareworkers.com-2018.12.14-17-37-34.png" />
            
            </figure><p>You can also check the time it took worker to reach and get data from your website:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/36SE1whkvsK8GAhh0rQ70H/d12aaa7e25ff4405461585a4bc515bf9/screenshot-cloudflareworkers.com-2018.12.14-17-41-03.png" />
            
            </figure><p>However, note that timings from a debugging service will be different than the ones in production in different locations, so it would make sense to compare these only with other requests on the same page or with the same request as you keep iterating on code of your Worker.</p><p>You can view the initiator of each request - this might come in handy if your worker contains complex routing handled by different paths, or if you want to simply check which requests on the page were intercepted and re-issued at all:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7mCM9hsucpRaamv8tGtzWz/ace524a49457ec5e66b0a7e9662c6312/image-25.png" />
            
            </figure><p>Basic features like filtering by type of content also work:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2b9Qmjos900pWFl40CIGfQ/c06dd239bd20e4628e9ccb2f0c887bd8/screenshot-cloudflareworkers.com-2018.12.14-17-56-13-1.png" />
            
            </figure><p>And, finally, you can copy or even export subrequests as HAR for further inspection:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/SY6GsgFGCCv78EAB8NYyb/2ec50bdc95c349a2bf7f4d86e1fa1cae/image-24.png" />
            
            </figure>
    <div>
      <h3>How did we do this?</h3>
      <a href="#how-did-we-do-this">
        
      </a>
    </div>
    <p>So far we have been using a built-in mode of the inspector which was specifically designed with JavaScript-only targets in mind. This allows it to avoid loading most of the components that would require a real browser (Chromium-based) backend, and instead leaves just the core that can be integrated directly with V8 in any embedder, whether it's Node.js or, in our case, Cloudflare Workers.</p><p>Luckily, the DevTools Protocol itself is pretty well documented - <a href="https://chromedevtools.github.io/devtools-protocol/">chromedevtools.github.io/devtools-protocol/</a> - to facilitate third-party implementors.</p><p>While this is commonly used from client-side (for editor integration), there are some third-party implementors of the server-side too, even for non-JavaScript targets like Lua, Go, ClojureScript and even system-wide network debugging both on desktop and mobile: <a href="https://github.com/ChromeDevTools/awesome-chrome-devtools">github.com/ChromeDevTools/awesome-chrome-devtools</a>.</p><p>So there is nothing preventing us from providing our own implementation of <code>Network</code> domain that would give a native DevTools experience.</p><p>On the Workers backend side, we are already in charge of the network stack, which means we have access to all the necessary information to report and can wrap all the request/response handlers into own hooks to send it back to the inspector.</p><p>Communication between the inspector and the debugger backend is happening over WebSockets. So far we've been just receiving messages and passing them pretty much directly to V8 as-is. However, if we want to handle Network messages ourselves, that's not going to work anymore and we need to actually parse the messages.</p><p>To do that in a standard way, V8 provides some build scripts to generate protocol handlers for any given list of domains. While these are used by Chromium, they require quite a bit of configuration and custom glue for different levels of message serialisation, deserialisation and error handling.</p><p>On the other hand, the protocol used for communication is essentially just <a href="https://www.jsonrpc.org/">JSON-RPC</a>, and <a href="https://capnproto.org/">capnproto</a>, which we're already using in other places behind the scenes, provides JSON (de)serialisation support, so it's easier to reuse it rather than build a separate glue layer for V8.</p><p>For example, to provide bindings for <code>[Runtime.callFrame](https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-CallFrame)</code> we need to just define a capnp structure like this:</p>
            <pre><code>struct CallFrame {
  # Stack entry for runtime errors and assertions.
  functionName @0 :Text; # JavaScript function name.
  scriptId @1 :ScriptId; # JavaScript script id.
  url @2 :Text; # JavaScript script name or url.
  lineNumber @3 :Int32; # JavaScript script line number (0-based).
  columnNumber @4 :Int32; # JavaScript script column number (0-based).
}</code></pre>
            <p>Okay, so by combining these two we can now parse and handle supported Network inspector messages ourselves and pass the rest through to V8 as usual.</p><p>Now, we needed to make some changes to the frontend. Wait, you might ask, wasn't the entire point of these changes to speak the same protocol as frontend already does? That's true, but there are other challenges.</p><p>First of all, because Network tab was designed to be used in a browser, it relies on various components that are actually irrelevant to us and, if pulled in as-is, would not only make frontend code larger, but also require extra backend support too. Some of them are used for cross-tab integration (e.g. with Profiler), but some are part of the Network tab itself - for example, it doesn't make much sense to use request blocking or mobile throttling when debugging server-side code. So we had some manual untangling to do here.</p><p>Another interesting challenge was in handling response bodies. Normally, when you click on a request in Network tab in the browser, and then ask to see its response body, devtools frontend sends a <code>[Network.getResponseBody](https://chromedevtools.github.io/devtools-protocol/tot/Fetch/#method-getResponseBody)</code> message to the browser backend and then the browser sends it back.</p><p>What this means is that, as long as the Network tab is active, browser has to store all of the responses for all of the requests from the page in memory, not knowing which of them are actually going to be requested in the future or not. Such lazy handling makes perfect sense for local or even remote Chrome debugging, where you are commonly fully in charge of both sides.</p><p>However, for us it wouldn't be ideal to have to store all of these responses from all of the users in memory on the debugging backend. After some forth and back on different solutions, we decided to deviate from the protocol and instead send original response bodies to the inspector frontend as they come through, and let frontend store them instead. This might seem not ideal either due to sending unnecessary data over the network during debugging sessions, but these tradeoffs make more sense for a shared debugging backend.</p><p>There were various smaller challenges and bug fixes to be made and upstreamed, but let them stay behind the scenes.</p><p>Is this feature useful to you? What other features would help you to debug and develop workers more efficiently? Or maybe you would like to work on Workers and tooling yourself?</p><p>Let us know!</p><p><b>P.S.</b>: If you’re looking for a fun personal project for the holidays, this could be your chance to try out Workers, and play around with our new tools.</p> ]]></content:encoded>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Dashboard]]></category>
            <category><![CDATA[Programming]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">1W7MPRFd3LOfuxcqHIlaJu</guid>
            <dc:creator>Ingvar Stepanyan</dc:creator>
        </item>
        <item>
            <title><![CDATA[Writing complex macros in Rust: Reverse Polish Notation]]></title>
            <link>https://blog.cloudflare.com/writing-complex-macros-in-rust-reverse-polish-notation/</link>
            <pubDate>Wed, 31 Jan 2018 12:11:15 GMT</pubDate>
            <description><![CDATA[ Among other interesting features, Rust has a powerful macro system. Unfortunately, even after reading The Book and various tutorials, when it came to trying to implement a macro which involved processing complex lists of different elements, I still struggled to understand how it should be done. ]]></description>
            <content:encoded><![CDATA[ <p>(<i>This is a crosspost of a tutorial </i><a href="https://rreverser.com/writing-complex-macros-in-rust/"><i>originally published</i></a><i> on my personal blog</i>)</p><p>Among other interesting features, Rust has a powerful macro system. Unfortunately, even after reading The Book and various tutorials, when it came to trying to implement a macro which involved processing complex lists of different elements, I still struggled to understand how it should be done, and it took some time till I got to that "ding" moment and started misusing macros for everything :) <i>(ok, not everything as in the i-am-using-macros-because-i-dont-want-to-use-functions-and-specify-types-and-lifetimes everything like I've seen some people do, but anywhere it's actually useful)</i></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5H983fEVulWNryLr4wz4Al/cb9ff5c7818560c6dd186183a2c6270a/25057125240_939a41249f_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/25057125240/in/photolist-EbdjmG-8NSN1q-qXhueG-YTYnm3-odaneQ-DxCKQA-228jg4t-DU8Axz-XTQfdD-4p6nJk-UKVzbn-YFeKcW-osZ2XM-e6qefx-Tb3a6Q-dCw1zk-Et3kKh-dbAR9x-zHP8TR-a9cqw4-9JQHRy-Et1Ag5-PqFtx1-7x3Ukq-67VJc6-cvoKSo-qH2S9L-zHJAr9-XmCLsL-8AMWXX-ZV2hHh-XGPiHq-ZKpFSB-yqd2P1-23hMiaC-zETYYa-Wj7BVi-PNP4YA-LCNm6c-8AnkrZ-KA7qmt-KjYPxC-SzQsZD-Cxwvqg-GuZ3nn-J4jBaA-TzyjpB-DcYJA1-YQYNA3-My1uu8">image</a> by <a href="https://www.flickr.com/photos/conchur/">Conor Lawless</a></p><p>So, here is my take on describing the principles behind writing such macros. It assumes you have read the <a href="https://doc.rust-lang.org/book/first-edition/macros.html">Macros</a> section from The Book and are familiar with basic macros definitions and token types.</p><p>I'll take a <a href="https://en.wikipedia.org/wiki/Reverse_Polish_notation">Reverse Polish Notation</a> as an example for this tutorial. It's interesting because it's simple enough, you might be already familiar with it from school, and yet to implement it statically at compile time, you already need to use a recursive macros approach.</p><p>Reverse Polish Notation (also called postfix notation) uses a stack for all its operations, so that any operand is pushed onto the stack, and any <i>[binary]</i> operator takes two operands from the stack, evaluates the result and puts it back. So an expression like following:</p>
            <pre><code>2 3 + 4 *</code></pre>
            <p>translates into:</p><ol><li><p>Put <code>2</code> onto the stack.</p></li><li><p>Put <code>3</code> onto the stack.</p></li><li><p>Take two last values from the stack (<code>3</code> and <code>2</code>), apply operator <code>+</code> and put the result (<code>5</code>) back onto the stack.</p></li><li><p>Put <code>4</code> onto the stack.</p></li><li><p>Take two last values from the stack (<code>4</code> and <code>5</code>), apply operator <code>*</code> (<code>4 * 5</code>) and put the result (<code>20</code>) back onto the stack.</p></li><li><p>End of expression, the single value on the stack is the result (<code>20</code>).</p></li></ol><p>In a more common infix notation, used in math and most modern programming languages, the expression would look like <code>(2 + 3) * 4</code>.</p><p>So let's write a macro that would evaluate RPN at compile-time by converting it into an infix notation that Rust understands.</p>
            <pre><code>macro_rules! rpn {
  // TODO
}

println!("{}", rpn!(2 3 + 4 *)); // 20</code></pre>
            <p>Let's start with pushing numbers onto the stack.</p><p>Macros currently don't allow matching literals, and <code>expr</code> won't work for us because it can accidentally match sequence like <code>2 + 3 ...</code> instead of taking just a single number, so we'll resort to <code>tt</code> - a generic token matcher that matches only one token tree (whether it's a primitive token like literal/identifier/lifetime/etc. or a <code>()</code>/<code>[]</code>/<code>{}</code>-parenthesized expression containing more tokens):</p>
            <pre><code>macro_rules! rpn {
  ($num:tt) =&gt; {
    // TODO
  };
}</code></pre>
            <p>Now, we'll need a variable for the stack.</p><p>Macros can't use real variables, because we want this stack to exist only at compile time. So, instead, the trick is to have a separate token sequence that can be passed around, and so used as kind of an accumulator.</p><p>In our case, let's represent it as a comma-separated sequence of <code>expr</code> (since we will be using it not only for simple numbers but also for intermediate infix expressions) and wrap it into brackets to separate from the rest of the input:</p>
            <pre><code>macro_rules! rpn {
  ([ $($stack:expr),* ] $num:tt) =&gt; {
    // TODO
  };
}</code></pre>
            <p>Now, a token sequence is not really a variable - you can't modify it in-place and do something afterwards. Instead, you can create a new copy of this token sequence with necessary modifications, and recursively call same macro again.</p><p>If you are coming from functional language background or worked with any library providing immutable data before, both of these approaches - mutating data by creating a modified copy and processing lists with a recursion - are likely already familiar to you:</p>
            <pre><code>macro_rules! rpn {
  ([ $($stack:expr),* ] $num:tt) =&gt; {
    rpn!([ $num $(, $stack)* ])
  };
}</code></pre>
            <p>Now, obviously, the case with just a single number is rather unlikely and not very interesting to us, so we'll need to match anything else after that number as a sequence of zero or more <code>tt</code> tokens, which can be passed to next invocation of our macro for further matching and processing:</p>
            <pre><code>macro_rules! rpn {
  ([ $($stack:expr),* ] $num:tt $($rest:tt)*) =&gt; {
      rpn!([ $num $(, $stack)* ] $($rest)*)
  };
}</code></pre>
            <p>At this point we're still missing operator support. How do we match operators?</p><p>If our RPN would be a sequence of tokens that we would want to process in an exactly same way, we could simply use a list like <code>$($token:tt)*</code>. Unfortunately, that wouldn't give us an ability to go through list and either push an operand or apply an operator depending on each token.</p><p>The Book says that "macro system does not deal with parse ambiguity at all", and that's true for a single macros branch - we can't match a sequence of numbers followed by an operator like <code>$($num:tt)* +</code> because <code>+</code> is also a valid token and could be matched by the <code>tt</code> group, but this is where recursive macros helps again.</p><p>If you have different branches in your macro definition, Rust will try them one by one, so we can put our operator branches before the numeric one and, this way, avoid any conflict:</p>
            <pre><code>macro_rules! rpn {
  ([ $($stack:expr),* ] + $($rest:tt)*) =&gt; {
    // TODO
  };
  
  ([ $($stack:expr),* ] - $($rest:tt)*) =&gt; {
    // TODO
  };
  
  ([ $($stack:expr),* ] * $($rest:tt)*) =&gt; {
    // TODO
  };
  
  ([ $($stack:expr),* ] / $($rest:tt)*) =&gt; {
    // TODO
  };

  ([ $($stack:expr),* ] $num:tt $($rest:tt)*) =&gt; {
    rpn!([ $num $(, $stack)* ] $($rest)*)
  };
}</code></pre>
            <p>As I said earlier, operators are applied to the last two numbers on the stack, so we'll need to match them separately, "evaluate" the result (construct a regular infix expression) and put it back:</p>
            <pre><code>macro_rules! rpn {
  ([ $b:expr, $a:expr $(, $stack:expr)* ] + $($rest:tt)*) =&gt; {
    rpn!([ $a + $b $(, $stack)* ] $($rest)*)
  };

  ([ $b:expr, $a:expr $(, $stack:expr)* ] - $($rest:tt)*) =&gt; {
    rpn!([ $a - $b $(, $stack)* ] $($rest)*)
  };

  ([ $b:expr, $a:expr $(, $stack:expr)* ] * $($rest:tt)*) =&gt; {
    rpn!([ $a * $b $(,$stack)* ] $($rest)*)
  };

  ([ $b:expr, $a:expr $(, $stack:expr)* ] / $($rest:tt)*) =&gt; {
    rpn!([ $a / $b $(,$stack)* ] $($rest)*)
  };

  ([ $($stack:expr),* ] $num:tt $($rest:tt)*) =&gt; {
    rpn!([ $num $(, $stack)* ] $($rest)*)
  };
}</code></pre>
            <p>I'm not really fan of such obvious repetitions, but, just like with literals, there is no special token type to match operators.</p><p>What we can do, however, is add a helper that would be responsible for the evaluation, and delegate any explicit operator branch to it.</p><p>In macros, you can't really use an external helper, but the only thing you can be sure about is that your macros is already in scope, so the usual trick is to have a branch in the same macro "marked" with some unique token sequence, and call it recursively like we did in regular branches.</p><p>Let's use <code>@op</code> as such marker, and accept any operator via <code>tt</code> inside it (<code>tt</code> would be unambiguous in such context because we'll be passing only operators to this helper).</p><p>And the stack does not need to be expanded in each separate branch anymore - since we wrapped it into <code>[]</code> brackets earlier, it can be matched as any another token tree (<code>tt</code>), and then passed into our helper:</p>
            <pre><code>macro_rules! rpn {
  (@op [ $b:expr, $a:expr $(, $stack:expr)* ] $op:tt $($rest:tt)*) =&gt; {
    rpn!([ $a $op $b $(, $stack)* ] $($rest)*)
  };

  ($stack:tt + $($rest:tt)*) =&gt; {
    rpn!(@op $stack + $($rest)*)
  };
  
  ($stack:tt - $($rest:tt)*) =&gt; {
    rpn!(@op $stack - $($rest)*)
  };

  ($stack:tt * $($rest:tt)*) =&gt; {
    rpn!(@op $stack * $($rest)*)
  };
  
  ($stack:tt / $($rest:tt)*) =&gt; {
    rpn!(@op $stack / $($rest)*)
  };

  ([ $($stack:expr),* ] $num:tt $($rest:tt)*) =&gt; {
    rpn!([ $num $(, $stack)* ] $($rest)*)
  };
}</code></pre>
            <p>Now any tokens are processed by corresponding branches, and we need to just handle final case when stack contains a single item, and no more tokens are left:</p>
            <pre><code>macro_rules! rpn {
  // ...
  
  ([ $result:expr ]) =&gt; {
    $result
  };
}</code></pre>
            <p>At this point, if you invoke this macro with an empty stack and RPN expression, it will already produce a correct result:</p><p><a href="https://play.rust-lang.org/?gist=cd56f6d7335e2d27c05e7fa89545b2cd&amp;version=stable">Playground</a></p>
            <pre><code>println!("{}", rpn!([] 2 3 + 4 *)); // 20</code></pre>
            <p>However, our stack is an implementation detail and we really wouldn't want every consumer to pass an empty stack in, so let's add another catch-all branch in the end that would serve as an entry point and add <code>[]</code> automatically:</p><p><a href="https://play.rust-lang.org/?gist=d94abc0e20aa5c7f689706af06fd1923&amp;version=stable">Playground</a></p>
            <pre><code>macro_rules! rpn {
  // ...

  ($($tokens:tt)*) =&gt; {
    rpn!([] $($tokens)*)
  };
}

println!("{}", rpn!(2 3 + 4 *)); // 20</code></pre>
            <p>Our macro even works for more complex expressions, like the one <a href="https://en.wikipedia.org/wiki/Reverse_Polish_notation#Example">from Wikipedia page about RPN</a>!</p>
            <pre><code>println!("{}", rpn!(15 7 1 1 + - / 3 * 2 1 1 + + -)); // 5</code></pre>
            
    <div>
      <h3>Error handling</h3>
      <a href="#error-handling">
        
      </a>
    </div>
    <p>Now everything seems to work smoothly for correct RPN expressions, but for a macros to be production-ready we need to be sure that it can handle invalid input as well, with a reasonable error message.</p><p>First, let's try to insert another number in the middle and see what happens:</p>
            <pre><code>println!("{}", rpn!(2 3 7 + 4 *));</code></pre>
            <p>Output:</p>
            <pre><code>error[E0277]: the trait bound `[{integer}; 2]: std::fmt::Display` is not satisfied
  --&gt; src/main.rs:36:20
   |
36 |     println!("{}", rpn!(2 3 7 + 4 *));
   |                    ^^^^^^^^^^^^^^^^^ `[{integer}; 2]` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
   |
   = help: the trait `std::fmt::Display` is not implemented for `[{integer}; 2]`
   = note: required by `std::fmt::Display::fmt`</code></pre>
            <p>Okay, that definitely doesn't look helpful as it doesn't provide any information relevant to the actual mistake in the expression.</p><p>In order to figure out what happened, we will need to debug our macros. For that, we'll use a <a href="https://doc.rust-lang.org/unstable-book/language-features/trace-macros.html"><code>trace_macros</code></a> feature (and, like for any other optional compiler feature, you'll need a nightly version of Rust). We don't want to trace <code>println!</code> call, so we'll separate our RPN calculation to a variable:</p><p><a href="https://play.rust-lang.org/?gist=610bc0c241aacda3d30a916f89b244cd&amp;version=nightly">Playground</a></p>
            <pre><code>#![feature(trace_macros)]

macro_rules! rpn { /* ... */ }

fn main() {
  trace_macros!(true);
  let e = rpn!(2 3 7 + 4 *);
  trace_macros!(false);
  println!("{}", e);
}</code></pre>
            <p>In the output we'll now see how our macro is being recursively evaluated step by step:</p>
            <pre><code>note: trace_macro
  --&gt; src/main.rs:39:13
   |
39 |     let e = rpn!(2 3 7 + 4 *);
   |             ^^^^^^^^^^^^^^^^^
   |
   = note: expanding `rpn! { 2 3 7 + 4 * }`
   = note: to `rpn ! ( [  ] 2 3 7 + 4 * )`
   = note: expanding `rpn! { [  ] 2 3 7 + 4 * }`
   = note: to `rpn ! ( [ 2 ] 3 7 + 4 * )`
   = note: expanding `rpn! { [ 2 ] 3 7 + 4 * }`
   = note: to `rpn ! ( [ 3 , 2 ] 7 + 4 * )`
   = note: expanding `rpn! { [ 3 , 2 ] 7 + 4 * }`
   = note: to `rpn ! ( [ 7 , 3 , 2 ] + 4 * )`
   = note: expanding `rpn! { [ 7 , 3 , 2 ] + 4 * }`
   = note: to `rpn ! ( @ op [ 7 , 3 , 2 ] + 4 * )`
   = note: expanding `rpn! { @ op [ 7 , 3 , 2 ] + 4 * }`
   = note: to `rpn ! ( [ 3 + 7 , 2 ] 4 * )`
   = note: expanding `rpn! { [ 3 + 7 , 2 ] 4 * }`
   = note: to `rpn ! ( [ 4 , 3 + 7 , 2 ] * )`
   = note: expanding `rpn! { [ 4 , 3 + 7 , 2 ] * }`
   = note: to `rpn ! ( @ op [ 4 , 3 + 7 , 2 ] * )`
   = note: expanding `rpn! { @ op [ 4 , 3 + 7 , 2 ] * }`
   = note: to `rpn ! ( [ 3 + 7 * 4 , 2 ] )`
   = note: expanding `rpn! { [ 3 + 7 * 4 , 2 ] }`
   = note: to `rpn ! ( [  ] [ 3 + 7 * 4 , 2 ] )`
   = note: expanding `rpn! { [  ] [ 3 + 7 * 4 , 2 ] }`
   = note: to `rpn ! ( [ [ 3 + 7 * 4 , 2 ] ] )`
   = note: expanding `rpn! { [ [ 3 + 7 * 4 , 2 ] ] }`
   = note: to `[(3 + 7) * 4, 2]`</code></pre>
            <p>If we carefully look through the trace, we'll notice that the problem originates in these steps:</p>
            <pre><code>   = note: expanding `rpn! { [ 3 + 7 * 4 , 2 ] }`
   = note: to `rpn ! ( [  ] [ 3 + 7 * 4 , 2 ] )`</code></pre>
            <p>Since <code>[ 3 + 7 * 4 , 2 ]</code> was not matched by <code>([$result:expr]) =&gt; ...</code> branch as a final expression, it was caught by our final catch-all <code>($($tokens:tt)*) =&gt; ...</code> branch instead, prepended with an empty stack <code>[]</code> and then the original <code>[ 3 + 7 * 4 , 2 ]</code> was matched by generic <code>$num:tt</code> and pushed onto the stack as a single final value.</p><p>In order to prevent this from happening, let's insert another branch between these last two that would match any stack.</p><p>It would be hit only when we ran out of tokens, but stack didn't have exactly one final value, so we can treat it as a compile error and produce a more helpful error message using a built-in <a href="https://doc.rust-lang.org/std/macro.compile_error.html"><code>compile_error!</code></a> macro.</p><p>Note that we can't use <code>format!</code> in this context since it uses runtime APIs to format a string, and instead we'll have to limit ourselves to built-in <code>concat!</code> and <code>stringify!</code> macros to format a message:</p><p><a href="https://play.rust-lang.org/?gist=e56be9422387bcae54aab3b8405a11e7&amp;version=stable">Playground</a></p>
            <pre><code>macro_rules! rpn {
  // ...

  ([ $result:expr ]) =&gt; {
    $result
  };

  ([ $($stack:expr),* ]) =&gt; {
    compile_error!(concat!(
      "Could not find final value for the expression, perhaps you missed an operator? Final stack: ",
      stringify!([ $($stack),* ])
    ))
  };

  ($($tokens:tt)*) =&gt; {
    rpn!([] $($tokens)*)
  };
}</code></pre>
            <p>The error message is now more meaningful and contains at least some details about current state of evaluation:</p>
            <pre><code>error: Could not find final value for the expression, perhaps you missed an operator? Final stack: [ (3 + 7) * 4 , 2 ]
  --&gt; src/main.rs:31:9
   |
31 |         compile_error!(concat!("Could not find final value for the expression, perhaps you missed an operator? Final stack: ", stringify!([$($stack),*])))
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
40 |     println!("{}", rpn!(2 3 7 + 4 *));
   |                    ----------------- in this macro invocation</code></pre>
            <p>But what if, instead, we miss some number?</p><p><a href="https://play.rust-lang.org/?gist=ce40630b8c1aa610c46b94557fdc9905&amp;version=stable">Playground</a></p>
            <pre><code>println!("{}", rpn!(2 3 + *));</code></pre>
            <p>Unfortunately, this one is still not too helpful:</p>
            <pre><code>error: expected expression, found `@`
  --&gt; src/main.rs:15:14
   |
15 |         rpn!(@op $stack * $($rest)*)
   |              ^
...
40 |     println!("{}", rpn!(2 3 + *));
   |                    ------------- in this macro invocation</code></pre>
            <p>If you try to use <code>trace_macros</code>, even it won't expand the stack here for some reason, but, luckily, it's relatively clear what's going on - <code>@op</code> has very specific conditions as to what should be matched (it expects at least two values on the stack), and, when it can't, <code>@</code> gets matched by the same way-too-greedy <code>$num:tt</code> and pushed onto the stack.</p><p>To avoid this, again, we'll add another branch to match anything starting with <code>@op</code> that wasn't matched already, and produce a compile error:</p><p><a href="https://play.rust-lang.org/?gist=8729a8f3c96fa58ed62d35804c48782d&amp;version=stable">Playground</a></p>
            <pre><code>macro_rules! rpn {
  (@op [ $b:expr, $a:expr $(, $stack:expr)* ] $op:tt $($rest:tt)*) =&gt; {
    rpn!([ $a $op $b $(, $stack)* ] $($rest)*)
  };

  (@op $stack:tt $op:tt $($rest:tt)*) =&gt; {
    compile_error!(concat!(
      "Could not apply operator `",
      stringify!($op),
      "` to the current stack: ",
      stringify!($stack)
    ))
  };

  // ...
}</code></pre>
            <p>Let's try again:</p>
            <pre><code>error: Could not apply operator `*` to the current stack: [ 2 + 3 ]
  --&gt; src/main.rs:9:9
   |
9  |         compile_error!(concat!("Could not apply operator ", stringify!($op), " to current stack: ", stringify!($stack)))
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
46 |     println!("{}", rpn!(2 3 + *));
   |                    ------------- in this macro invocation</code></pre>
            <p>Much better! Now our macro can evaluate any RPN expression at compile-time, and gracefully handles most common mistakes, so let's call it a day and say it's production-ready :)</p><p>There are many more small improvements we could add, but I'd like to leave them outside this demonstration tutorial.</p><p>Feel free to let me know if this has been useful and/or what topics you'd like to see better covered <a href="https://twitter.com/RReverser">on Twitter</a>!</p> ]]></content:encoded>
            <category><![CDATA[Rust]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Programming]]></category>
            <category><![CDATA[Cloudflare Polish]]></category>
            <guid isPermaLink="false">57apSexjoH5EJBBcLZNqv4</guid>
            <dc:creator>Ingvar Stepanyan</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>
    </channel>
</rss>