You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

nginx_hpack_remove_server_header_1.15.3.patch 40KB

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