Mercurial > hg > nginx
comparison src/http/v3/ngx_http_v3_uni.c @ 8991:3436b441239b quic
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.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Mon, 31 Jan 2022 09:46:30 +0300 |
parents | 18d23ed15eef |
children | a5aebd51e4c7 |
comparison
equal
deleted
inserted
replaced
8990:b42a041d23a2 | 8991:3436b441239b |
---|---|
24 } ngx_http_v3_push_t; | 24 } ngx_http_v3_push_t; |
25 | 25 |
26 | 26 |
27 static void ngx_http_v3_close_uni_stream(ngx_connection_t *c); | 27 static void ngx_http_v3_close_uni_stream(ngx_connection_t *c); |
28 static void ngx_http_v3_uni_read_handler(ngx_event_t *rev); | 28 static void ngx_http_v3_uni_read_handler(ngx_event_t *rev); |
29 static void ngx_http_v3_dummy_write_handler(ngx_event_t *wev); | 29 static void ngx_http_v3_uni_dummy_read_handler(ngx_event_t *wev); |
30 static void ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev); | |
30 static void ngx_http_v3_push_cleanup(void *data); | 31 static void ngx_http_v3_push_cleanup(void *data); |
31 static ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c, | 32 static ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c, |
32 ngx_uint_t type); | 33 ngx_uint_t type); |
33 | 34 |
34 | 35 |
66 us->index = -1; | 67 us->index = -1; |
67 | 68 |
68 c->data = us; | 69 c->data = us; |
69 | 70 |
70 c->read->handler = ngx_http_v3_uni_read_handler; | 71 c->read->handler = ngx_http_v3_uni_read_handler; |
71 c->write->handler = ngx_http_v3_dummy_write_handler; | 72 c->write->handler = ngx_http_v3_uni_dummy_write_handler; |
72 | 73 |
73 ngx_http_v3_uni_read_handler(c->read); | 74 ngx_http_v3_uni_read_handler(c->read); |
74 } | 75 } |
75 | 76 |
76 | 77 |
250 ngx_http_v3_close_uni_stream(c); | 251 ngx_http_v3_close_uni_stream(c); |
251 } | 252 } |
252 | 253 |
253 | 254 |
254 static void | 255 static void |
255 ngx_http_v3_dummy_write_handler(ngx_event_t *wev) | 256 ngx_http_v3_uni_dummy_read_handler(ngx_event_t *rev) |
257 { | |
258 u_char ch; | |
259 ngx_connection_t *c; | |
260 | |
261 c = rev->data; | |
262 | |
263 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 dummy read handler"); | |
264 | |
265 if (rev->ready) { | |
266 if (c->recv(c, &ch, 1) != 0) { | |
267 ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_NO_ERROR, NULL); | |
268 ngx_http_v3_close_uni_stream(c); | |
269 return; | |
270 } | |
271 } | |
272 | |
273 if (ngx_handle_read_event(rev, 0) != NGX_OK) { | |
274 ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR, | |
275 NULL); | |
276 ngx_http_v3_close_uni_stream(c); | |
277 } | |
278 } | |
279 | |
280 | |
281 static void | |
282 ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev) | |
256 { | 283 { |
257 ngx_connection_t *c; | 284 ngx_connection_t *c; |
258 | 285 |
259 c = wev->data; | 286 c = wev->data; |
260 | 287 |
391 | 418 |
392 us->index = index; | 419 us->index = index; |
393 | 420 |
394 sc->data = us; | 421 sc->data = us; |
395 | 422 |
396 sc->read->handler = ngx_http_v3_uni_read_handler; | 423 sc->read->handler = ngx_http_v3_uni_dummy_read_handler; |
397 sc->write->handler = ngx_http_v3_dummy_write_handler; | 424 sc->write->handler = ngx_http_v3_uni_dummy_write_handler; |
398 | 425 |
399 if (index >= 0) { | 426 if (index >= 0) { |
400 h3c->known_streams[index] = sc; | 427 h3c->known_streams[index] = sc; |
401 } | 428 } |
402 | 429 |
406 h3c->total_bytes += n; | 433 h3c->total_bytes += n; |
407 | 434 |
408 if (sc->send(sc, buf, n) != (ssize_t) n) { | 435 if (sc->send(sc, buf, n) != (ssize_t) n) { |
409 goto failed; | 436 goto failed; |
410 } | 437 } |
438 | |
439 ngx_post_event(sc->read, &ngx_posted_events); | |
411 | 440 |
412 return sc; | 441 return sc; |
413 | 442 |
414 failed: | 443 failed: |
415 | 444 |