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);
|
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 */
|
/* to be used when contents change in an HTTP message */
|
||||||
#define http_msg_move_end(msg, bytes) do { \
|
#define http_msg_move_end(msg, bytes) do { \
|
||||||
unsigned int _bytes = (bytes); \
|
unsigned int _bytes = (bytes); \
|
||||||
|
@ -256,6 +256,8 @@ enum {
|
|||||||
HTTP_REQ_ACT_DEL_ACL,
|
HTTP_REQ_ACT_DEL_ACL,
|
||||||
HTTP_REQ_ACT_DEL_MAP,
|
HTTP_REQ_ACT_DEL_MAP,
|
||||||
HTTP_REQ_ACT_SET_MAP,
|
HTTP_REQ_ACT_SET_MAP,
|
||||||
|
HTTP_REQ_ACT_CUSTOM_STOP,
|
||||||
|
HTTP_REQ_ACT_CUSTOM_CONT,
|
||||||
HTTP_REQ_ACT_MAX /* must always be last */
|
HTTP_REQ_ACT_MAX /* must always be last */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -275,6 +277,8 @@ enum {
|
|||||||
HTTP_RES_ACT_DEL_ACL,
|
HTTP_RES_ACT_DEL_ACL,
|
||||||
HTTP_RES_ACT_DEL_MAP,
|
HTTP_RES_ACT_DEL_MAP,
|
||||||
HTTP_RES_ACT_SET_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 */
|
HTTP_RES_ACT_MAX /* must always be last */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -394,10 +398,15 @@ struct http_auth_data {
|
|||||||
char *user, *pass; /* extracted username & password */
|
char *user, *pass; /* extracted username & password */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct proxy;
|
||||||
|
struct http_txn;
|
||||||
|
struct session;
|
||||||
|
|
||||||
struct http_req_rule {
|
struct http_req_rule {
|
||||||
struct list list;
|
struct list list;
|
||||||
struct acl_cond *cond; /* acl condition to meet */
|
struct acl_cond *cond; /* acl condition to meet */
|
||||||
unsigned int action; /* HTTP_REQ_* */
|
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 {
|
union {
|
||||||
struct {
|
struct {
|
||||||
char *realm;
|
char *realm;
|
||||||
@ -424,6 +433,7 @@ struct http_res_rule {
|
|||||||
struct list list;
|
struct list list;
|
||||||
struct acl_cond *cond; /* acl condition to meet */
|
struct acl_cond *cond; /* acl condition to meet */
|
||||||
unsigned int action; /* HTTP_RES_* */
|
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 {
|
union {
|
||||||
struct {
|
struct {
|
||||||
char *name; /* header name */
|
char *name; /* header name */
|
||||||
@ -464,6 +474,7 @@ struct http_txn {
|
|||||||
struct http_auth_data auth; /* HTTP auth data */
|
struct http_auth_data auth; /* HTTP auth data */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* This structure is used by http_find_header() to return values of headers.
|
/* 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
|
* The header starts at <line>, the value (excluding leading and trailing white
|
||||||
* spaces) at <line>+<val> for <vlen> bytes, followed by optional <tws> trailing
|
* spaces) at <line>+<val> for <vlen> bytes, followed by optional <tws> trailing
|
||||||
@ -486,6 +497,31 @@ struct http_method_name {
|
|||||||
int len;
|
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];
|
extern const struct http_method_name http_known_methods[HTTP_METH_OTHER];
|
||||||
|
|
||||||
#endif /* _TYPES_PROTO_HTTP_H */
|
#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
|
/* We must put the messages here since GCC cannot initialize consts depending
|
||||||
* on strlen().
|
* on strlen().
|
||||||
*/
|
*/
|
||||||
@ -3289,6 +3299,14 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session
|
|||||||
|
|
||||||
break;
|
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;
|
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;
|
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)) {
|
if (unlikely(objt_applet(s->target) == &http_stats_applet)) {
|
||||||
/* process the stats request now */
|
/* process the stats request now */
|
||||||
if (s->fe == s->be) /* report it if the request was intercepted by the frontend */
|
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 *parse_http_req_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
|
||||||
{
|
{
|
||||||
struct http_req_rule *rule;
|
struct http_req_rule *rule;
|
||||||
|
struct http_req_action_kw *custom = NULL;
|
||||||
int cur_arg;
|
int cur_arg;
|
||||||
|
|
||||||
rule = (struct http_req_rule*)calloc(1, sizeof(struct http_req_rule));
|
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;
|
proxy->conf.lfs_line = proxy->conf.args.line;
|
||||||
|
|
||||||
cur_arg += 2;
|
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 {
|
} 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",
|
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)");
|
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 *parse_http_res_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
|
||||||
{
|
{
|
||||||
struct http_res_rule *rule;
|
struct http_res_rule *rule;
|
||||||
|
struct http_res_action_kw *custom = NULL;
|
||||||
int cur_arg;
|
int cur_arg;
|
||||||
|
|
||||||
rule = calloc(1, sizeof(*rule));
|
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;
|
proxy->conf.lfs_line = proxy->conf.args.line;
|
||||||
|
|
||||||
cur_arg += 2;
|
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 {
|
} 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",
|
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)");
|
file, linenum, args[0], *args[0] ? "" : " (missing argument)");
|
||||||
@ -11122,6 +11175,44 @@ expect_comma:
|
|||||||
return smp->data.str.len != 0;
|
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. */
|
/* All supported ACL keywords must be declared here. */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user