diff --git a/doc/configuration.txt b/doc/configuration.txt index 2292674a8..2b980d5a3 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -829,6 +829,7 @@ option dontlognull (*) X X X - option forceclose (*) X X X X -- keyword -------------------------- defaults - frontend - listen -- backend - option forwardfor X X X X +option http-pretend-keepalive (*) X X X X option http-server-close (*) X X X X option http-use-proxy-header (*) X X X - option httpchk X - X X @@ -2619,10 +2620,14 @@ no option forceclose means we can close the connection to the server very quickly, releasing some resources earlier than with httpclose. + This option may also be combined with "option http-pretend-keepalive", which + will disable sending of the "Connection: close" header, but will still cause + the connection to be closed once the whole response is received. + 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. - See also : "option httpclose" + See also : "option httpclose" and "option http-pretend-keepalive" option forwardfor [ except ] [ header ] @@ -2685,6 +2690,48 @@ option forwardfor [ except ] [ header ] See also : "option httpclose" +option http-pretend-keepalive +no option http-pretend-keepalive + Define whether haproxy will announce keepalive to the server or not + May be used in sections : defaults | frontend | listen | backend + yes | yes | yes | yes + Arguments : none + + When running with "option http-server-close" or "option forceclose", haproxy + adds a "Connection: close" header to the request forwarded to the server. + Unfortunately, when some servers see this header, they automatically refrain + from using the chunked encoding for responses of unknown length, while this + is totally unrelated. The immediate effect is that this prevents haproxy from + maintaining the client connection alive. A second effect is that a client or + a cache could receive an incomplete response without being aware of it, and + consider the response complete. + + By setting "option http-pretend-keepalive", haproxy will make the server + believe it will keep the connection alive. The server will then not fall back + to the abnormal undesired above. When haproxy gets the whole response, it + will close the connection with the server just as it would do with the + "forceclose" option. That way the client gets a normal response and the + connection is correctly closed on the server side. + + It is recommended not to enable this option by default, because most servers + will more efficiently close the connection themselves after the last packet, + and release its buffers slightly earlier. Also, the added packet on the + network could slightly reduce the overall peak performance. However it is + worth noting that when this option is enabled, haproxy will have slightly + less work to do. So if haproxy is the bottleneck on the whole architecture, + enabling this option might save a few CPU cycles. + + 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. + This option has no effect if it is combined with "option httpclose", which + has precedence. + + 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. + + See also : "option forceclose" and "option http-server-close" + + option http-server-close no option http-server-close Enable or disable HTTP connection closing on the server side @@ -2698,7 +2745,10 @@ no option http-server-close fastest session reuse on the server side to save server resources, similarly to "option forceclose". It also permits non-keepalive capable servers to be served in keep-alive mode to the clients if they conform to the requirements - of RFC2616. + of RFC2616. Please note that some servers do not always conform to those + requirements when they see "Connection: close" in the request. The effect + will be that keep-alive will never be used. A workaround consists in enabling + "option http-pretend-keepalive". At the moment, logs will not indicate whether requests came from the same session or not. The accept date reported in the logs corresponds to the end @@ -2716,7 +2766,8 @@ no option http-server-close 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. - See also : "option forceclose" and "option httpclose" + See also : "option forceclose", "option http-pretend-keepalive" and + "option httpclose". option http-use-proxy-header diff --git a/include/types/proxy.h b/include/types/proxy.h index c3fd01a51..fb3451382 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -138,6 +138,7 @@ #define PR_O2_USE_PXHDR 0x00040000 /* use Proxy-Connection for proxy requests */ #define PR_O2_CHK_SNDST 0x00080000 /* send the state of each server along with HTTP health checks */ #define PR_O2_SSL3_CHK 0x00100000 /* use SSLv3 CLIENT_HELLO packets for server health */ +#define PR_O2_FAKE_KA 0x00200000 /* pretend we do keep-alive with server eventhough we close */ /* end of proxy->options2 */ /* bits for sticking rules */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 6af60da6c..dca5e6c57 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -150,6 +150,7 @@ static const struct cfg_opt cfg_opts2[] = { "tcp-smart-connect", PR_O2_SMARTCON, PR_CAP_BE, 0, 0 }, { "independant-streams", PR_O2_INDEPSTR, PR_CAP_FE|PR_CAP_BE, 0, 0 }, { "http-use-proxy-header", PR_O2_USE_PXHDR, PR_CAP_FE, 0, PR_MODE_HTTP }, + { "http-pretend-keepalive", PR_O2_FAKE_KA, PR_CAP_FE, 0, PR_MODE_HTTP }, { NULL, 0, 0, 0 } }; diff --git a/src/proto_http.c b/src/proto_http.c index 90f984827..6e8fa411f 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -2967,7 +2967,8 @@ int http_process_req_common(struct session *s, struct buffer *req, int an_bit, s /* parse the Connection header and possibly clean it */ int to_del = 0; if ((txn->flags & TX_REQ_VER_11) || - (txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL) + ((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 (!(txn->flags & TX_REQ_VER_11)) to_del |= 1; /* remove "close" */ @@ -3405,11 +3406,14 @@ int http_process_request(struct session *s, struct buffer *req, int an_bit) unsigned int want_flags = 0; if (txn->flags & TX_REQ_VER_11) { - if ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL || + if (((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL && + !((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA)) || ((s->fe->options|s->be->options) & PR_O_HTTP_CLOSE)) want_flags |= TX_CON_CLO_SET; } else { - if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL) + if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL || + (((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA) && + !((s->fe->options|s->be->options) & PR_O_HTTP_CLOSE))) want_flags |= TX_CON_KAL_SET; }