]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: http_htx: Add functions to retrieve a specific occurrence of a header
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 24 Oct 2018 08:39:35 +0000 (10:39 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 18 Nov 2018 21:08:55 +0000 (22:08 +0100)
There are 2 functions. The first one considers any comma as a delimiter for
distinct values. The second one considers full-line headers.

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

index c9f730ebc7e4c0db68d9c9175c127923183502ba..7a6d476b5761d21b15f25064bb1203b2a01e67a4 100644 (file)
@@ -42,5 +42,9 @@ int http_replace_res_reason(struct htx *htx, const struct ist reason);
 int http_replace_header_value(struct htx *htx, struct http_hdr_ctx *ctx, const struct ist data);
 int http_replace_header(struct htx *htx, struct http_hdr_ctx *ctx, const struct ist name, const struct ist value);
 int http_remove_header(struct htx *htx, struct http_hdr_ctx *ctx);
+unsigned int http_get_htx_hdr(const struct htx *htx, const struct ist hdr,
+                             int occ, struct http_hdr_ctx *ctx, char **vptr, size_t *vlen);
+unsigned int http_get_htx_fhdr(const struct htx *htx, const struct ist hdr,
+                              int occ, struct http_hdr_ctx *ctx, char **vptr, size_t *vlen);
 
 #endif /* _PROTO_HTTP_HTX_H */
index 36a27934249e58f67317d4905f1e8fe41286f1ab..129523178031bc7255954edac29ee579f51781ac 100644 (file)
@@ -535,3 +535,132 @@ int http_remove_header(struct htx *htx, struct http_hdr_ctx *ctx)
 
        return 1;
 }
+
+
+/* Return in <vptr> and <vlen> the pointer and length of occurrence <occ> of
+ * header whose name is <hname> of length <hlen>. If <ctx> is null, lookup is
+ * performed over the whole headers. Otherwise it must contain a valid header
+ * context, initialised with ctx->blk=NULL for the first lookup in a series. If
+ * <occ> is positive or null, occurrence #occ from the beginning (or last ctx)
+ * is returned. Occ #0 and #1 are equivalent. If <occ> is negative (and no less
+ * than -MAX_HDR_HISTORY), the occurrence is counted from the last one which is
+ * -1. The value fetch stops at commas, so this function is suited for use with
+ * list headers.
+ * The return value is 0 if nothing was found, or non-zero otherwise.
+ */
+unsigned int http_get_htx_hdr(const struct htx *htx, const struct ist hdr,
+                             int occ, struct http_hdr_ctx *ctx, char **vptr, size_t *vlen)
+{
+       struct http_hdr_ctx local_ctx;
+       struct ist val_hist[MAX_HDR_HISTORY];
+       unsigned int hist_idx;
+       int found;
+
+       if (!ctx) {
+               local_ctx.blk = NULL;
+               ctx = &local_ctx;
+       }
+
+       if (occ >= 0) {
+               /* search from the beginning */
+               while (http_find_header(htx, hdr, ctx, 0)) {
+                       occ--;
+                       if (occ <= 0) {
+                               *vptr = ctx->value.ptr;
+                               *vlen = ctx->value.len;
+                               return 1;
+                       }
+               }
+               return 0;
+       }
+
+       /* negative occurrence, we scan all the list then walk back */
+       if (-occ > MAX_HDR_HISTORY)
+               return 0;
+
+       found = hist_idx = 0;
+       while (http_find_header(htx, hdr, ctx, 0)) {
+               val_hist[hist_idx] = ctx->value;
+               if (++hist_idx >= MAX_HDR_HISTORY)
+                       hist_idx = 0;
+               found++;
+       }
+       if (-occ > found)
+               return 0;
+
+       /* OK now we have the last occurrence in [hist_idx-1], and we need to
+        * find occurrence -occ. 0 <= hist_idx < MAX_HDR_HISTORY, and we have
+        * -10 <= occ <= -1. So we have to check [hist_idx%MAX_HDR_HISTORY+occ]
+        * to remain in the 0..9 range.
+        */
+       hist_idx += occ + MAX_HDR_HISTORY;
+       if (hist_idx >= MAX_HDR_HISTORY)
+               hist_idx -= MAX_HDR_HISTORY;
+       *vptr = val_hist[hist_idx].ptr;
+       *vlen = val_hist[hist_idx].len;
+       return 1;
+}
+
+/* Return in <vptr> and <vlen> the pointer and length of occurrence <occ> of
+ * header whose name is <hname> of length <hlen>. If <ctx> is null, lookup is
+ * performed over the whole headers. Otherwise it must contain a valid header
+ * context, initialised with ctx->blk=NULL for the first lookup in a series. If
+ * <occ> is positive or null, occurrence #occ from the beginning (or last ctx)
+ * is returned. Occ #0 and #1 are equivalent. If <occ> is negative (and no less
+ * than -MAX_HDR_HISTORY), the occurrence is counted from the last one which is
+ * -1. This function differs from http_get_hdr() in that it only returns full
+ * line header values and does not stop at commas.
+ * The return value is 0 if nothing was found, or non-zero otherwise.
+ */
+unsigned int http_get_htx_fhdr(const struct htx *htx, const struct ist hdr,
+                              int occ, struct http_hdr_ctx *ctx, char **vptr, size_t *vlen)
+{
+       struct http_hdr_ctx local_ctx;
+       struct ist val_hist[MAX_HDR_HISTORY];
+       unsigned int hist_idx;
+       int found;
+
+       if (!ctx) {
+               local_ctx.blk = NULL;
+               ctx = &local_ctx;
+       }
+
+       if (occ >= 0) {
+               /* search from the beginning */
+               while (http_find_header(htx, hdr, ctx, 1)) {
+                       occ--;
+                       if (occ <= 0) {
+                               *vptr = ctx->value.ptr;
+                               *vlen = ctx->value.len;
+                               return 1;
+                       }
+               }
+               return 0;
+       }
+
+       /* negative occurrence, we scan all the list then walk back */
+       if (-occ > MAX_HDR_HISTORY)
+               return 0;
+
+       found = hist_idx = 0;
+       while (http_find_header(htx, hdr, ctx, 1)) {
+               val_hist[hist_idx] = ctx->value;
+               if (++hist_idx >= MAX_HDR_HISTORY)
+                       hist_idx = 0;
+               found++;
+       }
+       if (-occ > found)
+               return 0;
+
+       /* OK now we have the last occurrence in [hist_idx-1], and we need to
+        * find occurrence -occ. 0 <= hist_idx < MAX_HDR_HISTORY, and we have
+        * -10 <= occ <= -1. So we have to check [hist_idx%MAX_HDR_HISTORY+occ]
+        * to remain in the 0..9 range.
+        */
+       hist_idx += occ + MAX_HDR_HISTORY;
+       if (hist_idx >= MAX_HDR_HISTORY)
+               hist_idx -= MAX_HDR_HISTORY;
+       *vptr = val_hist[hist_idx].ptr;
+       *vlen = val_hist[hist_idx].len;
+       return 1;
+}