Mercurial > hg > nginx
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 } |