client_side.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2025 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 33 Client-side Routines */
10 
60 #include "squid.h"
61 #include "acl/FilledChecklist.h"
62 #include "anyp/Host.h"
63 #include "anyp/PortCfg.h"
64 #include "base/AsyncCallbacks.h"
65 #include "base/Subscription.h"
66 #include "base/TextException.h"
67 #include "CachePeer.h"
68 #include "client_db.h"
69 #include "client_side.h"
70 #include "client_side_reply.h"
71 #include "client_side_request.h"
72 #include "ClientRequestContext.h"
73 #include "clientStream.h"
74 #include "comm.h"
75 #include "comm/Connection.h"
76 #include "comm/Loops.h"
77 #include "comm/Read.h"
78 #include "comm/TcpAcceptor.h"
79 #include "comm/Write.h"
80 #include "CommCalls.h"
81 #include "compat/socket.h"
82 #include "debug/Messages.h"
84 #include "errorpage.h"
85 #include "fd.h"
86 #include "fde.h"
87 #include "fqdncache.h"
88 #include "FwdState.h"
89 #include "globals.h"
90 #include "helper.h"
91 #include "helper/Reply.h"
92 #include "http.h"
93 #include "http/one/RequestParser.h"
95 #include "http/Stream.h"
96 #include "HttpHdrContRange.h"
97 #include "HttpHeaderTools.h"
98 #include "HttpReply.h"
99 #include "HttpRequest.h"
100 #include "internal.h"
101 #include "ipc/FdNotes.h"
102 #include "ipc/StartListening.h"
103 #include "log/access_log.h"
104 #include "MemBuf.h"
105 #include "MemObject.h"
106 #include "mime_header.h"
107 #include "parser/Tokenizer.h"
108 #include "proxyp/Header.h"
109 #include "proxyp/Parser.h"
110 #include "sbuf/Stream.h"
111 #include "security/Certificate.h"
113 #include "security/Io.h"
114 #include "security/KeyLog.h"
116 #include "servers/forward.h"
117 #include "SquidConfig.h"
118 #include "StatCounters.h"
119 #include "StatHist.h"
120 #include "Store.h"
121 #include "TimeOrTag.h"
122 #include "tools.h"
123 
124 #if USE_AUTH
125 #include "auth/UserRequest.h"
126 #endif
127 #if USE_DELAY_POOLS
128 #include "ClientInfo.h"
129 #include "MessageDelayPools.h"
130 #endif
131 #if USE_OPENSSL
132 #include "ssl/bio.h"
133 #include "ssl/context_storage.h"
134 #include "ssl/gadgets.h"
135 #include "ssl/helper.h"
136 #include "ssl/ProxyCerts.h"
137 #include "ssl/ServerBump.h"
138 #include "ssl/support.h"
139 #endif
140 
141 #include <climits>
142 #include <cmath>
143 #include <limits>
144 
145 #if HAVE_SYSTEMD_SD_DAEMON_H
146 #include <systemd/sd-daemon.h>
147 #endif
148 
149 // TODO: Remove this custom dialer and simplify by creating the TcpAcceptor
150 // subscription later, inside clientListenerConnectionOpened() callback, just
151 // like htcpOpenPorts(), icpOpenPorts(), and snmpPortOpened() do it.
154  public CallDialer,
155  public WithAnswer<Ipc::StartListeningAnswer>
156 {
157 public:
160  handler(aHandler), portCfg(aPortCfg), portTypeNote(note), sub(aSub) {}
161 
162  /* CallDialer API */
163  void print(std::ostream &os) const override {
164  os << '(' << answer_ << ", " << FdNote(portTypeNote) << " port=" << (void*)&portCfg << ')';
165  }
166 
167  virtual bool canDial(AsyncCall &) const { return true; }
168  virtual void dial(AsyncCall &) { (handler)(portCfg, portTypeNote, sub); }
169 
170  /* WithAnswer API */
171  Ipc::StartListeningAnswer &answer() override { return answer_; }
172 
173 public:
175 
176 private:
177  // answer_.conn (set/updated by IPC code) is portCfg.listenConn (used by us)
182 };
183 
184 static void clientListenerConnectionOpened(AnyP::PortCfgPointer &s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub);
185 
187 static int clientIsRequestBodyTooLargeForPolicy(int64_t bodyLength);
188 
189 static void clientUpdateStatHistCounters(const LogTags &logType, int svc_time);
190 static void clientUpdateStatCounters(const LogTags &logType);
192 static bool clientPingHasFinished(ping_data const *aPing);
195 
196 char *skipLeadingSpace(char *aString);
197 
198 void
200 {
202 
203  if (logType.isTcpHit())
205 
206  if (logType.oldType == LOG_TCP_HIT)
208  else if (logType.oldType == LOG_TCP_MEM_HIT)
210 }
211 
212 void
213 clientUpdateStatHistCounters(const LogTags &logType, int svc_time)
214 {
223  switch (logType.oldType) {
224 
227  break;
228 
229  case LOG_TCP_INM_HIT:
230  case LOG_TCP_IMS_HIT:
232  break;
233 
234  case LOG_TCP_HIT:
235 
236  case LOG_TCP_MEM_HIT:
237 
238  case LOG_TCP_OFFLINE_HIT:
240  break;
241 
242  case LOG_TCP_MISS:
243 
246  break;
247 
248  default:
249  /* make compiler warnings go away */
250  break;
251  }
252 }
253 
254 bool
256 {
257  if (0 != aPing->stop.tv_sec && 0 != aPing->start.tv_sec)
258  return true;
259 
260  return false;
261 }
262 
263 void
265 {
266  ping_data *i;
267 
268  switch (someEntry->code) {
269 #if USE_CACHE_DIGESTS
270 
271  case CD_PARENT_HIT:
272 
273  case CD_SIBLING_HIT:
275  break;
276 #endif
277 
278  case SIBLING_HIT:
279 
280  case PARENT_HIT:
281 
282  case FIRST_PARENT_MISS:
283 
284  case CLOSEST_PARENT_MISS:
286  i = &someEntry->ping;
287 
288  if (clientPingHasFinished(i))
290 
291  if (i->timeout)
293 
294  break;
295 
296  case CLOSEST_PARENT:
297 
298  case CLOSEST_DIRECT:
300 
301  break;
302 
303  default:
304  break;
305  }
306 }
307 
308 void
310 {
312 
313  if (request->error)
315 
317  tvSubMsec(al->cache.start_time, current_time));
318 
320 }
321 
322 void
324 {
325  assert(request);
326  assert(aLogEntry != nullptr);
327 
328  if (Config.onoff.log_mime_hdrs) {
329  MemBuf mb;
330  mb.init();
331  request->header.packInto(&mb);
332  //This is the request after adaptation or redirection
333  aLogEntry->headers.adapted_request = xstrdup(mb.buf);
334 
335  // the virgin request is saved to aLogEntry->request
336  if (aLogEntry->request) {
337  mb.reset();
338  aLogEntry->request->header.packInto(&mb);
339  aLogEntry->headers.request = xstrdup(mb.buf);
340  }
341 
342 #if USE_ADAPTATION
343  const Adaptation::History::Pointer ah = request->adaptLogHistory();
344  if (ah != nullptr) {
345  mb.reset();
346  ah->lastMeta.packInto(&mb);
347  aLogEntry->adapt.last_meta = xstrdup(mb.buf);
348  }
349 #endif
350 
351  mb.clean();
352  }
353 
354 #if ICAP_CLIENT
355  const Adaptation::Icap::History::Pointer ih = request->icapHistory();
356  if (ih != nullptr)
357  ih->processingTime(aLogEntry->icap.processingTime);
358 #endif
359 
360  aLogEntry->http.method = request->method;
361  aLogEntry->http.version = request->http_ver;
362  aLogEntry->hier = request->hier;
363  aLogEntry->cache.extuser = request->extacl_user.termedBuf();
364 
365  // Adapted request, if any, inherits and then collects all the stats, but
366  // the virgin request gets logged instead; copy the stats to log them.
367  // TODO: avoid losses by keeping these stats in a shared history object?
368  if (aLogEntry->request) {
369  aLogEntry->request->dnsWait = request->dnsWait;
370  aLogEntry->request->error = request->error;
371  }
372 }
373 
374 void
376 {
377  if (!out.size && loggingTags().oldType == LOG_TAG_NONE)
378  debugs(33, 5, "logging half-baked transaction: " << log_uri);
379 
380  al->icp.opcode = ICP_INVALID;
381  al->url = log_uri;
382  debugs(33, 9, "clientLogRequest: al.url='" << al->url << "'");
383 
384  const auto findReply = [this]() -> const HttpReply * {
385  if (al->reply)
386  return al->reply.getRaw();
387  if (const auto le = loggingEntry())
388  return le->hasFreshestReply();
389  return nullptr;
390  };
391  if (const auto reply = findReply()) {
392  al->http.code = reply->sline.status();
393  al->http.content_type = reply->content_type.termedBuf();
394  }
395 
396  debugs(33, 9, "clientLogRequest: http.code='" << al->http.code << "'");
397 
398  if (loggingEntry() && loggingEntry()->mem_obj && loggingEntry()->objectLen() >= 0)
399  al->cache.objectSize = loggingEntry()->contentLen(); // payload duplicate ?? with or without TE ?
400 
401  al->http.clientRequestSz.header = req_sz;
402  // the virgin request is saved to al->request
403  if (al->request && al->request->body_pipe)
404  al->http.clientRequestSz.payloadData = al->request->body_pipe->producedSize();
405  al->http.clientReplySz.header = out.headers_sz;
406  // XXX: calculate without payload encoding or headers !!
407  al->http.clientReplySz.payloadData = out.size - out.headers_sz; // pretend its all un-encoded data for now.
408 
409  al->cache.highOffset = out.offset;
410 
411  tvSub(al->cache.trTime, al->cache.start_time, current_time);
412 
413  if (request)
415 
416 #if USE_OPENSSL && 0
417 
418  /* This is broken. Fails if the connection has been closed. Needs
419  * to snarf the ssl details some place earlier..
420  */
421  if (getConn() != NULL)
422  al->cache.ssluser = sslGetUserEmail(fd_table[getConn()->fd].ssl);
423 
424 #endif
425 
426  if (request) {
427  SBuf matched;
428  for (auto h: Config.notes) {
429  if (h->match(request, al->reply.getRaw(), al, matched)) {
430  request->notes()->add(h->key(), matched);
431  debugs(33, 3, h->key() << " " << matched);
432  }
433  }
434  // The al->notes and request->notes must point to the same object.
435  al->syncNotes(request);
436 
437  HTTPMSGUNLOCK(al->adapted_request);
438  al->adapted_request = request;
439  HTTPMSGLOCK(al->adapted_request);
440  }
441 
442  ACLFilledChecklist checklist(nullptr, request);
443  checklist.updateAle(al);
444  // no need checklist.syncAle(): already synced
445  accessLogLog(al, &checklist);
446 
447  bool updatePerformanceCounters = true;
450  statsCheck.updateAle(al);
451  updatePerformanceCounters = statsCheck.fastCheck().allowed();
452  }
453 
454  if (updatePerformanceCounters) {
455  if (request)
456  updateCounters();
457 
458  if (getConn() != nullptr && getConn()->clientConnection != nullptr)
459  clientdbUpdate(getConn()->clientConnection->remote, loggingTags(), AnyP::PROTO_HTTP, out.size);
460  }
461 }
462 
463 void
465 {
466  safe_free(uri);
469  clearRequest();
470 
471  if (client_stream.tail)
473 }
474 
475 void
476 httpRequestFree(void *data)
477 {
478  ClientHttpRequest *http = (ClientHttpRequest *)data;
479  assert(http != nullptr);
480  delete http;
481 }
482 
483 /* This is a handler normally called by comm_close() */
485 {
486  if (clientConnection) {
488  // keep closed clientConnection for logging, clientdb cleanup, etc.
489  }
490  deleteThis("ConnStateData::connStateClosed");
491 }
492 
493 #if USE_AUTH
494 void
496 {
497  if (auth_ == nullptr) {
498  if (aur != nullptr) {
499  debugs(33, 2, "Adding connection-auth to " << clientConnection << " from " << by);
500  auth_ = aur;
501  }
502  return;
503  }
504 
505  // clobered with self-pointer
506  // NP: something nasty is going on in Squid, but harmless.
507  if (aur == auth_) {
508  debugs(33, 2, "WARNING: Ignoring duplicate connection-auth for " << clientConnection << " from " << by);
509  return;
510  }
511 
512  /*
513  * Connection-auth relies on a single set of credentials being preserved
514  * for all requests on a connection once they have been setup.
515  * There are several things which need to happen to preserve security
516  * when connection-auth credentials change unexpectedly or are unset.
517  *
518  * 1) auth helper released from any active state
519  *
520  * They can only be reserved by a handshake process which this
521  * connection can now never complete.
522  * This prevents helpers hanging when their connections close.
523  *
524  * 2) pinning is expected to be removed and server conn closed
525  *
526  * The upstream link is authenticated with the same credentials.
527  * Expecting the same level of consistency we should have received.
528  * This prevents upstream being faced with multiple or missing
529  * credentials after authentication.
530  * NP: un-pin is left to the cleanup in ConnStateData::swanSong()
531  * we just trigger that cleanup here via comm_reset_close() or
532  * ConnStateData::stopReceiving()
533  *
534  * 3) the connection needs to close.
535  *
536  * This prevents attackers injecting requests into a connection,
537  * or gateways wrongly multiplexing users into a single connection.
538  *
539  * When credentials are missing closure needs to follow an auth
540  * challenge for best recovery by the client.
541  *
542  * When credentials change there is nothing we can do but abort as
543  * fast as possible. Sending TCP RST instead of an HTTP response
544  * is the best-case action.
545  */
546 
547  // clobbered with nul-pointer
548  if (aur == nullptr) {
549  debugs(33, 2, "WARNING: Graceful closure on " << clientConnection << " due to connection-auth erase from " << by);
551  auth_ = nullptr;
552  // XXX: need to test whether the connection re-auth challenge is sent. If not, how to trigger it from here.
553  // NP: the current situation seems to fix challenge loops in Safari without visible issues in others.
554  // we stop receiving more traffic but can leave the Job running to terminate after the error or challenge is delivered.
555  stopReceiving("connection-auth removed");
556  return;
557  }
558 
559  // clobbered with alternative credentials
560  if (aur != auth_) {
561  debugs(33, 2, "ERROR: Closing " << clientConnection << " due to change of connection-auth from " << by);
563  auth_ = nullptr;
564  // this is a fatal type of problem.
565  // Close the connection immediately with TCP RST to abort all traffic flow
567  return;
568  }
569 
570  /* NOT REACHABLE */
571 }
572 #endif
573 
574 void
575 ConnStateData::resetReadTimeout(const time_t timeout)
576 {
578  AsyncCall::Pointer callback = JobCallback(33, 5, TimeoutDialer, this, ConnStateData::requestTimeout);
579  commSetConnTimeout(clientConnection, timeout, callback);
580 }
581 
582 void
584 {
586  AsyncCall::Pointer callback = JobCallback(5, 4, TimeoutDialer, this, ConnStateData::lifetimeTimeout);
588 }
589 
590 // cleans up before destructor is called
591 void
593 {
594  debugs(33, 2, clientConnection);
595 
596  flags.readMore = false;
597  clientdbEstablished(clientConnection->remote, -1); /* decrement */
598 
600  checkLogging();
601 
602  // XXX: Closing pinned conn is too harsh: The Client may want to continue!
603  unpinConnection(true);
604 
606 
607 #if USE_AUTH
608  // NP: do this bit after closing the connections to avoid side effects from unwanted TCP RST
609  setAuth(nullptr, "ConnStateData::SwanSong cleanup");
610 #endif
611 
612  flags.swanSang = true;
613 }
614 
615 void
616 ConnStateData::callException(const std::exception &ex)
617 {
618  Server::callException(ex); // logs ex and stops the job
619 
620  ErrorDetail::Pointer errorDetail;
621  if (const auto tex = dynamic_cast<const TextException*>(&ex))
622  errorDetail = new ExceptionErrorDetail(tex->id());
623  else
624  errorDetail = new ExceptionErrorDetail(Here().id());
625  updateError(ERR_GATEWAY_FAILURE, errorDetail);
626 }
627 
628 void
630 {
631  if (const auto context = pipeline.front()) {
632  const auto http = context->http;
633  assert(http);
634  http->updateError(error);
635  } else {
637  }
638 }
639 
640 bool
642 {
643  return cbdataReferenceValid(this) && // XXX: checking "this" in a method
645  !fd_table[clientConnection->fd].closing();
646 }
647 
649 {
650  debugs(33, 3, clientConnection);
651 
652  if (isOpen())
653  debugs(33, DBG_IMPORTANT, "ERROR: Squid BUG: ConnStateData did not close " << clientConnection);
654 
655  if (!flags.swanSang)
656  debugs(33, DBG_IMPORTANT, "ERROR: Squid BUG: ConnStateData was not destroyed properly; " << clientConnection);
657 
658  if (bodyPipe != nullptr)
659  stopProducingFor(bodyPipe, false);
660 
661  delete bodyParser; // TODO: pool
662 
663 #if USE_OPENSSL
664  delete sslServerBump;
665 #endif
666 }
667 
674 void
676 {
677  HttpRequest *request = http->request;
678 
679  debugs(33, 3, "http_ver = " << request->http_ver);
680  debugs(33, 3, "method = " << request->method);
681 
682  // TODO: move to HttpRequest::hdrCacheInit, just like HttpReply.
683  request->flags.proxyKeepalive = request->persistent();
684 }
685 
686 int
688 {
690  bodyLength > Config.maxRequestBodySize)
691  return 1; /* too large */
692 
693  return 0;
694 }
695 
696 bool
698 {
699  return request->multipartRangeRequest();
700 }
701 
702 void
704 {
705  mb->appendf("\r\n--" SQUIDSTRINGPH "--\r\n", SQUIDSTRINGPRINT(boundary));
706  debugs(33, 6, "buf offset: " << mb->size);
707 }
708 
709 void
710 clientPackRangeHdr(const HttpReplyPointer &rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb)
711 {
712  HttpHeader hdr(hoReply);
713  assert(rep);
714  assert(spec);
715 
716  /* put boundary */
717  debugs(33, 5, "appending boundary: " << boundary);
718  /* rfc2046 requires to _prepend_ boundary with <crlf>! */
719  mb->appendf("\r\n--" SQUIDSTRINGPH "\r\n", SQUIDSTRINGPRINT(boundary));
720 
721  /* stuff the header with required entries and pack it */
722 
725 
726  httpHeaderAddContRange(&hdr, *spec, rep->content_length);
727 
728  hdr.packInto(mb);
729  hdr.clean();
730 
731  /* append <crlf> (we packed a header, not a reply) */
732  mb->append("\r\n", 2);
733 }
734 
740 int64_t
742 {
743  int64_t clen = 0;
744  MemBuf mb;
745 
746  assert(memObject());
747 
748  mb.init();
750 
751  while (pos != request->range->end()) {
752  /* account for headers for this range */
753  mb.reset();
754  clientPackRangeHdr(&storeEntry()->mem().freshestReply(),
755  *pos, range_iter.boundary, &mb);
756  clen += mb.size;
757 
758  /* account for range content */
759  clen += (*pos)->length;
760 
761  debugs(33, 6, "clientMRangeCLen: (clen += " << mb.size << " + " << (*pos)->length << ") == " << clen);
762  ++pos;
763  }
764 
765  /* account for the terminating boundary */
766  mb.reset();
767 
769 
770  clen += mb.size;
771 
772  mb.clean();
773 
774  return clen;
775 }
776 
780 String
782 {
783  const char *key;
785  b.append(":",1);
786  key = storeEntry()->getMD5Text();
787  b.append(key, strlen(key));
788  return b;
789 }
790 
800 void
802  HttpReply * rep, StoreIOBuffer receivedData)
803 {
804  // do not try to deliver if client already ABORTED
805  if (!http->getConn() || !cbdataReferenceValid(http->getConn()) || !Comm::IsConnOpen(http->getConn()->clientConnection))
806  return;
807 
808  /* Test preconditions */
809  assert(node != nullptr);
810  /* TODO: handle this rather than asserting
811  * - it should only ever happen if we cause an abort and
812  * the callback chain loops back to here, so we can simply return.
813  * However, that itself shouldn't happen, so it stays as an assert for now.
814  */
816  assert(node->node.next == nullptr);
817  Http::StreamPointer context = dynamic_cast<Http::Stream *>(node->data.getRaw());
818  assert(context != nullptr);
819 
820  /* TODO: check offset is what we asked for */
821 
822  // TODO: enforces HTTP/1 MUST on pipeline order, but is irrelevant to HTTP/2
823  if (context != http->getConn()->pipeline.front())
824  context->deferRecipientForLater(node, rep, receivedData);
825  else if (http->getConn()->cbControlMsgSent) // 1xx to the user is pending
826  context->deferRecipientForLater(node, rep, receivedData);
827  else
828  http->getConn()->handleReply(rep, receivedData);
829 }
830 
836 void
838 {
839  /* Test preconditions */
840  assert(node != nullptr);
841  /* TODO: handle this rather than asserting
842  * - it should only ever happen if we cause an abort and
843  * the callback chain loops back to here, so we can simply return.
844  * However, that itself shouldn't happen, so it stays as an assert for now.
845  */
847  /* Set null by ContextFree */
848  assert(node->node.next == nullptr);
849  /* this is the assert discussed above */
850  assert(nullptr == dynamic_cast<Http::Stream *>(node->data.getRaw()));
851  /* We are only called when the client socket shutsdown.
852  * Tell the prev pipeline member we're finished
853  */
854  clientStreamDetach(node, http);
855 }
856 
857 void
859 {
860  debugs(33, 5, clientConnection << " reading next req");
861 
862  fd_note(clientConnection->fd, "Idle client: Waiting for next request");
867 
868  readSomeData();
870 }
871 
872 static void
874 {
875  debugs(33, 2, conn->clientConnection << " Sending next");
876 
879  if (deferredRequest->flags.deferred) {
881  assert(deferredRequest->http->out.size == 0);
883  clientSocketRecipient(deferredRequest->deferredparams.node,
884  deferredRequest->http,
885  deferredRequest->deferredparams.rep,
886  deferredRequest->deferredparams.queuedBuffer);
887  }
888 
892 }
893 
894 void
896 {
898  debugs(33, 2, clientConnection << " Connection was closed");
899  return;
900  }
901 
902  if (pinning.pinned && !Comm::IsConnOpen(pinning.serverConnection)) {
903  debugs(33, 2, clientConnection << " Connection was pinned but server side gone. Terminating client connection");
905  return;
906  }
907 
922  if (const char *reason = stoppedReceiving()) {
923  debugs(33, 3, "closing for earlier request error: " << reason);
925  return;
926  }
927 
934  parseRequests();
935 
936  if (!isOpen())
937  return;
938 
946  Http::StreamPointer deferredRequest = pipeline.front();
947  if (deferredRequest != nullptr) {
948  debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded");
949  ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
950  } else if (flags.readMore) {
951  debugs(33, 3, clientConnection << ": calling readNextRequest()");
952  readNextRequest();
953  } else {
954  // XXX: Can this happen? CONNECT tunnels have deferredRequest set.
955  debugs(33, DBG_IMPORTANT, MYNAME << "abandoning " << clientConnection);
956  }
957 }
958 
959 void
961 {
962  debugs(33, 4, "sending error (" << clientConnection << "): " << error <<
963  "; old receiving error: " <<
964  (stoppedReceiving() ? stoppedReceiving_ : "none"));
965 
966  if (const char *oldError = stoppedSending()) {
967  debugs(33, 3, "already stopped sending: " << oldError);
968  return; // nothing has changed as far as this connection is concerned
969  }
971 
972  if (!stoppedReceiving()) {
973  if (const int64_t expecting = mayNeedToReadMoreBody()) {
974  debugs(33, 5, "must still read " << expecting <<
975  " request body bytes with " << inBuf.length() << " unused");
976  return; // wait for the request receiver to finish reading
977  }
978  }
979 
981 }
982 
983 void
985 {
986  if (pipeline.empty())
987  return;
988 
989  auto ctx = pipeline.front();
990  if (size) {
992  if (ctx->http->loggingTags().isTcpHit())
994  }
995  ctx->writeComplete(size);
996 }
997 
998 Http::Stream *
1000 {
1001  ClientHttpRequest *http = new ClientHttpRequest(this);
1002  http->req_sz = inBuf.length();
1003  http->setErrorUri(uri);
1004  auto *context = new Http::Stream(clientConnection, http);
1005  StoreIOBuffer tempBuffer;
1006  tempBuffer.data = context->reqbuf;
1007  tempBuffer.length = HTTP_REQBUF_SZ;
1010  clientSocketDetach, context, tempBuffer);
1011  return context;
1012 }
1013 
1014 void
1016 {
1017  // RegisteredRunner API callback - Squid has been shut down
1018 
1019  // if connection is idle terminate it now,
1020  // otherwise wait for grace period to end
1021  if (pipeline.empty())
1022  endingShutdown();
1023 }
1024 
1025 void
1027 {
1028  // RegisteredRunner API callback - Squid shutdown grace period is over
1029 
1030  // force the client connection to close immediately
1031  // swanSong() in the close handler will cleanup.
1034 }
1035 
1036 char *
1037 skipLeadingSpace(char *aString)
1038 {
1039  char *result = aString;
1040 
1041  while (xisspace(*aString))
1042  ++aString;
1043 
1044  return result;
1045 }
1046 
1052 const char *
1053 findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end)
1054 {
1055  if (nullptr == end) {
1056  end = uriAndHTTPVersion + strcspn(uriAndHTTPVersion, "\r\n");
1057  assert(end);
1058  }
1059 
1060  for (; end > uriAndHTTPVersion; --end) {
1061  if (*end == '\n' || *end == '\r')
1062  continue;
1063 
1064  if (xisspace(*end)) {
1065  if (strncasecmp(end + 1, "HTTP/", 5) == 0)
1066  return end + 1;
1067  else
1068  break;
1069  }
1070  }
1071 
1072  return nullptr;
1073 }
1074 
1075 static char *
1077 {
1078  int vhost = conn->port->vhost;
1079  int vport = conn->port->vport;
1080  static char ipbuf[MAX_IPSTRLEN];
1081 
1082  /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
1083 
1084  // XXX: reuse proper URL parser for this
1085  SBuf url = hp->requestUri(); // use full provided URI if we abort
1086  do { // use a loop so we can break out of it
1087  ::Parser::Tokenizer tok(url);
1088  if (tok.skip('/')) // origin-form URL already.
1089  break;
1090 
1091  if (conn->port->vhost)
1092  return nullptr; /* already in good shape */
1093 
1094  // skip the URI scheme
1095  static const CharacterSet uriScheme = CharacterSet("URI-scheme","+-.") + CharacterSet::ALPHA + CharacterSet::DIGIT;
1096  static const SBuf uriSchemeEnd("://");
1097  if (!tok.skipAll(uriScheme) || !tok.skip(uriSchemeEnd))
1098  break;
1099 
1100  // skip the authority segment
1101  // RFC 3986 complex nested ABNF for "authority" boils down to this:
1102  static const CharacterSet authority = CharacterSet("authority","-._~%:@[]!$&'()*+,;=") +
1104  if (!tok.skipAll(authority))
1105  break;
1106 
1107  static const SBuf slashUri("/");
1108  const SBuf t = tok.remaining();
1109  if (t.isEmpty())
1110  url = slashUri;
1111  else if (t[0]=='/') // looks like path
1112  url = t;
1113  else if (t[0]=='?' || t[0]=='#') { // looks like query or fragment. fix '/'
1114  url = slashUri;
1115  url.append(t);
1116  } // else do nothing. invalid path
1117 
1118  } while(false);
1119 
1120 #if SHOULD_REJECT_UNKNOWN_URLS
1121  // reject URI which are not well-formed even after the processing above
1122  if (url.isEmpty() || url[0] != '/') {
1123  hp->parseStatusCode = Http::scBadRequest;
1124  return conn->abortRequestParsing("error:invalid-request");
1125  }
1126 #endif
1127 
1128  if (vport < 0)
1129  vport = conn->clientConnection->local.port();
1130 
1131  char *receivedHost = nullptr;
1132  if (vhost && (receivedHost = hp->getHostHeaderField())) {
1133  SBuf host(receivedHost);
1134  debugs(33, 5, "ACCEL VHOST REWRITE: vhost=" << host << " + vport=" << vport);
1135  if (vport > 0) {
1136  // remove existing :port (if any), cope with IPv6+ without port
1137  const auto lastColonPos = host.rfind(':');
1138  if (lastColonPos != SBuf::npos && *host.rbegin() != ']') {
1139  host.chop(0, lastColonPos); // truncate until the last colon
1140  }
1141  host.appendf(":%d", vport);
1142  } // else nothing to alter port-wise.
1143  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1144  const auto url_sz = scheme.length() + host.length() + url.length() + 32;
1145  char *uri = static_cast<char *>(xcalloc(url_sz, 1));
1146  snprintf(uri, url_sz, SQUIDSBUFPH "://" SQUIDSBUFPH SQUIDSBUFPH, SQUIDSBUFPRINT(scheme), SQUIDSBUFPRINT(host), SQUIDSBUFPRINT(url));
1147  debugs(33, 5, "ACCEL VHOST REWRITE: " << uri);
1148  return uri;
1149  } else if (conn->port->defaultsite /* && !vhost */) {
1150  debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: defaultsite=" << conn->port->defaultsite << " + vport=" << vport);
1151  char vportStr[32];
1152  vportStr[0] = '\0';
1153  if (vport > 0) {
1154  snprintf(vportStr, sizeof(vportStr),":%d",vport);
1155  }
1156  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1157  const int url_sz = scheme.length() + strlen(conn->port->defaultsite) + sizeof(vportStr) + url.length() + 32;
1158  char *uri = static_cast<char *>(xcalloc(url_sz, 1));
1159  snprintf(uri, url_sz, SQUIDSBUFPH "://%s%s" SQUIDSBUFPH,
1160  SQUIDSBUFPRINT(scheme), conn->port->defaultsite, vportStr, SQUIDSBUFPRINT(url));
1161  debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: " << uri);
1162  return uri;
1163  } else if (vport > 0 /* && (!vhost || no Host:) */) {
1164  debugs(33, 5, "ACCEL VPORT REWRITE: *_port IP + vport=" << vport);
1165  /* Put the local socket IP address as the hostname, with whatever vport we found */
1167  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1168  const int url_sz = scheme.length() + sizeof(ipbuf) + url.length() + 32;
1169  char *uri = static_cast<char *>(xcalloc(url_sz, 1));
1170  snprintf(uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
1171  SQUIDSBUFPRINT(scheme), ipbuf, vport, SQUIDSBUFPRINT(url));
1172  debugs(33, 5, "ACCEL VPORT REWRITE: " << uri);
1173  return uri;
1174  }
1175 
1176  return nullptr;
1177 }
1178 
1179 static char *
1181 {
1182  char *uri = nullptr;
1183  /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
1184  if (const char *host = hp->getHostHeaderField()) {
1185  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1186  const int url_sz = scheme.length() + strlen(host) + hp->requestUri().length() + 32;
1187  uri = static_cast<char *>(xcalloc(url_sz, 1));
1188  snprintf(uri, url_sz, SQUIDSBUFPH "://%s" SQUIDSBUFPH,
1189  SQUIDSBUFPRINT(scheme),
1190  host,
1191  SQUIDSBUFPRINT(hp->requestUri()));
1192  }
1193  return uri;
1194 }
1195 
1196 char *
1198 {
1199  Must(switchedToHttps());
1200 
1201  if (!hp->requestUri().isEmpty() && hp->requestUri()[0] != '/')
1202  return nullptr; /* already in good shape */
1203 
1204  char *uri = buildUrlFromHost(this, hp);
1205 #if USE_OPENSSL
1206  if (!uri) {
1209  SBuf useHost;
1210  if (!tlsClientSni().isEmpty())
1211  useHost = tlsClientSni();
1212  else
1213  useHost = tlsConnectHostOrIp;
1214 
1215  const SBuf &scheme = AnyP::UriScheme(transferProtocol.protocol).image();
1216  const int url_sz = scheme.length() + useHost.length() + hp->requestUri().length() + 32;
1217  uri = static_cast<char *>(xcalloc(url_sz, 1));
1218  snprintf(uri, url_sz, SQUIDSBUFPH "://" SQUIDSBUFPH ":%hu" SQUIDSBUFPH,
1219  SQUIDSBUFPRINT(scheme),
1220  SQUIDSBUFPRINT(useHost),
1221  *tlsConnectPort,
1222  SQUIDSBUFPRINT(hp->requestUri()));
1223  }
1224 #endif
1225  if (uri)
1226  debugs(33, 5, "TLS switching host rewrite: " << uri);
1227  return uri;
1228 }
1229 
1230 static char *
1232 {
1233  // TODO Must() on URI !empty when the parser supports throw. For now avoid assert().
1234  if (!hp->requestUri().isEmpty() && hp->requestUri()[0] != '/')
1235  return nullptr; /* already in good shape */
1236 
1237  char *uri = buildUrlFromHost(conn, hp);
1238  if (!uri) {
1239  /* Put the local socket IP address as the hostname. */
1240  static char ipbuf[MAX_IPSTRLEN];
1242  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1243  const int url_sz = sizeof(ipbuf) + hp->requestUri().length() + 32;
1244  uri = static_cast<char *>(xcalloc(url_sz, 1));
1245  snprintf(uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
1246  SQUIDSBUFPRINT(scheme),
1247  ipbuf, conn->clientConnection->local.port(), SQUIDSBUFPRINT(hp->requestUri()));
1248  }
1249 
1250  if (uri)
1251  debugs(33, 5, "TRANSPARENT REWRITE: " << uri);
1252  return uri;
1253 }
1254 
1255 Http::Stream *
1257 {
1258  /* Attempt to parse the first line; this will define where the method, url, version and header begin */
1259  {
1260  Must(hp);
1261 
1264 
1265  const bool parsedOk = hp->parse(inBuf);
1266 
1267  // sync the buffers after parsing.
1268  inBuf = hp->remaining();
1269 
1270  if (hp->needsMoreData()) {
1271  debugs(33, 5, "Incomplete request, waiting for end of request line");
1272  return nullptr;
1273  }
1274 
1275  if (!parsedOk) {
1276  const bool tooBig =
1277  hp->parseStatusCode == Http::scRequestHeaderFieldsTooLarge ||
1278  hp->parseStatusCode == Http::scUriTooLong;
1279  auto result = abortRequestParsing(
1280  tooBig ? "error:request-too-large" : "error:invalid-request");
1281  // assume that remaining leftovers belong to this bad request
1282  if (!inBuf.isEmpty())
1284  return result;
1285  }
1286  }
1287 
1288  /* We know the whole request is in parser now */
1289  debugs(11, 2, "HTTP Client " << clientConnection);
1290  debugs(11, 2, "HTTP Client REQUEST:\n---------\n" <<
1291  hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol() << "\n" <<
1292  hp->mimeHeader() <<
1293  "\n----------");
1294 
1295  /* deny CONNECT via accelerated ports */
1296  if (hp->method() == Http::METHOD_CONNECT && port != nullptr && port->flags.accelSurrogate) {
1297  debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << transferProtocol << " Accelerator port " << port->s.port());
1298  debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1299  hp->parseStatusCode = Http::scMethodNotAllowed;
1300  return abortRequestParsing("error:method-not-allowed");
1301  }
1302 
1303  /* HTTP/2 connection magic prefix starts with "PRI ".
1304  * Deny "PRI" method if used in HTTP/1.x or 0.9 versions.
1305  * If seen it signals a broken client or proxy has corrupted the traffic.
1306  */
1307  if (hp->method() == Http::METHOD_PRI && hp->messageProtocol() < Http::ProtocolVersion(2,0)) {
1308  debugs(33, DBG_IMPORTANT, "WARNING: PRI method received on " << transferProtocol << " port " << port->s.port());
1309  debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1310  hp->parseStatusCode = Http::scMethodNotAllowed;
1311  return abortRequestParsing("error:method-not-allowed");
1312  }
1313 
1314  if (hp->method() == Http::METHOD_NONE) {
1315  debugs(33, DBG_IMPORTANT, "WARNING: Unsupported method: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1316  hp->parseStatusCode = Http::scMethodNotAllowed;
1317  return abortRequestParsing("error:unsupported-request-method");
1318  }
1319 
1320  // Process headers after request line
1321  debugs(33, 3, "complete request received. " <<
1322  "prefix_sz = " << hp->messageHeaderSize() <<
1323  ", request-line-size=" << hp->firstLineSize() <<
1324  ", mime-header-size=" << hp->headerBlockSize() <<
1325  ", mime header block:\n" << hp->mimeHeader() << "\n----------");
1326 
1327  /* Ok, all headers are received */
1328  ClientHttpRequest *http = new ClientHttpRequest(this);
1329 
1330  http->req_sz = hp->messageHeaderSize();
1331  Http::Stream *result = new Http::Stream(clientConnection, http);
1332 
1333  StoreIOBuffer tempBuffer;
1334  tempBuffer.data = result->reqbuf;
1335  tempBuffer.length = HTTP_REQBUF_SZ;
1336 
1337  ClientStreamData newServer = new clientReplyContext(http);
1338  ClientStreamData newClient = result;
1341  clientSocketDetach, newClient, tempBuffer);
1342 
1343  /* set url */
1344  debugs(33,5, "Prepare absolute URL from " <<
1345  (transparent()?"intercept":(port->flags.accelSurrogate ? "accel":"")));
1346  /* Rewrite the URL in transparent or accelerator mode */
1347  /* NP: there are several cases to traverse here:
1348  * - standard mode (forward proxy)
1349  * - transparent mode (TPROXY)
1350  * - transparent mode with failures
1351  * - intercept mode (NAT)
1352  * - intercept mode with failures
1353  * - accelerator mode (reverse proxy)
1354  * - internal relative-URL
1355  * - mixed combos of the above with internal URL
1356  * - remote interception with PROXY protocol
1357  * - remote reverse-proxy with PROXY protocol
1358  */
1359  if (switchedToHttps()) {
1360  http->uri = prepareTlsSwitchingURL(hp);
1361  } else if (transparent()) {
1362  /* intercept or transparent mode, properly working with no failures */
1363  http->uri = prepareTransparentURL(this, hp);
1364 
1365  } else if (internalCheck(hp->requestUri())) { // NP: only matches relative-URI
1366  /* internal URL mode */
1367  // XXX: By prepending our name and port, we create an absolute URL
1368  // that may mismatch the (yet unparsed) Host header in the request.
1369  http->uri = xstrdup(internalLocalUri(nullptr, hp->requestUri()));
1370 
1371  } else if (port->flags.accelSurrogate) {
1372  /* accelerator mode */
1373  http->uri = prepareAcceleratedURL(this, hp);
1374  http->flags.accel = true;
1375  }
1376 
1377  if (!http->uri) {
1378  /* No special rewrites have been applied above, use the
1379  * requested url. may be rewritten later, so make extra room */
1380  int url_sz = hp->requestUri().length() + Config.appendDomainLen + 5;
1381  http->uri = (char *)xcalloc(url_sz, 1);
1382  SBufToCstring(http->uri, hp->requestUri());
1383  }
1384 
1385  result->flags.parsed_ok = 1;
1386  return result;
1387 }
1388 
1389 bool
1391 {
1392  if (pipeline.empty() && inBuf.isEmpty()) {
1393  debugs(33, 4, "yes, without active requests and unparsed input");
1394  return true;
1395  }
1396 
1398  debugs(33, 3, "yes, without half_closed_clients");
1399  return true;
1400  }
1401 
1402  // Squid currently tries to parse (possibly again) a partially received
1403  // request after an EOF with half_closed_clients. To give that last parse in
1404  // afterClientRead() a chance, we ignore partially parsed requests here.
1405  debugs(33, 3, "no, honoring half_closed_clients");
1406  return false;
1407 }
1408 
1409 void
1410 ConnStateData::consumeInput(const size_t byteCount)
1411 {
1412  assert(byteCount > 0 && byteCount <= inBuf.length());
1413  inBuf.consume(byteCount);
1414  debugs(33, 5, "inBuf has " << inBuf.length() << " unused bytes");
1415 }
1416 
1417 void
1419 {
1420  // Were we expecting to read more request body from half-closed connection?
1422  debugs(33, 3, "truncated body: closing half-closed " << clientConnection);
1424  return;
1425  }
1426 
1427  if (flags.readMore)
1428  readSomeData();
1429 }
1430 
1431 void
1433 {
1434  // From HTTP p.o.v., we do not have to close after every error detected
1435  // at the client-side, but many such errors do require closure and the
1436  // client-side code is bad at handling errors so we play it safe.
1437  if (request)
1438  request->flags.proxyKeepalive = false;
1439  flags.readMore = false;
1440  debugs(33,4, "Will close after error: " << clientConnection);
1441 }
1442 
1443 #if USE_OPENSSL
1445 {
1446  ClientHttpRequest *http = context->http;
1447 
1448  if (!sslServerBump)
1449  return false;
1450 
1452  // Did we create an error entry while processing CONNECT?
1453  if (!sslServerBump->entry->isEmpty()) {
1454  quitAfterError(http->request);
1455 
1456  // Get the saved error entry and send it to the client by replacing the
1457  // ClientHttpRequest store entry with it.
1459  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1460  assert(repContext);
1461  debugs(33, 5, "Responding with delated error for " << http->uri);
1462  repContext->setReplyToStoreEntry(sslServerBump->entry, "delayed SslBump error");
1463 
1464  // Get error details from the fake certificate-peeking request.
1466  context->pullData();
1467  return true;
1468  }
1469 
1470  // In bump-server-first mode, we have not necessarily seen the intended
1471  // server name at certificate-peeking time. Check for domain mismatch now,
1472  // when we can extract the intended name from the bumped HTTP request.
1473  if (const Security::CertPointer &srvCert = sslServerBump->serverCert) {
1474  HttpRequest *request = http->request;
1475  const auto host = request->url.parsedHost();
1476  if (host && Ssl::HasSubjectName(*srvCert, *host)) {
1477  debugs(33, 5, "certificate matches requested host: " << *host);
1478  return false;
1479  } else {
1480  debugs(33, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " <<
1481  "does not match request target " << RawPointer(host));
1482 
1483  bool allowDomainMismatch = false;
1486  const auto sslErrors = std::make_unique<Security::CertErrors>(Security::CertError(SQUID_X509_V_ERR_DOMAIN_MISMATCH, srvCert));
1487  check.sslErrors = sslErrors.get();
1488  clientAclChecklistFill(check, http);
1489  allowDomainMismatch = check.fastCheck().allowed();
1490  }
1491 
1492  if (!allowDomainMismatch) {
1493  quitAfterError(request);
1494 
1496  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1497  assert (repContext);
1498 
1499  request->hier = sslServerBump->request->hier;
1500 
1501  // Create an error object and fill it
1502  const auto err = new ErrorState(ERR_SECURE_CONNECT_FAIL, Http::scServiceUnavailable, request, http->al);
1503  err->src_addr = clientConnection->remote;
1506  srvCert, nullptr);
1508  repContext->setReplyToError(request->method, err);
1509  assert(context->http->out.offset == 0);
1510  context->pullData();
1511  return true;
1512  }
1513  }
1514  }
1515 
1516  return false;
1517 }
1518 #endif // USE_OPENSSL
1519 
1521 bool
1523 {
1525  debugs(33, 5, "disabled; send error: " << requestError);
1526  return false;
1527  }
1528 
1529  if (!preservingClientData_) {
1530  debugs(33, 3, "may have forgotten client data; send error: " << requestError);
1531  return false;
1532  }
1533 
1535  checklist.requestErrorType = requestError;
1536  fillChecklist(checklist);
1537  const auto &answer = checklist.fastCheck();
1538  if (answer.allowed() && answer.kind == 1) {
1539  debugs(33, 3, "Request will be tunneled to server");
1540  const auto context = pipeline.front();
1541  const auto http = context ? context->http : nullptr;
1542  const auto request = http ? http->request : nullptr;
1543  if (context)
1544  context->finished(); // Will remove from pipeline queue
1545  Comm::SetSelect(clientConnection->fd, COMM_SELECT_READ, nullptr, nullptr, 0);
1546  return initiateTunneledRequest(request, "unknown-protocol", preservedClientData);
1547  }
1548  debugs(33, 3, "denied; send error: " << requestError);
1549  return false;
1550 }
1551 
1552 void
1554 {
1555  /*
1556  * DPW 2007-05-18
1557  * Moved the TCP_RESET feature from clientReplyContext::sendMoreData
1558  * to here because calling comm_reset_close() causes http to
1559  * be freed before accessing.
1560  */
1561  if (request != nullptr && request->flags.resetTcp && Comm::IsConnOpen(conn->clientConnection)) {
1562  debugs(33, 3, "Sending TCP RST on " << conn->clientConnection);
1563  conn->flags.readMore = false;
1565  }
1566 }
1567 
1568 void
1570 {
1571  ClientHttpRequest *http = context->http;
1572  bool mustReplyToOptions = false;
1573  bool expectBody = false;
1574 
1575  // We already have the request parsed and checked, so we
1576  // only need to go through the final body/conn setup to doCallouts().
1577  assert(http->request);
1578  HttpRequest::Pointer request = http->request;
1579 
1580  // temporary hack to avoid splitting this huge function with sensitive code
1581  const bool isFtp = !hp;
1582 
1583  // Some blobs below are still HTTP-specific, but we would have to rewrite
1584  // this entire function to remove them from the FTP code path. Connection
1585  // setup and body_pipe preparation blobs are needed for FTP.
1586 
1587  request->manager(conn, http->al);
1588 
1589  request->flags.accelerated = http->flags.accel;
1590  request->flags.sslBumped=conn->switchedToHttps();
1591  // TODO: decouple http->flags.accel from request->flags.sslBumped
1592  request->flags.noDirect = (request->flags.accelerated && !request->flags.sslBumped) ?
1593  !conn->port->allow_direct : 0;
1594  request->sources |= isFtp ? Http::Message::srcFtp :
1595  ((request->flags.sslBumped || conn->port->transport.protocol == AnyP::PROTO_HTTPS) ? Http::Message::srcHttps : Http::Message::srcHttp);
1596 #if USE_AUTH
1597  if (request->flags.sslBumped) {
1598  if (conn->getAuth() != nullptr)
1599  request->auth_user_request = conn->getAuth();
1600  }
1601 #endif
1602 
1603  http->checkForInternalAccess();
1604 
1605  if (!isFtp) {
1606  // XXX: for non-HTTP messages instantiate a different Http::Message child type
1607  // for now Squid only supports HTTP requests
1608  const AnyP::ProtocolVersion &http_ver = hp->messageProtocol();
1609  assert(request->http_ver.protocol == http_ver.protocol);
1610  request->http_ver.major = http_ver.major;
1611  request->http_ver.minor = http_ver.minor;
1612  }
1613 
1614  mustReplyToOptions = (request->method == Http::METHOD_OPTIONS) &&
1615  (request->header.getInt64(Http::HdrType::MAX_FORWARDS) == 0);
1616  if (!urlCheckRequest(request.getRaw()) || mustReplyToOptions) {
1618  conn->quitAfterError(request.getRaw());
1619  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1620  assert (repContext);
1622  conn, request.getRaw(), nullptr, nullptr);
1623  assert(context->http->out.offset == 0);
1624  context->pullData();
1625  clientProcessRequestFinished(conn, request);
1626  return;
1627  }
1628 
1629  const auto frameStatus = request->checkEntityFraming();
1630  if (frameStatus != Http::scNone) {
1632  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1633  assert (repContext);
1634  conn->quitAfterError(request.getRaw());
1635  repContext->setReplyToError(ERR_INVALID_REQ, frameStatus, nullptr, conn, request.getRaw(), nullptr, nullptr);
1636  assert(context->http->out.offset == 0);
1637  context->pullData();
1638  clientProcessRequestFinished(conn, request);
1639  return;
1640  }
1641 
1642  clientSetKeepaliveFlag(http);
1643  // Let tunneling code be fully responsible for CONNECT requests
1644  if (http->request->method == Http::METHOD_CONNECT) {
1645  context->mayUseConnection(true);
1646  conn->flags.readMore = false;
1647  }
1648 
1649 #if USE_OPENSSL
1650  if (conn->switchedToHttps() && conn->serveDelayedError(context)) {
1651  clientProcessRequestFinished(conn, request);
1652  return;
1653  }
1654 #endif
1655 
1656  /* Do we expect a request-body? */
1657  const auto chunked = request->header.chunked();
1658  expectBody = chunked || request->content_length > 0;
1659  if (!context->mayUseConnection() && expectBody) {
1660  request->body_pipe = conn->expectRequestBody(
1661  chunked ? -1 : request->content_length);
1662 
1663  /* Is it too large? */
1664  if (!chunked && // if chunked, we will check as we accumulate
1667  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1668  assert (repContext);
1669  conn->quitAfterError(request.getRaw());
1670  repContext->setReplyToError(ERR_TOO_BIG,
1671  Http::scContentTooLarge, nullptr,
1672  conn, http->request, nullptr, nullptr);
1673  assert(context->http->out.offset == 0);
1674  context->pullData();
1675  clientProcessRequestFinished(conn, request);
1676  return;
1677  }
1678 
1679  if (!isFtp) {
1680  // We may stop producing, comm_close, and/or call setReplyToError()
1681  // below, so quit on errors to avoid http->doCallouts()
1682  if (!conn->handleRequestBodyData()) {
1683  clientProcessRequestFinished(conn, request);
1684  return;
1685  }
1686 
1687  if (!request->body_pipe->productionEnded()) {
1688  debugs(33, 5, "need more request body");
1689  context->mayUseConnection(true);
1690  assert(conn->flags.readMore);
1691  }
1692  }
1693  }
1694 
1695  http->calloutContext = new ClientRequestContext(http);
1696 
1697  http->doCallouts();
1698 
1699  clientProcessRequestFinished(conn, request);
1700 }
1701 
1702 void
1704 {
1705  debugs(33, 3, context << " to " << pipeline.count() << '/' << pipeline.nrequests);
1706  if (bareError) {
1707  debugs(33, 5, "assigning " << bareError);
1708  assert(context);
1709  assert(context->http);
1710  context->http->updateError(bareError);
1711  bareError.clear();
1712  }
1713  pipeline.add(context);
1714 }
1715 
1716 int
1718 {
1719  // TODO: Support pipelined requests through pinned connections.
1720  if (pinning.pinned)
1721  return 0;
1723 }
1724 
1730 bool
1732 {
1733  const int existingRequestCount = pipeline.count();
1734 
1735  // default to the configured pipeline size.
1736  // add 1 because the head of pipeline is counted in concurrent requests and not prefetch queue
1737 #if USE_OPENSSL
1738  const int internalRequest = (transparent() && sslBumpMode == Ssl::bumpSplice) ? 1 : 0;
1739 #else
1740  const int internalRequest = 0;
1741 #endif
1742  const int concurrentRequestLimit = pipelinePrefetchMax() + 1 + internalRequest;
1743 
1744  // when queue filled already we can't add more.
1745  if (existingRequestCount >= concurrentRequestLimit) {
1746  debugs(33, 3, clientConnection << " max concurrent requests reached (" << concurrentRequestLimit << ")");
1747  debugs(33, 5, clientConnection << " deferring new request until one is done");
1748  return true;
1749  }
1750 
1751  return false;
1752 }
1753 
1759 bool
1761 {
1763  return proxyProtocolError("PROXY client not permitted by default ACL");
1764 
1766  fillChecklist(ch);
1767  if (!ch.fastCheck().allowed())
1768  return proxyProtocolError("PROXY client not permitted by ACLs");
1769 
1770  return true;
1771 }
1772 
1778 bool
1780 {
1781  if (msg) {
1782  // This is important to know, but maybe not so much that flooding the log is okay.
1783 #if QUIET_PROXY_PROTOCOL
1784  // display the first of every 32 occurrences at level 1, the others at level 2.
1785  static uint8_t hide = 0;
1786  debugs(33, (hide++ % 32 == 0 ? DBG_IMPORTANT : 2), msg << " from " << clientConnection);
1787 #else
1788  debugs(33, DBG_IMPORTANT, msg << " from " << clientConnection);
1789 #endif
1790  mustStop(msg);
1791  }
1792  return false;
1793 }
1794 
1799 bool
1801 {
1802  try {
1803  const auto parsed = ProxyProtocol::Parse(inBuf);
1804  proxyProtocolHeader_ = parsed.header;
1806  inBuf.consume(parsed.size);
1807  needProxyProtocolHeader_ = false;
1808  if (proxyProtocolHeader_->hasForwardedAddresses()) {
1809  clientConnection->local = proxyProtocolHeader_->destinationAddress;
1810  clientConnection->remote = proxyProtocolHeader_->sourceAddress;
1812  clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
1813  debugs(33, 5, "PROXY/" << proxyProtocolHeader_->version() << " upgrade: " << clientConnection);
1814  }
1815  } catch (const Parser::BinaryTokenizer::InsufficientInput &) {
1816  debugs(33, 3, "PROXY protocol: waiting for more than " << inBuf.length() << " bytes");
1817  return false;
1818  } catch (const std::exception &e) {
1819  return proxyProtocolError(e.what());
1820  }
1821  return true;
1822 }
1823 
1824 void
1826 {
1827  if (receivedFirstByte_)
1828  return;
1829 
1830  receivedFirstByte_ = true;
1832 }
1833 
1836 void
1838 {
1839  debugs(33, 5, clientConnection << ": attempting to parse");
1840 
1841  // Loop while we have read bytes that are not needed for producing the body
1842  // On errors, bodyPipe may become nil, but readMore will be cleared
1843  while (!inBuf.isEmpty() && !bodyPipe && flags.readMore) {
1844 
1845  // Prohibit concurrent requests when using a pinned to-server connection
1846  // because our Client classes do not support request pipelining.
1847  if (pinning.pinned && !pinning.readHandler) {
1848  debugs(33, 3, clientConnection << " waits for busy " << pinning.serverConnection);
1849  break;
1850  }
1851 
1852  /* Limit the number of concurrent requests */
1854  break;
1855 
1856  // try to parse the PROXY protocol header magic bytes
1858  if (!parseProxyProtocolHeader())
1859  break;
1860 
1861  // we have been waiting for PROXY to provide client-IP
1862  // for some lookups, ie rDNS
1864 
1865  // Done with PROXY protocol which has cleared preservingClientData_.
1866  // If the next protocol supports on_unsupported_protocol, then its
1867  // parseOneRequest() must reset preservingClientData_.
1869  }
1870 
1871  if (Http::StreamPointer context = parseOneRequest()) {
1872  debugs(33, 5, clientConnection << ": done parsing a request");
1873  extendLifetime();
1874  context->registerWithConn();
1875 
1876 #if USE_OPENSSL
1877  if (switchedToHttps())
1879 #endif
1880 
1881  processParsedRequest(context);
1882 
1883  if (context->mayUseConnection()) {
1884  debugs(33, 3, "Not parsing new requests, as this request may need the connection");
1885  break;
1886  }
1887  } else {
1888  debugs(33, 5, clientConnection << ": not enough request data: " <<
1889  inBuf.length() << " < " << Config.maxRequestHeaderSize);
1891  break;
1892  }
1893  }
1894 
1895  debugs(33, 7, "buffered leftovers: " << inBuf.length());
1896 
1898  if (pipeline.empty()) {
1899  // we processed what we could parse, and no more data is coming
1900  debugs(33, 5, "closing half-closed without parsed requests: " << clientConnection);
1902  } else {
1903  // we parsed what we could, and no more data is coming
1904  debugs(33, 5, "monitoring half-closed while processing parsed requests: " << clientConnection);
1905  flags.readMore = false; // may already be false
1906  }
1907  }
1908 }
1909 
1910 void
1912 {
1913 #if USE_OPENSSL
1914  if (parsingTlsHandshake) {
1916  return;
1917  }
1918 #endif
1919 
1920  /* Process next request */
1921  if (pipeline.empty())
1922  fd_note(clientConnection->fd, "Reading next request");
1923 
1924  parseRequests();
1925 
1926  if (!isOpen())
1927  return;
1928 
1930 }
1931 
1938 bool
1940 {
1941  // if we are reading a body, stuff data into the body pipe
1942  if (bodyPipe != nullptr)
1943  return handleRequestBodyData();
1944  return true;
1945 }
1946 
1954 bool
1956 {
1957  assert(bodyPipe != nullptr);
1958 
1959  if (bodyParser) { // chunked encoding
1960  if (const err_type error = handleChunkedRequestBody()) {
1962  return false;
1963  }
1964  } else { // identity encoding
1965  debugs(33,5, "handling plain request body for " << clientConnection);
1966  const auto putSize = bodyPipe->putMoreData(inBuf.rawContent(), inBuf.length());
1967  if (putSize > 0)
1968  consumeInput(putSize);
1969 
1970  if (!bodyPipe->mayNeedMoreData()) {
1971  // BodyPipe will clear us automagically when we produced everything
1972  bodyPipe = nullptr;
1973  }
1974  }
1975 
1976  if (!bodyPipe) {
1977  debugs(33,5, "produced entire request body for " << clientConnection);
1978 
1979  if (const char *reason = stoppedSending()) {
1980  /* we've finished reading like good clients,
1981  * now do the close that initiateClose initiated.
1982  */
1983  debugs(33, 3, "closing for earlier sending error: " << reason);
1985  return false;
1986  }
1987  }
1988 
1989  return true;
1990 }
1991 
1993 err_type
1995 {
1996  debugs(33, 7, "chunked from " << clientConnection << ": " << inBuf.length());
1997 
1998  try { // the parser will throw on errors
1999 
2000  if (inBuf.isEmpty()) // nothing to do
2001  return ERR_NONE;
2002 
2003  BodyPipeCheckout bpc(*bodyPipe);
2005  const bool parsed = bodyParser->parse(inBuf);
2006  inBuf = bodyParser->remaining(); // sync buffers
2007  bpc.checkIn();
2008 
2009  // dechunk then check: the size limit applies to _dechunked_ content
2011  return ERR_TOO_BIG;
2012 
2013  if (parsed) {
2015  Must(!bodyPipe);
2016  return ERR_NONE; // nil bodyPipe implies body end for the caller
2017  }
2018 
2019  // if chunk parser needs data, then the body pipe must need it too
2021 
2022  // if parser needs more space and we can consume nothing, we will stall
2024  } catch (...) { // TODO: be more specific
2025  debugs(33, 3, "malformed chunks" << bodyPipe->status());
2026  return ERR_INVALID_REQ;
2027  }
2028 
2029  debugs(33, 7, "need more chunked data" << *bodyPipe->status());
2030  return ERR_NONE;
2031 }
2032 
2034 void
2036 {
2037  finishDechunkingRequest(false);
2038 
2039  // XXX: The code below works if we fail during initial request parsing,
2040  // but if we fail when the server connection is used already, the server may send
2041  // us its response too, causing various assertions. How to prevent that?
2042 #if WE_KNOW_HOW_TO_SEND_ERRORS
2043  Http::StreamPointer context = pipeline.front();
2044  if (context != NULL && !context->http->out.offset) { // output nothing yet
2045  clientStreamNode *node = context->getClientReplyContext();
2046  clientReplyContext *repContext = dynamic_cast<clientReplyContext*>(node->data.getRaw());
2047  assert(repContext);
2048  const Http::StatusCode scode = (error == ERR_TOO_BIG) ?
2049  Http::scContentTooLarge : HTTP_BAD_REQUEST;
2050  repContext->setReplyToError(error, scode,
2051  repContext->http->uri,
2052  CachePeer,
2053  repContext->http->request,
2054  inBuf, nullptr);
2055  context->pullData();
2056  } else {
2057  // close or otherwise we may get stuck as nobody will notice the error?
2059  }
2060 #else
2061  debugs(33, 3, "aborting chunked request without error " << error);
2063 #endif
2064  flags.readMore = false;
2065 }
2066 
2067 void
2069 {
2070  // request reader may get stuck waiting for space if nobody consumes body
2071  if (bodyPipe != nullptr)
2073 
2074  // kids extend
2075 }
2076 
2078 void
2080 {
2081  if (!Comm::IsConnOpen(io.conn))
2082  return;
2083 
2085  updateError(error);
2086  if (tunnelOnError(error))
2087  return;
2088 
2089  /*
2090  * Just close the connection to not confuse browsers
2091  * using persistent connections. Some browsers open
2092  * a connection and then do not use it until much
2093  * later (presumably because the request triggering
2094  * the open has already been completed on another
2095  * connection)
2096  */
2097  debugs(33, 3, "requestTimeout: FD " << io.fd << ": lifetime is expired.");
2098  io.conn->close();
2099 }
2100 
2101 void
2103 {
2104  debugs(33, DBG_IMPORTANT, "WARNING: Closing client connection due to lifetime timeout" <<
2105  Debug::Extra << "connection: " << io.conn);
2106 
2107  LogTagsErrors lte;
2108  lte.timedout = true;
2110 }
2111 
2113  AsyncJob("ConnStateData"), // kids overwrite
2114  Server(xact)
2115 #if USE_OPENSSL
2116  , tlsParser(Security::HandshakeParser::fromClient)
2117 #endif
2118 {
2119  // store the details required for creating more MasterXaction objects as new requests come in
2120  log_addr = xact->tcpClient->remote;
2122 
2123  // register to receive notice of Squid signal events
2124  // which may affect long persisting client connections
2125  registerRunner();
2126 }
2127 
2128 void
2130 {
2133 
2134  if (port->disable_pmtu_discovery != DISABLE_PMTU_OFF &&
2135  (transparent() || port->disable_pmtu_discovery == DISABLE_PMTU_ALWAYS)) {
2136 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
2137  int i = IP_PMTUDISC_DONT;
2138  if (xsetsockopt(clientConnection->fd, SOL_IP, IP_MTU_DISCOVER, &i, sizeof(i)) < 0) {
2139  int xerrno = errno;
2140  debugs(33, 2, "WARNING: Path MTU discovery disabling failed on " << clientConnection << " : " << xstrerr(xerrno));
2141  }
2142 #else
2143  static bool reported = false;
2144 
2145  if (!reported) {
2146  debugs(33, DBG_IMPORTANT, "WARNING: Path MTU discovery disabling is not supported on your platform.");
2147  reported = true;
2148  }
2149 #endif
2150  }
2151 
2153  AsyncCall::Pointer call = JobCallback(33, 5, Dialer, this, ConnStateData::connStateClosed);
2155 
2156  needProxyProtocolHeader_ = port->flags.proxySurrogate;
2158  if (!proxyProtocolValidateClient()) // will close the connection on failure
2159  return;
2160  } else
2162 
2163  // requires needProxyProtocolHeader_ which is initialized above
2165 }
2166 
2167 void
2169 {
2170  debugs(33, 7, clientConnection->remote);
2173 
2175 
2176 #if USE_DELAY_POOLS
2177  fd_table[clientConnection->fd].clientInfo = nullptr;
2178 
2179  if (!Config.onoff.client_db)
2180  return; // client delay pools require client_db
2181 
2182  const auto &pools = ClientDelayPools::Instance()->pools;
2183  if (pools.size()) {
2184  ACLFilledChecklist ch(nullptr, nullptr);
2185  fillChecklist(ch);
2186  // TODO: we check early to limit error response bandwidth but we
2187  // should recheck when we can honor delay_pool_uses_indirect
2188  for (unsigned int pool = 0; pool < pools.size(); ++pool) {
2189 
2190  /* pools require explicit 'allow' to assign a client into them */
2191  if (pools[pool]->access) {
2192  ch.changeAcl(pools[pool]->access);
2193  const auto &answer = ch.fastCheck();
2194  if (answer.allowed()) {
2195 
2196  /* request client information from db after we did all checks
2197  this will save hash lookup if client failed checks */
2199  assert(cli);
2200 
2201  /* put client info in FDE */
2202  fd_table[clientConnection->fd].clientInfo = cli;
2203 
2204  /* setup write limiter for this request */
2205  const double burst = floor(0.5 +
2206  (pools[pool]->highwatermark * Config.ClientDelay.initial)/100.0);
2207  cli->setWriteLimiter(pools[pool]->rate, burst, pools[pool]->highwatermark);
2208  break;
2209  } else {
2210  debugs(83, 4, "Delay pool " << pool << " skipped because ACL " << answer);
2211  }
2212  }
2213  }
2214  }
2215 #endif
2216 
2217  // kids must extend to actually start doing something (e.g., reading)
2218 }
2219 
2222 {
2223  const auto handshakeResult = Security::Accept(*clientConnection);
2224 
2225 #if USE_OPENSSL
2226  // log ASAP, even if the handshake has not completed (or failed)
2227  const auto fd = clientConnection->fd;
2228  assert(fd >= 0);
2229  keyLogger.checkpoint(*fd_table[fd].ssl, *this);
2230 #else
2231  // TODO: Support fd_table[fd].ssl dereference in other builds.
2232 #endif
2233 
2234  return handshakeResult;
2235 }
2236 
2238 void
2240 {
2241  Assure(params.port);
2242 
2243  // NP: it is possible the port was reconfigured when the call or accept() was queued.
2244 
2245  if (params.flag != Comm::OK) {
2246  // Its possible the call was still queued when the client disconnected
2247  debugs(33, 2, params.port->listenConn << ": accept failure: " << xstrerr(params.xerrno));
2248  return;
2249  }
2250 
2251  debugs(33, 4, params.conn << ": accepted");
2252  fd_note(params.conn->fd, "client http connect");
2253  const auto xact = MasterXaction::MakePortful(params.port);
2254  xact->tcpClient = params.conn;
2255 
2256  // Socket is ready, setup the connection manager to start using it
2257  auto *srv = Http::NewServer(xact);
2258  // XXX: do not abandon the MasterXaction object
2259  AsyncJob::Start(srv); // usually async-calls readSomeData()
2260 }
2261 
2263 static bool
2265 {
2266  const auto conn = connState->clientConnection;
2267  if (Security::CreateServerSession(ctx, conn, connState->port->secure, "client https start")) {
2268  debugs(33, 5, "will negotiate TLS on " << conn);
2269  return true;
2270  }
2271 
2272  debugs(33, DBG_IMPORTANT, "ERROR: could not create TLS server context for " << conn);
2273  conn->close();
2274  return false;
2275 }
2276 
2278 static void
2279 clientNegotiateSSL(int fd, void *data)
2280 {
2281  ConnStateData *conn = (ConnStateData *)data;
2282 
2283  const auto handshakeResult = conn->acceptTls();
2284  switch (handshakeResult.category) {
2286  break;
2287 
2290  return;
2291 
2294  return;
2295 
2297  debugs(83, (handshakeResult.important ? Important(62) : 2), "ERROR: Cannot accept a TLS connection" <<
2298  Debug::Extra << "problem: " << WithExtras(handshakeResult));
2299  // TODO: No ConnStateData::tunnelOnError() on this forward-proxy code
2300  // path because we cannot know the intended connection target?
2301  conn->updateError(ERR_SECURE_ACCEPT_FAIL, handshakeResult.errorDetail);
2302  conn->clientConnection->close();
2303  return;
2304  }
2305 
2306  Security::SessionPointer session(fd_table[fd].ssl);
2307 
2308 #if USE_OPENSSL
2309  if (Security::SessionIsResumed(session)) {
2310  debugs(83, 2, "Session " << SSL_get_session(session.get()) <<
2311  " reused on FD " << fd << " (" << fd_table[fd].ipaddr <<
2312  ":" << (int)fd_table[fd].remote_port << ")");
2313  } else {
2314  if (Debug::Enabled(83, 4)) {
2315  /* Write out the SSL session details.. actually the call below, but
2316  * OpenSSL headers do strange typecasts confusing GCC.. */
2317  /* PEM_write_SSL_SESSION(DebugStream(), SSL_get_session(ssl)); */
2318 #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00908000L
2319  PEM_ASN1_write(reinterpret_cast<i2d_of_void *>(i2d_SSL_SESSION),
2320  PEM_STRING_SSL_SESSION, DebugStream(),
2321  reinterpret_cast<char *>(SSL_get_session(session.get())),
2322  nullptr, nullptr, 0, nullptr, nullptr);
2323 
2324 #elif (ALLOW_ALWAYS_SSL_SESSION_DETAIL == 1)
2325 
2326  /* When using gcc 3.3.x and OpenSSL 0.9.7x sometimes a compile error can occur here.
2327  * This is caused by an unpredictable gcc behaviour on a cast of the first argument
2328  * of PEM_ASN1_write(). For this reason this code section is disabled. To enable it,
2329  * define ALLOW_ALWAYS_SSL_SESSION_DETAIL=1.
2330  * Because there are two possible usable cast, if you get an error here, try the other
2331  * commented line. */
2332 
2333  PEM_ASN1_write((int(*)())i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2334  DebugStream(),
2335  reinterpret_cast<char *>(SSL_get_session(session.get())),
2336  nullptr, nullptr, 0, nullptr, nullptr);
2337  /* PEM_ASN1_write((int(*)(...))i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2338  DebugStream(),
2339  reinterpret_cast<char *>(SSL_get_session(session.get())),
2340  nullptr, nullptr, 0, nullptr, nullptr);
2341  */
2342 #else
2343  debugs(83, 4, "With " OPENSSL_VERSION_TEXT ", session details are available only defining ALLOW_ALWAYS_SSL_SESSION_DETAIL=1 in the source.");
2344 
2345 #endif
2346  /* Note: This does not automatically fflush the log file.. */
2347  }
2348 
2349  debugs(83, 2, "New session " << SSL_get_session(session.get()) <<
2350  " on FD " << fd << " (" << fd_table[fd].ipaddr << ":" <<
2351  fd_table[fd].remote_port << ")");
2352  }
2353 #else
2354  debugs(83, 2, "TLS session reuse not yet implemented.");
2355 #endif
2356 
2357  // Connection established. Retrieve TLS connection parameters for logging.
2359 
2360 #if USE_OPENSSL
2361  X509 *client_cert = SSL_get_peer_certificate(session.get());
2362 
2363  if (client_cert) {
2364  debugs(83, 3, "FD " << fd << " client certificate: subject: " <<
2365  Security::SubjectName(*client_cert));
2366 
2367  debugs(83, 3, "FD " << fd << " client certificate: issuer: " <<
2368  Security::IssuerName(*client_cert));
2369 
2370  X509_free(client_cert);
2371  } else {
2372  debugs(83, 5, "FD " << fd << " has no client certificate.");
2373  }
2374 #else
2375  debugs(83, 2, "Client certificate requesting not yet implemented.");
2376 #endif
2377 
2378  // If we are called, then bumped CONNECT has succeeded. Finalize it.
2379  if (auto xact = conn->pipeline.front()) {
2380  if (xact->http && xact->http->request && xact->http->request->method == Http::METHOD_CONNECT)
2381  xact->finished();
2382  // cannot proceed with encryption if requests wait for plain responses
2383  Must(conn->pipeline.empty());
2384  }
2385  /* careful: finished() above frees request, host, etc. */
2386 
2387  conn->readSomeData();
2388 }
2389 
2394 static void
2396 {
2397  assert(connState);
2398  const Comm::ConnectionPointer &details = connState->clientConnection;
2399 
2400  if (!ctx || !httpsCreate(connState, ctx))
2401  return;
2402 
2403  connState->resetReadTimeout(Config.Timeout.request);
2404 
2405  Comm::SetSelect(details->fd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
2406 }
2407 
2408 #if USE_OPENSSL
2409 
2412 static void
2414 {
2415  ConnStateData *connState = (ConnStateData *) data;
2416 
2417  // if the connection is closed or closing, just return.
2418  if (!connState->isOpen())
2419  return;
2420 
2421  if (answer.allowed()) {
2422  debugs(33, 2, "sslBump action " << Ssl::bumpMode(answer.kind) << "needed for " << connState->clientConnection);
2423  connState->sslBumpMode = static_cast<Ssl::BumpMode>(answer.kind);
2424  } else {
2425  debugs(33, 3, "sslBump not needed for " << connState->clientConnection);
2426  connState->sslBumpMode = Ssl::bumpSplice;
2427  }
2428 
2429  if (connState->sslBumpMode == Ssl::bumpTerminate) {
2430  connState->clientConnection->close();
2431  return;
2432  }
2433 
2434  if (!connState->fakeAConnectRequest("ssl-bump", connState->inBuf))
2435  connState->clientConnection->close();
2436 }
2437 #endif
2438 
2440 static void
2442 {
2443  Assure(params.port);
2444 
2445  // NP: it is possible the port was reconfigured when the call or accept() was queued.
2446 
2447  if (params.flag != Comm::OK) {
2448  // Its possible the call was still queued when the client disconnected
2449  debugs(33, 2, "httpsAccept: " << params.port->listenConn << ": accept failure: " << xstrerr(params.xerrno));
2450  return;
2451  }
2452 
2453  const auto xact = MasterXaction::MakePortful(params.port);
2454  xact->tcpClient = params.conn;
2455 
2456  debugs(33, 4, params.conn << " accepted, starting SSL negotiation.");
2457  fd_note(params.conn->fd, "client https connect");
2458 
2459  // Socket is ready, setup the connection manager to start using it
2460  auto *srv = Https::NewServer(xact);
2461  // XXX: do not abandon the MasterXaction object
2462  AsyncJob::Start(srv); // usually async-calls postHttpsAccept()
2463 }
2464 
2465 void
2467 {
2468  if (port->flags.tunnelSslBumping) {
2469 #if USE_OPENSSL
2470  debugs(33, 5, "accept transparent connection: " << clientConnection);
2471 
2472  if (!Config.accessList.ssl_bump) {
2474  return;
2475  }
2476 
2477  const auto mx = MasterXaction::MakePortful(port);
2478  mx->tcpClient = clientConnection;
2479  // Create a fake HTTP request and ALE for the ssl_bump ACL check,
2480  // using tproxy/intercept provided destination IP and port.
2481  // XXX: Merge with subsequent fakeAConnectRequest(), buildFakeRequest().
2482  // XXX: Do this earlier (e.g., in Http[s]::One::Server constructor).
2483  HttpRequest *request = new HttpRequest(mx);
2484  static char ip[MAX_IPSTRLEN];
2486  request->url.host(clientConnection->local.toStr(ip, sizeof(ip)));
2487  request->url.port(clientConnection->local.port());
2488  request->myportname = port->name;
2489  const AccessLogEntry::Pointer connectAle = new AccessLogEntry;
2490  CodeContext::Reset(connectAle);
2491  // TODO: Use these request/ALE when waiting for new bumped transactions.
2492 
2493  auto acl_checklist = ACLFilledChecklist::Make(Config.accessList.ssl_bump, request);
2494  fillChecklist(*acl_checklist);
2495  // Build a local AccessLogEntry to allow requiresAle() acls work
2496  acl_checklist->al = connectAle;
2497  acl_checklist->al->cache.start_time = current_time;
2498  acl_checklist->al->tcpClient = clientConnection;
2499  acl_checklist->al->cache.port = port;
2500  acl_checklist->al->cache.caddr = log_addr;
2501  acl_checklist->al->proxyProtocolHeader = proxyProtocolHeader_;
2502  acl_checklist->al->updateError(bareError);
2503  HTTPMSGUNLOCK(acl_checklist->al->request);
2504  acl_checklist->al->request = request;
2505  HTTPMSGLOCK(acl_checklist->al->request);
2506  Http::StreamPointer context = pipeline.front();
2507  ClientHttpRequest *http = context ? context->http : nullptr;
2508  const char *log_uri = http ? http->log_uri : nullptr;
2509  acl_checklist->syncAle(request, log_uri);
2510  ACLFilledChecklist::NonBlockingCheck(std::move(acl_checklist), httpsSslBumpAccessCheckDone, this);
2511 #else
2512  fatal("FATAL: SSL-Bump requires --with-openssl");
2513 #endif
2514  return;
2515  } else {
2516  httpsEstablish(this, port->secure.staticContext);
2517  }
2518 }
2519 
2520 #if USE_OPENSSL
2521 void
2523 {
2524  ConnStateData * state_data = (ConnStateData *)(data);
2525  state_data->sslCrtdHandleReply(reply);
2526 }
2527 
2528 void
2530 {
2531  if (!isOpen()) {
2532  debugs(33, 3, "Connection gone while waiting for ssl_crtd helper reply; helper reply:" << reply);
2533  return;
2534  }
2535 
2536  if (reply.result == Helper::BrokenHelper) {
2537  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply);
2538  } else if (!reply.other().hasContent()) {
2539  debugs(1, DBG_IMPORTANT, "\"ssl_crtd\" helper returned <NULL> reply.");
2540  } else {
2542  if (reply_message.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK) {
2543  debugs(33, 5, "Reply from ssl_crtd for " << tlsConnectHostOrIp << " is incorrect");
2544  } else {
2545  if (reply.result != Helper::Okay) {
2546  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply_message.getBody());
2547  } else {
2548  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " was successfully received from ssl_crtd");
2551  auto ssl = fd_table[clientConnection->fd].ssl.get();
2552  bool ret = Ssl::configureSSLUsingPkeyAndCertFromMemory(ssl, reply_message.getBody().c_str(), *port);
2553  if (!ret)
2554  debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
2555 
2558  } else {
2560  if (ctx && !sslBumpCertKey.isEmpty())
2562  getSslContextDone(ctx);
2563  }
2564  return;
2565  }
2566  }
2567  }
2569  getSslContextDone(nil);
2570 }
2571 
2573 {
2575 
2576  const bool connectedOk = sslServerBump && sslServerBump->connectedOk();
2577  if (connectedOk) {
2578  if (X509 *mimicCert = sslServerBump->serverCert.get())
2579  certProperties.mimicCert.resetAndLock(mimicCert);
2580 
2581  ACLFilledChecklist checklist(nullptr, sslServerBump->request.getRaw());
2582  fillChecklist(checklist);
2583 
2584  for (sslproxy_cert_adapt *ca = Config.ssl_client.cert_adapt; ca != nullptr; ca = ca->next) {
2585  // If the algorithm already set, then ignore it.
2586  if ((ca->alg == Ssl::algSetCommonName && certProperties.setCommonName) ||
2587  (ca->alg == Ssl::algSetValidAfter && certProperties.setValidAfter) ||
2588  (ca->alg == Ssl::algSetValidBefore && certProperties.setValidBefore) )
2589  continue;
2590 
2591  if (ca->aclList && checklist.fastCheck(ca->aclList).allowed()) {
2592  const char *alg = Ssl::CertAdaptAlgorithmStr[ca->alg];
2593  const char *param = ca->param;
2594 
2595  // For parameterless CN adaptation, use hostname from the
2596  // CONNECT request.
2597  if (ca->alg == Ssl::algSetCommonName) {
2598  if (!param)
2599  param = tlsConnectHostOrIp.c_str();
2600  certProperties.commonName = param;
2601  certProperties.setCommonName = true;
2602  } else if (ca->alg == Ssl::algSetValidAfter)
2603  certProperties.setValidAfter = true;
2604  else if (ca->alg == Ssl::algSetValidBefore)
2605  certProperties.setValidBefore = true;
2606 
2607  debugs(33, 5, "Matches certificate adaptation algorithm: " <<
2608  alg << " param: " << (param ? param : "-"));
2609  }
2610  }
2611 
2612  certProperties.signAlgorithm = Ssl::algSignEnd;
2613  for (sslproxy_cert_sign *sg = Config.ssl_client.cert_sign; sg != nullptr; sg = sg->next) {
2614  if (sg->aclList && checklist.fastCheck(sg->aclList).allowed()) {
2615  certProperties.signAlgorithm = (Ssl::CertSignAlgorithm)sg->alg;
2616  break;
2617  }
2618  }
2619  } else {// did not try to connect (e.g. client-first) or failed to connect
2620  // In case of an error while connecting to the secure server, use a
2621  // trusted certificate, with no mimicked fields and no adaptation
2622  // algorithms. There is nothing we can mimic, so we want to minimize the
2623  // number of warnings the user will have to see to get to the error page.
2624  // We will close the connection, so that the trust is not extended to
2625  // non-Squid content.
2626  certProperties.signAlgorithm = Ssl::algSignTrusted;
2627  }
2628 
2629  assert(certProperties.signAlgorithm != Ssl::algSignEnd);
2630 
2631  if (certProperties.signAlgorithm == Ssl::algSignUntrusted) {
2632  assert(port->secure.untrustedSigningCa.cert);
2633  certProperties.signWithX509.resetAndLock(port->secure.untrustedSigningCa.cert.get());
2634  certProperties.signWithPkey.resetAndLock(port->secure.untrustedSigningCa.pkey.get());
2635  } else {
2636  assert(port->secure.signingCa.cert.get());
2637  certProperties.signWithX509.resetAndLock(port->secure.signingCa.cert.get());
2638 
2639  if (port->secure.signingCa.pkey)
2640  certProperties.signWithPkey.resetAndLock(port->secure.signingCa.pkey.get());
2641  }
2642  signAlgorithm = certProperties.signAlgorithm;
2643 
2644  certProperties.signHash = Ssl::DefaultSignHash;
2645 }
2646 
2649 {
2650  debugs(33, 5, "Finding SSL certificate for " << cacheKey << " in cache");
2651  const auto ssl_ctx_cache = Ssl::TheGlobalContextStorage().getLocalStorage(port->s);
2652  if (const auto ctx = ssl_ctx_cache ? ssl_ctx_cache->get(cacheKey) : nullptr) {
2653  if (Ssl::verifySslCertificate(*ctx, certProperties)) {
2654  debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is valid");
2655  return *ctx;
2656  } else {
2657  debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is out of date. Delete this certificate from cache");
2658  if (ssl_ctx_cache)
2659  ssl_ctx_cache->del(cacheKey);
2660  }
2661  }
2662  return Security::ContextPointer(nullptr);
2663 }
2664 
2665 void
2667 {
2668  const auto ssl_ctx_cache = Ssl::TheGlobalContextStorage().getLocalStorage(port->s);
2669  if (!ssl_ctx_cache || !ssl_ctx_cache->add(cacheKey, ctx)) {
2670  // If it is not in storage delete after using. Else storage deleted it.
2671  fd_table[clientConnection->fd].html?amicTlsContext = ctx;
2672  }
2673 }
2674 
2675 void
2677 {
2678  if (port->secure.generateHostCertificates) {
2679  Ssl::CertificateProperties certProperties;
2680  buildSslCertGenerationParams(certProperties);
2681 
2682  // Disable caching for bumpPeekAndSplice mode
2685  Ssl::InRamCertificateDbKey(certProperties, sslBumpCertKey);
2687 
2689  if (ctx) {
2690  getSslContextDone(ctx);
2691  return;
2692  }
2693  }
2694 
2695 #if USE_SSL_CRTD
2696  try {
2697  debugs(33, 5, "Generating SSL certificate for " << certProperties.commonName << " using ssl_crtd.");
2700  request_message.composeRequest(certProperties);
2701  debugs(33, 5, "SSL crtd request: " << request_message.compose().c_str());
2702  Ssl::Helper::Submit(request_message, sslCrtdHandleReplyWrapper, this);
2703  return;
2704  } catch (const std::exception &e) {
2705  debugs(33, DBG_IMPORTANT, "ERROR: Failed to compose ssl_crtd " <<
2706  "request for " << certProperties.commonName <<
2707  " certificate: " << e.what() << "; will now block to " <<
2708  "generate that certificate.");
2709  // fall through to do blocking in-process generation.
2710  }
2711 #endif // USE_SSL_CRTD
2712 
2713  debugs(33, 5, "Generating SSL certificate for " << certProperties.commonName);
2716  auto ssl = fd_table[clientConnection->fd].ssl.get();
2717  if (!Ssl::configureSSL(ssl, certProperties, *port))
2718  debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
2719 
2722  } else {
2724  if (dynCtx && !sslBumpCertKey.isEmpty())
2726  getSslContextDone(dynCtx);
2727  }
2728  return;
2729  }
2730 
2732  getSslContextDone(nil);
2733 }
2734 
2735 void
2737 {
2738  if (port->secure.generateHostCertificates && !ctx) {
2739  debugs(33, 2, "Failed to generate TLS context for " << tlsConnectHostOrIp);
2740  }
2741 
2742  // If generated ssl context = nullptr, try to use static ssl context.
2743  if (!ctx) {
2744  if (!port->secure.staticContext) {
2745  debugs(83, DBG_IMPORTANT, "Closing " << clientConnection->remote << " as lacking TLS context");
2747  return;
2748  } else {
2749  debugs(33, 5, "Using static TLS context.");
2750  ctx = port->secure.staticContext;
2751  }
2752  }
2753 
2754  if (!httpsCreate(this, ctx))
2755  return;
2756 
2757  // bumped intercepted conns should already have Config.Timeout.request set
2758  // but forwarded connections may only have Config.Timeout.lifetime. [Re]set
2759  // to make sure the connection does not get stuck on non-SSL clients.
2761 
2762  switchedToHttps_ = true;
2763 
2764  auto ssl = fd_table[clientConnection->fd].ssl.get();
2765  BIO *b = SSL_get_rbio(ssl);
2766  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
2767  bio->setReadBufData(inBuf);
2768  inBuf.clear();
2770 }
2771 
2772 void
2774 {
2776  Must(http->request);
2777  auto &request = http->request;
2778 
2779  // Depending on receivedFirstByte_, we are at the start of either an
2780  // established CONNECT tunnel with the client or an intercepted TCP (and
2781  // presumably TLS) connection from the client. Expect TLS Client Hello.
2782  const auto insideConnectTunnel = receivedFirstByte_;
2783  debugs(33, 5, (insideConnectTunnel ? "post-CONNECT " : "raw TLS ") << clientConnection);
2784 
2785  tlsConnectHostOrIp = request->url.hostOrIp();
2786  tlsConnectPort = request->url.port();
2787  resetSslCommonName(request->url.host());
2788 
2789  // We are going to read new request
2790  flags.readMore = true;
2791 
2792  // keep version major.minor details the same.
2793  // but we are now performing the HTTPS handshake traffic
2795 
2796  // If sslServerBump is set, then we have decided to deny CONNECT
2797  // and now want to switch to SSL to send the error to the client
2798  // without even peeking at the origin server certificate.
2799  if (bumpServerMode == Ssl::bumpServerFirst && !sslServerBump) {
2800  request->flags.sslPeek = true;
2801  sslServerBump = new Ssl::ServerBump(http);
2802  } else if (bumpServerMode == Ssl::bumpPeek || bumpServerMode == Ssl::bumpStare) {
2803  request->flags.sslPeek = true;
2804  sslServerBump = new Ssl::ServerBump(http, nullptr, bumpServerMode);
2805  }
2806 
2807  // commSetConnTimeout() was called for this request before we switched.
2808  // Fix timeout to request_start_timeout
2810  // Also reset receivedFirstByte_ flag to allow this timeout work in the case we have
2811  // a bumped "connect" request on non transparent port.
2812  receivedFirstByte_ = false;
2813  // Get more data to peek at Tls
2814  parsingTlsHandshake = true;
2815 
2816  // If the protocol has changed, then reset preservingClientData_.
2817  // Otherwise, its value initially set in start() is still valid/fresh.
2818  // shouldPreserveClientData() uses parsingTlsHandshake which is reset above.
2819  if (insideConnectTunnel)
2821 
2822  readSomeData();
2823 }
2824 
2825 void
2827 {
2829 
2830  assert(!inBuf.isEmpty());
2832  fd_note(clientConnection->fd, "Parsing TLS handshake");
2833 
2834  // stops being nil if we fail to parse the handshake
2835  ErrorDetail::Pointer parseErrorDetails;
2836 
2837  try {
2838  if (!tlsParser.parseHello(inBuf)) {
2839  // need more data to finish parsing
2840  readSomeData();
2841  return;
2842  }
2843  }
2844  catch (const TextException &ex) {
2845  debugs(83, 2, "exception: " << ex);
2846  parseErrorDetails = new ExceptionErrorDetail(ex.id());
2847  }
2848  catch (...) {
2849  debugs(83, 2, "exception: " << CurrentException);
2850  static const auto d = MakeNamedErrorDetail("TLS_ACCEPT_PARSE");
2851  parseErrorDetails = d;
2852  }
2853 
2854  parsingTlsHandshake = false;
2855 
2856  // client data may be needed for splicing and for
2857  // tunneling unsupportedProtocol after an error
2859 
2860  // Even if the parser failed, each TLS detail should either be set
2861  // correctly or still be "unknown"; copying unknown detail is a no-op.
2864  if (details && !details->serverName.isEmpty()) {
2865  resetSslCommonName(details->serverName.c_str());
2866  tlsClientSni_ = details->serverName;
2867  }
2868 
2869  // We should disable read/write handlers
2871 
2872  if (parseErrorDetails) {
2873  Http::StreamPointer context = pipeline.front();
2874  Must(context && context->http);
2875  HttpRequest::Pointer request = context->http->request;
2876  debugs(83, 5, "Got something other than TLS Client Hello. Cannot SslBump.");
2877  updateError(ERR_PROTOCOL_UNKNOWN, parseErrorDetails);
2880  return;
2881  }
2882 
2883  if (!sslServerBump || sslServerBump->act.step1 == Ssl::bumpClientFirst) { // Either means client-first.
2885  return;
2886  } else if (sslServerBump->act.step1 == Ssl::bumpServerFirst) {
2887  debugs(83, 5, "server-first skips step2; start forwarding the request");
2889  Http::StreamPointer context = pipeline.front();
2890  ClientHttpRequest *http = context ? context->http : nullptr;
2891  // will call httpsPeeked() with certificate and connection, eventually
2893  } else {
2896  }
2897 }
2898 
2899 static void
2901 {
2902  ConnStateData *connState = (ConnStateData *) data;
2903 
2904  // if the connection is closed or closing, just return.
2905  if (!connState->isOpen())
2906  return;
2907 
2908  debugs(33, 5, "Answer: " << answer << " kind:" << answer.kind);
2909  assert(connState->serverBump());
2910  Ssl::BumpMode bumpAction;
2911  if (answer.allowed()) {
2912  bumpAction = (Ssl::BumpMode)answer.kind;
2913  } else
2914  bumpAction = Ssl::bumpSplice;
2915 
2916  connState->serverBump()->act.step2 = bumpAction;
2917  connState->sslBumpMode = bumpAction;
2918  Http::StreamPointer context = connState->pipeline.front();
2919  if (ClientHttpRequest *http = (context ? context->http : nullptr))
2920  http->al->ssl.bumpMode = bumpAction;
2921 
2922  if (bumpAction == Ssl::bumpTerminate) {
2923  connState->clientConnection->close();
2924  } else if (bumpAction != Ssl::bumpSplice) {
2925  connState->startPeekAndSplice();
2926  } else if (!connState->splice())
2927  connState->clientConnection->close();
2928 }
2929 
2930 bool
2932 {
2933  // normally we can splice here, because we just got client hello message
2934 
2935  // fde::ssl/tls_read_method() probably reads from our own inBuf. If so, then
2936  // we should not lose any raw bytes when switching to raw I/O here.
2937  if (fd_table[clientConnection->fd].ssl.get())
2938  fd_table[clientConnection->fd].useDefaultIo();
2939 
2940  // XXX: assuming that there was an HTTP/1.1 CONNECT to begin with...
2941  // reset the current protocol to HTTP/1.1 (was "HTTPS" for the bumping process)
2943  assert(!pipeline.empty());
2944  Http::StreamPointer context = pipeline.front();
2945  Must(context);
2946  Must(context->http);
2947  ClientHttpRequest *http = context->http;
2948  HttpRequest::Pointer request = http->request;
2949  context->finished();
2950  if (transparent()) {
2951  // For transparent connections, make a new fake CONNECT request, now
2952  // with SNI as target. doCallout() checks, adaptations may need that.
2953  return fakeAConnectRequest("splice", preservedClientData);
2954  } else {
2955  // For non transparent connections make a new tunneled CONNECT, which
2956  // also sets the HttpRequest::flags::forceTunnel flag to avoid
2957  // respond with "Connection Established" to the client.
2958  // This fake CONNECT request required to allow use of SNI in
2959  // doCallout() checks and adaptations.
2960  return initiateTunneledRequest(request, "splice", preservedClientData);
2961  }
2962 }
2963 
2964 void
2966 {
2967  // This is the Step2 of the SSL bumping
2969  Http::StreamPointer context = pipeline.front();
2970  ClientHttpRequest *http = context ? context->http : nullptr;
2971 
2974  // Run a accessList check to check if want to splice or continue bumping
2975 
2977  acl_checklist->banAction(Acl::Answer(ACCESS_ALLOWED, Ssl::bumpNone));
2978  acl_checklist->banAction(Acl::Answer(ACCESS_ALLOWED, Ssl::bumpClientFirst));
2979  acl_checklist->banAction(Acl::Answer(ACCESS_ALLOWED, Ssl::bumpServerFirst));
2980  fillChecklist(*acl_checklist);
2982  return;
2983  }
2984 
2985  // will call httpsPeeked() with certificate and connection, eventually
2986  Security::ContextPointer unConfiguredCTX(Ssl::createSSLContext(port->secure.signingCa.cert, port->secure.signingCa.pkey, port->secure));
2987  fd_table[clientConnection->fd].html?amicTlsContext = unConfiguredCTX;
2988 
2989  if (!httpsCreate(this, unConfiguredCTX))
2990  return;
2991 
2992  switchedToHttps_ = true;
2993 
2994  auto ssl = fd_table[clientConnection->fd].ssl.get();
2995  BIO *b = SSL_get_rbio(ssl);
2996  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
2997  bio->setReadBufData(inBuf);
2998  bio->hold(true);
2999 
3000  // We have successfully parsed client Hello, but our TLS handshake parser is
3001  // forgiving. Now we use a TLS library to parse the same bytes, so that we
3002  // can honor on_unsupported_protocol if needed. If there are no errors, we
3003  // expect Security::Accept() to ask us to write (our) TLS server Hello. We
3004  // also allow an ioWantRead result in case some fancy TLS extension that
3005  // Squid does not yet understand requires reading post-Hello client bytes.
3006  const auto handshakeResult = acceptTls();
3007  if (!handshakeResult.wantsIo())
3008  return handleSslBumpHandshakeError(handshakeResult);
3009 
3010  // We need to reset inBuf here, to be used by incoming requests in the case
3011  // of SSL bump
3012  inBuf.clear();
3013 
3014  debugs(83, 5, "Peek and splice at step2 done. Start forwarding the request!!! ");
3017 }
3018 
3020 void
3022 {
3023  auto errCategory = ERR_NONE;
3024 
3025  switch (handshakeResult.category) {
3027  static const auto d = MakeNamedErrorDetail("TLS_ACCEPT_UNEXPECTED_SUCCESS");
3028  updateError(errCategory = ERR_GATEWAY_FAILURE, d);
3029  break;
3030  }
3031 
3033  static const auto d = MakeNamedErrorDetail("TLS_ACCEPT_UNEXPECTED_READ");
3034  updateError(errCategory = ERR_GATEWAY_FAILURE, d);
3035  break;
3036  }
3037 
3039  static const auto d = MakeNamedErrorDetail("TLS_ACCEPT_UNEXPECTED_WRITE");
3040  updateError(errCategory = ERR_GATEWAY_FAILURE, d);
3041  break;
3042  }
3043 
3045  debugs(83, (handshakeResult.important ? DBG_IMPORTANT : 2), "ERROR: Cannot SslBump-accept a TLS connection" <<
3046  Debug::Extra << "problem: " << WithExtras(handshakeResult));
3047  updateError(errCategory = ERR_SECURE_ACCEPT_FAIL, handshakeResult.errorDetail);
3048  break;
3049 
3050  }
3051 
3052  if (!tunnelOnError(errCategory))
3054 }
3055 
3056 void
3058 {
3059  auto ssl = fd_table[clientConnection->fd].ssl.get();
3060  BIO *b = SSL_get_rbio(ssl);
3061  assert(b);
3062  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
3063 
3064  debugs(33, 5, "PeekAndSplice mode, proceed with client negotiation. Current state:" << SSL_state_string_long(ssl));
3065  bio->hold(false);
3066 
3068  switchedToHttps_ = true;
3069 }
3070 
3071 void
3073 {
3074  Must(sslServerBump != nullptr);
3075  Must(sslServerBump->request == pic.request);
3076  Must(pipeline.empty() || pipeline.front()->http == nullptr || pipeline.front()->http->request == pic.request.getRaw());
3077 
3078  if (Comm::IsConnOpen(pic.connection)) {
3080  debugs(33, 5, "bumped HTTPS server: " << tlsConnectHostOrIp);
3081  } else
3082  debugs(33, 5, "Error while bumping: " << tlsConnectHostOrIp);
3083 
3085 }
3086 
3087 #endif /* USE_OPENSSL */
3088 
3089 bool
3090 ConnStateData::initiateTunneledRequest(HttpRequest::Pointer const &cause, const char *reason, const SBuf &payload)
3091 {
3092  // fake a CONNECT request to force connState to tunnel
3093  SBuf connectHost;
3094  AnyP::Port connectPort;
3095 
3096  if (pinning.serverConnection != nullptr) {
3097  static char ip[MAX_IPSTRLEN];
3098  connectHost = pinning.serverConnection->remote.toStr(ip, sizeof(ip));
3099  if (const auto remotePort = pinning.serverConnection->remote.port())
3100  connectPort = remotePort;
3101  } else if (cause) {
3102  connectHost = cause->url.hostOrIp();
3103  connectPort = cause->url.port();
3104 #if USE_OPENSSL
3105  } else if (!tlsConnectHostOrIp.isEmpty()) {
3106  connectHost = tlsConnectHostOrIp;
3107  connectPort = tlsConnectPort;
3108 #endif
3109  } else if (transparent()) {
3110  static char ip[MAX_IPSTRLEN];
3111  connectHost = clientConnection->local.toStr(ip, sizeof(ip));
3112  connectPort = clientConnection->local.port();
3113  }
3114 
3115  if (!connectPort) {
3116  // Typical cases are malformed HTTP requests on http_port and malformed
3117  // TLS handshakes on non-bumping https_port. TODO: Discover these
3118  // problems earlier so that they can be classified/detailed better.
3119  debugs(33, 2, "Not able to compute URL, abort request tunneling for " << reason);
3120  // TODO: throw when NonBlockingCheck() callbacks gain job protections
3121  static const auto d = MakeNamedErrorDetail("TUNNEL_TARGET");
3123  return false;
3124  }
3125 
3126  debugs(33, 2, "Request tunneling for " << reason);
3127  const auto http = buildFakeRequest(connectHost, *connectPort, payload);
3128  HttpRequest::Pointer request = http->request;
3129  request->flags.forceTunnel = true;
3130  http->calloutContext = new ClientRequestContext(http);
3131  http->doCallouts();
3132  clientProcessRequestFinished(this, request);
3133  return true;
3134 }
3135 
3136 bool
3137 ConnStateData::fakeAConnectRequest(const char *reason, const SBuf &payload)
3138 {
3139  debugs(33, 2, "fake a CONNECT request to force connState to tunnel for " << reason);
3140 
3141  SBuf connectHost;
3142  assert(transparent());
3143  const unsigned short connectPort = clientConnection->local.port();
3144 
3145 #if USE_OPENSSL
3146  if (!tlsClientSni_.isEmpty())
3147  connectHost.assign(tlsClientSni_);
3148  else
3149 #endif
3150  {
3151  static char ip[MAX_IPSTRLEN];
3152  clientConnection->local.toHostStr(ip, sizeof(ip));
3153  connectHost.assign(ip);
3154  }
3155 
3156  ClientHttpRequest *http = buildFakeRequest(connectHost, connectPort, payload);
3157 
3158  http->calloutContext = new ClientRequestContext(http);
3159  HttpRequest::Pointer request = http->request;
3160  http->doCallouts();
3161  clientProcessRequestFinished(this, request);
3162  return true;
3163 }
3164 
3166 ConnStateData::buildFakeRequest(SBuf &useHost, const AnyP::KnownPort usePort, const SBuf &payload)
3167 {
3168  ClientHttpRequest *http = new ClientHttpRequest(this);
3169  Http::Stream *stream = new Http::Stream(clientConnection, http);
3170 
3171  StoreIOBuffer tempBuffer;
3172  tempBuffer.data = stream->reqbuf;
3173  tempBuffer.length = HTTP_REQBUF_SZ;
3174 
3175  ClientStreamData newServer = new clientReplyContext(http);
3176  ClientStreamData newClient = stream;
3179  clientSocketDetach, newClient, tempBuffer);
3180 
3181  stream->flags.parsed_ok = 1; // Do we need it?
3182  stream->mayUseConnection(true);
3183  extendLifetime();
3184  stream->registerWithConn();
3185 
3186  const auto mx = MasterXaction::MakePortful(port);
3187  mx->tcpClient = clientConnection;
3188  // Setup Http::Request object. Maybe should be replaced by a call to (modified)
3189  // clientProcessRequest
3190  HttpRequest::Pointer request = new HttpRequest(mx);
3191  request->url.setScheme(AnyP::PROTO_AUTHORITY_FORM, nullptr);
3192  request->method = Http::METHOD_CONNECT;
3193  request->url.host(useHost.c_str());
3194  request->url.port(usePort);
3195 
3196  http->uri = SBufToCstring(request->effectiveRequestUri());
3197  http->initRequest(request.getRaw());
3198 
3199  request->manager(this, http->al);
3200 
3201  request->header.putStr(Http::HOST, useHost.c_str());
3202 
3203  request->sources |= ((switchedToHttps() || port->transport.protocol == AnyP::PROTO_HTTPS) ? Http::Message::srcHttps : Http::Message::srcHttp);
3204 #if USE_AUTH
3205  if (getAuth())
3206  request->auth_user_request = getAuth();
3207 #endif
3208 
3209  inBuf = payload;
3210  flags.readMore = false;
3211 
3212  return http;
3213 }
3214 
3216 static bool
3218 {
3219  if (!Comm::IsConnOpen(c)) {
3220  Must(NHttpSockets > 0); // we tried to open some
3221  --NHttpSockets; // there will be fewer sockets than planned
3222  Must(HttpSockets[NHttpSockets] < 0); // no extra fds received
3223 
3224  if (!NHttpSockets) // we could not open any listen sockets at all
3225  fatalf("Unable to open %s",FdNote(portType));
3226 
3227  return false;
3228  }
3229  return true;
3230 }
3231 
3233 static bool
3235 {
3236  bool found = false;
3237  for (int i = 0; i < NHttpSockets && !found; ++i) {
3238  if ((found = HttpSockets[i] < 0))
3239  HttpSockets[i] = conn->fd;
3240  }
3241  return found;
3242 }
3243 
3244 static void
3246 {
3247  const auto savedContext = CodeContext::Current();
3248  for (AnyP::PortCfgPointer s = HttpPortList; s != nullptr; s = s->next) {
3249  CodeContext::Reset(s);
3250  const SBuf &scheme = AnyP::UriScheme(s->transport.protocol).image();
3251 
3253  debugs(1, DBG_IMPORTANT, "WARNING: You have too many '" << scheme << "_port' lines." <<
3254  Debug::Extra << "The limit is " << MAXTCPLISTENPORTS << " HTTP ports.");
3255  continue;
3256  }
3257 
3258 #if USE_OPENSSL
3259  if (s->flags.tunnelSslBumping) {
3260  if (!Config.accessList.ssl_bump) {
3261  debugs(33, DBG_IMPORTANT, "WARNING: No ssl_bump configured. Disabling ssl-bump on " << scheme << "_port " << s->s);
3262  s->flags.tunnelSslBumping = false;
3263  }
3264  if (!s->secure.staticContext && !s->secure.generateHostCertificates) {
3265  debugs(1, DBG_IMPORTANT, "Will not bump SSL at " << scheme << "_port " << s->s << " due to TLS initialization failure.");
3266  s->flags.tunnelSslBumping = false;
3267  if (s->transport.protocol == AnyP::PROTO_HTTP)
3268  s->secure.encryptTransport = false;
3269  }
3270  if (s->flags.tunnelSslBumping) {
3271  // Create ssl_ctx cache for this port.
3272  Ssl::TheGlobalContextStorage().addLocalStorage(s->s, s->secure.html?amicCertMemCacheSize);
3273  }
3274  }
3275 #endif
3276 
3277  if (s->secure.encryptTransport && !s->secure.staticContext) {
3278  debugs(1, DBG_CRITICAL, "ERROR: Ignoring " << scheme << "_port " << s->s << " due to TLS context initialization failure.");
3279  continue;
3280  }
3281 
3282  const auto protocol = s->transport.protocol;
3283  assert(protocol == AnyP::PROTO_HTTP || protocol == AnyP::PROTO_HTTPS);
3284  const auto isHttps = protocol == AnyP::PROTO_HTTPS;
3285  using AcceptCall = CommCbFunPtrCallT<CommAcceptCbPtrFun>;
3286  RefCount<AcceptCall> subCall = commCbCall(5, 5, isHttps ? "httpsAccept" : "httpAccept",
3289  }
3290  CodeContext::Reset(savedContext);
3291 }
3292 
3293 void
3295 {
3296  // Fill out a Comm::Connection which IPC will open as a listener for us
3297  port->listenConn = new Comm::Connection;
3298  port->listenConn->local = port->s;
3299  port->listenConn->flags =
3301  (port->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) |
3302  (port->flags.natIntercept ? COMM_INTERCEPTION : 0) |
3303  (port->workerQueues ? COMM_REUSEPORT : 0);
3304 
3305  // route new connections to subCall
3306  typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
3308  const auto listenCall =
3309  asyncCall(33, 2, "clientListenerConnectionOpened",
3311  port, fdNote, sub));
3312  AsyncCallback<Ipc::StartListeningAnswer> callback(listenCall);
3313  Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, port->listenConn, fdNote, callback);
3314 
3316  HttpSockets[NHttpSockets] = -1;
3317  ++NHttpSockets;
3318 }
3319 
3321 static void
3323 {
3324  Must(s != nullptr);
3325 
3326  if (!OpenedHttpSocket(s->listenConn, portTypeNote))
3327  return;
3328 
3329  Must(Comm::IsConnOpen(s->listenConn));
3330 
3331  // TCP: setup a job to handle accept() with subscribed handler
3332  AsyncJob::Start(new Comm::TcpAcceptor(s, FdNote(portTypeNote), sub));
3333 
3334  debugs(1, Important(13), "Accepting " <<
3335  (s->flags.natIntercept ? "NAT intercepted " : "") <<
3336  (s->flags.tproxyIntercept ? "TPROXY intercepted " : "") <<
3337  (s->flags.tunnelSslBumping ? "SSL bumped " : "") <<
3338  (s->flags.accelSurrogate ? "reverse-proxy " : "")
3339  << FdNote(portTypeNote) << " connections at "
3340  << s->listenConn);
3341 
3342  Must(AddOpenedHttpSocket(s->listenConn)); // otherwise, we have received a fd we did not ask for
3343 
3344 #if HAVE_LIBSYSTEMD
3345  // When the very first port opens, tell systemd we are able to serve connections.
3346  // Subsequent sd_notify() calls, including calls during reconfiguration,
3347  // do nothing because the first call parameter is 1.
3348  // XXX: Send the notification only after opening all configured ports.
3349  if (opt_foreground || opt_no_daemon) {
3350  const auto result = sd_notify(1, "READY=1");
3351  if (result < 0) {
3352  debugs(1, DBG_IMPORTANT, "WARNING: failed to send start-up notification to systemd" <<
3353  Debug::Extra << "sd_notify() error: " << xstrerr(-result));
3354  }
3355  }
3356 #endif
3357 }
3358 
3359 void
3361 {
3364 
3365  if (NHttpSockets < 1)
3366  fatal("No HTTP, HTTPS, or FTP ports configured");
3367 }
3368 
3369 void
3371 {
3372  const auto savedContext = CodeContext::Current();
3373  for (AnyP::PortCfgPointer s = HttpPortList; s != nullptr; s = s->next) {
3374  CodeContext::Reset(s);
3375  if (s->listenConn != nullptr) {
3376  debugs(1, Important(14), "Closing HTTP(S) port " << s->listenConn->local);
3377  s->listenConn->close();
3378  s->listenConn = nullptr;
3379  }
3380  }
3381  CodeContext::Reset(savedContext);
3382 
3384 
3385  // TODO see if we can drop HttpSockets array entirely */
3386  for (int i = 0; i < NHttpSockets; ++i) {
3387  HttpSockets[i] = -1;
3388  }
3389 
3390  NHttpSockets = 0;
3391 }
3392 
3393 int
3395 {
3396  SBuf vary(request->vary_headers);
3397  const auto &reply = entry->mem().freshestReply();
3398  auto has_vary = reply.header.has(Http::HdrType::VARY);
3399 #if X_ACCELERATOR_VARY
3400 
3401  has_vary |=
3402  reply.header.has(Http::HdrType::HDR_X_ACCELERATOR_VARY);
3403 #endif
3404 
3405  if (!has_vary || entry->mem_obj->vary_headers.isEmpty()) {
3406  if (!vary.isEmpty()) {
3407  /* Oops... something odd is going on here.. */
3408  debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary object on second attempt, '" <<
3409  entry->mem_obj->urlXXX() << "' '" << vary << "'");
3410  request->vary_headers.clear();
3411  return VARY_CANCEL;
3412  }
3413 
3414  if (!has_vary) {
3415  /* This is not a varying object */
3416  return VARY_NONE;
3417  }
3418 
3419  /* virtual "vary" object found. Calculate the vary key and
3420  * continue the search
3421  */
3422  vary = httpMakeVaryMark(request, &reply);
3423 
3424  if (!vary.isEmpty()) {
3425  request->vary_headers = vary;
3426  return VARY_OTHER;
3427  } else {
3428  /* Ouch.. we cannot handle this kind of variance */
3429  /* XXX This cannot really happen, but just to be complete */
3430  return VARY_CANCEL;
3431  }
3432  } else {
3433  if (vary.isEmpty()) {
3434  vary = httpMakeVaryMark(request, &reply);
3435 
3436  if (!vary.isEmpty())
3437  request->vary_headers = vary;
3438  }
3439 
3440  if (vary.isEmpty()) {
3441  /* Ouch.. we cannot handle this kind of variance */
3442  /* XXX This cannot really happen, but just to be complete */
3443  return VARY_CANCEL;
3444  } else if (vary.cmp(entry->mem_obj->vary_headers) == 0) {
3445  return VARY_MATCH;
3446  } else {
3447  /* Oops.. we have already been here and still haven't
3448  * found the requested variant. Bail out
3449  */
3450  debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary match on second attempt, '" <<
3451  entry->mem_obj->urlXXX() << "' '" << vary << "'");
3452  return VARY_CANCEL;
3453  }
3454  }
3455 }
3456 
3459 {
3460  auto checklist = ACLFilledChecklist::Make(acl, nullptr);
3461  clientAclChecklistFill(*checklist, http);
3462  return checklist;
3463 }
3464 
3465 void
3467 {
3468  assert(http);
3469 
3470  if (!checklist.request && http->request)
3471  checklist.setRequest(http->request);
3472 
3473  if (!checklist.al && http->al) {
3474  checklist.updateAle(http->al);
3475  checklist.syncAle(http->request, http->log_uri);
3476  }
3477 
3478  if (const auto conn = http->getConn())
3479  checklist.setConn(conn); // may already be set
3480 }
3481 
3482 void
3484 {
3485  const auto context = pipeline.front();
3486  if (const auto http = context ? context->http : nullptr)
3487  return clientAclChecklistFill(checklist, http); // calls checklist.setConn()
3488 
3489  // no requests, but we always have connection-level details
3490  // TODO: ACL checks should not require a mutable ConnStateData. Adjust the
3491  // code that accidentally violates that principle to remove this const_cast!
3492  checklist.setConn(const_cast<ConnStateData*>(this));
3493 
3494  // Set other checklist fields inside our fillConnectionLevelDetails() rather
3495  // than here because clientAclChecklistFill() code path calls that method
3496  // (via ACLFilledChecklist::setConn()) rather than calling us directly.
3497 }
3498 
3499 void
3501 {
3502  assert(checklist.conn() == this);
3504 
3505  if (!checklist.request) { // preserve (better) addresses supplied by setRequest()
3506  checklist.src_addr = clientConnection->remote;
3507  checklist.my_addr = clientConnection->local; // TODO: or port->s?
3508  }
3509 
3510 #if USE_OPENSSL
3511  if (!checklist.sslErrors && sslServerBump)
3512  checklist.sslErrors = sslServerBump->sslErrors();
3513 #endif
3514 }
3515 
3516 bool
3518 {
3520 }
3521 
3524 {
3525  bodyPipe = new BodyPipe(this);
3526  if (size >= 0)
3528  else
3530  return bodyPipe;
3531 }
3532 
3533 int64_t
3535 {
3536  if (!bodyPipe)
3537  return 0; // request without a body or read/produced all body bytes
3538 
3539  if (!bodyPipe->bodySizeKnown())
3540  return -1; // probably need to read more, but we cannot be sure
3541 
3542  const int64_t needToProduce = bodyPipe->unproducedSize();
3543  const int64_t haveAvailable = static_cast<int64_t>(inBuf.length());
3544 
3545  if (needToProduce <= haveAvailable)
3546  return 0; // we have read what we need (but are waiting for pipe space)
3547 
3548  return needToProduce - haveAvailable;
3549 }
3550 
3551 void
3553 {
3554  debugs(33, 4, "receiving error (" << clientConnection << "): " << error <<
3555  "; old sending error: " <<
3556  (stoppedSending() ? stoppedSending_ : "none"));
3557 
3558  if (const char *oldError = stoppedReceiving()) {
3559  debugs(33, 3, "already stopped receiving: " << oldError);
3560  return; // nothing has changed as far as this connection is concerned
3561  }
3562 
3564 
3565  if (const char *sendError = stoppedSending()) {
3566  debugs(33, 3, "closing because also stopped sending: " << sendError);
3568  }
3569 }
3570 
3571 void
3573 {
3574  if (bodyPipe != nullptr) {
3575  debugs(33, 4, "no consumer for virgin body " << bodyPipe->status());
3577  }
3578 }
3579 
3581 void
3583 {
3584  Must(bodyPipe != nullptr);
3585  debugs(33, 5, "start dechunking" << bodyPipe->status());
3586  assert(!bodyParser);
3588 }
3589 
3591 void
3593 {
3594  debugs(33, 5, "finish dechunking: " << withSuccess);
3595 
3596  if (bodyPipe != nullptr) {
3597  debugs(33, 7, "dechunked tail: " << bodyPipe->status());
3598  BodyPipe::Pointer myPipe = bodyPipe;
3599  stopProducingFor(bodyPipe, withSuccess); // sets bodyPipe->bodySize()
3600  Must(!bodyPipe); // we rely on it being nil after we are done with body
3601  if (withSuccess) {
3602  Must(myPipe->bodySizeKnown());
3603  Http::StreamPointer context = pipeline.front();
3604  if (context != nullptr && context->http && context->http->request)
3605  context->http->request->setContentLength(myPipe->bodySize());
3606  }
3607  }
3608 
3609  delete bodyParser;
3610  bodyParser = nullptr;
3611 }
3612 
3613 // XXX: this is an HTTP/1-only operation
3614 void
3616 {
3617  if (const auto context = pipeline.front()) {
3618  if (context->http)
3619  context->http->al->reply = msg.reply;
3620  }
3621 
3622  if (!isOpen()) {
3623  debugs(33, 3, "ignoring 1xx due to earlier closure");
3624  return;
3625  }
3626 
3627  // HTTP/1 1xx status messages are only valid when there is a transaction to trigger them
3628  if (!pipeline.empty()) {
3629  HttpReply::Pointer rep(msg.reply);
3630  Must(rep);
3631  // remember the callback
3633 
3636 
3637  if (!writeControlMsgAndCall(rep.getRaw(), call)) {
3638  // but still inform the caller (so it may resume its operation)
3640  }
3641  return;
3642  }
3643 
3644  debugs(33, 3, " closing due to missing context for 1xx");
3646 }
3647 
3648 void
3650 {
3652 
3653  if (Http::StreamPointer deferredRequest = pipeline.front()) {
3654  debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded after control msg wrote");
3655  ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
3656  }
3657 }
3658 
3660 void
3662 {
3663  // FwdState might repin a failed connection sooner than this close
3664  // callback is called for the failed connection.
3665  assert(pinning.serverConnection == io.conn);
3666  pinning.closeHandler = nullptr; // Comm unregisters handlers before calling
3667  const bool sawZeroReply = pinning.zeroReply; // reset when unpinning
3668  pinning.serverConnection->noteClosure();
3669  unpinConnection(false);
3670 
3671  if (sawZeroReply && clientConnection != nullptr) {
3672  debugs(33, 3, "Closing client connection on pinned zero reply.");
3674  }
3675 
3676 }
3677 
3678 void
3680 {
3681  pinConnection(pinServer, *request);
3682 }
3683 
3684 void
3686 {
3687  Must(pic.connection);
3688  Must(pic.request);
3689  pinConnection(pic.connection, *pic.request);
3690 
3691  // monitor pinned server connection for remote-end closures.
3693 
3694  if (pipeline.empty())
3695  kick(); // in case parseRequests() was blocked by a busy pic.connection
3696 }
3697 
3699 void
3701 {
3702  if (Comm::IsConnOpen(pinning.serverConnection) &&
3703  pinning.serverConnection->fd == pinServer->fd) {
3704  debugs(33, 3, "already pinned" << pinServer);
3705  return;
3706  }
3707 
3708  unpinConnection(true); // closes pinned connection, if any, and resets fields
3709 
3710  pinning.serverConnection = pinServer;
3711 
3712  debugs(33, 3, pinning.serverConnection);
3713 
3714  Must(pinning.serverConnection != nullptr);
3715 
3716  const char *pinnedHost = "[unknown]";
3717  pinning.host = xstrdup(request.url.host());
3718  pinning.port = request.url.port();
3719  pinnedHost = pinning.host;
3720  pinning.pinned = true;
3721  pinning.auth = request.flags.connectionAuth;
3722  char stmp[MAX_IPSTRLEN];
3723  char desc[FD_DESC_SZ];
3724  const auto peer = pinning.peer();
3725  snprintf(desc, FD_DESC_SZ, "%s pinned connection for %s (%d)",
3726  (pinning.auth || !peer) ? pinnedHost : peer->name,
3728  clientConnection->fd);
3729  fd_note(pinning.serverConnection->fd, desc);
3730 
3732  pinning.closeHandler = JobCallback(33, 5,
3734  // remember the pinned connection so that cb does not unpin a fresher one
3735  typedef CommCloseCbParams Params;
3736  Params &params = GetCommParams<Params>(pinning.closeHandler);
3737  params.conn = pinning.serverConnection;
3738  comm_add_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
3739 }
3740 
3743 void
3745 {
3746  if (pinning.readHandler != nullptr)
3747  return; // already monitoring
3748 
3750  pinning.readHandler = JobCallback(33, 3,
3752  Comm::Read(pinning.serverConnection, pinning.readHandler);
3753 }
3754 
3755 void
3757 {
3758  if (pinning.readHandler != nullptr) {
3759  Comm::ReadCancel(pinning.serverConnection->fd, pinning.readHandler);
3760  pinning.readHandler = nullptr;
3761  }
3762 }
3763 
3764 #if USE_OPENSSL
3765 bool
3767 {
3768  // A ready-for-reading connection means that the TLS server either closed
3769  // the connection, sent us some unexpected HTTP data, or started TLS
3770  // renegotiations. We should close the connection except for the last case.
3771 
3772  Must(pinning.serverConnection != nullptr);
3773  auto ssl = fd_table[pinning.serverConnection->fd].ssl.get();
3774  if (!ssl)
3775  return false;
3776 
3777  char buf[1];
3778  const int readResult = SSL_read(ssl, buf, sizeof(buf));
3779 
3780  if (readResult > 0 || SSL_pending(ssl) > 0) {
3781  debugs(83, 2, pinning.serverConnection << " TLS application data read");
3782  return false;
3783  }
3784 
3785  switch(const int error = SSL_get_error(ssl, readResult)) {
3786  case SSL_ERROR_WANT_WRITE:
3787  debugs(83, DBG_IMPORTANT, pinning.serverConnection << " TLS SSL_ERROR_WANT_WRITE request for idle pinned connection");
3788  [[fallthrough]]; // to restart monitoring, for now
3789 
3790  case SSL_ERROR_NONE:
3791  case SSL_ERROR_WANT_READ:
3793  return true;
3794 
3795  default:
3796  debugs(83, 2, pinning.serverConnection << " TLS error: " << error);
3797  return false;
3798  }
3799 
3800  // not reached
3801  return true;
3802 }
3803 #endif
3804 
3807 void
3809 {
3810  pinning.readHandler = nullptr; // Comm unregisters handlers before calling
3811 
3812  if (io.flag == Comm::ERR_CLOSING)
3813  return; // close handler will clean up
3814 
3815  Must(pinning.serverConnection == io.conn);
3816 
3817 #if USE_OPENSSL
3819  return;
3820 #endif
3821 
3822  const bool clientIsIdle = pipeline.empty();
3823 
3824  debugs(33, 3, "idle pinned " << pinning.serverConnection << " read " <<
3825  io.size << (clientIsIdle ? " with idle client" : ""));
3826 
3827  pinning.serverConnection->close();
3828 
3829  // If we are still sending data to the client, do not close now. When we are done sending,
3830  // ConnStateData::kick() checks pinning.serverConnection and will close.
3831  // However, if we are idle, then we must close to inform the idle client and minimize races.
3832  if (clientIsIdle && clientConnection != nullptr)
3834 }
3835 
3838 {
3839  debugs(33, 7, pinning.serverConnection);
3840  Must(request);
3841 
3842  const auto pinningError = [&](const err_type type) {
3843  unpinConnection(true);
3844  HttpRequestPointer requestPointer = request;
3845  return ErrorState::NewForwarding(type, requestPointer, ale);
3846  };
3847 
3848  if (!Comm::IsConnOpen(pinning.serverConnection))
3849  throw pinningError(ERR_ZERO_SIZE_OBJECT);
3850 
3851  if (pinning.auth && pinning.host && strcasecmp(pinning.host, request->url.host()) != 0)
3852  throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_CONFLICT_HOST
3853 
3854  if (pinning.port != request->url.port())
3855  throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_CONFLICT_HOST
3856 
3857  if (pinning.serverConnection->toGoneCachePeer())
3858  throw pinningError(ERR_ZERO_SIZE_OBJECT);
3859 
3860  if (pinning.peerAccessDenied)
3861  throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_FORWARDING_DENIED
3862 
3864  return pinning.serverConnection;
3865 }
3866 
3869 {
3870  if (const auto connManager = request ? request->pinnedConnection() : nullptr)
3871  return connManager->borrowPinnedConnection(request, ale);
3872 
3873  // ERR_CANNOT_FORWARD is somewhat misleading here; we can still forward, but
3874  // there is no point since the client connection is now gone
3875  HttpRequestPointer requestPointer = request;
3876  throw ErrorState::NewForwarding(ERR_CANNOT_FORWARD, requestPointer, ale);
3877 }
3878 
3879 void
3881 {
3882  debugs(33, 3, pinning.serverConnection);
3883 
3884  if (Comm::IsConnOpen(pinning.serverConnection)) {
3885  if (pinning.closeHandler != nullptr) {
3886  comm_remove_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
3887  pinning.closeHandler = nullptr;
3888  }
3889 
3891 
3892  // close the server side socket if requested
3893  if (andClose)
3894  pinning.serverConnection->close();
3895  pinning.serverConnection = nullptr;
3896  }
3897 
3898  safe_free(pinning.host);
3899 
3900  pinning.zeroReply = false;
3901  pinning.peerAccessDenied = false;
3902 
3903  /* NOTE: pinning.pinned should be kept. This combined with fd == -1 at the end of a request indicates that the host
3904  * connection has gone away */
3905 }
3906 
3907 void
3909 {
3910  auto error = rawError; // (cheap) copy so that we can detail
3911  // We detail even ERR_NONE: There should be no transactions left, and
3912  // detailed ERR_NONE will be unused. Otherwise, this detail helps in triage.
3913  if (error.details.empty()) {
3914  static const auto d = MakeNamedErrorDetail("WITH_CLIENT");
3915  error.details.push_back(d);
3916  }
3917 
3918  debugs(33, 3, pipeline.count() << '/' << pipeline.nrequests << " after " << error);
3919 
3920  if (pipeline.empty()) {
3921  bareError.update(error); // XXX: bareLogTagsErrors
3922  } else {
3923  // We terminate the current CONNECT/PUT/etc. context below, logging any
3924  // error details, but that context may leave unparsed bytes behind.
3925  // Consume them to stop checkLogging() from logging them again later.
3926  const auto intputToConsume =
3927 #if USE_OPENSSL
3928  parsingTlsHandshake ? "TLS handshake" : // more specific than CONNECT
3929 #endif
3930  bodyPipe ? "HTTP request body" :
3931  pipeline.back()->mayUseConnection() ? "HTTP CONNECT" :
3932  nullptr;
3933 
3934  while (const auto context = pipeline.front()) {
3935  context->noteIoError(error, lte);
3936  context->finished(); // cleanup and self-deregister
3937  assert(context != pipeline.front());
3938  }
3939 
3940  if (intputToConsume && !inBuf.isEmpty()) {
3941  debugs(83, 5, "forgetting client " << intputToConsume << " bytes: " << inBuf.length());
3942  inBuf.clear();
3943  }
3944  }
3945 
3947 }
3948 
3950 void
3952 {
3953  // to simplify our logic, we assume that terminateAll() has been called
3954  assert(pipeline.empty());
3955 
3956  // do not log connections that closed after a transaction (it is normal)
3957  // TODO: access_log needs ACLs to match received-no-bytes connections
3958  if (pipeline.nrequests && inBuf.isEmpty())
3959  return;
3960 
3961  /* Create a temporary ClientHttpRequest object. Its destructor will log. */
3962  ClientHttpRequest http(this);
3963  http.req_sz = inBuf.length();
3964  // XXX: Or we died while waiting for the pinned connection to become idle.
3965  http.setErrorUri("error:transaction-end-before-headers");
3966  http.updateError(bareError);
3967 }
3968 
3969 bool
3971 {
3972  // PROXY protocol bytes are meant for us and, hence, cannot be tunneled
3974  return false;
3975 
3976  // If our decision here is negative, configuration changes are irrelevant.
3977  // Otherwise, clientTunnelOnError() rechecks configuration before tunneling.
3979  return false;
3980 
3981  // TODO: Figure out whether/how we can support FTP tunneling.
3982  if (port->transport.protocol == AnyP::PROTO_FTP)
3983  return false;
3984 
3985 #if USE_OPENSSL
3986  if (parsingTlsHandshake)
3987  return true;
3988 
3989  // the 1st HTTP request on a bumped connection
3991  return true;
3992 #endif
3993 
3994  // the 1st HTTP(S) request on a connection to an intercepting port
3995  if (!pipeline.nrequests && transparent())
3996  return true;
3997 
3998  return false;
3999 }
4000 
4003 {
4004  if (!theNotes)
4005  theNotes = new NotePairs;
4006  return theNotes;
4007 }
4008 
4009 std::ostream &
4010 operator <<(std::ostream &os, const ConnStateData::PinnedIdleContext &pic)
4011 {
4012  return os << pic.connection << ", request=" << pic.request;
4013 }
4014 
4015 std::ostream &
4017 {
4018  return os << scc.conn_ << ", srv_bytes=" << scc.preReadServerBytes.length();
4019 }
4020 
const MemBuf & buf() const
Definition: BodyPipe.h:137
void Read(const Comm::ConnectionPointer &conn, AsyncCall::Pointer &callback)
Definition: Read.cc:40
#define FD_DESC_SZ
Definition: defines.h:32
bool shouldCloseOnEof() const override
whether to stop serving our client after reading EOF on its connection
bool shouldPreserveClientData() const
void fatal(const char *message)
Definition: fatal.cc:28
void whenClientIpKnown()
const char * xstrerr(int error)
Definition: xstrerror.cc:83
Definition: parse.c:104
@ bumpPeek
Definition: support.h:132
#define FQDN_LOOKUP_IF_MISS
Definition: defines.h:34
@ LOG_TCP_IMS_HIT
Definition: LogTags.h:50
AnyP::ProtocolVersion transferProtocol
Definition: Server.h:107
@ ERR_SECURE_CONNECT_FAIL
Definition: forward.h:31
char * buf
Definition: MemBuf.h:134
void checkpoint(const Connection &, const Acl::ChecklistFiller &)
Definition: KeyLogger.h:50
virtual void clientPinnedConnectionClosed(const CommCloseCbParams &io)
Our close handler called by Comm when the pinned connection is closed.
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:942
void clientAfterReadingRequests()
SBuf tlsClientSni_
TLS client delivered SNI value. Empty string if none has been received.
Definition: client_side.h:490
int half_closed_clients
Definition: SquidConfig.h:289
void pinConnection(const Comm::ConnectionPointer &pinServerConn, const HttpRequest &request)
Forward future client requests using the given server connection.
virtual void processParsedRequest(Http::StreamPointer &)=0
start processing a freshly parsed request
void fillConnectionLevelDetails(ACLFilledChecklist &) const
void IOACB(const CommAcceptCbParams &params)
Definition: CommCalls.h:31
@ hoReply
Definition: HttpHeader.h:37
const char * findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end)
SourceLocationId id() const
same-location exceptions have the same ID
Definition: TextException.h:40
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:71
unsigned int major
major version number
void fillChecklist(ACLFilledChecklist &) const override
configure the given checklist (to reflect the current transaction state)
#define Here()
source code location of the caller
Definition: Here.h:15
GlobalContextStorage & TheGlobalContextStorage()
Global cache for store all SSL server certificates.
Ipc::StartListeningAnswer & answer() override
callback results setter
Definition: client_side.cc:171
@ scMethodNotAllowed
Definition: StatusCode.h:50
void pinBusyConnection(const Comm::ConnectionPointer &pinServerConn, const HttpRequest::Pointer &request)
void clientProcessRequestFinished(ConnStateData *conn, const HttpRequest::Pointer &request)
void InRamCertificateDbKey(const Ssl::CertificateProperties &certProperties, SBuf &key)
Definition: support.cc:1486
AnyP::ProtocolVersion http_ver
Definition: Message.h:72
@ HDR_X_ACCELERATOR_VARY
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
#define DBG_CRITICAL
Definition: Stream.h:37
SBuf & assign(const SBuf &S)
Definition: SBuf.cc:83
@ CLOSEST_PARENT_MISS
Definition: hier_code.h:21
AnyP::Uri url
the request URI
Definition: HttpRequest.h:115
void stopPinnedConnectionMonitoring()
The caller assumes responsibility for connection closure detection.
CertSignAlgorithm
Definition: gadgets.h:169
void lifetimeTimeout(const CommTimeoutCbParams &params)
@ VARY_NONE
Definition: enums.h:188
BodyPipe::Pointer body_pipe
optional pipeline to receive message body
Definition: Message.h:97
ClientHttpRequest * http
std::shared_ptr< SSL_CTX > ContextPointer
Definition: Context.h:29
Comm::ConnectionPointer connection
to-server connection to be pinned
Definition: client_side.h:187
void clientConnectionsClose()
struct SquidConfig::@102 ssl_client
const_reverse_iterator rbegin() const
Definition: SBuf.h:595
const char * stoppedSending() const
true if we stopped sending the response
Definition: client_side.h:161
@ ERR_GATEWAY_FAILURE
Definition: forward.h:67
Ip::Address src_addr
@ scBadRequest
Definition: StatusCode.h:45
Security::CertPointer mimicCert
Certificate to mimic.
Definition: gadgets.h:235
const char * getStr(Http::HdrType id) const
Definition: HttpHeader.cc:1163
@ scNone
Definition: StatusCode.h:21
Security::CertPointer signWithX509
Certificate to sign the generated request.
Definition: gadgets.h:236
void getSslContextStart()
Start to create dynamic Security::ContextPointer for host or uses static port SSL context.
SBuf inBuf
read I/O buffer for the client connection
Definition: Server.h:113
void setAuth(const Auth::UserRequest::Pointer &aur, const char *cause)
Definition: client_side.cc:495
struct ClientHttpRequest::Redirect redirect
mb_size_t size
Definition: MemBuf.h:135
void retrieveParsedInfo(Security::TlsDetails::Pointer const &details)
Extract information from parser stored in TlsDetails object.
AnyP::PortCfgPointer HttpPortList
list of Squid http(s)_port configured
Definition: PortCfg.cc:22
void fd_note(int fd, const char *s)
Definition: fd.cc:211
HttpHeader header
Definition: Message.h:74
void resetSslCommonName(const char *name)
Definition: client_side.h:293
AsyncCall::Pointer cbControlMsgSent
Call to schedule when the control msg has been sent.
static void clientUpdateHierCounters(HierarchyLogEntry *)
Definition: client_side.cc:264
ByteCounter hit_kbytes_out
Definition: StatCounters.h:47
uint64_t unproducedSize() const
Definition: BodyPipe.cc:179
Security::ContextPointer GetFrom(Security::SessionPointer &s)
Helper function to retrieve a (non-locked) ContextPointer from a SessionPointer.
Definition: Session.h:109
@ PARENT_HIT
Definition: hier_code.h:16
acl_access * on_unsupported_protocol
Definition: SquidConfig.h:400
bool urlCheckRequest(const HttpRequest *r)
Definition: Uri.cc:959
bool isEmpty() const
Definition: SBuf.h:435
void initRequest(HttpRequest *)
MemObject * mem_obj
Definition: Store.h:220
StatHist nearHitSvcTime
Definition: StatCounters.h:50
void registerWithConn()
register this stream with the Server
Definition: Stream.cc:53
RequestFlags flags
Definition: HttpRequest.h:141
int64_t maxRequestBodySize
Definition: SquidConfig.h:135
bool proxyProtocolError(const char *reason)
int varyEvaluateMatch(StoreEntry *entry, HttpRequest *request)
void sslCrtdHandleReply(const Helper::Reply &reply)
Process response from ssl_crtd.
const EVP_MD * signHash
The signing hash to use.
Definition: gadgets.h:243
std::unique_ptr< ACLFilledChecklist > MakingPointer
bool empty() const
whether there are none or any requests currently pipelined
Definition: Pipeline.h:56
bool isTcpHit() const
determine if the log tag code indicates a cache HIT
Definition: LogTags.cc:110
NotePairs::Pointer theNotes
Definition: client_side.h:505
ErrorDetailPointer errorDetail
ioError case details (or nil)
Definition: Io.h:43
struct node * next
Definition: parse.c:105
AnyP::PortCfgPointer port
the configuration listening port this call relates to (may be nil)
Definition: CommCalls.h:100
int log_mime_hdrs
Definition: SquidConfig.h:286
ConnStateData * getConn() const
char * skipLeadingSpace(char *aString)
Callback cbSuccess
called after successfully writing the 1xx message
void setBodySize(uint64_t aSize)
Definition: BodyPipe.cc:147
void extendLifetime()
(re)sets client_lifetime timeout
Definition: client_side.cc:583
acl_access * cert_error
Definition: SquidConfig.h:512
MemObject & mem()
Definition: Store.h:47
Security::ContextPointer createSSLContext(Security::CertPointer &x509, Security::PrivateKeyPointer &pkey, Security::ServerOptions &)
Create SSL context and apply ssl certificate and private key to it.
Definition: support.cc:1021
void doPeekAndSpliceStep()
Comm::ConnectionPointer borrowPinnedConnection(HttpRequest *, const AccessLogEntryPointer &)
ConnStateData-specific part of BorrowPinnedConnection()
void clientStartListeningOn(AnyP::PortCfgPointer &port, const RefCount< CommCbFunPtrCallT< CommAcceptCbPtrFun > > &subCall, const Ipc::FdNoteId fdNote)
accept requests to a given port and inform subCall about them
dials clientListenerConnectionOpened call
Definition: client_side.cc:153
char reqbuf[HTTP_REQBUF_SZ]
Definition: Stream.h:137
CSS clientReplyStatus
Definition: client_side.h:530
void error(char *format,...)
static void Submit(CrtdMessage const &message, HLPCB *callback, void *data)
Submit crtd message to external crtd server.
Definition: helper.cc:128
unsigned int minor
minor version number
Ip::Address log_addr
Definition: client_side.h:136
SBuf hostOrIp() const
Definition: Uri.cc:139
void setWriteLimiter(const int aWriteSpeedLimit, const double anInitialBurst, const double aHighWatermark)
Definition: comm.cc:1343
void readNextRequest()
Traffic parsing.
Definition: client_side.cc:858
bool connectionAuth
Definition: RequestFlags.h:85
bool hasContent() const
Definition: MemBuf.h:54
void sendControlMsg(HttpControlMsg) override
called to send the 1xx message and notify the Source
std::vector< ClientDelayPool::Pointer > pools
#define SQUIDSTRINGPRINT(s)
Definition: SquidString.h:23
void hold(bool h)
Prevents or allow writing on socket.
Definition: bio.h:86
@ ERR_UNSUP_REQ
Definition: forward.h:44
void httpRequestFree(void *data)
Definition: client_side.cc:476
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:93
struct Ssl::ServerBump::@106 act
bumping actions at various bumping steps
Definition: SBuf.h:93
BumpMode
Definition: support.h:132
a smart AsyncCall pointer for delivery of future results
struct timeval stop
Definition: PingData.h:37
Ip::Address client_netmask
Definition: SquidConfig.h:242
BodyPipe::Pointer bodyPipe
set when we are reading request body
Definition: client_side.h:431
bool needsMoreData() const
Definition: Parser.h:66
static void httpsSslBumpStep2AccessCheckDone(Acl::Answer answer, void *data)
@ ERR_REQUEST_PARSE_TIMEOUT
Definition: forward.h:82
void SBufToCstring(char *d, const SBuf &s)
Definition: SBuf.h:756
bool splice()
Splice a bumped client connection on peek-and-splice mode.
void setErrorUri(const char *)
const char * stoppedReceiving_
the reason why we no longer read the request or nil
Definition: client_side.h:501
#define xstrdup
void enableAutoConsumption()
start or continue consuming when producing without consumer
Definition: BodyPipe.cc:316
int64_t mayNeedToReadMoreBody() const
@ bumpTerminate
Definition: support.h:132
struct ClientHttpRequest::Flags flags
void clientdbUpdate(const Ip::Address &addr, const LogTags &ltype, AnyP::ProtocolType p, size_t size)
Definition: client_db.cc:138
struct StatCounters::@109 icp
Definition: Server.h:31
int clientdbEstablished(const Ip::Address &addr, int delta)
Definition: client_db.cc:182
void noteBodyConsumerAborted(BodyPipe::Pointer) override=0
@ LOG_TCP_CLIENT_REFRESH_MISS
Definition: LogTags.h:49
int fd
FD which the call was about. Set by the async call creator.
Definition: CommCalls.h:85
time_t request_start_timeout
Definition: SquidConfig.h:125
Auth::UserRequest::Pointer auth_user_request
Definition: HttpRequest.h:127
Security::KeyLogger keyLogger
managers logging of the being-accepted TLS connection secrets
Definition: client_side.h:384
@ METHOD_PRI
Definition: MethodType.h:89
struct StatCounters::@107 client_http
struct ClientHttpRequest::Out out
C * getRaw() const
Definition: RefCount.h:89
Security::CertErrors * sslErrors() const
SSL [certificate validation] errors.
Definition: ServerBump.cc:66
virtual void dial(AsyncCall &)
Definition: client_side.cc:168
struct timeval start_time
The time the master transaction started.
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:270
ACLFilledChecklist::MakingPointer clientAclChecklistCreate(const acl_access *acl, ClientHttpRequest *http)
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
int dnsWait
sum of DNS lookup delays in milliseconds, for dt
Definition: HttpRequest.h:159
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:27
Http1::TeChunkedParser * bodyParser
parses HTTP/1.1 chunked request body
Definition: client_side.h:108
@ OK
Definition: Flag.h:16
const char * sslGetUserEmail(SSL *ssl)
Definition: support.cc:981
void add(const Http::StreamPointer &)
register a new request context to the pipeline
Definition: Pipeline.cc:20
std::vector< HttpHdrRangeSpec * >::iterator iterator
void accessLogLog(const AccessLogEntryPointer &, ACLChecklist *)
Definition: access_log.cc:136
a summary a TLS I/O operation outcome
Definition: Io.h:19
void StopListening()
reject new connections to any configured ftp_port
Definition: FtpServer.cc:287
void HTTPMSGUNLOCK(M *&a)
Definition: Message.h:150
bool commIsHalfClosed(int fd)
Definition: comm.h:104
char * toUrl(char *buf, unsigned int len) const
Definition: Address.cc:894
@ DISABLE_PMTU_ALWAYS
Definition: enums.h:226
@ ERR_NONE
Definition: forward.h:15
@ CLOSEST_PARENT
Definition: hier_code.h:22
void handleSslBumpHandshakeError(const Security::IoResult &)
process a problematic Security::Accept() result on the SslBump code path
StatusCode
Definition: StatusCode.h:20
err_type
Definition: forward.h:14
#define SQUIDSTRINGPH
Definition: SquidString.h:22
bool multipartRangeRequest() const
Definition: HttpRequest.cc:433
SBuf sslBumpCertKey
Key to use to store/retrieve generated certificate.
Definition: client_side.h:491
const char * FdNote(int fdNodeId)
converts FdNoteId into a string
Definition: FdNotes.cc:16
Notes notes
note
Definition: SquidConfig.h:471
void StartListening()
accept connections on all configured ftp_ports
Definition: FtpServer.cc:265
@ ERR_CLOSING
Definition: Flag.h:24
void * BIO_get_data(BIO *table)
Definition: openssl.h:62
Ssl::BumpStep step
The SSL bumping step.
Definition: ServerBump.h:63
static void Start(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *, const AccessLogEntryPointer &alp)
Initiates request forwarding to a peer or origin server.
Definition: FwdState.cc:338
@ LOG_TCP_HIT
Definition: LogTags.h:42
static void sslCrtdHandleReplyWrapper(void *data, const Helper::Reply &reply)
Callback function. It is called when squid receive message from ssl_crtd.
int xerrno
The last errno to occur. non-zero if flag is Comm::COMM_ERROR.
Definition: CommCalls.h:83
String extacl_user
Definition: HttpRequest.h:176
CbcPointer< Security::CertErrors > sslErrors
SBuf SubjectName(Certificate &)
The SubjectName field of the given certificate (if found) or an empty SBuf.
Definition: Certificate.cc:68
void startDechunkingRequest()
initialize dechunking state
static void clientListenerConnectionOpened(AnyP::PortCfgPointer &s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub)
process clientHttpConnectionsOpen result
ProtocolType protocol
which protocol this version is for
@ LOG_TCP_MISS
Definition: LogTags.h:43
static int port
Definition: ldap_backend.cc:70
Error error
the first transaction problem encountered (or falsy)
Definition: HttpRequest.h:161
RefCount< AsyncCallT< Dialer > > asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition: AsyncCall.h:156
Pipeline pipeline
set of requests waiting to be serviced
Definition: Server.h:118
void clear()
Definition: SBuf.cc:175
SBuf httpMakeVaryMark(HttpRequest *request, HttpReply const *reply)
Definition: http.cc:589
#define COMM_NONBLOCKING
Definition: Connection.h:46
void checkForInternalAccess()
Checks whether the current request is internal and adjusts it accordingly.
bool ResolveClientAddressesAsap
whether to do reverse DNS lookups for source IPs of accepted connections
Definition: fqdncache.cc:30
void syncAle(HttpRequest *adaptedRequest, const char *logUri) const override
assigns uninitialized adapted_request and url ALE components
StoreEntry * entry
Definition: ServerBump.h:54
ConnStateData * NewServer(const MasterXactionPointer &xact)
create a new HTTP connection handler; never returns NULL
Definition: Http1Server.cc:392
static const CharacterSet ALPHA
Definition: CharacterSet.h:76
int tvSubMsec(struct timeval t1, struct timeval t2)
Definition: gadgets.cc:51
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition: Address.cc:812
Security::IoResult acceptTls()
int opt_no_daemon
acl_access * stats_collection
Definition: SquidConfig.h:369
@ METHOD_OPTIONS
Definition: MethodType.h:31
void startPinnedConnectionMonitoring()
void finishDechunkingRequest(bool withSuccess)
put parsed content into input buffer and clean up
void stopReceiving(const char *error)
note request receiving error and close as soon as we write the response
static bool Enabled(const int section, const int level)
whether debugging the given section and the given level produces output
Definition: Stream.h:75
SBuf & chop(size_type pos, size_type n=npos)
Definition: SBuf.cc:530
void clientStreamDetach(clientStreamNode *thisObject, ClientHttpRequest *http)
int HttpSockets[MAXTCPLISTENPORTS]
Definition: PortCfg.cc:26
HttpHdrRangeIter range_iter
size_t headers_sz
Response header bytes written to the client connection.
bool chunked() const
Definition: HttpHeader.h:169
a transaction problem
Definition: Error.h:27
bool readMore
needs comm_read (for this request or new requests)
Definition: client_side.h:139
void(* Handler)(AnyP::PortCfgPointer &portCfg, const Ipc::FdNoteId note, const Subscription::Pointer &sub)
Definition: client_side.cc:158
String myportname
Definition: HttpRequest.h:172
Http::Stream * parseHttpRequest(const Http1::RequestParserPointer &)
const char * CertAdaptAlgorithmStr[]
Definition: gadgets.cc:239
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition: forward.h:25
static void Reset()
forgets the current context, setting it to nil/unknown
Definition: CodeContext.cc:77
HttpRequest::Pointer request
faked, minimal request; required by Client API
Definition: ServerBump.h:53
void parseRequests()
#define COMM_INTERCEPTION
Definition: Connection.h:51
void ReadCancel(int fd, AsyncCall::Pointer &callback)
Cancel the read pending on FD. No action if none pending.
Definition: Read.cc:219
@ VARY_OTHER
Definition: enums.h:190
size_type rfind(char c, size_type endPos=npos) const
Definition: SBuf.cc:692
bool persistent() const
Definition: Message.cc:236
bool bodySizeKnown() const
Definition: BodyPipe.h:109
@ SIBLING_HIT
Definition: hier_code.h:15
MemBuf & buf
Definition: BodyPipe.h:74
ConnStateData * conn() const
The client connection manager.
#define COMM_TRANSPARENT
Definition: Connection.h:50
void postHttpsAccept()
the second part of old httpsAccept, waiting for future HttpsServer home
struct SquidConfig::@88 Addrs
Ssl::ServerBump * sslServerBump
HTTPS server cert. fetching state for bump-ssl-server-first.
Definition: client_side.h:494
bool multipartRangeRequest() const
Definition: client_side.cc:697
bool SessionIsResumed(const Security::SessionPointer &)
whether the session is a resumed one
Definition: Session.cc:213
StartListening() result.
acl_access * proxyProtocol
acceptable PROXY protocol clients
Definition: SquidConfig.h:395
bool mayUseConnection() const
Definition: Stream.h:143
const char * stoppedSending_
the reason why we no longer write the response or nil
Definition: client_side.h:499
void connStateClosed(const CommCloseCbParams &io)
Definition: client_side.cc:484
@ ERR_REQUEST_START_TIMEOUT
Definition: forward.h:81
virtual Http::Stream * parseOneRequest()=0
unsigned int toHostStr(char *buf, const unsigned int len) const
Definition: Address.cc:862
void applyClientMask(const Address &mask)
Definition: Address.cc:125
void StartListening(int sock_type, int proto, const Comm::ConnectionPointer &listenConn, FdNoteId, StartListeningCallback &)
virtual void doneWithControlMsg()
void retrieveNegotiatedInfo(const Security::SessionPointer &)
Extract negotiation information from TLS object.
@ ICP_INVALID
Definition: icp_opcode.h:15
static MakingPointer Make(const acl_access *a, HttpRequest *r)
Ssl::CertSignAlgorithm signAlgorithm
The signing algorithm to use.
Definition: client_side.h:495
unsigned short initial
@ bumpServerFirst
Definition: support.h:132
bool needProxyProtocolHeader_
whether PROXY protocol header is still expected
Definition: client_side.h:467
mb_size_t contentSize() const
available data size
Definition: MemBuf.h:47
static const std::string code_new_certificate
String code for "new_certificate" messages.
Definition: crtd_message.h:76
void clearRequest()
resets the current request and log_uri to nil
uint64_t bodySize() const
Definition: BodyPipe.cc:161
StatHist nearMissSvcTime
Definition: StatCounters.h:49
int size
Definition: ModDevPoll.cc:70
Comm::ConnectionPointer tcpClient
the client TCP connection which originated this transaction
Definition: MasterXaction.h:66
struct timeval current_time
the current UNIX time in timeval {seconds, microseconds} format
Definition: gadgets.cc:18
const MemBuf & other() const
Definition: Reply.h:42
parameters for the async notePinnedConnectionBecameIdle() call
Definition: client_side.h:182
const char * fqdncache_gethostbyaddr(const Ip::Address &addr, int flags)
Definition: fqdncache.cc:481
void append(const char *c, int sz) override
Definition: MemBuf.cc:209
#define NULL
Definition: types.h:145
AnyP::Port tlsConnectPort
The TLS server port number as passed in the CONNECT request.
Definition: client_side.h:486
static void httpsAccept(const CommAcceptCbParams &params)
const char * rawContent() const
Definition: SBuf.cc:509
@ algSignTrusted
Definition: gadgets.h:169
SBuf consume(size_type n=npos)
Definition: SBuf.cc:481
@ ERR_PROTOCOL_UNKNOWN
Definition: forward.h:73
iterator end()
virtual void handleReply(HttpReply *header, StoreIOBuffer receivedData)=0
Ssl::BumpMode sslBumpMode
ssl_bump decision (Ssl::bumpEnd if n/a).
Definition: client_side.h:304
ICP probing of cache_peers during peer selection.
Definition: PingData.h:25
#define SQUIDSBUFPRINT(s)
Definition: SBuf.h:32
void mustStop(const char *aReason)
Definition: AsyncJob.cc:85
bundles HTTP 1xx reply and the "successfully forwarded" callback
time_t timeLeft(const time_t idleTimeout) const
Definition: Connection.cc:149
SBuf vary_headers
Definition: MemObject.h:221
sslproxy_cert_adapt * cert_adapt
Definition: SquidConfig.h:514
const EVP_MD * DefaultSignHash
Definition: support.cc:44
void updateError(const Error &)
if necessary, stores new error information (if any)
Definition: client_side.cc:629
void clientSocketRecipient(clientStreamNode *node, ClientHttpRequest *http, HttpReply *rep, StoreIOBuffer receivedData)
Definition: client_side.cc:801
@ scNotImplemented
Definition: StatusCode.h:74
static void httpsSslBumpAccessCheckDone(Acl::Answer answer, void *data)
@ ERR_SECURE_ACCEPT_FAIL
Definition: forward.h:80
Http::StreamPointer front() const
get the first request context in the pipeline
Definition: Pipeline.cc:28
LocalContextStorage * getLocalStorage(Ip::Address const &address)
Return the local storage for the given listening address/port.
uint64_t producedSize() const
Definition: BodyPipe.h:112
Category category
primary outcome classification
Definition: Io.h:45
bool parsingTlsHandshake
Definition: client_side.h:479
void append(char const *buf, int len)
Definition: String.cc:131
Subscription::Pointer sub
The handler to be subscribed for this connection listener.
Definition: client_side.cc:181
Helper::ResultCode result
The helper response 'result' field.
Definition: Reply.h:59
uint16_t KnownPort
validated/supported port number; these values are never zero
Definition: UriScheme.h:23
size_t count() const
how many requests are currently pipelined
Definition: Pipeline.h:53
const Acl::Answer & fastCheck()
Definition: Checklist.cc:298
@ algSignEnd
Definition: gadgets.h:169
@ LOG_TAG_NONE
Definition: LogTags.h:41
@ srcHttp
http_port or HTTP server
Definition: Message.h:39
std::string compose() const
ConnStateData * NewServer(const MasterXactionPointer &xact)
create a new HTTPS connection handler; never returns NULL
Definition: Http1Server.cc:398
@ DISABLE_PMTU_OFF
Definition: enums.h:225
unsigned short port() const
Definition: Address.cc:798
Definition: MemBuf.h:23
ConnStateData * pinnedConnection()
Definition: HttpRequest.cc:724
HttpRequest::Pointer request
void setReplyToStoreEntry(StoreEntry *e, const char *reason)
replaces current response store entry with the given one
struct SquidConfig::@94 accessList
clientStreamNode * getClientReplyContext() const
Definition: Stream.cc:511
Ip::Address local
Definition: Connection.h:149
static char * prepareAcceleratedURL(ConnStateData *conn, const Http1::RequestParserPointer &hp)
static const CharacterSet HEXDIG
Definition: CharacterSet.h:88
int64_t contentLen() const
Definition: Store.h:254
void configureUnconfiguredSslContext(Security::ContextPointer &, Ssl::CertSignAlgorithm signAlgorithm, AnyP::PortCfg &)
Definition: support.cc:1091
CSR clientGetMoreData
Definition: client_side.h:529
void clean()
Definition: MemBuf.cc:110
StatHist hitSvcTime
Definition: StatCounters.h:51
static void httpsEstablish(ConnStateData *connState, const Security::ContextPointer &ctx)
void start() override
called by AsyncStart; do not call directly
bool concurrentRequestQueueFilled() const
acl_access * ssl_bump
Definition: SquidConfig.h:388
@ FIRST_PARENT_MISS
Definition: hier_code.h:20
bool initiateTunneledRequest(HttpRequest::Pointer const &cause, const char *reason, const SBuf &payload)
generates and sends to tunnel.cc a fake request with a given payload
static void NonBlockingCheck(MakingPointer &&p, ACLCB *cb, void *data)
void afterClientWrite(size_t) override
processing to sync state after a Comm::Write()
Definition: client_side.cc:984
void httpsPeeked(PinnedIdleContext pic)
called by FwdState when it is done bumping the server
bool preservingClientData_
whether preservedClientData is valid and should be kept up to date
Definition: client_side.h:434
@ METHOD_CONNECT
Definition: MethodType.h:29
int xsetsockopt(int socketFd, int level, int option, const void *value, socklen_t valueLength)
POSIX setsockopt(2) equivalent.
Definition: socket.h:122
void resetReadTimeout(time_t timeout)
(re)sets timeout for receiving more bytes from the client
Definition: client_side.cc:575
FdNoteId
We cannot send char* FD notes to other processes. Pass int IDs and convert.
Definition: FdNotes.h:20
void stopSending(const char *error)
note response sending error and close as soon as we read the request
Definition: client_side.cc:960
Adaptation::Icap::History::Pointer icapHistory() const
Returns possibly nil history, creating it if icap logging is enabled.
Definition: HttpRequest.cc:388
Comm::ConnectionPointer conn
Definition: CommCalls.h:80
int64_t getInt64(Http::HdrType id) const
Definition: HttpHeader.cc:1133
bool handleIdleClientPinnedTlsRead()
std::optional< Host > parsedHost() const
Definition: Uri.cc:150
#define safe_free(x)
Definition: xalloc.h:73
@ LOG_TCP_REFRESH_UNMODIFIED
Definition: LogTags.h:44
@ srcFtp
ftp_port or FTP server
Definition: Message.h:40
virtual int pipelinePrefetchMax() const
returning N allows a pipeline of 1+N requests (see pipeline_prefetch)
Ip::Address remote
Definition: Connection.h:152
SBuf tlsConnectHostOrIp
The TLS server host name appears in CONNECT request or the server ip address for the intercepted requ...
Definition: client_side.h:485
const char * visible_appname_string
NotePairs::Pointer notes()
@ scRequestHeaderFieldsTooLarge
Definition: StatusCode.h:71
TlsDetails::Pointer details
TLS handshake meta info. Never nil.
Definition: Handshake.h:77
ClientHttpRequest * http
Definition: Stream.h:135
void parseTlsHandshake()
Http::StreamPointer back() const
get the last request context in the pipeline
Definition: Pipeline.cc:40
void count(double val)
Definition: StatHist.cc:55
CommCbFunPtrCallT< Dialer > * commCbCall(int debugSection, int debugLevel, const char *callName, const Dialer &dialer)
Definition: CommCalls.h:312
Http::Stream * abortRequestParsing(const char *const errUri)
stop parsing the request and create context for relaying error info
Definition: client_side.cc:999
void clientOpenListenSockets(void)
void comm_reset_close(const Comm::ConnectionPointer &conn)
Definition: comm.cc:787
@ ERR_ZERO_SIZE_OBJECT
Definition: forward.h:46
#define assert(EX)
Definition: assert.h:17
#define COMM_REUSEPORT
Definition: Connection.h:52
@ Okay
Definition: ResultCode.h:18
@ scUriTooLong
Definition: StatusCode.h:59
~ConnStateData() override
Definition: client_side.cc:648
bool parseHello(const SBuf &data)
Definition: Handshake.cc:641
@ algSetValidAfter
Definition: gadgets.h:207
StatHist missSvcTime
Definition: StatCounters.h:48
@ scContentTooLarge
Definition: StatusCode.h:58
bool transparent() const
void swanSong() override
Definition: client_side.cc:592
void setPayloadBuffer(MemBuf *parsedContent)
set the buffer to be used to store decoded chunk data
SSL Connection
Definition: Session.h:49
SBuf image() const
Definition: UriScheme.h:57
bool setValidBefore
Do not mimic "Not Valid Before" field.
Definition: gadgets.h:239
class AccessLogEntry::CacheDetails cache
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
HierarchyLogEntry hier
Definition: HttpRequest.h:157
SBuf IssuerName(Certificate &)
The Issuer field of the given certificate (if found) or an empty SBuf.
Definition: Certificate.cc:28
Security::ContextPointer GenerateSslContextUsingPkeyAndCertFromMemory(const char *data, Security::ServerOptions &, bool trusted)
Definition: support.cc:1038
HttpReply::Pointer reply
the 1xx message being forwarded
void changeAcl(const acl_access *)
change the current ACL list
Definition: Checklist.cc:187
bool switchedToHttps() const
Definition: client_side.h:284
void HTTPMSGLOCK(Http::Message *a)
Definition: Message.h:161
std::ostream & CurrentException(std::ostream &os)
prints active (i.e., thrown but not yet handled) exception
Comm::Flag flag
comm layer result status.
Definition: CommCalls.h:82
const SBuf & remaining() const
the remaining unprocessed section of buffer
Definition: Parser.h:98
struct timeval start
Definition: PingData.h:35
BodyPipe::Pointer expectRequestBody(int64_t size)
void readSomeData()
maybe grow the inBuf and schedule Comm::Read()
Definition: Server.cc:101
void buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties)
@ scServiceUnavailable
Definition: StatusCode.h:76
SBuf vary_headers
The variant second-stage cache key. Generated from Vary header pattern for this request.
Definition: HttpRequest.h:168
FILE * DebugStream()
Definition: debug.cc:355
#define COMM_SELECT_READ
Definition: defines.h:24
@ algSetCommonName
Definition: gadgets.h:207
Security::PrivateKeyPointer signWithPkey
The key of the signing certificate.
Definition: gadgets.h:237
#define Assure(condition)
Definition: Assure.h:35
#define JobCallback(dbgSection, dbgLevel, Dialer, job, method)
Convenience macro to create a Dialer-based job callback.
Definition: AsyncJobCalls.h:70
HttpHdrRange * range
Definition: HttpRequest.h:143
static const CharacterSet DIGIT
Definition: CharacterSet.h:84
static ClientDelayPools * Instance()
void packInto(Packable *p, bool mask_sensitive_info=false) const
Definition: HttpHeader.cc:539
void port(const Port p)
reset authority port subcomponent
Definition: Uri.h:90
@ fdnHttpSocket
Definition: FdNotes.h:20
const char * c_str()
Definition: SBuf.cc:516
Security::ContextPointer GenerateSslContext(CertificateProperties const &, Security::ServerOptions &, bool trusted)
Definition: support.cc:1052
Http::StatusCode checkEntityFraming() const
Definition: HttpRequest.cc:646
static char * prepareTransparentURL(ConnStateData *conn, const Http1::RequestParserPointer &hp)
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:419
size_t maxRequestHeaderSize
Definition: SquidConfig.h:134
bool CreateServerSession(const Security::ContextPointer &, const Comm::ConnectionPointer &, Security::PeerOptions &, const char *squidCtx)
Definition: Session.cc:194
ClientInfo * clientdbGetInfo(const Ip::Address &addr)
Definition: client_db.cc:119
void add(const Http::StreamPointer &context)
registers a newly created stream
static void clientNegotiateSSL(int fd, void *data)
int opt_foreground
bool proxyProtocolValidateClient()
void quitAfterError(HttpRequest *request)
virtual time_t idleTimeout() const =0
timeout to use when waiting for the next request
Comm::ConnectionPointer clientConnection
Definition: Server.h:100
void consumeInput(const size_t byteCount)
remove no longer needed leading bytes from the input buffer
uint64_t size
Response header and body bytes written to the client connection.
static char * buildUrlFromHost(ConnStateData *conn, const Http1::RequestParserPointer &hp)
@ LOG_TCP_INM_HIT
Definition: LogTags.h:51
static std::ostream & Extra(std::ostream &)
Definition: debug.cc:1316
SBuf & append(const SBuf &S)
Definition: SBuf.cc:185
ProxyProtocol::HeaderPointer proxyProtocolHeader_
the parsed PROXY protocol header
Definition: client_side.h:470
int64_t content_length
Definition: Message.h:83
Ssl::BumpMode step1
The SSL bump mode at step1.
Definition: ServerBump.h:59
@ bumpStare
Definition: support.h:132
static IOACB httpAccept
Definition: client_side.cc:186
static bool AddOpenedHttpSocket(const Comm::ConnectionPointer &conn)
find any unused HttpSockets[] slot and store fd there or return false
void setCode(std::string const &aCode)
Set new request/reply code to compose.
void deleteThis(const char *aReason)
Definition: AsyncJob.cc:65
Ipc::StartListeningAnswer answer_
StartListening() results.
Definition: client_side.cc:178
void receivedFirstByte() override
Update flags and timeout after the first byte received.
void notePinnedConnectionBecameIdle(PinnedIdleContext pic)
Called when a pinned connection becomes available for forwarding the next request.
void clientAclChecklistFill(ACLFilledChecklist &checklist, ClientHttpRequest *http)
static void clientHttpConnectionsOpen(void)
static const size_type npos
Definition: SBuf.h:100
virtual bool canDial(AsyncCall &) const
Definition: client_side.cc:167
uint32_t sources
The message sources.
Definition: Message.h:99
bool switchedToHttps_
Definition: client_side.h:478
uint32_t nrequests
Definition: Pipeline.h:63
void ResetSelect(int fd)
reset/undo/unregister the watch for an FD which was set by Comm::SetSelect()
Definition: Loops.h:30
SBuf preservedClientData
Definition: client_side.h:349
const LogTags & loggingTags() const
the processing tags associated with this request transaction.
void clientSetKeepaliveFlag(ClientHttpRequest *http)
decide whether to expect multiple requests on the corresponding connection
Definition: client_side.cc:675
struct SquidConfig::@93 onoff
virtual bool writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call)=0
handle a control message received by context from a peer and call back
void prepareLogWithRequestDetails(HttpRequest *, const AccessLogEntryPointer &)
Definition: client_side.cc:323
void clientPinnedConnectionRead(const CommIoCbParams &io)
Adaptation::History::Pointer adaptLogHistory() const
Returns possibly nil history, creating it if adapt. logging is enabled.
Definition: HttpRequest.cc:414
int tvSubUsec(struct timeval t1, struct timeval t2)
Definition: gadgets.cc:37
bool proxyKeepalive
Definition: RequestFlags.h:42
uint64_t parsedBumpedRequestCount
The number of parsed HTTP requests headers on a bumped client connection.
Definition: client_side.h:481
void getSslContextDone(Security::ContextPointer &)
finish configuring the newly created SSL context"
SBuf sslCommonName_
CN name for SSL certificate generation.
Definition: client_side.h:487
#define fd_table
Definition: fde.h:189
void switchToHttps(ClientHttpRequest *, Ssl::BumpMode bumpServerMode)
void abortChunkedRequestBody(const err_type error)
quit on errors related to chunked request body handling
void expectNoForwarding()
cleans up virgin request [body] forwarding state
ListeningStartedDialer(Handler aHandler, AnyP::PortCfgPointer &aPortCfg, const Ipc::FdNoteId note, const Subscription::Pointer &aSub)
Definition: client_side.cc:159
const Auth::UserRequest::Pointer & getAuth() const
Definition: client_side.h:123
@ PROTO_AUTHORITY_FORM
Definition: ProtocolType.h:40
struct StatCounters::@113 cd
void clientStreamInit(dlink_list *list, CSR *func, CSD *rdetach, CSS *readstatus, const ClientStreamData &readdata, CSCB *callback, CSD *cdetach, const ClientStreamData &callbackdata, StoreIOBuffer tailBuffer)
bool tunnelOnError(const err_type)
initiate tunneling if possible or return false otherwise
static Comm::ConnectionPointer BorrowPinnedConnection(HttpRequest *, const AccessLogEntryPointer &)
err_type handleChunkedRequestBody()
parses available chunked encoded body bytes, checks size, returns errors
bool handleRequestBodyData()
void startPeekAndSplice()
Initializes and starts a peek-and-splice negotiation with the SSL client.
void clientProcessRequest(ConnStateData *conn, const Http1::RequestParserPointer &hp, Http::Stream *context)
@ PROTO_HTTPS
Definition: ProtocolType.h:27
access to a callback result carried by an asynchronous CallDialer
@ algSignUntrusted
Definition: gadgets.h:169
bool accelerated
Definition: RequestFlags.h:62
unsigned parsed_ok
Was this parsed correctly?
Definition: Stream.h:140
HttpRequestMethod method
Definition: HttpRequest.h:114
std::ostream & operator<<(std::ostream &os, const ConnStateData::PinnedIdleContext &pic)
noteTakeServerConnectionControl() callback parameter
Definition: client_side.h:213
time_t request
Definition: SquidConfig.h:118
@ PROTO_FTP
Definition: ProtocolType.h:26
void composeRequest(Ssl::CertificateProperties const &)
std::shared_ptr< SSL > SessionPointer
Definition: Session.h:53
Auth::UserRequest::Pointer auth_
some user details that can be used to perform authentication on this connection
Definition: client_side.h:474
@ ERR_LIFETIME_EXP
Definition: forward.h:27
void commSetConnTimeout(const Comm::ConnectionPointer &conn, time_t timeout, AsyncCall::Pointer &callback)
Definition: comm.cc:594
@ PROTO_HTTP
Definition: ProtocolType.h:25
const char * termedBuf() const
Definition: SquidString.h:93
bool at(const BumpStep stp) const
whether we are currently performing the given processing step
Definition: ServerBump.h:47
ParseResult parse(const char *buffer, size_t len)
Definition: crtd_message.cc:23
StatHist allSvcTime
Definition: StatCounters.h:52
bool allowed() const
Definition: Acl.h:82
bool serveDelayedError(Http::Stream *)
void wroteControlMsg(const CommIoCbParams &)
callback to handle Comm::Write completion
size_t putMoreData(const char *buf, size_t size)
Definition: BodyPipe.cc:213
bool handleReadData() override
bool timedout
_TIMEDOUT: terminated due to a lifetime or I/O timeout
Definition: LogTags.h:28
void setConn(ConnStateData *)
set either conn
const char * status() const
Definition: BodyPipe.cc:446
bool productionEnded() const
Definition: BodyPipe.h:113
Definition: parse.c:160
int cmp(const SBuf &S, const size_type n) const
shorthand version for compare()
Definition: SBuf.h:279
void afterClientRead() override
processing to be done after a Comm::Read()
int pipeline_max_prefetch
Definition: SquidConfig.h:347
@ bumpNone
Definition: support.h:132
Parsed Parse(const SBuf &)
Definition: Parser.cc:252
void httpHeaderAddContRange(HttpHeader *, HttpHdrRangeSpec, int64_t)
static void clientUpdateStatCounters(const LogTags &logType)
Definition: client_side.cc:199
Helps prints T object using object's T::printWithExtras() method.
Definition: IoManip.h:293
static const Pointer & Current()
Definition: CodeContext.cc:33
@ LOG_TCP_OFFLINE_HIT
Definition: LogTags.h:57
@ algSetValidBefore
Definition: gadgets.h:207
bool configureSSLUsingPkeyAndCertFromMemory(SSL *ssl, const char *data, AnyP::PortCfg &port)
Definition: support.cc:1121
@ ERR_TOO_BIG
Definition: forward.h:40
Comm::ConnectionPointer conn_
to-server connection
Definition: client_side.h:224
Error bareError
a problem that occurred without a request (e.g., while parsing headers)
Definition: client_side.h:381
an std::runtime_error with thrower location info
Definition: TextException.h:20
void SetSelect(int, unsigned int, PF *, void *, time_t)
Mark an FD to be watched for its IO status.
Definition: ModDevPoll.cc:220
static ErrorState * NewForwarding(err_type, HttpRequestPointer &, const AccessLogEntryPointer &)
Creates a general request forwarding error with the right http_status.
Definition: errorpage.cc:691
int has(Http::HdrType id) const
Definition: HttpHeader.cc:937
std::string commonName
A CN to use for the generated certificate.
Definition: gadgets.h:241
char * content()
start of the added data
Definition: MemBuf.h:41
bool verifySslCertificate(const Security::ContextPointer &, CertificateProperties const &)
Definition: support.cc:1141
bool mayNeedMoreData() const
Definition: BodyPipe.h:118
void expectNoConsumption()
there will be no more setConsumer() calls
Definition: BodyPipe.cc:267
void putStr(Http::HdrType id, const char *str)
Definition: HttpHeader.cc:995
void setRequest(HttpRequest *)
configure client request-related fields for the first time
@ METHOD_NONE
Definition: MethodType.h:22
ConnStateData(const MasterXactionPointer &xact)
@ SQUID_X509_V_ERR_DOMAIN_MISMATCH
Definition: forward.h:238
bool isEmpty() const
Definition: Store.h:65
std::optional< KnownPort > Port
validated/supported port number (if any)
Definition: UriScheme.h:26
struct StatCounters::@114 netdb
void setReplyToError(err_type, Http::StatusCode, char const *, const ConnStateData *, HttpRequest *, const char *, Auth::UserRequest::Pointer)
builds error using clientBuildError() and calls setReplyToError() below
int timeout
Definition: PingData.h:41
virtual void start()
called by AsyncStart; do not call directly
Definition: AsyncJob.cc:59
void clientPackRangeHdr(const HttpReplyPointer &rep, const HttpHdrRangeSpec *spec, String boundary, MemBuf *mb)
append a "part" HTTP header (as in a multi-part/range reply) to the buffer
Definition: client_side.cc:710
@ ERR_INVALID_REQ
Definition: forward.h:43
Ssl::BumpMode step2
The SSL bump mode at step2.
Definition: ServerBump.h:60
#define Must(condition)
Definition: TextException.h:75
void startShutdown() override
#define Important(id)
Definition: Messages.h:93
@ ACCESS_ALLOWED
Definition: Acl.h:42
size_t req_sz
raw request size on input, not current request size
void manager(const CbcPointer< ConnStateData > &aMgr, const AccessLogEntryPointer &al)
associates the request with a from-client connection manager
Definition: HttpRequest.cc:773
bool internalCheck(const SBuf &urlPath)
Definition: internal.cc:72
@ ACCESS_DENIED
Definition: Acl.h:41
static bool httpsCreate(const ConnStateData *connState, const Security::ContextPointer &ctx)
Create TLS connection structure and update fd_table.
void stopProducingFor(RefCount< BodyPipe > &, bool atEof)
Definition: BodyPipe.cc:107
#define DBG_IMPORTANT
Definition: Stream.h:38
StatHist querySvcTime
Definition: StatCounters.h:82
Ssl::ServerBump * serverBump()
Definition: client_side.h:285
AnyP::Port port
destination port of the request that caused serverConnection
Definition: client_side.h:145
SBuf preReadServerBytes
post-101 bytes received from the server
Definition: client_side.h:220
#define MYNAME
Definition: Stream.h:219
CertSignAlgorithm signAlgorithm
The signing algorithm to use.
Definition: gadgets.h:242
LogTags_ot oldType
a set of client protocol, cache use, and other transaction outcome tags
Definition: LogTags.h:96
void addLocalStorage(Ip::Address const &address, size_t size_of_store)
Create new SSL context storage for the local listening address/port.
void reset()
Definition: MemBuf.cc:129
bool receivedFirstByte_
true if at least one byte received on this connection
Definition: Server.h:115
void pullData()
get more data to send
Definition: Stream.cc:110
const char * stoppedReceiving() const
true if we stopped receiving the request
Definition: client_side.h:159
String rangeBoundaryStr() const
Definition: client_side.cc:781
void add(const SBuf &key, const SBuf &value)
Definition: Notes.cc:317
const SBuf & tlsClientSni() const
Definition: client_side.h:294
bool HasSubjectName(X509 &, const AnyP::Host &)
whether at least one common or alternate subject name matches the given one
Definition: support.cc:338
const AccessLogEntry::Pointer al
access.log entry
sslproxy_cert_adapt * next
Definition: ProxyCerts.h:58
int kind
the matched custom access list verb (or zero)
Definition: Acl.h:99
sslproxy_cert_sign * next
Definition: ProxyCerts.h:35
@ BrokenHelper
Definition: ResultCode.h:20
const HttpReply & freshestReply() const
Definition: MemObject.h:68
bool parse(const SBuf &) override
void update(const Error &)
if necessary, stores the given error information (if any)
Definition: Error.cc:51
#define HTTP_REQBUF_SZ
Definition: forward.h:14
bool setValidAfter
Do not mimic "Not Valid After" field.
Definition: gadgets.h:238
@ VARY_MATCH
Definition: enums.h:189
static int clientIsRequestBodyTooLargeForPolicy(int64_t bodyLength)
Definition: client_side.cc:687
IoResult Accept(Comm::Connection &transport)
accept a TLS connection over the specified to-Squid transport connection
Definition: Io.cc:211
ClientRequestContext * calloutContext
void checkLogging()
log the last (attempt at) transaction if nobody else did
struct ConnStateData::@31 flags
void doneWithControlMsg() override
optimized set of C chars, with quick membership test and merge support
Definition: CharacterSet.h:17
@ srcHttps
https_port or bumped http_port tunnel; HTTPS server
Definition: Message.h:33
struct ConnStateData::@32 pinning
Security::CertPointer serverCert
Definition: ServerBump.h:57
@ ERR_CANNOT_FORWARD
Definition: forward.h:23
void kick()
try to make progress on a transaction or read more I/O
Definition: client_side.cc:895
@ CD_SIBLING_HIT
Definition: hier_code.h:29
int query_timeouts
Definition: StatCounters.h:84
#define xisspace(x)
Definition: xis.h:15
int NHttpSockets
Definition: PortCfg.cc:25
static bool OpenedHttpSocket(const Comm::ConnectionPointer &c, const Ipc::FdNoteId portType)
check FD after clientHttp[s]ConnectionOpened, adjust HttpSockets as needed
StoreEntry * storeEntry() const
bool important
whether the error was serious/unusual
Definition: Io.h:49
StoreEntry * loggingEntry() const
void swanSong() override
Definition: Server.cc:51
sslproxy_cert_sign * cert_sign
Definition: SquidConfig.h:513
const char * urlXXX() const
Definition: MemObject.h:138
size_t appendDomainLen
Definition: SquidConfig.h:223
bool isOpen() const
Definition: client_side.cc:641
bool connectedOk() const
whether there was a successful connection to (and peeking at) the origin server
Definition: ServerBump.h:44
@ bumpClientFirst
Definition: support.h:132
SBuf & appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Definition: SBuf.cc:229
virtual void callException(const std::exception &e)
called when the job throws during an async call
Definition: AsyncJob.cc:143
void setScheme(const AnyP::ProtocolType &p, const char *str)
convert the URL scheme to that given
Definition: Uri.h:61
time_t lifetime
Definition: SquidConfig.h:114
RawPointerT< Pointer > RawPointer(const char *label, const Pointer &ptr)
convenience wrapper for creating RawPointerT<> objects
Definition: IoManip.h:73
@ CLOSEST_DIRECT
Definition: hier_code.h:23
void storeTlsContextToCache(const SBuf &cacheKey, Security::ContextPointer &ctx)
@ VARY_CANCEL
Definition: enums.h:191
bool fakeAConnectRequest(const char *reason, const SBuf &payload)
@ fdnHttpsSocket
Definition: FdNotes.h:20
MemObject * memObject() const
iterator begin()
char * internalLocalUri(const char *dir, const SBuf &name)
Definition: internal.cc:139
@ LOG_TCP_MEM_HIT
Definition: LogTags.h:54
static void ClientSocketContextPushDeferredIfNeeded(Http::StreamPointer deferredRequest, ConnStateData *conn)
Definition: client_side.cc:873
const SBuf & effectiveRequestUri() const
RFC 7230 section 5.5 - Effective Request URI.
Definition: HttpRequest.cc:743
CSD clientReplyDetach
Definition: client_side.h:531
Network/connection security abstraction layer.
Definition: Connection.h:33
void updateError(const Error &)
if necessary, stores new error information (if any)
NotePairs::Pointer notes()
Definition: HttpRequest.cc:751
#define MAXTCPLISTENPORTS
Definition: PortCfg.h:86
bool configureSSL(SSL *ssl, CertificateProperties const &properties, AnyP::PortCfg &port)
Definition: support.cc:1098
Ipc::FdNoteId portTypeNote
Type of IPC socket being opened.
Definition: client_side.cc:180
void host(const char *src)
Definition: Uri.cc:123
bool setCommonName
Replace the CN field of the mimicking subject with the given.
Definition: gadgets.h:240
bool forceTunnel
whether to forward via TunnelStateData (instead of FwdState)
Definition: RequestFlags.h:120
ByteCounter kbytes_out
Definition: StatCounters.h:46
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
void setReadBufData(SBuf &data)
Definition: bio.h:91
Security::HandshakeParser tlsParser
Definition: client_side.h:308
@ CD_PARENT_HIT
Definition: hier_code.h:28
void clear()
switch to the default "no error information" state
Definition: Error.h:53
#define COMM_SELECT_WRITE
Definition: defines.h:25
const char * bumpMode(int bm)
Definition: support.h:144
thrown by modern "incremental" parsers when they need more data
Definition: forward.h:18
void unpinConnection(const bool andClose)
Undo pinConnection() and, optionally, close the pinned connection.
struct Http::Stream::@61 flags
Security::NegotiationHistory * tlsNegotiations()
Definition: Connection.cc:159
void callException(const std::exception &) override
called when the job throws during an async call
Definition: client_side.cc:616
void clientPackTermBound(String boundary, MemBuf *mb)
put terminating boundary for multiparts to the buffer
Definition: client_side.cc:703
struct SquidConfig::@80 Timeout
void clean()
Definition: HttpHeader.cc:185
void comm_remove_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:971
void updateAle(const AccessLogEntry::Pointer &)
void endingShutdown() override
HttpRequest::Pointer request
to-server request that initiated serverConnection
Definition: client_side.h:188
const char * getMD5Text() const
Definition: store.cc:207
void clientStreamAbort(clientStreamNode *thisObject, ClientHttpRequest *http)
void print(std::ostream &os) const override
Definition: client_side.cc:163
char * host
host name of pinned connection
Definition: client_side.h:144
ClientHttpRequest * buildFakeRequest(SBuf &useHost, AnyP::KnownPort usePort, const SBuf &payload)
build a fake http request
#define SQUIDSBUFPH
Definition: SBuf.h:31
char * prepareTlsSwitchingURL(const Http1::RequestParserPointer &hp)
AnyP::PortCfgPointer portCfg
from HttpPortList
Definition: client_side.cc:179
T * get() const
Returns raw and possibly nullptr pointer.
void requestTimeout(const CommTimeoutCbParams &params)
void tvSub(struct timeval &res, struct timeval const &t1, struct timeval const &t2)
Definition: gadgets.cc:58
Security::ContextPointer getTlsContextFromCache(const SBuf &cacheKey, const Ssl::CertificateProperties &certProperties)
class SquidConfig Config
Definition: SquidConfig.cc:12
HttpRequest *const request
bool parseProxyProtocolHeader()
ErrorDetail::Pointer MakeNamedErrorDetail(const char *name)
Definition: Detail.cc:54
StatCounters statCounter
Definition: StatCounters.cc:12
void clean()
Definition: String.cc:104
static void Start(const Pointer &job)
Definition: AsyncJob.cc:37
static bool clientPingHasFinished(ping_data const *aPing)
Definition: client_side.cc:255
AnyP::ProtocolVersion ProtocolVersion(unsigned int aMajor, unsigned int aMinor)
HTTP version label information.
void clientSocketDetach(clientStreamNode *node, ClientHttpRequest *http)
Definition: client_side.cc:837
int64_t mRangeCLen() const
Definition: client_side.cc:741
static Pointer MakePortful(const AnyP::PortCfgPointer &aPort)
Definition: MasterXaction.h:54
void terminateAll(const Error &, const LogTagsErrors &) override
abort any pending transactions and prevent new ones (by closing)
ClientDelayConfig ClientDelay
Definition: SquidConfig.h:446
@ bumpSplice
Definition: support.h:132
const std::string & getBody() const
Current body. If parsing is not finished the method returns incompleted body.
static void clientUpdateStatHistCounters(const LogTags &logType, int svc_time)
Definition: client_side.cc:213
virtual void releaseAuthServer()
Definition: UserRequest.cc:218

 

Introduction

Documentation

Support

Miscellaneous