From: Amos Jeffries Date: Wed, 23 Apr 2014 10:40:36 +0000 (-0600) Subject: Bug 3371: CONNECT with data sent at once loses data X-Git-Tag: SQUID_3_4_4_1~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2db24da41870e5e277e9e4a05deedb3a5eebef6c;p=thirdparty%2Fsquid.git Bug 3371: CONNECT with data sent at once loses data --- diff --git a/src/client_side.cc b/src/client_side.cc index 4f928bd255..e4fae95f46 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -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 diff --git a/src/tunnel.cc b/src/tunnel.cc index 37cc5f700b..a1d50f2e6d 100644 --- a/src/tunnel.cc +++ b/src/tunnel.cc @@ -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 http; HttpRequest::Pointer request; AccessLogEntryPointer al; Comm::ConnectionList serverDestinations; @@ -225,6 +227,7 @@ tunnelClientClosed(const CommCloseCbParams ¶ms) 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",