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"
This commit is contained in:
Aurelien DARRAGON 2022-12-30 16:37:03 +01:00 committed by Christopher Faulet
parent 5c6f86f465
commit 6fb58b8c9d
2 changed files with 74 additions and 0 deletions

View File

@ -17228,6 +17228,29 @@ rfc7239_is_valid
#input: "proto=custom"
# output: FALSE
rfc7239_field(<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(<value>)
Adds <value> to the input value of type signed integer, and returns the
result as a signed integer. <value> can be a numeric value or a variable

View File

@ -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 <const> 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 },
}};