MINOR: http-rules: Make replace-header and replace-value custom actions

Now, these actions use their own dedicated function and are no longer handled
"in place" during the HTTP rules evaluation. Thus the action names
ACT_HTTP_REPLACE_HDR and ACT_HTTP_REPLACE_VAL are removed. The action type is
now set to 0 to evaluate the whole header or to 1 to evaluate every
comma-delimited values.

The function http_transform_header_str() is renamed to http_replace_hdrs() to be
more explicit and the function http_transform_header() is removed. In fact, this
last one is now more or less the new action function.

The lua code has been updated accordingly to use http_replace_hdrs().
This commit is contained in:
Christopher Faulet 2019-12-17 09:20:34 +01:00
parent 2c22a6923a
commit 92d34fe38d
5 changed files with 70 additions and 77 deletions

View File

@ -40,8 +40,7 @@ int http_process_res_common(struct stream *s, struct channel *rep, int an_bit, s
int http_request_forward_body(struct stream *s, struct channel *req, int an_bit);
int http_response_forward_body(struct stream *s, struct channel *res, int an_bit);
int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struct http_txn *txn);
int http_transform_header_str(struct stream* s, struct channel *chn, struct htx *htx,
struct ist name, const char *str, struct my_regex *re, int action);
int http_replace_hdrs(struct stream* s, struct htx *htx, struct ist name, const char *str, struct my_regex *re, int full);
int http_req_replace_stline(int action, const char *replace, int len,
struct proxy *px, struct stream *s);
int http_res_set_status(unsigned int status, struct ist reason, struct stream *s);

View File

@ -79,8 +79,6 @@ enum act_name {
/* common http actions .*/
ACT_HTTP_ADD_HDR,
ACT_HTTP_REPLACE_HDR,
ACT_HTTP_REPLACE_VAL,
ACT_HTTP_SET_HDR,
ACT_HTTP_DEL_HDR,
ACT_HTTP_REDIR,

View File

@ -4795,7 +4795,7 @@ __LJMP static int hlua_http_res_get_headers(lua_State *L)
* 4 following functions.
*/
__LJMP static inline int hlua_http_rep_hdr(lua_State *L, struct hlua_txn *htxn,
struct http_msg *msg, int action)
struct http_msg *msg, int full)
{
size_t name_len;
const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
@ -4808,7 +4808,7 @@ __LJMP static inline int hlua_http_rep_hdr(lua_State *L, struct hlua_txn *htxn,
WILL_LJMP(luaL_argerror(L, 3, "invalid regex"));
htx = htxbuf(&msg->chn->buf);
http_transform_header_str(htxn->s, msg->chn, htx, ist2(name, name_len), value, re, action);
http_replace_hdrs(htxn->s, htx, ist2(name, name_len), value, re, full);
regex_free(re);
return 0;
}
@ -4823,7 +4823,7 @@ __LJMP static int hlua_http_req_rep_hdr(lua_State *L)
if (htxn->dir != SMP_OPT_DIR_REQ || !(htxn->flags & HLUA_TXN_HTTP_RDY))
WILL_LJMP(lua_error(L));
return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->req, ACT_HTTP_REPLACE_HDR));
return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->req, 1));
}
__LJMP static int hlua_http_res_rep_hdr(lua_State *L)
@ -4836,7 +4836,7 @@ __LJMP static int hlua_http_res_rep_hdr(lua_State *L)
if (htxn->dir != SMP_OPT_DIR_RES || !(htxn->flags & HLUA_TXN_HTTP_RDY))
WILL_LJMP(lua_error(L));
return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->rsp, ACT_HTTP_REPLACE_HDR));
return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->rsp, 1));
}
__LJMP static int hlua_http_req_rep_val(lua_State *L)
@ -4849,7 +4849,7 @@ __LJMP static int hlua_http_req_rep_val(lua_State *L)
if (htxn->dir != SMP_OPT_DIR_REQ || !(htxn->flags & HLUA_TXN_HTTP_RDY))
WILL_LJMP(lua_error(L));
return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->req, ACT_HTTP_REPLACE_VAL));
return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->req, 0));
}
__LJMP static int hlua_http_res_rep_val(lua_State *L)
@ -4862,7 +4862,7 @@ __LJMP static int hlua_http_res_rep_val(lua_State *L)
if (htxn->dir != SMP_OPT_DIR_RES || !(htxn->flags & HLUA_TXN_HTTP_RDY))
WILL_LJMP(lua_error(L));
return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->rsp, ACT_HTTP_REPLACE_VAL));
return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn->rsp, 0));
}
/* This function deletes all the occurrences of an header.

View File

@ -990,6 +990,56 @@ static enum act_parse_ret parse_http_set_header(const char **args, int *orig_arg
return ACT_RET_PRS_OK;
}
/* This function executes a replace-header or replace-value actions. It
* builds a string in the trash from the specified format string. It finds
* the action to be performed in <.action>, previously filled by function
* parse_replace_header(). The replacement action is excuted by the function
* http_action_replace_header(). On success, it returns ACT_RET_CONT. If an error
* occurs while soft rewrites are enabled, the action is canceled, but the rule
* processing continue. Otherwsize ACT_RET_ERR is returned.
*/
static enum act_return http_action_replace_header(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
struct htx *htx = htxbuf((rule->from == ACT_F_HTTP_REQ) ? &s->req.buf : &s->res.buf);
enum act_return ret = ACT_RET_CONT;
struct buffer *replace;
int r;
replace = alloc_trash_chunk();
if (!replace)
goto fail_alloc;
replace->data = build_logline(s, replace->area, replace->size, &rule->arg.http.fmt);
r = http_replace_hdrs(s, htx, rule->arg.http.str, replace->area, rule->arg.http.re, (rule->action == 0));
if (r == -1)
goto fail_rewrite;
leave:
free_trash_chunk(replace);
return ret;
fail_alloc:
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_RESOURCE;
ret = ACT_RET_ERR;
goto leave;
fail_rewrite:
_HA_ATOMIC_ADD(&sess->fe->fe_counters.failed_rewrites, 1);
if (s->flags & SF_BE_ASSIGNED)
_HA_ATOMIC_ADD(&s->be->be_counters.failed_rewrites, 1);
if (sess->listener->counters)
_HA_ATOMIC_ADD(&sess->listener->counters->failed_rewrites, 1);
if (objt_server(s->target))
_HA_ATOMIC_ADD(&__objt_server(s->target)->counters.failed_rewrites, 1);
if (!(s->txn->req.flags & HTTP_MSGF_SOFT_RW))
ret = ACT_RET_ERR;
goto leave;
}
/* Parse a "replace-header" or "replace-value" actions. It takes an header name,
* a regex and replacement string as arguments. It returns ACT_RET_PRS_OK on
* success, ACT_RET_PRS_ERR on error.
@ -999,7 +1049,11 @@ static enum act_parse_ret parse_http_replace_header(const char **args, int *orig
{
int cap, cur_arg;
rule->action = args[*orig_arg-1][8] == 'h' ? ACT_HTTP_REPLACE_HDR : ACT_HTTP_REPLACE_VAL;
if (args[*orig_arg-1][8] == 'h')
rule->action = 0; // replace-header
else
rule->action = 1; // replace-value
rule->action_ptr = http_action_replace_header;
cur_arg = *orig_arg;
if (!*args[cur_arg] || !*args[cur_arg+1] || !*args[cur_arg+2]) {

View File

@ -2704,15 +2704,19 @@ int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struc
return 0;
}
int http_transform_header_str(struct stream* s, struct channel *chn, struct htx *htx,
struct ist name, const char *str, struct my_regex *re, int action)
/* Replace all headers matching the name <name>. The header value is replaced if
* it matches the regex <re>. <str> is used for the replacement. If <full> is
* set to 1, the full-line is matched and replaced. Otherwise, comma-separated
* values are evaluated one by one. It returns 0 on success and -1 on error.
*/
int http_replace_hdrs(struct stream* s, struct htx *htx, struct ist name,
const char *str, struct my_regex *re, int full)
{
struct http_hdr_ctx ctx;
struct buffer *output = get_trash_chunk();
/* find full header is action is ACT_HTTP_REPLACE_HDR */
ctx.blk = NULL;
while (http_find_header(htx, name, &ctx, (action == ACT_HTTP_REPLACE_HDR))) {
while (http_find_header(htx, name, &ctx, full)) {
if (!regex_exec_match2(re, ctx.value.ptr, ctx.value.len, MAX_MATCH, pmatch, 0))
continue;
@ -2725,48 +2729,6 @@ int http_transform_header_str(struct stream* s, struct channel *chn, struct htx
return 0;
}
static int http_transform_header(struct stream* s, struct channel *chn, struct htx *htx,
const struct ist name, struct list *fmt, struct my_regex *re, int action)
{
struct buffer *replace;
int ret = 0;
replace = alloc_trash_chunk();
if (!replace)
goto fail_alloc;
replace->data = build_logline(s, replace->area, replace->size, fmt);
if (replace->data >= replace->size - 1)
goto fail_rewrite;
if (http_transform_header_str(s, chn, htx, name, replace->area, re, action) == -1)
goto fail_rewrite;
leave:
free_trash_chunk(replace);
return ret;
fail_alloc:
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_RESOURCE;
ret = -1;
goto leave;
fail_rewrite:
_HA_ATOMIC_ADD(&s->sess->fe->fe_counters.failed_rewrites, 1);
if (s->flags & SF_BE_ASSIGNED)
_HA_ATOMIC_ADD(&s->be->be_counters.failed_rewrites, 1);
if (s->sess->listener->counters)
_HA_ATOMIC_ADD(&s->sess->listener->counters->failed_rewrites, 1);
if (objt_server(s->target))
_HA_ATOMIC_ADD(&__objt_server(s->target)->counters.failed_rewrites, 1);
if (!(s->txn->req.flags & HTTP_MSGF_SOFT_RW))
ret = -1;
goto leave;
}
/* Terminate a 103-Erly-hints response and send it to the client. It returns 0
* on success and -1 on error. The response channel is updated accordingly.
*/
@ -3069,16 +3031,6 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis
s->logs.level = rule->arg.http.i;
break;
case ACT_HTTP_REPLACE_HDR:
case ACT_HTTP_REPLACE_VAL:
if (http_transform_header(s, &s->req, htx, rule->arg.http.str,
&rule->arg.http.fmt,
rule->arg.http.re, rule->action)) {
rule_ret = HTTP_RULE_RES_ERROR;
goto end;
}
break;
case ACT_HTTP_DEL_HDR:
/* remove all occurrences of the header */
ctx.blk = NULL;
@ -3441,16 +3393,6 @@ resume_execution:
s->logs.level = rule->arg.http.i;
break;
case ACT_HTTP_REPLACE_HDR:
case ACT_HTTP_REPLACE_VAL:
if (http_transform_header(s, &s->res, htx, rule->arg.http.str,
&rule->arg.http.fmt,
rule->arg.http.re, rule->action)) {
rule_ret = HTTP_RULE_RES_ERROR;
goto end;
}
break;
case ACT_HTTP_DEL_HDR:
/* remove all occurrences of the header */
ctx.blk = NULL;