Hi everyone,

Recently we've had a requirement come through that could be
implemented quite nicely using 1.5-dev's 'redirect scheme'
functionality. However, (understandably) policies prevent us from
running a dev version in production.

I found the original patch that Willy posted for this functionality
(http://marc.info/?l=haproxy&m=134743247117173) and adjusted it so
that it applies and runs under 1.4.24.

Not sure if you guys accept backport patches but I just wanted to get
this out there in case other folks were searching for the same thing.

Thanks again for HAProxy -- it is one amazing piece of software, and
we couldn't get by without it!

rusty

---------------------

diff -urb haproxy-1.4.24/doc/configuration.txt
haproxy-1.4.24-scheme/doc/configuration.txt
--- a/doc/configuration.txt 2013-06-17 09:28:14.000000000 -0400
+++ b/doc/configuration.txt 2013-11-15 19:15:58.000000000 -0500
@@ -4039,8 +4039,9 @@
   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
@@ -4049,14 +4050,25 @@
   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, 303, 307 and 308 are supported,
diff -urb haproxy-1.4.24/include/types/proto_http.h
haproxy-1.4.24-scheme/include/types/proto_http.h
--- a/include/types/proto_http.h 2013-06-17 09:28:14.000000000 -0400
+++ b/include/types/proto_http.h 2013-11-15 19:11:48.000000000 -0500
@@ -224,6 +224,7 @@
  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) */
diff -urb haproxy-1.4.24/src/cfgparse.c haproxy-1.4.24-scheme/src/cfgparse.c
--- a/src/cfgparse.c 2013-06-17 09:28:14.000000000 -0400
+++ b/src/cfgparse.c 2013-11-15 19:19:10.000000000 -0500
@@ -2182,6 +2182,18 @@
  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",
@@ -2240,7 +2252,7 @@
  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;
diff -urb haproxy-1.4.24/src/proto_http.c haproxy-1.4.24-scheme/src/proto_http.c
--- a/src/proto_http.c 2013-06-17 09:28:14.000000000 -0400
+++ b/src/proto_http.c 2013-11-15 19:11:48.000000000 -0500
@@ -3390,6 +3390,71 @@
  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, msg->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 + (txn->req.sol + 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;

Reply via email to