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.
This commit is contained in:
Willy Tarreau 2019-01-03 18:39:54 +01:00
parent 52610e905d
commit 1e1f27c5c1
2 changed files with 82 additions and 0 deletions

View File

@ -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_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_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_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. * Some helpful debugging functions.

View File

@ -894,3 +894,84 @@ int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *m
fail: fail:
return -1; return -1;
} }
/* Takes an H2 headers list <list> terminated by a name being <NULL,0> and
* emits the equivalent HTX trailers block not including the empty line. The
* output contents are emitted in <htx>, 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 <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 <n.len>
* 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;
}