HTX_BLK_DATA = 4, /* data block */
HTX_BLK_EOD = 5, /* end-of-data 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 */
HTX_BLK_UNUSED = 15, /* unused/removed block */
};
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_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_data_atonce(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);
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_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_trailer_to_h1(const struct ist tlr, struct buffer *chk);
/* Functions and macros to get parts of the start-line or legnth of these
* parts
switch (type) {
case HTX_BLK_HDR:
+ case HTX_BLK_TLR:
/* name.length + value.length */
return ((blk->info & 0xff) + ((blk->info >> 8) & 0xfffff));
default:
switch (type) {
case HTX_BLK_HDR:
+ case HTX_BLK_TLR:
blk->info = (type << 28) + (vlen << 8) + (blk->info & 0xff);
break;
case HTX_BLK_REQ_SL:
case HTX_BLK_RES_SL:
case HTX_BLK_DATA:
- case HTX_BLK_TLR:
blk->info = (type << 28) + vlen;
break;
default:
switch (type) {
case HTX_BLK_HDR:
+ case HTX_BLK_TLR:
ret.ptr = htx_get_blk_ptr(htx, blk);
ret.len = blk->info & 0xff;
break;
switch (type) {
case HTX_BLK_HDR:
+ case HTX_BLK_TLR:
ret.ptr = htx_get_blk_ptr(htx, blk) + (blk->info & 0xff);
ret.len = (blk->info >> 8) & 0xfffff;
break;
case HTX_BLK_REQ_SL:
case HTX_BLK_RES_SL:
case HTX_BLK_DATA:
- case HTX_BLK_TLR:
ret.ptr = htx_get_blk_ptr(htx, blk);
ret.len = blk->info & 0xfffffff;
break;
case HTX_BLK_DATA: return "HTX_BLK_DATA";
case HTX_BLK_EOD: return "HTX_BLK_EOD";
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_UNUSED: return "HTX_BLK_UNUSED";
default: return "HTX_BLK_???";
HTX_SL_P2_LEN(sl), HTX_SL_P2_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",
pos, htx_blk_type_str(type), sz, blk->addr,
(int)n.len, n.ptr,
max = htx_get_max_blksz(htx, channel_htx_recv_max(si_ic(appctx->owner), htx));
if (!max)
return 0;
- blksz = ((type == HTX_BLK_HDR)
+ blksz = ((type == HTX_BLK_HDR || type == HTX_BLK_TLR)
? (info & 0xff) + ((info >> 8) & 0xfffff)
: info & 0xfffffff);
if (blksz > max)
case HTX_BLK_EOD:
case HTX_BLK_TLR:
+ case HTX_BLK_EOT:
case HTX_BLK_EOM:
if (msg->flags & HTTP_MSGF_COMPRESSING) {
if (htx_compression_buffer_init(htx, &trash) < 0) {
if (v.len > len)
v.len = len;
len -= v.len;
- if (type == HTX_BLK_DATA || type == HTX_BLK_TLR)
+ if (type == HTX_BLK_DATA)
trace_hexdump(v);
}
}
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.
+/* Takes an H2 headers list <list> terminated by a name being <NULL,0> and emits
+ * the equivalent HTX trailers blocks. 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.
*
* The headers list <list> must be composed of :
* - n.name != NULL, n.len > 0 : literal header name
*/
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) */
isteq(list[idx].n, ist("transfer-encoding")))
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 (!blk)
+ if (!htx_add_endof(htx, HTX_BLK_EOT))
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:
offset -= sz;
continue;
}
- if (type == HTX_BLK_DATA || type == HTX_BLK_TLR) {
+ if (type == HTX_BLK_DATA) {
htx_set_blk_value_len(blk, offset);
htx->data -= (sz - offset);
}
return tailblk;
add_new_block:
- /* FIXME: check tlr.len (< 256MB) */
+ /* FIXME: check data.len (< 256MB) */
blk = htx_add_blk(htx, HTX_BLK_DATA, data.len);
if (!blk)
return NULL;
struct htx_blk *blk, *dstblk;
enum htx_blk_type type;
uint32_t info, max, sz, ret;
+ int inside_trailers = 0;
ret = htx_used_space(dst);
blk = htx_get_blk(src, htx_get_head(src));
if (type == HTX_BLK_UNUSED)
goto next;
- /* Be sure to have enough space to xfer all headers in one
- * time. If not while <dst> is empty, we report a parsing error
- * on <src>.
+ /* Be sure to have enough space to xfer all headers/trailers in
+ * one time. If not while <dst> is empty, we report a parsing
+ * error on <src>.
*/
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);
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);
info = blk->info;
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
* new block on success. Otherwise, it returns NULL. The caller is responsible
* for filling the block itself.
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
* on success. Otherwise, it returns NULL.
*/
return len;
add_new_block:
- /* FIXME: check tlr.len (< 256MB) */
+ /* FIXME: check data.len (< 256MB) */
blk = htx_add_blk(htx, HTX_BLK_DATA, len);
if (!blk)
return 0;
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,
const struct ist data)
{
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;
-}
#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_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_O_EOD 0x00001000 /* Set during output process to know the last empty chunk was processed */
-#define H1S_F_HAVE_O_TLR 0x00002000 /* Set during output process to know the trailers were processed */
+/* 0x00001000 .. 0x00002000 unused */
#define H1S_F_HAVE_O_CONN 0x00004000 /* Set during output process to know connection mode was processed */
/* H1 connection descriptor */
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
* it couldn't proceed. Parsing errors are reported by setting H1S_F_*_ERROR
}
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;
- h1m->state = H1_MSG_DONE;
- h1s->cs->flags |= CS_FL_EOI;
}
}
else if (h1m->flags & H1_MF_CHNK) {
if (!chksz) {
if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(htx, HTX_BLK_EOD))
goto end;
- h1s->flags |= H1S_F_HAVE_I_EOD;
h1m->state = H1_MSG_TRAILERS;
max -= sizeof(struct htx_blk) + 1;
}
h1m->body_len += chksz;
*ofs += ret;
total += ret;
+
+ if (!h1m->curr_len)
+ goto end;
}
if (h1m->state == H1_MSG_DATA) {
}
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 {
/* XFER_LEN is set but not CLEN nor CHNK, it means there
* 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;
- max -= sizeof(struct htx_blk) + 1;
- h1m->state = H1_MSG_DONE;
- h1s->cs->flags |= CS_FL_EOI;
}
}
else {
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
* <buf>. It returns the number of bytes parsed and transferred if > 0, or 0 if
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);
htx = htx_from_buf(buf);
if (!ret)
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) {
if (h1s->req.state < H1_MSG_DONE || h1s->res.state < H1_MSG_DONE)
h1c->flags |= H1C_F_IN_BUSY;
vlen = sz;
if (vlen > count) {
- if (type != HTX_BLK_DATA && type != HTX_BLK_TLR)
+ if (type != HTX_BLK_DATA)
goto copy;
vlen = count;
}
break;
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))
goto copy;
- h1s->flags |= H1S_F_HAVE_O_EOD;
- h1m->state = H1_MSG_TRAILERS;
- break;
- }
- if (type == HTX_BLK_TLR)
goto trailers;
- else if (type == HTX_BLK_EOM)
- goto done;
+ }
else if (type != HTX_BLK_DATA)
goto error;
v = htx_get_blk_value(chn_htx, blk);
case H1_MSG_TRAILERS:
if (type == HTX_BLK_EOM)
goto done;
- else if (type != HTX_BLK_TLR)
+ else if (type != HTX_BLK_TLR && type != HTX_BLK_EOT)
goto error;
trailers:
h1m->state = H1_MSG_TRAILERS;
- if (!(h1s->flags & H1S_F_HAVE_O_EOD)) {
- if (!chunk_memcat(tmp, "0\r\n", 3))
+ if (type == HTX_BLK_EOT) {
+ 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;
- 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;
case H1_MSG_DONE:
goto error;
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;
default:
* the EOM block we must remove the TLR block we've just added.
*/
if (htx) {
- 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);
+ if (!htx_add_endof(htx, HTX_BLK_EOM))
goto fail;
- }
}
else if (*flags & H2_SF_DATA_CHNK) {
if (!b_putblk(rxbuf, "\r\n", 2))
struct htx_blk *blk_end;
struct buffer outbuf;
struct buffer *mbuf;
- struct h1m h1m;
enum htx_blk_type type;
- uint32_t size;
int ret = 0;
int hdr;
int idx;
- void *start;
if (h2c_mux_busy(h2c, h2s)) {
h2s->flags |= H2_SF_BLK_MBUSY;
goto end;
}
- /* The principle is that we parse each and every trailers block using
- * the H1 headers parser, and append it to the list. We don't proceed
- * until EOM is met. blk_end will point to the EOM block.
- */
- hdr = 0;
- memset(list, 0, sizeof(list));
+ /* determine the first block which must not be deleted, blk_end may
+ * be NULL if all blocks have to be deleted. also get trailers.
+ */
+ idx = htx_get_head(htx);
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);
type = htx_get_blk_type(blk);
-
+ idx = htx_get_next(htx, idx);
if (type == HTX_BLK_UNUSED)
continue;
+ if (type == HTX_BLK_EOT) {
+ if (idx != -1)
+ blk_end = blk;
+ break;
+ }
if (type != HTX_BLK_TLR)
break;
if (unlikely(hdr >= sizeof(list)/sizeof(list[0]) - 1))
goto fail;
- size = htx_get_blksz(blk);
- start = htx_get_blk_ptr(htx, blk);
-
- 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++;
- }
+ list[hdr].n = htx_get_blk_name(htx, blk);
+ list[hdr].v = htx_get_blk_value(htx, blk);
+ hdr++;
}
- if (list[hdr].n.len != 0)
- goto fail; // empty trailer not found: internal error
+ /* marker for end of trailers */
+ list[hdr].n = ist("");
mbuf = br_tail(h2c->mbuf);
retry:
ret += htx_get_blksz(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:
return ret;
full:
break;
case HTX_BLK_TLR:
+ case HTX_BLK_EOT:
/* This is the first trailers block, all the subsequent ones AND
* the EOM will be swallowed by the parser.
*/