previous rule.
-add-headers-bin <fmt> [ prefix <str> ]
+add-headers-bin <expr> [ prefix <str> ]
Usable in: QUIC Ini| TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft
- | - | - | - | - | X | X | X
This is a variant of the "add-header" action where the header names and
- values are passed as a base64 encoded string of varint encoded header names
- and values. See the "req.hdrs_bin" sample fetch about the varint format. This
- is useful when you want to set multiple headers at once, without having to
- know the header names in advance. Note that these headers have not been
- validated by the HTTP parser and could lead to emitting invalid messages and
- in worst cases lead to request smuggling attacks. The number of headers
- inserted are also of importance, as that is limited by tune.http.maxhdr.
- Optional prefix will only set the headers from the encoded string that
- start with <str>.
+ values are passed as a varint encoded binary string. See the "req.hdrs_bin"
+ sample fetch about the varint format. This is useful when you want to set
+ multiple headers at once, without having to know the header names in
+ advance. Note that these headers have not been validated by the HTTP parser
+ and could lead to emitting invalid messages and in worst cases lead to
+ request smuggling attacks. The number of headers inserted are also of
+ importance, as that is limited by tune.http.maxhdr. Optional prefix will
+ only set the headers from the encoded string that start with <str>.
Example:
# This would reset the Accept/UA/Host headers to their initial values
- http-request set-var(txn.oldheaders) req.hdrs_bin,base64
+ http-request set-var(txn.oldheaders) req.hdrs_bin
http-request del-header Accept
http-request del-header User-Agent
http-request del-header Host
- http-request add-headers-bin %[var(txn.oldheaders)]
+ http-request add-headers-bin var(txn.oldheaders)
allow
method is used.
-del-headers-bin <fmt> [ -m <meth> ]
+del-headers-bin <expr> [ -m <meth> ]
Usable in: QUIC Ini| TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft
- | - | - | - | - | X | X | X
- This removes all HTTP header fields whose names are specified in <fmt>. <fmt>
- is a base64 encoded varint encoded string of all header names that should be
- deleted. See "add-headers-bin" and "set-headers-bin" for the description of
- encoding and examples. <meth> is the matching method, applied on all the
- header names. Supported matching methods are "str" (exact match), "beg"
- (prefix match), "end" (suffix match) and "sub" (substring match). The "reg"
- (regex match) is not supported due to unpredictable performance during
+ This removes all HTTP header fields whose names are specified in <expr>.
+ <expr> must return a varint encoded binary string of all header names that
+ should be deleted. See "add-headers-bin" and "set-headers-bin" for the
+ description of encoding and examples. <meth> is the matching method, applied
+ on all the header names. Supported matching methods are "str" (exact match),
+ "beg" (prefix match), "end" (suffix match) and "sub" (substring match). The
+ "reg" (regex match) is not supported due to unpredictable performance during
runtime. If not specified, exact matching method is used.
http-request set-header X-SSL-Client-NotBefore %{+Q}[ssl_c_notbefore]
http-request set-header X-SSL-Client-NotAfter %{+Q}[ssl_c_notafter]
-set-headers-bin <fmt> [ prefix <str> ]
+set-headers-bin <expr> [ prefix <str> ]
Usable in: QUIC Ini| TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft
- | - | - | - | - | X | X | X
This is a variant of the "set-header" action where the header names and
- values are passed as a base64 encoded string of varint encoded header names
- and values. See the "req.hdrs_bin" sample fetch about the varint format. This
- is useful when you want to set multiple headers at once, without having to
- know the header names in advance. Note that these headers have not been
- validated by the HTTP parser and could lead to emitting invalid messages and
- in worst cases lead to request smuggling attacks. The number of headers
- inserted are also of importance, as that is limited by tune.http.maxhdr.
- Optional prefix will only set the headers from the encoded string that
- start with <str>.
+ values are passed as a varint encoded binary string. See the "req.hdrs_bin"
+ sample fetch about the varint format. This is useful when you want to set
+ multiple headers at once, without having to know the header names in
+ advance. Note that these headers have not been validated by the HTTP parser
+ and could lead to emitting invalid messages and in worst cases lead to
+ request smuggling attacks. The number of headers inserted are also of
+ importance, as that is limited by tune.http.maxhdr. Optional prefix will
+ only set the headers from the encoded string that start with <str>.
Example:
# This would reset the Accept/UA/Host headers to their initial values
- http-request set-var(txn.oldheaders) req.hdrs_bin,base64
+ http-request set-var(txn.oldheaders) req.hdrs_bin
http-request del-header Accept
http-request del-header User-Agent
http-request del-header Host
- http-request set-headers-bin %[var(txn.oldheaders)]
+ http-request set-headers-bin var(txn.oldheaders)
set-log-level <level>
{
struct http_msg *msg = ((rule->from == ACT_F_HTTP_REQ) ? &s->txn->req : &s->txn->rsp);
struct htx *htx = htxbuf(&msg->chn->buf);
+ struct sample *hdrs_bin;
+ char *p, *end;
enum act_return ret = ACT_RET_CONT;
- struct buffer *binstring, *decoded = NULL;
struct http_hdr_ctx ctx;
struct ist n, v;
uint64_t sz = 0;
- size_t offset = 0;
- int bytes_read;
- char *oldarea = NULL;
- binstring = alloc_trash_chunk();
- if (!binstring)
- goto fail_alloc;
- decoded = alloc_trash_chunk();
- if (!decoded)
- goto fail_alloc;
-
- oldarea = decoded->area;
-
- binstring->data = build_logline(s, binstring->area, binstring->size, &rule->arg.http.fmt);
-
- bytes_read = base64dec(binstring->area, binstring->data, decoded->area, decoded->size);
- if (bytes_read < 0)
- goto fail_rewrite;
-
- decoded->data = bytes_read;
-
- while (1) {
- int ret;
+ hdrs_bin = sample_fetch_as_type(px, sess, s, SMP_OPT_FINAL, rule->arg.http.expr, SMP_T_BIN);
+ if (!hdrs_bin)
+ return ACT_RET_CONT;
- ret = decode_varint(&decoded->area, decoded->area + decoded->data - offset, &sz);
- if (ret == -1)
+ p = b_orig(&hdrs_bin->data.u.str);
+ end = b_tail(&hdrs_bin->data.u.str);
+ while (p < end) {
+ if (decode_varint(&p, end, &sz) == -1)
goto fail_rewrite;
- offset += ret;
-
if (!sz) {
- ret = decode_varint(&decoded->area, decoded->area + decoded->data - offset, &sz);
- if (ret == -1)
- goto fail_rewrite;
- offset += ret;
- if (!sz)
- goto leave;
- else
+ if (decode_varint(&p, end, &sz) == -1 || sz > 0)
goto fail_rewrite;
+ goto leave;
}
- n = ist2(decoded->area, sz);
- offset += sz;
- decoded->area += sz;
+ n = ist2(p, sz);
+ p += sz;
- ret = decode_varint(&decoded->area, decoded->area + decoded->data - offset, &sz);
- if (ret == -1)
+ if (decode_varint(&p, end, &sz) == -1)
goto fail_rewrite;
- offset += ret;
- v = ist2(decoded->area, sz);
- offset += sz;
- decoded->area += sz;
+ v = ist2(p, sz);
+ p += sz;
if (istlen(rule->arg.http.str) && !istmatch(n, rule->arg.http.str))
continue;
goto fail_rewrite;
}
+ /* invalid encoding */
+ ret = ACT_RET_ERR;
+
leave:
- free_trash_chunk(binstring);
- /* decode_varint moves the area pointer, so return it to the correct position */
- if (decoded)
- decoded->area = oldarea;
- free_trash_chunk(decoded);
return ret;
- fail_alloc:
- if (!(s->flags & SF_ERR_MASK))
- s->flags |= SF_ERR_RESOURCE;
- ret = ACT_RET_ERR;
- goto leave;
-
fail_rewrite:
if (sess->fe_tgcounters)
_HA_ATOMIC_INC(&sess->fe_tgcounters->failed_rewrites);
static enum act_parse_ret parse_http_set_headers_bin(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
- int cap = 0, cur_arg;
+ struct sample_expr *expr;
+ unsigned int where;
+ int cur_arg;
if (args[*orig_arg-1][0] == 's')
rule->action = 0; // set-header
else
rule->action = 1; // add-header
rule->action_ptr = http_action_set_headers_bin;
-
rule->release_ptr = release_http_action;
lf_expr_init(&rule->arg.http.fmt);
return ACT_RET_PRS_ERR;
}
- if (rule->from == ACT_F_HTTP_REQ) {
- px->conf.args.ctx = ARGC_HRQ;
- if (px->cap & PR_CAP_FE)
- cap |= SMP_VAL_FE_HRQ_HDR;
- if (px->cap & PR_CAP_BE)
- cap |= SMP_VAL_BE_HRQ_HDR;
- }
- else{
- px->conf.args.ctx = ARGC_HRS;
- if (px->cap & PR_CAP_FE)
- cap |= SMP_VAL_FE_HRS_HDR;
- if (px->cap & PR_CAP_BE)
- cap |= SMP_VAL_BE_HRS_HDR;
- }
- if (!parse_logformat_string(args[cur_arg], px, &rule->arg.http.fmt, LOG_OPT_HTTP, cap, err)) {
+ expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line,
+ err, &px->conf.args, NULL);
+ if (!expr)
+ return ACT_RET_PRS_ERR;
+
+ where = 0;
+ if (px->cap & PR_CAP_FE)
+ where |= (rule->from == ACT_F_HTTP_REQ ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_FE_HRS_HDR);
+ if (px->cap & PR_CAP_BE)
+ where |= (rule->from == ACT_F_HTTP_REQ ? SMP_VAL_BE_HRQ_HDR : SMP_VAL_BE_HRS_HDR);
+
+ if (!(expr->fetch->val & where)) {
+ 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));
+ release_sample_expr(expr);
return ACT_RET_PRS_ERR;
}
/* Check if an argument is available */
- if (*args[cur_arg+1] && strcmp(args[cur_arg+1], "prefix") == 0 ) {
- if(!*args[cur_arg+2]) {
+ if (strcmp(args[cur_arg], "prefix") == 0 ) {
+ cur_arg++;
+ if(!*args[cur_arg]) {
memprintf(err, "expects 1 argument: <headers>; or 3 arguments: <headers> prefix <pfx>");
+ release_sample_expr(expr);
return ACT_RET_PRS_ERR;
}
- cur_arg += 2;
rule->arg.http.str = ist(strdup(args[cur_arg]));
+ cur_arg++;
}
- *orig_arg = cur_arg + 1;
+ rule->arg.http.expr = expr;
+
+ *orig_arg = cur_arg;
return ACT_RET_PRS_OK;
}
struct http_hdr_ctx ctx;
struct http_msg *msg = ((rule->from == ACT_F_HTTP_REQ) ? &s->txn->req : &s->txn->rsp);
struct htx *htx = htxbuf(&msg->chn->buf);
+ struct sample *hdrs_bin;
+ char *p, *end;
enum act_return ret = ACT_RET_CONT;
- struct buffer *binstring, *decoded = NULL;
struct ist n;
uint64_t sz = 0;
- size_t offset = 0;
- int bytes_read;
- char *oldarea = NULL;
-
- binstring = alloc_trash_chunk();
- if (!binstring)
- goto fail_alloc;
- decoded = alloc_trash_chunk();
- if (!decoded)
- goto fail_alloc;
-
- oldarea = decoded->area;
- binstring->data = build_logline(s, binstring->area, binstring->size, &rule->arg.http.fmt);
-
- bytes_read = base64dec(binstring->area, binstring->data, decoded->area, decoded->size);
- if (bytes_read < 0) {
- goto fail_rewrite;
- }
-
- decoded->data = bytes_read;
-
- while (1) {
- int ret;
+ hdrs_bin = sample_fetch_as_type(px, sess, s, SMP_OPT_FINAL, rule->arg.http.expr, SMP_T_BIN);
+ if (!hdrs_bin)
+ return ACT_RET_CONT;
- ret = decode_varint(&decoded->area, decoded->area + decoded->data - offset, &sz);
- if (ret == -1)
+ p = b_orig(&hdrs_bin->data.u.str);
+ end = b_tail(&hdrs_bin->data.u.str);
+ while (p < end) {
+ if (decode_varint(&p, end, &sz) == -1)
goto fail_rewrite;
- offset += ret;
-
- if (!sz) {
- ret = decode_varint(&decoded->area, decoded->area + decoded->data - offset, &sz);
- if (ret == -1)
- goto fail_rewrite;
- offset += ret;
- if (!sz)
- goto leave;
- else
- goto fail_rewrite;
- }
+ if (!sz)
+ goto leave;
- n = ist2(decoded->area, sz);
- offset += sz;
- decoded->area += sz;
+ n = ist2(p, sz);
+ p += sz;
if (is_immutable_header(n))
continue;
}
}
+ /* invalid encoding */
+ ret = ACT_RET_ERR;
+
leave:
- free_trash_chunk(binstring);
- /* decode_varint moves the area pointer, so return it to the correct position */
- if (decoded)
- decoded->area = oldarea;
- free_trash_chunk(decoded);
return ret;
- fail_alloc:
- if (!(s->flags & SF_ERR_MASK))
- s->flags |= SF_ERR_RESOURCE;
- ret = ACT_RET_ERR;
- goto leave;
-
fail_rewrite:
if (sess->fe_tgcounters)
_HA_ATOMIC_INC(&sess->fe_tgcounters->failed_rewrites);
static enum act_parse_ret parse_http_del_headers_bin(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
- int cap = 0, cur_arg;
+ struct sample_expr *expr;
+ unsigned int where;
+ int cur_arg;
int pat_idx;
/* set exact matching (-m str) as default */
return ACT_RET_PRS_ERR;
}
- if (rule->from == ACT_F_HTTP_REQ) {
- px->conf.args.ctx = ARGC_HRQ;
- if (px->cap & PR_CAP_FE)
- cap |= SMP_VAL_FE_HRQ_HDR;
- if (px->cap & PR_CAP_BE)
- cap |= SMP_VAL_BE_HRQ_HDR;
- }
- else{
- px->conf.args.ctx = ARGC_HRS;
- if (px->cap & PR_CAP_FE)
- cap |= SMP_VAL_FE_HRS_HDR;
- if (px->cap & PR_CAP_BE)
- cap |= SMP_VAL_BE_HRS_HDR;
- }
+ expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line,
+ err, &px->conf.args, NULL);
+ if (!expr)
+ return ACT_RET_PRS_ERR;
- if (!parse_logformat_string(args[cur_arg], px, &rule->arg.http.fmt, LOG_OPT_HTTP, cap, err)) {
- istfree(&rule->arg.http.str);
+ where = 0;
+ if (px->cap & PR_CAP_FE)
+ where |= (rule->from == ACT_F_HTTP_REQ ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_FE_HRS_HDR);
+ if (px->cap & PR_CAP_BE)
+ where |= (rule->from == ACT_F_HTTP_REQ ? SMP_VAL_BE_HRQ_HDR : SMP_VAL_BE_HRS_HDR);
+
+ if (!(expr->fetch->val & where)) {
+ 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));
+ release_sample_expr(expr);
return ACT_RET_PRS_ERR;
}
- px->conf.args.ctx = (rule->from == ACT_F_HTTP_REQ ? ARGC_HRQ : ARGC_HRS);
-
- if (strcmp(args[cur_arg+1], "-m") == 0) {
+ if (strcmp(args[cur_arg], "-m") == 0) {
cur_arg++;
- if (!*args[cur_arg+1]) {
+ if (!*args[cur_arg]) {
memprintf(err, "-m flag expects exactly 1 argument");
+ release_sample_expr(expr);
return ACT_RET_PRS_ERR;
}
- cur_arg++;
pat_idx = pat_find_match_name(args[cur_arg]);
switch (pat_idx) {
case PAT_MATCH_REG:
memprintf(err, "-m reg with is unsupported with del-header-bin due to performance reasons");
+ release_sample_expr(expr);
return ACT_RET_PRS_ERR;
case PAT_MATCH_STR:
case PAT_MATCH_BEG:
break;
default:
memprintf(err, "-m with unsupported matching method '%s'", args[cur_arg]);
+ release_sample_expr(expr);
return ACT_RET_PRS_ERR;
}
+ cur_arg++;
}
- *orig_arg = cur_arg + 1;
+ rule->arg.http.expr = expr;
+
+ *orig_arg = cur_arg;
return ACT_RET_PRS_OK;
}