comparison src/http/v2/ngx_http_v2.c @ 7207:3d2b0b02bd3d

HTTP/2: push additional request headers (closes #1478). The Accept-Encoding, Accept-Language, and User-Agent header fields are now copied from the original request to pushed requests.
author Ruslan Ermilov <ru@nginx.com>
date Thu, 15 Feb 2018 17:51:32 +0300
parents e44c297a6b95
children affeb6ef732c
comparison
equal deleted inserted replaced
7206:33edea74bd58 7207:3d2b0b02bd3d
7 7
8 #include <ngx_config.h> 8 #include <ngx_config.h>
9 #include <ngx_core.h> 9 #include <ngx_core.h>
10 #include <ngx_http.h> 10 #include <ngx_http.h>
11 #include <ngx_http_v2_module.h> 11 #include <ngx_http_v2_module.h>
12
13
14 typedef struct {
15 ngx_str_t name;
16 ngx_uint_t offset;
17 ngx_uint_t hash;
18 ngx_http_header_t *hh;
19 } ngx_http_v2_parse_header_t;
12 20
13 21
14 /* errors */ 22 /* errors */
15 #define NGX_HTTP_V2_NO_ERROR 0x0 23 #define NGX_HTTP_V2_NO_ERROR 0x0
16 #define NGX_HTTP_V2_PROTOCOL_ERROR 0x1 24 #define NGX_HTTP_V2_PROTOCOL_ERROR 0x1
154 ngx_str_t *value); 162 ngx_str_t *value);
155 static ngx_int_t ngx_http_v2_parse_scheme(ngx_http_request_t *r, 163 static ngx_int_t ngx_http_v2_parse_scheme(ngx_http_request_t *r,
156 ngx_str_t *value); 164 ngx_str_t *value);
157 static ngx_int_t ngx_http_v2_parse_authority(ngx_http_request_t *r, 165 static ngx_int_t ngx_http_v2_parse_authority(ngx_http_request_t *r,
158 ngx_str_t *value); 166 ngx_str_t *value);
167 static ngx_int_t ngx_http_v2_parse_header(ngx_http_request_t *r,
168 ngx_http_v2_parse_header_t *header, ngx_str_t *value);
159 static ngx_int_t ngx_http_v2_construct_request_line(ngx_http_request_t *r); 169 static ngx_int_t ngx_http_v2_construct_request_line(ngx_http_request_t *r);
160 static ngx_int_t ngx_http_v2_cookie(ngx_http_request_t *r, 170 static ngx_int_t ngx_http_v2_cookie(ngx_http_request_t *r,
161 ngx_http_v2_header_t *header); 171 ngx_http_v2_header_t *header);
162 static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r); 172 static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r);
163 static void ngx_http_v2_run_request(ngx_http_request_t *r); 173 static void ngx_http_v2_run_request(ngx_http_request_t *r);
199 209
200 #define NGX_HTTP_V2_FRAME_STATES \ 210 #define NGX_HTTP_V2_FRAME_STATES \
201 (sizeof(ngx_http_v2_frame_states) / sizeof(ngx_http_v2_handler_pt)) 211 (sizeof(ngx_http_v2_frame_states) / sizeof(ngx_http_v2_handler_pt))
202 212
203 213
214 static ngx_http_v2_parse_header_t ngx_http_v2_parse_headers[] = {
215 { ngx_string("host"),
216 offsetof(ngx_http_headers_in_t, host), 0, NULL },
217
218 { ngx_string("accept-encoding"),
219 offsetof(ngx_http_headers_in_t, accept_encoding), 0, NULL },
220
221 { ngx_string("accept-language"),
222 offsetof(ngx_http_headers_in_t, accept_language), 0, NULL },
223
224 { ngx_string("user-agent"),
225 offsetof(ngx_http_headers_in_t, user_agent), 0, NULL },
226
227 { ngx_null_string, 0, 0, NULL }
228 };
229
230
204 void 231 void
205 ngx_http_v2_init(ngx_event_t *rev) 232 ngx_http_v2_init(ngx_event_t *rev)
206 { 233 {
207 ngx_connection_t *c; 234 ngx_connection_t *c;
208 ngx_pool_cleanup_t *cln; 235 ngx_pool_cleanup_t *cln;
2512 2539
2513 return NGX_AGAIN; 2540 return NGX_AGAIN;
2514 } 2541 }
2515 2542
2516 2543
2517 ngx_int_t 2544 ngx_http_v2_stream_t *
2518 ngx_http_v2_push_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t depend, 2545 ngx_http_v2_push_stream(ngx_http_v2_stream_t *parent, ngx_str_t *path)
2519 size_t request_length, ngx_str_t *path, ngx_str_t *authority) 2546 {
2520 { 2547 ngx_int_t rc;
2521 ngx_int_t rc; 2548 ngx_str_t value;
2522 ngx_str_t value; 2549 ngx_table_elt_t **h;
2523 ngx_connection_t *fc; 2550 ngx_connection_t *fc;
2524 ngx_http_request_t *r; 2551 ngx_http_request_t *r;
2525 ngx_http_v2_node_t *node; 2552 ngx_http_v2_node_t *node;
2526 ngx_http_v2_stream_t *stream; 2553 ngx_http_v2_stream_t *stream;
2554 ngx_http_v2_connection_t *h2c;
2555 ngx_http_v2_parse_header_t *header;
2556
2557 h2c = parent->connection;
2527 2558
2528 node = ngx_http_v2_get_node_by_id(h2c, h2c->last_push, 1); 2559 node = ngx_http_v2_get_node_by_id(h2c, h2c->last_push, 1);
2529 2560
2530 if (node == NULL) { 2561 if (node == NULL) {
2531 return NGX_ERROR; 2562 return NULL;
2532 } 2563 }
2533 2564
2534 if (node->parent) { 2565 if (node->parent) {
2535 ngx_queue_remove(&node->reuse); 2566 ngx_queue_remove(&node->reuse);
2536 h2c->closed_nodes--; 2567 h2c->closed_nodes--;
2537 } 2568 }
2538 2569
2539 stream = ngx_http_v2_create_stream(h2c, 1); 2570 stream = ngx_http_v2_create_stream(h2c, 1);
2540 if (stream == NULL) { 2571 if (stream == NULL) {
2541 return NGX_ERROR; 2572 return NULL;
2542 } 2573 }
2543 2574
2544 stream->pool = ngx_create_pool(1024, h2c->connection->log); 2575 stream->pool = ngx_create_pool(1024, h2c->connection->log);
2545 if (stream->pool == NULL) { 2576 if (stream->pool == NULL) {
2546 return NGX_ERROR; 2577 return NULL;
2547 } 2578 }
2548 2579
2549 r = stream->request; 2580 r = stream->request;
2550 fc = r->connection; 2581 fc = r->connection;
2551
2552 r->request_length = request_length;
2553 2582
2554 stream->in_closed = 1; 2583 stream->in_closed = 1;
2555 stream->node = node; 2584 stream->node = node;
2556 2585
2557 node->stream = stream; 2586 node->stream = stream;
2558 2587
2559 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, 2588 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2560 "http2 push stream sid:%ui " 2589 "http2 push stream sid:%ui "
2561 "depends on %ui excl:0 weight:16", 2590 "depends on %ui excl:0 weight:16",
2562 h2c->last_push, depend); 2591 h2c->last_push, parent->node->id);
2563 2592
2564 node->weight = NGX_HTTP_V2_DEFAULT_WEIGHT; 2593 node->weight = NGX_HTTP_V2_DEFAULT_WEIGHT;
2565 ngx_http_v2_set_dependency(h2c, node, depend, 0); 2594 ngx_http_v2_set_dependency(h2c, node, parent->node->id, 0);
2566 2595
2567 r->method_name = ngx_http_core_get_method; 2596 r->method_name = ngx_http_core_get_method;
2568 r->method = NGX_HTTP_GET; 2597 r->method = NGX_HTTP_GET;
2569 2598
2570 r->schema_start = (u_char *) "https"; 2599 r->schema_start = (u_char *) "https";
2577 #endif 2606 #endif
2578 { 2607 {
2579 r->schema_end = r->schema_start + 4; 2608 r->schema_end = r->schema_start + 4;
2580 } 2609 }
2581 2610
2582 value.len = authority->len; 2611 value.data = ngx_pstrdup(stream->pool, path);
2583
2584 value.data = ngx_pstrdup(stream->pool, authority);
2585 if (value.data == NULL) { 2612 if (value.data == NULL) {
2586 return NGX_ERROR; 2613 return NULL;
2587 } 2614 }
2588 2615
2589 rc = ngx_http_v2_parse_authority(r, &value); 2616 value.len = path->len;
2617
2618 rc = ngx_http_v2_parse_path(r, &value);
2590 2619
2591 if (rc != NGX_OK) { 2620 if (rc != NGX_OK) {
2592 goto error; 2621 goto error;
2593 } 2622 }
2594 2623
2595 value.len = path->len; 2624 for (header = ngx_http_v2_parse_headers; header->name.len; header++) {
2596 2625 h = (ngx_table_elt_t **)
2597 value.data = ngx_pstrdup(stream->pool, path); 2626 ((char *) &parent->request->headers_in + header->offset);
2598 if (value.data == NULL) { 2627
2599 return NGX_ERROR; 2628 if (*h == NULL) {
2600 } 2629 continue;
2601 2630 }
2602 rc = ngx_http_v2_parse_path(r, &value); 2631
2603 2632 value.len = (*h)->value.len;
2604 if (rc != NGX_OK) { 2633
2605 goto error; 2634 value.data = ngx_pnalloc(stream->pool, value.len + 1);
2635 if (value.data == NULL) {
2636 return NULL;
2637 }
2638
2639 ngx_memcpy(value.data, (*h)->value.data, value.len);
2640 value.data[value.len] = '\0';
2641
2642 rc = ngx_http_v2_parse_header(r, header, &value);
2643
2644 if (rc != NGX_OK) {
2645 goto error;
2646 }
2606 } 2647 }
2607 2648
2608 fc->write->handler = ngx_http_v2_run_request_handler; 2649 fc->write->handler = ngx_http_v2_run_request_handler;
2609 ngx_post_event(fc->write, &ngx_posted_events); 2650 ngx_post_event(fc->write, &ngx_posted_events);
2610 2651
2611 return NGX_OK; 2652 return stream;
2612 2653
2613 error: 2654 error:
2614 2655
2615 if (rc == NGX_ABORT) { 2656 if (rc == NGX_ABORT) {
2616 return NGX_ERROR; 2657 /* header handler has already finalized request */
2658 return NULL;
2617 } 2659 }
2618 2660
2619 if (rc == NGX_DECLINED) { 2661 if (rc == NGX_DECLINED) {
2620 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); 2662 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
2621 return NGX_ERROR; 2663 return NULL;
2622 } 2664 }
2623 2665
2624 (void) ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); 2666 (void) ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
2625 2667
2626 return NGX_ERROR; 2668 return NULL;
2627 } 2669 }
2628 2670
2629 2671
2630 static ngx_int_t 2672 static ngx_int_t
2631 ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c) 2673 ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c)
3434 3476
3435 3477
3436 static ngx_int_t 3478 static ngx_int_t
3437 ngx_http_v2_parse_authority(ngx_http_request_t *r, ngx_str_t *value) 3479 ngx_http_v2_parse_authority(ngx_http_request_t *r, ngx_str_t *value)
3438 { 3480 {
3481 return ngx_http_v2_parse_header(r, &ngx_http_v2_parse_headers[0], value);
3482 }
3483
3484
3485 static ngx_int_t
3486 ngx_http_v2_parse_header(ngx_http_request_t *r,
3487 ngx_http_v2_parse_header_t *header, ngx_str_t *value)
3488 {
3439 ngx_table_elt_t *h; 3489 ngx_table_elt_t *h;
3440 ngx_http_header_t *hh;
3441 ngx_http_core_main_conf_t *cmcf; 3490 ngx_http_core_main_conf_t *cmcf;
3442
3443 static ngx_str_t host = ngx_string("host");
3444 3491
3445 h = ngx_list_push(&r->headers_in.headers); 3492 h = ngx_list_push(&r->headers_in.headers);
3446 if (h == NULL) { 3493 if (h == NULL) {
3447 return NGX_ERROR; 3494 return NGX_ERROR;
3448 } 3495 }
3449 3496
3450 h->hash = ngx_hash_key(host.data, host.len); 3497 h->key.len = header->name.len;
3451 3498 h->key.data = header->name.data;
3452 h->key.len = host.len; 3499 h->lowcase_key = header->name.data;
3453 h->key.data = host.data; 3500
3501 if (header->hh == NULL) {
3502 header->hash = ngx_hash_key(header->name.data, header->name.len);
3503
3504 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
3505
3506 header->hh = ngx_hash_find(&cmcf->headers_in_hash, header->hash,
3507 h->lowcase_key, h->key.len);
3508 if (header->hh == NULL) {
3509 return NGX_ERROR;
3510 }
3511 }
3512
3513 h->hash = header->hash;
3454 3514
3455 h->value.len = value->len; 3515 h->value.len = value->len;
3456 h->value.data = value->data; 3516 h->value.data = value->data;
3457 3517
3458 h->lowcase_key = host.data; 3518 if (header->hh->handler(r, h, header->hh->offset) != NGX_OK) {
3459 3519 /* header handler has already finalized request */
3460 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
3461
3462 hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
3463 h->lowcase_key, h->key.len);
3464
3465 if (hh == NULL) {
3466 return NGX_ERROR;
3467 }
3468
3469 if (hh->handler(r, h, hh->offset) != NGX_OK) {
3470 /*
3471 * request has been finalized already
3472 * in ngx_http_process_host()
3473 */
3474 return NGX_ABORT; 3520 return NGX_ABORT;
3475 } 3521 }
3476 3522
3477 return NGX_OK; 3523 return NGX_OK;
3478 } 3524 }