[PATCH] HTTP/2: make http2 server support http1

Haitao Lv i at lvht.net
Fri Mar 2 07:53:07 UTC 2018


# HG changeset patch
# User 吕海涛 <i at lvht.net>
# Date 1519976498 -28800
#      Fri Mar 02 15:41:38 2018 +0800
# Node ID 200955343460c4726015180f20c03e31c0b35ff6
# Parent  81fae70d6cb81c67607931ec3ecc585a609c97e0
make http2 server support http1

diff -r 81fae70d6cb8 -r 200955343460 src/http/ngx_http.c
--- a/src/http/ngx_http.c	Thu Mar 01 20:25:50 2018 +0300
+++ b/src/http/ngx_http.c	Fri Mar 02 15:41:38 2018 +0800
@@ -1197,6 +1197,7 @@
     ngx_uint_t             ssl;
 #endif
 #if (NGX_HTTP_V2)
+    ngx_uint_t             http1;
     ngx_uint_t             http2;
 #endif
 
@@ -1232,6 +1233,7 @@
         ssl = lsopt->ssl || addr[i].opt.ssl;
 #endif
 #if (NGX_HTTP_V2)
+        http1 = lsopt->http1 || addr[i].opt.http1;
         http2 = lsopt->http2 || addr[i].opt.http2;
 #endif
 
@@ -1266,6 +1268,7 @@
         addr[i].opt.ssl = ssl;
 #endif
 #if (NGX_HTTP_V2)
+        addr[i].opt.http1 = http1;
         addr[i].opt.http2 = http2;
 #endif
 
@@ -1802,6 +1805,7 @@
         addrs[i].conf.ssl = addr[i].opt.ssl;
 #endif
 #if (NGX_HTTP_V2)
+        addrs[i].conf.http1 = addr[i].opt.http1;
         addrs[i].conf.http2 = addr[i].opt.http2;
 #endif
         addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol;
@@ -1867,6 +1871,7 @@
         addrs6[i].conf.ssl = addr[i].opt.ssl;
 #endif
 #if (NGX_HTTP_V2)
+        addrs6[i].conf.http1 = addr[i].opt.http1;
         addrs6[i].conf.http2 = addr[i].opt.http2;
 #endif
         addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol;
diff -r 81fae70d6cb8 -r 200955343460 src/http/ngx_http_core_module.c
--- a/src/http/ngx_http_core_module.c	Thu Mar 01 20:25:50 2018 +0300
+++ b/src/http/ngx_http_core_module.c	Fri Mar 02 15:41:38 2018 +0800
@@ -3985,6 +3985,18 @@
 #endif
         }
 
+        if (ngx_strcmp(value[n].data, "http1") == 0) {
+#if (NGX_HTTP_V2)
+            lsopt.http1 = 1;
+            continue;
+#else
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "the \"http1\" parameter requires "
+                               "ngx_http_v2_module");
+            return NGX_CONF_ERROR;
+#endif
+        }
+
         if (ngx_strcmp(value[n].data, "spdy") == 0) {
             ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
                                "invalid parameter \"spdy\": "
diff -r 81fae70d6cb8 -r 200955343460 src/http/ngx_http_core_module.h
--- a/src/http/ngx_http_core_module.h	Thu Mar 01 20:25:50 2018 +0300
+++ b/src/http/ngx_http_core_module.h	Fri Mar 02 15:41:38 2018 +0800
@@ -73,6 +73,7 @@
     unsigned                   bind:1;
     unsigned                   wildcard:1;
     unsigned                   ssl:1;
+    unsigned                   http1:1;
     unsigned                   http2:1;
 #if (NGX_HAVE_INET6)
     unsigned                   ipv6only:1;
@@ -234,6 +235,7 @@
     ngx_http_virtual_names_t  *virtual_names;
 
     unsigned                   ssl:1;
+    unsigned                   http1:1;
     unsigned                   http2:1;
     unsigned                   proxy_protocol:1;
 };
diff -r 81fae70d6cb8 -r 200955343460 src/http/ngx_http_parse.c
--- a/src/http/ngx_http_parse.c	Thu Mar 01 20:25:50 2018 +0300
+++ b/src/http/ngx_http_parse.c	Fri Mar 02 15:41:38 2018 +0800
@@ -285,6 +285,14 @@
                 break;
             }
 
+#if (NGX_HTTP_V2)
+            if (ch == '*') {
+                r->uri_start = p;
+                state = sw_uri;
+                break;
+            }
+#endif
+
             c = (u_char) (ch | 0x20);
             if (c >= 'a' && c <= 'z') {
                 r->schema_start = p;
@@ -724,9 +732,11 @@
 
             r->http_major = ch - '0';
 
+#if !(NGX_HTTP_V2)
             if (r->http_major > 1) {
                 return NGX_HTTP_PARSE_INVALID_VERSION;
             }
+#endif
 
             state = sw_major_digit;
             break;
@@ -744,9 +754,11 @@
 
             r->http_major = r->http_major * 10 + (ch - '0');
 
+#if !(NGX_HTTP_V2)
             if (r->http_major > 1) {
                 return NGX_HTTP_PARSE_INVALID_VERSION;
             }
+#endif
 
             break;
 
diff -r 81fae70d6cb8 -r 200955343460 src/http/ngx_http_request.c
--- a/src/http/ngx_http_request.c	Thu Mar 01 20:25:50 2018 +0300
+++ b/src/http/ngx_http_request.c	Fri Mar 02 15:41:38 2018 +0800
@@ -17,6 +17,10 @@
 static ngx_int_t ngx_http_alloc_large_header_buffer(ngx_http_request_t *r,
     ngx_uint_t request_line);
 
+#if (NGX_HTTP_V2)
+static void ngx_http_process_h2_preface(ngx_event_t *rev);
+#endif
+
 static ngx_int_t ngx_http_process_header_line(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset);
 static ngx_int_t ngx_http_process_unique_header_line(ngx_http_request_t *r,
@@ -320,7 +324,7 @@
     c->write->handler = ngx_http_empty_handler;
 
 #if (NGX_HTTP_V2)
-    if (hc->addr_conf->http2) {
+    if (hc->addr_conf->http2 && !hc->addr_conf->http1) {
         rev->handler = ngx_http_v2_init;
     }
 #endif
@@ -1033,6 +1037,20 @@
                 return;
             }
 
+#if (NGX_HTTP_V2)
+            if (r->http_connection->addr_conf->http2
+                && r->http_version >= NGX_HTTP_VERSION_20) {
+
+                c->log->action = "reading client h2 preface";
+
+                rev->handler = ngx_http_process_h2_preface;
+                ngx_http_process_h2_preface(rev);
+                return;
+            } else if (r->http_version >= NGX_HTTP_VERSION_20) {
+                ngx_http_finalize_request(r, NGX_HTTP_VERSION_NOT_SUPPORTED);
+                return;
+            }
+#endif
 
             if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
                               sizeof(ngx_table_elt_t))
@@ -1208,6 +1226,64 @@
     return NGX_OK;
 }
 
+#if (NGX_HTTP_V2)
+static void
+ngx_http_process_h2_preface(ngx_event_t *rev)
+{
+    size_t                      len;
+    ssize_t                     n;
+    ngx_connection_t           *c;
+    ngx_http_request_t         *r;
+
+    c = rev->data;
+    r = c->data;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+            "http process h2 preface");
+
+    if (rev->timedout) {
+        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
+        c->timedout = 1;
+        ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
+        return;
+    }
+
+    n = ngx_http_read_request_header(r);
+
+    if (n == NGX_AGAIN || n == NGX_ERROR) {
+        return;
+    }
+
+    len = r->header_in->last - r->header_in->start;
+
+    if (len < sizeof("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n") - 1) {
+        r->header_in->pos = r->header_in->last;
+        return;
+    }
+
+    if (ngx_strncmp(r->header_in->start,
+                "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", 24) == 0) {
+
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                "h2 preface done");
+
+        r->header_in->pos = r->header_in->start + 24;
+
+        c->data = r->http_connection;
+
+        r->http_connection = NULL;
+
+        ngx_http_v2_init_after_preface(rev, r->header_in);
+        return;
+    }
+
+    ngx_log_error(NGX_LOG_INFO, c->log, 0,
+            "client sent invalid h2 preface");
+
+    ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
+}
+#endif
+
 
 static void
 ngx_http_process_request_headers(ngx_event_t *rev)
@@ -1809,7 +1885,7 @@
         return NGX_ERROR;
     }
 
-    if (r->headers_in.host == NULL && r->http_version > NGX_HTTP_VERSION_10) {
+    if (r->headers_in.host == NULL && r->http_version == NGX_HTTP_VERSION_11) {
         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                    "client sent HTTP/1.1 request without \"Host\" header");
         ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
diff -r 81fae70d6cb8 -r 200955343460 src/http/v2/ngx_http_v2.c
--- a/src/http/v2/ngx_http_v2.c	Thu Mar 01 20:25:50 2018 +0300
+++ b/src/http/v2/ngx_http_v2.c	Fri Mar 02 15:41:38 2018 +0800
@@ -231,6 +231,13 @@
 void
 ngx_http_v2_init(ngx_event_t *rev)
 {
+    ngx_http_v2_init_after_preface(rev, NULL);
+}
+
+
+void
+ngx_http_v2_init_after_preface(ngx_event_t *rev, ngx_buf_t *buf)
+{
     ngx_connection_t          *c;
     ngx_pool_cleanup_t        *cln;
     ngx_http_connection_t     *hc;
@@ -316,6 +323,12 @@
     h2c->state.handler = hc->proxy_protocol ? ngx_http_v2_state_proxy_protocol
                                             : ngx_http_v2_state_preface;
 
+    if (buf != NULL) {
+        ngx_memcpy(h2mcf->recv_buffer, buf->pos, buf->last - buf->pos);
+        h2c->state.buffer_used = buf->last - buf->pos;
+        h2c->state.handler = ngx_http_v2_state_head;
+    }
+
     ngx_queue_init(&h2c->waiting);
     ngx_queue_init(&h2c->dependencies);
     ngx_queue_init(&h2c->closed);
@@ -381,13 +394,18 @@
     h2mcf = ngx_http_get_module_main_conf(h2c->http_connection->conf_ctx,
                                           ngx_http_v2_module);
 
-    available = h2mcf->recv_buffer_size - 2 * NGX_HTTP_V2_STATE_BUFFER_SIZE;
+    available = h2mcf->recv_buffer_size - h2c->state.buffer_used - 2 * NGX_HTTP_V2_STATE_BUFFER_SIZE;
 
     do {
         p = h2mcf->recv_buffer;
 
+        end = p + h2c->state.buffer_used;
+
+        if (h2c->state.buffer_used) {
+            goto do_state_handler;
+        }
+
         ngx_memcpy(p, h2c->state.buffer, NGX_HTTP_V2_STATE_BUFFER_SIZE);
-        end = p + h2c->state.buffer_used;
 
         n = c->recv(c, end, available);
 
@@ -410,6 +428,8 @@
 
         end += n;
 
+do_state_handler:
+
         h2c->state.buffer_used = 0;
         h2c->state.incomplete = 0;
 
diff -r 81fae70d6cb8 -r 200955343460 src/http/v2/ngx_http_v2.h
--- a/src/http/v2/ngx_http_v2.h	Thu Mar 01 20:25:50 2018 +0300
+++ b/src/http/v2/ngx_http_v2.h	Fri Mar 02 15:41:38 2018 +0800
@@ -279,6 +279,7 @@
 
 
 void ngx_http_v2_init(ngx_event_t *rev);
+void ngx_http_v2_init_after_preface(ngx_event_t *rev, ngx_buf_t *buf);
 
 ngx_int_t ngx_http_v2_read_request_body(ngx_http_request_t *r);
 ngx_int_t ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r);





More information about the nginx-devel mailing list