[PATCH] HTTP/2: make http2 server support http1
Haitao Lv
i at lvht.net
Sun Mar 4 05:49:45 UTC 2018
Here is the new patch
diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c
index 9d8b6d79..c06ef7c7 100644
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -1197,6 +1197,7 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
ngx_uint_t ssl;
#endif
#if (NGX_HTTP_V2)
+ ngx_uint_t http1;
ngx_uint_t http2;
#endif
@@ -1232,6 +1233,7 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
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 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
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 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport,
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 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport,
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 --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 6b318dd0..741a4dd9 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -3985,6 +3985,18 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
#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 --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
index d7985049..68b3e7d9 100644
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -73,6 +73,7 @@ typedef struct {
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 @@ struct ngx_http_addr_conf_s {
ngx_http_virtual_names_t *virtual_names;
unsigned ssl:1;
+ unsigned http1:1;
unsigned http2:1;
unsigned proxy_protocol:1;
};
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
index 844054c9..9eb713b7 100644
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -117,6 +117,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
sw_host_ip_literal,
sw_port,
sw_host_http_09,
+ sw_h2_preface,
sw_after_slash_in_uri,
sw_check_uri,
sw_check_uri_http_09,
@@ -134,6 +135,12 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
sw_almost_done
} state;
+#if (NGX_HTTP_V2)
+ static u_char h2_preface[] = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
+ u_char *h2_preface_end = h2_preface + 24;
+ u_char *n = h2_preface + 4;
+#endif
+
state = r->state;
for (p = b->pos; p < b->last; p++) {
@@ -145,10 +152,6 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
case sw_start:
r->request_start = p;
- if (ch == CR || ch == LF) {
- break;
- }
-
if ((ch < 'A' || ch > 'Z') && ch != '_' && ch != '-') {
return NGX_HTTP_PARSE_INVALID_METHOD;
}
@@ -174,6 +177,13 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
break;
}
+#if (NGX_HTTP_V2)
+ if (ngx_str3_cmp(m, 'P', 'R', 'I', ' ')) {
+ r->method = NGX_HTTP_PRI;
+ break;
+ }
+#endif
+
break;
case 4:
@@ -267,6 +277,14 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
}
state = sw_spaces_before_uri;
+
+#if (NGX_HTTP_V2)
+ if (r->method & NGX_HTTP_PRI) {
+ r->uri_start = p;
+ state = sw_h2_preface;
+ }
+#endif
+
break;
}
@@ -276,6 +294,29 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
break;
+#if (NGX_HTTP_V2)
+ case sw_h2_preface:
+
+ if (ch == *n++) {
+ if (n == h2_preface_end) {
+ r->request_end = r->request_start + 14;
+ r->uri_start = r->request_start + 4;
+ r->uri_end = r->request_start + 5;
+ r->http_protocol.data = r->request_start + 6;
+ r->http_major = 2;
+ r->http_minor = 0;
+
+ goto done;
+ }
+
+ break;
+ }
+
+ return NGX_HTTP_PARSE_INVALID_METHOD;
+
+ break;
+#endif
+
/* space* before URI */
case sw_spaces_before_uri:
@@ -724,9 +765,11 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
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 +787,11 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
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 --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 89cfe77a..3ae64569 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -8,6 +8,9 @@
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
+#if (NGX_HTTP_V2)
+#include <ngx_http_v2_module.h>
+#endif
static void ngx_http_wait_request_handler(ngx_event_t *ev);
@@ -17,6 +20,10 @@ static ssize_t ngx_http_read_request_header(ngx_http_request_t *r);
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 +327,7 @@ ngx_http_init_connection(ngx_connection_t *c)
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
@@ -939,14 +946,16 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
static void
ngx_http_process_request_line(ngx_event_t *rev)
{
- ssize_t n;
- ngx_int_t rc, rv;
- ngx_str_t host;
- ngx_connection_t *c;
- ngx_http_request_t *r;
+ ssize_t n;
+ ngx_int_t rc, rv;
+ ngx_str_t host;
+ ngx_connection_t *c;
+ ngx_http_connection_t *hc;
+ ngx_http_request_t *r;
c = rev->data;
r = c->data;
+ hc = r->http_connection;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
"http process request line");
@@ -1033,6 +1042,18 @@ ngx_http_process_request_line(ngx_event_t *rev)
return;
}
+#if (NGX_HTTP_V2)
+ if (hc->addr_conf->http2 && (r->method & NGX_HTTP_PRI)) {
+
+ c->log->action = "reading client h2 preface";
+
+ ngx_http_process_h2_preface(rev);
+ return;
+ } else if (r->method & NGX_HTTP_PRI) {
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
+ return;
+ }
+#endif
if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
sizeof(ngx_table_elt_t))
@@ -1208,6 +1229,45 @@ ngx_http_process_request_uri(ngx_http_request_t *r)
return NGX_OK;
}
+#if (NGX_HTTP_V2)
+static void
+ngx_http_process_h2_preface(ngx_event_t *rev)
+{
+ size_t len;
+ ngx_connection_t *c;
+ ngx_http_request_t *r;
+ ngx_http_connection_t *hc;
+ ngx_http_v2_main_conf_t *h2mcf;
+
+ c = rev->data;
+ r = c->data;
+ hc = r->http_connection;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "http process h2 preface");
+
+ r->header_in->pos = r->header_in->start + 24;
+
+ len = r->header_in->last - r->header_in->pos;
+
+ h2mcf = ngx_http_get_module_main_conf(hc->conf_ctx, ngx_http_v2_module);
+
+ if (len <= h2mcf->recv_buffer_size) {
+ c->data = r->http_connection;
+
+ ngx_http_free_request(r, -1);
+
+ 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 +1869,7 @@ ngx_http_process_request_header(ngx_http_request_t *r)
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);
@@ -3506,7 +3566,9 @@ ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc)
log->action = "logging request";
- ngx_http_log_request(r);
+ if (rc >= 0) {
+ ngx_http_log_request(r);
+ }
log->action = "closing request";
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index 5d44c06e..34140655 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -41,6 +41,7 @@
#define NGX_HTTP_UNLOCK 0x2000
#define NGX_HTTP_PATCH 0x4000
#define NGX_HTTP_TRACE 0x8000
+#define NGX_HTTP_PRI 0x010000
#define NGX_HTTP_CONNECTION_CLOSE 1
#define NGX_HTTP_CONNECTION_KEEP_ALIVE 2
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
index d9df0f90..ea72f129 100644
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -230,6 +230,13 @@ static ngx_http_v2_parse_header_t ngx_http_v2_parse_headers[] = {
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;
@@ -316,6 +323,12 @@ ngx_http_v2_init(ngx_event_t *rev)
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,17 @@ ngx_http_v2_read_handler(ngx_event_t *rev)
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;
- ngx_memcpy(p, h2c->state.buffer, NGX_HTTP_V2_STATE_BUFFER_SIZE);
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);
n = c->recv(c, end, available);
@@ -410,6 +427,8 @@ ngx_http_v2_read_handler(ngx_event_t *rev)
end += n;
+do_state_handler:
+
h2c->state.buffer_used = 0;
h2c->state.incomplete = 0;
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
index d89e8fef..cc9251f0 100644
--- a/src/http/v2/ngx_http_v2.h
+++ b/src/http/v2/ngx_http_v2.h
@@ -279,6 +279,7 @@ ngx_http_v2_queue_ordered_frame(ngx_http_v2_connection_t *h2c,
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);
> On Mar 4, 2018, at 10:53, Haitao Lv <i at lvht.net> wrote:
>
> Hi, wbr,
>
> Thanks for your review. I don't know why I can't receive your email.
> Let me reply directly.
>
>> It doesn't look like a useful feature.
>> Could you please explain the use cases?
>
> The current implementation support both http/1 and http/2 over the
> same TLS listen port by the ALPN Extension.
>
> Nginx also support listening http/2 over plain tcp port, which is
> perfect for development and inner production environment.
>
> However, the current implementation cannot support http/1.1 and http/2
> simultaneously. We have no choice but listen on two different ports.
> As a result, one same service has two ports and different clients
> should choose their suitable port.
>
> Besides, the http/2 is efficient, but http/1 is simple. So I see no
> chance that the http/2 will replace http/1 totally in the production
> inner environment. Will call the inner API by both http/1 and http/2.
>
> So I think support http/1 and http/2 on the plain tcp port will simplify
> both the production and development environment.
>
>
>> What if the received data is bigger than h2mcf->recv_buffer?
>
> Yes, it is a problem. However, it can be fixed easily.
>
> As we know, the http/2 preface is PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n.
> We could modify the ngx_http_parse_request_line and when we got A PRI
> method, we need to get a single * uri. If we got things other than *,
> we just return a invalid request response. By this, we will never got
> a PRI to_much_long_uri HTTP/2.0 request line, and the buffer will not
> be exhausted. So the ngx_http_alloc_large_header_buffer will not be called
> during the handshake. After the ngx_http_parse_request_line, we will
> ensure we got a PRI request, and the buffer size is client_header_buffer_size.
>
> And then we should the compare the r->header_in buffer's length and the
> h2mcf->recv_buffer_size. If we got a buffered data larger than the
> h2mcf->recv_buffer_size, we should send a bad request response.
>
> If this feature can be accepted, I will send a new patch.
>
> Thanks.
>
>
>> On Mar 2, 2018, at 15:53, Haitao Lv <i at lvht.net> wrote:
>>
>> # 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