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.
This commit is contained in:
Roman Arutyunyan 2022-01-31 09:46:30 +03:00
parent 6e7c3ad42c
commit c2e9c35718
1 changed files with 34 additions and 5 deletions

View File

@ -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_connection_t *c)
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_connection_t *c, ngx_uint_t type)
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_connection_t *c, ngx_uint_t type)
goto failed;
}
ngx_post_event(sc->read, &ngx_posted_events);
return sc;
failed: