]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MAJOR: http: add the keep-alive transition on the server side
authorWilly Tarreau <w@1wt.eu>
Sun, 15 Dec 2013 09:25:42 +0000 (10:25 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 16 Dec 2013 01:23:54 +0000 (02:23 +0100)
When a connection to the server is complete, if the transaction
requests keep-alive mode, we don't shut the connection and we just
reinitialize the stream interface in order to be able to reuse the
connection afterwards.

Note that the server connection count is decremented, just like the
backend's, and that we still try to wake up waiters. But that makes
sense considering that we'll eventually be able to immediately pass
idle connections to waiters.

src/proto_http.c

index a0717585a389afa78872b18872bdc883e6f515be..f9554b422469196162f508a107b954584e82b2c4 100644 (file)
@@ -4249,9 +4249,15 @@ void http_end_txn_clean_session(struct session *s)
         */
        http_silent_debug(__LINE__, s);
 
-       s->req->cons->flags |= SI_FL_NOLINGER | SI_FL_NOHALF;
-       si_shutr(s->req->cons);
-       si_shutw(s->req->cons);
+       /* unless we're doing keep-alive, we want to quickly close the connection
+        * to the server.
+        */
+       if (((s->txn.flags & TX_CON_WANT_MSK) != TX_CON_WANT_KAL) ||
+           !si_conn_ready(s->req->cons)) {
+               s->req->cons->flags |= SI_FL_NOLINGER | SI_FL_NOHALF;
+               si_shutr(s->req->cons);
+               si_shutw(s->req->cons);
+       }
 
        http_silent_debug(__LINE__, s);
 
@@ -4324,8 +4330,15 @@ void http_end_txn_clean_session(struct session *s)
 
        s->target = NULL;
 
+       /* only release our endpoint if we don't intend to reuse the
+        * connection.
+        */
+       if (((s->txn.flags & TX_CON_WANT_MSK) != TX_CON_WANT_KAL) ||
+           !si_conn_ready(s->req->cons)) {
+               si_release_endpoint(s->req->cons);
+       }
+
        s->req->cons->state     = s->req->cons->prev_state = SI_ST_INI;
-       si_release_endpoint(s->req->cons);
        s->req->cons->err_type  = SI_ET_NONE;
        s->req->cons->conn_retries = 0;  /* used for logging too */
        s->req->cons->exp       = TICK_ETERNITY;
@@ -4454,14 +4467,14 @@ int http_sync_req_state(struct session *s)
                        }
                }
                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.
+                       /* The last possible modes are keep-alive and tunnel. Tunnel mode
+                        * will not have any analyser so it needs to poll for reads.
                         */
-                       channel_auto_read(chn);
-                       txn->req.msg_state = HTTP_MSG_TUNNEL;
-                       chn->flags |= CF_NEVER_WAIT;
+                       if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_TUN) {
+                               channel_auto_read(chn);
+                               txn->req.msg_state = HTTP_MSG_TUNNEL;
+                               chn->flags |= CF_NEVER_WAIT;
+                       }
                }
 
                if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) {
@@ -4581,14 +4594,14 @@ int http_sync_res_state(struct session *s)
                        }
                }
                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.
+                       /* The last possible modes are keep-alive and tunnel. Tunnel will
+                        * need to forward remaining data. Keep-alive will need to monitor
+                        * for connection closing.
                         */
                        channel_auto_read(chn);
-                       txn->rsp.msg_state = HTTP_MSG_TUNNEL;
                        chn->flags |= CF_NEVER_WAIT;
+                       if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_TUN)
+                               txn->rsp.msg_state = HTTP_MSG_TUNNEL;
                }
 
                if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) {
@@ -4699,11 +4712,14 @@ int http_resync_states(struct session *s)
                channel_auto_read(s->req);
                bi_erase(s->req);
        }
-       else if (txn->req.msg_state == HTTP_MSG_CLOSED &&
+       else if ((txn->req.msg_state == HTTP_MSG_DONE ||
+                 txn->req.msg_state == HTTP_MSG_CLOSED) &&
                 txn->rsp.msg_state == HTTP_MSG_DONE &&
-                ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL)) {
-               /* server-close: terminate this server connection and
-                * reinitialize a fresh-new transaction.
+                ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL ||
+                 (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL)) {
+               /* server-close/keep-alive: terminate this transaction,
+                * possibly killing the server connection and reinitialize
+                * a fresh-new transaction.
                 */
                http_end_txn_clean_session(s);
        }