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.
#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 */
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
*/
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
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;
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 */