]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: http: add support for "http-request redirect" rules
authorWilly Tarreau <w@1wt.eu>
Thu, 27 Dec 2012 11:19:02 +0000 (12:19 +0100)
committerWilly Tarreau <w@1wt.eu>
Fri, 28 Dec 2012 13:47:19 +0000 (14:47 +0100)
These are exactly the same as the classic redirect rules except
that they can be interleaved with other http-request rules for
more flexibility.

The redirect parser should probably be changed to stop at the condition
so that the caller puts its own condition pointer. At the moment, the
redirect rule and condition are parsed at once by build_redirect_rule()
and the condition is assigned to the http_req_rule.

doc/configuration.txt
include/types/proto_http.h
src/proto_http.c

index 9aaf22d3aa815b6574124a874bbf871f88fe2057..a4973ecb705585bee6ea4c5a69867aa68cb577ea 100644 (file)
@@ -2606,7 +2606,7 @@ http-check send-state
 
   See also : "option httpchk", "http-check disable-on-404"
 
-http-request { allow | deny | auth [realm <realm>] |
+http-request { allow | deny | auth [realm <realm>] | redirect <rule> |
               add-header <name> <fmt> | set-header <name> <fmt> }
              [ { if | unless } <condition> ]
   Access control for Layer 7 requests
@@ -2634,6 +2634,11 @@ http-request { allow | deny | auth [realm <realm>] |
       optional "realm" parameter is supported, it sets the authentication realm
       that is returned with the response (typically the application's name).
 
+    - "redirect" : this performs an HTTP redirection based on a redirect rule.
+      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
+      "http-request" rules. See the "redirect" keyword for the rule's syntax.
+
     - "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
       rules (see Custom Log Format in section 8.2.4). This is particularly
index 7c5a42a3fff20b37f99f65a01f6eed764a166cb7..ef81a12a67cb446c077038f4bceef2b2d2232de6 100644 (file)
@@ -243,6 +243,7 @@ enum {
        HTTP_REQ_ACT_AUTH,
        HTTP_REQ_ACT_ADD_HDR,
        HTTP_REQ_ACT_SET_HDR,
+       HTTP_REQ_ACT_REDIR,
        HTTP_REQ_ACT_MAX /* must always be last */
 };
 
@@ -354,6 +355,7 @@ struct http_req_rule {
                        int name_len;          /* header name's length */
                        struct list fmt;       /* log-format compatible expression */
                } hdr_add;                     /* args used by "add-header" and "set-header" */
+               struct redirect_rule *redir;   /* redirect rule or "http-request redirect" */
        } arg;                                 /* arguments used by some actions */
 };
 
index 13a72c45fe58b3236547223ce2ce979aa0413721..7fc2dce2b09420809fc77049d487e32a237392d2 100644 (file)
@@ -3104,6 +3104,9 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session
                case HTTP_REQ_ACT_AUTH:
                        return rule;
 
+               case HTTP_REQ_ACT_REDIR:
+                       return rule;
+
                case HTTP_REQ_ACT_SET_HDR:
                        ctx.idx = 0;
                        /* remove all occurrences of the header */
@@ -3552,6 +3555,13 @@ int http_process_req_common(struct session *s, struct channel *req, int an_bit,
                        goto return_bad_req;
        }
 
+       if (http_req_last_rule && http_req_last_rule->action == HTTP_REQ_ACT_REDIR) {
+               if (!http_apply_redirect_rule(http_req_last_rule->arg.redir, s, txn))
+                       goto return_bad_req;
+               req->analyse_exp = TICK_ETERNITY;
+               return 1;
+       }
+
        if (unlikely(do_stats)) {
                /* process the stats request now */
                if (!http_handle_stats(s, req)) {
@@ -8040,7 +8050,7 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
        rule = (struct http_req_rule*)calloc(1, sizeof(struct http_req_rule));
        if (!rule) {
                Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
-               return NULL;
+               goto out_err;
        }
 
        if (!strcmp(args[0], "allow")) {
@@ -8068,7 +8078,7 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
                if (!*args[cur_arg] || !*args[cur_arg+1] || *args[cur_arg+2]) {
                        Alert("parsing [%s:%d]: 'http-request %s' expects exactly 2 arguments.\n",
                              file, linenum, args[0]);
-                       return NULL;
+                       goto out_err;
                }
 
                rule->arg.hdr_add.name = strdup(args[cur_arg]);
@@ -8076,10 +8086,29 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
                LIST_INIT(&rule->arg.hdr_add.fmt);
                parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.hdr_add.fmt, PR_MODE_HTTP);
                cur_arg += 2;
+       } else if (strcmp(args[0], "redirect") == 0) {
+               struct redirect_rule *redir;
+               char *errmsg;
+
+               if ((redir = http_parse_redirect_rule(file, linenum, proxy, (const char **)args + 1, &errmsg)) == NULL) {
+                       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);
+                       goto out_err;
+               }
+
+               /* this redirect rule might already contain a parsed condition which
+                * we'll pass to the http-request rule.
+                */
+               rule->action = HTTP_REQ_ACT_REDIR;
+               rule->arg.redir = redir;
+               rule->cond = redir->cond;
+               redir->cond = NULL;
+               cur_arg = 2;
+               return rule;
        } else {
                Alert("parsing [%s:%d]: 'http-request' expects 'allow', 'deny', 'auth', 'add-header', 'set-header', but got '%s'%s.\n",
                      file, linenum, args[0], *args[0] ? "" : " (missing argument)");
-               return NULL;
+               goto out_err;
        }
 
        if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
@@ -8090,7 +8119,7 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
                        Alert("parsing [%s:%d] : error detected while parsing an 'http-request %s' condition : %s.\n",
                              file, linenum, args[0], errmsg);
                        free(errmsg);
-                       return NULL;
+                       goto out_err;
                }
                rule->cond = cond;
        }
@@ -8098,10 +8127,13 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
                Alert("parsing [%s:%d]: 'http-request %s' expects 'realm' for 'auth' or"
                      " either 'if' or 'unless' followed by a condition but found '%s'.\n",
                      file, linenum, args[0], args[cur_arg]);
-               return NULL;
+               goto out_err;
        }
 
        return rule;
+ out_err:
+       free(rule);
+       return NULL;
 }
 
 /* Parses a redirect rule. Returns the redirect rule on success or NULL on error,