diff --git a/include/proto/http_htx.h b/include/proto/http_htx.h index c9f730ebc..7a6d476b5 100644 --- a/include/proto/http_htx.h +++ b/include/proto/http_htx.h @@ -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 */ diff --git a/src/http_htx.c b/src/http_htx.c index 36a279342..129523178 100644 --- a/src/http_htx.c +++ b/src/http_htx.c @@ -535,3 +535,132 @@ int http_remove_header(struct htx *htx, struct http_hdr_ctx *ctx) return 1; } + + +/* Return in and the pointer and length of occurrence of + * header whose name is of length . If 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 + * is positive or null, occurrence #occ from the beginning (or last ctx) + * is returned. Occ #0 and #1 are equivalent. If 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 and the pointer and length of occurrence of + * header whose name is of length . If 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 + * is positive or null, occurrence #occ from the beginning (or last ctx) + * is returned. Occ #0 and #1 are equivalent. If 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; +}