[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