MEDIUM: pattern: retrieve the sample type in the sample, not in the keyword description
We need the pattern fetchers and converters to correctly set the output type
so that they can be used by ACL fetchers. By using the sample type instead of
the keyword type, we also open the possibility to create some multi-type
pattern fetch methods later (eg: "src" being v4/v6). Right now the type in
the keyword is used to validate the configuration.
diff --git a/src/pattern.c b/src/pattern.c
index f851331..9787ecc 100644
--- a/src/pattern.c
+++ b/src/pattern.c
@@ -118,6 +118,8 @@
/******************************************************************/
/* Pattern casts functions */
+/* Note: these functions do *NOT* set the output type on the */
+/* sample, the caller is responsible for doing this on return. */
/******************************************************************/
static int c_ip2int(struct sample *smp)
@@ -466,6 +468,10 @@
* pattern is not found or when format conversion failed.
* If <p> is not null, function returns results in structure pointed by <p>.
* If <p> is null, functions returns a pointer on a static pattern structure.
+ *
+ * Note: the fetch functions are required to properly set the return type. The
+ * conversion functions must do so too. However the cast functions do not need
+ * to since they're made to cast mutiple types according to what is required.
*/
struct sample *pattern_process(struct proxy *px, struct session *l4, void *l7, int dir,
struct pattern_expr *expr, struct sample *p)
@@ -479,23 +485,21 @@
if (!expr->fetch->process(px, l4, l7, dir, expr->arg_p, p))
return NULL;
- p->type = expr->fetch->out_type;
-
list_for_each_entry(conv_expr, &expr->conv_exprs, list) {
if (!pattern_casts[p->type][conv_expr->conv->in_type](p))
return NULL;
+ /* force the output type after a cast */
p->type = conv_expr->conv->in_type;
if (!conv_expr->conv->process(conv_expr->arg_p, p))
return NULL;
-
- p->type = conv_expr->conv->out_type;
}
return p;
}
/*****************************************************************/
/* Pattern format convert functions */
+/* These functions set the data type on return. */
/*****************************************************************/
static int pattern_conv_str2lower(const struct arg *arg_p, struct sample *smp)
@@ -509,6 +513,7 @@
if ((smp->data.str.str[i] >= 'A') && (smp->data.str.str[i] <= 'Z'))
smp->data.str.str[i] += 'a' - 'A';
}
+ smp->type = SMP_T_STR;
return 1;
}
@@ -523,6 +528,7 @@
if ((smp->data.str.str[i] >= 'a') && (smp->data.str.str[i] <= 'z'))
smp->data.str.str[i] += 'A' - 'a';
}
+ smp->type = SMP_T_STR;
return 1;
}
@@ -530,6 +536,7 @@
static int pattern_conv_ipmask(const struct arg *arg_p, struct sample *smp)
{
smp->data.ipv4.s_addr &= arg_p->data.ipv4.s_addr;
+ smp->type = SMP_T_IPV4;
return 1;
}
diff --git a/src/proto_http.c b/src/proto_http.c
index 4d504b0..933351a 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -8352,6 +8352,7 @@
{
struct http_txn *txn = l7;
+ smp->type = SMP_T_CSTR;
return http_get_hdr(&txn->req, arg_p->data.str.str, arg_p->data.str.len, &txn->hdr_idx,
-1, NULL, &smp->data.str.str, &smp->data.str.len);
}
@@ -8455,6 +8456,7 @@
&url_param_value, &url_param_value_l))
return 0;
+ smp->type = SMP_T_CSTR;
smp->data.str.str = url_param_value;
smp->data.str.len = url_param_value_l;
return 1;
@@ -8508,6 +8510,7 @@
arg_p->data.str.str, arg_p->data.str.len, 1,
&cookie_value, &cookie_value_l);
if (found) {
+ smp->type = SMP_T_CSTR;
smp->data.str.str = cookie_value;
smp->data.str.len = cookie_value_l;
}
@@ -8530,6 +8533,7 @@
arg_p->data.str.str, arg_p->data.str.len, 1,
&cookie_value, &cookie_value_l);
if (found) {
+ smp->type = SMP_T_CSTR;
smp->data.str.str = cookie_value;
smp->data.str.len = cookie_value_l;
}
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 6b2101a..bd46de2 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -1281,6 +1281,7 @@
if (l4->si[0].addr.from.ss_family != AF_INET )
return 0;
+ smp->type = SMP_T_IPV4;
smp->data.ipv4.s_addr = ((struct sockaddr_in *)&l4->si[0].addr.from)->sin_addr.s_addr;
return 1;
}
@@ -1293,6 +1294,7 @@
if (l4->si[0].addr.from.ss_family != AF_INET6)
return 0;
+ smp->type = SMP_T_IPV6;
memcpy(smp->data.ipv6.s6_addr, ((struct sockaddr_in6 *)&l4->si[0].addr.from)->sin6_addr.s6_addr, sizeof(smp->data.ipv6.s6_addr));
return 1;
}
@@ -1346,6 +1348,7 @@
if (l4->si[0].addr.to.ss_family != AF_INET)
return 0;
+ smp->type = SMP_T_IPV4;
smp->data.ipv4.s_addr = ((struct sockaddr_in *)&l4->si[0].addr.to)->sin_addr.s_addr;
return 1;
}
@@ -1360,6 +1363,7 @@
if (l4->si[0].addr.to.ss_family != AF_INET6)
return 0;
+ smp->type = SMP_T_IPV6;
memcpy(smp->data.ipv6.s6_addr, ((struct sockaddr_in6 *)&l4->si[0].addr.to)->sin6_addr.s6_addr, sizeof(smp->data.ipv6.s6_addr));
return 1;
}
@@ -1383,6 +1387,7 @@
pattern_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir,
const struct arg *arg, struct sample *smp)
{
+ smp->type = SMP_T_UINT;
stream_sock_get_to_addr(&l4->si[0]);
if (!(smp->data.uint = get_host_port(&l4->si[0].addr.to)))
@@ -1435,6 +1440,7 @@
return 0;
/* init chunk as read only */
+ smp->type = SMP_T_CBIN;
chunk_initlen(&smp->data.str, b->p + buf_offset, 0, buf_size);
return 1;
@@ -1460,6 +1466,7 @@
return 0;
/* init chunk as read only */
+ smp->type = SMP_T_CBIN;
chunk_initlen(&smp->data.str, b->p + buf_offset, 0, buf_size);
return 1;
@@ -1486,6 +1493,7 @@
expr.args = args;
+ /* type set by acl_fetch_rdp_cookie */
ret = acl_fetch_rdp_cookie(px, l4, NULL, ACL_DIR_REQ, &expr, smp);
if (ret == 0 || (smp->flags & SMP_F_MAY_CHANGE) || smp->data.str.len == 0)
return 0;