* stored in <phdr[]>. <fields> indicates what was found so far. This should be
* called once at the detection of the first general header field or at the end
* of the request if no general header field was found yet. Returns 0 on success
- * or a negative error code on failure.
+ * or a negative error code on failure. Upon success, <msgf> is updated with a
+ * few H2_MSGF_* flags indicating what was found while parsing.
*/
-static int h2_prepare_h1_reqline(uint32_t fields, struct ist *phdr, char **ptr, char *end)
+static int h2_prepare_h1_reqline(uint32_t fields, struct ist *phdr, char **ptr, char *end, unsigned int *msgf)
{
char *out = *ptr;
int uri_idx = H2_PHDR_IDX_PATH;
}
// otherwise OK ; let's use the authority instead of the URI
uri_idx = H2_PHDR_IDX_AUTH;
+ *msgf |= H2_MSGF_BODY_TUNNEL;
}
else if ((fields & (H2_PHDR_FND_METH|H2_PHDR_FND_SCHM|H2_PHDR_FND_PATH)) !=
(H2_PHDR_FND_METH|H2_PHDR_FND_SCHM|H2_PHDR_FND_PATH)) {
* for a max of <osize> bytes, and the amount of bytes emitted is returned. In
* case of error, a negative error code is returned.
*
+ * Upon success, <msgf> is filled with a few H2_MSGF_* flags indicating what
+ * was found while parsing. The caller must set it to zero in or H2_MSGF_BODY
+ * if a body is detected (!ES).
+ *
* 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>
* 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)
+int h2_make_h1_request(struct http_hdr *list, char *out, int osize, unsigned int *msgf)
{
struct ist phdr_val[H2_PHDR_NUM_ENTRIES];
char *out_end = out + osize;
/* regular header field in (name,value) */
if (!(fields & H2_PHDR_FND_NONE)) {
/* no more pseudo-headers, time to build the request line */
- ret = h2_prepare_h1_reqline(fields, phdr_val, &out, out_end);
+ ret = h2_prepare_h1_reqline(fields, phdr_val, &out, out_end, msgf);
if (ret != 0)
goto leave;
fields |= H2_PHDR_FND_NONE;
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;
+
/* these ones are forbidden in requests (RFC7540#8.1.2.2) */
if (isteq(list[idx].n, ist("connection")) ||
isteq(list[idx].n, ist("proxy-connection")) ||
/* Let's dump the request now if not yet emitted. */
if (!(fields & H2_PHDR_FND_NONE)) {
- ret = h2_prepare_h1_reqline(fields, phdr_val, &out, out_end);
+ ret = h2_prepare_h1_reqline(fields, phdr_val, &out, out_end, msgf);
if (ret != 0)
goto leave;
}
struct chunk *tmp = get_trash_chunk();
struct http_hdr list[MAX_HTTP_HDR * 2];
struct chunk *copy = NULL;
+ unsigned int msgf;
int flen = h2c->dfl;
int outlen = 0;
int wrap;
}
/* OK now we have our header list in <list> */
- outlen = h2_make_h1_request(list, bi_end(buf), try);
+ msgf = (h2c->dff & H2_F_DATA_END_STREAM) ? 0 : H2_MSGF_BODY;
+ outlen = h2_make_h1_request(list, bi_end(buf), try, &msgf);
if (outlen < 0) {
h2c_error(h2c, H2_ERR_COMPRESSION_ERROR);
goto fail;
}
+ if (msgf & H2_MSGF_BODY) {
+ /* a payload is present */
+ if (msgf & H2_MSGF_BODY_CL)
+ h2s->flags |= H2_SF_DATA_CLEN;
+ else if (!(msgf & H2_MSGF_BODY_TUNNEL))
+ h2s->flags |= H2_SF_DATA_CHNK;
+ }
+
/* now consume the input data */
bi_del(h2c->dbuf, h2c->dfl);
h2c->st0 = H2_CS_FRAME_H;