aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRoman Arutyunyan <arut@nginx.com>2020-07-13 16:00:00 +0300
committerRoman Arutyunyan <arut@nginx.com>2020-07-13 16:00:00 +0300
commit04b2a169a47ac5054350e670bc5d6fd10f2434fc (patch)
treeb5db83276695ece162bd96a8eacc35565645a7fb /src
parent548d515fbaf39b8b567daffecf2bdc71ecbfa579 (diff)
downloadnginx-04b2a169a47ac5054350e670bc5d6fd10f2434fc.tar.gz
nginx-04b2a169a47ac5054350e670bc5d6fd10f2434fc.zip
HTTP/3: header encoding functions.
Diffstat (limited to 'src')
-rw-r--r--src/http/v3/ngx_http_v3.c128
-rw-r--r--src/http/v3/ngx_http_v3.h12
-rw-r--r--src/http/v3/ngx_http_v3_request.c176
3 files changed, 226 insertions, 90 deletions
diff --git a/src/http/v3/ngx_http_v3.c b/src/http/v3/ngx_http_v3.c
index e796da772..a80310faf 100644
--- a/src/http/v3/ngx_http_v3.c
+++ b/src/http/v3/ngx_http_v3.c
@@ -97,3 +97,131 @@ ngx_http_v3_encode_prefix_int(u_char *p, uint64_t value, ngx_uint_t prefix)
return (uintptr_t) p;
}
+
+
+uintptr_t
+ngx_http_v3_encode_header_block_prefix(u_char *p, ngx_uint_t insert_count,
+ ngx_uint_t sign, ngx_uint_t delta_base)
+{
+ if (p == NULL) {
+ return ngx_http_v3_encode_prefix_int(NULL, insert_count, 8)
+ + ngx_http_v3_encode_prefix_int(NULL, delta_base, 7);
+ }
+
+ *p = 0;
+ p = (u_char *) ngx_http_v3_encode_prefix_int(p, insert_count, 8);
+
+ *p = sign ? 0x80 : 0;
+ p = (u_char *) ngx_http_v3_encode_prefix_int(p, delta_base, 7);
+
+ return (uintptr_t) p;
+}
+
+
+uintptr_t
+ngx_http_v3_encode_header_ri(u_char *p, ngx_uint_t dynamic, ngx_uint_t index)
+{
+ /* Indexed Header Field */
+
+ if (p == NULL) {
+ return ngx_http_v3_encode_prefix_int(NULL, index, 6);
+ }
+
+ *p = dynamic ? 0x80 : 0xc0;
+
+ return ngx_http_v3_encode_prefix_int(p, index, 6);
+}
+
+
+uintptr_t
+ngx_http_v3_encode_header_lri(u_char *p, ngx_uint_t dynamic, ngx_uint_t index,
+ u_char *data, size_t len)
+{
+ /* Literal Header Field With Name Reference */
+
+ if (p == NULL) {
+ return ngx_http_v3_encode_prefix_int(NULL, index, 4)
+ + ngx_http_v3_encode_prefix_int(NULL, len, 7)
+ + len;
+ }
+
+ *p = dynamic ? 0x60 : 0x70;
+ p = (u_char *) ngx_http_v3_encode_prefix_int(p, index, 4);
+
+ *p = 0;
+ p = (u_char *) ngx_http_v3_encode_prefix_int(p, len, 7);
+
+ if (data) {
+ p = ngx_cpymem(p, data, len);
+ }
+
+ return (uintptr_t) p;
+}
+
+
+uintptr_t
+ngx_http_v3_encode_header_l(u_char *p, ngx_str_t *name, ngx_str_t *value)
+{
+ /* Literal Header Field Without Name Reference */
+
+ if (p == NULL) {
+ return ngx_http_v3_encode_prefix_int(NULL, name->len, 3)
+ + name->len
+ + ngx_http_v3_encode_prefix_int(NULL, value->len, 7)
+ + value->len;
+ }
+
+ *p = 0x30;
+ p = (u_char *) ngx_http_v3_encode_prefix_int(p, name->len, 3);
+
+ ngx_strlow(p, name->data, name->len);
+ p += name->len;
+
+ *p = 0;
+ p = (u_char *) ngx_http_v3_encode_prefix_int(p, value->len, 7);
+
+ p = ngx_cpymem(p, value->data, value->len);
+
+ return (uintptr_t) p;
+}
+
+
+uintptr_t
+ngx_http_v3_encode_header_pbi(u_char *p, ngx_uint_t index)
+{
+ /* Indexed Header Field With Post-Base Index */
+
+ if (p == NULL) {
+ return ngx_http_v3_encode_prefix_int(NULL, index, 4);
+ }
+
+ *p = 0x10;
+
+ return ngx_http_v3_encode_prefix_int(p, index, 4);
+}
+
+
+uintptr_t
+ngx_http_v3_encode_header_lpbi(u_char *p, ngx_uint_t index, u_char *data,
+ size_t len)
+{
+ /* Literal Header Field With Post-Base Name Reference */
+
+ if (p == NULL) {
+ return ngx_http_v3_encode_prefix_int(NULL, index, 3)
+ + ngx_http_v3_encode_prefix_int(NULL, len, 7)
+ + len;
+ }
+
+ *p = 0x08;
+ p = (u_char *) ngx_http_v3_encode_prefix_int(p, index, 3);
+
+ *p = 0;
+ p = (u_char *) ngx_http_v3_encode_prefix_int(p, len, 7);
+
+ if (data) {
+ p = ngx_cpymem(p, data, len);
+ }
+
+ return (uintptr_t) p;
+}
diff --git a/src/http/v3/ngx_http_v3.h b/src/http/v3/ngx_http_v3.h
index 51117f720..28e0e6f11 100644
--- a/src/http/v3/ngx_http_v3.h
+++ b/src/http/v3/ngx_http_v3.h
@@ -132,6 +132,18 @@ uintptr_t ngx_http_v3_encode_varlen_int(u_char *p, uint64_t value);
uintptr_t ngx_http_v3_encode_prefix_int(u_char *p, uint64_t value,
ngx_uint_t prefix);
+uintptr_t ngx_http_v3_encode_header_block_prefix(u_char *p,
+ ngx_uint_t insert_count, ngx_uint_t sign, ngx_uint_t delta_base);
+uintptr_t ngx_http_v3_encode_header_ri(u_char *p, ngx_uint_t dynamic,
+ ngx_uint_t index);
+uintptr_t ngx_http_v3_encode_header_lri(u_char *p, ngx_uint_t dynamic,
+ ngx_uint_t index, u_char *data, size_t len);
+uintptr_t ngx_http_v3_encode_header_l(u_char *p, ngx_str_t *name,
+ ngx_str_t *value);
+uintptr_t ngx_http_v3_encode_header_pbi(u_char *p, ngx_uint_t index);
+uintptr_t ngx_http_v3_encode_header_lpbi(u_char *p, ngx_uint_t index,
+ u_char *data, size_t len);
+
ngx_int_t ngx_http_v3_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic,
ngx_uint_t index, ngx_str_t *value);
ngx_int_t ngx_http_v3_insert(ngx_connection_t *c, ngx_str_t *name,
diff --git a/src/http/v3/ngx_http_v3_request.c b/src/http/v3/ngx_http_v3_request.c
index 0ffa8927d..5fa232a91 100644
--- a/src/http/v3/ngx_http_v3_request.c
+++ b/src/http/v3/ngx_http_v3_request.c
@@ -10,6 +10,16 @@
#include <ngx_http.h>
+/* static table indices */
+#define NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO 4
+#define NGX_HTTP_V3_HEADER_DATE 6
+#define NGX_HTTP_V3_HEADER_LAST_MODIFIED 10
+#define NGX_HTTP_V3_HEADER_STATUS_200 25
+#define NGX_HTTP_V3_HEADER_CONTENT_TYPE_TEXT_PLAIN 53
+#define NGX_HTTP_V3_HEADER_VARY_ACCEPT_ENCODING 59
+#define NGX_HTTP_V3_HEADER_SERVER 92
+
+
static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r,
ngx_str_t *name, ngx_str_t *value);
@@ -416,7 +426,7 @@ ngx_http_v3_create_header(ngx_http_request_t *r)
u_char *p;
size_t len, n;
ngx_buf_t *b;
- ngx_uint_t i, j;
+ ngx_uint_t i;
ngx_chain_t *hl, *cl, *bl;
ngx_list_part_t *part;
ngx_table_elt_t *header;
@@ -427,14 +437,16 @@ ngx_http_v3_create_header(ngx_http_request_t *r)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 create header");
- len = 2;
+ len = ngx_http_v3_encode_header_block_prefix(NULL, 0, 0, 0);
if (r->headers_out.status == NGX_HTTP_OK) {
- len += ngx_http_v3_encode_prefix_int(NULL, 25, 6);
+ len += ngx_http_v3_encode_header_ri(NULL, 0,
+ NGX_HTTP_V3_HEADER_STATUS_200);
} else {
- len += 3 + ngx_http_v3_encode_prefix_int(NULL, 25, 4)
- + ngx_http_v3_encode_prefix_int(NULL, 3, 7);
+ len += ngx_http_v3_encode_header_lri(NULL, 0,
+ NGX_HTTP_V3_HEADER_STATUS_200,
+ NULL, 3);
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
@@ -450,15 +462,14 @@ ngx_http_v3_create_header(ngx_http_request_t *r)
n = sizeof("nginx") - 1;
}
- len += ngx_http_v3_encode_prefix_int(NULL, 92, 4)
- + ngx_http_v3_encode_prefix_int(NULL, n, 7) + n;
+ len += ngx_http_v3_encode_header_lri(NULL, 0,
+ NGX_HTTP_V3_HEADER_SERVER,
+ NULL, n);
}
if (r->headers_out.date == NULL) {
- len += ngx_http_v3_encode_prefix_int(NULL, 6, 4)
- + ngx_http_v3_encode_prefix_int(NULL, ngx_cached_http_time.len,
- 7)
- + ngx_cached_http_time.len;
+ len += ngx_http_v3_encode_header_lri(NULL, 0, NGX_HTTP_V3_HEADER_DATE,
+ NULL, ngx_cached_http_time.len);
}
if (r->headers_out.content_type.len) {
@@ -470,22 +481,29 @@ ngx_http_v3_create_header(ngx_http_request_t *r)
n += sizeof("; charset=") - 1 + r->headers_out.charset.len;
}
- len += ngx_http_v3_encode_prefix_int(NULL, 53, 4)
- + ngx_http_v3_encode_prefix_int(NULL, n, 7) + n;
+ len += ngx_http_v3_encode_header_lri(NULL, 0,
+ NGX_HTTP_V3_HEADER_CONTENT_TYPE_TEXT_PLAIN,
+ NULL, n);
}
- if (r->headers_out.content_length_n > 0) {
- len += ngx_http_v3_encode_prefix_int(NULL, 4, 4) + 1 + NGX_OFF_T_LEN;
+ if (r->headers_out.content_length == NULL) {
+ if (r->headers_out.content_length_n > 0) {
+ len += ngx_http_v3_encode_header_lri(NULL, 0,
+ NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO,
+ NULL, NGX_OFF_T_LEN);
- } else if (r->headers_out.content_length_n == 0) {
- len += ngx_http_v3_encode_prefix_int(NULL, 4, 6);
+ } else if (r->headers_out.content_length_n == 0) {
+ len += ngx_http_v3_encode_header_ri(NULL, 0,
+ NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO);
+ }
}
if (r->headers_out.last_modified == NULL
&& r->headers_out.last_modified_time != -1)
{
- len += ngx_http_v3_encode_prefix_int(NULL, 10, 4) + 1
- + sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT");
+ len += ngx_http_v3_encode_header_lri(NULL, 0,
+ NGX_HTTP_V3_HEADER_LAST_MODIFIED, NULL,
+ sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1);
}
/* XXX location */
@@ -493,8 +511,8 @@ ngx_http_v3_create_header(ngx_http_request_t *r)
#if (NGX_HTTP_GZIP)
if (r->gzip_vary) {
if (clcf->gzip_vary) {
- /* Vary: Accept-Encoding */
- len += ngx_http_v3_encode_prefix_int(NULL, 59, 6);
+ len += ngx_http_v3_encode_header_ri(NULL, 0,
+ NGX_HTTP_V3_HEADER_VARY_ACCEPT_ENCODING);
} else {
r->gzip_vary = 0;
@@ -521,10 +539,8 @@ ngx_http_v3_create_header(ngx_http_request_t *r)
continue;
}
- len += ngx_http_v3_encode_prefix_int(NULL, header[i].key.len, 3)
- + header[i].key.len
- + ngx_http_v3_encode_prefix_int(NULL, header[i].value.len, 7 )
- + header[i].value.len;
+ len += ngx_http_v3_encode_header_l(NULL, &header[i].key,
+ &header[i].value);
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 header len:%uz", len);
@@ -534,20 +550,17 @@ ngx_http_v3_create_header(ngx_http_request_t *r)
return NULL;
}
- *b->last++ = 0;
- *b->last++ = 0;
+ b->last = (u_char *) ngx_http_v3_encode_header_block_prefix(b->last,
+ 0, 0, 0);
if (r->headers_out.status == NGX_HTTP_OK) {
- /* :status: 200 */
- *b->last = 0xc0;
- b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 25, 6);
+ b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0,
+ NGX_HTTP_V3_HEADER_STATUS_200);
} else {
- /* :status: 200 */
- *b->last = 0x70;
- b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 25, 4);
- *b->last = 0;
- b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 3, 7);
+ b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
+ NGX_HTTP_V3_HEADER_STATUS_200,
+ NULL, 3);
b->last = ngx_sprintf(b->last, "%03ui", r->headers_out.status);
}
@@ -565,23 +578,16 @@ ngx_http_v3_create_header(ngx_http_request_t *r)
n = sizeof("nginx") - 1;
}
- /* server */
- *b->last = 0x70;
- b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 92, 4);
- *b->last = 0;
- b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, n, 7);
- b->last = ngx_cpymem(b->last, p, n);
+ b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
+ NGX_HTTP_V3_HEADER_SERVER,
+ p, n);
}
if (r->headers_out.date == NULL) {
- /* date */
- *b->last = 0x70;
- b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 6, 4);
- *b->last = 0;
- b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last,
- ngx_cached_http_time.len, 7);
- b->last = ngx_cpymem(b->last, ngx_cached_http_time.data,
- ngx_cached_http_time.len);
+ b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
+ NGX_HTTP_V3_HEADER_DATE,
+ ngx_cached_http_time.data,
+ ngx_cached_http_time.len);
}
if (r->headers_out.content_type.len) {
@@ -593,23 +599,21 @@ ngx_http_v3_create_header(ngx_http_request_t *r)
n += sizeof("; charset=") - 1 + r->headers_out.charset.len;
}
- /* content-type: text/plain */
- *b->last = 0x70;
- b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 53, 4);
- *b->last = 0;
- b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, n, 7);
+ b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
+ NGX_HTTP_V3_HEADER_CONTENT_TYPE_TEXT_PLAIN,
+ NULL, n);
p = b->last;
- b->last = ngx_copy(b->last, r->headers_out.content_type.data,
- r->headers_out.content_type.len);
+ b->last = ngx_cpymem(b->last, r->headers_out.content_type.data,
+ r->headers_out.content_type.len);
if (r->headers_out.content_type_len == r->headers_out.content_type.len
&& r->headers_out.charset.len)
{
b->last = ngx_cpymem(b->last, "; charset=",
sizeof("; charset=") - 1);
- b->last = ngx_copy(b->last, r->headers_out.charset.data,
- r->headers_out.charset.len);
+ b->last = ngx_cpymem(b->last, r->headers_out.charset.data,
+ r->headers_out.charset.len);
/* update r->headers_out.content_type for possible logging */
@@ -618,36 +622,38 @@ ngx_http_v3_create_header(ngx_http_request_t *r)
}
}
- if (r->headers_out.content_length_n > 0) {
- /* content-length: 0 */
- *b->last = 0x70;
- b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 4, 4);
- p = b->last++;
- b->last = ngx_sprintf(b->last, "%O", r->headers_out.content_length_n);
- *p = b->last - p - 1;
+ if (r->headers_out.content_length == NULL) {
+ if (r->headers_out.content_length_n > 0) {
+ p = ngx_sprintf(b->last, "%O", r->headers_out.content_length_n);
+ n = p - b->last;
+
+ b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
+ NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO,
+ NULL, n);
+
+ b->last = ngx_sprintf(b->last, "%O",
+ r->headers_out.content_length_n);
- } else if (r->headers_out.content_length_n == 0) {
- /* content-length: 0 */
- *b->last = 0xc0;
- b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 4, 6);
+ } else if (r->headers_out.content_length_n == 0) {
+ b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0,
+ NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO);
+ }
}
if (r->headers_out.last_modified == NULL
&& r->headers_out.last_modified_time != -1)
{
- /* last-modified */
- *b->last = 0x70;
- b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 10, 4);
- p = b->last++;
+ b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
+ NGX_HTTP_V3_HEADER_LAST_MODIFIED, NULL,
+ sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1);
+
b->last = ngx_http_time(b->last, r->headers_out.last_modified_time);
- *p = b->last - p - 1;
}
#if (NGX_HTTP_GZIP)
if (r->gzip_vary) {
- /* vary: accept-encoding */
- *b->last = 0xc0;
- b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 59, 6);
+ b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0,
+ NGX_HTTP_V3_HEADER_VARY_ACCEPT_ENCODING);
}
#endif
@@ -670,19 +676,9 @@ ngx_http_v3_create_header(ngx_http_request_t *r)
continue;
}
- *b->last = 0x30;
- b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last,
- header[i].key.len,
- 3);
- for (j = 0; j < header[i].key.len; j++) {
- *b->last++ = ngx_tolower(header[i].key.data[j]);
- }
-
- *b->last = 0;
- b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last,
- header[i].value.len,
- 7);
- b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len);
+ b->last = (u_char *) ngx_http_v3_encode_header_l(b->last,
+ &header[i].key,
+ &header[i].value);
}
if (r->header_only) {