Hi Russell,
On Fri, Nov 15, 2013 at 07:37:31PM -0500, Russell Geldmacher wrote:
> 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.
That seems reasonably low impact, yes. However your patch was mangled,
all spaces and tabs used for indenting were removed by your mail agent
as you can see below. So I have just cherry-picked it again and it's
now OK.
Regards,
Willy
> ---------------------
>
> 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;