http-request { allow | deny | tarpit | auth [realm <realm>] | redirect <rule> |
add-header <name> <fmt> | set-header <name> <fmt> |
- capture <sample> len <length> |
+ capture <sample> [ len <length> | id <id> ] |
del-header <name> | set-nice <nice> | set-log-level <level> |
replace-header <name> <match-regex> <replace-fmt> |
replace-value <name> <match-regex> <replace-fmt> |
with large lists! It is the equivalent of the "set map" command from the
stats socket, but can be triggered by an HTTP request.
- - capture <sample> len <length> :
+ - capture <sample> [ len <length> | id <id> ] :
captures sample expression <sample> from the request buffer, and converts
it to a string of at most <len> characters. The resulting string is
stored into the next request "capture" slot, so it will possibly appear
session life. Please check section 7.3 (Fetching samples) and "capture
request header" for more information.
+ If the keyword "id" is used instead of "len", the action tries to store
+ the captured string in a previously declared capture slot. This is useful
+ to run captures in backends. The slot id can be declared by a previous
+ directive "http-request capture" or with the "declare capture" keyword.
+
- { track-sc0 | track-sc1 | track-sc2 } <key> [table <table>] :
enables tracking of sticky counters from current request. These rules
do not stop evaluation and do not change default action. Three sets of
return 1;
}
+/* This function executes the "capture" action and store the result in a
+ * capture slot if exists. It executes a fetch expression, turns the result
+ * into a string and puts it in a capture slot. It always returns 1. If an
+ * error occurs the action is cancelled, but the rule processing continues.
+ */
+int http_action_req_capture_by_id(struct http_req_rule *rule, struct proxy *px, struct stream *s)
+{
+ struct session *sess = s->sess;
+ struct sample *key;
+ struct sample_expr *expr = rule->arg.act.p[0];
+ struct cap_hdr *h;
+ int idx = (long)rule->arg.act.p[1];
+ char **cap = s->req_cap;
+ struct proxy *fe = strm_fe(s);
+ int len;
+ int i;
+
+ /* Look for the original configuration. */
+ for (h = fe->req_cap, i = fe->nb_req_cap - 1;
+ h != NULL && i != idx ;
+ i--, h = h->next);
+ if (!h)
+ return 1;
+
+ key = sample_fetch_string(s->be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, expr);
+ if (!key)
+ return 1;
+
+ if (cap[h->index] == NULL)
+ cap[h->index] = pool_alloc2(h->pool);
+
+ if (cap[h->index] == NULL) /* no more capture memory */
+ return 1;
+
+ len = key->data.str.len;
+ if (len > h->len)
+ len = h->len;
+
+ memcpy(cap[h->index], key->data.str.str, len);
+ cap[h->index][len] = 0;
+ return 1;
+}
+
/* parse an "http-request capture" action. It takes a single argument which is
* a sample fetch expression. It stores the expression into arg->act.p[0] and
- * the allocated hdr_cap struct into arg->act.p[1].
+ * the allocated hdr_cap struct or the preallocated "id" into arg->act.p[1].
* It returns 0 on success, < 0 on error.
*/
int parse_http_req_capture(const char **args, int *orig_arg, struct proxy *px, struct http_req_rule *rule, char **err)
break;
if (cur_arg < *orig_arg + 3) {
- memprintf(err, "expects <expression> 'len' <length> ");
+ memprintf(err, "expects <expression> [ 'len' <length> | id <idx> ]");
return -1;
}
- if (!(px->cap & PR_CAP_FE)) {
- memprintf(err, "proxy '%s' has no frontend capability", px->id);
- return -1;
- }
-
- LIST_INIT((struct list *)&rule->arg.act.p[0]);
- proxy->conf.args.ctx = ARGC_CAP;
-
cur_arg = *orig_arg;
expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args);
if (!expr)
return -1;
}
+ if (!args[cur_arg] || !*args[cur_arg]) {
+ memprintf(err, "expects 'len or 'id'");
+ free(expr);
+ return -1;
+ }
+
if (strcmp(args[cur_arg], "len") == 0) {
cur_arg++;
+
+ if (!(px->cap & PR_CAP_FE)) {
+ memprintf(err, "proxy '%s' has no frontend capability", px->id);
+ return -1;
+ }
+
+ proxy->conf.args.ctx = ARGC_CAP;
+
if (!args[cur_arg]) {
memprintf(err, "missing length value");
free(expr);
return -1;
}
cur_arg++;
- }
- if (!len) {
- memprintf(err, "a positive 'len' argument is mandatory");
- free(expr);
- return -1;
+ if (!len) {
+ memprintf(err, "a positive 'len' argument is mandatory");
+ free(expr);
+ return -1;
+ }
+
+ hdr = calloc(sizeof(struct cap_hdr), 1);
+ hdr->next = px->req_cap;
+ hdr->name = NULL; /* not a header capture */
+ hdr->namelen = 0;
+ hdr->len = len;
+ hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
+ hdr->index = px->nb_req_cap++;
+
+ px->req_cap = hdr;
+ px->to_log |= LW_REQHDR;
+
+ rule->action = HTTP_REQ_ACT_CUSTOM_CONT;
+ rule->action_ptr = http_action_req_capture;
+ rule->arg.act.p[0] = expr;
+ rule->arg.act.p[1] = hdr;
}
+ else if (strcmp(args[cur_arg], "id") == 0) {
+ int id;
+ char *error;
+
+ cur_arg++;
+
+ if (!args[cur_arg]) {
+ memprintf(err, "missing id value");
+ free(expr);
+ return -1;
+ }
+
+ id = strtol(args[cur_arg], &error, 10);
+ if (*error != '\0') {
+ memprintf(err, "cannot parse id '%s'", args[cur_arg]);
+ free(expr);
+ return -1;
+ }
+ cur_arg++;
- hdr = calloc(sizeof(struct cap_hdr), 1);
- hdr->next = px->req_cap;
- hdr->name = NULL; /* not a header capture */
- hdr->namelen = 0;
- hdr->len = len;
- hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
- hdr->index = px->nb_req_cap++;
+ proxy->conf.args.ctx = ARGC_CAP;
- px->req_cap = hdr;
- px->to_log |= LW_REQHDR;
+ rule->action = HTTP_REQ_ACT_CUSTOM_CONT;
+ rule->action_ptr = http_action_req_capture_by_id;
+ rule->arg.act.p[0] = expr;
+ rule->arg.act.p[1] = (void *)(long)id;
+ }
- rule->action = HTTP_REQ_ACT_CUSTOM_CONT;
- rule->action_ptr = http_action_req_capture;
- rule->arg.act.p[0] = expr;
- rule->arg.act.p[1] = hdr;
+ else {
+ memprintf(err, "expects 'len' or 'id', found '%s'", args[cur_arg]);
+ free(expr);
+ return -1;
+ }
*orig_arg = cur_arg;
return 0;