From: Willy Tarreau Date: Thu, 3 Jan 2019 17:39:54 +0000 (+0100) Subject: MINOR: h2: add h2_make_htx_trailers to turn H2 headers to HTX trailers X-Git-Tag: v2.0-dev1~277 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1e1f27c5c16e9b54b19f14a1558b5ce4cb9f09f2;p=thirdparty%2Fhaproxy.git MINOR: h2: add h2_make_htx_trailers to turn H2 headers to HTX trailers This function is usable to transform a list of H2 header fields to a HTX trailers block. It takes care of rejecting forbidden headers and pseudo-headers when performing the conversion. It also emits the trailing CRLF that is currently needed in the HTX trailers block. --- diff --git a/include/common/h2.h b/include/common/h2.h index c4b008376d..507a291b08 100644 --- a/include/common/h2.h +++ b/include/common/h2.h @@ -182,6 +182,7 @@ int h2_make_h1_trailers(struct http_hdr *list, char *out, int osize); int h2_parse_cont_len_header(unsigned int *msgf, struct ist *value, unsigned long long *body_len); int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *msgf); int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *msgf); +int h2_make_htx_trailers(struct http_hdr *list, struct htx *htx); /* * Some helpful debugging functions. diff --git a/src/h2.c b/src/h2.c index 4dba6758e0..72b2dc6138 100644 --- a/src/h2.c +++ b/src/h2.c @@ -894,3 +894,84 @@ int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *m fail: return -1; } + +/* Takes an H2 headers list terminated by a name being and + * emits the equivalent HTX trailers block not including the empty line. The + * output contents are emitted in , and a positive value is returned if + * some bytes were emitted. In case of error, a negative error code is + * returned. The caller must have verified that the message in the buffer is + * compatible with receipt of trailers. Note that for now the HTX trailers + * block is in fact an H1 block and it must contain the trailing CRLF. + * + * The headers list must be composed of : + * - n.name != NULL, n.len > 0 : literal header name + * - n.name == NULL, n.len > 0 : indexed pseudo header name number + * among H2_PHDR_IDX_* (illegal here) + * - n.name ignored, n.len == 0 : end of list + * - in all cases except the end of list, v.name and v.len must designate a + * valid value. + */ +int h2_make_htx_trailers(struct http_hdr *list, struct htx *htx) +{ + struct htx_blk *blk; + char *out; + uint32_t idx; + int len; + int i; + + len = 2; // CRLF + for (idx = 0; list[idx].n.len != 0; idx++) { + if (!list[idx].n.ptr) { + /* This is an indexed pseudo-header (RFC7540#8.1.2.1) */ + goto fail; + } + + /* RFC7540#8.1.2: upper case not allowed in header field names */ + for (i = 0; i < list[idx].n.len; i++) + if ((uint8_t)(list[idx].n.ptr[i] - 'A') < 'Z' - 'A') + goto fail; + + if (h2_str_to_phdr(list[idx].n) != 0) { + /* This is a pseudo-header (RFC7540#8.1.2.1) */ + goto fail; + } + + /* these ones are forbidden in trailers (RFC7540#8.1.2.2) */ + if (isteq(list[idx].n, ist("host")) || + isteq(list[idx].n, ist("content-length")) || + isteq(list[idx].n, ist("connection")) || + isteq(list[idx].n, ist("proxy-connection")) || + isteq(list[idx].n, ist("keep-alive")) || + isteq(list[idx].n, ist("upgrade")) || + isteq(list[idx].n, ist("te")) || + isteq(list[idx].n, ist("transfer-encoding"))) + goto fail; + + len += list[idx].n.len + 2 + list[idx].v.len + 2; + } + + blk = htx_add_blk_type_size(htx, HTX_BLK_TLR, len); + if (!blk) + goto fail; + + out = htx_get_blk_ptr(htx, blk); + for (idx = 0; list[idx].n.len != 0; idx++) { + /* copy "name: value" */ + memcpy(out, list[idx].n.ptr, list[idx].n.len); + out += list[idx].n.len; + *(out++) = ':'; + *(out++) = ' '; + + memcpy(out, list[idx].v.ptr, list[idx].v.len); + out += list[idx].v.len; + *(out++) = '\r'; + *(out++) = '\n'; + } + *(out++) = '\r'; + *(out++) = '\n'; + + return 1; + + fail: + return -1; +}