]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: http: try to stick to same server after status 401/407
authorWilly Tarreau <w@1wt.eu>
Mon, 23 Dec 2013 14:11:25 +0000 (15:11 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 23 Dec 2013 14:12:44 +0000 (15:12 +0100)
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).

doc/configuration.txt
include/types/proto_http.h
src/backend.c
src/proto_http.c
src/session.c

index 54005155f9d59b013cb1a2bf333b490da0f83614..98310214a71260cbbf3e8f1398d883b5501d61c4 100644 (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.
index 9d65d6f3ad2527e378820dea365933a77f576385..957ac02348842c26b781852910fbca38f69dabc1 100644 (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 */
index a80b6b44187c0339991a31854b1e80583796d2e1..8fcce7dd2ecae48d858903e4022f60ee297f27e8 100644 (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
index 2c6e27273c18c9bf37cfffec0615b0434f350f22..624a51fa38c62e35fc0bf0d9fd56705a1d6c5b45 100644 (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;
 
index fa5d6452c41187901b4cca3f6c1281a74b2aaf82..f06d06bbf2ae4ca66d1c0bc7629dc0072a99a168 100644 (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 */