haproxy: patches from upstream
authorThomas Heil <heil@terminal-consulting.de>
Wed, 17 Sep 2014 10:13:12 +0000 (12:13 +0200)
committerThomas Heil <heil@terminal-consulting.de>
Wed, 17 Sep 2014 10:13:12 +0000 (12:13 +0200)
- [PATCH 01/13] DOC: clearly state that the "show sess" output format
- [PATCH 02/13] MINOR: stats: fix minor typo fix in
- [PATCH 03/13] MEDIUM: Improve signal handling in systemd wrapper.
- [PATCH 04/13] MINOR: Also accept SIGHUP/SIGTERM in systemd-wrapper
- [PATCH 05/13] DOC: indicate in the doc that track-sc* can wait if
- [PATCH 06/13] MEDIUM: http: enable header manipulation for 101
- [PATCH 07/13] BUG/MEDIUM: config: propagate frontend to backend
- [PATCH 08/13] MEDIUM: config: properly propagate process binding
- [PATCH 09/13] MEDIUM: config: make the frontends automatically bind
- [PATCH 10/13] MEDIUM: config: compute the exact bind-process before
- [PATCH 11/13] MEDIUM: config: only warn if stats are attached to
- [PATCH 12/13] MEDIUM: config: report it when tcp-request rules are
- [PATCH 13/13] MINOR: config: detect the case where a tcp-request

Signed-off-by: Thomas Heil <heil@terminal-consulting.de>
14 files changed:
net/haproxy/Makefile
net/haproxy/patches/0001-DOC-clearly-state-that-the-show-sess-output-format-i.patch [new file with mode: 0644]
net/haproxy/patches/0002-MINOR-stats-fix-minor-typo-fix-in-stats_dump_errors_.patch [new file with mode: 0644]
net/haproxy/patches/0003-MEDIUM-Improve-signal-handling-in-systemd-wrapper.patch [new file with mode: 0644]
net/haproxy/patches/0004-MINOR-Also-accept-SIGHUP-SIGTERM-in-systemd-wrapper.patch [new file with mode: 0644]
net/haproxy/patches/0005-DOC-indicate-in-the-doc-that-track-sc-can-wait-if-da.patch [new file with mode: 0644]
net/haproxy/patches/0006-MEDIUM-http-enable-header-manipulation-for-101-respo.patch [new file with mode: 0644]
net/haproxy/patches/0007-BUG-MEDIUM-config-propagate-frontend-to-backend-proc.patch [new file with mode: 0644]
net/haproxy/patches/0008-MEDIUM-config-properly-propagate-process-binding-bet.patch [new file with mode: 0644]
net/haproxy/patches/0009-MEDIUM-config-make-the-frontends-automatically-bind-.patch [new file with mode: 0644]
net/haproxy/patches/0010-MEDIUM-config-compute-the-exact-bind-process-before-.patch [new file with mode: 0644]
net/haproxy/patches/0011-MEDIUM-config-only-warn-if-stats-are-attached-to-mul.patch [new file with mode: 0644]
net/haproxy/patches/0012-MEDIUM-config-report-it-when-tcp-request-rules-are-m.patch [new file with mode: 0644]
net/haproxy/patches/0013-MINOR-config-detect-the-case-where-a-tcp-request-con.patch [new file with mode: 0644]

index b0f81ef3849b79550019e842167e3d7afe341bd8..8ef49f8b443b62bc7a84d658487b5dfd1c183846 100644 (file)
@@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=haproxy
 PKG_VERSION:=1.5.4
-PKG_RELEASE:=01
+PKG_RELEASE:=13
 PKG_SOURCE:=haproxy-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=http://haproxy.1wt.eu/download/1.5/src/
 PKG_MD5SUM:=b027035bfd8f28326634f802c3447a34
diff --git a/net/haproxy/patches/0001-DOC-clearly-state-that-the-show-sess-output-format-i.patch b/net/haproxy/patches/0001-DOC-clearly-state-that-the-show-sess-output-format-i.patch
new file mode 100644 (file)
index 0000000..ff17cb7
--- /dev/null
@@ -0,0 +1,35 @@
+From e99d44d4bc3423b721c7f654fd1778b9822a94e3 Mon Sep 17 00:00:00 2001
+From: Olivier <webmaster@ajeux.com>
+Date: Fri, 5 Sep 2014 18:49:10 +0200
+Subject: [PATCH 01/13] DOC: clearly state that the "show sess" output format
+ is not fixed
+
+It requires to look at the code (src/dumpstats.c) since the format may
+change at any moment.
+(cherry picked from commit ce31e6e3baebe75a2e6f6b5c66553db8d76dff0c)
+---
+ doc/configuration.txt | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/doc/configuration.txt b/doc/configuration.txt
+index 19df5ae..1ecf15a 100644
+--- a/doc/configuration.txt
++++ b/doc/configuration.txt
+@@ -13734,9 +13734,11 @@ show sess <id>
+   of "show sess" (it corresponds to the session pointer). Those information are
+   useless to most users but may be used by haproxy developers to troubleshoot a
+   complex bug. The output format is intentionally not documented so that it can
+-  freely evolve depending on demands. The special id "all" dumps the states of
+-  all sessions, which can be avoided as much as possible as it is highly CPU
+-  intensive and can take a lot of time.
++  freely evolve depending on demands. You may find a description of all fields
++  returned in src/dumpstats.c
++
++  The special id "all" dumps the states of all sessions, which must be avoided
++  as much as possible as it is highly CPU intensive and can take a lot of time.
+ show stat [<iid> <type> <sid>]
+   Dump statistics in the CSV format. By passing <id>, <type> and <sid>, it is
+-- 
+1.8.5.5
+
diff --git a/net/haproxy/patches/0002-MINOR-stats-fix-minor-typo-fix-in-stats_dump_errors_.patch b/net/haproxy/patches/0002-MINOR-stats-fix-minor-typo-fix-in-stats_dump_errors_.patch
new file mode 100644 (file)
index 0000000..47542d2
--- /dev/null
@@ -0,0 +1,28 @@
+From 815d7d5c348575181874429b93b0ebdb0cf873c2 Mon Sep 17 00:00:00 2001
+From: Olivier Doucet <webmaster@ajeux.com>
+Date: Mon, 8 Sep 2014 11:23:00 +0200
+Subject: [PATCH 02/13] MINOR: stats: fix minor typo fix in
+ stats_dump_errors_to_buffer()
+
+Remove the space before the colon to match the format used in the frontend.
+(cherry picked from commit 08afdcb47bc39c071787f8fc2066776e1c5e8607)
+---
+ src/dumpstats.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/dumpstats.c b/src/dumpstats.c
+index 5365042..09bc7f6 100644
+--- a/src/dumpstats.c
++++ b/src/dumpstats.c
+@@ -6045,7 +6045,7 @@ static int stats_dump_errors_to_buffer(struct stream_interface *si)
+                               break;
+                       case 1:
+                               chunk_appendf(&trash,
+-                                           " backend %s (#%d) : invalid response\n"
++                                           " backend %s (#%d): invalid response\n"
+                                            "  frontend %s (#%d)",
+                                            appctx->ctx.errors.px->id, appctx->ctx.errors.px->uuid,
+                                            es->oe->id, es->oe->uuid);
+-- 
+1.8.5.5
+
diff --git a/net/haproxy/patches/0003-MEDIUM-Improve-signal-handling-in-systemd-wrapper.patch b/net/haproxy/patches/0003-MEDIUM-Improve-signal-handling-in-systemd-wrapper.patch
new file mode 100644 (file)
index 0000000..b745406
--- /dev/null
@@ -0,0 +1,105 @@
+From 62c8565cd5bbda6ac0dd818fa26922eeaef1605c Mon Sep 17 00:00:00 2001
+From: Conrad Hoffmann <conrad@soundcloud.com>
+Date: Mon, 28 Jul 2014 23:52:20 +0200
+Subject: [PATCH 03/13] MEDIUM: Improve signal handling in systemd wrapper.
+
+Move all code out of the signal handlers, since this is potentially
+dangerous. To make sure the signal handlers behave as expected, use
+sigaction() instead of signal(). That also obsoletes messing with
+the signal mask after restart.
+
+Signed-off-by: Conrad Hoffmann <conrad@soundcloud.com>
+(cherry picked from commit 5b5ea9c93384da49eea0f67ebed0966d4167b17a)
+---
+ src/haproxy-systemd-wrapper.c | 37 ++++++++++++++++++++++++-------------
+ 1 file changed, 24 insertions(+), 13 deletions(-)
+
+diff --git a/src/haproxy-systemd-wrapper.c b/src/haproxy-systemd-wrapper.c
+index 529b213..90a94ce 100644
+--- a/src/haproxy-systemd-wrapper.c
++++ b/src/haproxy-systemd-wrapper.c
+@@ -22,6 +22,8 @@
+ #define SD_DEBUG "<7>"
+ #define SD_NOTICE "<5>"
++static volatile sig_atomic_t caught_signal;
++
+ static char *pid_file = "/run/haproxy.pid";
+ static int wrapper_argc;
+ static char **wrapper_argv;
+@@ -103,7 +105,12 @@ static int read_pids(char ***pid_strv)
+       return read;
+ }
+-static void sigusr2_handler(int signum __attribute__((unused)))
++static void signal_handler(int signum)
++{
++      caught_signal = signum;
++}
++
++static void do_restart(void)
+ {
+       setenv(REEXEC_FLAG, "1", 1);
+       fprintf(stderr, SD_NOTICE "haproxy-systemd-wrapper: re-executing\n");
+@@ -111,7 +118,7 @@ static void sigusr2_handler(int signum __attribute__((unused)))
+       execv(wrapper_argv[0], wrapper_argv);
+ }
+-static void sigint_handler(int signum __attribute__((unused)))
++static void do_shutdown(void)
+ {
+       int i, pid;
+       char **pid_strv = NULL;
+@@ -147,25 +154,21 @@ int main(int argc, char **argv)
+       --argc; ++argv;
+       init(argc, argv);
+-      signal(SIGINT, &sigint_handler);
+-      signal(SIGUSR2, &sigusr2_handler);
++      struct sigaction sa;
++      memset(&sa, 0, sizeof(struct sigaction));
++      sa.sa_handler = &signal_handler;
++      sigaction(SIGUSR2, &sa, NULL);
++      sigaction(SIGINT, &sa, NULL);
+       if (getenv(REEXEC_FLAG) != NULL) {
+               /* We are being re-executed: restart HAProxy gracefully */
+               int i;
+               char **pid_strv = NULL;
+               int nb_pid = read_pids(&pid_strv);
+-              sigset_t sigs;
+               unsetenv(REEXEC_FLAG);
+               spawn_haproxy(pid_strv, nb_pid);
+-              /* Unblock SIGUSR2 which was blocked by the signal handler
+-               * before re-exec */
+-              sigprocmask(SIG_BLOCK, NULL, &sigs);
+-              sigdelset(&sigs, SIGUSR2);
+-              sigprocmask(SIG_SETMASK, &sigs, NULL);
+-
+               for (i = 0; i < nb_pid; ++i)
+                       free(pid_strv[i]);
+               free(pid_strv);
+@@ -176,8 +179,16 @@ int main(int argc, char **argv)
+       }
+       status = -1;
+-      while (-1 != wait(&status) || errno == EINTR)
+-              ;
++      while (-1 != wait(&status) || errno == EINTR) {
++              if (caught_signal == SIGUSR2) {
++                      caught_signal = 0;
++                      do_restart();
++              }
++              else if (caught_signal == SIGINT) {
++                      caught_signal = 0;
++                      do_shutdown();
++              }
++      }
+       fprintf(stderr, SD_NOTICE "haproxy-systemd-wrapper: exit, haproxy RC=%d\n",
+                       status);
+-- 
+1.8.5.5
+
diff --git a/net/haproxy/patches/0004-MINOR-Also-accept-SIGHUP-SIGTERM-in-systemd-wrapper.patch b/net/haproxy/patches/0004-MINOR-Also-accept-SIGHUP-SIGTERM-in-systemd-wrapper.patch
new file mode 100644 (file)
index 0000000..bbda7d8
--- /dev/null
@@ -0,0 +1,48 @@
+From 6bb7bf7949dd019403b65f400c4b3d0d8589327b Mon Sep 17 00:00:00 2001
+From: Matt Robenolt <matt@ydekproductions.com>
+Date: Thu, 11 Sep 2014 05:19:30 +0000
+Subject: [PATCH 04/13] MINOR: Also accept SIGHUP/SIGTERM in systemd-wrapper
+
+My proposal is to let haproxy-systemd-wrapper also accept normal
+SIGHUP/SIGTERM signals to play nicely with other process managers
+besides just systemd. In my use case, this will be for using with
+runit which has to ability to change the signal used for a
+"reload" or "stop" command. It also might be worth renaming this
+bin to just haproxy-wrapper or something of that sort to separate
+itself away from systemd. But that's a different discussion. :)
+(cherry picked from commit c54bdd2a118161b4dc36963b4201edfa7341dadb)
+---
+ src/haproxy-systemd-wrapper.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/haproxy-systemd-wrapper.c b/src/haproxy-systemd-wrapper.c
+index 90a94ce..cc8baa8 100644
+--- a/src/haproxy-systemd-wrapper.c
++++ b/src/haproxy-systemd-wrapper.c
+@@ -158,7 +158,9 @@ int main(int argc, char **argv)
+       memset(&sa, 0, sizeof(struct sigaction));
+       sa.sa_handler = &signal_handler;
+       sigaction(SIGUSR2, &sa, NULL);
++      sigaction(SIGHUP, &sa, NULL);
+       sigaction(SIGINT, &sa, NULL);
++      sigaction(SIGTERM, &sa, NULL);
+       if (getenv(REEXEC_FLAG) != NULL) {
+               /* We are being re-executed: restart HAProxy gracefully */
+@@ -180,11 +182,11 @@ int main(int argc, char **argv)
+       status = -1;
+       while (-1 != wait(&status) || errno == EINTR) {
+-              if (caught_signal == SIGUSR2) {
++              if (caught_signal == SIGUSR2 || caught_signal == SIGHUP) {
+                       caught_signal = 0;
+                       do_restart();
+               }
+-              else if (caught_signal == SIGINT) {
++              else if (caught_signal == SIGINT || caught_signal == SIGTERM) {
+                       caught_signal = 0;
+                       do_shutdown();
+               }
+-- 
+1.8.5.5
+
diff --git a/net/haproxy/patches/0005-DOC-indicate-in-the-doc-that-track-sc-can-wait-if-da.patch b/net/haproxy/patches/0005-DOC-indicate-in-the-doc-that-track-sc-can-wait-if-da.patch
new file mode 100644 (file)
index 0000000..d34b7ca
--- /dev/null
@@ -0,0 +1,52 @@
+From 531485c08ffb15b939a28ecf47090e4c93341d1b Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 16 Sep 2014 15:48:15 +0200
+Subject: [PATCH 05/13] DOC: indicate in the doc that track-sc* can wait if
+ data are missing
+
+Since commit 1b71eb5 ("BUG/MEDIUM: counters: fix track-sc* to wait on
+unstable contents"), we don't need the "if HTTP" anymore. But the doc
+was not updated to reflect this.
+
+Since this change was backported to 1.5, this doc update should be
+backported as well.
+(cherry picked from commit 4d54c7ca0286588de5060acce9aff8aa9645bb98)
+---
+ doc/configuration.txt | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/doc/configuration.txt b/doc/configuration.txt
+index 1ecf15a..3c75c92 100644
+--- a/doc/configuration.txt
++++ b/doc/configuration.txt
+@@ -7470,9 +7470,9 @@ tcp-request content <action> [{if | unless} <condition>]
+   contents will always be immediately present when the rule is evaluated first.
+   Tracking layer7 information is also possible provided that the information
+-  are present when the rule is processed. The current solution for making the
+-  rule engine wait for such information is to set an inspect delay and to
+-  condition its execution with an ACL relying on such information.
++  are present when the rule is processed. The rule processing engine is able to
++  wait until the inspect delay expires when the data to be tracked is not yet
++  available.
+   Example:
+         # Accept HTTP requests containing a Host header saying "example.com"
+@@ -7497,12 +7497,12 @@ tcp-request content <action> [{if | unless} <condition>]
+   Example:
+         # Track the last IP from X-Forwarded-For
+         tcp-request inspect-delay 10s
+-        tcp-request content track-sc0 hdr(x-forwarded-for,-1) if HTTP
++        tcp-request content track-sc0 hdr(x-forwarded-for,-1)
+   Example:
+         # track request counts per "base" (concatenation of Host+URL)
+         tcp-request inspect-delay 10s
+-        tcp-request content track-sc0 base table req-rate if HTTP
++        tcp-request content track-sc0 base table req-rate
+   Example: track per-frontend and per-backend counters, block abusers at the
+            frontend when the backend detects abuse.
+-- 
+1.8.5.5
+
diff --git a/net/haproxy/patches/0006-MEDIUM-http-enable-header-manipulation-for-101-respo.patch b/net/haproxy/patches/0006-MEDIUM-http-enable-header-manipulation-for-101-respo.patch
new file mode 100644 (file)
index 0000000..b189db7
--- /dev/null
@@ -0,0 +1,80 @@
+From 0cb4b899d370b9d04b3457a1d75dbd658c1a1646 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 16 Sep 2014 10:40:38 +0200
+Subject: [PATCH 06/13] MEDIUM: http: enable header manipulation for 101
+ responses
+
+Ryan Brock reported that server stickiness did not work for WebSocket
+because the cookies and headers are not modified on 1xx responses. He
+found that his browser correctly presents the cookies learned on 101
+responses, which was not specifically defined in the WebSocket spec,
+nor in the cookie spec. 101 is a very special case. Being part of 1xx,
+it's an interim response. But within 1xx, it's special because it's
+the last HTTP/1 response that transits on the wire, which is different
+from 100 or 102 which may appear multiple times. So in that sense, we
+can consider it as a final response regarding HTTP/1, and it makes
+sense to allow header processing there. Note that we still ensure not
+to mangle the Connection header, which is critical for HTTP upgrade to
+continue to work smoothly with agents that are a bit picky about what
+tokens are found there.
+
+The rspadd rules are now processed for 101 responses as well, but the
+cache-control checks are not performed (since no body is delivered).
+
+Ryan confirmed that this patch works for him.
+
+It would make sense to backport it to 1.5 given that it improves end
+user experience on WebSocket servers.
+(cherry picked from commit ce730de86719d0b5079dd8b0843559e4ff0a1ecc)
+---
+ src/proto_http.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/src/proto_http.c b/src/proto_http.c
+index 4d27b2c..7e35c8b 100644
+--- a/src/proto_http.c
++++ b/src/proto_http.c
+@@ -6249,7 +6249,7 @@ int http_process_res_common(struct session *s, struct channel *rep, int an_bit,
+               /* add response headers from the rule sets in the same order */
+               list_for_each_entry(wl, &rule_set->rsp_add, list) {
+-                      if (txn->status < 200)
++                      if (txn->status < 200 && txn->status != 101)
+                               break;
+                       if (wl->cond) {
+                               int ret = acl_exec_cond(wl->cond, px, s, txn, SMP_OPT_DIR_RES|SMP_OPT_FINAL);
+@@ -6270,7 +6270,7 @@ int http_process_res_common(struct session *s, struct channel *rep, int an_bit,
+       }
+       /* OK that's all we can do for 1xx responses */
+-      if (unlikely(txn->status < 200))
++      if (unlikely(txn->status < 200 && txn->status != 101))
+               goto skip_header_mangling;
+       /*
+@@ -6283,7 +6283,7 @@ int http_process_res_common(struct session *s, struct channel *rep, int an_bit,
+       /*
+        * Check for cache-control or pragma headers if required.
+        */
+-      if ((s->be->options & PR_O_CHK_CACHE) || (s->be->ck_opts & PR_CK_NOC))
++      if (((s->be->options & PR_O_CHK_CACHE) || (s->be->ck_opts & PR_CK_NOC)) && txn->status != 101)
+               check_response_for_cacheability(s, rep);
+       /*
+@@ -6399,9 +6399,11 @@ int http_process_res_common(struct session *s, struct channel *rep, int an_bit,
+        * Adjust "Connection: close" or "Connection: keep-alive" if needed.
+        * If an "Upgrade" token is found, the header is left untouched in order
+        * not to have to deal with some client bugs : some of them fail an upgrade
+-       * if anything but "Upgrade" is present in the Connection header.
++       * if anything but "Upgrade" is present in the Connection header. We don't
++       * want to touch any 101 response either since it's switching to another
++       * protocol.
+        */
+-      if (!(txn->flags & TX_HDR_CONN_UPG) &&
++      if ((txn->status != 101) && !(txn->flags & TX_HDR_CONN_UPG) &&
+           (((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) ||
+            ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL ||
+             (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL))) {
+-- 
+1.8.5.5
+
diff --git a/net/haproxy/patches/0007-BUG-MEDIUM-config-propagate-frontend-to-backend-proc.patch b/net/haproxy/patches/0007-BUG-MEDIUM-config-propagate-frontend-to-backend-proc.patch
new file mode 100644 (file)
index 0000000..c4fe96a
--- /dev/null
@@ -0,0 +1,60 @@
+From b53934eec71ab34eb3762a89cec326360a5b0bc5 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 16 Sep 2014 11:31:31 +0200
+Subject: [PATCH 07/13] BUG/MEDIUM: config: propagate frontend to backend
+ process binding again.
+
+This basically reverts 3507d5d ("MEDIUM: proxy: only adjust the backend's
+bind-process when already set"). It was needed during the transition to
+the new process binding method but is causing trouble now because frontend
+to backend binding is not properly propagated.
+
+This fix should be backported to 1.5.
+(cherry picked from commit 8a3478ed31a16904f45178c153f4649faf6de675)
+---
+ src/cfgparse.c | 15 ++++++---------
+ 1 file changed, 6 insertions(+), 9 deletions(-)
+
+diff --git a/src/cfgparse.c b/src/cfgparse.c
+index 943eba0..5288600 100644
+--- a/src/cfgparse.c
++++ b/src/cfgparse.c
+@@ -6165,9 +6165,8 @@ int check_config_validity()
+                               /* we force the backend to be present on at least all of
+                                * the frontend's processes.
+                                */
+-                              if (target->bind_proc)
+-                                      target->bind_proc = curproxy->bind_proc ?
+-                                              (target->bind_proc | curproxy->bind_proc) : 0;
++                              target->bind_proc = curproxy->bind_proc ?
++                                      (target->bind_proc | curproxy->bind_proc) : 0;
+                               /* Emit a warning if this proxy also has some servers */
+                               if (curproxy->srv) {
+@@ -6203,9 +6202,8 @@ int check_config_validity()
+                                       /* we force the backend to be present on at least all of
+                                        * the frontend's processes.
+                                        */
+-                                      if (target->bind_proc)
+-                                              target->bind_proc = curproxy->bind_proc ?
+-                                                      (target->bind_proc | curproxy->bind_proc) : 0;
++                                      target->bind_proc = curproxy->bind_proc ?
++                                              (target->bind_proc | curproxy->bind_proc) : 0;
+                               }
+                       }
+               }
+@@ -6257,9 +6255,8 @@ int check_config_validity()
+                               /* we force the backend to be present on at least all of
+                                * the frontend's processes.
+                                */
+-                              if (target->bind_proc)
+-                                      target->bind_proc = curproxy->bind_proc ?
+-                                              (target->bind_proc | curproxy->bind_proc) : 0;
++                              target->bind_proc = curproxy->bind_proc ?
++                                      (target->bind_proc | curproxy->bind_proc) : 0;
+                       }
+               }
+-- 
+1.8.5.5
+
diff --git a/net/haproxy/patches/0008-MEDIUM-config-properly-propagate-process-binding-bet.patch b/net/haproxy/patches/0008-MEDIUM-config-properly-propagate-process-binding-bet.patch
new file mode 100644 (file)
index 0000000..add6b6f
--- /dev/null
@@ -0,0 +1,142 @@
+From 5436afc9488531a5e2adff3a1a766af375e0922c Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 16 Sep 2014 12:17:36 +0200
+Subject: [PATCH 08/13] MEDIUM: config: properly propagate process binding
+ between proxies
+
+We now recursively propagate the bind-process values between frontends
+and backends instead of doing it during name resolving. This ensures
+that we're able to properly propagate all the bind-process directives
+even across "listen" instances, which are not perfectly covered at the
+moment, depending on the declaration order.
+(cherry picked from commit 64ab6077b768ee02b04a36b30ee195639a2fabc1)
+---
+ src/cfgparse.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 65 insertions(+), 16 deletions(-)
+
+diff --git a/src/cfgparse.c b/src/cfgparse.c
+index 5288600..b9853ef 100644
+--- a/src/cfgparse.c
++++ b/src/cfgparse.c
+@@ -5932,6 +5932,64 @@ int readcfgfile(const char *file)
+       return err_code;
+ }
++/* This function propagates processes from frontend <from> to backend <to> so
++ * that it is always guaranteed that a backend pointed to by a frontend is
++ * bound to all of its processes. After that, if the target is a "listen"
++ * instance, the function recursively descends the target's own targets along
++ * default_backend, use_backend rules, and reqsetbe rules. Since the bits are
++ * checked first to ensure that <to> is already bound to all processes of
++ * <from>, there is no risk of looping and we ensure to follow the shortest
++ * path to the destination.
++ *
++ * It is possible to set <to> to NULL for the first call so that the function
++ * takes care of visiting the initial frontend in <from>.
++ *
++ * It is important to note that the function relies on the fact that all names
++ * have already been resolved.
++ */
++void propagate_processes(struct proxy *from, struct proxy *to)
++{
++      struct switching_rule *rule;
++      struct hdr_exp *exp;
++
++      if (to) {
++              /* check whether we need to go down */
++              if (from->bind_proc &&
++                  (from->bind_proc & to->bind_proc) == from->bind_proc)
++                      return;
++
++              if (!from->bind_proc && !to->bind_proc)
++                      return;
++
++              to->bind_proc = from->bind_proc ?
++                      (to->bind_proc | from->bind_proc) : 0;
++
++              /* now propagate down */
++              from = to;
++      }
++
++      if (!from->cap & PR_CAP_FE)
++              return;
++
++      /* default_backend */
++      if (from->defbe.be)
++              propagate_processes(from, from->defbe.be);
++
++      /* use_backend */
++      list_for_each_entry(rule, &from->switching_rules, list) {
++              to = rule->be.backend;
++              propagate_processes(from, to);
++      }
++
++      /* reqsetbe */
++      for (exp = from->req_exp; exp != NULL; exp = exp->next) {
++              if (exp->action != ACT_SETBE)
++                      continue;
++              to = (struct proxy *)exp->replace;
++              propagate_processes(from, to);
++      }
++}
++
+ /*
+  * Returns the error code, 0 if OK, or any combination of :
+  *  - ERR_ABORT: must abort ASAP
+@@ -6162,11 +6220,6 @@ int check_config_validity()
+                       } else {
+                               free(curproxy->defbe.name);
+                               curproxy->defbe.be = target;
+-                              /* we force the backend to be present on at least all of
+-                               * the frontend's processes.
+-                               */
+-                              target->bind_proc = curproxy->bind_proc ?
+-                                      (target->bind_proc | curproxy->bind_proc) : 0;
+                               /* Emit a warning if this proxy also has some servers */
+                               if (curproxy->srv) {
+@@ -6199,11 +6252,6 @@ int check_config_validity()
+                               } else {
+                                       free((void *)exp->replace);
+                                       exp->replace = (const char *)target;
+-                                      /* we force the backend to be present on at least all of
+-                                       * the frontend's processes.
+-                                       */
+-                                      target->bind_proc = curproxy->bind_proc ?
+-                                              (target->bind_proc | curproxy->bind_proc) : 0;
+                               }
+                       }
+               }
+@@ -6252,15 +6300,10 @@ int check_config_validity()
+                       } else {
+                               free((void *)rule->be.name);
+                               rule->be.backend = target;
+-                              /* we force the backend to be present on at least all of
+-                               * the frontend's processes.
+-                               */
+-                              target->bind_proc = curproxy->bind_proc ?
+-                                      (target->bind_proc | curproxy->bind_proc) : 0;
+                       }
+               }
+-              /* find the target proxy for 'use_backend' rules */
++              /* find the target server for 'use_server' rules */
+               list_for_each_entry(srule, &curproxy->server_rules, list) {
+                       struct server *target = findserver(curproxy, srule->srv.name);
+@@ -7131,6 +7174,12 @@ out_uri_auth_compat:
+               }
+       }
++      /* At this point, target names have already been resolved */
++      for (curproxy = proxy; curproxy; curproxy = curproxy->next) {
++              if (curproxy->cap & PR_CAP_FE)
++                      propagate_processes(curproxy, NULL);
++      }
++
+       /* automatically compute fullconn if not set. We must not do it in the
+        * loop above because cross-references are not yet fully resolved.
+        */
+-- 
+1.8.5.5
+
diff --git a/net/haproxy/patches/0009-MEDIUM-config-make-the-frontends-automatically-bind-.patch b/net/haproxy/patches/0009-MEDIUM-config-make-the-frontends-automatically-bind-.patch
new file mode 100644 (file)
index 0000000..1d83add
--- /dev/null
@@ -0,0 +1,93 @@
+From e56c4f1f76c6731a5a0f4b128540071cffeb1951 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 16 Sep 2014 13:21:03 +0200
+Subject: [PATCH 09/13] MEDIUM: config: make the frontends automatically bind
+ to the listeners' processes
+
+When a frontend does not have any bind-process directive, make it
+automatically bind to the union of all of its listeners' processes
+instead of binding to all processes. That will make it possible to
+have the expected behaviour without having to explicitly specify a
+bind-process directive.
+
+Note that if the listeners are not bound to a specific process, the
+default is still to bind to all processes.
+
+This change could be backported to 1.5 as it simplifies process
+management, and was planned to be done during the 1.5 development phase.
+(cherry picked from commit b369a045d545b41ef2b250bf747caf83c97e0ca8)
+---
+ doc/configuration.txt |  4 ++++
+ src/cfgparse.c        | 36 ++++++++++++++++++++++++++++++++++++
+ 2 files changed, 40 insertions(+)
+
+diff --git a/doc/configuration.txt b/doc/configuration.txt
+index 3c75c92..1e32057 100644
+--- a/doc/configuration.txt
++++ b/doc/configuration.txt
+@@ -1905,6 +1905,10 @@ bind-process [ all | odd | even | <number 1-64>[-<number 1-64>] ] ...
+   Each "bind" line may further be limited to a subset of the proxy's processes,
+   please consult the "process" bind keyword in section 5.1.
++  When a frontend has no explicit "bind-process" line, it tries to bind to all
++  the processes referenced by its "bind" lines. That means that frontends can
++  easily adapt to their listeners' processes.
++
+   If some backends are referenced by frontends bound to other processes, the
+   backend automatically inherits the frontend's processes.
+diff --git a/src/cfgparse.c b/src/cfgparse.c
+index b9853ef..d53f69e 100644
+--- a/src/cfgparse.c
++++ b/src/cfgparse.c
+@@ -7175,11 +7175,47 @@ out_uri_auth_compat:
+       }
+       /* At this point, target names have already been resolved */
++
++      /* Make each frontend inherit bind-process from its listeners when not specified. */
++      for (curproxy = proxy; curproxy; curproxy = curproxy->next) {
++              if (curproxy->bind_proc)
++                      continue;
++
++              list_for_each_entry(bind_conf, &curproxy->conf.bind, by_fe) {
++                      unsigned long mask;
++
++                      mask = bind_conf->bind_proc ? bind_conf->bind_proc : ~0UL;
++                      curproxy->bind_proc |= mask;
++              }
++
++              if (!curproxy->bind_proc)
++                      curproxy->bind_proc = ~0UL;
++      }
++
++      if (global.stats_fe) {
++              list_for_each_entry(bind_conf, &global.stats_fe->conf.bind, by_fe) {
++                      unsigned long mask;
++
++                      mask = bind_conf->bind_proc ? bind_conf->bind_proc : ~0UL;
++                      global.stats_fe->bind_proc |= mask;
++              }
++              if (!global.stats_fe->bind_proc)
++                      global.stats_fe->bind_proc = ~0UL;
++      }
++
++      /* propagate bindings from frontends to backends */
+       for (curproxy = proxy; curproxy; curproxy = curproxy->next) {
+               if (curproxy->cap & PR_CAP_FE)
+                       propagate_processes(curproxy, NULL);
+       }
++      /* Bind each unbound backend to all processes when not specified. */
++      for (curproxy = proxy; curproxy; curproxy = curproxy->next) {
++              if (curproxy->bind_proc)
++                      continue;
++              curproxy->bind_proc = ~0UL;
++      }
++
+       /* automatically compute fullconn if not set. We must not do it in the
+        * loop above because cross-references are not yet fully resolved.
+        */
+-- 
+1.8.5.5
+
diff --git a/net/haproxy/patches/0010-MEDIUM-config-compute-the-exact-bind-process-before-.patch b/net/haproxy/patches/0010-MEDIUM-config-compute-the-exact-bind-process-before-.patch
new file mode 100644 (file)
index 0000000..4701df6
--- /dev/null
@@ -0,0 +1,209 @@
+From 91b00c2194b728ccd61133cca83f03de3650b674 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 16 Sep 2014 13:41:21 +0200
+Subject: [PATCH 10/13] MEDIUM: config: compute the exact bind-process before
+ listener's maxaccept
+
+This is a continuation of previous patch, the listener's maxaccept is divided
+by the number of processes, so it's best if we can swap the two blocks so that
+the number of processes is already known when computing the maxaccept value.
+(cherry picked from commit 419ead8eca9237f9cc2ec32630d96fde333282ee)
+---
+ src/cfgparse.c | 156 ++++++++++++++++++++++++++++++---------------------------
+ 1 file changed, 81 insertions(+), 75 deletions(-)
+
+diff --git a/src/cfgparse.c b/src/cfgparse.c
+index d53f69e..f3907bf 100644
+--- a/src/cfgparse.c
++++ b/src/cfgparse.c
+@@ -6042,12 +6042,11 @@ int check_config_validity()
+               proxy = next;
+       }
+-      while (curproxy != NULL) {
++      for (curproxy = proxy; curproxy; curproxy = curproxy->next) {
+               struct switching_rule *rule;
+               struct server_rule *srule;
+               struct sticking_rule *mrule;
+               struct tcp_rule *trule;
+-              struct listener *listener;
+               unsigned int next_id;
+               int nbproc;
+@@ -6115,14 +6114,6 @@ int check_config_validity()
+                       }
+               }
+-              /* here, if bind_proc is null, it means no limit, otherwise it's explicit.
+-               * We now check how many processes the proxy will effectively run on.
+-               */
+-
+-              nbproc = global.nbproc;
+-              if (curproxy->bind_proc)
+-                      nbproc = popcount(curproxy->bind_proc & nbits(global.nbproc));
+-
+               if (global.nbproc > 1 && curproxy->table.peers.name) {
+                       Alert("Proxy '%s': peers can't be used in multi-process mode (nbproc > 1).\n",
+                             curproxy->id);
+@@ -7005,6 +6996,86 @@ out_uri_auth_compat:
+                       if (curproxy->options2 & PR_O2_RDPC_PRST)
+                               curproxy->be_req_ana |= AN_REQ_PRST_RDP_COOKIE;
+               }
++      }
++
++      /***********************************************************/
++      /* At this point, target names have already been resolved. */
++      /***********************************************************/
++
++      /* Check multi-process mode compatibility */
++
++      if (global.nbproc > 1 && global.stats_fe) {
++              list_for_each_entry(bind_conf, &global.stats_fe->conf.bind, by_fe) {
++                      unsigned long mask;
++
++                      mask = nbits(global.nbproc);
++                      if (global.stats_fe->bind_proc)
++                              mask &= global.stats_fe->bind_proc;
++
++                      if (bind_conf->bind_proc)
++                              mask &= bind_conf->bind_proc;
++
++                      /* stop here if more than one process is used */
++                      if (popcount(mask) > 1)
++                              break;
++              }
++              if (&bind_conf->by_fe != &global.stats_fe->conf.bind) {
++                      Warning("stats socket will not work as expected in multi-process mode (nbproc > 1), you should force process binding globally using 'stats bind-process' or per socket using the 'process' attribute.\n");
++              }
++      }
++
++      /* Make each frontend inherit bind-process from its listeners when not specified. */
++      for (curproxy = proxy; curproxy; curproxy = curproxy->next) {
++              if (curproxy->bind_proc)
++                      continue;
++
++              list_for_each_entry(bind_conf, &curproxy->conf.bind, by_fe) {
++                      unsigned long mask;
++
++                      mask = bind_conf->bind_proc ? bind_conf->bind_proc : ~0UL;
++                      curproxy->bind_proc |= mask;
++              }
++
++              if (!curproxy->bind_proc)
++                      curproxy->bind_proc = ~0UL;
++      }
++
++      if (global.stats_fe) {
++              list_for_each_entry(bind_conf, &global.stats_fe->conf.bind, by_fe) {
++                      unsigned long mask;
++
++                      mask = bind_conf->bind_proc ? bind_conf->bind_proc : ~0UL;
++                      global.stats_fe->bind_proc |= mask;
++              }
++              if (!global.stats_fe->bind_proc)
++                      global.stats_fe->bind_proc = ~0UL;
++      }
++
++      /* propagate bindings from frontends to backends */
++      for (curproxy = proxy; curproxy; curproxy = curproxy->next) {
++              if (curproxy->cap & PR_CAP_FE)
++                      propagate_processes(curproxy, NULL);
++      }
++
++      /* Bind each unbound backend to all processes when not specified. */
++      for (curproxy = proxy; curproxy; curproxy = curproxy->next) {
++              if (curproxy->bind_proc)
++                      continue;
++              curproxy->bind_proc = ~0UL;
++      }
++
++      /*******************************************************/
++      /* At this step, all proxies have a non-null bind_proc */
++      /*******************************************************/
++
++      /* perform the final checks before creating tasks */
++
++      for (curproxy = proxy; curproxy; curproxy = curproxy->next) {
++              struct listener *listener;
++              unsigned int next_id;
++              int nbproc;
++
++              nbproc = popcount(curproxy->bind_proc & nbits(global.nbproc));
+ #ifdef USE_OPENSSL
+               /* Configure SSL for each bind line.
+@@ -7149,71 +7220,6 @@ out_uri_auth_compat:
+                             curproxy->id);
+                       cfgerr++;
+               }
+-
+-              curproxy = curproxy->next;
+-      }
+-
+-      /* Check multi-process mode compatibility */
+-      if (global.nbproc > 1 && global.stats_fe) {
+-              list_for_each_entry(bind_conf, &global.stats_fe->conf.bind, by_fe) {
+-                      unsigned long mask;
+-
+-                      mask = nbits(global.nbproc);
+-                      if (global.stats_fe->bind_proc)
+-                              mask &= global.stats_fe->bind_proc;
+-
+-                      if (bind_conf->bind_proc)
+-                              mask &= bind_conf->bind_proc;
+-
+-                      /* stop here if more than one process is used */
+-                      if (popcount(mask) > 1)
+-                              break;
+-              }
+-              if (&bind_conf->by_fe != &global.stats_fe->conf.bind) {
+-                      Warning("stats socket will not work as expected in multi-process mode (nbproc > 1), you should force process binding globally using 'stats bind-process' or per socket using the 'process' attribute.\n");
+-              }
+-      }
+-
+-      /* At this point, target names have already been resolved */
+-
+-      /* Make each frontend inherit bind-process from its listeners when not specified. */
+-      for (curproxy = proxy; curproxy; curproxy = curproxy->next) {
+-              if (curproxy->bind_proc)
+-                      continue;
+-
+-              list_for_each_entry(bind_conf, &curproxy->conf.bind, by_fe) {
+-                      unsigned long mask;
+-
+-                      mask = bind_conf->bind_proc ? bind_conf->bind_proc : ~0UL;
+-                      curproxy->bind_proc |= mask;
+-              }
+-
+-              if (!curproxy->bind_proc)
+-                      curproxy->bind_proc = ~0UL;
+-      }
+-
+-      if (global.stats_fe) {
+-              list_for_each_entry(bind_conf, &global.stats_fe->conf.bind, by_fe) {
+-                      unsigned long mask;
+-
+-                      mask = bind_conf->bind_proc ? bind_conf->bind_proc : ~0UL;
+-                      global.stats_fe->bind_proc |= mask;
+-              }
+-              if (!global.stats_fe->bind_proc)
+-                      global.stats_fe->bind_proc = ~0UL;
+-      }
+-
+-      /* propagate bindings from frontends to backends */
+-      for (curproxy = proxy; curproxy; curproxy = curproxy->next) {
+-              if (curproxy->cap & PR_CAP_FE)
+-                      propagate_processes(curproxy, NULL);
+-      }
+-
+-      /* Bind each unbound backend to all processes when not specified. */
+-      for (curproxy = proxy; curproxy; curproxy = curproxy->next) {
+-              if (curproxy->bind_proc)
+-                      continue;
+-              curproxy->bind_proc = ~0UL;
+       }
+       /* automatically compute fullconn if not set. We must not do it in the
+-- 
+1.8.5.5
+
diff --git a/net/haproxy/patches/0011-MEDIUM-config-only-warn-if-stats-are-attached-to-mul.patch b/net/haproxy/patches/0011-MEDIUM-config-only-warn-if-stats-are-attached-to-mul.patch
new file mode 100644 (file)
index 0000000..1d5527a
--- /dev/null
@@ -0,0 +1,45 @@
+From 036a83e9c300a42386cd378022420e52a43b314f Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 16 Sep 2014 15:11:04 +0200
+Subject: [PATCH 11/13] MEDIUM: config: only warn if stats are attached to
+ multi-process bind directives
+
+Some users want to have a stats frontend with one line per process, but while
+100% valid and safe, the config parser emits a warning. Relax this check to
+ensure that the warning is only emitted if at least one of the listeners is
+bound to multiple processes, or if the directive is placed in a backend called
+from multiple processes (since in this case we don't know if it's safe).
+(cherry picked from commit eb791e03b5c5abfddb24a439fa6434788db026b7)
+---
+ src/cfgparse.c | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+diff --git a/src/cfgparse.c b/src/cfgparse.c
+index f3907bf..5668393 100644
+--- a/src/cfgparse.c
++++ b/src/cfgparse.c
+@@ -7189,8 +7189,19 @@ out_uri_auth_compat:
+               if (nbproc > 1) {
+                       if (curproxy->uri_auth) {
+-                              Warning("Proxy '%s': in multi-process mode, stats will be limited to process assigned to the current request.\n",
+-                                      curproxy->id);
++                              int count, maxproc = 0;
++
++                              list_for_each_entry(bind_conf, &curproxy->conf.bind, by_fe) {
++                                      count = popcount(bind_conf->bind_proc);
++                                      if (count > maxproc)
++                                              maxproc = count;
++                              }
++                              /* backends have 0, frontends have 1 or more */
++                              if (maxproc != 1)
++                                      Warning("Proxy '%s': in multi-process mode, stats will be"
++                                              " limited to process assigned to the current request.\n",
++                                              curproxy->id);
++
+                               if (!LIST_ISEMPTY(&curproxy->uri_auth->admin_rules)) {
+                                       Warning("Proxy '%s': stats admin will not work correctly in multi-process mode.\n",
+                                               curproxy->id);
+-- 
+1.8.5.5
+
diff --git a/net/haproxy/patches/0012-MEDIUM-config-report-it-when-tcp-request-rules-are-m.patch b/net/haproxy/patches/0012-MEDIUM-config-report-it-when-tcp-request-rules-are-m.patch
new file mode 100644 (file)
index 0000000..ffd6cb4
--- /dev/null
@@ -0,0 +1,110 @@
+From 8b3c808c37dd5672f87e7b61085295e1316a6694 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 16 Sep 2014 15:39:51 +0200
+Subject: [PATCH 12/13] MEDIUM: config: report it when tcp-request rules are
+ misplaced
+
+A config where a tcp-request rule appears after an http-request rule
+might seem valid but it is not. So let's report a warning about this
+since this case is hard to detect by the naked eye.
+(cherry picked from commit 3986b9c14037f446f5f5bec6207a39e1bd753fae)
+---
+ include/common/cfgparse.h |  2 ++
+ src/cfgparse.c            | 38 ++++++++++++++++++++++++++++++++++++++
+ src/proto_tcp.c           |  4 ++++
+ 3 files changed, 44 insertions(+)
+
+diff --git a/include/common/cfgparse.h b/include/common/cfgparse.h
+index 80310ae..86a0035 100644
+--- a/include/common/cfgparse.h
++++ b/include/common/cfgparse.h
+@@ -73,6 +73,8 @@ int check_config_validity();
+ int str2listener(char *str, struct proxy *curproxy, struct bind_conf *bind_conf, const char *file, int line, char **err);
+ int cfg_register_section(char *section_name,
+                          int (*section_parser)(const char *, int, char **, int));
++int warnif_misplaced_tcp_conn(struct proxy *proxy, const char *file, int line, const char *arg);
++int warnif_misplaced_tcp_cont(struct proxy *proxy, const char *file, int line, const char *arg);
+ /*
+  * Sends a warning if proxy <proxy> does not have at least one of the
+diff --git a/src/cfgparse.c b/src/cfgparse.c
+index 5668393..9ff44e9 100644
+--- a/src/cfgparse.c
++++ b/src/cfgparse.c
+@@ -317,6 +317,19 @@ int str2listener(char *str, struct proxy *curproxy, struct bind_conf *bind_conf,
+       return 0;
+ }
++/* Report a warning if a rule is placed after a 'tcp-request content' rule.
++ * Return 1 if the warning has been emitted, otherwise 0.
++ */
++int warnif_rule_after_tcp_cont(struct proxy *proxy, const char *file, int line, const char *arg)
++{
++      if (!LIST_ISEMPTY(&proxy->tcp_req.inspect_rules)) {
++              Warning("parsing [%s:%d] : a '%s' rule placed after a 'tcp-request content' rule will still be processed before.\n",
++                      file, line, arg);
++              return 1;
++      }
++      return 0;
++}
++
+ /* Report a warning if a rule is placed after a 'block' rule.
+  * Return 1 if the warning has been emitted, otherwise 0.
+  */
+@@ -408,6 +421,31 @@ int warnif_rule_after_use_server(struct proxy *proxy, const char *file, int line
+       return 0;
+ }
++/* report a warning if a "tcp request connection" rule is dangerously placed */
++int warnif_misplaced_tcp_conn(struct proxy *proxy, const char *file, int line, const char *arg)
++{
++      return  warnif_rule_after_tcp_cont(proxy, file, line, arg) ||
++              warnif_rule_after_block(proxy, file, line, arg) ||
++              warnif_rule_after_http_req(proxy, file, line, arg) ||
++              warnif_rule_after_reqxxx(proxy, file, line, arg) ||
++              warnif_rule_after_reqadd(proxy, file, line, arg) ||
++              warnif_rule_after_redirect(proxy, file, line, arg) ||
++              warnif_rule_after_use_backend(proxy, file, line, arg) ||
++              warnif_rule_after_use_server(proxy, file, line, arg);
++}
++
++/* report a warning if a "tcp request content" rule is dangerously placed */
++int warnif_misplaced_tcp_cont(struct proxy *proxy, const char *file, int line, const char *arg)
++{
++      return  warnif_rule_after_block(proxy, file, line, arg) ||
++              warnif_rule_after_http_req(proxy, file, line, arg) ||
++              warnif_rule_after_reqxxx(proxy, file, line, arg) ||
++              warnif_rule_after_reqadd(proxy, file, line, arg) ||
++              warnif_rule_after_redirect(proxy, file, line, arg) ||
++              warnif_rule_after_use_backend(proxy, file, line, arg) ||
++              warnif_rule_after_use_server(proxy, file, line, arg);
++}
++
+ /* report a warning if a block rule is dangerously placed */
+ int warnif_misplaced_block(struct proxy *proxy, const char *file, int line, const char *arg)
+ {
+diff --git a/src/proto_tcp.c b/src/proto_tcp.c
+index 72dc92b..940c3f1 100644
+--- a/src/proto_tcp.c
++++ b/src/proto_tcp.c
+@@ -1711,6 +1711,8 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
+                       warn++;
+               }
++              /* the following function directly emits the warning */
++              warnif_misplaced_tcp_cont(curpx, file, line, args[0]);
+               LIST_ADDQ(&curpx->tcp_req.inspect_rules, &rule->list);
+       }
+       else if (strcmp(args[1], "connection") == 0) {
+@@ -1754,6 +1756,8 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
+                       warn++;
+               }
++              /* the following function directly emits the warning */
++              warnif_misplaced_tcp_conn(curpx, file, line, args[0]);
+               LIST_ADDQ(&curpx->tcp_req.l4_rules, &rule->list);
+       }
+       else {
+-- 
+1.8.5.5
+
diff --git a/net/haproxy/patches/0013-MINOR-config-detect-the-case-where-a-tcp-request-con.patch b/net/haproxy/patches/0013-MINOR-config-detect-the-case-where-a-tcp-request-con.patch
new file mode 100644 (file)
index 0000000..4d70d2b
--- /dev/null
@@ -0,0 +1,52 @@
+From 7fc7ebd5785629074297ee324b22e0aee9ad00f9 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 16 Sep 2014 16:21:19 +0200
+Subject: [PATCH 13/13] MINOR: config: detect the case where a tcp-request
+ content rule has no inspect-delay
+
+If a frontend has any tcp-request content rule relying on request contents
+without any inspect delay, we now emit a warning as this will randomly match.
+
+This can be backported to 1.5 as it reduces the support effort.
+(cherry picked from commit e42bd96d0acc38ea7c546c8de8115ffd1dd6c3f3)
+---
+ src/cfgparse.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/src/cfgparse.c b/src/cfgparse.c
+index 9ff44e9..f723a3a 100644
+--- a/src/cfgparse.c
++++ b/src/cfgparse.c
+@@ -6998,6 +6998,29 @@ out_uri_auth_compat:
+                       newsrv = newsrv->next;
+               }
++              /* check if we have a frontend with "tcp-request content" looking at L7
++               * with no inspect-delay
++               */
++              if ((curproxy->cap & PR_CAP_FE) && !curproxy->tcp_req.inspect_delay) {
++                      list_for_each_entry(trule, &curproxy->tcp_req.inspect_rules, list) {
++                              if (trule->action == TCP_ACT_CAPTURE &&
++                                  !(trule->act_prm.cap.expr->fetch->val & SMP_VAL_FE_SES_ACC))
++                                      break;
++                              if  ((trule->action >= TCP_ACT_TRK_SC0 && trule->action <= TCP_ACT_TRK_SCMAX) &&
++                                   !(trule->act_prm.trk_ctr.expr->fetch->val & SMP_VAL_FE_SES_ACC))
++                                      break;
++                      }
++
++                      if (&trule->list != &curproxy->tcp_req.inspect_rules) {
++                              Warning("config : %s '%s' : some 'tcp-request content' rules explicitly depending on request"
++                                      " contents were found in a frontend without any 'tcp-request inspect-delay' setting."
++                                      " This means that these rules will randomly find their contents. This can be fixed by"
++                                      " setting the tcp-request inspect-delay.\n",
++                                      proxy_type_str(curproxy), curproxy->id);
++                              err_code |= ERR_WARN;
++                      }
++              }
++
+               if (curproxy->cap & PR_CAP_FE) {
+                       if (!curproxy->accept)
+                               curproxy->accept = frontend_accept;
+-- 
+1.8.5.5
+