]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
REORG: h2: extract cookies concat function in http_htx
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 17 Aug 2022 14:33:53 +0000 (16:33 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 18 Aug 2022 14:13:33 +0000 (16:13 +0200)
As specified by RFC 7540, multiple cookie headers are merged in a single
entry before passing it to a HTTP/1.1 connection. This step is
implemented during headers parsing in h2 module.

Extract this code in the generic http_htx module. This will allow to
reuse it quickly for HTTP/3 implementation which has the same
requirement for cookie headers.

include/haproxy/http_htx.h
src/h2.c
src/http_htx.c

index f7becff268887c6d7723c82a8845252e6999917c..71f56bc15b91934b01191ecf469fb45997123a73 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <import/ist.h>
 #include <haproxy/buf-t.h>
+#include <haproxy/http-hdr-t.h>
 #include <haproxy/http_htx-t.h>
 #include <haproxy/proxy-t.h>
 #include <haproxy/regex-t.h>
@@ -68,6 +69,9 @@ struct http_reply *http_parse_http_reply(const char **args, int *orig_arg, struc
 
 int http_scheme_based_normalize(struct htx *htx);
 
+void http_cookie_register(struct http_hdr *list, int idx, int *first, int *last);
+int http_cookie_merge(struct htx *htx, struct http_hdr *list, int first);
+
 struct buffer *http_load_errorfile(const char *file, char **errmsg);
 struct buffer *http_load_errormsg(const char *key, const struct ist msg, char **errmsg);
 struct buffer *http_parse_errorfile(int status, const char *file, char **errmsg);
index 5c3a6aeaf8ecba1911c0448072ab6054b0e707ad..c191881f2b7fd8ce886cececda757a086bbc8eff 100644 (file)
--- a/src/h2.c
+++ b/src/h2.c
@@ -501,14 +501,7 @@ int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *ms
 
                /* cookie requires special processing at the end */
                if (isteq(list[idx].n, ist("cookie"))) {
-                       list[idx].n.len = -1;
-
-                       if (ck < 0)
-                               ck = idx;
-                       else
-                               list[lck].n.len = idx;
-
-                       lck = idx;
+                       http_cookie_register(list, idx, &ck, &lck);
                        continue;
                }
 
@@ -561,37 +554,8 @@ int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *ms
         * visited headers.
         */
        if (ck >= 0) {
-               uint32_t fs; // free space
-               uint32_t bs; // block size
-               uint32_t vl; // value len
-               uint32_t tl; // total length
-               struct htx_blk *blk;
-
-               blk = htx_add_header(htx, ist("cookie"), list[ck].v);
-               if (!blk)
+               if (http_cookie_merge(htx, list, ck))
                        goto fail;
-
-               tl = list[ck].v.len;
-               fs = htx_free_data_space(htx);
-               bs = htx_get_blksz(blk);
-
-               /* for each extra cookie, we'll extend the cookie's value and
-                * insert "; " before the new value.
-                */
-               fs += tl; // first one is already counted
-               while ((ck = list[ck].n.len) >= 0) {
-                       vl = list[ck].v.len;
-                       tl += vl + 2;
-                       if (tl > fs)
-                               goto fail;
-
-                       htx_change_blk_value_len(htx, blk, tl);
-                       *(char *)(htx_get_blk_ptr(htx, blk) + bs + 0) = ';';
-                       *(char *)(htx_get_blk_ptr(htx, blk) + bs + 1) = ' ';
-                       memcpy(htx_get_blk_ptr(htx, blk) + bs + 2, list[ck].v.ptr, vl);
-                       bs += vl + 2;
-               }
-
        }
 
        /* now send the end of headers marker */
index fbd626068075e4680267725d9ad0719fb006cefe..9b7ef6fcb0e39599acdc5d0b223814e416a49057 100644 (file)
@@ -21,6 +21,7 @@
 #include <haproxy/global.h>
 #include <haproxy/h1.h>
 #include <haproxy/http.h>
+#include <haproxy/http-hdr.h>
 #include <haproxy/http_fetch.h>
 #include <haproxy/http_htx.h>
 #include <haproxy/htx.h>
@@ -1799,6 +1800,83 @@ int http_scheme_based_normalize(struct htx *htx)
        return 1;
 }
 
+/* First step function to merge multiple cookie headers in a single entry.
+ *
+ * Use it for each cookie header at <idx> index over HTTP headers in <list>.
+ * <first> and <last> are state variables used internally and must be
+ * initialized to -1 before the first invocation.
+ */
+void http_cookie_register(struct http_hdr *list, int idx, int *first, int *last)
+{
+       /* Build a linked list of cookie headers. Use header length to point to
+        * the next one. The last entry will contains -1.
+        */
+
+       /* Mark the current end of cookie linked list. */
+       list[idx].n.len = -1;
+       if (*first < 0) {
+               /* Save first found cookie for http_cookie_merge call. */
+               *first = idx;
+       }
+       else {
+               /* Update linked list of cookies. */
+               list[*last].n.len = idx;
+       }
+
+       *last = idx;
+}
+
+/* Second step to merge multiple cookie headers in a single entry.
+ *
+ * Use it when looping over HTTP headers is done and <htx> message is built.
+ * This will concatenate each cookie headers present from <list> directly into
+ * <htx> message. <first> is reused from previous http_cookie_register
+ * invocation.
+ *
+ * Returns 0 on success else non-zero.
+ */
+int http_cookie_merge(struct htx *htx, struct http_hdr *list, int first)
+{
+       uint32_t fs; /* free space */
+       uint32_t bs; /* block size */
+       uint32_t vl; /* value len */
+       uint32_t tl; /* total length */
+       struct htx_blk *blk;
+
+       if (first < 0)
+               return 0;
+
+       blk = htx_add_header(htx, ist("cookie"), list[first].v);
+       if (!blk)
+               return 1;
+
+       tl = list[first].v.len;
+       fs = htx_free_data_space(htx);
+       bs = htx_get_blksz(blk);
+
+       /* for each extra cookie, we'll extend the cookie's value and insert
+        * ";" before the new value.
+        */
+       fs += tl; /* first one is already counted */
+
+       /* Loop over cookies linked list built from http_cookie_register. */
+       while ((first = list[first].n.len) >= 0) {
+               vl = list[first].v.len;
+               tl += vl + 2;
+               if (tl > fs)
+                       return 1;
+
+               htx_change_blk_value_len(htx, blk, tl);
+               *(char *)(htx_get_blk_ptr(htx, blk) + bs + 0) = ';';
+               *(char *)(htx_get_blk_ptr(htx, blk) + bs + 1) = ' ';
+               memcpy(htx_get_blk_ptr(htx, blk) + bs + 2,
+                      list[first].v.ptr, vl);
+               bs += vl + 2;
+       }
+
+       return 0;
+}
+
 /* Parses the "errorloc[302|303]" proxy keyword */
 static int proxy_parse_errorloc(char **args, int section, struct proxy *curpx,
                                  const struct proxy *defpx, const char *file, int line,