53863c53dde5987b1e7384a8b4ab1f3736be04bc
[packages.git] / net / haproxy / patches / 0010-MEDIUM-http-add-redirect-scheme-to-ease-HTTP-to-HTTP.patch
1 From eb9632f7c6ae675bdee4c82eb0d298ba7f37fc52 Mon Sep 17 00:00:00 2001
2 From: Willy Tarreau <w@1wt.eu>
3 Date: Wed, 12 Sep 2012 08:43:15 +0200
4 Subject: [PATCH 10/10] MEDIUM: http: add "redirect scheme" to ease HTTP to
5  HTTPS redirection
6
7 For instance :
8
9    redirect scheme https if !{ is_ssl }
10
11 Backport-suggested-by: Russell Geldmacher <russell.geldmacher@gmail.com>
12 (cherry picked from commit 2e1dca8f5238155cbc52d37316fe858c4f61cf34)
13 ---
14  doc/configuration.txt      | 35 ++++++++++++++++++-------
15  include/types/proto_http.h |  1 +
16  src/cfgparse.c             | 14 +++++++++-
17  src/proto_http.c           | 65 ++++++++++++++++++++++++++++++++++++++++++++++
18  4 files changed, 104 insertions(+), 11 deletions(-)
19
20 diff --git a/doc/configuration.txt b/doc/configuration.txt
21 index 56438dd..f2043a1 100644
22 --- a/doc/configuration.txt
23 +++ b/doc/configuration.txt
24 @@ -4039,8 +4039,9 @@ rate-limit sessions <rate>
25    See also : the "backlog" keyword and the "fe_sess_rate" ACL criterion.
26  
27  
28 -redirect location <to> [code <code>] <option> [{if | unless} <condition>]
29 -redirect prefix   <to> [code <code>] <option> [{if | unless} <condition>]
30 +redirect location <loc> [code <code>] <option> [{if | unless} <condition>]
31 +redirect prefix   <pfx> [code <code>] <option> [{if | unless} <condition>]
32 +redirect scheme   <sch> [code <code>] <option> [{if | unless} <condition>]
33    Return an HTTP redirection if/unless a condition is matched
34    May be used in sections :   defaults | frontend | listen | backend
35                                   no    |    yes   |   yes  |   yes
36 @@ -4049,14 +4050,25 @@ redirect prefix   <to> [code <code>] <option> [{if | unless} <condition>]
37    response. If no condition is specified, the redirect applies unconditionally.
38  
39    Arguments :
40 -    <to>      With "redirect location", the exact value in <to> is placed into
41 -              the HTTP "Location" header. In case of "redirect prefix", the
42 -              "Location" header is built from the concatenation of <to> and the
43 -              complete URI, including the query string, unless the "drop-query"
44 -              option is specified (see below). As a special case, if <to>
45 -              equals exactly "/" in prefix mode, then nothing is inserted
46 -              before the original URI. It allows one to redirect to the same
47 -              URL.
48 +    <loc>     With "redirect location", the exact value in <loc> is placed into
49 +              the HTTP "Location" header.
50 +
51 +    <pfx>     With "redirect prefix", the "Location" header is built from the
52 +              concatenation of <pfx> and the complete URI path, including the
53 +              query string, unless the "drop-query" option is specified (see
54 +              below). As a special case, if <pfx> equals exactly "/", then
55 +              nothing is inserted before the original URI. It allows one to
56 +              redirect to the same URL (for instance, to insert a cookie).
57 +
58 +    <sch>     With "redirect scheme", then the "Location" header is built by
59 +              concatenating <sch> with "://" then the first occurrence of the
60 +              "Host" header, and then the URI path, including the query string
61 +              unless the "drop-query" option is specified (see below). If no
62 +              path is found or if the path is "*", then "/" is used instead. If
63 +              no "Host" header is found, then an empty host component will be
64 +              returned, which most recent browsers interprete as redirecting to
65 +              the same host. This directive is mostly used to redirect HTTP to
66 +              HTTPS.
67  
68      <code>    The code is optional. It indicates which type of HTTP redirection
69                is desired. Only codes 301, 302, 303, 307 and 308 are supported,
70 @@ -4117,6 +4129,9 @@ redirect prefix   <to> [code <code>] <option> [{if | unless} <condition>]
71          acl missing_slash path_reg ^/article/[^/]*$
72          redirect code 301 prefix / drop-query append-slash if missing_slash
73  
74 +  Example: redirect all HTTP traffic to HTTPS when SSL is handled by haproxy.
75 +        redirect scheme https if !{ is_ssl }
76 +
77    See section 7 about ACL usage.
78  
79  
80 diff --git a/include/types/proto_http.h b/include/types/proto_http.h
81 index 09d4dd8..0e2b14f 100644
82 --- a/include/types/proto_http.h
83 +++ b/include/types/proto_http.h
84 @@ -224,6 +224,7 @@ enum {
85         REDIRECT_TYPE_NONE = 0,         /* no redirection */
86         REDIRECT_TYPE_LOCATION,         /* location redirect */
87         REDIRECT_TYPE_PREFIX,           /* prefix redirect */
88 +       REDIRECT_TYPE_SCHEME,           /* scheme redirect (eg: switch from http to https) */
89  };
90  
91  /* Perist types (force-persist, ignore-persist) */
92 diff --git a/src/cfgparse.c b/src/cfgparse.c
93 index cecec03..09ffcd3 100644
94 --- a/src/cfgparse.c
95 +++ b/src/cfgparse.c
96 @@ -2182,6 +2182,18 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
97                                 cur_arg++;
98                                 destination = args[cur_arg];
99                         }
100 +                       else if (!strcmp(args[cur_arg], "scheme")) {
101 +                               if (!*args[cur_arg + 1]) {
102 +                                       Alert("parsing [%s:%d] : '%s': missing argument for '%s'.\n",
103 +                                             file, linenum, args[0], args[cur_arg]);
104 +                                       err_code |= ERR_ALERT | ERR_FATAL;
105 +                                       goto out;
106 +                               }
107 +
108 +                               type = REDIRECT_TYPE_SCHEME;
109 +                               cur_arg++;
110 +                               destination = args[cur_arg];
111 +                       }
112                         else if (!strcmp(args[cur_arg], "set-cookie")) {
113                                 if (!*args[cur_arg + 1]) {
114                                         Alert("parsing [%s:%d] : '%s': missing argument for '%s'.\n",
115 @@ -2240,7 +2252,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
116                                 break;
117                         }
118                         else {
119 -                               Alert("parsing [%s:%d] : '%s' expects 'code', 'prefix', 'location', 'set-cookie', 'clear-cookie', 'drop-query' or 'append-slash' (was '%s').\n",
120 +                               Alert("parsing [%s:%d] : '%s' expects 'code', 'prefix', 'location', 'scheme', 'set-cookie', 'clear-cookie', 'drop-query' or 'append-slash' (was '%s').\n",
121                                       file, linenum, args[0], args[cur_arg]);
122                                 err_code |= ERR_ALERT | ERR_FATAL;
123                                 goto out;
124 diff --git a/src/proto_http.c b/src/proto_http.c
125 index 7fd1fe6..ed35795 100644
126 --- a/src/proto_http.c
127 +++ b/src/proto_http.c
128 @@ -3390,6 +3390,71 @@ int http_process_req_common(struct session *s, struct buffer *req, int an_bit, s
129                                 goto return_bad_req;
130  
131                         switch(rule->type) {
132 +                       case REDIRECT_TYPE_SCHEME: {
133 +                               const char *path;
134 +                               const char *host;
135 +                               struct hdr_ctx ctx;
136 +                               int pathlen;
137 +                               int hostlen;
138 +
139 +                               host = "";
140 +                               hostlen = 0;
141 +                               ctx.idx = 0;
142 +                               if (http_find_header2("Host", 4, msg->sol, &txn->hdr_idx, &ctx)) {
143 +                                       host = ctx.line + ctx.val;
144 +                                       hostlen = ctx.vlen;
145 +                               }
146 +
147 +                               path = http_get_path(txn);
148 +                               /* build message using path */
149 +                               if (path) {
150 +                                       pathlen = txn->req.sl.rq.u_l + (txn->req.sol + txn->req.sl.rq.u) - path;
151 +                                       if (rule->flags & REDIRECT_FLAG_DROP_QS) {
152 +                                               int qs = 0;
153 +                                               while (qs < pathlen) {
154 +                                                       if (path[qs] == '?') {
155 +                                                               pathlen = qs;
156 +                                                               break;
157 +                                                       }
158 +                                                       qs++;
159 +                                               }
160 +                                       }
161 +                               } else {
162 +                                       path = "/";
163 +                                       pathlen = 1;
164 +                               }
165 +
166 +                               /* check if we can add scheme + "://" + host + path */
167 +                               if (rdr.len + rule->rdr_len + 3 + hostlen + pathlen > rdr.size - 4)
168 +                                       goto return_bad_req;
169 +
170 +                               /* add scheme */
171 +                               memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
172 +                               rdr.len += rule->rdr_len;
173 +
174 +                               /* add "://" */
175 +                               memcpy(rdr.str + rdr.len, "://", 3);
176 +                               rdr.len += 3;
177 +
178 +                               /* add host */
179 +                               memcpy(rdr.str + rdr.len, host, hostlen);
180 +                               rdr.len += hostlen;
181 +
182 +                               /* add path */
183 +                               memcpy(rdr.str + rdr.len, path, pathlen);
184 +                               rdr.len += pathlen;
185 +
186 +                               /* append a slash at the end of the location is needed and missing */
187 +                               if (rdr.len && rdr.str[rdr.len - 1] != '/' &&
188 +                                   (rule->flags & REDIRECT_FLAG_APPEND_SLASH)) {
189 +                                       if (rdr.len > rdr.size - 5)
190 +                                               goto return_bad_req;
191 +                                       rdr.str[rdr.len] = '/';
192 +                                       rdr.len++;
193 +                               }
194 +
195 +                               break;
196 +                       }
197                         case REDIRECT_TYPE_PREFIX: {
198                                 const char *path;
199                                 int pathlen;
200 -- 
201 1.8.1.5
202