# HG changeset patch # User Igor Sysoev # Date 1312196532 0 # Node ID 19de03b4217f6a33fe890f5e22a54a986527c66c # Parent 1d9353fbc077719203fe1ebd5097ea6340d1c928 Accept-Encoding refactoring: "gzip; q=0" support diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -70,6 +70,7 @@ static char *ngx_http_core_internal(ngx_ static char *ngx_http_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); #if (NGX_HTTP_GZIP) +static ngx_int_t ngx_http_gzip_accept_encoding(ngx_str_t *ae); static char *ngx_http_gzip_disable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); #endif @@ -2013,7 +2014,6 @@ ngx_http_auth_basic_user(ngx_http_reques ngx_int_t ngx_http_gzip_ok(ngx_http_request_t *r) { - u_char *g; time_t date, expires; ngx_uint_t p; ngx_array_t *cc; @@ -2031,24 +2031,24 @@ ngx_http_gzip_ok(ngx_http_request_t *r) return NGX_DECLINED; } - if (ngx_strncmp(ae->value.data, "gzip,", 5) == 0) { - /* - * test for the most common case "gzip,...": - * MSIE: "gzip, deflate" - * Firefox: "gzip,deflate" - * Chrome: "gzip,deflate,sdch" - * Safari: "gzip, deflate" - * Opera: "gzip, deflate" - */ - goto found; - } - - g = ngx_strcasestrn(ae->value.data, "gzip", 4 - 1); - if (g == NULL) { + if (ae->value.len < 5) { return NGX_DECLINED; } -found: + /* + * test first for the most common case "gzip,...": + * MSIE: "gzip, deflate" + * Firefox: "gzip,deflate" + * Chrome: "gzip,deflate,sdch" + * Safari: "gzip, deflate" + * Opera: "gzip, deflate" + */ + + if (ngx_memcmp(ae->value.data, "gzip,", 5) != 0 + && ngx_http_gzip_accept_encoding(&ae->value) != NGX_OK) + { + return NGX_DECLINED; + } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); @@ -2171,6 +2171,127 @@ ok: return NGX_OK; } + +/* + * gzip is enabled for the following quantities: + * "gzip; q=0.001" ... "gzip; q=0.999", "gzip; q=1" + * gzip is disabled for the following quantities: + * "gzip; q=0" ... "gzip; q=0.000", and for any invalid cases + */ + +static ngx_int_t +ngx_http_gzip_accept_encoding(ngx_str_t *ae) +{ + u_char c, *p, *start, *last; + ngx_uint_t n, q; + + start = ae->data; + last = start + ae->len; + + for ( ;; ) { + p = ngx_strcasestrn(start, "gzip", 4 - 1); + if (p == NULL) { + return NGX_DECLINED; + } + + if (p > start && (*(p - 1) == ',' || *(p - 1) == ' ')) { + break; + } + + start = p + 4; + } + + p += 4; + + while (p < last) { + switch(*p++) { + case ',': + return NGX_OK; + case ';': + goto quantity; + case ' ': + continue; + default: + return NGX_DECLINED; + } + } + + return NGX_OK; + +quantity: + + while (p < last) { + switch(*p++) { + case 'q': + case 'Q': + goto equal; + case ' ': + continue; + default: + return NGX_DECLINED; + } + } + + return NGX_OK; + +equal: + + if (p + 2 > last || *p++ != '=') { + return NGX_DECLINED; + } + + c = *p++; + + if (c == '1') { + if (p == last || *p == ',' || *p == ' ') { + return NGX_OK; + } + return NGX_DECLINED; + } + + if (c != '0') { + return NGX_DECLINED; + } + + if (p == last) { + return NGX_DECLINED; + } + + if (*p++ != '.') { + return NGX_DECLINED; + } + + n = 0; + q = 0; + + while (p < last) { + c = *p++; + + if (c == ',') { + break; + } + + if (c >= '1' && c <= '9') { + n++; + q++; + continue; + } + + if (c == '0') { + n++; + continue; + } + + return NGX_DECLINED; + } + + if (n < 4 && q != 0) { + return NGX_OK; + } + + return NGX_DECLINED; +} + #endif