]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: http-ana: Add option to keep query-string on a localtion-based redirect
authorChristopher Faulet <cfaulet@haproxy.com>
Fri, 15 Nov 2024 16:03:06 +0000 (17:03 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Tue, 19 Nov 2024 14:20:02 +0000 (15:20 +0100)
On prefix-based redirect, there is an option to drop the query-string of the
location. Here it is the opposite. an option is added to preserve the
query-string of the original URI for a localtion-based redirect.

By setting "keep-query" option, for a location-based redirect only, the
query-string of the original URI is appended to the location. If there is no
query-string, nothing is added (no empty '?'). If there is already a
non-empty query-string on the localtion, the original one is appended with
'&' separator.

This patch should fix issue #2728.

doc/configuration.txt
include/haproxy/http_ana-t.h
src/http_ana.c
src/http_rules.c

index bca9974aeef70c9a384eac56c323ae04636d6e00..9bd5d45aefc1580331ac09e725e8bb87223cff44 100644 (file)
@@ -11461,6 +11461,14 @@ redirect scheme   <sch> [code <code>] <option> [{if | unless} <condition>]
         cookie set with "NAME=value". You have to clear the cookie "NAME=" for
         that, because the browser makes the difference.
 
+      - "keep-query"
+        When this keyword is used in a location-based redirection, then the
+        query-string of the original URI, if any, will be appended to the
+        location. If no query-string is found, nothing is added. If the
+        location already contains a query-string, the original one will be
+        appended with the '&' delimiter.
+
+
   Example: move the login URL only to HTTPS.
         acl clear      dst_port  80
         acl secure     dst_port  8080
index f43aa3258941ec63378788eb26c63ece31abc9fc..2010aa045b48e7b68b0adf3ebb6601899f29344f 100644 (file)
@@ -167,6 +167,7 @@ enum {
        REDIRECT_FLAG_APPEND_SLASH = 2, /* append a slash if missing at the end */
        REDIRECT_FLAG_FROM_REQ = 4,     /* redirect rule on the request path */
        REDIRECT_FLAG_IGNORE_EMPTY = 8, /* silently ignore empty location expressions */
+       REDIRECT_FLAG_KEEP_QS = 16,     /* append the query string to location, if any */
 };
 
 /* Redirect types (location, prefix, extended ) */
index ca05a146f1cfe90aae1aa3924f712fd1d88803ed..fea5f1f9a88a8c02cdf9d19275f5303d16a0ab8c 100644 (file)
@@ -2420,6 +2420,7 @@ int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struc
                }
                case REDIRECT_TYPE_LOCATION:
                default:
+                       memset(chunk->area, 0x50, chunk->size);
                        if (rule->rdr_str) { /* this is an old "redirect" rule */
                                /* add location */
                                if (!chunk_memcat(chunk, rule->rdr_str, rule->rdr_len))
@@ -2437,6 +2438,36 @@ int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struc
 
                                chunk->data += len;
                        }
+
+                       if (rule->flags & REDIRECT_FLAG_KEEP_QS) {
+                               struct ist path;
+                               struct http_uri_parser parser;
+                               char *ptr, *end;
+                               char sep = '?';
+
+                               ptr = memchr(chunk->area, '?', chunk->data);
+                               if (ptr != NULL)
+                                       sep = ((ptr+1 != b_tail(chunk)) ? '&' : '\0');
+
+                               sl = http_get_stline(htx);
+                               parser = http_uri_parser_init(htx_sl_req_uri(sl));
+                               path = http_parse_path(&parser);
+                               ptr = istptr(path);
+                               end = istend(path);
+
+                               /* look up the '?' */
+                               do {
+                                       if (ptr == end)
+                                               return 0;
+                               } while (*ptr++ != '?');
+
+                               if (ptr == end)
+                                       break;
+                               if (sep != '\0' && !chunk_memcat(chunk, &sep, 1))
+                                       goto fail;
+                               if (!chunk_memcat(chunk, ptr, end-ptr))
+                                       goto fail;
+                       }
                        break;
        }
        location = ist2(chunk->area, chunk->data);
index 6ceacdf7eec64551bb746fa0695f622dfa6c6fc6..86df4cf435817efab71f8f2ab9b40b0476ebf22e 100644 (file)
@@ -402,6 +402,9 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
                else if (strcmp(args[cur_arg], "drop-query") == 0) {
                        flags |= REDIRECT_FLAG_DROP_QS;
                }
+               else if (strcmp(args[cur_arg], "keep-query") == 0) {
+                       flags |= REDIRECT_FLAG_KEEP_QS;
+               }
                else if (strcmp(args[cur_arg], "append-slash") == 0) {
                        flags |= REDIRECT_FLAG_APPEND_SLASH;
                }
@@ -419,7 +422,7 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
                }
                else {
                        memprintf(errmsg,
-                                 "expects 'code', 'prefix', 'location', 'scheme', 'set-cookie', 'clear-cookie', 'drop-query', 'ignore-empty' or 'append-slash' (was '%s')",
+                                 "expects 'code', 'prefix', 'location', 'scheme', 'set-cookie', 'clear-cookie', 'drop-query', 'keep-query', 'ignore-empty' or 'append-slash' (was '%s')",
                                  args[cur_arg]);
                        goto err;
                }