From: Aurelien DARRAGON Date: Fri, 30 Dec 2022 15:37:03 +0000 (+0100) Subject: MINOR: http_ext: add rfc7239_field converter X-Git-Tag: v2.8-dev3~68 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6fb58b8c9d53e2d28a3085d6f583fa72d24daaae;p=thirdparty%2Fhaproxy.git MINOR: http_ext: add rfc7239_field converter Adding new http converter: rfc7239_field. Takes a string representing 7239 forwarded header single value as input and extracts a single field/parameter from the header according to user selection. Example: # extract host field from forwarded header and store it in req.fhost var http-request set-var(req.fhost) req.hdr(forwarded),rfc7239_field(host) #input: "proto=https;host=\"haproxy.org:80\"" # output: "haproxy.org:80" # extract for field from forwarded header and store it in req.ffor var http-request set-var(req.ffor) req.hdr(forwarded),rfc7239_field(for) #input: "proto=https;host=\"haproxy.org:80\";for=\"127.0.0.1:9999\"" # output: "127.0.0.1:9999" Depends on: - "MINOR: http_ext: introduce http ext converters" --- diff --git a/doc/configuration.txt b/doc/configuration.txt index a40f0903fb..b0c64a5bf9 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -17228,6 +17228,29 @@ rfc7239_is_valid #input: "proto=custom" # output: FALSE +rfc7239_field() + Extracts a single field/parameter from RFC 7239 compliant header value input. + + Supported fields are: + - proto: either 'http' or 'https' + - host: http compliant host + - for: RFC7239 node + - by: RFC7239 node + + More info here: + https://www.rfc-editor.org/rfc/rfc7239.html#section-6 + + Example: + # extract host field from forwarded header and store it in req.fhost var + http-request set-var(req.fhost) req.hdr(forwarded),rfc7239_field(host) + #input: "proto=https;host=\"haproxy.org:80\"" + # output: "haproxy.org:80" + + # extract for field from forwarded header and store it in req.ffor var + http-request set-var(req.ffor) req.hdr(forwarded),rfc7239_field(for) + #input: "proto=https;host=\"haproxy.org:80\";for=\"127.0.0.1:9999\"" + # output: "127.0.0.1:9999" + add() Adds to the input value of type signed integer, and returns the result as a signed integer. can be a numeric value or a variable diff --git a/src/http_ext.c b/src/http_ext.c index 1b899471cb..ba8bec8e00 100644 --- a/src/http_ext.c +++ b/src/http_ext.c @@ -1383,9 +1383,60 @@ static int sample_conv_7239_valid(const struct arg *args, struct sample *smp, vo return 1; } +/* input: string representing 7239 forwarded header single value + * argument: parameter name to look for in the header + * output: header parameter raw value, as a string + */ +static int sample_conv_7239_field(const struct arg *args, struct sample *smp, void *private) +{ + struct ist input = ist2(smp->data.u.str.area, smp->data.u.str.data); + struct buffer *output; + struct forwarded_header_ctx ctx; + int validate; + int field = 0; + + if (strcmp(args->data.str.area, "proto") == 0) + field = FORWARDED_HEADER_PROTO; + else if (strcmp(args->data.str.area, "host") == 0) + field = FORWARDED_HEADER_HOST; + else if (strcmp(args->data.str.area, "for") == 0) + field = FORWARDED_HEADER_FOR; + else if (strcmp(args->data.str.area, "by") == 0) + field = FORWARDED_HEADER_BY; + + validate = http_validate_7239_header(input, FORWARDED_HEADER_ALL, &ctx); + if (!(validate & field)) + return 0; /* invalid header or header does not contain field */ + output = get_trash_chunk(); + switch (field) { + case FORWARDED_HEADER_PROTO: + if (ctx.proto == FORWARDED_HEADER_HTTP) + chunk_appendf(output, "http"); + else if (ctx.proto == FORWARDED_HEADER_HTTPS) + chunk_appendf(output, "https"); + break; + case FORWARDED_HEADER_HOST: + chunk_istcat(output, ctx.host); + break; + case FORWARDED_HEADER_FOR: + chunk_istcat(output, ctx.nfor.raw); + break; + case FORWARDED_HEADER_BY: + chunk_istcat(output, ctx.nby.raw); + break; + default: + break; + } + smp->flags &= ~SMP_F_CONST; + smp->data.type = SMP_T_STR; + smp->data.u.str = *output; + return 1; +} + /* Note: must not be declared as its list will be overwritten */ static struct sample_conv_kw_list sample_conv_kws = {ILH, { { "rfc7239_is_valid", sample_conv_7239_valid, 0, NULL, SMP_T_STR, SMP_T_BOOL}, + { "rfc7239_field", sample_conv_7239_field, ARG1(1,STR), NULL, SMP_T_STR, SMP_T_STR}, { NULL, NULL, 0, 0, 0 }, }};