mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-04-24 20:08:01 +00:00
MEDIUM: capture: adds http-response capture
This patch adds a http response capture keyword with the same behavior as the previous patch called "MEDIUM: capture: Allow capture with slot identifier".
This commit is contained in:
parent
cdb67cad01
commit
e80fadaaca
@ -3612,6 +3612,7 @@ http-request { allow | deny | tarpit | auth [realm <realm>] | redirect <rule> |
|
||||
about ACL usage.
|
||||
|
||||
http-response { allow | deny | add-header <name> <fmt> | set-nice <nice> |
|
||||
capture <sample> id <id> |
|
||||
set-header <name> <fmt> | del-header <name> |
|
||||
replace-header <name> <regex-match> <replace-fmt> |
|
||||
replace-value <name> <regex-match> <replace-fmt> |
|
||||
@ -3772,6 +3773,21 @@ http-response { allow | deny | add-header <name> <fmt> | set-nice <nice> |
|
||||
parameter is the name of the function to run. The prototype of the
|
||||
function is documented in the API documentation.
|
||||
|
||||
- capture <sample> id <id> :
|
||||
captures sample expression <sample> from the response buffer, and converts
|
||||
it to a string. The resulting string is stored into the next request
|
||||
"capture" slot, so it will possibly appear next to some captured HTTP
|
||||
headers. It will then automatically appear in the logs, and it will be
|
||||
possible to extract it using sample fetch rules to feed it into headers or
|
||||
anything. Please check section 7.3 (Fetching samples) and "capture
|
||||
response header" for more information.
|
||||
|
||||
The keyword "id" is the id of the capture slot which is used for storing
|
||||
the string. The capture slot must be defined in an associated frontend.
|
||||
This is useful to run captures in backends. The slot id can be declared by
|
||||
a previous directive "http-response capture" or with the "declare capture"
|
||||
keyword.
|
||||
|
||||
There is no limit to the number of http-response statements per instance.
|
||||
|
||||
It is important to know that http-response rules are processed very early in
|
||||
|
127
src/proto_http.c
127
src/proto_http.c
@ -12633,6 +12633,124 @@ int parse_http_req_capture(const char **args, int *orig_arg, struct proxy *px, s
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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_res_capture_by_id(struct http_res_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->res_cap;
|
||||
struct proxy *fe = strm_fe(s);
|
||||
int len;
|
||||
int i;
|
||||
|
||||
/* Look for the original configuration. */
|
||||
for (h = fe->rsp_cap, i = fe->nb_rsp_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_RES|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-response 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 od the preallocated id into arg->act.p[1].
|
||||
* It returns 0 on success, < 0 on error.
|
||||
*/
|
||||
int parse_http_res_capture(const char **args, int *orig_arg, struct proxy *px, struct http_res_rule *rule, char **err)
|
||||
{
|
||||
struct sample_expr *expr;
|
||||
int cur_arg;
|
||||
int id;
|
||||
char *error;
|
||||
|
||||
for (cur_arg = *orig_arg; cur_arg < *orig_arg + 3 && *args[cur_arg]; cur_arg++)
|
||||
if (strcmp(args[cur_arg], "if") == 0 ||
|
||||
strcmp(args[cur_arg], "unless") == 0)
|
||||
break;
|
||||
|
||||
if (cur_arg < *orig_arg + 3) {
|
||||
memprintf(err, "expects <expression> [ 'len' <length> | id <idx> ]");
|
||||
return -1;
|
||||
}
|
||||
|
||||
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 (!(expr->fetch->val & SMP_VAL_FE_HRS_HDR)) {
|
||||
memprintf(err,
|
||||
"fetch method '%s' extracts information from '%s', none of which is available here",
|
||||
args[cur_arg-1], sample_src_names(expr->fetch->use));
|
||||
free(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], "id") != 0) {
|
||||
memprintf(err, "expects 'id', found '%s'", args[cur_arg]);
|
||||
free(expr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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++;
|
||||
|
||||
LIST_INIT((struct list *)&rule->arg.act.p[0]);
|
||||
proxy->conf.args.ctx = ARGC_CAP;
|
||||
|
||||
rule->action = HTTP_RES_ACT_CUSTOM_CONT;
|
||||
rule->action_ptr = http_action_res_capture_by_id;
|
||||
rule->arg.act.p[0] = expr;
|
||||
rule->arg.act.p[1] = (void *)(long)id;
|
||||
|
||||
*orig_arg = cur_arg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the struct http_req_action_kw associated to a keyword.
|
||||
*/
|
||||
@ -12908,6 +13026,14 @@ struct http_req_action_kw_list http_req_actions = {
|
||||
}
|
||||
};
|
||||
|
||||
struct http_res_action_kw_list http_res_actions = {
|
||||
.scope = "http",
|
||||
.kw = {
|
||||
{ "capture", parse_http_res_capture },
|
||||
{ NULL, NULL }
|
||||
}
|
||||
};
|
||||
|
||||
__attribute__((constructor))
|
||||
static void __http_protocol_init(void)
|
||||
{
|
||||
@ -12915,6 +13041,7 @@ static void __http_protocol_init(void)
|
||||
sample_register_fetches(&sample_fetch_keywords);
|
||||
sample_register_convs(&sample_conv_kws);
|
||||
http_req_keywords_register(&http_req_actions);
|
||||
http_res_keywords_register(&http_res_actions);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user