Chaszcze

I've never heard of chunked transfer encoding before my partner decided to run a website on a ESP32 microcontroller. Apparently, it's a way of streaming HTTP data in chunks (yeah) preceded by their length. So while a regular HTTP response might look like this:

hello there!

A chunked one will look like this:

12␍␊hello there!␍␊0␍␊␍␊

That's a mouthful. Let's break it down a little bit:

12␍␊           <- chunk size
hello there!   <- chunk data
␍␊             <- end of chunk
0␍␊            <- chunk size 0, no more chunks will follow
␍␊             <- end of chunk

This is largely unimportant, because clients make it transparent for us: they see the Transfer-Encoding: chunked header and glue everything together, so we never see these sizes and newlines.

That is, until we put the thing behind Nginx "to get HTTPS and stuff". Then your browser will render the chunk size within the HTML. curl will show them too. Why?

Well, it turns out that chunked only works with HTTP 1.1. It doesn't work with 1.0, and it doesn't work with 2.0. Should be an easy fix, right?

-listen 443 ssl http2;
+listen 443 ssl;

Unfortunately, that doesn't change anything. It's not about the HTTP version between us and Nginx, it's about the version between Nginx and the service.

client
 |
 | <- HTTP whatever
 v
nginx
 |
 | <- MUST be HTTP 1.1
 v
service

And for some reason, for proxying Nginx uses HTTP 1.0 by default. So the real fix looks like this:

server {
    # ...
    location {
        # ...
	proxy_http_version 1.1;
    }
    # ...
}

Hope it helps.