diff --git a/doc/haproxy-en.txt b/doc/haproxy-en.txt index 5b6e3c55b..335cff842 100644 --- a/doc/haproxy-en.txt +++ b/doc/haproxy-en.txt @@ -1757,7 +1757,7 @@ know what the client address was (eg for statistics on domains). Last, the 'httpclose' option removes any 'Connection' header both ways, and adds a 'Connection: close' header in each direction. This makes it easier to -disable HTTP keep-alive than the previous 4-rules block.. +disable HTTP keep-alive than the previous 4-rules block. Example : --------- @@ -1769,6 +1769,26 @@ Example : option forwardfor option httpclose +Note that some HTTP servers do not necessarily close the connections when they +receive the 'Connection: close', and if the client does not close either, then +the connection will be maintained up to the time-out. This translates into high +number of simultaneous sessions and high global session times in the logs. To +workaround this, a new option 'forceclose' appeared in version 1.2.9 to enforce +the closing of the outgoing server channel as soon as the server begins to +reply and only if the request buffer is empty. Note that this should NOT be +used if CONNECT requests are expected between the client and the server. The +'forceclose' option implies the 'httpclose' option. + +Example : +--------- + listen http_proxy 0.0.0.0:80 + mode http + log global + option httplog + option dontlognull + option forwardfor + option forceclose + 4.4) Load balancing with persistence ------------------------------------ diff --git a/doc/haproxy-fr.txt b/doc/haproxy-fr.txt index b14238a76..d2a963ce2 100644 --- a/doc/haproxy-fr.txt +++ b/doc/haproxy-fr.txt @@ -1819,6 +1819,27 @@ Exemple : option forwardfor option httpclose +Notons que certains serveurs HTTP ne referment pas nécessairement la session +TCP en fin de traitement lorsqu'ils reçoivent un entête 'Connection: close', +ce qui se traduit par des grands nombres de sessions établies et des temps +globaux très longs sur les requêtes. Pour contourner ce problème, la version +1.2.9 apporte une nouvelle option 'forceclose' qui referme la connexion sortant +vers le serveur dès qu'il commence à répondre et seulement si le tampon de +requête est vide. Attention toutefois à ne PAS utiliser cette option si des +méthodes CONNECT sont attendues entre le client et le serveur. L'option +'forceclose' implique l'option 'httpclose'. + +Exemple : +--------- + listen http_proxy 0.0.0.0:80 + mode http + log global + option httplog + option dontlognull + option forwardfor + option forceclose + + 4.4) Répartition avec persistence --------------------------------- La combinaison de l'insertion de cookie avec la répartition de charge interne diff --git a/haproxy.c b/haproxy.c index c5784a75f..690777624 100644 --- a/haproxy.c +++ b/haproxy.c @@ -326,6 +326,7 @@ int strlcpy2(char *dst, const char *src, int size) { #define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */ #define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */ #define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */ +#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */ /* various session flags */ #define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */ @@ -4234,6 +4235,24 @@ int process_srv(struct session *t) { rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */ t->logs.t_data = tv_diff(&t->logs.tv_accept, &now); + /* client connection already closed or option 'httpclose' required : + * we close the server's outgoing connection right now. + */ + if ((req->l == 0) && + (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) { + FD_CLR(t->srv_fd, StaticWriteEvent); + tv_eternity(&t->swexpire); + + /* We must ensure that the read part is still alive when switching + * to shutw */ + FD_SET(t->srv_fd, StaticReadEvent); + if (t->proxy->srvtimeout) + tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout); + + shutdown(t->srv_fd, SHUT_WR); + t->srv_state = SV_STSHUTW; + } + /* if the user wants to log as soon as possible, without counting bytes from the server, then this is the right moment. */ if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) { @@ -6574,6 +6593,9 @@ int cfg_parse_listen(char *file, int linenum, char **args) { else if (!strcmp(args[1], "httpclose")) /* force connection: close in both directions in HTTP mode */ curproxy->options |= PR_O_HTTP_CLOSE; + else if (!strcmp(args[1], "forceclose")) + /* force connection: close in both directions in HTTP mode and enforce end of session */ + curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE; else if (!strcmp(args[1], "checkcache")) /* require examination of cacheability of the 'set-cookie' field */ curproxy->options |= PR_O_CHK_CACHE;