]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] http: restore the original behaviour of option httpclose
authorWilly Tarreau <w@1wt.eu>
Tue, 5 Jan 2010 10:33:11 +0000 (11:33 +0100)
committerWilly Tarreau <w@1wt.eu>
Tue, 5 Jan 2010 10:33:11 +0000 (11:33 +0100)
Historically, "option httpclose" has always worked the same way. It
only mangles the "Connection" header in the request and the response
if needed, but does not affect the connection by itself, and ignores
any further data. It is dangerous to change this behaviour without
leaving any other alternative. If an active close is desired, it's
better to make use of "option forceclose" which does exactly what
it intends to do.

So as of now, "option httpclose" will only mangle the headers as
before, and will only affect the connection by itself when combined
with another connection-related option (eg: keepalive or server-close).

doc/configuration.txt
src/proto_http.c

index 0fa20025c9e8911cacfacaa39677a61efd967b62..46787e59dba500d4d3bca039a5cdd3b1d7826567 100644 (file)
@@ -2396,7 +2396,10 @@ no option forceclose
 
   When this happens, it is possible to use "option forceclose". It will
   actively close the outgoing server channel as soon as the server has finished
-  to respond. This option implicitly enables the "httpclose" option.
+  to respond. This option implicitly enables the "httpclose" option. Note that
+  this option also enables the parsing of the full request and response, which
+  means we can close the connection to the server very quickly, releasing some
+  resources earlier than with httpclose.
 
   If this option has been enabled in a "defaults" section, it can be disabled
   in a specific instance by prepending the "no" keyword before it.
@@ -2535,8 +2538,9 @@ no option http-server-close
 
   This option may be set both in a frontend and in a backend. It is enabled if
   at least one of the frontend or backend holding a connection has it enabled.
-  It is worth noting that "option forceclose" has precedence over "httpclose",
-  which itself has precedence over "option http-server-close".
+  It is worth noting that "option forceclose" has precedence over "option
+  http-server-close" and that combining "http-server-close" with "httpclose"
+  basically achieve the same result as "forceclose".
 
   If this option has been enabled in a "defaults" section, it can be disabled
   in a specific instance by prepending the "no" keyword before it.
@@ -2562,14 +2566,18 @@ no option httpclose
   be removed.
 
   It seldom happens that some servers incorrectly ignore this header and do not
-  close the connection eventough they reply "Connection: close". For this
-  reason, they are not compatible with older HTTP 1.0 browsers. If this
-  happens it is possible to use the "option forceclose" which actively closes
-  the request connection once the server responds.
+  close the connection eventhough they reply "Connection: close". For this
+  reason, they are not compatible with older HTTP 1.0 browsers. If this happens
+  it is possible to use the "option forceclose" which actively closes the
+  request connection once the server responds. Option "forceclose" also
+  releases the server connection earlier because it does not have to wait for
+  the client to acknowledge it.
 
   This option may be set both in a frontend and in a backend. It is enabled if
   at least one of the frontend or backend holding a connection has it enabled.
   If "option forceclose" is specified too, it has precedence over "httpclose".
+  If "option http-server-close" is enabled at the same time as "httpclose", it
+  basically achieves the same result as "option forceclose".
 
   If this option has been enabled in a "defaults" section, it can be disabled
   in a specific instance by prepending the "no" keyword before it.
index ae7288a7324245d292829529361ecaf19733537f..07e701de9accfd5821309c629a6e3e41947e0ba8 100644 (file)
@@ -1808,17 +1808,21 @@ void http_req_parse_connection_header(struct http_txn *txn)
         * it, so that it can be enforced later.
         */
 
-       if (txn->flags & TX_REQ_VER_11) {       /* HTTP/1.1 */
+       if (conn_cl && conn_ka) {
+               txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
+       }
+       else if (txn->flags & TX_REQ_VER_11) {  /* HTTP/1.1 */
                if (conn_cl) {
-                       txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
-                       if (!conn_ka)
-                               txn->flags |= TX_REQ_CONN_CLO;
+                       txn->flags |= TX_REQ_CONN_CLO;
+                       if ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN)
+                               txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
                }
        } else {        /* HTTP/1.0 */
-               if (!conn_ka)
-                       txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO | TX_REQ_CONN_CLO;
-               else if (conn_cl)
-                       txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
+               if (!conn_ka) {
+                       txn->flags |= TX_REQ_CONN_CLO;
+                       if ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN)
+                               txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
+               }
        }
        txn->flags |= TX_CON_HDR_PARS;
 }
@@ -2616,6 +2620,9 @@ int http_process_req_common(struct session *s, struct buffer *req, int an_bit, s
 
        /* Until set to anything else, the connection mode is set as TUNNEL. It will
         * only change if both the request and the config reference something else.
+        * Option httpclose by itself does not set a mode, it remains a tunnel mode
+        * in which headers are mangled. However, if another mode is set, it will
+        * affect it (eg: server-close/keep-alive + httpclose = close).
         */
 
        if ((txn->meth != HTTP_METH_CONNECT) &&
@@ -2625,10 +2632,7 @@ int http_process_req_common(struct session *s, struct buffer *req, int an_bit, s
                        tmp = TX_CON_WANT_KAL;
                if ((s->fe->options|s->be->options) & PR_O_SERVER_CLO)
                        tmp = TX_CON_WANT_SCL;
-               if ((s->fe->options|s->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))
-                       tmp = TX_CON_WANT_CLO;
-
-               if (!(txn->flags & TX_REQ_XFER_LEN))
+               if ((s->fe->options|s->be->options) & PR_O_FORCE_CLO)
                        tmp = TX_CON_WANT_CLO;
 
                if (!(txn->flags & TX_CON_HDR_PARS))
@@ -2636,6 +2640,13 @@ int http_process_req_common(struct session *s, struct buffer *req, int an_bit, s
 
                if ((txn->flags & TX_CON_WANT_MSK) < tmp)
                        txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | tmp;
+
+               if ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) {
+                       if ((s->fe->options|s->be->options) & PR_O_HTTP_CLOSE)
+                               txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
+                       if (!(txn->flags & TX_REQ_XFER_LEN))
+                               txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
+               }
        }
 
        /* We're really certain of the connection mode (tunnel, close, keep-alive)
@@ -2650,7 +2661,9 @@ int http_process_req_common(struct session *s, struct buffer *req, int an_bit, s
         * Connection header exists. Note that a CONNECT method will not enter
         * here.
         */
-       if (!(txn->flags & TX_REQ_CONN_CLO) && ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL)) {
+       if (!(txn->flags & TX_REQ_CONN_CLO) &&
+           ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL ||
+            ((s->fe->options|s->be->options) & PR_O_HTTP_CLOSE))) {
                char *cur_ptr, *cur_end, *cur_next;
                int old_idx, delta, val;
                int must_delete;
@@ -3070,7 +3083,9 @@ int http_process_request(struct session *s, struct buffer *req, int an_bit)
        }
 
        /* 11: add "Connection: close" if needed and not yet set. */
-       if (!(txn->flags & TX_REQ_CONN_CLO) && ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL)) {
+       if (!(txn->flags & TX_REQ_CONN_CLO) &&
+           ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL ||
+            ((s->fe->options|s->be->options) & PR_O_HTTP_CLOSE))) {
                if (unlikely(http_header_add_tail2(req, &txn->req, &txn->hdr_idx,
                                                   "Connection: close", 17) < 0))
                        goto return_bad_req;
@@ -3471,7 +3486,7 @@ int http_sync_req_state(struct session *s)
                                buffer_shutw_now(buf);
                                buf->cons->flags |= SI_FL_NOLINGER;
                        }
-                       else if ((s->fe->options | s->be->options) & PR_O_FORCE_CLO) {
+                       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.
                                 */
@@ -4322,9 +4337,9 @@ int http_process_res_common(struct session *t, struct buffer *rep, int an_bit, s
         */
 
        if ((txn->meth != HTTP_METH_CONNECT) &&
-           (txn->status >= 200) &&
-           (txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN &&
-           !(txn->flags & TX_CON_HDR_PARS)) {
+           (txn->status >= 200) && !(txn->flags & TX_CON_HDR_PARS) &&
+           ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN ||
+            ((t->fe->options|t->be->options) & PR_O_HTTP_CLOSE))) {
                int may_keep = 0, may_close = 0; /* how it may be understood */
                struct hdr_ctx ctx;
 
@@ -4364,19 +4379,19 @@ int http_process_res_common(struct session *t, struct buffer *rep, int an_bit, s
                 * handled. We also explicitly state that we will close in
                 * case of an ambiguous response having no content-length.
                 */
-               if ((may_close &&
+               if ((may_close && ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) &&
                     (may_keep || ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_SCL))) ||
                    !(txn->flags & TX_RES_XFER_LEN))
                        txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
 
                /* Now we must adjust the response header :
-                *  - set "close" if may_keep and WANT_CLO
+                *  - set "close" if may_keep and (WANT_CLO | httpclose)
                 *  - remove "close" if WANT_SCL and REQ_1.1 and may_close and (content-length or TE_CHNK)
                 *  - add "keep-alive" if WANT_SCL and REQ_1.0 and may_close and content-length
-                *
-                * Until we support the server-close mode, we'll only support the set "close".
                 */
-               if (may_keep && (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_CLO)
+               if (may_keep &&
+                   ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_CLO ||
+                    ((t->fe->options|t->be->options) & PR_O_HTTP_CLOSE)))
                        must_close = 1;
                else if (((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) &&
                         may_close && (txn->flags & TX_RES_XFER_LEN)) {