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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors