2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 26 Secure Sockets Layer Proxy */
12 #include "acl/FilledChecklist.h"
13 #include "base/AsyncCallbacks.h"
14 #include "base/CbcPointer.h"
15 #include "base/JobWait.h"
17 #include "CachePeer.h"
19 #include "client_side.h"
20 #include "client_side_request.h"
21 #include "clients/HttpTunneler.h"
23 #include "comm/Connection.h"
24 #include "comm/ConnOpener.h"
25 #include "comm/Read.h"
26 #include "comm/Write.h"
27 #include "errorpage.h"
32 #include "HappyConnOpener.h"
34 #include "http/StatusCode.h"
35 #include "http/Stream.h"
36 #include "HttpRequest.h"
37 #include "icmp/net_db.h"
38 #include "ip/QosConfig.h"
41 #include "neighbors.h"
42 #include "PeerSelectState.h"
43 #include "ResolvedPeers.h"
44 #include "sbuf/SBuf.h"
45 #include "security/BlindPeerConnector.h"
46 #include "SquidConfig.h"
47 #include "StatCounters.h"
50 #include "ssl/ServerBump.h"
62 * TunnelStateData is the state engine performing the tasks for
63 * setup of a TCP tunnel from an existing open client FD to a server
64 * then shuffling binary data between the resulting FD pair.
67 * TODO 1: implement a read/write API on ConnStateData to send/receive blocks
68 * of pre-formatted data. Then we can use that as the client side of the tunnel
69 * instead of re-implementing it here and occasionally getting the ConnStateData
70 * read/write state wrong.
72 * TODO 2: then convert this into a AsyncJob, possibly a child of 'Server'
74 class TunnelStateData
: public PeerSelectionInitiator
76 CBDATA_CHILD(TunnelStateData
);
79 TunnelStateData(ClientHttpRequest
*);
80 ~TunnelStateData() override
;
81 TunnelStateData(const TunnelStateData
&); // do not implement
82 TunnelStateData
&operator =(const TunnelStateData
&); // do not implement
85 static void ReadClient(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
);
86 static void ReadServer(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
);
87 static void WriteClientDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
);
88 static void WriteServerDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
);
90 bool noConnections() const;
91 /// closes both client and server connections
92 void closeConnections();
95 CbcPointer
<ClientHttpRequest
> http
;
96 HttpRequest::Pointer request
;
97 AccessLogEntryPointer al
;
99 const char * getHost() const {
100 return (server
.conn
!= nullptr && server
.conn
->getPeer() ? server
.conn
->getPeer()->host
: request
->url
.host());
103 /// store the given to-server connection; prohibit retries and do not look
104 /// for any other destinations
105 void commitToServer(const Comm::ConnectionPointer
&);
107 /// Whether the client sent a CONNECT request to us.
108 bool clientExpectsConnectResponse() const {
109 // If we are forcing a tunnel after receiving a client CONNECT, then we
110 // have already responded to that CONNECT before tunnel.cc started.
111 if (request
&& request
->flags
.forceTunnel
)
114 // We are bumping and we had already send "OK CONNECTED"
115 if (http
.valid() && http
->getConn() && http
->getConn()->serverBump() && http
->getConn()->serverBump()->at(XactionStep::tlsBump2
, XactionStep::tlsBump3
))
118 return !(request
!= nullptr &&
119 (request
->flags
.interceptTproxy
|| request
->flags
.intercepted
));
122 /// starts connecting to the next hop, either for the first time or while
123 /// recovering from the previous connect failure
124 void startConnecting();
125 void closePendingConnection(const Comm::ConnectionPointer
&conn
, const char *reason
);
127 /// called when negotiations with the peer have been successfully completed
128 void notePeerReadyToShovel(const Comm::ConnectionPointer
&);
134 Connection() : len (0), buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF
)), size_ptr(nullptr), delayedLoops(0),
136 readPending(nullptr), readPendingFunc(nullptr) {}
140 /// initiates Comm::Connection ownership, including closure monitoring
141 template <typename Method
>
142 void initConnection(const Comm::ConnectionPointer
&aConn
, Method method
, const char *name
, TunnelStateData
*tunnelState
);
144 /// reacts to the external closure of our connection
147 int bytesWanted(int lower
=0, int upper
= INT_MAX
) const;
148 void bytesIn(int const &);
151 void setDelayId(DelayId
const &);
154 void error(int const xerrno
);
155 int debugLevelForError(int const xerrno
) const;
157 void dataSent (size_t amount
);
158 /// writes 'b' buffer, setting the 'writer' member to 'callback'.
159 void write(const char *b
, int size
, AsyncCall::Pointer
&callback
, FREE
* free_func
);
162 AsyncCall::Pointer writer
; ///< pending Comm::Write callback
163 uint64_t *size_ptr
; /* pointer to size in an ConnStateData for logging */
165 Comm::ConnectionPointer conn
; ///< The currently connected connection.
166 uint8_t delayedLoops
; ///< how many times a read on this connection has been postponed.
168 bool dirty
; ///< whether write() has been called (at least once)
170 // XXX: make these an AsyncCall when event API can handle them
171 TunnelStateData
*readPending
;
172 EVH
*readPendingFunc
;
180 /// the registered close handler for the connection
181 AsyncCall::Pointer closer
;
184 Connection client
, server
;
185 int *status_ptr
; ///< pointer for logging HTTP status
187 SBuf preReadClientData
;
188 SBuf preReadServerData
;
189 time_t startTime
; ///< object creation time, before any peer selection/connection attempts
190 ResolvedPeersPointer destinations
; ///< paths for forwarding the request
191 bool destinationsFound
; ///< At least one candidate path found
193 /// whether the decision to tunnel to a particular destination was final
194 bool committedToServer
;
196 int n_tries
; ///< the number of forwarding attempts so far
198 /// a reason to ban reforwarding attempts (or nil)
199 const char *banRetries
;
201 // TODO: remove after fixing deferred reads in TunnelStateData::copyRead()
202 CodeContext::Pointer codeContext
; ///< our creator context
204 /// waits for a transport connection to the peer to be established/opened
205 JobWait
<HappyConnOpener
> transportWait
;
207 /// waits for the established transport connection to be secured/encrypted
208 JobWait
<Security::PeerConnector
> encryptionWait
;
210 /// waits for an HTTP CONNECT tunnel through a cache_peer to be negotiated
211 /// over the (encrypted, if needed) transport connection to that cache_peer
212 JobWait
<Http::Tunneler
> peerWait
;
214 void copyRead(Connection
&from
, IOCB
*completion
);
216 /// continue to set up connection to a peer, going async for SSL peers
217 void connectToPeer(const Comm::ConnectionPointer
&);
218 void secureConnectionToPeer(const Comm::ConnectionPointer
&);
220 /* PeerSelectionInitiator API */
221 void noteDestination(Comm::ConnectionPointer conn
) override
;
222 void noteDestinationsEnd(ErrorState
*selectionError
) override
;
224 void syncHierNote(const Comm::ConnectionPointer
&server
, const char *origin
);
226 /// called when a connection has been successfully established or
227 /// when all candidate destinations have been tried and all have failed
228 void noteConnection(HappyConnOpenerAnswer
&);
230 /// Start using an established connection
231 void connectDone(const Comm::ConnectionPointer
&conn
, const char *origin
, const bool reused
);
233 void notifyConnOpener();
235 void saveError(ErrorState
*finalError
);
236 void sendError(ErrorState
*finalError
, const char *reason
);
241 /// callback handler for the Security::PeerConnector encryptor
242 void noteSecurityPeerConnectorAnswer(Security::EncryptorAnswer
&);
244 /// called after connection setup (including any encryption)
245 void connectedToPeer(const Comm::ConnectionPointer
&);
246 void establishTunnelThruProxy(const Comm::ConnectionPointer
&);
248 template <typename StepStart
>
249 void advanceDestination(const char *stepDescription
, const Comm::ConnectionPointer
&conn
, const StepStart
&startStep
);
251 /// \returns whether the request should be retried (nil) or the description why it should not
252 const char *checkRetry();
254 bool transporting() const;
256 // TODO: convert to unique_ptr
257 /// details of the "last tunneling attempt" failure (if it failed)
258 ErrorState
*savedError
= nullptr;
260 /// resumes operations after the (possibly failed) HTTP CONNECT exchange
261 void tunnelEstablishmentDone(Http::TunnelerAnswer
&answer
);
265 void cancelStep(const char *reason
);
267 bool exhaustedTries() const;
268 void updateAttempts(int);
271 bool keepGoingAfterRead(size_t len
, Comm::Flag errcode
, int xerrno
, Connection
&from
, Connection
&to
);
272 void copy(size_t len
, Connection
&from
, Connection
&to
, IOCB
*);
273 void readServer(char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
);
274 void readClient(char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
);
275 void writeClientDone(char *buf
, size_t len
, Comm::Flag flag
, int xerrno
);
276 void writeServerDone(char *buf
, size_t len
, Comm::Flag flag
, int xerrno
);
278 void copyClientBytes();
279 void copyServerBytes();
281 /// handles client-to-Squid connection closure; may destroy us
284 /// handles Squid-to-server connection closure; may destroy us
287 /// tries connecting to another destination, if available,
288 /// otherwise, initiates the transaction termination
289 void retryOrBail(const char *context
);
292 static ERCB tunnelErrorComplete
;
293 static CLCB tunnelServerClosed
;
294 static CLCB tunnelClientClosed
;
295 static CTCB tunnelTimeout
;
296 static EVH tunnelDelayedClientRead
;
297 static EVH tunnelDelayedServerRead
;
299 /// TunnelStateData::serverClosed() wrapper
301 tunnelServerClosed(const CommCloseCbParams
¶ms
)
303 const auto tunnelState
= reinterpret_cast<TunnelStateData
*>(params
.data
);
304 tunnelState
->serverClosed();
308 TunnelStateData::serverClosed()
310 server
.noteClosure();
312 retryOrBail(__FUNCTION__
);
315 /// TunnelStateData::clientClosed() wrapper
317 tunnelClientClosed(const CommCloseCbParams
¶ms
)
319 const auto tunnelState
= reinterpret_cast<TunnelStateData
*>(params
.data
);
320 tunnelState
->clientClosed();
324 TunnelStateData::clientClosed()
326 client
.noteClosure();
332 server
.conn
->close();
335 /// destroys the tunnel (after performing potentially-throwing cleanup)
337 TunnelStateData::deleteThis()
339 assert(noConnections());
340 // ConnStateData pipeline should contain the CONNECT we are performing
341 // but it may be invalid already (bug 4392)
342 if (const auto h
= http
.valid()) {
343 if (const auto c
= h
->getConn())
344 if (const auto ctx
= c
->pipeline
.front())
350 TunnelStateData::TunnelStateData(ClientHttpRequest
*clientRequest
) :
351 startTime(squid_curtime
),
352 destinations(new ResolvedPeers()),
353 destinationsFound(false),
354 committedToServer(false),
357 codeContext(CodeContext::Current())
359 debugs(26, 3, "TunnelStateData constructed this=" << this);
360 client
.readPendingFunc
= &tunnelDelayedClientRead
;
361 server
.readPendingFunc
= &tunnelDelayedServerRead
;
363 assert(clientRequest
);
364 url
= xstrdup(clientRequest
->uri
);
365 request
= clientRequest
->request
;
367 server
.size_ptr
= &clientRequest
->out
.size
;
368 client
.size_ptr
= &clientRequest
->al
->http
.clientRequestSz
.payloadData
;
369 status_ptr
= &clientRequest
->al
->http
.code
;
370 al
= clientRequest
->al
;
371 http
= clientRequest
;
373 client
.initConnection(clientRequest
->getConn()->clientConnection
, tunnelClientClosed
, "tunnelClientClosed", this);
375 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
376 CommTimeoutCbPtrFun(tunnelTimeout
, this));
377 commSetConnTimeout(client
.conn
, Config
.Timeout
.lifetime
, timeoutCall
);
380 TunnelStateData::~TunnelStateData()
382 debugs(26, 3, "TunnelStateData destructed this=" << this);
383 assert(noConnections());
385 cancelStep("~TunnelStateData");
389 TunnelStateData::Connection::~Connection()
392 eventDelete(readPendingFunc
, readPending
);
398 TunnelStateData::checkRetry()
401 return "shutting down";
402 if (exhaustedTries())
403 return "exhausted tries";
404 if (!FwdState::EnoughTimeToReForward(startTime
))
405 return "forwarding timeout";
409 return "no connections";
411 // TODO: Use std::optional for peer_reply_status to avoid treating zero value specially.
412 if (request
->hier
.peer_reply_status
!= Http::scNone
&& !Http::IsReforwardableStatus(request
->hier
.peer_reply_status
))
413 return "received HTTP status code is not reforwardable";
415 // TODO: check pinned connections; see FwdState::pinnedCanRetry()
420 TunnelStateData::retryOrBail(const char *context
)
422 assert(!server
.conn
);
424 const auto *bailDescription
= checkRetry();
425 if (!bailDescription
) {
426 if (!destinations
->empty())
427 return startConnecting(); // try connecting to another destination
430 debugs(26, 4, "wait for more destinations to try");
431 return; // expect a noteDestination*() call
434 // fall through to bail
440 request
->hier
.stopPeerClock(false);
442 // TODO: Add sendSavedErrorOr(err_type type, Http::StatusCode, context).
443 // Then, the remaining method code (below) should become the common part of
444 // sendNewError() and sendSavedErrorOr(), used in "error detected" cases.
446 saveError(new ErrorState(ERR_CANNOT_FORWARD
, Http::scInternalServerError
, request
.getRaw(), al
));
447 const auto canSendError
= Comm::IsConnOpen(client
.conn
) && !client
.dirty
&&
448 clientExpectsConnectResponse();
450 return sendError(savedError
, bailDescription
? bailDescription
: context
);
451 *status_ptr
= savedError
->httpStatus
;
456 // This is a "Comm::IsConnOpen(client.conn) but !canSendError" case.
457 // Closing the connection (after finishing writing) is the best we can do.
459 client
.conn
->close();
460 // else writeClientDone() must notice a closed server and close the client
464 TunnelStateData::Connection::bytesWanted(int lowerbound
, int upperbound
) const
467 return delayId
.bytesWanted(lowerbound
, upperbound
);
475 TunnelStateData::Connection::bytesIn(int const &count
)
477 debugs(26, 3, "len=" << len
<< " + count=" << count
);
479 delayId
.bytesIn(count
);
485 /// update "hierarchy" annotations with a new (possibly failed) destination
486 /// \param origin the name of the origin server we were trying to reach
488 TunnelStateData::syncHierNote(const Comm::ConnectionPointer
&conn
, const char *origin
)
490 request
->hier
.resetPeerNotes(conn
, origin
);
491 al
->hier
.resetPeerNotes(conn
, origin
);
494 /// sets n_tries to the given value (while keeping ALE in sync)
496 TunnelStateData::updateAttempts(const int newValue
)
498 Assure(n_tries
<= newValue
); // n_tries cannot decrease
500 // Squid probably creates at most one FwdState/TunnelStateData object per
501 // ALE, but, unlike an assignment would, this increment logic works even if
502 // Squid uses multiple such objects for a given ALE in some esoteric cases.
503 al
->requestAttempts
+= (newValue
- n_tries
);
506 debugs(26, 5, n_tries
);
510 TunnelStateData::Connection::debugLevelForError(int const xerrno
) const
514 if (xerrno
== ECONNRESET
)
519 if (ignoreErrno(xerrno
))
525 /* Read from server side and queue it for writing to the client */
527 TunnelStateData::ReadServer(const Comm::ConnectionPointer
&c
, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
)
529 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
530 assert(cbdataReferenceValid(tunnelState
));
533 tunnelState
->readServer(buf
, len
, errcode
, xerrno
);
537 TunnelStateData::readServer(char *, size_t len
, Comm::Flag errcode
, int xerrno
)
539 debugs(26, 3, server
.conn
<< ", read " << len
<< " bytes, err=" << errcode
);
540 server
.delayedLoops
=0;
543 * Bail out early on Comm::ERR_CLOSING
544 * - close handlers will tidy up for us
547 if (errcode
== Comm::ERR_CLOSING
)
552 statCounter
.server
.all
.kbytes_in
+= len
;
553 statCounter
.server
.other
.kbytes_in
+= len
;
554 request
->hier
.notePeerRead();
557 if (keepGoingAfterRead(len
, errcode
, xerrno
, server
, client
))
558 copy(len
, server
, client
, WriteClientDone
);
562 TunnelStateData::Connection::error(int const xerrno
)
564 debugs(50, debugLevelForError(xerrno
), conn
<< ": read/write failure: " << xstrerr(xerrno
));
566 if (!ignoreErrno(xerrno
))
570 /* Read from client side and queue it for writing to the server */
572 TunnelStateData::ReadClient(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
)
574 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
575 assert (cbdataReferenceValid (tunnelState
));
577 tunnelState
->readClient(buf
, len
, errcode
, xerrno
);
581 TunnelStateData::readClient(char *, size_t len
, Comm::Flag errcode
, int xerrno
)
583 debugs(26, 3, client
.conn
<< ", read " << len
<< " bytes, err=" << errcode
);
584 client
.delayedLoops
=0;
587 * Bail out early on Comm::ERR_CLOSING
588 * - close handlers will tidy up for us
591 if (errcode
== Comm::ERR_CLOSING
)
596 statCounter
.client_http
.kbytes_in
+= len
;
599 if (keepGoingAfterRead(len
, errcode
, xerrno
, client
, server
))
600 copy(len
, client
, server
, WriteServerDone
);
603 /// Updates state after reading from client or server.
604 /// Returns whether the caller should use the data just read.
606 TunnelStateData::keepGoingAfterRead(size_t len
, Comm::Flag errcode
, int xerrno
, Connection
&from
, Connection
&to
)
608 debugs(26, 3, "from={" << from
.conn
<< "}, to={" << to
.conn
<< "}");
610 /* I think this is to prevent free-while-in-a-callback behaviour
612 * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
614 const CbcPointer
<TunnelStateData
> safetyLock(this);
616 /* Bump the source connection read timeout on any activity */
617 if (Comm::IsConnOpen(from
.conn
)) {
618 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
619 CommTimeoutCbPtrFun(tunnelTimeout
, this));
620 commSetConnTimeout(from
.conn
, Config
.Timeout
.read
, timeoutCall
);
623 /* Bump the dest connection read timeout on any activity */
624 /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
625 if (Comm::IsConnOpen(to
.conn
)) {
626 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
627 CommTimeoutCbPtrFun(tunnelTimeout
, this));
628 commSetConnTimeout(to
.conn
, Config
.Timeout
.read
, timeoutCall
);
633 else if (len
== 0 || !Comm::IsConnOpen(to
.conn
)) {
634 debugs(26, 3, "Nothing to write or client gone. Terminate the tunnel.");
637 /* Only close the remote end if we've finished queueing data to it */
638 if (from
.len
== 0 && Comm::IsConnOpen(to
.conn
) ) {
641 } else if (cbdataReferenceValid(this)) {
649 TunnelStateData::copy(size_t len
, Connection
&from
, Connection
&to
, IOCB
*completion
)
651 debugs(26, 3, "Schedule Write");
652 AsyncCall::Pointer call
= commCbCall(5,5, "TunnelBlindCopyWriteHandler",
653 CommIoCbPtrFun(completion
, this));
654 to
.write(from
.buf
, len
, call
, nullptr);
657 /* Writes data from the client buffer to the server side */
659 TunnelStateData::WriteServerDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
661 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
662 assert (cbdataReferenceValid (tunnelState
));
663 tunnelState
->server
.writer
= nullptr;
665 tunnelState
->writeServerDone(buf
, len
, flag
, xerrno
);
669 TunnelStateData::writeServerDone(char *, size_t len
, Comm::Flag flag
, int xerrno
)
671 debugs(26, 3, server
.conn
<< ", " << len
<< " bytes written, flag=" << flag
);
673 if (flag
== Comm::ERR_CLOSING
)
676 request
->hier
.notePeerWrite();
679 if (flag
!= Comm::OK
) {
680 debugs(26, 4, "to-server write failed: " << xerrno
);
681 server
.error(xerrno
); // may call comm_close
687 debugs(26, 4, "No read input. Closing server connection.");
688 server
.conn
->close();
693 statCounter
.server
.all
.kbytes_out
+= len
;
694 statCounter
.server
.other
.kbytes_out
+= len
;
695 client
.dataSent(len
);
697 /* If the other end has closed, so should we */
698 if (!Comm::IsConnOpen(client
.conn
)) {
699 debugs(26, 4, "Client gone away. Shutting down server connection.");
700 server
.conn
->close();
704 const CbcPointer
<TunnelStateData
> safetyLock(this); /* ??? should be locked by the caller... */
706 if (cbdataReferenceValid(this))
710 /* Writes data from the server buffer to the client side */
712 TunnelStateData::WriteClientDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
714 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
715 assert (cbdataReferenceValid (tunnelState
));
716 tunnelState
->client
.writer
= nullptr;
718 tunnelState
->writeClientDone(buf
, len
, flag
, xerrno
);
722 TunnelStateData::Connection::dataSent(size_t amount
)
724 debugs(26, 3, "len=" << len
<< " - amount=" << amount
);
725 assert(amount
== (size_t)len
);
727 /* increment total object size */
735 TunnelStateData::Connection::write(const char *b
, int size
, AsyncCall::Pointer
&callback
, FREE
* free_func
)
739 Comm::Write(conn
, b
, size
, callback
, free_func
);
742 template <typename Method
>
744 TunnelStateData::Connection::initConnection(const Comm::ConnectionPointer
&aConn
, Method method
, const char *name
, TunnelStateData
*tunnelState
)
746 Must(!Comm::IsConnOpen(conn
));
748 Must(Comm::IsConnOpen(aConn
));
750 closer
= commCbCall(5, 4, name
, CommCloseCbPtrFun(method
, tunnelState
));
751 comm_add_close_handler(conn
->fd
, closer
);
755 TunnelStateData::Connection::noteClosure()
760 writer
= nullptr; // may already be nil
764 TunnelStateData::writeClientDone(char *, size_t len
, Comm::Flag flag
, int xerrno
)
766 debugs(26, 3, client
.conn
<< ", " << len
<< " bytes written, flag=" << flag
);
768 if (flag
== Comm::ERR_CLOSING
)
772 if (flag
!= Comm::OK
) {
773 debugs(26, 4, "from-client read failed: " << xerrno
);
774 client
.error(xerrno
); // may call comm_close
780 debugs(26, 4, "Closing client connection due to 0 byte read.");
781 client
.conn
->close();
786 statCounter
.client_http
.kbytes_out
+= len
;
787 server
.dataSent(len
);
789 /* If the other end has closed, so should we */
790 if (!Comm::IsConnOpen(server
.conn
)) {
791 debugs(26, 4, "Server has gone away. Terminating client connection.");
792 client
.conn
->close();
796 CbcPointer
<TunnelStateData
> safetyLock(this); /* ??? should be locked by the caller... */
798 if (cbdataReferenceValid(this))
803 tunnelTimeout(const CommTimeoutCbParams
&io
)
805 TunnelStateData
*tunnelState
= static_cast<TunnelStateData
*>(io
.data
);
806 debugs(26, 3, io
.conn
);
807 /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
808 CbcPointer
<TunnelStateData
> safetyLock(tunnelState
);
810 tunnelState
->closeConnections();
814 TunnelStateData::closePendingConnection(const Comm::ConnectionPointer
&conn
, const char *reason
)
816 debugs(26, 3, "because " << reason
<< "; " << conn
);
817 assert(!server
.conn
);
818 if (IsConnOpen(conn
))
823 TunnelStateData::closeConnections()
825 if (Comm::IsConnOpen(server
.conn
))
826 server
.conn
->close();
827 if (Comm::IsConnOpen(client
.conn
))
828 client
.conn
->close();
832 tunnelDelayedClientRead(void *data
)
837 TunnelStateData
*tunnel
= static_cast<TunnelStateData
*>(data
);
838 const auto savedContext
= CodeContext::Current();
839 CodeContext::Reset(tunnel
->codeContext
);
840 tunnel
->client
.readPending
= nullptr;
841 static uint64_t counter
=0;
842 debugs(26, 7, "Client read(2) delayed " << ++counter
<< " times");
843 tunnel
->copyRead(tunnel
->client
, TunnelStateData::ReadClient
);
844 CodeContext::Reset(savedContext
);
848 tunnelDelayedServerRead(void *data
)
853 TunnelStateData
*tunnel
= static_cast<TunnelStateData
*>(data
);
854 const auto savedContext
= CodeContext::Current();
855 CodeContext::Reset(tunnel
->codeContext
);
856 tunnel
->server
.readPending
= nullptr;
857 static uint64_t counter
=0;
858 debugs(26, 7, "Server read(2) delayed " << ++counter
<< " times");
859 tunnel
->copyRead(tunnel
->server
, TunnelStateData::ReadServer
);
860 CodeContext::Reset(savedContext
);
864 TunnelStateData::copyRead(Connection
&from
, IOCB
*completion
)
866 assert(from
.len
== 0);
867 // If only the minimum permitted read size is going to be attempted
868 // then we schedule an event to try again in a few I/O cycles.
869 // Allow at least 1 byte to be read every (0.3*10) seconds.
870 int bw
= from
.bytesWanted(1, SQUID_TCP_SO_RCVBUF
);
871 // XXX: Delay pools must not delay client-to-Squid traffic (i.e. when
872 // from.readPendingFunc is tunnelDelayedClientRead()).
873 // XXX: Bug #4913: For delay pools, use delayRead() API instead.
874 if (bw
== 1 && ++from
.delayedLoops
< 10) {
875 from
.readPending
= this;
876 eventAdd("tunnelDelayedServerRead", from
.readPendingFunc
, from
.readPending
, 0.3, true);
880 AsyncCall::Pointer call
= commCbCall(5,4, "TunnelBlindCopyReadHandler",
881 CommIoCbPtrFun(completion
, this));
882 comm_read(from
.conn
, from
.buf
, bw
, call
);
886 TunnelStateData::copyClientBytes()
888 if (preReadClientData
.length()) {
889 size_t copyBytes
= preReadClientData
.length() > SQUID_TCP_SO_RCVBUF
? SQUID_TCP_SO_RCVBUF
: preReadClientData
.length();
890 memcpy(client
.buf
, preReadClientData
.rawContent(), copyBytes
);
891 preReadClientData
.consume(copyBytes
);
892 client
.bytesIn(copyBytes
);
893 if (keepGoingAfterRead(copyBytes
, Comm::OK
, 0, client
, server
))
894 copy(copyBytes
, client
, server
, TunnelStateData::WriteServerDone
);
896 copyRead(client
, ReadClient
);
900 TunnelStateData::copyServerBytes()
902 if (preReadServerData
.length()) {
903 size_t copyBytes
= preReadServerData
.length() > SQUID_TCP_SO_RCVBUF
? SQUID_TCP_SO_RCVBUF
: preReadServerData
.length();
904 memcpy(server
.buf
, preReadServerData
.rawContent(), copyBytes
);
905 preReadServerData
.consume(copyBytes
);
906 server
.bytesIn(copyBytes
);
907 if (keepGoingAfterRead(copyBytes
, Comm::OK
, 0, server
, client
))
908 copy(copyBytes
, server
, client
, TunnelStateData::WriteClientDone
);
910 copyRead(server
, ReadServer
);
914 * Set the HTTP status for this request and sets the read handlers for client
915 * and server side connections.
918 tunnelStartShoveling(TunnelStateData
*tunnelState
)
920 assert(!tunnelState
->transportWait
);
921 assert(!tunnelState
->encryptionWait
);
922 assert(!tunnelState
->peerWait
);
924 assert(tunnelState
->server
.conn
);
925 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
926 CommTimeoutCbPtrFun(tunnelTimeout
, tunnelState
));
927 commSetConnTimeout(tunnelState
->server
.conn
, Config
.Timeout
.read
, timeoutCall
);
929 *tunnelState
->status_ptr
= Http::scOkay
;
930 tunnelState
->al
->cache
.code
.update(LOG_TCP_TUNNEL
);
931 if (cbdataReferenceValid(tunnelState
)) {
933 // Shovel any payload already pushed into reply buffer by the server response
934 if (!tunnelState
->server
.len
)
935 tunnelState
->copyServerBytes();
937 debugs(26, DBG_DATA
, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState
->server
.buf
, tunnelState
->server
.len
) << "\n----------");
938 tunnelState
->copy(tunnelState
->server
.len
, tunnelState
->server
, tunnelState
->client
, TunnelStateData::WriteClientDone
);
941 if (tunnelState
->http
.valid() && tunnelState
->http
->getConn() && !tunnelState
->http
->getConn()->inBuf
.isEmpty()) {
942 SBuf
* const in
= &tunnelState
->http
->getConn()->inBuf
;
943 debugs(26, DBG_DATA
, "Tunnel client PUSH Payload: \n" << *in
<< "\n----------");
944 tunnelState
->preReadClientData
.append(*in
);
945 in
->consume(); // ConnStateData buffer accounting after the shuffle.
947 tunnelState
->copyClientBytes();
952 * All the pieces we need to write to client and/or server connection
954 * Call the tunnelStartShoveling to start the blind pump.
957 tunnelConnectedWriteDone(const Comm::ConnectionPointer
&conn
, char *, size_t len
, Comm::Flag flag
, int, void *data
)
959 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
960 debugs(26, 3, conn
<< ", flag=" << flag
);
961 tunnelState
->client
.writer
= nullptr;
963 if (flag
!= Comm::OK
) {
964 *tunnelState
->status_ptr
= Http::scInternalServerError
;
965 tunnelErrorComplete(conn
->fd
, data
, 0);
969 if (auto http
= tunnelState
->http
.get()) {
970 http
->out
.headers_sz
+= len
;
971 http
->out
.size
+= len
;
974 tunnelStartShoveling(tunnelState
);
978 TunnelStateData::tunnelEstablishmentDone(Http::TunnelerAnswer
&answer
)
983 al
->cache
.code
.update(LOG_TCP_TUNNEL
);
985 // XXX: al->http.code (i.e. *status_ptr) should not be (re)set
986 // until we actually start responding to the client. Right here/now, we only
987 // know how this cache_peer has responded to us.
988 if (answer
.peerResponseStatus
!= Http::scNone
)
989 *status_ptr
= answer
.peerResponseStatus
;
991 auto sawProblem
= false;
993 if (!answer
.positive()) {
995 assert(!answer
.conn
);
996 } else if (!Comm::IsConnOpen(answer
.conn
) || fd_table
[answer
.conn
->fd
].closing()) {
998 closePendingConnection(answer
.conn
, "conn was closed while waiting for tunnelEstablishmentDone");
1002 assert(answer
.positive()); // paranoid
1003 // copy any post-200 OK bytes to our buffer
1004 preReadServerData
= answer
.leftovers
;
1005 notePeerReadyToShovel(answer
.conn
);
1009 ErrorState
*error
= nullptr;
1010 if (answer
.positive()) {
1011 error
= new ErrorState(ERR_CANNOT_FORWARD
, Http::scServiceUnavailable
, request
.getRaw(), al
);
1013 error
= answer
.squidError
.get();
1015 answer
.squidError
.clear(); // preserve error for errorSendComplete()
1019 retryOrBail("tunneler error");
1023 TunnelStateData::notePeerReadyToShovel(const Comm::ConnectionPointer
&conn
)
1025 assert(!client
.dirty
);
1026 commitToServer(conn
);
1028 if (!clientExpectsConnectResponse())
1029 tunnelStartShoveling(this); // ssl-bumped connection, be quiet
1031 *status_ptr
= Http::scOkay
;
1032 AsyncCall::Pointer call
= commCbCall(5,5, "tunnelConnectedWriteDone",
1033 CommIoCbPtrFun(tunnelConnectedWriteDone
, this));
1034 al
->reply
= HttpReply::MakeConnectionEstablished();
1035 const auto mb
= al
->reply
->pack();
1036 client
.write(mb
->content(), mb
->contentSize(), call
, mb
->freeFunc());
1042 TunnelStateData::commitToServer(const Comm::ConnectionPointer
&conn
)
1044 committedToServer
= true;
1045 banRetries
= "committed to server";
1046 PeerSelectionInitiator::subscribed
= false; // may already be false
1047 server
.initConnection(conn
, tunnelServerClosed
, "tunnelServerClosed", this);
1051 tunnelErrorComplete(int fd
/*const Comm::ConnectionPointer &*/, void *data
, size_t)
1053 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
1054 debugs(26, 3, "FD " << fd
);
1055 assert(tunnelState
!= nullptr);
1056 /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
1057 CbcPointer
<TunnelStateData
> safetyLock(tunnelState
);
1059 if (Comm::IsConnOpen(tunnelState
->client
.conn
))
1060 tunnelState
->client
.conn
->close();
1062 if (Comm::IsConnOpen(tunnelState
->server
.conn
))
1063 tunnelState
->server
.conn
->close();
1067 TunnelStateData::noteConnection(HappyConnOpener::Answer
&answer
)
1069 transportWait
.finish();
1071 updateAttempts(answer
.n_tries
);
1073 ErrorState
*error
= nullptr;
1074 if ((error
= answer
.error
.get())) {
1075 banRetries
= "HappyConnOpener gave up";
1076 Must(!Comm::IsConnOpen(answer
.conn
));
1077 syncHierNote(answer
.conn
, request
->url
.host());
1078 answer
.error
.clear();
1079 } else if (!Comm::IsConnOpen(answer
.conn
) || fd_table
[answer
.conn
->fd
].closing()) {
1080 error
= new ErrorState(ERR_CANNOT_FORWARD
, Http::scServiceUnavailable
, request
.getRaw(), al
);
1081 closePendingConnection(answer
.conn
, "conn was closed while waiting for noteConnection");
1086 retryOrBail("tried all destinations");
1090 connectDone(answer
.conn
, request
->url
.host(), answer
.reused
);
1094 TunnelStateData::connectDone(const Comm::ConnectionPointer
&conn
, const char *origin
, const bool reused
)
1096 Must(Comm::IsConnOpen(conn
));
1099 ResetMarkingsToServer(request
.getRaw(), *conn
);
1100 // else Comm::ConnOpener already applied proper/current markings
1102 // TODO: add pconn race state tracking
1104 syncHierNote(conn
, origin
);
1107 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1108 if (conn
->getPeer() && conn
->getPeer()->options
.no_delay
)
1109 server
.setDelayId(DelayId());
1112 netdbPingSite(request
->url
.host());
1114 request
->peer_host
= conn
->getPeer() ? conn
->getPeer()->host
: nullptr;
1116 bool toOrigin
= false; // same semantics as StateFlags::toOrigin
1117 if (const auto * const peer
= conn
->getPeer()) {
1118 request
->prepForPeering(*peer
);
1119 toOrigin
= peer
->options
.originserver
;
1121 request
->prepForDirect();
1126 connectToPeer(conn
);
1128 notePeerReadyToShovel(conn
);
1132 /// whether we have used up all permitted forwarding attempts
1134 TunnelStateData::exhaustedTries() const
1136 return n_tries
>= Config
.forward_max_tries
;
1140 tunnelStart(ClientHttpRequest
* http
)
1142 debugs(26, 3, MYNAME
);
1143 /* Create state structure. */
1144 TunnelStateData
*tunnelState
= nullptr;
1145 ErrorState
*err
= nullptr;
1146 HttpRequest
*request
= http
->request
;
1147 char *url
= http
->uri
;
1150 * client_addr.isNoAddr() indicates this is an "internal" request
1151 * from peer_digest.c, asn.c, netdb.c, etc and should always
1152 * be allowed. yuck, I know.
1155 if (Config
.accessList
.miss
&& !request
->client_addr
.isNoAddr()) {
1157 * Check if this host is allowed to fetch MISSES from us (miss_access)
1158 * default is to allow.
1160 ACLFilledChecklist
ch(Config
.accessList
.miss
, request
, nullptr);
1162 ch
.src_addr
= request
->client_addr
;
1163 ch
.my_addr
= request
->my_addr
;
1164 ch
.syncAle(request
, http
->log_uri
);
1165 if (ch
.fastCheck().denied()) {
1166 debugs(26, 4, "MISS access forbidden.");
1167 err
= new ErrorState(ERR_FORWARDING_DENIED
, Http::scForbidden
, request
, http
->al
);
1168 http
->al
->http
.code
= Http::scForbidden
;
1169 errorSend(http
->getConn()->clientConnection
, err
);
1174 debugs(26, 3, request
->method
<< ' ' << url
<< ' ' << request
->http_ver
);
1175 ++statCounter
.server
.all
.requests
;
1176 ++statCounter
.server
.other
.requests
;
1178 tunnelState
= new TunnelStateData(http
);
1180 tunnelState
->server
.setDelayId(DelayId::DelayClient(http
));
1182 tunnelState
->startSelectingDestinations(request
, http
->al
, nullptr);
1186 TunnelStateData::connectToPeer(const Comm::ConnectionPointer
&conn
)
1188 if (const auto p
= conn
->getPeer()) {
1189 if (p
->secure
.encryptTransport
)
1190 return advanceDestination("secure connection to peer", conn
, [this,&conn
] {
1191 secureConnectionToPeer(conn
);
1195 connectedToPeer(conn
);
1198 /// encrypts an established TCP connection to peer
1200 TunnelStateData::secureConnectionToPeer(const Comm::ConnectionPointer
&conn
)
1202 const auto callback
= asyncCallback(5, 4, TunnelStateData::noteSecurityPeerConnectorAnswer
, this);
1203 const auto connector
= new Security::BlindPeerConnector(request
, conn
, callback
, al
);
1204 encryptionWait
.start(connector
, callback
);
1207 /// starts a preparation step for an established connection; retries on failures
1208 template <typename StepStart
>
1210 TunnelStateData::advanceDestination(const char *stepDescription
, const Comm::ConnectionPointer
&conn
, const StepStart
&startStep
)
1212 // TODO: Extract destination-specific handling from TunnelStateData so that
1213 // all the awkward, limited-scope advanceDestination() calls can be replaced
1214 // with a single simple try/catch,retry block.
1217 // now wait for the step callback
1219 debugs (26, 2, "exception while trying to " << stepDescription
<< ": " << CurrentException
);
1220 closePendingConnection(conn
, "connection preparation exception");
1222 saveError(new ErrorState(ERR_CANNOT_FORWARD
, Http::scInternalServerError
, request
.getRaw(), al
));
1223 retryOrBail(stepDescription
);
1227 /// callback handler for the connection encryptor
1229 TunnelStateData::noteSecurityPeerConnectorAnswer(Security::EncryptorAnswer
&answer
)
1231 encryptionWait
.finish();
1233 ErrorState
*error
= nullptr;
1234 assert(!answer
.tunneled
);
1235 if ((error
= answer
.error
.get())) {
1236 assert(!answer
.conn
);
1237 answer
.error
.clear();
1238 } else if (!Comm::IsConnOpen(answer
.conn
) || fd_table
[answer
.conn
->fd
].closing()) {
1239 error
= new ErrorState(ERR_CANNOT_FORWARD
, Http::scServiceUnavailable
, request
.getRaw(), al
);
1240 closePendingConnection(answer
.conn
, "conn was closed while waiting for noteSecurityPeerConnectorAnswer");
1245 retryOrBail("TLS peer connection error");
1249 connectedToPeer(answer
.conn
);
1253 TunnelStateData::connectedToPeer(const Comm::ConnectionPointer
&conn
)
1255 advanceDestination("establish tunnel through proxy", conn
, [this,&conn
] {
1256 establishTunnelThruProxy(conn
);
1261 TunnelStateData::establishTunnelThruProxy(const Comm::ConnectionPointer
&conn
)
1263 const auto callback
= asyncCallback(5, 4, TunnelStateData::tunnelEstablishmentDone
, this);
1264 const auto tunneler
= new Http::Tunneler(conn
, request
, callback
, Config
.Timeout
.lifetime
, al
);
1266 tunneler
->setDelayId(server
.delayId
);
1268 peerWait
.start(tunneler
, callback
);
1272 TunnelStateData::noteDestination(Comm::ConnectionPointer path
)
1274 destinationsFound
= true;
1276 if (!path
) { // decided to use a pinned connection
1277 // We can call usePinned() without fear of clashing with an earlier
1278 // forwarding attempt because PINNED must be the first destination.
1279 assert(destinations
->empty());
1284 destinations
->addPath(path
);
1286 if (transportWait
) {
1287 assert(!transporting());
1289 return; // and continue to wait for tunnelConnectDone() callback
1293 return; // and continue to receive destinations for backup
1299 TunnelStateData::noteDestinationsEnd(ErrorState
*selectionError
)
1301 PeerSelectionInitiator::subscribed
= false;
1302 destinations
->destinationsFinalized
= true;
1303 if (!destinationsFound
) {
1305 // XXX: Honor clientExpectsConnectResponse() before replying.
1308 return sendError(selectionError
, "path selection has failed");
1310 // TODO: Merge with FwdState and remove this likely unnecessary check.
1312 return sendError(savedError
, "path selection found no paths (with an impossible early error)");
1314 return sendError(new ErrorState(ERR_CANNOT_FORWARD
, Http::scInternalServerError
, request
.getRaw(), al
),
1315 "path selection found no paths");
1317 // else continue to use one of the previously noted destinations;
1318 // if all of them fail, tunneling as whole will fail
1319 Must(!selectionError
); // finding at least one path means selection succeeded
1321 if (transportWait
) {
1322 assert(!transporting());
1324 return; // and continue to wait for the noteConnection() callback
1327 if (transporting()) {
1328 // We are already using a previously opened connection (but were also
1329 // receiving more destinations in case we need to re-forward).
1330 debugs(17, 7, "keep transporting");
1334 // destinationsFound, but none of them worked, and we were waiting for more
1336 // XXX: Honor clientExpectsConnectResponse() before replying.
1337 sendError(savedError
, "all found paths have failed");
1340 /// Whether a tunneling attempt to some selected destination X is in progress
1341 /// (after successfully opening/reusing a transport connection to X).
1342 /// \sa transportWait
1344 TunnelStateData::transporting() const
1346 return encryptionWait
|| peerWait
|| committedToServer
;
1349 /// remembers an error to be used if there will be no more connection attempts
1351 TunnelStateData::saveError(ErrorState
*error
)
1353 debugs(26, 4, savedError
<< " ? " << error
);
1355 delete savedError
; // may be nil
1359 /// Starts sending the given error message to the client, leading to the
1360 /// eventual transaction termination. Call with savedError to send savedError.
1362 TunnelStateData::sendError(ErrorState
*finalError
, const char *reason
)
1364 debugs(26, 3, "aborting transaction for " << reason
);
1367 request
->hier
.stopPeerClock(false);
1373 // get rid of any cached error unless that is what the caller is sending
1374 if (savedError
!= finalError
)
1375 delete savedError
; // may be nil
1376 savedError
= nullptr;
1378 // we cannot try other destinations after responding with an error
1379 PeerSelectionInitiator::subscribed
= false; // may already be false
1381 *status_ptr
= finalError
->httpStatus
;
1382 finalError
->callback
= tunnelErrorComplete
;
1383 finalError
->callback_data
= this;
1384 errorSend(client
.conn
, finalError
);
1387 /// Notify a pending subtask, if any, that we no longer need its help. We do not
1388 /// have to do this -- the subtask job will eventually end -- but ending it
1389 /// earlier reduces waste and may reduce DoS attack surface.
1391 TunnelStateData::cancelStep(const char *reason
)
1393 transportWait
.cancel(reason
);
1394 encryptionWait
.cancel(reason
);
1395 peerWait
.cancel(reason
);
1399 TunnelStateData::startConnecting()
1402 request
->hier
.startPeerClock();
1404 assert(!destinations
->empty());
1405 assert(!transporting());
1407 delete savedError
; // may still be nil
1408 savedError
= nullptr;
1409 request
->hier
.peer_reply_status
= Http::scNone
; // TODO: Move to startPeerClock()?
1411 const auto callback
= asyncCallback(17, 5, TunnelStateData::noteConnection
, this);
1412 const auto cs
= new HappyConnOpener(destinations
, callback
, request
, startTime
, n_tries
, al
);
1413 cs
->setHost(request
->url
.host());
1414 cs
->setRetriable(false);
1415 cs
->allowPersistent(false);
1416 destinations
->notificationPending
= true; // start() is async
1417 transportWait
.start(cs
, callback
);
1420 /// send request on an existing connection dedicated to the requesting client
1422 TunnelStateData::usePinned()
1425 const auto connManager
= request
->pinnedConnection();
1427 const auto serverConn
= ConnStateData::BorrowPinnedConnection(request
.getRaw(), al
);
1428 debugs(26, 7, "pinned peer connection: " << serverConn
);
1430 updateAttempts(n_tries
+ 1);
1432 // Set HttpRequest pinned related flags for consistency even if
1433 // they are not really used by tunnel.cc code.
1434 request
->flags
.pinned
= true;
1435 if (connManager
->pinnedAuth())
1436 request
->flags
.auth
= true;
1438 // the server may close the pinned connection before this request
1439 const auto reused
= true;
1440 connectDone(serverConn
, connManager
->pinning
.host
, reused
);
1441 } catch (ErrorState
* const error
) {
1442 syncHierNote(nullptr, connManager
? connManager
->pinning
.host
: request
->url
.host());
1443 // XXX: Honor clientExpectsConnectResponse() before replying.
1444 // a PINNED path failure is fatal; do not wait for more paths
1445 sendError(error
, "pinned path failure");
1451 CBDATA_CLASS_INIT(TunnelStateData
);
1454 TunnelStateData::noConnections() const
1456 return !Comm::IsConnOpen(server
.conn
) && !Comm::IsConnOpen(client
.conn
);
1461 TunnelStateData::Connection::setDelayId(DelayId
const &newDelay
)
1468 /// makes sure connection opener knows that the destinations have changed
1470 TunnelStateData::notifyConnOpener()
1472 if (destinations
->notificationPending
) {
1473 debugs(17, 7, "reusing pending notification");
1475 destinations
->notificationPending
= true;
1476 CallJobHere(17, 5, transportWait
.job(), HappyConnOpener
, noteCandidatesChange
);
1481 * Sets up a TCP tunnel through Squid and starts shoveling traffic.
1482 * \param request the request that initiated/caused this tunnel
1483 * \param clientConn the already accepted client-to-Squid TCP connection
1484 * \param srvConn the already established Squid-to-server TCP connection
1485 * \param preReadServerData server-sent bytes to be forwarded to the client
1488 switchToTunnel(HttpRequest
*request
, const Comm::ConnectionPointer
&clientConn
, const Comm::ConnectionPointer
&srvConn
, const SBuf
&preReadServerData
)
1490 Must(Comm::IsConnOpen(clientConn
));
1491 Must(Comm::IsConnOpen(srvConn
));
1493 debugs(26,5, "Revert to tunnel FD " << clientConn
->fd
<< " with FD " << srvConn
->fd
);
1495 /* Create state structure. */
1496 ++statCounter
.server
.all
.requests
;
1497 ++statCounter
.server
.other
.requests
;
1499 auto conn
= request
->clientConnectionManager
.get();
1501 Http::StreamPointer context
= conn
->pipeline
.front();
1502 Must(context
&& context
->http
);
1504 debugs(26, 3, request
->method
<< " " << context
->http
->uri
<< " " << request
->http_ver
);
1506 TunnelStateData
*tunnelState
= new TunnelStateData(context
->http
);
1507 tunnelState
->commitToServer(srvConn
);
1509 request
->hier
.resetPeerNotes(srvConn
, tunnelState
->getHost());
1512 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1513 if (!srvConn
->getPeer() || !srvConn
->getPeer()->options
.no_delay
)
1514 tunnelState
->server
.setDelayId(DelayId::DelayClient(context
->http
));
1517 request
->peer_host
= srvConn
->getPeer() ? srvConn
->getPeer()->host
: nullptr;
1519 debugs(26, 4, "determine post-connect handling pathway.");
1520 if (const auto peer
= srvConn
->getPeer())
1521 request
->prepForPeering(*peer
);
1523 request
->prepForDirect();
1525 tunnelState
->preReadServerData
= preReadServerData
;
1527 tunnelStartShoveling(tunnelState
);