diff src/http/v3/ngx_http_v3_streams.c @ 8460:72f9ff4e0a88 quic

HTTP/3: close QUIC connection with HTTP/QPACK errors when needed. Previously errors led only to closing streams. To simplify closing QUIC connection from a QUIC stream context, new macro ngx_http_v3_finalize_connection() is introduced. It calls ngx_quic_finalize_connection() for the parent connection.
author Roman Arutyunyan <arut@nginx.com>
date Thu, 02 Jul 2020 16:47:51 +0300
parents c9538aef3211
children 0d2b2664b41c
line wrap: on
line diff
--- a/src/http/v3/ngx_http_v3_streams.c
+++ b/src/http/v3/ngx_http_v3_streams.c
@@ -39,6 +39,8 @@ ngx_http_v3_handle_client_uni_stream(ngx
 
     us = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_uni_stream_t));
     if (us == NULL) {
+        ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
+                                        NULL);
         ngx_http_v3_close_uni_stream(c);
         return;
     }
@@ -85,7 +87,7 @@ ngx_http_v3_read_uni_stream_type(ngx_eve
 {
     u_char                     ch;
     ssize_t                    n;
-    ngx_int_t                  index;
+    ngx_int_t                  index, rc;
     ngx_connection_t          *c;
     ngx_http_v3_connection_t  *h3c;
     ngx_http_v3_uni_stream_t  *us;
@@ -100,12 +102,18 @@ ngx_http_v3_read_uni_stream_type(ngx_eve
 
         n = c->recv(c, &ch, 1);
 
-        if (n == NGX_ERROR) {
+        if (n == NGX_AGAIN) {
+            break;
+        }
+
+        if (n == 0) {
+            rc = NGX_HTTP_V3_ERR_GENERAL_PROTOCOL_ERROR;
             goto failed;
         }
 
-        if (n == NGX_AGAIN || n != 1) {
-            break;
+        if (n != 1) {
+            rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
+            goto failed;
         }
 
         switch (ch) {
@@ -154,6 +162,7 @@ ngx_http_v3_read_uni_stream_type(ngx_eve
         if (index >= 0) {
             if (h3c->known_streams[index]) {
                 ngx_log_error(NGX_LOG_INFO, c->log, 0, "stream exists");
+                rc = NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR;
                 goto failed;
             }
 
@@ -164,6 +173,7 @@ ngx_http_v3_read_uni_stream_type(ngx_eve
         if (n) {
             us->data = ngx_pcalloc(c->pool, n);
             if (us->data == NULL) {
+                rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
                 goto failed;
             }
         }
@@ -174,6 +184,7 @@ ngx_http_v3_read_uni_stream_type(ngx_eve
     }
 
     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
+        rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
         goto failed;
     }
 
@@ -181,6 +192,7 @@ ngx_http_v3_read_uni_stream_type(ngx_eve
 
 failed:
 
+    ngx_http_v3_finalize_connection(c, rc, "could not read stream type");
     ngx_http_v3_close_uni_stream(c);
 }
 
@@ -203,10 +215,22 @@ ngx_http_v3_uni_read_handler(ngx_event_t
 
         n = c->recv(c, buf, sizeof(buf));
 
-        if (n == NGX_ERROR || n == 0) {
+        if (n == NGX_ERROR) {
+            rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
             goto failed;
         }
 
+        if (n == 0) {
+            if (us->index >= 0) {
+                rc = NGX_HTTP_V3_ERR_CLOSED_CRITICAL_STREAM;
+                goto failed;
+            }
+
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read eof");
+            ngx_http_v3_close_uni_stream(c);
+            return;
+        }
+
         if (n == NGX_AGAIN) {
             break;
         }
@@ -219,30 +243,34 @@ ngx_http_v3_uni_read_handler(ngx_event_t
 
             rc = us->handler(c, us->data, buf[i]);
 
-            if (rc == NGX_ERROR) {
+            if (rc == NGX_DONE) {
+                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                               "http3 read done");
+                ngx_http_v3_close_uni_stream(c);
+                return;
+            }
+
+            if (rc > 0) {
                 goto failed;
             }
 
-            if (rc == NGX_DONE) {
-                goto done;
+            if (rc != NGX_AGAIN) {
+                rc = NGX_HTTP_V3_ERR_GENERAL_PROTOCOL_ERROR;
+                goto failed;
             }
-
-            /* rc == NGX_AGAIN */
         }
     }
 
     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
+        rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
         goto failed;
     }
 
     return;
 
-done:
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read done");
-
 failed:
 
+    ngx_http_v3_finalize_connection(c, rc, "stream error");
     ngx_http_v3_close_uni_stream(c);
 }
 
@@ -257,6 +285,8 @@ ngx_http_v3_dummy_write_handler(ngx_even
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 dummy write handler");
 
     if (ngx_handle_write_event(wev, 0) != NGX_OK) {
+        ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
+                                        NULL);
         ngx_http_v3_close_uni_stream(c);
     }
 }