diff --git a/include/types/h1.h b/include/types/h1.h index dd883e87a..ec967ac4a 100644 --- a/include/types/h1.h +++ b/include/types/h1.h @@ -141,6 +141,18 @@ enum h1m_state { #define H1_MF_RESP 0x00000004 // this message is the response message #define H1_MF_TOLOWER 0x00000008 // turn the header names to lower case #define H1_MF_VER_11 0x00000010 // message indicates version 1.1 or above +#define H1_MF_CONN_CLO 0x00000020 // message contains "connection: close" +#define H1_MF_CONN_KAL 0x00000040 // message contains "connection: keep-alive" +#define H1_MF_CONN_UPG 0x00000080 // message contains "connection: upgrade" + +/* Note: for a connection to be persistent, we need this for the request : + * - one of CLEN or CHNK + * - version 1.0 and KAL and not CLO + * - or version 1.1 and not CLO + * For the response it's the same except that UPG must not appear either. + * So in short, for a request it's (CLEN|CHNK) > 0 && !CLO && (VER_11 || KAL) + * and for a response it's (CLEN|CHNK) > 0 && !(CLO|UPG) && (VER_11 || KAL) + */ /* basic HTTP/1 message state for use in parsers. The err_pos field is special, diff --git a/src/h1.c b/src/h1.c index ec8bb3870..b78f5847a 100644 --- a/src/h1.c +++ b/src/h1.c @@ -659,6 +659,44 @@ void http_msg_analyzer(struct http_msg *msg, struct hdr_idx *idx) return; } + +/* Parse the Connection: header of an HTTP/1 request, looking for "close", + * "keep-alive", and "upgrade" values, and updating h1m->flags according to + * what was found there. Note that flags are only added, not removed, so the + * function is safe for being called multiple times if multiple occurrences + * are found. + */ +void h1_parse_connection_header(struct h1m *h1m, struct ist value) +{ + char *e, *n; + struct ist word; + + word.ptr = value.ptr - 1; // -1 for next loop's pre-increment + e = value.ptr + value.len; + + while (++word.ptr < e) { + /* skip leading delimitor and blanks */ + if (HTTP_IS_LWS(*word.ptr)) + continue; + + n = http_find_hdr_value_end(word.ptr, e); // next comma or end of line + word.len = n - word.ptr; + + /* trim trailing blanks */ + while (word.len && HTTP_IS_LWS(word.ptr[word.len-1])) + word.len--; + + if (isteqi(word, ist("keep-alive"))) + h1m->flags |= H1_MF_CONN_KAL; + else if (isteqi(word, ist("close"))) + h1m->flags |= H1_MF_CONN_CLO; + else if (isteqi(word, ist("upgrade"))) + h1m->flags |= H1_MF_CONN_UPG; + + word.ptr = n; + } +} + /* This function parses a contiguous HTTP/1 headers block starting at * and ending before , at once, and converts it a list of (name,value) * pairs representing header fields into the array of size , @@ -1244,6 +1282,9 @@ int h1_headers_to_hdr_list(char *start, const char *stop, strl2llrc(v.ptr, v.len, &cl); h1m->curr_len = h1m->body_len = cl; } + else if (isteqi(n, ist("connection"))) { + h1_parse_connection_header(h1m, v); + } } sol = ptr - start;