Tim Perry

Creator of HTTP Toolkit: powerful tools to debug, test & build with HTTP(S).

Passionate tech speaker, open-source contributor, and maintainer of Loglevel, Git‑Confirm and notes.

HTTP content encoding is an incredibly powerful tool that can save you huge amounts of bandwidth and make your web or mobile application faster, basically for free.

Unfortunately, it's poorly understood by most developers. There's a lot of power here, but few people are aware of the options or what "content encoding" really means, so it's mostly le...

HTTP(S) is the glue that binds together modern architectures, passing requests between microservices and connecting web & mobile apps alike to the APIs they depend on.

What if you could embed scripts directly into that glue?

By doing so, you could:

  • Inject errors, timeouts and unusual responses to test system reliability.
  • Record & report ...

Traditionally, a TCP port has a single server listening for incoming connections, and that server expects you to send messages in the right protocol for that port. For HTTP, it's normally a web server that'll send you a response directly, or some kind of proxy that will pass all requests through to another server, and then pass the responses back.


Nothing is ever finished or perfect, and HTTP is no exception.

HTTP SEARCH is a new HTTP method, for safe requests that include a request body. It's still early & evolving, but it was recently adopted as an IETF draft standard, and it's going to add some great new tools for HTTP development everywhere.

What does that mean, why do we need a new...

CORS can be complicated. If you're struggling with it, you might discover the concept of a 'CORS proxy' that promises to solve this, like cors-anywhere or one of the many 'free CORS proxy' hosted services.

CORS proxies let you bypass the security restrictions that CORS applies, with just a tiny change of URL.

That feels convenient, but turning off ...

HTTP is used by almost all Android apps to request data, load content, and send changes to backend servers. If you can see and edit these requests & responses then you can understand, debug, and change how any app works, but Android makes this hard to do.

By default, almost all apps will use HTTPS but won't trust user-installed certificates. T...

Java and the JVM more generally are widely used for services everywhere, but often challenging to debug and manually test, particularly in complicated microservice architectures.

HTTP requests and responses are the core of interactions between these services, and with their external APIs, but they're also often invisible and inaccessible. It's hard...


HTTP is fundamental to modern development, from frontend to backend to mobile. But like any widespread mature standard, it's got some funky skeletons in the closet.

Some of these skeletons are little-known but genuinely useful features, some of them are legacy oddities relied on by billions of connections daily, and some of them really shouldn't ex...

CORS is a necessity for many APIs, but basic configurations can create a huge number of extra requests, slowing down every browser API client, and sending unnecessary traffic to your backend.

This can be a problem with a traditional API, but becomes a much larger issue with serverless platforms, where your billing is often directly tied to the numb...

Fixing DNS in Node.js

DNS is one of those invisible technologies that you use every day, but which works so well that you can conveniently ignore it.

That is until it breaks completely, or slows your application down to a crawl, or you want to resolve something unusual, and then you're in a world of trouble.

Unfortunately, DNS in Node.js isn't implemented quite as you m...

Wouldn't it be neat if you could take any HTTP request URL, and immediately find the matching API documentation, along with a detailed specification of the endpoint you're talking to?

I thought that would be very neat, so I built an index to do it.

More specifically, I've taken the OpenAPI Directory - an amazing project that has collected the OpenA...

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.

Inconveniently though, your API has clients...

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 & faster to type, by creating aliases.

But which aliases? Which commands are most important for your usage? You can probably guess a couple, but it's hard to know for ...

When an API request doesn't work, hopefully the client receives a sensible HTTP error status, like 409 or 500, which is a good start. Unfortunately though, whilst 400 Bad Request might be enough to know who's at fault, it's rarely enough information to understand or fix the actual problem.

Many APIs will give you more details in the response body, ...

Attach error codes to all receiver errors
Oxford bumps racing is now livestreamed! Complete with surprisingly good commentators: https://oxfordbumpsracing.com/live.php (in… https://twitter.com/i/web/status/1403310708876484609
New repo: httptoolkit/windows-system-proxy
Big hugs to the Fastly team, but also what a great demo of why our super centralized internet architecture with may… https://twitter.com/i/web/status/1402280936373473291
New repo: httptoolkit/sysproxy
New repo: httptoolkit/mac-system-proxy
Run tests & prebuild for node 16
Delving into webassembly against my will 😭 I want to decompress + compress brotli in the browser, and every existi… https://twitter.com/i/web/status/1395724347512328197
@cholmugod it depends. The node app there isn't sending a request, instead it's probably launching a subprocess or using an OS API to request that the system opens a browser in its preferred URL. To capture that, you'll need to intercept that, which isn't HTTP at all. Maybe you could register your script as the system browser, so it...
There's definitely points to improve, but Paddle has still saved me a mountain of pain, and I would use them over S… https://twitter.com/i/web/status/1392806809262505986
Does this actually reset the socket, or just simulate it within node? There's use cases for that but it is different from a network perspective - i.e. the other end of the socket won't receive a RST packet.
¡Feliç Sant Jordi a tothom! It's roses & books day in Cataluña (https://en.m.wikipedia.org/wiki/Saint_George%27s_Day_(Spain)#Catalonia). Even my coworking has po… https://twitter.com/i/web/status/1385556084115623944
Seen testimonials you liked recently? I'm adding social proof to my landing page, and I need more examples... Some… https://twitter.com/i/web/status/1385547706551226368
Big features week with this + ADB tunnels. Turns out this one is much harder! Channelling @kentbeck all the way: f… https://twitter.com/i/web/status/1385291360178163715
Ah, the classic 200 response + "success: false". Dear oh dear @PaddleHQ... This should clearly be a 403! https://t.co/8zyotZBvE8
I love discovering things like http://Natto.dev. Brief glimpses of totally different ways to program, somewh… https://twitter.com/i/web/status/1381947595417862149
This is an absurd masterpiece: https://github.com/zhuowei/nft_ptr
I think my latest blog post might be quite popular https://twitter.com/HttpToolkit/status/1367501410951176200 https://t.co/fT91LCcbr5

In the end, it seems this isn't possible on a normal device any way that I can find. I think is possible if you're a device admin, but that requires managed enterprise devices etc.

For now, I've handled this by watching for near-instant (less than 200ms) VPN setup failures (between running startActivityForResult(vpnIntent) and receiving onActivityR...

You do need to send a host header, but the browser actually does this for you - it automatically sets the host header to match the hostname in the URL, which is probably what you want (and that seems to be all that aws4-axios is doing in its implementation anyway).

The browser is just complaining because you're trying to override that, but you don'...

In the above code, you're sending a body with a GET request:

var options = { host: 'localhost', port: 3000, path: `/getReviewByBookId/${books[i].id}`, method: 'GET' // <-- It's a GET request }; var req = request(options, function(res) { ... }); req.write('data\n'); // <-- This writes a request body req.write('data\n'); // <-- req.end(); 


In the response, you can call res.setHeader(headerName, headerValue) to set any header, including HSTS headers. Typically you'll want to do something like:

res.setHeader('Strict-Transport-Security', 'max-age=3600; includeSubDomains'); 

That enables HSTS for 1 hour - this is a good value for a first test, but you should probably increase it to somet...

James Proxy is now unmaintained - they recommend HTTP Toolkit instead, which is also open-source & doesn't require admin privileges for install or interception.
Sometimes open-source users _can_ be nice people: https://github.com/httptoolkit/httptoolkit/issues/128