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