mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-22 22:31:28 +02:00
MEDIUM: http: The redirect strings follows the log format rules.
We handle "http-request redirect" with a log-format string now, but we leave "redirect" unaffected. Note that the control of the special "/" case is move from the runtime execution to the configuration parsing. If the format rule list is empty, the build_logline() function does nothing.
This commit is contained in:
parent
06d97f935c
commit
d18cd0f110
@ -2768,7 +2768,8 @@ http-request { allow | deny | tarpit | auth [realm <realm>] | redirect <rule> |
|
|||||||
- "redirect" : this performs an HTTP redirection based on a redirect rule.
|
- "redirect" : this performs an HTTP redirection based on a redirect rule.
|
||||||
This is exactly the same as the "redirect" statement except that it
|
This is exactly the same as the "redirect" statement except that it
|
||||||
inserts a redirect rule which can be processed in the middle of other
|
inserts a redirect rule which can be processed in the middle of other
|
||||||
"http-request" rules. See the "redirect" keyword for the rule's syntax.
|
"http-request" rules and that these rules use the "log-format" strings.
|
||||||
|
See the "redirect" keyword for the rule's syntax.
|
||||||
|
|
||||||
- "add-header" appends an HTTP header field whose name is specified in
|
- "add-header" appends an HTTP header field whose name is specified in
|
||||||
<name> and whose value is defined by <fmt> which follows the log-format
|
<name> and whose value is defined by <fmt> which follows the log-format
|
||||||
@ -4709,14 +4710,19 @@ redirect scheme <sch> [code <code>] <option> [{if | unless} <condition>]
|
|||||||
|
|
||||||
Arguments :
|
Arguments :
|
||||||
<loc> With "redirect location", the exact value in <loc> is placed into
|
<loc> With "redirect location", the exact value in <loc> is placed into
|
||||||
the HTTP "Location" header.
|
the HTTP "Location" header. When used in an "http-request" rule,
|
||||||
|
<loc> value follows the log-format rules and can include some
|
||||||
|
dynamic values (see Custom Log Format in section 8.2.4).
|
||||||
|
|
||||||
<pfx> With "redirect prefix", the "Location" header is built from the
|
<pfx> With "redirect prefix", the "Location" header is built from the
|
||||||
concatenation of <pfx> and the complete URI path, including the
|
concatenation of <pfx> and the complete URI path, including the
|
||||||
query string, unless the "drop-query" option is specified (see
|
query string, unless the "drop-query" option is specified (see
|
||||||
below). As a special case, if <pfx> equals exactly "/", then
|
below). As a special case, if <pfx> equals exactly "/", then
|
||||||
nothing is inserted before the original URI. It allows one to
|
nothing is inserted before the original URI. It allows one to
|
||||||
redirect to the same URL (for instance, to insert a cookie).
|
redirect to the same URL (for instance, to insert a cookie). When
|
||||||
|
used in an "http-request" rule, <pfx> value follows the log-format
|
||||||
|
rules and can include some dynamic values (see Custom Log Format
|
||||||
|
in section 8.2.4).
|
||||||
|
|
||||||
<sch> With "redirect scheme", then the "Location" header is built by
|
<sch> With "redirect scheme", then the "Location" header is built by
|
||||||
concatenating <sch> with "://" then the first occurrence of the
|
concatenating <sch> with "://" then the first occurrence of the
|
||||||
@ -4726,7 +4732,9 @@ redirect scheme <sch> [code <code>] <option> [{if | unless} <condition>]
|
|||||||
no "Host" header is found, then an empty host component will be
|
no "Host" header is found, then an empty host component will be
|
||||||
returned, which most recent browsers interprete as redirecting to
|
returned, which most recent browsers interprete as redirecting to
|
||||||
the same host. This directive is mostly used to redirect HTTP to
|
the same host. This directive is mostly used to redirect HTTP to
|
||||||
HTTPS.
|
HTTPS. When used in an "http-request" rule, <sch> value follows
|
||||||
|
the log-format rules and can include some dynamic values (see
|
||||||
|
Custom Log Format in section 8.2.4).
|
||||||
|
|
||||||
<code> The code is optional. It indicates which type of HTTP redirection
|
<code> The code is optional. It indicates which type of HTTP redirection
|
||||||
is desired. Only codes 301, 302, 303, 307 and 308 are supported,
|
is desired. Only codes 301, 302, 303, 307 and 308 are supported,
|
||||||
@ -4790,6 +4798,10 @@ redirect scheme <sch> [code <code>] <option> [{if | unless} <condition>]
|
|||||||
Example: redirect all HTTP traffic to HTTPS when SSL is handled by haproxy.
|
Example: redirect all HTTP traffic to HTTPS when SSL is handled by haproxy.
|
||||||
redirect scheme https if !{ ssl_fc }
|
redirect scheme https if !{ ssl_fc }
|
||||||
|
|
||||||
|
Example: append 'www.' prefix in front of all hosts not having it
|
||||||
|
http-request redirect code 301 location www.%[hdr(host)]%[req.uri] \
|
||||||
|
unless { hdr_beg(host) -i www }
|
||||||
|
|
||||||
See section 7 about ACL usage.
|
See section 7 about ACL usage.
|
||||||
|
|
||||||
|
|
||||||
|
@ -117,8 +117,8 @@ 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);
|
||||||
void free_http_req_rules(struct list *r);
|
void free_http_req_rules(struct list *r);
|
||||||
struct chunk *http_error_message(struct session *s, int msgnum);
|
struct chunk *http_error_message(struct session *s, int msgnum);
|
||||||
struct redirect_rule *http_parse_redirect_rule(const char *file, int line, struct proxy *curproxy,
|
struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, struct proxy *curproxy,
|
||||||
const char **args, char **errmsg);
|
const char **args, char **errmsg, int use_fmt);
|
||||||
|
|
||||||
/* 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 { \
|
||||||
|
@ -57,6 +57,7 @@ enum {
|
|||||||
ARGC_HRQ, /* http-request */
|
ARGC_HRQ, /* http-request */
|
||||||
ARGC_HRS, /* http-response */
|
ARGC_HRS, /* http-response */
|
||||||
ARGC_UIF, /* unique-id-format */
|
ARGC_UIF, /* unique-id-format */
|
||||||
|
ARGC_RDR, /* redirect */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* some types that are externally defined */
|
/* some types that are externally defined */
|
||||||
|
@ -403,6 +403,7 @@ struct redirect_rule {
|
|||||||
int type;
|
int type;
|
||||||
int rdr_len;
|
int rdr_len;
|
||||||
char *rdr_str;
|
char *rdr_str;
|
||||||
|
struct list rdr_fmt;
|
||||||
int code;
|
int code;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
int cookie_len;
|
int cookie_len;
|
||||||
|
@ -2770,7 +2770,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((rule = http_parse_redirect_rule(file, linenum, curproxy, (const char **)args + 1, &errmsg)) == NULL) {
|
if ((rule = http_parse_redirect_rule(file, linenum, curproxy, (const char **)args + 1, &errmsg, 0)) == NULL) {
|
||||||
Alert("parsing [%s:%d] : error detected in %s '%s' while parsing redirect rule : %s.\n",
|
Alert("parsing [%s:%d] : error detected in %s '%s' while parsing redirect rule : %s.\n",
|
||||||
file, linenum, proxy_type_str(curproxy), curproxy->id, errmsg);
|
file, linenum, proxy_type_str(curproxy), curproxy->id, errmsg);
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
|
@ -1073,6 +1073,10 @@ void deinit(void)
|
|||||||
free(rdr->cond);
|
free(rdr->cond);
|
||||||
}
|
}
|
||||||
free(rdr->rdr_str);
|
free(rdr->rdr_str);
|
||||||
|
list_for_each_entry_safe(lf, lfb, &rdr->rdr_fmt, list) {
|
||||||
|
LIST_DEL(&lf->list);
|
||||||
|
free(lf);
|
||||||
|
}
|
||||||
free(rdr);
|
free(rdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,6 +177,8 @@ static inline const char *fmt_directive(const struct proxy *curproxy)
|
|||||||
return "stick";
|
return "stick";
|
||||||
case ARGC_TRK:
|
case ARGC_TRK:
|
||||||
return "track-sc"; break;
|
return "track-sc"; break;
|
||||||
|
case ARGC_RDR:
|
||||||
|
return "redirect"; break;
|
||||||
case ARGC_ACL:
|
case ARGC_ACL:
|
||||||
return "acl"; break;
|
return "acl"; break;
|
||||||
default:
|
default:
|
||||||
|
108
src/proto_http.c
108
src/proto_http.c
@ -3340,6 +3340,7 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct session *
|
|||||||
{
|
{
|
||||||
struct http_msg *msg = &txn->req;
|
struct http_msg *msg = &txn->req;
|
||||||
const char *msg_fmt;
|
const char *msg_fmt;
|
||||||
|
const char *location;
|
||||||
|
|
||||||
/* build redirect message */
|
/* build redirect message */
|
||||||
switch(rule->code) {
|
switch(rule->code) {
|
||||||
@ -3364,6 +3365,8 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct session *
|
|||||||
if (unlikely(!chunk_strcpy(&trash, msg_fmt)))
|
if (unlikely(!chunk_strcpy(&trash, msg_fmt)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
location = trash.str + trash.len;
|
||||||
|
|
||||||
switch(rule->type) {
|
switch(rule->type) {
|
||||||
case REDIRECT_TYPE_SCHEME: {
|
case REDIRECT_TYPE_SCHEME: {
|
||||||
const char *path;
|
const char *path;
|
||||||
@ -3399,14 +3402,23 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct session *
|
|||||||
pathlen = 1;
|
pathlen = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if we can add scheme + "://" + host + path */
|
if (rule->rdr_str) { /* this is an old "redirect" rule */
|
||||||
if (trash.len + rule->rdr_len + 3 + hostlen + pathlen > trash.size - 4)
|
/* check if we can add scheme + "://" + host + path */
|
||||||
return 0;
|
if (trash.len + rule->rdr_len + 3 + hostlen + pathlen > trash.size - 4)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* add scheme */
|
/* add scheme */
|
||||||
memcpy(trash.str + trash.len, rule->rdr_str, rule->rdr_len);
|
memcpy(trash.str + trash.len, rule->rdr_str, rule->rdr_len);
|
||||||
trash.len += rule->rdr_len;
|
trash.len += rule->rdr_len;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* add scheme with executing log format */
|
||||||
|
trash.len += build_logline(s, trash.str + trash.len, trash.size - trash.len, &rule->rdr_fmt);
|
||||||
|
|
||||||
|
/* check if we can add scheme + "://" + host + path */
|
||||||
|
if (trash.len + 3 + hostlen + pathlen > trash.size - 4)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
/* add "://" */
|
/* add "://" */
|
||||||
memcpy(trash.str + trash.len, "://", 3);
|
memcpy(trash.str + trash.len, "://", 3);
|
||||||
trash.len += 3;
|
trash.len += 3;
|
||||||
@ -3419,7 +3431,7 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct session *
|
|||||||
memcpy(trash.str + trash.len, path, pathlen);
|
memcpy(trash.str + trash.len, path, pathlen);
|
||||||
trash.len += pathlen;
|
trash.len += pathlen;
|
||||||
|
|
||||||
/* append a slash at the end of the location is needed and missing */
|
/* append a slash at the end of the location if needed and missing */
|
||||||
if (trash.len && trash.str[trash.len - 1] != '/' &&
|
if (trash.len && trash.str[trash.len - 1] != '/' &&
|
||||||
(rule->flags & REDIRECT_FLAG_APPEND_SLASH)) {
|
(rule->flags & REDIRECT_FLAG_APPEND_SLASH)) {
|
||||||
if (trash.len > trash.size - 5)
|
if (trash.len > trash.size - 5)
|
||||||
@ -3453,23 +3465,33 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct session *
|
|||||||
pathlen = 1;
|
pathlen = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trash.len + rule->rdr_len + pathlen > trash.size - 4)
|
if (rule->rdr_str) { /* this is an old "redirect" rule */
|
||||||
return 0;
|
if (trash.len + rule->rdr_len + pathlen > trash.size - 4)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* add prefix. Note that if prefix == "/", we don't want to
|
/* add prefix. Note that if prefix == "/", we don't want to
|
||||||
* add anything, otherwise it makes it hard for the user to
|
* add anything, otherwise it makes it hard for the user to
|
||||||
* configure a self-redirection.
|
* configure a self-redirection.
|
||||||
*/
|
*/
|
||||||
if (rule->rdr_len != 1 || *rule->rdr_str != '/') {
|
if (rule->rdr_len != 1 || *rule->rdr_str != '/') {
|
||||||
memcpy(trash.str + trash.len, rule->rdr_str, rule->rdr_len);
|
memcpy(trash.str + trash.len, rule->rdr_str, rule->rdr_len);
|
||||||
trash.len += rule->rdr_len;
|
trash.len += rule->rdr_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* add prefix with executing log format */
|
||||||
|
trash.len += build_logline(s, trash.str + trash.len, trash.size - trash.len, &rule->rdr_fmt);
|
||||||
|
|
||||||
|
/* Check length */
|
||||||
|
if (trash.len + pathlen > trash.size - 4)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add path */
|
/* add path */
|
||||||
memcpy(trash.str + trash.len, path, pathlen);
|
memcpy(trash.str + trash.len, path, pathlen);
|
||||||
trash.len += pathlen;
|
trash.len += pathlen;
|
||||||
|
|
||||||
/* append a slash at the end of the location is needed and missing */
|
/* append a slash at the end of the location if needed and missing */
|
||||||
if (trash.len && trash.str[trash.len - 1] != '/' &&
|
if (trash.len && trash.str[trash.len - 1] != '/' &&
|
||||||
(rule->flags & REDIRECT_FLAG_APPEND_SLASH)) {
|
(rule->flags & REDIRECT_FLAG_APPEND_SLASH)) {
|
||||||
if (trash.len > trash.size - 5)
|
if (trash.len > trash.size - 5)
|
||||||
@ -3482,12 +3504,22 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct session *
|
|||||||
}
|
}
|
||||||
case REDIRECT_TYPE_LOCATION:
|
case REDIRECT_TYPE_LOCATION:
|
||||||
default:
|
default:
|
||||||
if (trash.len + rule->rdr_len > trash.size - 4)
|
if (rule->rdr_str) { /* this is an old "redirect" rule */
|
||||||
return 0;
|
if (trash.len + rule->rdr_len > trash.size - 4)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* add location */
|
/* add location */
|
||||||
memcpy(trash.str + trash.len, rule->rdr_str, rule->rdr_len);
|
memcpy(trash.str + trash.len, rule->rdr_str, rule->rdr_len);
|
||||||
trash.len += rule->rdr_len;
|
trash.len += rule->rdr_len;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* add location with executing log format */
|
||||||
|
trash.len += build_logline(s, trash.str + trash.len, trash.size - trash.len, &rule->rdr_fmt);
|
||||||
|
|
||||||
|
/* Check left length */
|
||||||
|
if (trash.len > trash.size - 4)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3509,7 +3541,7 @@ static int http_apply_redirect_rule(struct redirect_rule *rule, struct session *
|
|||||||
/* let's log the request time */
|
/* let's log the request time */
|
||||||
s->logs.tv_request = now;
|
s->logs.tv_request = now;
|
||||||
|
|
||||||
if (rule->rdr_len >= 1 && *rule->rdr_str == '/' &&
|
if (*location == '/' &&
|
||||||
(msg->flags & HTTP_MSGF_XFER_LEN) &&
|
(msg->flags & HTTP_MSGF_XFER_LEN) &&
|
||||||
!(msg->flags & HTTP_MSGF_TE_CHNK) && !txn->req.body_len &&
|
!(msg->flags & HTTP_MSGF_TE_CHNK) && !txn->req.body_len &&
|
||||||
((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL ||
|
((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL ||
|
||||||
@ -8474,7 +8506,7 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
|
|||||||
struct redirect_rule *redir;
|
struct redirect_rule *redir;
|
||||||
char *errmsg = NULL;
|
char *errmsg = NULL;
|
||||||
|
|
||||||
if ((redir = http_parse_redirect_rule(file, linenum, proxy, (const char **)args + 1, &errmsg)) == NULL) {
|
if ((redir = http_parse_redirect_rule(file, linenum, proxy, (const char **)args + 1, &errmsg, 1)) == NULL) {
|
||||||
Alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
|
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);
|
file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
|
||||||
goto out_err;
|
goto out_err;
|
||||||
@ -8670,10 +8702,11 @@ struct http_res_rule *parse_http_res_cond(const char **args, const char *file, i
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Parses a redirect rule. Returns the redirect rule on success or NULL on error,
|
/* Parses a redirect rule. Returns the redirect rule on success or NULL on error,
|
||||||
* with <err> filled with the error message.
|
* with <err> filled with the error message. If <use_fmt> is not null, builds a
|
||||||
|
* dynamic log-format rule instead of a static string.
|
||||||
*/
|
*/
|
||||||
struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, struct proxy *curproxy,
|
struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, struct proxy *curproxy,
|
||||||
const char **args, char **errmsg)
|
const char **args, char **errmsg, int use_fmt)
|
||||||
{
|
{
|
||||||
struct redirect_rule *rule;
|
struct redirect_rule *rule;
|
||||||
int cur_arg;
|
int cur_arg;
|
||||||
@ -8771,8 +8804,27 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
|
|||||||
|
|
||||||
rule = (struct redirect_rule *)calloc(1, sizeof(*rule));
|
rule = (struct redirect_rule *)calloc(1, sizeof(*rule));
|
||||||
rule->cond = cond;
|
rule->cond = cond;
|
||||||
rule->rdr_str = strdup(destination);
|
|
||||||
rule->rdr_len = strlen(destination);
|
if (!use_fmt) {
|
||||||
|
/* old-style static redirect rule */
|
||||||
|
rule->rdr_str = strdup(destination);
|
||||||
|
rule->rdr_len = strlen(destination);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* log-format based redirect rule */
|
||||||
|
LIST_INIT(&rule->rdr_fmt);
|
||||||
|
|
||||||
|
/* Parse destination. Note that in the REDIRECT_TYPE_PREFIX case,
|
||||||
|
* if prefix == "/", we don't want to add anything, otherwise it
|
||||||
|
* makes it hard for the user to configure a self-redirection.
|
||||||
|
*/
|
||||||
|
proxy->conf.args.ctx = ARGC_RDR;
|
||||||
|
if (!(type == REDIRECT_TYPE_PREFIX && destination[0] == '/' && destination[1] == '\0')) {
|
||||||
|
parse_logformat_string(destination, curproxy, &rule->rdr_fmt, 0,
|
||||||
|
(curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (cookie) {
|
if (cookie) {
|
||||||
/* depending on cookie_set, either we want to set the cookie, or to clear it.
|
/* depending on cookie_set, either we want to set the cookie, or to clear it.
|
||||||
* a clear consists in appending "; path=/; Max-Age=0;" at the end.
|
* a clear consists in appending "; path=/; Max-Age=0;" at the end.
|
||||||
|
@ -901,6 +901,7 @@ int smp_resolve_args(struct proxy *p)
|
|||||||
case ARGC_HRQ: where = "in http-request header format string in"; break;
|
case ARGC_HRQ: where = "in http-request header format string in"; break;
|
||||||
case ARGC_HRS: where = "in http-response header format string in"; break;
|
case ARGC_HRS: where = "in http-response header format string in"; break;
|
||||||
case ARGC_UIF: where = "in unique-id-format string in"; break;
|
case ARGC_UIF: where = "in unique-id-format string in"; break;
|
||||||
|
case ARGC_RDR: where = "in redirect format string in"; break;
|
||||||
case ARGC_ACL: ctx = "ACL keyword"; break;
|
case ARGC_ACL: ctx = "ACL keyword"; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user