This commit is contained in:
hongzhidao 2026-06-26 00:51:54 +00:00 committed by GitHub
commit dec44ac81e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 99 additions and 21 deletions

View file

@ -77,6 +77,7 @@ typedef struct {
ngx_str_t value;
u_char *field_end;
size_t header_limit;
size_t field_length;
size_t field_rest;
u_char field_state;
@ -978,6 +979,14 @@ ngx_http_proxy_v2_reinit_request(ngx_http_request_t *r)
}
ctx->state = 0;
ctx->frame_state = 0;
ctx->fragment_state = 0;
ctx->rest = 0;
ctx->stream_id = 0;
ctx->type = 0;
ctx->flags = 0;
ctx->padding = 0;
ctx->error = 0;
ctx->header_sent = 0;
ctx->output_closed = 0;
ctx->output_blocked = 0;
@ -1480,6 +1489,10 @@ ngx_http_proxy_v2_process_header(ngx_http_request_t *r)
return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
if (rc == NGX_HTTP_UPSTREAM_RETRY) {
return NGX_HTTP_UPSTREAM_RETRY;
}
if (rc == NGX_OK) {
continue;
}
@ -1961,7 +1974,9 @@ ngx_http_proxy_v2_process_control_frame(ngx_http_request_t *r,
if (ctx->stream_id < ctx->id) {
/* TODO: we can retry non-idempotent requests */
if (ctx->error == 0) {
return NGX_HTTP_UPSTREAM_RETRY;
}
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent goaway with error %ui",
@ -2250,6 +2265,10 @@ ngx_http_proxy_v2_process_frames(ngx_http_request_t *r,
return NGX_ERROR;
}
if (rc == NGX_HTTP_UPSTREAM_RETRY) {
return NGX_ERROR;
}
if (rc == NGX_OK) {
continue;
}
@ -2535,6 +2554,7 @@ ngx_http_proxy_v2_parse_header(ngx_http_request_t *r,
if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME) {
ctx->parsing_headers = 1;
ctx->fragment_state = 0;
ctx->header_limit = r->upstream->conf->buffer_size;
min = (ctx->flags & NGX_HTTP_V2_PADDED_FLAG ? 1 : 0)
+ (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG ? 5 : 0);
@ -2730,7 +2750,7 @@ ngx_http_proxy_v2_parse_fragment(ngx_http_request_t *r,
ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
{
u_char ch, *p, *last;
size_t size;
size_t len, size;
ngx_uint_t index, size_update;
enum {
sw_start = 0,
@ -3067,6 +3087,14 @@ ngx_http_proxy_v2_parse_fragment(ngx_http_request_t *r,
break;
case sw_name:
if (ctx->field_length > r->upstream->conf->buffer_size) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent too large http2 "
"header name length: %uz",
ctx->field_length);
return NGX_ERROR;
}
ctx->name.len = ctx->field_huffman ?
ctx->field_length * 8 / 5 : ctx->field_length;
@ -3176,6 +3204,14 @@ ngx_http_proxy_v2_parse_fragment(ngx_http_request_t *r,
break;
case sw_value:
if (ctx->field_length > r->upstream->conf->buffer_size) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent too large http2 "
"header value length: %uz",
ctx->field_length);
return NGX_ERROR;
}
ctx->value.len = ctx->field_huffman ?
ctx->field_length * 8 / 5 : ctx->field_length;
@ -3272,6 +3308,16 @@ ngx_http_proxy_v2_parse_fragment(ngx_http_request_t *r,
}
}
len = ctx->name.len + ctx->value.len;
if (len > ctx->header_limit) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent too large http2 header");
return NGX_ERROR;
}
ctx->header_limit -= len;
return NGX_OK;
}
@ -3695,7 +3741,7 @@ ngx_http_proxy_v2_parse_settings(ngx_http_request_t *r,
return NGX_ERROR;
}
if (ctx->free == NULL && ctx->settings++ > 1000) {
if (ctx->settings++ > 1000) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent too many settings frames");
return NGX_ERROR;
@ -3853,7 +3899,7 @@ ngx_http_proxy_v2_parse_ping(ngx_http_request_t *r,
return NGX_ERROR;
}
if (ctx->free == NULL && ctx->pings++ > 1000) {
if (ctx->pings++ > 1000) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent too many ping frames");
return NGX_ERROR;

View file

@ -2597,6 +2597,11 @@ done:
return;
}
if (rc == NGX_HTTP_UPSTREAM_RETRY) {
ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_RETRY);
return;
}
if (rc == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
@ -4598,7 +4603,8 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
}
if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_403
|| ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404)
|| ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404
|| ft_type == NGX_HTTP_UPSTREAM_FT_RETRY)
{
state = NGX_PEER_NEXT;
@ -4619,7 +4625,10 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
"upstream timed out");
}
if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) {
if (u->peer.cached
&& (ft_type == NGX_HTTP_UPSTREAM_FT_ERROR
|| ft_type == NGX_HTTP_UPSTREAM_FT_RETRY))
{
/* TODO: inform balancer instead */
u->peer.tries++;
}
@ -4670,14 +4679,16 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
timeout = u->conf->next_upstream_timeout;
if (u->request_sent
if (ft_type != NGX_HTTP_UPSTREAM_FT_RETRY
&& u->request_sent
&& (r->method & (NGX_HTTP_POST|NGX_HTTP_LOCK|NGX_HTTP_PATCH)))
{
ft_type |= NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT;
}
if (u->peer.tries == 0
|| ((u->conf->next_upstream & ft_type) != ft_type)
|| (ft_type != NGX_HTTP_UPSTREAM_FT_RETRY
&& ((u->conf->next_upstream & ft_type) != ft_type))
|| (u->request_sent && r->request_body_no_buffering)
|| (timeout && ngx_current_msec - u->peer.start_time >= timeout))
{

View file

@ -31,6 +31,7 @@
#define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK 0x00001000
#define NGX_HTTP_UPSTREAM_FT_MAX_WAITING 0x00002000
#define NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT 0x00004000
#define NGX_HTTP_UPSTREAM_FT_RETRY 0x00008000
#define NGX_HTTP_UPSTREAM_FT_NOLIVE 0x40000000
#define NGX_HTTP_UPSTREAM_FT_OFF 0x80000000
@ -44,6 +45,7 @@
#define NGX_HTTP_UPSTREAM_INVALID_HEADER 40
#define NGX_HTTP_UPSTREAM_EARLY_HINTS 41
#define NGX_HTTP_UPSTREAM_RETRY 42
#define NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT 0x00000002

View file

@ -2181,6 +2181,9 @@ ngx_http_v2_state_settings(ngx_http_v2_connection_t *h2c, u_char *pos,
return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
}
h2c->state.init_window_set = 0;
h2c->state.max_frame_set = 0;
return ngx_http_v2_state_settings_params(h2c, pos, end);
}
@ -2193,8 +2196,6 @@ ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos,
ngx_uint_t id, value;
ngx_http_v2_out_frame_t *frame;
window_delta = 0;
while (h2c->state.length) {
if (end - pos < NGX_HTTP_V2_SETTINGS_PARAM_SIZE) {
return ngx_http_v2_state_save(h2c, pos, end,
@ -2222,7 +2223,8 @@ ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos,
NGX_HTTP_V2_FLOW_CTRL_ERROR);
}
window_delta = value - h2c->init_window;
h2c->state.init_window_size = value;
h2c->state.init_window_set = 1;
break;
case NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING:
@ -2238,7 +2240,8 @@ ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos,
NGX_HTTP_V2_PROTOCOL_ERROR);
}
h2c->frame_size = value;
h2c->state.max_frame_size = value;
h2c->state.max_frame_set = 1;
break;
case NGX_HTTP_V2_ENABLE_PUSH_SETTING:
@ -2266,6 +2269,27 @@ ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos,
pos += NGX_HTTP_V2_SETTINGS_PARAM_SIZE;
}
if (h2c->state.max_frame_set) {
h2c->frame_size = h2c->state.max_frame_size;
h2c->state.max_frame_set = 0;
}
if (h2c->state.init_window_set) {
window_delta = (ssize_t) h2c->state.init_window_size
- (ssize_t) h2c->init_window;
h2c->init_window = h2c->state.init_window_size;
if (window_delta
&& ngx_http_v2_adjust_windows(h2c, window_delta) != NGX_OK)
{
return ngx_http_v2_connection_error(h2c,
NGX_HTTP_V2_INTERNAL_ERROR);
}
h2c->state.init_window_set = 0;
}
frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_SETTINGS_ACK_SIZE,
NGX_HTTP_V2_SETTINGS_FRAME,
NGX_HTTP_V2_ACK_FLAG, 0);
@ -2275,15 +2299,6 @@ ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos,
ngx_http_v2_queue_ordered_frame(h2c, frame);
if (window_delta) {
h2c->init_window += window_delta;
if (ngx_http_v2_adjust_windows(h2c, window_delta) != NGX_OK) {
return ngx_http_v2_connection_error(h2c,
NGX_HTTP_V2_INTERNAL_ERROR);
}
}
return ngx_http_v2_state_complete(h2c, pos, end);
}

View file

@ -80,10 +80,14 @@ typedef struct {
ngx_uint_t sid;
size_t length;
size_t padding;
size_t init_window_size;
size_t max_frame_size;
unsigned flags:8;
unsigned incomplete:1;
unsigned keep_pool:1;
unsigned init_window_set:1;
unsigned max_frame_set:1;
/* HPACK */
unsigned parse_name:1;