]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Bug 3371: CONNECT with data sent at once loses data
authorAmos Jeffries <squid3@treenet.co.nz>
Wed, 23 Apr 2014 10:40:36 +0000 (04:40 -0600)
committerAmos Jeffries <squid3@treenet.co.nz>
Wed, 23 Apr 2014 10:40:36 +0000 (04:40 -0600)
src/client_side.cc
src/tunnel.cc

index 4f928bd255fe9a3cb308d8bd2e3166b9a453e614..e4fae95f466358a0af340523dc8777dcbe5dfee2 100644 (file)
@@ -2864,6 +2864,10 @@ clientProcessRequest(ConnStateData *conn, HttpParser *hp, ClientSocketContext *c
     if (http->request->method == Http::METHOD_CONNECT) {
         context->mayUseConnection(true);
         conn->flags.readMore = false;
+
+        // consume header early so that tunnel gets just the body
+        connNoteUseOfBuffer(conn, http->req_sz);
+        notedUseOfBuffer = true;
     }
 
 #if USE_SSL
index 37cc5f700b4cdccbe73fbd4a7e60d933f501a159..a1d50f2e6d290976f7f2c8dbe372af79000f4b4c 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "squid.h"
 #include "acl/FilledChecklist.h"
+#include "base/CbcPointer.h"
 #include "base/Vector.h"
 #include "CachePeer.h"
 #include "client_side_request.h"
@@ -99,6 +100,7 @@ public:
 
     bool noConnections() const;
     char *url;
+    CbcPointer<ClientHttpRequest> http;
     HttpRequest::Pointer request;
     AccessLogEntryPointer al;
     Comm::ConnectionList serverDestinations;
@@ -225,6 +227,7 @@ tunnelClientClosed(const CommCloseCbParams &params)
 
 TunnelStateData::TunnelStateData() :
         url(NULL),
+        http(),
         request(NULL),
         status_ptr(NULL),
         connectRespBuf(NULL),
@@ -675,11 +678,27 @@ tunnelStartShoveling(TunnelStateData *tunnelState)
     assert(!tunnelState->waitingForConnectExchange());
     *tunnelState->status_ptr = Http::scOkay;
     if (cbdataReferenceValid(tunnelState)) {
+
+        // Shovel any payload already pushed into reply buffer by the server response
         if (!tunnelState->server.len)
             tunnelState->copyRead(tunnelState->server, TunnelStateData::ReadServer);
-        else
+        else {
+            debugs(26, DBG_DATA, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState->server.buf, tunnelState->server.len) << "\n----------");
             tunnelState->copy(tunnelState->server.len, tunnelState->server, tunnelState->client, TunnelStateData::WriteClientDone);
-        tunnelState->copyRead(tunnelState->client, TunnelStateData::ReadClient);
+        }
+
+        // Bug 3371: shovel any payload already pushed into ConnStateData by the client request
+        if (tunnelState->http.valid() && tunnelState->http->getConn() && !tunnelState->http->getConn()->in.notYetUsed) {
+            struct ConnStateData::In *in = &tunnelState->http->getConn()->in;
+            debugs(26, DBG_DATA, "Tunnel client PUSH Payload: \n" << Raw("", in->buf, in->notYetUsed) << "\n----------");
+
+            // We just need to ensure the bytes from ConnStateData are in client.buf already to deliver
+            memcpy(tunnelState->client.buf, in->buf, in->notYetUsed);
+            // NP: readClient() takes care of buffer length accounting.
+            tunnelState->readClient(tunnelState->client.buf, in->notYetUsed, COMM_OK, 0);
+            in->notYetUsed = 0; // ConnStateData buffer accounting after the shuffle.
+        } else
+            tunnelState->copyRead(tunnelState->client, TunnelStateData::ReadClient);
     }
 }
 
@@ -891,6 +910,7 @@ tunnelStart(ClientHttpRequest * http, int64_t * size_ptr, int *status_ptr, const
     tunnelState->server.size_ptr = size_ptr;
     tunnelState->status_ptr = status_ptr;
     tunnelState->client.conn = http->getConn()->clientConnection;
+    tunnelState->http = http;
     tunnelState->al = al;
 
     comm_add_close_handler(tunnelState->client.conn->fd,
@@ -932,6 +952,9 @@ tunnelRelayConnectRequest(const Comm::ConnectionPointer &srv, void *data)
     packerClean(&p);
     mb.append("\r\n", 2);
 
+    debugs(11, 2, "Tunnel Server REQUEST: " << tunnelState->server.conn << ":\n----------\n" <<
+           Raw("tunnelRelayConnectRequest", mb.content(), mb.contentSize()) << "\n----------");
+
     if (tunnelState->clientExpectsConnectResponse()) {
         // hack: blindly tunnel peer response (to our CONNECT request) to the client as ours.
         AsyncCall::Pointer writeCall = commCbCall(5,5, "tunnelConnectedWriteDone",