FwdState.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2022 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 "CacheManager.h"
18#include "CachePeer.h"
19#include "client_side.h"
20#include "clients/forward.h"
22#include "comm/Connection.h"
23#include "comm/ConnOpener.h"
24#include "comm/Loops.h"
25#include "CommCalls.h"
26#include "errorpage.h"
27#include "event.h"
28#include "fd.h"
29#include "fde.h"
30#include "FwdState.h"
31#include "globals.h"
32#include "HappyConnOpener.h"
33#include "hier_code.h"
34#include "http.h"
35#include "http/Stream.h"
36#include "HttpReply.h"
37#include "HttpRequest.h"
38#include "icmp/net_db.h"
39#include "internal.h"
40#include "ip/Intercept.h"
41#include "ip/NfMarkConfig.h"
42#include "ip/QosConfig.h"
43#include "ip/tools.h"
44#include "MemObject.h"
45#include "mgr/Registration.h"
46#include "neighbors.h"
47#include "pconn.h"
48#include "PeerPoolMgr.h"
49#include "ResolvedPeers.h"
51#include "SquidConfig.h"
53#include "Store.h"
54#include "StoreClient.h"
55#include "urn.h"
56#include "whois.h"
57#if USE_OPENSSL
59#include "ssl/Config.h"
60#include "ssl/helper.h"
61#include "ssl/ServerBump.h"
62#include "ssl/support.h"
63#else
65#endif
66
67#include <cerrno>
68
70
72
73#define MAX_FWD_STATS_IDX 9
75
76PconnPool *fwdPconnPool = new PconnPool("server-peers", nullptr);
77
79
81{
82public:
84
86 method_(method), fwd_(fwd), answer_() {}
87
88 /* CallDialer API */
89 virtual bool canDial(AsyncCall &) { return fwd_.valid(); }
90 void dial(AsyncCall &) { ((&(*fwd_))->*method_)(answer_); }
91 virtual void print(std::ostream &os) const {
92 os << '(' << fwd_.get() << ", " << answer_ << ')';
93 }
94
95 /* Security::PeerConnector::CbDialer API */
97
98private:
102};
103
104void
106{
107 Pointer tmp = fwd; // Grab a temporary pointer to keep the object alive during our scope.
108
110 fwd->closeServerConnection("store entry aborted");
111 } else {
112 debugs(17, 7, "store entry aborted; no connection to close");
113 }
114 fwd->stopAndDestroy("store entry aborted");
115}
116
117void
119{
120 debugs(17, 3, "because " << reason << "; " << conn);
123 if (IsConnOpen(conn)) {
124 fwdPconnPool->noteUses(fd_table[conn->fd].pconn.uses);
125 conn->close();
126 }
127}
128
129void
131{
132 debugs(17, 3, "because " << reason << "; " << serverConn);
135 closeHandler = nullptr;
137 serverConn->close();
138}
139
140/**** PUBLIC INTERFACE ********************************************************/
141
143 entry(e),
144 request(r),
145 al(alp),
146 err(nullptr),
147 clientConn(client),
148 start_t(squid_curtime),
149 n_tries(0),
150 waitingForDispatched(false),
151 destinations(new ResolvedPeers()),
152 pconnRace(raceImpossible),
153 storedWholeReply_(nullptr)
154{
155 debugs(17, 2, "Forwarding client request " << client << ", url=" << e->url());
157 e->lock("FwdState");
158 flags.connected_okay = false;
159 flags.dont_retry = false;
160 flags.forward_completed = false;
161 flags.destinationsFound = false;
162 debugs(17, 3, "FwdState constructed, this=" << this);
163}
164
165// Called once, right after object creation, when it is safe to set self
167{
168 // Protect ourselves from being destroyed when the only Server pointing
169 // to us is gone (while we expect to talk to more Servers later).
170 // Once we set self, we are responsible for clearing it when we do not
171 // expect to talk to any servers.
172 self = aSelf; // refcounted
173
174 // We hope that either the store entry aborts or peer is selected.
175 // Otherwise we are going to leak our object.
176
177 // Ftp::Relay needs to preserve control connection on data aborts
178 // so it registers its own abort handler that calls ours when needed.
179 if (!request->flags.ftpNative) {
180 AsyncCall::Pointer call = asyncCall(17, 4, "FwdState::Abort", cbdataDialer(&FwdState::HandleStoreAbort, this));
182 }
183
184 // just in case; should already be initialized to false
185 request->flags.pinned = false;
186
187#if STRICT_ORIGINAL_DST
188 // Bug 3243: CVE 2009-0801
189 // Bypass of browser same-origin access control in intercepted communication
190 // To resolve this we must force DIRECT and only to the original client destination.
191 const bool isIntercepted = request && !request->flags.redirected && (request->flags.intercepted || request->flags.interceptTproxy);
192 const bool useOriginalDst = Config.onoff.client_dst_passthru || (request && !request->flags.hostVerified);
193 if (isIntercepted && useOriginalDst) {
194 selectPeerForIntercepted();
195 return;
196 }
197#endif
198
199 // do full route options selection
201}
202
204void
205FwdState::stopAndDestroy(const char *reason)
206{
207 debugs(17, 3, "for " << reason);
208
209 cancelStep(reason);
210
211 PeerSelectionInitiator::subscribed = false; // may already be false
212 self = nullptr; // we hope refcounting destroys us soon; may already be nil
213 /* do not place any code here as this object may be gone by now */
214}
215
219void
220FwdState::cancelStep(const char *reason)
221{
222 transportWait.cancel(reason);
223 encryptionWait.cancel(reason);
224 peerWait.cancel(reason);
225}
226
227#if STRICT_ORIGINAL_DST
229void
230FwdState::selectPeerForIntercepted()
231{
232 // We do not support re-wrapping inside CONNECT.
233 // Our only alternative is to fake a noteDestination() call.
234
235 // use pinned connection if available
236 if (ConnStateData *client = request->pinnedConnection()) {
237 // emulate the PeerSelector::selectPinned() "Skip ICP" effect
239
240 usePinned();
241 return;
242 }
243
244 // use client original destination as second preferred choice
245 const auto p = new Comm::Connection();
246 p->peerType = ORIGINAL_DST;
247 p->remote = clientConn->local;
249
250 debugs(17, 3, "using client original destination: " << *p);
255}
256#endif
257
259void
261{
262 if (!err || !al)
263 return;
264
265 LogTagsErrors lte;
266 lte.timedout = (err->xerrno == ETIMEDOUT || err->type == ERR_READ_TIMEOUT);
267 al->cache.code.err.update(lte);
268 if (!err->detail) {
269 static const auto d = MakeNamedErrorDetail("WITH_SERVER");
270 err->detailError(d);
271 }
273}
274
275void
277{
278 if (flags.forward_completed) {
279 debugs(17, DBG_IMPORTANT, "ERROR: FwdState::completed called on a completed request! Bad!");
280 return;
281 }
282
283 flags.forward_completed = true;
284
285 request->hier.stopPeerClock(false);
286
288 debugs(17, 3, "entry aborted");
289 return ;
290 }
291
292#if URL_CHECKSUM_DEBUG
293
294 entry->mem_obj->checkUrlChecksum();
295#endif
296
298 if (entry->isEmpty()) {
300 if (!err) // we quit (e.g., fd closed) before an error or content
302 assert(err);
305 err = nullptr;
306#if USE_OPENSSL
310 // no flags.dont_retry: completed() is a post-reforward() act
311 }
312#endif
313 } else {
314 updateAleWithFinalError(); // if any
317 else
318 entry->completeTruncated("FwdState default");
319 }
320 }
321
324
325}
326
328{
329 debugs(17, 3, "FwdState destructor start");
330
331 if (! flags.forward_completed)
332 completed();
333
335
337
338 delete err;
339
340 entry->unregisterAbortCallback("FwdState object destructed");
341
342 entry->unlock("FwdState");
343
344 entry = nullptr;
345
346 cancelStep("~FwdState");
347
349 closeServerConnection("~FwdState");
350
351 debugs(17, 3, "FwdState destructed, this=" << this);
352}
353
359void
361{
376 ch.al = al;
378 ch.syncAle(request, nullptr);
379 if (ch.fastCheck().denied()) {
380 err_type page_id;
382
383 if (page_id == ERR_NONE)
384 page_id = ERR_FORWARDING_DENIED;
385
386 const auto anErr = new ErrorState(page_id, Http::scForbidden, request, al);
387 errorAppendEntry(entry, anErr); // frees anErr
388 return;
389 }
390 }
391
392 debugs(17, 3, "'" << entry->url() << "'");
393 /*
394 * This seems like an odd place to bind mem_obj and request.
395 * Might want to assert that request is NULL at this point
396 */
398#if URL_CHECKSUM_DEBUG
399
400 entry->mem_obj->checkUrlChecksum();
401#endif
402
403 if (shutting_down) {
404 /* more yuck */
406 errorAppendEntry(entry, anErr); // frees anErr
407 return;
408 }
409
410 if (request->flags.internal) {
411 debugs(17, 2, "calling internalStart() due to request flag");
413 return;
414 }
415
416 switch (request->url.getScheme()) {
417
419 debugs(17, 2, "calling CacheManager due to request scheme " << request->url.getScheme());
421 return;
422
423 case AnyP::PROTO_URN:
425 return;
426
427 default:
429 fwd->start(fwd);
430 return;
431 }
432
433 /* NOTREACHED */
434}
435
436void
438{
439 // Hides AccessLogEntry.h from code that does not supply ALE anyway.
440 Start(clientConn, entry, request, nullptr);
441}
442
445static inline time_t
446diffOrZero(const time_t larger, const time_t smaller)
447{
448 return (larger > smaller) ? (larger - smaller) : 0;
449}
450
452time_t
453FwdState::ForwardTimeout(const time_t fwdStart)
454{
455 // time already spent on forwarding (0 if clock went backwards)
456 const time_t timeSpent = diffOrZero(squid_curtime, fwdStart);
457 return diffOrZero(Config.Timeout.forward, timeSpent);
458}
459
460bool
462{
463 return ForwardTimeout(fwdStart) > 0;
464}
465
466void
468{
469 if (!destinations->empty()) {
470 connectStart();
471 } else {
473 debugs(17, 4, "wait for more destinations to try");
474 return; // expect a noteDestination*() call
475 }
476
477 debugs(17, 3, "Connection failed: " << entry->url());
478 if (!err) {
480 fail(anErr);
481 } // else use actual error from last connection attempt
482
483 stopAndDestroy("tried all destinations");
484 }
485}
486
487void
489{
490 debugs(17, 3, err_type_str[errorState->type] << " \"" << Http::StatusCodeString(errorState->httpStatus) << "\"\n\t" << entry->url());
491
492 delete err;
493 err = errorState;
494
495 if (!errorState->request)
496 errorState->request = request;
497
500
501 destinationReceipt = nullptr; // may already be nil
502}
503
505void
507{
509
510 if (pconnRace == racePossible) {
511 debugs(17, 5, "pconn race happened");
513 if (destinationReceipt) {
515 destinationReceipt = nullptr;
516 }
517 }
518
519 if (ConnStateData *pinned_connection = request->pinnedConnection()) {
520 pinned_connection->pinning.zeroReply = true;
521 debugs(17, 4, "zero reply on pinned connection");
522 }
523}
524
528void
530{
531 debugs(17, 3, entry->url() );
535 closeHandler = nullptr;
536 serverConn = nullptr;
537 destinationReceipt = nullptr;
538}
539
540// \deprecated use unregister(Comm::ConnectionPointer &conn) instead
541void
543{
544 debugs(17, 3, entry->url() );
545 assert(fd == serverConnection()->fd);
547}
548
555void
557{
558 const auto replyStatus = entry->mem().baseReply().sline.status();
559 debugs(17, 3, *entry << " status " << replyStatus << ' ' << entry->url());
560#if URL_CHECKSUM_DEBUG
561
562 entry->mem_obj->checkUrlChecksum();
563#endif
564
565 logReplyStatus(n_tries, replyStatus);
566
567 // will already be false if complete() was called before/without dispatch()
568 waitingForDispatched = false;
569
570 if (reforward()) {
571 debugs(17, 3, "re-forwarding " << replyStatus << " " << entry->url());
572
575 serverConn = nullptr;
576 destinationReceipt = nullptr;
577
578 storedWholeReply_ = nullptr;
579 entry->reset();
580
582
583 } else {
585 debugs(17, 3, "server FD " << serverConnection()->fd << " not re-forwarding status " << replyStatus);
586 else
587 debugs(17, 3, "server (FD closed) not re-forwarding status " << replyStatus);
588
589 completed();
590
591 stopAndDestroy("forwarding completed");
592 }
593}
594
598bool
600{
602}
603
604void
605FwdState::markStoredReplyAsWhole(const char * const whyWeAreSure)
606{
607 debugs(17, 5, whyWeAreSure << " for " << *entry);
608
609 // the caller wrote everything to Store, but Store may silently abort writes
611 return;
612
613 storedWholeReply_ = whyWeAreSure;
614}
615
616void
618{
619 flags.destinationsFound = true;
620
621 if (!path) {
622 // We can call usePinned() without fear of clashing with an earlier
623 // forwarding attempt because PINNED must be the first destination.
625 usePinned();
626 return;
627 }
628
629 debugs(17, 3, path);
630
631 destinations->addPath(path);
632
633 if (transportWait) {
636 return; // and continue to wait for FwdState::noteConnection() callback
637 }
638
639 if (transporting())
640 return; // and continue to receive destinations for backup
641
643}
644
645void
647{
650
651 if (!flags.destinationsFound) {
652 if (selectionError) {
653 debugs(17, 3, "Will abort forwarding because path selection has failed.");
654 Must(!err); // if we tried to connect, then path selection succeeded
655 fail(selectionError);
656 }
657
658 stopAndDestroy("path selection found no paths");
659 return;
660 }
661 // else continue to use one of the previously noted destinations;
662 // if all of them fail, forwarding as whole will fail
663 Must(!selectionError); // finding at least one path means selection succeeded
664
665 if (transportWait) {
668 return; // and continue to wait for FwdState::noteConnection() callback
669 }
670
671 if (transporting()) {
672 // We are already using a previously opened connection (but were also
673 // receiving more destinations in case we need to re-forward).
674 debugs(17, 7, "keep transporting");
675 return;
676 }
677
678 // destinationsFound, but none of them worked, and we were waiting for more
679 assert(err);
680 stopAndDestroy("all found paths have failed");
681}
682
684void
686{
688 debugs(17, 7, "reusing pending notification about " << *destinations);
689 } else {
690 debugs(17, 7, "notifying about " << *destinations);
692 CallJobHere(17, 5, transportWait.job(), HappyConnOpener, noteCandidatesChange);
693 }
694}
695
696/**** CALLBACK WRAPPERS ************************************************************/
697
698static void
700{
701 FwdState *fwd = (FwdState *)params.data;
702 fwd->serverClosed();
703}
704
705/**** PRIVATE *****************************************************************/
706
707/*
708 * FwdState::checkRetry
709 *
710 * Return TRUE if the request SHOULD be retried. This method is
711 * called when the HTTP connection fails, or when the connection
712 * is closed before reading the end of HTTP headers from the server.
713 */
714bool
716{
717 if (shutting_down)
718 return false;
719
720 if (!self) { // we have aborted before the server called us back
721 debugs(17, 5, "not retrying because of earlier abort");
722 // we will be destroyed when the server clears its Pointer to us
723 return false;
724 }
725
727 return false;
728
729 if (!entry->isEmpty())
730 return false;
731
732 if (exhaustedTries())
733 return false;
734
736 return false;
737
739 return false;
740
741 if (flags.dont_retry)
742 return false;
743
744 if (request->bodyNibbled())
745 return false;
746
747 // NP: not yet actually connected anywhere. retry is safe.
748 if (!flags.connected_okay)
749 return true;
750
751 if (!checkRetriable())
752 return false;
753
754 return true;
755}
756
758bool
760{
761 // Optimize: A compliant proxy may retry PUTs, but Squid lacks the [rather
762 // complicated] code required to protect the PUT request body from being
763 // nibbled during the first try. Thus, Squid cannot retry some PUTs today.
764 if (request->body_pipe != nullptr)
765 return false;
766
767 // RFC2616 9.1 Safe and Idempotent Methods
769}
770
771void
773{
774 // XXX: This method logic attempts to tolerate Connection::close() called
775 // for serverConn earlier, by one of our dispatch()ed jobs. If that happens,
776 // serverConn will already be closed here or, worse, it will already be open
777 // for the next forwarding attempt. The current code prevents us getting
778 // stuck, but the long term solution is to stop sharing serverConn.
779 debugs(17, 2, serverConn);
781 const auto uses = fd_table[serverConn->fd].pconn.uses;
782 debugs(17, 3, "prior uses: " << uses);
783 fwdPconnPool->noteUses(uses); // XXX: May not have come from fwdPconnPool
785 }
786 serverConn = nullptr;
787 closeHandler = nullptr;
788 destinationReceipt = nullptr;
789
790 // will already be false if this closure happened before/without dispatch()
791 waitingForDispatched = false;
792
793 retryOrBail();
794}
795
796void
798{
799 if (checkRetry()) {
800 debugs(17, 3, "re-forwarding (" << n_tries << " tries, " << (squid_curtime - start_t) << " secs)");
802 return;
803 }
804
805 // TODO: should we call completed() here and move doneWithRetries there?
807
808 request->hier.stopPeerClock(false);
809
810 if (self != nullptr && !err && shutting_down && entry->isEmpty()) {
812 errorAppendEntry(entry, anErr);
813 }
814
815 stopAndDestroy("cannot retry");
816}
817
818// If the Server quits before nibbling at the request body, the body sender
819// will not know (so that we can retry). Call this if we will not retry. We
820// will notify the sender so that it does not get stuck waiting for space.
821void
823{
824 if (request && request->body_pipe != nullptr)
826}
827
828// called by the server that failed after calling unregister()
829void
831{
832 debugs(17, 2, "self=" << self << " err=" << err << ' ' << entry->url());
834 serverConn = nullptr;
835 destinationReceipt = nullptr;
836
837 // might already be false due to uncertainties documented in serverClosed()
838 waitingForDispatched = false;
839
840 retryOrBail();
841}
842
844template <typename StepStart>
845void
846FwdState::advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep)
847{
848 // TODO: Extract destination-specific handling from FwdState so that all the
849 // awkward, limited-scope advanceDestination() calls can be replaced with a
850 // single simple try/catch,retry block.
851 try {
852 startStep();
853 // now wait for the step callback
854 } catch (...) {
855 debugs (17, 2, "exception while trying to " << stepDescription << ": " << CurrentException);
856 closePendingConnection(conn, "connection preparation exception");
857 if (!err)
859 retryOrBail();
860 }
861}
862
865void
867{
869
871
872 Must(n_tries <= answer.n_tries); // n_tries cannot decrease
873 n_tries = answer.n_tries;
874
875 ErrorState *error = nullptr;
876 if ((error = answer.error.get())) {
877 flags.dont_retry = true; // or HappyConnOpener would not have given up
878 syncHierNote(answer.conn, request->url.host());
879 Must(!Comm::IsConnOpen(answer.conn));
880 answer.error.clear(); // preserve error for errorSendComplete()
881 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
882 // The socket could get closed while our callback was queued. Sync
883 // Connection. XXX: Connection::fd may already be stale/invalid here.
884 // We do not know exactly why the connection got closed, so we play it
885 // safe, allowing retries only for persistent (reused) connections
886 if (answer.reused) {
887 destinationReceipt = answer.conn;
889 }
890 syncHierNote(answer.conn, request->url.host());
891 closePendingConnection(answer.conn, "conn was closed while waiting for noteConnection");
893 } else {
894 assert(!error);
895 destinationReceipt = answer.conn;
897 // serverConn remains nil until syncWithServerConn()
898 }
899
900 if (error) {
901 fail(error);
902 retryOrBail();
903 return;
904 }
905
906 if (answer.reused) {
907 syncWithServerConn(answer.conn, request->url.host(), answer.reused);
908 return dispatch();
909 }
910
911 // Check if we need to TLS before use
912 if (const auto *peer = answer.conn->getPeer()) {
913 // Assume that it is only possible for the client-first from the
914 // bumping modes to try connect to a remote server. The bumped
915 // requests with other modes are using pinned connections or fails.
916 const bool clientFirstBump = request->flags.sslBumped;
917 // We need a CONNECT tunnel to send encrypted traffic through a proxy,
918 // but we do not support TLS inside TLS, so we exclude HTTPS proxies.
919 const bool originWantsEncryptedTraffic =
922 clientFirstBump;
923 if (originWantsEncryptedTraffic && // the "encrypted traffic" part
924 !peer->options.originserver && // the "through a proxy" part
925 !peer->secure.encryptTransport) // the "exclude HTTPS proxies" part
926 return advanceDestination("establish tunnel through proxy", answer.conn, [this,&answer] {
927 establishTunnelThruProxy(answer.conn);
928 });
929 }
930
932}
933
934void
936{
937 AsyncCall::Pointer callback = asyncCall(17,4,
938 "FwdState::tunnelEstablishmentDone",
940 HttpRequest::Pointer requestPointer = request;
941 const auto tunneler = new Http::Tunneler(conn, requestPointer, callback, connectingTimeout(conn), al);
942
943 // TODO: Replace this hack with proper Comm::Connection-Pool association
944 // that is not tied to fwdPconnPool and can handle disappearing pools.
945 tunneler->noteFwdPconnUse = true;
946
947#if USE_DELAY_POOLS
948 Must(conn);
949 Must(conn->getPeer());
950 if (!conn->getPeer()->options.no_delay)
951 tunneler->setDelayId(entry->mem_obj->mostBytesAllowed());
952#endif
953 peerWait.start(tunneler, callback);
954}
955
957void
959{
961
962 ErrorState *error = nullptr;
963 if (!answer.positive()) {
964 Must(!answer.conn);
965 error = answer.squidError.get();
966 Must(error);
967 answer.squidError.clear(); // preserve error for fail()
968 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
969 // The socket could get closed while our callback was queued. Sync
970 // Connection. XXX: Connection::fd may already be stale/invalid here.
971 closePendingConnection(answer.conn, "conn was closed while waiting for tunnelEstablishmentDone");
973 } else if (!answer.leftovers.isEmpty()) {
974 // This should not happen because TLS servers do not speak first. If we
975 // have to handle this, then pass answer.leftovers via a PeerConnector
976 // to ServerBio. See ClientBio::setReadBufData().
977 static int occurrences = 0;
978 const auto level = (occurrences++ < 100) ? DBG_IMPORTANT : 2;
979 debugs(17, level, "ERROR: Early data after CONNECT response. " <<
980 "Found " << answer.leftovers.length() << " bytes. " <<
981 "Closing " << answer.conn);
983 closePendingConnection(answer.conn, "server spoke before tunnelEstablishmentDone");
984 }
985 if (error) {
986 fail(error);
987 retryOrBail();
988 return;
989 }
990
992}
993
995void
997{
999
1000 const auto p = conn->getPeer();
1001 const bool peerWantsTls = p && p->secure.encryptTransport;
1002 // userWillTlsToPeerForUs assumes CONNECT == HTTPS
1003 const bool userWillTlsToPeerForUs = p && p->options.originserver &&
1005 const bool needTlsToPeer = peerWantsTls && !userWillTlsToPeerForUs;
1006 const bool clientFirstBump = request->flags.sslBumped; // client-first (already) bumped connection
1007 const bool needsBump = request->flags.sslPeek || clientFirstBump;
1008
1009 // 'GET https://...' requests. If a peer is used the request is forwarded
1010 // as is
1011 const bool needTlsToOrigin = !p && request->url.getScheme() == AnyP::PROTO_HTTPS && !clientFirstBump;
1012
1013 if (needTlsToPeer || needTlsToOrigin || needsBump) {
1014 return advanceDestination("secure connection to peer", conn, [this,&conn] {
1016 });
1017 }
1018
1019 // if not encrypting just run the post-connect actions
1021}
1022
1024void
1026{
1027 HttpRequest::Pointer requestPointer = request;
1028 AsyncCall::Pointer callback = asyncCall(17,4,
1029 "FwdState::ConnectedToPeer",
1031 const auto sslNegotiationTimeout = connectingTimeout(conn);
1032 Security::PeerConnector *connector = nullptr;
1033#if USE_OPENSSL
1034 if (request->flags.sslPeek)
1035 connector = new Ssl::PeekingPeerConnector(requestPointer, conn, clientConn, callback, al, sslNegotiationTimeout);
1036 else
1037#endif
1038 connector = new Security::BlindPeerConnector(requestPointer, conn, callback, al, sslNegotiationTimeout);
1039 connector->noteFwdPconnUse = true;
1040 encryptionWait.start(connector, callback);
1041}
1042
1044void
1046{
1048
1049 ErrorState *error = nullptr;
1050 if ((error = answer.error.get())) {
1051 assert(!answer.conn);
1052 answer.error.clear(); // preserve error for errorSendComplete()
1053 } else if (answer.tunneled) {
1054 assert(!answer.conn);
1055 // TODO: When ConnStateData establishes tunnels, its state changes
1056 // [in ways that may affect logging?]. Consider informing
1057 // ConnStateData about our tunnel or otherwise unifying tunnel
1058 // establishment [side effects].
1059 flags.dont_retry = true; // TunnelStateData took forwarding control
1060 entry->abort();
1061 complete(); // destroys us
1062 return;
1063 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1064 // The socket could get closed while our callback was queued. Sync
1065 // Connection. XXX: Connection::fd may already be stale/invalid here.
1066 closePendingConnection(answer.conn, "conn was closed while waiting for connectedToPeer");
1068 }
1069
1070 if (error) {
1071 fail(error);
1072 retryOrBail();
1073 return;
1074 }
1075
1077}
1078
1080void
1082{
1084
1085 // should reach ConnStateData before the dispatched Client job starts
1088
1089 if (serverConnection()->getPeer())
1091
1092 dispatch();
1093}
1094
1096void
1097FwdState::syncWithServerConn(const Comm::ConnectionPointer &conn, const char *host, const bool reused)
1098{
1100 serverConn = conn;
1101 // no effect on destinationReceipt (which may even be nil here)
1102
1104
1105 if (reused) {
1108 } else {
1110 // Comm::ConnOpener already applied proper/current markings
1111 }
1112
1113 syncHierNote(serverConn, host);
1114}
1115
1116void
1118{
1119 if (request)
1121 if (al)
1122 al->hier.resetPeerNotes(server, host);
1123}
1124
1130void
1132{
1133 debugs(17, 3, *destinations << " to " << entry->url());
1134
1136
1138 assert(!transporting());
1139
1140 // Ditch error page if it was created before.
1141 // A new one will be created if there's another problem
1142 delete err;
1143 err = nullptr;
1145
1147
1148 AsyncCall::Pointer callback = asyncCall(17, 5, "FwdState::noteConnection", HappyConnOpener::CbDialer<FwdState>(&FwdState::noteConnection, this));
1149
1151 const auto cs = new HappyConnOpener(destinations, callback, cause, start_t, n_tries, al);
1152 cs->setHost(request->url.host());
1153 bool retriable = checkRetriable();
1154 if (!retriable && Config.accessList.serverPconnForNonretriable) {
1156 ch.al = al;
1157 ch.syncAle(request, nullptr);
1158 retriable = ch.fastCheck().allowed();
1159 }
1160 cs->setRetriable(retriable);
1161 cs->allowPersistent(pconnRace != raceHappened);
1162 destinations->notificationPending = true; // start() is async
1163 transportWait.start(cs, callback);
1164}
1165
1167void
1169{
1170 const auto connManager = request->pinnedConnection();
1171 debugs(17, 7, "connection manager: " << connManager);
1172
1173 try {
1174 // TODO: Refactor syncWithServerConn() and callers to always set
1175 // serverConn inside that method.
1177 debugs(17, 5, "connection: " << serverConn);
1178 } catch (ErrorState * const anErr) {
1179 syncHierNote(nullptr, connManager ? connManager->pinning.host : request->url.host());
1180 serverConn = nullptr;
1181 fail(anErr);
1182 // Connection managers monitor their idle pinned to-server
1183 // connections and close from-client connections upon seeing
1184 // a to-server connection closure. Retrying here is futile.
1185 stopAndDestroy("pinned connection failure");
1186 return;
1187 }
1188
1189 ++n_tries;
1190 request->flags.pinned = true;
1191
1192 assert(connManager);
1193 if (connManager->pinnedAuth())
1194 request->flags.auth = true;
1195
1196 // the server may close the pinned connection before this request
1197 const auto reused = true;
1198 syncWithServerConn(serverConn, connManager->pinning.host, reused);
1199
1200 dispatch();
1201}
1202
1203void
1205{
1206 debugs(17, 3, clientConn << ": Fetching " << request->method << ' ' << entry->url());
1207 /*
1208 * Assert that server_fd is set. This is to guarantee that fwdState
1209 * is attached to something and will be deallocated when server_fd
1210 * is closed.
1211 */
1213
1215 waitingForDispatched = true;
1216
1217 fd_note(serverConnection()->fd, entry->url());
1218
1219 fd_table[serverConnection()->fd].noteUse();
1220
1221 /*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */
1223
1224 assert(entry->locked());
1225
1227
1228 flags.connected_okay = true;
1229
1231
1232 /* Retrieves remote server TOS or MARK value, and stores it as part of the
1233 * original client request FD object. It is later used to forward
1234 * remote server's TOS/MARK in the response to the client in case of a MISS.
1235 */
1236 if (Ip::Qos::TheConfig.isHitNfmarkActive()) {
1238 fde * clientFde = &fd_table[clientConn->fd]; // XXX: move the fd_table access into Ip::Qos
1239 /* Get the netfilter CONNMARK */
1241 }
1242 }
1243
1244#if _SQUID_LINUX_
1245 /* Bug 2537: The TOS forward part of QOS only applies to patched Linux kernels. */
1246 if (Ip::Qos::TheConfig.isHitTosActive()) {
1248 fde * clientFde = &fd_table[clientConn->fd]; // XXX: move the fd_table access into Ip::Qos
1249 /* Get the TOS value for the packet */
1251 }
1252 }
1253#endif
1254
1255#if USE_OPENSSL
1256 if (request->flags.sslPeek) {
1257 // we were just asked to peek at the server, and we did that
1260 unregister(serverConn); // async call owns it now
1261 flags.dont_retry = true; // we gave up forwarding control
1262 entry->abort();
1263 complete(); // destroys us
1264 return;
1265 }
1266#endif
1267
1268 if (const auto peer = serverConnection()->getPeer()) {
1269 ++peer->stats.fetches;
1270 request->prepForPeering(*peer);
1271 httpStart(this);
1272 } else {
1275
1276 switch (request->url.getScheme()) {
1277
1278 case AnyP::PROTO_HTTPS:
1279 httpStart(this);
1280 break;
1281
1282 case AnyP::PROTO_HTTP:
1283 httpStart(this);
1284 break;
1285
1286 case AnyP::PROTO_FTP:
1287 if (request->flags.ftpNative)
1288 Ftp::StartRelay(this);
1289 else
1290 Ftp::StartGateway(this);
1291 break;
1292
1294
1295 case AnyP::PROTO_URN:
1296 fatal_dump("Should never get here");
1297 break;
1298
1299 case AnyP::PROTO_WHOIS:
1300 whoisStart(this);
1301 break;
1302
1303 case AnyP::PROTO_WAIS: /* Not implemented */
1304
1305 default:
1306 debugs(17, DBG_IMPORTANT, "WARNING: Cannot retrieve '" << entry->url() << "'.");
1307 const auto anErr = new ErrorState(ERR_UNSUP_REQ, Http::scBadRequest, request, al);
1308 fail(anErr);
1309 // Set the dont_retry flag because this is not a transient (network) error.
1310 flags.dont_retry = true;
1312 serverConn->close(); // trigger cleanup
1313 }
1314 break;
1315 }
1316 }
1317}
1318
1319/*
1320 * FwdState::reforward
1321 *
1322 * returns TRUE if the transaction SHOULD be re-forwarded to the
1323 * next choice in the serverDestinations list. This method is called when
1324 * peer communication completes normally, or experiences
1325 * some error after receiving the end of HTTP headers.
1326 */
1327int
1329{
1330 StoreEntry *e = entry;
1331
1332 if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
1333 debugs(17, 3, "entry aborted");
1334 return 0;
1335 }
1336
1338 assert(e->mem_obj);
1339#if URL_CHECKSUM_DEBUG
1340
1341 e->mem_obj->checkUrlChecksum();
1342#endif
1343
1344 debugs(17, 3, e->url() << "?" );
1345
1346 if (request->flags.pinned && !pinnedCanRetry()) {
1347 debugs(17, 3, "pinned connection; cannot retry");
1348 return 0;
1349 }
1350
1352 debugs(17, 3, "No, ENTRY_FWD_HDR_WAIT isn't set");
1353 return 0;
1354 }
1355
1356 if (exhaustedTries())
1357 return 0;
1358
1359 if (request->bodyNibbled())
1360 return 0;
1361
1363 debugs(17, 3, "No alternative forwarding paths left");
1364 return 0;
1365 }
1366
1367 const auto s = entry->mem().baseReply().sline.status();
1368 debugs(17, 3, "status " << s);
1369 return reforwardableStatus(s);
1370}
1371
1372static void
1374{
1375 int i;
1376 int j;
1377 storeAppendPrintf(s, "Status");
1378
1379 for (j = 1; j < MAX_FWD_STATS_IDX; ++j) {
1380 storeAppendPrintf(s, "\ttry#%d", j);
1381 }
1382
1383 storeAppendPrintf(s, "\n");
1384
1385 for (i = 0; i <= (int) Http::scInvalidHeader; ++i) {
1386 if (FwdReplyCodes[0][i] == 0)
1387 continue;
1388
1389 storeAppendPrintf(s, "%3d", i);
1390
1391 for (j = 0; j <= MAX_FWD_STATS_IDX; ++j) {
1392 storeAppendPrintf(s, "\t%d", FwdReplyCodes[j][i]);
1393 }
1394
1395 storeAppendPrintf(s, "\n");
1396 }
1397}
1398
1399/**** STATIC MEMBER FUNCTIONS *************************************************/
1400
1401bool
1403{
1404 switch (s) {
1405
1406 case Http::scBadGateway:
1407
1409 return true;
1410
1411 case Http::scForbidden:
1412
1414
1416
1418 return Config.retry.onerror;
1419
1420 default:
1421 return false;
1422 }
1423
1424 /* NOTREACHED */
1425}
1426
1427void
1429{
1431}
1432
1433void
1435{
1436 Mgr::RegisterAction("forward", "Request Forwarding Statistics", fwdStats, 0, 1);
1437}
1438
1439void
1441{
1442 if (status > Http::scInvalidHeader)
1443 return;
1444
1445 assert(tries >= 0);
1446
1447 if (tries > MAX_FWD_STATS_IDX)
1448 tries = MAX_FWD_STATS_IDX;
1449
1450 ++ FwdReplyCodes[tries][status];
1451}
1452
1453bool
1455{
1457}
1458
1459bool
1461{
1463
1464 // pconn race on pinned connection: Currently we do not have any mechanism
1465 // to retry current pinned connection path.
1466 if (pconnRace == raceHappened)
1467 return false;
1468
1469 // If a bumped connection was pinned, then the TLS client was given our peer
1470 // details. Do not retry because we do not ensure that those details stay
1471 // constant. Step1-bumped connections do not get our TLS peer details, are
1472 // never pinned, and, hence, never reach this method.
1473 if (request->flags.sslBumped)
1474 return false;
1475
1476 // The other pinned cases are FTP proxying and connection-based HTTP
1477 // authentication. TODO: Do these cases have restrictions?
1478 return true;
1479}
1480
1481time_t
1483{
1484 const auto connTimeout = conn->connectTimeout(start_t);
1485 return positiveTimeout(connTimeout);
1486}
1487
1488/**** PRIVATE NON-MEMBER FUNCTIONS ********************************************/
1489
1490/*
1491 * DPW 2007-05-19
1492 * Formerly static, but now used by client_side_request.cc
1493 */
1495tos_t
1497{
1498 for (acl_tos *l = head; l; l = l->next) {
1499 if (!l->aclList || ch->fastCheck(l->aclList).allowed())
1500 return l->tos;
1501 }
1502
1503 return 0;
1504}
1505
1509{
1510 for (acl_nfmark *l = head; l; l = l->next) {
1511 if (!l->aclList || ch->fastCheck(l->aclList).allowed())
1512 return l->markConfig;
1513 }
1514
1515 return {};
1516}
1517
1518void
1520{
1521 // skip if an outgoing address is already set.
1522 if (!conn->local.isAnyAddr()) return;
1523
1524 // ensure that at minimum the wildcard local matches remote protocol
1525 if (conn->remote.isIPv4())
1526 conn->local.setIPv4();
1527
1528 // maybe use TPROXY client address
1529 if (request && request->flags.spoofClientIp) {
1530 if (!conn->getPeer() || !conn->getPeer()->options.no_tproxy) {
1531#if FOLLOW_X_FORWARDED_FOR && LINUX_NETFILTER
1533 conn->local = request->indirect_client_addr;
1534 else
1535#endif
1536 conn->local = request->client_addr;
1537 conn->local.port(0); // let OS pick the source port to prevent address clashes
1538 // some flags need setting on the socket to use this address
1539 conn->flags |= COMM_DOBIND;
1540 conn->flags |= COMM_TRANSPARENT;
1541 return;
1542 }
1543 // else no tproxy today ...
1544 }
1545
1547 return; // anything will do.
1548 }
1549
1550 ACLFilledChecklist ch(nullptr, request, nullptr);
1551 ch.dst_peer_name = conn->getPeer() ? conn->getPeer()->name : nullptr;
1552 ch.dst_addr = conn->remote;
1553
1554 // TODO use the connection details in ACL.
1555 // needs a bit of rework in ACLFilledChecklist to use Comm::Connection instead of ConnStateData
1556
1557 for (Acl::Address *l = Config.accessList.outgoing_address; l; l = l->next) {
1558
1559 /* check if the outgoing address is usable to the destination */
1560 if (conn->remote.isIPv4() != l->addr.isIPv4()) continue;
1561
1562 /* check ACLs for this outgoing address */
1563 if (!l->aclList || ch.fastCheck(l->aclList).allowed()) {
1564 conn->local = l->addr;
1565 return;
1566 }
1567 }
1568}
1569
1571static tos_t
1573{
1574 if (!Ip::Qos::TheConfig.tosToServer)
1575 return 0;
1576
1577 ACLFilledChecklist ch(nullptr, request, nullptr);
1578 ch.dst_peer_name = conn.getPeer() ? conn.getPeer()->name : nullptr;
1579 ch.dst_addr = conn.remote;
1580 return aclMapTOS(Ip::Qos::TheConfig.tosToServer, &ch);
1581}
1582
1584static nfmark_t
1586{
1587 if (!Ip::Qos::TheConfig.nfmarkToServer)
1588 return 0;
1589
1590 ACLFilledChecklist ch(nullptr, request, nullptr);
1591 ch.dst_peer_name = conn.getPeer() ? conn.getPeer()->name : nullptr;
1592 ch.dst_addr = conn.remote;
1593 const auto mc = aclFindNfMarkConfig(Ip::Qos::TheConfig.nfmarkToServer, &ch);
1594 return mc.mark;
1595}
1596
1597void
1599{
1600 // Get the server side TOS and Netfilter mark to be set on the connection.
1603 debugs(17, 3, "from " << conn.local << " tos " << int(conn.tos) << " netfilter mark " << conn.nfmark);
1604}
1605
1606void
1608{
1610
1611 // TODO: Avoid these calls if markings has not changed.
1612 if (conn.tos)
1614 if (conn.nfmark)
1616}
1617
AsyncCall * asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition: AsyncCall.h:154
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 CLCB(const CommCloseCbParams &params)
Definition: CommCalls.h:42
#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[]
Definition: stub_liberror.cc:8
PconnPool * fwdPconnPool
a collection of previously used persistent Squid-to-peer HTTP(S) connections
Definition: FwdState.cc:76
static int FwdReplyCodes[MAX_FWD_STATS_IDX+1][Http::scInvalidHeader+1]
Definition: FwdState.cc:74
static nfmark_t GetNfmarkToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1585
void getOutgoingAddress(HttpRequest *request, const Comm::ConnectionPointer &conn)
Definition: FwdState.cc:1519
Ip::NfMarkConfig aclFindNfMarkConfig(acl_nfmark *head, ACLChecklist *ch)
Checks for a netfilter mark value to apply depending on the ACL.
Definition: FwdState.cc:1508
void ResetMarkingsToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1607
tos_t aclMapTOS(acl_tos *head, ACLChecklist *ch)
Checks for a TOS value to apply depending on the ACL.
Definition: FwdState.cc:1496
void GetMarkingsToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1598
static tos_t GetTosToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1572
static OBJH fwdStats
Definition: FwdState.cc:71
static time_t diffOrZero(const time_t larger, const time_t smaller)
Definition: FwdState.cc:446
#define MAX_FWD_STATS_IDX
Definition: FwdState.cc:73
static CLCB fwdServerClosedWrapper
Definition: FwdState.cc:69
#define false
Definition: GnuRegex.c:240
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:126
#define assert(EX)
Definition: assert.h:19
static char server[MAXLINE]
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:318
Acl::Answer const & fastCheck()
Definition: Checklist.cc:332
virtual void syncAle(HttpRequest *adaptedRequest, const char *logUri) const
assigns uninitialized adapted_request and url ALE components
Ip::Address dst_addr
Ip::Address src_addr
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
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:156
bool allowed() const
Definition: Acl.h:150
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:162
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:168
ErrorDetail::Pointer detail
Definition: errorpage.h:204
int xerrno
Definition: errorpage.h:177
void detailError(const ErrorDetail::Pointer &dCode)
set error type-specific detail code
Definition: errorpage.h:109
HttpRequestPointer request
Definition: errorpage.h:175
Http::StatusCode httpStatus
Definition: errorpage.h:171
void dial(AsyncCall &)
Definition: FwdState.cc:90
virtual Security::EncryptorAnswer & answer()
gives PeerConnector access to the in-dialer answer
Definition: FwdState.cc:96
FwdStatePeerAnswerDialer(Method method, FwdState *fwd)
Definition: FwdState.cc:85
CbcPointer< FwdState > fwd_
Definition: FwdState.cc:100
virtual void print(std::ostream &os) const
Definition: FwdState.cc:91
void(FwdState::* Method)(Security::EncryptorAnswer &)
Definition: FwdState.cc:83
virtual bool canDial(AsyncCall &)
Definition: FwdState.cc:89
Security::EncryptorAnswer answer_
Definition: FwdState.cc:101
void secureConnectionToPeerIfNeeded(const Comm::ConnectionPointer &)
handles an established TCP connection to peer (including origin servers)
Definition: FwdState.cc:996
Comm::ConnectionPointer clientConn
a possibly open connection to the client.
Definition: FwdState.h:179
bool checkRetry()
Definition: FwdState.cc:715
void reactToZeroSizeObject()
ERR_ZERO_SIZE_OBJECT requires special adjustments.
Definition: FwdState.cc:506
void handleUnregisteredServerEnd()
Definition: FwdState.cc:830
virtual void noteDestinationsEnd(ErrorState *selectionError) override
Definition: FwdState.cc:646
void connectedToPeer(Security::EncryptorAnswer &answer)
called when all negotiations with the TLS-speaking peer have been completed
Definition: FwdState.cc:1045
HttpRequest * request
Definition: FwdState.h:170
void serverClosed()
Definition: FwdState.cc:772
void successfullyConnectedToPeer(const Comm::ConnectionPointer &)
called when all negotiations with the peer have been completed
Definition: FwdState.cc:1081
PconnRace pconnRace
current pconn race state
Definition: FwdState.h:211
const char * storedWholeReply_
Definition: FwdState.h:215
struct FwdState::@73 flags
FwdState(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *, const AccessLogEntryPointer &alp)
Definition: FwdState.cc:142
JobWait< HappyConnOpener > transportWait
waits for a transport connection to the peer to be established/opened
Definition: FwdState.h:191
void doneWithRetries()
Definition: FwdState.cc:822
JobWait< Http::Tunneler > peerWait
Definition: FwdState.h:198
void completed()
Definition: FwdState.cc:276
bool transporting() const
Definition: FwdState.cc:599
@ racePossible
Definition: FwdState.h:210
@ raceHappened
Definition: FwdState.h:210
@ raceImpossible
Definition: FwdState.h:210
void complete()
Definition: FwdState.cc:556
static void Start(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *, const AccessLogEntryPointer &alp)
Initiates request forwarding to a peer or origin server.
Definition: FwdState.cc:360
virtual void noteDestination(Comm::ConnectionPointer conn) override
called when a new unique destination has been found
Definition: FwdState.cc:617
static void HandleStoreAbort(FwdState *)
called by Store if the entry is no longer usable
Definition: FwdState.cc:105
time_t connectingTimeout(const Comm::ConnectionPointer &conn) const
Definition: FwdState.cc:1482
static bool EnoughTimeToReForward(const time_t fwdStart)
Definition: FwdState.cc:461
void closePendingConnection(const Comm::ConnectionPointer &conn, const char *reason)
get rid of a to-server connection that failed to become serverConn
Definition: FwdState.cc:118
void unregister(Comm::ConnectionPointer &conn)
Definition: FwdState.cc:529
void start(Pointer aSelf)
Definition: FwdState.cc:166
Comm::ConnectionPointer const & serverConnection() const
Definition: FwdState.h:106
Comm::ConnectionPointer serverConn
a successfully opened connection to a server.
Definition: FwdState.h:204
void fail(ErrorState *err)
Definition: FwdState.cc:488
static time_t ForwardTimeout(const time_t fwdStart)
time left to finish the whole forwarding process (which started at fwdStart)
Definition: FwdState.cc:453
void closeServerConnection(const char *reason)
stops monitoring server connection for closure and updates pconn stats
Definition: FwdState.cc:130
JobWait< Security::PeerConnector > encryptionWait
waits for the established transport connection to be secured/encrypted
Definition: FwdState.h:194
void usePinned()
send request on an existing connection dedicated to the requesting client
Definition: FwdState.cc:1168
void tunnelEstablishmentDone(Http::TunnelerAnswer &answer)
resumes operations after the (possibly failed) HTTP CONNECT exchange
Definition: FwdState.cc:958
int n_tries
the number of forwarding attempts so far
Definition: FwdState.h:181
AsyncCall::Pointer closeHandler
The serverConn close handler.
Definition: FwdState.h:207
static void logReplyStatus(int tries, const Http::StatusCode status)
Definition: FwdState.cc:1440
static void RegisterWithCacheManager(void)
Definition: FwdState.cc:1434
void updateAleWithFinalError()
updates ALE when we finalize the transaction error (if any)
Definition: FwdState.cc:260
bool exhaustedTries() const
whether we have used up all permitted forwarding attempts
Definition: FwdState.cc:1454
void cancelStep(const char *reason)
Definition: FwdState.cc:220
void dispatch()
Definition: FwdState.cc:1204
StoreEntry * entry
Definition: FwdState.h:169
void establishTunnelThruProxy(const Comm::ConnectionPointer &)
Definition: FwdState.cc:935
void stopAndDestroy(const char *reason)
ends forwarding; relies on refcounting so the effect may not be immediate
Definition: FwdState.cc:205
static void initModule()
Definition: FwdState.cc:1428
time_t start_t
Definition: FwdState.h:180
bool checkRetriable()
Whether we may try sending this request again after a failure.
Definition: FwdState.cc:759
void syncWithServerConn(const Comm::ConnectionPointer &server, const char *host, const bool reused)
commits to using the given open to-peer connection
Definition: FwdState.cc:1097
bool waitingForDispatched
whether we are waiting for the last dispatch()ed activity to end
Definition: FwdState.h:201
void retryOrBail()
Definition: FwdState.cc:797
void noteConnection(HappyConnOpenerAnswer &)
Definition: FwdState.cc:866
ResolvedPeersPointer destinations
paths for forwarding the request
Definition: FwdState.h:203
void notifyConnOpener()
makes sure connection opener knows that the destinations have changed
Definition: FwdState.cc:685
void markStoredReplyAsWhole(const char *whyWeAreSure)
Definition: FwdState.cc:605
void connectStart()
Definition: FwdState.cc:1131
Pointer self
Definition: FwdState.h:177
PeerConnectionPointer destinationReceipt
peer selection result (or nil)
Definition: FwdState.h:205
void useDestinations()
Definition: FwdState.cc:467
void secureConnectionToPeer(const Comm::ConnectionPointer &)
encrypts an established TCP connection to peer (including origin servers)
Definition: FwdState.cc:1025
static void fwdStart(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *)
Same as Start() but no master xaction info (AccessLogEntry) available.
Definition: FwdState.cc:437
void syncHierNote(const Comm::ConnectionPointer &server, const char *host)
Definition: FwdState.cc:1117
int reforward()
Definition: FwdState.cc:1328
AccessLogEntryPointer al
info for the future access.log entry
Definition: FwdState.h:171
bool pinnedCanRetry() const
Definition: FwdState.cc:1460
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:846
ErrorState * err
Definition: FwdState.h:178
virtual ~FwdState()
Definition: FwdState.cc:327
bool reforwardableStatus(const Http::StatusCode s) const
Definition: FwdState.cc:1402
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)
AsyncCall dialer for our callback. Gives us access to callback Answer.
void startPeerClock()
Start recording total time spent communicating with peers.
Definition: access_log.cc:296
void stopPeerClock(const bool force)
Definition: access_log.cc:303
void resetPeerNotes(const Comm::ConnectionPointer &server, const char *requestedHost)
Definition: access_log.cc:250
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
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)
Callback dialer API to allow Tunneler to set the answer.
Definition: HttpTunneler.h:40
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
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:188
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:66
bool ftpNative
carries a representation of an FTP command [received on ftp_port]
Definition: RequestFlags.h:103
bool hostVerified
Definition: RequestFlags.h:64
bool intercepted
Definition: RequestFlags.h:62
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
Callback dialer API to allow PeerConnector to set the answer.
Definition: PeerConnector.h:57
bool noteFwdPconnUse
hack: whether the connection requires fwdPconnPool->noteUses()
Definition: PeerConnector.h:72
struct SquidConfig::@111 onoff
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::@112 accessList
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::@115 retry
acl_access * miss
Definition: SquidConfig.h:360
struct SquidConfig::@98 Timeout
A PeerConnector for HTTP origin servers. Capable of SslBumping.
void completeSuccessfully(const char *whyWeAreSureWeStoredTheWholeReply)
Definition: store.cc:990
void unregisterAbortCallback(const char *reason)
Definition: store.cc:1456
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:997
int unlock(const char *context)
Definition: store.cc:442
const char * url() const
Definition: store.cc:1533
void lock(const char *context)
Definition: store.cc:418
void registerAbortCallback(const AsyncCall::Pointer &)
notify the StoreEntry writer of a 3rd-party initiated StoreEntry abort
Definition: store.cc:1448
MemObject * mem_obj
Definition: Store.h:221
ping_status_t ping_status
Definition: Store.h:242
void reset()
Definition: store.cc:1588
void abort()
Definition: store.cc:1050
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:947
void comm_remove_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:976
#define DBG_IMPORTANT
Definition: Stream.h:41
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:196
#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:217
#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:719
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:2449
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:2684
void StartRelay(FwdState *const fwdState)
A new FTP Relay job.
Definition: FtpRelay.cc:807
@ Error
Definition: ResultCode.h:19
StatusCode
Definition: StatusCode.h:20
@ scGatewayTimeout
Definition: StatusCode.h:75
@ scForbidden
Definition: StatusCode.h:47
@ scNotImplemented
Definition: StatusCode.h:72
@ 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
@ METHOD_CONNECT
Definition: MethodType.h:29
const char * StatusCodeString(const Http::StatusCode status)
Definition: StatusCode.cc:14
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
void peerConnectSucceded(CachePeer *p)
Definition: neighbors.cc:1305
time_t positiveTimeout(const time_t timeout)
Definition: neighbors.cc:1195
void netdbPingSite(const char *hostname)
Definition: net_db.cc:890
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:828
int storePendingNClients(const StoreEntry *e)
struct squidaio_request_t * next
Definition: aiops.cc:50
int unsigned int
Definition: stub_fd.cc:19
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
void urnStart(HttpRequest *r, StoreEntry *e, const AccessLogEntryPointer &ale)
Definition: urn.cc:211

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors