]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] http: don't switch to tunnel mode upon close
authorWilly Tarreau <w@1wt.eu>
Sat, 16 Jan 2010 22:19:39 +0000 (23:19 +0100)
committerWilly Tarreau <w@1wt.eu>
Sun, 17 Jan 2010 10:38:34 +0000 (11:38 +0100)
The close mode of a transaction would be switched to tunnel mode
at the end of the processing, letting a lot of pending data pass
in the other direction if any. Let's fix that by checking for the
close mode during state resync too.

src/proto_http.c

index 1f6c05b1488f4e11b18a47cc7de3bf07398c2df2..980ef392f403d4324ca717778454d3a51c69c90d 100644 (file)
@@ -3542,25 +3542,36 @@ int http_sync_req_state(struct session *s)
                 * direction, and sometimes for a close to be effective.
                 */
 
-               if (!(buf->flags & (BF_SHUTW|BF_SHUTW_NOW))) {
-                       if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) {
-                               /* Server-close mode : queue a connection close to the server */
+               if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) {
+                       /* Server-close mode : queue a connection close to the server */
+                       if (!(buf->flags & (BF_SHUTW|BF_SHUTW_NOW)))
                                buffer_shutw_now(buf);
-                               buf->cons->flags |= SI_FL_NOLINGER;
-                       }
-                       else if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_CLO) {
-                               /* Option forceclose is set, let's enforce it now
-                                * that we're not expecting any new data to come.
-                                */
+               }
+               else if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_CLO) {
+                       /* Option forceclose is set, or either side wants to close,
+                        * let's enforce it now that we're not expecting any new
+                        * data to come. The caller knows the session is complete
+                        * once both states are CLOSED.
+                        */
+                       if (!(buf->flags & (BF_SHUTW|BF_SHUTW_NOW))) {
                                buffer_shutr_now(buf);
                                buffer_shutw_now(buf);
-                               buf->cons->flags |= SI_FL_NOLINGER;
                        }
-                       /* other modes include httpclose (no action) and keepalive (not implemented) */
+               }
+               else {
+                       /* The last possible modes are keep-alive and tunnel. Since tunnel
+                        * mode does not set the body analyser, we can't reach this place
+                        * in tunnel mode, so we're left with keep-alive only.
+                        * This mode is currently not implemented, we switch to tunnel mode.
+                        */
+                       buffer_auto_read(buf);
+                       txn->req.msg_state = HTTP_MSG_TUNNEL;
                }
 
                if (buf->flags & (BF_SHUTW|BF_SHUTW_NOW)) {
                        /* if we've just closed an output, let's switch */
+                       buf->cons->flags |= SI_FL_NOLINGER;  /* we want to close ASAP */
+
                        if (!(buf->flags & BF_OUT_EMPTY)) {
                                txn->req.msg_state = HTTP_MSG_CLOSING;
                                goto http_msg_closing;
@@ -3570,12 +3581,7 @@ int http_sync_req_state(struct session *s)
                                goto http_msg_closed;
                        }
                }
-               else {
-                       /* other modes are used as a tunnel right now */
-                       buffer_auto_read(buf);
-                       txn->req.msg_state = HTTP_MSG_TUNNEL;
-                       goto wait_other_side;
-               }
+               goto wait_other_side;
        }
 
        if (txn->req.msg_state == HTTP_MSG_CLOSING) {
@@ -3663,26 +3669,26 @@ int http_sync_res_state(struct session *s)
                         */
                        if (!(buf->flags & (BF_SHUTR|BF_SHUTR_NOW)))
                                buffer_shutr_now(buf);
-                       goto wait_other_side;
                }
-               else if (!(buf->flags & (BF_SHUTW|BF_SHUTW_NOW)) &&
-                        ((s->fe->options | s->be->options) & PR_O_FORCE_CLO)) {
-                       /* Option forceclose is set, let's enforce it now
-                        * that we're not expecting any new data to come.
-                        * The caller knows the session is complete once
-                        * both states are CLOSED.
+               else if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_CLO) {
+                       /* Option forceclose is set, or either side wants to close,
+                        * let's enforce it now that we're not expecting any new
+                        * data to come. The caller knows the session is complete
+                        * once both states are CLOSED.
                         */
-                       buffer_shutr_now(buf);
-                       buffer_shutw_now(buf);
+                       if (!(buf->flags & (BF_SHUTW|BF_SHUTW_NOW))) {
+                               buffer_shutr_now(buf);
+                               buffer_shutw_now(buf);
+                       }
                }
                else {
-                       /* other modes include httpclose (no action) and keepalive
-                        * (not implemented). These modes are used as a tunnel right
-                        * now.
+                       /* The last possible modes are keep-alive and tunnel. Since tunnel
+                        * mode does not set the body analyser, we can't reach this place
+                        * in tunnel mode, so we're left with keep-alive only.
+                        * This mode is currently not implemented, we switch to tunnel mode.
                         */
                        buffer_auto_read(buf);
                        txn->rsp.msg_state = HTTP_MSG_TUNNEL;
-                       goto wait_other_side;
                }
 
                if (buf->flags & (BF_SHUTW|BF_SHUTW_NOW)) {