/* This function executes one of the set-{method,path,query,uri} actions. It
* builds a string in the trash from the specified format string. It finds
- * the action to be performed in <http.action>, previously filled by function
+ * the action to be performed in <http.i>, previously filled by function
* parse_set_req_line(). The replacement action is excuted by the function
* http_action_set_req_line(). On success, it returns ACT_RET_CONT. If an error
* occurs while soft rewrites are enabled, the action is canceled, but the rule
goto fail_alloc;
/* If we have to create a query string, prepare a '?'. */
- if (rule->arg.http.action == 2)
+ if (rule->arg.http.i == 2) // set-query
replace->area[replace->data++] = '?';
replace->data += build_logline(s, replace->area + replace->data,
replace->size - replace->data,
- &rule->arg.http.logfmt);
+ &rule->arg.http.fmt);
- if (http_req_replace_stline(rule->arg.http.action, replace->area,
+ if (http_req_replace_stline(rule->arg.http.i, replace->area,
replace->data, px, s) == -1)
goto fail_rewrite;
* set-uri
*
* All of them accept a single argument of type string representing a log-format.
- * The resulting rule makes use of arg->act.p[0..1] to store the log-format list
- * head, and p[2] to store the action as an int (0=method, 1=path, 2=query, 3=uri).
+ * The resulting rule makes use of <http.fmt> to store the log-format list head,
+ * and <http.i> to store the action as an int (0=method, 1=path, 2=query, 3=uri).
* It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_set_req_line(const char **args, int *orig_arg, struct proxy *px,
switch (args[0][4]) {
case 'm' :
- rule->arg.http.action = 0;
- rule->action_ptr = http_action_set_req_line;
+ rule->arg.http.i = 0; // set-method
break;
case 'p' :
- rule->arg.http.action = 1;
- rule->action_ptr = http_action_set_req_line;
+ rule->arg.http.i = 1; // set-path
break;
case 'q' :
- rule->arg.http.action = 2;
- rule->action_ptr = http_action_set_req_line;
+ rule->arg.http.i = 2; // set-query
break;
case 'u' :
- rule->arg.http.action = 3;
- rule->action_ptr = http_action_set_req_line;
+ rule->arg.http.i = 3; // set-uri
break;
default:
memprintf(err, "internal error: unhandled action '%s'", args[0]);
return ACT_RET_PRS_ERR;
}
+ rule->action_ptr = http_action_set_req_line;
if (!*args[cur_arg] ||
(*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
return ACT_RET_PRS_ERR;
}
- LIST_INIT(&rule->arg.http.logfmt);
+ LIST_INIT(&rule->arg.http.fmt);
px->conf.args.ctx = ARGC_HRQ;
- if (!parse_logformat_string(args[cur_arg], px, &rule->arg.http.logfmt, LOG_OPT_HTTP,
+ if (!parse_logformat_string(args[cur_arg], px, &rule->arg.http.fmt, LOG_OPT_HTTP,
(px->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, err)) {
return ACT_RET_PRS_ERR;
}
}
/* This function executes a replace-uri action. It finds its arguments in
- * <rule>.arg.act.p[]. It builds a string in the trash from the format string
+ * <rule>.arg.http. It builds a string in the trash from the format string
* previously filled by function parse_replace_uri() and will execute the regex
- * in p[1] to replace the URI. It uses the format string present in act.p[2..3].
- * The component to act on (path/uri) is taken from act.p[0] which contains 1
- * for the path or 3 for the URI (values used by http_req_replace_stline()).
- * 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.
+ * in <http.re> to replace the URI. It uses the format string present in
+ * <http.fmt>. The component to act on (path/uri) is taken from <http.i> which
+ * contains 1 for the path or 3 for the URI (values used by
+ * http_req_replace_stline()). 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_uri(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
goto fail_alloc;
uri = htx_sl_req_uri(http_get_stline(htxbuf(&s->req.buf)));
- if (rule->arg.act.p[0] == (void *)1)
- uri = http_get_path(uri); // replace path
+ if (rule->arg.http.i == 1) // replace-path
+ uri = http_get_path(uri);
- if (!regex_exec_match2(rule->arg.act.p[1], uri.ptr, uri.len, MAX_MATCH, pmatch, 0))
+ if (!regex_exec_match2(rule->arg.http.re, uri.ptr, uri.len, MAX_MATCH, pmatch, 0))
goto leave;
- replace->data = build_logline(s, replace->area, replace->size, (struct list *)&rule->arg.act.p[2]);
+ replace->data = build_logline(s, replace->area, replace->size, &rule->arg.http.fmt);
/* note: uri.ptr doesn't need to be zero-terminated because it will
* only be used to pick pmatch references.
if (len == -1)
goto fail_rewrite;
- if (http_req_replace_stline((long)rule->arg.act.p[0], output->area, len, px, s) == -1)
+ if (http_req_replace_stline(rule->arg.http.i, output->area, len, px, s) == -1)
goto fail_rewrite;
leave:
/* parse a "replace-uri" or "replace-path" http-request action.
* This action takes 2 arguments (a regex and a replacement format string).
- * The resulting rule makes use of arg->act.p[0] to store the action (1/3 for now),
- * p[1] to store the compiled regex, and arg->act.p[2..3] to store the log-format
+ * The resulting rule makes use of <http.i> to store the action (1/3 for now),
+ * <http.re> to store the compiled regex, and <http.fmt> to store the log-format
* list head. It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
*/
static enum act_parse_ret parse_replace_uri(const char **args, int *orig_arg, struct proxy *px,
rule->action = ACT_CUSTOM;
if (strcmp(args[cur_arg-1], "replace-path") == 0)
- rule->arg.act.p[0] = (void *)1; // replace-path
+ rule->arg.http.i = 1; // replace-path
else
- rule->arg.act.p[0] = (void *)3; // replace-uri
+ rule->arg.http.i = 3; // replace-uri
rule->action_ptr = http_action_replace_uri;
return ACT_RET_PRS_ERR;
}
- if (!(rule->arg.act.p[1] = regex_comp(args[cur_arg], 1, 1, &error))) {
+ if (!(rule->arg.http.re = regex_comp(args[cur_arg], 1, 1, &error))) {
memprintf(err, "failed to parse the regex : %s", error);
free(error);
return ACT_RET_PRS_ERR;
}
- LIST_INIT((struct list *)&rule->arg.act.p[2]);
+ LIST_INIT(&rule->arg.http.fmt);
px->conf.args.ctx = ARGC_HRQ;
- if (!parse_logformat_string(args[cur_arg + 1], px, (struct list *)&rule->arg.act.p[2], LOG_OPT_HTTP,
+ if (!parse_logformat_string(args[cur_arg + 1], px, &rule->arg.http.fmt, LOG_OPT_HTTP,
(px->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, err)) {
return ACT_RET_PRS_ERR;
}
static enum act_return action_http_set_status(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags)
{
- if (http_res_set_status(rule->arg.status.code, rule->arg.status.reason, s) == -1) {
+ if (http_res_set_status(rule->arg.http.i, rule->arg.http.str, s) == -1) {
_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);
}
/* convert status code as integer */
- rule->arg.status.code = strtol(args[*orig_arg], &error, 10);
- if (*error != '\0' || rule->arg.status.code < 100 || rule->arg.status.code > 999) {
+ rule->arg.http.i = strtol(args[*orig_arg], &error, 10);
+ if (*error != '\0' || rule->arg.http.i < 100 || rule->arg.http.i > 999) {
memprintf(err, "expects an integer status code between 100 and 999");
return ACT_RET_PRS_ERR;
}
(*orig_arg)++;
/* set custom reason string */
- rule->arg.status.reason = NULL; // If null, we use the default reason for the status code.
+ rule->arg.http.str = ist(NULL); // If null, we use the default reason for the status code.
if (*args[*orig_arg] && strcmp(args[*orig_arg], "reason") == 0 &&
(*args[*orig_arg + 1] && strcmp(args[*orig_arg + 1], "if") != 0 && strcmp(args[*orig_arg + 1], "unless") != 0)) {
(*orig_arg)++;
- rule->arg.status.reason = strdup(args[*orig_arg]);
+ rule->arg.http.str.ptr = strdup(args[*orig_arg]);
+ rule->arg.http.str.len = strlen(rule->arg.http.str.ptr);
(*orig_arg)++;
}
cur_arg = *orig_arg;
if (!strcmp(args[cur_arg-1], "tarpit")) {
rule->action = ACT_HTTP_REQ_TARPIT;
- rule->deny_status = HTTP_ERR_500;
+ rule->arg.http.i = HTTP_ERR_500;
}
else {
rule->action = ACT_ACTION_DENY;
- rule->deny_status = HTTP_ERR_403;
+ rule->arg.http.i = HTTP_ERR_403;
}
if (strcmp(args[cur_arg], "deny_status") == 0) {
cur_arg++;
for (hc = 0; hc < HTTP_ERR_SIZE; hc++) {
if (http_err_codes[hc] == code) {
- rule->deny_status = hc;
+ rule->arg.http.i = hc;
break;
}
}
if (hc >= HTTP_ERR_SIZE)
memprintf(err, "status code %d not handled, using default code %d",
- code, http_err_codes[rule->deny_status]);
+ code, http_err_codes[rule->arg.http.i]);
}
*orig_arg = cur_arg;
memprintf(err, "missing realm value.\n");
return ACT_RET_PRS_ERR;
}
- rule->arg.auth.realm = strdup(args[cur_arg]);
+ rule->arg.http.str.ptr = strdup(args[cur_arg]);
+ rule->arg.http.str.len = strlen(rule->arg.http.str.ptr);
cur_arg++;
}
memprintf(err, "expects exactly 1 argument (integer value)");
return ACT_RET_PRS_ERR;
}
- rule->arg.nice = atoi(args[cur_arg]);
- if (rule->arg.nice < -1024)
- rule->arg.nice = -1024;
- else if (rule->arg.nice > 1024)
- rule->arg.nice = 1024;
+ rule->arg.http.i = atoi(args[cur_arg]);
+ if (rule->arg.http.i < -1024)
+ rule->arg.http.i = -1024;
+ else if (rule->arg.http.i > 1024)
+ rule->arg.http.i = 1024;
*orig_arg = cur_arg + 1;
return ACT_RET_PRS_OK;
memprintf(err, "expects exactly 1 argument (integer/hex value)");
return ACT_RET_PRS_ERR;
}
- rule->arg.tos = strtol(args[cur_arg], &endp, 0);
+ rule->arg.http.i = strtol(args[cur_arg], &endp, 0);
if (endp && *endp != '\0') {
memprintf(err, "invalid character starting at '%s' (integer/hex value expected)", endp);
return ACT_RET_PRS_ERR;
memprintf(err, "expects exactly 1 argument (integer/hex value)");
return ACT_RET_PRS_ERR;
}
- rule->arg.mark = strtoul(args[cur_arg], &endp, 0);
+ rule->arg.http.i = strtoul(args[cur_arg], &endp, 0);
if (endp && *endp != '\0') {
memprintf(err, "invalid character starting at '%s' (integer/hex value expected)", endp);
return ACT_RET_PRS_ERR;
return ACT_RET_PRS_ERR;
}
if (strcmp(args[cur_arg], "silent") == 0)
- rule->arg.loglevel = -1;
- else if ((rule->arg.loglevel = get_log_level(args[cur_arg]) + 1) == 0)
+ rule->arg.http.i = -1;
+ else if ((rule->arg.http.i = get_log_level(args[cur_arg]) + 1) == 0)
goto bad_log_level;
*orig_arg = cur_arg + 1;
static enum act_parse_ret parse_http_set_header(const char **args, int *orig_arg, struct proxy *px,
struct act_rule *rule, char **err)
{
- char **hdr_name;
- int *hdr_name_len;
- struct list *fmt;
int cap, cur_arg;
rule->action = (*args[*orig_arg-1] == 'a' ? ACT_HTTP_ADD_HDR :
return ACT_RET_PRS_ERR;
}
- hdr_name = (*args[cur_arg-1] == 'e' ? &rule->arg.early_hint.name : &rule->arg.hdr_add.name);
- hdr_name_len = (*args[cur_arg-1] == 'e' ? &rule->arg.early_hint.name_len : &rule->arg.hdr_add.name_len);
- fmt = (*args[cur_arg-1] == 'e' ? &rule->arg.early_hint.fmt : &rule->arg.hdr_add.fmt);
- *hdr_name = strdup(args[cur_arg]);
- *hdr_name_len = strlen(*hdr_name);
- LIST_INIT(fmt);
+ rule->arg.http.str.ptr = strdup(args[cur_arg]);
+ rule->arg.http.str.len = strlen(rule->arg.http.str.ptr);
+ LIST_INIT(&rule->arg.http.fmt);
if (rule->from == ACT_F_HTTP_REQ) {
px->conf.args.ctx = ARGC_HRQ;
}
cur_arg++;
- if (!parse_logformat_string(args[cur_arg], px, fmt, LOG_OPT_HTTP, cap, err))
+ if (!parse_logformat_string(args[cur_arg], px, &rule->arg.http.fmt, LOG_OPT_HTTP, cap, err))
return ACT_RET_PRS_ERR;
free(px->conf.lfs_file);
return ACT_RET_PRS_ERR;
}
- rule->arg.hdr_add.name = strdup(args[cur_arg]);
- rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
- LIST_INIT(&rule->arg.hdr_add.fmt);
+ rule->arg.http.str.ptr = strdup(args[cur_arg]);
+ rule->arg.http.str.len = strlen(rule->arg.http.str.ptr);
+ LIST_INIT(&rule->arg.http.fmt);
cur_arg++;
- if (!(rule->arg.hdr_add.re = regex_comp(args[cur_arg], 1, 1, err)))
+ if (!(rule->arg.http.re = regex_comp(args[cur_arg], 1, 1, err)))
return ACT_RET_PRS_ERR;
if (rule->from == ACT_F_HTTP_REQ) {
}
cur_arg++;
- if (!parse_logformat_string(args[cur_arg], px, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP, cap, err))
+ if (!parse_logformat_string(args[cur_arg], px, &rule->arg.http.fmt, LOG_OPT_HTTP, cap, err))
return ACT_RET_PRS_ERR;
free(px->conf.lfs_file);
return ACT_RET_PRS_ERR;
}
- rule->arg.hdr_add.name = strdup(args[cur_arg]);
- rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
+ rule->arg.http.str.ptr = strdup(args[cur_arg]);
+ rule->arg.http.str.len = strlen(rule->arg.http.str.ptr);
px->conf.args.ctx = (rule->from == ACT_F_HTTP_REQ ? ARGC_HRQ : ARGC_HRS);
* variable <status> contains the new status code. This function never fails. It
* returns 0 in case of success, -1 in case of internal error.
*/
-int http_res_set_status(unsigned int status, const char *reason, struct stream *s)
+int http_res_set_status(unsigned int status, struct ist reason, struct stream *s)
{
struct htx *htx = htxbuf(&s->res.buf);
char *res;
trash.data = res - trash.area;
/* Do we have a custom reason format string? */
- if (reason == NULL)
- reason = http_get_reason(status);
+ if (reason.ptr == NULL) {
+ const char *str = http_get_reason(status);
+ reason = ist2(str, strlen(str));
+ }
if (!http_replace_res_status(htx, ist2(trash.area, trash.data)))
return -1;
- if (!http_replace_res_reason(htx, ist2(reason, strlen(reason))))
+ if (!http_replace_res_reason(htx, reason))
return -1;
return 0;
}
case ACT_ACTION_DENY:
if (deny_status)
- *deny_status = rule->deny_status;
+ *deny_status = rule->arg.http.i;
rule_ret = HTTP_RULE_RES_DENY;
goto end;
case ACT_HTTP_REQ_TARPIT:
txn->flags |= TX_CLTARPIT;
if (deny_status)
- *deny_status = rule->deny_status;
+ *deny_status = rule->arg.http.i;
rule_ret = HTTP_RULE_RES_DENY;
goto end;
case ACT_HTTP_REQ_AUTH:
/* Auth might be performed on regular http-req rules as well as on stats */
- auth_realm = rule->arg.auth.realm;
+ auth_realm = rule->arg.http.str.ptr;
if (!auth_realm) {
if (px->uri_auth && rules == &px->uri_auth->http_req_rules)
auth_realm = STATS_DEFAULT_REALM;
goto end;
case ACT_HTTP_SET_NICE:
- s->task->nice = rule->arg.nice;
+ s->task->nice = rule->arg.http.i;
break;
case ACT_HTTP_SET_TOS:
- conn_set_tos(objt_conn(sess->origin), rule->arg.tos);
+ conn_set_tos(objt_conn(sess->origin), rule->arg.http.i);
break;
case ACT_HTTP_SET_MARK:
- conn_set_mark(objt_conn(sess->origin), rule->arg.mark);
+ conn_set_mark(objt_conn(sess->origin), rule->arg.http.i);
break;
case ACT_HTTP_SET_LOGL:
- s->logs.level = rule->arg.loglevel;
+ 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,
- ist2(rule->arg.hdr_add.name, rule->arg.hdr_add.name_len),
- &rule->arg.hdr_add.fmt,
- rule->arg.hdr_add.re, rule->action)) {
+ 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;
}
case ACT_HTTP_DEL_HDR:
/* remove all occurrences of the header */
ctx.blk = NULL;
- while (http_find_header(htx, ist2(rule->arg.hdr_add.name, rule->arg.hdr_add.name_len), &ctx, 1))
+ while (http_find_header(htx, rule->arg.http.str, &ctx, 1))
http_remove_header(htx, &ctx);
break;
goto end;
}
- replace->data = build_logline(s, replace->area, replace->size, &rule->arg.hdr_add.fmt);
- n = ist2(rule->arg.hdr_add.name, rule->arg.hdr_add.name_len);
+ replace->data = build_logline(s, replace->area, replace->size, &rule->arg.http.fmt);
+ n = rule->arg.http.str;
v = ist2(replace->area, replace->data);
if (rule->action == ACT_HTTP_SET_HDR) {
/* remove all occurrences of the header */
ctx.blk = NULL;
- while (http_find_header(htx, ist2(rule->arg.hdr_add.name, rule->arg.hdr_add.name_len), &ctx, 1))
+ while (http_find_header(htx, n, &ctx, 1))
http_remove_header(htx, &ctx);
}
case ACT_HTTP_EARLY_HINT:
if (!(txn->req.flags & HTTP_MSGF_VER_11))
break;
- early_hints = http_add_early_hint_header(s, early_hints,
- ist2(rule->arg.early_hint.name, rule->arg.early_hint.name_len),
- &rule->arg.early_hint.fmt);
+ early_hints = http_add_early_hint_header(s, early_hints, rule->arg.http.str, &rule->arg.http.fmt);
if (early_hints == -1) {
rule_ret = HTTP_RULE_RES_ERROR;
goto end;
goto end;
case ACT_HTTP_SET_NICE:
- s->task->nice = rule->arg.nice;
+ s->task->nice = rule->arg.http.i;
break;
case ACT_HTTP_SET_TOS:
- conn_set_tos(objt_conn(sess->origin), rule->arg.tos);
+ conn_set_tos(objt_conn(sess->origin), rule->arg.http.i);
break;
case ACT_HTTP_SET_MARK:
- conn_set_mark(objt_conn(sess->origin), rule->arg.mark);
+ conn_set_mark(objt_conn(sess->origin), rule->arg.http.i);
break;
case ACT_HTTP_SET_LOGL:
- s->logs.level = rule->arg.loglevel;
+ 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,
- ist2(rule->arg.hdr_add.name, rule->arg.hdr_add.name_len),
- &rule->arg.hdr_add.fmt,
- rule->arg.hdr_add.re, rule->action)) {
+ 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;
}
case ACT_HTTP_DEL_HDR:
/* remove all occurrences of the header */
ctx.blk = NULL;
- while (http_find_header(htx, ist2(rule->arg.hdr_add.name, rule->arg.hdr_add.name_len), &ctx, 1))
+ while (http_find_header(htx, rule->arg.http.str, &ctx, 1))
http_remove_header(htx, &ctx);
break;
goto end;
}
- replace->data = build_logline(s, replace->area, replace->size, &rule->arg.hdr_add.fmt);
- n = ist2(rule->arg.hdr_add.name, rule->arg.hdr_add.name_len);
+ replace->data = build_logline(s, replace->area, replace->size, &rule->arg.http.fmt);
+ n = rule->arg.http.str;
v = ist2(replace->area, replace->data);
if (rule->action == ACT_HTTP_SET_HDR) {
/* remove all occurrences of the header */
ctx.blk = NULL;
- while (http_find_header(htx, ist2(rule->arg.hdr_add.name, rule->arg.hdr_add.name_len), &ctx, 1))
+ while (http_find_header(htx, n, &ctx, 1))
http_remove_header(htx, &ctx);
}