]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: http: adjust close mode when switching to backend
authorWilly Tarreau <w@1wt.eu>
Tue, 30 Sep 2014 16:44:22 +0000 (18:44 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 30 Sep 2014 16:44:22 +0000 (18:44 +0200)
Commit 179085c ("MEDIUM: http: move Connection header processing earlier")
introduced a regression : the backend's HTTP mode is not considered anymore
when setting the session's HTTP mode, because wait_for_request() is only
called once, when the frontend receives the request (or when the frontend
is in TCP mode, when the backend receives the request).

The net effect is that in some situations when the frontend and the backend
do not work in the same mode (eg: keep-alive vs close), the backend's mode
is ignored.

This patch moves all that processing to a dedicated function, which is
called from the original place, as well as from session_set_backend()
when switching from an HTTP frontend to an HTTP backend in different
modes.

This fix must be backported to 1.5.

include/proto/proto_http.h
src/proto_http.c
src/proxy.c

index 3db8e10f6f7d9a59fa8e60f6446e9496fd1c94ff..945d49cf515a896b338b44cd2261b35f2005a1ff 100644 (file)
@@ -112,6 +112,7 @@ unsigned int http_get_hdr(const struct http_msg *msg, const char *hname, int hle
 void http_init_txn(struct session *s);
 void http_end_txn(struct session *s);
 void http_reset_txn(struct session *s);
+void http_adjust_conn_mode(struct session *s, struct http_txn *txn, struct http_msg *msg);
 
 struct http_req_rule *parse_http_req_cond(const char **args, const char *file, int linenum, struct proxy *proxy);
 struct http_res_rule *parse_http_res_cond(const char **args, const char *file, int linenum, struct proxy *proxy);
index 11177cb062d42882a6afdc802e481788d865130e..89e91a986083368d6566b607025fbbcc92f33737 100644 (file)
@@ -2393,6 +2393,59 @@ fail:
        return 0;
 }
 
+void http_adjust_conn_mode(struct session *s, struct http_txn *txn, struct http_msg *msg)
+{
+       int tmp = TX_CON_WANT_KAL;
+
+       if (!((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA)) {
+               if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN ||
+                   (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN)
+                       tmp = TX_CON_WANT_TUN;
+
+               if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL ||
+                   (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL)
+                       tmp = TX_CON_WANT_TUN;
+       }
+
+       if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL ||
+           (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL) {
+               /* option httpclose + server_close => forceclose */
+               if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL ||
+                   (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL)
+                       tmp = TX_CON_WANT_CLO;
+               else
+                       tmp = TX_CON_WANT_SCL;
+       }
+
+       if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL ||
+           (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL)
+               tmp = TX_CON_WANT_CLO;
+
+       if ((txn->flags & TX_CON_WANT_MSK) < tmp)
+               txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | tmp;
+
+       if (!(txn->flags & TX_HDR_CONN_PRS) &&
+           (txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) {
+               /* parse the Connection header and possibly clean it */
+               int to_del = 0;
+               if ((msg->flags & HTTP_MSGF_VER_11) ||
+                   ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL &&
+                    !((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA)))
+                       to_del |= 2; /* remove "keep-alive" */
+               if (!(msg->flags & HTTP_MSGF_VER_11))
+                       to_del |= 1; /* remove "close" */
+               http_parse_connection_header(txn, msg, to_del);
+       }
+
+       /* check if client or config asks for explicit close in KAL/SCL */
+       if (((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL ||
+            (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) &&
+           ((txn->flags & TX_HDR_CONN_CLO) ||                         /* "connection: close" */
+            (!(msg->flags & HTTP_MSGF_VER_11) && !(txn->flags & TX_HDR_CONN_KAL)) || /* no "connection: k-a" in 1.0 */
+            !(msg->flags & HTTP_MSGF_XFER_LEN) ||                     /* no length known => close */
+            s->fe->state == PR_STSTOPPED))                            /* frontend is stopping */
+               txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
+}
 
 /* This stream analyser waits for a complete HTTP request. It returns 1 if the
  * processing can continue on next analysers, or zero if it either needs more
@@ -2929,58 +2982,8 @@ int http_wait_for_request(struct session *s, struct channel *req, int an_bit)
         * time.
         */
        if (!(txn->flags & TX_HDR_CONN_PRS) ||
-           ((s->fe->options & PR_O_HTTP_MODE) != (s->be->options & PR_O_HTTP_MODE))) {
-               int tmp = TX_CON_WANT_KAL;
-
-               if (!((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA)) {
-                       if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN ||
-                           (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN)
-                               tmp = TX_CON_WANT_TUN;
-
-                       if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL ||
-                           (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL)
-                               tmp = TX_CON_WANT_TUN;
-               }
-
-               if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL ||
-                   (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL) {
-                       /* option httpclose + server_close => forceclose */
-                       if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL ||
-                           (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL)
-                               tmp = TX_CON_WANT_CLO;
-                       else
-                               tmp = TX_CON_WANT_SCL;
-               }
-
-               if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL ||
-                   (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL)
-                       tmp = TX_CON_WANT_CLO;
-
-               if ((txn->flags & TX_CON_WANT_MSK) < tmp)
-                       txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | tmp;
-
-               if (!(txn->flags & TX_HDR_CONN_PRS) &&
-                   (txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) {
-                       /* parse the Connection header and possibly clean it */
-                       int to_del = 0;
-                       if ((msg->flags & HTTP_MSGF_VER_11) ||
-                           ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL &&
-                            !((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA)))
-                               to_del |= 2; /* remove "keep-alive" */
-                       if (!(msg->flags & HTTP_MSGF_VER_11))
-                               to_del |= 1; /* remove "close" */
-                       http_parse_connection_header(txn, msg, to_del);
-               }
-
-               /* check if client or config asks for explicit close in KAL/SCL */
-               if (((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL ||
-                    (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) &&
-                   ((txn->flags & TX_HDR_CONN_CLO) ||                         /* "connection: close" */
-                    (!(msg->flags & HTTP_MSGF_VER_11) && !(txn->flags & TX_HDR_CONN_KAL)) || /* no "connection: k-a" in 1.0 */
-                    !(msg->flags & HTTP_MSGF_XFER_LEN) ||                     /* no length known => close */
-                    s->fe->state == PR_STSTOPPED))                            /* frontend is stopping */
-                   txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
-       }
+           ((s->fe->options & PR_O_HTTP_MODE) != (s->be->options & PR_O_HTTP_MODE)))
+               http_adjust_conn_mode(s, txn, msg);
 
        /* end of job, return OK */
        req->analysers &= ~an_bit;
index 02103ee11723e3a9576498c128b12e4f5fa9c386..405c4c4ada41f110c2450d03f4e2240c9ad51e4b 100644 (file)
@@ -955,6 +955,14 @@ int session_set_backend(struct session *s, struct proxy *be)
                http_init_txn(s);
        }
 
+       /* If we chain to an HTTP backend running a different HTTP mode, we
+        * have to re-adjust the desired keep-alive/close mode to accommodate
+        * both the frontend's and the backend's modes.
+        */
+       if (s->fe->mode == PR_MODE_HTTP && be->mode == PR_MODE_HTTP &&
+           ((s->fe->options & PR_O_HTTP_MODE) != (be->options & PR_O_HTTP_MODE)))
+               http_adjust_conn_mode(s, &s->txn, &s->txn.req);
+
        /* If an LB algorithm needs to access some pre-parsed body contents,
         * we must not start to forward anything until the connection is
         * confirmed otherwise we'll lose the pointer to these data and