]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: http-htx: Support different methods to look for header names
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 5 May 2020 05:42:42 +0000 (07:42 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Tue, 5 May 2020 09:07:00 +0000 (11:07 +0200)
It is now possible to use different matching methods to look for header names in
an HTTP message:

 * The exact match. It is the default method. http_find_header() uses this
   method. http_find_str_header() is an alias.

 * The prefix match. It evals the header names starting by a prefix.
   http_find_pfx_header() must be called to use this method.

 * The suffix match. It evals the header names ending by a suffix.
   http_find_sfx_header() must be called to use this method.

 * The substring match. It evals the header names containing a string.
   http_find_sub_header() must be called to use this method.

 * The regex match. It evals the header names matching a regular expression.
   http_match_header() must be called to use this method.

include/proto/http_htx.h
src/http_htx.c

index 99d56b42be0f600f1a6bbc7eb57baa581cd83c09..9a70ca52db42c4302f6f6c4e14f0d9d26035acd9 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <common/buf.h>
 #include <common/ist.h>
+#include <common/regex.h>
 
 #include <types/http_htx.h>
 
@@ -34,6 +35,11 @@ extern struct list http_errors_list;
 struct htx_sl *http_get_stline(struct htx *htx);
 size_t http_get_hdrs_size(struct htx *htx);
 int http_find_header(const struct htx *htx, const struct ist name, struct http_hdr_ctx *ctx, int full);
+int http_find_str_header(const struct htx *htx, const struct ist name, struct http_hdr_ctx *ctx, int full);
+int http_find_pfx_header(const struct htx *htx, const struct ist prefix, struct http_hdr_ctx *ctx, int full);
+int http_find_sfx_header(const struct htx *htx, const struct ist suffix, struct http_hdr_ctx *ctx, int full);
+int http_find_sub_header(const struct htx *htx, const struct ist sub, struct http_hdr_ctx *ctx, int full);
+int http_match_header(const struct htx *htx, const struct my_regex *re, struct http_hdr_ctx *ctx, int full);
 int http_add_header(struct htx *htx, const struct ist n, const struct ist v);
 int http_replace_stline(struct htx *htx, const struct ist p1, const struct ist p2, const struct ist p3);
 int http_replace_req_meth(struct htx *htx, const struct ist meth);
index cffbbffc9594c0c557168f6748777e4a2c1480c8..0cb76766e009528b64b1cc51cc11d8d1755413bf 100644 (file)
@@ -87,19 +87,42 @@ size_t http_get_hdrs_size(struct htx *htx)
        return sz;
 }
 
-/* Finds the first or next occurrence of header <name> in the HTX message <htx>
- * using the context <ctx>. This structure holds everything necessary to use the
- * header and find next occurrence. If its <blk> member is NULL, the header is
- * searched from the beginning. Otherwise, the next occurrence is returned. The
- * function returns 1 when it finds a value, and 0 when there is no more. It is
- * designed to work with headers defined as comma-separated lists. If <full> is
- * set, it works on full-line headers in whose comma is not a delimiter but is
- * part of the syntax. A special case, if ctx->value is NULL when searching for
- * a new values of a header, the current header is rescanned. This allows
- * rescanning after a header deletion.
+/* Finds the first or next occurrence of header matching <pattern> in the HTX
+ * message <htx> using the context <ctx>. This structure holds everything
+ * necessary to use the header and find next occurrence. If its <blk> member is
+ * NULL, the header is searched from the beginning. Otherwise, the next
+ * occurrence is returned. The function returns 1 when it finds a value, and 0
+ * when there is no more. It is designed to work with headers defined as
+ * comma-separated lists. If HTTP_FIND_FL_FULL flag is set, it works on
+ * full-line headers in whose comma is not a delimiter but is part of the
+ * syntax. A special case, if ctx->value is NULL when searching for a new values
+ * of a header, the current header is rescanned. This allows rescanning after a
+ * header deletion.
+ *
+ * The matching method is chosen by checking the flags :
+ *
+ *     * HTTP_FIND_FL_MATCH_REG : <pattern> is a regex. header names matching
+ *                                the regex are evaluated.
+ *     * HTTP_FIND_FL_MATCH_STR : <pattern> is a string. The header names equal
+ *                                to the string are evaluated.
+ *     * HTTP_FIND_FL_MATCH_PFX : <pattern> is a string. The header names
+ *                                starting by the string are evaluated.
+ *     * HTTP_FIND_FL_MATCH_SFX : <pattern> is a string. The header names
+ *                                ending by the string are evaluated.
+ *     * HTTP_FIND_FL_MATCH_SUB : <pattern> is a string. The header names
+ *                                containing the string are evaluated.
  */
-int http_find_header(const struct htx *htx, const struct ist name,
-                   struct http_hdr_ctx *ctx, int full)
+
+#define HTTP_FIND_FL_MATCH_STR  0x0001
+#define HTTP_FIND_FL_MATCH_PFX  0x0002
+#define HTTP_FIND_FL_MATCH_SFX  0x0003
+#define HTTP_FIND_FL_MATCH_SUB  0x0004
+#define HTTP_FIND_FL_MATCH_REG  0x0005
+/* 0x0006..0x000f: for other matching methods */
+#define HTTP_FIND_FL_MATCH_TYPE 0x000F
+#define HTTP_FIND_FL_FULL 0x0010
+
+static int __http_find_header(const struct htx *htx, const void *pattern, struct http_hdr_ctx *ctx, int flags)
 {
        struct htx_blk *blk = ctx->blk;
        struct ist n, v;
@@ -110,7 +133,7 @@ int http_find_header(const struct htx *htx, const struct ist name,
 
                if (!isttest(ctx->value))
                        goto rescan_hdr;
-               if (full)
+               if (flags & HTTP_FIND_FL_FULL)
                        goto next_blk;
                v = htx_get_blk_value(htx, blk);
                p = ctx->value.ptr + ctx->value.len + ctx->lws_after;
@@ -137,12 +160,53 @@ int http_find_header(const struct htx *htx, const struct ist name,
                        break;
                if (type != HTX_BLK_HDR)
                        continue;
-               if (name.len) {
+
+               if ((flags & HTTP_FIND_FL_MATCH_TYPE) == HTTP_FIND_FL_MATCH_REG) {
+                       const struct my_regex *re = pattern;
+
+                       n = htx_get_blk_name(htx, blk);
+                       if (!regex_exec2(re, n.ptr, n.len))
+                               goto next_blk;
+               }
+               else {
+                       const struct ist name = *(const struct ist *)(pattern);
+
                        /* If no name was passed, we want any header. So skip the comparison */
+                       if (!istlen(name))
+                               goto match;
+
                        n = htx_get_blk_name(htx, blk);
-                       if (!isteqi(n, name))
+                       switch (flags & HTTP_FIND_FL_MATCH_TYPE) {
+                       case HTTP_FIND_FL_MATCH_STR:
+                               if (!isteqi(n, name))
+                                       goto next_blk;
+                               break;
+                       case HTTP_FIND_FL_MATCH_PFX:
+                               if (istlen(n) < istlen(name))
+                                       goto next_blk;
+
+                               n = ist2(istptr(n), istlen(name));
+                               if (!isteqi(n, name))
+                                       goto next_blk;
+                               break;
+                       case HTTP_FIND_FL_MATCH_SFX:
+                               if (istlen(n) < istlen(name))
+                                       goto next_blk;
+
+                               n = ist2(istptr(n) + istlen(n) - istlen(name), istlen(name));
+                               if (!isteqi(n, name))
+                                       goto next_blk;
+                               break;
+                       case HTTP_FIND_FL_MATCH_SUB:
+                               if (strnistr(n.ptr, n.len, name.ptr, n.len) != NULL)
+                                       goto next_blk;
+                               break;
+                       default:
                                goto next_blk;
+                               break;
+                       }
                }
+         match:
                v = htx_get_blk_value(htx, blk);
 
          return_hdr:
@@ -153,7 +217,7 @@ int http_find_header(const struct htx *htx, const struct ist name,
                        v.len--;
                        ctx->lws_before++;
                }
-               if (!full)
+               if (!(flags & HTTP_FIND_FL_FULL))
                        v.len = http_find_hdr_value_end(v.ptr, v.ptr + v.len) - v.ptr;
                while (v.len && HTTP_IS_LWS(*(v.ptr + v.len - 1))) {
                        v.len--;
@@ -173,6 +237,44 @@ int http_find_header(const struct htx *htx, const struct ist name,
        return 0;
 }
 
+
+/* Header names must match <name> */
+int http_find_header(const struct htx *htx, const struct ist name, struct http_hdr_ctx *ctx, int full)
+{
+       return __http_find_header(htx, &name, ctx, HTTP_FIND_FL_MATCH_STR | (full ? HTTP_FIND_FL_FULL : 0));
+}
+
+/* Header names must match <name>. Same than http_find_header */
+int http_find_str_header(const struct htx *htx, const struct ist name, struct http_hdr_ctx *ctx, int full)
+{
+       return __http_find_header(htx, &name, ctx, HTTP_FIND_FL_MATCH_STR | (full ? HTTP_FIND_FL_FULL : 0));
+}
+
+
+/* Header names must start with <prefix> */
+int http_find_pfx_header(const struct htx *htx, const struct ist prefix, struct http_hdr_ctx *ctx, int full)
+{
+       return __http_find_header(htx, &prefix, ctx, HTTP_FIND_FL_MATCH_PFX | (full ? HTTP_FIND_FL_FULL : 0));
+}
+
+/* Header names must end with <suffix> */
+int http_find_sfx_header(const struct htx *htx, const struct ist suffix, struct http_hdr_ctx *ctx, int full)
+{
+       return __http_find_header(htx, &suffix, ctx, HTTP_FIND_FL_MATCH_SFX | (full ? HTTP_FIND_FL_FULL : 0));
+}
+/* Header names must contain <sub> */
+int http_find_sub_header(const struct htx *htx, const struct ist sub, struct http_hdr_ctx *ctx, int full)
+{
+       return __http_find_header(htx, &sub, ctx, HTTP_FIND_FL_MATCH_SUB | (full ? HTTP_FIND_FL_FULL : 0));
+}
+
+/* Header names must match <re> regex*/
+int http_match_header(const struct htx *htx, const struct my_regex *re, struct http_hdr_ctx *ctx, int full)
+{
+       return __http_find_header(htx, re, ctx, HTTP_FIND_FL_MATCH_REG | (full ? HTTP_FIND_FL_FULL : 0));
+}
+
+
 /* Adds a header block int the HTX message <htx>, just before the EOH block. It
  * returns 1 on success, otherwise it returns 0.
  */