Squid Web Cache master
Loading...
Searching...
No Matches
FwdState.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
3 *
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.
7 */
8
9/* DEBUG: section 17 Request Forwarding */
10
11#include "squid.h"
12#include "AccessLogEntry.h"
13#include "acl/Address.h"
14#include "acl/FilledChecklist.h"
15#include "acl/Gadgets.h"
16#include "anyp/PortCfg.h"
17#include "base/AsyncCallbacks.h"
19#include "CacheManager.h"
20#include "CachePeer.h"
21#include "client_side.h"
22#include "clients/forward.h"
25#include "comm/Connection.h"
26#include "comm/ConnOpener.h"
27#include "comm/Loops.h"
28#include "CommCalls.h"
29#include "errorpage.h"
30#include "event.h"
31#include "fd.h"
32#include "fde.h"
33#include "FwdState.h"
34#include "globals.h"
35#include "HappyConnOpener.h"
36#include "hier_code.h"
37#include "http.h"
38#include "http/Stream.h"
39#include "HttpReply.h"
40#include "HttpRequest.h"
41#include "icmp/net_db.h"
42#include "internal.h"
43#include "ip/Intercept.h"
44#include "ip/NfMarkConfig.h"
45#include "ip/QosConfig.h"
46#include "ip/tools.h"
47#include "MemObject.h"
48#include "mgr/Registration.h"
49#include "neighbors.h"
50#include "pconn.h"
51#include "PeerPoolMgr.h"
52#include "ResolvedPeers.h"
54#include "SquidConfig.h"
56#include "Store.h"
57#include "StoreClient.h"
58#include "urn.h"
59#if USE_OPENSSL
61#include "ssl/Config.h"
62#include "ssl/helper.h"
63#include "ssl/ServerBump.h"
64#include "ssl/support.h"
65#else
67#endif
68
69#include <cerrno>
70
72
74
75#define MAX_FWD_STATS_IDX 9
77
78PconnPool *fwdPconnPool = new PconnPool("server-peers", nullptr);
79
81
82void
84{
85 Pointer tmp = fwd; // Grab a temporary pointer to keep the object alive during our scope.
86
88 fwd->closeServerConnection("store entry aborted");
89 } else {
90 debugs(17, 7, "store entry aborted; no connection to close");
91 }
92 fwd->stopAndDestroy("store entry aborted");
93}
94
95void
97{
98 debugs(17, 3, "because " << reason << "; " << conn);
101 if (IsConnOpen(conn)) {
102 fwdPconnPool->noteUses(fd_table[conn->fd].pconn.uses);
103 conn->close();
104 }
105}
106
107void
109{
110 debugs(17, 3, "because " << reason << "; " << serverConn);
113 closeHandler = nullptr;
115 serverConn->close();
116}
117
118/**** PUBLIC INTERFACE ********************************************************/
119
121 entry(e),
122 request(r),
123 al(alp),
124 err(nullptr),
125 clientConn(client),
126 start_t(squid_curtime),
127 n_tries(0),
128 waitingForDispatched(false),
129 destinations(new ResolvedPeers()),
130 pconnRace(raceImpossible),
131 storedWholeReply_(nullptr),
132 peeringTimer(r)
133{
134 debugs(17, 2, "Forwarding client request " << client << ", url=" << e->url());
136 e->lock("FwdState");
137 flags.connected_okay = false;
138 flags.dont_retry = false;
139 flags.forward_completed = false;
140 flags.destinationsFound = false;
141 debugs(17, 3, "FwdState constructed, this=" << this);
142}
143
144// Called once, right after object creation, when it is safe to set self
146{
147 // Protect ourselves from being destroyed when the only Server pointing
148 // to us is gone (while we expect to talk to more Servers later).
149 // Once we set self, we are responsible for clearing it when we do not
150 // expect to talk to any servers.
151 self = aSelf; // refcounted
152
153 // We hope that either the store entry aborts or peer is selected.
154 // Otherwise we are going to leak our object.
155
156 // Ftp::Relay needs to preserve control connection on data aborts
157 // so it registers its own abort handler that calls ours when needed.
158 if (!request->flags.ftpNative) {
159 AsyncCall::Pointer call = asyncCall(17, 4, "FwdState::Abort", cbdataDialer(&FwdState::HandleStoreAbort, this));
161 }
162
163 // just in case; should already be initialized to false
164 request->flags.pinned = false;
165
166#if STRICT_ORIGINAL_DST
167 // Bug 3243: CVE 2009-0801
168 // Bypass of browser same-origin access control in intercepted communication
169 // To resolve this we must force DIRECT and only to the original client destination.
170 const bool isIntercepted = request && !request->flags.redirected && (request->flags.intercepted || request->flags.interceptTproxy);
171 const bool useOriginalDst = Config.onoff.client_dst_passthru || (request && !request->flags.hostVerified);
172 if (isIntercepted && useOriginalDst) {
173 selectPeerForIntercepted();
174 return;
175 }
176#endif
177
178 // do full route options selection
180}
181
183void
184FwdState::stopAndDestroy(const char *reason)
185{
186 debugs(17, 3, "for " << reason);
187
188 cancelStep(reason);
189
191
192 PeerSelectionInitiator::subscribed = false; // may already be false
193 self = nullptr; // we hope refcounting destroys us soon; may already be nil
194 /* do not place any code here as this object may be gone by now */
195}
196
200void
201FwdState::cancelStep(const char *reason)
202{
203 transportWait.cancel(reason);
204 encryptionWait.cancel(reason);
205 peerWait.cancel(reason);
206}
207
208#if STRICT_ORIGINAL_DST
210void
211FwdState::selectPeerForIntercepted()
212{
213 // We do not support re-wrapping inside CONNECT.
214 // Our only alternative is to fake a noteDestination() call.
215
216 // use pinned connection if available
217 if (ConnStateData *client = request->pinnedConnection()) {
218 // emulate the PeerSelector::selectPinned() "Skip ICP" effect
220
221 usePinned();
222 return;
223 }
224
225 // use client original destination as second preferred choice
226 const auto p = new Comm::Connection();
227 p->peerType = ORIGINAL_DST;
228 p->remote = clientConn->local;
230
231 debugs(17, 3, "using client original destination: " << *p);
236}
237#endif
238
240void
242{
243 if (!err || !al)
244 return;
245
246 const auto lte = LogTagsErrors::FromErrno(err->type == ERR_READ_TIMEOUT ? ETIMEDOUT : err->xerrno);
247 al->cache.code.err.update(lte);
248 if (!err->detail) {
249 static const auto d = MakeNamedErrorDetail("WITH_SERVER");
250 err->detailError(d);
251 }
253}
254
255void
257{
258 if (flags.forward_completed) {
259 debugs(17, DBG_IMPORTANT, "ERROR: FwdState::completed called on a completed request! Bad!");
260 return;
261 }
262
263 flags.forward_completed = true;
264
266 debugs(17, 3, "entry aborted");
267 return ;
268 }
269
270#if URL_CHECKSUM_DEBUG
271
272 entry->mem_obj->checkUrlChecksum();
273#endif
274
276 if (entry->isEmpty()) {
278 if (!err) // we quit (e.g., fd closed) before an error or content
280 assert(err);
283 err = nullptr;
284#if USE_OPENSSL
288 // no flags.dont_retry: completed() is a post-reforward() act
289 }
290#endif
291 } else {
292 updateAleWithFinalError(); // if any
295 else
296 entry->completeTruncated("FwdState default");
297 }
298 }
299
302
303}
304
306{
307 debugs(17, 3, "FwdState destructor start");
308
309 if (! flags.forward_completed)
310 completed();
311
313
315
316 delete err;
317
318 entry->unregisterAbortCallback("FwdState object destructed");
319
320 entry->unlock("FwdState");
321
322 entry = nullptr;
323
324 cancelStep("~FwdState");
325
327 closeServerConnection("~FwdState");
328
329 debugs(17, 3, "FwdState destructed, this=" << this);
330}
331
337void
339{
353 ch.al = al;
355 ch.syncAle(request, nullptr);
356 if (ch.fastCheck().denied()) {
357 auto page_id = FindDenyInfoPage(ch.currentAnswer(), true);
358 if (page_id == ERR_NONE)
359 page_id = ERR_FORWARDING_DENIED;
360
361 const auto anErr = new ErrorState(page_id, Http::scForbidden, request, al);
362 errorAppendEntry(entry, anErr); // frees anErr
363 return;
364 }
365 }
366
367 debugs(17, 3, "'" << entry->url() << "'");
368 /*
369 * This seems like an odd place to bind mem_obj and request.
370 * Might want to assert that request is NULL at this point
371 */
373#if URL_CHECKSUM_DEBUG
374
375 entry->mem_obj->checkUrlChecksum();
376#endif
377
378 if (shutting_down) {
379 /* more yuck */
381 errorAppendEntry(entry, anErr); // frees anErr
382 return;
383 }
384
385 if (request->flags.internal) {
386 debugs(17, 2, "calling internalStart() due to request flag");
388 return;
389 }
390
391 switch (request->url.getScheme()) {
392
393 case AnyP::PROTO_URN:
395 return;
396
397 default:
399 fwd->start(fwd);
400 return;
401 }
402
403 /* NOTREACHED */
404}
405
406void
408{
409 // Hides AccessLogEntry.h from code that does not supply ALE anyway.
410 Start(clientConn, entry, request, nullptr);
411}
412
415static inline time_t
416diffOrZero(const time_t larger, const time_t smaller)
417{
418 return (larger > smaller) ? (larger - smaller) : 0;
419}
420
422time_t
423FwdState::ForwardTimeout(const time_t fwdStart)
424{
425 // time already spent on forwarding (0 if clock went backwards)
426 const time_t timeSpent = diffOrZero(squid_curtime, fwdStart);
427 return diffOrZero(Config.Timeout.forward, timeSpent);
428}
429
430bool
432{
433 return ForwardTimeout(fwdStart) > 0;
434}
435
436void
438{
439 if (!destinations->empty()) {
440 connectStart();
441 } else {
443 debugs(17, 4, "wait for more destinations to try");
444 return; // expect a noteDestination*() call
445 }
446
447 debugs(17, 3, "Connection failed: " << entry->url());
448 if (!err) {
450 fail(anErr);
451 } // else use actual error from last connection attempt
452
453 stopAndDestroy("tried all destinations");
454 }
455}
456
457void
459{
460 debugs(17, 3, errorState << "; was: " << err);
461
462 delete err;
463 err = errorState;
464
465 if (!errorState->request)
466 errorState->request = request;
467
470
471 destinationReceipt = nullptr; // may already be nil
472}
473
475void
477{
479
480 if (pconnRace == racePossible) {
481 debugs(17, 5, "pconn race happened");
483 if (destinationReceipt) {
485 destinationReceipt = nullptr;
486 }
487 }
488
489 if (ConnStateData *pinned_connection = request->pinnedConnection()) {
490 pinned_connection->pinning.zeroReply = true;
491 debugs(17, 4, "zero reply on pinned connection");
492 }
493}
494
498void
500{
501 debugs(17, 3, entry->url() );
502 assert(serverConnection() == conn);
505 closeHandler = nullptr;
506 serverConn = nullptr;
507 destinationReceipt = nullptr;
508}
509
510// \deprecated use unregister(Comm::ConnectionPointer &conn) instead
511void
513{
514 debugs(17, 3, entry->url() );
515 assert(fd == serverConnection()->fd);
517}
518
525void
527{
528 const auto replyStatus = entry->mem().baseReply().sline.status();
529 debugs(17, 3, *entry << " status " << replyStatus << ' ' << entry->url());
530#if URL_CHECKSUM_DEBUG
531
532 entry->mem_obj->checkUrlChecksum();
533#endif
534
535 logReplyStatus(n_tries, replyStatus);
536
537 // will already be false if complete() was called before/without dispatch()
538 waitingForDispatched = false;
539
540 if (reforward()) {
541 debugs(17, 3, "re-forwarding " << replyStatus << " " << entry->url());
542
545 serverConn = nullptr;
546 destinationReceipt = nullptr;
547
548 storedWholeReply_ = nullptr;
549 entry->reset();
550
552
553 } else {
555 debugs(17, 3, "server FD " << serverConnection()->fd << " not re-forwarding status " << replyStatus);
556 else
557 debugs(17, 3, "server (FD closed) not re-forwarding status " << replyStatus);
558
559 completed();
560
561 stopAndDestroy("forwarding completed");
562 }
563}
564
568bool
573
574void
575FwdState::markStoredReplyAsWhole(const char * const whyWeAreSure)
576{
577 debugs(17, 5, whyWeAreSure << " for " << *entry);
578
579 // the caller wrote everything to Store, but Store may silently abort writes
581 return;
582
583 storedWholeReply_ = whyWeAreSure;
584}
585
586void
588{
589 flags.destinationsFound = true;
590
591 if (!path) {
592 // We can call usePinned() without fear of clashing with an earlier
593 // forwarding attempt because PINNED must be the first destination.
595 usePinned();
596 return;
597 }
598
599 debugs(17, 3, path);
600
601 destinations->addPath(path);
602
603 if (transportWait) {
606 return; // and continue to wait for FwdState::noteConnection() callback
607 }
608
609 if (transporting())
610 return; // and continue to receive destinations for backup
611
613}
614
615void
617{
620
621 if (!flags.destinationsFound) {
622 if (selectionError) {
623 debugs(17, 3, "Will abort forwarding because path selection has failed.");
624 Must(!err); // if we tried to connect, then path selection succeeded
625 fail(selectionError);
626 }
627
628 stopAndDestroy("path selection found no paths");
629 return;
630 }
631 // else continue to use one of the previously noted destinations;
632 // if all of them fail, forwarding as whole will fail
633 Must(!selectionError); // finding at least one path means selection succeeded
634
635 if (transportWait) {
638 return; // and continue to wait for FwdState::noteConnection() callback
639 }
640
641 if (transporting()) {
642 // We are already using a previously opened connection (but were also
643 // receiving more destinations in case we need to re-forward).
644 debugs(17, 7, "keep transporting");
645 return;
646 }
647
648 // destinationsFound, but none of them worked, and we were waiting for more
649 debugs(17, 7, "no more destinations to try after " << n_tries << " failed attempts");
650 if (!err) {
651 const auto finalError = new ErrorState(ERR_CANNOT_FORWARD, Http::scBadGateway, request, al);
652 static const auto d = MakeNamedErrorDetail("REFORWARD_TO_NONE");
653 finalError->detailError(d);
654 fail(finalError);
655 } // else use actual error from last forwarding attempt
656 stopAndDestroy("all found paths have failed");
657}
658
660void
662{
664 debugs(17, 7, "reusing pending notification about " << *destinations);
665 } else {
666 debugs(17, 7, "notifying about " << *destinations);
668 CallJobHere(17, 5, transportWait.job(), HappyConnOpener, noteCandidatesChange);
669 }
670}
671
672/**** CALLBACK WRAPPERS ************************************************************/
673
674static void
676{
677 FwdState *fwd = (FwdState *)params.data;
678 fwd->serverClosed();
679}
680
681/**** PRIVATE *****************************************************************/
682
683/*
684 * FwdState::checkRetry
685 *
686 * Return TRUE if the request SHOULD be retried. This method is
687 * called when the HTTP connection fails, or when the connection
688 * is closed before reading the end of HTTP headers from the server.
689 */
690bool
692{
693 if (shutting_down)
694 return false;
695
696 if (!self) { // we have aborted before the server called us back
697 debugs(17, 5, "not retrying because of earlier abort");
698 // we will be destroyed when the server clears its Pointer to us
699 return false;
700 }
701
703 return false;
704
705 if (!entry->isEmpty())
706 return false;
707
708 if (exhaustedTries())
709 return false;
710
712 return false;
713
715 return false;
716
717 if (flags.dont_retry)
718 return false;
719
720 if (request->bodyNibbled())
721 return false;
722
723 // NP: not yet actually connected anywhere. retry is safe.
724 if (!flags.connected_okay)
725 return true;
726
727 if (!checkRetriable())
728 return false;
729
730 return true;
731}
732
734bool
736{
737 // Optimize: A compliant proxy may retry PUTs, but Squid lacks the [rather
738 // complicated] code required to protect the PUT request body from being
739 // nibbled during the first try. Thus, Squid cannot retry some PUTs today.
740 if (request->body_pipe != nullptr)
741 return false;
742
743 // RFC2616 9.1 Safe and Idempotent Methods
745}
746
747void
749{
750 // XXX: This method logic attempts to tolerate Connection::close() called
751 // for serverConn earlier, by one of our dispatch()ed jobs. If that happens,
752 // serverConn will already be closed here or, worse, it will already be open
753 // for the next forwarding attempt. The current code prevents us getting
754 // stuck, but the long term solution is to stop sharing serverConn.
755 debugs(17, 2, serverConn);
757 const auto uses = fd_table[serverConn->fd].pconn.uses;
758 debugs(17, 3, "prior uses: " << uses);
759 fwdPconnPool->noteUses(uses); // XXX: May not have come from fwdPconnPool
761 }
762 serverConn = nullptr;
763 closeHandler = nullptr;
764 destinationReceipt = nullptr;
765
766 // will already be false if this closure happened before/without dispatch()
767 waitingForDispatched = false;
768
769 retryOrBail();
770}
771
772void
774{
775 if (checkRetry()) {
776 debugs(17, 3, "re-forwarding (" << n_tries << " tries, " << (squid_curtime - start_t) << " secs)");
778 return;
779 }
780
781 // TODO: should we call completed() here and move doneWithRetries there?
783
784 if (self != nullptr && !err && shutting_down && entry->isEmpty()) {
786 errorAppendEntry(entry, anErr);
787 }
788
789 stopAndDestroy("cannot retry");
790}
791
792// If the Server quits before nibbling at the request body, the body sender
793// will not know (so that we can retry). Call this if we will not retry. We
794// will notify the sender so that it does not get stuck waiting for space.
795void
801
802// called by the server that failed after calling unregister()
803void
805{
806 debugs(17, 2, "self=" << self << " err=" << err << ' ' << entry->url());
808 serverConn = nullptr;
809 destinationReceipt = nullptr;
810
811 // might already be false due to uncertainties documented in serverClosed()
812 waitingForDispatched = false;
813
814 retryOrBail();
815}
816
818template <typename StepStart>
819void
820FwdState::advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep)
821{
822 // TODO: Extract destination-specific handling from FwdState so that all the
823 // awkward, limited-scope advanceDestination() calls can be replaced with a
824 // single simple try/catch,retry block.
825 try {
826 startStep();
827 // now wait for the step callback
828 } catch (...) {
829 debugs (17, 2, "exception while trying to " << stepDescription << ": " << CurrentException);
830 closePendingConnection(conn, "connection preparation exception");
831 if (!err)
833 retryOrBail();
834 }
835}
836
839void
841{
843
845
846 updateAttempts(answer.n_tries);
847
848 ErrorState *error = nullptr;
849 if ((error = answer.error.get())) {
850 flags.dont_retry = true; // or HappyConnOpener would not have given up
851 syncHierNote(answer.conn, request->url.host());
852 Must(!Comm::IsConnOpen(answer.conn));
853 answer.error.clear(); // preserve error for errorSendComplete()
854 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
855 // The socket could get closed while our callback was queued. Sync
856 // Connection. XXX: Connection::fd may already be stale/invalid here.
857 // We do not know exactly why the connection got closed, so we play it
858 // safe, allowing retries only for persistent (reused) connections
859 if (answer.reused) {
860 destinationReceipt = answer.conn;
862 }
863 syncHierNote(answer.conn, request->url.host());
864 closePendingConnection(answer.conn, "conn was closed while waiting for noteConnection");
866 } else {
867 assert(!error);
868 destinationReceipt = answer.conn;
870 // serverConn remains nil until syncWithServerConn()
871 }
872
873 if (error) {
874 fail(error);
875 retryOrBail();
876 return;
877 }
878
879 if (answer.reused) {
880 syncWithServerConn(answer.conn, request->url.host(), answer.reused);
881 return dispatch();
882 }
883
884 // Check if we need to TLS before use
885 if (const auto *peer = answer.conn->getPeer()) {
886 // Assume that it is only possible for the client-first from the
887 // bumping modes to try connect to a remote server. The bumped
888 // requests with other modes are using pinned connections or fails.
889 const bool clientFirstBump = request->flags.sslBumped;
890 // We need a CONNECT tunnel to send encrypted traffic through a proxy,
891 // but we do not support TLS inside TLS, so we exclude HTTPS proxies.
892 const bool originWantsEncryptedTraffic =
895 clientFirstBump;
896 if (originWantsEncryptedTraffic && // the "encrypted traffic" part
897 !peer->options.originserver && // the "through a proxy" part
898 !peer->secure.encryptTransport) // the "exclude HTTPS proxies" part
899 return advanceDestination("establish tunnel through proxy", answer.conn, [this,&answer] {
900 establishTunnelThruProxy(answer.conn);
901 });
902 }
903
905}
906
907void
909{
910 const auto callback = asyncCallback(17, 4, FwdState::tunnelEstablishmentDone, this);
911 HttpRequest::Pointer requestPointer = request;
912 const auto tunneler = new Http::Tunneler(conn, requestPointer, callback, connectingTimeout(conn), al);
913
914 // TODO: Replace this hack with proper Comm::Connection-Pool association
915 // that is not tied to fwdPconnPool and can handle disappearing pools.
916 tunneler->noteFwdPconnUse = true;
917
918#if USE_DELAY_POOLS
919 Must(conn);
920 Must(conn->getPeer());
921 if (!conn->getPeer()->options.no_delay)
922 tunneler->setDelayId(entry->mem_obj->mostBytesAllowed());
923#endif
924 peerWait.start(tunneler, callback);
925}
926
928void
930{
932
933 ErrorState *error = nullptr;
934 if (!answer.positive()) {
935 Must(!answer.conn);
936 error = answer.squidError.get();
937 Must(error);
938 answer.squidError.clear(); // preserve error for fail()
939 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
940 // The socket could get closed while our callback was queued. Sync
941 // Connection. XXX: Connection::fd may already be stale/invalid here.
942 closePendingConnection(answer.conn, "conn was closed while waiting for tunnelEstablishmentDone");
944 } else if (!answer.leftovers.isEmpty()) {
945 // This should not happen because TLS servers do not speak first. If we
946 // have to handle this, then pass answer.leftovers via a PeerConnector
947 // to ServerBio. See ClientBio::setReadBufData().
948 static int occurrences = 0;
949 const auto level = (occurrences++ < 100) ? DBG_IMPORTANT : 2;
950 debugs(17, level, "ERROR: Early data after CONNECT response. " <<
951 "Found " << answer.leftovers.length() << " bytes. " <<
952 "Closing " << answer.conn);
954 closePendingConnection(answer.conn, "server spoke before tunnelEstablishmentDone");
955 }
956 if (error) {
957 fail(error);
958 retryOrBail();
959 return;
960 }
961
963}
964
966void
968{
970
971 const auto p = conn->getPeer();
972 const bool peerWantsTls = p && p->secure.encryptTransport;
973 // userWillTlsToPeerForUs assumes CONNECT == HTTPS
974 const bool userWillTlsToPeerForUs = p && p->options.originserver &&
976 const bool needTlsToPeer = peerWantsTls && !userWillTlsToPeerForUs;
977 const bool clientFirstBump = request->flags.sslBumped; // client-first (already) bumped connection
978 const bool needsBump = request->flags.sslPeek || clientFirstBump;
979
980 // 'GET https://...' requests. If a peer is used the request is forwarded
981 // as is
982 const bool needTlsToOrigin = !p && request->url.getScheme() == AnyP::PROTO_HTTPS && !clientFirstBump;
983
984 if (needTlsToPeer || needTlsToOrigin || needsBump) {
985 return advanceDestination("secure connection to peer", conn, [this,&conn] {
987 });
988 }
989
990 // if not encrypting just run the post-connect actions
992}
993
995void
997{
998 HttpRequest::Pointer requestPointer = request;
999 const auto callback = asyncCallback(17, 4, FwdState::connectedToPeer, this);
1000 const auto sslNegotiationTimeout = connectingTimeout(conn);
1001 Security::PeerConnector *connector = nullptr;
1002#if USE_OPENSSL
1003 if (request->flags.sslPeek)
1004 connector = new Ssl::PeekingPeerConnector(requestPointer, conn, clientConn, callback, al, sslNegotiationTimeout);
1005 else
1006#endif
1007 connector = new Security::BlindPeerConnector(requestPointer, conn, callback, al, sslNegotiationTimeout);
1008 connector->noteFwdPconnUse = true;
1009 encryptionWait.start(connector, callback);
1010}
1011
1013void
1015{
1017
1018 ErrorState *error = nullptr;
1019 if ((error = answer.error.get())) {
1020 assert(!answer.conn);
1021 answer.error.clear(); // preserve error for errorSendComplete()
1022 } else if (answer.tunneled) {
1023 assert(!answer.conn);
1024 // TODO: When ConnStateData establishes tunnels, its state changes
1025 // [in ways that may affect logging?]. Consider informing
1026 // ConnStateData about our tunnel or otherwise unifying tunnel
1027 // establishment [side effects].
1028 flags.dont_retry = true; // TunnelStateData took forwarding control
1029 entry->abort();
1030 complete(); // destroys us
1031 return;
1032 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1033 // The socket could get closed while our callback was queued. Sync
1034 // Connection. XXX: Connection::fd may already be stale/invalid here.
1035 closePendingConnection(answer.conn, "conn was closed while waiting for connectedToPeer");
1037 }
1038
1039 if (error) {
1040 fail(error);
1041 retryOrBail();
1042 return;
1043 }
1044
1046}
1047
1049void
1051{
1052 syncWithServerConn(conn, request->url.host(), false);
1053
1054 // should reach ConnStateData before the dispatched Client job starts
1057
1059
1060 dispatch();
1061}
1062
1064void
1065FwdState::syncWithServerConn(const Comm::ConnectionPointer &conn, const char *host, const bool reused)
1066{
1067 Must(IsConnOpen(conn));
1068 serverConn = conn;
1069 // no effect on destinationReceipt (which may even be nil here)
1070
1072
1073 if (reused) {
1076 } else {
1078 // Comm::ConnOpener already applied proper/current markings
1079 }
1080
1081 syncHierNote(serverConn, host);
1082}
1083
1084void
1086{
1087 if (request)
1089 if (al)
1090 al->hier.resetPeerNotes(server, host);
1091}
1092
1094void
1095FwdState::updateAttempts(const int newValue)
1096{
1097 Assure(n_tries <= newValue); // n_tries cannot decrease
1098
1099 // Squid probably creates at most one FwdState/TunnelStateData object per
1100 // ALE, but, unlike an assignment would, this increment logic works even if
1101 // Squid uses multiple such objects for a given ALE in some esoteric cases.
1102 if (al)
1103 al->requestAttempts += (newValue - n_tries);
1104
1105 n_tries = newValue;
1106 debugs(17, 5, n_tries);
1107}
1108
1114void
1116{
1117 debugs(17, 3, *destinations << " to " << entry->url());
1118
1120
1122 assert(!transporting());
1123
1124 // Ditch error page if it was created before.
1125 // A new one will be created if there's another problem
1126 delete err;
1127 err = nullptr;
1129
1130 const auto callback = asyncCallback(17, 5, FwdState::noteConnection, this);
1132 const auto cs = new HappyConnOpener(destinations, callback, cause, start_t, n_tries, al);
1133 cs->setHost(request->url.host());
1134 bool retriable = checkRetriable();
1135 if (!retriable && Config.accessList.serverPconnForNonretriable) {
1137 ch.al = al;
1138 ch.syncAle(request, nullptr);
1139 retriable = ch.fastCheck().allowed();
1140 }
1141 cs->setRetriable(retriable);
1142 cs->allowPersistent(pconnRace != raceHappened);
1143 destinations->notificationPending = true; // start() is async
1144 transportWait.start(cs, callback);
1145}
1146
1148void
1150{
1151 const auto connManager = request->pinnedConnection();
1152 debugs(17, 7, "connection manager: " << connManager);
1153
1154 try {
1155 // TODO: Refactor syncWithServerConn() and callers to always set
1156 // serverConn inside that method.
1158 debugs(17, 5, "connection: " << serverConn);
1159 } catch (ErrorState * const anErr) {
1160 syncHierNote(nullptr, connManager ? connManager->pinning.host : request->url.host());
1161 serverConn = nullptr;
1162 fail(anErr);
1163 // Connection managers monitor their idle pinned to-server
1164 // connections and close from-client connections upon seeing
1165 // a to-server connection closure. Retrying here is futile.
1166 stopAndDestroy("pinned connection failure");
1167 return;
1168 }
1169
1171
1172 request->flags.pinned = true;
1173
1174 assert(connManager);
1175 if (connManager->pinnedAuth())
1176 request->flags.auth = true;
1177
1178 // the server may close the pinned connection before this request
1179 const auto reused = true;
1180 syncWithServerConn(serverConn, connManager->pinning.host, reused);
1181
1182 dispatch();
1183}
1184
1185void
1187{
1188 debugs(17, 3, clientConn << ": Fetching " << request->method << ' ' << entry->url());
1189 /*
1190 * Assert that server_fd is set. This is to guarantee that fwdState
1191 * is attached to something and will be deallocated when server_fd
1192 * is closed.
1193 */
1195
1197 waitingForDispatched = true;
1198
1199 fd_note(serverConnection()->fd, entry->url());
1200
1201 fd_table[serverConnection()->fd].noteUse();
1202
1203 /*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */
1205
1206 assert(entry->locked());
1207
1209
1210 flags.connected_okay = true;
1211
1213
1214 /* Retrieves remote server TOS or MARK value, and stores it as part of the
1215 * original client request FD object. It is later used to forward
1216 * remote server's TOS/MARK in the response to the client in case of a MISS.
1217 */
1218 if (Ip::Qos::TheConfig.isHitNfmarkActive()) {
1220 fde * clientFde = &fd_table[clientConn->fd]; // XXX: move the fd_table access into Ip::Qos
1221 /* Get the netfilter CONNMARK */
1223 }
1224 }
1225
1226#if _SQUID_LINUX_
1227 /* Bug 2537: The TOS forward part of QOS only applies to patched Linux kernels. */
1228 if (Ip::Qos::TheConfig.isHitTosActive()) {
1230 fde * clientFde = &fd_table[clientConn->fd]; // XXX: move the fd_table access into Ip::Qos
1231 /* Get the TOS value for the packet */
1233 }
1234 }
1235#endif
1236
1237#if USE_OPENSSL
1238 if (request->flags.sslPeek) {
1239 // we were just asked to peek at the server, and we did that
1242 unregister(serverConn); // async call owns it now
1243 flags.dont_retry = true; // we gave up forwarding control
1244 entry->abort();
1245 complete(); // destroys us
1246 return;
1247 }
1248#endif
1249
1250 if (const auto peer = serverConnection()->getPeer()) {
1251 ++peer->stats.fetches;
1252 request->prepForPeering(*peer);
1253 httpStart(this);
1254 } else {
1257
1258 switch (request->url.getScheme()) {
1259
1260 case AnyP::PROTO_HTTPS:
1261 httpStart(this);
1262 break;
1263
1264 case AnyP::PROTO_HTTP:
1265 httpStart(this);
1266 break;
1267
1268 case AnyP::PROTO_FTP:
1269 if (request->flags.ftpNative)
1270 Ftp::StartRelay(this);
1271 else
1272 Ftp::StartGateway(this);
1273 break;
1274
1275 case AnyP::PROTO_URN:
1276 fatal_dump("Should never get here");
1277 break;
1278
1279 case AnyP::PROTO_WHOIS:
1280 whoisStart(this);
1281 break;
1282
1283 case AnyP::PROTO_WAIS: /* Not implemented */
1284
1285 default:
1286 debugs(17, DBG_IMPORTANT, "WARNING: Cannot retrieve '" << entry->url() << "'.");
1287 const auto anErr = new ErrorState(ERR_UNSUP_REQ, Http::scBadRequest, request, al);
1288 fail(anErr);
1289 // Set the dont_retry flag because this is not a transient (network) error.
1290 flags.dont_retry = true;
1292 serverConn->close(); // trigger cleanup
1293 }
1294 break;
1295 }
1296 }
1297}
1298
1299/*
1300 * FwdState::reforward
1301 *
1302 * returns TRUE if the transaction SHOULD be re-forwarded to the
1303 * next choice in the serverDestinations list. This method is called when
1304 * peer communication completes normally, or experiences
1305 * some error after receiving the end of HTTP headers.
1306 */
1307int
1309{
1310 StoreEntry *e = entry;
1311
1312 if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
1313 debugs(17, 3, "entry aborted");
1314 return 0;
1315 }
1316
1318 assert(e->mem_obj);
1319#if URL_CHECKSUM_DEBUG
1320
1321 e->mem_obj->checkUrlChecksum();
1322#endif
1323
1324 debugs(17, 3, e->url() << "?" );
1325
1326 if (request->flags.pinned && !pinnedCanRetry()) {
1327 debugs(17, 3, "pinned connection; cannot retry");
1328 return 0;
1329 }
1330
1332 debugs(17, 3, "No, ENTRY_FWD_HDR_WAIT isn't set");
1333 return 0;
1334 }
1335
1336 if (exhaustedTries())
1337 return 0;
1338
1339 if (request->bodyNibbled())
1340 return 0;
1341
1343 debugs(17, 3, "No alternative forwarding paths left");
1344 return 0;
1345 }
1346
1347 const auto s = entry->mem().baseReply().sline.status();
1348 debugs(17, 3, "status " << s);
1350}
1351
1352// TODO: Refactor to fix multiple mgr:forward accounting/reporting bugs. See
1353// https://lists.squid-cache.org/pipermail/squid-users/2024-December/027331.html
1354static void
1356{
1357 int i;
1358 int j;
1359 storeAppendPrintf(s, "Status");
1360
1361 // XXX: Missing try#0 heading for FwdReplyCodes[0][i]
1362 for (j = 1; j <= MAX_FWD_STATS_IDX; ++j) {
1363 storeAppendPrintf(s, "\ttry#%d", j);
1364 }
1365
1366 storeAppendPrintf(s, "\n");
1367
1368 for (i = 0; i <= (int) Http::scInvalidHeader; ++i) {
1369 // XXX: Missing reporting of status codes for which logReplyStatus() was
1370 // only called with n_tries exceeding 1. To be more precise, we are
1371 // missing (the equivalent of) logReplyStatus() calls for attempts done
1372 // outside of FwdState. Relying on n_tries<=1 counters is too fragile.
1373 if (!FwdReplyCodes[0][i] && !FwdReplyCodes[1][i])
1374 continue;
1375
1376 storeAppendPrintf(s, "%3d", i);
1377
1378 // XXX: Missing FwdReplyCodes[0][i] reporting
1379 for (j = 1; j <= MAX_FWD_STATS_IDX; ++j) {
1380 storeAppendPrintf(s, "\t%d", FwdReplyCodes[j][i]);
1381 }
1382
1383 storeAppendPrintf(s, "\n");
1384 }
1385}
1386
1387/**** STATIC MEMBER FUNCTIONS *************************************************/
1388
1389void
1394
1395void
1397{
1398 Mgr::RegisterAction("forward", "Request Forwarding Statistics", fwdStats, 0, 1);
1399}
1400
1401void
1403{
1404 if (status > Http::scInvalidHeader)
1405 return;
1406
1407 assert(tries >= 0);
1408
1409 if (tries > MAX_FWD_STATS_IDX)
1410 tries = MAX_FWD_STATS_IDX;
1411
1412 ++ FwdReplyCodes[tries][status];
1413}
1414
1415bool
1417{
1419}
1420
1421bool
1423{
1425
1426 // pconn race on pinned connection: Currently we do not have any mechanism
1427 // to retry current pinned connection path.
1428 if (pconnRace == raceHappened)
1429 return false;
1430
1431 // If a bumped connection was pinned, then the TLS client was given our peer
1432 // details. Do not retry because we do not ensure that those details stay
1433 // constant. Step1-bumped connections do not get our TLS peer details, are
1434 // never pinned, and, hence, never reach this method.
1435 if (request->flags.sslBumped)
1436 return false;
1437
1438 // The other pinned cases are FTP proxying and connection-based HTTP
1439 // authentication. TODO: Do these cases have restrictions?
1440 return true;
1441}
1442
1443time_t
1445{
1446 const auto connTimeout = conn->connectTimeout(start_t);
1447 return positiveTimeout(connTimeout);
1448}
1449
1450/**** PRIVATE NON-MEMBER FUNCTIONS ********************************************/
1451
1452/*
1453 * DPW 2007-05-19
1454 * Formerly static, but now used by client_side_request.cc
1455 */
1457tos_t
1459{
1460 for (acl_tos *l = head; l; l = l->next) {
1461 if (!l->aclList || ch->fastCheck(l->aclList).allowed())
1462 return l->tos;
1463 }
1464
1465 return 0;
1466}
1467
1471{
1472 for (acl_nfmark *l = head; l; l = l->next) {
1473 if (!l->aclList || ch->fastCheck(l->aclList).allowed())
1474 return l->markConfig;
1475 }
1476
1477 return {};
1478}
1479
1480void
1482{
1483 // skip if an outgoing address is already set.
1484 if (!conn->local.isAnyAddr()) return;
1485
1486 // ensure that at minimum the wildcard local matches remote protocol
1487 if (conn->remote.isIPv4())
1488 conn->local.setIPv4();
1489
1490 // maybe use TPROXY client address
1491 if (request && request->flags.spoofClientIp) {
1492 if (!conn->getPeer() || !conn->getPeer()->options.no_tproxy) {
1493#if FOLLOW_X_FORWARDED_FOR && LINUX_NETFILTER
1495 conn->local = request->indirect_client_addr;
1496 else
1497#endif
1498 conn->local = request->client_addr;
1499 conn->local.port(0); // let OS pick the source port to prevent address clashes
1500 // some flags need setting on the socket to use this address
1501 conn->flags |= COMM_DOBIND;
1502 conn->flags |= COMM_TRANSPARENT;
1503 return;
1504 }
1505 // else no tproxy today ...
1506 }
1507
1509 return; // anything will do.
1510 }
1511
1512 ACLFilledChecklist ch(nullptr, request);
1513 ch.dst_peer_name = conn->getPeer() ? conn->getPeer()->name : nullptr;
1514 ch.dst_addr = conn->remote;
1515
1516 // TODO use the connection details in ACL.
1517 // needs a bit of rework in ACLFilledChecklist to use Comm::Connection instead of ConnStateData
1518
1519 for (Acl::Address *l = Config.accessList.outgoing_address; l; l = l->next) {
1520
1521 /* check if the outgoing address is usable to the destination */
1522 if (conn->remote.isIPv4() != l->addr.isIPv4()) continue;
1523
1524 /* check ACLs for this outgoing address */
1525 if (!l->aclList || ch.fastCheck(l->aclList).allowed()) {
1526 conn->local = l->addr;
1527 return;
1528 }
1529 }
1530}
1531
1533static tos_t
1535{
1536 if (!Ip::Qos::TheConfig.tosToServer)
1537 return 0;
1538
1539 ACLFilledChecklist ch(nullptr, request);
1540 ch.dst_peer_name = conn.getPeer() ? conn.getPeer()->name : nullptr;
1541 ch.dst_addr = conn.remote;
1542 return aclMapTOS(Ip::Qos::TheConfig.tosToServer, &ch);
1543}
1544
1546static nfmark_t
1548{
1549 if (!Ip::Qos::TheConfig.nfmarkToServer)
1550 return 0;
1551
1552 ACLFilledChecklist ch(nullptr, request);
1553 ch.dst_peer_name = conn.getPeer() ? conn.getPeer()->name : nullptr;
1554 ch.dst_addr = conn.remote;
1555 const auto mc = aclFindNfMarkConfig(Ip::Qos::TheConfig.nfmarkToServer, &ch);
1556 return mc.mark;
1557}
1558
1559void
1561{
1562 // Get the server side TOS and Netfilter mark to be set on the connection.
1563 conn.tos = GetTosToServer(request, conn);
1564 conn.nfmark = GetNfmarkToServer(request, conn);
1565 debugs(17, 3, "from " << conn.local << " tos " << int(conn.tos) << " netfilter mark " << conn.nfmark);
1566}
1567
1568void
1570{
1571 GetMarkingsToServer(request, conn);
1572
1573 // TODO: Avoid these calls if markings has not changed.
1574 if (conn.tos)
1575 Ip::Qos::setSockTos(&conn, conn.tos);
1576 if (conn.nfmark)
1577 Ip::Qos::setSockNfmark(&conn, conn.nfmark);
1578}
1579
1580/* PeeringActivityTimer */
1581
1582// The simple methods below are not inlined to avoid exposing some of the
1583// current FwdState.h users to a full HttpRequest definition they do not need.
1584
1590
1595
1596Stopwatch &
1601
#define Assure(condition)
Definition Assure.h:35
RefCount< AsyncCallT< Dialer > > asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition AsyncCall.h:156
#define asyncCallback(dbgSection, dbgLevel, method, object)
UnaryCbdataDialer< Argument1 > cbdataDialer(typename UnaryCbdataDialer< Argument1 >::Handler *handler, Argument1 *arg1)
#define CallJobHere(debugSection, debugLevel, job, Class, method)
#define CallJobHere1(debugSection, debugLevel, job, Class, method, arg1)
void NoteOutgoingConnectionSuccess(CachePeer *const peer)
Definition CachePeer.h:237
void CLCB(const CommCloseCbParams &params)
Definition CommCalls.h:40
#define COMM_TRANSPARENT
Definition Connection.h:50
#define COMM_DOBIND
Definition Connection.h:49
ErrorDetail::Pointer MakeNamedErrorDetail(const char *name)
Definition Detail.cc:54
PconnPool * fwdPconnPool
a collection of previously used persistent Squid-to-peer HTTP(S) connections
Definition FwdState.cc:78
static int FwdReplyCodes[MAX_FWD_STATS_IDX+1][Http::scInvalidHeader+1]
Definition FwdState.cc:76
static nfmark_t GetNfmarkToServer(HttpRequest *request, Comm::Connection &conn)
Definition FwdState.cc:1547
void getOutgoingAddress(HttpRequest *request, const Comm::ConnectionPointer &conn)
Definition FwdState.cc:1481
Ip::NfMarkConfig aclFindNfMarkConfig(acl_nfmark *head, ACLChecklist *ch)
Checks for a netfilter mark value to apply depending on the ACL.
Definition FwdState.cc:1470
void ResetMarkingsToServer(HttpRequest *request, Comm::Connection &conn)
Definition FwdState.cc:1569
tos_t aclMapTOS(acl_tos *head, ACLChecklist *ch)
Checks for a TOS value to apply depending on the ACL.
Definition FwdState.cc:1458
void GetMarkingsToServer(HttpRequest *request, Comm::Connection &conn)
Definition FwdState.cc:1560
static tos_t GetTosToServer(HttpRequest *request, Comm::Connection &conn)
Definition FwdState.cc:1534
static OBJH fwdStats
Definition FwdState.cc:73
static time_t diffOrZero(const time_t larger, const time_t smaller)
Definition FwdState.cc:416
#define MAX_FWD_STATS_IDX
Definition FwdState.cc:75
static CLCB fwdServerClosedWrapper
Definition FwdState.cc:71
PconnPool * fwdPconnPool
a collection of previously used persistent Squid-to-peer HTTP(S) connections
Definition FwdState.cc:78
void getOutgoingAddress(HttpRequest *, const Comm::ConnectionPointer &)
Definition FwdState.cc:1481
void ResetMarkingsToServer(HttpRequest *, Comm::Connection &)
Definition FwdState.cc:1569
time_t squid_curtime
class SquidConfig Config
std::ostream & CurrentException(std::ostream &os)
prints active (i.e., thrown but not yet handled) exception
#define Must(condition)
err_type FindDenyInfoPage(const Acl::Answer &answer, const bool redirect_allowed)
Definition Gadgets.cc:34
void error(char *format,...)
squidaio_request_t * head
Definition aiops.cc:129
#define assert(EX)
Definition assert.h:17
static char server[MAXLINE]
#define CBDATA_CLASS_INIT(type)
Definition cbdata.h:325
Acl::Answer const & fastCheck()
Definition Checklist.cc:298
const Acl::Answer & currentAnswer() const
Definition Checklist.h:106
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
void syncAle(HttpRequest *adaptedRequest, const char *logUri) const override
assigns uninitialized adapted_request and url ALE components
class AccessLogEntry::CacheDetails cache
HierarchyLogEntry hier
void updateError(const Error &)
sets (or updates the already stored) transaction error as needed
list of address-based ACLs.
Definition Address.h:21
bool denied() const
Definition Acl.h:88
bool allowed() const
Definition Acl.h:82
AnyP::UriScheme const & getScheme() const
Definition Uri.h:58
void host(const char *src)
Definition Uri.cc:154
void expectNoConsumption()
there will be no more setConsumer() calls
Definition BodyPipe.cc:267
bool no_tproxy
Definition CachePeer.h:145
struct CachePeer::@20 options
Security::PeerOptions secure
security settings for peer connection
Definition CachePeer.h:219
char * name
Definition CachePeer.h:61
bool no_delay
Definition CachePeer.h:128
Cbc * valid() const
was set and is valid
Definition CbcPointer.h:41
void clear()
make pointer not set; does not invalidate cbdata
Definition CbcPointer.h:144
Cbc * get() const
a temporary valid raw Cbc pointer or NULL
Definition CbcPointer.h:159
CachePeer * getPeer() const
Ip::Address remote
Definition Connection.h:152
Ip::Address local
Definition Connection.h:149
time_t connectTimeout(const time_t fwdStart) const
parameters for the async notePinnedConnectionBecameIdle() call
void httpsPeeked(PinnedIdleContext pic)
called by FwdState when it is done bumping the server
static Comm::ConnectionPointer BorrowPinnedConnection(HttpRequest *, const AccessLogEntryPointer &)
virtual void notePeerConnection(Comm::ConnectionPointer)
called just before a FwdState-dispatched job starts using connection
err_type type
Definition errorpage.h:170
ErrorDetail::Pointer detail
Definition errorpage.h:204
void detailError(const ErrorDetail::Pointer &dCode)
set error type-specific detail code
Definition errorpage.h:111
HttpRequestPointer request
Definition errorpage.h:177
a transaction problem
Definition Error.h:27
void secureConnectionToPeerIfNeeded(const Comm::ConnectionPointer &)
handles an established TCP connection to peer (including origin servers)
Definition FwdState.cc:967
Comm::ConnectionPointer clientConn
a possibly open connection to the client.
Definition FwdState.h:212
bool checkRetry()
Definition FwdState.cc:691
void reactToZeroSizeObject()
ERR_ZERO_SIZE_OBJECT requires special adjustments.
Definition FwdState.cc:476
void handleUnregisteredServerEnd()
Definition FwdState.cc:804
void noteDestinationsEnd(ErrorState *selectionError) override
Definition FwdState.cc:616
void connectedToPeer(Security::EncryptorAnswer &answer)
called when all negotiations with the TLS-speaking peer have been completed
Definition FwdState.cc:1014
HttpRequest * request
Definition FwdState.h:203
void serverClosed()
Definition FwdState.cc:748
void successfullyConnectedToPeer(const Comm::ConnectionPointer &)
called when all negotiations with the peer have been completed
Definition FwdState.cc:1050
PconnRace pconnRace
current pconn race state
Definition FwdState.h:244
const char * storedWholeReply_
Definition FwdState.h:248
FwdState(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *, const AccessLogEntryPointer &alp)
Definition FwdState.cc:120
JobWait< HappyConnOpener > transportWait
waits for a transport connection to the peer to be established/opened
Definition FwdState.h:224
void doneWithRetries()
Definition FwdState.cc:796
JobWait< Http::Tunneler > peerWait
Definition FwdState.h:231
void completed()
Definition FwdState.cc:256
bool transporting() const
Definition FwdState.cc:569
@ racePossible
Definition FwdState.h:243
@ raceHappened
Definition FwdState.h:243
@ raceImpossible
Definition FwdState.h:243
void complete()
Definition FwdState.cc:526
static void Start(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *, const AccessLogEntryPointer &alp)
Initiates request forwarding to a peer or origin server.
Definition FwdState.cc:338
void noteDestination(Comm::ConnectionPointer conn) override
called when a new unique destination has been found
Definition FwdState.cc:587
static void HandleStoreAbort(FwdState *)
called by Store if the entry is no longer usable
Definition FwdState.cc:83
time_t connectingTimeout(const Comm::ConnectionPointer &conn) const
Definition FwdState.cc:1444
static bool EnoughTimeToReForward(const time_t fwdStart)
Definition FwdState.cc:431
void closePendingConnection(const Comm::ConnectionPointer &conn, const char *reason)
get rid of a to-server connection that failed to become serverConn
Definition FwdState.cc:96
PeeringActivityTimer peeringTimer
Measures time spent on selecting and communicating with peers.
Definition FwdState.h:251
void unregister(Comm::ConnectionPointer &conn)
Definition FwdState.cc:499
void start(Pointer aSelf)
Definition FwdState.cc:145
Comm::ConnectionPointer const & serverConnection() const
Definition FwdState.h:138
Comm::ConnectionPointer serverConn
a successfully opened connection to a server.
Definition FwdState.h:237
void fail(ErrorState *err)
Definition FwdState.cc:458
static time_t ForwardTimeout(const time_t fwdStart)
time left to finish the whole forwarding process (which started at fwdStart)
Definition FwdState.cc:423
void closeServerConnection(const char *reason)
stops monitoring server connection for closure and updates pconn stats
Definition FwdState.cc:108
JobWait< Security::PeerConnector > encryptionWait
waits for the established transport connection to be secured/encrypted
Definition FwdState.h:227
void updateAttempts(int)
sets n_tries to the given value (while keeping ALE, if any, in sync)
Definition FwdState.cc:1095
void usePinned()
send request on an existing connection dedicated to the requesting client
Definition FwdState.cc:1149
void tunnelEstablishmentDone(Http::TunnelerAnswer &answer)
resumes operations after the (possibly failed) HTTP CONNECT exchange
Definition FwdState.cc:929
int n_tries
the number of forwarding attempts so far
Definition FwdState.h:214
AsyncCall::Pointer closeHandler
The serverConn close handler.
Definition FwdState.h:240
static void logReplyStatus(int tries, const Http::StatusCode status)
Definition FwdState.cc:1402
static void RegisterWithCacheManager(void)
Definition FwdState.cc:1396
void updateAleWithFinalError()
updates ALE when we finalize the transaction error (if any)
Definition FwdState.cc:241
bool exhaustedTries() const
whether we have used up all permitted forwarding attempts
Definition FwdState.cc:1416
void cancelStep(const char *reason)
Definition FwdState.cc:201
void dispatch()
Definition FwdState.cc:1186
StoreEntry * entry
Definition FwdState.h:202
~FwdState() override
Definition FwdState.cc:305
struct FwdState::@52 flags
void establishTunnelThruProxy(const Comm::ConnectionPointer &)
Definition FwdState.cc:908
void stopAndDestroy(const char *reason)
ends forwarding; relies on refcounting so the effect may not be immediate
Definition FwdState.cc:184
static void initModule()
Definition FwdState.cc:1390
time_t start_t
Definition FwdState.h:213
bool checkRetriable()
Whether we may try sending this request again after a failure.
Definition FwdState.cc:735
void syncWithServerConn(const Comm::ConnectionPointer &server, const char *host, const bool reused)
commits to using the given open to-peer connection
Definition FwdState.cc:1065
bool waitingForDispatched
whether we are waiting for the last dispatch()ed activity to end
Definition FwdState.h:234
void retryOrBail()
Definition FwdState.cc:773
void noteConnection(HappyConnOpenerAnswer &)
Definition FwdState.cc:840
ResolvedPeersPointer destinations
paths for forwarding the request
Definition FwdState.h:236
void notifyConnOpener()
makes sure connection opener knows that the destinations have changed
Definition FwdState.cc:661
void markStoredReplyAsWhole(const char *whyWeAreSure)
Definition FwdState.cc:575
void connectStart()
Definition FwdState.cc:1115
Pointer self
Definition FwdState.h:210
PeerConnectionPointer destinationReceipt
peer selection result (or nil)
Definition FwdState.h:238
void useDestinations()
Definition FwdState.cc:437
void secureConnectionToPeer(const Comm::ConnectionPointer &)
encrypts an established TCP connection to peer (including origin servers)
Definition FwdState.cc:996
static void fwdStart(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *)
Same as Start() but no master xaction info (AccessLogEntry) available.
Definition FwdState.cc:407
void syncHierNote(const Comm::ConnectionPointer &server, const char *host)
Definition FwdState.cc:1085
int reforward()
Definition FwdState.cc:1308
AccessLogEntryPointer al
info for the future access.log entry
Definition FwdState.h:204
bool pinnedCanRetry() const
Definition FwdState.cc:1422
void advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep)
starts a preparation step for an established connection; retries on failures
Definition FwdState.cc:820
ErrorState * err
Definition FwdState.h:211
Final result (an open connection or an error) sent to the job initiator.
bool reused
whether conn was open earlier, by/for somebody else
PeerConnectionPointer conn
CbcPointer< ErrorState > error
problem details (nil on success)
Stopwatch totalPeeringTime
cumulative time spent (so far) communicating with all peers (see %<tt)
void resetPeerNotes(const Comm::ConnectionPointer &server, const char *requestedHost)
Http::StatusLine sline
Definition HttpReply.h:56
bool isHttpSafe() const
bool isIdempotent() const
CbcPointer< ConnStateData > clientConnectionManager
void clearError()
clear error details, useful for retries/repeats
void prepForDirect()
get ready to be sent directly to an origin server, excluding originserver
void prepForPeering(const CachePeer &peer)
get ready to be sent to the given cache_peer, including originserver
HttpRequestMethod method
Ip::Address indirect_client_addr
HierarchyLogEntry hier
RequestFlags flags
bool bodyNibbled() const
ConnStateData * pinnedConnection()
AnyP::Uri url
the request URI
Ip::Address client_addr
BodyPipe::Pointer body_pipe
optional pipeline to receive message body
Definition Message.h:97
Http::StatusCode status() const
retrieve the status code for this status line
Definition StatusLine.h:45
Comm::ConnectionPointer conn
SBuf leftovers
peer-generated bytes after a positive answer (or empty)
CbcPointer< ErrorState > squidError
problem details (or nil)
bool setIPv4()
Definition Address.cc:244
bool isIPv4() const
Definition Address.cc:178
bool isNoAddr() const
Definition Address.cc:304
bool isAnyAddr() const
Definition Address.cc:190
unsigned short port() const
Definition Address.cc:790
a netfilter mark/mask pair
void finish()
Definition JobWait.cc:44
void cancel(const char *reason)
Definition JobWait.cc:54
JobPointer job() const
Definition JobWait.h:76
void start(const JobPointer &aJob, const AsyncCall::Pointer &aCallback)
starts waiting for the given job to call the given callback
Definition JobWait.h:69
void update(const LogTagsErrors &other)
Definition LogTags.cc:14
static LogTagsErrors FromErrno(int errNo)
constructs an object matching errno(3) of a failed I/O call
Definition LogTags.cc:22
LogTagsErrors err
various problems augmenting the primary log tag
Definition LogTags.h:87
DelayId mostBytesAllowed() const
Definition MemObject.cc:466
HttpRequestPointer request
Definition MemObject.h:205
const HttpReply & baseReply() const
Definition MemObject.h:60
void noteUses(int uses)
Definition pconn.cc:559
bool subscribed
whether noteDestination() and noteDestinationsEnd() calls are allowed
void startSelectingDestinations(HttpRequest *request, const AccessLogEntry::Pointer &ale, StoreEntry *entry)
void stop()
pauses timer if stop() has not been called
Definition FwdState.h:64
Stopwatch & timer()
managed Stopwatch object within HierarchyLogEntry
Definition FwdState.cc:1597
HttpRequestPointer request
the owner of managed HierarchyLogEntry
Definition FwdState.h:77
~PeeringActivityTimer()
pauses timer if stop() has not been called
Definition FwdState.cc:1591
PeeringActivityTimer(const HttpRequestPointer &)
resumes timer
Definition FwdState.cc:1585
bool interceptTproxy
Set for requests handled by a "tproxy" port.
bool ftpNative
carries a representation of an FTP command [received on ftp_port]
void reinstatePath(const PeerConnectionPointer &)
bool notificationPending
whether HappyConnOpener::noteCandidatesChange() is scheduled to fire
bool empty() const
whether we lack any known candidate paths
bool destinationsFinalized
whether all of the available candidate paths received from DNS
void addPath(const Comm::ConnectionPointer &)
add a candidate path to try after all the existing paths
size_type length() const
Returns the number of bytes stored in SBuf.
Definition SBuf.h:419
bool isEmpty() const
Definition SBuf.h:435
A PeerConnector for TLS cache_peers and origin servers. No SslBump capabilities.
CbcPointer< ErrorState > error
problem details (nil on success)
Comm::ConnectionPointer conn
peer connection (secured on success)
bool tunneled
whether we spliced the connections instead of negotiating encryption
bool noteFwdPconnUse
hack: whether the connection requires fwdPconnPool->noteUses()
bool encryptTransport
whether transport encryption (TLS/SSL) is to be used on connections to the peer
int client_dst_passthru
int tproxy_uses_indirect_client
int forward_max_tries
struct SquidConfig::@77 Timeout
Acl::Address * outgoing_address
time_t forward
struct SquidConfig::@90 onoff
acl_access * serverPconnForNonretriable
struct SquidConfig::@91 accessList
acl_access * miss
A PeerConnector for HTTP origin servers. Capable of SslBumping.
void resume()
Definition Stopwatch.cc:31
void completeSuccessfully(const char *whyWeAreSureWeStoredTheWholeReply)
Definition store.cc:1017
void unregisterAbortCallback(const char *reason)
Definition store.cc:1489
uint16_t flags
Definition Store.h:231
MemObject & mem()
Definition Store.h:47
int locked() const
Definition Store.h:145
void completeTruncated(const char *whyWeConsiderTheReplyTruncated)
Definition store.cc:1024
int unlock(const char *context)
Definition store.cc:469
const char * url() const
Definition store.cc:1566
void lock(const char *context)
Definition store.cc:445
void registerAbortCallback(const AsyncCall::Pointer &)
notify the StoreEntry writer of a 3rd-party initiated StoreEntry abort
Definition store.cc:1481
MemObject * mem_obj
Definition Store.h:220
ping_status_t ping_status
Definition Store.h:241
void reset()
Definition store.cc:1621
void abort()
Definition store.cc:1077
store_status_t store_status
Definition Store.h:243
bool isEmpty() const
Definition Store.h:65
Definition fde.h:52
unsigned int nfConnmarkFromServer
Definition fde.h:171
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
Definition comm.cc:942
void comm_remove_close_handler(int fd, CLCB *handler, void *data)
Definition comm.cc:971
#define DBG_IMPORTANT
Definition Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
#define EBIT_SET(flag, bit)
Definition defines.h:65
#define EBIT_TEST(flag, bit)
Definition defines.h:67
@ ENTRY_FWD_HDR_WAIT
Definition enums.h:106
@ ENTRY_DISPATCHED
Definition enums.h:96
@ ENTRY_ABORTED
Definition enums.h:110
@ PING_WAITING
Sent ICP queries to peers and still awaiting responses.
Definition enums.h:38
@ PING_DONE
Definition enums.h:41
@ STORE_PENDING
Definition enums.h:46
@ ERR_CONNECT_FAIL
Definition forward.h:30
@ ERR_READ_TIMEOUT
Definition forward.h:26
@ ERR_FORWARDING_DENIED
Definition forward.h:21
@ ERR_UNSUP_REQ
Definition forward.h:44
@ ERR_GATEWAY_FAILURE
Definition forward.h:67
@ ERR_NONE
Definition forward.h:15
@ ERR_SHUTTING_DOWN
Definition forward.h:72
@ ERR_ZERO_SIZE_OBJECT
Definition forward.h:46
@ ERR_READ_ERROR
Definition forward.h:28
@ ERR_CANNOT_FORWARD
Definition forward.h:23
void fatal_dump(const char *message)
Definition fatal.cc:78
void fd_note(int fd, const char *s)
Definition fd.cc:211
#define fd_table
Definition fde.h:189
int shutting_down
void errorAppendEntry(StoreEntry *entry, ErrorState *err)
Definition errorpage.cc:738
void whoisStart(FwdState *fwd)
@ ORIGINAL_DST
Definition hier_code.h:36
void HTTPMSGUNLOCK(M *&a)
Definition Message.h:150
void HTTPMSGLOCK(Http::Message *a)
Definition Message.h:161
void httpStart(FwdState *fwd)
Definition http.cc:2531
void internalStart(const Comm::ConnectionPointer &clientConn, HttpRequest *request, StoreEntry *entry, const AccessLogEntry::Pointer &ale)
Definition internal.cc:32
unsigned char tos_t
Definition forward.h:27
uint32_t nfmark_t
Definition forward.h:26
void OBJH(StoreEntry *)
Definition forward.h:44
@ PROTO_HTTPS
@ PROTO_HTTP
@ PROTO_FTP
@ PROTO_WHOIS
@ PROTO_URN
@ PROTO_WAIS
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition Connection.cc:27
void StartGateway(FwdState *const fwdState)
A new FTP Gateway job.
void StartRelay(FwdState *const fwdState)
A new FTP Relay job.
Definition FtpRelay.cc:807
StatusCode
Definition StatusCode.h:20
@ scForbidden
Definition StatusCode.h:48
@ scInternalServerError
Definition StatusCode.h:73
@ scBadRequest
Definition StatusCode.h:45
@ scInvalidHeader
Squid header parsing error.
Definition StatusCode.h:88
@ scBadGateway
Definition StatusCode.h:75
@ scServiceUnavailable
Definition StatusCode.h:76
bool IsReforwardableStatus(StatusCode)
whether to send the request to another peer based on the current response status code
@ METHOD_CONNECT
Definition MethodType.h:29
void getTosFromServer(const Comm::ConnectionPointer &server, fde *clientFde)
Definition QosConfig.cc:48
@ dirOpened
opened (by Squid to an origin server or peer)
Definition QosConfig.h:72
Config TheConfig
Globally available instance of Qos::Config.
Definition QosConfig.cc:288
int setSockTos(const Comm::ConnectionPointer &conn, tos_t tos)
Definition QosConfig.cc:558
int setSockNfmark(const Comm::ConnectionPointer &conn, nfmark_t mark)
Definition QosConfig.cc:590
nfmark_t getNfConnmark(const Comm::ConnectionPointer &conn, const ConnectionDirection connDir)
Definition QosConfig.cc:151
void RegisterAction(char const *action, char const *desc, OBJH *handler, Protected, Atomic, Format)
time_t positiveTimeout(const time_t timeout)
void netdbPingSite(const char *hostname)
Definition net_db.cc:811
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition store.cc:855
int storePendingNClients(const StoreEntry *e)
struct squidaio_request_t * next
Definition aiops.cc:53
int unsigned int
Definition stub_fd.cc:19
void urnStart(HttpRequest *r, StoreEntry *e, const AccessLogEntryPointer &ale)
Definition urn.cc:206