Opened 10 years ago

Closed 10 years ago

Last modified 9 years ago

#471 closed defect (invalid)

GZIP does not compress 201 Created Responses

Reported by: Craig Minihan Owned by:
Priority: major Milestone:
Component: nginx-module Version: 1.3.x
Keywords: gzip 201 Cc:
uname -a: Linux 2.6.32-358.el6.x86_64 #1 SMP Fri Feb 22 00:31:26 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.4.3

Description

I have NGiNX running as a proxy for CouchDB. The CouchDB REST API returns 201 in response to document create requests. These responses can be large therefore gzip compression greatly increases performance.

I've noticed that gzip is fine on all requests except where the response is a 201. This is easy to reproduce even in a browser:

1) Setup CouchDB with NGiNX handling requests as a proxy.
2) Access CouchDB's Futon web site from a browser. Create a database, create a document and set the id of the document as a long string.
3) Clicking 'Save Document' in the UI prompts the browser to call onto NGiNX/CouchDB with the PUT request below:


REQUEST:

PUT /tb_fct_agent_logout2/A_VERY_LONG_ID_APPEARS_HERE HTTP/1.1
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/json
X-Requested-With: XMLHttpRequest
Referer: http://192.168.122.10:15984/_utils/document.html?tb_fct_agent_logout2
Accept-Language: en-gb
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Host: 192.168.122.10:15984
Content-Length: 3073
Connection: Keep-Alive
Pragma: no-cache


RESPONSE HEADERS:

HTTP/1.1 201 Created
Server: nginx/1.4.3
Date: Thu, 19 Dec 2013 12:55:03 GMT
Content-Type: application/json
Content-Length: 3126
Location: http://192.168.122.10:15984/tb_fct_agent_logout2/A_VERY_LONG_ID_APPEARS_HERE
Connection: keep-alive
ETag: "1-967a00dff5e02add41819138abb3284d"
Cache-Control: must-revalidate

THE RAW JSON BODY APPEARS HERE, 3126 CHARS IN LENGTH AS YOU WOULD EXPECT FROM THE CONTENT-LENGTH ABOVE. IT IS NOT COMPRESSED.


All other requests using the browser accessing the Futon site via NGiNX are compressed as you would expect.

NGiNX is built from source not an RPM.

Since CouchDB is has a REST API they make heavy use of response codes you wouldn't typically see from a standard web site. Therefore the loss of compression on 201 responses presents a major issue in my use case. Thanks!

Change History (8)

comment:1 by Craig Minihan, 10 years ago

I just realised the -V above is actually -v, here is the real -V:
nginx version: nginx/1.4.3
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-3) (GCC)
configure arguments: --add-module=../lua-nginx-module-0.9.0/

comment:2 by Craig Minihan, 10 years ago

I can confirm that changing ngx_http_gzip_filter_module.c as follows solves this problem:

static ngx_int_t
ngx_http_gzip_header_filter(ngx_http_request_t *r)
{
    ngx_table_elt_t       *h;
    ngx_http_gzip_ctx_t   *ctx;
    ngx_http_gzip_conf_t  *conf;

    conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);

    if (!conf->enable
        || (r->headers_out.status != NGX_HTTP_OK
==>         && r->headers_out.status != NGX_HTTP_CREATED         <==
            && r->headers_out.status != NGX_HTTP_FORBIDDEN
            && r->headers_out.status != NGX_HTTP_NOT_FOUND)
        || (r->headers_out.content_encoding
            && r->headers_out.content_encoding->value.len)
        || (r->headers_out.content_length_n != -1
            && r->headers_out.content_length_n < conf->min_length)
        || ngx_http_test_content_type(r, &conf->types) == NULL
        || r->header_only)
    {
        return ngx_http_next_header_filter(r);
    }

I guess there is a reason that 201 wasn't included in the original 'if'?

comment:3 by Maxim Dounin, 10 years ago

Resolution: invalid
Status: newclosed

This is intended behaviour, see ticket #394.

comment:4 by Craig Minihan, 10 years ago

This seems like a major omission for running any REST API via NGiNX. In the case of Apache CouchDB there is no real difference between 200 and 201 responses. Their full API is documented here: http://docs.couchdb.org/en/latest/api/index.html

If the client asks for gzip or deflate via the accept encoding header then the proxy should attempt to honour it.

It seems to me this could easily be implemented via gzip configuration settings to meet the individual installed requirements since it may not be a setting that would work in all scenarios.

If you don't include the feature then I'll either have to run a patched version or switch to an alternate solution.

comment:5 by Norberto Lopes, 9 years ago

I just encountered this issue today for the first time.
I understand this is intended behaviour for partial response codes and or bad/malformed codes. But why isn't this allowed for 201 responses? There is no partial content here and it is a valid response with content. What is the issue gzipping it?

Maxim, would you mind explaining the reasoning?

Thank you!

comment:6 by Maxim Dounin, 9 years ago

Please see ticket #394 for details. While it may be safe to gzip such responses, we would like to see some interoperability tests before doing changes.

comment:7 by Norberto Lopes, 9 years ago

I have seen ticket 394. It doesn't say anything about 200/201 responses. 201 should be as safe as 200. I really can't think of a reason not to gzip it. Am I missing something here?

comment:8 by Maxim Dounin, 9 years ago

The statement "201 should be as safe as 200" should be backed by some interoperability tests, that's the point.

Note: See TracTickets for help on using tickets.