]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: h1: parse the Connection header field
authorWilly Tarreau <w@1wt.eu>
Thu, 13 Sep 2018 12:15:58 +0000 (14:15 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 13 Sep 2018 12:52:31 +0000 (14:52 +0200)
The new function h1_parse_connection_header() is called when facing a
connection header in the generic parser, and it will set up to 3 bits
in h1m->flags indicating if at least one "close", "keep-alive" or "upgrade"
tokens was seen.

include/types/h1.h
src/h1.c

index dd883e87a30305e3f5ed423da2f0400f2503dffe..ec967ac4a2c1e55c5eea8ff2e9b69783e919c6ec 100644 (file)
@@ -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,
index ec8bb3870f850e989597cde0b694b88384faf110..b78f5847a580d853f7addec0e01a7729cd93d930 100644 (file)
--- 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 <start>
  * and ending before <stop>, at once, and converts it a list of (name,value)
  * pairs representing header fields into the array <hdr> of size <hdr_num>,
@@ -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;