MINOR: converter: adding support for url_enc

add base support for url encode following RFC3986, supporting `query`
type only.

- add test checking url_enc/url_dec/url_enc
- update documentation
- leave the door open for future changes

this should resolve github issue #941

Signed-off-by: William Dauchy <wdauchy@gmail.com>
This commit is contained in:
William Dauchy 2021-01-06 23:39:50 +01:00 committed by Willy Tarreau
parent 421ed3952d
commit 888b0ae8cf
3 changed files with 126 additions and 0 deletions

View File

@ -16240,6 +16240,12 @@ url_dec([<in_form>])
space (' '). Otherwise this will only happen after a question mark indicating space (' '). Otherwise this will only happen after a question mark indicating
a query string ('?'). a query string ('?').
url_enc([<enc_type>])
Takes a string provided as input and returns the encoded version as output.
The input and the output are of type string. By default the type of encoding
is meant for `query` type. There is no other type supported for now but the
optional argument is here for future changes.
ungrpc(<field_number>,[<field_type>]) ungrpc(<field_number>,[<field_type>])
This extracts the protocol buffers message field in raw mode of an input binary This extracts the protocol buffers message field in raw mode of an input binary
sample representation of a gRPC message with <field_number> as field number sample representation of a gRPC message with <field_number> as field number

View File

@ -0,0 +1,43 @@
varnishtest "url_enc converter test"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
server s1 {
rxreq
txresp
} -repeat 2 -start
haproxy h1 -conf {
defaults
mode http
timeout connect 1s
timeout client 1s
timeout server 1s
frontend fe
bind "fd@${fe}"
http-request set-var(txn.url0) "str(foo=bar+42 42 )"
http-request set-var(txn.url1) "var(txn.url0),url_enc"
http-request set-var(txn.url2) "var(txn.url1),url_dec"
http-request set-var(txn.url3) "var(txn.url2),url_enc(query)"
http-response set-header url_enc0 "%[var(txn.url1)]"
http-response set-header url_dec "%[var(txn.url2)]"
http-response set-header url_enc1 "%[var(txn.url3)]"
default_backend be
backend be
server s1 ${s1_addr}:${s1_port}
} -start
client c1 -connect ${h1_fe_sock} {
txreq -url "/"
rxresp
expect resp.http.url_enc0 == "foo%3Dbar%2B42%2042%20"
expect resp.http.url_dec == "foo=bar+42 42 "
expect resp.http.url_enc1 == "foo%3Dbar%2B42%2042%20"
expect resp.status == 200
} -run

View File

@ -268,6 +268,82 @@ static int sample_conv_url_dec(const struct arg *args, struct sample *smp, void
return 1; return 1;
} }
/* url-encode types and encode maps */
enum encode_type {
ENC_QUERY = 0,
};
long query_encode_map[(256 / 8) / sizeof(long)];
/* Check url-encode type */
static int sample_conv_url_enc_check(struct arg *arg, struct sample_conv *conv,
const char *file, int line, char **err)
{
enum encode_type enc_type;
if (strcmp(arg->data.str.area, "") == 0)
enc_type = ENC_QUERY;
else if (strcmp(arg->data.str.area, "query") == 0)
enc_type = ENC_QUERY;
else {
memprintf(err, "Unexpected encode type. "
"Allowed value is 'query'");
return 0;
}
chunk_destroy(&arg->data.str);
arg->type = ARGT_SINT;
arg->data.sint = enc_type;
return 1;
}
/* Initializes some url encode data at boot */
static void sample_conf_url_enc_init()
{
int i;
memset(query_encode_map, 0, sizeof(query_encode_map));
/* use rfc3986 to determine list of characters to keep unchanged for
* query string */
for (i = 0; i < 256; i++) {
if (!((i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z')
|| (i >= '0' && i <= '9') ||
i == '-' || i == '.' || i == '_' || i == '~'))
ha_bit_set(i, query_encode_map);
}
}
INITCALL0(STG_PREPARE, sample_conf_url_enc_init);
/* This fetch url-encode any input string. Only support query string for now */
static int sample_conv_url_enc(const struct arg *args, struct sample *smp, void
*private)
{
enum encode_type enc_type;
struct buffer *trash = get_trash_chunk();
long *encode_map;
char *ret;
enc_type = ENC_QUERY;
if (args)
enc_type = args->data.sint;
/* Add final \0 required by encode_string() */
smp->data.u.str.area[smp->data.u.str.data] = '\0';
if (enc_type == ENC_QUERY)
encode_map = query_encode_map;
else
return 0;
ret = encode_string(trash->area, trash->area + trash->size, '%',
encode_map, smp->data.u.str.area);
if (ret == NULL || *ret != '\0')
return 0;
trash->data = ret - trash->area;
smp->data.u.str = *trash;
return 1;
}
static int smp_conv_req_capture(const struct arg *args, struct sample *smp, void *private) static int smp_conv_req_capture(const struct arg *args, struct sample *smp, void *private)
{ {
struct proxy *fe; struct proxy *fe;
@ -369,6 +445,7 @@ static struct sample_conv_kw_list sample_conv_kws = {ILH, {
{ "capture-req", smp_conv_req_capture, ARG1(1,SINT), NULL, SMP_T_STR, SMP_T_STR}, { "capture-req", smp_conv_req_capture, ARG1(1,SINT), NULL, SMP_T_STR, SMP_T_STR},
{ "capture-res", smp_conv_res_capture, ARG1(1,SINT), NULL, SMP_T_STR, SMP_T_STR}, { "capture-res", smp_conv_res_capture, ARG1(1,SINT), NULL, SMP_T_STR, SMP_T_STR},
{ "url_dec", sample_conv_url_dec, ARG1(0,SINT), NULL, SMP_T_STR, SMP_T_STR}, { "url_dec", sample_conv_url_dec, ARG1(0,SINT), NULL, SMP_T_STR, SMP_T_STR},
{ "url_enc", sample_conv_url_enc, ARG1(1,STR), sample_conv_url_enc_check, SMP_T_STR, SMP_T_STR},
{ NULL, NULL, 0, 0, 0 }, { NULL, NULL, 0, 0, 0 },
}}; }};