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{
356 ch.al = al;
358 ch.syncAle(request, nullptr);
359 if (ch.fastCheck().denied()) {
360 err_type page_id;
362
363 if (page_id == ERR_NONE)
364 page_id = ERR_FORWARDING_DENIED;
365
366 const auto anErr = new ErrorState(page_id, Http::scForbidden, request, al);
367 errorAppendEntry(entry, anErr); // frees anErr
368 return;
369 }
370 }
371
372 debugs(17, 3, "'" << entry->url() << "'");
373 /*
374 * This seems like an odd place to bind mem_obj and request.
375 * Might want to assert that request is NULL at this point
376 */
378#if URL_CHECKSUM_DEBUG
379
380 entry->mem_obj->checkUrlChecksum();
381#endif
382
383 if (shutting_down) {
384 /* more yuck */
386 errorAppendEntry(entry, anErr); // frees anErr
387 return;
388 }
389
390 if (request->flags.internal) {
391 debugs(17, 2, "calling internalStart() due to request flag");
393 return;
394 }
395
396 switch (request->url.getScheme()) {
397
398 case AnyP::PROTO_URN:
400 return;
401
402 default:
404 fwd->start(fwd);
405 return;
406 }
407
408 /* NOTREACHED */
409}
410
411void
413{
414 // Hides AccessLogEntry.h from code that does not supply ALE anyway.
415 Start(clientConn, entry, request, nullptr);
416}
417
420static inline time_t
421diffOrZero(const time_t larger, const time_t smaller)
422{
423 return (larger > smaller) ? (larger - smaller) : 0;
424}
425
427time_t
428FwdState::ForwardTimeout(const time_t fwdStart)
429{
430 // time already spent on forwarding (0 if clock went backwards)
431 const time_t timeSpent = diffOrZero(squid_curtime, fwdStart);
432 return diffOrZero(Config.Timeout.forward, timeSpent);
433}
434
435bool
437{
438 return ForwardTimeout(fwdStart) > 0;
439}
440
441void
443{
444 if (!destinations->empty()) {
445 connectStart();
446 } else {
448 debugs(17, 4, "wait for more destinations to try");
449 return; // expect a noteDestination*() call
450 }
451
452 debugs(17, 3, "Connection failed: " << entry->url());
453 if (!err) {
455 fail(anErr);
456 } // else use actual error from last connection attempt
457
458 stopAndDestroy("tried all destinations");
459 }
460}
461
462void
464{
465 debugs(17, 3, err_type_str[errorState->type] << " \"" << Http::StatusCodeString(errorState->httpStatus) << "\"\n\t" << entry->url());
466
467 delete err;
468 err = errorState;
469
470 if (!errorState->request)
471 errorState->request = request;
472
475
476 destinationReceipt = nullptr; // may already be nil
477}
478
480void
482{
484
485 if (pconnRace == racePossible) {
486 debugs(17, 5, "pconn race happened");
488 if (destinationReceipt) {
490 destinationReceipt = nullptr;
491 }
492 }
493
494 if (ConnStateData *pinned_connection = request->pinnedConnection()) {
495 pinned_connection->pinning.zeroReply = true;
496 debugs(17, 4, "zero reply on pinned connection");
497 }
498}
499
503void
505{
506 debugs(17, 3, entry->url() );
510 closeHandler = nullptr;
511 serverConn = nullptr;
512 destinationReceipt = nullptr;
513}
514
515// \deprecated use unregister(Comm::ConnectionPointer &conn) instead
516void
518{
519 debugs(17, 3, entry->url() );
520 assert(fd == serverConnection()->fd);
522}
523
530void
532{
533 const auto replyStatus = entry->mem().baseReply().sline.status();
534 debugs(17, 3, *entry << " status " << replyStatus << ' ' << entry->url());
535#if URL_CHECKSUM_DEBUG
536
537 entry->mem_obj->checkUrlChecksum();
538#endif
539
540 logReplyStatus(n_tries, replyStatus);
541
542 // will already be false if complete() was called before/without dispatch()
543 waitingForDispatched = false;
544
545 if (reforward()) {
546 debugs(17, 3, "re-forwarding " << replyStatus << " " << entry->url());
547
550 serverConn = nullptr;
551 destinationReceipt = nullptr;
552
553 storedWholeReply_ = nullptr;
554 entry->reset();
555
557
558 } else {
560 debugs(17, 3, "server FD " << serverConnection()->fd << " not re-forwarding status " << replyStatus);
561 else
562 debugs(17, 3, "server (FD closed) not re-forwarding status " << replyStatus);
563
564 completed();
565
566 stopAndDestroy("forwarding completed");
567 }
568}
569
573bool
575{
577}
578
579void
580FwdState::markStoredReplyAsWhole(const char * const whyWeAreSure)
581{
582 debugs(17, 5, whyWeAreSure << " for " << *entry);
583
584 // the caller wrote everything to Store, but Store may silently abort writes
586 return;
587
588 storedWholeReply_ = whyWeAreSure;
589}
590
591void
593{
594 flags.destinationsFound = true;
595
596 if (!path) {
597 // We can call usePinned() without fear of clashing with an earlier
598 // forwarding attempt because PINNED must be the first destination.
600 usePinned();
601 return;
602 }
603
604 debugs(17, 3, path);
605
606 destinations->addPath(path);
607
608 if (transportWait) {
611 return; // and continue to wait for FwdState::noteConnection() callback
612 }
613
614 if (transporting())
615 return; // and continue to receive destinations for backup
616
618}
619
620void
622{
625
626 if (!flags.destinationsFound) {
627 if (selectionError) {
628 debugs(17, 3, "Will abort forwarding because path selection has failed.");
629 Must(!err); // if we tried to connect, then path selection succeeded
630 fail(selectionError);
631 }
632
633 stopAndDestroy("path selection found no paths");
634 return;
635 }
636 // else continue to use one of the previously noted destinations;
637 // if all of them fail, forwarding as whole will fail
638 Must(!selectionError); // finding at least one path means selection succeeded
639
640 if (transportWait) {
643 return; // and continue to wait for FwdState::noteConnection() callback
644 }
645
646 if (transporting()) {
647 // We are already using a previously opened connection (but were also
648 // receiving more destinations in case we need to re-forward).
649 debugs(17, 7, "keep transporting");
650 return;
651 }
652
653 // destinationsFound, but none of them worked, and we were waiting for more
654 assert(err);
655 stopAndDestroy("all found paths have failed");
656}
657
659void
661{
663 debugs(17, 7, "reusing pending notification about " << *destinations);
664 } else {
665 debugs(17, 7, "notifying about " << *destinations);
667 CallJobHere(17, 5, transportWait.job(), HappyConnOpener, noteCandidatesChange);
668 }
669}
670
671/**** CALLBACK WRAPPERS ************************************************************/
672
673static void
675{
676 FwdState *fwd = (FwdState *)params.data;
677 fwd->serverClosed();
678}
679
680/**** PRIVATE *****************************************************************/
681
682/*
683 * FwdState::checkRetry
684 *
685 * Return TRUE if the request SHOULD be retried. This method is
686 * called when the HTTP connection fails, or when the connection
687 * is closed before reading the end of HTTP headers from the server.
688 */
689bool
691{
692 if (shutting_down)
693 return false;
694
695 if (!self) { // we have aborted before the server called us back
696 debugs(17, 5, "not retrying because of earlier abort");
697 // we will be destroyed when the server clears its Pointer to us
698 return false;
699 }
700
702 return false;
703
704 if (!entry->isEmpty())
705 return false;
706
707 if (exhaustedTries())
708 return false;
709
711 return false;
712
714 return false;
715
716 if (flags.dont_retry)
717 return false;
718
719 if (request->bodyNibbled())
720 return false;
721
722 // NP: not yet actually connected anywhere. retry is safe.
723 if (!flags.connected_okay)
724 return true;
725
726 if (!checkRetriable())
727 return false;
728
729 return true;
730}
731
733bool
735{
736 // Optimize: A compliant proxy may retry PUTs, but Squid lacks the [rather
737 // complicated] code required to protect the PUT request body from being
738 // nibbled during the first try. Thus, Squid cannot retry some PUTs today.
739 if (request->body_pipe != nullptr)
740 return false;
741
742 // RFC2616 9.1 Safe and Idempotent Methods
744}
745
746void
748{
749 // XXX: This method logic attempts to tolerate Connection::close() called
750 // for serverConn earlier, by one of our dispatch()ed jobs. If that happens,
751 // serverConn will already be closed here or, worse, it will already be open
752 // for the next forwarding attempt. The current code prevents us getting
753 // stuck, but the long term solution is to stop sharing serverConn.
754 debugs(17, 2, serverConn);
756 const auto uses = fd_table[serverConn->fd].pconn.uses;
757 debugs(17, 3, "prior uses: " << uses);
758 fwdPconnPool->noteUses(uses); // XXX: May not have come from fwdPconnPool
760 }
761 serverConn = nullptr;
762 closeHandler = nullptr;
763 destinationReceipt = nullptr;
764
765 // will already be false if this closure happened before/without dispatch()
766 waitingForDispatched = false;
767
768 retryOrBail();
769}
770
771void
773{
774 if (checkRetry()) {
775 debugs(17, 3, "re-forwarding (" << n_tries << " tries, " << (squid_curtime - start_t) << " secs)");
777 return;
778 }
779
780 // TODO: should we call completed() here and move doneWithRetries there?
782
783 request->hier.stopPeerClock(false);
784
785 if (self != nullptr && !err && shutting_down && entry->isEmpty()) {
787 errorAppendEntry(entry, anErr);
788 }
789
790 stopAndDestroy("cannot retry");
791}
792
793// If the Server quits before nibbling at the request body, the body sender
794// will not know (so that we can retry). Call this if we will not retry. We
795// will notify the sender so that it does not get stuck waiting for space.
796void
798{
799 if (request && request->body_pipe != nullptr)
801}
802
803// called by the server that failed after calling unregister()
804void
806{
807 debugs(17, 2, "self=" << self << " err=" << err << ' ' << entry->url());
809 serverConn = nullptr;
810 destinationReceipt = nullptr;
811
812 // might already be false due to uncertainties documented in serverClosed()
813 waitingForDispatched = false;
814
815 retryOrBail();
816}
817
819template <typename StepStart>
820void
821FwdState::advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep)
822{
823 // TODO: Extract destination-specific handling from FwdState so that all the
824 // awkward, limited-scope advanceDestination() calls can be replaced with a
825 // single simple try/catch,retry block.
826 try {
827 startStep();
828 // now wait for the step callback
829 } catch (...) {
830 debugs (17, 2, "exception while trying to " << stepDescription << ": " << CurrentException);
831 closePendingConnection(conn, "connection preparation exception");
832 if (!err)
834 retryOrBail();
835 }
836}
837
840void
842{
844
846
847 updateAttempts(answer.n_tries);
848
849 ErrorState *error = nullptr;
850 if ((error = answer.error.get())) {
851 flags.dont_retry = true; // or HappyConnOpener would not have given up
852 syncHierNote(answer.conn, request->url.host());
853 Must(!Comm::IsConnOpen(answer.conn));
854 answer.error.clear(); // preserve error for errorSendComplete()
855 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
856 // The socket could get closed while our callback was queued. Sync
857 // Connection. XXX: Connection::fd may already be stale/invalid here.
858 // We do not know exactly why the connection got closed, so we play it
859 // safe, allowing retries only for persistent (reused) connections
860 if (answer.reused) {
861 destinationReceipt = answer.conn;
863 }
864 syncHierNote(answer.conn, request->url.host());
865 closePendingConnection(answer.conn, "conn was closed while waiting for noteConnection");
867 } else {
868 assert(!error);
869 destinationReceipt = answer.conn;
871 // serverConn remains nil until syncWithServerConn()
872 }
873
874 if (error) {
875 fail(error);
876 retryOrBail();
877 return;
878 }
879
880 if (answer.reused) {
881 syncWithServerConn(answer.conn, request->url.host(), answer.reused);
882 return dispatch();
883 }
884
885 // Check if we need to TLS before use
886 if (const auto *peer = answer.conn->getPeer()) {
887 // Assume that it is only possible for the client-first from the
888 // bumping modes to try connect to a remote server. The bumped
889 // requests with other modes are using pinned connections or fails.
890 const bool clientFirstBump = request->flags.sslBumped;
891 // We need a CONNECT tunnel to send encrypted traffic through a proxy,
892 // but we do not support TLS inside TLS, so we exclude HTTPS proxies.
893 const bool originWantsEncryptedTraffic =
896 clientFirstBump;
897 if (originWantsEncryptedTraffic && // the "encrypted traffic" part
898 !peer->options.originserver && // the "through a proxy" part
899 !peer->secure.encryptTransport) // the "exclude HTTPS proxies" part
900 return advanceDestination("establish tunnel through proxy", answer.conn, [this,&answer] {
901 establishTunnelThruProxy(answer.conn);
902 });
903 }
904
906}
907
908void
910{
911 const auto callback = asyncCallback(17, 4, FwdState::tunnelEstablishmentDone, this);
912 HttpRequest::Pointer requestPointer = request;
913 const auto tunneler = new Http::Tunneler(conn, requestPointer, callback, connectingTimeout(conn), al);
914
915 // TODO: Replace this hack with proper Comm::Connection-Pool association
916 // that is not tied to fwdPconnPool and can handle disappearing pools.
917 tunneler->noteFwdPconnUse = true;
918
919#if USE_DELAY_POOLS
920 Must(conn);
921 Must(conn->getPeer());
922 if (!conn->getPeer()->options.no_delay)
923 tunneler->setDelayId(entry->mem_obj->mostBytesAllowed());
924#endif
925 peerWait.start(tunneler, callback);
926}
927
929void
931{
933
934 ErrorState *error = nullptr;
935 if (!answer.positive()) {
936 Must(!answer.conn);
937 error = answer.squidError.get();
938 Must(error);
939 answer.squidError.clear(); // preserve error for fail()
940 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
941 // The socket could get closed while our callback was queued. Sync
942 // Connection. XXX: Connection::fd may already be stale/invalid here.
943 closePendingConnection(answer.conn, "conn was closed while waiting for tunnelEstablishmentDone");
945 } else if (!answer.leftovers.isEmpty()) {
946 // This should not happen because TLS servers do not speak first. If we
947 // have to handle this, then pass answer.leftovers via a PeerConnector
948 // to ServerBio. See ClientBio::setReadBufData().
949 static int occurrences = 0;
950 const auto level = (occurrences++ < 100) ? DBG_IMPORTANT : 2;
951 debugs(17, level, "ERROR: Early data after CONNECT response. " <<
952 "Found " << answer.leftovers.length() << " bytes. " <<
953 "Closing " << answer.conn);
955 closePendingConnection(answer.conn, "server spoke before tunnelEstablishmentDone");
956 }
957 if (error) {
958 fail(error);
959 retryOrBail();
960 return;
961 }
962
964}
965
967void
969{
971
972 const auto p = conn->getPeer();
973 const bool peerWantsTls = p && p->secure.encryptTransport;
974 // userWillTlsToPeerForUs assumes CONNECT == HTTPS
975 const bool userWillTlsToPeerForUs = p && p->options.originserver &&
977 const bool needTlsToPeer = peerWantsTls && !userWillTlsToPeerForUs;
978 const bool clientFirstBump = request->flags.sslBumped; // client-first (already) bumped connection
979 const bool needsBump = request->flags.sslPeek || clientFirstBump;
980
981 // 'GET https://...' requests. If a peer is used the request is forwarded
982 // as is
983 const bool needTlsToOrigin = !p && request->url.getScheme() == AnyP::PROTO_HTTPS && !clientFirstBump;
984
985 if (needTlsToPeer || needTlsToOrigin || needsBump) {
986 return advanceDestination("secure connection to peer", conn, [this,&conn] {
988 });
989 }
990
991 // if not encrypting just run the post-connect actions
993}
994
996void
998{
999 HttpRequest::Pointer requestPointer = request;
1000 const auto callback = asyncCallback(17, 4, FwdState::connectedToPeer, this);
1001 const auto sslNegotiationTimeout = connectingTimeout(conn);
1002 Security::PeerConnector *connector = nullptr;
1003#if USE_OPENSSL
1004 if (request->flags.sslPeek)
1005 connector = new Ssl::PeekingPeerConnector(requestPointer, conn, clientConn, callback, al, sslNegotiationTimeout);
1006 else
1007#endif
1008 connector = new Security::BlindPeerConnector(requestPointer, conn, callback, al, sslNegotiationTimeout);
1009 connector->noteFwdPconnUse = true;
1010 encryptionWait.start(connector, callback);
1011}
1012
1014void
1016{
1018
1019 ErrorState *error = nullptr;
1020 if ((error = answer.error.get())) {
1021 assert(!answer.conn);
1022 answer.error.clear(); // preserve error for errorSendComplete()
1023 } else if (answer.tunneled) {
1024 assert(!answer.conn);
1025 // TODO: When ConnStateData establishes tunnels, its state changes
1026 // [in ways that may affect logging?]. Consider informing
1027 // ConnStateData about our tunnel or otherwise unifying tunnel
1028 // establishment [side effects].
1029 flags.dont_retry = true; // TunnelStateData took forwarding control
1030 entry->abort();
1031 complete(); // destroys us
1032 return;
1033 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1034 // The socket could get closed while our callback was queued. Sync
1035 // Connection. XXX: Connection::fd may already be stale/invalid here.
1036 closePendingConnection(answer.conn, "conn was closed while waiting for connectedToPeer");
1038 }
1039
1040 if (error) {
1041 fail(error);
1042 retryOrBail();
1043 return;
1044 }
1045
1047}
1048
1050void
1052{
1054
1055 // should reach ConnStateData before the dispatched Client job starts
1058
1060
1061 dispatch();
1062}
1063
1065void
1066FwdState::syncWithServerConn(const Comm::ConnectionPointer &conn, const char *host, const bool reused)
1067{
1069 serverConn = conn;
1070 // no effect on destinationReceipt (which may even be nil here)
1071
1073
1074 if (reused) {
1077 } else {
1079 // Comm::ConnOpener already applied proper/current markings
1080 }
1081
1082 syncHierNote(serverConn, host);
1083}
1084
1085void
1087{
1088 if (request)
1090 if (al)
1091 al->hier.resetPeerNotes(server, host);
1092}
1093
1095void
1096FwdState::updateAttempts(const int newValue)
1097{
1098 Assure(n_tries <= newValue); // n_tries cannot decrease
1099
1100 // Squid probably creates at most one FwdState/TunnelStateData object per
1101 // ALE, but, unlike an assignment would, this increment logic works even if
1102 // Squid uses multiple such objects for a given ALE in some esoteric cases.
1103 if (al)
1104 al->requestAttempts += (newValue - n_tries);
1105
1106 n_tries = newValue;
1107 debugs(17, 5, n_tries);
1108}
1109
1115void
1117{
1118 debugs(17, 3, *destinations << " to " << entry->url());
1119
1121
1123 assert(!transporting());
1124
1125 // Ditch error page if it was created before.
1126 // A new one will be created if there's another problem
1127 delete err;
1128 err = nullptr;
1130
1132
1133 const auto callback = asyncCallback(17, 5, FwdState::noteConnection, this);
1135 const auto cs = new HappyConnOpener(destinations, callback, cause, start_t, n_tries, al);
1136 cs->setHost(request->url.host());
1137 bool retriable = checkRetriable();
1138 if (!retriable && Config.accessList.serverPconnForNonretriable) {
1140 ch.al = al;
1141 ch.syncAle(request, nullptr);
1142 retriable = ch.fastCheck().allowed();
1143 }
1144 cs->setRetriable(retriable);
1145 cs->allowPersistent(pconnRace != raceHappened);
1146 destinations->notificationPending = true; // start() is async
1147 transportWait.start(cs, callback);
1148}
1149
1151void
1153{
1154 const auto connManager = request->pinnedConnection();
1155 debugs(17, 7, "connection manager: " << connManager);
1156
1157 try {
1158 // TODO: Refactor syncWithServerConn() and callers to always set
1159 // serverConn inside that method.
1161 debugs(17, 5, "connection: " << serverConn);
1162 } catch (ErrorState * const anErr) {
1163 syncHierNote(nullptr, connManager ? connManager->pinning.host : request->url.host());
1164 serverConn = nullptr;
1165 fail(anErr);
1166 // Connection managers monitor their idle pinned to-server
1167 // connections and close from-client connections upon seeing
1168 // a to-server connection closure. Retrying here is futile.
1169 stopAndDestroy("pinned connection failure");
1170 return;
1171 }
1172
1174
1175 request->flags.pinned = true;
1176
1177 assert(connManager);
1178 if (connManager->pinnedAuth())
1179 request->flags.auth = true;
1180
1181 // the server may close the pinned connection before this request
1182 const auto reused = true;
1183 syncWithServerConn(serverConn, connManager->pinning.host, reused);
1184
1185 dispatch();
1186}
1187
1188void
1190{
1191 debugs(17, 3, clientConn << ": Fetching " << request->method << ' ' << entry->url());
1192 /*
1193 * Assert that server_fd is set. This is to guarantee that fwdState
1194 * is attached to something and will be deallocated when server_fd
1195 * is closed.
1196 */
1198
1200 waitingForDispatched = true;
1201
1202 fd_note(serverConnection()->fd, entry->url());
1203
1204 fd_table[serverConnection()->fd].noteUse();
1205
1206 /*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */
1208
1209 assert(entry->locked());
1210
1212
1213 flags.connected_okay = true;
1214
1216
1217 /* Retrieves remote server TOS or MARK value, and stores it as part of the
1218 * original client request FD object. It is later used to forward
1219 * remote server's TOS/MARK in the response to the client in case of a MISS.
1220 */
1221 if (Ip::Qos::TheConfig.isHitNfmarkActive()) {
1223 fde * clientFde = &fd_table[clientConn->fd]; // XXX: move the fd_table access into Ip::Qos
1224 /* Get the netfilter CONNMARK */
1226 }
1227 }
1228
1229#if _SQUID_LINUX_
1230 /* Bug 2537: The TOS forward part of QOS only applies to patched Linux kernels. */
1231 if (Ip::Qos::TheConfig.isHitTosActive()) {
1233 fde * clientFde = &fd_table[clientConn->fd]; // XXX: move the fd_table access into Ip::Qos
1234 /* Get the TOS value for the packet */
1236 }
1237 }
1238#endif
1239
1240#if USE_OPENSSL
1241 if (request->flags.sslPeek) {
1242 // we were just asked to peek at the server, and we did that
1245 unregister(serverConn); // async call owns it now
1246 flags.dont_retry = true; // we gave up forwarding control
1247 entry->abort();
1248 complete(); // destroys us
1249 return;
1250 }
1251#endif
1252
1253 if (const auto peer = serverConnection()->getPeer()) {
1254 ++peer->stats.fetches;
1255 request->prepForPeering(*peer);
1256 httpStart(this);
1257 } else {
1260
1261 switch (request->url.getScheme()) {
1262
1263 case AnyP::PROTO_HTTPS:
1264 httpStart(this);
1265 break;
1266
1267 case AnyP::PROTO_HTTP:
1268 httpStart(this);
1269 break;
1270
1271 case AnyP::PROTO_FTP:
1272 if (request->flags.ftpNative)
1273 Ftp::StartRelay(this);
1274 else
1275 Ftp::StartGateway(this);
1276 break;
1277
1278 case AnyP::PROTO_URN:
1279 fatal_dump("Should never get here");
1280 break;
1281
1282 case AnyP::PROTO_WHOIS:
1283 whoisStart(this);
1284 break;
1285
1286 case AnyP::PROTO_WAIS: /* Not implemented */
1287
1288 default:
1289 debugs(17, DBG_IMPORTANT, "WARNING: Cannot retrieve '" << entry->url() << "'.");
1290 const auto anErr = new ErrorState(ERR_UNSUP_REQ, Http::scBadRequest, request, al);
1291 fail(anErr);
1292 // Set the dont_retry flag because this is not a transient (network) error.
1293 flags.dont_retry = true;
1295 serverConn->close(); // trigger cleanup
1296 }
1297 break;
1298 }
1299 }
1300}
1301
1302/*
1303 * FwdState::reforward
1304 *
1305 * returns TRUE if the transaction SHOULD be re-forwarded to the
1306 * next choice in the serverDestinations list. This method is called when
1307 * peer communication completes normally, or experiences
1308 * some error after receiving the end of HTTP headers.
1309 */
1310int
1312{
1313 StoreEntry *e = entry;
1314
1315 if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
1316 debugs(17, 3, "entry aborted");
1317 return 0;
1318 }
1319
1321 assert(e->mem_obj);
1322#if URL_CHECKSUM_DEBUG
1323
1324 e->mem_obj->checkUrlChecksum();
1325#endif
1326
1327 debugs(17, 3, e->url() << "?" );
1328
1329 if (request->flags.pinned && !pinnedCanRetry()) {
1330 debugs(17, 3, "pinned connection; cannot retry");
1331 return 0;
1332 }
1333
1335 debugs(17, 3, "No, ENTRY_FWD_HDR_WAIT isn't set");
1336 return 0;
1337 }
1338
1339 if (exhaustedTries())
1340 return 0;
1341
1342 if (request->bodyNibbled())
1343 return 0;
1344
1346 debugs(17, 3, "No alternative forwarding paths left");
1347 return 0;
1348 }
1349
1350 const auto s = entry->mem().baseReply().sline.status();
1351 debugs(17, 3, "status " << s);
1353}
1354
1355static void
1357{
1358 int i;
1359 int j;
1360 storeAppendPrintf(s, "Status");
1361
1362 for (j = 1; j < MAX_FWD_STATS_IDX; ++j) {
1363 storeAppendPrintf(s, "\ttry#%d", j);
1364 }
1365
1366 storeAppendPrintf(s, "\n");
1367
1368 for (i = 0; i <= (int) Http::scInvalidHeader; ++i) {
1369 if (FwdReplyCodes[0][i] == 0)
1370 continue;
1371
1372 storeAppendPrintf(s, "%3d", i);
1373
1374 for (j = 0; j <= MAX_FWD_STATS_IDX; ++j) {
1375 storeAppendPrintf(s, "\t%d", FwdReplyCodes[j][i]);
1376 }
1377
1378 storeAppendPrintf(s, "\n");
1379 }
1380}
1381
1382/**** STATIC MEMBER FUNCTIONS *************************************************/
1383
1384void
1386{
1388}
1389
1390void
1392{
1393 Mgr::RegisterAction("forward", "Request Forwarding Statistics", fwdStats, 0, 1);
1394}
1395
1396void
1398{
1399 if (status > Http::scInvalidHeader)
1400 return;
1401
1402 assert(tries >= 0);
1403
1404 if (tries > MAX_FWD_STATS_IDX)
1405 tries = MAX_FWD_STATS_IDX;
1406
1407 ++ FwdReplyCodes[tries][status];
1408}
1409
1410bool
1412{
1414}
1415
1416bool
1418{
1420
1421 // pconn race on pinned connection: Currently we do not have any mechanism
1422 // to retry current pinned connection path.
1423 if (pconnRace == raceHappened)
1424 return false;
1425
1426 // If a bumped connection was pinned, then the TLS client was given our peer
1427 // details. Do not retry because we do not ensure that those details stay
1428 // constant. Step1-bumped connections do not get our TLS peer details, are
1429 // never pinned, and, hence, never reach this method.
1430 if (request->flags.sslBumped)
1431 return false;
1432
1433 // The other pinned cases are FTP proxying and connection-based HTTP
1434 // authentication. TODO: Do these cases have restrictions?
1435 return true;
1436}
1437
1438time_t
1440{
1441 const auto connTimeout = conn->connectTimeout(start_t);
1442 return positiveTimeout(connTimeout);
1443}
1444
1445/**** PRIVATE NON-MEMBER FUNCTIONS ********************************************/
1446
1447/*
1448 * DPW 2007-05-19
1449 * Formerly static, but now used by client_side_request.cc
1450 */
1452tos_t
1454{
1455 for (acl_tos *l = head; l; l = l->next) {
1456 if (!l->aclList || ch->fastCheck(l->aclList).allowed())
1457 return l->tos;
1458 }
1459
1460 return 0;
1461}
1462
1466{
1467 for (acl_nfmark *l = head; l; l = l->next) {
1468 if (!l->aclList || ch->fastCheck(l->aclList).allowed())
1469 return l->markConfig;
1470 }
1471
1472 return {};
1473}
1474
1475void
1477{
1478 // skip if an outgoing address is already set.
1479 if (!conn->local.isAnyAddr()) return;
1480
1481 // ensure that at minimum the wildcard local matches remote protocol
1482 if (conn->remote.isIPv4())
1483 conn->local.setIPv4();
1484
1485 // maybe use TPROXY client address
1486 if (request && request->flags.spoofClientIp) {
1487 if (!conn->getPeer() || !conn->getPeer()->options.no_tproxy) {
1488#if FOLLOW_X_FORWARDED_FOR && LINUX_NETFILTER
1490 conn->local = request->indirect_client_addr;
1491 else
1492#endif
1493 conn->local = request->client_addr;
1494 conn->local.port(0); // let OS pick the source port to prevent address clashes
1495 // some flags need setting on the socket to use this address
1496 conn->flags |= COMM_DOBIND;
1497 conn->flags |= COMM_TRANSPARENT;
1498 return;
1499 }
1500 // else no tproxy today ...
1501 }
1502
1504 return; // anything will do.
1505 }
1506
1507 ACLFilledChecklist ch(nullptr, request, nullptr);
1508 ch.dst_peer_name = conn->getPeer() ? conn->getPeer()->name : nullptr;
1509 ch.dst_addr = conn->remote;
1510
1511 // TODO use the connection details in ACL.
1512 // needs a bit of rework in ACLFilledChecklist to use Comm::Connection instead of ConnStateData
1513
1514 for (Acl::Address *l = Config.accessList.outgoing_address; l; l = l->next) {
1515
1516 /* check if the outgoing address is usable to the destination */
1517 if (conn->remote.isIPv4() != l->addr.isIPv4()) continue;
1518
1519 /* check ACLs for this outgoing address */
1520 if (!l->aclList || ch.fastCheck(l->aclList).allowed()) {
1521 conn->local = l->addr;
1522 return;
1523 }
1524 }
1525}
1526
1528static tos_t
1530{
1531 if (!Ip::Qos::TheConfig.tosToServer)
1532 return 0;
1533
1534 ACLFilledChecklist ch(nullptr, request, nullptr);
1535 ch.dst_peer_name = conn.getPeer() ? conn.getPeer()->name : nullptr;
1536 ch.dst_addr = conn.remote;
1537 return aclMapTOS(Ip::Qos::TheConfig.tosToServer, &ch);
1538}
1539
1541static nfmark_t
1543{
1544 if (!Ip::Qos::TheConfig.nfmarkToServer)
1545 return 0;
1546
1547 ACLFilledChecklist ch(nullptr, request, nullptr);
1548 ch.dst_peer_name = conn.getPeer() ? conn.getPeer()->name : nullptr;
1549 ch.dst_addr = conn.remote;
1550 const auto mc = aclFindNfMarkConfig(Ip::Qos::TheConfig.nfmarkToServer, &ch);
1551 return mc.mark;
1552}
1553
1554void
1556{
1557 // Get the server side TOS and Netfilter mark to be set on the connection.
1558 conn.tos = GetTosToServer(request, conn);
1559 conn.nfmark = GetNfmarkToServer(request, conn);
1560 debugs(17, 3, "from " << conn.local << " tos " << int(conn.tos) << " netfilter mark " << conn.nfmark);
1561}
1562
1563void
1565{
1566 GetMarkingsToServer(request, conn);
1567
1568 // TODO: Avoid these calls if markings has not changed.
1569 if (conn.tos)
1571 if (conn.nfmark)
1573}
1574
#define Assure(condition)
Definition: Assure.h:35
RefCount< AsyncCallT< Dialer > > asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition: AsyncCall.h:156
#define asyncCallback(dbgSection, dbgLevel, method, object)
UnaryCbdataDialer< Argument1 > cbdataDialer(typename UnaryCbdataDialer< Argument1 >::Handler *handler, Argument1 *arg1)
#define CallJobHere(debugSection, debugLevel, job, Class, method)
Definition: AsyncJobCalls.h:58
#define CallJobHere1(debugSection, debugLevel, job, Class, method, arg1)
Definition: AsyncJobCalls.h:63
void NoteOutgoingConnectionSuccess(CachePeer *const peer)
Definition: CachePeer.h:233
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:1542
void getOutgoingAddress(HttpRequest *request, const Comm::ConnectionPointer &conn)
Definition: FwdState.cc:1476
Ip::NfMarkConfig aclFindNfMarkConfig(acl_nfmark *head, ACLChecklist *ch)
Checks for a netfilter mark value to apply depending on the ACL.
Definition: FwdState.cc:1465
void ResetMarkingsToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1564
tos_t aclMapTOS(acl_tos *head, ACLChecklist *ch)
Checks for a TOS value to apply depending on the ACL.
Definition: FwdState.cc:1453
void GetMarkingsToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1555
static tos_t GetTosToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1529
static OBJH fwdStats
Definition: FwdState.cc:73
static time_t diffOrZero(const time_t larger, const time_t smaller)
Definition: FwdState.cc:421
#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:75
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:100
void expectNoConsumption()
there will be no more setConsumer() calls
Definition: BodyPipe.cc:267
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:183
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:207
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:968
Comm::ConnectionPointer clientConn
a possibly open connection to the client.
Definition: FwdState.h:178
bool checkRetry()
Definition: FwdState.cc:690
void reactToZeroSizeObject()
ERR_ZERO_SIZE_OBJECT requires special adjustments.
Definition: FwdState.cc:481
void handleUnregisteredServerEnd()
Definition: FwdState.cc:805
void noteDestinationsEnd(ErrorState *selectionError) override
Definition: FwdState.cc:621
void connectedToPeer(Security::EncryptorAnswer &answer)
called when all negotiations with the TLS-speaking peer have been completed
Definition: FwdState.cc:1015
HttpRequest * request
Definition: FwdState.h:169
void serverClosed()
Definition: FwdState.cc:747
void successfullyConnectedToPeer(const Comm::ConnectionPointer &)
called when all negotiations with the peer have been completed
Definition: FwdState.cc:1051
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:797
JobWait< Http::Tunneler > peerWait
Definition: FwdState.h:197
void completed()
Definition: FwdState.cc:257
bool transporting() const
Definition: FwdState.cc:574
@ racePossible
Definition: FwdState.h:209
@ raceHappened
Definition: FwdState.h:209
@ raceImpossible
Definition: FwdState.h:209
void complete()
Definition: FwdState.cc:531
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:592
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:1439
static bool EnoughTimeToReForward(const time_t fwdStart)
Definition: FwdState.cc:436
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:504
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:463
static time_t ForwardTimeout(const time_t fwdStart)
time left to finish the whole forwarding process (which started at fwdStart)
Definition: FwdState.cc:428
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:1096
void usePinned()
send request on an existing connection dedicated to the requesting client
Definition: FwdState.cc:1152
void tunnelEstablishmentDone(Http::TunnelerAnswer &answer)
resumes operations after the (possibly failed) HTTP CONNECT exchange
Definition: FwdState.cc:930
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
static void logReplyStatus(int tries, const Http::StatusCode status)
Definition: FwdState.cc:1397
static void RegisterWithCacheManager(void)
Definition: FwdState.cc:1391
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:1411
void cancelStep(const char *reason)
Definition: FwdState.cc:198
void dispatch()
Definition: FwdState.cc:1189
StoreEntry * entry
Definition: FwdState.h:168
~FwdState() override
Definition: FwdState.cc:308
void establishTunnelThruProxy(const Comm::ConnectionPointer &)
Definition: FwdState.cc:909
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:1385
time_t start_t
Definition: FwdState.h:179
bool checkRetriable()
Whether we may try sending this request again after a failure.
Definition: FwdState.cc:734
void syncWithServerConn(const Comm::ConnectionPointer &server, const char *host, const bool reused)
commits to using the given open to-peer connection
Definition: FwdState.cc:1066
bool waitingForDispatched
whether we are waiting for the last dispatch()ed activity to end
Definition: FwdState.h:200
void retryOrBail()
Definition: FwdState.cc:772
void noteConnection(HappyConnOpenerAnswer &)
Definition: FwdState.cc:841
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:660
void markStoredReplyAsWhole(const char *whyWeAreSure)
Definition: FwdState.cc:580
void connectStart()
Definition: FwdState.cc:1116
Pointer self
Definition: FwdState.h:176
PeerConnectionPointer destinationReceipt
peer selection result (or nil)
Definition: FwdState.h:204
void useDestinations()
Definition: FwdState.cc:442
void secureConnectionToPeer(const Comm::ConnectionPointer &)
encrypts an established TCP connection to peer (including origin servers)
Definition: FwdState.cc:997
struct FwdState::@67 flags
static void fwdStart(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *)
Same as Start() but no master xaction info (AccessLogEntry) available.
Definition: FwdState.cc:412
void syncHierNote(const Comm::ConnectionPointer &server, const char *host)
Definition: FwdState.cc:1086
int reforward()
Definition: FwdState.cc:1311
AccessLogEntryPointer al
info for the future access.log entry
Definition: FwdState.h:170
bool pinnedCanRetry() const
Definition: FwdState.cc:1417
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:821
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:245
void stopPeerClock(const bool force)
Definition: access_log.cc:252
void resetPeerNotes(const Comm::ConnectionPointer &server, const char *requestedHost)
Definition: access_log.cc:199
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:725
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:23
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:466
HttpRequestPointer request
Definition: MemObject.h:212
const HttpReply & baseReply() const
Definition: MemObject.h:60
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:335
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:112
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:85
bool empty() const
whether we lack any known candidate paths
Definition: ResolvedPeers.h:46
bool destinationsFinalized
whether all of the available candidate paths received from DNS
Definition: ResolvedPeers.h:82
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:338
int tproxy_uses_indirect_client
Definition: SquidConfig.h:330
int forward_max_tries
Definition: SquidConfig.h:351
struct SquidConfig::@106 onoff
Acl::Address * outgoing_address
Definition: SquidConfig.h:380
time_t forward
Definition: SquidConfig.h:116
AclDenyInfoList * denyInfoList
Definition: SquidConfig.h:408
acl_access * serverPconnForNonretriable
Definition: SquidConfig.h:405
struct SquidConfig::@93 Timeout
acl_access * miss
Definition: SquidConfig.h:362
A PeerConnector for HTTP origin servers. Capable of SslBumping.
void completeSuccessfully(const char *whyWeAreSureWeStoredTheWholeReply)
Definition: store.cc:1003
void unregisterAbortCallback(const char *reason)
Definition: store.cc:1475
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:1010
int unlock(const char *context)
Definition: store.cc:455
const char * url() const
Definition: store.cc:1552
void lock(const char *context)
Definition: store.cc:431
void registerAbortCallback(const AsyncCall::Pointer &)
notify the StoreEntry writer of a 3rd-party initiated StoreEntry abort
Definition: store.cc:1467
MemObject * mem_obj
Definition: Store.h:221
ping_status_t ping_status
Definition: Store.h:242
void reset()
Definition: store.cc:1607
void abort()
Definition: store.cc:1063
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:39
const char * AclMatchedName
Definition: Acl.cc:29
void errorAppendEntry(StoreEntry *entry, ErrorState *err)
Definition: errorpage.cc:717
void whoisStart(FwdState *fwd)
Definition: whois.cc:56
@ ORIGINAL_DST
Definition: hier_code.h:36
void HTTPMSGUNLOCK(M *&a)
Definition: Message.h:150
void HTTPMSGLOCK(Http::Message *a)
Definition: Message.h:161
void httpStart(FwdState *fwd)
Definition: http.cc:2459
void internalStart(const Comm::ConnectionPointer &clientConn, HttpRequest *request, StoreEntry *entry, const AccessLogEntry::Pointer &ale)
Definition: internal.cc:33
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:36
@ PROTO_URN
Definition: ProtocolType.h:35
@ 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:70
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:1095
void netdbPingSite(const char *hostname)
Definition: net_db.cc:827
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:841
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:204

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors