FwdState.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2020 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"
53 #include "SquidTime.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/ErrorDetail.h"
63 #include "ssl/helper.h"
64 #include "ssl/ServerBump.h"
65 #include "ssl/support.h"
66 #else
68 #endif
69 
70 #include <cerrno>
71 
73 
74 static OBJH fwdStats;
75 
76 #define MAX_FWD_STATS_IDX 9
78 
79 PconnPool *fwdPconnPool = new PconnPool("server-peers", nullptr);
80 
82 
84 {
85 public:
87 
89  method_(method), fwd_(fwd), answer_() {}
90 
91  /* CallDialer API */
92  virtual bool canDial(AsyncCall &call) { return fwd_.valid(); }
93  void dial(AsyncCall &call) { ((&(*fwd_))->*method_)(answer_); }
94  virtual void print(std::ostream &os) const {
95  os << '(' << fwd_.get() << ", " << answer_ << ')';
96  }
97 
98  /* Security::PeerConnector::CbDialer API */
99  virtual Security::EncryptorAnswer &answer() { return answer_; }
100 
101 private:
105 };
106 
107 void
109 {
110  FwdState* fwd = (FwdState*)d;
111  Pointer tmp = fwd; // Grab a temporary pointer to keep the object alive during our scope.
112 
113  if (Comm::IsConnOpen(fwd->serverConnection())) {
114  fwd->closeServerConnection("store entry aborted");
115  } else {
116  debugs(17, 7, HERE << "store entry aborted; no connection to close");
117  }
118  fwd->stopAndDestroy("store entry aborted");
119 }
120 
121 void
123 {
124  debugs(17, 3, "because " << reason << "; " << conn);
125  assert(!serverConn);
127  if (IsConnOpen(conn)) {
128  fwdPconnPool->noteUses(fd_table[conn->fd].pconn.uses);
129  conn->close();
130  }
131 }
132 
133 void
135 {
136  debugs(17, 3, "because " << reason << "; " << serverConn);
138  closeHandler = NULL;
139  fwdPconnPool->noteUses(fd_table[serverConn->fd].pconn.uses);
140  serverConn->close();
141 }
142 
143 /**** PUBLIC INTERFACE ********************************************************/
144 
146  entry(e),
147  request(r),
148  al(alp),
149  err(NULL),
150  clientConn(client),
151  start_t(squid_curtime),
152  n_tries(0),
153  destinations(new ResolvedPeers()),
154  pconnRace(raceImpossible)
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)
182 
183  // just in case; should already be initialized to false
184  request->flags.pinned = false;
185 
186 #if STRICT_ORIGINAL_DST
187  // Bug 3243: CVE 2009-0801
188  // Bypass of browser same-origin access control in intercepted communication
189  // To resolve this we must force DIRECT and only to the original client destination.
190  const bool isIntercepted = request && !request->flags.redirected && (request->flags.intercepted || request->flags.interceptTproxy);
191  const bool useOriginalDst = Config.onoff.client_dst_passthru || (request && !request->flags.hostVerified);
192  if (isIntercepted && useOriginalDst) {
193  selectPeerForIntercepted();
194  return;
195  }
196 #endif
197 
198  // do full route options selection
200 }
201 
203 void
204 FwdState::stopAndDestroy(const char *reason)
205 {
206  debugs(17, 3, "for " << reason);
207 
208  if (opening())
209  cancelOpening(reason);
210 
211  PeerSelectionInitiator::subscribed = false; // may already be false
212  self = nullptr; // we hope refcounting destroys us soon; may already be nil
213  /* do not place any code here as this object may be gone by now */
214 }
215 
220 void
221 FwdState::cancelOpening(const char *reason)
222 {
223  assert(calls.connector);
224  calls.connector->cancel(reason);
225  calls.connector = nullptr;
227  connOpener.clear();
228 }
229 
230 #if STRICT_ORIGINAL_DST
231 void
233 FwdState::selectPeerForIntercepted()
234 {
235  // We do not support re-wrapping inside CONNECT.
236  // Our only alternative is to fake a noteDestination() call.
237 
238  // use pinned connection if available
239  if (ConnStateData *client = request->pinnedConnection()) {
240  // emulate the PeerSelector::selectPinned() "Skip ICP" effect
242 
243  usePinned();
244  return;
245  }
246 
247  // use client original destination as second preferred choice
248  const auto p = new Comm::Connection();
249  p->peerType = ORIGINAL_DST;
250  p->remote = clientConn->local;
252 
253  debugs(17, 3, HERE << "using client original destination: " << *p);
254  destinations->addPath(p);
257  useDestinations();
258 }
259 #endif
260 
261 void
263 {
264  if (flags.forward_completed) {
265  debugs(17, DBG_IMPORTANT, HERE << "FwdState::completed called on a completed request! Bad!");
266  return;
267  }
268 
269  flags.forward_completed = true;
270 
271  request->hier.stopPeerClock(false);
272 
274  debugs(17, 3, HERE << "entry aborted");
275  return ;
276  }
277 
278 #if URL_CHECKSUM_DEBUG
279 
280  entry->mem_obj->checkUrlChecksum();
281 #endif
282 
283  if (entry->store_status == STORE_PENDING) {
284  if (entry->isEmpty()) {
285  if (!err) // we quit (e.g., fd closed) before an error or content
287  assert(err);
289  err = NULL;
290 #if USE_OPENSSL
294  }
295 #endif
296  } else {
297  entry->complete();
299  }
300  }
301 
302  if (storePendingNClients(entry) > 0)
304 
305 }
306 
308 {
309  debugs(17, 3, "FwdState destructor start");
310 
311  if (! flags.forward_completed)
312  completed();
313 
314  doneWithRetries();
315 
317 
318  delete err;
319 
321 
322  entry->unlock("FwdState");
323 
324  entry = NULL;
325 
326  if (opening())
327  cancelOpening("~FwdState");
328 
330  closeServerConnection("~FwdState");
331 
332  debugs(17, 3, "FwdState destructed, this=" << this);
333 }
334 
340 void
342 {
357  ch.al = al;
359  ch.syncAle(request, nullptr);
360  if (ch.fastCheck().denied()) {
361  err_type page_id;
363 
364  if (page_id == ERR_NONE)
365  page_id = ERR_FORWARDING_DENIED;
366 
367  const auto anErr = new ErrorState(page_id, Http::scForbidden, request, al);
368  errorAppendEntry(entry, anErr); // frees anErr
369  return;
370  }
371  }
372 
373  debugs(17, 3, HERE << "'" << entry->url() << "'");
374  /*
375  * This seems like an odd place to bind mem_obj and request.
376  * Might want to assert that request is NULL at this point
377  */
379 #if URL_CHECKSUM_DEBUG
380 
381  entry->mem_obj->checkUrlChecksum();
382 #endif
383 
384  if (shutting_down) {
385  /* more yuck */
387  errorAppendEntry(entry, anErr); // frees anErr
388  return;
389  }
390 
391  if (request->flags.internal) {
392  debugs(17, 2, "calling internalStart() due to request flag");
394  return;
395  }
396 
397  switch (request->url.getScheme()) {
398 
400  debugs(17, 2, "calling CacheManager due to request scheme " << request->url.getScheme());
402  return;
403 
404  case AnyP::PROTO_URN:
406  return;
407 
408  default:
410  fwd->start(fwd);
411  return;
412  }
413 
414  /* NOTREACHED */
415 }
416 
417 void
419 {
420  // Hides AccessLogEntry.h from code that does not supply ALE anyway.
422 }
423 
426 static inline time_t
427 diffOrZero(const time_t larger, const time_t smaller)
428 {
429  return (larger > smaller) ? (larger - smaller) : 0;
430 }
431 
433 time_t
434 FwdState::ForwardTimeout(const time_t fwdStart)
435 {
436  // time already spent on forwarding (0 if clock went backwards)
437  const time_t timeSpent = diffOrZero(squid_curtime, fwdStart);
438  return diffOrZero(Config.Timeout.forward, timeSpent);
439 }
440 
441 bool
442 FwdState::EnoughTimeToReForward(const time_t fwdStart)
443 {
444  return ForwardTimeout(fwdStart) > 0;
445 }
446 
447 void
449 {
450  if (!destinations->empty()) {
451  connectStart();
452  } else {
454  debugs(17, 4, "wait for more destinations to try");
455  return; // expect a noteDestination*() call
456  }
457 
458  debugs(17, 3, HERE << "Connection failed: " << entry->url());
459  if (!err) {
461  fail(anErr);
462  } // else use actual error from last connection attempt
463 
464  stopAndDestroy("tried all destinations");
465  }
466 }
467 
468 void
470 {
471  debugs(17, 3, err_type_str[errorState->type] << " \"" << Http::StatusCodeString(errorState->httpStatus) << "\"\n\t" << entry->url());
472 
473  delete err;
474  err = errorState;
475 
476  if (!errorState->request)
477  errorState->request = request;
478 
479  if (err->type != ERR_ZERO_SIZE_OBJECT)
480  return;
481 
482  if (pconnRace == racePossible) {
483  debugs(17, 5, HERE << "pconn race happened");
486  }
487 
488  if (ConnStateData *pinned_connection = request->pinnedConnection()) {
489  pinned_connection->pinning.zeroReply = true;
490  debugs(17, 4, "zero reply on pinned connection");
491  }
492 }
493 
497 void
499 {
500  debugs(17, 3, HERE << entry->url() );
504  closeHandler = NULL;
505  serverConn = NULL;
506 }
507 
508 // \deprecated use unregister(Comm::ConnectionPointer &conn) instead
509 void
511 {
512  debugs(17, 3, HERE << entry->url() );
513  assert(fd == serverConnection()->fd);
515 }
516 
523 void
525 {
526  const auto replyStatus = entry->mem().baseReply().sline.status();
527  debugs(17, 3, *entry << " status " << replyStatus << ' ' << entry->url());
528 #if URL_CHECKSUM_DEBUG
529 
530  entry->mem_obj->checkUrlChecksum();
531 #endif
532 
533  logReplyStatus(n_tries, replyStatus);
534 
535  if (reforward()) {
536  debugs(17, 3, "re-forwarding " << replyStatus << " " << entry->url());
537 
540 
541  entry->reset();
542 
543  useDestinations();
544 
545  } else {
547  debugs(17, 3, "server FD " << serverConnection()->fd << " not re-forwarding status " << replyStatus);
548  else
549  debugs(17, 3, "server (FD closed) not re-forwarding status " << replyStatus);
550  entry->complete();
551 
553  completed();
554 
555  stopAndDestroy("forwarding completed");
556  }
557 }
558 
559 void
561 {
562  flags.destinationsFound = true;
563 
564  if (!path) {
565  // We can call usePinned() without fear of clashing with an earlier
566  // forwarding attempt because PINNED must be the first destination.
568  usePinned();
569  return;
570  }
571 
572  debugs(17, 3, path);
573 
574  destinations->addPath(path);
575 
577  // We are already using a previously opened connection, so we cannot be
578  // waiting for connOpener. We still receive destinations for backup.
579  Must(!opening());
580  return;
581  }
582 
583  if (opening()) {
585  return; // and continue to wait for FwdState::noteConnection() callback
586  }
587 
588  // This is the first path candidate we have seen. Create connOpener.
589  useDestinations();
590 }
591 
592 void
594 {
597 
598  if (!flags.destinationsFound) {
599  if (selectionError) {
600  debugs(17, 3, "Will abort forwarding because path selection has failed.");
601  Must(!err); // if we tried to connect, then path selection succeeded
602  fail(selectionError);
603  }
604  else if (err)
605  debugs(17, 3, "Will abort forwarding because all found paths have failed.");
606  else
607  debugs(17, 3, "Will abort forwarding because path selection found no paths.");
608 
609  useDestinations(); // will detect and handle the lack of paths
610  return;
611  }
612  // else continue to use one of the previously noted destinations;
613  // if all of them fail, forwarding as whole will fail
614  Must(!selectionError); // finding at least one path means selection succeeded
615 
617  // We are already using a previously opened connection, so we cannot be
618  // waiting for connOpener. We were receiving destinations for backup.
619  Must(!opening());
620  return;
621  }
622 
623  Must(opening()); // or we would be stuck with nothing to do or wait for
625  // and continue to wait for FwdState::noteConnection() callback
626 }
627 
629 void
631 {
633  debugs(17, 7, "reusing pending notification about " << *destinations);
634  } else {
635  debugs(17, 7, "notifying about " << *destinations);
637  CallJobHere(17, 5, connOpener, HappyConnOpener, noteCandidatesChange);
638  }
639 }
640 
641 /**** CALLBACK WRAPPERS ************************************************************/
642 
643 static void
645 {
646  FwdState *fwd = (FwdState *)params.data;
647  fwd->serverClosed(params.fd);
648 }
649 
650 /**** PRIVATE *****************************************************************/
651 
652 /*
653  * FwdState::checkRetry
654  *
655  * Return TRUE if the request SHOULD be retried. This method is
656  * called when the HTTP connection fails, or when the connection
657  * is closed before reading the end of HTTP headers from the server.
658  */
659 bool
661 {
662  if (shutting_down)
663  return false;
664 
665  if (!self) { // we have aborted before the server called us back
666  debugs(17, 5, HERE << "not retrying because of earlier abort");
667  // we will be destroyed when the server clears its Pointer to us
668  return false;
669  }
670 
672  return false;
673 
674  if (!entry->isEmpty())
675  return false;
676 
677  if (exhaustedTries())
678  return false;
679 
680  if (request->flags.pinned && !pinnedCanRetry())
681  return false;
682 
684  return false;
685 
686  if (flags.dont_retry)
687  return false;
688 
689  if (request->bodyNibbled())
690  return false;
691 
692  // NP: not yet actually connected anywhere. retry is safe.
693  if (!flags.connected_okay)
694  return true;
695 
696  if (!checkRetriable())
697  return false;
698 
699  return true;
700 }
701 
703 bool
705 {
706  // Optimize: A compliant proxy may retry PUTs, but Squid lacks the [rather
707  // complicated] code required to protect the PUT request body from being
708  // nibbled during the first try. Thus, Squid cannot retry some PUTs today.
709  if (request->body_pipe != NULL)
710  return false;
711 
712  // RFC2616 9.1 Safe and Idempotent Methods
714 }
715 
716 void
718 {
719  // XXX: fd is often -1 here
720  debugs(17, 2, "FD " << fd << " " << entry->url() << " after " <<
721  (fd >= 0 ? fd_table[fd].pconn.uses : -1) << " requests");
722  if (fd >= 0 && serverConnection()->fd == fd)
723  fwdPconnPool->noteUses(fd_table[fd].pconn.uses);
724  retryOrBail();
725 }
726 
727 void
729 {
730  if (checkRetry()) {
731  debugs(17, 3, HERE << "re-forwarding (" << n_tries << " tries, " << (squid_curtime - start_t) << " secs)");
732  useDestinations();
733  return;
734  }
735 
736  // TODO: should we call completed() here and move doneWithRetries there?
737  doneWithRetries();
738 
739  request->hier.stopPeerClock(false);
740 
741  if (self != NULL && !err && shutting_down && entry->isEmpty()) {
743  errorAppendEntry(entry, anErr);
744  }
745 
746  stopAndDestroy("cannot retry");
747 }
748 
749 // If the Server quits before nibbling at the request body, the body sender
750 // will not know (so that we can retry). Call this if we will not retry. We
751 // will notify the sender so that it does not get stuck waiting for space.
752 void
754 {
755  if (request && request->body_pipe != NULL)
757 }
758 
759 // called by the server that failed after calling unregister()
760 void
762 {
763  debugs(17, 2, HERE << "self=" << self << " err=" << err << ' ' << entry->url());
765  retryOrBail();
766 }
767 
769 template <typename StepStart>
770 void
771 FwdState::advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep)
772 {
773  // TODO: Extract destination-specific handling from FwdState so that all the
774  // awkward, limited-scope advanceDestination() calls can be replaced with a
775  // single simple try/catch,retry block.
776  try {
777  startStep();
778  // now wait for the step callback
779  } catch (...) {
780  debugs (17, 2, "exception while trying to " << stepDescription << ": " << CurrentException);
781  closePendingConnection(conn, "connection preparation exception");
782  retryOrBail();
783  }
784 }
785 
788 void
790 {
791  calls.connector = nullptr;
792  connOpener.clear();
793 
794  Must(n_tries <= answer.n_tries); // n_tries cannot decrease
795  n_tries = answer.n_tries;
796 
797  ErrorState *error = nullptr;
798  if ((error = answer.error.get())) {
799  flags.dont_retry = true; // or HappyConnOpener would not have given up
800  syncHierNote(answer.conn, request->url.host());
801  Must(!Comm::IsConnOpen(answer.conn));
802  answer.error.clear(); // preserve error for errorSendComplete()
803  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
804  syncHierNote(answer.conn, request->url.host());
805  closePendingConnection(answer.conn, "conn was closed while waiting for noteConnection");
807  }
808 
809  if (error) {
810  fail(error);
811  retryOrBail(); // will notice flags.dont_retry and bail
812  return;
813  }
814 
815  if (answer.reused) {
816  syncWithServerConn(answer.conn, request->url.host(), answer.reused);
817  return dispatch();
818  }
819 
820  // Check if we need to TLS before use
821  if (const auto *peer = answer.conn->getPeer()) {
822  // Assume that it is only possible for the client-first from the
823  // bumping modes to try connect to a remote server. The bumped
824  // requests with other modes are using pinned connections or fails.
825  const bool clientFirstBump = request->flags.sslBumped;
826  // We need a CONNECT tunnel to send encrypted traffic through a proxy,
827  // but we do not support TLS inside TLS, so we exclude HTTPS proxies.
828  const bool originWantsEncryptedTraffic =
830  request->flags.sslPeek ||
831  clientFirstBump;
832  if (originWantsEncryptedTraffic && // the "encrypted traffic" part
833  !peer->options.originserver && // the "through a proxy" part
834  !peer->secure.encryptTransport) // the "exclude HTTPS proxies" part
835  return advanceDestination("establish tunnel through proxy", answer.conn, [this,&answer] {
836  establishTunnelThruProxy(answer.conn);
837  });
838  }
839 
841 }
842 
843 void
845 {
847  "FwdState::tunnelEstablishmentDone",
849  HttpRequest::Pointer requestPointer = request;
850  const auto tunneler = new Http::Tunneler(conn, requestPointer, callback, connectingTimeout(serverConnection()), al);
851 
852  // TODO: Replace this hack with proper Comm::Connection-Pool association
853  // that is not tied to fwdPconnPool and can handle disappearing pools.
854  tunneler->noteFwdPconnUse = true;
855 
856 #if USE_DELAY_POOLS
857  Must(serverConnection()->getPeer());
858  if (!serverConnection()->getPeer()->options.no_delay)
859  tunneler->setDelayId(entry->mem_obj->mostBytesAllowed());
860 #endif
861  AsyncJob::Start(tunneler);
862  // and wait for the tunnelEstablishmentDone() call
863 }
864 
866 void
868 {
869  ErrorState *error = nullptr;
870  if (!answer.positive()) {
871  Must(!Comm::IsConnOpen(answer.conn));
872  error = answer.squidError.get();
873  Must(error);
874  answer.squidError.clear(); // preserve error for fail()
875  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
876  // The socket could get closed while our callback was queued.
877  // We close Connection here to sync Connection::fd.
878  closePendingConnection(answer.conn, "conn was closed while waiting for tunnelEstablishmentDone");
880  } else if (!answer.leftovers.isEmpty()) {
881  // This should not happen because TLS servers do not speak first. If we
882  // have to handle this, then pass answer.leftovers via a PeerConnector
883  // to ServerBio. See ClientBio::setReadBufData().
884  static int occurrences = 0;
885  const auto level = (occurrences++ < 100) ? DBG_IMPORTANT : 2;
886  debugs(17, level, "ERROR: Early data after CONNECT response. " <<
887  "Found " << answer.leftovers.length() << " bytes. " <<
888  "Closing " << answer.conn);
890  closePendingConnection(answer.conn, "server spoke before tunnelEstablishmentDone");
891  }
892  if (error) {
893  fail(error);
894  retryOrBail();
895  return;
896  }
897 
899 }
900 
902 void
904 {
906 
907  const auto p = conn->getPeer();
908  const bool peerWantsTls = p && p->secure.encryptTransport;
909  // userWillTlsToPeerForUs assumes CONNECT == HTTPS
910  const bool userWillTlsToPeerForUs = p && p->options.originserver &&
912  const bool needTlsToPeer = peerWantsTls && !userWillTlsToPeerForUs;
913  const bool clientFirstBump = request->flags.sslBumped; // client-first (already) bumped connection
914  const bool needsBump = request->flags.sslPeek || clientFirstBump;
915 
916  // 'GET https://...' requests. If a peer is used the request is forwarded
917  // as is
918  const bool needTlsToOrigin = !p && request->url.getScheme() == AnyP::PROTO_HTTPS && !clientFirstBump;
919 
920  if (needTlsToPeer || needTlsToOrigin || needsBump) {
921  return advanceDestination("secure connection to peer", conn, [this,&conn] {
923  });
924  }
925 
926  // if not encrypting just run the post-connect actions
928 }
929 
931 void
933 {
934  HttpRequest::Pointer requestPointer = request;
936  "FwdState::ConnectedToPeer",
938  const auto sslNegotiationTimeout = connectingTimeout(conn);
940 #if USE_OPENSSL
941  if (request->flags.sslPeek)
942  connector = new Ssl::PeekingPeerConnector(requestPointer, conn, clientConn, callback, al, sslNegotiationTimeout);
943  else
944 #endif
945  connector = new Security::BlindPeerConnector(requestPointer, conn, callback, al, sslNegotiationTimeout);
946  connector->noteFwdPconnUse = true;
947  AsyncJob::Start(connector); // will call our callback
948 }
949 
951 void
953 {
954  ErrorState *error = nullptr;
955  if ((error = answer.error.get())) {
956  Must(!Comm::IsConnOpen(answer.conn));
957  answer.error.clear(); // preserve error for errorSendComplete()
958  } else if (answer.tunneled) {
959  // TODO: When ConnStateData establishes tunnels, its state changes
960  // [in ways that may affect logging?]. Consider informing
961  // ConnStateData about our tunnel or otherwise unifying tunnel
962  // establishment [side effects].
963  complete(); // destroys us
964  return;
965  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
966  closePendingConnection(answer.conn, "conn was closed while waiting for connectedToPeer");
968  }
969 
970  if (error) {
971  fail(error);
972  retryOrBail();
973  return;
974  }
975 
977 }
978 
980 void
982 {
983  syncWithServerConn(conn, request->url.host(), false);
984 
985  // should reach ConnStateData before the dispatched Client job starts
988 
989  if (serverConnection()->getPeer())
991 
992  dispatch();
993 }
994 
996 void
997 FwdState::syncWithServerConn(const Comm::ConnectionPointer &conn, const char *host, const bool reused)
998 {
999  Must(IsConnOpen(conn));
1000  serverConn = conn;
1001 
1003 
1004  if (reused) {
1007  } else {
1009  // Comm::ConnOpener already applied proper/current markings
1010  }
1011 
1012  syncHierNote(serverConn, host);
1013 }
1014 
1015 void
1017 {
1018  if (request)
1020  if (al)
1021  al->hier.resetPeerNotes(server, host);
1022 }
1023 
1029 void
1031 {
1032  debugs(17, 3, *destinations << " to " << entry->url());
1033 
1035 
1036  assert(!destinations->empty());
1037  assert(!opening());
1038 
1039  // Ditch error page if it was created before.
1040  // A new one will be created if there's another problem
1041  delete err;
1042  err = nullptr;
1043  request->clearError();
1044  serverConn = nullptr;
1045 
1047 
1048  calls.connector = asyncCall(17, 5, "FwdState::noteConnection", HappyConnOpener::CbDialer<FwdState>(&FwdState::noteConnection, this));
1049 
1050  HttpRequest::Pointer cause = request;
1051  const auto cs = new HappyConnOpener(destinations, calls.connector, cause, start_t, n_tries, al);
1052  cs->setHost(request->url.host());
1053  bool retriable = checkRetriable();
1054  if (!retriable && Config.accessList.serverPconnForNonretriable) {
1056  ch.al = al;
1057  ch.syncAle(request, nullptr);
1058  retriable = ch.fastCheck().allowed();
1059  }
1060  cs->setRetriable(retriable);
1061  cs->allowPersistent(pconnRace != raceHappened);
1062  destinations->notificationPending = true; // start() is async
1063  connOpener = cs;
1064  AsyncJob::Start(cs);
1065 }
1066 
1068 void
1070 {
1071  const auto connManager = request->pinnedConnection();
1072  debugs(17, 7, "connection manager: " << connManager);
1073 
1074  try {
1076  debugs(17, 5, "connection: " << serverConn);
1077  } catch (ErrorState * const anErr) {
1078  syncHierNote(nullptr, connManager ? connManager->pinning.host : request->url.host());
1079  serverConn = nullptr;
1080  fail(anErr);
1081  // Connection managers monitor their idle pinned to-server
1082  // connections and close from-client connections upon seeing
1083  // a to-server connection closure. Retrying here is futile.
1084  stopAndDestroy("pinned connection failure");
1085  return;
1086  }
1087 
1088  ++n_tries;
1089  request->flags.pinned = true;
1090 
1091  assert(connManager);
1092  if (connManager->pinnedAuth())
1093  request->flags.auth = true;
1094 
1095  // the server may close the pinned connection before this request
1096  const auto reused = true;
1097  syncWithServerConn(serverConn, connManager->pinning.host, reused);
1098 
1099  dispatch();
1100 }
1101 
1102 void
1104 {
1105  debugs(17, 3, clientConn << ": Fetching " << request->method << ' ' << entry->url());
1106  /*
1107  * Assert that server_fd is set. This is to guarantee that fwdState
1108  * is attached to something and will be deallocated when server_fd
1109  * is closed.
1110  */
1112 
1113  fd_note(serverConnection()->fd, entry->url());
1114 
1115  fd_table[serverConnection()->fd].noteUse();
1116 
1117  /*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */
1119 
1120  assert(entry->locked());
1121 
1123 
1124  flags.connected_okay = true;
1125 
1127 
1128  /* Retrieves remote server TOS or MARK value, and stores it as part of the
1129  * original client request FD object. It is later used to forward
1130  * remote server's TOS/MARK in the response to the client in case of a MISS.
1131  */
1132  if (Ip::Qos::TheConfig.isHitNfmarkActive()) {
1134  fde * clientFde = &fd_table[clientConn->fd]; // XXX: move the fd_table access into Ip::Qos
1135  /* Get the netfilter CONNMARK */
1137  }
1138  }
1139 
1140 #if _SQUID_LINUX_
1141  /* Bug 2537: The TOS forward part of QOS only applies to patched Linux kernels. */
1142  if (Ip::Qos::TheConfig.isHitTosActive()) {
1144  fde * clientFde = &fd_table[clientConn->fd]; // XXX: move the fd_table access into Ip::Qos
1145  /* Get the TOS value for the packet */
1147  }
1148  }
1149 #endif
1150 
1151 #if USE_OPENSSL
1152  if (request->flags.sslPeek) {
1155  unregister(serverConn); // async call owns it now
1156  complete(); // destroys us
1157  return;
1158  }
1159 #endif
1160 
1161  if (const auto peer = serverConnection()->getPeer()) {
1162  ++peer->stats.fetches;
1163  request->prepForPeering(*peer);
1164  httpStart(this);
1165  } else {
1168 
1169  switch (request->url.getScheme()) {
1170 
1171  case AnyP::PROTO_HTTPS:
1172  httpStart(this);
1173  break;
1174 
1175  case AnyP::PROTO_HTTP:
1176  httpStart(this);
1177  break;
1178 
1179  case AnyP::PROTO_GOPHER:
1180  gopherStart(this);
1181  break;
1182 
1183  case AnyP::PROTO_FTP:
1184  if (request->flags.ftpNative)
1185  Ftp::StartRelay(this);
1186  else
1187  Ftp::StartGateway(this);
1188  break;
1189 
1191 
1192  case AnyP::PROTO_URN:
1193  fatal_dump("Should never get here");
1194  break;
1195 
1196  case AnyP::PROTO_WHOIS:
1197  whoisStart(this);
1198  break;
1199 
1200  case AnyP::PROTO_WAIS: /* Not implemented */
1201 
1202  default:
1203  debugs(17, DBG_IMPORTANT, "WARNING: Cannot retrieve '" << entry->url() << "'.");
1204  const auto anErr = new ErrorState(ERR_UNSUP_REQ, Http::scBadRequest, request, al);
1205  fail(anErr);
1206  // Set the dont_retry flag because this is not a transient (network) error.
1207  flags.dont_retry = true;
1209  serverConn->close(); // trigger cleanup
1210  }
1211  break;
1212  }
1213  }
1214 }
1215 
1216 /*
1217  * FwdState::reforward
1218  *
1219  * returns TRUE if the transaction SHOULD be re-forwarded to the
1220  * next choice in the serverDestinations list. This method is called when
1221  * peer communication completes normally, or experiences
1222  * some error after receiving the end of HTTP headers.
1223  */
1224 int
1226 {
1227  StoreEntry *e = entry;
1228 
1229  if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
1230  debugs(17, 3, HERE << "entry aborted");
1231  return 0;
1232  }
1233 
1235  assert(e->mem_obj);
1236 #if URL_CHECKSUM_DEBUG
1237 
1238  e->mem_obj->checkUrlChecksum();
1239 #endif
1240 
1241  debugs(17, 3, HERE << e->url() << "?" );
1242 
1243  if (request->flags.pinned && !pinnedCanRetry()) {
1244  debugs(17, 3, "pinned connection; cannot retry");
1245  return 0;
1246  }
1247 
1248  if (!EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)) {
1249  debugs(17, 3, HERE << "No, ENTRY_FWD_HDR_WAIT isn't set");
1250  return 0;
1251  }
1252 
1253  if (exhaustedTries())
1254  return 0;
1255 
1256  if (request->bodyNibbled())
1257  return 0;
1258 
1260  debugs(17, 3, HERE << "No alternative forwarding paths left");
1261  return 0;
1262  }
1263 
1264  const auto s = entry->mem().baseReply().sline.status();
1265  debugs(17, 3, HERE << "status " << s);
1266  return reforwardableStatus(s);
1267 }
1268 
1269 static void
1271 {
1272  int i;
1273  int j;
1274  storeAppendPrintf(s, "Status");
1275 
1276  for (j = 1; j < MAX_FWD_STATS_IDX; ++j) {
1277  storeAppendPrintf(s, "\ttry#%d", j);
1278  }
1279 
1280  storeAppendPrintf(s, "\n");
1281 
1282  for (i = 0; i <= (int) Http::scInvalidHeader; ++i) {
1283  if (FwdReplyCodes[0][i] == 0)
1284  continue;
1285 
1286  storeAppendPrintf(s, "%3d", i);
1287 
1288  for (j = 0; j <= MAX_FWD_STATS_IDX; ++j) {
1289  storeAppendPrintf(s, "\t%d", FwdReplyCodes[j][i]);
1290  }
1291 
1292  storeAppendPrintf(s, "\n");
1293  }
1294 }
1295 
1296 /**** STATIC MEMBER FUNCTIONS *************************************************/
1297 
1298 bool
1300 {
1301  switch (s) {
1302 
1303  case Http::scBadGateway:
1304 
1306  return true;
1307 
1308  case Http::scForbidden:
1309 
1311 
1313 
1315  return Config.retry.onerror;
1316 
1317  default:
1318  return false;
1319  }
1320 
1321  /* NOTREACHED */
1322 }
1323 
1324 void
1326 {
1328 }
1329 
1330 void
1332 {
1333  Mgr::RegisterAction("forward", "Request Forwarding Statistics", fwdStats, 0, 1);
1334 }
1335 
1336 void
1338 {
1339  if (status > Http::scInvalidHeader)
1340  return;
1341 
1342  assert(tries >= 0);
1343 
1344  if (tries > MAX_FWD_STATS_IDX)
1345  tries = MAX_FWD_STATS_IDX;
1346 
1347  ++ FwdReplyCodes[tries][status];
1348 }
1349 
1350 bool
1352 {
1353  return n_tries >= Config.forward_max_tries;
1354 }
1355 
1356 bool
1358 {
1360 
1361  // pconn race on pinned connection: Currently we do not have any mechanism
1362  // to retry current pinned connection path.
1363  if (pconnRace == raceHappened)
1364  return false;
1365 
1366  // If a bumped connection was pinned, then the TLS client was given our peer
1367  // details. Do not retry because we do not ensure that those details stay
1368  // constant. Step1-bumped connections do not get our TLS peer details, are
1369  // never pinned, and, hence, never reach this method.
1370  if (request->flags.sslBumped)
1371  return false;
1372 
1373  // The other pinned cases are FTP proxying and connection-based HTTP
1374  // authentication. TODO: Do these cases have restrictions?
1375  return true;
1376 }
1377 
1378 time_t
1380 {
1381  const auto connTimeout = conn->connectTimeout(start_t);
1382  return positiveTimeout(connTimeout);
1383 }
1384 
1385 /**** PRIVATE NON-MEMBER FUNCTIONS ********************************************/
1386 
1387 /*
1388  * DPW 2007-05-19
1389  * Formerly static, but now used by client_side_request.cc
1390  */
1392 tos_t
1394 {
1395  for (acl_tos *l = head; l; l = l->next) {
1396  if (!l->aclList || ch->fastCheck(l->aclList).allowed())
1397  return l->tos;
1398  }
1399 
1400  return 0;
1401 }
1402 
1406 {
1407  for (acl_nfmark *l = head; l; l = l->next) {
1408  if (!l->aclList || ch->fastCheck(l->aclList).allowed())
1409  return l->markConfig;
1410  }
1411 
1412  return {};
1413 }
1414 
1415 void
1417 {
1418  // skip if an outgoing address is already set.
1419  if (!conn->local.isAnyAddr()) return;
1420 
1421  // ensure that at minimum the wildcard local matches remote protocol
1422  if (conn->remote.isIPv4())
1423  conn->local.setIPv4();
1424 
1425  // maybe use TPROXY client address
1426  if (request && request->flags.spoofClientIp) {
1427  if (!conn->getPeer() || !conn->getPeer()->options.no_tproxy) {
1428 #if FOLLOW_X_FORWARDED_FOR && LINUX_NETFILTER
1430  conn->local = request->indirect_client_addr;
1431  else
1432 #endif
1433  conn->local = request->client_addr;
1434  conn->local.port(0); // let OS pick the source port to prevent address clashes
1435  // some flags need setting on the socket to use this address
1436  conn->flags |= COMM_DOBIND;
1437  conn->flags |= COMM_TRANSPARENT;
1438  return;
1439  }
1440  // else no tproxy today ...
1441  }
1442 
1444  return; // anything will do.
1445  }
1446 
1448  ch.dst_peer_name = conn->getPeer() ? conn->getPeer()->name : NULL;
1449  ch.dst_addr = conn->remote;
1450 
1451  // TODO use the connection details in ACL.
1452  // needs a bit of rework in ACLFilledChecklist to use Comm::Connection instead of ConnStateData
1453 
1454  for (Acl::Address *l = Config.accessList.outgoing_address; l; l = l->next) {
1455 
1456  /* check if the outgoing address is usable to the destination */
1457  if (conn->remote.isIPv4() != l->addr.isIPv4()) continue;
1458 
1459  /* check ACLs for this outgoing address */
1460  if (!l->aclList || ch.fastCheck(l->aclList).allowed()) {
1461  conn->local = l->addr;
1462  return;
1463  }
1464  }
1465 }
1466 
1468 static tos_t
1470 {
1471  if (!Ip::Qos::TheConfig.tosToServer)
1472  return 0;
1473 
1475  ch.dst_peer_name = conn.getPeer() ? conn.getPeer()->name : nullptr;
1476  ch.dst_addr = conn.remote;
1477  return aclMapTOS(Ip::Qos::TheConfig.tosToServer, &ch);
1478 }
1479 
1481 static nfmark_t
1483 {
1484  if (!Ip::Qos::TheConfig.nfmarkToServer)
1485  return 0;
1486 
1488  ch.dst_peer_name = conn.getPeer() ? conn.getPeer()->name : nullptr;
1489  ch.dst_addr = conn.remote;
1490  const auto mc = aclFindNfMarkConfig(Ip::Qos::TheConfig.nfmarkToServer, &ch);
1491  return mc.mark;
1492 }
1493 
1494 void
1496 {
1497  // Get the server side TOS and Netfilter mark to be set on the connection.
1498  conn.tos = GetTosToServer(request, conn);
1499  conn.nfmark = GetNfmarkToServer(request, conn);
1500  debugs(17, 3, "from " << conn.local << " tos " << int(conn.tos) << " netfilter mark " << conn.nfmark);
1501 }
1502 
1503 void
1505 {
1507 
1508  // TODO: Avoid these calls if markings has not changed.
1509  if (conn.tos)
1510  Ip::Qos::setSockTos(&conn, conn.tos);
1511  if (conn.nfmark)
1512  Ip::Qos::setSockNfmark(&conn, conn.nfmark);
1513 }
1514 
bool bodyNibbled() const
Definition: HttpRequest.cc:443
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:983
bool tunneled
whether we spliced the connections instead of negotiating encryption
void noteConnection(HappyConnOpenerAnswer &)
Definition: FwdState.cc:789
FwdStatePeerAnswerDialer(Method method, FwdState *fwd)
Definition: FwdState.cc:88
static OBJH fwdStats
Definition: FwdState.cc:74
#define MAX_FWD_STATS_IDX
Definition: FwdState.cc:76
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
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:198
Acl::Address * outgoing_address
Definition: SquidConfig.h:383
struct squidaio_request_t * next
Definition: aiops.cc:51
time_t start_t
Definition: FwdState.h:181
void releaseRequest(const bool shareable=false)
Definition: store.cc:452
void whoisStart(FwdState *fwd)
Definition: whois.cc:55
Ip::Address src_addr
void stopPeerClock(const bool force)
Definition: access_log.cc:303
@ scBadRequest
Definition: StatusCode.h:44
int setSockNfmark(const Comm::ConnectionPointer &conn, nfmark_t mark)
Definition: QosConfig.cc:586
bool destinationsFinalized
whether all of the available candidate paths received from DNS
Definition: ResolvedPeers.h:77
void(FwdState::* Method)(Security::EncryptorAnswer &)
Definition: FwdState.cc:86
void fd_note(int fd, const char *s)
Definition: fd.cc:246
CbcPointer< ErrorState > error
problem details (nil on success)
#define EBIT_SET(flag, bit)
Definition: defines.h:105
void errorAppendEntry(StoreEntry *entry, ErrorState *err)
Definition: errorpage.cc:711
bool isEmpty() const
Definition: SBuf.h:420
const char * StatusCodeString(const Http::StatusCode status)
Definition: stub_libhttp.cc:86
MemObject * mem_obj
Definition: Store.h:209
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:482
static void initModule()
Definition: FwdState.cc:1325
void addPath(const Comm::ConnectionPointer &)
add a candidate path to try after all the existing paths
void syncWithServerConn(const Comm::ConnectionPointer &server, const char *host, const bool reused)
commits to using the given open to-peer connection
Definition: FwdState.cc:997
void Comm::ConnectionPointer & clientConn
Definition: stub_tunnel.cc:19
const char * url() const
Definition: store.cc:1612
MemObject & mem()
Definition: Store.h:52
void useDestinations()
Definition: FwdState.cc:448
@ ERR_NONE
Definition: err_type.h:13
static CLCB fwdServerClosedWrapper
Definition: FwdState.cc:72
void secureConnectionToPeerIfNeeded(const Comm::ConnectionPointer &)
handles an established TCP connection to peer (including origin servers)
Definition: FwdState.cc:903
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:881
void lock(const char *context)
Definition: store.cc:439
struct SquidConfig::@116 retry
void error(char *format,...)
unsigned int nfConnmarkFromServer
Definition: fde.h:171
struct SquidConfig::@113 accessList
AccessLogEntryPointer al
info for the future access.log entry
Definition: FwdState.h:173
bool isHttpSafe() const
void startSelectingDestinations(HttpRequest *request, const AccessLogEntry::Pointer &ale, StoreEntry *entry)
Definition: peer_select.cc:193
void getTosFromServer(const Comm::ConnectionPointer &server, fde *clientFde)
Definition: QosConfig.cc:41
int tproxy_uses_indirect_client
Definition: SquidConfig.h:335
acl_access * miss
Definition: SquidConfig.h:365
@ PING_WAITING
Definition: enums.h:41
void internalStart(const Comm::ConnectionPointer &clientConn, HttpRequest *request, StoreEntry *entry, const AccessLogEntry::Pointer &ale)
Definition: internal.cc:32
@ raceHappened
Definition: FwdState.h:203
time_t connectingTimeout(const Comm::ConnectionPointer &conn) const
Definition: FwdState.cc:1379
DelayId mostBytesAllowed() const
Definition: MemObject.cc:478
virtual void print(std::ostream &os) const
Definition: FwdState.cc:94
bool hostVerified
Definition: RequestFlags.h:64
PconnPool * fwdPconnPool
a collection of previously used persistent Squid-to-peer HTTP(S) connections
Definition: FwdState.cc:79
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:771
int fd
FD which the call was about. Set by the async call creator.
Definition: CommCalls.h:90
void cancelOpening(const char *reason)
Definition: FwdState.cc:221
HierarchyLogEntry hier
void connectStart()
Definition: FwdState.cc:1030
unsigned char tos_t
Definition: forward.h:26
uint16_t flags
Definition: Store.h:220
bool SIGHDLR int STUB void int
Definition: stub_tools.cc:68
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:26
@ 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:1069
Http::StatusLine sline
Definition: HttpReply.h:60
void HTTPMSGUNLOCK(M *&a)
Definition: Message.h:149
void syncHierNote(const Comm::ConnectionPointer &server, const char *host)
Definition: FwdState.cc:1016
void tunnelEstablishmentDone(Http::TunnelerAnswer &answer)
resumes operations after the (possibly failed) HTTP CONNECT exchange
Definition: FwdState.cc:867
StatusCode
Definition: StatusCode.h:20
static CacheManager * GetInstance()
void unregister(Comm::ConnectionPointer &conn)
Definition: FwdState.cc:498
void CLCB(const CommCloseCbParams &params)
Definition: CommCalls.h:42
void fail(ErrorState *err)
Definition: FwdState.cc:469
Acl::Address * next
Definition: Address.h:27
A PeerConnector for HTTP origin servers. Capable of SslBumping.
acl_access * serverPconnForNonretriable
Definition: SquidConfig.h:408
AsyncCall::Pointer connector
a call linking us to the ConnOpener producing serverConn.
Definition: FwdState.h:186
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
@ ORIGINAL_DST
Definition: hier_code.h:36
@ ERR_CANNOT_FORWARD
Definition: err_type.h:21
void reset()
Definition: store.cc:1667
#define DBG_IMPORTANT
Definition: Debug.h:46
struct FwdState::@72 calls
AclDenyInfoList * denyInfoList
Definition: SquidConfig.h:411
static time_t diffOrZero(const time_t larger, const time_t smaller)
Definition: FwdState.cc:427
Callback dialer API to allow Tunneler to set the answer.
Definition: HttpTunneler.h:39
bool isIdempotent() const
Definition: fde.h:51
static void RegisterWithCacheManager(void)
Definition: FwdState.cc:1331
Security::EncryptorAnswer answer_
Definition: FwdState.cc:104
@ racePossible
Definition: FwdState.h:203
bool empty() const
whether we lack any known candidate paths
Definition: ResolvedPeers.h:42
void registerAbort(STABH *cb, void *)
Definition: store.cc:1526
list of address-based ACLs.
Definition: Address.h:19
void getOutgoingAddress(HttpRequest *request, const Comm::ConnectionPointer &conn)
Definition: FwdState.cc:1416
virtual void noteDestination(Comm::ConnectionPointer conn) override
called when a new unique destination has been found
Definition: FwdState.cc:560
CbcPointer< FwdState > fwd_
Definition: FwdState.cc:103
void stopAndDestroy(const char *reason)
ends forwarding; relies on refcounting so the effect may not be immediate
Definition: FwdState.cc:204
@ PROTO_URN
Definition: ProtocolType.h:37
void closeServerConnection(const char *reason)
stops monitoring server connection for closure and updates pconn stats
Definition: FwdState.cc:134
@ scGatewayTimeout
Definition: StatusCode.h:75
@ ENTRY_FWD_HDR_WAIT
Definition: enums.h:107
#define COMM_TRANSPARENT
Definition: Connection.h:50
const char * AclMatchedName
Definition: Acl.cc:30
Comm::ConnectionPointer conn
peer connection (secured on success)
void peerConnectSucceded(CachePeer *p)
Definition: neighbors.cc:1304
const char * err_type_str[]
bool exhaustedTries() const
whether we have used up all permitted forwarding attempts
Definition: FwdState.cc:1351
parameters for the async notePinnedConnectionBecameIdle() call
Definition: client_side.h:170
void serverClosed(int fd)
Definition: FwdState.cc:717
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:1482
@ scForbidden
Definition: StatusCode.h:47
err_type aclGetDenyInfoPage(AclDenyInfoList **head, const char *name, int redirect_allowed)
Definition: Gadgets.cc:41
void ResetMarkingsToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1504
void dispatch()
Definition: FwdState.cc:1103
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:128
bool pinnedCanRetry() const
Definition: FwdState.cc:1357
@ 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:60
const Comm::ConnectionPointer & serverConnection() const
Definition: FwdState.h:109
void doneWithRetries()
Definition: FwdState.cc:753
err_type type
Definition: errorpage.h:171
void start(const Comm::ConnectionPointer &client, HttpRequest *request, StoreEntry *entry, const AccessLogEntryPointer &ale)
HttpRequestPointer request
Definition: errorpage.h:178
const Acl::Answer & fastCheck()
Definition: Checklist.cc:336
static Pointer Start(AsyncJob *job)
starts a freshly created job (i.e., makes the job asynchronous)
Definition: AsyncJob.cc:23
virtual ~FwdState()
Definition: FwdState.cc:307
@ scBadGateway
Definition: StatusCode.h:73
ConnStateData * pinnedConnection()
Definition: HttpRequest.cc:686
@ ERR_CONNECT_FAIL
Definition: err_type.h:28
Ip::Address local
Definition: Connection.h:142
#define EBIT_TEST(flag, bit)
Definition: defines.h:107
CachePeer * getPeer() const
Definition: Connection.cc:100
bool subscribed
whether noteDestination() and noteDestinationsEnd() calls are allowed
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:157
ping_status_t ping_status
Definition: Store.h:230
void successfullyConnectedToPeer(const Comm::ConnectionPointer &)
called when all negotiations with the peer have been completed
Definition: FwdState.cc:981
void httpsPeeked(PinnedIdleContext pic)
called by FwdState when it is done bumping the server
err_type
Definition: err_type.h:12
@ METHOD_CONNECT
Definition: MethodType.h:29
void establishTunnelThruProxy(const Comm::ConnectionPointer &)
Definition: FwdState.cc:844
Callback dialer API to allow PeerConnector to set the answer.
Definition: PeerConnector.h:49
#define CallJobHere(debugSection, debugLevel, job, Class, method)
Definition: AsyncJobCalls.h:58
int unlock(const char *context)
Definition: store.cc:463
@ ERR_UNSUP_REQ
Definition: err_type.h:42
Comm::ConnectionPointer clientConn
a possibly open connection to the client.
Definition: FwdState.h:180
virtual void noteDestinationsEnd(ErrorState *selectionError) override
Definition: FwdState.cc:593
bool denied() const
Definition: Acl.h:149
FwdState(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *, const AccessLogEntryPointer &alp)
Definition: FwdState.cc:145
AsyncCall::Pointer closeHandler
The serverConn close handler.
Definition: FwdState.h:200
int n_tries
the number of forwarding attempts so far
Definition: FwdState.h:182
int client_dst_passthru
Definition: SquidConfig.h:343
store_status_t store_status
Definition: Store.h:232
static tos_t GetTosToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1469
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
bool intercepted
Definition: RequestFlags.h:62
virtual bool canDial(AsyncCall &call)
Definition: FwdState.cc:92
uint32_t nfmark_t
Definition: forward.h:25
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:160
static bool EnoughTimeToReForward(const time_t fwdStart)
Definition: FwdState.cc:442
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:434
void clear()
make pointer not set; does not invalidate cbdata
Definition: CbcPointer.h:144
@ scServiceUnavailable
Definition: StatusCode.h:74
@ ERR_READ_ERROR
Definition: err_type.h:26
const AnyP::UriScheme & getScheme() const
Definition: Uri.h:67
void retryOrBail()
Definition: FwdState.cc:728
bool checkRetry()
Definition: FwdState.cc:660
ErrorState * err
Definition: FwdState.h:179
@ PROTO_GOPHER
Definition: ProtocolType.h:30
@ scInternalServerError
Definition: StatusCode.h:71
void completed()
Definition: FwdState.cc:262
@ ERR_FORWARDING_DENIED
Definition: err_type.h:19
AsyncJobPointer StartGateway(FwdState *const fwdState)
A new FTP Gateway job.
Definition: FtpGateway.cc:2730
#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:404
time_t squid_curtime
Definition: stub_time.cc:17
static void logReplyStatus(int tries, const Http::StatusCode status)
Definition: FwdState.cc:1337
bool isNoAddr() const
Definition: Address.cc:284
virtual Security::EncryptorAnswer & answer()
gives PeerConnector access to the in-dialer answer
Definition: FwdState.cc:99
struct SquidConfig::@112 onoff
void retryPath(const Comm::ConnectionPointer &)
re-inserts the previously extracted address into the same position
bool notificationPending
whether HappyConnOpener::noteCandidatesChange() is scheduled to fire
Definition: ResolvedPeers.h:80
@ ENTRY_DISPATCHED
Definition: enums.h:97
struct FwdState::@73 flags
@ ERR_ZERO_SIZE_OBJECT
Definition: err_type.h:44
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:197
@ PROTO_CACHE_OBJECT
Definition: ProtocolType.h:32
#define fd_table
Definition: fde.h:189
void complete()
Definition: store.cc:1058
void urnStart(HttpRequest *r, StoreEntry *e, const AccessLogEntryPointer &ale)
Definition: urn.cc:216
tos_t aclMapTOS(acl_tos *head, ACLChecklist *ch)
Checks for a TOS value to apply depending on the ACL.
Definition: FwdState.cc:1393
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:1194
@ PROTO_HTTPS
Definition: ProtocolType.h:27
bool opening() const
Definition: FwdState.h:164
HttpRequestMethod method
Definition: HttpRequest.h:114
Config TheConfig
Globally available instance of Qos::Config.
Definition: QosConfig.cc:271
Comm::ConnectionPointer conn
@ PROTO_FTP
Definition: ProtocolType.h:26
@ ENTRY_ABORTED
Definition: enums.h:111
@ PING_DONE
Definition: enums.h:42
nfmark_t getNfConnmark(const Comm::ConnectionPointer &conn, const ConnectionDirection connDir)
Definition: QosConfig.cc:141
@ PROTO_HTTP
Definition: ProtocolType.h:25
bool allowed() const
Definition: Acl.h:143
void prepForPeering(const CachePeer &peer)
get ready to be sent to the given cache_peer, including originserver
Definition: HttpRequest.cc:449
a netfilter mark/mask pair
Definition: NfMarkConfig.h:20
void unregisterAbort()
Definition: store.cc:1535
void complete()
Definition: FwdState.cc:524
int reforward()
Definition: FwdState.cc:1225
squidaio_request_t * head
Definition: aiops.cc:127
@ raceImpossible
Definition: FwdState.h:203
@ PROTO_WAIS
Definition: ProtocolType.h:31
static char server[MAXLINE]
Comm::ConnectionPointer conn
void connectedToPeer(Security::EncryptorAnswer &answer)
called when all negotiations with the TLS-speaking peer have been completed
Definition: FwdState.cc:952
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:77
bool isEmpty() const
Definition: Store.h:67
size_t HttpReply *STUB StoreEntry const KeyScope scope const HttpRequestMethod & method
Definition: stub_store.cc:108
bool reforwardableStatus(const Http::StatusCode s) const
Definition: FwdState.cc:1299
AsyncCall dialer for our callback. Gives us access to callback Answer.
#define Must(condition)
Like assert() but throws an exception instead of aborting the process.
Definition: TextException.h:69
Ip::NfMarkConfig aclFindNfMarkConfig(acl_nfmark *head, ACLChecklist *ch)
Checks for a netfilter mark value to apply depending on the ACL.
Definition: FwdState.cc:1405
void dial(AsyncCall &call)
Definition: FwdState.cc:93
void const char HLPCB * callback
Definition: stub_helper.cc:16
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:161
void resetPeerNotes(const Comm::ConnectionPointer &server, const char *requestedHost)
Definition: access_log.cc:250
StoreEntry * entry
Definition: FwdState.h:171
bool reused
whether conn was open earlier, by/for somebody else
int setSockTos(const Comm::ConnectionPointer &conn, tos_t tos)
Definition: QosConfig.cc:558
@ scInvalidHeader
Definition: StatusCode.h:86
AsyncJobPointer StartRelay(FwdState *const fwdState)
A new FTP Relay job.
Definition: FtpRelay.cc:798
void secureConnectionToPeer(const Comm::ConnectionPointer &)
encrypts an established TCP connection to peer (including origin servers)
Definition: FwdState.cc:932
time_t forward
Definition: SquidConfig.h:112
int shutting_down
int forward_max_tries
Definition: SquidConfig.h:354
static void fwdStart(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *)
Same as Start() but no master xaction info (AccessLogEntry) available.
Definition: FwdState.cc:418
PconnRace pconnRace
current pconn race state
Definition: FwdState.h:204
void prepForDirect()
get ready to be sent directly to an origin server, excluding originserver
Definition: HttpRequest.cc:459
struct SquidConfig::@98 Timeout
int locked() const
Definition: Store.h:136
void start(Pointer aSelf)
Definition: FwdState.cc:167
void RegisterAction(char const *action, char const *desc, OBJH *handler, int pw_req_flag, int atomic)
Definition: Registration.cc:16
HappyConnOpenerPointer connOpener
current connection opening job
Definition: FwdState.h:196
@ ERR_SHUTTING_DOWN
Definition: err_type.h:70
void gopherStart(FwdState *fwd)
Definition: gopher.cc:928
HttpRequest * request
Definition: FwdState.h:172
Ip::Address client_addr
Definition: HttpRequest.h:149
void host(const char *src)
Definition: Uri.cc:98
void netdbPingSite(const char *hostname)
Definition: net_db.cc:908
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:122
HttpRequestPointer request
Definition: MemObject.h:189
bool checkRetriable()
Whether we may try sending this request again after a failure.
Definition: FwdState.cc:704
void comm_remove_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:1010
Http::StatusCode httpStatus
Definition: errorpage.h:174
CbcPointer< ErrorState > squidError
problem details (or nil)
CbcPointer< ConnStateData > clientConnectionManager
Definition: HttpRequest.h:233
bool ftpNative
carries a representation of an FTP command [received on ftp_port]
Definition: RequestFlags.h:103
void handleUnregisteredServerEnd()
Definition: FwdState.cc:761
class SquidConfig Config
Definition: SquidConfig.cc:12
void GetMarkingsToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1495
ResolvedPeersPointer destinations
paths for forwarding the request
Definition: FwdState.h:197
int storePendingNClients(const StoreEntry *e)
void httpStart(FwdState *fwd)
Definition: http.cc:2326
void notifyConnOpener()
makes sure connOpener knows that destinations have changed
Definition: FwdState.cc:630
#define CallJobHere1(debugSection, debugLevel, job, Class, method, arg1)
Definition: AsyncJobCalls.h:63
static void abort(void *)
Definition: FwdState.cc:108
@ STORE_PENDING
Definition: enums.h:47

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors