# HG changeset patch # User Roman Arutyunyan # Date 1643611590 -10800 # Node ID 3436b441239b494e6f63db3b8d26a71682b4f106 # Parent b42a041d23a2226ec6def395bd0b084889b85473 HTTP/3: proper uni stream closure detection. Previously, closure detection for server-initiated uni streams was not properly implemented. Instead, HTTP/3 code relied on QUIC code posting the read event and setting rev->error when it needed to close the stream. Then, regular uni stream read handler called c->recv() and received error, which closed the stream. This was an ad-hoc solution. If, for whatever reason, the read handler was called earlier, c->recv() would return 0, which would also close the stream. Now server-initiated uni streams have a separate read event handler for tracking stream closure. The handler calls c->recv(), which normally returns 0, but may return error in case of closure. diff --git a/src/http/v3/ngx_http_v3_uni.c b/src/http/v3/ngx_http_v3_uni.c --- a/src/http/v3/ngx_http_v3_uni.c +++ b/src/http/v3/ngx_http_v3_uni.c @@ -26,7 +26,8 @@ typedef struct { static void ngx_http_v3_close_uni_stream(ngx_connection_t *c); static void ngx_http_v3_uni_read_handler(ngx_event_t *rev); -static void ngx_http_v3_dummy_write_handler(ngx_event_t *wev); +static void ngx_http_v3_uni_dummy_read_handler(ngx_event_t *wev); +static void ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev); static void ngx_http_v3_push_cleanup(void *data); static ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c, ngx_uint_t type); @@ -68,7 +69,7 @@ ngx_http_v3_init_uni_stream(ngx_connecti c->data = us; c->read->handler = ngx_http_v3_uni_read_handler; - c->write->handler = ngx_http_v3_dummy_write_handler; + c->write->handler = ngx_http_v3_uni_dummy_write_handler; ngx_http_v3_uni_read_handler(c->read); } @@ -252,7 +253,33 @@ failed: static void -ngx_http_v3_dummy_write_handler(ngx_event_t *wev) +ngx_http_v3_uni_dummy_read_handler(ngx_event_t *rev) +{ + u_char ch; + ngx_connection_t *c; + + c = rev->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 dummy read handler"); + + if (rev->ready) { + if (c->recv(c, &ch, 1) != 0) { + ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_NO_ERROR, NULL); + ngx_http_v3_close_uni_stream(c); + return; + } + } + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR, + NULL); + ngx_http_v3_close_uni_stream(c); + } +} + + +static void +ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev) { ngx_connection_t *c; @@ -393,8 +420,8 @@ ngx_http_v3_get_uni_stream(ngx_connectio sc->data = us; - sc->read->handler = ngx_http_v3_uni_read_handler; - sc->write->handler = ngx_http_v3_dummy_write_handler; + sc->read->handler = ngx_http_v3_uni_dummy_read_handler; + sc->write->handler = ngx_http_v3_uni_dummy_write_handler; if (index >= 0) { h3c->known_streams[index] = sc; @@ -409,6 +436,8 @@ ngx_http_v3_get_uni_stream(ngx_connectio goto failed; } + ngx_post_event(sc->read, &ngx_posted_events); + return sc; failed: