MINOR: http: capture.req.method and capture.req.uri
Add 2 sample fetchs allowing to extract the method and the uri of an
HTTP request.
FIXME: the sample fetches parser can't add the LW_REQ requirement, at
the moment this flag is used automatically when you use sample fetches.
Note: also fixed the alphabetical order of other capture.req.* keywords
in the doc.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 014d9db..6d4df7d 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -10556,6 +10556,28 @@
depending on the source address family. This can be used to track per-IP,
per-URL counters.
+capture.req.hdr(<idx>) : string
+ This extracts the content of the header captured by the "capture request
+ header", idx is the position of the capture keyword in the configuration.
+ The first entry is an index of 0. See also: "capture request header".
+
+capture.req.method : string
+ This extracts the METHOD of an HTTP request. It can be used in both request
+ and response. Unlike "method", it can be used in both request and response
+ because it's allocated.
+
+capture.req.uri : string
+ This extracts the request's URI, which starts at the first slash and ends
+ before the first space in the request (without the host part). Unlike "path"
+ and "url", it can be used in both request and response because it's
+ allocated.
+
+capture.res.hdr(<idx>) : string
+ This extracts the content of the header captured by the "capture response
+ header", idx is the position of the capture keyword in the configuration.
+ The first entry is an index of 0.
+ See also: "capture response header"
+
req.cook([<name>]) : string
cook([<name>]) : string (deprecated)
This extracts the last occurrence of the cookie name <name> on a "Cookie"
@@ -10601,18 +10623,6 @@
ambiguously uses the direction based on the context where it is used.
See also : "appsession".
-capture.req.hdr(<idx>) : string
- This extracts the content of the header captured by the "capture request
- header", idx is the position of the capture keyword in the configuration.
- The first entry is an index of 0.
- See also: "capture request header"
-
-capture.res.hdr(<idx>) : string
- This extracts the content of the header captured by the "capture response
- header", idx is the position of the capture keyword in the configuration.
- The first entry is an index of 0.
- See also: "capture response header"
-
hdr([<name>[,<occ>]]) : string
This is equivalent to req.hdr() when used on requests, and to res.hdr() when
used on responses. Please refer to these respective fetches for more details.
diff --git a/src/log.c b/src/log.c
index 2a6acf4..046294e 100644
--- a/src/log.c
+++ b/src/log.c
@@ -382,11 +382,12 @@
/* Note, we may also need to set curpx->to_log with certain fetches */
curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
- /* FIXME: temporary workaround for missing LW_XPRT flag needed with some
- * sample fetches (eg: ssl*). We always set it for now on, but this will
- * leave with sample capabilities soon.
+ /* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags
+ * needed with some sample fetches (eg: ssl*). We always set it for
+ * now on, but this will leave with sample capabilities soon.
*/
curpx->to_log |= LW_XPRT;
+ curpx->to_log |= LW_REQ;
LIST_ADDQ(list_format, &node->list);
}
diff --git a/src/proto_http.c b/src/proto_http.c
index e92dc6a..211a37a 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -835,6 +835,46 @@
return ptr;
}
+/* Parse the URI from the given string and look for the "/" beginning the PATH.
+ * If not found, return NULL. It is returned otherwise.
+ */
+static char *
+http_get_path_from_string(char *str)
+{
+ char *ptr = str;
+
+ /* RFC2616, par. 5.1.2 :
+ * Request-URI = "*" | absuri | abspath | authority
+ */
+
+ if (*ptr == '*')
+ return NULL;
+
+ if (isalpha((unsigned char)*ptr)) {
+ /* this is a scheme as described by RFC3986, par. 3.1 */
+ ptr++;
+ while (isalnum((unsigned char)*ptr) || *ptr == '+' || *ptr == '-' || *ptr == '.')
+ ptr++;
+ /* skip '://' */
+ if (*ptr == '\0' || *ptr++ != ':')
+ return NULL;
+ if (*ptr == '\0' || *ptr++ != '/')
+ return NULL;
+ if (*ptr == '\0' || *ptr++ != '/')
+ return NULL;
+ }
+ /* skip [user[:passwd]@]host[:[port]] */
+
+ while (*ptr != '\0' && *ptr != ' ' && *ptr != '/')
+ ptr++;
+
+ if (*ptr == '\0' || *ptr == ' ')
+ return NULL;
+
+ /* OK, we got the '/' ! */
+ return ptr;
+}
+
/* Returns a 302 for a redirectable request that reaches a server working in
* in redirect mode. This may only be called just after the stream interface
* has moved to SI_ST_ASS. Unprocessable requests are left unchanged and will
@@ -9731,6 +9771,78 @@
return 1;
}
+/* Extracts the METHOD in the HTTP request, the txn->uri should be filled before the call */
+static int
+smp_fetch_capture_req_method(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
+ const struct arg *args, struct sample *smp, const char *kw)
+{
+ struct chunk *temp;
+ struct http_txn *txn = l7;
+ char *spc;
+ int len;
+
+ if (!txn->uri)
+ return 0;
+
+ spc = strchr(txn->uri, ' '); /* first space before URI */
+ if (likely(spc))
+ len = spc - txn->uri;
+ else
+ len = strlen(txn->uri);
+
+ temp = get_trash_chunk();
+ len = MIN(len, temp->size - 1);
+ strncpy(temp->str, txn->uri, len);
+ temp->str[len] = '\0';
+
+ smp->data.str = *temp;
+ smp->data.str.len = len;
+ smp->type = SMP_T_STR;
+
+ return 1;
+
+}
+
+/* Extracts the path in the HTTP request, the txn->uri should be filled before the call */
+static int
+smp_fetch_capture_req_uri(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
+ const struct arg *args, struct sample *smp, const char *kw)
+{
+ struct chunk *temp;
+ struct http_txn *txn = l7;
+ char *ptr;
+ char *ret;
+
+ if (!txn->uri)
+ return 0;
+ ptr = txn->uri;
+
+ while (*ptr != ' ' && *ptr != '\0') /* find first space */
+ ptr++;
+ if (!*ptr)
+ return 0;
+
+ ptr++; /* skip the space */
+
+ temp = get_trash_chunk();
+ ret = encode_string(temp->str, temp->str + temp->size, '#', url_encode_map, ptr);
+ if (ret == NULL || *ret != '\0')
+ return 0;
+ ptr = temp->str = http_get_path_from_string(temp->str);
+ if (!ptr)
+ return 0;
+ while (*ptr != ' ' && *ptr != '\0') /* find space after URI */
+ ptr++;
+ *ptr = '\0';
+
+ smp->data.str = *temp;
+ smp->data.str.len = strlen(smp->data.str.str);
+ smp->type = SMP_T_STR;
+
+ return 1;
+}
+
+
/* Iterate over all cookies present in a message. The context is stored in
* smp->ctx.a[0] for the in-header position, smp->ctx.a[1] for the
* end-of-header-value, and smp->ctx.a[2] for the hdr_ctx. Depending on
@@ -10289,6 +10401,9 @@
{ "base32", smp_fetch_base32, 0, NULL, SMP_T_UINT, SMP_USE_HRQHV },
{ "base32+src", smp_fetch_base32_src, 0, NULL, SMP_T_BIN, SMP_USE_HRQHV },
+ { "capture.req.uri", smp_fetch_capture_req_uri, 0, NULL, SMP_T_CSTR, SMP_USE_HRQHP },
+ { "capture.req.method", smp_fetch_capture_req_method, 0, NULL, SMP_T_CSTR, SMP_USE_HRQHP },
+
/* capture are allocated and are permanent in the session */
{ "capture.req.hdr", smp_fetch_capture_header_req, ARG1(1, UINT), NULL, SMP_T_CSTR, SMP_USE_HRQHP },
{ "capture.res.hdr", smp_fetch_capture_header_res, ARG1(1, UINT), NULL, SMP_T_CSTR, SMP_USE_HRSHP },