mirror of
https://github.com/nginx/nginx.git
synced 2025-06-24 23:43:06 +08:00
QUIC: reject streams which we could not create.
The reasons why a stream may not be created by server currently include hitting worker_connections limit and memory allocation error. Previously in these cases the entire QUIC connection was closed and all its streams were shut down. Now the new stream is rejected and existing streams continue working. To reject an HTTP/3 request stream, RESET_STREAM and STOP_SENDING with H3_REQUEST_REJECTED error code are sent to client. HTTP/3 uni streams and Stream streams are not rejected.
This commit is contained in:
parent
54655cebbb
commit
50dd9ba7e8
@ -61,6 +61,9 @@ typedef struct {
|
||||
ngx_flag_t retry;
|
||||
ngx_flag_t gso_enabled;
|
||||
ngx_str_t host_key;
|
||||
ngx_int_t stream_close_code;
|
||||
ngx_int_t stream_reject_code_uni;
|
||||
ngx_int_t stream_reject_code_bidi;
|
||||
u_char av_token_key[NGX_QUIC_AV_KEY_LEN];
|
||||
u_char sr_token_key[NGX_QUIC_SR_KEY_LEN];
|
||||
} ngx_quic_conf_t;
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
static ngx_quic_stream_t *ngx_quic_create_client_stream(ngx_connection_t *c,
|
||||
uint64_t id);
|
||||
static ngx_int_t ngx_quic_reject_stream(ngx_connection_t *c, uint64_t id);
|
||||
static ngx_int_t ngx_quic_init_stream(ngx_quic_stream_t *qs);
|
||||
static void ngx_quic_init_streams_handler(ngx_connection_t *c);
|
||||
static ngx_quic_stream_t *ngx_quic_create_stream(ngx_connection_t *c,
|
||||
@ -377,10 +378,15 @@ ngx_quic_create_client_stream(ngx_connection_t *c, uint64_t id)
|
||||
for ( /* void */ ; min_id < id; min_id += 0x04) {
|
||||
|
||||
qs = ngx_quic_create_stream(c, min_id);
|
||||
|
||||
if (qs == NULL) {
|
||||
if (ngx_quic_reject_stream(c, min_id) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ngx_quic_init_stream(qs) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
@ -390,7 +396,66 @@ ngx_quic_create_client_stream(ngx_connection_t *c, uint64_t id)
|
||||
}
|
||||
}
|
||||
|
||||
return ngx_quic_create_stream(c, id);
|
||||
qs = ngx_quic_create_stream(c, id);
|
||||
|
||||
if (qs == NULL) {
|
||||
if (ngx_quic_reject_stream(c, id) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NGX_QUIC_STREAM_GONE;
|
||||
}
|
||||
|
||||
return qs;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_quic_reject_stream(ngx_connection_t *c, uint64_t id)
|
||||
{
|
||||
uint64_t code;
|
||||
ngx_quic_frame_t *frame;
|
||||
ngx_quic_connection_t *qc;
|
||||
|
||||
qc = ngx_quic_get_connection(c);
|
||||
|
||||
code = (id & NGX_QUIC_STREAM_UNIDIRECTIONAL)
|
||||
? qc->conf->stream_reject_code_uni
|
||||
: qc->conf->stream_reject_code_bidi;
|
||||
|
||||
if (code == 0) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic stream id:0x%xL reject err:0x%xL", id, code);
|
||||
|
||||
frame = ngx_quic_alloc_frame(c);
|
||||
if (frame == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
frame->level = ssl_encryption_application;
|
||||
frame->type = NGX_QUIC_FT_RESET_STREAM;
|
||||
frame->u.reset_stream.id = id;
|
||||
frame->u.reset_stream.error_code = code;
|
||||
frame->u.reset_stream.final_size = 0;
|
||||
|
||||
ngx_quic_queue_frame(qc, frame);
|
||||
|
||||
frame = ngx_quic_alloc_frame(c);
|
||||
if (frame == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
frame->level = ssl_encryption_application;
|
||||
frame->type = NGX_QUIC_FT_STOP_SENDING;
|
||||
frame->u.stop_sending.id = id;
|
||||
frame->u.stop_sending.error_code = code;
|
||||
|
||||
ngx_quic_queue_frame(qc, frame);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -866,7 +931,9 @@ ngx_quic_stream_cleanup_handler(void *data)
|
||||
if ((qs->id & NGX_QUIC_STREAM_SERVER_INITIATED) == 0
|
||||
|| (qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0)
|
||||
{
|
||||
if (!c->read->pending_eof && !c->read->error) {
|
||||
if (!c->read->pending_eof && !c->read->error
|
||||
&& qc->conf->stream_close_code)
|
||||
{
|
||||
frame = ngx_quic_alloc_frame(pc);
|
||||
if (frame == NULL) {
|
||||
goto done;
|
||||
@ -875,7 +942,7 @@ ngx_quic_stream_cleanup_handler(void *data)
|
||||
frame->level = ssl_encryption_application;
|
||||
frame->type = NGX_QUIC_FT_STOP_SENDING;
|
||||
frame->u.stop_sending.id = qs->id;
|
||||
frame->u.stop_sending.error_code = 0x100; /* HTTP/3 no error */
|
||||
frame->u.stop_sending.error_code = qc->conf->stream_close_code;
|
||||
|
||||
ngx_quic_queue_frame(qc, frame);
|
||||
}
|
||||
|
@ -314,6 +314,7 @@ ngx_http_quic_create_srv_conf(ngx_conf_t *cf)
|
||||
* conf->tp.sr_enabled = 0
|
||||
* conf->tp.preferred_address = NULL
|
||||
* conf->host_key = { 0, NULL }
|
||||
* cong->stream_reject_code_uni = 0;
|
||||
*/
|
||||
|
||||
conf->tp.max_idle_timeout = NGX_CONF_UNSET_MSEC;
|
||||
@ -331,6 +332,8 @@ ngx_http_quic_create_srv_conf(ngx_conf_t *cf)
|
||||
|
||||
conf->retry = NGX_CONF_UNSET;
|
||||
conf->gso_enabled = NGX_CONF_UNSET;
|
||||
conf->stream_close_code = NGX_HTTP_V3_ERR_NO_ERROR;
|
||||
conf->stream_reject_code_bidi = NGX_HTTP_V3_ERR_REQUEST_REJECTED;
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
@ -241,6 +241,9 @@ ngx_stream_quic_create_srv_conf(ngx_conf_t *cf)
|
||||
* conf->tp.retry_scid = { 0, NULL };
|
||||
* conf->tp.preferred_address = NULL
|
||||
* conf->host_key = { 0, NULL }
|
||||
* conf->stream_close_code = 0;
|
||||
* conf->stream_reject_code_uni = 0;
|
||||
* conf->stream_reject_code_bidi= 0;
|
||||
*/
|
||||
|
||||
conf->tp.max_idle_timeout = NGX_CONF_UNSET_MSEC;
|
||||
|
Loading…
Reference in New Issue
Block a user