Browse Source

Add HPACK & Remove nginx server header.

master
Hakase 6 months ago
parent
commit
58858c503b
2 changed files with 1194 additions and 0 deletions
  1. 1
    0
      README.md
  2. 1193
    0
      nginx_hpack_remove_server_header_1.15.3.patch

+ 1
- 0
README.md View File

@@ -69,6 +69,7 @@ Example of setting TLS 1.3 cipher in nginx (pre7 or higher):
69 69
 | nginx_hpack_push.patch | _Patch both_ the HPACK patch and the **PUSH ERROR**. |
70 70
 | nginx_hpack_push_fix.patch | _Patch only_ the **PUSH ERROR** of the hpack patch. (If the HPACK patch has already been completed) |
71 71
 | remove_nginx_server_header.patch | Remove nginx server header. (http2, http1.1) |
72
+| nginx_hpack_remove_server_header_1.15.3.patch | HPACK + Remove nginx server header. (http2, http1.1) |
72 73
 
73 74
 ## How To Use?
74 75
 

+ 1193
- 0
nginx_hpack_remove_server_header_1.15.3.patch View File

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

Loading…
Cancel
Save