[MINOR] Add pattern's fetchs payload and payload_lv
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 380136f..5039db8 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -1340,6 +1340,180 @@
 	return 1;
 }
 
+static int
+pattern_arg_fetch_payloadlv(const char *arg, struct pattern_arg **arg_p, int *arg_i)
+{
+	int member = 0;
+	int len_offset = 0;
+	int len_size = 0;
+	int buf_offset = 0;
+	int relative = 0;
+	int arg_len = strlen(arg);
+	int i;
+
+	for (i = 0; i < arg_len; i++) {
+		if (arg[i] == ',') {
+			member++;
+		} else if (member == 0) {
+			if (arg[i] < '0' || arg[i] > '9')
+				return 0;
+
+			len_offset = 10 * len_offset + arg[i] - '0';
+		} else if (member == 1) {
+			if (arg[i] < '0' || arg[i] > '9')
+				return 0;
+
+			len_size = 10 * len_size + arg[i] - '0';
+		} else if (member == 2) {
+			if (!relative && !buf_offset && arg[i] == '+') {
+				relative = 1;
+				continue;
+			} else if (!relative && !buf_offset && arg[i] == '-') {
+				relative = 2;
+				continue;
+			} else if (arg[i] < '0' || arg[i] > '9')
+				return 0;
+
+			buf_offset = 10 * buf_offset + arg[i] - '0';
+		}
+	}
+
+	if (member < 1)
+		return 0;
+
+	if (!len_size)
+		return 0;
+
+	if (member == 1) {
+		buf_offset = len_offset + len_size;
+	}
+	else if (relative == 1) {
+		buf_offset = len_offset + len_size + buf_offset;
+	}
+	else if (relative == 2) {
+		if (len_offset + len_size < buf_offset)
+			return 0;
+
+		buf_offset = len_offset + len_size - buf_offset;
+	}
+
+	*arg_i = 3;
+	*arg_p = calloc(1, *arg_i*sizeof(struct pattern_arg));
+	(*arg_p)[0].type = PATTERN_ARG_TYPE_INTEGER;
+	(*arg_p)[0].data.integer = len_offset;
+	(*arg_p)[1].type = PATTERN_ARG_TYPE_INTEGER;
+	(*arg_p)[1].data.integer = len_size;
+	(*arg_p)[2].type = PATTERN_ARG_TYPE_INTEGER;
+	(*arg_p)[2].data.integer = buf_offset;
+
+	return 1;
+}
+
+static int
+pattern_fetch_payloadlv(struct proxy *px, struct session *l4, void *l7, int dir,
+                        const struct pattern_arg *arg_p, int arg_i, union pattern_data *data)
+{
+	int len_offset = arg_p[0].data.integer;
+	int len_size = arg_p[1].data.integer;
+	int buf_offset = arg_p[2].data.integer;
+	int buf_size = 0;
+	struct buffer *b;
+	int i;
+
+	/* Format is (len offset, len size, buf offset) or (len offset, len size) */
+	/* by default buf offset == len offset + len size */
+	/* buf offset could be absolute or relative to len offset + len size if prefixed by + or - */
+
+	if (!l4)
+		return 0;
+
+	b = (dir & PATTERN_FETCH_RTR) ? l4->rep : l4->req;
+
+	if (!b || !b->l)
+		return 0;
+
+	if (len_offset + len_size > b->l)
+		return 0;
+
+	for (i = 0; i < len_size; i++) {
+		buf_size = (buf_size << 8) + ((unsigned char *)b->w)[i + len_offset];
+	}
+
+	if (!buf_size)
+		return 0;
+
+	if (buf_offset + buf_size > b->l)
+		return 0;
+
+	/* init chunk as read only */
+	chunk_initlen(&data->str, (char *)(b->w + buf_offset), 0, buf_size);
+
+	return 1;
+}
+
+static int
+pattern_arg_fetch_payload (const char *arg, struct pattern_arg **arg_p, int *arg_i)
+{
+	int member = 0;
+	int buf_offset = 0;
+	int buf_size = 0;
+	int arg_len = strlen(arg);
+	int i;
+
+	for (i = 0 ; i < arg_len ; i++) {
+		if (arg[i] == ',') {
+			member++;
+		} else if (member == 0) {
+			if (arg[i] < '0' || arg[i] > '9')
+				return 0;
+
+			buf_offset = 10 * buf_offset + arg[i] - '0';
+		} else if (member == 1) {
+			if (arg[i] < '0' || arg[i] > '9')
+				return 0;
+
+			buf_size = 10 * buf_size + arg[i] - '0';
+		}
+	}
+
+	if (!buf_size)
+		return 0;
+
+	*arg_i = 2;
+	*arg_p = calloc(1, *arg_i*sizeof(struct pattern_arg));
+	(*arg_p)[0].type = PATTERN_ARG_TYPE_INTEGER;
+	(*arg_p)[0].data.integer = buf_offset;
+	(*arg_p)[1].type = PATTERN_ARG_TYPE_INTEGER;
+	(*arg_p)[1].data.integer = buf_size;
+
+	return 1;
+}
+
+static int
+pattern_fetch_payload(struct proxy *px, struct session *l4, void *l7, int dir,
+                      const struct pattern_arg *arg_p, int arg_i, union pattern_data *data)
+{
+	int buf_offset = arg_p[0].data.integer;
+	int buf_size = arg_p[1].data.integer;
+	struct buffer *b;
+
+	if (!l4)
+		return 0;
+
+	b = (dir & PATTERN_FETCH_RTR) ? l4->rep : l4->req;
+
+	if (!b || !b->l)
+		return 0;
+
+	if (buf_offset + buf_size > b->l)
+		return 0;
+
+	/* init chunk as read only */
+	chunk_initlen(&data->str, (char *)(b->w + buf_offset), 0, buf_size);
+
+	return 1;
+}
+
 static struct cfg_kw_list cfg_kws = {{ },{
 	{ CFG_LISTEN, "tcp-request", tcp_parse_tcp_req },
 	{ CFG_LISTEN, "tcp-response", tcp_parse_tcp_rep },
@@ -1357,9 +1531,11 @@
 
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct pattern_fetch_kw_list pattern_fetch_keywords = {{ },{
-	{ "src",         pattern_fetch_src,   NULL, PATTERN_TYPE_IP,        PATTERN_FETCH_REQ },
-	{ "dst",         pattern_fetch_dst,   NULL, PATTERN_TYPE_IP,        PATTERN_FETCH_REQ },
-	{ "dst_port",    pattern_fetch_dport, NULL, PATTERN_TYPE_INTEGER,   PATTERN_FETCH_REQ },
+	{ "src",         pattern_fetch_src,       NULL,                         PATTERN_TYPE_IP,        PATTERN_FETCH_REQ },
+	{ "dst",         pattern_fetch_dst,       NULL,                         PATTERN_TYPE_IP,        PATTERN_FETCH_REQ },
+	{ "dst_port",    pattern_fetch_dport,     NULL,                         PATTERN_TYPE_INTEGER,   PATTERN_FETCH_REQ },
+	{ "payload",     pattern_fetch_payload,   pattern_arg_fetch_payload,    PATTERN_TYPE_CONSTDATA, PATTERN_FETCH_REQ|PATTERN_FETCH_RTR },
+	{ "payload_lv",  pattern_fetch_payloadlv, pattern_arg_fetch_payloadlv,  PATTERN_TYPE_CONSTDATA, PATTERN_FETCH_REQ|PATTERN_FETCH_RTR },
 	{ NULL, NULL, NULL, 0, 0 },
 }};