Mercurial > hg > nginx
comparison src/event/quic/ngx_event_quic_streams.c @ 8906:41caf5410110 quic
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.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Thu, 11 Nov 2021 19:07:00 +0300 |
parents | 832723a49026 |
children | e8cbbfabe547 |
comparison
equal
deleted
inserted
replaced
8905:832723a49026 | 8906:41caf5410110 |
---|---|
13 #define NGX_QUIC_STREAM_GONE (void *) -1 | 13 #define NGX_QUIC_STREAM_GONE (void *) -1 |
14 | 14 |
15 | 15 |
16 static ngx_quic_stream_t *ngx_quic_create_client_stream(ngx_connection_t *c, | 16 static ngx_quic_stream_t *ngx_quic_create_client_stream(ngx_connection_t *c, |
17 uint64_t id); | 17 uint64_t id); |
18 static ngx_int_t ngx_quic_reject_stream(ngx_connection_t *c, uint64_t id); | |
18 static ngx_int_t ngx_quic_init_stream(ngx_quic_stream_t *qs); | 19 static ngx_int_t ngx_quic_init_stream(ngx_quic_stream_t *qs); |
19 static void ngx_quic_init_streams_handler(ngx_connection_t *c); | 20 static void ngx_quic_init_streams_handler(ngx_connection_t *c); |
20 static ngx_quic_stream_t *ngx_quic_create_stream(ngx_connection_t *c, | 21 static ngx_quic_stream_t *ngx_quic_create_stream(ngx_connection_t *c, |
21 uint64_t id); | 22 uint64_t id); |
22 static void ngx_quic_empty_handler(ngx_event_t *ev); | 23 static void ngx_quic_empty_handler(ngx_event_t *ev); |
375 */ | 376 */ |
376 | 377 |
377 for ( /* void */ ; min_id < id; min_id += 0x04) { | 378 for ( /* void */ ; min_id < id; min_id += 0x04) { |
378 | 379 |
379 qs = ngx_quic_create_stream(c, min_id); | 380 qs = ngx_quic_create_stream(c, min_id); |
381 | |
380 if (qs == NULL) { | 382 if (qs == NULL) { |
381 return NULL; | 383 if (ngx_quic_reject_stream(c, min_id) != NGX_OK) { |
384 return NULL; | |
385 } | |
386 | |
387 continue; | |
382 } | 388 } |
383 | 389 |
384 if (ngx_quic_init_stream(qs) != NGX_OK) { | 390 if (ngx_quic_init_stream(qs) != NGX_OK) { |
385 return NULL; | 391 return NULL; |
386 } | 392 } |
388 if (qc->shutdown || qc->closing) { | 394 if (qc->shutdown || qc->closing) { |
389 return NGX_QUIC_STREAM_GONE; | 395 return NGX_QUIC_STREAM_GONE; |
390 } | 396 } |
391 } | 397 } |
392 | 398 |
393 return ngx_quic_create_stream(c, id); | 399 qs = ngx_quic_create_stream(c, id); |
400 | |
401 if (qs == NULL) { | |
402 if (ngx_quic_reject_stream(c, id) != NGX_OK) { | |
403 return NULL; | |
404 } | |
405 | |
406 return NGX_QUIC_STREAM_GONE; | |
407 } | |
408 | |
409 return qs; | |
410 } | |
411 | |
412 | |
413 static ngx_int_t | |
414 ngx_quic_reject_stream(ngx_connection_t *c, uint64_t id) | |
415 { | |
416 uint64_t code; | |
417 ngx_quic_frame_t *frame; | |
418 ngx_quic_connection_t *qc; | |
419 | |
420 qc = ngx_quic_get_connection(c); | |
421 | |
422 code = (id & NGX_QUIC_STREAM_UNIDIRECTIONAL) | |
423 ? qc->conf->stream_reject_code_uni | |
424 : qc->conf->stream_reject_code_bidi; | |
425 | |
426 if (code == 0) { | |
427 return NGX_DECLINED; | |
428 } | |
429 | |
430 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
431 "quic stream id:0x%xL reject err:0x%xL", id, code); | |
432 | |
433 frame = ngx_quic_alloc_frame(c); | |
434 if (frame == NULL) { | |
435 return NGX_ERROR; | |
436 } | |
437 | |
438 frame->level = ssl_encryption_application; | |
439 frame->type = NGX_QUIC_FT_RESET_STREAM; | |
440 frame->u.reset_stream.id = id; | |
441 frame->u.reset_stream.error_code = code; | |
442 frame->u.reset_stream.final_size = 0; | |
443 | |
444 ngx_quic_queue_frame(qc, frame); | |
445 | |
446 frame = ngx_quic_alloc_frame(c); | |
447 if (frame == NULL) { | |
448 return NGX_ERROR; | |
449 } | |
450 | |
451 frame->level = ssl_encryption_application; | |
452 frame->type = NGX_QUIC_FT_STOP_SENDING; | |
453 frame->u.stop_sending.id = id; | |
454 frame->u.stop_sending.error_code = code; | |
455 | |
456 ngx_quic_queue_frame(qc, frame); | |
457 | |
458 return NGX_OK; | |
394 } | 459 } |
395 | 460 |
396 | 461 |
397 static ngx_int_t | 462 static ngx_int_t |
398 ngx_quic_init_stream(ngx_quic_stream_t *qs) | 463 ngx_quic_init_stream(ngx_quic_stream_t *qs) |
864 (void) ngx_quic_update_flow(c, qs->recv_last); | 929 (void) ngx_quic_update_flow(c, qs->recv_last); |
865 | 930 |
866 if ((qs->id & NGX_QUIC_STREAM_SERVER_INITIATED) == 0 | 931 if ((qs->id & NGX_QUIC_STREAM_SERVER_INITIATED) == 0 |
867 || (qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) | 932 || (qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) |
868 { | 933 { |
869 if (!c->read->pending_eof && !c->read->error) { | 934 if (!c->read->pending_eof && !c->read->error |
935 && qc->conf->stream_close_code) | |
936 { | |
870 frame = ngx_quic_alloc_frame(pc); | 937 frame = ngx_quic_alloc_frame(pc); |
871 if (frame == NULL) { | 938 if (frame == NULL) { |
872 goto done; | 939 goto done; |
873 } | 940 } |
874 | 941 |
875 frame->level = ssl_encryption_application; | 942 frame->level = ssl_encryption_application; |
876 frame->type = NGX_QUIC_FT_STOP_SENDING; | 943 frame->type = NGX_QUIC_FT_STOP_SENDING; |
877 frame->u.stop_sending.id = qs->id; | 944 frame->u.stop_sending.id = qs->id; |
878 frame->u.stop_sending.error_code = 0x100; /* HTTP/3 no error */ | 945 frame->u.stop_sending.error_code = qc->conf->stream_close_code; |
879 | 946 |
880 ngx_quic_queue_frame(qc, frame); | 947 ngx_quic_queue_frame(qc, frame); |
881 } | 948 } |
882 } | 949 } |
883 | 950 |