comparison src/http/v3/ngx_http_v3_request.c @ 7699:1e45c02f6376 quic

HTTP/3 $request_line variable.
author Roman Arutyunyan <arut@nginx.com>
date Wed, 18 Mar 2020 20:22:16 +0300
parents 31f7c697b6d9
children a3257a725b3d
comparison
equal deleted inserted replaced
7698:253cf267f95a 7699:1e45c02f6376
38 38
39 39
40 ngx_int_t 40 ngx_int_t
41 ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b) 41 ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b)
42 { 42 {
43 size_t n;
44 u_char *p;
43 ngx_int_t rc; 45 ngx_int_t rc;
44 ngx_str_t *name, *value; 46 ngx_str_t *name, *value;
45 ngx_connection_t *c; 47 ngx_connection_t *c;
46 ngx_http_v3_parse_headers_t *st; 48 ngx_http_v3_parse_headers_t *st;
47 enum { 49 enum {
95 } 97 }
96 98
97 name = &st->header_rep.header.name; 99 name = &st->header_rep.header.name;
98 value = &st->header_rep.header.value; 100 value = &st->header_rep.header.value;
99 101
100 if (r->state == sw_start 102 if (r->state == sw_start) {
101 && ngx_http_v3_process_pseudo_header(r, name, value) != NGX_OK) 103
102 { 104 if (ngx_http_v3_process_pseudo_header(r, name, value) == NGX_OK) {
103 if (rc == NGX_DONE) { 105 if (rc == NGX_OK) {
106 continue;
107 }
108
109 r->state = sw_done;
110
111 } else if (rc == NGX_OK) {
112 r->state = sw_prev;
113
114 } else {
104 r->state = sw_last; 115 r->state = sw_last;
105 } else {
106 r->state = sw_prev;
107 } 116 }
117
118 n = (r->method_end - r->method_start) + 1
119 + (r->uri_end - r->uri_start) + 1
120 + sizeof("HTTP/3") - 1;
121
122 p = ngx_pnalloc(c->pool, n);
123 if (p == NULL) {
124 goto failed;
125 }
126
127 r->request_start = p;
128
129 p = ngx_cpymem(p, r->method_start, r->method_end - r->method_start);
130 *p++ = ' ';
131 p = ngx_cpymem(p, r->uri_start, r->uri_end - r->uri_start);
132 *p++ = ' ';
133 p = ngx_cpymem(p, "HTTP/3", sizeof("HTTP/3") - 1);
134
135 r->request_end = p;
108 136
109 } else if (rc == NGX_DONE) { 137 } else if (rc == NGX_DONE) {
110 r->state = sw_done; 138 r->state = sw_done;
111 }
112
113 if (r->state == sw_start) {
114 continue;
115 } 139 }
116 140
117 r->header_name_start = name->data; 141 r->header_name_start = name->data;
118 r->header_name_end = name->data + name->len; 142 r->header_name_end = name->data + name->len;
119 r->header_start = value->data; 143 r->header_start = value->data;
136 160
137 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header done"); 161 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header done");
138 162
139 return NGX_HTTP_PARSE_HEADER_DONE; 163 return NGX_HTTP_PARSE_HEADER_DONE;
140 } 164 }
141
142 #if 0
143 ngx_int_t
144 ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b, ngx_uint_t pseudo)
145 {
146 u_char *p, ch;
147 ngx_str_t name, value;
148 ngx_int_t rc;
149 ngx_uint_t length, index, insert_count, sign, base, delta_base,
150 huffman, dynamic, offset;
151 ngx_connection_t *c;
152 ngx_http_v3_header_t *h;
153 enum {
154 sw_start = 0,
155 sw_length,
156 sw_length_1,
157 sw_length_2,
158 sw_length_3,
159 sw_header_block,
160 sw_req_insert_count,
161 sw_delta_base,
162 sw_read_delta_base,
163 sw_header,
164 sw_old_header,
165 sw_header_ri,
166 sw_header_pbi,
167 sw_header_lri,
168 sw_header_lpbi,
169 sw_header_l_name_len,
170 sw_header_l_name,
171 sw_header_value_len,
172 sw_header_read_value_len,
173 sw_header_value
174 } state;
175
176 c = r->connection;
177
178 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
179 "http3 parse header, pseudo:%ui", pseudo);
180
181 if (r->state == sw_old_header) {
182 r->state = sw_header;
183 return NGX_OK;
184 }
185
186 length = r->h3_length;
187 index = r->h3_index;
188 insert_count = r->h3_insert_count;
189 sign = r->h3_sign;
190 delta_base = r->h3_delta_base;
191 huffman = r->h3_huffman;
192 dynamic = r->h3_dynamic;
193 offset = r->h3_offset;
194
195 name.data = r->header_name_start;
196 name.len = r->header_name_end - r->header_name_start;
197 value.data = r->header_start;
198 value.len = r->header_end - r->header_start;
199
200 if (r->state == sw_start) {
201 length = 1;
202 }
203
204 again:
205
206 state = r->state;
207
208 if (state == sw_header && length == 0) {
209 r->state = sw_start;
210 return NGX_HTTP_PARSE_HEADER_DONE;
211 }
212
213 for (p = b->pos; p < b->last; p++) {
214
215 if (state >= sw_header_block && length-- == 0) {
216 goto failed;
217 }
218
219 ch = *p;
220
221 switch (state) {
222
223 case sw_start:
224
225 if (ch != NGX_HTTP_V3_FRAME_HEADERS) {
226 goto failed;
227 }
228
229 r->request_start = p;
230 state = sw_length;
231 break;
232
233 case sw_length:
234
235 length = ch;
236 if (length & 0xc0) {
237 state = sw_length_1;
238 break;
239 }
240
241 state = sw_header_block;
242 break;
243
244 case sw_length_1:
245
246 length = (length << 8) + ch;
247 if ((length & 0xc000) != 0x4000) {
248 state = sw_length_2;
249 break;
250 }
251
252 length &= 0x3fff;
253 state = sw_header_block;
254 break;
255
256 case sw_length_2:
257
258 length = (length << 8) + ch;
259 if ((length & 0xc00000) != 0x800000) {
260 state = sw_length_3;
261 break;
262 }
263
264 length &= 0x3fffff;
265 state = sw_header_block;
266 break;
267
268 case sw_length_3:
269
270 length = (length << 8) + ch;
271 length &= 0x3fffffff;
272 state = sw_header_block;
273 break;
274
275 case sw_header_block:
276
277 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
278 "http3 header block length:%ui", length);
279
280 if (ch != 0xff) {
281 insert_count = ch;
282 state = sw_delta_base;
283 break;
284 }
285
286 insert_count = 0;
287 state = sw_req_insert_count;
288 break;
289
290 case sw_req_insert_count:
291
292 insert_count = (insert_count << 7) + (ch & 0x7f);
293 if (ch & 0x80) {
294 break;
295 }
296
297 insert_count += 0xff;
298 state = sw_delta_base;
299 break;
300
301 case sw_delta_base:
302
303 sign = (ch & 0x80) ? 1 : 0;
304 delta_base = ch & 0x7f;
305
306 if (delta_base != 0x7f) {
307 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
308 "http3 header block "
309 "insert_count:%ui, sign:%ui, delta_base:%ui",
310 insert_count, sign, delta_base);
311 goto done;
312 }
313
314 delta_base = 0;
315 state = sw_read_delta_base;
316 break;
317
318 case sw_read_delta_base:
319
320 delta_base = (delta_base << 7) + (ch & 0x7f);
321 if (ch & 0x80) {
322 break;
323 }
324
325 delta_base += 0x7f;
326
327 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
328 "http3 header block "
329 "insert_count:%ui, sign:%ui, delta_base:%ui",
330 insert_count, sign, delta_base);
331 goto done;
332
333 case sw_header:
334
335 index = 0;
336 huffman = 0;
337 ngx_str_null(&name);
338 ngx_str_null(&value);
339
340 if (ch & 0x80) {
341 /* Indexed Header Field */
342
343 dynamic = (ch & 0x40) ? 0 : 1;
344 index = ch & 0x3f;
345
346 if (index != 0x3f) {
347 goto done;
348 }
349
350 index = 0;
351 state = sw_header_ri;
352 break;
353 }
354
355 if (ch & 0x40) {
356 /* Literal Header Field With Name Reference */
357
358 dynamic = (ch & 0x10) ? 0 : 1;
359 index = ch & 0x0f;
360
361 if (index != 0x0f) {
362 state = sw_header_value_len;
363 break;
364 }
365
366 index = 0;
367 state = sw_header_lri;
368 break;
369 }
370
371 if (ch & 0x20) {
372 /* Literal Header Field Without Name Reference */
373
374 huffman = (ch & 0x08) ? 1 : 0;
375 name.len = ch & 0x07;
376
377 if (name.len == 0) {
378 goto failed;
379 }
380
381 if (name.len != 0x07) {
382 offset = 0;
383 state = sw_header_l_name;
384 break;
385 }
386
387 name.len = 0;
388 state = sw_header_l_name_len;
389 break;
390 }
391
392 if (ch & 10) {
393 /* Indexed Header Field With Post-Base Index */
394
395 dynamic = 2;
396 index = ch & 0x0f;
397
398 if (index != 0x0f) {
399 goto done;
400 }
401
402 index = 0;
403 state = sw_header_pbi;
404 break;
405 }
406
407 /* Literal Header Field With Post-Base Name Reference */
408
409 dynamic = 2;
410 index = ch & 0x07;
411
412 if (index != 0x07) {
413 state = sw_header_value_len;
414 break;
415 }
416
417 index = 0;
418 state = sw_header_lpbi;
419 break;
420
421 case sw_header_ri:
422
423 index = (index << 7) + (ch & 0x7f);
424 if (ch & 0x80) {
425 break;
426 }
427
428 index += 0x3f;
429 goto done;
430
431 case sw_header_pbi:
432
433 index = (index << 7) + (ch & 0x7f);
434 if (ch & 0x80) {
435 break;
436 }
437
438 index += 0x0f;
439 goto done;
440
441 case sw_header_lri:
442
443 index = (index << 7) + (ch & 0x7f);
444 if (ch & 0x80) {
445 break;
446 }
447
448 index += 0x0f;
449 state = sw_header_value_len;
450 break;
451
452 case sw_header_lpbi:
453
454 index = (index << 7) + (ch & 0x7f);
455 if (ch & 0x80) {
456 break;
457 }
458
459 index += 0x07;
460 state = sw_header_value_len;
461 break;
462
463
464 case sw_header_l_name_len:
465
466 name.len = (name.len << 7) + (ch & 0x7f);
467 if (ch & 0x80) {
468 break;
469 }
470
471 name.len += 0x07;
472 offset = 0;
473 state = sw_header_l_name;
474 break;
475
476 case sw_header_l_name:
477 if (offset++ == 0) {
478 name.data = p;
479 }
480
481 if (offset != name.len) {
482 break;
483 }
484
485 if (huffman) {
486 if (ngx_http_v3_decode_huffman(c, &name) != NGX_OK) {
487 goto failed;
488 }
489 }
490
491 state = sw_header_value_len;
492 break;
493
494 case sw_header_value_len:
495
496 huffman = (ch & 0x80) ? 1 : 0;
497 value.len = ch & 0x7f;
498
499 if (value.len == 0) {
500 value.data = p;
501 goto done;
502 }
503
504 if (value.len != 0x7f) {
505 offset = 0;
506 state = sw_header_value;
507 break;
508 }
509
510 value.len = 0;
511 state = sw_header_read_value_len;
512 break;
513
514 case sw_header_read_value_len:
515
516 value.len = (value.len << 7) + (ch & 0x7f);
517 if (ch & 0x80) {
518 break;
519 }
520
521 value.len += 0x7f;
522 offset = 0;
523 state = sw_header_value;
524 break;
525
526 case sw_header_value:
527
528 if (offset++ == 0) {
529 value.data = p;
530 }
531
532 if (offset != value.len) {
533 break;
534 }
535
536 if (huffman) {
537 if (ngx_http_v3_decode_huffman(c, &value) != NGX_OK) {
538 goto failed;
539 }
540 }
541
542 goto done;
543
544 case sw_old_header:
545
546 break;
547 }
548 }
549
550 b->pos = p;
551 r->state = state;
552 r->h3_length = length;
553 r->h3_index = index;
554 r->h3_insert_count = insert_count;
555 r->h3_sign = sign;
556 r->h3_delta_base = delta_base;
557 r->h3_huffman = huffman;
558 r->h3_dynamic = dynamic;
559 r->h3_offset = offset;
560
561 /* XXX fix large reallocations */
562 r->header_name_start = name.data;
563 r->header_name_end = name.data + name.len;
564 r->header_start = value.data;
565 r->header_end = value.data + value.len;
566
567 /* XXX r->lowcase_index = i; */
568
569 return NGX_AGAIN;
570
571 done:
572
573 b->pos = p + 1;
574 r->state = sw_header;
575 r->h3_length = length;
576 r->h3_insert_count = insert_count;
577 r->h3_sign = sign;
578 r->h3_delta_base = delta_base;
579
580 if (state < sw_header) {
581 if (ngx_http_v3_check_insert_count(c, insert_count) != NGX_OK) {
582 return NGX_DONE;
583 }
584
585 goto again;
586 }
587
588 if (sign == 0) {
589 base = insert_count + delta_base;
590 } else {
591 base = insert_count - delta_base - 1;
592 }
593
594 ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0,
595 "http3 header %s[%ui], base:%ui, \"%V\":\"%V\"",
596 dynamic ? "dynamic" : "static", index, base, &name, &value);
597
598 if (name.data == NULL) {
599
600 if (dynamic == 2) {
601 index = base - index - 1;
602 } else if (dynamic == 1) {
603 index += base;
604 }
605
606 h = ngx_http_v3_lookup_table(c, dynamic, index);
607 if (h == NULL) {
608 goto failed;
609 }
610
611 name = h->name;
612
613 if (value.data == NULL) {
614 value = h->value;
615 }
616 }
617
618 /* XXX ugly reallocation for the trailing '\0' */
619
620 p = ngx_pnalloc(c->pool, name.len + value.len + 2);
621 if (p == NULL) {
622 return NGX_ERROR;
623 }
624
625 ngx_memcpy(p, name.data, name.len);
626 name.data = p;
627 ngx_memcpy(p + name.len + 1, value.data, value.len);
628 value.data = p + name.len + 1;
629
630 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
631 "http3 header \"%V\":\"%V\"", &name, &value);
632
633 if (pseudo) {
634 rc = ngx_http_v3_process_pseudo_header(r, &name, &value);
635
636 if (rc == NGX_ERROR) {
637 goto failed;
638 }
639
640 if (rc == NGX_OK) {
641 r->request_end = p + 1;
642 goto again;
643 }
644
645 /* rc == NGX_DONE */
646
647 r->state = sw_old_header;
648 }
649
650 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
651 "http3 header left:%ui", length);
652
653 r->header_name_start = name.data;
654 r->header_name_end = name.data + name.len;
655 r->header_start = value.data;
656 r->header_end = value.data + value.len;
657 r->header_hash = ngx_hash_key(name.data, name.len); /* XXX */
658
659 /* XXX r->lowcase_index = i; */
660
661 return NGX_OK;
662
663 failed:
664
665 return NGX_HTTP_PARSE_INVALID_REQUEST;
666 }
667 #endif
668 165
669 166
670 static ngx_int_t 167 static ngx_int_t
671 ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name, 168 ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name,
672 ngx_str_t *value) 169 ngx_str_t *value)
673 { 170 {
674 ngx_uint_t i; 171 ngx_uint_t i;
675 ngx_connection_t *c; 172 ngx_connection_t *c;
676 173
677 if (name->len == 0 || name->data[0] != ':') { 174 if (name->len == 0 || name->data[0] != ':') {
678 return NGX_DECLINED; 175 return NGX_DONE;
679 } 176 }
680 177
681 c = r->connection; 178 c = r->connection;
682 179
683 if (name->len == 7 && ngx_strncmp(name->data, ":method", 7) == 0) { 180 if (name->len == 7 && ngx_strncmp(name->data, ":method", 7) == 0) {