MINOR: http: try to stick to same server after status 401/407

In HTTP keep-alive mode, if we receive a 401, we still have a chance
of being able to send the visitor again to the same server over the
same connection. This is required by some broken protocols such as
NTLM, and anyway whenever there is an opportunity for sending the
challenge to the proper place, it's better to do it (at least it
helps with debugging).
This commit is contained in:
Willy Tarreau 2013-12-23 15:11:25 +01:00
parent 9f708ab707
commit 068621e4ad
5 changed files with 25 additions and 3 deletions

View File

@ -4446,7 +4446,13 @@ no option prefer-last-server
this option is used, haproxy will try to reuse the same connection that is
attached to the server instead of rebalancing to another server, causing a
close of the connection. This can make sense for static file servers. It does
not make much sense to use this in combination with hashing algorithms.
not make much sense to use this in combination with hashing algorithms. Note,
haproxy already automatically tries to stick to a server which sends a 401 or
to a proxy which sends a 407 (authentication required). This is mandatory for
use with the broken NTLM authentication challenge, and significantly helps in
troubleshooting some faulty applications. Option prefer-last-server might be
desirable in these environments as well, to avoid redistributing the traffic
after every other response.
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.

View File

@ -83,7 +83,7 @@
#define TX_CON_CLO_SET 0x00400000 /* "connection: close" is now set */
#define TX_CON_KAL_SET 0x00800000 /* "connection: keep-alive" is now set */
/* Unused: 0x1000000 */
#define TX_PREFER_LAST 0x01000000 /* try to stay on same server if possible (eg: after 401) */
#define TX_HDR_CONN_UPG 0x02000000 /* The "Upgrade" token was found in the "Connection" header */
#define TX_WAIT_NEXT_RQ 0x04000000 /* waiting for the second request to start, use keep-alive timeout */

View File

@ -534,7 +534,8 @@ int assign_server(struct session *s)
s->target = NULL;
conn = objt_conn(s->req->cons->end);
if (conn && (s->be->options & PR_O_PREF_LAST) &&
if (conn &&
((s->be->options & PR_O_PREF_LAST) || (s->txn.flags & TX_PREFER_LAST)) &&
objt_server(conn->target) && __objt_server(conn->target)->proxy == s->be &&
srv_is_usable(__objt_server(conn->target)->state, __objt_server(conn->target)->eweight)) {
/* This session was relying on a server in a previous request

View File

@ -4281,6 +4281,8 @@ int http_send_name_header(struct http_txn *txn, struct proxy* be, const char* sr
*/
void http_end_txn_clean_session(struct session *s)
{
int prev_status = s->txn.status;
/* FIXME: We need a more portable way of releasing a backend's and a
* server's connections. We need a safer way to reinitialize buffer
* flags. We also need a more accurate method for computing per-request
@ -4395,6 +4397,18 @@ void http_end_txn_clean_session(struct session *s)
s->txn.meth = 0;
http_reset_txn(s);
s->txn.flags |= TX_NOT_FIRST | TX_WAIT_NEXT_RQ;
if (prev_status == 401 || prev_status == 407) {
/* In HTTP keep-alive mode, if we receive a 401, we still have
* a chance of being able to send the visitor again to the same
* server over the same connection. This is required by some
* broken protocols such as NTLM, and anyway whenever there is
* an opportunity for sending the challenge to the proper place,
* it's better to do it (at least it helps with debugging).
*/
s->txn.flags |= TX_PREFER_LAST;
}
if (s->fe->options2 & PR_O2_INDEPSTR)
s->req->cons->flags |= SI_FL_INDEP_STR;

View File

@ -536,6 +536,7 @@ int session_complete(struct session *s)
txn->rsp.cap = NULL;
txn->hdr_idx.v = NULL;
txn->hdr_idx.size = txn->hdr_idx.used = 0;
txn->flags = 0;
txn->req.flags = 0;
txn->rsp.flags = 0;
/* the HTTP messages need to know what buffer they're associated with */