client_side.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 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 "debug/Messages.h"
83 #include "errorpage.h"
84 #include "fd.h"
85 #include "fde.h"
86 #include "fqdncache.h"
87 #include "FwdState.h"
88 #include "globals.h"
89 #include "helper.h"
90 #include "helper/Reply.h"
91 #include "http.h"
92 #include "http/one/RequestParser.h"
94 #include "http/Stream.h"
95 #include "HttpHdrContRange.h"
96 #include "HttpHeaderTools.h"
97 #include "HttpReply.h"
98 #include "HttpRequest.h"
99 #include "internal.h"
100 #include "ipc/FdNotes.h"
101 #include "ipc/StartListening.h"
102 #include "log/access_log.h"
103 #include "MemBuf.h"
104 #include "MemObject.h"
105 #include "mime_header.h"
106 #include "parser/Tokenizer.h"
107 #include "proxyp/Header.h"
108 #include "proxyp/Parser.h"
109 #include "sbuf/Stream.h"
110 #include "security/Certificate.h"
112 #include "security/Io.h"
113 #include "security/KeyLog.h"
115 #include "servers/forward.h"
116 #include "SquidConfig.h"
117 #include "StatCounters.h"
118 #include "StatHist.h"
119 #include "Store.h"
120 #include "TimeOrTag.h"
121 #include "tools.h"
122 
123 #if USE_AUTH
124 #include "auth/UserRequest.h"
125 #endif
126 #if USE_DELAY_POOLS
127 #include "ClientInfo.h"
128 #include "MessageDelayPools.h"
129 #endif
130 #if USE_OPENSSL
131 #include "ssl/bio.h"
132 #include "ssl/context_storage.h"
133 #include "ssl/gadgets.h"
134 #include "ssl/helper.h"
135 #include "ssl/ProxyCerts.h"
136 #include "ssl/ServerBump.h"
137 #include "ssl/support.h"
138 #endif
139 
140 #include <climits>
141 #include <cmath>
142 #include <limits>
143 
144 #if HAVE_SYSTEMD_SD_DAEMON_H
145 #include <systemd/sd-daemon.h>
146 #endif
147 
148 // TODO: Remove this custom dialer and simplify by creating the TcpAcceptor
149 // subscription later, inside clientListenerConnectionOpened() callback, just
150 // like htcpOpenPorts(), icpOpenPorts(), and snmpPortOpened() do it.
153  public CallDialer,
154  public WithAnswer<Ipc::StartListeningAnswer>
155 {
156 public:
159  handler(aHandler), portCfg(aPortCfg), portTypeNote(note), sub(aSub) {}
160 
161  /* CallDialer API */
162  void print(std::ostream &os) const override {
163  os << '(' << answer_ << ", " << FdNote(portTypeNote) << " port=" << (void*)&portCfg << ')';
164  }
165 
166  virtual bool canDial(AsyncCall &) const { return true; }
167  virtual void dial(AsyncCall &) { (handler)(portCfg, portTypeNote, sub); }
168 
169  /* WithAnswer API */
170  Ipc::StartListeningAnswer &answer() override { return answer_; }
171 
172 public:
174 
175 private:
176  // answer_.conn (set/updated by IPC code) is portCfg.listenConn (used by us)
181 };
182 
183 static void clientListenerConnectionOpened(AnyP::PortCfgPointer &s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub);
184 
186 static int clientIsRequestBodyTooLargeForPolicy(int64_t bodyLength);
187 
188 static void clientUpdateStatHistCounters(const LogTags &logType, int svc_time);
189 static void clientUpdateStatCounters(const LogTags &logType);
191 static bool clientPingHasFinished(ping_data const *aPing);
194 
195 char *skipLeadingSpace(char *aString);
196 
197 void
199 {
201 
202  if (logType.isTcpHit())
204 
205  if (logType.oldType == LOG_TCP_HIT)
207  else if (logType.oldType == LOG_TCP_MEM_HIT)
209 }
210 
211 void
212 clientUpdateStatHistCounters(const LogTags &logType, int svc_time)
213 {
222  switch (logType.oldType) {
223 
226  break;
227 
228  case LOG_TCP_INM_HIT:
229  case LOG_TCP_IMS_HIT:
231  break;
232 
233  case LOG_TCP_HIT:
234 
235  case LOG_TCP_MEM_HIT:
236 
237  case LOG_TCP_OFFLINE_HIT:
239  break;
240 
241  case LOG_TCP_MISS:
242 
245  break;
246 
247  default:
248  /* make compiler warnings go away */
249  break;
250  }
251 }
252 
253 bool
255 {
256  if (0 != aPing->stop.tv_sec && 0 != aPing->start.tv_sec)
257  return true;
258 
259  return false;
260 }
261 
262 void
264 {
265  ping_data *i;
266 
267  switch (someEntry->code) {
268 #if USE_CACHE_DIGESTS
269 
270  case CD_PARENT_HIT:
271 
272  case CD_SIBLING_HIT:
274  break;
275 #endif
276 
277  case SIBLING_HIT:
278 
279  case PARENT_HIT:
280 
281  case FIRST_PARENT_MISS:
282 
283  case CLOSEST_PARENT_MISS:
285  i = &someEntry->ping;
286 
287  if (clientPingHasFinished(i))
289 
290  if (i->timeout)
292 
293  break;
294 
295  case CLOSEST_PARENT:
296 
297  case CLOSEST_DIRECT:
299 
300  break;
301 
302  default:
303  break;
304  }
305 }
306 
307 void
309 {
311 
312  if (request->error)
314 
316  tvSubMsec(al->cache.start_time, current_time));
317 
319 }
320 
321 void
323 {
324  assert(request);
325  assert(aLogEntry != nullptr);
326 
327  if (Config.onoff.log_mime_hdrs) {
328  MemBuf mb;
329  mb.init();
330  request->header.packInto(&mb);
331  //This is the request after adaptation or redirection
332  aLogEntry->headers.adapted_request = xstrdup(mb.buf);
333 
334  // the virgin request is saved to aLogEntry->request
335  if (aLogEntry->request) {
336  mb.reset();
337  aLogEntry->request->header.packInto(&mb);
338  aLogEntry->headers.request = xstrdup(mb.buf);
339  }
340 
341 #if USE_ADAPTATION
342  const Adaptation::History::Pointer ah = request->adaptLogHistory();
343  if (ah != nullptr) {
344  mb.reset();
345  ah->lastMeta.packInto(&mb);
346  aLogEntry->adapt.last_meta = xstrdup(mb.buf);
347  }
348 #endif
349 
350  mb.clean();
351  }
352 
353 #if ICAP_CLIENT
354  const Adaptation::Icap::History::Pointer ih = request->icapHistory();
355  if (ih != nullptr)
356  ih->processingTime(aLogEntry->icap.processingTime);
357 #endif
358 
359  aLogEntry->http.method = request->method;
360  aLogEntry->http.version = request->http_ver;
361  aLogEntry->hier = request->hier;
362  aLogEntry->cache.extuser = request->extacl_user.termedBuf();
363 
364  // Adapted request, if any, inherits and then collects all the stats, but
365  // the virgin request gets logged instead; copy the stats to log them.
366  // TODO: avoid losses by keeping these stats in a shared history object?
367  if (aLogEntry->request) {
368  aLogEntry->request->dnsWait = request->dnsWait;
369  aLogEntry->request->error = request->error;
370  }
371 }
372 
373 void
375 {
376  if (!out.size && loggingTags().oldType == LOG_TAG_NONE)
377  debugs(33, 5, "logging half-baked transaction: " << log_uri);
378 
379  al->icp.opcode = ICP_INVALID;
380  al->url = log_uri;
381  debugs(33, 9, "clientLogRequest: al.url='" << al->url << "'");
382 
383  const auto findReply = [this]() -> const HttpReply * {
384  if (al->reply)
385  return al->reply.getRaw();
386  if (const auto le = loggingEntry())
387  return le->hasFreshestReply();
388  return nullptr;
389  };
390  if (const auto reply = findReply()) {
391  al->http.code = reply->sline.status();
392  al->http.content_type = reply->content_type.termedBuf();
393  }
394 
395  debugs(33, 9, "clientLogRequest: http.code='" << al->http.code << "'");
396 
397  if (loggingEntry() && loggingEntry()->mem_obj && loggingEntry()->objectLen() >= 0)
398  al->cache.objectSize = loggingEntry()->contentLen(); // payload duplicate ?? with or without TE ?
399 
400  al->http.clientRequestSz.header = req_sz;
401  // the virgin request is saved to al->request
402  if (al->request && al->request->body_pipe)
403  al->http.clientRequestSz.payloadData = al->request->body_pipe->producedSize();
404  al->http.clientReplySz.header = out.headers_sz;
405  // XXX: calculate without payload encoding or headers !!
406  al->http.clientReplySz.payloadData = out.size - out.headers_sz; // pretend its all un-encoded data for now.
407 
408  al->cache.highOffset = out.offset;
409 
410  tvSub(al->cache.trTime, al->cache.start_time, current_time);
411 
412  if (request)
414 
415 #if USE_OPENSSL && 0
416 
417  /* This is broken. Fails if the connection has been closed. Needs
418  * to snarf the ssl details some place earlier..
419  */
420  if (getConn() != NULL)
421  al->cache.ssluser = sslGetUserEmail(fd_table[getConn()->fd].ssl);
422 
423 #endif
424 
425  if (request) {
426  SBuf matched;
427  for (auto h: Config.notes) {
428  if (h->match(request, al->reply.getRaw(), al, matched)) {
429  request->notes()->add(h->key(), matched);
430  debugs(33, 3, h->key() << " " << matched);
431  }
432  }
433  // The al->notes and request->notes must point to the same object.
434  al->syncNotes(request);
435 
436  HTTPMSGUNLOCK(al->adapted_request);
437  al->adapted_request = request;
438  HTTPMSGLOCK(al->adapted_request);
439  }
440 
441  ACLFilledChecklist checklist(nullptr, request);
442  checklist.updateAle(al);
443  // no need checklist.syncAle(): already synced
444  accessLogLog(al, &checklist);
445 
446  bool updatePerformanceCounters = true;
449  statsCheck.updateAle(al);
450  updatePerformanceCounters = statsCheck.fastCheck().allowed();
451  }
452 
453  if (updatePerformanceCounters) {
454  if (request)
455  updateCounters();
456 
457  if (getConn() != nullptr && getConn()->clientConnection != nullptr)
458  clientdbUpdate(getConn()->clientConnection->remote, loggingTags(), AnyP::PROTO_HTTP, out.size);
459  }
460 }
461 
462 void
464 {
465  safe_free(uri);
468  clearRequest();
469 
470  if (client_stream.tail)
472 }
473 
474 void
475 httpRequestFree(void *data)
476 {
477  ClientHttpRequest *http = (ClientHttpRequest *)data;
478  assert(http != nullptr);
479  delete http;
480 }
481 
482 /* This is a handler normally called by comm_close() */
484 {
485  if (clientConnection) {
487  // keep closed clientConnection for logging, clientdb cleanup, etc.
488  }
489  deleteThis("ConnStateData::connStateClosed");
490 }
491 
492 #if USE_AUTH
493 void
495 {
496  if (auth_ == nullptr) {
497  if (aur != nullptr) {
498  debugs(33, 2, "Adding connection-auth to " << clientConnection << " from " << by);
499  auth_ = aur;
500  }
501  return;
502  }
503 
504  // clobered with self-pointer
505  // NP: something nasty is going on in Squid, but harmless.
506  if (aur == auth_) {
507  debugs(33, 2, "WARNING: Ignoring duplicate connection-auth for " << clientConnection << " from " << by);
508  return;
509  }
510 
511  /*
512  * Connection-auth relies on a single set of credentials being preserved
513  * for all requests on a connection once they have been setup.
514  * There are several things which need to happen to preserve security
515  * when connection-auth credentials change unexpectedly or are unset.
516  *
517  * 1) auth helper released from any active state
518  *
519  * They can only be reserved by a handshake process which this
520  * connection can now never complete.
521  * This prevents helpers hanging when their connections close.
522  *
523  * 2) pinning is expected to be removed and server conn closed
524  *
525  * The upstream link is authenticated with the same credentials.
526  * Expecting the same level of consistency we should have received.
527  * This prevents upstream being faced with multiple or missing
528  * credentials after authentication.
529  * NP: un-pin is left to the cleanup in ConnStateData::swanSong()
530  * we just trigger that cleanup here via comm_reset_close() or
531  * ConnStateData::stopReceiving()
532  *
533  * 3) the connection needs to close.
534  *
535  * This prevents attackers injecting requests into a connection,
536  * or gateways wrongly multiplexing users into a single connection.
537  *
538  * When credentials are missing closure needs to follow an auth
539  * challenge for best recovery by the client.
540  *
541  * When credentials change there is nothing we can do but abort as
542  * fast as possible. Sending TCP RST instead of an HTTP response
543  * is the best-case action.
544  */
545 
546  // clobbered with nul-pointer
547  if (aur == nullptr) {
548  debugs(33, 2, "WARNING: Graceful closure on " << clientConnection << " due to connection-auth erase from " << by);
550  auth_ = nullptr;
551  // XXX: need to test whether the connection re-auth challenge is sent. If not, how to trigger it from here.
552  // NP: the current situation seems to fix challenge loops in Safari without visible issues in others.
553  // we stop receiving more traffic but can leave the Job running to terminate after the error or challenge is delivered.
554  stopReceiving("connection-auth removed");
555  return;
556  }
557 
558  // clobbered with alternative credentials
559  if (aur != auth_) {
560  debugs(33, 2, "ERROR: Closing " << clientConnection << " due to change of connection-auth from " << by);
562  auth_ = nullptr;
563  // this is a fatal type of problem.
564  // Close the connection immediately with TCP RST to abort all traffic flow
566  return;
567  }
568 
569  /* NOT REACHABLE */
570 }
571 #endif
572 
573 void
574 ConnStateData::resetReadTimeout(const time_t timeout)
575 {
577  AsyncCall::Pointer callback = JobCallback(33, 5, TimeoutDialer, this, ConnStateData::requestTimeout);
578  commSetConnTimeout(clientConnection, timeout, callback);
579 }
580 
581 void
583 {
585  AsyncCall::Pointer callback = JobCallback(5, 4, TimeoutDialer, this, ConnStateData::lifetimeTimeout);
587 }
588 
589 // cleans up before destructor is called
590 void
592 {
593  debugs(33, 2, clientConnection);
594 
595  flags.readMore = false;
596  clientdbEstablished(clientConnection->remote, -1); /* decrement */
597 
599  checkLogging();
600 
601  // XXX: Closing pinned conn is too harsh: The Client may want to continue!
602  unpinConnection(true);
603 
605 
606 #if USE_AUTH
607  // NP: do this bit after closing the connections to avoid side effects from unwanted TCP RST
608  setAuth(nullptr, "ConnStateData::SwanSong cleanup");
609 #endif
610 
611  flags.swanSang = true;
612 }
613 
614 void
615 ConnStateData::callException(const std::exception &ex)
616 {
617  Server::callException(ex); // logs ex and stops the job
618 
619  ErrorDetail::Pointer errorDetail;
620  if (const auto tex = dynamic_cast<const TextException*>(&ex))
621  errorDetail = new ExceptionErrorDetail(tex->id());
622  else
623  errorDetail = new ExceptionErrorDetail(Here().id());
624  updateError(ERR_GATEWAY_FAILURE, errorDetail);
625 }
626 
627 void
629 {
630  if (const auto context = pipeline.front()) {
631  const auto http = context->http;
632  assert(http);
633  http->updateError(error);
634  } else {
636  }
637 }
638 
639 bool
641 {
642  return cbdataReferenceValid(this) && // XXX: checking "this" in a method
644  !fd_table[clientConnection->fd].closing();
645 }
646 
648 {
649  debugs(33, 3, clientConnection);
650 
651  if (isOpen())
652  debugs(33, DBG_IMPORTANT, "ERROR: Squid BUG: ConnStateData did not close " << clientConnection);
653 
654  if (!flags.swanSang)
655  debugs(33, DBG_IMPORTANT, "ERROR: Squid BUG: ConnStateData was not destroyed properly; " << clientConnection);
656 
657  if (bodyPipe != nullptr)
658  stopProducingFor(bodyPipe, false);
659 
660  delete bodyParser; // TODO: pool
661 
662 #if USE_OPENSSL
663  delete sslServerBump;
664 #endif
665 }
666 
673 void
675 {
676  HttpRequest *request = http->request;
677 
678  debugs(33, 3, "http_ver = " << request->http_ver);
679  debugs(33, 3, "method = " << request->method);
680 
681  // TODO: move to HttpRequest::hdrCacheInit, just like HttpReply.
682  request->flags.proxyKeepalive = request->persistent();
683 }
684 
685 int
687 {
689  bodyLength > Config.maxRequestBodySize)
690  return 1; /* too large */
691 
692  return 0;
693 }
694 
695 bool
697 {
698  return request->multipartRangeRequest();
699 }
700 
701 void
703 {
704  mb->appendf("\r\n--" SQUIDSTRINGPH "--\r\n", SQUIDSTRINGPRINT(boundary));
705  debugs(33, 6, "buf offset: " << mb->size);
706 }
707 
708 void
709 clientPackRangeHdr(const HttpReplyPointer &rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb)
710 {
711  HttpHeader hdr(hoReply);
712  assert(rep);
713  assert(spec);
714 
715  /* put boundary */
716  debugs(33, 5, "appending boundary: " << boundary);
717  /* rfc2046 requires to _prepend_ boundary with <crlf>! */
718  mb->appendf("\r\n--" SQUIDSTRINGPH "\r\n", SQUIDSTRINGPRINT(boundary));
719 
720  /* stuff the header with required entries and pack it */
721 
724 
725  httpHeaderAddContRange(&hdr, *spec, rep->content_length);
726 
727  hdr.packInto(mb);
728  hdr.clean();
729 
730  /* append <crlf> (we packed a header, not a reply) */
731  mb->append("\r\n", 2);
732 }
733 
739 int64_t
741 {
742  int64_t clen = 0;
743  MemBuf mb;
744 
745  assert(memObject());
746 
747  mb.init();
749 
750  while (pos != request->range->end()) {
751  /* account for headers for this range */
752  mb.reset();
753  clientPackRangeHdr(&storeEntry()->mem().freshestReply(),
754  *pos, range_iter.boundary, &mb);
755  clen += mb.size;
756 
757  /* account for range content */
758  clen += (*pos)->length;
759 
760  debugs(33, 6, "clientMRangeCLen: (clen += " << mb.size << " + " << (*pos)->length << ") == " << clen);
761  ++pos;
762  }
763 
764  /* account for the terminating boundary */
765  mb.reset();
766 
768 
769  clen += mb.size;
770 
771  mb.clean();
772 
773  return clen;
774 }
775 
779 String
781 {
782  const char *key;
784  b.append(":",1);
785  key = storeEntry()->getMD5Text();
786  b.append(key, strlen(key));
787  return b;
788 }
789 
799 void
801  HttpReply * rep, StoreIOBuffer receivedData)
802 {
803  // do not try to deliver if client already ABORTED
804  if (!http->getConn() || !cbdataReferenceValid(http->getConn()) || !Comm::IsConnOpen(http->getConn()->clientConnection))
805  return;
806 
807  /* Test preconditions */
808  assert(node != nullptr);
809  /* TODO: handle this rather than asserting
810  * - it should only ever happen if we cause an abort and
811  * the callback chain loops back to here, so we can simply return.
812  * However, that itself shouldn't happen, so it stays as an assert for now.
813  */
815  assert(node->node.next == nullptr);
816  Http::StreamPointer context = dynamic_cast<Http::Stream *>(node->data.getRaw());
817  assert(context != nullptr);
818 
819  /* TODO: check offset is what we asked for */
820 
821  // TODO: enforces HTTP/1 MUST on pipeline order, but is irrelevant to HTTP/2
822  if (context != http->getConn()->pipeline.front())
823  context->deferRecipientForLater(node, rep, receivedData);
824  else if (http->getConn()->cbControlMsgSent) // 1xx to the user is pending
825  context->deferRecipientForLater(node, rep, receivedData);
826  else
827  http->getConn()->handleReply(rep, receivedData);
828 }
829 
835 void
837 {
838  /* Test preconditions */
839  assert(node != nullptr);
840  /* TODO: handle this rather than asserting
841  * - it should only ever happen if we cause an abort and
842  * the callback chain loops back to here, so we can simply return.
843  * However, that itself shouldn't happen, so it stays as an assert for now.
844  */
846  /* Set null by ContextFree */
847  assert(node->node.next == nullptr);
848  /* this is the assert discussed above */
849  assert(nullptr == dynamic_cast<Http::Stream *>(node->data.getRaw()));
850  /* We are only called when the client socket shutsdown.
851  * Tell the prev pipeline member we're finished
852  */
853  clientStreamDetach(node, http);
854 }
855 
856 void
858 {
859  debugs(33, 5, clientConnection << " reading next req");
860 
861  fd_note(clientConnection->fd, "Idle client: Waiting for next request");
866 
867  readSomeData();
869 }
870 
871 static void
873 {
874  debugs(33, 2, conn->clientConnection << " Sending next");
875 
878  if (deferredRequest->flags.deferred) {
880  assert(deferredRequest->http->out.size == 0);
882  clientSocketRecipient(deferredRequest->deferredparams.node,
883  deferredRequest->http,
884  deferredRequest->deferredparams.rep,
885  deferredRequest->deferredparams.queuedBuffer);
886  }
887 
891 }
892 
893 void
895 {
897  debugs(33, 2, clientConnection << " Connection was closed");
898  return;
899  }
900 
901  if (pinning.pinned && !Comm::IsConnOpen(pinning.serverConnection)) {
902  debugs(33, 2, clientConnection << " Connection was pinned but server side gone. Terminating client connection");
904  return;
905  }
906 
921  if (const char *reason = stoppedReceiving()) {
922  debugs(33, 3, "closing for earlier request error: " << reason);
924  return;
925  }
926 
933  parseRequests();
934 
935  if (!isOpen())
936  return;
937 
945  Http::StreamPointer deferredRequest = pipeline.front();
946  if (deferredRequest != nullptr) {
947  debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded");
948  ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
949  } else if (flags.readMore) {
950  debugs(33, 3, clientConnection << ": calling readNextRequest()");
951  readNextRequest();
952  } else {
953  // XXX: Can this happen? CONNECT tunnels have deferredRequest set.
954  debugs(33, DBG_IMPORTANT, MYNAME << "abandoning " << clientConnection);
955  }
956 }
957 
958 void
960 {
961  debugs(33, 4, "sending error (" << clientConnection << "): " << error <<
962  "; old receiving error: " <<
963  (stoppedReceiving() ? stoppedReceiving_ : "none"));
964 
965  if (const char *oldError = stoppedSending()) {
966  debugs(33, 3, "already stopped sending: " << oldError);
967  return; // nothing has changed as far as this connection is concerned
968  }
970 
971  if (!stoppedReceiving()) {
972  if (const int64_t expecting = mayNeedToReadMoreBody()) {
973  debugs(33, 5, "must still read " << expecting <<
974  " request body bytes with " << inBuf.length() << " unused");
975  return; // wait for the request receiver to finish reading
976  }
977  }
978 
980 }
981 
982 void
984 {
985  if (pipeline.empty())
986  return;
987 
988  auto ctx = pipeline.front();
989  if (size) {
991  if (ctx->http->loggingTags().isTcpHit())
993  }
994  ctx->writeComplete(size);
995 }
996 
997 Http::Stream *
999 {
1000  ClientHttpRequest *http = new ClientHttpRequest(this);
1001  http->req_sz = inBuf.length();
1002  http->setErrorUri(uri);
1003  auto *context = new Http::Stream(clientConnection, http);
1004  StoreIOBuffer tempBuffer;
1005  tempBuffer.data = context->reqbuf;
1006  tempBuffer.length = HTTP_REQBUF_SZ;
1009  clientSocketDetach, context, tempBuffer);
1010  return context;
1011 }
1012 
1013 void
1015 {
1016  // RegisteredRunner API callback - Squid has been shut down
1017 
1018  // if connection is idle terminate it now,
1019  // otherwise wait for grace period to end
1020  if (pipeline.empty())
1021  endingShutdown();
1022 }
1023 
1024 void
1026 {
1027  // RegisteredRunner API callback - Squid shutdown grace period is over
1028 
1029  // force the client connection to close immediately
1030  // swanSong() in the close handler will cleanup.
1033 }
1034 
1035 char *
1036 skipLeadingSpace(char *aString)
1037 {
1038  char *result = aString;
1039 
1040  while (xisspace(*aString))
1041  ++aString;
1042 
1043  return result;
1044 }
1045 
1051 const char *
1052 findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end)
1053 {
1054  if (nullptr == end) {
1055  end = uriAndHTTPVersion + strcspn(uriAndHTTPVersion, "\r\n");
1056  assert(end);
1057  }
1058 
1059  for (; end > uriAndHTTPVersion; --end) {
1060  if (*end == '\n' || *end == '\r')
1061  continue;
1062 
1063  if (xisspace(*end)) {
1064  if (strncasecmp(end + 1, "HTTP/", 5) == 0)
1065  return end + 1;
1066  else
1067  break;
1068  }
1069  }
1070 
1071  return nullptr;
1072 }
1073 
1074 static char *
1076 {
1077  int vhost = conn->port->vhost;
1078  int vport = conn->port->vport;
1079  static char ipbuf[MAX_IPSTRLEN];
1080 
1081  /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
1082 
1083  // XXX: re-use proper URL parser for this
1084  SBuf url = hp->requestUri(); // use full provided URI if we abort
1085  do { // use a loop so we can break out of it
1086  ::Parser::Tokenizer tok(url);
1087  if (tok.skip('/')) // origin-form URL already.
1088  break;
1089 
1090  if (conn->port->vhost)
1091  return nullptr; /* already in good shape */
1092 
1093  // skip the URI scheme
1094  static const CharacterSet uriScheme = CharacterSet("URI-scheme","+-.") + CharacterSet::ALPHA + CharacterSet::DIGIT;
1095  static const SBuf uriSchemeEnd("://");
1096  if (!tok.skipAll(uriScheme) || !tok.skip(uriSchemeEnd))
1097  break;
1098 
1099  // skip the authority segment
1100  // RFC 3986 complex nested ABNF for "authority" boils down to this:
1101  static const CharacterSet authority = CharacterSet("authority","-._~%:@[]!$&'()*+,;=") +
1103  if (!tok.skipAll(authority))
1104  break;
1105 
1106  static const SBuf slashUri("/");
1107  const SBuf t = tok.remaining();
1108  if (t.isEmpty())
1109  url = slashUri;
1110  else if (t[0]=='/') // looks like path
1111  url = t;
1112  else if (t[0]=='?' || t[0]=='#') { // looks like query or fragment. fix '/'
1113  url = slashUri;
1114  url.append(t);
1115  } // else do nothing. invalid path
1116 
1117  } while(false);
1118 
1119 #if SHOULD_REJECT_UNKNOWN_URLS
1120  // reject URI which are not well-formed even after the processing above
1121  if (url.isEmpty() || url[0] != '/') {
1122  hp->parseStatusCode = Http::scBadRequest;
1123  return conn->abortRequestParsing("error:invalid-request");
1124  }
1125 #endif
1126 
1127  if (vport < 0)
1128  vport = conn->clientConnection->local.port();
1129 
1130  char *receivedHost = nullptr;
1131  if (vhost && (receivedHost = hp->getHostHeaderField())) {
1132  SBuf host(receivedHost);
1133  debugs(33, 5, "ACCEL VHOST REWRITE: vhost=" << host << " + vport=" << vport);
1134  if (vport > 0) {
1135  // remove existing :port (if any), cope with IPv6+ without port
1136  const auto lastColonPos = host.rfind(':');
1137  if (lastColonPos != SBuf::npos && *host.rbegin() != ']') {
1138  host.chop(0, lastColonPos); // truncate until the last colon
1139  }
1140  host.appendf(":%d", vport);
1141  } // else nothing to alter port-wise.
1142  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1143  const auto url_sz = scheme.length() + host.length() + url.length() + 32;
1144  char *uri = static_cast<char *>(xcalloc(url_sz, 1));
1145  snprintf(uri, url_sz, SQUIDSBUFPH "://" SQUIDSBUFPH SQUIDSBUFPH, SQUIDSBUFPRINT(scheme), SQUIDSBUFPRINT(host), SQUIDSBUFPRINT(url));
1146  debugs(33, 5, "ACCEL VHOST REWRITE: " << uri);
1147  return uri;
1148  } else if (conn->port->defaultsite /* && !vhost */) {
1149  debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: defaultsite=" << conn->port->defaultsite << " + vport=" << vport);
1150  char vportStr[32];
1151  vportStr[0] = '\0';
1152  if (vport > 0) {
1153  snprintf(vportStr, sizeof(vportStr),":%d",vport);
1154  }
1155  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1156  const int url_sz = scheme.length() + strlen(conn->port->defaultsite) + sizeof(vportStr) + url.length() + 32;
1157  char *uri = static_cast<char *>(xcalloc(url_sz, 1));
1158  snprintf(uri, url_sz, SQUIDSBUFPH "://%s%s" SQUIDSBUFPH,
1159  SQUIDSBUFPRINT(scheme), conn->port->defaultsite, vportStr, SQUIDSBUFPRINT(url));
1160  debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: " << uri);
1161  return uri;
1162  } else if (vport > 0 /* && (!vhost || no Host:) */) {
1163  debugs(33, 5, "ACCEL VPORT REWRITE: *_port IP + vport=" << vport);
1164  /* Put the local socket IP address as the hostname, with whatever vport we found */
1166  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1167  const int url_sz = scheme.length() + sizeof(ipbuf) + url.length() + 32;
1168  char *uri = static_cast<char *>(xcalloc(url_sz, 1));
1169  snprintf(uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
1170  SQUIDSBUFPRINT(scheme), ipbuf, vport, SQUIDSBUFPRINT(url));
1171  debugs(33, 5, "ACCEL VPORT REWRITE: " << uri);
1172  return uri;
1173  }
1174 
1175  return nullptr;
1176 }
1177 
1178 static char *
1180 {
1181  char *uri = nullptr;
1182  /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
1183  if (const char *host = hp->getHostHeaderField()) {
1184  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1185  const int url_sz = scheme.length() + strlen(host) + hp->requestUri().length() + 32;
1186  uri = static_cast<char *>(xcalloc(url_sz, 1));
1187  snprintf(uri, url_sz, SQUIDSBUFPH "://%s" SQUIDSBUFPH,
1188  SQUIDSBUFPRINT(scheme),
1189  host,
1190  SQUIDSBUFPRINT(hp->requestUri()));
1191  }
1192  return uri;
1193 }
1194 
1195 char *
1197 {
1198  Must(switchedToHttps());
1199 
1200  if (!hp->requestUri().isEmpty() && hp->requestUri()[0] != '/')
1201  return nullptr; /* already in good shape */
1202 
1203  char *uri = buildUrlFromHost(this, hp);
1204 #if USE_OPENSSL
1205  if (!uri) {
1208  SBuf useHost;
1209  if (!tlsClientSni().isEmpty())
1210  useHost = tlsClientSni();
1211  else
1212  useHost = tlsConnectHostOrIp;
1213 
1214  const SBuf &scheme = AnyP::UriScheme(transferProtocol.protocol).image();
1215  const int url_sz = scheme.length() + useHost.length() + hp->requestUri().length() + 32;
1216  uri = static_cast<char *>(xcalloc(url_sz, 1));
1217  snprintf(uri, url_sz, SQUIDSBUFPH "://" SQUIDSBUFPH ":%hu" SQUIDSBUFPH,
1218  SQUIDSBUFPRINT(scheme),
1219  SQUIDSBUFPRINT(useHost),
1220  *tlsConnectPort,
1221  SQUIDSBUFPRINT(hp->requestUri()));
1222  }
1223 #endif
1224  if (uri)
1225  debugs(33, 5, "TLS switching host rewrite: " << uri);
1226  return uri;
1227 }
1228 
1229 static char *
1231 {
1232  // TODO Must() on URI !empty when the parser supports throw. For now avoid assert().
1233  if (!hp->requestUri().isEmpty() && hp->requestUri()[0] != '/')
1234  return nullptr; /* already in good shape */
1235 
1236  char *uri = buildUrlFromHost(conn, hp);
1237  if (!uri) {
1238  /* Put the local socket IP address as the hostname. */
1239  static char ipbuf[MAX_IPSTRLEN];
1241  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1242  const int url_sz = sizeof(ipbuf) + hp->requestUri().length() + 32;
1243  uri = static_cast<char *>(xcalloc(url_sz, 1));
1244  snprintf(uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
1245  SQUIDSBUFPRINT(scheme),
1246  ipbuf, conn->clientConnection->local.port(), SQUIDSBUFPRINT(hp->requestUri()));
1247  }
1248 
1249  if (uri)
1250  debugs(33, 5, "TRANSPARENT REWRITE: " << uri);
1251  return uri;
1252 }
1253 
1254 Http::Stream *
1256 {
1257  /* Attempt to parse the first line; this will define where the method, url, version and header begin */
1258  {
1259  Must(hp);
1260 
1263 
1264  const bool parsedOk = hp->parse(inBuf);
1265 
1266  // sync the buffers after parsing.
1267  inBuf = hp->remaining();
1268 
1269  if (hp->needsMoreData()) {
1270  debugs(33, 5, "Incomplete request, waiting for end of request line");
1271  return nullptr;
1272  }
1273 
1274  if (!parsedOk) {
1275  const bool tooBig =
1276  hp->parseStatusCode == Http::scRequestHeaderFieldsTooLarge ||
1277  hp->parseStatusCode == Http::scUriTooLong;
1278  auto result = abortRequestParsing(
1279  tooBig ? "error:request-too-large" : "error:invalid-request");
1280  // assume that remaining leftovers belong to this bad request
1281  if (!inBuf.isEmpty())
1283  return result;
1284  }
1285  }
1286 
1287  /* We know the whole request is in parser now */
1288  debugs(11, 2, "HTTP Client " << clientConnection);
1289  debugs(11, 2, "HTTP Client REQUEST:\n---------\n" <<
1290  hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol() << "\n" <<
1291  hp->mimeHeader() <<
1292  "\n----------");
1293 
1294  /* deny CONNECT via accelerated ports */
1295  if (hp->method() == Http::METHOD_CONNECT && port != nullptr && port->flags.accelSurrogate) {
1296  debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << transferProtocol << " Accelerator port " << port->s.port());
1297  debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1298  hp->parseStatusCode = Http::scMethodNotAllowed;
1299  return abortRequestParsing("error:method-not-allowed");
1300  }
1301 
1302  /* HTTP/2 connection magic prefix starts with "PRI ".
1303  * Deny "PRI" method if used in HTTP/1.x or 0.9 versions.
1304  * If seen it signals a broken client or proxy has corrupted the traffic.
1305  */
1306  if (hp->method() == Http::METHOD_PRI && hp->messageProtocol() < Http::ProtocolVersion(2,0)) {
1307  debugs(33, DBG_IMPORTANT, "WARNING: PRI method received on " << transferProtocol << " port " << port->s.port());
1308  debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1309  hp->parseStatusCode = Http::scMethodNotAllowed;
1310  return abortRequestParsing("error:method-not-allowed");
1311  }
1312 
1313  if (hp->method() == Http::METHOD_NONE) {
1314  debugs(33, DBG_IMPORTANT, "WARNING: Unsupported method: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1315  hp->parseStatusCode = Http::scMethodNotAllowed;
1316  return abortRequestParsing("error:unsupported-request-method");
1317  }
1318 
1319  // Process headers after request line
1320  debugs(33, 3, "complete request received. " <<
1321  "prefix_sz = " << hp->messageHeaderSize() <<
1322  ", request-line-size=" << hp->firstLineSize() <<
1323  ", mime-header-size=" << hp->headerBlockSize() <<
1324  ", mime header block:\n" << hp->mimeHeader() << "\n----------");
1325 
1326  /* Ok, all headers are received */
1327  ClientHttpRequest *http = new ClientHttpRequest(this);
1328 
1329  http->req_sz = hp->messageHeaderSize();
1330  Http::Stream *result = new Http::Stream(clientConnection, http);
1331 
1332  StoreIOBuffer tempBuffer;
1333  tempBuffer.data = result->reqbuf;
1334  tempBuffer.length = HTTP_REQBUF_SZ;
1335 
1336  ClientStreamData newServer = new clientReplyContext(http);
1337  ClientStreamData newClient = result;
1340  clientSocketDetach, newClient, tempBuffer);
1341 
1342  /* set url */
1343  debugs(33,5, "Prepare absolute URL from " <<
1344  (transparent()?"intercept":(port->flags.accelSurrogate ? "accel":"")));
1345  /* Rewrite the URL in transparent or accelerator mode */
1346  /* NP: there are several cases to traverse here:
1347  * - standard mode (forward proxy)
1348  * - transparent mode (TPROXY)
1349  * - transparent mode with failures
1350  * - intercept mode (NAT)
1351  * - intercept mode with failures
1352  * - accelerator mode (reverse proxy)
1353  * - internal relative-URL
1354  * - mixed combos of the above with internal URL
1355  * - remote interception with PROXY protocol
1356  * - remote reverse-proxy with PROXY protocol
1357  */
1358  if (switchedToHttps()) {
1359  http->uri = prepareTlsSwitchingURL(hp);
1360  } else if (transparent()) {
1361  /* intercept or transparent mode, properly working with no failures */
1362  http->uri = prepareTransparentURL(this, hp);
1363 
1364  } else if (internalCheck(hp->requestUri())) { // NP: only matches relative-URI
1365  /* internal URL mode */
1366  // XXX: By prepending our name and port, we create an absolute URL
1367  // that may mismatch the (yet unparsed) Host header in the request.
1368  http->uri = xstrdup(internalLocalUri(nullptr, hp->requestUri()));
1369 
1370  } else if (port->flags.accelSurrogate) {
1371  /* accelerator mode */
1372  http->uri = prepareAcceleratedURL(this, hp);
1373  http->flags.accel = true;
1374  }
1375 
1376  if (!http->uri) {
1377  /* No special rewrites have been applied above, use the
1378  * requested url. may be rewritten later, so make extra room */
1379  int url_sz = hp->requestUri().length() + Config.appendDomainLen + 5;
1380  http->uri = (char *)xcalloc(url_sz, 1);
1381  SBufToCstring(http->uri, hp->requestUri());
1382  }
1383 
1384  result->flags.parsed_ok = 1;
1385  return result;
1386 }
1387 
1388 bool
1390 {
1391  if (pipeline.empty() && inBuf.isEmpty()) {
1392  debugs(33, 4, "yes, without active requests and unparsed input");
1393  return true;
1394  }
1395 
1397  debugs(33, 3, "yes, without half_closed_clients");
1398  return true;
1399  }
1400 
1401  // Squid currently tries to parse (possibly again) a partially received
1402  // request after an EOF with half_closed_clients. To give that last parse in
1403  // afterClientRead() a chance, we ignore partially parsed requests here.
1404  debugs(33, 3, "no, honoring half_closed_clients");
1405  return false;
1406 }
1407 
1408 void
1409 ConnStateData::consumeInput(const size_t byteCount)
1410 {
1411  assert(byteCount > 0 && byteCount <= inBuf.length());
1412  inBuf.consume(byteCount);
1413  debugs(33, 5, "inBuf has " << inBuf.length() << " unused bytes");
1414 }
1415 
1416 void
1418 {
1419  // Were we expecting to read more request body from half-closed connection?
1421  debugs(33, 3, "truncated body: closing half-closed " << clientConnection);
1423  return;
1424  }
1425 
1426  if (flags.readMore)
1427  readSomeData();
1428 }
1429 
1430 void
1432 {
1433  // From HTTP p.o.v., we do not have to close after every error detected
1434  // at the client-side, but many such errors do require closure and the
1435  // client-side code is bad at handling errors so we play it safe.
1436  if (request)
1437  request->flags.proxyKeepalive = false;
1438  flags.readMore = false;
1439  debugs(33,4, "Will close after error: " << clientConnection);
1440 }
1441 
1442 #if USE_OPENSSL
1444 {
1445  ClientHttpRequest *http = context->http;
1446 
1447  if (!sslServerBump)
1448  return false;
1449 
1451  // Did we create an error entry while processing CONNECT?
1452  if (!sslServerBump->entry->isEmpty()) {
1453  quitAfterError(http->request);
1454 
1455  // Get the saved error entry and send it to the client by replacing the
1456  // ClientHttpRequest store entry with it.
1458  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1459  assert(repContext);
1460  debugs(33, 5, "Responding with delated error for " << http->uri);
1461  repContext->setReplyToStoreEntry(sslServerBump->entry, "delayed SslBump error");
1462 
1463  // Get error details from the fake certificate-peeking request.
1465  context->pullData();
1466  return true;
1467  }
1468 
1469  // In bump-server-first mode, we have not necessarily seen the intended
1470  // server name at certificate-peeking time. Check for domain mismatch now,
1471  // when we can extract the intended name from the bumped HTTP request.
1472  if (const Security::CertPointer &srvCert = sslServerBump->serverCert) {
1473  HttpRequest *request = http->request;
1474  const auto host = request->url.parsedHost();
1475  if (host && Ssl::HasSubjectName(*srvCert, *host)) {
1476  debugs(33, 5, "certificate matches requested host: " << *host);
1477  return false;
1478  } else {
1479  debugs(33, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " <<
1480  "does not match request target " << RawPointer(host));
1481 
1482  bool allowDomainMismatch = false;
1485  const auto sslErrors = std::make_unique<Security::CertErrors>(Security::CertError(SQUID_X509_V_ERR_DOMAIN_MISMATCH, srvCert));
1486  check.sslErrors = sslErrors.get();
1487  clientAclChecklistFill(check, http);
1488  allowDomainMismatch = check.fastCheck().allowed();
1489  }
1490 
1491  if (!allowDomainMismatch) {
1492  quitAfterError(request);
1493 
1495  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1496  assert (repContext);
1497 
1498  request->hier = sslServerBump->request->hier;
1499 
1500  // Create an error object and fill it
1501  const auto err = new ErrorState(ERR_SECURE_CONNECT_FAIL, Http::scServiceUnavailable, request, http->al);
1502  err->src_addr = clientConnection->remote;
1505  srvCert, nullptr);
1507  repContext->setReplyToError(request->method, err);
1508  assert(context->http->out.offset == 0);
1509  context->pullData();
1510  return true;
1511  }
1512  }
1513  }
1514 
1515  return false;
1516 }
1517 #endif // USE_OPENSSL
1518 
1520 bool
1522 {
1524  debugs(33, 5, "disabled; send error: " << requestError);
1525  return false;
1526  }
1527 
1528  if (!preservingClientData_) {
1529  debugs(33, 3, "may have forgotten client data; send error: " << requestError);
1530  return false;
1531  }
1532 
1534  checklist.requestErrorType = requestError;
1535  fillChecklist(checklist);
1536  const auto &answer = checklist.fastCheck();
1537  if (answer.allowed() && answer.kind == 1) {
1538  debugs(33, 3, "Request will be tunneled to server");
1539  const auto context = pipeline.front();
1540  const auto http = context ? context->http : nullptr;
1541  const auto request = http ? http->request : nullptr;
1542  if (context)
1543  context->finished(); // Will remove from pipeline queue
1544  Comm::SetSelect(clientConnection->fd, COMM_SELECT_READ, nullptr, nullptr, 0);
1545  return initiateTunneledRequest(request, "unknown-protocol", preservedClientData);
1546  }
1547  debugs(33, 3, "denied; send error: " << requestError);
1548  return false;
1549 }
1550 
1551 void
1553 {
1554  /*
1555  * DPW 2007-05-18
1556  * Moved the TCP_RESET feature from clientReplyContext::sendMoreData
1557  * to here because calling comm_reset_close() causes http to
1558  * be freed before accessing.
1559  */
1560  if (request != nullptr && request->flags.resetTcp && Comm::IsConnOpen(conn->clientConnection)) {
1561  debugs(33, 3, "Sending TCP RST on " << conn->clientConnection);
1562  conn->flags.readMore = false;
1564  }
1565 }
1566 
1567 void
1569 {
1570  ClientHttpRequest *http = context->http;
1571  bool mustReplyToOptions = false;
1572  bool expectBody = false;
1573 
1574  // We already have the request parsed and checked, so we
1575  // only need to go through the final body/conn setup to doCallouts().
1576  assert(http->request);
1577  HttpRequest::Pointer request = http->request;
1578 
1579  // temporary hack to avoid splitting this huge function with sensitive code
1580  const bool isFtp = !hp;
1581 
1582  // Some blobs below are still HTTP-specific, but we would have to rewrite
1583  // this entire function to remove them from the FTP code path. Connection
1584  // setup and body_pipe preparation blobs are needed for FTP.
1585 
1586  request->manager(conn, http->al);
1587 
1588  request->flags.accelerated = http->flags.accel;
1589  request->flags.sslBumped=conn->switchedToHttps();
1590  // TODO: decouple http->flags.accel from request->flags.sslBumped
1591  request->flags.noDirect = (request->flags.accelerated && !request->flags.sslBumped) ?
1592  !conn->port->allow_direct : 0;
1593  request->sources |= isFtp ? Http::Message::srcFtp :
1594  ((request->flags.sslBumped || conn->port->transport.protocol == AnyP::PROTO_HTTPS) ? Http::Message::srcHttps : Http::Message::srcHttp);
1595 #if USE_AUTH
1596  if (request->flags.sslBumped) {
1597  if (conn->getAuth() != nullptr)
1598  request->auth_user_request = conn->getAuth();
1599  }
1600 #endif
1601 
1602  http->checkForInternalAccess();
1603 
1604  if (!isFtp) {
1605  // XXX: for non-HTTP messages instantiate a different Http::Message child type
1606  // for now Squid only supports HTTP requests
1607  const AnyP::ProtocolVersion &http_ver = hp->messageProtocol();
1608  assert(request->http_ver.protocol == http_ver.protocol);
1609  request->http_ver.major = http_ver.major;
1610  request->http_ver.minor = http_ver.minor;
1611  }
1612 
1613  mustReplyToOptions = (request->method == Http::METHOD_OPTIONS) &&
1614  (request->header.getInt64(Http::HdrType::MAX_FORWARDS) == 0);
1615  if (!urlCheckRequest(request.getRaw()) || mustReplyToOptions) {
1617  conn->quitAfterError(request.getRaw());
1618  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1619  assert (repContext);
1621  conn, request.getRaw(), nullptr, nullptr);
1622  assert(context->http->out.offset == 0);
1623  context->pullData();
1624  clientProcessRequestFinished(conn, request);
1625  return;
1626  }
1627 
1628  const auto frameStatus = request->checkEntityFraming();
1629  if (frameStatus != Http::scNone) {
1631  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1632  assert (repContext);
1633  conn->quitAfterError(request.getRaw());
1634  repContext->setReplyToError(ERR_INVALID_REQ, frameStatus, nullptr, conn, request.getRaw(), nullptr, nullptr);
1635  assert(context->http->out.offset == 0);
1636  context->pullData();
1637  clientProcessRequestFinished(conn, request);
1638  return;
1639  }
1640 
1641  clientSetKeepaliveFlag(http);
1642  // Let tunneling code be fully responsible for CONNECT requests
1643  if (http->request->method == Http::METHOD_CONNECT) {
1644  context->mayUseConnection(true);
1645  conn->flags.readMore = false;
1646  }
1647 
1648 #if USE_OPENSSL
1649  if (conn->switchedToHttps() && conn->serveDelayedError(context)) {
1650  clientProcessRequestFinished(conn, request);
1651  return;
1652  }
1653 #endif
1654 
1655  /* Do we expect a request-body? */
1656  const auto chunked = request->header.chunked();
1657  expectBody = chunked || request->content_length > 0;
1658  if (!context->mayUseConnection() && expectBody) {
1659  request->body_pipe = conn->expectRequestBody(
1660  chunked ? -1 : request->content_length);
1661 
1662  /* Is it too large? */
1663  if (!chunked && // if chunked, we will check as we accumulate
1666  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1667  assert (repContext);
1668  conn->quitAfterError(request.getRaw());
1669  repContext->setReplyToError(ERR_TOO_BIG,
1670  Http::scContentTooLarge, nullptr,
1671  conn, http->request, nullptr, nullptr);
1672  assert(context->http->out.offset == 0);
1673  context->pullData();
1674  clientProcessRequestFinished(conn, request);
1675  return;
1676  }
1677 
1678  if (!isFtp) {
1679  // We may stop producing, comm_close, and/or call setReplyToError()
1680  // below, so quit on errors to avoid http->doCallouts()
1681  if (!conn->handleRequestBodyData()) {
1682  clientProcessRequestFinished(conn, request);
1683  return;
1684  }
1685 
1686  if (!request->body_pipe->productionEnded()) {
1687  debugs(33, 5, "need more request body");
1688  context->mayUseConnection(true);
1689  assert(conn->flags.readMore);
1690  }
1691  }
1692  }
1693 
1694  http->calloutContext = new ClientRequestContext(http);
1695 
1696  http->doCallouts();
1697 
1698  clientProcessRequestFinished(conn, request);
1699 }
1700 
1701 void
1703 {
1704  debugs(33, 3, context << " to " << pipeline.count() << '/' << pipeline.nrequests);
1705  if (bareError) {
1706  debugs(33, 5, "assigning " << bareError);
1707  assert(context);
1708  assert(context->http);
1709  context->http->updateError(bareError);
1710  bareError.clear();
1711  }
1712  pipeline.add(context);
1713 }
1714 
1715 int
1717 {
1718  // TODO: Support pipelined requests through pinned connections.
1719  if (pinning.pinned)
1720  return 0;
1722 }
1723 
1729 bool
1731 {
1732  const int existingRequestCount = pipeline.count();
1733 
1734  // default to the configured pipeline size.
1735  // add 1 because the head of pipeline is counted in concurrent requests and not prefetch queue
1736 #if USE_OPENSSL
1737  const int internalRequest = (transparent() && sslBumpMode == Ssl::bumpSplice) ? 1 : 0;
1738 #else
1739  const int internalRequest = 0;
1740 #endif
1741  const int concurrentRequestLimit = pipelinePrefetchMax() + 1 + internalRequest;
1742 
1743  // when queue filled already we can't add more.
1744  if (existingRequestCount >= concurrentRequestLimit) {
1745  debugs(33, 3, clientConnection << " max concurrent requests reached (" << concurrentRequestLimit << ")");
1746  debugs(33, 5, clientConnection << " deferring new request until one is done");
1747  return true;
1748  }
1749 
1750  return false;
1751 }
1752 
1758 bool
1760 {
1762  return proxyProtocolError("PROXY client not permitted by default ACL");
1763 
1765  fillChecklist(ch);
1766  if (!ch.fastCheck().allowed())
1767  return proxyProtocolError("PROXY client not permitted by ACLs");
1768 
1769  return true;
1770 }
1771 
1777 bool
1779 {
1780  if (msg) {
1781  // This is important to know, but maybe not so much that flooding the log is okay.
1782 #if QUIET_PROXY_PROTOCOL
1783  // display the first of every 32 occurrences at level 1, the others at level 2.
1784  static uint8_t hide = 0;
1785  debugs(33, (hide++ % 32 == 0 ? DBG_IMPORTANT : 2), msg << " from " << clientConnection);
1786 #else
1787  debugs(33, DBG_IMPORTANT, msg << " from " << clientConnection);
1788 #endif
1789  mustStop(msg);
1790  }
1791  return false;
1792 }
1793 
1798 bool
1800 {
1801  try {
1802  const auto parsed = ProxyProtocol::Parse(inBuf);
1803  proxyProtocolHeader_ = parsed.header;
1805  inBuf.consume(parsed.size);
1806  needProxyProtocolHeader_ = false;
1807  if (proxyProtocolHeader_->hasForwardedAddresses()) {
1808  clientConnection->local = proxyProtocolHeader_->destinationAddress;
1809  clientConnection->remote = proxyProtocolHeader_->sourceAddress;
1811  clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
1812  debugs(33, 5, "PROXY/" << proxyProtocolHeader_->version() << " upgrade: " << clientConnection);
1813  }
1814  } catch (const Parser::BinaryTokenizer::InsufficientInput &) {
1815  debugs(33, 3, "PROXY protocol: waiting for more than " << inBuf.length() << " bytes");
1816  return false;
1817  } catch (const std::exception &e) {
1818  return proxyProtocolError(e.what());
1819  }
1820  return true;
1821 }
1822 
1823 void
1825 {
1826  if (receivedFirstByte_)
1827  return;
1828 
1829  receivedFirstByte_ = true;
1831 }
1832 
1835 void
1837 {
1838  debugs(33, 5, clientConnection << ": attempting to parse");
1839 
1840  // Loop while we have read bytes that are not needed for producing the body
1841  // On errors, bodyPipe may become nil, but readMore will be cleared
1842  while (!inBuf.isEmpty() && !bodyPipe && flags.readMore) {
1843 
1844  // Prohibit concurrent requests when using a pinned to-server connection
1845  // because our Client classes do not support request pipelining.
1846  if (pinning.pinned && !pinning.readHandler) {
1847  debugs(33, 3, clientConnection << " waits for busy " << pinning.serverConnection);
1848  break;
1849  }
1850 
1851  /* Limit the number of concurrent requests */
1853  break;
1854 
1855  // try to parse the PROXY protocol header magic bytes
1857  if (!parseProxyProtocolHeader())
1858  break;
1859 
1860  // we have been waiting for PROXY to provide client-IP
1861  // for some lookups, ie rDNS
1863 
1864  // Done with PROXY protocol which has cleared preservingClientData_.
1865  // If the next protocol supports on_unsupported_protocol, then its
1866  // parseOneRequest() must reset preservingClientData_.
1868  }
1869 
1870  if (Http::StreamPointer context = parseOneRequest()) {
1871  debugs(33, 5, clientConnection << ": done parsing a request");
1872  extendLifetime();
1873  context->registerWithConn();
1874 
1875 #if USE_OPENSSL
1876  if (switchedToHttps())
1878 #endif
1879 
1880  processParsedRequest(context);
1881 
1882  if (context->mayUseConnection()) {
1883  debugs(33, 3, "Not parsing new requests, as this request may need the connection");
1884  break;
1885  }
1886  } else {
1887  debugs(33, 5, clientConnection << ": not enough request data: " <<
1888  inBuf.length() << " < " << Config.maxRequestHeaderSize);
1890  break;
1891  }
1892  }
1893 
1894  debugs(33, 7, "buffered leftovers: " << inBuf.length());
1895 
1897  if (pipeline.empty()) {
1898  // we processed what we could parse, and no more data is coming
1899  debugs(33, 5, "closing half-closed without parsed requests: " << clientConnection);
1901  } else {
1902  // we parsed what we could, and no more data is coming
1903  debugs(33, 5, "monitoring half-closed while processing parsed requests: " << clientConnection);
1904  flags.readMore = false; // may already be false
1905  }
1906  }
1907 }
1908 
1909 void
1911 {
1912 #if USE_OPENSSL
1913  if (parsingTlsHandshake) {
1915  return;
1916  }
1917 #endif
1918 
1919  /* Process next request */
1920  if (pipeline.empty())
1921  fd_note(clientConnection->fd, "Reading next request");
1922 
1923  parseRequests();
1924 
1925  if (!isOpen())
1926  return;
1927 
1929 }
1930 
1937 bool
1939 {
1940  // if we are reading a body, stuff data into the body pipe
1941  if (bodyPipe != nullptr)
1942  return handleRequestBodyData();
1943  return true;
1944 }
1945 
1953 bool
1955 {
1956  assert(bodyPipe != nullptr);
1957 
1958  if (bodyParser) { // chunked encoding
1959  if (const err_type error = handleChunkedRequestBody()) {
1961  return false;
1962  }
1963  } else { // identity encoding
1964  debugs(33,5, "handling plain request body for " << clientConnection);
1965  const auto putSize = bodyPipe->putMoreData(inBuf.rawContent(), inBuf.length());
1966  if (putSize > 0)
1967  consumeInput(putSize);
1968 
1969  if (!bodyPipe->mayNeedMoreData()) {
1970  // BodyPipe will clear us automagically when we produced everything
1971  bodyPipe = nullptr;
1972  }
1973  }
1974 
1975  if (!bodyPipe) {
1976  debugs(33,5, "produced entire request body for " << clientConnection);
1977 
1978  if (const char *reason = stoppedSending()) {
1979  /* we've finished reading like good clients,
1980  * now do the close that initiateClose initiated.
1981  */
1982  debugs(33, 3, "closing for earlier sending error: " << reason);
1984  return false;
1985  }
1986  }
1987 
1988  return true;
1989 }
1990 
1992 err_type
1994 {
1995  debugs(33, 7, "chunked from " << clientConnection << ": " << inBuf.length());
1996 
1997  try { // the parser will throw on errors
1998 
1999  if (inBuf.isEmpty()) // nothing to do
2000  return ERR_NONE;
2001 
2002  BodyPipeCheckout bpc(*bodyPipe);
2004  const bool parsed = bodyParser->parse(inBuf);
2005  inBuf = bodyParser->remaining(); // sync buffers
2006  bpc.checkIn();
2007 
2008  // dechunk then check: the size limit applies to _dechunked_ content
2010  return ERR_TOO_BIG;
2011 
2012  if (parsed) {
2014  Must(!bodyPipe);
2015  return ERR_NONE; // nil bodyPipe implies body end for the caller
2016  }
2017 
2018  // if chunk parser needs data, then the body pipe must need it too
2020 
2021  // if parser needs more space and we can consume nothing, we will stall
2023  } catch (...) { // TODO: be more specific
2024  debugs(33, 3, "malformed chunks" << bodyPipe->status());
2025  return ERR_INVALID_REQ;
2026  }
2027 
2028  debugs(33, 7, "need more chunked data" << *bodyPipe->status());
2029  return ERR_NONE;
2030 }
2031 
2033 void
2035 {
2036  finishDechunkingRequest(false);
2037 
2038  // XXX: The code below works if we fail during initial request parsing,
2039  // but if we fail when the server connection is used already, the server may send
2040  // us its response too, causing various assertions. How to prevent that?
2041 #if WE_KNOW_HOW_TO_SEND_ERRORS
2042  Http::StreamPointer context = pipeline.front();
2043  if (context != NULL && !context->http->out.offset) { // output nothing yet
2044  clientStreamNode *node = context->getClientReplyContext();
2045  clientReplyContext *repContext = dynamic_cast<clientReplyContext*>(node->data.getRaw());
2046  assert(repContext);
2047  const Http::StatusCode scode = (error == ERR_TOO_BIG) ?
2048  Http::scContentTooLarge : HTTP_BAD_REQUEST;
2049  repContext->setReplyToError(error, scode,
2050  repContext->http->uri,
2051  CachePeer,
2052  repContext->http->request,
2053  inBuf, nullptr);
2054  context->pullData();
2055  } else {
2056  // close or otherwise we may get stuck as nobody will notice the error?
2058  }
2059 #else
2060  debugs(33, 3, "aborting chunked request without error " << error);
2062 #endif
2063  flags.readMore = false;
2064 }
2065 
2066 void
2068 {
2069  // request reader may get stuck waiting for space if nobody consumes body
2070  if (bodyPipe != nullptr)
2072 
2073  // kids extend
2074 }
2075 
2077 void
2079 {
2080  if (!Comm::IsConnOpen(io.conn))
2081  return;
2082 
2084  updateError(error);
2085  if (tunnelOnError(error))
2086  return;
2087 
2088  /*
2089  * Just close the connection to not confuse browsers
2090  * using persistent connections. Some browsers open
2091  * a connection and then do not use it until much
2092  * later (presumeably because the request triggering
2093  * the open has already been completed on another
2094  * connection)
2095  */
2096  debugs(33, 3, "requestTimeout: FD " << io.fd << ": lifetime is expired.");
2097  io.conn->close();
2098 }
2099 
2100 void
2102 {
2103  debugs(33, DBG_IMPORTANT, "WARNING: Closing client connection due to lifetime timeout" <<
2104  Debug::Extra << "connection: " << io.conn);
2105 
2106  LogTagsErrors lte;
2107  lte.timedout = true;
2109 }
2110 
2112  AsyncJob("ConnStateData"), // kids overwrite
2113  Server(xact)
2114 #if USE_OPENSSL
2115  , tlsParser(Security::HandshakeParser::fromClient)
2116 #endif
2117 {
2118  // store the details required for creating more MasterXaction objects as new requests come in
2119  log_addr = xact->tcpClient->remote;
2121 
2122  // register to receive notice of Squid signal events
2123  // which may affect long persisting client connections
2124  registerRunner();
2125 }
2126 
2127 void
2129 {
2132 
2133  if (port->disable_pmtu_discovery != DISABLE_PMTU_OFF &&
2134  (transparent() || port->disable_pmtu_discovery == DISABLE_PMTU_ALWAYS)) {
2135 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
2136  int i = IP_PMTUDISC_DONT;
2137  if (setsockopt(clientConnection->fd, SOL_IP, IP_MTU_DISCOVER, &i, sizeof(i)) < 0) {
2138  int xerrno = errno;
2139  debugs(33, 2, "WARNING: Path MTU discovery disabling failed on " << clientConnection << " : " << xstrerr(xerrno));
2140  }
2141 #else
2142  static bool reported = false;
2143 
2144  if (!reported) {
2145  debugs(33, DBG_IMPORTANT, "WARNING: Path MTU discovery disabling is not supported on your platform.");
2146  reported = true;
2147  }
2148 #endif
2149  }
2150 
2152  AsyncCall::Pointer call = JobCallback(33, 5, Dialer, this, ConnStateData::connStateClosed);
2154 
2155  needProxyProtocolHeader_ = port->flags.proxySurrogate;
2157  if (!proxyProtocolValidateClient()) // will close the connection on failure
2158  return;
2159  } else
2161 
2162  // requires needProxyProtocolHeader_ which is initialized above
2164 }
2165 
2166 void
2168 {
2169  debugs(33, 7, clientConnection->remote);
2172 
2174 
2175 #if USE_DELAY_POOLS
2176  fd_table[clientConnection->fd].clientInfo = nullptr;
2177 
2178  if (!Config.onoff.client_db)
2179  return; // client delay pools require client_db
2180 
2181  const auto &pools = ClientDelayPools::Instance()->pools;
2182  if (pools.size()) {
2183  ACLFilledChecklist ch(nullptr, nullptr);
2184  fillChecklist(ch);
2185  // TODO: we check early to limit error response bandwidth but we
2186  // should recheck when we can honor delay_pool_uses_indirect
2187  for (unsigned int pool = 0; pool < pools.size(); ++pool) {
2188 
2189  /* pools require explicit 'allow' to assign a client into them */
2190  if (pools[pool]->access) {
2191  ch.changeAcl(pools[pool]->access);
2192  const auto &answer = ch.fastCheck();
2193  if (answer.allowed()) {
2194 
2195  /* request client information from db after we did all checks
2196  this will save hash lookup if client failed checks */
2198  assert(cli);
2199 
2200  /* put client info in FDE */
2201  fd_table[clientConnection->fd].clientInfo = cli;
2202 
2203  /* setup write limiter for this request */
2204  const double burst = floor(0.5 +
2205  (pools[pool]->highwatermark * Config.ClientDelay.initial)/100.0);
2206  cli->setWriteLimiter(pools[pool]->rate, burst, pools[pool]->highwatermark);
2207  break;
2208  } else {
2209  debugs(83, 4, "Delay pool " << pool << " skipped because ACL " << answer);
2210  }
2211  }
2212  }
2213  }
2214 #endif
2215 
2216  // kids must extend to actually start doing something (e.g., reading)
2217 }
2218 
2221 {
2222  const auto handshakeResult = Security::Accept(*clientConnection);
2223 
2224 #if USE_OPENSSL
2225  // log ASAP, even if the handshake has not completed (or failed)
2226  const auto fd = clientConnection->fd;
2227  assert(fd >= 0);
2228  keyLogger.checkpoint(*fd_table[fd].ssl, *this);
2229 #else
2230  // TODO: Support fd_table[fd].ssl dereference in other builds.
2231 #endif
2232 
2233  return handshakeResult;
2234 }
2235 
2237 void
2239 {
2240  Assure(params.port);
2241 
2242  // NP: it is possible the port was reconfigured when the call or accept() was queued.
2243 
2244  if (params.flag != Comm::OK) {
2245  // Its possible the call was still queued when the client disconnected
2246  debugs(33, 2, params.port->listenConn << ": accept failure: " << xstrerr(params.xerrno));
2247  return;
2248  }
2249 
2250  debugs(33, 4, params.conn << ": accepted");
2251  fd_note(params.conn->fd, "client http connect");
2252  const auto xact = MasterXaction::MakePortful(params.port);
2253  xact->tcpClient = params.conn;
2254 
2255  // Socket is ready, setup the connection manager to start using it
2256  auto *srv = Http::NewServer(xact);
2257  // XXX: do not abandon the MasterXaction object
2258  AsyncJob::Start(srv); // usually async-calls readSomeData()
2259 }
2260 
2262 static bool
2264 {
2265  const auto conn = connState->clientConnection;
2266  if (Security::CreateServerSession(ctx, conn, connState->port->secure, "client https start")) {
2267  debugs(33, 5, "will negotiate TLS on " << conn);
2268  return true;
2269  }
2270 
2271  debugs(33, DBG_IMPORTANT, "ERROR: could not create TLS server context for " << conn);
2272  conn->close();
2273  return false;
2274 }
2275 
2277 static void
2278 clientNegotiateSSL(int fd, void *data)
2279 {
2280  ConnStateData *conn = (ConnStateData *)data;
2281 
2282  const auto handshakeResult = conn->acceptTls();
2283  switch (handshakeResult.category) {
2285  break;
2286 
2289  return;
2290 
2293  return;
2294 
2296  debugs(83, (handshakeResult.important ? Important(62) : 2), "ERROR: Cannot accept a TLS connection" <<
2297  Debug::Extra << "problem: " << WithExtras(handshakeResult));
2298  // TODO: No ConnStateData::tunnelOnError() on this forward-proxy code
2299  // path because we cannot know the intended connection target?
2300  conn->updateError(ERR_SECURE_ACCEPT_FAIL, handshakeResult.errorDetail);
2301  conn->clientConnection->close();
2302  return;
2303  }
2304 
2305  Security::SessionPointer session(fd_table[fd].ssl);
2306 
2307 #if USE_OPENSSL
2308  if (Security::SessionIsResumed(session)) {
2309  debugs(83, 2, "Session " << SSL_get_session(session.get()) <<
2310  " reused on FD " << fd << " (" << fd_table[fd].ipaddr <<
2311  ":" << (int)fd_table[fd].remote_port << ")");
2312  } else {
2313  if (Debug::Enabled(83, 4)) {
2314  /* Write out the SSL session details.. actually the call below, but
2315  * OpenSSL headers do strange typecasts confusing GCC.. */
2316  /* PEM_write_SSL_SESSION(DebugStream(), SSL_get_session(ssl)); */
2317 #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00908000L
2318  PEM_ASN1_write(reinterpret_cast<i2d_of_void *>(i2d_SSL_SESSION),
2319  PEM_STRING_SSL_SESSION, DebugStream(),
2320  reinterpret_cast<char *>(SSL_get_session(session.get())),
2321  nullptr, nullptr, 0, nullptr, nullptr);
2322 
2323 #elif (ALLOW_ALWAYS_SSL_SESSION_DETAIL == 1)
2324 
2325  /* When using gcc 3.3.x and OpenSSL 0.9.7x sometimes a compile error can occur here.
2326  * This is caused by an unpredicatble gcc behaviour on a cast of the first argument
2327  * of PEM_ASN1_write(). For this reason this code section is disabled. To enable it,
2328  * define ALLOW_ALWAYS_SSL_SESSION_DETAIL=1.
2329  * Because there are two possible usable cast, if you get an error here, try the other
2330  * commented line. */
2331 
2332  PEM_ASN1_write((int(*)())i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2333  DebugStream(),
2334  reinterpret_cast<char *>(SSL_get_session(session.get())),
2335  nullptr, nullptr, 0, nullptr, nullptr);
2336  /* PEM_ASN1_write((int(*)(...))i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2337  DebugStream(),
2338  reinterpret_cast<char *>(SSL_get_session(session.get())),
2339  nullptr, nullptr, 0, nullptr, nullptr);
2340  */
2341 #else
2342  debugs(83, 4, "With " OPENSSL_VERSION_TEXT ", session details are available only defining ALLOW_ALWAYS_SSL_SESSION_DETAIL=1 in the source.");
2343 
2344 #endif
2345  /* Note: This does not automatically fflush the log file.. */
2346  }
2347 
2348  debugs(83, 2, "New session " << SSL_get_session(session.get()) <<
2349  " on FD " << fd << " (" << fd_table[fd].ipaddr << ":" <<
2350  fd_table[fd].remote_port << ")");
2351  }
2352 #else
2353  debugs(83, 2, "TLS session reuse not yet implemented.");
2354 #endif
2355 
2356  // Connection established. Retrieve TLS connection parameters for logging.
2358 
2359 #if USE_OPENSSL
2360  X509 *client_cert = SSL_get_peer_certificate(session.get());
2361 
2362  if (client_cert) {
2363  debugs(83, 3, "FD " << fd << " client certificate: subject: " <<
2364  Security::SubjectName(*client_cert));
2365 
2366  debugs(83, 3, "FD " << fd << " client certificate: issuer: " <<
2367  Security::IssuerName(*client_cert));
2368 
2369  X509_free(client_cert);
2370  } else {
2371  debugs(83, 5, "FD " << fd << " has no client certificate.");
2372  }
2373 #else
2374  debugs(83, 2, "Client certificate requesting not yet implemented.");
2375 #endif
2376 
2377  // If we are called, then bumped CONNECT has succeeded. Finalize it.
2378  if (auto xact = conn->pipeline.front()) {
2379  if (xact->http && xact->http->request && xact->http->request->method == Http::METHOD_CONNECT)
2380  xact->finished();
2381  // cannot proceed with encryption if requests wait for plain responses
2382  Must(conn->pipeline.empty());
2383  }
2384  /* careful: finished() above frees request, host, etc. */
2385 
2386  conn->readSomeData();
2387 }
2388 
2393 static void
2395 {
2396  assert(connState);
2397  const Comm::ConnectionPointer &details = connState->clientConnection;
2398 
2399  if (!ctx || !httpsCreate(connState, ctx))
2400  return;
2401 
2402  connState->resetReadTimeout(Config.Timeout.request);
2403 
2404  Comm::SetSelect(details->fd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
2405 }
2406 
2407 #if USE_OPENSSL
2408 
2411 static void
2413 {
2414  ConnStateData *connState = (ConnStateData *) data;
2415 
2416  // if the connection is closed or closing, just return.
2417  if (!connState->isOpen())
2418  return;
2419 
2420  if (answer.allowed()) {
2421  debugs(33, 2, "sslBump action " << Ssl::bumpMode(answer.kind) << "needed for " << connState->clientConnection);
2422  connState->sslBumpMode = static_cast<Ssl::BumpMode>(answer.kind);
2423  } else {
2424  debugs(33, 3, "sslBump not needed for " << connState->clientConnection);
2425  connState->sslBumpMode = Ssl::bumpSplice;
2426  }
2427 
2428  if (connState->sslBumpMode == Ssl::bumpTerminate) {
2429  connState->clientConnection->close();
2430  return;
2431  }
2432 
2433  if (!connState->fakeAConnectRequest("ssl-bump", connState->inBuf))
2434  connState->clientConnection->close();
2435 }
2436 #endif
2437 
2439 static void
2441 {
2442  Assure(params.port);
2443 
2444  // NP: it is possible the port was reconfigured when the call or accept() was queued.
2445 
2446  if (params.flag != Comm::OK) {
2447  // Its possible the call was still queued when the client disconnected
2448  debugs(33, 2, "httpsAccept: " << params.port->listenConn << ": accept failure: " << xstrerr(params.xerrno));
2449  return;
2450  }
2451 
2452  const auto xact = MasterXaction::MakePortful(params.port);
2453  xact->tcpClient = params.conn;
2454 
2455  debugs(33, 4, params.conn << " accepted, starting SSL negotiation.");
2456  fd_note(params.conn->fd, "client https connect");
2457 
2458  // Socket is ready, setup the connection manager to start using it
2459  auto *srv = Https::NewServer(xact);
2460  // XXX: do not abandon the MasterXaction object
2461  AsyncJob::Start(srv); // usually async-calls postHttpsAccept()
2462 }
2463 
2464 void
2466 {
2467  if (port->flags.tunnelSslBumping) {
2468 #if USE_OPENSSL
2469  debugs(33, 5, "accept transparent connection: " << clientConnection);
2470 
2471  if (!Config.accessList.ssl_bump) {
2473  return;
2474  }
2475 
2476  const auto mx = MasterXaction::MakePortful(port);
2477  mx->tcpClient = clientConnection;
2478  // Create a fake HTTP request and ALE for the ssl_bump ACL check,
2479  // using tproxy/intercept provided destination IP and port.
2480  // XXX: Merge with subsequent fakeAConnectRequest(), buildFakeRequest().
2481  // XXX: Do this earlier (e.g., in Http[s]::One::Server constructor).
2482  HttpRequest *request = new HttpRequest(mx);
2483  static char ip[MAX_IPSTRLEN];
2485  request->url.host(clientConnection->local.toStr(ip, sizeof(ip)));
2486  request->url.port(clientConnection->local.port());
2487  request->myportname = port->name;
2488  const AccessLogEntry::Pointer connectAle = new AccessLogEntry;
2489  CodeContext::Reset(connectAle);
2490  // TODO: Use these request/ALE when waiting for new bumped transactions.
2491 
2492  auto acl_checklist = ACLFilledChecklist::Make(Config.accessList.ssl_bump, request);
2493  fillChecklist(*acl_checklist);
2494  // Build a local AccessLogEntry to allow requiresAle() acls work
2495  acl_checklist->al = connectAle;
2496  acl_checklist->al->cache.start_time = current_time;
2497  acl_checklist->al->tcpClient = clientConnection;
2498  acl_checklist->al->cache.port = port;
2499  acl_checklist->al->cache.caddr = log_addr;
2500  acl_checklist->al->proxyProtocolHeader = proxyProtocolHeader_;
2501  acl_checklist->al->updateError(bareError);
2502  HTTPMSGUNLOCK(acl_checklist->al->request);
2503  acl_checklist->al->request = request;
2504  HTTPMSGLOCK(acl_checklist->al->request);
2505  Http::StreamPointer context = pipeline.front();
2506  ClientHttpRequest *http = context ? context->http : nullptr;
2507  const char *log_uri = http ? http->log_uri : nullptr;
2508  acl_checklist->syncAle(request, log_uri);
2509  ACLFilledChecklist::NonBlockingCheck(std::move(acl_checklist), httpsSslBumpAccessCheckDone, this);
2510 #else
2511  fatal("FATAL: SSL-Bump requires --with-openssl");
2512 #endif
2513  return;
2514  } else {
2515  httpsEstablish(this, port->secure.staticContext);
2516  }
2517 }
2518 
2519 #if USE_OPENSSL
2520 void
2522 {
2523  ConnStateData * state_data = (ConnStateData *)(data);
2524  state_data->sslCrtdHandleReply(reply);
2525 }
2526 
2527 void
2529 {
2530  if (!isOpen()) {
2531  debugs(33, 3, "Connection gone while waiting for ssl_crtd helper reply; helper reply:" << reply);
2532  return;
2533  }
2534 
2535  if (reply.result == Helper::BrokenHelper) {
2536  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply);
2537  } else if (!reply.other().hasContent()) {
2538  debugs(1, DBG_IMPORTANT, "\"ssl_crtd\" helper returned <NULL> reply.");
2539  } else {
2541  if (reply_message.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK) {
2542  debugs(33, 5, "Reply from ssl_crtd for " << tlsConnectHostOrIp << " is incorrect");
2543  } else {
2544  if (reply.result != Helper::Okay) {
2545  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply_message.getBody());
2546  } else {
2547  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " was successfully received from ssl_crtd");
2550  auto ssl = fd_table[clientConnection->fd].ssl.get();
2551  bool ret = Ssl::configureSSLUsingPkeyAndCertFromMemory(ssl, reply_message.getBody().c_str(), *port);
2552  if (!ret)
2553  debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
2554 
2557  } else {
2559  if (ctx && !sslBumpCertKey.isEmpty())
2561  getSslContextDone(ctx);
2562  }
2563  return;
2564  }
2565  }
2566  }
2568  getSslContextDone(nil);
2569 }
2570 
2572 {
2574 
2575  const bool connectedOk = sslServerBump && sslServerBump->connectedOk();
2576  if (connectedOk) {
2577  if (X509 *mimicCert = sslServerBump->serverCert.get())
2578  certProperties.mimicCert.resetAndLock(mimicCert);
2579 
2580  ACLFilledChecklist checklist(nullptr, sslServerBump->request.getRaw());
2581  fillChecklist(checklist);
2582 
2583  for (sslproxy_cert_adapt *ca = Config.ssl_client.cert_adapt; ca != nullptr; ca = ca->next) {
2584  // If the algorithm already set, then ignore it.
2585  if ((ca->alg == Ssl::algSetCommonName && certProperties.setCommonName) ||
2586  (ca->alg == Ssl::algSetValidAfter && certProperties.setValidAfter) ||
2587  (ca->alg == Ssl::algSetValidBefore && certProperties.setValidBefore) )
2588  continue;
2589 
2590  if (ca->aclList && checklist.fastCheck(ca->aclList).allowed()) {
2591  const char *alg = Ssl::CertAdaptAlgorithmStr[ca->alg];
2592  const char *param = ca->param;
2593 
2594  // For parameterless CN adaptation, use hostname from the
2595  // CONNECT request.
2596  if (ca->alg == Ssl::algSetCommonName) {
2597  if (!param)
2598  param = tlsConnectHostOrIp.c_str();
2599  certProperties.commonName = param;
2600  certProperties.setCommonName = true;
2601  } else if (ca->alg == Ssl::algSetValidAfter)
2602  certProperties.setValidAfter = true;
2603  else if (ca->alg == Ssl::algSetValidBefore)
2604  certProperties.setValidBefore = true;
2605 
2606  debugs(33, 5, "Matches certificate adaptation aglorithm: " <<
2607  alg << " param: " << (param ? param : "-"));
2608  }
2609  }
2610 
2611  certProperties.signAlgorithm = Ssl::algSignEnd;
2612  for (sslproxy_cert_sign *sg = Config.ssl_client.cert_sign; sg != nullptr; sg = sg->next) {
2613  if (sg->aclList && checklist.fastCheck(sg->aclList).allowed()) {
2614  certProperties.signAlgorithm = (Ssl::CertSignAlgorithm)sg->alg;
2615  break;
2616  }
2617  }
2618  } else {// did not try to connect (e.g. client-first) or failed to connect
2619  // In case of an error while connecting to the secure server, use a
2620  // trusted certificate, with no mimicked fields and no adaptation
2621  // algorithms. There is nothing we can mimic, so we want to minimize the
2622  // number of warnings the user will have to see to get to the error page.
2623  // We will close the connection, so that the trust is not extended to
2624  // non-Squid content.
2625  certProperties.signAlgorithm = Ssl::algSignTrusted;
2626  }
2627 
2628  assert(certProperties.signAlgorithm != Ssl::algSignEnd);
2629 
2630  if (certProperties.signAlgorithm == Ssl::algSignUntrusted) {
2631  assert(port->secure.untrustedSigningCa.cert);
2632  certProperties.signWithX509.resetAndLock(port->secure.untrustedSigningCa.cert.get());
2633  certProperties.signWithPkey.resetAndLock(port->secure.untrustedSigningCa.pkey.get());
2634  } else {
2635  assert(port->secure.signingCa.cert.get());
2636  certProperties.signWithX509.resetAndLock(port->secure.signingCa.cert.get());
2637 
2638  if (port->secure.signingCa.pkey)
2639  certProperties.signWithPkey.resetAndLock(port->secure.signingCa.pkey.get());
2640  }
2641  signAlgorithm = certProperties.signAlgorithm;
2642 
2643  certProperties.signHash = Ssl::DefaultSignHash;
2644 }
2645 
2648 {
2649  debugs(33, 5, "Finding SSL certificate for " << cacheKey << " in cache");
2651  if (const auto ctx = ssl_ctx_cache ? ssl_ctx_cache->get(cacheKey) : nullptr) {
2652  if (Ssl::verifySslCertificate(*ctx, certProperties)) {
2653  debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is valid");
2654  return *ctx;
2655  } else {
2656  debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is out of date. Delete this certificate from cache");
2657  if (ssl_ctx_cache)
2658  ssl_ctx_cache->del(cacheKey);
2659  }
2660  }
2661  return Security::ContextPointer(nullptr);
2662 }
2663 
2664 void
2666 {
2668  if (!ssl_ctx_cache || !ssl_ctx_cache->add(cacheKey, ctx)) {
2669  // If it is not in storage delete after using. Else storage deleted it.
2670  fd_table[clientConnection->fd].html?amicTlsContext = ctx;
2671  }
2672 }
2673 
2674 void
2676 {
2677  if (port->secure.generateHostCertificates) {
2678  Ssl::CertificateProperties certProperties;
2679  buildSslCertGenerationParams(certProperties);
2680 
2681  // Disable caching for bumpPeekAndSplice mode
2684  Ssl::InRamCertificateDbKey(certProperties, sslBumpCertKey);
2686 
2688  if (ctx) {
2689  getSslContextDone(ctx);
2690  return;
2691  }
2692  }
2693 
2694 #if USE_SSL_CRTD
2695  try {
2696  debugs(33, 5, "Generating SSL certificate for " << certProperties.commonName << " using ssl_crtd.");
2699  request_message.composeRequest(certProperties);
2700  debugs(33, 5, "SSL crtd request: " << request_message.compose().c_str());
2701  Ssl::Helper::Submit(request_message, sslCrtdHandleReplyWrapper, this);
2702  return;
2703  } catch (const std::exception &e) {
2704  debugs(33, DBG_IMPORTANT, "ERROR: Failed to compose ssl_crtd " <<
2705  "request for " << certProperties.commonName <<
2706  " certificate: " << e.what() << "; will now block to " <<
2707  "generate that certificate.");
2708  // fall through to do blocking in-process generation.
2709  }
2710 #endif // USE_SSL_CRTD
2711 
2712  debugs(33, 5, "Generating SSL certificate for " << certProperties.commonName);
2715  auto ssl = fd_table[clientConnection->fd].ssl.get();
2716  if (!Ssl::configureSSL(ssl, certProperties, *port))
2717  debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
2718 
2721  } else {
2723  if (dynCtx && !sslBumpCertKey.isEmpty())
2725  getSslContextDone(dynCtx);
2726  }
2727  return;
2728  }
2729 
2731  getSslContextDone(nil);
2732 }
2733 
2734 void
2736 {
2737  if (port->secure.generateHostCertificates && !ctx) {
2738  debugs(33, 2, "Failed to generate TLS context for " << tlsConnectHostOrIp);
2739  }
2740 
2741  // If generated ssl context = nullptr, try to use static ssl context.
2742  if (!ctx) {
2743  if (!port->secure.staticContext) {
2744  debugs(83, DBG_IMPORTANT, "Closing " << clientConnection->remote << " as lacking TLS context");
2746  return;
2747  } else {
2748  debugs(33, 5, "Using static TLS context.");
2749  ctx = port->secure.staticContext;
2750  }
2751  }
2752 
2753  if (!httpsCreate(this, ctx))
2754  return;
2755 
2756  // bumped intercepted conns should already have Config.Timeout.request set
2757  // but forwarded connections may only have Config.Timeout.lifetime. [Re]set
2758  // to make sure the connection does not get stuck on non-SSL clients.
2760 
2761  switchedToHttps_ = true;
2762 
2763  auto ssl = fd_table[clientConnection->fd].ssl.get();
2764  BIO *b = SSL_get_rbio(ssl);
2765  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
2766  bio->setReadBufData(inBuf);
2767  inBuf.clear();
2769 }
2770 
2771 void
2773 {
2775  Must(http->request);
2776  auto &request = http->request;
2777 
2778  // Depending on receivedFirstByte_, we are at the start of either an
2779  // established CONNECT tunnel with the client or an intercepted TCP (and
2780  // presumably TLS) connection from the client. Expect TLS Client Hello.
2781  const auto insideConnectTunnel = receivedFirstByte_;
2782  debugs(33, 5, (insideConnectTunnel ? "post-CONNECT " : "raw TLS ") << clientConnection);
2783 
2784  tlsConnectHostOrIp = request->url.hostOrIp();
2785  tlsConnectPort = request->url.port();
2786  resetSslCommonName(request->url.host());
2787 
2788  // We are going to read new request
2789  flags.readMore = true;
2790 
2791  // keep version major.minor details the same.
2792  // but we are now performing the HTTPS handshake traffic
2794 
2795  // If sslServerBump is set, then we have decided to deny CONNECT
2796  // and now want to switch to SSL to send the error to the client
2797  // without even peeking at the origin server certificate.
2798  if (bumpServerMode == Ssl::bumpServerFirst && !sslServerBump) {
2799  request->flags.sslPeek = true;
2800  sslServerBump = new Ssl::ServerBump(http);
2801  } else if (bumpServerMode == Ssl::bumpPeek || bumpServerMode == Ssl::bumpStare) {
2802  request->flags.sslPeek = true;
2803  sslServerBump = new Ssl::ServerBump(http, nullptr, bumpServerMode);
2804  }
2805 
2806  // commSetConnTimeout() was called for this request before we switched.
2807  // Fix timeout to request_start_timeout
2809  // Also reset receivedFirstByte_ flag to allow this timeout work in the case we have
2810  // a bumbed "connect" request on non transparent port.
2811  receivedFirstByte_ = false;
2812  // Get more data to peek at Tls
2813  parsingTlsHandshake = true;
2814 
2815  // If the protocol has changed, then reset preservingClientData_.
2816  // Otherwise, its value initially set in start() is still valid/fresh.
2817  // shouldPreserveClientData() uses parsingTlsHandshake which is reset above.
2818  if (insideConnectTunnel)
2820 
2821  readSomeData();
2822 }
2823 
2824 void
2826 {
2828 
2829  assert(!inBuf.isEmpty());
2831  fd_note(clientConnection->fd, "Parsing TLS handshake");
2832 
2833  // stops being nil if we fail to parse the handshake
2834  ErrorDetail::Pointer parseErrorDetails;
2835 
2836  try {
2837  if (!tlsParser.parseHello(inBuf)) {
2838  // need more data to finish parsing
2839  readSomeData();
2840  return;
2841  }
2842  }
2843  catch (const TextException &ex) {
2844  debugs(83, 2, "exception: " << ex);
2845  parseErrorDetails = new ExceptionErrorDetail(ex.id());
2846  }
2847  catch (...) {
2848  debugs(83, 2, "exception: " << CurrentException);
2849  static const auto d = MakeNamedErrorDetail("TLS_ACCEPT_PARSE");
2850  parseErrorDetails = d;
2851  }
2852 
2853  parsingTlsHandshake = false;
2854 
2855  // client data may be needed for splicing and for
2856  // tunneling unsupportedProtocol after an error
2858 
2859  // Even if the parser failed, each TLS detail should either be set
2860  // correctly or still be "unknown"; copying unknown detail is a no-op.
2863  if (details && !details->serverName.isEmpty()) {
2864  resetSslCommonName(details->serverName.c_str());
2865  tlsClientSni_ = details->serverName;
2866  }
2867 
2868  // We should disable read/write handlers
2870 
2871  if (parseErrorDetails) {
2872  Http::StreamPointer context = pipeline.front();
2873  Must(context && context->http);
2874  HttpRequest::Pointer request = context->http->request;
2875  debugs(83, 5, "Got something other than TLS Client Hello. Cannot SslBump.");
2876  updateError(ERR_PROTOCOL_UNKNOWN, parseErrorDetails);
2879  return;
2880  }
2881 
2882  if (!sslServerBump || sslServerBump->act.step1 == Ssl::bumpClientFirst) { // Either means client-first.
2884  return;
2885  } else if (sslServerBump->act.step1 == Ssl::bumpServerFirst) {
2886  debugs(83, 5, "server-first skips step2; start forwarding the request");
2888  Http::StreamPointer context = pipeline.front();
2889  ClientHttpRequest *http = context ? context->http : nullptr;
2890  // will call httpsPeeked() with certificate and connection, eventually
2892  } else {
2895  }
2896 }
2897 
2898 static void
2900 {
2901  ConnStateData *connState = (ConnStateData *) data;
2902 
2903  // if the connection is closed or closing, just return.
2904  if (!connState->isOpen())
2905  return;
2906 
2907  debugs(33, 5, "Answer: " << answer << " kind:" << answer.kind);
2908  assert(connState->serverBump());
2909  Ssl::BumpMode bumpAction;
2910  if (answer.allowed()) {
2911  bumpAction = (Ssl::BumpMode)answer.kind;
2912  } else
2913  bumpAction = Ssl::bumpSplice;
2914 
2915  connState->serverBump()->act.step2 = bumpAction;
2916  connState->sslBumpMode = bumpAction;
2917  Http::StreamPointer context = connState->pipeline.front();
2918  if (ClientHttpRequest *http = (context ? context->http : nullptr))
2919  http->al->ssl.bumpMode = bumpAction;
2920 
2921  if (bumpAction == Ssl::bumpTerminate) {
2922  connState->clientConnection->close();
2923  } else if (bumpAction != Ssl::bumpSplice) {
2924  connState->startPeekAndSplice();
2925  } else if (!connState->splice())
2926  connState->clientConnection->close();
2927 }
2928 
2929 bool
2931 {
2932  // normally we can splice here, because we just got client hello message
2933 
2934  // fde::ssl/tls_read_method() probably reads from our own inBuf. If so, then
2935  // we should not lose any raw bytes when switching to raw I/O here.
2936  if (fd_table[clientConnection->fd].ssl.get())
2937  fd_table[clientConnection->fd].useDefaultIo();
2938 
2939  // XXX: assuming that there was an HTTP/1.1 CONNECT to begin with...
2940  // reset the current protocol to HTTP/1.1 (was "HTTPS" for the bumping process)
2942  assert(!pipeline.empty());
2943  Http::StreamPointer context = pipeline.front();
2944  Must(context);
2945  Must(context->http);
2946  ClientHttpRequest *http = context->http;
2947  HttpRequest::Pointer request = http->request;
2948  context->finished();
2949  if (transparent()) {
2950  // For transparent connections, make a new fake CONNECT request, now
2951  // with SNI as target. doCallout() checks, adaptations may need that.
2952  return fakeAConnectRequest("splice", preservedClientData);
2953  } else {
2954  // For non transparent connections make a new tunneled CONNECT, which
2955  // also sets the HttpRequest::flags::forceTunnel flag to avoid
2956  // respond with "Connection Established" to the client.
2957  // This fake CONNECT request required to allow use of SNI in
2958  // doCallout() checks and adaptations.
2959  return initiateTunneledRequest(request, "splice", preservedClientData);
2960  }
2961 }
2962 
2963 void
2965 {
2966  // This is the Step2 of the SSL bumping
2968  Http::StreamPointer context = pipeline.front();
2969  ClientHttpRequest *http = context ? context->http : nullptr;
2970 
2973  // Run a accessList check to check if want to splice or continue bumping
2974 
2976  acl_checklist->banAction(Acl::Answer(ACCESS_ALLOWED, Ssl::bumpNone));
2977  acl_checklist->banAction(Acl::Answer(ACCESS_ALLOWED, Ssl::bumpClientFirst));
2978  acl_checklist->banAction(Acl::Answer(ACCESS_ALLOWED, Ssl::bumpServerFirst));
2979  fillChecklist(*acl_checklist);
2981  return;
2982  }
2983 
2984  // will call httpsPeeked() with certificate and connection, eventually
2985  Security::ContextPointer unConfiguredCTX(Ssl::createSSLContext(port->secure.signingCa.cert, port->secure.signingCa.pkey, port->secure));
2986  fd_table[clientConnection->fd].html?amicTlsContext = unConfiguredCTX;
2987 
2988  if (!httpsCreate(this, unConfiguredCTX))
2989  return;
2990 
2991  switchedToHttps_ = true;
2992 
2993  auto ssl = fd_table[clientConnection->fd].ssl.get();
2994  BIO *b = SSL_get_rbio(ssl);
2995  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
2996  bio->setReadBufData(inBuf);
2997  bio->hold(true);
2998 
2999  // We have successfully parsed client Hello, but our TLS handshake parser is
3000  // forgiving. Now we use a TLS library to parse the same bytes, so that we
3001  // can honor on_unsupported_protocol if needed. If there are no errors, we
3002  // expect Security::Accept() to ask us to write (our) TLS server Hello. We
3003  // also allow an ioWantRead result in case some fancy TLS extension that
3004  // Squid does not yet understand requires reading post-Hello client bytes.
3005  const auto handshakeResult = acceptTls();
3006  if (!handshakeResult.wantsIo())
3007  return handleSslBumpHandshakeError(handshakeResult);
3008 
3009  // We need to reset inBuf here, to be used by incoming requests in the case
3010  // of SSL bump
3011  inBuf.clear();
3012 
3013  debugs(83, 5, "Peek and splice at step2 done. Start forwarding the request!!! ");
3016 }
3017 
3019 void
3021 {
3022  auto errCategory = ERR_NONE;
3023 
3024  switch (handshakeResult.category) {
3026  static const auto d = MakeNamedErrorDetail("TLS_ACCEPT_UNEXPECTED_SUCCESS");
3027  updateError(errCategory = ERR_GATEWAY_FAILURE, d);
3028  break;
3029  }
3030 
3032  static const auto d = MakeNamedErrorDetail("TLS_ACCEPT_UNEXPECTED_READ");
3033  updateError(errCategory = ERR_GATEWAY_FAILURE, d);
3034  break;
3035  }
3036 
3038  static const auto d = MakeNamedErrorDetail("TLS_ACCEPT_UNEXPECTED_WRITE");
3039  updateError(errCategory = ERR_GATEWAY_FAILURE, d);
3040  break;
3041  }
3042 
3044  debugs(83, (handshakeResult.important ? DBG_IMPORTANT : 2), "ERROR: Cannot SslBump-accept a TLS connection" <<
3045  Debug::Extra << "problem: " << WithExtras(handshakeResult));
3046  updateError(errCategory = ERR_SECURE_ACCEPT_FAIL, handshakeResult.errorDetail);
3047  break;
3048 
3049  }
3050 
3051  if (!tunnelOnError(errCategory))
3053 }
3054 
3055 void
3057 {
3058  auto ssl = fd_table[clientConnection->fd].ssl.get();
3059  BIO *b = SSL_get_rbio(ssl);
3060  assert(b);
3061  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
3062 
3063  debugs(33, 5, "PeekAndSplice mode, proceed with client negotiation. Current state:" << SSL_state_string_long(ssl));
3064  bio->hold(false);
3065 
3067  switchedToHttps_ = true;
3068 }
3069 
3070 void
3072 {
3073  Must(sslServerBump != nullptr);
3074  Must(sslServerBump->request == pic.request);
3075  Must(pipeline.empty() || pipeline.front()->http == nullptr || pipeline.front()->http->request == pic.request.getRaw());
3076 
3077  if (Comm::IsConnOpen(pic.connection)) {
3079  debugs(33, 5, "bumped HTTPS server: " << tlsConnectHostOrIp);
3080  } else
3081  debugs(33, 5, "Error while bumping: " << tlsConnectHostOrIp);
3082 
3084 }
3085 
3086 #endif /* USE_OPENSSL */
3087 
3088 bool
3089 ConnStateData::initiateTunneledRequest(HttpRequest::Pointer const &cause, const char *reason, const SBuf &payload)
3090 {
3091  // fake a CONNECT request to force connState to tunnel
3092  SBuf connectHost;
3093  AnyP::Port connectPort;
3094 
3095  if (pinning.serverConnection != nullptr) {
3096  static char ip[MAX_IPSTRLEN];
3097  connectHost = pinning.serverConnection->remote.toStr(ip, sizeof(ip));
3098  if (const auto remotePort = pinning.serverConnection->remote.port())
3099  connectPort = remotePort;
3100  } else if (cause) {
3101  connectHost = cause->url.hostOrIp();
3102  connectPort = cause->url.port();
3103 #if USE_OPENSSL
3104  } else if (!tlsConnectHostOrIp.isEmpty()) {
3105  connectHost = tlsConnectHostOrIp;
3106  connectPort = tlsConnectPort;
3107 #endif
3108  } else if (transparent()) {
3109  static char ip[MAX_IPSTRLEN];
3110  connectHost = clientConnection->local.toStr(ip, sizeof(ip));
3111  connectPort = clientConnection->local.port();
3112  }
3113 
3114  if (!connectPort) {
3115  // Typical cases are malformed HTTP requests on http_port and malformed
3116  // TLS handshakes on non-bumping https_port. TODO: Discover these
3117  // problems earlier so that they can be classified/detailed better.
3118  debugs(33, 2, "Not able to compute URL, abort request tunneling for " << reason);
3119  // TODO: throw when NonBlockingCheck() callbacks gain job protections
3120  static const auto d = MakeNamedErrorDetail("TUNNEL_TARGET");
3122  return false;
3123  }
3124 
3125  debugs(33, 2, "Request tunneling for " << reason);
3126  const auto http = buildFakeRequest(connectHost, *connectPort, payload);
3127  HttpRequest::Pointer request = http->request;
3128  request->flags.forceTunnel = true;
3129  http->calloutContext = new ClientRequestContext(http);
3130  http->doCallouts();
3131  clientProcessRequestFinished(this, request);
3132  return true;
3133 }
3134 
3135 bool
3136 ConnStateData::fakeAConnectRequest(const char *reason, const SBuf &payload)
3137 {
3138  debugs(33, 2, "fake a CONNECT request to force connState to tunnel for " << reason);
3139 
3140  SBuf connectHost;
3141  assert(transparent());
3142  const unsigned short connectPort = clientConnection->local.port();
3143 
3144 #if USE_OPENSSL
3145  if (!tlsClientSni_.isEmpty())
3146  connectHost.assign(tlsClientSni_);
3147  else
3148 #endif
3149  {
3150  static char ip[MAX_IPSTRLEN];
3151  clientConnection->local.toHostStr(ip, sizeof(ip));
3152  connectHost.assign(ip);
3153  }
3154 
3155  ClientHttpRequest *http = buildFakeRequest(connectHost, connectPort, payload);
3156 
3157  http->calloutContext = new ClientRequestContext(http);
3158  HttpRequest::Pointer request = http->request;
3159  http->doCallouts();
3160  clientProcessRequestFinished(this, request);
3161  return true;
3162 }
3163 
3165 ConnStateData::buildFakeRequest(SBuf &useHost, const AnyP::KnownPort usePort, const SBuf &payload)
3166 {
3167  ClientHttpRequest *http = new ClientHttpRequest(this);
3168  Http::Stream *stream = new Http::Stream(clientConnection, http);
3169 
3170  StoreIOBuffer tempBuffer;
3171  tempBuffer.data = stream->reqbuf;
3172  tempBuffer.length = HTTP_REQBUF_SZ;
3173 
3174  ClientStreamData newServer = new clientReplyContext(http);
3175  ClientStreamData newClient = stream;
3178  clientSocketDetach, newClient, tempBuffer);
3179 
3180  stream->flags.parsed_ok = 1; // Do we need it?
3181  stream->mayUseConnection(true);
3182  extendLifetime();
3183  stream->registerWithConn();
3184 
3185  const auto mx = MasterXaction::MakePortful(port);
3186  mx->tcpClient = clientConnection;
3187  // Setup Http::Request object. Maybe should be replaced by a call to (modified)
3188  // clientProcessRequest
3189  HttpRequest::Pointer request = new HttpRequest(mx);
3190  request->url.setScheme(AnyP::PROTO_AUTHORITY_FORM, nullptr);
3191  request->method = Http::METHOD_CONNECT;
3192  request->url.host(useHost.c_str());
3193  request->url.port(usePort);
3194 
3195  http->uri = SBufToCstring(request->effectiveRequestUri());
3196  http->initRequest(request.getRaw());
3197 
3198  request->manager(this, http->al);
3199 
3200  request->header.putStr(Http::HOST, useHost.c_str());
3201 
3202  request->sources |= ((switchedToHttps() || port->transport.protocol == AnyP::PROTO_HTTPS) ? Http::Message::srcHttps : Http::Message::srcHttp);
3203 #if USE_AUTH
3204  if (getAuth())
3205  request->auth_user_request = getAuth();
3206 #endif
3207 
3208  inBuf = payload;
3209  flags.readMore = false;
3210 
3211  return http;
3212 }
3213 
3215 static bool
3217 {
3218  if (!Comm::IsConnOpen(c)) {
3219  Must(NHttpSockets > 0); // we tried to open some
3220  --NHttpSockets; // there will be fewer sockets than planned
3221  Must(HttpSockets[NHttpSockets] < 0); // no extra fds received
3222 
3223  if (!NHttpSockets) // we could not open any listen sockets at all
3224  fatalf("Unable to open %s",FdNote(portType));
3225 
3226  return false;
3227  }
3228  return true;
3229 }
3230 
3232 static bool
3234 {
3235  bool found = false;
3236  for (int i = 0; i < NHttpSockets && !found; ++i) {
3237  if ((found = HttpSockets[i] < 0))
3238  HttpSockets[i] = conn->fd;
3239  }
3240  return found;
3241 }
3242 
3243 static void
3245 {
3246  const auto savedContext = CodeContext::Current();
3247  for (AnyP::PortCfgPointer s = HttpPortList; s != nullptr; s = s->next) {
3248  CodeContext::Reset(s);
3249  const SBuf &scheme = AnyP::UriScheme(s->transport.protocol).image();
3250 
3252  debugs(1, DBG_IMPORTANT, "WARNING: You have too many '" << scheme << "_port' lines." <<
3253  Debug::Extra << "The limit is " << MAXTCPLISTENPORTS << " HTTP ports.");
3254  continue;
3255  }
3256 
3257 #if USE_OPENSSL
3258  if (s->flags.tunnelSslBumping) {
3259  if (!Config.accessList.ssl_bump) {
3260  debugs(33, DBG_IMPORTANT, "WARNING: No ssl_bump configured. Disabling ssl-bump on " << scheme << "_port " << s->s);
3261  s->flags.tunnelSslBumping = false;
3262  }
3263  if (!s->secure.staticContext && !s->secure.generateHostCertificates) {
3264  debugs(1, DBG_IMPORTANT, "Will not bump SSL at " << scheme << "_port " << s->s << " due to TLS initialization failure.");
3265  s->flags.tunnelSslBumping = false;
3266  if (s->transport.protocol == AnyP::PROTO_HTTP)
3267  s->secure.encryptTransport = false;
3268  }
3269  if (s->flags.tunnelSslBumping) {
3270  // Create ssl_ctx cache for this port.
3271  Ssl::TheGlobalContextStorage.addLocalStorage(s->s, s->secure.html?amicCertMemCacheSize);
3272  }
3273  }
3274 #endif
3275 
3276  if (s->secure.encryptTransport && !s->secure.staticContext) {
3277  debugs(1, DBG_CRITICAL, "ERROR: Ignoring " << scheme << "_port " << s->s << " due to TLS context initialization failure.");
3278  continue;
3279  }
3280 
3281  const auto protocol = s->transport.protocol;
3282  assert(protocol == AnyP::PROTO_HTTP || protocol == AnyP::PROTO_HTTPS);
3283  const auto isHttps = protocol == AnyP::PROTO_HTTPS;
3284  using AcceptCall = CommCbFunPtrCallT<CommAcceptCbPtrFun>;
3285  RefCount<AcceptCall> subCall = commCbCall(5, 5, isHttps ? "httpsAccept" : "httpAccept",
3288  }
3289  CodeContext::Reset(savedContext);
3290 }
3291 
3292 void
3294 {
3295  // Fill out a Comm::Connection which IPC will open as a listener for us
3296  port->listenConn = new Comm::Connection;
3297  port->listenConn->local = port->s;
3298  port->listenConn->flags =
3300  (port->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) |
3301  (port->flags.natIntercept ? COMM_INTERCEPTION : 0) |
3302  (port->workerQueues ? COMM_REUSEPORT : 0);
3303 
3304  // route new connections to subCall
3305  typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
3307  const auto listenCall =
3308  asyncCall(33, 2, "clientListenerConnectionOpened",
3310  port, fdNote, sub));
3311  AsyncCallback<Ipc::StartListeningAnswer> callback(listenCall);
3312  Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, port->listenConn, fdNote, callback);
3313 
3315  HttpSockets[NHttpSockets] = -1;
3316  ++NHttpSockets;
3317 }
3318 
3320 static void
3322 {
3323  Must(s != nullptr);
3324 
3325  if (!OpenedHttpSocket(s->listenConn, portTypeNote))
3326  return;
3327 
3328  Must(Comm::IsConnOpen(s->listenConn));
3329 
3330  // TCP: setup a job to handle accept() with subscribed handler
3331  AsyncJob::Start(new Comm::TcpAcceptor(s, FdNote(portTypeNote), sub));
3332 
3333  debugs(1, Important(13), "Accepting " <<
3334  (s->flags.natIntercept ? "NAT intercepted " : "") <<
3335  (s->flags.tproxyIntercept ? "TPROXY intercepted " : "") <<
3336  (s->flags.tunnelSslBumping ? "SSL bumped " : "") <<
3337  (s->flags.accelSurrogate ? "reverse-proxy " : "")
3338  << FdNote(portTypeNote) << " connections at "
3339  << s->listenConn);
3340 
3341  Must(AddOpenedHttpSocket(s->listenConn)); // otherwise, we have received a fd we did not ask for
3342 
3343 #if HAVE_LIBSYSTEMD
3344  // When the very first port opens, tell systemd we are able to serve connections.
3345  // Subsequent sd_notify() calls, including calls during reconfiguration,
3346  // do nothing because the first call parameter is 1.
3347  // XXX: Send the notification only after opening all configured ports.
3348  if (opt_foreground || opt_no_daemon) {
3349  const auto result = sd_notify(1, "READY=1");
3350  if (result < 0) {
3351  debugs(1, DBG_IMPORTANT, "WARNING: failed to send start-up notification to systemd" <<
3352  Debug::Extra << "sd_notify() error: " << xstrerr(-result));
3353  }
3354  }
3355 #endif
3356 }
3357 
3358 void
3360 {
3363 
3364  if (NHttpSockets < 1)
3365  fatal("No HTTP, HTTPS, or FTP ports configured");
3366 }
3367 
3368 void
3370 {
3371  const auto savedContext = CodeContext::Current();
3372  for (AnyP::PortCfgPointer s = HttpPortList; s != nullptr; s = s->next) {
3373  CodeContext::Reset(s);
3374  if (s->listenConn != nullptr) {
3375  debugs(1, Important(14), "Closing HTTP(S) port " << s->listenConn->local);
3376  s->listenConn->close();
3377  s->listenConn = nullptr;
3378  }
3379  }
3380  CodeContext::Reset(savedContext);
3381 
3383 
3384  // TODO see if we can drop HttpSockets array entirely */
3385  for (int i = 0; i < NHttpSockets; ++i) {
3386  HttpSockets[i] = -1;
3387  }
3388 
3389  NHttpSockets = 0;
3390 }
3391 
3392 int
3394 {
3395  SBuf vary(request->vary_headers);
3396  const auto &reply = entry->mem().freshestReply();
3397  auto has_vary = reply.header.has(Http::HdrType::VARY);
3398 #if X_ACCELERATOR_VARY
3399 
3400  has_vary |=
3401  reply.header.has(Http::HdrType::HDR_X_ACCELERATOR_VARY);
3402 #endif
3403 
3404  if (!has_vary || entry->mem_obj->vary_headers.isEmpty()) {
3405  if (!vary.isEmpty()) {
3406  /* Oops... something odd is going on here.. */
3407  debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary object on second attempt, '" <<
3408  entry->mem_obj->urlXXX() << "' '" << vary << "'");
3409  request->vary_headers.clear();
3410  return VARY_CANCEL;
3411  }
3412 
3413  if (!has_vary) {
3414  /* This is not a varying object */
3415  return VARY_NONE;
3416  }
3417 
3418  /* virtual "vary" object found. Calculate the vary key and
3419  * continue the search
3420  */
3421  vary = httpMakeVaryMark(request, &reply);
3422 
3423  if (!vary.isEmpty()) {
3424  request->vary_headers = vary;
3425  return VARY_OTHER;
3426  } else {
3427  /* Ouch.. we cannot handle this kind of variance */
3428  /* XXX This cannot really happen, but just to be complete */
3429  return VARY_CANCEL;
3430  }
3431  } else {
3432  if (vary.isEmpty()) {
3433  vary = httpMakeVaryMark(request, &reply);
3434 
3435  if (!vary.isEmpty())
3436  request->vary_headers = vary;
3437  }
3438 
3439  if (vary.isEmpty()) {
3440  /* Ouch.. we cannot handle this kind of variance */
3441  /* XXX This cannot really happen, but just to be complete */
3442  return VARY_CANCEL;
3443  } else if (vary.cmp(entry->mem_obj->vary_headers) == 0) {
3444  return VARY_MATCH;
3445  } else {
3446  /* Oops.. we have already been here and still haven't
3447  * found the requested variant. Bail out
3448  */
3449  debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary match on second attempt, '" <<
3450  entry->mem_obj->urlXXX() << "' '" << vary << "'");
3451  return VARY_CANCEL;
3452  }
3453  }
3454 }
3455 
3458 {
3459  auto checklist = ACLFilledChecklist::Make(acl, nullptr);
3460  clientAclChecklistFill(*checklist, http);
3461  return checklist;
3462 }
3463 
3464 void
3466 {
3467  assert(http);
3468 
3469  if (!checklist.request && http->request)
3470  checklist.setRequest(http->request);
3471 
3472  if (!checklist.al && http->al) {
3473  checklist.updateAle(http->al);
3474  checklist.syncAle(http->request, http->log_uri);
3475  }
3476 
3477  if (const auto conn = http->getConn())
3478  checklist.setConn(conn); // may already be set
3479 }
3480 
3481 void
3483 {
3484  const auto context = pipeline.front();
3485  if (const auto http = context ? context->http : nullptr)
3486  return clientAclChecklistFill(checklist, http); // calls checklist.setConn()
3487 
3488  // no requests, but we always have connection-level details
3489  // TODO: ACL checks should not require a mutable ConnStateData. Adjust the
3490  // code that accidentally violates that principle to remove this const_cast!
3491  checklist.setConn(const_cast<ConnStateData*>(this));
3492 
3493  // Set other checklist fields inside our fillConnectionLevelDetails() rather
3494  // than here because clientAclChecklistFill() code path calls that method
3495  // (via ACLFilledChecklist::setConn()) rather than calling us directly.
3496 }
3497 
3498 void
3500 {
3501  assert(checklist.conn() == this);
3503 
3504  if (!checklist.request) { // preserve (better) addresses supplied by setRequest()
3505  checklist.src_addr = clientConnection->remote;
3506  checklist.my_addr = clientConnection->local; // TODO: or port->s?
3507  }
3508 
3509 #if USE_OPENSSL
3510  if (!checklist.sslErrors && sslServerBump)
3511  checklist.sslErrors = sslServerBump->sslErrors();
3512 #endif
3513 }
3514 
3515 bool
3517 {
3519 }
3520 
3523 {
3524  bodyPipe = new BodyPipe(this);
3525  if (size >= 0)
3527  else
3529  return bodyPipe;
3530 }
3531 
3532 int64_t
3534 {
3535  if (!bodyPipe)
3536  return 0; // request without a body or read/produced all body bytes
3537 
3538  if (!bodyPipe->bodySizeKnown())
3539  return -1; // probably need to read more, but we cannot be sure
3540 
3541  const int64_t needToProduce = bodyPipe->unproducedSize();
3542  const int64_t haveAvailable = static_cast<int64_t>(inBuf.length());
3543 
3544  if (needToProduce <= haveAvailable)
3545  return 0; // we have read what we need (but are waiting for pipe space)
3546 
3547  return needToProduce - haveAvailable;
3548 }
3549 
3550 void
3552 {
3553  debugs(33, 4, "receiving error (" << clientConnection << "): " << error <<
3554  "; old sending error: " <<
3555  (stoppedSending() ? stoppedSending_ : "none"));
3556 
3557  if (const char *oldError = stoppedReceiving()) {
3558  debugs(33, 3, "already stopped receiving: " << oldError);
3559  return; // nothing has changed as far as this connection is concerned
3560  }
3561 
3563 
3564  if (const char *sendError = stoppedSending()) {
3565  debugs(33, 3, "closing because also stopped sending: " << sendError);
3567  }
3568 }
3569 
3570 void
3572 {
3573  if (bodyPipe != nullptr) {
3574  debugs(33, 4, "no consumer for virgin body " << bodyPipe->status());
3576  }
3577 }
3578 
3580 void
3582 {
3583  Must(bodyPipe != nullptr);
3584  debugs(33, 5, "start dechunking" << bodyPipe->status());
3585  assert(!bodyParser);
3587 }
3588 
3590 void
3592 {
3593  debugs(33, 5, "finish dechunking: " << withSuccess);
3594 
3595  if (bodyPipe != nullptr) {
3596  debugs(33, 7, "dechunked tail: " << bodyPipe->status());
3597  BodyPipe::Pointer myPipe = bodyPipe;
3598  stopProducingFor(bodyPipe, withSuccess); // sets bodyPipe->bodySize()
3599  Must(!bodyPipe); // we rely on it being nil after we are done with body
3600  if (withSuccess) {
3601  Must(myPipe->bodySizeKnown());
3602  Http::StreamPointer context = pipeline.front();
3603  if (context != nullptr && context->http && context->http->request)
3604  context->http->request->setContentLength(myPipe->bodySize());
3605  }
3606  }
3607 
3608  delete bodyParser;
3609  bodyParser = nullptr;
3610 }
3611 
3612 // XXX: this is an HTTP/1-only operation
3613 void
3615 {
3616  if (const auto context = pipeline.front()) {
3617  if (context->http)
3618  context->http->al->reply = msg.reply;
3619  }
3620 
3621  if (!isOpen()) {
3622  debugs(33, 3, "ignoring 1xx due to earlier closure");
3623  return;
3624  }
3625 
3626  // HTTP/1 1xx status messages are only valid when there is a transaction to trigger them
3627  if (!pipeline.empty()) {
3628  HttpReply::Pointer rep(msg.reply);
3629  Must(rep);
3630  // remember the callback
3632 
3635 
3636  if (!writeControlMsgAndCall(rep.getRaw(), call)) {
3637  // but still inform the caller (so it may resume its operation)
3639  }
3640  return;
3641  }
3642 
3643  debugs(33, 3, " closing due to missing context for 1xx");
3645 }
3646 
3647 void
3649 {
3651 
3652  if (Http::StreamPointer deferredRequest = pipeline.front()) {
3653  debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded after control msg wrote");
3654  ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
3655  }
3656 }
3657 
3659 void
3661 {
3662  // FwdState might repin a failed connection sooner than this close
3663  // callback is called for the failed connection.
3664  assert(pinning.serverConnection == io.conn);
3665  pinning.closeHandler = nullptr; // Comm unregisters handlers before calling
3666  const bool sawZeroReply = pinning.zeroReply; // reset when unpinning
3667  pinning.serverConnection->noteClosure();
3668  unpinConnection(false);
3669 
3670  if (sawZeroReply && clientConnection != nullptr) {
3671  debugs(33, 3, "Closing client connection on pinned zero reply.");
3673  }
3674 
3675 }
3676 
3677 void
3679 {
3680  pinConnection(pinServer, *request);
3681 }
3682 
3683 void
3685 {
3686  Must(pic.connection);
3687  Must(pic.request);
3688  pinConnection(pic.connection, *pic.request);
3689 
3690  // monitor pinned server connection for remote-end closures.
3692 
3693  if (pipeline.empty())
3694  kick(); // in case parseRequests() was blocked by a busy pic.connection
3695 }
3696 
3698 void
3700 {
3701  if (Comm::IsConnOpen(pinning.serverConnection) &&
3702  pinning.serverConnection->fd == pinServer->fd) {
3703  debugs(33, 3, "already pinned" << pinServer);
3704  return;
3705  }
3706 
3707  unpinConnection(true); // closes pinned connection, if any, and resets fields
3708 
3709  pinning.serverConnection = pinServer;
3710 
3711  debugs(33, 3, pinning.serverConnection);
3712 
3713  Must(pinning.serverConnection != nullptr);
3714 
3715  const char *pinnedHost = "[unknown]";
3716  pinning.host = xstrdup(request.url.host());
3717  pinning.port = request.url.port();
3718  pinnedHost = pinning.host;
3719  pinning.pinned = true;
3720  if (CachePeer *aPeer = pinServer->getPeer())
3721  pinning.peer = cbdataReference(aPeer);
3722  pinning.auth = request.flags.connectionAuth;
3723  char stmp[MAX_IPSTRLEN];
3724  char desc[FD_DESC_SZ];
3725  snprintf(desc, FD_DESC_SZ, "%s pinned connection for %s (%d)",
3726  (pinning.auth || !pinning.peer) ? pinnedHost : pinning.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.peer && !cbdataReferenceValid(pinning.peer))
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 
3885 
3886  if (Comm::IsConnOpen(pinning.serverConnection)) {
3887  if (pinning.closeHandler != nullptr) {
3888  comm_remove_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
3889  pinning.closeHandler = nullptr;
3890  }
3891 
3893 
3894  // close the server side socket if requested
3895  if (andClose)
3896  pinning.serverConnection->close();
3897  pinning.serverConnection = nullptr;
3898  }
3899 
3900  safe_free(pinning.host);
3901 
3902  pinning.zeroReply = false;
3903  pinning.peerAccessDenied = false;
3904 
3905  /* NOTE: pinning.pinned should be kept. This combined with fd == -1 at the end of a request indicates that the host
3906  * connection has gone away */
3907 }
3908 
3909 void
3911 {
3912  auto error = rawError; // (cheap) copy so that we can detail
3913  // We detail even ERR_NONE: There should be no transactions left, and
3914  // detailed ERR_NONE will be unused. Otherwise, this detail helps in triage.
3915  if (error.details.empty()) {
3916  static const auto d = MakeNamedErrorDetail("WITH_CLIENT");
3917  error.details.push_back(d);
3918  }
3919 
3920  debugs(33, 3, pipeline.count() << '/' << pipeline.nrequests << " after " << error);
3921 
3922  if (pipeline.empty()) {
3923  bareError.update(error); // XXX: bareLogTagsErrors
3924  } else {
3925  // We terminate the current CONNECT/PUT/etc. context below, logging any
3926  // error details, but that context may leave unparsed bytes behind.
3927  // Consume them to stop checkLogging() from logging them again later.
3928  const auto intputToConsume =
3929 #if USE_OPENSSL
3930  parsingTlsHandshake ? "TLS handshake" : // more specific than CONNECT
3931 #endif
3932  bodyPipe ? "HTTP request body" :
3933  pipeline.back()->mayUseConnection() ? "HTTP CONNECT" :
3934  nullptr;
3935 
3936  while (const auto context = pipeline.front()) {
3937  context->noteIoError(error, lte);
3938  context->finished(); // cleanup and self-deregister
3939  assert(context != pipeline.front());
3940  }
3941 
3942  if (intputToConsume && !inBuf.isEmpty()) {
3943  debugs(83, 5, "forgetting client " << intputToConsume << " bytes: " << inBuf.length());
3944  inBuf.clear();
3945  }
3946  }
3947 
3949 }
3950 
3952 void
3954 {
3955  // to simplify our logic, we assume that terminateAll() has been called
3956  assert(pipeline.empty());
3957 
3958  // do not log connections that closed after a transaction (it is normal)
3959  // TODO: access_log needs ACLs to match received-no-bytes connections
3960  if (pipeline.nrequests && inBuf.isEmpty())
3961  return;
3962 
3963  /* Create a temporary ClientHttpRequest object. Its destructor will log. */
3964  ClientHttpRequest http(this);
3965  http.req_sz = inBuf.length();
3966  // XXX: Or we died while waiting for the pinned connection to become idle.
3967  http.setErrorUri("error:transaction-end-before-headers");
3968  http.updateError(bareError);
3969 }
3970 
3971 bool
3973 {
3974  // PROXY protocol bytes are meant for us and, hence, cannot be tunneled
3976  return false;
3977 
3978  // If our decision here is negative, configuration changes are irrelevant.
3979  // Otherwise, clientTunnelOnError() rechecks configuration before tunneling.
3981  return false;
3982 
3983  // TODO: Figure out whether/how we can support FTP tunneling.
3984  if (port->transport.protocol == AnyP::PROTO_FTP)
3985  return false;
3986 
3987 #if USE_OPENSSL
3988  if (parsingTlsHandshake)
3989  return true;
3990 
3991  // the 1st HTTP request on a bumped connection
3993  return true;
3994 #endif
3995 
3996  // the 1st HTTP(S) request on a connection to an intercepting port
3997  if (!pipeline.nrequests && transparent())
3998  return true;
3999 
4000  return false;
4001 }
4002 
4005 {
4006  if (!theNotes)
4007  theNotes = new NotePairs;
4008  return theNotes;
4009 }
4010 
4011 std::ostream &
4012 operator <<(std::ostream &os, const ConnStateData::PinnedIdleContext &pic)
4013 {
4014  return os << pic.connection << ", request=" << pic.request;
4015 }
4016 
4017 std::ostream &
4019 {
4020  return os << scc.conn_ << ", srv_bytes=" << scc.preReadServerBytes.length();
4021 }
4022 
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:952
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
@ VARY_CANCEL
Definition: enums.h:191
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
Ipc::StartListeningAnswer & answer() override
callback results setter
Definition: client_side.cc:170
@ DISABLE_PMTU_ALWAYS
Definition: enums.h:226
@ 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:1481
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)
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()
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
struct SquidConfig::@98 accessList
const char * getStr(Http::HdrType id) const
Definition: HttpHeader.cc:1163
@ SQUID_X509_V_ERR_DOMAIN_MISMATCH
Definition: forward.h:238
@ 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:494
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:216
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:263
ByteCounter hit_kbytes_out
Definition: StatCounters.h:48
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:51
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
struct StatCounters::@117 cd
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:582
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:1016
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:152
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:123
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:1358
void readNextRequest()
Traffic parsing.
Definition: client_side.cc:857
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:22
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:475
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:93
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
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
struct SquidConfig::@97 onoff
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
HierarchyLogEntry hier
@ METHOD_PRI
Definition: MethodType.h:89
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:167
struct timeval start_time
The time the master transaction started.
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:270
struct ConnStateData::@35 flags
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:976
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
AnyP::ProtocolVersion version
@ 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:21
bool multipartRangeRequest() const
Definition: HttpRequest.cc:434
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
#define cbdataReference(var)
Definition: cbdata.h:348
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.
struct StatCounters::@111 client_http
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:178
CbcPointer< Security::CertErrors > sslErrors
@ VARY_OTHER
Definition: enums.h:190
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
const Value * get(const Key &)
Definition: ClpMap.h:188
Security::IoResult acceptTls()
struct SquidConfig::@106 ssl_client
class AccessLogEntry::HttpDetails http
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
@ VARY_NONE
Definition: enums.h:188
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:157
String myportname
Definition: HttpRequest.h:174
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
class AccessLogEntry::IcapLogEntry icap
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
HttpRequest * request
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
@ VARY_MATCH
Definition: enums.h:189
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:696
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:483
@ 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:50
int size
Definition: ModDevPoll.cc:69
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
char * last_meta
image of the last ICAP response header or eCAP meta received
@ 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:143
SBuf vary_headers
Definition: MemObject.h:221
sslproxy_cert_adapt * cert_adapt
Definition: SquidConfig.h:514
const EVP_MD * DefaultSignHash
Definition: support.cc:46
void updateError(const Error &)
if necessary, stores new error information (if any)
Definition: client_side.cc:628
void clientSocketRecipient(clientStreamNode *node, ClientHttpRequest *http, HttpReply *rep, StoreIOBuffer receivedData)
Definition: client_side.cc:800
@ 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:130
Subscription::Pointer sub
The handler to be subscribed for this connection listener.
Definition: client_side.cc:180
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
unsigned short port() const
Definition: Address.cc:798
Definition: MemBuf.h:23
ConnStateData * pinnedConnection()
Definition: HttpRequest.cc:725
HttpRequest::Pointer request
void setReplyToStoreEntry(StoreEntry *e, const char *reason)
replaces current response store entry with the given one
clientStreamNode * getClientReplyContext() const
Definition: Stream.cc:511
Ip::Address local
Definition: Connection.h:146
CachePeer * getPeer() const
Definition: Connection.cc:121
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:1086
CSR clientGetMoreData
Definition: client_side.h:529
void clean()
Definition: MemBuf.cc:110
StatHist hitSvcTime
Definition: StatCounters.h:52
static void httpsEstablish(ConnStateData *connState, const Security::ContextPointer &ctx)
void start() override
called by AsyncStart; do not call directly
bool concurrentRequestQueueFilled() const
Definition: ClpMap.h:40
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:983
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
void resetReadTimeout(time_t timeout)
(re)sets timeout for receiving more bytes from the client
Definition: client_side.cc:574
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:959
Adaptation::Icap::History::Pointer icapHistory() const
Returns possibly nil history, creating it if icap logging is enabled.
Definition: HttpRequest.cc:389
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:149
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:998
void clientOpenListenSockets(void)
void comm_reset_close(const Comm::ConnectionPointer &conn)
Definition: comm.cc:797
@ 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:647
bool parseHello(const SBuf &data)
Definition: Handshake.cc:641
@ algSetValidAfter
Definition: gadgets.h:207
StatHist missSvcTime
Definition: StatCounters.h:49
@ scContentTooLarge
Definition: StatusCode.h:58
bool transparent() const
void swanSong() override
Definition: client_side.cc:591
void setPayloadBuffer(MemBuf *parsedContent)
set the buffer to be used to store decoded chunk data
SSL Connection
Definition: Session.h:49
void del(const Key &)
Remove the corresponding entry (if any)
Definition: ClpMap.h:268
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:1033
HttpReply::Pointer reply
the 1xx message being forwarded
HttpRequestMethod method
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:170
FILE * DebugStream()
Definition: debug.cc:355
#define COMM_SELECT_READ
Definition: defines.h:24
#define cbdataReferenceDone(var)
Definition: cbdata.h:357
@ 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
class AccessLogEntry::Headers headers
const char * c_str()
Definition: SBuf.cc:516
Security::ContextPointer GenerateSslContext(CertificateProperties const &, Security::ServerOptions &, bool trusted)
Definition: support.cc:1047
Http::StatusCode checkEntityFraming() const
Definition: HttpRequest.cc:647
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
class AccessLogEntry::AdaptationDetails adapt
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:185
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:177
void receivedFirstByte() override
Update flags and timeout after the first byte received.
bool add(const Key &, const Value &, Ttl)
Definition: ClpMap.h:220
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:166
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.
struct StatCounters::@118 netdb
void clientSetKeepaliveFlag(ClientHttpRequest *http)
decide whether to expect multiple requests on the corresponding connection
Definition: client_side.cc:674
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:322
void clientPinnedConnectionRead(const CommIoCbParams &io)
Adaptation::History::Pointer adaptLogHistory() const
Returns possibly nil history, creating it if adapt. logging is enabled.
Definition: HttpRequest.cc:415
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:158
const Auth::UserRequest::Pointer & getAuth() const
Definition: client_side.h:123
@ PROTO_AUTHORITY_FORM
Definition: ProtocolType.h:40
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
GlobalContextStorage TheGlobalContextStorage
Global cache for store all SSL server certificates.
bool handleRequestBodyData()
struct ConnStateData::@36 pinning
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:592
@ PROTO_HTTP
Definition: ProtocolType.h:25
const char * termedBuf() const
Definition: SquidString.h:92
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:53
bool allowed() const
Definition: Acl.h:82
bool serveDelayedError(Http::Stream *)
void wroteControlMsg(const CommIoCbParams &)
callback to handle Comm::Write completion
@ DISABLE_PMTU_OFF
Definition: enums.h:225
size_t putMoreData(const char *buf, size_t size)
Definition: BodyPipe.cc:213
bool handleReadData() override
struct timeval processingTime
total ICAP processing time
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:198
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:1116
@ ERR_TOO_BIG
Definition: forward.h:40
Comm::ConnectionPointer conn_
to-server connection
Definition: client_side.h:224
struct SquidConfig::@84 Timeout
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:1136
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)
bool isEmpty() const
Definition: Store.h:65
std::optional< KnownPort > Port
validated/supported port number (if any)
Definition: UriScheme.h:26
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:709
@ 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:774
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:83
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:780
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:333
const AccessLogEntry::Pointer al
access.log entry
sslproxy_cert_adapt * next
Definition: ProxyCerts.h:58
struct Http::Stream::@65 flags
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
static int clientIsRequestBodyTooLargeForPolicy(int64_t bodyLength)
Definition: client_side.cc:686
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
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
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:894
@ CD_SIBLING_HIT
Definition: hier_code.h:29
int query_timeouts
Definition: StatCounters.h:85
#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:640
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
struct Ssl::ServerBump::@110 act
bumping actions at various bumping steps
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
struct SquidConfig::@92 Addrs
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)
bool fakeAConnectRequest(const char *reason, const SBuf &payload)
@ fdnHttpsSocket
Definition: FdNotes.h:20
MemObject * memObject() const
iterator begin()
struct StatCounters::@113 icp
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:872
const SBuf & effectiveRequestUri() const
RFC 7230 section 5.5 - Effective Request URI.
Definition: HttpRequest.cc:744
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:752
#define MAXTCPLISTENPORTS
Definition: PortCfg.h:86
bool configureSSL(SSL *ssl, CertificateProperties const &properties, AnyP::PortCfg &port)
Definition: support.cc:1093
Ipc::FdNoteId portTypeNote
Type of IPC socket being opened.
Definition: client_side.cc:179
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:47
#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.
Security::NegotiationHistory * tlsNegotiations()
Definition: Connection.cc:153
void callException(const std::exception &) override
called when the job throws during an async call
Definition: client_side.cc:615
void clientPackTermBound(String boundary, MemBuf *mb)
put terminating boundary for multiparts to the buffer
Definition: client_side.cc:702
void clean()
Definition: HttpHeader.cc:185
void comm_remove_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:981
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:162
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:178
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:103
static void Start(const Pointer &job)
Definition: AsyncJob.cc:37
static bool clientPingHasFinished(ping_data const *aPing)
Definition: client_side.cc:254
AnyP::ProtocolVersion ProtocolVersion(unsigned int aMajor, unsigned int aMinor)
HTTP version label information.
void clientSocketDetach(clientStreamNode *node, ClientHttpRequest *http)
Definition: client_side.cc:836
int64_t mRangeCLen() const
Definition: client_side.cc:740
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:212
virtual void releaseAuthServer()
Definition: UserRequest.cc:218

 

Introduction

Documentation

Support

Miscellaneous