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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors