changeset 3980:19de03b4217f

Accept-Encoding refactoring: "gzip; q=0" support
author Igor Sysoev <igor@sysoev.ru>
date Mon, 01 Aug 2011 11:02:12 +0000
parents 1d9353fbc077
children 77604e9a1ed8
files src/http/ngx_http_core_module.c
diffstat 1 files changed, 137 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- 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