mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-29 08:02:08 +00:00
MEDIUM: htx: Add the parsing of trailers of chunked messages
HTTP trailers are now parsed in the same way headers are. It means trailers are converted to K/V blocks followed by an end-of-trailer marker. For now, to make things simple, the type for trailer blocks are not the same than for header blocks. But the aim is to make no difference between headers and trailers by using the same type. Probably for the end-of marker too.
This commit is contained in:
parent
8f3c256f7e
commit
2d7c5395ed
@ -103,7 +103,8 @@ enum htx_blk_type {
|
|||||||
HTX_BLK_DATA = 4, /* data block */
|
HTX_BLK_DATA = 4, /* data block */
|
||||||
HTX_BLK_EOD = 5, /* end-of-data block */
|
HTX_BLK_EOD = 5, /* end-of-data block */
|
||||||
HTX_BLK_TLR = 6, /* trailer name/value block */
|
HTX_BLK_TLR = 6, /* trailer name/value block */
|
||||||
HTX_BLK_EOM = 7, /* end-of-message block */
|
HTX_BLK_EOT = 7, /* end-of-trailers block */
|
||||||
|
HTX_BLK_EOM = 8, /* end-of-message block */
|
||||||
/* 8 .. 14 unused */
|
/* 8 .. 14 unused */
|
||||||
HTX_BLK_UNUSED = 15, /* unused/removed block */
|
HTX_BLK_UNUSED = 15, /* unused/removed block */
|
||||||
};
|
};
|
||||||
@ -182,19 +183,19 @@ struct htx_blk *htx_replace_header(struct htx *htx, struct htx_blk *blk,
|
|||||||
const struct ist name, const struct ist value);
|
const struct ist name, const struct ist value);
|
||||||
|
|
||||||
struct htx_blk *htx_add_header(struct htx *htx, const struct ist name, const struct ist value);
|
struct htx_blk *htx_add_header(struct htx *htx, const struct ist name, const struct ist value);
|
||||||
|
struct htx_blk *htx_add_trailer(struct htx *htx, const struct ist name, const struct ist value);
|
||||||
struct htx_blk *htx_add_blk_type_size(struct htx *htx, enum htx_blk_type type, uint32_t blksz);
|
struct htx_blk *htx_add_blk_type_size(struct htx *htx, enum htx_blk_type type, uint32_t blksz);
|
||||||
struct htx_blk *htx_add_all_headers(struct htx *htx, const struct http_hdr *hdrs);
|
struct htx_blk *htx_add_all_headers(struct htx *htx, const struct http_hdr *hdrs);
|
||||||
|
struct htx_blk *htx_add_all_trailers(struct htx *htx, const struct http_hdr *hdrs);
|
||||||
struct htx_blk *htx_add_endof(struct htx *htx, enum htx_blk_type type);
|
struct htx_blk *htx_add_endof(struct htx *htx, enum htx_blk_type type);
|
||||||
struct htx_blk *htx_add_data_atonce(struct htx *htx, const struct ist data);
|
struct htx_blk *htx_add_data_atonce(struct htx *htx, const struct ist data);
|
||||||
size_t htx_add_data(struct htx *htx, const struct ist data);
|
size_t htx_add_data(struct htx *htx, const struct ist data);
|
||||||
struct htx_blk *htx_add_trailer(struct htx *htx, const struct ist tlr);
|
|
||||||
struct htx_blk *htx_add_data_before(struct htx *htx, const struct htx_blk *ref, const struct ist data);
|
struct htx_blk *htx_add_data_before(struct htx *htx, const struct htx_blk *ref, const struct ist data);
|
||||||
|
|
||||||
int htx_reqline_to_h1(const struct htx_sl *sl, struct buffer *chk);
|
int htx_reqline_to_h1(const struct htx_sl *sl, struct buffer *chk);
|
||||||
int htx_stline_to_h1(const struct htx_sl *sl, struct buffer *chk);
|
int htx_stline_to_h1(const struct htx_sl *sl, struct buffer *chk);
|
||||||
int htx_hdr_to_h1(const struct ist n, const struct ist v, struct buffer *chk);
|
int htx_hdr_to_h1(const struct ist n, const struct ist v, struct buffer *chk);
|
||||||
int htx_data_to_h1(const struct ist data, struct buffer *chk, int chunked);
|
int htx_data_to_h1(const struct ist data, struct buffer *chk, int chunked);
|
||||||
int htx_trailer_to_h1(const struct ist tlr, struct buffer *chk);
|
|
||||||
|
|
||||||
/* Functions and macros to get parts of the start-line or legnth of these
|
/* Functions and macros to get parts of the start-line or legnth of these
|
||||||
* parts
|
* parts
|
||||||
@ -299,6 +300,7 @@ static inline uint32_t htx_get_blksz(const struct htx_blk *blk)
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case HTX_BLK_HDR:
|
case HTX_BLK_HDR:
|
||||||
|
case HTX_BLK_TLR:
|
||||||
/* name.length + value.length */
|
/* name.length + value.length */
|
||||||
return ((blk->info & 0xff) + ((blk->info >> 8) & 0xfffff));
|
return ((blk->info & 0xff) + ((blk->info >> 8) & 0xfffff));
|
||||||
default:
|
default:
|
||||||
@ -513,12 +515,12 @@ static inline void htx_set_blk_value_len(struct htx_blk *blk, uint32_t vlen)
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case HTX_BLK_HDR:
|
case HTX_BLK_HDR:
|
||||||
|
case HTX_BLK_TLR:
|
||||||
blk->info = (type << 28) + (vlen << 8) + (blk->info & 0xff);
|
blk->info = (type << 28) + (vlen << 8) + (blk->info & 0xff);
|
||||||
break;
|
break;
|
||||||
case HTX_BLK_REQ_SL:
|
case HTX_BLK_REQ_SL:
|
||||||
case HTX_BLK_RES_SL:
|
case HTX_BLK_RES_SL:
|
||||||
case HTX_BLK_DATA:
|
case HTX_BLK_DATA:
|
||||||
case HTX_BLK_TLR:
|
|
||||||
blk->info = (type << 28) + vlen;
|
blk->info = (type << 28) + vlen;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -543,6 +545,7 @@ static inline struct ist htx_get_blk_name(const struct htx *htx, const struct ht
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case HTX_BLK_HDR:
|
case HTX_BLK_HDR:
|
||||||
|
case HTX_BLK_TLR:
|
||||||
ret.ptr = htx_get_blk_ptr(htx, blk);
|
ret.ptr = htx_get_blk_ptr(htx, blk);
|
||||||
ret.len = blk->info & 0xff;
|
ret.len = blk->info & 0xff;
|
||||||
break;
|
break;
|
||||||
@ -564,6 +567,7 @@ static inline struct ist htx_get_blk_value(const struct htx *htx, const struct h
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case HTX_BLK_HDR:
|
case HTX_BLK_HDR:
|
||||||
|
case HTX_BLK_TLR:
|
||||||
ret.ptr = htx_get_blk_ptr(htx, blk) + (blk->info & 0xff);
|
ret.ptr = htx_get_blk_ptr(htx, blk) + (blk->info & 0xff);
|
||||||
ret.len = (blk->info >> 8) & 0xfffff;
|
ret.len = (blk->info >> 8) & 0xfffff;
|
||||||
break;
|
break;
|
||||||
@ -571,7 +575,6 @@ static inline struct ist htx_get_blk_value(const struct htx *htx, const struct h
|
|||||||
case HTX_BLK_REQ_SL:
|
case HTX_BLK_REQ_SL:
|
||||||
case HTX_BLK_RES_SL:
|
case HTX_BLK_RES_SL:
|
||||||
case HTX_BLK_DATA:
|
case HTX_BLK_DATA:
|
||||||
case HTX_BLK_TLR:
|
|
||||||
ret.ptr = htx_get_blk_ptr(htx, blk);
|
ret.ptr = htx_get_blk_ptr(htx, blk);
|
||||||
ret.len = blk->info & 0xfffffff;
|
ret.len = blk->info & 0xfffffff;
|
||||||
break;
|
break;
|
||||||
@ -755,6 +758,7 @@ static inline const char *htx_blk_type_str(enum htx_blk_type type)
|
|||||||
case HTX_BLK_DATA: return "HTX_BLK_DATA";
|
case HTX_BLK_DATA: return "HTX_BLK_DATA";
|
||||||
case HTX_BLK_EOD: return "HTX_BLK_EOD";
|
case HTX_BLK_EOD: return "HTX_BLK_EOD";
|
||||||
case HTX_BLK_TLR: return "HTX_BLK_TLR";
|
case HTX_BLK_TLR: return "HTX_BLK_TLR";
|
||||||
|
case HTX_BLK_EOT: return "HTX_BLK_EOT";
|
||||||
case HTX_BLK_EOM: return "HTX_BLK_EOM";
|
case HTX_BLK_EOM: return "HTX_BLK_EOM";
|
||||||
case HTX_BLK_UNUSED: return "HTX_BLK_UNUSED";
|
case HTX_BLK_UNUSED: return "HTX_BLK_UNUSED";
|
||||||
default: return "HTX_BLK_???";
|
default: return "HTX_BLK_???";
|
||||||
@ -789,7 +793,7 @@ static inline void htx_dump(struct htx *htx)
|
|||||||
HTX_SL_P2_LEN(sl), HTX_SL_P2_PTR(sl),
|
HTX_SL_P2_LEN(sl), HTX_SL_P2_PTR(sl),
|
||||||
HTX_SL_P3_LEN(sl), HTX_SL_P3_PTR(sl));
|
HTX_SL_P3_LEN(sl), HTX_SL_P3_PTR(sl));
|
||||||
}
|
}
|
||||||
else if (type == HTX_BLK_HDR)
|
else if (type == HTX_BLK_HDR || type == HTX_BLK_TLR)
|
||||||
fprintf(stderr, "\t\t[%u] type=%-17s - size=%-6u - addr=%-6u\t%.*s: %.*s\n",
|
fprintf(stderr, "\t\t[%u] type=%-17s - size=%-6u - addr=%-6u\t%.*s: %.*s\n",
|
||||||
pos, htx_blk_type_str(type), sz, blk->addr,
|
pos, htx_blk_type_str(type), sz, blk->addr,
|
||||||
(int)n.len, n.ptr,
|
(int)n.len, n.ptr,
|
||||||
|
@ -875,7 +875,7 @@ static unsigned int htx_cache_dump_blk(struct appctx *appctx, struct htx *htx, e
|
|||||||
max = htx_get_max_blksz(htx, channel_htx_recv_max(si_ic(appctx->owner), htx));
|
max = htx_get_max_blksz(htx, channel_htx_recv_max(si_ic(appctx->owner), htx));
|
||||||
if (!max)
|
if (!max)
|
||||||
return 0;
|
return 0;
|
||||||
blksz = ((type == HTX_BLK_HDR)
|
blksz = ((type == HTX_BLK_HDR || type == HTX_BLK_TLR)
|
||||||
? (info & 0xff) + ((info >> 8) & 0xfffff)
|
? (info & 0xff) + ((info >> 8) & 0xfffff)
|
||||||
: info & 0xfffffff);
|
: info & 0xfffffff);
|
||||||
if (blksz > max)
|
if (blksz > max)
|
||||||
|
@ -247,6 +247,7 @@ comp_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
|
|||||||
|
|
||||||
case HTX_BLK_EOD:
|
case HTX_BLK_EOD:
|
||||||
case HTX_BLK_TLR:
|
case HTX_BLK_TLR:
|
||||||
|
case HTX_BLK_EOT:
|
||||||
case HTX_BLK_EOM:
|
case HTX_BLK_EOM:
|
||||||
if (msg->flags & HTTP_MSGF_COMPRESSING) {
|
if (msg->flags & HTTP_MSGF_COMPRESSING) {
|
||||||
if (htx_compression_buffer_init(htx, &trash) < 0) {
|
if (htx_compression_buffer_init(htx, &trash) < 0) {
|
||||||
|
@ -151,7 +151,7 @@ trace_htx_hexdump(struct htx *htx, unsigned int offset, unsigned int len)
|
|||||||
if (v.len > len)
|
if (v.len > len)
|
||||||
v.len = len;
|
v.len = len;
|
||||||
len -= v.len;
|
len -= v.len;
|
||||||
if (type == HTX_BLK_DATA || type == HTX_BLK_TLR)
|
if (type == HTX_BLK_DATA)
|
||||||
trace_hexdump(v);
|
trace_hexdump(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
38
src/h2.c
38
src/h2.c
@ -943,13 +943,11 @@ int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *m
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Takes an H2 headers list <list> terminated by a name being <NULL,0> and
|
/* Takes an H2 headers list <list> terminated by a name being <NULL,0> and emits
|
||||||
* emits the equivalent HTX trailers block not including the empty line. The
|
* the equivalent HTX trailers blocks. The output contents are emitted in <htx>,
|
||||||
* output contents are emitted in <htx>, and a positive value is returned if
|
* and a positive value is returned if some bytes were emitted. In case of
|
||||||
* some bytes were emitted. In case of error, a negative error code is
|
* error, a negative error code is returned. The caller must have verified that
|
||||||
* returned. The caller must have verified that the message in the buffer is
|
* the message in the buffer is compatible with receipt of trailers.
|
||||||
* 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 :
|
* The headers list <list> must be composed of :
|
||||||
* - n.name != NULL, n.len > 0 : literal header name
|
* - n.name != NULL, n.len > 0 : literal header name
|
||||||
@ -961,13 +959,9 @@ int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *m
|
|||||||
*/
|
*/
|
||||||
int h2_make_htx_trailers(struct http_hdr *list, struct htx *htx)
|
int h2_make_htx_trailers(struct http_hdr *list, struct htx *htx)
|
||||||
{
|
{
|
||||||
struct htx_blk *blk;
|
|
||||||
char *out;
|
|
||||||
uint32_t idx;
|
uint32_t idx;
|
||||||
int len;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
len = 2; // CRLF
|
|
||||||
for (idx = 0; list[idx].n.len != 0; idx++) {
|
for (idx = 0; list[idx].n.len != 0; idx++) {
|
||||||
if (!list[idx].n.ptr) {
|
if (!list[idx].n.ptr) {
|
||||||
/* This is an indexed pseudo-header (RFC7540#8.1.2.1) */
|
/* This is an indexed pseudo-header (RFC7540#8.1.2.1) */
|
||||||
@ -995,29 +989,13 @@ int h2_make_htx_trailers(struct http_hdr *list, struct htx *htx)
|
|||||||
isteq(list[idx].n, ist("transfer-encoding")))
|
isteq(list[idx].n, ist("transfer-encoding")))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
len += list[idx].n.len + 2 + list[idx].v.len + 2;
|
if (!htx_add_trailer(htx, list[idx].n, list[idx].v))
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
blk = htx_add_blk_type_size(htx, HTX_BLK_TLR, len);
|
if (!htx_add_endof(htx, HTX_BLK_EOT))
|
||||||
if (!blk)
|
|
||||||
goto fail;
|
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;
|
return 1;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
81
src/htx.c
81
src/htx.c
@ -293,7 +293,7 @@ void htx_truncate(struct htx *htx, uint32_t offset)
|
|||||||
offset -= sz;
|
offset -= sz;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (type == HTX_BLK_DATA || type == HTX_BLK_TLR) {
|
if (type == HTX_BLK_DATA) {
|
||||||
htx_set_blk_value_len(blk, offset);
|
htx_set_blk_value_len(blk, offset);
|
||||||
htx->data -= (sz - offset);
|
htx->data -= (sz - offset);
|
||||||
}
|
}
|
||||||
@ -407,7 +407,7 @@ struct htx_blk *htx_add_data_atonce(struct htx *htx, const struct ist data)
|
|||||||
return tailblk;
|
return tailblk;
|
||||||
|
|
||||||
add_new_block:
|
add_new_block:
|
||||||
/* FIXME: check tlr.len (< 256MB) */
|
/* FIXME: check data.len (< 256MB) */
|
||||||
blk = htx_add_blk(htx, HTX_BLK_DATA, data.len);
|
blk = htx_add_blk(htx, HTX_BLK_DATA, data.len);
|
||||||
if (!blk)
|
if (!blk)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -492,6 +492,7 @@ struct htx_ret htx_xfer_blks(struct htx *dst, struct htx *src, uint32_t count,
|
|||||||
struct htx_blk *blk, *dstblk;
|
struct htx_blk *blk, *dstblk;
|
||||||
enum htx_blk_type type;
|
enum htx_blk_type type;
|
||||||
uint32_t info, max, sz, ret;
|
uint32_t info, max, sz, ret;
|
||||||
|
int inside_trailers = 0;
|
||||||
|
|
||||||
ret = htx_used_space(dst);
|
ret = htx_used_space(dst);
|
||||||
blk = htx_get_blk(src, htx_get_head(src));
|
blk = htx_get_blk(src, htx_get_head(src));
|
||||||
@ -504,9 +505,9 @@ struct htx_ret htx_xfer_blks(struct htx *dst, struct htx *src, uint32_t count,
|
|||||||
if (type == HTX_BLK_UNUSED)
|
if (type == HTX_BLK_UNUSED)
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
/* Be sure to have enough space to xfer all headers in one
|
/* Be sure to have enough space to xfer all headers/trailers in
|
||||||
* time. If not while <dst> is empty, we report a parsing error
|
* one time. If not while <dst> is empty, we report a parsing
|
||||||
* on <src>.
|
* error on <src>.
|
||||||
*/
|
*/
|
||||||
if (mark >= HTX_BLK_EOH && (type == HTX_BLK_REQ_SL || type == HTX_BLK_RES_SL)) {
|
if (mark >= HTX_BLK_EOH && (type == HTX_BLK_REQ_SL || type == HTX_BLK_RES_SL)) {
|
||||||
struct htx_sl *sl = htx_get_blk_ptr(src, blk);
|
struct htx_sl *sl = htx_get_blk_ptr(src, blk);
|
||||||
@ -517,6 +518,15 @@ struct htx_ret htx_xfer_blks(struct htx *dst, struct htx *src, uint32_t count,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if ((type == HTX_BLK_TLR || type == HTX_BLK_EOT) &&
|
||||||
|
!inside_trailers && mark >= HTX_BLK_EOT) {
|
||||||
|
inside_trailers = 1;
|
||||||
|
if (htx_used_space(src) > count) {
|
||||||
|
if (htx_is_empty(dst))
|
||||||
|
src->flags |= HTX_FL_PARSING_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sz = htx_get_blksz(blk);
|
sz = htx_get_blksz(blk);
|
||||||
info = blk->info;
|
info = blk->info;
|
||||||
@ -714,6 +724,25 @@ struct htx_blk *htx_add_header(struct htx *htx, const struct ist name,
|
|||||||
return blk;
|
return blk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Adds an HTX block of type TLR in <htx>. It returns the new block on
|
||||||
|
* success. Otherwise, it returns NULL. The header name is always lower cased.
|
||||||
|
*/
|
||||||
|
struct htx_blk *htx_add_trailer(struct htx *htx, const struct ist name,
|
||||||
|
const struct ist value)
|
||||||
|
{
|
||||||
|
struct htx_blk *blk;
|
||||||
|
|
||||||
|
/* FIXME: check name.len (< 256B) and value.len (< 1MB) */
|
||||||
|
blk = htx_add_blk(htx, HTX_BLK_TLR, name.len + value.len);
|
||||||
|
if (!blk)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
blk->info += (value.len << 8) + name.len;
|
||||||
|
ist2bin_lc(htx_get_blk_ptr(htx, blk), name);
|
||||||
|
memcpy(htx_get_blk_ptr(htx, blk) + name.len, value.ptr, value.len);
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
|
||||||
/* Adds an HTX block of type <type> in <htx>, of size <blksz>. It returns the
|
/* Adds an HTX block of type <type> in <htx>, of size <blksz>. It returns the
|
||||||
* new block on success. Otherwise, it returns NULL. The caller is responsible
|
* new block on success. Otherwise, it returns NULL. The caller is responsible
|
||||||
* for filling the block itself.
|
* for filling the block itself.
|
||||||
@ -741,6 +770,17 @@ struct htx_blk *htx_add_all_headers(struct htx *htx, const struct http_hdr *hdrs
|
|||||||
return htx_add_endof(htx, HTX_BLK_EOH);
|
return htx_add_endof(htx, HTX_BLK_EOH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct htx_blk *htx_add_all_trailers(struct htx *htx, const struct http_hdr *hdrs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; hdrs[i].n.len; i++) {
|
||||||
|
if (!htx_add_trailer(htx, hdrs[i].n, hdrs[i].v))
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return htx_add_endof(htx, HTX_BLK_EOT);
|
||||||
|
}
|
||||||
|
|
||||||
/* Adds an HTX block of type EOH,EOD or EOM in <htx>. It returns the new block
|
/* Adds an HTX block of type EOH,EOD or EOM in <htx>. It returns the new block
|
||||||
* on success. Otherwise, it returns NULL.
|
* on success. Otherwise, it returns NULL.
|
||||||
*/
|
*/
|
||||||
@ -818,7 +858,7 @@ size_t htx_add_data(struct htx *htx, const struct ist data)
|
|||||||
return len;
|
return len;
|
||||||
|
|
||||||
add_new_block:
|
add_new_block:
|
||||||
/* FIXME: check tlr.len (< 256MB) */
|
/* FIXME: check data.len (< 256MB) */
|
||||||
blk = htx_add_blk(htx, HTX_BLK_DATA, len);
|
blk = htx_add_blk(htx, HTX_BLK_DATA, len);
|
||||||
if (!blk)
|
if (!blk)
|
||||||
return 0;
|
return 0;
|
||||||
@ -828,23 +868,6 @@ size_t htx_add_data(struct htx *htx, const struct ist data)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adds an HTX block of type TLR in <htx>. It returns the new block on
|
|
||||||
* success. Otherwise, it returns NULL.
|
|
||||||
*/
|
|
||||||
struct htx_blk *htx_add_trailer(struct htx *htx, const struct ist tlr)
|
|
||||||
{
|
|
||||||
struct htx_blk *blk;
|
|
||||||
|
|
||||||
/* FIXME: check tlr.len (< 256MB) */
|
|
||||||
blk = htx_add_blk(htx, HTX_BLK_TLR, tlr.len);
|
|
||||||
if (!blk)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
blk->info += tlr.len;
|
|
||||||
memcpy(htx_get_blk_ptr(htx, blk), tlr.ptr, tlr.len);
|
|
||||||
return blk;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct htx_blk *htx_add_data_before(struct htx *htx, const struct htx_blk *ref,
|
struct htx_blk *htx_add_data_before(struct htx *htx, const struct htx_blk *ref,
|
||||||
const struct ist data)
|
const struct ist data)
|
||||||
{
|
{
|
||||||
@ -976,15 +999,3 @@ int htx_data_to_h1(const struct ist data, struct buffer *chk, int chunked)
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Appends the h1 representation of the trailer block <blk> to the chunk
|
|
||||||
* <chk>. It returns 1 if data are successfully appended, otherwise it returns
|
|
||||||
* 0.
|
|
||||||
*/
|
|
||||||
int htx_trailer_to_h1(const struct ist tlr, struct buffer *chk)
|
|
||||||
{
|
|
||||||
/* FIXME: be sure the CRLF is here or remove it when inserted */
|
|
||||||
if (!chunk_memcat(chk, tlr.ptr, tlr.len))
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
194
src/mux_h1.c
194
src/mux_h1.c
@ -66,10 +66,8 @@
|
|||||||
#define H1S_F_NOT_FIRST 0x00000080 /* The H1 stream is not the first one */
|
#define H1S_F_NOT_FIRST 0x00000080 /* The H1 stream is not the first one */
|
||||||
#define H1S_F_BUF_FLUSH 0x00000100 /* Flush input buffer and don't read more data */
|
#define H1S_F_BUF_FLUSH 0x00000100 /* Flush input buffer and don't read more data */
|
||||||
#define H1S_F_SPLICED_DATA 0x00000200 /* Set when the kernel splicing is in used */
|
#define H1S_F_SPLICED_DATA 0x00000200 /* Set when the kernel splicing is in used */
|
||||||
#define H1S_F_HAVE_I_EOD 0x00000400 /* Set during input process to know the last empty chunk was processed */
|
|
||||||
#define H1S_F_HAVE_I_TLR 0x00000800 /* Set during input process to know the trailers were processed */
|
#define H1S_F_HAVE_I_TLR 0x00000800 /* Set during input process to know the trailers were processed */
|
||||||
#define H1S_F_HAVE_O_EOD 0x00001000 /* Set during output process to know the last empty chunk was processed */
|
/* 0x00001000 .. 0x00002000 unused */
|
||||||
#define H1S_F_HAVE_O_TLR 0x00002000 /* Set during output process to know the trailers were processed */
|
|
||||||
#define H1S_F_HAVE_O_CONN 0x00004000 /* Set during output process to know connection mode was processed */
|
#define H1S_F_HAVE_O_CONN 0x00004000 /* Set during output process to know connection mode was processed */
|
||||||
|
|
||||||
/* H1 connection descriptor */
|
/* H1 connection descriptor */
|
||||||
@ -934,6 +932,22 @@ static size_t h1_eval_htx_res_size(struct h1m *h1m, union h1_sl *h1sl, struct ht
|
|||||||
return sz;
|
return sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the EOM in the HTX message and switch the message to the DONE state. It
|
||||||
|
* returns the number of bytes parsed if > 0, or 0 if iet couldn't proceed. This
|
||||||
|
* functions is responsible to update the parser state <h1m>. It also add the
|
||||||
|
* flag CS_FL_EOI on the CS.
|
||||||
|
*/
|
||||||
|
static size_t h1_process_eom(struct h1s *h1s, struct h1m *h1m, struct htx *htx, size_t max)
|
||||||
|
{
|
||||||
|
if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(htx, HTX_BLK_EOM))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
h1m->state = H1_MSG_DONE;
|
||||||
|
h1s->cs->flags |= CS_FL_EOI;
|
||||||
|
return (sizeof(struct htx_blk) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse HTTP/1 headers. It returns the number of bytes parsed if > 0, or 0 if
|
* Parse HTTP/1 headers. It returns the number of bytes parsed if > 0, or 0 if
|
||||||
* it couldn't proceed. Parsing errors are reported by setting H1S_F_*_ERROR
|
* it couldn't proceed. Parsing errors are reported by setting H1S_F_*_ERROR
|
||||||
@ -1178,10 +1192,8 @@ static size_t h1_process_data(struct h1s *h1s, struct h1m *h1m, struct htx *htx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!h1m->curr_len) {
|
if (!h1m->curr_len) {
|
||||||
if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(htx, HTX_BLK_EOM))
|
if (!h1_process_eom(h1s, h1m, htx, max))
|
||||||
goto end;
|
goto end;
|
||||||
h1m->state = H1_MSG_DONE;
|
|
||||||
h1s->cs->flags |= CS_FL_EOI;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (h1m->flags & H1_MF_CHNK) {
|
else if (h1m->flags & H1_MF_CHNK) {
|
||||||
@ -1206,7 +1218,6 @@ static size_t h1_process_data(struct h1s *h1s, struct h1m *h1m, struct htx *htx,
|
|||||||
if (!chksz) {
|
if (!chksz) {
|
||||||
if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(htx, HTX_BLK_EOD))
|
if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(htx, HTX_BLK_EOD))
|
||||||
goto end;
|
goto end;
|
||||||
h1s->flags |= H1S_F_HAVE_I_EOD;
|
|
||||||
h1m->state = H1_MSG_TRAILERS;
|
h1m->state = H1_MSG_TRAILERS;
|
||||||
max -= sizeof(struct htx_blk) + 1;
|
max -= sizeof(struct htx_blk) + 1;
|
||||||
}
|
}
|
||||||
@ -1217,6 +1228,9 @@ static size_t h1_process_data(struct h1s *h1s, struct h1m *h1m, struct htx *htx,
|
|||||||
h1m->body_len += chksz;
|
h1m->body_len += chksz;
|
||||||
*ofs += ret;
|
*ofs += ret;
|
||||||
total += ret;
|
total += ret;
|
||||||
|
|
||||||
|
if (!h1m->curr_len)
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h1m->state == H1_MSG_DATA) {
|
if (h1m->state == H1_MSG_DATA) {
|
||||||
@ -1243,55 +1257,13 @@ static size_t h1_process_data(struct h1s *h1s, struct h1m *h1m, struct htx *htx,
|
|||||||
}
|
}
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h1m->state == H1_MSG_TRAILERS) {
|
|
||||||
/* Trailers were alread parsed, only the EOM
|
|
||||||
* need to be added */
|
|
||||||
if (h1s->flags & H1S_F_HAVE_I_TLR)
|
|
||||||
goto skip_tlr_parsing;
|
|
||||||
|
|
||||||
ret = htx_get_max_blksz(htx, max);
|
|
||||||
ret = h1_measure_trailers(buf, *ofs, ret);
|
|
||||||
if (ret <= 0) {
|
|
||||||
if (!ret && b_full(buf))
|
|
||||||
ret = -1;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Realing input buffer if tailers wrap. For now
|
|
||||||
* this is a workaroung. Because trailers are
|
|
||||||
* not split on CRLF, like headers, there is no
|
|
||||||
* way to know where to split it when trailers
|
|
||||||
* wrap. This is a limitation of
|
|
||||||
* h1_measure_trailers.
|
|
||||||
*/
|
|
||||||
if (b_peek(buf, *ofs) > b_peek(buf, *ofs + ret))
|
|
||||||
b_slow_realign(buf, trash.area, 0);
|
|
||||||
|
|
||||||
if (!htx_add_trailer(htx, ist2(b_peek(buf, *ofs), ret)))
|
|
||||||
goto end;
|
|
||||||
h1s->flags |= H1S_F_HAVE_I_TLR;
|
|
||||||
max -= sizeof(struct htx_blk) + ret;
|
|
||||||
*ofs += ret;
|
|
||||||
total += ret;
|
|
||||||
|
|
||||||
skip_tlr_parsing:
|
|
||||||
if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(htx, HTX_BLK_EOM))
|
|
||||||
goto end;
|
|
||||||
max -= sizeof(struct htx_blk) + 1;
|
|
||||||
h1m->state = H1_MSG_DONE;
|
|
||||||
h1s->cs->flags |= CS_FL_EOI;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* XFER_LEN is set but not CLEN nor CHNK, it means there
|
/* XFER_LEN is set but not CLEN nor CHNK, it means there
|
||||||
* is no body. Switch the message in DONE state
|
* is no body. Switch the message in DONE state
|
||||||
*/
|
*/
|
||||||
if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(htx, HTX_BLK_EOM))
|
if (!h1_process_eom(h1s, h1m, htx, max))
|
||||||
goto end;
|
goto end;
|
||||||
max -= sizeof(struct htx_blk) + 1;
|
|
||||||
h1m->state = H1_MSG_DONE;
|
|
||||||
h1s->cs->flags |= CS_FL_EOI;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1328,6 +1300,65 @@ static size_t h1_process_data(struct h1s *h1s, struct h1m *h1m, struct htx *htx,
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse HTTP/1 trailers. It returns the number of bytes parsed if > 0, or 0 if
|
||||||
|
* it couldn't proceed. Parsing errors are reported by setting H1S_F_*_ERROR
|
||||||
|
* flag and filling h1s->err_pos and h1s->err_state fields. This functions is
|
||||||
|
* responsible to update the parser state <h1m>.
|
||||||
|
*/
|
||||||
|
static size_t h1_process_trailers(struct h1s *h1s, struct h1m *h1m, struct htx *htx,
|
||||||
|
struct buffer *buf, size_t *ofs, size_t max)
|
||||||
|
{
|
||||||
|
struct http_hdr hdrs[MAX_HTTP_HDR];
|
||||||
|
struct h1m tlr_h1m;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!max || !b_data(buf))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
/* Realing input buffer if necessary */
|
||||||
|
if (b_peek(buf, *ofs) > b_tail(buf))
|
||||||
|
b_slow_realign(buf, trash.area, 0);
|
||||||
|
|
||||||
|
tlr_h1m.flags = (H1_MF_NO_PHDR|H1_MF_HDRS_ONLY);
|
||||||
|
ret = h1_headers_to_hdr_list(b_peek(buf, *ofs), b_tail(buf),
|
||||||
|
hdrs, sizeof(hdrs)/sizeof(hdrs[0]), &tlr_h1m, NULL);
|
||||||
|
if (ret <= 0) {
|
||||||
|
/* Incomplete or invalid trailers. If the buffer is full, it's
|
||||||
|
* an error because traliers are too large to be handled by the
|
||||||
|
* parser. */
|
||||||
|
if (ret < 0 || (!ret && !buf_room_for_htx_data(buf)))
|
||||||
|
goto error;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* messages trailers fully parsed. */
|
||||||
|
if (h1_eval_htx_hdrs_size(hdrs) > max) {
|
||||||
|
if (htx_is_empty(htx))
|
||||||
|
goto error;
|
||||||
|
ret = 0;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!htx_add_all_trailers(htx, hdrs))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
*ofs += ret;
|
||||||
|
h1s->flags |= H1S_F_HAVE_I_TLR;
|
||||||
|
end:
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
error:
|
||||||
|
h1m->err_state = h1m->state;
|
||||||
|
h1m->err_pos = h1m->next;
|
||||||
|
h1s->flags |= (!(h1m->flags & H1_MF_RESP) ? H1S_F_REQ_ERROR : H1S_F_RES_ERROR);
|
||||||
|
h1s->cs->flags |= CS_FL_EOI;
|
||||||
|
htx->flags |= HTX_FL_PARSING_ERROR;
|
||||||
|
h1_capture_bad_message(h1s->h1c, h1s, h1m, buf);
|
||||||
|
ret = 0;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process incoming data. It parses data and transfer them from h1c->ibuf into
|
* Process incoming data. It parses data and transfer them from h1c->ibuf into
|
||||||
* <buf>. It returns the number of bytes parsed and transferred if > 0, or 0 if
|
* <buf>. It returns the number of bytes parsed and transferred if > 0, or 0 if
|
||||||
@ -1367,12 +1398,21 @@ static size_t h1_process_input(struct h1c *h1c, struct buffer *buf, size_t count
|
|||||||
h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
|
h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (h1m->state <= H1_MSG_TRAILERS) {
|
else if (h1m->state < H1_MSG_TRAILERS) {
|
||||||
ret = h1_process_data(h1s, h1m, htx, &h1c->ibuf, &total, count, buf);
|
ret = h1_process_data(h1s, h1m, htx, &h1c->ibuf, &total, count, buf);
|
||||||
htx = htx_from_buf(buf);
|
htx = htx_from_buf(buf);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else if (h1m->state == H1_MSG_TRAILERS) {
|
||||||
|
if (!(h1s->flags & H1S_F_HAVE_I_TLR)) {
|
||||||
|
ret = h1_process_trailers(h1s, h1m, htx, &h1c->ibuf, &total, count);
|
||||||
|
if (!ret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!h1_process_eom(h1s, h1m, htx, count))
|
||||||
|
break;
|
||||||
|
}
|
||||||
else if (h1m->state == H1_MSG_DONE) {
|
else if (h1m->state == H1_MSG_DONE) {
|
||||||
if (h1s->req.state < H1_MSG_DONE || h1s->res.state < H1_MSG_DONE)
|
if (h1s->req.state < H1_MSG_DONE || h1s->res.state < H1_MSG_DONE)
|
||||||
h1c->flags |= H1C_F_IN_BUSY;
|
h1c->flags |= H1C_F_IN_BUSY;
|
||||||
@ -1523,7 +1563,7 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun
|
|||||||
|
|
||||||
vlen = sz;
|
vlen = sz;
|
||||||
if (vlen > count) {
|
if (vlen > count) {
|
||||||
if (type != HTX_BLK_DATA && type != HTX_BLK_TLR)
|
if (type != HTX_BLK_DATA)
|
||||||
goto copy;
|
goto copy;
|
||||||
vlen = count;
|
vlen = count;
|
||||||
}
|
}
|
||||||
@ -1647,17 +1687,21 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case H1_MSG_DATA:
|
case H1_MSG_DATA:
|
||||||
if (type == HTX_BLK_EOD) {
|
if (type == HTX_BLK_EOM) {
|
||||||
|
/* Chunked message without explicit trailers */
|
||||||
|
if (h1m->flags & H1_MF_CHNK) {
|
||||||
|
if (!chunk_memcat(tmp, "0\r\n\r\n", 5))
|
||||||
|
goto copy;
|
||||||
|
}
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else if (type == HTX_BLK_EOD)
|
||||||
|
break;
|
||||||
|
else if (type == HTX_BLK_EOT || type == HTX_BLK_TLR) {
|
||||||
if (!chunk_memcat(tmp, "0\r\n", 3))
|
if (!chunk_memcat(tmp, "0\r\n", 3))
|
||||||
goto copy;
|
goto copy;
|
||||||
h1s->flags |= H1S_F_HAVE_O_EOD;
|
|
||||||
h1m->state = H1_MSG_TRAILERS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (type == HTX_BLK_TLR)
|
|
||||||
goto trailers;
|
goto trailers;
|
||||||
else if (type == HTX_BLK_EOM)
|
}
|
||||||
goto done;
|
|
||||||
else if (type != HTX_BLK_DATA)
|
else if (type != HTX_BLK_DATA)
|
||||||
goto error;
|
goto error;
|
||||||
v = htx_get_blk_value(chn_htx, blk);
|
v = htx_get_blk_value(chn_htx, blk);
|
||||||
@ -1669,20 +1713,20 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun
|
|||||||
case H1_MSG_TRAILERS:
|
case H1_MSG_TRAILERS:
|
||||||
if (type == HTX_BLK_EOM)
|
if (type == HTX_BLK_EOM)
|
||||||
goto done;
|
goto done;
|
||||||
else if (type != HTX_BLK_TLR)
|
else if (type != HTX_BLK_TLR && type != HTX_BLK_EOT)
|
||||||
goto error;
|
goto error;
|
||||||
trailers:
|
trailers:
|
||||||
h1m->state = H1_MSG_TRAILERS;
|
h1m->state = H1_MSG_TRAILERS;
|
||||||
if (!(h1s->flags & H1S_F_HAVE_O_EOD)) {
|
if (type == HTX_BLK_EOT) {
|
||||||
if (!chunk_memcat(tmp, "0\r\n", 3))
|
if (!chunk_memcat(tmp, "\r\n", 2))
|
||||||
|
goto copy;
|
||||||
|
}
|
||||||
|
else { // HTX_BLK_TLR
|
||||||
|
n = htx_get_blk_name(chn_htx, blk);
|
||||||
|
v = htx_get_blk_value(chn_htx, blk);
|
||||||
|
if (!htx_hdr_to_h1(n, v, tmp))
|
||||||
goto copy;
|
goto copy;
|
||||||
h1s->flags |= H1S_F_HAVE_O_EOD;
|
|
||||||
}
|
}
|
||||||
v = htx_get_blk_value(chn_htx, blk);
|
|
||||||
v.len = vlen;
|
|
||||||
if (!htx_trailer_to_h1(v, tmp))
|
|
||||||
goto copy;
|
|
||||||
h1s->flags |= H1S_F_HAVE_O_TLR;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case H1_MSG_DONE:
|
case H1_MSG_DONE:
|
||||||
@ -1690,18 +1734,6 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun
|
|||||||
goto error;
|
goto error;
|
||||||
done:
|
done:
|
||||||
h1m->state = H1_MSG_DONE;
|
h1m->state = H1_MSG_DONE;
|
||||||
if ((h1m->flags & H1_MF_CHNK)) {
|
|
||||||
if (!(h1s->flags & H1S_F_HAVE_O_EOD)) {
|
|
||||||
if (!chunk_memcat(tmp, "0\r\n", 3))
|
|
||||||
goto copy;
|
|
||||||
h1s->flags |= H1S_F_HAVE_O_EOD;
|
|
||||||
}
|
|
||||||
if (!(h1s->flags & H1S_F_HAVE_O_TLR)) {
|
|
||||||
if (!chunk_memcat(tmp, "\r\n", 2))
|
|
||||||
goto copy;
|
|
||||||
h1s->flags |= H1S_F_HAVE_O_TLR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
67
src/mux_h2.c
67
src/mux_h2.c
@ -3687,13 +3687,8 @@ next_frame:
|
|||||||
* the EOM block we must remove the TLR block we've just added.
|
* the EOM block we must remove the TLR block we've just added.
|
||||||
*/
|
*/
|
||||||
if (htx) {
|
if (htx) {
|
||||||
if (!htx_add_endof(htx, HTX_BLK_EOM)) {
|
if (!htx_add_endof(htx, HTX_BLK_EOM))
|
||||||
struct htx_blk *tail = htx_get_tail_blk(htx);
|
|
||||||
|
|
||||||
if (tail && htx_get_blk_type(tail) == HTX_BLK_TLR)
|
|
||||||
htx_remove_blk(htx, tail);
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (*flags & H2_SF_DATA_CHNK) {
|
else if (*flags & H2_SF_DATA_CHNK) {
|
||||||
if (!b_putblk(rxbuf, "\r\n", 2))
|
if (!b_putblk(rxbuf, "\r\n", 2))
|
||||||
@ -5150,67 +5145,48 @@ static size_t h2s_htx_make_trailers(struct h2s *h2s, struct htx *htx)
|
|||||||
struct htx_blk *blk_end;
|
struct htx_blk *blk_end;
|
||||||
struct buffer outbuf;
|
struct buffer outbuf;
|
||||||
struct buffer *mbuf;
|
struct buffer *mbuf;
|
||||||
struct h1m h1m;
|
|
||||||
enum htx_blk_type type;
|
enum htx_blk_type type;
|
||||||
uint32_t size;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int hdr;
|
int hdr;
|
||||||
int idx;
|
int idx;
|
||||||
void *start;
|
|
||||||
|
|
||||||
if (h2c_mux_busy(h2c, h2s)) {
|
if (h2c_mux_busy(h2c, h2s)) {
|
||||||
h2s->flags |= H2_SF_BLK_MBUSY;
|
h2s->flags |= H2_SF_BLK_MBUSY;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The principle is that we parse each and every trailers block using
|
/* determine the first block which must not be deleted, blk_end may
|
||||||
* the H1 headers parser, and append it to the list. We don't proceed
|
* be NULL if all blocks have to be deleted. also get trailers.
|
||||||
* until EOM is met. blk_end will point to the EOM block.
|
*/
|
||||||
*/
|
idx = htx_get_head(htx);
|
||||||
hdr = 0;
|
|
||||||
memset(list, 0, sizeof(list));
|
|
||||||
blk_end = NULL;
|
blk_end = NULL;
|
||||||
|
|
||||||
for (idx = htx_get_head(htx); idx != -1; idx = htx_get_next(htx, idx)) {
|
hdr = 0;
|
||||||
|
while (idx != -1) {
|
||||||
blk = htx_get_blk(htx, idx);
|
blk = htx_get_blk(htx, idx);
|
||||||
type = htx_get_blk_type(blk);
|
type = htx_get_blk_type(blk);
|
||||||
|
idx = htx_get_next(htx, idx);
|
||||||
if (type == HTX_BLK_UNUSED)
|
if (type == HTX_BLK_UNUSED)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (type == HTX_BLK_EOT) {
|
||||||
|
if (idx != -1)
|
||||||
|
blk_end = blk;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (type != HTX_BLK_TLR)
|
if (type != HTX_BLK_TLR)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (unlikely(hdr >= sizeof(list)/sizeof(list[0]) - 1))
|
if (unlikely(hdr >= sizeof(list)/sizeof(list[0]) - 1))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
size = htx_get_blksz(blk);
|
list[hdr].n = htx_get_blk_name(htx, blk);
|
||||||
start = htx_get_blk_ptr(htx, blk);
|
list[hdr].v = htx_get_blk_value(htx, blk);
|
||||||
|
hdr++;
|
||||||
h1m.flags = H1_MF_HDRS_ONLY | H1_MF_TOLOWER;
|
|
||||||
h1m.err_pos = 0;
|
|
||||||
ret = h1_headers_to_hdr_list(start, start + size,
|
|
||||||
list + hdr, sizeof(list)/sizeof(list[0]) - hdr,
|
|
||||||
&h1m, NULL);
|
|
||||||
if (ret < 0)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/* ret == 0 if an incomplete trailers block was found (missing
|
|
||||||
* empty line), or > 0 if it was found. We have to continue on
|
|
||||||
* incomplete messages because the trailers block might be
|
|
||||||
* incomplete.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* search the new end */
|
|
||||||
while (hdr <= sizeof(list)/sizeof(list[0])) {
|
|
||||||
if (!list[hdr].n.len)
|
|
||||||
break;
|
|
||||||
hdr++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list[hdr].n.len != 0)
|
/* marker for end of trailers */
|
||||||
goto fail; // empty trailer not found: internal error
|
list[hdr].n = ist("");
|
||||||
|
|
||||||
mbuf = br_tail(h2c->mbuf);
|
mbuf = br_tail(h2c->mbuf);
|
||||||
retry:
|
retry:
|
||||||
@ -5294,6 +5270,12 @@ static size_t h2s_htx_make_trailers(struct h2s *h2s, struct htx *htx)
|
|||||||
ret += htx_get_blksz(blk);
|
ret += htx_get_blksz(blk);
|
||||||
blk = htx_remove_blk(htx, blk);
|
blk = htx_remove_blk(htx, blk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (blk_end && htx_get_blk_type(blk_end) == HTX_BLK_EOM) {
|
||||||
|
ret += htx_get_blksz(blk_end);
|
||||||
|
htx_remove_blk(htx, blk_end);
|
||||||
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
return ret;
|
return ret;
|
||||||
full:
|
full:
|
||||||
@ -5577,6 +5559,7 @@ static size_t h2_snd_buf(struct conn_stream *cs, struct buffer *buf, size_t coun
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case HTX_BLK_TLR:
|
case HTX_BLK_TLR:
|
||||||
|
case HTX_BLK_EOT:
|
||||||
/* This is the first trailers block, all the subsequent ones AND
|
/* This is the first trailers block, all the subsequent ones AND
|
||||||
* the EOM will be swallowed by the parser.
|
* the EOM will be swallowed by the parser.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user