------------------------------------------------------------ revno: 13126 revision-id: squid3@treenet.co.nz-20140423104036-kgy0ceigzs2k1w8x parent: squid3@treenet.co.nz-20140423051549-dup5fwxvyxv9fiw7 fixes bug(s): http://bugs.squid-cache.org/show_bug.cgi?id=3371 committer: Amos Jeffries branch nick: 3.4 timestamp: Wed 2014-04-23 04:40:36 -0600 message: Bug 3371: CONNECT with data sent at once loses data ------------------------------------------------------------ # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: squid3@treenet.co.nz-20140423104036-kgy0ceigzs2k1w8x # target_branch: http://bzr.squid-cache.org/bzr/squid3/3.4 # testament_sha1: f5a88ade53fc053502be200dd91b65d25c579a77 # timestamp: 2014-04-23 10:41:34 +0000 # source_branch: http://bzr.squid-cache.org/bzr/squid3/3.4 # base_revision_id: squid3@treenet.co.nz-20140423051549-\ # dup5fwxvyxv9fiw7 # # Begin patch === modified file 'src/client_side.cc' --- src/client_side.cc 2014-04-09 16:53:05 +0000 +++ src/client_side.cc 2014-04-23 10:40:36 +0000 @@ -2864,6 +2864,10 @@ 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 === modified file 'src/tunnel.cc' --- src/tunnel.cc 2013-09-29 14:08:23 +0000 +++ src/tunnel.cc 2014-04-23 10:40:36 +0000 @@ -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 @@ bool noConnections() const; char *url; + CbcPointer http; HttpRequest::Pointer request; AccessLogEntryPointer al; Comm::ConnectionList serverDestinations; @@ -225,6 +227,7 @@ TunnelStateData::TunnelStateData() : url(NULL), + http(), request(NULL), status_ptr(NULL), connectRespBuf(NULL), @@ -675,11 +678,27 @@ 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 @@ 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 @@ 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",