]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Bug 3643: NTLM helpers stuck in reserved state by Safari
authorAmos Jeffries <squid3@treenet.co.nz>
Thu, 4 Apr 2013 06:15:00 +0000 (00:15 -0600)
committerAmos Jeffries <squid3@treenet.co.nz>
Thu, 4 Apr 2013 06:15:00 +0000 (00:15 -0600)
NTLM failures are not always cleaning up connection-auth credentials
properly. In particular they are not releasing the NTLM helpers when
the connection is closed between challenge and handshake completion.
Resulting in permanently reserved helpers locking up all access
through the proxy.

This change redesigns the connection authentication state management
to move the auth link/unlink operations into the connection state
manager objects instead of being managed by NTLM auth components.
As a result we are able to manage credentials from any auth scheme
consistently and terminate the connection properly on several
error conditions which the auth components are not easily aware of.

 Fix sponsored by Netbox Blue Pty (http://netboxblue.com/)

16 files changed:
SPONSORS.list
src/Makefile.am
src/auth/Acl.cc
src/auth/AclProxyAuth.cc
src/auth/UserRequest.cc
src/auth/UserRequest.h
src/auth/negotiate/UserRequest.cc
src/auth/negotiate/UserRequest.h
src/auth/ntlm/UserRequest.cc
src/auth/ntlm/UserRequest.h
src/client_side.cc
src/client_side.h
src/client_side_request.cc
src/redirect.cc
src/tests/Stub.list
src/tests/stub_client_side.cc [new file with mode: 0644]

index 1608e864eb76252dcdaf42973611596ce6237614..aa1229f01bb3b83ee861b7f7d2427f852fd27feb 100644 (file)
@@ -2,6 +2,13 @@ In addition to the numerous volunteer developers (see CONTRIBUTORS),
 the following organizations have provided non-financial support for
 the Squid Project:
 
+@Squid-3.3:
+Netbox Blue Pty (http://netboxblue.com/)
+
+       Netbox Blue Pty. contributed development resources towards
+       testing and stabilizing of authentication systems in Squid-3.2
+       and Squid-3.3.
+
 @Squid-3.2:
 iiNet Ltd - http://www.iinet.net.au/
 
index 8cab7437f9969ac10d176178bf91f0c656d30fa2..d8c141ca7bd2a444f32b240d7b960234e23da46b 100644 (file)
@@ -1284,6 +1284,7 @@ tests_testACLMaxUserIP_SOURCES= \
        cache_cf.h \
        YesNoNone.h \
        tests/stub_cache_cf.cc \
+       tests/stub_client_side.cc \
        tests/stub_debug.cc \
        tests/stub_DelayId.cc \
        tests/stub_DiskIOModule.cc \
index 6ab23c354bda391bb256c13fe3ed4c6ea9971da7..e388d684968f9432e13095a58e49743f5c514147 100644 (file)
@@ -26,7 +26,7 @@ AuthenticateAcl(ACLChecklist *ch)
         return ACCESS_DENIED;
     } else if (request->flags.sslBumped) {
         debugs(28, 5, "SslBumped request: It is an encapsulated request do not authenticate");
-        checklist->auth_user_request = checklist->conn() != NULL ? checklist->conn()->auth_user_request : request->auth_user_request;
+        checklist->auth_user_request = checklist->conn() != NULL ? checklist->conn()->getAuth() : request->auth_user_request;
         if (checklist->auth_user_request != NULL)
             return ACCESS_ALLOWED;
         else
index 100d38e6a648ace37d6a3c4be56fe28d9f79167d..60d17ccba60a399023911fc99658670e1434cd55 100644 (file)
@@ -163,7 +163,7 @@ ProxyAuthLookup::LookupDone(void *data)
         checklist->auth_user_request = NULL;
 
         if (checklist->conn() != NULL) {
-            checklist->conn()->auth_user_request = NULL;
+            checklist->conn()->setAuth(NULL, "proxy_auth ACL failure");
         }
     }
 
index 899e381964c8b78c5875d0eb965a95caa8eca49b..9d7761af8e381d6c2bccf14c0b8b54dfdd7beab0 100644 (file)
@@ -221,7 +221,7 @@ Auth::UserRequest::addAuthenticationInfoTrailer(HttpReply * rep, int accelerated
 {}
 
 void
-Auth::UserRequest::onConnectionClose(ConnStateData *)
+Auth::UserRequest::releaseAuthServer()
 {}
 
 const char *
@@ -253,7 +253,7 @@ authTryGetUser(Auth::UserRequest::Pointer auth_user_request, ConnStateData * con
     else if (request != NULL && request->auth_user_request != NULL)
         return request->auth_user_request;
     else if (conn != NULL)
-        return conn->auth_user_request;
+        return conn->getAuth();
     else
         return NULL;
 }
@@ -303,7 +303,7 @@ Auth::UserRequest::authenticate(Auth::UserRequest::Pointer * auth_user_request,
 
         /* connection auth we must reset on auth errors */
         if (conn != NULL) {
-            conn->auth_user_request = NULL;
+            conn->setAuth(NULL, "HTTP request missing credentials");
         }
 
         *auth_user_request = NULL;
@@ -315,13 +315,13 @@ Auth::UserRequest::authenticate(Auth::UserRequest::Pointer * auth_user_request,
      * No check for function required in the if: its compulsory for conn based
      * auth modules
      */
-    if (proxy_auth && conn != NULL && conn->auth_user_request != NULL &&
-            authenticateUserAuthenticated(conn->auth_user_request) &&
-            conn->auth_user_request->connLastHeader() != NULL &&
-            strcmp(proxy_auth, conn->auth_user_request->connLastHeader())) {
+    if (proxy_auth && conn != NULL && conn->getAuth() != NULL &&
+            authenticateUserAuthenticated(conn->getAuth()) &&
+            conn->getAuth()->connLastHeader() != NULL &&
+            strcmp(proxy_auth, conn->getAuth()->connLastHeader())) {
         debugs(29, 2, "WARNING: DUPLICATE AUTH - authentication header on already authenticated connection!. AU " <<
-               conn->auth_user_request << ", Current user '" <<
-               conn->auth_user_request->username() << "' proxy_auth " <<
+               conn->getAuth() << ", Current user '" <<
+               conn->getAuth()->username() << "' proxy_auth " <<
                proxy_auth);
 
         /* remove this request struct - the link is already authed and it can't be to reauth. */
@@ -330,7 +330,7 @@ Auth::UserRequest::authenticate(Auth::UserRequest::Pointer * auth_user_request,
          * authenticateAuthenticate
          */
         assert(*auth_user_request == NULL);
-        conn->auth_user_request = NULL;
+        conn->setAuth(NULL, "changed credentials token");
     }
 
     /* we have a proxy auth header and as far as we know this connection has
@@ -342,20 +342,20 @@ Auth::UserRequest::authenticate(Auth::UserRequest::Pointer * auth_user_request,
             debugs(29, 9, HERE << "This is a new checklist test on:" << conn->clientConnection);
         }
 
-        if (proxy_auth && request->auth_user_request == NULL && conn != NULL && conn->auth_user_request != NULL) {
+        if (proxy_auth && request->auth_user_request == NULL && conn != NULL && conn->getAuth() != NULL) {
             Auth::Config * scheme = Auth::Config::Find(proxy_auth);
 
-            if (conn->auth_user_request->user() == NULL || conn->auth_user_request->user()->config != scheme) {
+            if (conn->getAuth()->user() == NULL || conn->getAuth()->user()->config != scheme) {
                 debugs(29, DBG_IMPORTANT, "WARNING: Unexpected change of authentication scheme from '" <<
-                       conn->auth_user_request->user()->config->type() <<
+                       (conn->getAuth()->user()!=NULL?conn->getAuth()->user()->config->type():"[no user]") <<
                        "' to '" << proxy_auth << "' (client " <<
                        src_addr << ")");
 
-                conn->auth_user_request = NULL;
+                conn->setAuth(NULL, "changed auth scheme");
             }
         }
 
-        if (request->auth_user_request == NULL && (conn == NULL || conn->auth_user_request == NULL)) {
+        if (request->auth_user_request == NULL && (conn == NULL || conn->getAuth() == NULL)) {
             /* beginning of a new request check */
             debugs(29, 4, HERE << "No connection authentication type");
 
@@ -378,15 +378,11 @@ Auth::UserRequest::authenticate(Auth::UserRequest::Pointer * auth_user_request,
             *auth_user_request = request->auth_user_request;
         } else {
             assert (conn != NULL);
-            if (conn->auth_user_request != NULL) {
-                *auth_user_request = conn->auth_user_request;
+            if (conn->getAuth() != NULL) {
+                *auth_user_request = conn->getAuth();
             } else {
                 /* failed connection based authentication */
-                debugs(29, 4, HERE << "Auth user request " <<
-                       *auth_user_request << " conn-auth user request " <<
-                       conn->auth_user_request << " conn type " <<
-                       conn->auth_user_request->user()->auth_type << " authentication failed.");
-
+                debugs(29, 4, HERE << "Auth user request " << *auth_user_request << " conn-auth missing and failed to authenticate.");
                 *auth_user_request = NULL;
                 return AUTH_ACL_CHALLENGE;
             }
index a59337539f37a101b6c0298816c8926bceaca3f5..beed1b994218645abe3e78a922844478b145719e 100644 (file)
@@ -155,7 +155,7 @@ public:
     /* add the [Proxy-]Authentication-Info trailer */
     virtual void addAuthenticationInfoTrailer(HttpReply * rep, int accel);
 
-    virtual void onConnectionClose(ConnStateData *);
+    virtual void releaseAuthServer();
 
     /**
      * Called when squid is ready to put the request on hold and wait for a callback from the auth module
index d4f08a7f362a40a614bb80f801dee2b209ef5823..5c6f29c4f84412b363e3fdc8694cade54bfd4059 100644 (file)
@@ -129,27 +129,6 @@ Auth::Negotiate::UserRequest::releaseAuthServer()
         debugs(29, 6, HERE << "No Negotiate auth server to release.");
 }
 
-/* clear any connection related authentication details */
-void
-Auth::Negotiate::UserRequest::onConnectionClose(ConnStateData *conn)
-{
-    assert(conn != NULL);
-
-    debugs(29, 8, HERE << "closing connection '" << conn << "' (this is '" << this << "')");
-
-    if (conn->auth_user_request == NULL) {
-        debugs(29, 8, HERE << "no auth_user_request");
-        return;
-    }
-
-    releaseAuthServer();
-
-    /* unlock the connection based lock */
-    debugs(29, 9, HERE << "Unlocking auth_user from the connection '" << conn << "'.");
-
-    conn->auth_user_request = NULL;
-}
-
 void
 Auth::Negotiate::UserRequest::authenticate(HttpRequest * aRequest, ConnStateData * conn, http_hdr_type type)
 {
@@ -199,8 +178,8 @@ Auth::Negotiate::UserRequest::authenticate(HttpRequest * aRequest, ConnStateData
         user()->credentials(Auth::Pending);
         safe_free(client_blob);
         client_blob=xstrdup(blob);
-        assert(conn->auth_user_request == NULL);
-        conn->auth_user_request = this;
+        assert(conn->getAuth() == NULL);
+        conn->setAuth(this, "new Negotiate handshake request");
         request = aRequest;
         HTTPMSGLOCK(request);
         break;
index 79c0e19f19ff8251e75f1babf4160d81321692b6..98276841d46b8a689fcb9e16542f2c41ac2c5a43 100644 (file)
@@ -26,7 +26,6 @@ public:
     virtual int authenticated() const;
     virtual void authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type);
     virtual Direction module_direction();
-    virtual void onConnectionClose(ConnStateData *);
     virtual void module_start(AUTHCB *, void *);
 
     virtual void addAuthenticationInfoHeader(HttpReply * rep, int accel);
index eca993bf02a09b09177e82017d390ade15434223..696119a0033dae116e5d60dffd6c7b53b954df67 100644 (file)
@@ -122,26 +122,6 @@ Auth::Ntlm::UserRequest::releaseAuthServer()
         debugs(29, 6, HERE << "No NTLM auth server to release.");
 }
 
-void
-Auth::Ntlm::UserRequest::onConnectionClose(ConnStateData *conn)
-{
-    assert(conn != NULL);
-
-    debugs(29, 8, HERE << "closing connection '" << conn << "' (this is '" << this << "')");
-
-    if (conn->auth_user_request == NULL) {
-        debugs(29, 8, HERE << "no auth_user_request");
-        return;
-    }
-
-    releaseAuthServer();
-
-    /* unlock the connection based lock */
-    debugs(29, 9, HERE << "Unlocking auth_user from the connection '" << conn << "'.");
-
-    conn->auth_user_request = NULL;
-}
-
 void
 Auth::Ntlm::UserRequest::authenticate(HttpRequest * aRequest, ConnStateData * conn, http_hdr_type type)
 {
@@ -192,8 +172,8 @@ Auth::Ntlm::UserRequest::authenticate(HttpRequest * aRequest, ConnStateData * co
         user()->credentials(Auth::Pending);
         safe_free(client_blob);
         client_blob=xstrdup(blob);
-        assert(conn->auth_user_request == NULL);
-        conn->auth_user_request = this;
+        assert(conn->getAuth() == NULL);
+        conn->setAuth(this, "new NTLM handshake request");
         request = aRequest;
         HTTPMSGLOCK(request);
         break;
index 406ae5e305443378aa7d29558fead6e6182442ff..396e86038cf009e8fe98e097829dbc66b23f1204 100644 (file)
@@ -26,14 +26,13 @@ public:
     virtual int authenticated() const;
     virtual void authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type);
     virtual Auth::Direction module_direction();
-    virtual void onConnectionClose(ConnStateData *);
     virtual void module_start(AUTHCB *, void *);
 
     virtual const char * connLastHeader();
 
     /* we need to store the helper server between requests */
     helper_stateful_server *authserver;
-    void releaseAuthServer(void); ///< Release authserver NTLM helpers properly when finished or abandoning.
+    virtual void releaseAuthServer(); ///< Release authserver NTLM helpers properly when finished or abandoning.
 
     /* our current blob to pass to the client */
     char *server_blob;
index 25ed433d670bc9bcfd6f76f75e94e32220933714..7ad866991848eb34be4a29909271b571e118656a 100644 (file)
@@ -793,6 +793,87 @@ void ConnStateData::connStateClosed(const CommCloseCbParams &io)
     deleteThis("ConnStateData::connStateClosed");
 }
 
+#if USE_AUTH
+void
+ConnStateData::setAuth(const Auth::UserRequest::Pointer &aur, const char *by)
+{
+    if (auth_ == NULL) {
+        if (aur != NULL) {
+            debugs(33, 2, "Adding connection-auth to " << clientConnection << " from " << by);
+            auth_ = aur;
+        }
+        return;
+    }
+
+    // clobered with self-pointer
+    // NP: something nasty is going on in Squid, but harmless.
+    if (aur == auth_) {
+        debugs(33, 2, "WARNING: Ignoring duplicate connection-auth for " << clientConnection << " from " << by);
+        return;
+    }
+
+    /*
+     * Connection-auth relies on a single set of credentials being preserved
+     * for all requests on a connection once they have been setup.
+     * There are several things which need to happen to preserve security
+     * when connection-auth credentials change unexpectedly or are unset.
+     *
+     * 1) auth helper released from any active state
+     *
+     * They can only be reserved by a handshake process which this
+     * connection can now never complete.
+     * This prevents helpers hanging when their connections close.
+     *
+     * 2) pinning is expected to be removed and server conn closed
+     *
+     * The upstream link is authenticated with the same credentials.
+     * Expecting the same level of consistency we should have received.
+     * This prevents upstream being faced with multiple or missing
+     * credentials after authentication.
+     * NP: un-pin is left to the cleanup in ConnStateData::swanSong()
+     *     we just trigger that cleanup here via comm_reset_close() or
+     *     ConnStateData::stopReceiving()
+     *
+     * 3) the connection needs to close.
+     *
+     * This prevents attackers injecting requests into a connection,
+     * or gateways wrongly multiplexing users into a single connection.
+     *
+     * When credentials are missing closure needs to follow an auth
+     * challenge for best recovery by the client.
+     *
+     * When credentials change there is nothing we can do but abort as
+     * fast as possible. Sending TCP RST instead of an HTTP response
+     * is the best-case action.
+     */
+
+    // clobbered with nul-pointer
+    if (aur == NULL) {
+        debugs(33, 2, "WARNING: Graceful closure on " << clientConnection << " due to connection-auth erase from " << by);
+        auth_->releaseAuthServer();
+        auth_ = NULL;
+        // XXX: need to test whether the connection re-auth challenge is sent. If not, how to trigger it from here.
+        // NP: the current situation seems to fix challenge loops in Safari without visible issues in others.
+        // we stop receiving more traffic but can leave the Job running to terminate after the error or challenge is delivered.
+        stopReceiving("connection-auth removed");
+        return;
+    }
+
+    // clobbered with alternative credentials
+    if (aur != auth_) {
+        debugs(33, 2, "ERROR: Closing " << clientConnection << " due to change of connection-auth from " << by);
+        auth_->releaseAuthServer();
+        auth_ = NULL;
+        // this is a fatal type of problem.
+        // Close the connection immediately with TCP RST to abort all traffic flow
+        comm_reset_close(clientConnection);
+        return;
+    }
+
+    /* NOT REACHABLE */
+}
+#endif
+
 // cleans up before destructor is called
 void
 ConnStateData::swanSong()
@@ -802,12 +883,6 @@ ConnStateData::swanSong()
     clientdbEstablished(clientConnection->remote, -1); /* decrement */
     assert(areAllContextsForThisConnection());
     freeAllContexts();
-#if USE_AUTH
-    if (auth_user_request != NULL) {
-        debugs(33, 4, "ConnStateData::swanSong: freeing auth_user_request '" << auth_user_request << "' (this is '" << this << "')");
-        auth_user_request->onConnectionClose(this);
-    }
-#endif
 
     unpinConnection();
 
@@ -815,6 +890,11 @@ ConnStateData::swanSong()
         clientConnection->close();
     clientConnection = NULL;
 
+#if USE_AUTH
+    // NP: do this bit after closing the connections to avoid side effects from unwanted TCP RST
+    setAuth(NULL, "ConnStateData::SwanSong cleanup");
+#endif
+
     BodyProducer::swanSong();
     flags.swanSang = true;
 }
@@ -2682,8 +2762,8 @@ clientProcessRequest(ConnStateData *conn, HttpParser *hp, ClientSocketContext *c
                               !conn->port->allow_direct : 0;
 #if USE_AUTH
     if (request->flags.sslBumped) {
-        if (conn->auth_user_request != NULL)
-            request->auth_user_request = conn->auth_user_request;
+        if (conn->getAuth() != NULL)
+            request->auth_user_request = conn->getAuth();
     }
 #endif
 
index 208b3bf3619e2bd3278af0b440a96fe3e0900f83..ffe33e58ce46cb157a92b88e51ab7c71af393be4 100644 (file)
@@ -239,10 +239,20 @@ public:
 
 #if USE_AUTH
     /**
-     * note this is ONLY connection based because NTLM and Negotiate is against HTTP spec.
-     * the user details for connection based authentication
+     * Fetch the user details for connection based authentication
+     * NOTE: this is ONLY connection based because NTLM and Negotiate is against HTTP spec.
      */
-    Auth::UserRequest::Pointer auth_user_request;
+    const Auth::UserRequest::Pointer &getAuth() const { return auth_; }
+
+    /**
+     * Set the user details for connection-based authentication to use from now until connection closure.
+     *
+     * Any change to existing credentials shows that something invalid has happened. Such as:
+     * - NTLM/Negotiate auth was violated by the per-request headers missing a revalidation token
+     * - NTLM/Negotiate auth was violated by the per-request headers being for another user
+     * - SSL-Bump CONNECT tunnel with persistent credentials has ended
+     */
+    void setAuth(const Auth::UserRequest::Pointer &aur, const char *cause);
 #endif
 
     /**
@@ -383,7 +393,11 @@ private:
     int connFinishedWithConn(int size);
     void clientAfterReadingRequests();
 
-private:
+#if USE_AUTH
+    /// some user details that can be used to perform authentication on this connection
+    Auth::UserRequest::Pointer auth_;
+#endif
+
     HttpParser parser_;
 
     // XXX: CBDATA plays with public/private and leaves the following 'private' fields all public... :(
index a4c356463f8959d757595a9a9d430709d2cb36ba..8e80ba33520e8fea48ccf454e0cab71457e8dec4 100644 (file)
@@ -616,8 +616,8 @@ ClientRequestContext::hostHeaderVerifyFailed(const char *A, const char *B)
                                 http->request,
                                 NULL,
 #if USE_AUTH
-                                http->getConn() != NULL && http->getConn()->auth_user_request != NULL ?
-                                http->getConn()->auth_user_request : http->request->auth_user_request);
+                                http->getConn() != NULL && http->getConn()->getAuth() != NULL ?
+                                http->getConn()->getAuth() : http->request->auth_user_request);
 #else
                                 NULL);
 #endif
@@ -785,8 +785,8 @@ ClientRequestContext::clientAccessCheckDone(const allow_t &answer)
 
 #if USE_AUTH
     char const *proxy_auth_msg = "<null>";
-    if (http->getConn() != NULL && http->getConn()->auth_user_request != NULL)
-        proxy_auth_msg = http->getConn()->auth_user_request->denyMessage("<null>");
+    if (http->getConn() != NULL && http->getConn()->getAuth() != NULL)
+        proxy_auth_msg = http->getConn()->getAuth()->denyMessage("<null>");
     else if (http->request->auth_user_request != NULL)
         proxy_auth_msg = http->request->auth_user_request->denyMessage("<null>");
 #endif
@@ -849,8 +849,8 @@ ClientRequestContext::clientAccessCheckDone(const allow_t &answer)
 
 #if USE_AUTH
         error->auth_user_request =
-            http->getConn() != NULL && http->getConn()->auth_user_request != NULL ?
-            http->getConn()->auth_user_request : http->request->auth_user_request;
+            http->getConn() != NULL && http->getConn()->getAuth() != NULL ?
+            http->getConn()->getAuth() : http->request->auth_user_request;
 #endif
 
         readNextRequest = true;
@@ -1607,7 +1607,7 @@ ClientHttpRequest::sslBumpEstablish(comm_err_t errflag)
 #if USE_AUTH
     // Preserve authentication info for the ssl-bumped request
     if (request->auth_user_request != NULL)
-        getConn()->auth_user_request = request->auth_user_request;
+        getConn()->setAuth(request->auth_user_request, "SSL-bumped CONNECT");
 #endif
 
     assert(sslBumpNeeded());
@@ -2089,7 +2089,7 @@ ClientHttpRequest::handleAdaptationFailure(int errDetail, bool bypassable)
                                                 );
 #if USE_AUTH
         calloutContext->error->auth_user_request =
-            c != NULL && c->auth_user_request != NULL ? c->auth_user_request : request->auth_user_request;
+            c != NULL && c->getAuth() != NULL ? c->getAuth() : request->auth_user_request;
 #endif
         calloutContext->error->detailError(errDetail);
         calloutContext->readNextRequest = true;
index 2f0cf74c6887f7d97e33f5968b7a4e03539d9aeb..4ede04722ae953fed5f185f4b308344515ae8e4a 100644 (file)
@@ -301,8 +301,8 @@ constructHelperQuery(const char *name, helper *hlp, HLPCB *replyHandler, ClientH
                                     http->request,
                                     NULL,
 #if USE_AUTH
-                                    http->getConn() != NULL && http->getConn()->auth_user_request != NULL ?
-                                    http->getConn()->auth_user_request : http->request->auth_user_request);
+                                    http->getConn() != NULL && http->getConn()->getAuth() != NULL ?
+                                    http->getConn()->getAuth() : http->request->auth_user_request);
 #else
                                     NULL);
 #endif
index fe076a7402f7df29f756181861faded8234f8f5e..196c3a9fd3e3cd2592d4ff8820c990fe011c9c9a 100644 (file)
@@ -17,6 +17,7 @@ STUB_SOURCE= tests/STUB.h \
        tests/stub_cache_manager.cc \
        tests/stub_cbdata.cc \
        tests/stub_client_db.cc \
+       tests/stub_client_side.cc \
        tests/stub_client_side_request.cc \
        tests/stub_comm.cc \
        tests/stub_debug.cc \
diff --git a/src/tests/stub_client_side.cc b/src/tests/stub_client_side.cc
new file mode 100644 (file)
index 0000000..77d9ff4
--- /dev/null
@@ -0,0 +1,84 @@
+#include "squid.h"
+#include "client_side.h"
+
+#define STUB_API "client_side.cc"
+#include "tests/STUB.h"
+
+ClientSocketContext::ClientSocketContext() STUB
+ClientSocketContext::~ClientSocketContext() STUB
+bool ClientSocketContext::startOfOutput() const STUB_RETVAL(false)
+void ClientSocketContext::writeComplete(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, comm_err_t errflag) STUB
+void ClientSocketContext::keepaliveNextRequest() STUB
+void ClientSocketContext::pullData() STUB
+int64_t ClientSocketContext::getNextRangeOffset() const STUB_RETVAL(0)
+bool ClientSocketContext::canPackMoreRanges() const STUB_RETVAL(false)
+clientStream_status_t ClientSocketContext::socketState() STUB_RETVAL(STREAM_NONE)
+void ClientSocketContext::sendBody(HttpReply * rep, StoreIOBuffer bodyData) STUB
+void ClientSocketContext::sendStartOfMessage(HttpReply * rep, StoreIOBuffer bodyData) STUB
+size_t ClientSocketContext::lengthToSend(Range<int64_t> const &available) STUB_RETVAL(0)
+void ClientSocketContext::noteSentBodyBytes(size_t) STUB
+void ClientSocketContext::buildRangeHeader(HttpReply * rep) STUB
+clientStreamNode * ClientSocketContext::getTail() const STUB_RETVAL(NULL)
+clientStreamNode * ClientSocketContext::getClientReplyContext() const STUB_RETVAL(NULL)
+void ClientSocketContext::connIsFinished() STUB
+void ClientSocketContext::removeFromConnectionList(ConnStateData * conn) STUB
+void ClientSocketContext::deferRecipientForLater(clientStreamNode * node, HttpReply * rep, StoreIOBuffer receivedData) STUB
+bool ClientSocketContext::multipartRangeRequest() const STUB_RETVAL(false)
+void ClientSocketContext::registerWithConn() STUB
+void ClientSocketContext::noteIoError(const int xerrno) STUB
+void ClientSocketContext::writeControlMsg(HttpControlMsg &msg) STUB
+
+void ConnStateData::readSomeData() STUB
+int ConnStateData::getAvailableBufferLength() const STUB_RETVAL(0)
+bool ConnStateData::areAllContextsForThisConnection() const STUB_RETVAL(false)
+void ConnStateData::freeAllContexts() STUB
+void ConnStateData::notifyAllContexts(const int xerrno) STUB
+bool ConnStateData::clientParseRequests() STUB_RETVAL(false)
+void ConnStateData::readNextRequest() STUB
+bool ConnStateData::maybeMakeSpaceAvailable() STUB_RETVAL(false)
+void ConnStateData::addContextToQueue(ClientSocketContext * context) STUB
+int ConnStateData::getConcurrentRequestCount() const STUB_RETVAL(0)
+bool ConnStateData::isOpen() const STUB_RETVAL(false)
+void ConnStateData::checkHeaderLimits() STUB
+void ConnStateData::sendControlMsg(HttpControlMsg msg) STUB
+char *ConnStateData::In::addressToReadInto() const STUB_RETVAL(NULL)
+int64_t ConnStateData::mayNeedToReadMoreBody() const STUB_RETVAL(0)
+#if USE_AUTH
+void ConnStateData::setAuth(const Auth::UserRequest::Pointer &aur, const char *cause) STUB
+#endif
+bool ConnStateData::transparent() const STUB_RETVAL(false)
+bool ConnStateData::reading() const STUB_RETVAL(false)
+void ConnStateData::stopReading() STUB
+void ConnStateData::stopReceiving(const char *error) STUB
+void ConnStateData::stopSending(const char *error) STUB
+void ConnStateData::expectNoForwarding() STUB
+void ConnStateData::noteMoreBodySpaceAvailable(BodyPipe::Pointer) STUB
+void ConnStateData::noteBodyConsumerAborted(BodyPipe::Pointer) STUB
+bool ConnStateData::handleReadData(char *buf, size_t size) STUB_RETVAL(false)
+bool ConnStateData::handleRequestBodyData() STUB_RETVAL(false)
+void ConnStateData::pinConnection(const Comm::ConnectionPointer &pinServerConn, HttpRequest *request, CachePeer *peer, bool auth) STUB
+void ConnStateData::unpinConnection() STUB
+const Comm::ConnectionPointer ConnStateData::validatePinnedConnection(HttpRequest *request, const CachePeer *peer) STUB_RETVAL(NULL)
+void ConnStateData::clientPinnedConnectionClosed(const CommCloseCbParams &io) STUB
+void ConnStateData::clientReadRequest(const CommIoCbParams &io) STUB
+void ConnStateData::connStateClosed(const CommCloseCbParams &io) STUB
+void ConnStateData::requestTimeout(const CommTimeoutCbParams &params) STUB
+void ConnStateData::swanSong() STUB
+void ConnStateData::quitAfterError(HttpRequest *request) STUB
+#if USE_SSL
+void ConnStateData::httpsPeeked(Comm::ConnectionPointer serverConnection) STUB
+void ConnStateData::getSslContextStart() STUB
+void ConnStateData::getSslContextDone(SSL_CTX * sslContext, bool isNew) STUB
+void ConnStateData::sslCrtdHandleReplyWrapper(void *data, const HelperReply &reply) STUB
+void ConnStateData::sslCrtdHandleReply(const HelperReply &reply) STUB
+void ConnStateData::switchToHttps(HttpRequest *request, Ssl::BumpMode bumpServerMode) STUB
+void ConnStateData::buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties) STUB
+bool ConnStateData::serveDelayedError(ClientSocketContext *context) STUB_RETVAL(false)
+#endif
+
+void setLogUri(ClientHttpRequest * http, char const *uri, bool cleanUrl) STUB
+const char *findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end) STUB_RETVAL(NULL)
+int varyEvaluateMatch(StoreEntry * entry, HttpRequest * req) STUB_RETVAL(0)
+void clientOpenListenSockets(void) STUB
+void clientHttpConnectionsClose(void) STUB
+void httpRequestFree(void *) STUB