mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-24 23:31:40 +02:00
MEDIUM: http: register http-request and http-response keywords
The http_(res|req)_keywords_register() functions allow to register new keywords. You need to declare a keyword list: struct http_req_action_kw_list test_kws = { .scope = "testscope", .kw = { { "test", parse_test }, { NULL, NULL }, } }; and a parsing function: int parse_test(const char **args, int *cur_arg, struct proxy *px, struct http_req_rule *rule, char **err) { rule->action = HTTP_REQ_ACT_CUSTOM_STOP; rule->action_ptr = action_function; return 0; } http_req_keywords_register(&test_kws); The HTTP_REQ_ACT_CUSTOM_STOP action stops evaluation of rules after your rule, HTTP_REQ_ACT_CUSTOM_CONT permits the evaluation of rules after your rule.
This commit is contained in:
parent
fabcbe0de6
commit
73025dd7e2
@ -122,6 +122,20 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
|
||||
|
||||
enum http_meth_t find_http_meth(const char *str, const int len);
|
||||
|
||||
struct http_req_action_kw *action_http_req_custom(const char *kw);
|
||||
struct http_res_action_kw *action_http_res_custom(const char *kw);
|
||||
|
||||
static inline void http_req_keywords_register(struct http_req_action_kw_list *kw_list)
|
||||
{
|
||||
LIST_ADDQ(&http_req_keywords.list, &kw_list->list);
|
||||
}
|
||||
|
||||
static inline void http_res_keywords_register(struct http_res_action_kw_list *kw_list)
|
||||
{
|
||||
LIST_ADDQ(&http_res_keywords.list, &kw_list->list);
|
||||
}
|
||||
|
||||
|
||||
/* to be used when contents change in an HTTP message */
|
||||
#define http_msg_move_end(msg, bytes) do { \
|
||||
unsigned int _bytes = (bytes); \
|
||||
|
@ -256,6 +256,8 @@ enum {
|
||||
HTTP_REQ_ACT_DEL_ACL,
|
||||
HTTP_REQ_ACT_DEL_MAP,
|
||||
HTTP_REQ_ACT_SET_MAP,
|
||||
HTTP_REQ_ACT_CUSTOM_STOP,
|
||||
HTTP_REQ_ACT_CUSTOM_CONT,
|
||||
HTTP_REQ_ACT_MAX /* must always be last */
|
||||
};
|
||||
|
||||
@ -275,6 +277,8 @@ enum {
|
||||
HTTP_RES_ACT_DEL_ACL,
|
||||
HTTP_RES_ACT_DEL_MAP,
|
||||
HTTP_RES_ACT_SET_MAP,
|
||||
HTTP_RES_ACT_CUSTOM_STOP, /* used for module keywords */
|
||||
HTTP_RES_ACT_CUSTOM_CONT, /* used for module keywords */
|
||||
HTTP_RES_ACT_MAX /* must always be last */
|
||||
};
|
||||
|
||||
@ -394,10 +398,15 @@ struct http_auth_data {
|
||||
char *user, *pass; /* extracted username & password */
|
||||
};
|
||||
|
||||
struct proxy;
|
||||
struct http_txn;
|
||||
struct session;
|
||||
|
||||
struct http_req_rule {
|
||||
struct list list;
|
||||
struct acl_cond *cond; /* acl condition to meet */
|
||||
unsigned int action; /* HTTP_REQ_* */
|
||||
int (*action_ptr)(struct http_req_rule *rule, struct proxy *px, struct session *s, struct http_txn *http_txn); /* ptr to custom action */
|
||||
union {
|
||||
struct {
|
||||
char *realm;
|
||||
@ -424,6 +433,7 @@ struct http_res_rule {
|
||||
struct list list;
|
||||
struct acl_cond *cond; /* acl condition to meet */
|
||||
unsigned int action; /* HTTP_RES_* */
|
||||
int (*action_ptr)(struct http_res_rule *rule, struct proxy *px, struct session *s, struct http_txn *http_txn); /* ptr to custom action */
|
||||
union {
|
||||
struct {
|
||||
char *name; /* header name */
|
||||
@ -464,6 +474,7 @@ struct http_txn {
|
||||
struct http_auth_data auth; /* HTTP auth data */
|
||||
};
|
||||
|
||||
|
||||
/* This structure is used by http_find_header() to return values of headers.
|
||||
* The header starts at <line>, the value (excluding leading and trailing white
|
||||
* spaces) at <line>+<val> for <vlen> bytes, followed by optional <tws> trailing
|
||||
@ -486,6 +497,31 @@ struct http_method_name {
|
||||
int len;
|
||||
};
|
||||
|
||||
struct http_req_action_kw {
|
||||
const char *kw;
|
||||
int (*parse)(const char **args, int *cur_arg, struct proxy *px, struct http_req_rule *rule, char **err);
|
||||
};
|
||||
|
||||
struct http_res_action_kw {
|
||||
const char *kw;
|
||||
int (*parse)(const char **args, int *cur_arg, struct proxy *px, struct http_res_rule *rule, char **err);
|
||||
};
|
||||
|
||||
struct http_req_action_kw_list {
|
||||
const char *scope;
|
||||
struct list list;
|
||||
struct http_req_action_kw kw[VAR_ARRAY];
|
||||
};
|
||||
|
||||
struct http_res_action_kw_list {
|
||||
const char *scope;
|
||||
struct list list;
|
||||
struct http_res_action_kw kw[VAR_ARRAY];
|
||||
};
|
||||
|
||||
extern struct http_req_action_kw_list http_req_keywords;
|
||||
extern struct http_res_action_kw_list http_res_keywords;
|
||||
|
||||
extern const struct http_method_name http_known_methods[HTTP_METH_OTHER];
|
||||
|
||||
#endif /* _TYPES_PROTO_HTTP_H */
|
||||
|
@ -217,6 +217,16 @@ const char *stat_status_codes[STAT_STATUS_SIZE] = {
|
||||
};
|
||||
|
||||
|
||||
/* List head of all known action keywords for "http-request" */
|
||||
struct http_req_action_kw_list http_req_keywords = {
|
||||
.list = LIST_HEAD_INIT(http_req_keywords.list)
|
||||
};
|
||||
|
||||
/* List head of all known action keywords for "http-response" */
|
||||
struct http_res_action_kw_list http_res_keywords = {
|
||||
.list = LIST_HEAD_INIT(http_res_keywords.list)
|
||||
};
|
||||
|
||||
/* We must put the messages here since GCC cannot initialize consts depending
|
||||
* on strlen().
|
||||
*/
|
||||
@ -3289,6 +3299,14 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case HTTP_REQ_ACT_CUSTOM_CONT:
|
||||
rule->action_ptr(rule, px, s, txn);
|
||||
break;
|
||||
|
||||
case HTTP_REQ_ACT_CUSTOM_STOP:
|
||||
rule->action_ptr(rule, px, s, txn);
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3462,6 +3480,14 @@ http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct session
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case HTTP_RES_ACT_CUSTOM_CONT:
|
||||
rule->action_ptr(rule, px, s, txn);
|
||||
break;
|
||||
|
||||
case HTTP_RES_ACT_CUSTOM_STOP:
|
||||
rule->action_ptr(rule, px, s, txn);
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3959,6 +3985,11 @@ int http_process_req_common(struct session *s, struct channel *req, int an_bit,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (http_req_last_rule && http_req_last_rule->action == HTTP_REQ_ACT_CUSTOM_STOP) {
|
||||
req->analyse_exp = TICK_ETERNITY;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (unlikely(objt_applet(s->target) == &http_stats_applet)) {
|
||||
/* process the stats request now */
|
||||
if (s->fe == s->be) /* report it if the request was intercepted by the frontend */
|
||||
@ -8650,6 +8681,7 @@ void free_http_req_rules(struct list *r) {
|
||||
struct http_req_rule *parse_http_req_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
|
||||
{
|
||||
struct http_req_rule *rule;
|
||||
struct http_req_action_kw *custom = NULL;
|
||||
int cur_arg;
|
||||
|
||||
rule = (struct http_req_rule*)calloc(1, sizeof(struct http_req_rule));
|
||||
@ -8938,6 +8970,16 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
|
||||
proxy->conf.lfs_line = proxy->conf.args.line;
|
||||
|
||||
cur_arg += 2;
|
||||
} else if (((custom = action_http_req_custom(args[0])) != NULL)) {
|
||||
char *errmsg = NULL;
|
||||
cur_arg = 1;
|
||||
/* try in the module list */
|
||||
if (custom->parse(args, &cur_arg, proxy, rule, &errmsg) < 0) {
|
||||
Alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
|
||||
file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
|
||||
free(errmsg);
|
||||
goto out_err;
|
||||
}
|
||||
} else {
|
||||
Alert("parsing [%s:%d]: 'http-request' expects 'allow', 'deny', 'auth', 'redirect', 'tarpit', 'add-header', 'set-header', 'set-nice', 'set-tos', 'set-mark', 'set-log-level', 'add-acl', 'del-acl', 'del-map', 'set-map', but got '%s'%s.\n",
|
||||
file, linenum, args[0], *args[0] ? "" : " (missing argument)");
|
||||
@ -8973,6 +9015,7 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
|
||||
struct http_res_rule *parse_http_res_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
|
||||
{
|
||||
struct http_res_rule *rule;
|
||||
struct http_res_action_kw *custom = NULL;
|
||||
int cur_arg;
|
||||
|
||||
rule = calloc(1, sizeof(*rule));
|
||||
@ -9230,6 +9273,16 @@ struct http_res_rule *parse_http_res_cond(const char **args, const char *file, i
|
||||
proxy->conf.lfs_line = proxy->conf.args.line;
|
||||
|
||||
cur_arg += 2;
|
||||
} else if (((custom = action_http_res_custom(args[0])) != NULL)) {
|
||||
char *errmsg = NULL;
|
||||
cur_arg = 1;
|
||||
/* try in the module list */
|
||||
if (custom->parse(args, &cur_arg, proxy, rule, &errmsg) < 0) {
|
||||
Alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-response %s' rule : %s.\n",
|
||||
file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
|
||||
free(errmsg);
|
||||
goto out_err;
|
||||
}
|
||||
} else {
|
||||
Alert("parsing [%s:%d]: 'http-response' expects 'allow', 'deny', 'redirect', 'add-header', 'del-header', 'set-header', 'set-nice', 'set-tos', 'set-mark', 'set-log-level', 'del-acl', 'add-acl', 'del-map', 'set-map', but got '%s'%s.\n",
|
||||
file, linenum, args[0], *args[0] ? "" : " (missing argument)");
|
||||
@ -11122,6 +11175,44 @@ expect_comma:
|
||||
return smp->data.str.len != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the struct http_req_action_kw associated to a keyword.
|
||||
*/
|
||||
struct http_req_action_kw *action_http_req_custom(const char *kw)
|
||||
{
|
||||
if (!LIST_ISEMPTY(&http_req_keywords.list)) {
|
||||
struct http_req_action_kw_list *kw_list;
|
||||
int i;
|
||||
|
||||
list_for_each_entry(kw_list, &http_req_keywords.list, list) {
|
||||
for (i = 0; kw_list->kw[i].kw != NULL; i++) {
|
||||
if (!strcmp(kw, kw_list->kw[i].kw))
|
||||
return &kw_list->kw[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the struct http_res_action_kw associated to a keyword.
|
||||
*/
|
||||
struct http_res_action_kw *action_http_res_custom(const char *kw)
|
||||
{
|
||||
if (!LIST_ISEMPTY(&http_res_keywords.list)) {
|
||||
struct http_res_action_kw_list *kw_list;
|
||||
int i;
|
||||
|
||||
list_for_each_entry(kw_list, &http_res_keywords.list, list) {
|
||||
for (i = 0; kw_list->kw[i].kw != NULL; i++) {
|
||||
if (!strcmp(kw, kw_list->kw[i].kw))
|
||||
return &kw_list->kw[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* All supported ACL keywords must be declared here. */
|
||||
/************************************************************************/
|
||||
|
Loading…
x
Reference in New Issue
Block a user