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
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>])
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

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;
}
/* 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)
{
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-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_enc", sample_conv_url_enc, ARG1(1,STR), sample_conv_url_enc_check, SMP_T_STR, SMP_T_STR},
{ NULL, NULL, 0, 0, 0 },
}};