mirror of
https://github.com/nginx/nginx.git
synced 2026-10-21 11:31:24 +00:00
HTTP/2: parse Priority request header
Parse the RFC 9218 Priority request header, an RFC 8941 Structured Fields Dictionary such as "u=3, i". The header lines are collected during header block processing and, once the block is complete, combined into a single value and parsed once in ngx_http_v2_run_request(), as RFC 8941, Section 4.2, requires all field lines of the same field to be combined before parsing. This mirrors how cookies are handled. The header is still passed through to the request so it stays visible to variables and proxying. A malformed field is ignored, leaving the defaults. A PRIORITY_UPDATE frame overrides the header (RFC 9218, Section 7): if a frame has already been applied to the stream the header is not consulted. Assisted-by: opencode:claude-opus-4.8
This commit is contained in:
parent
2b6c2de41d
commit
4d147459db
2 changed files with 126 additions and 0 deletions
|
|
@ -160,6 +160,9 @@ static ngx_int_t ngx_http_v2_construct_request_line(ngx_http_request_t *r);
|
|||
static ngx_int_t ngx_http_v2_cookie(ngx_http_request_t *r,
|
||||
ngx_http_v2_header_t *header);
|
||||
static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r);
|
||||
static ngx_int_t ngx_http_v2_priority(ngx_http_request_t *r,
|
||||
ngx_http_v2_header_t *header);
|
||||
static ngx_int_t ngx_http_v2_process_priority(ngx_http_request_t *r);
|
||||
static ngx_int_t ngx_http_v2_construct_host_header(ngx_http_request_t *r);
|
||||
static void ngx_http_v2_run_request(ngx_http_request_t *r);
|
||||
static ngx_int_t ngx_http_v2_process_request_body(ngx_http_request_t *r,
|
||||
|
|
@ -1354,6 +1357,7 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos,
|
|||
if (node->priority_set) {
|
||||
stream->priority.client = node->priority;
|
||||
node->priority_set = 0;
|
||||
stream->priority_update = 1;
|
||||
|
||||
ngx_http_priority_state_update(&stream->priority);
|
||||
|
||||
|
|
@ -1741,6 +1745,7 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos,
|
|||
ngx_http_core_main_conf_t *cmcf;
|
||||
|
||||
static ngx_str_t cookie = ngx_string("cookie");
|
||||
static ngx_str_t priority = ngx_string("priority");
|
||||
|
||||
header = &h2c->state.header;
|
||||
|
||||
|
|
@ -1839,6 +1844,15 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos,
|
|||
}
|
||||
}
|
||||
|
||||
if (header->name.len == priority.len
|
||||
&& ngx_memcmp(header->name.data, priority.data, priority.len) == 0)
|
||||
{
|
||||
if (ngx_http_v2_priority(r, header) != NGX_OK) {
|
||||
return ngx_http_v2_connection_error(h2c,
|
||||
NGX_HTTP_V2_INTERNAL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
if (header->name.len == cookie.len
|
||||
&& ngx_memcmp(header->name.data, cookie.data, cookie.len) == 0)
|
||||
{
|
||||
|
|
@ -2201,6 +2215,7 @@ ngx_http_v2_state_priority_update(ngx_http_v2_connection_t *h2c, u_char *pos,
|
|||
} else if (node && node->stream) {
|
||||
stream = node->stream;
|
||||
stream->priority.client = priority;
|
||||
stream->priority_update = 1;
|
||||
ngx_http_priority_state_update(&stream->priority);
|
||||
}
|
||||
|
||||
|
|
@ -3904,6 +3919,111 @@ ngx_http_v2_construct_cookie_header(ngx_http_request_t *r)
|
|||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_v2_priority(ngx_http_request_t *r, ngx_http_v2_header_t *header)
|
||||
{
|
||||
ngx_str_t *val;
|
||||
ngx_array_t *priorities;
|
||||
|
||||
priorities = r->stream->priorities;
|
||||
|
||||
if (priorities == NULL) {
|
||||
priorities = ngx_array_create(r->pool, 1, sizeof(ngx_str_t));
|
||||
if (priorities == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
r->stream->priorities = priorities;
|
||||
}
|
||||
|
||||
val = ngx_array_push(priorities);
|
||||
if (val == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
val->len = header->value.len;
|
||||
val->data = header->value.data;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_v2_process_priority(ngx_http_request_t *r)
|
||||
{
|
||||
u_char *p;
|
||||
size_t len;
|
||||
ngx_str_t value, *vals;
|
||||
ngx_uint_t i;
|
||||
ngx_array_t *priorities;
|
||||
ngx_http_priority_t priority;
|
||||
|
||||
priorities = r->stream->priorities;
|
||||
|
||||
if (priorities == NULL) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* RFC 9218, Section 7: a PRIORITY_UPDATE frame overrides the Priority
|
||||
* header field, so ignore the header once a frame has been applied.
|
||||
*/
|
||||
|
||||
if (r->stream->priority_update) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
vals = priorities->elts;
|
||||
|
||||
if (priorities->nelts == 1) {
|
||||
value = vals[0];
|
||||
|
||||
} else {
|
||||
|
||||
/* combine the field lines into a single value, "v1, v2, ..." */
|
||||
|
||||
len = 0;
|
||||
|
||||
for (i = 0; i < priorities->nelts; i++) {
|
||||
len += vals[i].len + 2;
|
||||
}
|
||||
|
||||
len -= 2;
|
||||
|
||||
p = ngx_pnalloc(r->pool, len);
|
||||
if (p == NULL) {
|
||||
ngx_http_v2_close_stream(r->stream,
|
||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
value.data = p;
|
||||
value.len = len;
|
||||
|
||||
for (i = 0; /* void */ ; i++) {
|
||||
p = ngx_cpymem(p, vals[i].data, vals[i].len);
|
||||
|
||||
if (i == priorities->nelts - 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
*p++ = ','; *p++ = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
if (ngx_http_priority_parse(&value, &priority) != NGX_OK) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"http2 ignoring malformed priority header");
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
r->stream->priority.client = priority;
|
||||
ngx_http_priority_state_update(&r->stream->priority);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_v2_construct_host_header(ngx_http_request_t *r)
|
||||
{
|
||||
|
|
@ -3980,6 +4100,10 @@ ngx_http_v2_run_request(ngx_http_request_t *r)
|
|||
goto failed;
|
||||
}
|
||||
|
||||
if (ngx_http_v2_process_priority(r) != NGX_OK) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
|
||||
|
||||
if (r->headers_in.connection) {
|
||||
|
|
|
|||
|
|
@ -214,6 +214,7 @@ struct ngx_http_v2_stream_s {
|
|||
ngx_queue_t queue;
|
||||
|
||||
ngx_array_t *cookies;
|
||||
ngx_array_t *priorities;
|
||||
|
||||
ngx_http_priority_state_t priority;
|
||||
|
||||
|
|
@ -228,6 +229,7 @@ struct ngx_http_v2_stream_s {
|
|||
unsigned rst_sent:1;
|
||||
unsigned no_flow_control:1;
|
||||
unsigned skip_data:1;
|
||||
unsigned priority_update:1;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue