google / ngx_brotli

NGINX module for Brotli compression

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

nginx only uses br if content-length response header is missing

haarp opened this issue · comments

commented

Hello,

the Brotli nginx module just landed in Debian! Yay!

I gave it a try and installed libnginx-mod-http-brotli-filter on my Debian bookworm install for on-the-fly compression. It is indeed working, but not everywhere.

It seems that br is only being used when there is no content-length response header (lowercase due to HTTP/2). If that header is present, nginx will use gzip instead.

nginx-1.22.1-2, libnginx-mod-http-brotli-filter 1.0.0~rc-1+b1. Client is Firefox 107.0.

nginx config:

gzip on;
gzip_comp_level 4;
gzip_min_length 250;    # not always respected: https://stackoverflow.com/q/33269448/5424487
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript
                        application/x-json image/svg+xml;

brotli on;
brotli_comp_level 4;
brotli_min_length 250;
brotli_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript
                        application/x-json image/svg+xml;

gzip_min_length and brotli_min_length doesn't seem to make a difference in this behavior. I've tested it with multiple sites, using both PHP over fcgi and reverse proxying. Here are two examples on a reverse-proxy site install.

Successfully uses br (no content-length):

GET /css/Core.css?v=ay495y HTTP/2
Host: domain.net
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:107.0) Gecko/20100101 Firefox/107.0
Accept: text/css,*/*;q=0.1
Accept-Language: en
Accept-Encoding: gzip, deflate, br
Referer: https://domain.net/
Connection: keep-alive
Cookie: ...
Sec-Fetch-Dest: style
Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: same-origin
Pragma: no-cache
Cache-Control: no-cache
TE: trailers

->

HTTP/2 200 OK
date: Mon, 12 Dec 2022 19:58:18 GMT
content-type: text/css
cache-control: private, max-age=43200
content-security-policy: default-src 'self' data: 'unsafe-inline' 'unsafe-eval'; object-src 'none'; worker-src 'none'
referrer-policy: same-origin
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-permitted-cross-domain-policies: none
x-robots-tag: none
strict-transport-security: max-age=63072000; includeSubdomains
content-encoding: br
X-Firefox-Spdy: h2

Uses gzip instead (content-length present)

GET /css/Layout.css?v=ay495y HTTP/2
Host: domain.net
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:107.0) Gecko/20100101 Firefox/107.0
Accept: text/css,*/*;q=0.1
Accept-Language: en
Accept-Encoding: gzip, deflate, br
Referer: https://domain.net/
Connection: keep-alive
Cookie: ...
Sec-Fetch-Dest: style
Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: same-origin
Pragma: no-cache
Cache-Control: no-cache
TE: trailers

->

HTTP/2 200 OK
date: Mon, 12 Dec 2022 19:58:18 GMT
content-type: text/css
content-length: 2085
cache-control: private, max-age=43200
content-encoding: gzip
content-security-policy: default-src 'self' data: 'unsafe-inline' 'unsafe-eval'; object-src 'none'; worker-src 'none'
referrer-policy: same-origin
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-permitted-cross-domain-policies: none
x-robots-tag: none
strict-transport-security: max-age=63072000; includeSubdomains
X-Firefox-Spdy: h2

Thanks!

commented

Solved it. Upstream had already compressed certain assets, i.e. those over 1kB in size. nginx will simply not re-compress them, which makes sense. The small gains of ungzip→br wouldn't justify the latency. But nginx will compress uncompressed assets, which results in the Content-Length header being stripped. That's what I was observing here.

Related issues: #22, #30