Browse Source

Push patch compatibility in nginx 1.15.3

master
Hakase 7 months ago
parent
commit
40f9f05922
1 changed files with 1083 additions and 0 deletions
  1. 1083
    0
      nginx_hpack_push_1.15.3.patch

+ 1083
- 0
nginx_hpack_push_1.15.3.patch View File

@@ -0,0 +1,1083 @@
1
+diff --git a/auto/modules b/auto/modules
2
+index 09bfcb08..645eb897 100644
3
+--- a/auto/modules
4
++++ b/auto/modules
5
+@@ -438,6 +438,10 @@ if [ $HTTP = YES ]; then
6
+         . auto/module
7
+     fi
8
+ 
9
++    if [ $HTTP_V2_HPACK_ENC = YES ]; then
10
++        have=NGX_HTTP_V2_HPACK_ENC . auto/have
11
++    fi
12
++
13
+     if :; then
14
+         ngx_module_name=ngx_http_static_module
15
+         ngx_module_incs=
16
+diff --git a/auto/options b/auto/options
17
+index d8b421b0..55b339e6 100644
18
+--- a/auto/options
19
++++ b/auto/options
20
+@@ -59,6 +59,7 @@ HTTP_CHARSET=YES
21
+ HTTP_GZIP=YES
22
+ HTTP_SSL=NO
23
+ HTTP_V2=NO
24
++HTTP_V2_HPACK_ENC=NO
25
+ HTTP_SSI=YES
26
+ HTTP_POSTPONE=NO
27
+ HTTP_REALIP=NO
28
+@@ -225,6 +226,7 @@ $0: warning: the \"--with-ipv6\" option is deprecated"
29
+ 
30
+         --with-http_ssl_module)          HTTP_SSL=YES               ;;
31
+         --with-http_v2_module)           HTTP_V2=YES                ;;
32
++        --with-http_v2_hpack_enc)        HTTP_V2_HPACK_ENC=YES      ;;
33
+         --with-http_realip_module)       HTTP_REALIP=YES            ;;
34
+         --with-http_addition_module)     HTTP_ADDITION=YES          ;;
35
+         --with-http_xslt_module)         HTTP_XSLT=YES              ;;
36
+@@ -440,6 +442,7 @@ cat << END
37
+ 
38
+   --with-http_ssl_module             enable ngx_http_ssl_module
39
+   --with-http_v2_module              enable ngx_http_v2_module
40
++  --with-http_v2_hpack_enc           enable ngx_http_v2_hpack_enc
41
+   --with-http_realip_module          enable ngx_http_realip_module
42
+   --with-http_addition_module        enable ngx_http_addition_module
43
+   --with-http_xslt_module            enable ngx_http_xslt_module
44
+diff --git a/src/core/ngx_murmurhash.c b/src/core/ngx_murmurhash.c
45
+index 5ade658d..4932f20d 100644
46
+--- a/src/core/ngx_murmurhash.c
47
++++ b/src/core/ngx_murmurhash.c
48
+@@ -50,3 +50,63 @@ ngx_murmur_hash2(u_char *data, size_t len)
49
+ 
50
+     return h;
51
+ }
52
++
53
++
54
++uint64_t
55
++ngx_murmur_hash2_64(u_char *data, size_t len, uint64_t seed)
56
++{
57
++    uint64_t  h, k;
58
++
59
++    h = seed ^ len;
60
++
61
++    while (len >= 8) {
62
++        k  = data[0];
63
++        k |= data[1] << 8;
64
++        k |= data[2] << 16;
65
++        k |= data[3] << 24;
66
++        k |= (uint64_t)data[4] << 32;
67
++        k |= (uint64_t)data[5] << 40;
68
++        k |= (uint64_t)data[6] << 48;
69
++        k |= (uint64_t)data[7] << 56;
70
++
71
++        k *= 0xc6a4a7935bd1e995ull;
72
++        k ^= k >> 47;
73
++        k *= 0xc6a4a7935bd1e995ull;
74
++
75
++        h ^= k;
76
++        h *= 0xc6a4a7935bd1e995ull;
77
++
78
++        data += 8;
79
++        len -= 8;
80
++    }
81
++
82
++    switch (len) {
83
++    case 7:
84
++        h ^= (uint64_t)data[6] << 48;
85
++        /* fall through */
86
++    case 6:
87
++        h ^= (uint64_t)data[5] << 40;
88
++        /* fall through */
89
++    case 5:
90
++        h ^= (uint64_t)data[4] << 32;
91
++        /* fall through */
92
++    case 4:
93
++        h ^= data[3] << 24;
94
++        /* fall through */
95
++    case 3:
96
++        h ^= data[2] << 16;
97
++        /* fall through */
98
++    case 2:
99
++        h ^= data[1] << 8;
100
++        /* fall through */
101
++    case 1:
102
++        h ^= data[0];
103
++        h *= 0xc6a4a7935bd1e995ull;
104
++    }
105
++
106
++    h ^= h >> 47;
107
++    h *= 0xc6a4a7935bd1e995ull;
108
++    h ^= h >> 47;
109
++
110
++    return h;
111
++}
112
+diff --git a/src/core/ngx_murmurhash.h b/src/core/ngx_murmurhash.h
113
+index 54e867d3..322b3df9 100644
114
+--- a/src/core/ngx_murmurhash.h
115
++++ b/src/core/ngx_murmurhash.h
116
+@@ -15,5 +15,7 @@
117
+ 
118
+ uint32_t ngx_murmur_hash2(u_char *data, size_t len);
119
+ 
120
++uint64_t ngx_murmur_hash2_64(u_char *data, size_t len, uint64_t seed);
121
++
122
+ 
123
+ #endif /* _NGX_MURMURHASH_H_INCLUDED_ */
124
+diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
125
+index e7770192..c18b60ca 100644
126
+--- a/src/http/v2/ngx_http_v2.c
127
++++ b/src/http/v2/ngx_http_v2.c
128
+@@ -270,6 +270,8 @@ ngx_http_v2_init(ngx_event_t *rev)
129
+ 
130
+     h2c->frame_size = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
131
+ 
132
++    h2c->max_hpack_table_size = NGX_HTTP_V2_DEFAULT_HPACK_TABLE_SIZE;
133
++
134
+     h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module);
135
+ 
136
+     h2c->concurrent_pushes = h2scf->concurrent_pushes;
137
+@@ -2076,6 +2078,14 @@ ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos,
138
+         case NGX_HTTP_V2_HEADER_TABLE_SIZE_SETTING:
139
+ 
140
+             h2c->table_update = 1;
141
++
142
++            if (value > NGX_HTTP_V2_MAX_HPACK_TABLE_SIZE) {
143
++                h2c->max_hpack_table_size = NGX_HTTP_V2_MAX_HPACK_TABLE_SIZE;
144
++            } else {
145
++                h2c->max_hpack_table_size = value;
146
++            }
147
++
148
++            h2c->indicate_resize = 1;
149
+             break;
150
+ 
151
+         default:
152
+diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
153
+index ebd0e77c..b152b504 100644
154
+--- a/src/http/v2/ngx_http_v2.h
155
++++ b/src/http/v2/ngx_http_v2.h
156
+@@ -52,6 +52,14 @@
157
+ #define NGX_HTTP_V2_MAX_WINDOW           ((1U << 31) - 1)
158
+ #define NGX_HTTP_V2_DEFAULT_WINDOW       65535
159
+ 
160
++#define HPACK_ENC_HTABLE_SZ              128 /* better to keep a PoT < 64k */
161
++#define HPACK_ENC_HTABLE_ENTRIES         ((HPACK_ENC_HTABLE_SZ * 100) / 128)
162
++#define HPACK_ENC_DYNAMIC_KEY_TBL_SZ     10  /* 10 is sufficient for most */
163
++#define HPACK_ENC_MAX_ENTRY              512 /* longest header size to match */
164
++
165
++#define NGX_HTTP_V2_DEFAULT_HPACK_TABLE_SIZE     4096
166
++#define NGX_HTTP_V2_MAX_HPACK_TABLE_SIZE         16384 /* < 64k */
167
++
168
+ #define NGX_HTTP_V2_DEFAULT_WEIGHT       16
169
+ 
170
+ 
171
+@@ -115,6 +123,46 @@ typedef struct {
172
+ } ngx_http_v2_hpack_t;
173
+ 
174
+ 
175
++#if (NGX_HTTP_V2_HPACK_ENC)
176
++typedef struct {
177
++    uint64_t                         hash_val;
178
++    uint32_t                         index;
179
++    uint16_t                         pos;
180
++    uint16_t                         klen, vlen;
181
++    uint16_t                         size;
182
++    uint16_t                         next;
183
++} ngx_http_v2_hpack_enc_entry_t;
184
++
185
++
186
++typedef struct {
187
++    uint64_t                         hash_val;
188
++    uint32_t                         index;
189
++    uint16_t                         pos;
190
++    uint16_t                         klen;
191
++} ngx_http_v2_hpack_name_entry_t;
192
++
193
++
194
++typedef struct {
195
++    size_t                           size;    /* size as defined in RFC 7541 */
196
++    uint32_t                         top;     /* the last entry */
197
++    uint32_t                         pos;
198
++    uint16_t                         n_elems; /* number of elements */
199
++    uint16_t                         base;    /* index of the oldest entry */
200
++    uint16_t                         last;    /* index of the newest entry */
201
++
202
++    /* hash table for dynamic entries, instead using a generic hash table,
203
++       which would be too slow to process a significant amount of headers,
204
++       this table is not determenistic, and might ocasionally fail to insert
205
++       a value, at the cost of slightly worse compression, but significantly
206
++       faster performance */
207
++    ngx_http_v2_hpack_enc_entry_t    htable[HPACK_ENC_HTABLE_SZ];
208
++    ngx_http_v2_hpack_name_entry_t   heads[HPACK_ENC_DYNAMIC_KEY_TBL_SZ];
209
++    u_char                           storage[NGX_HTTP_V2_MAX_HPACK_TABLE_SIZE +
210
++                                             HPACK_ENC_MAX_ENTRY];
211
++} ngx_http_v2_hpack_enc_t;
212
++#endif
213
++
214
++
215
+ struct ngx_http_v2_connection_s {
216
+     ngx_connection_t                *connection;
217
+     ngx_http_connection_t           *http_connection;
218
+@@ -130,6 +178,8 @@ struct ngx_http_v2_connection_s {
219
+ 
220
+     size_t                           frame_size;
221
+ 
222
++    size_t                           max_hpack_table_size;
223
++
224
+     ngx_queue_t                      waiting;
225
+ 
226
+     ngx_http_v2_state_t              state;
227
+@@ -157,6 +207,11 @@ struct ngx_http_v2_connection_s {
228
+     unsigned                         blocked:1;
229
+     unsigned                         goaway:1;
230
+     unsigned                         push_disabled:1;
231
++    unsigned                         indicate_resize:1;
232
++
233
++#if (NGX_HTTP_V2_HPACK_ENC)
234
++    ngx_http_v2_hpack_enc_t          hpack_enc;
235
++#endif
236
+ };
237
+ 
238
+ 
239
+@@ -198,6 +253,8 @@ struct ngx_http_v2_stream_s {
240
+ 
241
+     ngx_array_t                     *cookies;
242
+ 
243
++    size_t                           header_limit;
244
++
245
+     ngx_pool_t                      *pool;
246
+ 
247
+     unsigned                         waiting:1;
248
+@@ -410,4 +467,35 @@ u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len,
249
+     u_char *tmp, ngx_uint_t lower);
250
+ 
251
+ 
252
++u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len,
253
++    u_char *tmp, ngx_uint_t lower);
254
++
255
++u_char *
256
++ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, ngx_uint_t value);
257
++
258
++#define ngx_http_v2_write_name(dst, src, len, tmp)                            \
259
++    ngx_http_v2_string_encode(dst, src, len, tmp, 1)
260
++#define ngx_http_v2_write_value(dst, src, len, tmp)                           \
261
++    ngx_http_v2_string_encode(dst, src, len, tmp, 0)
262
++
263
++u_char *
264
++ngx_http_v2_write_header(ngx_http_v2_connection_t *h2c, u_char *pos,
265
++    u_char *key, size_t key_len, u_char *value, size_t value_len,
266
++    u_char *tmp);
267
++
268
++void
269
++ngx_http_v2_table_resize(ngx_http_v2_connection_t *h2c);
270
++
271
++#define ngx_http_v2_write_header_str(key, value)                        \
272
++    ngx_http_v2_write_header(h2c, pos, (u_char *) key, sizeof(key) - 1, \
273
++    (u_char *) value, sizeof(value) - 1, tmp);
274
++
275
++#define ngx_http_v2_write_header_tbl(key, val)                          \
276
++    ngx_http_v2_write_header(h2c, pos, (u_char *) key, sizeof(key) - 1, \
277
++    val.data, val.len, tmp);
278
++
279
++#define ngx_http_v2_write_header_pot(key, val)                          \
280
++    ngx_http_v2_write_header(h2c, pos, (u_char *) key, sizeof(key) - 1, \
281
++    val->data, val->len, tmp);
282
++
283
+ #endif /* _NGX_HTTP_V2_H_INCLUDED_ */
284
+diff --git a/src/http/v2/ngx_http_v2_encode.c b/src/http/v2/ngx_http_v2_encode.c
285
+index ac792084..d1fb7217 100644
286
+--- a/src/http/v2/ngx_http_v2_encode.c
287
++++ b/src/http/v2/ngx_http_v2_encode.c
288
+@@ -10,7 +10,7 @@
289
+ #include <ngx_http.h>
290
+ 
291
+ 
292
+-static u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix,
293
++u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix,
294
+     ngx_uint_t value);
295
+ 
296
+ 
297
+@@ -40,7 +40,7 @@ ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp,
298
+ }
299
+ 
300
+ 
301
+-static u_char *
302
++u_char *
303
+ ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, ngx_uint_t value)
304
+ {
305
+     if (value < prefix) {
306
+diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c
307
+index 853faefd..61e1f051 100644
308
+--- a/src/http/v2/ngx_http_v2_filter_module.c
309
++++ b/src/http/v2/ngx_http_v2_filter_module.c
310
+@@ -23,10 +23,53 @@
311
+ #define ngx_http_v2_literal_size(h)                                           \
312
+     (ngx_http_v2_integer_octets(sizeof(h) - 1) + sizeof(h) - 1)
313
+ 
314
++#define ngx_http_v2_indexed(i)      (128 + (i))
315
++#define ngx_http_v2_inc_indexed(i)  (64 + (i))
316
++
317
++#define NGX_HTTP_V2_ENCODE_RAW            0
318
++#define NGX_HTTP_V2_ENCODE_HUFF           0x80
319
++
320
++#define NGX_HTTP_V2_AUTHORITY_INDEX       1
321
++#define NGX_HTTP_V2_METHOD_GET_INDEX      2
322
++#define NGX_HTTP_V2_PATH_INDEX            4
323
++
324
++#define NGX_HTTP_V2_SCHEME_HTTP_INDEX     6
325
++#define NGX_HTTP_V2_SCHEME_HTTPS_INDEX    7
326
++
327
++#define NGX_HTTP_V2_STATUS_INDEX          8
328
++#define NGX_HTTP_V2_STATUS_200_INDEX      8
329
++#define NGX_HTTP_V2_STATUS_204_INDEX      9
330
++#define NGX_HTTP_V2_STATUS_206_INDEX      10
331
++#define NGX_HTTP_V2_STATUS_304_INDEX      11
332
++#define NGX_HTTP_V2_STATUS_400_INDEX      12
333
++#define NGX_HTTP_V2_STATUS_404_INDEX      13
334
++#define NGX_HTTP_V2_STATUS_500_INDEX      14
335
++
336
++#define NGX_HTTP_V2_ACCEPT_ENCODING_INDEX 16
337
++#define NGX_HTTP_V2_ACCEPT_LANGUAGE_INDEX 17
338
++#define NGX_HTTP_V2_CONTENT_LENGTH_INDEX  28
339
++#define NGX_HTTP_V2_CONTENT_TYPE_INDEX    31
340
++#define NGX_HTTP_V2_DATE_INDEX            33
341
++#define NGX_HTTP_V2_LAST_MODIFIED_INDEX   44
342
++#define NGX_HTTP_V2_LOCATION_INDEX        46
343
++#define NGX_HTTP_V2_SERVER_INDEX          54
344
++#define NGX_HTTP_V2_USER_AGENT_INDEX      58
345
++#define NGX_HTTP_V2_VARY_INDEX            59
346
+ 
347
+ #define NGX_HTTP_V2_NO_TRAILERS           (ngx_http_v2_out_frame_t *) -1
348
+ 
349
+ 
350
++static const struct {
351
++    u_char        *name;
352
++    u_char const   len;
353
++} push_header[] = {
354
++    { (u_char*)":authority"      , 10 },
355
++    { (u_char*)"accept-encoding" , 15 },
356
++    { (u_char*)"accept-language" , 15 },
357
++    { (u_char*)"user-agent"      , 10 }
358
++};
359
++
360
++
361
+ typedef struct {
362
+     ngx_str_t      name;
363
+     u_char         index;
364
+@@ -155,11 +198,9 @@ ngx_http_v2_header_filter(ngx_http_request_t *r)
365
+ #endif
366
+ 
367
+     static size_t nginx_ver_len = ngx_http_v2_literal_size(NGINX_VER);
368
+-    static u_char nginx_ver[ngx_http_v2_literal_size(NGINX_VER)];
369
+ 
370
+     static size_t nginx_ver_build_len =
371
+                                   ngx_http_v2_literal_size(NGINX_VER_BUILD);
372
+-    static u_char nginx_ver_build[ngx_http_v2_literal_size(NGINX_VER_BUILD)];
373
+ 
374
+     stream = r->stream;
375
+ 
376
+@@ -435,7 +476,7 @@ ngx_http_v2_header_filter(ngx_http_request_t *r)
377
+     }
378
+ 
379
+     tmp = ngx_palloc(r->pool, tmp_len);
380
+-    pos = ngx_pnalloc(r->pool, len);
381
++    pos = ngx_pnalloc(r->pool, len + 15 + 1);
382
+ 
383
+     if (pos == NULL || tmp == NULL) {
384
+         return NGX_ERROR;
385
+@@ -443,11 +484,16 @@ ngx_http_v2_header_filter(ngx_http_request_t *r)
386
+ 
387
+     start = pos;
388
+ 
389
+-    if (h2c->table_update) {
390
+-        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
391
+-                       "http2 table size update: 0");
392
+-        *pos++ = (1 << 5) | 0;
393
+-        h2c->table_update = 0;
394
++    h2c = r->stream->connection;
395
++
396
++    if (h2c->indicate_resize) {
397
++        *pos = 32;
398
++        pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(5),
399
++                                    h2c->max_hpack_table_size);
400
++        h2c->indicate_resize = 0;
401
++#if (NGX_HTTP_V2_HPACK_ENC)
402
++        ngx_http_v2_table_resize(h2c);
403
++#endif
404
+     }
405
+ 
406
+     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
407
+@@ -458,67 +504,28 @@ ngx_http_v2_header_filter(ngx_http_request_t *r)
408
+         *pos++ = status;
409
+ 
410
+     } else {
411
+-        *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_STATUS_INDEX);
412
+-        *pos++ = NGX_HTTP_V2_ENCODE_RAW | 3;
413
+-        pos = ngx_sprintf(pos, "%03ui", r->headers_out.status);
414
++        ngx_sprintf(pos + 8, "%O3ui", r->headers_out.status);
415
++        pos = ngx_http_v2_write_header(h2c, pos, (u_char *)":status",
416
++                                       sizeof(":status") - 1, pos + 8, 3, tmp);
417
+     }
418
+ 
419
+     if (r->headers_out.server == NULL) {
420
+-
421
+         if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) {
422
+-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
423
+-                           "http2 output header: \"server: %s\"",
424
+-                           NGINX_VER);
425
++            pos = ngx_http_v2_write_header_str("server", NGINX_VER);
426
+ 
427
+         } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) {
428
+-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
429
+-                           "http2 output header: \"server: %s\"",
430
+-                           NGINX_VER_BUILD);
431
++            pos = ngx_http_v2_write_header_str("server", NGINX_VER_BUILD);
432
+ 
433
+         } else {
434
+-            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
435
+-                           "http2 output header: \"server: nginx\"");
436
+-        }
437
+-
438
+-        *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_SERVER_INDEX);
439
+-
440
+-        if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) {
441
+-            if (nginx_ver[0] == '\0') {
442
+-                p = ngx_http_v2_write_value(nginx_ver, (u_char *) NGINX_VER,
443
+-                                            sizeof(NGINX_VER) - 1, tmp);
444
+-                nginx_ver_len = p - nginx_ver;
445
+-            }
446
+-
447
+-            pos = ngx_cpymem(pos, nginx_ver, nginx_ver_len);
448
+-
449
+-        } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) {
450
+-            if (nginx_ver_build[0] == '\0') {
451
+-                p = ngx_http_v2_write_value(nginx_ver_build,
452
+-                                            (u_char *) NGINX_VER_BUILD,
453
+-                                            sizeof(NGINX_VER_BUILD) - 1, tmp);
454
+-                nginx_ver_build_len = p - nginx_ver_build;
455
+-            }
456
+-
457
+-            pos = ngx_cpymem(pos, nginx_ver_build, nginx_ver_build_len);
458
+-
459
+-        } else {
460
+-            pos = ngx_cpymem(pos, nginx, sizeof(nginx));
461
++            pos = ngx_http_v2_write_header_str("server", "nginx");
462
+         }
463
+     }
464
+ 
465
+     if (r->headers_out.date == NULL) {
466
+-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
467
+-                       "http2 output header: \"date: %V\"",
468
+-                       &ngx_cached_http_time);
469
+-
470
+-        *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_DATE_INDEX);
471
+-        pos = ngx_http_v2_write_value(pos, ngx_cached_http_time.data,
472
+-                                      ngx_cached_http_time.len, tmp);
473
++        pos = ngx_http_v2_write_header_tbl("date", ngx_cached_http_time);
474
+     }
475
+ 
476
+     if (r->headers_out.content_type.len) {
477
+-        *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_CONTENT_TYPE_INDEX);
478
+-
479
+         if (r->headers_out.content_type_len == r->headers_out.content_type.len
480
+             && r->headers_out.charset.len)
481
+         {
482
+@@ -544,64 +551,36 @@ ngx_http_v2_header_filter(ngx_http_request_t *r)
483
+             r->headers_out.content_type.data = p - len;
484
+         }
485
+ 
486
+-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
487
+-                       "http2 output header: \"content-type: %V\"",
488
+-                       &r->headers_out.content_type);
489
+-
490
+-        pos = ngx_http_v2_write_value(pos, r->headers_out.content_type.data,
491
+-                                      r->headers_out.content_type.len, tmp);
492
++        pos = ngx_http_v2_write_header_tbl("content-type",
493
++                                           r->headers_out.content_type);
494
+     }
495
+ 
496
+     if (r->headers_out.content_length == NULL
497
+         && r->headers_out.content_length_n >= 0)
498
+     {
499
+-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
500
+-                       "http2 output header: \"content-length: %O\"",
501
+-                       r->headers_out.content_length_n);
502
+-
503
+-        *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_CONTENT_LENGTH_INDEX);
504
+-
505
+-        p = pos;
506
+-        pos = ngx_sprintf(pos + 1, "%O", r->headers_out.content_length_n);
507
+-        *p = NGX_HTTP_V2_ENCODE_RAW | (u_char) (pos - p - 1);
508
++        p = ngx_sprintf(pos + 15, "%O", r->headers_out.content_length_n);
509
++        pos = ngx_http_v2_write_header(h2c, pos, (u_char *)"content-length",
510
++                                       sizeof("content-length") - 1, pos + 15,
511
++                                       p - (pos + 15), tmp);
512
+     }
513
+ 
514
+     if (r->headers_out.last_modified == NULL
515
+         && r->headers_out.last_modified_time != -1)
516
+     {
517
+-        *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_LAST_MODIFIED_INDEX);
518
+-
519
+-        ngx_http_time(pos, r->headers_out.last_modified_time);
520
++        ngx_http_time(pos + 14, r->headers_out.last_modified_time);
521
+         len = sizeof("Wed, 31 Dec 1986 18:00:00 GMT") - 1;
522
+-
523
+-        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, fc->log, 0,
524
+-                       "http2 output header: \"last-modified: %*s\"",
525
+-                       len, pos);
526
+-
527
+-        /*
528
+-         * Date will always be encoded using huffman in the temporary buffer,
529
+-         * so it's safe here to use src and dst pointing to the same address.
530
+-         */
531
+-        pos = ngx_http_v2_write_value(pos, pos, len, tmp);
532
++        pos = ngx_http_v2_write_header(h2c, pos, (u_char *)"last-modified",
533
++                                       sizeof("last-modified") - 1, pos + 14,
534
++                                       len, tmp);
535
+     }
536
+ 
537
+     if (r->headers_out.location && r->headers_out.location->value.len) {
538
+-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
539
+-                       "http2 output header: \"location: %V\"",
540
+-                       &r->headers_out.location->value);
541
+-
542
+-        *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_LOCATION_INDEX);
543
+-        pos = ngx_http_v2_write_value(pos, r->headers_out.location->value.data,
544
+-                                      r->headers_out.location->value.len, tmp);
545
++        pos = ngx_http_v2_write_header_tbl("location", r->headers_out.location->value);
546
+     }
547
+ 
548
+ #if (NGX_HTTP_GZIP)
549
+     if (r->gzip_vary) {
550
+-        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
551
+-                       "http2 output header: \"vary: Accept-Encoding\"");
552
+-
553
+-        *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_VARY_INDEX);
554
+-        pos = ngx_cpymem(pos, accept_encoding, sizeof(accept_encoding));
555
++        pos = ngx_http_v2_write_header_str("vary", "Accept-Encoding");
556
+     }
557
+ #endif
558
+ 
559
+@@ -624,23 +603,10 @@ ngx_http_v2_header_filter(ngx_http_request_t *r)
560
+             continue;
561
+         }
562
+ 
563
+-#if (NGX_DEBUG)
564
+-        if (fc->log->log_level & NGX_LOG_DEBUG_HTTP) {
565
+-            ngx_strlow(tmp, header[i].key.data, header[i].key.len);
566
+-
567
+-            ngx_log_debug3(NGX_LOG_DEBUG_HTTP, fc->log, 0,
568
+-                           "http2 output header: \"%*s: %V\"",
569
+-                           header[i].key.len, tmp, &header[i].value);
570
+-        }
571
+-#endif
572
+-
573
+-        *pos++ = 0;
574
+-
575
+-        pos = ngx_http_v2_write_name(pos, header[i].key.data,
576
+-                                     header[i].key.len, tmp);
577
++        pos = ngx_http_v2_write_header(h2c, pos, header[i].key.data,
578
++                                       header[i].key.len, header[i].value.data,
579
++                                       header[i].value.len, tmp);
580
+ 
581
+-        pos = ngx_http_v2_write_value(pos, header[i].value.data,
582
+-                                      header[i].value.len, tmp);
583
+     }
584
+ 
585
+     fin = r->header_only
586
+@@ -998,6 +964,7 @@ ngx_http_v2_push_resource(ngx_http_request_t *r, ngx_str_t *path,
587
+ 
588
+     for (i = 0; i < NGX_HTTP_V2_PUSH_HEADERS; i++) {
589
+         len += binary[i].len;
590
++        len += push_header[i].len + 1;
591
+     }
592
+ 
593
+     pos = ngx_pnalloc(r->pool, len);
594
+@@ -1007,12 +974,17 @@ ngx_http_v2_push_resource(ngx_http_request_t *r, ngx_str_t *path,
595
+ 
596
+     start = pos;
597
+ 
598
+-    if (h2c->table_update) {
599
+-        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
600
+-                       "http2 table size update: 0");
601
+-        *pos++ = (1 << 5) | 0;
602
+-        h2c->table_update = 0;
603
+-    }
604
++    h2c = r->stream->connection;
605
++
606
++    if (h2c->indicate_resize) {
607
++        *pos = 32;
608
++        pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(5),
609
++                                    h2c->max_hpack_table_size);
610
++        h2c->indicate_resize = 0;
611
++#if (NGX_HTTP_V2_HPACK_ENC)
612
++        ngx_http_v2_table_resize(h2c);
613
++#endif
614
++     }
615
+ 
616
+     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
617
+                    "http2 push header: \":method: GET\"");
618
+@@ -1022,8 +994,7 @@ ngx_http_v2_push_resource(ngx_http_request_t *r, ngx_str_t *path,
619
+     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
620
+                    "http2 push header: \":path: %V\"", path);
621
+ 
622
+-    *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
623
+-    pos = ngx_http_v2_write_value(pos, path->data, path->len, tmp);
624
++    pos = ngx_http_v2_write_header_pot(":path", path);
625
+ 
626
+     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
627
+                    "http2 push header: \":scheme: %V\"", &r->schema);
628
+@@ -1048,11 +1019,15 @@ ngx_http_v2_push_resource(ngx_http_request_t *r, ngx_str_t *path,
629
+             continue;
630
+         }
631
+ 
632
++        value = &(*h)->value;
633
++
634
+         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, fc->log, 0,
635
+                        "http2 push header: \"%V: %V\"",
636
+                        &ph[i].name, &(*h)->value);
637
+ 
638
+-        pos = ngx_cpymem(pos, binary[i].data, binary[i].len);
639
++        pos = ngx_http_v2_write_header(h2c, pos,
640
++                  push_header[i].name, push_header[i].len, value->data, value->len,
641
++                  tmp);
642
+     }
643
+ 
644
+     frame = ngx_http_v2_create_push_frame(r, start, pos);
645
+diff --git a/src/http/v2/ngx_http_v2_table.c b/src/http/v2/ngx_http_v2_table.c
646
+index 7d49803f..b9ee2048 100644
647
+--- a/src/http/v2/ngx_http_v2_table.c
648
++++ b/src/http/v2/ngx_http_v2_table.c
649
+@@ -361,3 +361,434 @@ ngx_http_v2_table_size(ngx_http_v2_connection_t *h2c, size_t size)
650
+ 
651
+     return NGX_OK;
652
+ }
653
++
654
++
655
++#if (NGX_HTTP_V2_HPACK_ENC)
656
++
657
++static ngx_int_t
658
++hpack_get_static_index(ngx_http_v2_connection_t *h2c, u_char *val, size_t len);
659
++
660
++static ngx_int_t
661
++hpack_get_dynamic_index(ngx_http_v2_connection_t *h2c, uint64_t key_hash,
662
++                        uint8_t *key, size_t key_len);
663
++
664
++
665
++void
666
++ngx_http_v2_table_resize(ngx_http_v2_connection_t *h2c)
667
++{
668
++    ngx_http_v2_hpack_enc_entry_t  *table;
669
++    uint64_t                        idx;
670
++
671
++    table = h2c->hpack_enc.htable;
672
++
673
++    while (h2c->hpack_enc.size > h2c->max_hpack_table_size) {
674
++        idx = h2c->hpack_enc.base;
675
++        h2c->hpack_enc.base = table[idx].next;
676
++        h2c->hpack_enc.size -= table[idx].size;
677
++        table[idx].hash_val = 0;
678
++        h2c->hpack_enc.n_elems--;
679
++    }
680
++}
681
++
682
++
683
++/* checks if a header is in the hpack table - if so returns the table entry,
684
++   otherwise encodes and inserts into the table and returns 0,
685
++   if failed to insert into table, returns -1 */
686
++static ngx_int_t
687
++ngx_http_v2_table_encode_strings(ngx_http_v2_connection_t *h2c,
688
++    size_t key_len, size_t val_len, uint8_t *key, uint8_t *val,
689
++    ngx_int_t *header_idx)
690
++{
691
++    uint64_t  hash_val, key_hash, idx, lru;
692
++    int       i;
693
++    size_t    size = key_len + val_len + 32;
694
++    uint8_t  *storage = h2c->hpack_enc.storage;
695
++
696
++    ngx_http_v2_hpack_enc_entry_t   *table;
697
++    ngx_http_v2_hpack_name_entry_t  *name;
698
++
699
++    *header_idx = NGX_ERROR;
700
++    /* step 1: compute the hash value of header */
701
++    if (size > HPACK_ENC_MAX_ENTRY || size > h2c->max_hpack_table_size) {
702
++        return NGX_ERROR;
703
++    }
704
++
705
++    key_hash = ngx_murmur_hash2_64(key, key_len, 0x01234);
706
++    hash_val = ngx_murmur_hash2_64(val, val_len, key_hash);
707
++
708
++    if (hash_val == 0) {
709
++        return NGX_ERROR;
710
++    }
711
++
712
++    /* step 2: check if full header in the table */
713
++    idx = hash_val;
714
++    i = -1;
715
++    while (idx) {
716
++         /* at most 8 locations are checked, but most will be done in 1 or 2 */
717
++        table = &h2c->hpack_enc.htable[idx % HPACK_ENC_HTABLE_SZ];
718
++        if (table->hash_val == hash_val
719
++            && table->klen == key_len
720
++            && table->vlen == val_len
721
++            && ngx_memcmp(key, storage + table->pos, key_len) == 0
722
++            && ngx_memcmp(val, storage + table->pos + key_len, val_len) == 0)
723
++        {
724
++            return (h2c->hpack_enc.top - table->index) + 61;
725
++        }
726
++
727
++        if (table->hash_val == 0 && i == -1) {
728
++            i = idx % HPACK_ENC_HTABLE_SZ;
729
++            break;
730
++        }
731
++
732
++        idx >>= 8;
733
++    }
734
++
735
++    /* step 3: check if key is in one of the tables */
736
++    *header_idx = hpack_get_static_index(h2c, key, key_len);
737
++
738
++    if (i == -1) {
739
++        return NGX_ERROR;
740
++    }
741
++
742
++    if (*header_idx == NGX_ERROR) {
743
++        *header_idx = hpack_get_dynamic_index(h2c, key_hash, key, key_len);
744
++    }
745
++
746
++    /* step 4: store the new entry */
747
++    table =  h2c->hpack_enc.htable;
748
++
749
++    if (h2c->hpack_enc.top == 0xffffffff) {
750
++        /* just to be on the safe side, avoid overflow */
751
++        ngx_memset(&h2c->hpack_enc, 0, sizeof(ngx_http_v2_hpack_enc_t));
752
++    }
753
++
754
++    while ((h2c->hpack_enc.size + size > h2c->max_hpack_table_size)
755
++           || h2c->hpack_enc.n_elems == HPACK_ENC_HTABLE_ENTRIES) {
756
++        /* make space for the new entry first */
757
++        idx = h2c->hpack_enc.base;
758
++        h2c->hpack_enc.base = table[idx].next;
759
++        h2c->hpack_enc.size -= table[idx].size;
760
++        table[idx].hash_val = 0;
761
++        h2c->hpack_enc.n_elems--;
762
++    }
763
++
764
++    table[i] = (ngx_http_v2_hpack_enc_entry_t){.hash_val = hash_val,
765
++                                               .index = h2c->hpack_enc.top,
766
++                                               .pos = h2c->hpack_enc.pos,
767
++                                               .klen = key_len,
768
++                                               .vlen = val_len,
769
++                                               .size = size,
770
++                                               .next = 0};
771
++
772
++    table[h2c->hpack_enc.last].next = i;
773
++    if (h2c->hpack_enc.n_elems == 0) {
774
++        h2c->hpack_enc.base = i;
775
++    }
776
++
777
++    h2c->hpack_enc.last = i;
778
++    h2c->hpack_enc.top++;
779
++    h2c->hpack_enc.size += size;
780
++    h2c->hpack_enc.n_elems++;
781
++
782
++    /* update header name lookup */
783
++    if (*header_idx == NGX_ERROR ) {
784
++        lru = h2c->hpack_enc.top;
785
++
786
++        for (i=0; i<HPACK_ENC_DYNAMIC_KEY_TBL_SZ; i++) {
787
++
788
++            name = &h2c->hpack_enc.heads[i];
789
++
790
++            if ( name->hash_val == 0 || (name->hash_val == key_hash
791
++                && ngx_memcmp(storage + name->pos, key, key_len) == 0) )
792
++            {
793
++                name->hash_val = key_hash;
794
++                name->pos = h2c->hpack_enc.pos;
795
++                name->index = h2c->hpack_enc.top - 1;
796
++                break;
797
++            }
798
++
799
++            if (lru > name->index) {
800
++                lru = name->index;
801
++                idx = i;
802
++            }
803
++        }
804
++
805
++        if (i == HPACK_ENC_DYNAMIC_KEY_TBL_SZ) {
806
++            name = &h2c->hpack_enc.heads[idx];
807
++            name->hash_val = hash_val;
808
++            name->pos = h2c->hpack_enc.pos;
809
++            name->index = h2c->hpack_enc.top - 1;
810
++        }
811
++    }
812
++
813
++    ngx_memcpy(storage + h2c->hpack_enc.pos, key, key_len);
814
++    ngx_memcpy(storage + h2c->hpack_enc.pos + key_len, val, val_len);
815
++
816
++    h2c->hpack_enc.pos += size;
817
++    if (h2c->hpack_enc.pos > NGX_HTTP_V2_MAX_HPACK_TABLE_SIZE) {
818
++        h2c->hpack_enc.pos = 0;
819
++    }
820
++
821
++    return NGX_OK;
822
++}
823
++
824
++
825
++u_char *
826
++ngx_http_v2_write_header(ngx_http_v2_connection_t *h2c, u_char *pos,
827
++                         u_char *key, size_t key_len,
828
++                         u_char *value, size_t value_len,
829
++                         u_char *tmp)
830
++{
831
++    ngx_int_t idx, header_idx;
832
++
833
++    ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
834
++                   "http2 output header: %*s: %*s", key_len, key, value_len,
835
++                   value);
836
++
837
++    /* attempt to find the value in the dynamic table */
838
++    idx = ngx_http_v2_table_encode_strings(h2c, key_len, value_len, key, value,
839
++                                           &header_idx);
840
++
841
++    if (idx > 0) {
842
++        /* positive index indicates success */
843
++        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
844
++                       "http2 hpack encode: Indexed Header Field: %ud", idx);
845
++
846
++        *pos = 128;
847
++        pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(7), idx);
848
++
849
++    } else {
850
++
851
++        if (header_idx == NGX_ERROR) { /* if key is not present */
852
++
853
++            if (idx == NGX_ERROR) {    /* if header was not added */
854
++                *pos++ = 0;
855
++
856
++                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
857
++                              "http2 hpack encode: Literal Header Field without"
858
++                              " Indexing — New Name");
859
++            } else {                   /* if header was added */
860
++                *pos++ = 64;
861
++
862
++                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
863
++                              "http2 hpack encode: Literal Header Field with "
864
++                              "Incremental Indexing — New Name");
865
++            }
866
++
867
++            pos = ngx_http_v2_write_name(pos, key, key_len, tmp);
868
++
869
++        } else {                       /* if key is present */
870
++
871
++            if (idx == NGX_ERROR) {
872
++                *pos = 0;
873
++                pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(4), header_idx);
874
++
875
++                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
876
++                              "http2 hpack encode: Literal Header Field without"
877
++                              " Indexing — Indexed Name: %ud", header_idx);
878
++            } else {
879
++                *pos = 64;
880
++                pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(6), header_idx);
881
++
882
++                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
883
++                              "http2 hpack encode: Literal Header Field with "
884
++                              "Incremental Indexing — Indexed Name: %ud", header_idx);
885
++            }
886
++        }
887
++
888
++        pos = ngx_http_v2_write_value(pos, value, value_len, tmp);
889
++    }
890
++
891
++    return pos;
892
++}
893
++
894
++
895
++static ngx_int_t
896
++hpack_get_dynamic_index(ngx_http_v2_connection_t *h2c, uint64_t key_hash,
897
++                        uint8_t *key, size_t key_len)
898
++{
899
++    ngx_http_v2_hpack_name_entry_t  *name;
900
++    int                              i;
901
++
902
++    for (i=0; i<HPACK_ENC_DYNAMIC_KEY_TBL_SZ; i++) {
903
++        name = &h2c->hpack_enc.heads[i];
904
++
905
++        if (name->hash_val == key_hash
906
++            && ngx_memcmp(h2c->hpack_enc.storage + name->pos, key, key_len) == 0)
907
++        {
908
++            if (name->index >= h2c->hpack_enc.top - h2c->hpack_enc.n_elems) {
909
++                return (h2c->hpack_enc.top - name->index) + 61;
910
++            }
911
++            break;
912
++        }
913
++    }
914
++
915
++    return NGX_ERROR;
916
++}
917
++
918
++
919
++/* decide if a given header is present in the static dictionary, this could be
920
++   done in several ways, but it seems the fastest one is "exhaustive" search */
921
++static ngx_int_t
922
++hpack_get_static_index(ngx_http_v2_connection_t *h2c, u_char *val, size_t len)
923
++{
924
++    /* the static dictionary of response only headers,
925
++       although response headers can be put by origin,
926
++       that would be rare */
927
++    static const struct {
928
++        u_char         len;
929
++        const u_char   val[28];
930
++        u_char         idx;
931
++    } server_headers[] = {
932
++        { 3, "age",                         21},//0
933
++        { 3, "via",                         60},
934
++        { 4, "date",                        33},//2
935
++        { 4, "etag",                        34},
936
++        { 4, "link",                        45},
937
++        { 4, "vary",                        59},
938
++        { 5, "allow",                       22},//6
939
++        { 6, "server",                      54},//7
940
++        { 7, "expires",                     36},//8
941
++        { 7, "refresh",                     52},
942
++        { 8, "location",                    46},//10
943
++        {10, "set-cookie",                  55},//11
944
++        {11, "retry-after",                 53},//12
945
++        {12, "content-type",                31},//13
946
++        {13, "content-range",               30},//14
947
++        {13, "accept-ranges",               18},
948
++        {13, "cache-control",               24},
949
++        {13, "last-modified",               44},
950
++        {14, "content-length",              28},//18
951
++        {16, "content-encoding",            26},//19
952
++        {16, "content-language",            27},
953
++        {16, "content-location",            29},
954
++        {16, "www-authenticate",            61},
955
++        {17, "transfer-encoding",           57},//23
956
++        {18, "proxy-authenticate",          48},//24
957
++        {19, "content-disposition",         25},//25
958
++        {25, "strict-transport-security",   56},//26
959
++        {27, "access-control-allow-origin", 20},//27
960
++        {99, "",                            99},
961
++    }, *header;
962
++
963
++    /* for a given length, where to start the search
964
++       since minimal length is 3, the table has a -3
965
++       offset */
966
++    static const int8_t start_at[] = {
967
++        [3-3]  = 0,
968
++        [4-3]  = 2,
969
++        [5-3]  = 6,
970
++        [6-3]  = 7,
971
++        [7-3]  = 8,
972
++        [8-3]  = 10,
973
++        [9-3]  = -1,
974
++        [10-3] = 11,
975
++        [11-3] = 12,
976
++        [12-3] = 13,
977
++        [13-3] = 14,
978
++        [14-3] = 18,
979
++        [15-3] = -1,
980
++        [16-3] = 19,
981
++        [17-3] = 23,
982
++        [18-3] = 24,
983
++        [19-3] = 25,
984
++        [20-3] = -1,
985
++        [21-3] = -1,
986
++        [22-3] = -1,
987
++        [23-3] = -1,
988
++        [24-3] = -1,
989
++        [25-3] = 26,
990
++        [26-3] = -1,
991
++        [27-3] = 27,
992
++    };
993
++
994
++    uint64_t pref;
995
++    size_t   save_len = len, i;
996
++    int8_t   start;
997
++
998
++    /* early exit for out of bounds lengths */
999
++    if (len < 3 || len > 27) {
1000
++        return NGX_ERROR;
1001
++    }
1002
++
1003
++    start = start_at[len - 3];
1004
++    if (start == -1) {
1005
++        /* exit for non existent lengths */
1006
++        return NGX_ERROR;
1007
++    }
1008
++
1009
++    header = &server_headers[start_at[len - 3]];
1010
++
1011
++    /* load first 8 bytes of key, for fast comparison */
1012
++    if (len < 8) {
1013
++        pref = 0;
1014
++        if (len >= 4) {
1015
++            pref = *(uint32_t *)(val + len - 4) | 0x20202020;
1016
++            len -= 4;
1017
++        }
1018
++        while (len > 0) { /* 3 iterations at most */
1019
++            pref = (pref << 8) ^ (val[len - 1] | 0x20);
1020
++            len--;
1021
++        }
1022
++    } else {
1023
++        pref = *(uint64_t *)val | 0x2020202020202020;
1024
++        len -= 8;
1025
++    }
1026
++
1027
++    /* iterate over headers with the right length */
1028
++    while (header->len == save_len) {
1029
++        /* quickly compare the first 8 bytes, most tests will end here */
1030
++        if (pref != *(uint64_t *) header->val) {
1031
++            header++;
1032
++            continue;
1033
++        }
1034
++
1035
++        if (len == 0) {
1036
++            /* len == 0, indicates prefix held the entire key */
1037
++            return header->idx;
1038
++        }
1039
++        /* for longer keys compare the rest */
1040
++        i = 1 + (save_len + 7) % 8; /* align so we can compare in quadwords */
1041
++
1042
++        while (i + 8 <= save_len) { /* 3 iterations at most */
1043
++            if ( *(uint64_t *)&header->val[i]
1044
++                 != (*(uint64_t *) &val[i]| 0x2020202020202020) )
1045
++            {
1046
++                header++;
1047
++                i = 0;
1048
++                break;
1049
++            }
1050
++            i += 8;
1051
++        }
1052
++
1053
++        if (i == 0) {
1054
++            continue;
1055
++        }
1056
++
1057
++        /* found the corresponding entry in the static dictionary */
1058
++        return header->idx;
1059
++    }
1060
++
1061
++    return NGX_ERROR;
1062
++}
1063
++
1064
++#else
1065
++
1066
++u_char *
1067
++ngx_http_v2_write_header(ngx_http_v2_connection_t *h2c, u_char *pos,
1068
++                         u_char *key, size_t key_len,
1069
++                         u_char *value, size_t value_len,
1070
++                         u_char *tmp)
1071
++{
1072
++    ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1073
++                   "http2 output header: %*s: %*s", key_len, key, value_len,
1074
++                   value);
1075
++
1076
++    *pos++ = 64;
1077
++    pos = ngx_http_v2_write_name(pos, key, key_len, tmp);
1078
++    pos = ngx_http_v2_write_value(pos, value, value_len, tmp);
1079
++
1080
++    return pos;
1081
++}
1082
++
1083
++#endif

Loading…
Cancel
Save