Opened 4 years ago

Closed 4 years ago

#1159 closed defect (wontfix)

gzip doesn't work for HTTP status 202

Reported by: wkornewald@… Owned by:
Priority: minor Milestone:
Component: other Version: 1.11.x
Keywords: Cc:
uname -a: Linux myserver 4.7.3-coreos-r3 #1 SMP Wed Dec 7 09:29:55 UTC 2016 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.11.7
built by gcc 4.9.2 (Debian 4.9.2-10)
built with OpenSSL 1.0.1t 3 May 2016
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed'

Description

Whenever our backend returns a non-200 status code the response, nginx doesn't gzip the response. In order to track this down to nginx I've setup a simple localhost proxy like this:

worker_processes auto;

events {
  use epoll;
  multi_accept on;
  worker_connections 2048;
}

error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;

daemon off;

http {
  include /etc/nginx/mime.types;
  default_type application/octet-stream;
  proxy_headers_hash_max_size 1024;
  proxy_headers_hash_bucket_size 128;

  server_tokens off;

  log_format main '$remote_addr - $remote_user [$time_local] $http_host '
                  '$server_port $status "$request" '
                  '$body_bytes_sent $request_time $upstream_addr '
                  '$upstream_response_time "$http_referer" '
                  '"$http_user_agent"';

  access_log /var/log/nginx/access.log main;

  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;
  keepalive_timeout 65;
  keepalive_requests 100000;
  types_hash_max_size 2048;
  reset_timedout_connection on;
  send_timeout 4;

  gzip on;
  gzip_min_length 256;
  gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript text/x-js;
  gzip_comp_level 6;

  server {
    listen [::]:80 so_keepalive=on reuseport deferred;
    listen 80 so_keepalive=on reuseport deferred;
    server_name "";

    location / {
      return 444;
    }

    location /raw/200 {
      return 200 gaga;
    }

    location /raw/202 {
      return 202 lulu;
    }

    location /comp {
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_redirect off;
      proxy_buffering off;
      proxy_pass http://127.0.0.1/raw;
      gzip on;
      gzip_min_length 1;
      gzip_types *;
      gzip_proxied any;
    }
  }
}

The result with response 200:

# curl -v --compressed localhost/comp/200
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /comp/200 HTTP/1.1
> Host: localhost
> User-Agent: curl/7.50.2
> Accept: */*
> Accept-Encoding: deflate, gzip
>
< HTTP/1.1 200 OK
< Server: nginx
< Date: Wed, 14 Dec 2016 10:51:26 GMT
< Content-Type: application/octet-stream
< Transfer-Encoding: chunked
< Connection: keep-alive
< Content-Encoding: gzip
<
* Curl_http_done: called premature == 0
* Connection #0 to host localhost left intact
gaga

The result with response 202:

# curl -v --compressed localhost/comp/202
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /comp/202 HTTP/1.1
> Host: localhost
> User-Agent: curl/7.50.2
> Accept: */*
> Accept-Encoding: deflate, gzip
>
< HTTP/1.1 202 Accepted
< Server: nginx
< Date: Wed, 14 Dec 2016 10:52:11 GMT
< Content-Type: application/octet-stream
< Content-Length: 4
< Connection: keep-alive
<
* Curl_http_done: called premature == 0
* Connection #0 to host localhost left intact
lulu

Change History (3)

comment:1 by Maxim Dounin, 4 years ago

Gzip module only compresses responses with some common HTTP statuses which are known to be safe to compress. See detailed explanation here. See also ticket #394.

It doesn't look to me that 202 needs to be compressed. If at all used, I would expect the response body to be empty or very small.

If you think that 202 needs to be compressed - please provide more detailed explanation why (is it actually used? can it be large and seriously benefit from the compression?), as well as some safety analysis (are common clients using it work fine with compressed responses?).

comment:2 by wkornewald@…, 4 years ago

We use several REST APIs which return 202 when we should continue polling the API for results. Our own service simply passes the status through. Not sure if this is reason enough, but I just find it very surprising that our JSON response's compression depends on the status code. The content is still JSON.

comment:3 by Maxim Dounin, 4 years ago

Resolution: wontfix
Status: newclosed

The message linked above explains why status code is important.

Note: See TracTickets for help on using tickets.