*
* WARNING: Don't forget to update it if a new flag must be preserved when
* headers parsing is restarted.
+ *
+ * Note: H1_MF_CONN_CLO and H1_MF_CONN_KAL must be preserved because the
+ * corresponding values may have been removed from the connection
+ * headers before the restart (see h1_parse_connection_header()).
*/
#define H1_MF_RESTART_MASK (H1_MF_RESP|H1_MF_TOLOWER|H1_MF_NO_PHDR|H1_MF_HDRS_ONLY| \
- H1_MF_CLEAN_CONN_HDR|H1_MF_METH_CONNECT|H1_MF_METH_HEAD)
+ H1_MF_CLEAN_CONN_HDR|H1_MF_METH_CONNECT|H1_MF_METH_HEAD| \
+ H1_MF_CONN_CLO|H1_MF_CONN_KAL)
/* Note: for a connection to be persistent, we need this for the request :
* - one of CLEN or CHNK
* function is safe for being called multiple times if multiple occurrences
* are found. If the flag H1_MF_CLEAN_CONN_HDR, the header value is cleaned
* up from "keep-alive" and "close" values. To do so, the header value is
- * rewritten in place and its length is updated.
+ * rewritten in place and its length is updated. The bytes freed at the end of
+ * the original value are replaced with spaces so that parsing the same area
+ * again (e.g. when the parser restarts on an incomplete message) gives the
+ * same value. However the removed values are not there anymore, so the caller
+ * must preserve the H1_MF_CONN_CLO and H1_MF_CONN_KAL flags across such
+ * restarts.
*/
void h1_parse_connection_header(struct h1m *h1m, struct ist *value)
{
skip_val:
word.ptr = p = n;
}
+
+ /* blank the freed area to make the operation idempotent */
+ if ((h1m->flags & H1_MF_CLEAN_CONN_HDR) && value->ptr + value->len < e)
+ memset(value->ptr + value->len, ' ', e - (value->ptr + value->len));
}
/* Parse the Upgrade: header of an HTTP/1 request.
* If "websocket" is found, set H1_MF_UPG_WEBSOCKET flag
- * If "h2c" or "h2" found, the value is skipped.
+ * If "h2c" or "h2" found, the value is skipped. The header value is rewritten
+ * in place and the bytes freed at the end of the original value are replaced
+ * with spaces so that parsing the same area again gives the same value.
*/
void h1_parse_upgrade_header(struct h1m *h1m, struct ist *value)
{
word.ptr = p = n;
}
+ /* blank the freed area to make the operation idempotent */
+ if (value->ptr + value->len < e)
+ memset(value->ptr + value->len, ' ', e - (value->ptr + value->len));
+
if (istlen(*value))
h1m->flags |= H1_MF_UPG_HDR;
}
return 1;
output_full:
+ /* The connection header values may have been cleaned up, so the
+ * corresponding flags must be preserved for the next parsing.
+ */
+ flags = h1m->flags & (H1_MF_CONN_CLO|H1_MF_CONN_KAL);
h1m_init_req(h1m);
- h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
+ h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR|flags);
return -2;
error:
h1m->err_pos = h1m->next;
return 1;
output_full:
+ /* The connection header values may have been cleaned up, so the
+ * corresponding flags must be preserved for the next parsing.
+ */
+ flags = h1m->flags & (H1_MF_CONN_CLO|H1_MF_CONN_KAL);
h1m_init_res(h1m);
- h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
+ h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR|flags);
return -2;
error:
h1m->err_pos = h1m->next;