diff src/http/ngx_http_core_module.c @ 632:65fd8be45530 NGINX_1_0_6

nginx 1.0.6 *) Feature: cache loader run time decrease. *) Feature: loading time decrease of configuration with large number of HTTPS sites. *) Feature: now nginx supports ECDHE key exchange ciphers. Thanks to Adrian Kotelba. *) Feature: the "lingering_close" directive. *) Feature: now shared zones and caches use POSIX semaphores on Solaris. Thanks to Den Ivanov. *) Bugfix: nginx could not be built on Linux 3.0. *) Bugfix: a segmentation fault might occur in a worker process if "fastcgi/scgi/uwsgi_param" directives were used with values starting with "HTTP_"; the bug had appeared in 0.8.40. *) Bugfix: in closing connection for pipelined requests. *) Bugfix: nginx did not disable gzipping if client sent "gzip;q=0" in "Accept-Encoding" request header line. *) Bugfix: in timeout in unbuffered proxied mode. *) Bugfix: memory leaks when a "proxy_pass" directive contains variables and proxies to an HTTPS backend. *) Bugfix: in parameter validaiton of a "proxy_pass" directive with variables. Thanks to Lanshun Zhou. *) Bugfix: SSL did not work on QNX. *) Bugfix: SSL modules could not be built by gcc 4.6 without --with-debug option.
author Igor Sysoev <http://sysoev.ru>
date Fri, 29 Jul 2011 00:00:00 +0400
parents 8dc007eddbcf
children 0d6525917227
line wrap: on
line diff
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -70,6 +70,8 @@ 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 ngx_uint_t ngx_http_gzip_quantity(u_char *p, u_char *last);
 static char *ngx_http_gzip_disable(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 #endif
@@ -125,6 +127,14 @@ static ngx_conf_enum_t  ngx_http_core_sa
 };
 
 
+static ngx_conf_enum_t  ngx_http_core_lingering_close[] = {
+    { ngx_string("off"), NGX_HTTP_LINGERING_OFF },
+    { ngx_string("on"), NGX_HTTP_LINGERING_ON },
+    { ngx_string("always"), NGX_HTTP_LINGERING_ALWAYS },
+    { ngx_null_string, 0 }
+};
+
+
 static ngx_conf_enum_t  ngx_http_core_if_modified_since[] = {
     { ngx_string("off"), NGX_HTTP_IMS_OFF },
     { ngx_string("exact"), NGX_HTTP_IMS_EXACT },
@@ -530,6 +540,13 @@ static ngx_command_t  ngx_http_core_comm
       0,
       NULL },
 
+    { ngx_string("lingering_close"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_enum_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, lingering_close),
+      &ngx_http_core_lingering_close },
+
     { ngx_string("lingering_time"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
@@ -2016,24 +2033,35 @@ ngx_http_gzip_ok(ngx_http_request_t *r)
     time_t                     date, expires;
     ngx_uint_t                 p;
     ngx_array_t               *cc;
-    ngx_table_elt_t           *e, *d;
+    ngx_table_elt_t           *e, *d, *ae;
     ngx_http_core_loc_conf_t  *clcf;
 
     r->gzip_tested = 1;
 
-    if (r != r->main
-        || r->headers_in.accept_encoding == NULL
-        || ngx_strcasestrn(r->headers_in.accept_encoding->value.data,
-                           "gzip", 4 - 1)
-           == NULL
-
-        /*
-         * if the URL (without the "http://" prefix) is longer than 253 bytes,
-         * then MSIE 4.x can not handle the compressed stream - it waits
-         * too long, hangs up or crashes
-         */
-
-        || (r->headers_in.msie4 && r->unparsed_uri.len > 200))
+    if (r != r->main) {
+        return NGX_DECLINED;
+    }
+
+    ae = r->headers_in.accept_encoding;
+    if (ae == NULL) {
+        return NGX_DECLINED;
+    }
+
+    if (ae->value.len < sizeof("gzip") - 1) {
+        return NGX_DECLINED;
+    }
+
+    /*
+     * 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;
     }
@@ -2159,6 +2187,135 @@ ok:
     return NGX_OK;
 }
 
+
+/*
+ * gzip is enabled for the following quantities:
+ *     "gzip; q=0.001" ... "gzip; q=1.000"
+ * 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  *p, *start, *last;
+
+    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;
+    }
+
+    if (ngx_http_gzip_quantity(p, last) == 0) {
+        return NGX_DECLINED;
+    }
+
+    return NGX_OK;
+}
+
+
+ngx_uint_t
+ngx_http_gzip_quantity(u_char *p, u_char *last)
+{
+    u_char      c;
+    ngx_uint_t  n, q;
+
+    c = *p++;
+
+    if (c != '0' && c != '1') {
+        return 0;
+    }
+
+    q = (c - '0') * 100;
+
+    if (p == last) {
+        return q;
+    }
+
+    c = *p++;
+
+    if (c == ',' || c == ' ') {
+        return q;
+    }
+
+    if (c != '.') {
+        return 0;
+    }
+
+    n = 0;
+
+    while (p < last) {
+        c = *p++;
+
+        if (c == ',' || c == ' ') {
+            break;
+        }
+
+        if (c >= '0' && c <= '9') {
+            q += c - '0';
+            n++;
+            continue;
+        }
+
+        return 0;
+    }
+
+    if (q > 100 || n > 3) {
+        return 0;
+    }
+
+    return q;
+}
+
 #endif
 
 
@@ -3117,6 +3274,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t
     clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC;
     clcf->keepalive_header = NGX_CONF_UNSET;
     clcf->keepalive_requests = NGX_CONF_UNSET_UINT;
+    clcf->lingering_close = NGX_CONF_UNSET_UINT;
     clcf->lingering_time = NGX_CONF_UNSET_MSEC;
     clcf->lingering_timeout = NGX_CONF_UNSET_MSEC;
     clcf->resolver_timeout = NGX_CONF_UNSET_MSEC;
@@ -3333,6 +3491,8 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
                               prev->keepalive_header, 0);
     ngx_conf_merge_uint_value(conf->keepalive_requests,
                               prev->keepalive_requests, 100);
+    ngx_conf_merge_uint_value(conf->lingering_close,
+                              prev->lingering_close, NGX_HTTP_LINGERING_ON);
     ngx_conf_merge_msec_value(conf->lingering_time,
                               prev->lingering_time, 30000);
     ngx_conf_merge_msec_value(conf->lingering_timeout,