<div dir="ltr"><div># HG changeset patch</div><div># User Evgenii Kliuchnikov <<a href="mailto:eustas.ru@gmail.com">eustas.ru@gmail.com</a>></div><div># Date 1487764873 -3600</div><div>#      Wed Feb 22 13:01:13 2017 +0100</div><div># Node ID 81eacab152efa88d1296cc04dfd110a168a6b1fb</div><div># Parent  87cf6ddb41c216876d13cffa5e637a61b159362c</div><div>Add brotli static serving module</div><div><br></div><div>Brotli static serving module is a copy of gzip static serving module</div><div>with "gzip" and derivatives replaced with "brotli" and derivatives.</div><div><br></div><div>This module does not add any dependencies.</div><div>It allows serving offline-compressed content when browser specifies</div><div>that "br" content encoding is supported.</div><div><br></div><div>For lower binary overhead ngx_http_gzip_accept_encoding and</div><div>ngx_http_gzip_quantity were refactored and to be used both by gzip</div><div>and brotli modules.</div><div><br></div><div>diff -r 87cf6ddb41c2 -r 81eacab152ef auto/modules</div><div>--- a/auto/modules<span class="gmail-Apple-tab-span" style="white-space:pre">   </span>Fri Feb 17 17:01:27 2017 +0300</div><div>+++ b/auto/modules<span class="gmail-Apple-tab-span" style="white-space:pre">       </span>Wed Feb 22 13:01:13 2017 +0100</div><div>@@ -124,6 +124,7 @@</div><div> </div><div> # the module order is important</div><div> #     ngx_http_static_module</div><div>+#     ngx_http_brotli_static_module</div><div> #     ngx_http_gzip_static_module</div><div> #     ngx_http_dav_module</div><div> #     ngx_http_autoindex_module</div><div>@@ -160,6 +161,7 @@</div><div> HTTP_FILTER_MODULES=</div><div> </div><div> ngx_module_order="ngx_http_static_module \</div><div>+                  ngx_http_brotli_static_module \</div><div>                   ngx_http_gzip_static_module \</div><div>                   ngx_http_dav_module \</div><div>                   ngx_http_autoindex_module \</div><div>@@ -451,6 +453,19 @@</div><div>     . auto/module</div><div> fi</div><div> </div><div>+if [ $HTTP_BROTLI_STATIC = YES ]; then</div><div>+    have=NGX_HTTP_BROTLI . auto/have</div><div>+</div><div>+    ngx_module_name=ngx_http_brotli_static_module</div><div>+    ngx_module_incs=</div><div>+    ngx_module_deps=</div><div>+    ngx_module_srcs=src/http/modules/ngx_http_brotli_static_module.c</div><div>+    ngx_module_libs=</div><div>+    ngx_module_link=$HTTP_BROTLI_STATIC</div><div>+</div><div>+    . auto/module</div><div>+fi</div><div>+</div><div> if [ $HTTP_GZIP_STATIC = YES ]; then</div><div>     have=NGX_HTTP_GZIP . auto/have</div><div> </div><div>diff -r 87cf6ddb41c2 -r 81eacab152ef auto/options</div><div>--- a/auto/options<span class="gmail-Apple-tab-span" style="white-space:pre">        </span>Fri Feb 17 17:01:27 2017 +0300</div><div>+++ b/auto/options<span class="gmail-Apple-tab-span" style="white-space:pre">       </span>Wed Feb 22 13:01:13 2017 +0100</div><div>@@ -96,6 +96,7 @@</div><div> HTTP_FLV=NO</div><div> HTTP_MP4=NO</div><div> HTTP_GUNZIP=NO</div><div>+HTTP_BROTLI_STATIC=NO</div><div> HTTP_GZIP_STATIC=NO</div><div> HTTP_UPSTREAM_HASH=YES</div><div> HTTP_UPSTREAM_IP_HASH=YES</div><div>@@ -236,6 +237,7 @@</div><div>         --with-http_flv_module)          HTTP_FLV=YES               ;;</div><div>         --with-http_mp4_module)          HTTP_MP4=YES               ;;</div><div>         --with-http_gunzip_module)       HTTP_GUNZIP=YES            ;;</div><div>+        --with-http_brotli_static_module) HTTP_BROTLI_STATIC=YES    ;;</div><div>         --with-http_gzip_static_module)  HTTP_GZIP_STATIC=YES       ;;</div><div>         --with-http_auth_request_module) HTTP_AUTH_REQUEST=YES      ;;</div><div>         --with-http_random_index_module) HTTP_RANDOM_INDEX=YES      ;;</div><div>@@ -444,6 +446,7 @@</div><div>   --with-http_flv_module             enable ngx_http_flv_module</div><div>   --with-http_mp4_module             enable ngx_http_mp4_module</div><div>   --with-http_gunzip_module          enable ngx_http_gunzip_module</div><div>+  --with-http_brotli_static_module   enable ngx_http_brotli_static_module</div><div>   --with-http_gzip_static_module     enable ngx_http_gzip_static_module</div><div>   --with-http_auth_request_module    enable ngx_http_auth_request_module</div><div>   --with-http_random_index_module    enable ngx_http_random_index_module</div><div>diff -r 87cf6ddb41c2 -r 81eacab152ef contrib/vim/syntax/nginx.vim</div><div>--- a/contrib/vim/syntax/nginx.vim<span class="gmail-Apple-tab-span" style="white-space:pre">    </span>Fri Feb 17 17:01:27 2017 +0300</div><div>+++ b/contrib/vim/syntax/nginx.vim<span class="gmail-Apple-tab-span" style="white-space:pre">       </span>Wed Feb 22 13:01:13 2017 +0100</div><div>@@ -86,6 +86,7 @@</div><div> syn keyword ngxDirective autoindex</div><div> syn keyword ngxDirective autoindex_exact_size</div><div> syn keyword ngxDirective autoindex_localtime</div><div>+syn keyword ngxDirective brotli_static</div><div> syn keyword ngxDirective charset</div><div> syn keyword ngxDirective charset_types</div><div> syn keyword ngxDirective chunked_transfer_encoding</div><div>diff -r 87cf6ddb41c2 -r 81eacab152ef misc/GNUmakefile</div><div>--- a/misc/GNUmakefile<span class="gmail-Apple-tab-span" style="white-space:pre">        </span>Fri Feb 17 17:01:27 2017 +0300</div><div>+++ b/misc/GNUmakefile<span class="gmail-Apple-tab-span" style="white-space:pre">   </span>Wed Feb 22 13:01:13 2017 +0100</div><div>@@ -74,6 +74,7 @@</div><div> <span class="gmail-Apple-tab-span" style="white-space:pre">               </span>--with-http_flv_module<span class="gmail-Apple-tab-span" style="white-space:pre">                                        </span>\</div><div> <span class="gmail-Apple-tab-span" style="white-space:pre">            </span>--with-http_mp4_module<span class="gmail-Apple-tab-span" style="white-space:pre">                                        </span>\</div><div> <span class="gmail-Apple-tab-span" style="white-space:pre">            </span>--with-http_gunzip_module<span class="gmail-Apple-tab-span" style="white-space:pre">                             </span>\</div><div>+<span class="gmail-Apple-tab-span" style="white-space:pre">             </span>--with-http_brotli_static_module<span class="gmail-Apple-tab-span" style="white-space:pre">                      </span>\</div><div> <span class="gmail-Apple-tab-span" style="white-space:pre">            </span>--with-http_gzip_static_module<span class="gmail-Apple-tab-span" style="white-space:pre">                                </span>\</div><div> <span class="gmail-Apple-tab-span" style="white-space:pre">            </span>--with-http_auth_request_module<span class="gmail-Apple-tab-span" style="white-space:pre">                               </span>\</div><div> <span class="gmail-Apple-tab-span" style="white-space:pre">            </span>--with-http_random_index_module<span class="gmail-Apple-tab-span" style="white-space:pre">                               </span>\</div><div>diff -r 87cf6ddb41c2 -r 81eacab152ef src/http/modules/ngx_http_brotli_static_module.c</div><div>--- /dev/null<span class="gmail-Apple-tab-span" style="white-space:pre">     </span>Thu Jan 01 00:00:00 1970 +0000</div><div>+++ b/src/http/modules/ngx_http_brotli_static_module.c<span class="gmail-Apple-tab-span" style="white-space:pre">   </span>Wed Feb 22 13:01:13 2017 +0100</div><div>@@ -0,0 +1,331 @@</div><div>+</div><div>+/*</div><div>+ * Copyright (C) Igor Sysoev</div><div>+ * Copyright (C) Nginx, Inc.</div><div>+ */</div><div>+</div><div>+</div><div>+#include <ngx_config.h></div><div>+#include <ngx_core.h></div><div>+#include <ngx_http.h></div><div>+</div><div>+</div><div>+#define NGX_HTTP_BROTLI_STATIC_OFF     0</div><div>+#define NGX_HTTP_BROTLI_STATIC_ON      1</div><div>+#define NGX_HTTP_BROTLI_STATIC_ALWAYS  2</div><div>+</div><div>+</div><div>+typedef struct {</div><div>+    ngx_uint_t  enable;</div><div>+} ngx_http_brotli_static_conf_t;</div><div>+</div><div>+</div><div>+static ngx_int_t ngx_http_brotli_static_handler(ngx_http_request_t *r);</div><div>+static void *ngx_http_brotli_static_create_conf(ngx_conf_t *cf);</div><div>+static char *ngx_http_brotli_static_merge_conf(ngx_conf_t *cf, void *parent,</div><div>+    void *child);</div><div>+static ngx_int_t ngx_http_brotli_static_init(ngx_conf_t *cf);</div><div>+</div><div>+</div><div>+static ngx_conf_enum_t  ngx_http_brotli_static[] = {</div><div>+    { ngx_string("off"), NGX_HTTP_BROTLI_STATIC_OFF },</div><div>+    { ngx_string("on"), NGX_HTTP_BROTLI_STATIC_ON },</div><div>+    { ngx_string("always"), NGX_HTTP_BROTLI_STATIC_ALWAYS },</div><div>+    { ngx_null_string, 0 }</div><div>+};</div><div>+</div><div>+</div><div>+static ngx_command_t  ngx_http_brotli_static_commands[] = {</div><div>+</div><div>+    { ngx_string("brotli_static"),</div><div>+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,</div><div>+      ngx_conf_set_enum_slot,</div><div>+      NGX_HTTP_LOC_CONF_OFFSET,</div><div>+      offsetof(ngx_http_brotli_static_conf_t, enable),</div><div>+      &ngx_http_brotli_static },</div><div>+</div><div>+      ngx_null_command</div><div>+};</div><div>+</div><div>+</div><div>+ngx_http_module_t  ngx_http_brotli_static_module_ctx = {</div><div>+    NULL,                                  /* preconfiguration */</div><div>+    ngx_http_brotli_static_init,           /* postconfiguration */</div><div>+</div><div>+    NULL,                                  /* create main configuration */</div><div>+    NULL,                                  /* init main configuration */</div><div>+</div><div>+    NULL,                                  /* create server configuration */</div><div>+    NULL,                                  /* merge server configuration */</div><div>+</div><div>+    ngx_http_brotli_static_create_conf,    /* create location configuration */</div><div>+    ngx_http_brotli_static_merge_conf      /* merge location configuration */</div><div>+};</div><div>+</div><div>+</div><div>+ngx_module_t  ngx_http_brotli_static_module = {</div><div>+    NGX_MODULE_V1,</div><div>+    &ngx_http_brotli_static_module_ctx,    /* module context */</div><div>+    ngx_http_brotli_static_commands,       /* module directives */</div><div>+    NGX_HTTP_MODULE,                       /* module type */</div><div>+    NULL,                                  /* init master */</div><div>+    NULL,                                  /* init module */</div><div>+    NULL,                                  /* init process */</div><div>+    NULL,                                  /* init thread */</div><div>+    NULL,                                  /* exit thread */</div><div>+    NULL,                                  /* exit process */</div><div>+    NULL,                                  /* exit master */</div><div>+    NGX_MODULE_V1_PADDING</div><div>+};</div><div>+</div><div>+</div><div>+static ngx_int_t</div><div>+ngx_http_brotli_static_handler(ngx_http_request_t *r)</div><div>+{</div><div>+    u_char                         *p;</div><div>+    size_t                          root;</div><div>+    ngx_str_t                       path;</div><div>+    ngx_int_t                       rc;</div><div>+    ngx_uint_t                      level;</div><div>+    ngx_log_t                      *log;</div><div>+    ngx_buf_t                      *b;</div><div>+    ngx_chain_t                     out;</div><div>+    ngx_table_elt_t                *h;</div><div>+    ngx_open_file_info_t            of;</div><div>+    ngx_http_core_loc_conf_t       *clcf;</div><div>+    ngx_http_brotli_static_conf_t  *bscf;</div><div>+</div><div>+    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {</div><div>+        return NGX_DECLINED;</div><div>+    }</div><div>+</div><div>+    if (r->uri.data[r->uri.len - 1] == '/') {</div><div>+        return NGX_DECLINED;</div><div>+    }</div><div>+</div><div>+    bscf = ngx_http_get_module_loc_conf(r, ngx_http_brotli_static_module);</div><div>+</div><div>+    if (bscf->enable == NGX_HTTP_BROTLI_STATIC_OFF) {</div><div>+        return NGX_DECLINED;</div><div>+    }</div><div>+</div><div>+    if (bscf->enable == NGX_HTTP_BROTLI_STATIC_ON) {</div><div>+        rc = ngx_http_brotli_ok(r);</div><div>+</div><div>+    } else {</div><div>+        /* always */</div><div>+        rc = NGX_OK;</div><div>+    }</div><div>+</div><div>+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);</div><div>+</div><div>+    if (!clcf->gzip_vary && rc != NGX_OK) {</div><div>+        return NGX_DECLINED;</div><div>+    }</div><div>+</div><div>+    log = r->connection->log;</div><div>+</div><div>+    p = ngx_http_map_uri_to_path(r, &path, &root, sizeof(".br") - 1);</div><div>+    if (p == NULL) {</div><div>+        return NGX_HTTP_INTERNAL_SERVER_ERROR;</div><div>+    }</div><div>+</div><div>+    *p++ = '.';</div><div>+    *p++ = 'b';</div><div>+    *p++ = 'r';</div><div>+    *p = '\0';</div><div>+</div><div>+    path.len = p - path.data;</div><div>+</div><div>+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,</div><div>+                   "http filename: \"%s\"", path.data);</div><div>+</div><div>+    ngx_memzero(&of, sizeof(ngx_open_file_info_t));</div><div>+</div><div>+    of.read_ahead = clcf->read_ahead;</div><div>+    of.directio = clcf->directio;</div><div>+    of.valid = clcf->open_file_cache_valid;</div><div>+    of.min_uses = clcf->open_file_cache_min_uses;</div><div>+    of.errors = clcf->open_file_cache_errors;</div><div>+    of.events = clcf->open_file_cache_events;</div><div>+</div><div>+    if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {</div><div>+        return NGX_HTTP_INTERNAL_SERVER_ERROR;</div><div>+    }</div><div>+</div><div>+    if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)</div><div>+        != NGX_OK)</div><div>+    {</div><div>+        switch (of.err) {</div><div>+</div><div>+        case 0:</div><div>+            return NGX_HTTP_INTERNAL_SERVER_ERROR;</div><div>+</div><div>+        case NGX_ENOENT:</div><div>+        case NGX_ENOTDIR:</div><div>+        case NGX_ENAMETOOLONG:</div><div>+</div><div>+            return NGX_DECLINED;</div><div>+</div><div>+        case NGX_EACCES:</div><div>+#if (NGX_HAVE_OPENAT)</div><div>+        case NGX_EMLINK:</div><div>+        case NGX_ELOOP:</div><div>+#endif</div><div>+</div><div>+            level = NGX_LOG_ERR;</div><div>+            break;</div><div>+</div><div>+        default:</div><div>+</div><div>+            level = NGX_LOG_CRIT;</div><div>+            break;</div><div>+        }</div><div>+</div><div>+        ngx_log_error(level, log, of.err,</div><div>+                      "%s \"%s\" failed", of.failed, path.data);</div><div>+</div><div>+        return NGX_DECLINED;</div><div>+    }</div><div>+</div><div>+    if (bscf->enable == NGX_HTTP_BROTLI_STATIC_ON) {</div><div>+        r->gzip_vary = 1;</div><div>+</div><div>+        if (rc != NGX_OK) {</div><div>+            return NGX_DECLINED;</div><div>+        }</div><div>+    }</div><div>+</div><div>+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd);</div><div>+</div><div>+    if (of.is_dir) {</div><div>+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");</div><div>+        return NGX_DECLINED;</div><div>+    }</div><div>+</div><div>+#if !(NGX_WIN32) /* the not regular files are probably Unix specific */</div><div>+</div><div>+    if (!of.is_file) {</div><div>+        ngx_log_error(NGX_LOG_CRIT, log, 0,</div><div>+                      "\"%s\" is not a regular file", path.data);</div><div>+</div><div>+        return NGX_HTTP_NOT_FOUND;</div><div>+    }</div><div>+</div><div>+#endif</div><div>+</div><div>+    r->root_tested = !r->error_page;</div><div>+</div><div>+    rc = ngx_http_discard_request_body(r);</div><div>+</div><div>+    if (rc != NGX_OK) {</div><div>+        return rc;</div><div>+    }</div><div>+</div><div>+    log->action = "sending response to client";</div><div>+</div><div>+    r->headers_out.status = NGX_HTTP_OK;</div><div>+    r->headers_out.content_length_n = of.size;</div><div>+    r->headers_out.last_modified_time = of.mtime;</div><div>+</div><div>+    if (ngx_http_set_etag(r) != NGX_OK) {</div><div>+        return NGX_HTTP_INTERNAL_SERVER_ERROR;</div><div>+    }</div><div>+</div><div>+    if (ngx_http_set_content_type(r) != NGX_OK) {</div><div>+        return NGX_HTTP_INTERNAL_SERVER_ERROR;</div><div>+    }</div><div>+</div><div>+    h = ngx_list_push(&r->headers_out.headers);</div><div>+    if (h == NULL) {</div><div>+        return NGX_ERROR;</div><div>+    }</div><div>+</div><div>+    h->hash = 1;</div><div>+    ngx_str_set(&h->key, "Content-Encoding");</div><div>+    ngx_str_set(&h->value, "br");</div><div>+    r->headers_out.content_encoding = h;</div><div>+</div><div>+    /* we need to allocate all before the header would be sent */</div><div>+</div><div>+    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));</div><div>+    if (b == NULL) {</div><div>+        return NGX_HTTP_INTERNAL_SERVER_ERROR;</div><div>+    }</div><div>+</div><div>+    b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));</div><div>+    if (b->file == NULL) {</div><div>+        return NGX_HTTP_INTERNAL_SERVER_ERROR;</div><div>+    }</div><div>+</div><div>+    rc = ngx_http_send_header(r);</div><div>+</div><div>+    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {</div><div>+        return rc;</div><div>+    }</div><div>+</div><div>+    b->file_pos = 0;</div><div>+    b->file_last = of.size;</div><div>+</div><div>+    b->in_file = b->file_last ? 1 : 0;</div><div>+    b->last_buf = (r == r->main) ? 1 : 0;</div><div>+    b->last_in_chain = 1;</div><div>+</div><div>+    b->file->fd = of.fd;</div><div>+    b->file->name = path;</div><div>+    b->file->log = log;</div><div>+    b->file->directio = of.is_directio;</div><div>+</div><div>+    out.buf = b;</div><div>+    out.next = NULL;</div><div>+</div><div>+    return ngx_http_output_filter(r, &out);</div><div>+}</div><div>+</div><div>+</div><div>+static void *</div><div>+ngx_http_brotli_static_create_conf(ngx_conf_t *cf)</div><div>+{</div><div>+    ngx_http_brotli_static_conf_t  *conf;</div><div>+</div><div>+    conf = ngx_palloc(cf->pool, sizeof(ngx_http_brotli_static_conf_t));</div><div>+    if (conf == NULL) {</div><div>+        return NULL;</div><div>+    }</div><div>+</div><div>+    conf->enable = NGX_CONF_UNSET_UINT;</div><div>+</div><div>+    return conf;</div><div>+}</div><div>+</div><div>+</div><div>+static char *</div><div>+ngx_http_brotli_static_merge_conf(ngx_conf_t *cf, void *parent, void *child)</div><div>+{</div><div>+    ngx_http_brotli_static_conf_t *prev = parent;</div><div>+    ngx_http_brotli_static_conf_t *conf = child;</div><div>+</div><div>+    ngx_conf_merge_uint_value(conf->enable, prev->enable,</div><div>+                              NGX_HTTP_BROTLI_STATIC_OFF);</div><div>+</div><div>+    return NGX_CONF_OK;</div><div>+}</div><div>+</div><div>+</div><div>+static ngx_int_t</div><div>+ngx_http_brotli_static_init(ngx_conf_t *cf)</div><div>+{</div><div>+    ngx_http_handler_pt        *h;</div><div>+    ngx_http_core_main_conf_t  *cmcf;</div><div>+</div><div>+    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);</div><div>+</div><div>+    h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);</div><div>+    if (h == NULL) {</div><div>+        return NGX_ERROR;</div><div>+    }</div><div>+</div><div>+    *h = ngx_http_brotli_static_handler;</div><div>+</div><div>+    return NGX_OK;</div><div>+}</div><div>diff -r 87cf6ddb41c2 -r 81eacab152ef src/http/ngx_http_core_module.c</div><div>--- a/src/http/ngx_http_core_module.c<span class="gmail-Apple-tab-span" style="white-space:pre">    </span>Fri Feb 17 17:01:27 2017 +0300</div><div>+++ b/src/http/ngx_http_core_module.c<span class="gmail-Apple-tab-span" style="white-space:pre">    </span>Wed Feb 22 13:01:13 2017 +0100</div><div>@@ -73,9 +73,11 @@</div><div>     void *conf);</div><div> static char *ngx_http_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd,</div><div>     void *conf);</div><div>+#if (NGX_HTTP_BROTLI || NGX_HTTP_GZIP)</div><div>+static ngx_int_t ngx_http_accept_encoding(ngx_str_t *ae, char *e, size_t n);</div><div>+static ngx_uint_t ngx_http_encoding_quantity(u_char *p, u_char *last);</div><div>+#endif</div><div> #if (NGX_HTTP_GZIP)</div><div>-static ngx_int_t ngx_http_gzip_accept_encoding(ngx_str_t *ae);</div><div>-static ngx_uint_t ngx_http_gzip_quantity(u_char *p, u_char *last);</div><div> static char *ngx_http_gzip_disable(ngx_conf_t *cf, ngx_command_t *cmd,</div><div>     void *conf);</div><div> #endif</div><div>@@ -2170,7 +2172,7 @@</div><div>      */</div><div> </div><div>     if (ngx_memcmp(ae->value.data, "gzip,", 5) != 0</div><div>-        && ngx_http_gzip_accept_encoding(&ae->value) != NGX_OK)</div><div>+        && ngx_http_accept_encoding(&ae->value, "gzip", 4) != NGX_OK)</div><div>     {</div><div>         return NGX_DECLINED;</div><div>     }</div><div>@@ -2296,16 +2298,20 @@</div><div>     return NGX_OK;</div><div> }</div><div> </div><div>+#endif</div><div>+</div><div>+</div><div>+#if (NGX_HTTP_BROTLI || NGX_HTTP_GZIP)</div><div> </div><div> /*</div><div>- * gzip is enabled for the following quantities:</div><div>+ * encoding is enabled for the following quantities:</div><div>  *     "gzip; q=0.001" ... "gzip; q=1.000"</div><div>- * gzip is disabled for the following quantities:</div><div>- *     "gzip; q=0" ... "gzip; q=0.000", and for any invalid cases</div><div>+ * encoding is disabled for the following quantities:</div><div>+ *     "br; q=0" ... "br; q=0.000", and for any invalid cases</div><div>  */</div><div> </div><div> static ngx_int_t</div><div>-ngx_http_gzip_accept_encoding(ngx_str_t *ae)</div><div>+ngx_http_accept_encoding(ngx_str_t *ae, char *e, size_t n)</div><div> {</div><div>     u_char  *p, *start, *last;</div><div> </div><div>@@ -2313,7 +2319,7 @@</div><div>     last = start + ae->len;</div><div> </div><div>     for ( ;; ) {</div><div>-        p = ngx_strcasestrn(start, "gzip", 4 - 1);</div><div>+        p = ngx_strcasestrn(start, e, n - 1);</div><div>         if (p == NULL) {</div><div>             return NGX_DECLINED;</div><div>         }</div><div>@@ -2322,10 +2328,10 @@</div><div>             break;</div><div>         }</div><div> </div><div>-        start = p + 4;</div><div>-    }</div><div>-</div><div>-    p += 4;</div><div>+        start = p + n;</div><div>+    }</div><div>+</div><div>+    p += n;</div><div> </div><div>     while (p < last) {</div><div>         switch (*p++) {</div><div>@@ -2364,7 +2370,7 @@</div><div>         return NGX_DECLINED;</div><div>     }</div><div> </div><div>-    if (ngx_http_gzip_quantity(p, last) == 0) {</div><div>+    if (ngx_http_encoding_quantity(p, last) == 0) {</div><div>         return NGX_DECLINED;</div><div>     }</div><div> </div><div>@@ -2373,7 +2379,7 @@</div><div> </div><div> </div><div> static ngx_uint_t</div><div>-ngx_http_gzip_quantity(u_char *p, u_char *last)</div><div>+ngx_http_encoding_quantity(u_char *p, u_char *last)</div><div> {</div><div>     u_char      c;</div><div>     ngx_uint_t  n, q;</div><div>@@ -2428,6 +2434,37 @@</div><div> #endif</div><div> </div><div> </div><div>+#if (NGX_HTTP_BROTLI)</div><div>+</div><div>+ngx_int_t</div><div>+ngx_http_brotli_ok(ngx_http_request_t *r)</div><div>+{</div><div>+    ngx_table_elt_t  *ae;</div><div>+</div><div>+    if (r != r->main) {</div><div>+        return NGX_DECLINED;</div><div>+    }</div><div>+</div><div>+    ae = r->headers_in.accept_encoding;</div><div>+    if (ae == NULL) {</div><div>+        return NGX_DECLINED;</div><div>+    }</div><div>+</div><div>+    if (ae->value.len < sizeof("br") - 1) {</div><div>+        return NGX_DECLINED;</div><div>+    }</div><div>+</div><div>+    if (ngx_http_accept_encoding(&ae->value, "br", 2) != NGX_OK)</div><div>+    {</div><div>+        return NGX_DECLINED;</div><div>+    }</div><div>+</div><div>+    return NGX_OK;</div><div>+}</div><div>+</div><div>+#endif</div><div>+</div><div>+</div><div> ngx_int_t</div><div> ngx_http_subrequest(ngx_http_request_t *r,</div><div>     ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr,</div><div>diff -r 87cf6ddb41c2 -r 81eacab152ef src/http/ngx_http_core_module.h</div><div>--- a/src/http/ngx_http_core_module.h<span class="gmail-Apple-tab-span" style="white-space:pre">     </span>Fri Feb 17 17:01:27 2017 +0300</div><div>+++ b/src/http/ngx_http_core_module.h<span class="gmail-Apple-tab-span" style="white-space:pre">    </span>Wed Feb 22 13:01:13 2017 +0100</div><div>@@ -506,6 +506,9 @@</div><div> ngx_int_t ngx_http_gzip_ok(ngx_http_request_t *r);</div><div> #endif</div><div> </div><div>+#if (NGX_HTTP_BROTLI)</div><div>+ngx_int_t ngx_http_brotli_ok(ngx_http_request_t *r);</div><div>+#endif</div><div> </div><div> ngx_int_t ngx_http_subrequest(ngx_http_request_t *r,</div><div>     ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **sr,</div><div><br></div><div><br></div>-- <br><div class="gmail_signature">С наилучшими пожеланиями, Евгений Ключников<br>WBR, Eugene Kluchnikov<br></div>
</div>