MEDIUM: http: make url_param iterate over multiple occurrences

There are some situations hwere it's desirable to scan multiple occurrences
of a same parameter name in the query string. This change ensures this can
work, even with an empty name which will then iterate over all parameters.
This commit is contained in:
Willy Tarreau 2015-05-07 16:06:18 +02:00
parent 26ea822190
commit 1ede1daab6
2 changed files with 71 additions and 32 deletions

View File

@ -12709,17 +12709,18 @@ url_port : integer
restrict access to certain systems through a proxy, for example when combined
with option "http_proxy".
urlp(<name>[,<delim>]) : string
url_param(<name>[,<delim>]) : string
urlp([<name>[,<delim>]]) : string
url_param([<name>[,<delim>]]) : string
This extracts the first occurrence of the parameter <name> in the query
string, which begins after either '?' or <delim>, and which ends before '&',
';' or <delim>. The parameter name is case-sensitive. The result is a string
corresponding to the value of the parameter <name> as presented in the
request (no URL decoding is performed). This can be used for session
';' or <delim>. The parameter name is case-sensitive. If no name is given,
any parameter will match, and the first one will be returned. The result is
a string corresponding to the value of the parameter <name> as presented in
the request (no URL decoding is performed). This can be used for session
stickiness based on a client ID, to extract an application cookie passed as a
URL parameter, or in ACLs to apply some checks. Note that the ACL version of
this fetch do not iterate over multiple parameters and stop at the first one
as well.
this fetch iterates over multiple parameters and will iteratively report all
parameters values if no name is given
ACL derivatives :
urlp(<name>[,<delim>]) : exact string match
@ -12738,7 +12739,7 @@ url_param(<name>[,<delim>]) : string
# match http://example.com/foo;JSESSIONID=some_id
stick on urlp(JSESSIONID,;)
urlp_val(<name>[,<delim>]) : integer
urlp_val([<name>[,<delim>])] : integer
See "urlp" above. This one extracts the URL parameter <name> in the request
and converts it to an integer value. This can be used for session stickiness
based on a user ID for example, or with ACLs to match a page number or price.

View File

@ -11488,7 +11488,7 @@ smp_fetch_cookie_val(const struct arg *args, struct sample *smp, const char *kw,
*
* Example: if path = "/foo/bar/fubar?yo=mama;ye=daddy", and n = 22:
*
* find_query_string(path, n) points to "yo=mama;ye=daddy" string.
* find_query_string(path, n, '?') points to "yo=mama;ye=daddy" string.
*/
static inline char *find_param_list(char *path, size_t path_l, char delim)
{
@ -11512,7 +11512,7 @@ static inline int is_param_delimiter(char c, char delim)
*/
static char*
find_url_param_pos(char* query_string, size_t query_string_l,
char* url_param_name, size_t url_param_name_l,
const char* url_param_name, size_t url_param_name_l,
char delim)
{
char *pos, *last;
@ -11534,31 +11534,37 @@ find_url_param_pos(char* query_string, size_t query_string_l,
}
/*
* Given a url parameter name, returns its value and size into *value and
* *value_l respectively, and returns non-zero. If the parameter is not found,
* zero is returned and value/value_l are not touched.
* Given a url parameter name and a query string, returns its value and size
* into *value and *value_l respectively, and returns non-zero. An empty
* url_param_name matches the first available parameter. If the parameter is
* not found, zero is returned and value/value_l are not touched.
*/
static int
find_url_param_value(char* path, size_t path_l,
char* url_param_name, size_t url_param_name_l,
char** value, int* value_l, char delim)
find_next_url_param(char* query_string, char *qs_end,
const char* url_param_name, size_t url_param_name_l,
char** value, int* value_l, char delim)
{
char *query_string, *qs_end;
char *arg_start;
char *value_start, *value_end;
query_string = find_param_list(path, path_l, delim);
if (!query_string)
return 0;
qs_end = path + path_l;
arg_start = find_url_param_pos(query_string, qs_end - query_string,
url_param_name, url_param_name_l,
delim);
arg_start = query_string;
if (url_param_name_l) {
arg_start = find_url_param_pos(query_string, qs_end - query_string,
url_param_name, url_param_name_l,
delim);
}
if (!arg_start)
return 0;
value_start = arg_start + url_param_name_l + 1;
if (!url_param_name_l) {
value_start = memchr(arg_start, '=', qs_end - arg_start);
if (!value_start)
return 0;
value_start++;
}
else
value_start = arg_start + url_param_name_l + 1;
value_end = value_start;
while ((value_end < qs_end) && !is_param_delimiter(*value_end, delim))
@ -11574,8 +11580,12 @@ smp_fetch_url_param(const struct arg *args, struct sample *smp, const char *kw,
{
char delim = '?';
struct http_msg *msg;
char *query_string, *qs_end;
const char *name;
int name_len;
if (!args || args[0].type != ARGT_STR ||
if (!args ||
(args[0].type && args[0].type != ARGT_STR) ||
(args[1].type && args[1].type != ARGT_STR))
return 0;
@ -11586,14 +11596,42 @@ smp_fetch_url_param(const struct arg *args, struct sample *smp, const char *kw,
if (args[1].type)
delim = *args[1].data.str.str;
if (!find_url_param_value(msg->chn->buf->p + msg->sl.rq.u, msg->sl.rq.u_l,
args->data.str.str, args->data.str.len,
query_string = smp->ctx.a[0];
qs_end = smp->ctx.a[1];
if (!query_string) { // first call, find the query string
query_string = find_param_list(msg->chn->buf->p + msg->sl.rq.u,
msg->sl.rq.u_l, delim);
if (!query_string)
return 0;
qs_end = msg->chn->buf->p + msg->sl.rq.u + msg->sl.rq.u_l;
smp->ctx.a[0] = query_string;
smp->ctx.a[1] = qs_end;
}
name = "";
name_len = 0;
if (args->type == ARGT_STR) {
name = args->data.str.str;
name_len = args->data.str.len;
}
if (!find_next_url_param(query_string, qs_end,
name, name_len,
&smp->data.str.str, &smp->data.str.len,
delim))
return 0;
query_string = smp->data.str.str + smp->data.str.len + 1;
smp->ctx.a[0] = query_string;
smp->type = SMP_T_STR;
smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
if (query_string < qs_end)
smp->flags |= SMP_F_NOT_LAST;
return 1;
}
@ -12466,9 +12504,9 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
{ "url32+src", smp_fetch_url32_src, 0, NULL, SMP_T_BIN, SMP_USE_HRQHV },
{ "url_ip", smp_fetch_url_ip, 0, NULL, SMP_T_IPV4, SMP_USE_HRQHV },
{ "url_port", smp_fetch_url_port, 0, NULL, SMP_T_UINT, SMP_USE_HRQHV },
{ "url_param", smp_fetch_url_param, ARG2(1,STR,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
{ "urlp" , smp_fetch_url_param, ARG2(1,STR,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
{ "urlp_val", smp_fetch_url_param_val, ARG2(1,STR,STR), NULL, SMP_T_UINT, SMP_USE_HRQHV },
{ "url_param", smp_fetch_url_param, ARG2(0,STR,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
{ "urlp" , smp_fetch_url_param, ARG2(0,STR,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
{ "urlp_val", smp_fetch_url_param_val, ARG2(0,STR,STR), NULL, SMP_T_UINT, SMP_USE_HRQHV },
{ /* END */ },
}};