/* various protocol processing functions */
-int h2_make_h1_request(struct http_hdr *list, char *out, int osize, unsigned int *msgf);
+int h2_make_h1_request(struct http_hdr *list, char *out, int osize, unsigned int *msgf, unsigned long long *body_len);
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_request(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len);
+int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len);
int h2_make_htx_trailers(struct http_hdr *list, struct htx *htx);
/*
* The Cookie header will be reassembled at the end, and for this, the <list>
* will be used to create a linked list, so its contents may be destroyed.
*/
-int h2_make_h1_request(struct http_hdr *list, char *out, int osize, unsigned int *msgf)
+int h2_make_h1_request(struct http_hdr *list, char *out, int osize, unsigned int *msgf, unsigned long long *body_len)
{
struct ist phdr_val[H2_PHDR_NUM_ENTRIES];
char *out_end = out + osize;
if (isteq(list[idx].n, ist("host")))
fields |= H2_PHDR_FND_HOST;
- if ((*msgf & (H2_MSGF_BODY|H2_MSGF_BODY_TUNNEL|H2_MSGF_BODY_CL)) == H2_MSGF_BODY &&
- isteq(list[idx].n, ist("content-length")))
- *msgf |= H2_MSGF_BODY_CL;
+ if (isteq(list[idx].n, ist("content-length"))) {
+ ret = h2_parse_cont_len_header(msgf, &list[idx].v, body_len);
+ if (ret < 0)
+ goto fail;
+
+ if (ret == 0)
+ continue; // skip this duplicate
+ }
/* these ones are forbidden in requests (RFC7540#8.1.2.2) */
if (isteq(list[idx].n, ist("connection")) ||
* The Cookie header will be reassembled at the end, and for this, the <list>
* will be used to create a linked list, so its contents may be destroyed.
*/
-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, unsigned long long *body_len)
{
struct ist phdr_val[H2_PHDR_NUM_ENTRIES];
uint32_t fields; /* bit mask of H2_PHDR_FND_* */
int i;
struct htx_sl *sl = NULL;
unsigned int sl_flags = 0;
- unsigned long long body_len;
lck = ck = -1; // no cookie for now
fields = 0;
fields |= H2_PHDR_FND_HOST;
if (isteq(list[idx].n, ist("content-length"))) {
- ret = h2_parse_cont_len_header(msgf, &list[idx].v, &body_len);
+ ret = h2_parse_cont_len_header(msgf, &list[idx].v, body_len);
if (ret < 0)
goto fail;
* - in all cases except the end of list, v.name and v.len must designate a
* valid value.
*/
-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, unsigned long long *body_len)
{
struct ist phdr_val[H2_PHDR_NUM_ENTRIES];
uint32_t fields; /* bit mask of H2_PHDR_FND_* */
int i;
struct htx_sl *sl = NULL;
unsigned int sl_flags = 0;
- unsigned long long body_len;
fields = 0;
for (idx = 0; list[idx].n.len != 0; idx++) {
}
if (isteq(list[idx].n, ist("content-length"))) {
- ret = h2_parse_cont_len_header(msgf, &list[idx].v, &body_len);
+ ret = h2_parse_cont_len_header(msgf, &list[idx].v, body_len);
if (ret < 0)
goto fail;
static int h2_process(struct h2c *h2c);
static struct task *h2_io_cb(struct task *t, void *ctx, unsigned short state);
static inline struct h2s *h2c_st_by_id(struct h2c *h2c, int id);
-static int h2c_decode_headers(struct h2c *h2c, struct buffer *rxbuf, uint32_t *flags);
+static int h2c_decode_headers(struct h2c *h2c, struct buffer *rxbuf, uint32_t *flags, unsigned long long *body_len);
static int h2_frt_transfer_data(struct h2s *h2s);
static struct task *h2_deferred_shut(struct task *t, void *ctx, unsigned short state);
static struct h2s *h2c_bck_stream_new(struct h2c *h2c, struct conn_stream *cs, struct session *sess);
static struct h2s *h2c_frt_handle_headers(struct h2c *h2c, struct h2s *h2s)
{
struct buffer rxbuf = BUF_NULL;
+ unsigned long long body_len = 0;
uint32_t flags = 0;
int error;
if (h2s->st != H2_SS_IDLE) {
/* The stream exists/existed, this must be a trailers frame */
if (h2s->st != H2_SS_CLOSED) {
- if (h2c_decode_headers(h2c, &h2s->rxbuf, &h2s->flags) <= 0)
+ if (h2c_decode_headers(h2c, &h2s->rxbuf, &h2s->flags, &body_len) <= 0)
goto out;
goto done;
}
else if (h2c->flags & H2_CF_DEM_TOOMANY)
goto out; // IDLE but too many cs still present
- error = h2c_decode_headers(h2c, &rxbuf, &flags);
+ error = h2c_decode_headers(h2c, &rxbuf, &flags, &body_len);
/* unrecoverable error ? */
if (h2c->st0 >= H2_CS_ERROR)
*/
static struct h2s *h2c_bck_handle_headers(struct h2c *h2c, struct h2s *h2s)
{
+ unsigned long long body_len = 0;
int error;
if (!h2c->dfl) {
if (b_data(&h2c->dbuf) < h2c->dfl && !b_full(&h2c->dbuf))
return NULL; // incomplete frame
- error = h2c_decode_headers(h2c, &h2s->rxbuf, &h2s->flags);
+ error = h2c_decode_headers(h2c, &h2s->rxbuf, &h2s->flags, &body_len);
/* unrecoverable error ? */
if (h2c->st0 >= H2_CS_ERROR)
* decoding, in order to detect if we're dealing with a headers or a trailers
* block (the trailers block appears after H2_SF_HEADERS_RCVD was seen).
*/
-static int h2c_decode_headers(struct h2c *h2c, struct buffer *rxbuf, uint32_t *flags)
+static int h2c_decode_headers(struct h2c *h2c, struct buffer *rxbuf, uint32_t *flags, unsigned long long *body_len)
{
const uint8_t *hdrs = (uint8_t *)b_head(&h2c->dbuf);
struct buffer *tmp = get_trash_chunk();
if (htx) {
/* HTX mode */
if (h2c->flags & H2_CF_IS_BACK)
- outlen = h2_make_htx_response(list, htx, &msgf);
+ outlen = h2_make_htx_response(list, htx, &msgf, body_len);
else
- outlen = h2_make_htx_request(list, htx, &msgf);
+ outlen = h2_make_htx_request(list, htx, &msgf, body_len);
} else {
/* HTTP/1 mode */
- outlen = h2_make_h1_request(list, b_tail(rxbuf), try, &msgf);
+ outlen = h2_make_h1_request(list, b_tail(rxbuf), try, &msgf, body_len);
if (outlen > 0)
b_add(rxbuf, outlen);
}