<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tim Perry</title>
    <description>The latest articles on DEV Community by Tim Perry (@pimterry).</description>
    <link>https://dev.to/pimterry</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F70382%2F626dad1b-4daf-45b8-a1d8-62a743619654.jpg</url>
      <title>DEV Community: Tim Perry</title>
      <link>https://dev.to/pimterry</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pimterry"/>
    <language>en</language>
    <item>
      <title>The right way to turn off your old APIs</title>
      <dc:creator>Tim Perry</dc:creator>
      <pubDate>Thu, 21 Jan 2021 12:25:00 +0000</pubDate>
      <link>https://dev.to/pimterry/the-right-way-to-turn-off-your-old-apis-3j29</link>
      <guid>https://dev.to/pimterry/the-right-way-to-turn-off-your-old-apis-3j29</guid>
      <description>&lt;p&gt;All things come to an end, even HTTP APIs. However great your API may be today, one day you'll want to release a completely new version, an improved but incompatible endpoint, a new parameter that solves the same problem better, or to shut down your API entirely. Your current API will not be live forever.&lt;/p&gt;

&lt;p&gt;Inconveniently though, your API has clients. If you shut down endpoints, parameters, or entire APIs without properly warning them then they're going to be very unhappy.&lt;/p&gt;

&lt;p&gt;How do you shut down your APIs safely, making it at easy as possible for your users?&lt;/p&gt;

&lt;p&gt;There are right ways to do this, including two new draft headers being standardized by the exciting new IETF "Building Blocks for HTTP APIs" working group, designed to help with this exact process. Let's take a look.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make a plan
&lt;/h2&gt;

&lt;p&gt;First up: check if the API in question actually has any clients.&lt;/p&gt;

&lt;p&gt;Hopefully you have some API metrics or at least logging somewhere. If you don't, add some! If you do, and you can tell for sure that nobody is using this API anymore, then you win. Turn it off right now, delete the code, skip this article and have a well-deserved nap.&lt;/p&gt;

&lt;p&gt;The next question, if you're not napping, is to ask yourself is whether there's an alternative to shutting down this API. Everything you turn off will break somebody's code and take their time to fix it. It's good for the health of your client ecosystem and the web as a whole if APIs keep working.&lt;/p&gt;

&lt;p&gt;In many cases, old APIs can be translated internally, to transparently transform requests into calls to a new API instead, without maintaining two completely independent versions. This is a fundamental part of &lt;a href="https://stripe.com/blog/api-versioning#versioning-under-the-hood"&gt;the API versioning approach at Stripe&lt;/a&gt; who include transformations with all API changes to ensure that requests for incompatible old versions continue to work as before, automatically translating the requests and responses to use the newer code as required.&lt;/p&gt;

&lt;p&gt;Translation like this isn't always possible, and doing so &lt;em&gt;forever&lt;/em&gt; can entail significant extra complexity, but if you can do it, this can provide a valuable stability for your users, and avoid a lot the work required for deprecation or old version maintenance.&lt;/p&gt;

&lt;p&gt;However, if this service/endpoint/parameter is in use in production, and it's not practical to keep supporting it, it's got to go.&lt;/p&gt;

&lt;p&gt;To do that, you need a plan. There's three key questions to ask first:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What do you expect clients using this to do? Common answers include:

&lt;ul&gt;
&lt;li&gt;Update to a newer still-supported version of the same thing.&lt;/li&gt;
&lt;li&gt;Use some other substitute endpoint/parameter/service instead.&lt;/li&gt;
&lt;li&gt;Use a different service, they're on their own, you don't care.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;When should they start migrating away from this API? Is your proposed replacement ready to use today?&lt;/li&gt;
&lt;li&gt;What's the deadline? I.e. when will this API stop working completely? (If you're not totally sure yet, you can delay this answer for a little bit).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you've got a plan, it's time to tell people about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Communicate
&lt;/h2&gt;

&lt;p&gt;First up: tell the humans.&lt;/p&gt;

&lt;p&gt;Email your mailing list, post it on Twitter, update your API specification if you have them (e.g. OpenAPI has a &lt;code&gt;deprecated&lt;/code&gt; field on &lt;a href="https://swagger.io/specification/#operation-object"&gt;operations&lt;/a&gt; and &lt;a href="https://swagger.io/specification/#parameter-object"&gt;parameters&lt;/a&gt;), and highlight this loudly in the relevant documentation online.&lt;/p&gt;

&lt;p&gt;You should include all the info above: what they should do instead, when you recommend they start migrating, and the deadline when they &lt;em&gt;must&lt;/em&gt; migrate (if you have one).&lt;/p&gt;

&lt;p&gt;Once you've told the humans, it's time to tell the computers. This is where the new IETF headers come in.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Deprecation Header
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://datatracker.ietf.org/doc/rfc8594/?include_text=1"&gt;Deprecation header&lt;/a&gt; tells clients that the requested resource still works as before, but is no longer recommended. You can state that very simply with a single HTTP header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deprecation: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, you can provide a date. This date tells users when they should start migrating elsewhere. This can be in the past (if they should start migrating immediately) or the future (usually meaning that the thing they should migrate to isn't ready yet). Like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deprecation: Thu, 21 Jan 2021 23:59:59 GMT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're deprecating the whole endpoint or service, you can just return this with every response. If you're deprecating a specific feature, perhaps a parameter, request method, or a certain field in the request body, then you want to just return this in requests when that feature is used.&lt;/p&gt;

&lt;p&gt;To give the client more information, you can use &lt;code&gt;Link&lt;/code&gt; HTTP response headers to link to endpoints or human-readable documentation elsewhere. You can more than one of these in combination in the same &lt;code&gt;Link&lt;/code&gt; header, by just comma-separating them (we'll see a full example later). The spec defines 4 links related to deprecation:&lt;/p&gt;

&lt;h4&gt;
  
  
  Deprecation links
&lt;/h4&gt;

&lt;p&gt;You can link to a human-readable description of the deprecation like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Link: &amp;lt;https://developer.example.com/deprecation&amp;gt;; rel="deprecation"; type="text/html"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the main way to tell your users what's going on, and what they should do about it. You almost always want to use this! If you don't have the full details and a final shutdown date yet, then even a placeholder saying that will be helpful. In that case, don't forget to let users subscribe for updates, with a mailing list or RSS or similar, so they can hear about the full plan once it's ready.&lt;/p&gt;

&lt;h4&gt;
  
  
  Latest-Version links
&lt;/h4&gt;

&lt;p&gt;If you want clients to move to the latest version of the same endpoint of your API, use this to point them there, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Link: &amp;lt;https://api.example.com/v10/customers&amp;gt;; rel="latest-version"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Successor-Version links
&lt;/h4&gt;

&lt;p&gt;If you have multiple versions of your API available, it's usually nicer to migrate one version forwards at a time, rather than jumping straight from the oldest now-deprecated version to the latest. To help with this, you can link to the &lt;em&gt;next&lt;/em&gt; version of the deprecated endpoint, not just the latest, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Link: &amp;lt;https://api.example.com/v2/customers&amp;gt;; rel="successor-version"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Alternate links
&lt;/h4&gt;

&lt;p&gt;If there's no new equivalent version of this API, and users should migrate to a totally different resource that might be a good substitute, you can use alternate links to indicate that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Link: &amp;lt;https://api.example.com/v2/users/123/clients&amp;gt;; rel="alternate"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Sunset Header
&lt;/h3&gt;

&lt;p&gt;Once you know when the API is going to shutdown entirely, you should add a &lt;a href="https://datatracker.ietf.org/doc/rfc8594/?include_text=1"&gt;Sunset header&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Sunset header tells clients when this will stop working. It's a hard deadline: API clients &lt;em&gt;must&lt;/em&gt; move elsewhere before this date, and you promise not to break anything until then.&lt;/p&gt;

&lt;p&gt;You must provide a date here, and it &lt;em&gt;should&lt;/em&gt; be in the future. If it's in the past, that's OK though: at that point you're effectively saying "this could turn off at any moment you need to stop using it immediately". It looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sunset: Tue, 20 Jul 2021 23:59:59 GMT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is super simple, and can be used for more than just API shutdowns: you can use it to signal HTTP redirects that will come in the future for URL migrations, or to indicate limited lifetimes of certain URLs (for content that's temporary by nature, or for regulatory reasons like data retention policies on certain resources). All it says is "this endpoint may stop doing what you expect after this date, be ready".&lt;/p&gt;

&lt;h4&gt;
  
  
  Sunset links
&lt;/h4&gt;

&lt;p&gt;This spec also provides a sunset link relationship. This is designed to link to more information about your plan for shutting down this specific endpoint (probably the same documentation as your deprecation link, if you have one) or about the general sunset policy for your service. Like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Link: &amp;lt;http://developer.example.com/our-sunset-policy&amp;gt;;rel="sunset";type="text/html"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a good place to point out that a general sunset policy is a very useful thing! A sunset policy tells clients when you shut down endpoints (e.g. 1 year after a replacement goes live) how users should ensure they hear about this (mailing lists, status pages, HTTP headers, you name it), what they should usually do about it (update, check the docs, follow &lt;code&gt;Link&lt;/code&gt; headers).&lt;/p&gt;

&lt;p&gt;Adding one doesn't help much with doing a deprecation right now, but if you'd published one a year ago, your clients would be ready already. The second best time to publish a sunset/deprecation policy is now. Might be worth considering if you're writing deprecation docs anyway.&lt;/p&gt;

&lt;h3&gt;
  
  
  All together
&lt;/h3&gt;

&lt;p&gt;These parts are designed to work nicely together. For example, to indicate that an API was deprecated recently, will be turned off in 6 months, link to the documentation, and provide a direct link to the next version, you should include headers like this in the response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deprecation: Thu, 21 Jan 2021 23:59:59 GMT
Sunset: Tue, 20 Jul 2021 23:59:59 GMT
Link: &amp;lt;https://api.example.com/v2/customers&amp;gt;; rel="successor-version",
    &amp;lt;https://developer.example.com/shutting-down-customers-v1&amp;gt;; rel="deprecation"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Progressive shutdowns
&lt;/h2&gt;

&lt;p&gt;Once all that's in place, and your sunset deadline has passed, you're good to go.&lt;/p&gt;

&lt;p&gt;That doesn't mean you need to immediately kill the API completely though. Progressive shutdowns can help ensure that any clients still using this API get a last-chance warning before it disappears completely. GitHub &lt;a href="https://github.blog/2018-02-01-crypto-removal-notice/"&gt;did this&lt;/a&gt; when removing some crypto support in 2018: first they disabled it for one hour, then reenabled it, then they disabled it permanently two weeks later.&lt;/p&gt;

&lt;p&gt;There's other tricks too: Android &lt;a href="https://twitter.com/jbaruch/status/930476565065953280"&gt;added increasing delays to deprecated native APIs&lt;/a&gt; in 2015, eventually going up to a full 16 second wait, before finally turning off the API entirely. These progressive shutdowns provide a little flexibility for clients who miss your deadline, and may help clients who haven't noticed the deprecation spot and deal with the issue before the API turns off completely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flip the switch
&lt;/h2&gt;

&lt;p&gt;Either way, once you've done the best you can to communicate the shutdown, it's time to turn off the endpoint/feature/entire service, delete the code, and finally go take that nap.&lt;/p&gt;

&lt;p&gt;Doing deprecations and shutdowns carefully like this makes it as clear as possible to your clients how they can depend on your API, when they need to take action, and what they need to do. These kind of changes can be a big deal, and this information is important!&lt;/p&gt;

&lt;p&gt;These new draft headers allow us to communicate not only to humans, but also to expose this information to automated systems. As these headers become widespread, I'm really excited to start seeing more tooling building on top of them. Generic HTTP clients can log useful warnings automatically based on this data, API generators themselves can handle more and more of this for you based on API specifications, and HTTP debuggers like &lt;strong&gt;&lt;a href="https://httptoolkit.tech/"&gt;HTTP Toolkit&lt;/a&gt;&lt;/strong&gt; can highlight usages of deprecated endpoints for you in intercepted live traffic. It's an exciting time to start turning things off!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is important to note that these headers are &lt;em&gt;draft&lt;/em&gt; HTTP specifications&lt;/strong&gt;. It's possible they may change before they're finalized. That said, they've been through a few rounds of revisions already, it's fairly unlikely they'll change dramatically from here, and it's time to start testing them in the wild.&lt;/p&gt;

&lt;p&gt;This does mean there's still time for feedback though! If you have thoughts on how this works and how it could work better, get in touch with the "Building Blocks for HTTP APIs" working group. You can email the mailing list at &lt;a href="//mailto:httpapi@ietf.org"&gt;httpapi@ietf.org&lt;/a&gt;, or scroll the previous mailing list discussions &lt;a href="https://mailarchive.ietf.org/arch/browse/httpapi/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://httptoolkit.tech/blog/how-to-turn-off-your-old-apis/"&gt;the HTTP Toolkit blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>http</category>
      <category>webdev</category>
      <category>api</category>
    </item>
    <item>
      <title>Mining your CLI history for good git aliases</title>
      <dc:creator>Tim Perry</dc:creator>
      <pubDate>Mon, 30 Nov 2020 13:35:00 +0000</pubDate>
      <link>https://dev.to/pimterry/mining-your-cli-history-for-good-git-aliases-41c8</link>
      <guid>https://dev.to/pimterry/mining-your-cli-history-for-good-git-aliases-41c8</guid>
      <description>&lt;p&gt;If you use the command-line all day, CLI improvements can add a huge boost to your workflow. One of the simplest ways to improve things is to make your most used commands easier &amp;amp; faster to type, by creating aliases.&lt;/p&gt;

&lt;p&gt;But which aliases? Which commands are most important for your usage? You can probably guess a couple, but it's hard to know for sure, and there's plenty you'll miss. Fortunately your CLI history already has all the answers, if you just know how to ask.&lt;/p&gt;

&lt;p&gt;As a software developer I'm going to focus on git aliases here, but this applies equally well to any command-line tools you use heavily. I'm also assuming a bash-compatible shell, but the same concept should translate elsewhere easily enough.&lt;/p&gt;

&lt;p&gt;The first step is to use &lt;code&gt;history&lt;/code&gt; to do some digging and find out what commands you run most frequently. &lt;code&gt;history&lt;/code&gt; prints every line you've run recently in your shell, in chronological order. That gives us the data we need, and with a little bash-fu we can start to get some answers.&lt;/p&gt;

&lt;p&gt;First, what're your most run git commands?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;git | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;uniq&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-k1&lt;/span&gt;,1nr &lt;span class="nt"&gt;-k2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That takes your history, filters for git commands, sorts them alphabetically, counts the repeated lines, and then sorts by the repeat count.&lt;/p&gt;

&lt;p&gt;You can add a &lt;code&gt;| head -n X&lt;/code&gt; too, if you'd like to see just the top &lt;code&gt;X&lt;/code&gt; results. For me, with a few weeks history on a new laptop, that looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    543 git status
    272 git add &lt;span class="nt"&gt;-p&lt;/span&gt;
    214 git tree
     71 git diff
     55 git commit &lt;span class="nt"&gt;--amend&lt;/span&gt;
     53 git push origin master
     32 git checkout &lt;span class="nt"&gt;-p&lt;/span&gt;
     30 git reset
     27 git stash pop
     26 git stash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That tells you a bunch about my git workflow already! These are all common commands I'm using frequently, and commands I should very seriously consider aliasing.&lt;/p&gt;

&lt;p&gt;It doesn't tell the whole story though. How come &lt;code&gt;git commit --amend&lt;/code&gt; is so high up, but &lt;code&gt;git commit&lt;/code&gt; doesn't appear at all?&lt;/p&gt;

&lt;p&gt;That's because for many commits I run &lt;code&gt;git commit -m "..."&lt;/code&gt; to commit and pass a message inline, so each of those commands is treated as unique, and won't appear in this top list. We need to get a little smarter.&lt;/p&gt;

&lt;p&gt;We can catch cases like that too, by limiting the input we consider for uniqueness. Like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;git | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;-3&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;uniq&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-k1&lt;/span&gt;,1nr &lt;span class="nt"&gt;-k2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I've added &lt;code&gt;cut -d' ' -f -3&lt;/code&gt;, which splits each line by spaces, and includes only the first 3 parts (e.g. &lt;code&gt;git push origin master&lt;/code&gt; becomes &lt;code&gt;git push origin&lt;/code&gt;). This isn't perfect, but it does let us find command prefixes of a given length.&lt;/p&gt;

&lt;p&gt;With that, my results become:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    543 git status
    299 git add &lt;span class="nt"&gt;-p&lt;/span&gt;
    214 git tree
    199 git commit &lt;span class="nt"&gt;-m&lt;/span&gt;
    117 git push origin
     71 git diff
     60 git commit &lt;span class="nt"&gt;--amend&lt;/span&gt;
     34 git checkout &lt;span class="nt"&gt;-p&lt;/span&gt;
     30 git reset
     29 git diff &lt;span class="nt"&gt;--cached&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now see that I'm committing a lot too, but with messages, I'm pushing with many other branches, and I'm diffing my cached (already added) changes often, but usually with an argument ('show me what I've just added to the tests').&lt;/p&gt;

&lt;p&gt;Fiddle around with this a little, try a few different lengths of prefix, and you'll quickly find a set of commands that stand out with frequent use patterns, with or without extra arguments.&lt;/p&gt;

&lt;p&gt;From there, it's alias time. I could make these aliases within git, but I'd actually prefer to do it at the shell level, so I can shorten them further (not just to &lt;code&gt;git x&lt;/code&gt; but &lt;code&gt;gx&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;In my case, I'm doing that by adding the below to my &lt;code&gt;.bashrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;git status
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;git add &lt;span class="nt"&gt;-p&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;git tree

&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;git commit
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gcm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gca&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;git commit &lt;span class="nt"&gt;--amend&lt;/span&gt;

&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gpo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;git push origin
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;git diff
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gdc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;git diff &lt;span class="nt"&gt;--cached&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Don't forget to check these don't conflict with anything else you use on your machine!)&lt;/p&gt;

&lt;p&gt;These aliases can also be a very convenient place to add any extra arguments you often want but don't always remember, like &lt;code&gt;-w&lt;/code&gt; for &lt;code&gt;diff&lt;/code&gt; (ignore whitespace changes) or &lt;code&gt;-v&lt;/code&gt; for &lt;code&gt;git commit&lt;/code&gt; (include the diff contents in the commit template, so you can see it while you write your message).&lt;/p&gt;

&lt;p&gt;It's a quick trick, but just a little bash magic can tell you a lot about your working habits, and shine a useful light on ways you can make your life easier. Give it a go, and let me know what you think on &lt;a href="https://twitter.com/pimterry"&gt;Twitter&lt;/a&gt; or in the comments below.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://httptoolkit.tech/blog/find-best-git-aliases/"&gt;the HTTP Toolkit blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>git</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Intercepting HTTPS on Android</title>
      <dc:creator>Tim Perry</dc:creator>
      <pubDate>Thu, 05 Nov 2020 18:00:00 +0000</pubDate>
      <link>https://dev.to/pimterry/intercepting-https-on-android-393k</link>
      <guid>https://dev.to/pimterry/intercepting-https-on-android-393k</guid>
      <description>&lt;p&gt;To intercept, inspect or manipulate HTTPS traffic, you need the HTTPS client to trust you.&lt;/p&gt;

&lt;p&gt;If you want to intercept your own HTTPS on Android, perhaps to capture &amp;amp; rewrite traffic from your Android device for debugging or testing, how do you do that?&lt;/p&gt;

&lt;p&gt;This isn't theoretical - &lt;a href="https://httptoolkit.tech/android/"&gt;HTTP Toolkit&lt;/a&gt; does exactly this, automatically intercepting HTTPS from real Android devices, for inspection, testing &amp;amp; mocking. To do so, it has to automatically ensure that it's trusted by HTTPS clients on Android devices, without breaking security on those devices completely (it would be a very bad idea to simply turn off certificate validation, for example). Here's a demo: &lt;a href="https://www.youtube.com/watch?v=ttf8IhfI0Ao"&gt;https://www.youtube.com/watch?v=ttf8IhfI0Ao&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's talk though how HTTPS clients in general manage this kind of trust, see how that works on Android specifically, and then look at how it's possible to get around this and intercept real HTTPS traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  How HTTPS trust works
&lt;/h2&gt;

&lt;p&gt;An HTTPS request is an HTTP request, made over a TLS connection. Everything we're going to talk about here is really about TLS - the HTTP within is just normal &lt;code&gt;GET /&lt;/code&gt; requests and &lt;code&gt;200 OK&lt;/code&gt; responses.&lt;/p&gt;

&lt;p&gt;I'm not going to go into the lowest level details, but it is important to understand the basics of how TLS works. If you are interested in the fine details of TLS, &lt;a href="https://tls13.ulfheim.net/"&gt;The Illustrated TLS Connection&lt;/a&gt; is well worth a look, for a byte-by-byte breakdown of the whole process.&lt;/p&gt;

&lt;p&gt;The high-level summary is this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every TLS client keeps track of some set of root certificate authorities (root CAs) that it trusts completely.&lt;/li&gt;
&lt;li&gt;When any modern TLS client first connects to a server, its initial message includes a Server Name Indication (SNI), telling the server which hostname it's looking for (e.g. example.com). It expects the server's response to include a valid certificate for that hostname.&lt;/li&gt;
&lt;li&gt;TLS certificates include a reference to the issuer of the certificate, and a signature proving that the issuer verified the certificate. The issuer's certificate in turn will have its own issuer &amp;amp; signature, creating a chain of certificates, up until a final self-signed root certificate.&lt;/li&gt;
&lt;li&gt;The client must decide if it trusts the server's certificate. It does so by checking the details of the certificate (notably checking the hostname is what was expected), and then examining the issuer of the certificate, and then issuer of the issuer's certificate, and so on and so on until it reaches a certificate that it already trusts (a trusted certificate authority) or running out of issuers and deciding that it doesn't trust the certificate at all.&lt;/li&gt;
&lt;li&gt;If the client trusts the certificate, it continues creating the encrypted connection, and then sends and receives data over that connection. If it doesn't trust the certificate, it closes the connection before sending any content, i.e. it never sends any part of its HTTPS request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short: every TLS client has a list of root CAs that it trusts, and to successfully receive an HTTPS request, you must be able to present a certificate for the target hostname that includes a trusted root CA somewhere in its chain.&lt;/p&gt;

&lt;p&gt;This is a bit simplified and I'm ignoring all sorts of edge cases, but it's enough for our purposes. If you'd like to get into the nitty gritty of how the certificate validation really works, Scott Helme has written up &lt;a href="https://scotthelme.co.uk/cross-signing-alternate-trust-paths-how-they-work/"&gt;a great guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, given the above, if we want to intercept HTTPS we need to be able to present a certificate issued by a trusted certificate authority. Since nobody reading this has a globally trusted root CA to hand, in practice that means we need to create our own CA, and ensure the TLS client (in this case, Android's HTTPS clients) already trusts that CA, before we can get started.&lt;/p&gt;

&lt;p&gt;How do Android HTTPS clients decide who they trust?&lt;/p&gt;

&lt;h2&gt;
  
  
  Android Certificate Stores
&lt;/h2&gt;

&lt;p&gt;Each HTTPS or TLS client on Android will check certificates against the CAs in some certificate store.&lt;/p&gt;

&lt;p&gt;There's at least 3 types of Android CA certificate store:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The OS has a 'system' certificate store, at &lt;code&gt;/system/etc/security/cacerts/&lt;/code&gt;. This is prepopulated on the device at install time, it's impossible to add certificates to it without root access, and is used as the default list of trusted CA certificates by most apps. In practice, this store defines which CA certificate most apps on your phone will trust.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The OS also has a 'user' certificate store, usually at &lt;code&gt;/data/misc/user/0/cacerts-added/&lt;/code&gt;, containing trusted CA certificates that were manually installed by the user of the device. Installing one of these certificates requires accepting quite a few warnings, and &lt;a href="https://httptoolkit.tech/blog/android-11-trust-ca-certificates/"&gt;became even more difficult in Android 11&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Apps targeting Android API level &amp;lt;24, i.e. before Android 7, or applications that specifically opt in will trust CA certificates in this store. Most apps don't, but this is enabled on a few apps where it's widely useful (notably Chrome, &lt;a href="https://www.chromium.org/Home/chromium-security/root-ca-policy"&gt;for now&lt;/a&gt;) and it's easy for developers to enable for testing with &lt;a href="https://httptoolkit.tech/docs/guides/android/#if-you-dont-have-a-custom-network-security-config"&gt;a few lines of XML&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lastly, each application can include its own CA certificates, embedding its own short list of trusted certificate authorities internally, and refusing to trust HTTPS communication with certificates signed by anybody else. Nowadays this is fairly uncommon, except for apps that are especially security conscious (banking) or very high-profile (facebook), mostly because it's complicated and the changes in Android 7 to untrust the user store make this kind of pinning unnecessary.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to intercept HTTPS traffic from an app, you need to ensure your CA certificate is trusted in the app's certificate store of choice. How can you do that?&lt;/p&gt;

&lt;h2&gt;
  
  
  How to intercept Android HTTPS
&lt;/h2&gt;

&lt;p&gt;To intercept HTTPS, you first need the TLS connections to come to you. HTTP Toolkit runs as a desktop app on your computer, acting as an HTTP(S) proxy, and does this with an Android VPN app on the device that redirects packets to that proxy. I've written quite a bit of detail about that &lt;a href="https://httptoolkit.tech/blog/inspecting-android-http"&gt;over here&lt;/a&gt;, and it's fairly easy to do if you either use the VPN APIs or configure an HTTPS proxy, so let's take that as a given.&lt;/p&gt;

&lt;p&gt;Once you have TLS connections going to our server, you need to be able to respond to the initial client handshake with a certificate that Android will trust. Typically you'll generate a self-signed CA certificate when setting up interception, and then use that to generate TLS certificates for incoming connections, generating a fresh certificate for each requested hostname.&lt;/p&gt;

&lt;p&gt;To make that work, you need to make your Android device's HTTPS clients trust your locally generated CA.&lt;/p&gt;

&lt;p&gt;There's two big cases here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Non-rooted production devices. Normal phones. This includes most phones sold and used day to day, and official 'Google Play' Android emulators.&lt;/li&gt;
&lt;li&gt;Rooted devices. More specifically: devices where root access is available via ADB (not that root access is necessarily available to apps on the device). This includes normal phones that have been manually rooted, but also both the 'Google APIs' and AOSP official Google emulators, and most other Android emulators like &lt;a href="https://www.genymotion.com/"&gt;Genymotion&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In general, less than 1% (according to some &lt;em&gt;very&lt;/em&gt; &lt;a href="https://www.quora.com/What-percentage-of-Android-phones-are-rooted"&gt;dubious&lt;/a&gt; &lt;a href="https://www.reddit.com/r/Android/comments/ue3gc/what_percentage_of_android_phone_users_a_root/c4ullqs/"&gt;guesstimates&lt;/a&gt;) of typical user's devices are rooted.&lt;/p&gt;

&lt;p&gt;However for Android developers, testers, and security researchers, that number runs far higher. Within HTTP Toolkit's user base for example, it looks closer to 30% (whilst I don't know for sure, but I suspect that emulators make up a large percentage of that).&lt;/p&gt;

&lt;h3&gt;
  
  
  Injecting CA certificates into rooted devices
&lt;/h3&gt;

&lt;p&gt;This is the fun case. If you have root, how do you make apps trust your CA certificate? It turns out that even with root it's not quite as easy as it could be, but it's definitely possible to inject system certificates, so that almost all apps trust your CA by default.&lt;/p&gt;

&lt;p&gt;There's a couple of challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Even as root, &lt;code&gt;/system&lt;/code&gt; is not writable by default&lt;/li&gt;
&lt;li&gt;Making &lt;code&gt;/system&lt;/code&gt; writable on emulators is only possible if the emulator is always started with an extra command line argument, and so requires restarting the emulator if that's not already set. To make this worse, it's not possible to set custom command line arguments in Android Studio, making this very inconvenient for normal use.&lt;/li&gt;
&lt;li&gt;Even if you write a valid CA certificate to the right place in the system certificate files, it won't be recognized. You need to ensure all the permissions &amp;amp; SELinux context labels are set correctly before Android will trust files in that directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To handle all this, as root, HTTP Toolkit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pushes the HTTP Toolkit CA certificate to the device over ADB.&lt;/li&gt;
&lt;li&gt;Copies all system certificates out of &lt;code&gt;/system/etc/security/cacerts/&lt;/code&gt; to a temporary directory.&lt;/li&gt;
&lt;li&gt;Mounts a &lt;a href="https://en.wikipedia.org/wiki/Tmpfs"&gt;tmpfs&lt;/a&gt; in-memory filesystem on top of &lt;code&gt;/system/etc/security/cacerts/&lt;/code&gt;. This effectively places a fresh empty filesystem that &lt;em&gt;is&lt;/em&gt; writable over the top of a small part of &lt;code&gt;/system&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Moves the copied system certificates back into that mount.&lt;/li&gt;
&lt;li&gt;Moves the HTTP Toolkit CA certificate into that mount too.&lt;/li&gt;
&lt;li&gt;Updates the permissions to &lt;code&gt;644&lt;/code&gt; &amp;amp; sets the &lt;code&gt;system_file&lt;/code&gt; SELinux label on everything in the temporary mount, so it all looks like legitimate Android system files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is all open source of course, and the full script to do this is here: &lt;a href="https://github.com/httptoolkit/httptoolkit-server/blob/8a4b4d283fbe98694ddd09a44d6e9c9941aa91e2/src/interceptors/android/adb-commands.ts#L200-L253"&gt;httptoolkit-server:adb-commands.ts#L200-L253&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have a CA certificate, you can do this for yourself on any device with root access, to temporarily add new CAs that'll be trusted like any other CA prebundled on the device.&lt;/p&gt;

&lt;p&gt;If you are doing this for yourself though, be careful around permissions, as the default for ADB pushed files is very relaxed. If the CA you inject or the copied system certificates are globally writable, it'd be theoretically possible for another app on the device to change or add a CA during this process, and sneakily get visibility into all HTTPS traffic on the device for itself without you realizing or granting it root access.&lt;/p&gt;

&lt;p&gt;All put together, this injects a system certificate without needing emulator startup arguments, and works 100% automatically &amp;amp; immediately, without even needing to reboot. As a nice bonus the tmpfs disappears on reboot, so everything is cleaned up automatically afterwards, and you only trust the inject CA temporarily (wherever possible, it's always a good idea to &lt;a href="https://httptoolkit.tech/blog/debugging-https-without-global-root-ca-certs"&gt;limit and/or avoid global developer CAs&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Intercepting HTTPS on non-rooted devices
&lt;/h3&gt;

&lt;p&gt;If you don't have root access, you can't do this. Instead, the best you can do is to install the certificate into the user store. To do so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you're setting the device up manually:

&lt;ul&gt;
&lt;li&gt;Download the certificate onto your device.&lt;/li&gt;
&lt;li&gt;Go to "Encryption &amp;amp; Credentials" in your device security settings.&lt;/li&gt;
&lt;li&gt;Select "Install a certificate", then "CA Certificate".&lt;/li&gt;
&lt;li&gt;Open the downloaded certificate, and follow the confirmation prompts.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;If you're automating/scripting this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On Android up to and including Android 10, you can use the &lt;a href="https://developer.android.com/reference/android/security/KeyChain#createInstallIntent()"&gt;KeyChain.createInstallIntent()&lt;/a&gt; to prompt users to trust your CA certificate in your app. There'll be some warnings there, and they'll need to set or confirm the device pin to do so, but it's very straightforward. You can see HTTP Toolkit's code in &lt;a href="https://github.com/httptoolkit/httptoolkit-android/blob/03f10f2eff28f30d8cdbfb9fe86a075891714172/app/src/main/java/tech/httptoolkit/android/MainActivity.kt#L603-L606"&gt;httptoolkit-android:MainActivity.kt#L603-L606&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On Android 11, due to &lt;a href="https://httptoolkit.tech/blog/android-11-trust-ca-certificates"&gt;recent changes&lt;/a&gt; you're in trouble. You can't launch the prompt to trust a CA directly, and it must be installed in the settings completely manually. If you do try to use the &lt;code&gt;createInstallIntent()&lt;/code&gt; API to install the certificate, it just shows "Can't install CA certificates: CA certificates can put your privacy at risk and must be installed in Settings".&lt;/p&gt;

&lt;p&gt;If you download the CA certificate to the device though, it's easy enough to explain the process to users, and you can see how HTTP Toolkit does that in &lt;a href="https://github.com/httptoolkit/httptoolkit-android/blob/03f10f2eff28f30d8cdbfb9fe86a075891714172/app/src/main/java/tech/httptoolkit/android/MainActivity.kt#L615-L661"&gt;httptoolkit-android:MainActivity.kt#L615-L661&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With that done you can intercept HTTPS from Chrome, and other Chromium-based browsers, and you can intercept traffic from apps that explicitly opt in.&lt;/p&gt;

&lt;p&gt;If you're debugging your own app that's fine, since it's just a few lines of XML to do so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;network-security-config&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;base-config&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;trust-anchors&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;certificates&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"system"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;certificates&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"user"&lt;/span&gt; &lt;span class="na"&gt;overridePins=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/trust-anchors&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/base-config&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/network-security-config&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That XML trusts the user CA certificates installed on the device, if saved as an XML resources like &lt;code&gt;network_security_config.xml&lt;/code&gt; and referenced with &lt;code&gt;android:networkSecurityConfig="@xml/network_security_config"&lt;/code&gt; in the &lt;code&gt;&amp;lt;application&amp;gt;&lt;/code&gt; element of your app manifest.&lt;/p&gt;

&lt;p&gt;With that and a certificate in your user store, you're done! But only if you're trying to intercept Chrome or your own apps...&lt;/p&gt;

&lt;h3&gt;
  
  
  Intercepting HTTPS from a 3rd party app on non-rooted devices
&lt;/h3&gt;

&lt;p&gt;One last case then: what if you have a non-rooted phone, and you want to intercept HTTPS from an app that doesn't trust the user CA store, and which you can't easily edit the source code for yourself? For example, if you want to inspect HTTPS traffic from somebody else's app, or from your own existing production builds?&lt;/p&gt;

&lt;p&gt;This is a tricky case on Android nowadays, but still it's often possible. You'll still need to edit the app, but it turns out you can do so without directly rebuilding from source.&lt;/p&gt;

&lt;p&gt;First, you need to download the APK for the app. APKs aren't available for direct download from Google Play, but they are often available in various other alternate sites, with &lt;a href="https://apkpure.com"&gt;ApkPure.com&lt;/a&gt; being the most well known. You can search for most Google Play apps there to download an APK and get started.&lt;/p&gt;

&lt;p&gt;Once you have an APK, you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decode &amp;amp; unpack the contents.&lt;/li&gt;
&lt;li&gt;Patch the network config within to trust the user certificate store.&lt;/li&gt;
&lt;li&gt;Repack an APK from that patched contents.&lt;/li&gt;
&lt;li&gt;Sign the APK with a valid certificate so it can be installed on the device.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That can be quite complicated, but fortunately there's a tool called &lt;a href="https://github.com/shroudedcode/apk-mitm#apk-mitm"&gt;apk-mitm&lt;/a&gt; that can do all of this for you! In addition, it strips pinned certificates and can even automatically patch apps using the newer Android App Bundle format.&lt;/p&gt;

&lt;p&gt;If you have Node.js (10+) &amp;amp; Java (8+) installed, installing and using this just requires:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npx apk-mitm ./downloaded-app.apk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That should complete the above steps and give you a patched APK. If you've already trusted your CA certificate in your device's user store, as in the previous section, just install the patched app with &lt;code&gt;adb install ./patched-app.apk&lt;/code&gt; and you're away.&lt;/p&gt;




&lt;p&gt;Hopefully that's a good intro into managing HTTPS trust on Android, and using &amp;amp; abusing it to intercept, inspect and rewrite HTTPS traffic.&lt;/p&gt;

&lt;p&gt;Want to see this in action and see exactly what HTTPS your apps and device are sending? Give &lt;strong&gt;&lt;a href="https://httptoolkit.tech/android"&gt;HTTP Toolkit&lt;/a&gt;&lt;/strong&gt; a go now.&lt;/p&gt;

&lt;p&gt;Want to know more about how this all works? HTTP Toolkit is 100% open-source, so feel free to check out &lt;a href="http://github.com/httptoolkit"&gt;HTTP Toolkit on GitHub&lt;/a&gt;, and do &lt;a href="https://httptoolkit.tech/contact"&gt;get in touch&lt;/a&gt; or comment below if you have any questions or feedback.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="//httptoolkit.tech/blog/intercepting-android-https/"&gt;the HTTP Toolkit blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>security</category>
      <category>http</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Migrating a JS project from Travis to GitHub Actions</title>
      <dc:creator>Tim Perry</dc:creator>
      <pubDate>Tue, 27 Oct 2020 11:45:00 +0000</pubDate>
      <link>https://dev.to/pimterry/migrating-a-js-project-from-travis-to-github-actions-251n</link>
      <guid>https://dev.to/pimterry/migrating-a-js-project-from-travis-to-github-actions-251n</guid>
      <description>&lt;p&gt;Travis has been the most popular place to build open-source code for a long time, but the world is moving on. GitHub Actions is modern, tightly integrated with the most popular code hosting platform in the world, flexible, fast, and free (for public repos).&lt;/p&gt;

&lt;p&gt;Travis has been popular for years though, there's still a lot of projects being built there, including many of &lt;a href="https://httptoolkit.tech/"&gt;HTTP Toolkit&lt;/a&gt;'s own repos.&lt;/p&gt;

&lt;p&gt;Last week, I decided to bite the bullet, and start migrating. Travis was having a particularly bad build backlog day, and HTTP Toolkit is entirely open source on GitHub already, so it's super convenient. I've been looking longingly at GitHub Actions builds on other projects for a little while, and I'd already seen lots of useful extensions in the &lt;a href="https://github.com/marketplace?type=actions"&gt;marketplace&lt;/a&gt; of drop-in action steps that'd make my life much easier.&lt;/p&gt;

&lt;p&gt;Unfortunately, I knew very little about GitHub actions, and I already had some Travis configuration that worked. In this post, I want to share how I converted my JavaScript (well, TypeScript) build from Travis to GitHub, so you can do the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Goal
&lt;/h2&gt;

&lt;p&gt;I decided to start with the simplest Travis setup I had: the &lt;a href="https://github.com/httptoolkit/httptoolkit-ui"&gt;HTTP Toolkit UI repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's the previous &lt;code&gt;travis.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dist: xenial
sudo: required
language: node_js
node_js:
    - '14'
install:
    - npm ci
services:
    - xvfb
before_script:
    - sudo chown root /opt/google/chrome/chrome-sandbox
    - sudo chmod 4755 /opt/google/chrome/chrome-sandbox
script:
    - npm test
addons:
    chrome: stable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's a few notable things here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I want to build with a specific node version.&lt;/li&gt;
&lt;li&gt;I need Chrome &amp;amp; XVFB installed for testing with Puppeteer &amp;amp; Karma.&lt;/li&gt;
&lt;li&gt;There's some existing workarounds (&lt;code&gt;before_script&lt;/code&gt;) for Travis.yml in here.&lt;/li&gt;
&lt;li&gt;The build itself is just &lt;code&gt;npm ci&lt;/code&gt; to install dependencies and then &lt;code&gt;npm test&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Although not shown here, some of the npm dependencies include native node extensions, and need a working native build environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One other feature I'd really like, and which I'd strongly recommend for everybody, is the option to &lt;strong&gt;run an equivalent CI environment locally&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Yes, you can install and run tests on my machine normally, but especially with more complicated builds you'll quickly discover that that isn't a &lt;em&gt;perfect&lt;/em&gt; match for the cloud build environment, and you'll occasionally hit remote failures that don't reproduce in your own environment. Slightly different versions of Chrome or Node, leftover git-ignored files and build output, and other environment-specific details can cause havoc.&lt;/p&gt;

&lt;p&gt;Being able to quickly reproduce the exact cloud build environment locally makes debugging those issues much less frustrating!&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;We'll start with GitHub's &lt;a href="https://docs.github.com/en/free-pro-team@latest/actions/guides/building-and-testing-nodejs"&gt;JavaScript action getting started guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That summarizes the options available, and with a little wrangling that quickly gets us to a basic workflow (which I've saved as &lt;code&gt;.github/workflows/ci.yml&lt;/code&gt;) matching the essential steps of the Travis config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: CI
on: push
jobs:
  build:
    name: Build &amp;amp; test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      # Install Node 14
      - uses: actions/setup-node@v1
        with:
          node-version: 14

      # Install &amp;amp; build &amp;amp; test:
      - run: npm ci
      - run: npm test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Very clear and easy: every time code is pushed, check it out and use node 14 to install dependencies &amp;amp; run the tests.&lt;/p&gt;

&lt;p&gt;Note that I've skipped the Chrome &amp;amp; XVFB steps here entirely - we don't need them. The GitHub base image (&lt;code&gt;ubuntu-latest&lt;/code&gt;) includes Chrome set up for testing and a enough of a native build environment that you can immediately install native modules and get going. Great! You can see the full standard list of what's available in each image here: &lt;a href="https://docs.github.com/en/free-pro-team@latest/actions/reference/specifications-for-github-hosted-runners#supported-software"&gt;https://docs.github.com/en/free-pro-team@latest/actions/reference/specifications-for-github-hosted-runners#supported-software&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You may find there's one small code change required though: you need to pass &lt;code&gt;no-sandbox&lt;/code&gt; as an option to Chrome, if you're not already using it. This ensures Chrome runs happily in containerized environments like this (I think the &lt;code&gt;chrome-sandbox&lt;/code&gt; steps in the Travis config were actually old workarounds for this on Travis).&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://github.com/httptoolkit/httptoolkit-ui/blob/64b89dec90f5ea86290b4091008974b06639d519/test/unit/karma.conf.js#L30-L36"&gt;my Karma config&lt;/a&gt;, using headless Chrome, that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;browsers: ['ChromeHeadlessNoSandbox'],
customLaunchers: {
    ChromeHeadlessNoSandbox: {
        base: 'ChromeHeadless',
        flags: ['--no-sandbox']
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Puppeteer, my &lt;a href="https://github.com/httptoolkit/httptoolkit-ui/blob/64b89dec90f5ea86290b4091008974b06639d519/test/integration/smoke-test.spec.ts#L24-L29"&gt;browser launch code&lt;/a&gt; looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;puppeteer.launch({
    headless: true,
    args: ['--no-sandbox']
}),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Very easy. A quick &lt;code&gt;git push&lt;/code&gt; and you'll see your job start running on GitHub's cloud runners straight away.&lt;/p&gt;

&lt;p&gt;But we also wanted reproducible local builds too...&lt;/p&gt;

&lt;h2&gt;
  
  
  Build Like a Local
&lt;/h2&gt;

&lt;p&gt;Being able to locally reproduce your CI builds is essential for a healthy CI workflow, and with GitHub Actions it's already very easy.&lt;/p&gt;

&lt;p&gt;To run builds locally, we can use &lt;a href="https://github.com/nektos/act"&gt;act&lt;/a&gt;. GitHub Actions is built on Docker, starting images specified and injecting configuration into containers to run your build. Act does the exact same thing: parsing your workflow and automating Docker on your local machine to build in the exact same way.&lt;/p&gt;

&lt;p&gt;To try this out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;a href="https://www.docker.com/get-started"&gt;Docker&lt;/a&gt;, if you don't have it already&lt;/li&gt;
&lt;li&gt;Install &lt;a href="https://github.com/nektos/act#installation"&gt;act&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;act&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That will automatically find &lt;code&gt;.github/workflows/*.yml&lt;/code&gt; files in your current directory, and attempt to run them. Unfortunately, in my project that doesn't work so well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| &amp;gt; registry-js@1.12.0 install /github/workspace/node_modules/registry-js
| &amp;gt; prebuild-install || node-gyp rebuild
| 
| prebuild-install WARN install No prebuilt binaries found (target=14.14.0 runtime=node arch=x64 libc= platform=linux)
| gyp ERR! find Python 
| gyp ERR! find Python Python is not set from command line or npm configuration
| gyp ERR! find Python Python is not set from environment variable PYTHON
| gyp ERR! find Python checking if "python" can be used
| gyp ERR! find Python - "python" is not in PATH or produced an error
| gyp ERR! find Python checking if "python2" can be used
| gyp ERR! find Python - "python2" is not in PATH or produced an error
| gyp ERR! find Python checking if "python3" can be used
| gyp ERR! find Python - "python3" is not in PATH or produced an error
| gyp ERR! find Python 
| gyp ERR! find Python **********************************************************
| gyp ERR! find Python You need to install the latest version of Python.
| gyp ERR! find Python Node-gyp should be able to find and use Python. If not,
| gyp ERR! find Python you can try one of the following options:
| gyp ERR! find Python - Use the switch --python="/path/to/pythonexecutable"
| gyp ERR! find Python (accepted by both node-gyp and npm)
| gyp ERR! find Python - Set the environment variable PYTHON
| gyp ERR! find Python - Set the npm configuration variable python:
| gyp ERR! find Python npm config set python "/path/to/pythonexecutable"
| gyp ERR! find Python For more information consult the documentation at:
| gyp ERR! find Python https://github.com/nodejs/node-gyp#installation
| gyp ERR! find Python **********************************************************
| gyp ERR! find Python 
| gyp ERR! configure error 
| gyp ERR! stack Error: Could not find any Python installation to use
| gyp ERR! stack at PythonFinder.fail (/opt/hostedtoolcache/node/14.14.0/x64/lib/node_modules/npm/node_modules/node-gyp/lib/find-python.js:307:47)
| gyp ERR! stack at PythonFinder.runChecks (/opt/hostedtoolcache/node/14.14.0/x64/lib/node_modules/npm/node_modules/node-gyp/lib/find-python.js:136:21)
| gyp ERR! stack at PythonFinder.&amp;lt;anonymous&amp;gt; (/opt/hostedtoolcache/node/14.14.0/x64/lib/node_modules/npm/node_modules/node-gyp/lib/find-python.js:179:16)
| gyp ERR! stack at PythonFinder.execFileCallback (/opt/hostedtoolcache/node/14.14.0/x64/lib/node_modules/npm/node_modules/node-gyp/lib/find-python.js:271:16)
| gyp ERR! stack at exithandler (child_process.js:315:5)
| gyp ERR! stack at ChildProcess.errorhandler (child_process.js:327:5)
| gyp ERR! stack at ChildProcess.emit (events.js:315:20)
| gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:275:12)
| gyp ERR! stack at onErrorNT (internal/child_process.js:465:16)
| gyp ERR! stack at processTicksAndRejections (internal/process/task_queues.js:80:21)
| gyp ERR! System Linux 4.15.0-121-generic
| gyp ERR! command "/opt/hostedtoolcache/node/14.14.0/x64/bin/node" "/opt/hostedtoolcache/node/14.14.0/x64/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
| gyp ERR! cwd /github/workspace/node_modules/registry-js
| gyp ERR! node -v v14.14.0
| gyp ERR! node-gyp -v v5.1.0
| gyp ERR! not ok 
| npm ERR! code ELIFECYCLE
| npm ERR! errno 1
| npm ERR! registry-js@1.12.0 install: `prebuild-install || node-gyp rebuild`
| npm ERR! Exit status 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whilst &lt;code&gt;act&lt;/code&gt; runs build steps just like GitHub Actions does, it doesn't use the exact same base image (in part because the same image naively built locally would be &lt;a href="https://github.com/nektos/act/issues/196#issuecomment-619735743"&gt;50GB&lt;/a&gt;!). There's a few options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If you're only using basic features (normal node modules, and running &lt;code&gt;node&lt;/code&gt; scripts), &lt;code&gt;act&lt;/code&gt; will work out of the box and you're all good.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can use act's own &lt;a href="https://hub.docker.com/r/nektos/act-environments-ubuntu/tags"&gt;full-fat image&lt;/a&gt;, which includes all the standard GitHub tools in a somewhat smaller image size. This is opt-in, because it's still an up-front 6GB download (and then 18GB locally, once it's uncompressed) but it'll immediately give you everything you need from the GitHub Actions cloud environment.&lt;/p&gt;

&lt;p&gt;To use this, you just need to map &lt;code&gt;ubuntu-latest&lt;/code&gt; (the GitHub base runner) to the published image, with:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;act -P ubuntu-latest=nektos/act-environments-ubuntu:18.04
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you're familiar with Docker, you can build your own base image including just the extra tools you need. This gives you a convenient matching environment (within the selected subset of tools) with none of the disk space &amp;amp; download hassle.&lt;/p&gt;

&lt;p&gt;This is what I've done for HTTP Toolkit. The &lt;a href="https://github.com/httptoolkit/act-build-base/blob/main/Dockerfile"&gt;dockerfile&lt;/a&gt; directly runs the setup scripts from the act base image repo (in turn generated from GitHub's own setup scripts), but only runs the ones I care about: &lt;code&gt;build-essentials&lt;/code&gt; (for native builds) and Chrome. That shrinks it down to a mere 300MB download, and below 1GB on disk.&lt;/p&gt;

&lt;p&gt;You can do this for yourself, customizing your own image, or if you need the exact same customizations you can use the HTTP Toolkit image with:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;act -P ubuntu-latest=httptoolkit/act-build-base
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;It is possible with this approach that your base image could diverge in behaviour from the GitHub runner. You're using the same scripts, for the scripts you include, but if you skip running a script that would affect your build then you could see differences here. To &lt;em&gt;guarantee&lt;/em&gt; reproducibility, you can fix this by setting &lt;code&gt;container: httptoolkit/act-build-base&lt;/code&gt; (for the HTTP Toolkit image) in the job in your GitHub workflow, thereby ensuring you use the exact same image in both places.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you do need either of these non-default base image options, you don't have to specify the &lt;code&gt;-P&lt;/code&gt; argument every time. You can create an &lt;code&gt;.actrc&lt;/code&gt; file in the root of your project that sets your default arguments (HTTP Toolkit UI's is &lt;a href="https://github.com/httptoolkit/httptoolkit-ui/blob/master/.actrc"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;With that done, we can reproduce remote GitHub Actions builds locally any time with just a quick &lt;code&gt;act&lt;/code&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Going Further
&lt;/h2&gt;

&lt;p&gt;That should give you enough to get most simple JavaScript or Node projects set up with GitHub Actions, locally and remotely. If you need a full example, feel free to take a look at the &lt;a href="https://github.com/httptoolkit/httptoolkit-ui"&gt;HTTP Toolkit UI repo&lt;/a&gt;. For me, this has dramatically sped up builds &amp;amp; CI feedback, mainly by them starting much faster, but also seeming to knock about 10% off the runtime itself.&lt;/p&gt;

&lt;p&gt;Now the real fun begins though, as you can begin to extend this setup. Some more bonus steps you might want to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up caching, to speed up slow &lt;code&gt;npm install&lt;/code&gt; steps, with &lt;a href="https://github.com/marketplace/actions/cache"&gt;&lt;code&gt;actions/cache&lt;/code&gt;&lt;/a&gt;. GitHub even have a &lt;a href="https://github.com/actions/cache/blob/main/examples.md#node---npm"&gt;ready-to-use example for npm&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Store build artifacts, as output attached to the workflow, using &lt;a href="https://github.com/marketplace/actions/upload-a-build-artifact"&gt;&lt;code&gt;actions/upload-artifact&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create GitHub releases from content automatically, with &lt;a href="https://github.com/marketplace/actions/create-a-release"&gt;&lt;code&gt;actions/create-release&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Deploy generated content to GitHub Pages, with &lt;a href="https://github.com/marketplace/actions/github-pages-action"&gt;&lt;code&gt;peaceiris/actions-gh-pages&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a badge to your readme, with a sprinkle of markdown:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[![Build Status](https://github.com/$USER/$REPO/workflows/$WORKFLOW/badge.svg)](https://github.com/$USER/$REPO/actions)
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Have further questions or suggestions? Get in touch &lt;a href="https://twitter.com/pimterry"&gt;on Twitter&lt;/a&gt; or add a comment below.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally posted on the &lt;a href="https://httptoolkit.tech/blog/migrating-javascript-from-travis-to-github-actions/"&gt;HTTP Toolkit blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Debug CORS Errors</title>
      <dc:creator>Tim Perry</dc:creator>
      <pubDate>Wed, 07 Oct 2020 14:30:00 +0000</pubDate>
      <link>https://dev.to/pimterry/how-to-debug-cors-errors-35dk</link>
      <guid>https://dev.to/pimterry/how-to-debug-cors-errors-35dk</guid>
      <description>&lt;p&gt;Your request is hitting an error due to CORS. Not all is lost! Most CORS errors are quick &amp;amp; easy to debug and fix, once you understand the basics. Let's sort it out.&lt;/p&gt;

&lt;p&gt;You know you're hitting a CORS error when you see error messages like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Access to fetch at '&lt;a href="https://example.com"&gt;https://example.com&lt;/a&gt;' from origin '&lt;a href="http://localhost:8000"&gt;http://localhost:8000&lt;/a&gt;' has been blocked by CORS policy.&lt;/p&gt;

&lt;p&gt;No 'Access-Control-Allow-Origin' header is present on the requested resource&lt;/p&gt;

&lt;p&gt;Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at &lt;a href="https://example.com/"&gt;https://example.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Response to preflight request doesn't pass access control check&lt;/p&gt;

&lt;p&gt;The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'&lt;/p&gt;

&lt;p&gt;Method PUT is not allowed by Access-Control-Allow-Methods in preflight response.&lt;/p&gt;

&lt;p&gt;Request header field custom is not allowed by Access-Control-Allow-Headers in preflight response.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In each of these cases, you've asked JavaScript running in your page to send a request to a different origin, and at some stage the browser is refusing to do what you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is CORS?
&lt;/h2&gt;

&lt;p&gt;When you include JavaScript in a web page, you're running code on your user's computer, inside their browsing session.&lt;/p&gt;

&lt;p&gt;That's a lot of power, and browsers are designed to protect users from the risks of this. CORS is one of these protections, aiming to protect the user and the services they use from two main attacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CORS stops you from using the user's existing login session (their cookies and other cached authentication details) when communicating with other servers. JavaScript on your web page shouldn't be able to send requests to the Facebook API using their existing Facebook session. Without CORS, any web page could talk to other servers as you.&lt;/li&gt;
&lt;li&gt;CORS stops you from talking to servers that might only be accessible from their machine, but which aren't accessible publicly. Your web page should not be able to send requests to &lt;code&gt;my-intranet-server.local&lt;/code&gt;, which might be an internal company server or your home router, and it should not be able to talk to servers that are listening only for localhost requests. Servers like these are often unauthenticated and very trusting, because they aren't connected to the public internet. Without CORS, any web page you visit could access them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This only applies to cross origin requests, e.g. requests from &lt;code&gt;https://example.com&lt;/code&gt; to &lt;code&gt;https://google.com&lt;/code&gt;. The protocol, domain, and port all count as part of a URL's origin, but the path does not, so &lt;code&gt;https://example.com/abc&lt;/code&gt; and &lt;code&gt;https://example.com/def&lt;/code&gt; have the same origin, but &lt;code&gt;http://localhost:123&lt;/code&gt; and &lt;code&gt;http://localhost:456&lt;/code&gt; do not.&lt;/p&gt;

&lt;p&gt;CORS protects against the above attacks by requiring the target server to opt into receiving dangerous requests from the source server, and to opt in to allowing pages from other origins to read responses. The Facebook API and your local network servers can accept requests from web pages running on other origins if they want to, but only if they agree.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why doesn't my CORS work?
&lt;/h2&gt;

&lt;p&gt;Your CORS request is failing because you're sending a request that the target server hasn't agreed to allow.&lt;/p&gt;

&lt;p&gt;There's two classes of CORS request:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;'Simple' cross-origin requests. There are basic requests that use no unsafe headers, don't stream requests or responses, and only use HEAD, GET or POST methods (with limited safe content types). Any request that's possible here would also be possible by e.g. loading an image or posting a form to the cross-origin request (and we can't stop those, for huge backwards compatibility reasons).&lt;/p&gt;

&lt;p&gt;You can always send simple requests, but you might not be allowed to read the response.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;'Preflighted' cross-origin requests. These are more complex requests, that aren't easy to send in other ways. A 'preflight' request will be sent to ask the server for permission before sending any of these requests, and if it's rejected, you won't be able to send the request at all.&lt;/p&gt;

&lt;p&gt;If the preflight request is successful, the real request is sent, and the final response to that still has to follow the same rules as a 'simple' response for you to be allowed to read it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a request is preflighted, before sending the real request the browser sends an OPTIONS request with headers explaining the real request that it wants to send. It expects a response including headers that explicitly allow the real request.&lt;/p&gt;

&lt;p&gt;There's three ways that this might hit an error:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You're sending a simple request, which is sent immediately, but the headers on the response don't allow you to read it.&lt;/li&gt;
&lt;li&gt;You're sending a preflighted request, and the headers on the preflight response don't allow you to send the real request.&lt;/li&gt;
&lt;li&gt;You're sending a preflighted request, the preflight went OK and the request was sent, but the headers on the final response for the real request don't allow you to read it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The browser error message should show you which is happening for you. You can know if your request is being preflighted by looking for an OPTIONS request that's sent immediately before it.&lt;/p&gt;

&lt;p&gt;The rules for the final (after preflight, if applicable) response are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The response must include a &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; header, whose value either matches the page's origin or is &lt;code&gt;*&lt;/code&gt;. The page's origin is sent in the request in an &lt;code&gt;Origin&lt;/code&gt; header.&lt;/li&gt;
&lt;li&gt;If the request included credentials (e.g. &lt;code&gt;fetch(url, { credentials: 'include' })&lt;/code&gt;) then the response headers must include &lt;code&gt;Access-Control-Allow-Credentials: true&lt;/code&gt;, and the &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; header must match &lt;em&gt;exactly&lt;/em&gt; (i.e. &lt;code&gt;*&lt;/code&gt; is not allowed).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the response doesn't follow those rules, then the server hasn't opted in to your request, and you won't be allowed to read the response.&lt;/p&gt;

&lt;p&gt;If you're in cases 1 or 3, you must be breaking one of these rules.&lt;/p&gt;

&lt;p&gt;The rules for the preflight request are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The preflight response must include a &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; header, whose value either matches the page's origin or is &lt;code&gt;*&lt;/code&gt;. The page's origin is sent in the preflight request in an &lt;code&gt;Origin&lt;/code&gt; header.&lt;/li&gt;
&lt;li&gt;If the page wants to send custom headers, then it will include &lt;code&gt;Access-Control-Request-Headers&lt;/code&gt; listing the headers in the preflight OPTIONS request, and the server must include a &lt;code&gt;Access-Control-Allow-Headers&lt;/code&gt; header that includes all those headers in the response. &lt;code&gt;*&lt;/code&gt; can also be used here, but it won't match an &lt;code&gt;Authorization&lt;/code&gt; header - that must always be listed explicitly.&lt;/li&gt;
&lt;li&gt;If the page wants to use a non-simple HTTP method, it will include &lt;code&gt;Access-Control-Request-Method&lt;/code&gt; in the preflight OPTIONS request, and the server must include a &lt;code&gt;Access-Control-Allow-Methods&lt;/code&gt; header that includes that method in the response.&lt;/li&gt;
&lt;li&gt;If the page wants to send credentials (e.g. &lt;code&gt;fetch(url, { credentials: 'include' })&lt;/code&gt;) the response must include a &lt;code&gt;Access-Control-Allow-Credentials: true&lt;/code&gt; header, and the &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; header must match &lt;em&gt;exactly&lt;/em&gt; (i.e. &lt;code&gt;*&lt;/code&gt; is not allowed).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your preflight OPTIONS response doesn't follow these rules, then you won't be allowed to send the real request at all.&lt;/p&gt;

&lt;p&gt;If you're in case 2, you must be breaking one of these rules.&lt;/p&gt;

&lt;p&gt;It's also possible that you're in case 2, but you actually don't want to read the response - you just want to send it. To do that, you'll need to simplify your request such that it's a simple request. You can use &lt;code&gt;{ mode: 'no-cors' }&lt;/code&gt; on your fetch options to enforce this (but note that this doesn't change the rules, it just enforces that it's a simple request where you can't read the result).&lt;/p&gt;

&lt;h2&gt;
  
  
  How can I fix my CORS error?
&lt;/h2&gt;

&lt;p&gt;To know exactly why your request is failing, you need to inspect the traffic itself, find where you're breaking the rules above, and then either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Change the request to make it a simple request&lt;/li&gt;
&lt;li&gt;Change the server's response to follow the rules above&lt;/li&gt;
&lt;li&gt;If all else fails, proxy the request through your own server on your own origin, so it's not a cross-origin request (proxying avoids the attacks above, because it doesn't let you use the cookies or authentication details from the user's browser, and it requires the target server to be accessible from your source server)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To inspect the traffic, you can use your browser built-in tools, but it's usually easier to use a dedicated HTTP debugger like &lt;a href="https://httptoolkit.tech/"&gt;HTTP Toolkit&lt;/a&gt;. Dedicated tools make it much easier to see the data, rather than (for example) Chrome's very cramped and fiddly network tab, and you can also breakpoint responses and edit the headers to test how the browser will handle changes without actually changing your server. Also, &lt;a href="https://httptoolkit.tech/blog/chrome-79-doesnt-show-cors-preflight"&gt;some Chrome versions&lt;/a&gt; don't show all CORS requests.&lt;/p&gt;

&lt;p&gt;Hopefully, once you examine your CORS requests &amp;amp; responses, it's clear where you're breaking the rules above.&lt;/p&gt;

&lt;p&gt;If not, try walking through &lt;a href="https://httptoolkit.tech/will-it-cors/"&gt;Will It CORS&lt;/a&gt;. This is a self-explaining implementation of the CORS rules: you can input step by step what you're trying to do, and it'll tell you what will happen and why, and how you can change it.&lt;/p&gt;

&lt;p&gt;There's also a few common mistakes that you should watch out for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trying to request content from another origin that isn't explicitly available cross-origin. If its not your server, and it doesn't actively want CORS requests, you're not going to work around most issues: you need to proxy the request, ask the owner to allow it, or do something entirely different.&lt;/li&gt;
&lt;li&gt;Always returning &lt;code&gt;*&lt;/code&gt; for &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt;, and then trying to send credentials.&lt;/li&gt;
&lt;li&gt;Adding CORS headers for preflight OPTIONS requests, but forgetting to also include CORS headers on the final request too.&lt;/li&gt;
&lt;li&gt;Unnecessarily sending custom request headers. This will trigger a preflight request. You can often get by just using the &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_request_header"&gt;CORS-safe request headers&lt;/a&gt; instead, or moving request data into the body of your request.&lt;/li&gt;
&lt;li&gt;Incorrectnyl caching CORS response headers independent of their origin, by not using &lt;code&gt;Vary: Origin&lt;/code&gt;. If you do this then responses for requests from one origin may be cached and returned for later requests from a different origin. That mismatched data can quickly break things.&lt;/li&gt;
&lt;li&gt;Trying to access response headers without including an &lt;code&gt;Access-Control-Expose-Headers&lt;/code&gt; header. In this case, all headers except the &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_response_header"&gt;CORS-safe response headers&lt;/a&gt; will be unexpectedly undefined, even though they were sent by the server.&lt;/li&gt;
&lt;li&gt;Sending cross-origin mixed-content requests (a request from &lt;code&gt;https://...&lt;/code&gt; to &lt;code&gt;http://...&lt;/code&gt;). These will always be blocked, regardless of the details, as insecure content like this is never allowed on HTTPS origins. There's not much you can do about this, other than changing to use HTTPS on both servers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That covers the core of CORS, how it can go wrong, and how to fix it. Have more questions? Comment below, or get in touch &lt;a href="https://twitter.com/pimterry"&gt;on Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://httptoolkit.tech/blog/how-to-debug-cors-errors/"&gt;the HTTP Toolkit blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>debugging</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>GraphQL the Simple Way, or: Don't Use Apollo</title>
      <dc:creator>Tim Perry</dc:creator>
      <pubDate>Wed, 02 Sep 2020 12:00:00 +0000</pubDate>
      <link>https://dev.to/pimterry/graphql-the-simple-way-or-don-t-use-apollo-8l3</link>
      <guid>https://dev.to/pimterry/graphql-the-simple-way-or-don-t-use-apollo-8l3</guid>
      <description>&lt;p&gt;The fundamentals of GraphQL are remarkably simple. Nonetheless, a busy hype train &amp;amp; rocket-speed ecosystem means that building a GraphQL API in the real world can be a tricky balancing act of piling complex interacting components a mile high, none of which anybody fully understands.&lt;/p&gt;

&lt;p&gt;About 90% of this pile is built &amp;amp; heavily promoted by a VC-funded company called &lt;a href="https://www.apollographql.com/"&gt;Apollo&lt;/a&gt;. Apollo describe themselves as a "data graph platform" who've built the self-described "industry-standard GraphQL implementation".&lt;/p&gt;

&lt;p&gt;Unfortunately, while I'm sure their platform is great, &lt;strong&gt;if you're setting up a fresh GraphQL API you should not start with Apollo&lt;/strong&gt;. It certainly might be useful later, but on day 1 it's a trap, and you'll make your life simpler and easier if you avoid it entirely.&lt;/p&gt;

&lt;p&gt;Let's talk about why that is, what can go wrong, and what you should do instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Apollo
&lt;/h2&gt;

&lt;p&gt;In practice, "industry-standard GraphQL implementation" means &lt;a href="https://www.npmjs.com/~apollo-bot"&gt;169 separate npm packages&lt;/a&gt;, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;44 different server packages and &lt;code&gt;apollo-server-*&lt;/code&gt; subpackages.&lt;/li&gt;
&lt;li&gt;7 different GraphQL 'transport layers', plus a long list of link layer extensions that build on top of this.&lt;/li&gt;
&lt;li&gt;8 code generation packages&lt;/li&gt;
&lt;li&gt;5 different &lt;code&gt;create-*&lt;/code&gt; project setup packages&lt;/li&gt;
&lt;li&gt;3 different GraphQL Babel plugins (plus a Relay un-Babel plugin, so you can avoid using Babel for some specific cases).&lt;/li&gt;
&lt;li&gt;Much much more...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Apollo packages required to install the base &lt;code&gt;apollo-server&lt;/code&gt; package suggested in their &lt;a href="https://www.apollographql.com/docs/apollo-server/"&gt;Getting Started guide&lt;/a&gt; include the "Apollo Studio" (née Apollo Graph Manager, néeée Apollo Engine) &lt;a href="https://www.npmjs.com/package/apollo-engine-reporting"&gt;reporting engine&lt;/a&gt;, which integrates your server with their cloud service, plus &lt;a href="https://www.npmjs.com/package/apollo-engine-reporting-protobuf"&gt;extra protobuf definitions&lt;/a&gt; on top of that to reporting to the cloud service with Protobuf. It includes &lt;a href="https://www.npmjs.com/package/apollo-tracing"&gt;request tracing&lt;/a&gt; for their own custom tracing format, &lt;a href="https://www.npmjs.com/package/apollo-server-caching"&gt;multiple&lt;/a&gt; &lt;a href="https://www.npmjs.com/package/apollo-cache-control"&gt;different&lt;/a&gt; custom caching packages, an &lt;a href="https://www.npmjs.com/package/apollo-link"&gt;abstraction layer&lt;/a&gt; that powers the many available transport link layers, an &lt;a href="https://www.npmjs.com/package/apollo-datasource"&gt;abstraction layer&lt;/a&gt; for connecting external data sources...&lt;/p&gt;

&lt;p&gt;In total, installing &lt;code&gt;apollo-server&lt;/code&gt; installs actually installs 33 direct dependencies, and 179 packages in total, pulling in about 35MB of JavaScript.&lt;/p&gt;

&lt;p&gt;Once all put together, by itself this package creates web servers that can't do anything.&lt;/p&gt;

&lt;p&gt;If however you also use the (official, non-Apollo) &lt;code&gt;graphql&lt;/code&gt; package too, then you can now just about answer complex queries like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  books {
    title
    author
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To be clear, that &lt;code&gt;graphql&lt;/code&gt; package is the official GraphQL JS implementation, which takes a schema, a query, and a resolver (in effect, a data set object), and gives you a result. I.e. it does &lt;em&gt;all&lt;/em&gt; the GraphQL heavy lifting required to process a query like this, except the HTTP.&lt;/p&gt;

&lt;p&gt;I know I'm treating Apollo very harshly here, and that's not wholly fair. Most of their published packages do have cases where they're genuinely useful, many of the packages I'm counting are deprecated or duplicates (though published and often still well used), and as far as I'm aware everything they've released works perfectly effectively. I certainly don't think that &lt;em&gt;nobody&lt;/em&gt; should use Apollo!&lt;/p&gt;

&lt;p&gt;I do 100% think that Apollo shouldn't be anybody's GraphQL starting point though, and that nonetheless it's marketed as such.&lt;/p&gt;

&lt;p&gt;They clearly want to be the entrance to the ecosystem, and of course they do! Ensuring a nascent fast-growing ecosystem depends on your free tools is a great startup play. They're the first result for "how to set up a graphql server", and either they or GraphQL-Yoga (another package on top of Apollo Server) are the suggested beginner option in most other articles on that page, from &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-a-graphql-server-in-node-js-with-apollo-server-and-sequelize"&gt;Digital Ocean's docs&lt;/a&gt; to &lt;a href="https://www.howtographql.com/graphql-js/1-getting-started/"&gt;howtographql.com&lt;/a&gt;. This isn't healthy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you're setting up a GraphQL API, you don't need all this.&lt;/strong&gt; Pluggable transport layers and data sources, request tracing, cool GraphQL extensions like &lt;code&gt;@defer&lt;/code&gt; and multi-layered caching strategies all have their place, but you don't want that complexity to start with, and they're not a requirement to make your simple API 'production ready'.&lt;/p&gt;

&lt;p&gt;It is great that Apollo makes these available to you, but they're features you can add in later, even if you don't start off using Apollo at all. A GraphQL schema is pretty standard, and entirely portable from the standard tools to Apollo (but not always back, if you start using Apollo's own extensions...).&lt;/p&gt;

&lt;p&gt;If I seem personally annoyed by this, it's because I am! I was burned by this myself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://httptoolkit.tech/"&gt;HTTP Toolkit&lt;/a&gt;'s internal APIs (e.g. &lt;a href="https://github.com/httptoolkit/mockttp/blob/master/src/standalone/schema.gql"&gt;for defining HTTP mocking rules and querying traffic&lt;/a&gt;) use GraphQL throughout. Those APIs started off built on Apollo, because that's the very widely recommended &amp;amp; documented option. The overly complex setup required to do so caused a long stream of serious pain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Apollo's packages like to move fast and break things, and each often requires specific conflicting &lt;code&gt;graphql&lt;/code&gt; peer dependencies, making updates remarkably &lt;a href="https://github.com/httptoolkit/mockttp/issues/29"&gt;painful&lt;/a&gt; all round.&lt;/li&gt;
&lt;li&gt;The base packages include a lot of features and subdependencies, as above, which in turn means a &lt;em&gt;lot&lt;/em&gt; of vulnerability reports. Even if vulnerabilities aren't relevant or exploitable, downstream users of my packages very reasonably &lt;a href="https://github.com/httptoolkit/mockttp/pull/37#issuecomment-661937314"&gt;don't want security warnings&lt;/a&gt;, making keeping everything up to date obligatory.&lt;/li&gt;
&lt;li&gt;Some Apollo packages are effectively quietly unmaintained, meaning that conflicting dependencies there can block you from upgrading entirely, unless you fork the whole package yourself.&lt;/li&gt;
&lt;li&gt;Once you start having multiple interacting packages in your system that use Apollo this gets even worse, as dependent packages need updating in lockstep, or your peer dependency interactions explode, scattering debris for miles.&lt;/li&gt;
&lt;li&gt;The packages involved are &lt;em&gt;huge&lt;/em&gt;: &lt;code&gt;apollo-server&lt;/code&gt; alone installs 35MB of JS, before you even start doing anything (that's v2, which is 2.3x the size of the last Apollo Server v1 release, but hey the upgrade is unavoidable anyway, so who's counting?).&lt;/li&gt;
&lt;li&gt;These problems are getting worse. &lt;a href="https://github.com/apollographql/apollo-server/issues/2360"&gt;&lt;code&gt;apollo-server&lt;/code&gt; v3&lt;/a&gt; is coming soon, with built-in support for GraphQL federation, non-Node backend platforms, and a new plugin API. Don't get me wrong, these features are very cool, but you don't need them all included by default in your starter project!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's not fun. However there is an alternative:&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Build a Simple GraphQL Server (without Apollo)
&lt;/h2&gt;

&lt;p&gt;To build a GraphQL API server, you really need just 3 things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A web server&lt;/li&gt;
&lt;li&gt;An executable GraphQL schema (i.e. a schema and a resolver) which can together can answer GraphQL queries&lt;/li&gt;
&lt;li&gt;A request handler that can accept GraphQL requests, hand them to the schema, and return the results or errors&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'm assuming you already have a preferred web server (if not, &lt;a href="https://www.npmjs.com/package/express"&gt;Express&lt;/a&gt; is an easy, convenient &amp;amp; reliable choice). The official &lt;a href="https://www.npmjs.com/package/graphql"&gt;&lt;code&gt;graphql&lt;/code&gt;&lt;/a&gt; package can turn a string schema and a resolver object into an executable schema for you.&lt;/p&gt;

&lt;p&gt;That leaves the final step, which is easily handled with &lt;a href="https://github.com/graphql/express-graphql"&gt;&lt;code&gt;express-graphql&lt;/code&gt;&lt;/a&gt;: a simple Express middleware, with just 4 dependencies that handle content negotiation &amp;amp; body parsing. That works for Express or Connect, and there's similar tiny packages available for most other servers.&lt;/p&gt;

&lt;p&gt;To set up your GraphQL server, install those packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install express graphql express-graphql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And then set up a server that uses them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;graphqlHTTP&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express-graphql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;buildSchema&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;graphql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Create a server:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Create a schema and a root resolver:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buildSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`
    type Book {
        title: String!
        author: String!
    }

    type Query {
        books: [Book]
    }
`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rootValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The Name of the Wind&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Patrick Rothfuss&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The Wise Man's Fear&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Patrick Rothfuss&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Use those to handle incoming requests:&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graphqlHTTP&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;rootValue&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// Start the server:&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Server started on port 8080&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Run that and you're done. This is solid, reliable, fast, and good enough for most initial use cases. It's also short, clear, and comparatively tiny: &lt;code&gt;node_modules&lt;/code&gt; here is just over 15% of the size of the Apollo equivalent. &lt;strong&gt;Running 80% less code is a very good thing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In addition, you can still add in extra features incrementally later on, to add complexity &amp;amp; power only where you need it.&lt;/p&gt;

&lt;p&gt;For example, in my case, I want subscriptions. &lt;a href="https://github.com/httptoolkit/mockttp"&gt;Mockttp&lt;/a&gt; (the internals of HTTP Toolkit's proxy) accepts GraphQL queries over websockets, so it can stream intercepted request details to clients as they come in, with &lt;a href="https://github.com/httptoolkit/mockttp/blob/52d4f6062c352add81571ea2e498620a3bd06322/src/standalone/schema.gql#L14-L21"&gt;a GraphQL schema&lt;/a&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Subscription {
    requestInitiated: InitiatedRequest!
    requestReceived: Request!
    responseCompleted: Response!
    requestAborted: Request!
    failedTlsRequest: TlsRequest!
    failedClientRequest: ClientError!
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To add this, I can just expand the basic setup above. To do so, I do actually use a couple of small Apollo modules! Most can be picked and configured independently. For this case, &lt;a href="https://github.com/apollographql/graphql-subscriptions"&gt;&lt;code&gt;graphql-subscriptions&lt;/code&gt;&lt;/a&gt; provides a little bit of pubsub logic that works within resolvers, and &lt;a href="https://www.npmjs.com/package/subscriptions-transport-ws"&gt;&lt;code&gt;subscriptions-transport-ws&lt;/code&gt;&lt;/a&gt; integrates that into Express to handle the websockets themselves. Super helpful&lt;/p&gt;

&lt;p&gt;Here's a full example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;graphqlHTTP&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express-graphql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;buildSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subscribe&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;graphql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Pull in some specific Apollo packages:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PubSub&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;graphql-subscriptions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SubscriptionServer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subscriptions-transport-ws&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Create a server:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Create a schema and a root resolver:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buildSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`
    type Book {
        title: String!
        author: String!
    }

    type Query {
        books: [Book]
    }

    type Subscription { # New: subscribe to all the latest books!
        newBooks: Book!
    }
`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pubsub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;PubSub&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rootValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The Name of the Wind&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Patrick Rothfuss&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The Wise Man's Fear&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Patrick Rothfuss&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;newBooks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;pubsub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asyncIterator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BOOKS_TOPIC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Handle incoming HTTP requests as before:&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graphqlHTTP&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;rootValue&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// Start the server:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Server started on port 8080&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Handle incoming websocket subscriptions too:&lt;/span&gt;
&lt;span class="nx"&gt;SubscriptionServer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rootValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subscribe&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="c1"&gt;// Listens for 'upgrade' websocket events on the raw server&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// ...some time later, push updates to subscribers:&lt;/span&gt;
&lt;span class="nx"&gt;pubsub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BOOKS_TOPIC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The Doors of Stone&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Patrick Rothfuss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;My point isn't that you need subscriptions in your app, or that everybody should use all these extra packages (quite the opposite).&lt;/p&gt;

&lt;p&gt;This does demonstrate how you can extend your setup to progressively use these kinds of features though. Moving from request/response model to also supporting subscriptions is not a trivial change, but even in this case, adding in Apollo extensions is a few simple lines on top of the existing logic here that fits nicely into a standard setup.&lt;/p&gt;

&lt;p&gt;You can also extend with non-Apollo tools too. Here we're building primarily around the vanilla GraphQL packages and Express directly, composing Apollo components in separately, rather than basing everything on top of them. That means you could still drop in any other Express middleware or GraphQL tools you like, to add any kind of authentication, caching, logging or other cross-cutting features just using standard non-GraphQL solutions &amp;amp; examples, with no lock-in from the Apollo ecosystem.&lt;/p&gt;

&lt;p&gt;Apollo do have a wide selection of interesting &amp;amp; useful packages, and they should be lauded for the effort and contributions they've made to the ecosystem. At the same time though, they're not a neutral actor. Don't assume that the Next Big Thing is the right choice for your project, especially if it calls itself "industry-standard".&lt;/p&gt;

&lt;p&gt;Instead, start simple: build a system that you can fully understand &amp;amp; manage, avoid unnecessary complexity, and keep your project lean &amp;amp; flexible for as long as you can.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using GraphQL, and want to debug, rewrite &amp;amp; mock live traffic? &lt;a href="https://httptoolkit.tech/"&gt;Try out HTTP Toolkit&lt;/a&gt;. One-click HTTP(S) interception &amp;amp; debugging for browsers, servers, Android &amp;amp; more.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>graphql</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Inspecting Android HTTP with a fake VPN</title>
      <dc:creator>Tim Perry</dc:creator>
      <pubDate>Tue, 25 Aug 2020 12:20:00 +0000</pubDate>
      <link>https://dev.to/pimterry/inspecting-android-http-with-a-fake-vpn-2l64</link>
      <guid>https://dev.to/pimterry/inspecting-android-http-with-a-fake-vpn-2l64</guid>
      <description>&lt;p&gt;&lt;strong&gt;Can you build an Android app that can inspect &amp;amp; rewrite the network traffic from every other app on the device?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In turns out that, yes, you can. &lt;a href="https://httptoolkit.tech/android"&gt;HTTP Toolkit&lt;/a&gt; does exactly this, by building an app on top of the Android VPN APIs that fully simulates a fake VPN connection entirely within the device.&lt;/p&gt;

&lt;p&gt;Here I want to talk through how that works, look at the code that makes it happen, and show you how you can do the same thing for yourself.&lt;/p&gt;

&lt;p&gt;To be clear, this is not intended (or very effective) as a attack on the security of traffic from the device. When you actually do this Android provides clear warnings &amp;amp; permission prompts to the user during setup, and requires persistent UI notifications any time this is active. In addition this doesn't give you any way to read the contents of encrypted traffic, by default (in the next post, we'll talk about how HTTP Toolkit &lt;em&gt;can&lt;/em&gt; do that).&lt;/p&gt;

&lt;p&gt;There are some interesting &amp;amp; constructive use cases this opens up though for developer tooling. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inspecting &amp;amp; rewriting mobile traffic for testing &amp;amp; debugging (this is &lt;a href="https://httptoolkit.tech/android"&gt;HTTP Toolkit&lt;/a&gt;'s raison d'être).&lt;/li&gt;
&lt;li&gt;Building a firewall for Android that blocks outgoing app connections according to your custom rules.&lt;/li&gt;
&lt;li&gt;Recording metrics on the traffic sent &amp;amp; received by your device.&lt;/li&gt;
&lt;li&gt;Simulating connection issues by adding delays or randomly injecting packet resets.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How do Android VPNs work?
&lt;/h2&gt;

&lt;p&gt;The Android developer docs have a &lt;a href="https://developer.android.com/guide/topics/connectivity/vpn"&gt;VPN guide&lt;/a&gt;, which is a good starting point.&lt;/p&gt;

&lt;p&gt;These VPN APIs allow you to register a service in your app, which when activated is given a file descriptor that backs a network tunnel interface.&lt;/p&gt;

&lt;p&gt;That tunnel interface is then used by the whole device for all network traffic. In addition, your VPN service is given the power to create protected sockets that don't use this tunnel, so the VPN app can communicate with the network without going through itself.&lt;/p&gt;

&lt;p&gt;Once this is activated, when an app sends some data, instead of that going out to the network, each IP packet is buffered behind this file descriptor. When you read from it you're given raw network bytes directly, and when you write bytes to it they're treated as bytes received directly from the network interface.&lt;/p&gt;

&lt;p&gt;This is designed to allow implementing a VPN connection in your app. In that case, your app would forward all the read bytes directly to a VPN provider over some protected separate connection, without any substantial processing of them on the device. The VPN provider would then forward that data on as part of the VPN's traffic, forward response packets back to your app over your connection, and you'd write the resulting packets back to the file descriptor.&lt;/p&gt;

&lt;p&gt;That's what's this is primarily designed for, but that doesn't mean that that's all we can do with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  When is a VPN not a VPN?
&lt;/h2&gt;

&lt;p&gt;Once we have a VPN service running, our app will receive every network byte the device sends, and has the power to inject raw bytes back.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Things get interesting if rather than forwarding these bytes to a VPN provider, we examine them, and then simply put them straight back on the real network&lt;/strong&gt;. In that case, we get to see every network byte, but we don't interfere with the network connection of the device, and we don't need an externally hosted VPN provider to do it.&lt;/p&gt;

&lt;p&gt;Unfortunately that's easier said than done. Our file descriptor works with raw IP data, but Android doesn't actually have an API for us to send raw IP data anywhere else. Instead, we have higher level APIs for TCP and UDP, and the IP part is always done invisibly under the hood.&lt;/p&gt;

&lt;p&gt;If we want to proxy these bytes, we need to match these two APIs up. We need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When we read an IP packet from our tunnel:

&lt;ul&gt;
&lt;li&gt;Parse the raw packet bytes into an IP packet.&lt;/li&gt;
&lt;li&gt;Parse the TCP/UDP packet within and extract its content.&lt;/li&gt;
&lt;li&gt;(For TCP) Track the connection state of the overall TCP connection, and ack/fin/etc each packet in the session appropriately.&lt;/li&gt;
&lt;li&gt;Send the equivalent TCP/UDP content upstream, using Android's TCP/UDP APIs.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;When we receive a TCP/UDP response from upstream:

&lt;ul&gt;
&lt;li&gt;(For TCP) Match that to the tunnelled TCP connection.&lt;/li&gt;
&lt;li&gt;Build our own complete TCP/UDP + IP packet data around the received data.&lt;/li&gt;
&lt;li&gt;Write the resulting bytes back into the tunnel.&lt;/li&gt;
&lt;li&gt;Cleanly (or messily) close connections when the upstream socket is done.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is quite complicated. We effectively need to reimplement UDP &amp;amp; TCP from scratch!&lt;/p&gt;

&lt;p&gt;Fortunately, we're not the first people to want to do this. Most of the existing implementations are unmaintained demos, but they are open-source so we can build upon them! My own solution is based on a GitHub proof-of-concept called &lt;a href="https://github.com/LipiLee/ToyShark"&gt;ToyShark&lt;/a&gt; (a pun on Wireshark, I assume) which was in turn based on some of the open-source network collection internals of an old AT&amp;amp;T project called &lt;a href="https://www.att.com/gen/press-room?pid=22388"&gt;Application Resource Optimizer&lt;/a&gt; (&lt;a href="https://github.com/attdevsupport/ARO/tree/master/ClientCollectors/Non-rooted-ARODataCollector/ARO.Android.Net/src/main/java/com/att/aro/android/arocollector"&gt;source&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The resulting HTTP Toolkit Android app implements all the above. This is 100% free &amp;amp; open-source (&lt;strong&gt;&lt;a href="https://github.com/httptoolkit/httptoolkit-android"&gt;github.com/httptoolkit/httptoolkit-android&lt;/a&gt;&lt;/strong&gt;) so similar open-source implementations in future can build upon it in turn.&lt;/p&gt;

&lt;p&gt;This implementation acts as a VPN, while proxying all traffic back onto the real network, all without native code, just powered by &lt;a href="https://en.wikipedia.org/wiki/Non-blocking_I/O_(Java)"&gt;Java NIO&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The core VPN implementation is in &lt;a href="https://github.com/httptoolkit/httptoolkit-android/tree/070830e3ea3d2cadf141468a83c83b6d078272ac/app/src/main/java/tech/httptoolkit/android/vpn"&gt;src/main/java/tech/httptoolkit/android/vpn&lt;/a&gt;, and there's a README there with an outline of the implementation details. We'll explore this a little more below, as we look at ways to extend it.&lt;/p&gt;

&lt;p&gt;There is a performance penalty to all this of course, in both network bandwidth and latency. The impact isn't really noticeable in normal usage on any modern device though. On cellular connections it's usually dwarfed by the underlying connection performance, and even on wifi you can reach quite acceptable numbers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://httptoolkit.tech/static/4fe19acbeb69660f22ccbc6e3b0202c5/5792a/android-interception-performance.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OaWgzzD---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://httptoolkit.tech/static/4fe19acbeb69660f22ccbc6e3b0202c5/4c7b4/android-interception-performance.jpg" alt="Android speed test screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This could probably be improved further by rewriting the Java code as a native code, but that entails significant extra complexity. For the HTTP Toolkit use case (targeted debugging, rather than heavy everyday usage) it's not worth it.&lt;/p&gt;

&lt;p&gt;With that in place, we now transparently receive every network packet from the device. We can inspect it as we'd like, and even edit that traffic, through either the raw IP stream or the parsed TCP/UDP packet data. To what end?&lt;/p&gt;

&lt;h2&gt;
  
  
  How can we use this?
&lt;/h2&gt;

&lt;p&gt;In HTTP Toolkit's case, the usage of this is very direct: we forcibly redirect all HTTP(S) traffic via the debugging proxy (which is running on your local development machine). That proxy then lets you inspect and rewrite all the traffic there as you see fit.&lt;/p&gt;

&lt;p&gt;There's a demo video on &lt;a href="https://httptoolkit.tech/android"&gt;HTTP Toolkit's Android page&lt;/a&gt; if you want to see this in action.&lt;/p&gt;

&lt;p&gt;To do this, we check the target port of outgoing TCP connections, and rewrite the address if it's one of our configured HTTP ports (e.g. 80, 443, ...), by just adding the following lines into &lt;a href="https://github.com/httptoolkit/httptoolkit-android/blob/b4cb5a97d48d299958b4e7a907b41fc9b44d2129/app/src/main/java/tech/httptoolkit/android/vpn/SessionManager.java#L169-L212"&gt;TCP session setup&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Session&lt;/span&gt; &lt;span class="nf"&gt;createNewTCPSession&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;srcIp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;srcPort&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;

    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;ips&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PacketUtil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;intToIPAddress&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Use the given target address, unless tcpPortRedirection has specified&lt;/span&gt;
    &lt;span class="c1"&gt;// a different target address for traffic on this port:&lt;/span&gt;
    &lt;span class="nc"&gt;SocketAddress&lt;/span&gt; &lt;span class="n"&gt;socketAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tcpPortRedirection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
        &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;tcpPortRedirection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InetSocketAddress&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ips&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;connect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socketAddress&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That forcibly sends all the matching traffic to the proxy, and immediately gives us full visibility into HTTP traffic. On Android 10 we also set &lt;a href="https://developer.android.com/reference/android/net/VpnService.Builder#setHttpProxy(android.net.ProxyInfo)"&gt;a VPN proxy configuration&lt;/a&gt;, which catches most traffic on further ports that aren't explicitly matched (although in that case it's advisory default configuration, rather than enforced redirection).&lt;/p&gt;

&lt;p&gt;That's enough to redirect traffic for remote inspection &amp;amp; rewriting. How else could you extend this? Let's talk about the 3 other use cases I mentioned at the start:&lt;/p&gt;

&lt;h3&gt;
  
  
  Blocking outgoing connections
&lt;/h3&gt;

&lt;p&gt;To block outgoing connections to specific addresses or on specific ports, you just need to throw away the packets after you receive them from the VPN interface, once you've parsed them to work out where they're going.&lt;/p&gt;

&lt;p&gt;You can use this to block specific hosts you don't like, block DNS requests for certain addresses to build an on-device &lt;a href="https://pi-hole.net/"&gt;Pi-Hole&lt;/a&gt;, or allow traffic only to a short trusted list of hosts to lock down your networking entirely.&lt;/p&gt;

&lt;p&gt;In HTTP Toolkit's implementation, SessionHandler's &lt;a href="https://github.com/httptoolkit/httptoolkit-android/blob/070830e3ea3d2cadf141468a83c83b6d078272ac/app/src/main/java/tech/httptoolkit/android/vpn/SessionHandler.java#L79"&gt;&lt;code&gt;handlePacket&lt;/code&gt;&lt;/a&gt; is where we handle the raw packet data that the device wants to send. It looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handlePacket&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NonNull&lt;/span&gt; &lt;span class="nc"&gt;ByteBuffer&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;PacketHeaderException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;rawPacket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;()];&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rawPacket&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;rewind&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;IPv4Header&lt;/span&gt; &lt;span class="n"&gt;ipHeader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;IPPacketFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createIPv4Header&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// TODO: inspect ipHeader here, and 'return' to drop the packet&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ipHeader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProtocol&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;handleTCPPacket&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ipHeader&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ipHeader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProtocol&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;handleUDPPacket&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ipHeader&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ipHeader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProtocol&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;handleICMPPacket&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ipHeader&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;w&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;TAG&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Unsupported IP protocol: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ipHeader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProtocol&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;From that we can drop packets entirely based on the target address or port in the IP header, by simply doing nothing.&lt;/p&gt;

&lt;p&gt;Dropping a packet here is literally packet loss, where the app sending the original request will never hear any response at all.&lt;/p&gt;

&lt;p&gt;Alternatively, for more complex rules you can make changes within specific protocol handling, e.g. the &lt;code&gt;handleTCPPacket&lt;/code&gt; or &lt;code&gt;handleUDPPacket&lt;/code&gt; methods above. In both cases you can examine the parsed TCP/UDP packets, and drop them there (or in the TCP case, inject an immediate RST packet to tell the app the connection failed).&lt;/p&gt;

&lt;h3&gt;
  
  
  Recording traffic metrics
&lt;/h3&gt;

&lt;p&gt;Want to know what your device sends and receives? Normally Android makes that more or less invisible. Within a fake VPN application like this though you have every network byte, so it's easy to examine and record data about outgoing &amp;amp; incoming packets.&lt;/p&gt;

&lt;p&gt;It's simplest to do total byte metrics by address and/or port, but you could also build more complex analyses of packet data itself. E.g. tracking the duration of TCP sessions with certain hosts, recording metrics about the unencrypted data available, or looking at DNS UDP packets to examine which hostnames you're looking up.&lt;/p&gt;

&lt;p&gt;For this codebase, we can easily capture outgoing traffic in the &lt;code&gt;handlePacket&lt;/code&gt; method above. We have the raw IP packet data there, and the full TCP &amp;amp; UDP data is just a little more parsing away.&lt;/p&gt;

&lt;p&gt;To track incoming traffic, we'd need to look at the code that handles the upstream connections. For example in &lt;a href="https://github.com/httptoolkit/httptoolkit-android/blob/070830e3ea3d2cadf141468a83c83b6d078272ac/app/src/main/java/tech/httptoolkit/android/vpn/socket/SocketChannelReader.java#L85-L117"&gt;&lt;code&gt;readTCP&lt;/code&gt;&lt;/a&gt; from &lt;code&gt;SocketChannelReader&lt;/code&gt;, where upstream TCP data is received:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;readTCP&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NonNull&lt;/span&gt; &lt;span class="nc"&gt;Session&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// We're received some TCP data from the external network:&lt;/span&gt;
                &lt;span class="n"&gt;sendToRequester&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clear&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// The external network connection is finished:&lt;/span&gt;
                &lt;span class="n"&gt;sendFin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAbortingConnection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;At this point, we're handling the contents of the TCP connection, before we pack it back up into the raw bytes for the VPN interface.&lt;/p&gt;

&lt;p&gt;By examining the TCP data read here and associating it with the IP &amp;amp; port of the TCP session, you can quickly start to build a view into your device's network communication.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simulating connection issues
&lt;/h3&gt;

&lt;p&gt;It's possible to simulate connection issues on the device too. That's especially useful to test how applications handle low-quality internet connections and network errors.&lt;/p&gt;

&lt;p&gt;Unfortunately you can't simulate &lt;em&gt;all&lt;/em&gt; issues, as Android's APIs give us limited control of upstream traffic. We control the contents of upstream TCP &amp;amp; UDP packets, but not the raw network connection itself. That means, for example, we can't simulate our device sending the wrong upstream packet sequence number or corrupting a TCP checksum, but we can simulate the device receiving such packets.&lt;/p&gt;

&lt;p&gt;There's still a lot of interesting things you can simulate with this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Incoming or outgoing packet loss, where some packets simply disappear in transit.&lt;/li&gt;
&lt;li&gt;Repeated or misordered packets.&lt;/li&gt;
&lt;li&gt;Random connection resets (similar to &lt;a href="https://en.wikipedia.org/wiki/Tcpkill"&gt;tcpkill&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Delays to packets, in either direction.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In each case you'd normally do this probabilistically, so that 10% of connections fail, or packets are delayed by 500ms on average.&lt;/p&gt;

&lt;p&gt;When you do this, you'll often see some surprising results and errors in your app. In effect we're doing on-device &lt;a href="https://en.wikipedia.org/wiki/Chaos_engineering"&gt;chaos engineering&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Adding random connection resets like this will usually result in very visible TCP connection failures, causing random HTTP requests, raw network sockets or whatever else to suddenly fail and disconnect.&lt;/p&gt;

&lt;p&gt;Packet loss and ordering issues meanwhile are normally be handled at the TCP level, invisibly to your application code, but the process of doing so can result in unpredictable performance, and cause real issues at the application level.&lt;/p&gt;

&lt;p&gt;During day-to-day development it's very easy to never see these issues, given the fast &amp;amp; reliable wifi in your office or at home, and simulating rural 2G issues like this can be eye-opening!&lt;/p&gt;

&lt;p&gt;You do most of this at a very low level, just hooking into the places where individual raw IP packets are passed to and from the VPN. For TCP error simulation though, you'll need a lot more information about the TCP connection itself, to find packets to reorder, or to inject RSTs into active connections.&lt;/p&gt;

&lt;p&gt;In the HTTP Toolkit app specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/httptoolkit/httptoolkit-android/blob/070830e3ea3d2cadf141468a83c83b6d078272ac/app/src/main/java/tech/httptoolkit/android/vpn/ClientPacketWriter.java#L67"&gt;&lt;code&gt;ClientPacketWriter&lt;/code&gt;&lt;/a&gt; is where raw IP data is written back to the VPN (incoming IP packets). At this stage we can easily drop, corrupt or delay incoming packets at the IP level.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/httptoolkit/httptoolkit-android/blob/master/app/src/main/java/tech/httptoolkit/android/vpn/SessionHandler.java#L74-L95"&gt;&lt;code&gt;handlePacket&lt;/code&gt;&lt;/a&gt; again in &lt;code&gt;SessionHandler&lt;/code&gt;, would allow us to drop, delay or otherwise react to outgoing packets.&lt;/li&gt;
&lt;li&gt;SessionHandler also controls the TCP flow of each connection to process each packet, allowing us to hook into that flow directly. For example, you could extend &lt;a href="https://github.com/httptoolkit/httptoolkit-android/blob/master/app/src/main/java/tech/httptoolkit/android/vpn/SessionHandler.java#L360-L386"&gt;&lt;code&gt;replySynAck&lt;/code&gt;&lt;/a&gt; to schedule a connection reset (just a call to &lt;code&gt;resetConnection&lt;/code&gt;) for 50% of new connections 2s after they're created.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/httptoolkit/httptoolkit-android/blob/master/app/src/main/java/tech/httptoolkit/android/vpn/SessionManager.java"&gt;&lt;code&gt;SessionManager&lt;/code&gt;&lt;/a&gt; stores the state controlled by &lt;code&gt;SessionHandler&lt;/code&gt;. Given the list of active connections there, we could select random active TCP sessions and kill them according to whatever criteria you like.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As we've seen, the Android VPN APIs are powerful, and there's a lot of potential here.&lt;/p&gt;

&lt;p&gt;With a few tricks like this to hook into network traffic, there's a whole world of interesting tools you can build. Give it a go! Have any thoughts or feedback? Let me know &lt;a href="https://twitter.com/pimterry"&gt;on Twitter&lt;/a&gt; or in the comments below.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want to take your Android debugging to the next level? &lt;a href="https://httptoolkit.tech/android"&gt;HTTP Toolkit&lt;/a&gt; gives you one-click HTTP(S) inspection &amp;amp; mocking for any Android app (plus lots of other tools too).&lt;/em&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>tutorial</category>
      <category>http</category>
      <category>debugging</category>
    </item>
    <item>
      <title>How to Debug Node.js Segmentation Faults</title>
      <dc:creator>Tim Perry</dc:creator>
      <pubDate>Wed, 12 Aug 2020 16:12:00 +0000</pubDate>
      <link>https://dev.to/pimterry/how-to-debug-node-js-segmentation-faults-3ab2</link>
      <guid>https://dev.to/pimterry/how-to-debug-node-js-segmentation-faults-3ab2</guid>
      <description>&lt;p&gt;Oh no, your JavaScript code isn't just throwing an exception or crashing: it's &lt;em&gt;segfaulting&lt;/em&gt;. What does that mean, and how can you fix it?&lt;/p&gt;

&lt;p&gt;You'll know this happens because node will hard crash, exiting silently without any kind of real stack trace, perhaps printing just &lt;code&gt;segmentation fault (core dumped)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;(If you do get a normal JavaScript stack trace on the other hand, then you're dealing with a normal JS error, not a segfault. Lucky you! You might be more interested in the guide on &lt;a href="https://httptoolkit.tech/blog/how-to-debug-anything"&gt;How to Debug Anything&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Segmentation Fault?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A segmentation fault occurs when a program attempts to access a memory location that it is not allowed to access, or attempts to access a memory location in a way that is not allowed (for example, attempting to write to a read-only location, or to overwrite part of the operating system).&lt;br&gt;
- &lt;a href="https://en.wikipedia.org/wiki/Segmentation_fault"&gt;wikipedia.org/wiki/Segmentation_fault&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In practice, a segfault occurs when your program breaks some fundamental rule set by the operating system. In that case, the operating system sends your process a signal (SIGSEGV on Mac &amp;amp; Linux, STATUS_ACCESS_VIOLATION on Windows), and typically the process shuts down immediately.&lt;/p&gt;

&lt;p&gt;The rules that you can break to cause this include things like reading or writing to an invalid memory address (e.g. native code somewhere trying to use a null pointer as a memory address), causing a stack or buffer overflow, or reading or writing from memory that's not yours (maybe it was yours but it's now been released, maybe it's unused, or maybe it's owned by another process or the operating system).&lt;/p&gt;

&lt;p&gt;All of these cases involve low-level concerns, like pointers &amp;amp; memory management. You shouldn't normally have to worry about this when writing JavaScript! The language runtime normally manages your memory, doesn't expose the kinds of APIs that could cause these issues, and enforces its own rules on the APIs that are available, to guarantee that your code behaves correctly.&lt;/p&gt;

&lt;p&gt;That all ensures that the underlying operating system's rules are never broken, and ensures that any time you do accidentally try to take any invalid actions, you get a clear error that appears straight away, rather than random failures later.&lt;/p&gt;

&lt;p&gt;Unfortunately, there are a few cases where you can still hit segfaults in Node:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you use &lt;a href="https://nodejs.org/api/addons.html"&gt;native addons&lt;/a&gt; (either directly, or because one of your dependencies uses them), so you're effectively running your own native code as part of your application. If that native code is either buggy or just incompatible with your version of Node, you'll often get segfaults.&lt;/li&gt;
&lt;li&gt;If you manipulate parts of the internal private state of Node objects. This can break Node's assumptions, so that Node's built-in native code does the wrong thing, resulting in segfaults.&lt;/li&gt;
&lt;li&gt;When Node.js itself has a bug somewhere, and segfaults all by itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How can I fix it?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Find the culprit
&lt;/h3&gt;

&lt;p&gt;First, you need to work out which of the 3 cases above you have.&lt;/p&gt;

&lt;p&gt;Native addons are always the most likely cause here. There's a couple of things to try straight away:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Rebuild all your native node modules with &lt;code&gt;npm rebuild&lt;/code&gt;. This will recompile native code with your current version of node, and should resolve any issues where your native modules are compiled for the wrong node version.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Find all the native modules you have installed, by searching your node_modules folder for &lt;code&gt;.node&lt;/code&gt; files. On Linux/Mac you can list them with:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;find node_modules &lt;span class="nt"&gt;-iname&lt;/span&gt; &lt;span class="s2"&gt;"*.node"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you have no native modules installed, you can rule that case out entirely. If you do have modules installed there that seem related to the crash you're seeing, then that's probably a good place to start looking.&lt;/p&gt;

&lt;p&gt;You can also try to get more detail on the segmentation fault itself.&lt;/p&gt;

&lt;p&gt;To do this, you can use the &lt;a href="https://www.npmjs.com/package/segfault-handler"&gt;Segfault-Handler&lt;/a&gt; module. Just run &lt;code&gt;npm install segfault-handler&lt;/code&gt;, and then add the below right at the start of your application code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SegfaultHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;segfault-handler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;SegfaultHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;registerHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crash.log&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That module listens for any SIGSEGV signal, and reports the detailed stack trace that caused it before the process shuts down. When you next hit your segmentation fault, you'll get something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;PID&lt;/span&gt; &lt;span class="mi"&gt;30818&lt;/span&gt; &lt;span class="nx"&gt;received&lt;/span&gt; &lt;span class="nx"&gt;SIGSEGV&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;0x20&lt;/span&gt;
&lt;span class="p"&gt;[...]&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;node_modules&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;segfault&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;Release&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;segfault&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x3127&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mh"&gt;0x7fdb5a5fb127&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;x86_64&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;linux&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;gnu&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;libpthread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;so&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x128a0&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mh"&gt;0x7fdb735f58a0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_ZN4node7TLSWrap6EncOutEv&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x170&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mh"&gt;0xa09010&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_ZN4node7TLSWrap7DoWriteEPNS_9WriteWrapEP8uv_buf_tmP11uv_stream_s&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x2c7&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mh"&gt;0xa0a6c7&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_ZN4node5http212Http2Session15SendPendingDataEv&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x4ce&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mh"&gt;0x93b5ae&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_ZN4node5http212Http2Session5CloseEjb&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0xda&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mh"&gt;0x93c4fa&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mh"&gt;0xb62a3f&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_ZN2v88internal21Builtin_HandleApiCallEiPPNS0_6ObjectEPNS0_7IsolateE&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0xb9&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mh"&gt;0xb635a9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mh"&gt;0xcec6c2dbe1d&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="mi"&gt;30818&lt;/span&gt; &lt;span class="nx"&gt;segmentation&lt;/span&gt; &lt;span class="nx"&gt;fault&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;core&lt;/span&gt; &lt;span class="nx"&gt;dumped&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's the output from a segmentation fault I was hitting recently, where the new HTTP/2 debugging support in &lt;a href="https://httptoolkit.tech/"&gt;HTTP Toolkit&lt;/a&gt; occasionally crashed the Node process, after certain patterns of connections &amp;amp; disconnections.&lt;/p&gt;

&lt;p&gt;A trace like this doesn't give you enough to fix the issue, but it does give a clear clue where the problem lies.&lt;/p&gt;

&lt;p&gt;In my case, the &lt;code&gt;SendPendingData&lt;/code&gt; method of an &lt;code&gt;HTTP2Session&lt;/code&gt; is trying to write to a TLS stream as the session closes down, and that's then crashing the process. That gave me some clear info: it's an issue with HTTP/2 requests, and it's happening in node itself, not a native addon. From there, a &lt;a href="https://github.com/nodejs/node/issues?q=http2+segmentation+fault+is%3Aopen"&gt;quick search&lt;/a&gt; of the Node issue tracker led me to a &lt;a href="https://github.com/nodejs/node/issues/29902"&gt;reported bug&lt;/a&gt;, and eventually to a workaround.&lt;/p&gt;

&lt;h3&gt;
  
  
  Find a fix
&lt;/h3&gt;

&lt;p&gt;From here, you should have some pointer towards the code that's buggy. If there's a suspicious native addon module involved then that's almost certainly the culprit, and you should start there.&lt;/p&gt;

&lt;p&gt;Otherwise, if the trace is clearly pointing to Node internals (as above) and you're not messing around with those yourself, or using any relevant native addons, then you've probably found a bug in Node. Congratulations! Node should never segfault if you're writing normal JavaScript code, so something very wrong is going on.&lt;/p&gt;

&lt;p&gt;From here, there's a few good next steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Update to the latest version of Node/the node module in question, and make sure the same bug still appears there.&lt;/p&gt;

&lt;p&gt;In many cases just a quick update of the right thing will solve your issue, and if not then maintainers will be much happier to help you investigate if they know it's definitely a current issue.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Double-check your code is using the failing code as intended.&lt;/p&gt;

&lt;p&gt;Check the documentation of the related properties and methods you're accessing, and make sure that they are indeed documented (i.e. you're not unexpectedly messing with internal state) and that you're following the instructions in that documentation correctly. It's often useful to look through the native module's test code too, to see some examples of how it's supposed to be accessed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Report the issue to the addon maintainers/Node team.&lt;/p&gt;

&lt;p&gt;GitHub is your friend here: use the details you've found to &lt;strong&gt;do a quick search on the relevant repo's issue tracker first&lt;/strong&gt;. The Node issue tracker is available at &lt;a href="https://github.com/nodejs/node/issues"&gt;github.com/nodejs/node/issues&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you're lucky, you'll find an issue with more information, and maybe even an existing workaround. You can then add any extra details you have and an upvote there to help the maintainers. Of course, if not, it's time to file a bug for yourself.&lt;/p&gt;

&lt;p&gt;Either way the best way to ensure these bugs actually get fixed is to provide a reliable way for other developers to reproduce the issue. The more information on how to do so, and the simpler the steps required, the better.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use your segfault trace to find the relevant code, add detailed logging or use debugging tools, and very carefully walk through the code that's failing to try and find something that's not quite right.&lt;/p&gt;

&lt;p&gt;If you're not familiar with the code in question, and you haven't written native addons for Node.js before this can be intimidating and difficult. It's worth a go though, and you don't need to understand the code perfectly to do this. In many cases you'll quickly spot a comment or clue for why this crash could occur, that'll lead you back to a nice clean fix in your own JavaScript.&lt;/p&gt;

&lt;p&gt;Especially in native addons, you'll often find that they make certain assumptions (this method will never be called twice, this parameter will never be undefined) that aren't always checked everywhere. Any of these can easily mean that a minor bug in your code results in the addon's native code doing completely the wrong thing, and crashing the whole process.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Find a workaround: change how you're using the module in question, use a different module entirely for now, delete the broken feature from your product entirely, or quit your job and go live in the forest.&lt;/p&gt;

&lt;p&gt;Hopefully that's enough to show where the issue is, and get the information to fix or workaround it so you can get your code back on track.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Have any other suggestions or advice for others in the same place? Write a comment below, or let me know on &lt;a href="https://twitter.com/pimterry"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://httptoolkit.tech/blog"&gt;the HTTP Toolkit blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>debugging</category>
      <category>testing</category>
    </item>
    <item>
      <title>Translating between HTTP/1 and HTTP/2</title>
      <dc:creator>Tim Perry</dc:creator>
      <pubDate>Wed, 15 Jul 2020 14:30:00 +0000</pubDate>
      <link>https://dev.to/pimterry/translating-between-http-1-and-http-2-1lpo</link>
      <guid>https://dev.to/pimterry/translating-between-http-1-and-http-2-1lpo</guid>
      <description>&lt;p&gt;Semantically, what changed in HTTP/2?&lt;/p&gt;

&lt;p&gt;Multiplexed connections, binary frames, header compression - all the headline changes are syntactic and network format changes, rather than fundamental changes to the concept. As a developer building on top of this, you can often ignore the low-level syntax of network protocols like this, and just think about the meaning of each message (the semantics) rather than byte-by-byte how it's sent between computers.&lt;/p&gt;

&lt;p&gt;Semantically though, while HTTP/2 is built on top of the ideas of HTTP/1.1, and the &lt;a href="https://http2.github.io/http2-spec/"&gt;HTTP/2 spec&lt;/a&gt; is at pains to emphasize that it is not redefining HTTP's semantics, there are a few real-world semantic differences you need to use it effectively (and with HTTP/2 now in use on &lt;a href="https://w3techs.com/technologies/details/ce-http2"&gt;nearly 50% of the top 10 million webservers&lt;/a&gt;, you really do need to know how it works).&lt;/p&gt;

&lt;p&gt;This matters when building anything non-trivial on HTTP/2, but especially matters if your application does need to translate between the two, e.g. as a proxy or from a cache, and it's important to understand if you want to reliably handle requests in both protocols using the same code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The more things change, the more they stay the same
&lt;/h2&gt;

&lt;p&gt;Let's start with what &lt;em&gt;doesn't&lt;/em&gt; change.&lt;/p&gt;

&lt;p&gt;Firstly, the core communication model is still a request from a client followed by a response from the server.&lt;/p&gt;

&lt;p&gt;Requests have a method like GET, a URL, some headers, and optionally a body. Responses have a status code (200, 404...), their own headers, and their own body. Most HTTP methods and status codes still have the same fundamental meanings.&lt;/p&gt;

&lt;p&gt;You can write code that takes a request, looks at the method &amp;amp; URL to decide what to do, and sends back a response with a status code and the data requested, and most frameworks will make that work for you automatically. For basic HTTP handling like that, you can just enable HTTP/2 in your server of choice, and you're golden.&lt;/p&gt;

&lt;p&gt;Once you get into anything more complex though, you can run into some interesting issues. Let's dig into the differences:&lt;/p&gt;

&lt;h3&gt;
  
  
  Status messages are dead
&lt;/h3&gt;

&lt;p&gt;In HTTP/1, every response has a status code, and a status message. In its raw format, that might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/1.1 200 OK
header-name: header-value
another-header: ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;OK&lt;/code&gt; is the default for 200, but it's not fixed. This is equally valid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/1.1 200 Super great
header-name: header-value
another-header: ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This status info is received in the client, and can be used to make error messages more informative, to differentiate nuance in status-only responses, and so on.&lt;/p&gt;

&lt;p&gt;However, although it's useful in theory to have a space for a single-line summary of a response, this isn't used much in practice, and adds complexity, so HTTP/2 drops it entirely. It's just status codes now, and you'll need to put other data into the body or headers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Everything's a header
&lt;/h3&gt;

&lt;p&gt;HTTP/2 moves request and response metadata into so-called 'pseudo-headers'. These are headers, but prefixed with a colon, like &lt;code&gt;:path&lt;/code&gt; (because in HTTP/1 that's an unparseable header name, so it's guaranteed to not have been used).&lt;/p&gt;

&lt;p&gt;That means that although requests do still have methods and URLs and responses still have status codes, they're now part of the header data itself. Rather than building the URL from the request path plus the old &lt;code&gt;Host&lt;/code&gt; header, we now have &lt;code&gt;:scheme&lt;/code&gt; (http/https), &lt;code&gt;:authority&lt;/code&gt; (the hostname) and &lt;code&gt;:path&lt;/code&gt; (the URL path) headers. Rather than a standalone status code, we have a &lt;code&gt;:status&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;This makes translation a bit more complicated, as a lot of pre-HTTP/2 code will choke on header names like these and the values need to be extracted for HTTP/1-compatible usage, but this allows these values to take advantage of &lt;a href="https://blog.cloudflare.com/hpack-the-silent-killer-feature-of-http-2/"&gt;header compression&lt;/a&gt; to be sent far more efficiently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hop-by-hop connection headers are no more
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection"&gt;Connection header&lt;/a&gt;, along with a few other related headers, describes specific details about how the direct TCP connection between the client and the server or proxy works. For example, in HTTP/1.1 a &lt;code&gt;Connection: close&lt;/code&gt; header might be sent with a message to close the connection immediately afterwards, rather than keeping it alive ready for future requests.&lt;/p&gt;

&lt;p&gt;The Connection header can also include a list of other header names, to declare them as only relevant for the current direct connection, i.e. to tell any proxies involved not to forward them to the target server.&lt;/p&gt;

&lt;p&gt;Other hop-by-hop headers include &lt;code&gt;Keep-Alive&lt;/code&gt; (which defines exactly &lt;em&gt;how&lt;/em&gt; a connection should be kept alive), &lt;code&gt;Proxy-Authenticate&lt;/code&gt; (authentication details for HTTP proxies) , &lt;code&gt;Trailer&lt;/code&gt; (announces headers that will arrive &lt;em&gt;after&lt;/em&gt; the message body in chunked messages), &lt;code&gt;Upgrade&lt;/code&gt; (switches the protocol of the current connection), and &lt;code&gt;Transfer-Encoding&lt;/code&gt; (describes data transfer formats, made unnecessary with HTTP/2's data framing).&lt;/p&gt;

&lt;p&gt;In HTTP/2, connection-specific headers like &lt;code&gt;Connection&lt;/code&gt; and &lt;code&gt;Keep-Alive&lt;/code&gt; are prohibited. While some browsers will simply ignore them, Safari and other webkit-based browsers will outright reject any response that contains them. Easy to do by accident, and a big problem.&lt;/p&gt;

&lt;p&gt;Other hop-by-hop headers aren't forbidden, but are not generally functional, and it's recommended that they not be used.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cookie headers
&lt;/h3&gt;

&lt;p&gt;In HTTP/1, according to &lt;a href="https://tools.ietf.org/html/rfc6265#section-5.4"&gt;RFC 6265&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When the user agent generates an HTTP request, the user agent MUST NOT attach more than one Cookie header field.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When a user agent (typically a browser) wants to send multiple cookies with a request, it sends them separated with a semicolon and space, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cookie: cookie1=a; cookie2=b
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In HTTP/2, you can still use this form, but you can also send multiple cookie headers separately, breaking the rule above.&lt;/p&gt;

&lt;p&gt;Splitting them up is generally better to do, because it allows HTTP/2 to more effectively compress cookie headers, so they're not sent repeatedly within the same connection. If you do send them separated like this then any change to them only requires sending the new changed header. If you concatenate them as with HTTP/1 then every change to any cookie requires resending all of them.&lt;/p&gt;

&lt;p&gt;Unfortunately that means headers for most HTTP/2 requests are invalid in HTTP/1, potentially resulting in your server rejecting the request entirely, missing all but one of the values provided, or other undefined behaviour. It's easy to fix though: just join all Cookie header values with a &lt;code&gt;'; '&lt;/code&gt; (semicolon + space) separator.&lt;/p&gt;

&lt;h3&gt;
  
  
  The CONNECT method
&lt;/h3&gt;

&lt;p&gt;A CONNECT request asks the server for a raw TCP tunnel to a different server. In HTTP/1 this is used almost exclusively for HTTP proxying, so that a client can make an HTTPS connection to a server through a proxy, without sharing the content of the connection with the proxy.&lt;/p&gt;

&lt;p&gt;In HTTP/1, a proxy client makes a CONNECT request with the name of the target server, the proxy server returns a 200 response (if it accepts it), and then the entire TCP connection becomes a tunnel to the target server. Every byte sent is sent directly on to the target, and every byte received is sent back to the client.&lt;/p&gt;

&lt;p&gt;In HTTP/2, a proxy client makes a CONNECT request with the name of the target server, the proxy returns a 200 response (if it accepts it), and then that one specific &lt;a href="https://developers.google.com/web/fundamentals/performance/http2#streams_messages_and_frames"&gt;request stream&lt;/a&gt; becomes a tunnel to the target server. To send data, it must be wrapped up as an HTTP/2 DATA frame, with the id of the tunnelled stream, and the data within that is then forwarded on to the target server, and received data is similarly packed into DATA frames on that stream, whilst other HTTP/2 requests with the proxy server can keep using the same TCP connection independently.&lt;/p&gt;

&lt;p&gt;In addition, setting up websockets and other HTTP protocol changes is now done using CONNECT requests, rather than the GET request + Upgrade header + 101 response that was used with HTTP/1. Like CONNECT tunnelling, websockets also now work over only a single stream within the HTTP/2 connection, rather than taking over the entire connection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server Push
&lt;/h3&gt;

&lt;p&gt;Server Push allows an HTTP/2 server to proactively send content to an HTTP/2 client, without it being requested.&lt;/p&gt;

&lt;p&gt;You can think of it semantically as an extra response given to a client, along with the metadata of a request that would have generated this response, like "if you were to send me a GET request for /abc, this is what you'd receive".&lt;/p&gt;

&lt;p&gt;This is useful when a server can guess what you're likely to request next, for example when you request an HTML page that contains lots of images, it can be useful for the server to push the critical images back alongside the HTML rather than wait for the client to realise they need them.&lt;/p&gt;

&lt;p&gt;HTTP/1 has no mechanism similar to this, so there's no way to translate this back for older clients, but fortunately push support is entirely optional, and clients or intermediaries are free to ignore push requests, or set the &lt;code&gt;SETTINGS_ENABLE_PUSH&lt;/code&gt; setting to &lt;code&gt;0&lt;/code&gt; to explicitly refuse them up front.&lt;/p&gt;

&lt;h2&gt;
  
  
  Translating one to the other
&lt;/h2&gt;

&lt;p&gt;If you're translating between the two, what does that mean in practice?&lt;/p&gt;

&lt;p&gt;If you want to safely translate an HTTP/2 message into HTTP/1, e.g. to handle an HTTP/2 request with HTTP/1.1-compatible code, you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In requests, build a method, URL and 'Host' header from the pseudo-headers&lt;/li&gt;
&lt;li&gt;In responses, read the status from the &lt;code&gt;:status&lt;/code&gt; pseudo-header, and set the status message to the default for that status code&lt;/li&gt;
&lt;li&gt;Strip all pseudo-headers from the header data&lt;/li&gt;
&lt;li&gt;Join your &lt;code&gt;Cookie&lt;/code&gt; headers with a &lt;code&gt;;&lt;/code&gt; separator, if you have more than one&lt;/li&gt;
&lt;li&gt;Build tunnels from CONNECT requests like normal, but tunneling just within that specific HTTP/2 stream, not the entire connection&lt;/li&gt;
&lt;li&gt;If you receive a server push, drop it silently (although you could cache it first), or considering signaling in the initial HTTP/2 SETTINGS frame that you don't accept pushes in the first place&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To safely translate an HTTP/1.1 message into HTTP/2, e.g. to return an HTTP/1.1-compatible response to an HTTP/2 client:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In responses, drop the status message entirely, and put the status code into the &lt;code&gt;:status&lt;/code&gt; pseudo-header&lt;/li&gt;
&lt;li&gt;In requests, build the &lt;code&gt;:scheme&lt;/code&gt;, &lt;code&gt;:authority&lt;/code&gt; and&lt;code&gt;:path&lt;/code&gt; headers from the URL and &lt;code&gt;host&lt;/code&gt; header&lt;/li&gt;
&lt;li&gt;Optional, but recommended: Split &lt;code&gt;Cookie&lt;/code&gt; headers into a separate header per cookie&lt;/li&gt;
&lt;li&gt;Strip all headers made illegal in HTTP/2 messages:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;connection&lt;/code&gt; (and all headers listed in the value of the connection header)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;upgrade&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;host&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;http2-settings&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keep-alive&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;proxy-connection&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;transfer-encoding&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;te&lt;/code&gt; (unless the value is just &lt;code&gt;trailers&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With all that in place, you can convert back and forth between HTTP/2 and HTTP/1 messages freely, and easily integrate HTTP/2 into your existing HTTP-powered codebase. Enjoy!&lt;/p&gt;

&lt;p&gt;If you're interested in the finer details of implementing this, you might enjoy &lt;a href="https://twitter.com/pimterry/status/1280132796951007233"&gt;this thread&lt;/a&gt;, where I'm currently live tweeting the entire implementation of &lt;a href="https://dev.to/"&gt;HTTP Toolkit&lt;/a&gt;'s new HTTP/2 interception &amp;amp; debugging support, with links and explanation for each commit along the way.&lt;/p&gt;

&lt;p&gt;Anything I've missed? Any thoughts? Leave a comment below or get in touch &lt;a href="https://twitter.com/pimterry"&gt;on Twitter&lt;/a&gt; and let me know.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://httptoolkit.tech/blog/translating-http-2-into-http-1"&gt;the HTTP Toolkit blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>http</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>What's coming in TypeScript 4?</title>
      <dc:creator>Tim Perry</dc:creator>
      <pubDate>Mon, 22 Jun 2020 16:00:00 +0000</pubDate>
      <link>https://dev.to/pimterry/what-s-coming-in-typescript-4-1024</link>
      <guid>https://dev.to/pimterry/what-s-coming-in-typescript-4-1024</guid>
      <description>&lt;p&gt;TypeScript 4 is coming up fast: a first beta release is planned for this week (June 25th), with the final release aiming for mid-August.&lt;/p&gt;

&lt;p&gt;It's important to note that &lt;a href="https://github.com/microsoft/TypeScript/issues/14116#issuecomment-280410804"&gt;TypeScript does not follow semver&lt;/a&gt;, so 4.0 is not as big a deal as it sounds! There can be (and often are) breaking changes between any minor TypeScript versions, and major version bumps like this happen primarily for marketing reasons, not technical ones.&lt;/p&gt;

&lt;p&gt;This bump to 4.0 doesn't suggest that everything is going to break, and this won't be a huge world-changing release, but it does bring some nice additions, particularly on the typing side. For projects like &lt;a href="https://httptoolkit.tech/"&gt;HTTP Toolkit&lt;/a&gt; (written entirely in TypeScript) that means faster development &amp;amp; fewer bugs!&lt;/p&gt;

&lt;p&gt;Let's dive into the details:&lt;/p&gt;

&lt;h2&gt;
  
  
  Variadic tuple types
&lt;/h2&gt;

&lt;p&gt;Also known as 'variadic &lt;a href="https://en.wikipedia.org/wiki/Kind_(type_theory)"&gt;kinds&lt;/a&gt;', this is a complex but substantial new feature for TypeScript's type system.&lt;/p&gt;

&lt;p&gt;It's not 100% confirmed yet (the &lt;a href="https://github.com/microsoft/TypeScript/pull/39094"&gt;PR&lt;/a&gt; remains unmerged), but it's explicitly in the 4.0 roadmap, and Anders Hejlsberg himself has &lt;a href="https://twitter.com/ahejlsberg/status/1272986860957003788"&gt;called it out&lt;/a&gt; as planned for the coming release.&lt;/p&gt;

&lt;p&gt;Explaining this is complicated if you don't have an strong existing grasp of type theory, but it's easy to demo. Let's try to type a &lt;code&gt;concat&lt;/code&gt; function with tuple arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="nx"&gt;strs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;strs&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;vals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// infers string | number, but we *know* it's a number (2)&lt;/span&gt;

&lt;span class="c1"&gt;// TS does support accurate types for these values though:&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;typedVals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;typedVal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;typedVals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; infers number, correctly&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is valid TypeScript code today, but it's suboptimal.&lt;/p&gt;

&lt;p&gt;Here, &lt;code&gt;concat&lt;/code&gt; works OK, but we're losing information in the types and we have to manually fix that later if we want to get accurate values elsewhere. Right now it's impossible to fully type such a function to avoid this.&lt;/p&gt;

&lt;p&gt;With variadic types though, we can:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nx"&gt;strs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;strs&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;vals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; infers number&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;val2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; infers 2, not just any number&lt;/span&gt;

&lt;span class="c1"&gt;// Go even further and accurately concat _anything_:&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In essence, tuple types can now include &lt;code&gt;...T&lt;/code&gt; as a generic placeholder for multiple types in the tuple. You can describe an unknown tuple (&lt;code&gt;[...T]&lt;/code&gt;), or use these to describe partially known tuples (&lt;code&gt;[string, ...T, boolean, ...U]&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;TypeScript can infer types for these placeholders for you later, so you can describe only the overall shape of the tuple, and write code using that, without depending on the specific details.&lt;/p&gt;

&lt;p&gt;This is neat, and applies more generally than just concatenating arrays. By combining this with existing varadic functions, like &lt;code&gt;f&amp;lt;T extends unknown[]&amp;gt;(...args: [...T])&lt;/code&gt;, you can treat function arguments as arrays, and describe functions with far more flexible argument formats and patterns than in the past.&lt;/p&gt;

&lt;p&gt;For example, right now rest/varadic parameters in TypeScript must always be the last param in a function. For example, &lt;code&gt;f(a: number, ...b: string[], c: boolean)&lt;/code&gt; is invalid.&lt;/p&gt;

&lt;p&gt;With this change, by defining the arguments of the function using a variadic tuple type like &lt;code&gt;f&amp;lt;T extends string[]&amp;gt;(...args: [number, ...T, boolean])&lt;/code&gt; you can do that.&lt;/p&gt;

&lt;p&gt;That's all a bit abstract. In practice, this means you'll be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Destructure array types:
&lt;code&gt;type head = &amp;lt;H extends unknown, T extends unknown[]&amp;gt;(list: [H, ...T]) =&amp;gt; H&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Do many of the things allowed by &lt;a href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#mapped-types"&gt;mapped types&lt;/a&gt;, but on arbitrary-length arrays of values, not just on objects.&lt;/li&gt;
&lt;li&gt;Infer full types for functions with variadic arguments: &lt;code&gt;type f = &amp;lt;T extends unknown[]&amp;gt;(...args: [...T]) =&amp;gt; T&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Infer proper types even for extra complicated partially-known variadic arguments: &lt;code&gt;type f = &amp;lt;T extends unknown[]&amp;gt;(...args: [string, ...T, boolean]) =&amp;gt; T&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.typescriptlang.org/play/index.html?ts=4.0.0-pr-39094-7&amp;amp;ssl=26&amp;amp;ssc=21&amp;amp;pln=26&amp;amp;pc=30#code/C4TwDgpgBAkgdgMwgJwILIOYFcC2E7ADOAPACoB8UAvAFBRSlQQAew+AJoVABQB0-UYAC4oAbX68AlohRQASgBoeEgIaZCIlXBABKapS0gAunqoHtUAPzyoIuBABuKGjVCRYM5HIiEsAGyIySiooOgYmVg4uPgFhMQlpJGQGJW5kHxFE2TlTc2NcqEMrGztHZxoELDgAY2BJAHs4KDBkepxJQkkEEGIwgDEqiLY4TmV+NQwNQu1RE31pkBpybgQRAbgdERjeCan4JPRsPAISdfICgAVW9sIIYn2Ub18A06rySgBvMPTgLGQmyo1OqNba7EQPNCYXD4QJnPRfej0H5-Jr2ADuUCubQ6EG4aR89T8TgKCMR9EBtQaTWqKj8fgARipqgBrfHPOIQp7+WFveFhMlIglE3Hpdk6fmIgC+Evou14YCwhAAFtwaXTGSydABuGVQBC8NV+bhwfx+JSqdTismSq1QaXSmjsCDVPxqaAU4FNPz1FTsbhhBCSPwQESEYDIaQYBRhfDVersSOh8OR6P0Q0a5lbUXcpMRuAYAoOeqSdibKBFksuONwMNQb2+rE3aAhFrYzrdbj10suLuNnHcADkvAA9GxWLwcOwB0oB1hgAgALQADgHOl4wCV+DZ81Jw+HUFFUA6UDDeYwAEIaDaXG5oABZHyEFQYHzUKAD+qQOADqAAH3faIRmwP7-gOHAge+KCtMgA6Os6rrpHqVSUo0UAgmEOCEBgIgPoQT4voQqZQOmTKZjwmHYVAHyCOAIZQLh+E+Eo1bDHEp6RnahbFuwNBlhWPE0NWtaNH2txvq2NxdCA3CNOKNAidc-Yfl+q7rpucDbmYVFhEJhIQLw3oYGyBqNKxeh7lAgC8G4AsjtXnJNBAA"&gt;Fully define types&lt;/a&gt; for &lt;code&gt;promisify&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create accurate types for many other higher-order function definitions, like &lt;code&gt;curry&lt;/code&gt;, &lt;code&gt;apply&lt;/code&gt;, &lt;code&gt;compose&lt;/code&gt;, &lt;code&gt;cons&lt;/code&gt;, ...&lt;/li&gt;
&lt;li&gt;Kill all sorts of &lt;a href="https://github.com/microsoft/TypeScript/issues/1773#issuecomment-81514630"&gt;workarounds&lt;/a&gt; where you had to separately define an overload for each possible number of arguments (I've been &lt;a href="https://github.com/pimterry/typesafe-get/blob/master/index.ts"&gt;guilty&lt;/a&gt; of this myself).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even if you're not writing a lot of higher order functions, improved typing here should allow more detailed types to spread far and wide through your code, inferring away many non-specific array types, and improving other types all over the place.&lt;/p&gt;

&lt;p&gt;There's a lot more depth and many other use cases for this - take a look at &lt;a href="https://github.com/microsoft/TypeScript/issues/5453"&gt;the full GitHub discussion&lt;/a&gt; for more info.&lt;/p&gt;

&lt;h2&gt;
  
  
  Labelled Tuples
&lt;/h2&gt;

&lt;p&gt;As a related but drastically simpler feature: TypeScript will allow labelling the elements of your tuples.&lt;/p&gt;

&lt;p&gt;What does the below tell you?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getSize&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;How about now?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getSize&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;These labels disappear at runtime and don't do any extra type checking, but they do make usage of tuples like these far clearer.&lt;/p&gt;

&lt;p&gt;These also work for rest &amp;amp; optional arguments too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MyTuple&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For more info, checkout the &lt;a href="https://github.com/Microsoft/TypeScript/issues/28259"&gt;GitHub issue&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Property type inference from constructor usage
&lt;/h2&gt;

&lt;p&gt;A nice clear improvement to type inference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;X&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the above code right now, the type of &lt;code&gt;a&lt;/code&gt; is &lt;code&gt;any&lt;/code&gt; (triggering an error if &lt;code&gt;noImplicitAny&lt;/code&gt; is enabled). Property types are only inferred from direct initialization, so you always need either an initializer or an explicit type definition.&lt;/p&gt;

&lt;p&gt;In TypeScript 4.0, the type of &lt;code&gt;a&lt;/code&gt; will be &lt;code&gt;string | boolean&lt;/code&gt;: constructor usage is used to infer property types automatically.&lt;/p&gt;

&lt;p&gt;If that's not sufficient, you can still explicitly define types for properties, and those will be used in preference when they exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Short-circuit assignment operators
&lt;/h2&gt;

&lt;p&gt;Not interested in typing improvements? TypeScript 4.0 will also implement the stage 3 JS &lt;a href="https://github.com/tc39/proposal-logical-assignment"&gt;logical assignment&lt;/a&gt; proposal, supporting the new syntax and compiling it back to make that usable in older environments too.&lt;/p&gt;

&lt;p&gt;That looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="c1"&gt;// equivalent to: a = a || b&lt;/span&gt;

&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;=&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="c1"&gt;// equivalent to: a = a &amp;amp;&amp;amp; b&lt;/span&gt;

&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;??=&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="c1"&gt;// equivalent to: a = a ?? b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Nowadays the last option is probably the most useful here, unless you're exclusively handling booleans. This null-coalescing assignment is perfect for default or fallback values, where &lt;code&gt;a&lt;/code&gt; might not have a value.&lt;/p&gt;

&lt;h2&gt;
  
  
  The also rans
&lt;/h2&gt;

&lt;p&gt;That's a few of the bigger notices, but there's a lot of other good stuff here too:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;unknown&lt;/code&gt; now supported as a type annotation for catch clauses:
&lt;code&gt;try { ... } catch (e: unknown) { ... }&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Support for React's new &lt;a href="https://github.com/microsoft/TypeScript/issues/34547"&gt;JSX internals&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Editor support for &lt;code&gt;@deprecated&lt;/code&gt; JSDoc annotations&lt;/li&gt;
&lt;li&gt;More performance improvements, following on from the big &lt;a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-9.html#speed-improvements"&gt;improvements&lt;/a&gt; in 3.9&lt;/li&gt;
&lt;li&gt;New editor refactorings (e.g. automatically refactoring code to use optional chaining), improved editor refactorings (better auto-import!), and &lt;a href="https://github.com/microsoft/TypeScript/issues/38435"&gt;semantic highlighting&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these are individually huge, but nonetheless, cumulatively it'll improve life for TypeScript developers, with some great improvements to type safety and developer experience all round.&lt;/p&gt;

&lt;p&gt;I should note that none of this is final yet! I've skipped a few discussed-but-not-implemented changes - from &lt;a href="https://github.com/microsoft/TypeScript/issues/27711"&gt;&lt;code&gt;awaited T&lt;/code&gt;&lt;/a&gt; to &lt;a href="https://github.com/microsoft/TypeScript/issues/31894#issuecomment-640942186"&gt;placeholder types&lt;/a&gt; - and it's quite possible some of these features could suddenly appear in the next month, or equally that a new problem could cause changes in the implemented features above, so do keep your eyes peeled...&lt;/p&gt;

&lt;p&gt;Hope that's useful! Get in touch on &lt;a href="https://twitter.com/pimterry"&gt;Twitter&lt;/a&gt; or stick a comment below if you've got any questions or thoughts.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://httptoolkit.tech/blog/whats-coming-in-typescript-4"&gt;the HTTP Toolkit blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Bye bye Feature-Policy, hello Permissions-Policy</title>
      <dc:creator>Tim Perry</dc:creator>
      <pubDate>Wed, 27 May 2020 13:30:00 +0000</pubDate>
      <link>https://dev.to/pimterry/bye-bye-feature-policy-hello-permissions-policy-31gd</link>
      <guid>https://dev.to/pimterry/bye-bye-feature-policy-hello-permissions-policy-31gd</guid>
      <description>&lt;p&gt;Ever heard of &lt;a href="https://w3c.github.io/webappsec-feature-policy/"&gt;&lt;code&gt;Feature-Policy&lt;/code&gt;&lt;/a&gt;? It's a draft W3C web security standard, defining an HTTP header and iframe attribute that sets limits on the browser features a page can use.&lt;/p&gt;

&lt;p&gt;It's useful for any site that's concerned about XSS attacks, embedded content, security risks in dependencies, or major bugs in their own software, by setting guardrails on the browser features a page can use. You can use feature policy to guarantee your page or an embedded iframe cannot access the user's microphone or camera, can't read their location or phone sensors, can't use the Payment Request API, and so on. This is an &lt;em&gt;extra&lt;/em&gt; safeguard, in addition to the browser's own permissions system, so it only tightens existing permission restrictions further.&lt;/p&gt;

&lt;p&gt;Feature Policy has been around a couple of years now, and got some good early press as a recommended security technique all over, from Google's &lt;a href="https://developers.google.com/web/updates/2018/06/feature-policy"&gt;web developer guide&lt;/a&gt; to &lt;a href="https://www.smashingmagazine.com/2018/12/feature-policy/"&gt;Smashing Magazine&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since then browser support has made steady progress, with about 75% of users globally &lt;a href="https://caniuse.com/#feat=feature-policy"&gt;now supporting&lt;/a&gt; it (that's all recent browser versions except Safari). More recently that's lead to the start of real production usage: &lt;a href="https://github.com/rails/rails/pull/33439"&gt;Rails 6.1&lt;/a&gt; and Node.js's popular &lt;a href="https://www.npmjs.com/package/helmet"&gt;helmet&lt;/a&gt; security package recently shipped built-in support, and Scott Helme's &lt;a href="https://scotthelme.co.uk/top-1-million-analysis-march-2020/"&gt;latest analysis&lt;/a&gt; of the top 1 million sites shows the Feature-Policy header in use by nearly 5,000 of them.&lt;/p&gt;

&lt;p&gt;It is still just a draft though. That means it's subject to change, and it is now changing: &lt;strong&gt;the Feature-Policy standard &amp;amp; header is being renamed to Permissions-Policy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There's some discussion of the reasoning in &lt;a href="https://github.com/w3c/webappsec-feature-policy/issues/359"&gt;the spec repo&lt;/a&gt;. In short:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Many proposed additions don't mesh with the existing Feature-Policy behaviour, so these (along with some of the existing features) are being defined instead in a new &lt;a href="https://w3c.github.io/webappsec-feature-policy/document-policy.html"&gt;Document-Policy&lt;/a&gt; header, with different semantics focused on feature &lt;em&gt;configuration&lt;/em&gt;, rather than security.&lt;/li&gt;
&lt;li&gt;The remaining features are a strict subset of the &lt;a href="https://w3c.github.io/permissions/#permission-registry"&gt;separately defined&lt;/a&gt; set of web permissions.&lt;/li&gt;
&lt;li&gt;Renaming offers an opportunity to change the header value syntax, to align it with the new &lt;a href="https://datatracker.ietf.org/doc/draft-ietf-httpbis-header-structure/"&gt;Structured Headers&lt;/a&gt; standard.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Any kind of migration of web standards comes with some risk. In this case, a different risk than normal: removing or renaming this header won't break anything outright, but it does silently remove a security safeguard from existing sites.&lt;/p&gt;

&lt;p&gt;The exact migration plan is unclear, but it seems likely that browsers will include support for the existing header &amp;amp; syntax for a while with a warning, to ensure this is as obvious as possible for the existing sites that expect it to work. Seeing this change in the real world is still a couple of browser releases away, so we'll have to wait to find out exactly how each browser decides to handle this.&lt;/p&gt;

&lt;p&gt;Consider this an early warning though: if you're currently using Feature-Policy, you're going to want to migrate soon, and as a community we've got a whole bunch of documentation that's going to need updating.&lt;/p&gt;

&lt;p&gt;Want to test out Feature/Permissions policy headers right now? Fire up &lt;strong&gt;&lt;a href="https://httptoolkit.tech/"&gt;HTTP Toolkit&lt;/a&gt;&lt;/strong&gt;, set some breakpoint rules, intercept some real web traffic, and rewrite the live headers to your heart's content.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published &lt;a href="https://httptoolkit.tech/blog"&gt;on the HTTP Toolkit blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>http</category>
    </item>
    <item>
      <title>How will user-agent client hints work?</title>
      <dc:creator>Tim Perry</dc:creator>
      <pubDate>Wed, 06 May 2020 17:00:00 +0000</pubDate>
      <link>https://dev.to/pimterry/how-will-user-agent-client-hints-work-1fgi</link>
      <guid>https://dev.to/pimterry/how-will-user-agent-client-hints-work-1fgi</guid>
      <description>&lt;p&gt;In the coming months, browsers are going to start killing the &lt;code&gt;User-Agent&lt;/code&gt; HTTP header to replace it with user-agent client hints, a set of opt-in &lt;code&gt;Sec-CH-UA-*&lt;/code&gt; headers.&lt;/p&gt;

&lt;p&gt;Maybe you've heard about this already, maybe that all sounds great, but what &lt;em&gt;exactly&lt;/em&gt; does this mean in practice?&lt;/p&gt;

&lt;p&gt;Let's talk about how the &lt;code&gt;Accept-CH&lt;/code&gt; and &lt;code&gt;Sec-CH-UA-*&lt;/code&gt; headers will work, how you can test that with your own services today, and what comes next.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the current situation?
&lt;/h2&gt;

&lt;p&gt;Right now the user agent (UA) includes your browser version, OS version and architecture, specific mobile phone manufacturer &amp;amp; model, and more. This creates a wide range of unique user agent header values, and that means a server &amp;amp; proxies can use this header (along with other data points) to &lt;a href="https://en.wikipedia.org/wiki/Device_fingerprint" rel="noopener noreferrer"&gt;fingerprint&lt;/a&gt; users - to recognize &amp;amp; track individual people without using cookies or other restricted tracking mechanisms.&lt;/p&gt;

&lt;p&gt;In addition, many sites use UAs to decide which content to server. This UA 'sniffing' has historically been abused, blocking functional browsers from accessing services when they don't fit a whitelist of known UA formats. That in turn has resulted in UAs trying to preserve backward compatibility, and UA strings gaining more and more cruft that can never be removed. Right now, 100% of popular browsers' user agents start with &lt;code&gt;Mozilla/5.0&lt;/code&gt;, for instance. Not great.&lt;/p&gt;

&lt;p&gt;As a case in point, here's a user agent for Chrome on Android:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mozilla/5.0 (Linux; Android 9; Pixel 2 XL Build/PPP3.180510.008) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Very specific, and very inaccurate. In reality, there's no KHTML, Gecko, Safari or Mozilla involved. All this information is sent to every service your browser communicates with in any way. This is a mess.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the plan?
&lt;/h2&gt;

&lt;p&gt;The solution is not to remove the &lt;code&gt;User-Agent&lt;/code&gt; header completely. For compatibility reasons it will still be sent, probably forever, but 'frozen'. The plan is to progressively reduce the number of unique UA values, by grouping more and more cases together to return the same UA.&lt;/p&gt;

&lt;p&gt;Soon, there's likely be a single UA used by all Chrome versions on all desktop OSs, and a single UA used by all Chrome versions of all mobile OSs. That reduces the real information in the user agent down to just mobile/desktop, and the browser itself. Long term, it's very possible those will be frozen too, sharing UAs across desktop and mobile and more browsers.&lt;/p&gt;

&lt;p&gt;This will apply to both the &lt;code&gt;User-Agent&lt;/code&gt; header that's sent in HTTP requests, and the &lt;code&gt;navigator.userAgent&lt;/code&gt; property accessible from client-side JavaScript.&lt;/p&gt;

&lt;p&gt;Some services do need the information that the UA provides though. You might be serving content that depends on the specific browser version a user is using (either because the content itself is relevant to the browser, or because you need to work around behaviour in specific known versions), or you might be serving content that depends on the user's specific OS and OS version (offering a Mac download to Mac users and a Windows download to Windows users).&lt;/p&gt;

&lt;p&gt;These cases exist, and will continue to be supported, but explicitly: the server will need to send an &lt;code&gt;Accept-CH&lt;/code&gt; header to request this information.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Accept-CH header
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Accept-CH&lt;/code&gt; is an existing HTTP header, currently an active but experimental &lt;a href="https://datatracker.ietf.org/doc/draft-ietf-httpbis-client-hints/?include_text=1" rel="noopener noreferrer"&gt;draft standard&lt;/a&gt;, currently in the "Last Call" phase (until the 8th of May 2020). It's been supported in Chrome on desktop &amp;amp; Android since 2015, and other Chromium-based browsers, though it's not yet available in Firefox or Safari.&lt;/p&gt;

&lt;p&gt;Until now, its been used to request bonus details from browsers, such as the user's connection speed, viewport size or screen density. The idea is to allow servers to customize the content they serve, optimizing images and other content for mobile devices or users on low-bandwidth connections.&lt;/p&gt;

&lt;p&gt;It works like so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The client sends a request to the server with no hints, for example an initial navigation to &lt;code&gt;https://example.com/index.html&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The server responds with the content requested, and includes an &lt;code&gt;Accept-CH&lt;/code&gt; header, such as:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Accept-CH: Viewport-Width&lt;/code&gt; - the server wants to know the width of the client's screen&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Accept-CH: Width&lt;/code&gt; - the server wants to know the desired width of resources being requested (e.g. how much space is available to show an image)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Accept-CH: DPR, Device-Memory, Downlink&lt;/code&gt; - the server wants to know the screen density, amount of RAM, and bandwidth of the client&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;For subsequent requests for pages or resources from the same origin, the client sends these hints, each as a separate header:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Width: 123&lt;/code&gt; - the size of image the device wants to show&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Device-Memory: 2&lt;/code&gt; - the memory of the device, in GiB, rounded to 0.25/0.5/1/2/4/8 to resist fingerprinting&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Download: 2.5&lt;/code&gt; - the bandwidth available, in Mbps, rounded to the nearest 25Kbps to resist fingerprinting&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  There's a few caveats to this:
&lt;/h3&gt;

&lt;p&gt;First, client hints aren't always honoured. They're only supported for HTTPS connections, and only on first-party resources, so if you open &lt;code&gt;https://example.com&lt;/code&gt; in your browser, requests to load subresources from &lt;code&gt;example.com&lt;/code&gt; may include client hints, but requests for subresources from &lt;code&gt;ads.otherdomain.com&lt;/code&gt; will not (although this may be &lt;a href="https://github.com/WICG/client-hints-infrastructure#cross-origin-hint-delegation" rel="noopener noreferrer"&gt;configurable&lt;/a&gt; using a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy" rel="noopener noreferrer"&gt;feature policy&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;They're also optional. Clients might refuse to send them, or might not support them at all, and they'll likely never appear in the first request to your origin.&lt;/p&gt;

&lt;p&gt;That said, if you do need a hint in the initial request, you could return an &lt;code&gt;Accept-CH&lt;/code&gt; header with a 307 redirect back to the same URL to ask for the hint immediately, but you rarely want to do this. Doing so adds a redirect to your page load, and you risk putting users who can't or won't provide these hints into a redirect loop that locks them out of your site. It's better to serve a default version of your content, and treat client hints as progressive enhancement, to be used when available but not depended upon.&lt;/p&gt;

&lt;p&gt;These client hints are then persisted for the origin. The exact lifetime is left up to the client (a previous draft included a &lt;code&gt;Accept-CH-Lifetime&lt;/code&gt; header, but that's now &lt;a href="https://github.com/httpwg/http-extensions/pull/878" rel="noopener noreferrer"&gt;been removed&lt;/a&gt;) but its likely to be at least the rest of the current browser session. Although this means the same hint headers are duplicated on all future requests, with HTTP/2's &lt;a href="https://blog.cloudflare.com/hpack-the-silent-killer-feature-of-http-2/" rel="noopener noreferrer"&gt;header compression&lt;/a&gt; that can be done extremely efficiently.&lt;/p&gt;

&lt;p&gt;Lastly, if you are building a server that uses any client hints, you should be sure to include &lt;code&gt;Vary: &amp;lt;hint name&amp;gt;&lt;/code&gt; in all responses, to ensure that they're only cached for requests that send the same hint values.&lt;/p&gt;

&lt;p&gt;All of this is Chrome only right now, although there's &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=935216" rel="noopener noreferrer"&gt;some progress&lt;/a&gt; in other browsers, and the standardisation process is intended to encourage that. The set of opt-in hints supported in the latest stable Chrome includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Width&lt;/li&gt;
&lt;li&gt;Viewport-Width&lt;/li&gt;
&lt;li&gt;DPR&lt;/li&gt;
&lt;li&gt;Content-DPR&lt;/li&gt;
&lt;li&gt;Device-Memory&lt;/li&gt;
&lt;li&gt;RTT&lt;/li&gt;
&lt;li&gt;Downlink&lt;/li&gt;
&lt;li&gt;ECT&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google's web fundamentals guide has &lt;a href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/client-hints" rel="noopener noreferrer"&gt;more detail&lt;/a&gt; about using these in practice.&lt;/p&gt;

&lt;p&gt;That's the state of things &lt;em&gt;today&lt;/em&gt;. Let's talk about how we can use this to kill off &lt;code&gt;User-Agent&lt;/code&gt; once and for all.&lt;/p&gt;

&lt;h2&gt;
  
  
  User-agent client hints
&lt;/h2&gt;

&lt;p&gt;The current &lt;a href="https://wicg.github.io/ua-client-hints/" rel="noopener noreferrer"&gt;UA client hints draft&lt;/a&gt; proposes a few user-agent client hint headers to expose the information from &lt;code&gt;User-Agent&lt;/code&gt; in a granular form:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Sec-CH-UA&lt;/code&gt; - basic UA info, e.g. &lt;code&gt;"Google Chrome"; v="84"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Sec-CH-UA-Arch&lt;/code&gt; - the CPU architecture, e.g. &lt;code&gt;x86_64&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Sec-CH-UA-Model&lt;/code&gt; - the device model, e.g. &lt;code&gt;Pixel 3&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Sec-CH-UA-Platform&lt;/code&gt; - the client OS, e.g. &lt;code&gt;Linux&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Sec-CH-UA-Platform-Version&lt;/code&gt; - the client OS version, e.g. &lt;code&gt;NT 6.0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Sec-CH-UA-Full-Version&lt;/code&gt; - the full client UA version, e.g. &lt;code&gt;"84.0.4128.3"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Sec-CH-UA-Mobile&lt;/code&gt; - a &lt;a href="https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-18#section-3.3.6" rel="noopener noreferrer"&gt;boolean header&lt;/a&gt;, describing whether the client a mobile device, either &lt;code&gt;?1&lt;/code&gt; (yes) or &lt;code&gt;?0&lt;/code&gt; (no)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;Sec-&lt;/code&gt; prefix here may be unfamiliar. This is a general prefix for a &lt;a href="https://fetch.spec.whatwg.org/#forbidden-header-name" rel="noopener noreferrer"&gt;forbidden header name&lt;/a&gt; as defined by &lt;a href="https://fetch.spec.whatwg.org/" rel="noopener noreferrer"&gt;the Fetch spec&lt;/a&gt;. Headers starting with &lt;code&gt;Sec-&lt;/code&gt; can never be manually sent by JS in a web page.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Sec-CH-UA&lt;/code&gt; and &lt;code&gt;Sec-CH-UA-Mobile&lt;/code&gt; are considered &lt;a href="https://wicg.github.io/client-hints-infrastructure/#low-entropy-table" rel="noopener noreferrer"&gt;'low-entropy hints'&lt;/a&gt;, which will be sent by default. For the others, you'll need to send an &lt;code&gt;Accept-CH&lt;/code&gt; header, with the header name without the &lt;code&gt;Sec-CH-&lt;/code&gt; prefix. For example, if you want to know what platform the client is using, send a &lt;code&gt;Accept-CH: UA-Platform&lt;/code&gt; response.&lt;/p&gt;

&lt;p&gt;It's important not to ask for too much, and request only the hints you really need. In addition to potential data transfer concerns (especially for HTTP/1.1 clients or servers), requesting too much information may trip a &lt;a href="https://github.com/bslassey/privacy-budget" rel="noopener noreferrer"&gt;privacy budget&lt;/a&gt; or otherwise trigger permission prompts in future, and implies collecting unnecessary personal information about your users.&lt;/p&gt;

&lt;p&gt;The draft also proposes a &lt;code&gt;navigator.userAgentData&lt;/code&gt; JavaScript API to access this hint data client-side, but that doesn't seem to be implemented anywhere yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to start using these today
&lt;/h2&gt;

&lt;p&gt;Right now, the only browser that supports this is Chrome, and only in the dev &amp;amp; canary channels, and behind a flag. It's early days! That said, testing it out now allows you to see how this might impact your application, and start to see how you can capture any hints that you need to handle this, once this does land for real.&lt;/p&gt;

&lt;p&gt;To test this out today, you'll need an HTTPS server locally where you can log requests and play with the response headers, or you can use an HTTP debugger like &lt;a href="https://dev.to/"&gt;HTTP Toolkit&lt;/a&gt; to directly inspect &amp;amp; inject responses to test around with. Once you have that in place:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open Chrome (either the Dev or Canary builds)&lt;/li&gt;
&lt;li&gt;Enable "Experimental Web Platform features" and "Freeze User-Agent request header" from &lt;code&gt;chrome://flags&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Load a page from your domain over HTTPS, and look at the request headers you receive - this is what'll happen soon by default: &lt;a href="https://httptoolkit.tech/static/273be58bfe47fd714d770de83e7fffb1/cfa2d/chrome-ua-frozen.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhttptoolkit.tech%2Fstatic%2F273be58bfe47fd714d770de83e7fffb1%2Fcfa2d%2Fchrome-ua-frozen.png" alt="Example.com loaded with the UA frozen"&gt;&lt;/a&gt;&lt;em&gt;Note the frozen "84.0.0.0" version and "Windows" platform in the UA here&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Load the page afresh, this time returning edited headers (directly from your server, or by adding a breakpoint from the &lt;a href="https://dev.to/docs/reference/mock-page"&gt;Mock page&lt;/a&gt; in HTTP Toolkit) that include &lt;code&gt;Accept-CH: UA-Platform&lt;/code&gt; &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhttptoolkit.tech%2Fstatic%2F8ff13588fa0efe35cbefe51c049ae165%2Fcfa2d%2Fexample.com-accept-ch.png" alt="An example.com response with an accept-ch header"&gt;
&lt;/li&gt;
&lt;li&gt;Reload once more, and you should see the client send you a new &lt;code&gt;Sec-CH-UA-Platform&lt;/code&gt; header in the request. &lt;a href="https://httptoolkit.tech/static/f116d9e05ec49d82e93ba6b442955f2a/cfa2d/example.com-with-client-hint-header.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhttptoolkit.tech%2Fstatic%2Ff116d9e05ec49d82e93ba6b442955f2a%2Fcfa2d%2Fexample.com-with-client-hint-header.png" alt="An example.com request including a Sec-CH-UA-Platform client hint"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bear in mind this is still a draft, not yet released in any stable browsers, and not yet final. &lt;strong&gt;Don't ship code that depends on this!&lt;/strong&gt; The full details aren't yet decided, and it's still very possible that it'll change over the coming months.&lt;/p&gt;

&lt;h2&gt;
  
  
  When is this happening?
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://groups.google.com/a/chromium.org/forum/#!msg/blink-dev/-2JIRNMWJ7s/yHe4tQNLCgAJ" rel="noopener noreferrer"&gt;Chromium's original timeline&lt;/a&gt; (now &lt;a href="https://groups.google.com/a/chromium.org/d/msg/blink-dev/-2JIRNMWJ7s/u-YzXjZ8BAAJ" rel="noopener noreferrer"&gt;disrupted&lt;/a&gt; by COVID-19), the goal was to freeze browser &amp;amp; OS versions from June 2020, eventually freezing to just 2 possible user-agent values - one for desktop &amp;amp; one for mobile - for all versions of Chrome from September 2020.&lt;/p&gt;

&lt;p&gt;That's now delayed until 2021, and the specific new plan hasn't yet been announced, but it's likely to take a similar shape.&lt;/p&gt;

&lt;p&gt;Other browsers will likely follow suite. Edge have been &lt;a href="https://twitter.com/_scottlow/status/1206831008261132289" rel="noopener noreferrer"&gt;supportive&lt;/a&gt;, while Firefox are &lt;a href="https://github.com/mozilla/standards-positions/issues/202#issuecomment-558294095" rel="noopener noreferrer"&gt;broadly supportive&lt;/a&gt;, and already have UA freezing implemented in place as a privacy option today. Recording Firefox's HTTP traffic with HTTP Toolkit normally shows Firefox sending a detailed UA:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://httptoolkit.tech/static/d33563112d955c6c18569608f3c86b48/a99e1/firefox-ua.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhttptoolkit.tech%2Fstatic%2Fd33563112d955c6c18569608f3c86b48%2Fa99e1%2Ffirefox-ua.png" alt="Firefox's full UA"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But if the &lt;code&gt;privacy.resistFingerprinting&lt;/code&gt; flag is set in Firefox's &lt;code&gt;about:config&lt;/code&gt;, that same browser sends:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://httptoolkit.tech/static/9f56dfd1780cc978c511f2df3db2fdfe/0582b/firefox-ua-restricted.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhttptoolkit.tech%2Fstatic%2F9f56dfd1780cc978c511f2df3db2fdfe%2F0582b%2Ffirefox-ua-restricted.png" alt="Firefox's restricted UA"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Safari haven't formally announced their position, but they've previously attempted to freeze the UA in &lt;a href="https://twitter.com/rmondello/status/943545865204989953" rel="noopener noreferrer"&gt;preview builds&lt;/a&gt; (though that was partially rolled back), and it seems likely they'd follow suit once the rest of the ecosystem commits to this.&lt;/p&gt;

&lt;p&gt;Watch out for more changes in the same direction too, as browsers move other fingerprintable data behind client hints in future, including the &lt;a href="https://github.com/WICG/lang-client-hint" rel="noopener noreferrer"&gt;&lt;code&gt;Accept-Language&lt;/code&gt;&lt;/a&gt; header, and begin investigating approaches like &lt;a href="https://wicg.github.io/ua-client-hints/#grease" rel="noopener noreferrer"&gt;GREASE&lt;/a&gt; to mitigate sniffing risks. You can follow the detailed progress on this in the &lt;a href="https://bugs.chromium.org/p/chromium/issues/detail?id=924047" rel="noopener noreferrer"&gt;Chromium&lt;/a&gt; and &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1609304" rel="noopener noreferrer"&gt;Firefox&lt;/a&gt; bug trackers.&lt;/p&gt;

&lt;p&gt;Have thoughts? &lt;code&gt;Accept-CH&lt;/code&gt; in general is now in its &lt;a href="https://datatracker.ietf.org/doc/draft-ietf-httpbis-client-hints/" rel="noopener noreferrer"&gt;last call for comments&lt;/a&gt;, until the 8th of May 2020, whilst the UA freezing and client hints details are still very much subject to change, with discussion happening in the WICG &lt;a href="https://github.com/WICG/ua-client-hints" rel="noopener noreferrer"&gt;ua-client-hints repo&lt;/a&gt; on GitHub. There's still time to shape them to work for you!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://httptoolkit.tech/blog/user-agent-client-hints" rel="noopener noreferrer"&gt;the HTTP Toolkit blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>http</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
