]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: http: add "redirect scheme" to ease HTTP to HTTPS redirection
authorWilly Tarreau <w@1wt.eu>
Wed, 12 Sep 2012 06:43:15 +0000 (08:43 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 12 Sep 2012 06:43:15 +0000 (08:43 +0200)
For instance :

   redirect scheme https if !{ is_ssl }

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

index b7aa6907f347fa92849c16240f6b47daba084448..7be333505f057e94ffa287ac6d492c932b43cd78 100644 (file)
@@ -4393,8 +4393,9 @@ rate-limit sessions <rate>
   See also : the "backlog" keyword and the "fe_sess_rate" ACL criterion.
 
 
-redirect location <to> [code <code>] <option> [{if | unless} <condition>]
-redirect prefix   <to> [code <code>] <option> [{if | unless} <condition>]
+redirect location <loc> [code <code>] <option> [{if | unless} <condition>]
+redirect prefix   <pfx> [code <code>] <option> [{if | unless} <condition>]
+redirect scheme   <sch> [code <code>] <option> [{if | unless} <condition>]
   Return an HTTP redirection if/unless a condition is matched
   May be used in sections :   defaults | frontend | listen | backend
                                  no    |    yes   |   yes  |   yes
@@ -4403,14 +4404,25 @@ redirect prefix   <to> [code <code>] <option> [{if | unless} <condition>]
   response. If no condition is specified, the redirect applies unconditionally.
 
   Arguments :
-    <to>      With "redirect location", the exact value in <to> is placed into
-              the HTTP "Location" header. In case of "redirect prefix", the
-              "Location" header is built from the concatenation of <to> and the
-              complete URI, including the query string, unless the "drop-query"
-              option is specified (see below). As a special case, if <to>
-              equals exactly "/" in prefix mode, then nothing is inserted
-              before the original URI. It allows one to redirect to the same
-              URL.
+    <loc>     With "redirect location", the exact value in <loc> is placed into
+              the HTTP "Location" header.
+
+    <pfx>     With "redirect prefix", the "Location" header is built from the
+              concatenation of <pfx> and the complete URI path, including the
+              query string, unless the "drop-query" option is specified (see
+              below). As a special case, if <pfx> equals exactly "/", then
+              nothing is inserted before the original URI. It allows one to
+              redirect to the same URL (for instance, to insert a cookie).
+
+    <sch>     With "redirect scheme", then the "Location" header is built by
+              concatenating <sch> with "://" then the first occurrence of the
+              "Host" header, and then the URI path, including the query string
+              unless the "drop-query" option is specified (see below). If no
+              path is found or if the path is "*", then "/" is used instead. If
+              no "Host" header is found, then an empty host component will be
+              returned, which most recent browsers interprete as redirecting to
+              the same host. This directive is mostly used to redirect HTTP to
+              HTTPS.
 
     <code>    The code is optional. It indicates which type of HTTP redirection
               is desired. Only codes 301, 302 and 303 are supported, and 302 is
@@ -4469,6 +4481,9 @@ redirect prefix   <to> [code <code>] <option> [{if | unless} <condition>]
         acl missing_slash path_reg ^/article/[^/]*$
         redirect code 301 prefix / drop-query append-slash if missing_slash
 
+  Example: redirect all HTTP traffic to HTTPS when SSL is handled by haproxy.
+        redirect scheme https if !{ is_ssl }
+
   See section 7 about ACL usage.
 
 
index 665ec75290f0348d028e1b22779adf6be293e1b4..3e807fd1a22ebd10c6df81d2dd90e55e030af3ac 100644 (file)
@@ -204,6 +204,7 @@ enum {
        REDIRECT_TYPE_NONE = 0,         /* no redirection */
        REDIRECT_TYPE_LOCATION,         /* location redirect */
        REDIRECT_TYPE_PREFIX,           /* prefix redirect */
+       REDIRECT_TYPE_SCHEME,           /* scheme redirect (eg: switch from http to https) */
 };
 
 /* Perist types (force-persist, ignore-persist) */
index 282c128e6c7d0cbf810684b0f461de6fdc3f47bd..c91e996c8763a9b01d7b4eb0308d8d23b6b71447 100644 (file)
@@ -2837,6 +2837,18 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                                cur_arg++;
                                destination = args[cur_arg];
                        }
+                       else if (!strcmp(args[cur_arg], "scheme")) {
+                               if (!*args[cur_arg + 1]) {
+                                       Alert("parsing [%s:%d] : '%s': missing argument for '%s'.\n",
+                                             file, linenum, args[0], args[cur_arg]);
+                                       err_code |= ERR_ALERT | ERR_FATAL;
+                                       goto out;
+                               }
+
+                               type = REDIRECT_TYPE_SCHEME;
+                               cur_arg++;
+                               destination = args[cur_arg];
+                       }
                        else if (!strcmp(args[cur_arg], "set-cookie")) {
                                if (!*args[cur_arg + 1]) {
                                        Alert("parsing [%s:%d] : '%s': missing argument for '%s'.\n",
@@ -2895,7 +2907,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                                break;
                        }
                        else {
-                               Alert("parsing [%s:%d] : '%s' expects 'code', 'prefix', 'location', 'set-cookie', 'clear-cookie', 'drop-query' or 'append-slash' (was '%s').\n",
+                               Alert("parsing [%s:%d] : '%s' expects 'code', 'prefix', 'location', 'scheme', 'set-cookie', 'clear-cookie', 'drop-query' or 'append-slash' (was '%s').\n",
                                      file, linenum, args[0], args[cur_arg]);
                                err_code |= ERR_ALERT | ERR_FATAL;
                                goto out;
index d7208d28efff206dddd50564ae21ab712a0d5279..a2030f6f354dd73c9c9234360db41bd97005c6ce 100644 (file)
@@ -3072,6 +3072,71 @@ int http_process_req_common(struct session *s, struct channel *req, int an_bit,
                                goto return_bad_req;
 
                        switch(rule->type) {
+                       case REDIRECT_TYPE_SCHEME: {
+                               const char *path;
+                               const char *host;
+                               struct hdr_ctx ctx;
+                               int pathlen;
+                               int hostlen;
+
+                               host = "";
+                               hostlen = 0;
+                               ctx.idx = 0;
+                               if (http_find_header2("Host", 4, txn->req.buf->buf.p + txn->req.sol, &txn->hdr_idx, &ctx)) {
+                                       host = ctx.line + ctx.val;
+                                       hostlen = ctx.vlen;
+                               }
+
+                               path = http_get_path(txn);
+                               /* build message using path */
+                               if (path) {
+                                       pathlen = txn->req.sl.rq.u_l + (req->buf.p + txn->req.sl.rq.u) - path;
+                                       if (rule->flags & REDIRECT_FLAG_DROP_QS) {
+                                               int qs = 0;
+                                               while (qs < pathlen) {
+                                                       if (path[qs] == '?') {
+                                                               pathlen = qs;
+                                                               break;
+                                                       }
+                                                       qs++;
+                                               }
+                                       }
+                               } else {
+                                       path = "/";
+                                       pathlen = 1;
+                               }
+
+                               /* check if we can add scheme + "://" + host + path */
+                               if (rdr.len + rule->rdr_len + 3 + hostlen + pathlen > rdr.size - 4)
+                                       goto return_bad_req;
+
+                               /* add scheme */
+                               memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
+                               rdr.len += rule->rdr_len;
+
+                               /* add "://" */
+                               memcpy(rdr.str + rdr.len, "://", 3);
+                               rdr.len += 3;
+
+                               /* add host */
+                               memcpy(rdr.str + rdr.len, host, hostlen);
+                               rdr.len += hostlen;
+
+                               /* add path */
+                               memcpy(rdr.str + rdr.len, path, pathlen);
+                               rdr.len += pathlen;
+
+                               /* append a slash at the end of the location is needed and missing */
+                               if (rdr.len && rdr.str[rdr.len - 1] != '/' &&
+                                   (rule->flags & REDIRECT_FLAG_APPEND_SLASH)) {
+                                       if (rdr.len > rdr.size - 5)
+                                               goto return_bad_req;
+                                       rdr.str[rdr.len] = '/';
+                                       rdr.len++;
+                               }
+
+                               break;
+                       }
                        case REDIRECT_TYPE_PREFIX: {
                                const char *path;
                                int pathlen;