# HG changeset patch # User Roman Arutyunyan # Date 1594645200 -10800 # Node ID 79125ef2e39f611f7f03607dc8b1ac1d22a52574 # Parent 6e84524886d4f83028311d56bf102cbe9406b406 HTTP/3: header encoding functions. diff --git a/src/http/v3/ngx_http_v3.c b/src/http/v3/ngx_http_v3.c --- 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, 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 --- 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( 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 --- a/src/http/v3/ngx_http_v3_request.c +++ b/src/http/v3/ngx_http_v3_request.c @@ -10,6 +10,16 @@ #include +/* 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_reque 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_reque 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_reque 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_reque 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_reque #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_reque 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_reque 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_reque 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_reque 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_reque } } - 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; - } 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); + 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) { + 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_reque 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) {