client_side.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 33 Client-side Routines */
10 
60 #include "squid.h"
61 #include "acl/FilledChecklist.h"
62 #include "anyp/PortCfg.h"
63 #include "base/Subscription.h"
64 #include "base/TextException.h"
65 #include "CachePeer.h"
66 #include "client_db.h"
67 #include "client_side.h"
68 #include "client_side_reply.h"
69 #include "client_side_request.h"
70 #include "ClientRequestContext.h"
71 #include "clientStream.h"
72 #include "comm.h"
73 #include "comm/Connection.h"
74 #include "comm/Loops.h"
75 #include "comm/Read.h"
76 #include "comm/TcpAcceptor.h"
77 #include "comm/Write.h"
78 #include "CommCalls.h"
79 #include "errorpage.h"
80 #include "fd.h"
81 #include "fde.h"
82 #include "fqdncache.h"
83 #include "FwdState.h"
84 #include "globals.h"
85 #include "helper.h"
86 #include "helper/Reply.h"
87 #include "http.h"
88 #include "http/one/RequestParser.h"
90 #include "http/Stream.h"
91 #include "HttpHdrContRange.h"
92 #include "HttpHeaderTools.h"
93 #include "HttpReply.h"
94 #include "HttpRequest.h"
95 #include "ident/Config.h"
96 #include "ident/Ident.h"
97 #include "internal.h"
98 #include "ipc/FdNotes.h"
99 #include "ipc/StartListening.h"
100 #include "log/access_log.h"
101 #include "MemBuf.h"
102 #include "MemObject.h"
103 #include "mime_header.h"
104 #include "parser/Tokenizer.h"
105 #include "profiler/Profiler.h"
106 #include "proxyp/Header.h"
107 #include "proxyp/Parser.h"
109 #include "servers/forward.h"
110 #include "SquidConfig.h"
111 #include "SquidTime.h"
112 #include "StatCounters.h"
113 #include "StatHist.h"
114 #include "Store.h"
115 #include "TimeOrTag.h"
116 #include "tools.h"
117 
118 #if USE_AUTH
119 #include "auth/UserRequest.h"
120 #endif
121 #if USE_DELAY_POOLS
122 #include "ClientInfo.h"
123 #include "MessageDelayPools.h"
124 #endif
125 #if USE_OPENSSL
126 #include "ssl/bio.h"
127 #include "ssl/context_storage.h"
128 #include "ssl/gadgets.h"
129 #include "ssl/helper.h"
130 #include "ssl/ProxyCerts.h"
131 #include "ssl/ServerBump.h"
132 #include "ssl/support.h"
133 #endif
134 
135 // for tvSubUsec() which should be in SquidTime.h
136 #include "util.h"
137 
138 #include <climits>
139 #include <cmath>
140 #include <limits>
141 
142 #if HAVE_SYSTEMD_SD_DAEMON_H
143 #include <systemd/sd-daemon.h>
144 #endif
145 
146 #if LINGERING_CLOSE
147 #define comm_close comm_lingering_close
148 #endif
149 
152 {
153 public:
156  handler(aHandler), portCfg(aPortCfg), portTypeNote(note), sub(aSub) {}
157 
158  virtual void print(std::ostream &os) const {
159  startPrint(os) <<
160  ", " << FdNote(portTypeNote) << " port=" << (void*)&portCfg << ')';
161  }
162 
163  virtual bool canDial(AsyncCall &) const { return true; }
164  virtual void dial(AsyncCall &) { (handler)(portCfg, portTypeNote, sub); }
165 
166 public:
168 
169 private:
173 };
174 
175 static void clientListenerConnectionOpened(AnyP::PortCfgPointer &s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub);
176 
179 #if USE_IDENT
181 #endif
183 static int clientIsRequestBodyTooLargeForPolicy(int64_t bodyLength);
184 
185 static void clientUpdateStatHistCounters(const LogTags &logType, int svc_time);
186 static void clientUpdateStatCounters(const LogTags &logType);
188 static bool clientPingHasFinished(ping_data const *aPing);
191 
192 char *skipLeadingSpace(char *aString);
193 
194 #if USE_IDENT
195 static void
196 clientIdentDone(const char *ident, void *data)
197 {
199  xstrncpy(conn->clientConnection->rfc931, ident ? ident : dash_str, USER_IDENT_SZ);
200 }
201 #endif
202 
203 void
205 {
207 
208  if (logType.isTcpHit())
210 
211  if (logType.oldType == LOG_TCP_HIT)
213  else if (logType.oldType == LOG_TCP_MEM_HIT)
215 }
216 
217 void
218 clientUpdateStatHistCounters(const LogTags &logType, int svc_time)
219 {
228  switch (logType.oldType) {
229 
232  break;
233 
234  case LOG_TCP_INM_HIT:
235  case LOG_TCP_IMS_HIT:
237  break;
238 
239  case LOG_TCP_HIT:
240 
241  case LOG_TCP_MEM_HIT:
242 
243  case LOG_TCP_OFFLINE_HIT:
245  break;
246 
247  case LOG_TCP_MISS:
248 
251  break;
252 
253  default:
254  /* make compiler warnings go away */
255  break;
256  }
257 }
258 
259 bool
261 {
262  if (0 != aPing->stop.tv_sec && 0 != aPing->start.tv_sec)
263  return true;
264 
265  return false;
266 }
267 
268 void
270 {
271  ping_data *i;
272 
273  switch (someEntry->code) {
274 #if USE_CACHE_DIGESTS
275 
276  case CD_PARENT_HIT:
277 
278  case CD_SIBLING_HIT:
280  break;
281 #endif
282 
283  case SIBLING_HIT:
284 
285  case PARENT_HIT:
286 
287  case FIRST_PARENT_MISS:
288 
289  case CLOSEST_PARENT_MISS:
291  i = &someEntry->ping;
292 
294  statCounter.icp.querySvcTime.count(tvSubUsec(i->start, i->stop));
295 
296  if (i->timeout)
298 
299  break;
300 
301  case CLOSEST_PARENT:
302 
303  case CLOSEST_DIRECT:
305 
306  break;
307 
308  default:
309  break;
310  }
311 }
312 
313 void
315 {
317 
318  if (request->errType != ERR_NONE)
320 
323 
325 }
326 
327 void
329 {
330  assert(request);
331  assert(aLogEntry != NULL);
332 
333  if (Config.onoff.log_mime_hdrs) {
334  MemBuf mb;
335  mb.init();
336  request->header.packInto(&mb);
337  //This is the request after adaptation or redirection
338  aLogEntry->headers.adapted_request = xstrdup(mb.buf);
339 
340  // the virgin request is saved to aLogEntry->request
341  if (aLogEntry->request) {
342  mb.reset();
343  aLogEntry->request->header.packInto(&mb);
344  aLogEntry->headers.request = xstrdup(mb.buf);
345  }
346 
347 #if USE_ADAPTATION
348  const Adaptation::History::Pointer ah = request->adaptLogHistory();
349  if (ah != NULL) {
350  mb.reset();
351  ah->lastMeta.packInto(&mb);
352  aLogEntry->adapt.last_meta = xstrdup(mb.buf);
353  }
354 #endif
355 
356  mb.clean();
357  }
358 
359 #if ICAP_CLIENT
360  const Adaptation::Icap::History::Pointer ih = request->icapHistory();
361  if (ih != NULL)
362  ih->processingTime(aLogEntry->icap.processingTime);
363 #endif
364 
365  aLogEntry->http.method = request->method;
366  aLogEntry->http.version = request->http_ver;
367  aLogEntry->hier = request->hier;
368  aLogEntry->cache.extuser = request->extacl_user.termedBuf();
369 
370  // Adapted request, if any, inherits and then collects all the stats, but
371  // the virgin request gets logged instead; copy the stats to log them.
372  // TODO: avoid losses by keeping these stats in a shared history object?
373  if (aLogEntry->request) {
374  aLogEntry->request->dnsWait = request->dnsWait;
375  aLogEntry->request->errType = request->errType;
376  aLogEntry->request->errDetail = request->errDetail;
377  }
378 }
379 
380 void
382 {
383  if (!out.size && logType.oldType == LOG_TAG_NONE)
384  debugs(33, 5, "logging half-baked transaction: " << log_uri);
385 
387  al->url = log_uri;
388  debugs(33, 9, "clientLogRequest: al.url='" << al->url << "'");
389 
390  const auto findReply = [this]() -> const HttpReply * {
391  if (al->reply)
392  return al->reply.getRaw();
393  if (const auto le = loggingEntry())
394  return le->hasFreshestReply();
395  return nullptr;
396  };
397  if (const auto reply = findReply()) {
398  al->http.code = reply->sline.status();
399  al->http.content_type = reply->content_type.termedBuf();
400  }
401 
402  debugs(33, 9, "clientLogRequest: http.code='" << al->http.code << "'");
403 
404  if (loggingEntry() && loggingEntry()->mem_obj && loggingEntry()->objectLen() >= 0)
405  al->cache.objectSize = loggingEntry()->contentLen(); // payload duplicate ?? with or without TE ?
406 
408  // the virgin request is saved to al->request
409  if (al->request && al->request->body_pipe)
412  // XXX: calculate without payload encoding or headers !!
413  al->http.clientReplySz.payloadData = out.size - out.headers_sz; // pretend its all un-encoded data for now.
414 
416 
417  al->cache.code = logType;
418 
420 
421  if (request)
423 
424 #if USE_OPENSSL && 0
425 
426  /* This is broken. Fails if the connection has been closed. Needs
427  * to snarf the ssl details some place earlier..
428  */
429  if (getConn() != NULL)
431 
432 #endif
433 
434  /* Add notes (if we have a request to annotate) */
435  if (request) {
436  SBuf matched;
437  for (auto h: Config.notes) {
438  if (h->match(request, al->reply.getRaw(), al, matched)) {
439  request->notes()->add(h->key(), matched);
440  debugs(33, 3, h->key() << " " << matched);
441  }
442  }
443  // The al->notes and request->notes must point to the same object.
444  al->syncNotes(request);
445  }
446 
447  ACLFilledChecklist checklist(NULL, request, NULL);
448  if (al->reply) {
449  checklist.reply = al->reply.getRaw();
450  HTTPMSGLOCK(checklist.reply);
451  }
452 
453  if (request) {
457  }
458  // no need checklist.syncAle(): already synced
459  checklist.al = al;
460  accessLogLog(al, &checklist);
461 
462  bool updatePerformanceCounters = true;
465  statsCheck.al = al;
466  if (al->reply) {
467  statsCheck.reply = al->reply.getRaw();
468  HTTPMSGLOCK(statsCheck.reply);
469  }
470  updatePerformanceCounters = statsCheck.fastCheck().allowed();
471  }
472 
473  if (updatePerformanceCounters) {
474  if (request)
475  updateCounters();
476 
477  if (getConn() != NULL && getConn()->clientConnection != NULL)
479  }
480 }
481 
482 void
484 {
485  safe_free(uri);
488  clearRequest();
489 
490  if (client_stream.tail)
492 }
493 
494 void
496 {
498  assert(http != NULL);
499  delete http;
500 }
501 
502 /* This is a handler normally called by comm_close() */
504 {
505  deleteThis("ConnStateData::connStateClosed");
506 }
507 
508 #if USE_AUTH
509 void
511 {
512  if (auth_ == NULL) {
513  if (aur != NULL) {
514  debugs(33, 2, "Adding connection-auth to " << clientConnection << " from " << by);
515  auth_ = aur;
516  }
517  return;
518  }
519 
520  // clobered with self-pointer
521  // NP: something nasty is going on in Squid, but harmless.
522  if (aur == auth_) {
523  debugs(33, 2, "WARNING: Ignoring duplicate connection-auth for " << clientConnection << " from " << by);
524  return;
525  }
526 
527  /*
528  * Connection-auth relies on a single set of credentials being preserved
529  * for all requests on a connection once they have been setup.
530  * There are several things which need to happen to preserve security
531  * when connection-auth credentials change unexpectedly or are unset.
532  *
533  * 1) auth helper released from any active state
534  *
535  * They can only be reserved by a handshake process which this
536  * connection can now never complete.
537  * This prevents helpers hanging when their connections close.
538  *
539  * 2) pinning is expected to be removed and server conn closed
540  *
541  * The upstream link is authenticated with the same credentials.
542  * Expecting the same level of consistency we should have received.
543  * This prevents upstream being faced with multiple or missing
544  * credentials after authentication.
545  * NP: un-pin is left to the cleanup in ConnStateData::swanSong()
546  * we just trigger that cleanup here via comm_reset_close() or
547  * ConnStateData::stopReceiving()
548  *
549  * 3) the connection needs to close.
550  *
551  * This prevents attackers injecting requests into a connection,
552  * or gateways wrongly multiplexing users into a single connection.
553  *
554  * When credentials are missing closure needs to follow an auth
555  * challenge for best recovery by the client.
556  *
557  * When credentials change there is nothing we can do but abort as
558  * fast as possible. Sending TCP RST instead of an HTTP response
559  * is the best-case action.
560  */
561 
562  // clobbered with nul-pointer
563  if (aur == NULL) {
564  debugs(33, 2, "WARNING: Graceful closure on " << clientConnection << " due to connection-auth erase from " << by);
566  auth_ = NULL;
567  // XXX: need to test whether the connection re-auth challenge is sent. If not, how to trigger it from here.
568  // NP: the current situation seems to fix challenge loops in Safari without visible issues in others.
569  // we stop receiving more traffic but can leave the Job running to terminate after the error or challenge is delivered.
570  stopReceiving("connection-auth removed");
571  return;
572  }
573 
574  // clobbered with alternative credentials
575  if (aur != auth_) {
576  debugs(33, 2, "ERROR: Closing " << clientConnection << " due to change of connection-auth from " << by);
578  auth_ = NULL;
579  // this is a fatal type of problem.
580  // Close the connection immediately with TCP RST to abort all traffic flow
582  return;
583  }
584 
585  /* NOT REACHABLE */
586 }
587 #endif
588 
589 // cleans up before destructor is called
590 void
592 {
593  debugs(33, 2, HERE << clientConnection);
594  checkLogging();
595 
596  flags.readMore = false;
597  clientdbEstablished(clientConnection->remote, -1); /* decrement */
599 
600  // XXX: Closing pinned conn is too harsh: The Client may want to continue!
601  unpinConnection(true);
602 
603  Server::swanSong(); // closes the client connection
604 
605 #if USE_AUTH
606  // NP: do this bit after closing the connections to avoid side effects from unwanted TCP RST
607  setAuth(NULL, "ConnStateData::SwanSong cleanup");
608 #endif
609 
610  flags.swanSang = true;
611 }
612 
613 bool
615 {
616  return cbdataReferenceValid(this) && // XXX: checking "this" in a method
618  !fd_table[clientConnection->fd].closing();
619 }
620 
622 {
623  debugs(33, 3, HERE << clientConnection);
624 
625  if (isOpen())
626  debugs(33, DBG_IMPORTANT, "BUG: ConnStateData did not close " << clientConnection);
627 
628  if (!flags.swanSang)
629  debugs(33, DBG_IMPORTANT, "BUG: ConnStateData was not destroyed properly; " << clientConnection);
630 
631  if (bodyPipe != NULL)
632  stopProducingFor(bodyPipe, false);
633 
634  delete bodyParser; // TODO: pool
635 
636 #if USE_OPENSSL
637  delete sslServerBump;
638 #endif
639 }
640 
647 void
649 {
650  HttpRequest *request = http->request;
651 
652  debugs(33, 3, "http_ver = " << request->http_ver);
653  debugs(33, 3, "method = " << request->method);
654 
655  // TODO: move to HttpRequest::hdrCacheInit, just like HttpReply.
656  request->flags.proxyKeepalive = request->persistent();
657 }
658 
660 static int
662 {
663  // No Content-Length means this request just has no body, but conflicting
664  // Content-Lengths mean a message framing error (RFC 7230 Section 3.3.3 #4).
666  return 0;
667 
668  switch (r->method.id()) {
669 
670  case Http::METHOD_GET:
671 
672  case Http::METHOD_HEAD:
673  /* We do not want to see a request entity on GET/HEAD requests */
674  return (r->content_length <= 0 || Config.onoff.request_entities);
675 
676  default:
677  /* For other types of requests we don't care */
678  return 1;
679  }
680 
681  /* NOT REACHED */
682 }
683 
684 int
686 {
688  bodyLength > Config.maxRequestBodySize)
689  return 1; /* too large */
690 
691  return 0;
692 }
693 
694 bool
696 {
697  return request->multipartRangeRequest();
698 }
699 
700 void
702 {
703  mb->appendf("\r\n--" SQUIDSTRINGPH "--\r\n", SQUIDSTRINGPRINT(boundary));
704  debugs(33, 6, "buf offset: " << mb->size);
705 }
706 
707 void
708 clientPackRangeHdr(const HttpReplyPointer &rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb)
709 {
710  HttpHeader hdr(hoReply);
711  assert(rep);
712  assert(spec);
713 
714  /* put boundary */
715  debugs(33, 5, "appending boundary: " << boundary);
716  /* rfc2046 requires to _prepend_ boundary with <crlf>! */
717  mb->appendf("\r\n--" SQUIDSTRINGPH "\r\n", SQUIDSTRINGPRINT(boundary));
718 
719  /* stuff the header with required entries and pack it */
720 
721  if (rep->header.has(Http::HdrType::CONTENT_TYPE))
723 
724  httpHeaderAddContRange(&hdr, *spec, rep->content_length);
725 
726  hdr.packInto(mb);
727  hdr.clean();
728 
729  /* append <crlf> (we packed a header, not a reply) */
730  mb->append("\r\n", 2);
731 }
732 
738 int
740 {
741  int64_t clen = 0;
742  MemBuf mb;
743 
744  assert(memObject());
745 
746  mb.init();
748 
749  while (pos != request->range->end()) {
750  /* account for headers for this range */
751  mb.reset();
752  clientPackRangeHdr(&storeEntry()->mem().freshestReply(),
753  *pos, range_iter.boundary, &mb);
754  clen += mb.size;
755 
756  /* account for range content */
757  clen += (*pos)->length;
758 
759  debugs(33, 6, "clientMRangeCLen: (clen += " << mb.size << " + " << (*pos)->length << ") == " << clen);
760  ++pos;
761  }
762 
763  /* account for the terminating boundary */
764  mb.reset();
765 
767 
768  clen += mb.size;
769 
770  mb.clean();
771 
772  return clen;
773 }
774 
778 String
780 {
781  const char *key;
782  String b(APP_FULLNAME);
783  b.append(":",1);
784  key = storeEntry()->getMD5Text();
785  b.append(key, strlen(key));
786  return b;
787 }
788 
798 void
800  HttpReply * rep, StoreIOBuffer receivedData)
801 {
802  // do not try to deliver if client already ABORTED
803  if (!http->getConn() || !cbdataReferenceValid(http->getConn()) || !Comm::IsConnOpen(http->getConn()->clientConnection))
804  return;
805 
806  /* Test preconditions */
807  assert(node != NULL);
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 == NULL);
816  Http::StreamPointer context = dynamic_cast<Http::Stream *>(node->data.getRaw());
817  assert(context != NULL);
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 
830 }
831 
837 void
839 {
840  /* Test preconditions */
841  assert(node != NULL);
842  /* TODO: handle this rather than asserting
843  * - it should only ever happen if we cause an abort and
844  * the callback chain loops back to here, so we can simply return.
845  * However, that itself shouldn't happen, so it stays as an assert for now.
846  */
848  /* Set null by ContextFree */
849  assert(node->node.next == NULL);
850  /* this is the assert discussed above */
851  assert(NULL == dynamic_cast<Http::Stream *>(node->data.getRaw()));
852  /* We are only called when the client socket shutsdown.
853  * Tell the prev pipeline member we're finished
854  */
855  clientStreamDetach(node, http);
856 }
857 
858 void
860 {
861  debugs(33, 5, HERE << clientConnection << " reading next req");
862 
863  fd_note(clientConnection->fd, "Idle client: Waiting for next request");
868  AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
869  TimeoutDialer, this, ConnStateData::requestTimeout);
871 
872  readSomeData();
874 }
875 
876 static void
878 {
879  debugs(33, 2, HERE << conn->clientConnection << " Sending next");
880 
883  if (deferredRequest->flags.deferred) {
885  assert(deferredRequest->http->out.size == 0);
887  clientSocketRecipient(deferredRequest->deferredparams.node,
888  deferredRequest->http,
889  deferredRequest->deferredparams.rep,
890  deferredRequest->deferredparams.queuedBuffer);
891  }
892 
896 }
897 
898 void
900 {
902  debugs(33, 2, clientConnection << " Connection was closed");
903  return;
904  }
905 
906  if (pinning.pinned && !Comm::IsConnOpen(pinning.serverConnection)) {
907  debugs(33, 2, clientConnection << " Connection was pinned but server side gone. Terminating client connection");
909  return;
910  }
911 
926  if (const char *reason = stoppedReceiving()) {
927  debugs(33, 3, "closing for earlier request error: " << reason);
929  return;
930  }
931 
942  if (clientParseRequests()) {
943  debugs(33, 3, clientConnection << ": parsed next request from buffer");
944  }
945 
954  debugs(33, 3, "half-closed client with no pending requests, closing");
956  return;
957  }
958 
966  Http::StreamPointer deferredRequest = pipeline.front();
967  if (deferredRequest != nullptr) {
968  debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded");
969  ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
970  } else if (flags.readMore) {
971  debugs(33, 3, clientConnection << ": calling readNextRequest()");
972  readNextRequest();
973  } else {
974  // XXX: Can this happen? CONNECT tunnels have deferredRequest set.
975  debugs(33, DBG_IMPORTANT, MYNAME << "abandoning " << clientConnection);
976  }
977 }
978 
979 void
981 {
982  debugs(33, 4, HERE << "sending error (" << clientConnection << "): " << error <<
983  "; old receiving error: " <<
984  (stoppedReceiving() ? stoppedReceiving_ : "none"));
985 
986  if (const char *oldError = stoppedSending()) {
987  debugs(33, 3, HERE << "already stopped sending: " << oldError);
988  return; // nothing has changed as far as this connection is concerned
989  }
991 
992  if (!stoppedReceiving()) {
993  if (const int64_t expecting = mayNeedToReadMoreBody()) {
994  debugs(33, 5, HERE << "must still read " << expecting <<
995  " request body bytes with " << inBuf.length() << " unused");
996  return; // wait for the request receiver to finish reading
997  }
998  }
999 
1001 }
1002 
1003 void
1005 {
1006  if (pipeline.empty())
1007  return;
1008 
1009  auto ctx = pipeline.front();
1010  if (size) {
1012  if (ctx->http->logType.isTcpHit())
1014  }
1015  ctx->writeComplete(size);
1016 }
1017 
1018 Http::Stream *
1020 {
1021  ClientHttpRequest *http = new ClientHttpRequest(this);
1022  http->req_sz = inBuf.length();
1023  http->setErrorUri(uri);
1024  auto *context = new Http::Stream(clientConnection, http);
1025  StoreIOBuffer tempBuffer;
1026  tempBuffer.data = context->reqbuf;
1027  tempBuffer.length = HTTP_REQBUF_SZ;
1030  clientSocketDetach, context, tempBuffer);
1031  return context;
1032 }
1033 
1034 void
1036 {
1037  // RegisteredRunner API callback - Squid has been shut down
1038 
1039  // if connection is idle terminate it now,
1040  // otherwise wait for grace period to end
1041  if (pipeline.empty())
1042  endingShutdown();
1043 }
1044 
1045 void
1047 {
1048  // RegisteredRunner API callback - Squid shutdown grace period is over
1049 
1050  // force the client connection to close immediately
1051  // swanSong() in the close handler will cleanup.
1054 }
1055 
1056 char *
1057 skipLeadingSpace(char *aString)
1058 {
1059  char *result = aString;
1060 
1061  while (xisspace(*aString))
1062  ++aString;
1063 
1064  return result;
1065 }
1066 
1072 const char *
1073 findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end)
1074 {
1075  if (NULL == end) {
1076  end = uriAndHTTPVersion + strcspn(uriAndHTTPVersion, "\r\n");
1077  assert(end);
1078  }
1079 
1080  for (; end > uriAndHTTPVersion; --end) {
1081  if (*end == '\n' || *end == '\r')
1082  continue;
1083 
1084  if (xisspace(*end)) {
1085  if (strncasecmp(end + 1, "HTTP/", 5) == 0)
1086  return end + 1;
1087  else
1088  break;
1089  }
1090  }
1091 
1092  return NULL;
1093 }
1094 
1095 static char *
1097 {
1098  int vhost = conn->port->vhost;
1099  int vport = conn->port->vport;
1100  static char ipbuf[MAX_IPSTRLEN];
1101 
1102  /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
1103 
1104  static const SBuf cache_object("cache_object://");
1105  if (hp->requestUri().startsWith(cache_object))
1106  return nullptr; /* already in good shape */
1107 
1108  // XXX: re-use proper URL parser for this
1109  SBuf url = hp->requestUri(); // use full provided URI if we abort
1110  do { // use a loop so we can break out of it
1111  ::Parser::Tokenizer tok(url);
1112  if (tok.skip('/')) // origin-form URL already.
1113  break;
1114 
1115  if (conn->port->vhost)
1116  return nullptr; /* already in good shape */
1117 
1118  // skip the URI scheme
1119  static const CharacterSet uriScheme = CharacterSet("URI-scheme","+-.") + CharacterSet::ALPHA + CharacterSet::DIGIT;
1120  static const SBuf uriSchemeEnd("://");
1121  if (!tok.skipAll(uriScheme) || !tok.skip(uriSchemeEnd))
1122  break;
1123 
1124  // skip the authority segment
1125  // RFC 3986 complex nested ABNF for "authority" boils down to this:
1126  static const CharacterSet authority = CharacterSet("authority","-._~%:@[]!$&'()*+,;=") +
1128  if (!tok.skipAll(authority))
1129  break;
1130 
1131  static const SBuf slashUri("/");
1132  const SBuf t = tok.remaining();
1133  if (t.isEmpty())
1134  url = slashUri;
1135  else if (t[0]=='/') // looks like path
1136  url = t;
1137  else if (t[0]=='?' || t[0]=='#') { // looks like query or fragment. fix '/'
1138  url = slashUri;
1139  url.append(t);
1140  } // else do nothing. invalid path
1141 
1142  } while(false);
1143 
1144 #if SHOULD_REJECT_UNKNOWN_URLS
1145  // reject URI which are not well-formed even after the processing above
1146  if (url.isEmpty() || url[0] != '/') {
1147  hp->parseStatusCode = Http::scBadRequest;
1148  return conn->abortRequestParsing("error:invalid-request");
1149  }
1150 #endif
1151 
1152  if (vport < 0)
1153  vport = conn->clientConnection->local.port();
1154 
1155  char *receivedHost = nullptr;
1156  if (vhost && (receivedHost = hp->getHostHeaderField())) {
1157  SBuf host(receivedHost);
1158  debugs(33, 5, "ACCEL VHOST REWRITE: vhost=" << host << " + vport=" << vport);
1159  if (vport > 0) {
1160  // remove existing :port (if any), cope with IPv6+ without port
1161  const auto lastColonPos = host.rfind(':');
1162  if (lastColonPos != SBuf::npos && *host.rbegin() != ']') {
1163  host.chop(0, lastColonPos); // truncate until the last colon
1164  }
1165  host.appendf(":%d", vport);
1166  } // else nothing to alter port-wise.
1167  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1168  const auto url_sz = scheme.length() + host.length() + url.length() + 32;
1169  char *uri = static_cast<char *>(xcalloc(url_sz, 1));
1170  snprintf(uri, url_sz, SQUIDSBUFPH "://" SQUIDSBUFPH SQUIDSBUFPH, SQUIDSBUFPRINT(scheme), SQUIDSBUFPRINT(host), SQUIDSBUFPRINT(url));
1171  debugs(33, 5, "ACCEL VHOST REWRITE: " << uri);
1172  return uri;
1173  } else if (conn->port->defaultsite /* && !vhost */) {
1174  debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: defaultsite=" << conn->port->defaultsite << " + vport=" << vport);
1175  char vportStr[32];
1176  vportStr[0] = '\0';
1177  if (vport > 0) {
1178  snprintf(vportStr, sizeof(vportStr),":%d",vport);
1179  }
1180  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1181  const int url_sz = scheme.length() + strlen(conn->port->defaultsite) + sizeof(vportStr) + url.length() + 32;
1182  char *uri = static_cast<char *>(xcalloc(url_sz, 1));
1183  snprintf(uri, url_sz, SQUIDSBUFPH "://%s%s" SQUIDSBUFPH,
1184  SQUIDSBUFPRINT(scheme), conn->port->defaultsite, vportStr, SQUIDSBUFPRINT(url));
1185  debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: " << uri);
1186  return uri;
1187  } else if (vport > 0 /* && (!vhost || no Host:) */) {
1188  debugs(33, 5, "ACCEL VPORT REWRITE: *_port IP + vport=" << vport);
1189  /* Put the local socket IP address as the hostname, with whatever vport we found */
1190  conn->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN);
1191  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1192  const int url_sz = scheme.length() + sizeof(ipbuf) + url.length() + 32;
1193  char *uri = static_cast<char *>(xcalloc(url_sz, 1));
1194  snprintf(uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
1195  SQUIDSBUFPRINT(scheme), ipbuf, vport, SQUIDSBUFPRINT(url));
1196  debugs(33, 5, "ACCEL VPORT REWRITE: " << uri);
1197  return uri;
1198  }
1199 
1200  return nullptr;
1201 }
1202 
1203 static char *
1205 {
1206  char *uri = nullptr;
1207  /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
1208  if (const char *host = hp->getHostHeaderField()) {
1209  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1210  const int url_sz = scheme.length() + strlen(host) + hp->requestUri().length() + 32;
1211  uri = static_cast<char *>(xcalloc(url_sz, 1));
1212  snprintf(uri, url_sz, SQUIDSBUFPH "://%s" SQUIDSBUFPH,
1213  SQUIDSBUFPRINT(scheme),
1214  host,
1215  SQUIDSBUFPRINT(hp->requestUri()));
1216  }
1217  return uri;
1218 }
1219 
1220 char *
1222 {
1223  Must(switchedToHttps());
1224 
1225  if (!hp->requestUri().isEmpty() && hp->requestUri()[0] != '/')
1226  return nullptr; /* already in good shape */
1227 
1228  char *uri = buildUrlFromHost(this, hp);
1229 #if USE_OPENSSL
1230  if (!uri) {
1233  SBuf useHost;
1234  if (!tlsClientSni().isEmpty())
1235  useHost = tlsClientSni();
1236  else
1237  useHost = tlsConnectHostOrIp;
1238 
1239  const SBuf &scheme = AnyP::UriScheme(transferProtocol.protocol).image();
1240  const int url_sz = scheme.length() + useHost.length() + hp->requestUri().length() + 32;
1241  uri = static_cast<char *>(xcalloc(url_sz, 1));
1242  snprintf(uri, url_sz, SQUIDSBUFPH "://" SQUIDSBUFPH ":%d" SQUIDSBUFPH,
1243  SQUIDSBUFPRINT(scheme),
1244  SQUIDSBUFPRINT(useHost),
1246  SQUIDSBUFPRINT(hp->requestUri()));
1247  }
1248 #endif
1249  if (uri)
1250  debugs(33, 5, "TLS switching host rewrite: " << uri);
1251  return uri;
1252 }
1253 
1254 static char *
1256 {
1257  // TODO Must() on URI !empty when the parser supports throw. For now avoid assert().
1258  if (!hp->requestUri().isEmpty() && hp->requestUri()[0] != '/')
1259  return nullptr; /* already in good shape */
1260 
1261  char *uri = buildUrlFromHost(conn, hp);
1262  if (!uri) {
1263  /* Put the local socket IP address as the hostname. */
1264  static char ipbuf[MAX_IPSTRLEN];
1265  conn->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN);
1266  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1267  const int url_sz = sizeof(ipbuf) + hp->requestUri().length() + 32;
1268  uri = static_cast<char *>(xcalloc(url_sz, 1));
1269  snprintf(uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
1270  SQUIDSBUFPRINT(scheme),
1271  ipbuf, conn->clientConnection->local.port(), SQUIDSBUFPRINT(hp->requestUri()));
1272  }
1273 
1274  if (uri)
1275  debugs(33, 5, "TRANSPARENT REWRITE: " << uri);
1276  return uri;
1277 }
1278 
1279 Http::Stream *
1281 {
1282  /* Attempt to parse the first line; this will define where the method, url, version and header begin */
1283  {
1284  Must(hp);
1285 
1288 
1289  const bool parsedOk = hp->parse(inBuf);
1290 
1291  // sync the buffers after parsing.
1292  inBuf = hp->remaining();
1293 
1294  if (hp->needsMoreData()) {
1295  debugs(33, 5, "Incomplete request, waiting for end of request line");
1296  return NULL;
1297  }
1298 
1299  if (!parsedOk) {
1300  const bool tooBig =
1301  hp->parseStatusCode == Http::scRequestHeaderFieldsTooLarge ||
1302  hp->parseStatusCode == Http::scUriTooLong;
1303  auto result = abortRequestParsing(
1304  tooBig ? "error:request-too-large" : "error:invalid-request");
1305  // assume that remaining leftovers belong to this bad request
1306  if (!inBuf.isEmpty())
1308  return result;
1309  }
1310  }
1311 
1312  /* We know the whole request is in parser now */
1313  debugs(11, 2, "HTTP Client " << clientConnection);
1314  debugs(11, 2, "HTTP Client REQUEST:\n---------\n" <<
1315  hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol() << "\n" <<
1316  hp->mimeHeader() <<
1317  "\n----------");
1318 
1319  /* deny CONNECT via accelerated ports */
1320  if (hp->method() == Http::METHOD_CONNECT && port != NULL && port->flags.accelSurrogate) {
1321  debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << transferProtocol << " Accelerator port " << port->s.port());
1322  debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1323  hp->parseStatusCode = Http::scMethodNotAllowed;
1324  return abortRequestParsing("error:method-not-allowed");
1325  }
1326 
1327  /* RFC 7540 section 11.6 registers the method PRI as HTTP/2 specific
1328  * Deny "PRI" method if used in HTTP/1.x or 0.9 versions.
1329  * If seen it signals a broken client or proxy has corrupted the traffic.
1330  */
1331  if (hp->method() == Http::METHOD_PRI && hp->messageProtocol() < Http::ProtocolVersion(2,0)) {
1332  debugs(33, DBG_IMPORTANT, "WARNING: PRI method received on " << transferProtocol << " port " << port->s.port());
1333  debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1334  hp->parseStatusCode = Http::scMethodNotAllowed;
1335  return abortRequestParsing("error:method-not-allowed");
1336  }
1337 
1338  if (hp->method() == Http::METHOD_NONE) {
1339  debugs(33, DBG_IMPORTANT, "WARNING: Unsupported method: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1340  hp->parseStatusCode = Http::scMethodNotAllowed;
1341  return abortRequestParsing("error:unsupported-request-method");
1342  }
1343 
1344  // Process headers after request line
1345  debugs(33, 3, "complete request received. " <<
1346  "prefix_sz = " << hp->messageHeaderSize() <<
1347  ", request-line-size=" << hp->firstLineSize() <<
1348  ", mime-header-size=" << hp->headerBlockSize() <<
1349  ", mime header block:\n" << hp->mimeHeader() << "\n----------");
1350 
1351  /* Ok, all headers are received */
1352  ClientHttpRequest *http = new ClientHttpRequest(this);
1353 
1354  http->req_sz = hp->messageHeaderSize();
1355  Http::Stream *result = new Http::Stream(clientConnection, http);
1356 
1357  StoreIOBuffer tempBuffer;
1358  tempBuffer.data = result->reqbuf;
1359  tempBuffer.length = HTTP_REQBUF_SZ;
1360 
1361  ClientStreamData newServer = new clientReplyContext(http);
1362  ClientStreamData newClient = result;
1363  clientStreamInit(&http->client_stream, clientGetMoreData, clientReplyDetach,
1365  clientSocketDetach, newClient, tempBuffer);
1366 
1367  /* set url */
1368  debugs(33,5, "Prepare absolute URL from " <<
1369  (transparent()?"intercept":(port->flags.accelSurrogate ? "accel":"")));
1370  /* Rewrite the URL in transparent or accelerator mode */
1371  /* NP: there are several cases to traverse here:
1372  * - standard mode (forward proxy)
1373  * - transparent mode (TPROXY)
1374  * - transparent mode with failures
1375  * - intercept mode (NAT)
1376  * - intercept mode with failures
1377  * - accelerator mode (reverse proxy)
1378  * - internal relative-URL
1379  * - mixed combos of the above with internal URL
1380  * - remote interception with PROXY protocol
1381  * - remote reverse-proxy with PROXY protocol
1382  */
1383  if (switchedToHttps()) {
1384  http->uri = prepareTlsSwitchingURL(hp);
1385  } else if (transparent()) {
1386  /* intercept or transparent mode, properly working with no failures */
1387  http->uri = prepareTransparentURL(this, hp);
1388 
1389  } else if (internalCheck(hp->requestUri())) { // NP: only matches relative-URI
1390  /* internal URL mode */
1391  /* prepend our name & port */
1392  http->uri = xstrdup(internalLocalUri(NULL, hp->requestUri()));
1393  // We just re-wrote the URL. Must replace the Host: header.
1394  // But have not parsed there yet!! flag for local-only handling.
1395  http->flags.internal = true;
1396 
1397  } else if (port->flags.accelSurrogate) {
1398  /* accelerator mode */
1399  http->uri = prepareAcceleratedURL(this, hp);
1400  http->flags.accel = true;
1401  }
1402 
1403  if (!http->uri) {
1404  /* No special rewrites have been applied above, use the
1405  * requested url. may be rewritten later, so make extra room */
1406  int url_sz = hp->requestUri().length() + Config.appendDomainLen + 5;
1407  http->uri = (char *)xcalloc(url_sz, 1);
1408  SBufToCstring(http->uri, hp->requestUri());
1409  }
1410 
1411  result->flags.parsed_ok = 1;
1412  return result;
1413 }
1414 
1415 bool
1417 {
1418  if (size == 0) {
1419  if (pipeline.empty() && inBuf.isEmpty()) {
1420  /* no current or pending requests */
1421  debugs(33, 4, HERE << clientConnection << " closed");
1422  return true;
1423  } else if (!Config.onoff.half_closed_clients) {
1424  /* admin doesn't want to support half-closed client sockets */
1425  debugs(33, 3, HERE << clientConnection << " aborted (half_closed_clients disabled)");
1427  return true;
1428  }
1429  }
1430 
1431  return false;
1432 }
1433 
1434 void
1435 ConnStateData::consumeInput(const size_t byteCount)
1436 {
1437  assert(byteCount > 0 && byteCount <= inBuf.length());
1438  inBuf.consume(byteCount);
1439  debugs(33, 5, "inBuf has " << inBuf.length() << " unused bytes");
1440 }
1441 
1442 void
1444 {
1445  // Were we expecting to read more request body from half-closed connection?
1447  debugs(33, 3, HERE << "truncated body: closing half-closed " << clientConnection);
1449  return;
1450  }
1451 
1452  if (flags.readMore)
1453  readSomeData();
1454 }
1455 
1456 void
1458 {
1459  // From HTTP p.o.v., we do not have to close after every error detected
1460  // at the client-side, but many such errors do require closure and the
1461  // client-side code is bad at handling errors so we play it safe.
1462  if (request)
1463  request->flags.proxyKeepalive = false;
1464  flags.readMore = false;
1465  debugs(33,4, HERE << "Will close after error: " << clientConnection);
1466 }
1467 
1468 #if USE_OPENSSL
1470 {
1471  ClientHttpRequest *http = context->http;
1472 
1473  if (!sslServerBump)
1474  return false;
1475 
1477  // Did we create an error entry while processing CONNECT?
1478  if (!sslServerBump->entry->isEmpty()) {
1479  quitAfterError(http->request);
1480 
1481  // Get the saved error entry and send it to the client by replacing the
1482  // ClientHttpRequest store entry with it.
1484  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1485  assert(repContext);
1486  debugs(33, 5, "Responding with delated error for " << http->uri);
1487  repContext->setReplyToStoreEntry(sslServerBump->entry, "delayed SslBump error");
1488 
1489  // Get error details from the fake certificate-peeking request.
1491  context->pullData();
1492  return true;
1493  }
1494 
1495  // In bump-server-first mode, we have not necessarily seen the intended
1496  // server name at certificate-peeking time. Check for domain mismatch now,
1497  // when we can extract the intended name from the bumped HTTP request.
1498  if (const Security::CertPointer &srvCert = sslServerBump->serverCert) {
1499  HttpRequest *request = http->request;
1500  if (!Ssl::checkX509ServerValidity(srvCert.get(), request->url.host())) {
1501  debugs(33, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " <<
1502  "does not match domainname " << request->url.host());
1503 
1504  bool allowDomainMismatch = false;
1507  check.al = http->al;
1509  check.syncAle(request, http->log_uri);
1510  allowDomainMismatch = check.fastCheck().allowed();
1511  delete check.sslErrors;
1512  check.sslErrors = NULL;
1513  }
1514 
1515  if (!allowDomainMismatch) {
1517 
1519  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1520  assert (repContext);
1521 
1522  request->hier = sslServerBump->request->hier;
1523 
1524  // Create an error object and fill it
1526  err->src_addr = clientConnection->remote;
1527  Ssl::ErrorDetail *errDetail = new Ssl::ErrorDetail(
1529  srvCert.get(), nullptr);
1530  err->detail = errDetail;
1531  repContext->setReplyToError(request->method, err);
1532  assert(context->http->out.offset == 0);
1533  context->pullData();
1534  return true;
1535  }
1536  }
1537  }
1538 
1539  return false;
1540 }
1541 #endif // USE_OPENSSL
1542 
1544 bool
1546 {
1547  assert(conn);
1548  assert(conn->pipeline.front() == context);
1549  return conn->tunnelOnError(method, requestError);
1550 }
1551 
1553 bool
1555 {
1557  debugs(33, 5, "disabled; send error: " << requestError);
1558  return false;
1559  }
1560 
1561  if (!preservingClientData_) {
1562  debugs(33, 3, "may have forgotten client data; send error: " << requestError);
1563  return false;
1564  }
1565 
1566  const auto context = pipeline.front();
1567  const auto http = context ? context->http : nullptr;
1568  const auto request = http ? http->request : nullptr;
1569 
1571  checklist.al = http ? http->al : nullptr;
1572  checklist.requestErrorType = requestError;
1573  checklist.src_addr = clientConnection->remote;
1574  checklist.my_addr = clientConnection->local;
1575  checklist.conn(this);
1576  const char *log_uri = http ? http->log_uri : nullptr;
1577  checklist.syncAle(request, log_uri);
1578  auto answer = checklist.fastCheck();
1579  if (answer.allowed() && answer.kind == 1) {
1580  debugs(33, 3, "Request will be tunneled to server");
1581  if (context)
1582  context->finished(); // Will remove from pipeline queue
1585  }
1586  debugs(33, 3, "denied; send error: " << requestError);
1587  return false;
1588 }
1589 
1590 void
1592 {
1593  /*
1594  * DPW 2007-05-18
1595  * Moved the TCP_RESET feature from clientReplyContext::sendMoreData
1596  * to here because calling comm_reset_close() causes http to
1597  * be freed before accessing.
1598  */
1599  if (request != NULL && request->flags.resetTcp && Comm::IsConnOpen(conn->clientConnection)) {
1600  debugs(33, 3, HERE << "Sending TCP RST on " << conn->clientConnection);
1601  conn->flags.readMore = false;
1602  comm_reset_close(conn->clientConnection);
1603  }
1604 }
1605 
1606 void
1608 {
1609  ClientHttpRequest *http = context->http;
1610  bool chunked = false;
1611  bool mustReplyToOptions = false;
1612  bool unsupportedTe = false;
1613  bool expectBody = false;
1614 
1615  // We already have the request parsed and checked, so we
1616  // only need to go through the final body/conn setup to doCallouts().
1617  assert(http->request);
1619 
1620  // temporary hack to avoid splitting this huge function with sensitive code
1621  const bool isFtp = !hp;
1622 
1623  // Some blobs below are still HTTP-specific, but we would have to rewrite
1624  // this entire function to remove them from the FTP code path. Connection
1625  // setup and body_pipe preparation blobs are needed for FTP.
1626 
1627  request->manager(conn, http->al);
1628 
1629  request->flags.accelerated = http->flags.accel;
1630  request->flags.sslBumped=conn->switchedToHttps();
1631  // TODO: decouple http->flags.accel from request->flags.sslBumped
1632  request->flags.noDirect = (request->flags.accelerated && !request->flags.sslBumped) ?
1633  !conn->port->allow_direct : 0;
1634  request->sources |= isFtp ? Http::Message::srcFtp :
1635  ((request->flags.sslBumped || conn->port->transport.protocol == AnyP::PROTO_HTTPS) ? Http::Message::srcHttps : Http::Message::srcHttp);
1636 #if USE_AUTH
1637  if (request->flags.sslBumped) {
1638  if (conn->getAuth() != NULL)
1639  request->auth_user_request = conn->getAuth();
1640  }
1641 #endif
1642 
1643  if (internalCheck(request->url.path())) {
1644  if (internalHostnameIs(request->url.host()) && request->url.port() == getMyPort()) {
1645  debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true));
1646  http->flags.internal = true;
1648  debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (global_internal_static on)");
1649  request->url.setScheme(AnyP::PROTO_HTTP, "http");
1650  request->url.host(internalHostname());
1651  request->url.port(getMyPort());
1652  http->flags.internal = true;
1653  http->setLogUriToRequestUri();
1654  } else
1655  debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (not this proxy)");
1656  }
1657 
1658  request->flags.internal = http->flags.internal;
1659 
1660  if (!isFtp) {
1661  // XXX: for non-HTTP messages instantiate a different Http::Message child type
1662  // for now Squid only supports HTTP requests
1663  const AnyP::ProtocolVersion &http_ver = hp->messageProtocol();
1664  assert(request->http_ver.protocol == http_ver.protocol);
1665  request->http_ver.major = http_ver.major;
1666  request->http_ver.minor = http_ver.minor;
1667  }
1668 
1669  if (request->header.chunked()) {
1670  chunked = true;
1671  } else if (request->header.has(Http::HdrType::TRANSFER_ENCODING)) {
1672  const String te = request->header.getList(Http::HdrType::TRANSFER_ENCODING);
1673  // HTTP/1.1 requires chunking to be the last encoding if there is one
1674  unsupportedTe = te.size() && te != "identity";
1675  } // else implied identity coding
1676 
1677  mustReplyToOptions = (request->method == Http::METHOD_OPTIONS) &&
1678  (request->header.getInt64(Http::HdrType::MAX_FORWARDS) == 0);
1679  if (!urlCheckRequest(request.getRaw()) || mustReplyToOptions || unsupportedTe) {
1681  conn->quitAfterError(request.getRaw());
1682  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1683  assert (repContext);
1685  conn->clientConnection->remote, request.getRaw(), NULL, NULL);
1686  assert(context->http->out.offset == 0);
1687  context->pullData();
1689  return;
1690  }
1691 
1692  if (!chunked && !clientIsContentLengthValid(request.getRaw())) {
1694  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1695  assert (repContext);
1696  conn->quitAfterError(request.getRaw());
1697  repContext->setReplyToError(ERR_INVALID_REQ,
1699  conn->clientConnection->remote, request.getRaw(), NULL, NULL);
1700  assert(context->http->out.offset == 0);
1701  context->pullData();
1703  return;
1704  }
1705 
1706  clientSetKeepaliveFlag(http);
1707  // Let tunneling code be fully responsible for CONNECT requests
1708  if (http->request->method == Http::METHOD_CONNECT) {
1709  context->mayUseConnection(true);
1710  conn->flags.readMore = false;
1711  }
1712 
1713 #if USE_OPENSSL
1714  if (conn->switchedToHttps() && conn->serveDelayedError(context)) {
1716  return;
1717  }
1718 #endif
1719 
1720  /* Do we expect a request-body? */
1721  expectBody = chunked || request->content_length > 0;
1722  if (!context->mayUseConnection() && expectBody) {
1723  request->body_pipe = conn->expectRequestBody(
1724  chunked ? -1 : request->content_length);
1725 
1726  /* Is it too large? */
1727  if (!chunked && // if chunked, we will check as we accumulate
1730  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1731  assert (repContext);
1732  conn->quitAfterError(request.getRaw());
1733  repContext->setReplyToError(ERR_TOO_BIG,
1735  conn->clientConnection->remote, http->request, NULL, NULL);
1736  assert(context->http->out.offset == 0);
1737  context->pullData();
1739  return;
1740  }
1741 
1742  if (!isFtp) {
1743  // We may stop producing, comm_close, and/or call setReplyToError()
1744  // below, so quit on errors to avoid http->doCallouts()
1745  if (!conn->handleRequestBodyData()) {
1747  return;
1748  }
1749 
1750  if (!request->body_pipe->productionEnded()) {
1751  debugs(33, 5, "need more request body");
1752  context->mayUseConnection(true);
1753  assert(conn->flags.readMore);
1754  }
1755  }
1756  }
1757 
1758  http->calloutContext = new ClientRequestContext(http);
1759 
1760  http->doCallouts();
1761 
1763 }
1764 
1765 int
1767 {
1768  // TODO: Support pipelined requests through pinned connections.
1769  if (pinning.pinned)
1770  return 0;
1772 }
1773 
1779 bool
1781 {
1782  const int existingRequestCount = pipeline.count();
1783 
1784  // default to the configured pipeline size.
1785  // add 1 because the head of pipeline is counted in concurrent requests and not prefetch queue
1786 #if USE_OPENSSL
1787  const int internalRequest = (transparent() && sslBumpMode == Ssl::bumpSplice) ? 1 : 0;
1788 #else
1789  const int internalRequest = 0;
1790 #endif
1791  const int concurrentRequestLimit = pipelinePrefetchMax() + 1 + internalRequest;
1792 
1793  // when queue filled already we can't add more.
1794  if (existingRequestCount >= concurrentRequestLimit) {
1795  debugs(33, 3, clientConnection << " max concurrent requests reached (" << concurrentRequestLimit << ")");
1796  debugs(33, 5, clientConnection << " deferring new request until one is done");
1797  return true;
1798  }
1799 
1800  return false;
1801 }
1802 
1808 bool
1810 {
1812  return proxyProtocolError("PROXY client not permitted by default ACL");
1813 
1817  ch.conn(this);
1818 
1819  if (!ch.fastCheck().allowed())
1820  return proxyProtocolError("PROXY client not permitted by ACLs");
1821 
1822  return true;
1823 }
1824 
1830 bool
1832 {
1833  if (msg) {
1834  // This is important to know, but maybe not so much that flooding the log is okay.
1835 #if QUIET_PROXY_PROTOCOL
1836  // display the first of every 32 occurrences at level 1, the others at level 2.
1837  static uint8_t hide = 0;
1838  debugs(33, (hide++ % 32 == 0 ? DBG_IMPORTANT : 2), msg << " from " << clientConnection);
1839 #else
1840  debugs(33, DBG_IMPORTANT, msg << " from " << clientConnection);
1841 #endif
1842  mustStop(msg);
1843  }
1844  return false;
1845 }
1846 
1851 bool
1853 {
1854  try {
1855  const auto parsed = ProxyProtocol::Parse(inBuf);
1856  proxyProtocolHeader_ = parsed.header;
1858  inBuf.consume(parsed.size);
1859  needProxyProtocolHeader_ = false;
1860  if (proxyProtocolHeader_->hasForwardedAddresses()) {
1861  clientConnection->local = proxyProtocolHeader_->destinationAddress;
1862  clientConnection->remote = proxyProtocolHeader_->sourceAddress;
1864  clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
1865  debugs(33, 5, "PROXY/" << proxyProtocolHeader_->version() << " upgrade: " << clientConnection);
1866  }
1867  } catch (const Parser::BinaryTokenizer::InsufficientInput &) {
1868  debugs(33, 3, "PROXY protocol: waiting for more than " << inBuf.length() << " bytes");
1869  return false;
1870  } catch (const std::exception &e) {
1871  return proxyProtocolError(e.what());
1872  }
1873  return true;
1874 }
1875 
1876 void
1878 {
1879  if (receivedFirstByte_)
1880  return;
1881 
1882  receivedFirstByte_ = true;
1883  // Set timeout to Config.Timeout.request
1885  AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
1886  TimeoutDialer, this, ConnStateData::requestTimeout);
1888 }
1889 
1895 bool
1897 {
1898  bool parsed_req = false;
1899 
1900  debugs(33, 5, HERE << clientConnection << ": attempting to parse");
1901 
1902  // Loop while we have read bytes that are not needed for producing the body
1903  // On errors, bodyPipe may become nil, but readMore will be cleared
1904  while (!inBuf.isEmpty() && !bodyPipe && flags.readMore) {
1905 
1906  // Prohibit concurrent requests when using a pinned to-server connection
1907  // because our Client classes do not support request pipelining.
1908  if (pinning.pinned && !pinning.readHandler) {
1909  debugs(33, 3, clientConnection << " waits for busy " << pinning.serverConnection);
1910  break;
1911  }
1912 
1913  /* Limit the number of concurrent requests */
1915  break;
1916 
1917  // try to parse the PROXY protocol header magic bytes
1919  if (!parseProxyProtocolHeader())
1920  break;
1921 
1922  // we have been waiting for PROXY to provide client-IP
1923  // for some lookups, ie rDNS and IDENT.
1925 
1926  // Done with PROXY protocol which has cleared preservingClientData_.
1927  // If the next protocol supports on_unsupported_protocol, then its
1928  // parseOneRequest() must reset preservingClientData_.
1930  }
1931 
1932  if (Http::StreamPointer context = parseOneRequest()) {
1933  debugs(33, 5, clientConnection << ": done parsing a request");
1934 
1935  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "clientLifetimeTimeout",
1936  CommTimeoutCbPtrFun(clientLifetimeTimeout, context->http));
1938 
1939  context->registerWithConn();
1940 
1941 #if USE_OPENSSL
1942  if (switchedToHttps())
1944 #endif
1945 
1946  processParsedRequest(context);
1947 
1948  parsed_req = true; // XXX: do we really need to parse everything right NOW ?
1949 
1950  if (context->mayUseConnection()) {
1951  debugs(33, 3, HERE << "Not parsing new requests, as this request may need the connection");
1952  break;
1953  }
1954  } else {
1955  debugs(33, 5, clientConnection << ": not enough request data: " <<
1956  inBuf.length() << " < " << Config.maxRequestHeaderSize);
1958  break;
1959  }
1960  }
1961 
1962  /* XXX where to 'finish' the parsing pass? */
1963  return parsed_req;
1964 }
1965 
1966 void
1968 {
1969 #if USE_OPENSSL
1970  if (parsingTlsHandshake) {
1972  return;
1973  }
1974 #endif
1975 
1976  /* Process next request */
1977  if (pipeline.empty())
1978  fd_note(clientConnection->fd, "Reading next request");
1979 
1980  if (!clientParseRequests()) {
1981  if (!isOpen())
1982  return;
1983  /*
1984  * If the client here is half closed and we failed
1985  * to parse a request, close the connection.
1986  * The above check with connFinishedWithConn() only
1987  * succeeds _if_ the buffer is empty which it won't
1988  * be if we have an incomplete request.
1989  * XXX: This duplicates ConnStateData::kick
1990  */
1992  debugs(33, 5, clientConnection << ": half-closed connection, no completed request parsed, connection closing.");
1994  return;
1995  }
1996  }
1997 
1998  if (!isOpen())
1999  return;
2000 
2002 }
2003 
2010 bool
2012 {
2013  // if we are reading a body, stuff data into the body pipe
2014  if (bodyPipe != NULL)
2015  return handleRequestBodyData();
2016  return true;
2017 }
2018 
2026 bool
2028 {
2029  assert(bodyPipe != NULL);
2030 
2031  if (bodyParser) { // chunked encoding
2032  if (const err_type error = handleChunkedRequestBody()) {
2034  return false;
2035  }
2036  } else { // identity encoding
2037  debugs(33,5, HERE << "handling plain request body for " << clientConnection);
2038  const size_t putSize = bodyPipe->putMoreData(inBuf.c_str(), inBuf.length());
2039  if (putSize > 0)
2040  consumeInput(putSize);
2041 
2042  if (!bodyPipe->mayNeedMoreData()) {
2043  // BodyPipe will clear us automagically when we produced everything
2044  bodyPipe = NULL;
2045  }
2046  }
2047 
2048  if (!bodyPipe) {
2049  debugs(33,5, HERE << "produced entire request body for " << clientConnection);
2050 
2051  if (const char *reason = stoppedSending()) {
2052  /* we've finished reading like good clients,
2053  * now do the close that initiateClose initiated.
2054  */
2055  debugs(33, 3, HERE << "closing for earlier sending error: " << reason);
2057  return false;
2058  }
2059  }
2060 
2061  return true;
2062 }
2063 
2065 err_type
2067 {
2068  debugs(33, 7, "chunked from " << clientConnection << ": " << inBuf.length());
2069 
2070  try { // the parser will throw on errors
2071 
2072  if (inBuf.isEmpty()) // nothing to do
2073  return ERR_NONE;
2074 
2075  BodyPipeCheckout bpc(*bodyPipe);
2077  const bool parsed = bodyParser->parse(inBuf);
2078  inBuf = bodyParser->remaining(); // sync buffers
2079  bpc.checkIn();
2080 
2081  // dechunk then check: the size limit applies to _dechunked_ content
2083  return ERR_TOO_BIG;
2084 
2085  if (parsed) {
2087  Must(!bodyPipe);
2088  return ERR_NONE; // nil bodyPipe implies body end for the caller
2089  }
2090 
2091  // if chunk parser needs data, then the body pipe must need it too
2093 
2094  // if parser needs more space and we can consume nothing, we will stall
2096  } catch (...) { // TODO: be more specific
2097  debugs(33, 3, HERE << "malformed chunks" << bodyPipe->status());
2098  return ERR_INVALID_REQ;
2099  }
2100 
2101  debugs(33, 7, HERE << "need more chunked data" << *bodyPipe->status());
2102  return ERR_NONE;
2103 }
2104 
2106 void
2108 {
2109  finishDechunkingRequest(false);
2110 
2111  // XXX: The code below works if we fail during initial request parsing,
2112  // but if we fail when the server connection is used already, the server may send
2113  // us its response too, causing various assertions. How to prevent that?
2114 #if WE_KNOW_HOW_TO_SEND_ERRORS
2115  Http::StreamPointer context = pipeline.front();
2116  if (context != NULL && !context->http->out.offset) { // output nothing yet
2117  clientStreamNode *node = context->getClientReplyContext();
2118  clientReplyContext *repContext = dynamic_cast<clientReplyContext*>(node->data.getRaw());
2119  assert(repContext);
2120  const Http::StatusCode scode = (error == ERR_TOO_BIG) ?
2121  Http::scPayloadTooLarge : HTTP_BAD_REQUEST;
2122  repContext->setReplyToError(error, scode,
2123  repContext->http->request->method,
2124  repContext->http->uri,
2125  CachePeer,
2126  repContext->http->request,
2127  inBuf, NULL);
2128  context->pullData();
2129  } else {
2130  // close or otherwise we may get stuck as nobody will notice the error?
2132  }
2133 #else
2134  debugs(33, 3, HERE << "aborting chunked request without error " << error);
2136 #endif
2137  flags.readMore = false;
2138 }
2139 
2140 void
2142 {
2143  // request reader may get stuck waiting for space if nobody consumes body
2144  if (bodyPipe != NULL)
2146 
2147  // kids extend
2148 }
2149 
2151 void
2153 {
2154  if (!Comm::IsConnOpen(io.conn))
2155  return;
2156 
2159  return;
2160 
2161  /*
2162  * Just close the connection to not confuse browsers
2163  * using persistent connections. Some browsers open
2164  * a connection and then do not use it until much
2165  * later (presumeably because the request triggering
2166  * the open has already been completed on another
2167  * connection)
2168  */
2169  debugs(33, 3, "requestTimeout: FD " << io.fd << ": lifetime is expired.");
2170  io.conn->close();
2171 }
2172 
2173 static void
2175 {
2176  ClientHttpRequest *http = static_cast<ClientHttpRequest *>(io.data);
2177  debugs(33, DBG_IMPORTANT, "WARNING: Closing client connection due to lifetime timeout");
2178  debugs(33, DBG_IMPORTANT, "\t" << http->uri);
2179  http->logType.err.timedout = true;
2180  if (Comm::IsConnOpen(io.conn))
2181  io.conn->close();
2182 }
2183 
2185  AsyncJob("ConnStateData"), // kids overwrite
2186  Server(xact),
2187  bodyParser(nullptr),
2188 #if USE_OPENSSL
2189  sslBumpMode(Ssl::bumpEnd),
2190 #endif
2191  needProxyProtocolHeader_(false),
2192 #if USE_OPENSSL
2193  switchedToHttps_(false),
2194  parsingTlsHandshake(false),
2195  parsedBumpedRequestCount(0),
2196  tlsConnectPort(0),
2197  sslServerBump(NULL),
2198  signAlgorithm(Ssl::algSignTrusted),
2199 #endif
2200  stoppedSending_(NULL),
2201  stoppedReceiving_(NULL)
2202 {
2203  flags.readMore = true; // kids may overwrite
2204  flags.swanSang = false;
2205 
2206  pinning.host = NULL;
2207  pinning.port = -1;
2208  pinning.pinned = false;
2209  pinning.auth = false;
2210  pinning.zeroReply = false;
2211  pinning.peerAccessDenied = false;
2212  pinning.peer = NULL;
2213 
2214  // store the details required for creating more MasterXaction objects as new requests come in
2215  log_addr = xact->tcpClient->remote;
2217 
2218  // register to receive notice of Squid signal events
2219  // which may affect long persisting client connections
2220  registerRunner();
2221 }
2222 
2223 void
2225 {
2228 
2229  if (port->disable_pmtu_discovery != DISABLE_PMTU_OFF &&
2230  (transparent() || port->disable_pmtu_discovery == DISABLE_PMTU_ALWAYS)) {
2231 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
2232  int i = IP_PMTUDISC_DONT;
2233  if (setsockopt(clientConnection->fd, SOL_IP, IP_MTU_DISCOVER, &i, sizeof(i)) < 0) {
2234  int xerrno = errno;
2235  debugs(33, 2, "WARNING: Path MTU discovery disabling failed on " << clientConnection << " : " << xstrerr(xerrno));
2236  }
2237 #else
2238  static bool reported = false;
2239 
2240  if (!reported) {
2241  debugs(33, DBG_IMPORTANT, "NOTICE: Path MTU discovery disabling is not supported on your platform.");
2242  reported = true;
2243  }
2244 #endif
2245  }
2246 
2248  AsyncCall::Pointer call = JobCallback(33, 5, Dialer, this, ConnStateData::connStateClosed);
2250 
2251  needProxyProtocolHeader_ = port->flags.proxySurrogate;
2253  if (!proxyProtocolValidateClient()) // will close the connection on failure
2254  return;
2255  } else
2257 
2258  // requires needProxyProtocolHeader_ which is initialized above
2260 }
2261 
2262 void
2264 {
2265  if (Config.onoff.log_fqdn)
2267 
2268 #if USE_IDENT
2269  if (Ident::TheConfig.identLookup) {
2270  ACLFilledChecklist identChecklist(Ident::TheConfig.identLookup, NULL, NULL);
2271  identChecklist.src_addr = clientConnection->remote;
2272  identChecklist.my_addr = clientConnection->local;
2273  if (identChecklist.fastCheck().allowed())
2275  }
2276 #endif
2277 
2279 
2280 #if USE_DELAY_POOLS
2281  fd_table[clientConnection->fd].clientInfo = NULL;
2282 
2283  if (!Config.onoff.client_db)
2284  return; // client delay pools require client_db
2285 
2286  const auto &pools = ClientDelayPools::Instance()->pools;
2287  if (pools.size()) {
2289 
2290  // TODO: we check early to limit error response bandwidth but we
2291  // should recheck when we can honor delay_pool_uses_indirect
2292  // TODO: we should also pass the port details for myportname here.
2295 
2296  for (unsigned int pool = 0; pool < pools.size(); ++pool) {
2297 
2298  /* pools require explicit 'allow' to assign a client into them */
2299  if (pools[pool]->access) {
2300  ch.changeAcl(pools[pool]->access);
2301  auto answer = ch.fastCheck();
2302  if (answer.allowed()) {
2303 
2304  /* request client information from db after we did all checks
2305  this will save hash lookup if client failed checks */
2307  assert(cli);
2308 
2309  /* put client info in FDE */
2310  fd_table[clientConnection->fd].clientInfo = cli;
2311 
2312  /* setup write limiter for this request */
2313  const double burst = floor(0.5 +
2314  (pools[pool]->highwatermark * Config.ClientDelay.initial)/100.0);
2315  cli->setWriteLimiter(pools[pool]->rate, burst, pools[pool]->highwatermark);
2316  break;
2317  } else {
2318  debugs(83, 4, HERE << "Delay pool " << pool << " skipped because ACL " << answer);
2319  }
2320  }
2321  }
2322  }
2323 #endif
2324 
2325  // kids must extend to actually start doing something (e.g., reading)
2326 }
2327 
2329 void
2331 {
2332  MasterXaction::Pointer xact = params.xaction;
2333  AnyP::PortCfgPointer s = xact->squidPort;
2334 
2335  // NP: it is possible the port was reconfigured when the call or accept() was queued.
2336 
2337  if (params.flag != Comm::OK) {
2338  // Its possible the call was still queued when the client disconnected
2339  debugs(33, 2, s->listenConn << ": accept failure: " << xstrerr(params.xerrno));
2340  return;
2341  }
2342 
2343  debugs(33, 4, params.conn << ": accepted");
2344  fd_note(params.conn->fd, "client http connect");
2345 
2346  if (s->tcp_keepalive.enabled)
2347  commSetTcpKeepalive(params.conn->fd, s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
2348 
2350 
2351  // Socket is ready, setup the connection manager to start using it
2352  auto *srv = Http::NewServer(xact);
2353  AsyncJob::Start(srv); // usually async-calls readSomeData()
2354 }
2355 
2357 static bool
2359 {
2360  const auto conn = connState->clientConnection;
2361  if (Security::CreateServerSession(ctx, conn, connState->port->secure, "client https start")) {
2362  debugs(33, 5, "will negotiate TLS on " << conn);
2363  return true;
2364  }
2365 
2366  debugs(33, DBG_IMPORTANT, "ERROR: could not create TLS server context for " << conn);
2367  conn->close();
2368  return false;
2369 }
2370 
2377 static int
2379 {
2380  // TODO: maybe throw instead of returning -1
2381  // see https://github.com/squid-cache/squid/pull/81#discussion_r153053278
2382  int fd = conn->clientConnection->fd;
2383  auto session = fd_table[fd].ssl.get();
2384 
2385  errno = 0;
2386 
2387 #if USE_OPENSSL
2388  const auto ret = SSL_accept(session);
2389  if (ret > 0)
2390  return 1;
2391 
2392  const int xerrno = errno;
2393  const auto ssl_error = SSL_get_error(session, ret);
2394 
2395  switch (ssl_error) {
2396 
2397  case SSL_ERROR_WANT_READ:
2398  Comm::SetSelect(fd, COMM_SELECT_READ, callback, (callback ? conn : nullptr), 0);
2399  return 0;
2400 
2401  case SSL_ERROR_WANT_WRITE:
2402  Comm::SetSelect(fd, COMM_SELECT_WRITE, callback, (callback ? conn : nullptr), 0);
2403  return 0;
2404 
2405  case SSL_ERROR_SYSCALL:
2406  if (ret == 0) {
2407  debugs(83, 2, "Error negotiating SSL connection on FD " << fd << ": Aborted by client: " << ssl_error);
2408  } else {
2409  debugs(83, (xerrno == ECONNRESET) ? 1 : 2, "Error negotiating SSL connection on FD " << fd << ": " <<
2410  (xerrno == 0 ? Security::ErrorString(ssl_error) : xstrerr(xerrno)));
2411  }
2412  break;
2413 
2414  case SSL_ERROR_ZERO_RETURN:
2415  debugs(83, DBG_IMPORTANT, "Error negotiating SSL connection on FD " << fd << ": Closed by client");
2416  break;
2417 
2418  default:
2419  debugs(83, DBG_IMPORTANT, "Error negotiating SSL connection on FD " <<
2420  fd << ": " << Security::ErrorString(ssl_error) <<
2421  " (" << ssl_error << "/" << ret << ")");
2422  }
2423 
2424 #elif USE_GNUTLS
2425 
2426  const auto x = gnutls_handshake(session);
2427  if (x == GNUTLS_E_SUCCESS)
2428  return 1;
2429 
2430  if (gnutls_error_is_fatal(x)) {
2431  debugs(83, 2, "Error negotiating TLS on " << conn->clientConnection << ": Aborted by client: " << Security::ErrorString(x));
2432 
2433  } else if (x == GNUTLS_E_INTERRUPTED || x == GNUTLS_E_AGAIN) {
2434  const auto ioAction = (gnutls_record_get_direction(session)==0 ? COMM_SELECT_READ : COMM_SELECT_WRITE);
2435  Comm::SetSelect(fd, ioAction, callback, (callback ? conn : nullptr), 0);
2436  return 0;
2437  }
2438 
2439 #else
2440  // Performing TLS handshake should never be reachable without a TLS/SSL library.
2441  (void)session; // avoid compiler and static analysis complaints
2442  fatal("FATAL: HTTPS not supported by this Squid.");
2443 #endif
2444 
2445  return -1;
2446 }
2447 
2449 static void
2450 clientNegotiateSSL(int fd, void *data)
2451 {
2453 
2454  const int ret = tlsAttemptHandshake(conn, clientNegotiateSSL);
2455  if (ret <= 0) {
2456  if (ret < 0) // An error
2457  conn->clientConnection->close();
2458  return;
2459  }
2460 
2461  Security::SessionPointer session(fd_table[fd].ssl);
2462 
2463 #if USE_OPENSSL
2464  if (Security::SessionIsResumed(session)) {
2465  debugs(83, 2, "Session " << SSL_get_session(session.get()) <<
2466  " reused on FD " << fd << " (" << fd_table[fd].ipaddr <<
2467  ":" << (int)fd_table[fd].remote_port << ")");
2468  } else {
2469  if (Debug::Enabled(83, 4)) {
2470  /* Write out the SSL session details.. actually the call below, but
2471  * OpenSSL headers do strange typecasts confusing GCC.. */
2472  /* PEM_write_SSL_SESSION(debug_log, SSL_get_session(ssl)); */
2473 #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00908000L
2474  PEM_ASN1_write(reinterpret_cast<i2d_of_void *>(i2d_SSL_SESSION),
2475  PEM_STRING_SSL_SESSION, debug_log,
2476  reinterpret_cast<char *>(SSL_get_session(session.get())),
2477  nullptr, nullptr, 0, nullptr, nullptr);
2478 
2479 #elif (ALLOW_ALWAYS_SSL_SESSION_DETAIL == 1)
2480 
2481  /* When using gcc 3.3.x and OpenSSL 0.9.7x sometimes a compile error can occur here.
2482  * This is caused by an unpredicatble gcc behaviour on a cast of the first argument
2483  * of PEM_ASN1_write(). For this reason this code section is disabled. To enable it,
2484  * define ALLOW_ALWAYS_SSL_SESSION_DETAIL=1.
2485  * Because there are two possible usable cast, if you get an error here, try the other
2486  * commented line. */
2487 
2488  PEM_ASN1_write((int(*)())i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2489  debug_log,
2490  reinterpret_cast<char *>(SSL_get_session(session.get())),
2491  nullptr, nullptr, 0, nullptr, nullptr);
2492  /* PEM_ASN1_write((int(*)(...))i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2493  debug_log,
2494  reinterpret_cast<char *>(SSL_get_session(session.get())),
2495  nullptr, nullptr, 0, nullptr, nullptr);
2496  */
2497 #else
2498  debugs(83, 4, "With " OPENSSL_VERSION_TEXT ", session details are available only defining ALLOW_ALWAYS_SSL_SESSION_DETAIL=1 in the source.");
2499 
2500 #endif
2501  /* Note: This does not automatically fflush the log file.. */
2502  }
2503 
2504  debugs(83, 2, "New session " << SSL_get_session(session.get()) <<
2505  " on FD " << fd << " (" << fd_table[fd].ipaddr << ":" <<
2506  fd_table[fd].remote_port << ")");
2507  }
2508 #else
2509  debugs(83, 2, "TLS session reuse not yet implemented.");
2510 #endif
2511 
2512  // Connection established. Retrieve TLS connection parameters for logging.
2513  conn->clientConnection->tlsNegotiations()->retrieveNegotiatedInfo(session);
2514 
2515 #if USE_OPENSSL
2516  X509 *client_cert = SSL_get_peer_certificate(session.get());
2517 
2518  if (client_cert) {
2519  debugs(83, 3, "FD " << fd << " client certificate: subject: " <<
2520  X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0));
2521 
2522  debugs(83, 3, "FD " << fd << " client certificate: issuer: " <<
2523  X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0));
2524 
2525  X509_free(client_cert);
2526  } else {
2527  debugs(83, 5, "FD " << fd << " has no client certificate.");
2528  }
2529 #else
2530  debugs(83, 2, "Client certificate requesting not yet implemented.");
2531 #endif
2532 
2533  conn->readSomeData();
2534 }
2535 
2540 static void
2542 {
2543  assert(connState);
2544  const Comm::ConnectionPointer &details = connState->clientConnection;
2545 
2546  if (!ctx || !httpsCreate(connState, ctx))
2547  return;
2548 
2550  AsyncCall::Pointer timeoutCall = JobCallback(33, 5, TimeoutDialer,
2551  connState, ConnStateData::requestTimeout);
2552  commSetConnTimeout(details, Config.Timeout.request, timeoutCall);
2553 
2554  Comm::SetSelect(details->fd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
2555 }
2556 
2557 #if USE_OPENSSL
2558 
2561 static void
2563 {
2564  ConnStateData *connState = (ConnStateData *) data;
2565 
2566  // if the connection is closed or closing, just return.
2567  if (!connState->isOpen())
2568  return;
2569 
2570  if (answer.allowed()) {
2571  debugs(33, 2, "sslBump action " << Ssl::bumpMode(answer.kind) << "needed for " << connState->clientConnection);
2572  connState->sslBumpMode = static_cast<Ssl::BumpMode>(answer.kind);
2573  } else {
2574  debugs(33, 3, "sslBump not needed for " << connState->clientConnection);
2575  connState->sslBumpMode = Ssl::bumpSplice;
2576  }
2577 
2578  if (connState->sslBumpMode == Ssl::bumpTerminate) {
2579  connState->clientConnection->close();
2580  return;
2581  }
2582 
2583  if (!connState->fakeAConnectRequest("ssl-bump", connState->inBuf))
2584  connState->clientConnection->close();
2585 }
2586 #endif
2587 
2589 static void
2591 {
2592  MasterXaction::Pointer xact = params.xaction;
2593  const AnyP::PortCfgPointer s = xact->squidPort;
2594 
2595  // NP: it is possible the port was reconfigured when the call or accept() was queued.
2596 
2597  if (params.flag != Comm::OK) {
2598  // Its possible the call was still queued when the client disconnected
2599  debugs(33, 2, "httpsAccept: " << s->listenConn << ": accept failure: " << xstrerr(params.xerrno));
2600  return;
2601  }
2602 
2603  debugs(33, 4, HERE << params.conn << " accepted, starting SSL negotiation.");
2604  fd_note(params.conn->fd, "client https connect");
2605 
2606  if (s->tcp_keepalive.enabled) {
2607  commSetTcpKeepalive(params.conn->fd, s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
2608  }
2610 
2611  // Socket is ready, setup the connection manager to start using it
2612  auto *srv = Https::NewServer(xact);
2613  AsyncJob::Start(srv); // usually async-calls postHttpsAccept()
2614 }
2615 
2616 void
2618 {
2619  if (port->flags.tunnelSslBumping) {
2620 #if USE_OPENSSL
2621  debugs(33, 5, "accept transparent connection: " << clientConnection);
2622 
2623  if (!Config.accessList.ssl_bump) {
2625  return;
2626  }
2627 
2630  // Create a fake HTTP request and ALE for the ssl_bump ACL check,
2631  // using tproxy/intercept provided destination IP and port.
2632  // XXX: Merge with subsequent fakeAConnectRequest(), buildFakeRequest().
2633  // XXX: Do this earlier (e.g., in Http[s]::One::Server constructor).
2634  HttpRequest *request = new HttpRequest(mx);
2635  static char ip[MAX_IPSTRLEN];
2637  request->url.host(clientConnection->local.toStr(ip, sizeof(ip)));
2639  request->myportname = port->name;
2640  const AccessLogEntry::Pointer connectAle = new AccessLogEntry;
2641  CodeContext::Reset(connectAle);
2642  // TODO: Use these request/ALE when waiting for new bumped transactions.
2643 
2645  acl_checklist->src_addr = clientConnection->remote;
2646  acl_checklist->my_addr = port->s;
2647  // Build a local AccessLogEntry to allow requiresAle() acls work
2648  acl_checklist->al = connectAle;
2649  acl_checklist->al->cache.start_time = current_time;
2650  acl_checklist->al->tcpClient = clientConnection;
2651  acl_checklist->al->cache.port = port;
2652  acl_checklist->al->cache.caddr = log_addr;
2653  acl_checklist->al->proxyProtocolHeader = proxyProtocolHeader_;
2654  HTTPMSGUNLOCK(acl_checklist->al->request);
2655  acl_checklist->al->request = request;
2656  HTTPMSGLOCK(acl_checklist->al->request);
2657  Http::StreamPointer context = pipeline.front();
2658  ClientHttpRequest *http = context ? context->http : nullptr;
2659  const char *log_uri = http ? http->log_uri : nullptr;
2660  acl_checklist->syncAle(request, log_uri);
2661  acl_checklist->nonBlockingCheck(httpsSslBumpAccessCheckDone, this);
2662 #else
2663  fatal("FATAL: SSL-Bump requires --with-openssl");
2664 #endif
2665  return;
2666  } else {
2667  httpsEstablish(this, port->secure.staticContext);
2668  }
2669 }
2670 
2671 #if USE_OPENSSL
2672 void
2674 {
2675  ConnStateData * state_data = (ConnStateData *)(data);
2676  state_data->sslCrtdHandleReply(reply);
2677 }
2678 
2679 void
2681 {
2682  if (!isOpen()) {
2683  debugs(33, 3, "Connection gone while waiting for ssl_crtd helper reply; helper reply:" << reply);
2684  return;
2685  }
2686 
2687  if (reply.result == Helper::BrokenHelper) {
2688  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply);
2689  } else if (!reply.other().hasContent()) {
2690  debugs(1, DBG_IMPORTANT, HERE << "\"ssl_crtd\" helper returned <NULL> reply.");
2691  } else {
2693  if (reply_message.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK) {
2694  debugs(33, 5, "Reply from ssl_crtd for " << tlsConnectHostOrIp << " is incorrect");
2695  } else {
2696  if (reply.result != Helper::Okay) {
2697  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply_message.getBody());
2698  } else {
2699  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " was successfully received from ssl_crtd");
2702  auto ssl = fd_table[clientConnection->fd].ssl.get();
2703  bool ret = Ssl::configureSSLUsingPkeyAndCertFromMemory(ssl, reply_message.getBody().c_str(), *port);
2704  if (!ret)
2705  debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
2706 
2709  } else {
2711  if (ctx && !sslBumpCertKey.isEmpty())
2713  getSslContextDone(ctx);
2714  }
2715  return;
2716  }
2717  }
2718  }
2721 }
2722 
2724 {
2726 
2727  const bool connectedOk = sslServerBump && sslServerBump->connectedOk();
2728  if (connectedOk) {
2729  if (X509 *mimicCert = sslServerBump->serverCert.get())
2730  certProperties.mimicCert.resetAndLock(mimicCert);
2731 
2735 
2736  for (sslproxy_cert_adapt *ca = Config.ssl_client.cert_adapt; ca != NULL; ca = ca->next) {
2737  // If the algorithm already set, then ignore it.
2738  if ((ca->alg == Ssl::algSetCommonName && certProperties.setCommonName) ||
2739  (ca->alg == Ssl::algSetValidAfter && certProperties.setValidAfter) ||
2740  (ca->alg == Ssl::algSetValidBefore && certProperties.setValidBefore) )
2741  continue;
2742 
2743  if (ca->aclList && checklist.fastCheck(ca->aclList).allowed()) {
2744  const char *alg = Ssl::CertAdaptAlgorithmStr[ca->alg];
2745  const char *param = ca->param;
2746 
2747  // For parameterless CN adaptation, use hostname from the
2748  // CONNECT request.
2749  if (ca->alg == Ssl::algSetCommonName) {
2750  if (!param)
2751  param = tlsConnectHostOrIp.c_str();
2752  certProperties.commonName = param;
2753  certProperties.setCommonName = true;
2754  } else if (ca->alg == Ssl::algSetValidAfter)
2755  certProperties.setValidAfter = true;
2756  else if (ca->alg == Ssl::algSetValidBefore)
2757  certProperties.setValidBefore = true;
2758 
2759  debugs(33, 5, HERE << "Matches certificate adaptation aglorithm: " <<
2760  alg << " param: " << (param ? param : "-"));
2761  }
2762  }
2763 
2764  certProperties.signAlgorithm = Ssl::algSignEnd;
2765  for (sslproxy_cert_sign *sg = Config.ssl_client.cert_sign; sg != NULL; sg = sg->next) {
2766  if (sg->aclList && checklist.fastCheck(sg->aclList).allowed()) {
2767  certProperties.signAlgorithm = (Ssl::CertSignAlgorithm)sg->alg;
2768  break;
2769  }
2770  }
2771  } else {// did not try to connect (e.g. client-first) or failed to connect
2772  // In case of an error while connecting to the secure server, use a
2773  // trusted certificate, with no mimicked fields and no adaptation
2774  // algorithms. There is nothing we can mimic, so we want to minimize the
2775  // number of warnings the user will have to see to get to the error page.
2776  // We will close the connection, so that the trust is not extended to
2777  // non-Squid content.
2778  certProperties.signAlgorithm = Ssl::algSignTrusted;
2779  }
2780 
2781  assert(certProperties.signAlgorithm != Ssl::algSignEnd);
2782 
2783  if (certProperties.signAlgorithm == Ssl::algSignUntrusted) {
2784  assert(port->secure.untrustedSigningCa.cert);
2785  certProperties.signWithX509.resetAndLock(port->secure.untrustedSigningCa.cert.get());
2786  certProperties.signWithPkey.resetAndLock(port->secure.untrustedSigningCa.pkey.get());
2787  } else {
2788  assert(port->secure.signingCa.cert.get());
2789  certProperties.signWithX509.resetAndLock(port->secure.signingCa.cert.get());
2790 
2791  if (port->secure.signingCa.pkey)
2792  certProperties.signWithPkey.resetAndLock(port->secure.signingCa.pkey.get());
2793  }
2794  signAlgorithm = certProperties.signAlgorithm;
2795 
2796  certProperties.signHash = Ssl::DefaultSignHash;
2797 }
2798 
2801 {
2802  debugs(33, 5, "Finding SSL certificate for " << cacheKey << " in cache");
2804  if (Security::ContextPointer *ctx = ssl_ctx_cache ? ssl_ctx_cache->get(cacheKey) : nullptr) {
2805  if (Ssl::verifySslCertificate(*ctx, certProperties)) {
2806  debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is valid");
2807  return *ctx;
2808  } else {
2809  debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is out of date. Delete this certificate from cache");
2810  if (ssl_ctx_cache)
2811  ssl_ctx_cache->del(cacheKey);
2812  }
2813  }
2814  return Security::ContextPointer(nullptr);
2815 }
2816 
2817 void
2819 {
2821  if (!ssl_ctx_cache || !ssl_ctx_cache->add(cacheKey, new Security::ContextPointer(ctx))) {
2822  // If it is not in storage delete after using. Else storage deleted it.
2823  fd_table[clientConnection->fd].html?amicTlsContext = ctx;
2824  }
2825 }
2826 
2827 void
2829 {
2830  // If we are called, then CONNECT has succeeded. Finalize it.
2831  if (auto xact = pipeline.front()) {
2832  if (xact->http && xact->http->request && xact->http->request->method == Http::METHOD_CONNECT)
2833  xact->finished();
2834  // cannot proceed with encryption if requests wait for plain responses
2835  Must(pipeline.empty());
2836  }
2837  /* careful: finished() above frees request, host, etc. */
2838 
2839  if (port->secure.generateHostCertificates) {
2840  Ssl::CertificateProperties certProperties;
2841  buildSslCertGenerationParams(certProperties);
2842 
2843  // Disable caching for bumpPeekAndSplice mode
2846  Ssl::InRamCertificateDbKey(certProperties, sslBumpCertKey);
2848 
2850  if (ctx) {
2851  getSslContextDone(ctx);
2852  return;
2853  }
2854  }
2855 
2856 #if USE_SSL_CRTD
2857  try {
2858  debugs(33, 5, HERE << "Generating SSL certificate for " << certProperties.commonName << " using ssl_crtd.");
2861  request_message.composeRequest(certProperties);
2862  debugs(33, 5, HERE << "SSL crtd request: " << request_message.compose().c_str());
2863  Ssl::Helper::Submit(request_message, sslCrtdHandleReplyWrapper, this);
2864  return;
2865  } catch (const std::exception &e) {
2866  debugs(33, DBG_IMPORTANT, "ERROR: Failed to compose ssl_crtd " <<
2867  "request for " << certProperties.commonName <<
2868  " certificate: " << e.what() << "; will now block to " <<
2869  "generate that certificate.");
2870  // fall through to do blocking in-process generation.
2871  }
2872 #endif // USE_SSL_CRTD
2873 
2874  debugs(33, 5, HERE << "Generating SSL certificate for " << certProperties.commonName);
2877  auto ssl = fd_table[clientConnection->fd].ssl.get();
2878  if (!Ssl::configureSSL(ssl, certProperties, *port))
2879  debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
2880 
2883  } else {
2885  if (dynCtx && !sslBumpCertKey.isEmpty())
2887  getSslContextDone(dynCtx);
2888  }
2889  return;
2890  }
2891 
2894 }
2895 
2896 void
2898 {
2899  if (port->secure.generateHostCertificates && !ctx) {
2900  debugs(33, 2, "Failed to generate TLS context for " << tlsConnectHostOrIp);
2901  }
2902 
2903  // If generated ssl context = NULL, try to use static ssl context.
2904  if (!ctx) {
2905  if (!port->secure.staticContext) {
2906  debugs(83, DBG_IMPORTANT, "Closing " << clientConnection->remote << " as lacking TLS context");
2908  return;
2909  } else {
2910  debugs(33, 5, "Using static TLS context.");
2911  ctx = port->secure.staticContext;
2912  }
2913  }
2914 
2915  if (!httpsCreate(this, ctx))
2916  return;
2917 
2918  // bumped intercepted conns should already have Config.Timeout.request set
2919  // but forwarded connections may only have Config.Timeout.lifetime. [Re]set
2920  // to make sure the connection does not get stuck on non-SSL clients.
2922  AsyncCall::Pointer timeoutCall = JobCallback(33, 5, TimeoutDialer,
2925 
2926  switchedToHttps_ = true;
2927 
2928  auto ssl = fd_table[clientConnection->fd].ssl.get();
2929  BIO *b = SSL_get_rbio(ssl);
2930  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
2931  bio->setReadBufData(inBuf);
2932  inBuf.clear();
2934 }
2935 
2936 void
2938 {
2940  Must(http->request);
2941  auto &request = http->request;
2942 
2943  // Depending on receivedFirstByte_, we are at the start of either an
2944  // established CONNECT tunnel with the client or an intercepted TCP (and
2945  // presumably TLS) connection from the client. Expect TLS Client Hello.
2946  const auto insideConnectTunnel = receivedFirstByte_;
2947  debugs(33, 5, (insideConnectTunnel ? "post-CONNECT " : "raw TLS ") << clientConnection);
2948 
2949  tlsConnectHostOrIp = request->url.hostOrIp();
2950  tlsConnectPort = request->url.port();
2951  resetSslCommonName(request->url.host());
2952 
2953  // We are going to read new request
2954  flags.readMore = true;
2955 
2956  // keep version major.minor details the same.
2957  // but we are now performing the HTTPS handshake traffic
2959 
2960  // If sslServerBump is set, then we have decided to deny CONNECT
2961  // and now want to switch to SSL to send the error to the client
2962  // without even peeking at the origin server certificate.
2963  if (bumpServerMode == Ssl::bumpServerFirst && !sslServerBump) {
2964  request->flags.sslPeek = true;
2965  sslServerBump = new Ssl::ServerBump(http);
2966  } else if (bumpServerMode == Ssl::bumpPeek || bumpServerMode == Ssl::bumpStare) {
2967  request->flags.sslPeek = true;
2968  sslServerBump = new Ssl::ServerBump(http, nullptr, bumpServerMode);
2969  }
2970 
2971  // commSetConnTimeout() was called for this request before we switched.
2972  // Fix timeout to request_start_timeout
2974  AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
2975  TimeoutDialer, this, ConnStateData::requestTimeout);
2977  // Also reset receivedFirstByte_ flag to allow this timeout work in the case we have
2978  // a bumbed "connect" request on non transparent port.
2979  receivedFirstByte_ = false;
2980  // Get more data to peek at Tls
2981  parsingTlsHandshake = true;
2982 
2983  // If the protocol has changed, then reset preservingClientData_.
2984  // Otherwise, its value initially set in start() is still valid/fresh.
2985  // shouldPreserveClientData() uses parsingTlsHandshake which is reset above.
2986  if (insideConnectTunnel)
2988 
2989  readSomeData();
2990 }
2991 
2992 void
2994 {
2996 
2997  assert(!inBuf.isEmpty());
2999  fd_note(clientConnection->fd, "Parsing TLS handshake");
3000 
3001  bool unsupportedProtocol = false;
3002  try {
3003  if (!tlsParser.parseHello(inBuf)) {
3004  // need more data to finish parsing
3005  readSomeData();
3006  return;
3007  }
3008  }
3009  catch (const std::exception &ex) {
3010  debugs(83, 2, "error on FD " << clientConnection->fd << ": " << ex.what());
3011  unsupportedProtocol = true;
3012  }
3013 
3014  parsingTlsHandshake = false;
3015 
3016  // client data may be needed for splicing and for
3017  // tunneling unsupportedProtocol after an error
3019 
3020  // Even if the parser failed, each TLS detail should either be set
3021  // correctly or still be "unknown"; copying unknown detail is a no-op.
3024  if (details && !details->serverName.isEmpty()) {
3025  resetSslCommonName(details->serverName.c_str());
3026  tlsClientSni_ = details->serverName;
3027  }
3028 
3029  // We should disable read/write handlers
3031 
3032  if (unsupportedProtocol) {
3033  Http::StreamPointer context = pipeline.front();
3034  Must(context && context->http);
3035  HttpRequest::Pointer request = context->http->request;
3036  debugs(83, 5, "Got something other than TLS Client Hello. Cannot SslBump.");
3038  context->http->al->ssl.bumpMode = Ssl::bumpSplice;
3041  return;
3042  }
3043 
3044  if (!sslServerBump || sslServerBump->act.step1 == Ssl::bumpClientFirst) { // Either means client-first.
3046  return;
3047  } else if (sslServerBump->act.step1 == Ssl::bumpServerFirst) {
3048  Http::StreamPointer context = pipeline.front();
3049  ClientHttpRequest *http = context ? context->http : nullptr;
3050  // will call httpsPeeked() with certificate and connection, eventually
3052  } else {
3055  }
3056 }
3057 
3059 {
3060  ConnStateData *connState = (ConnStateData *) data;
3061 
3062  // if the connection is closed or closing, just return.
3063  if (!connState->isOpen())
3064  return;
3065 
3066  debugs(33, 5, "Answer: " << answer << " kind:" << answer.kind);
3067  assert(connState->serverBump());
3068  Ssl::BumpMode bumpAction;
3069  if (answer.allowed()) {
3070  bumpAction = (Ssl::BumpMode)answer.kind;
3071  } else
3072  bumpAction = Ssl::bumpSplice;
3073 
3074  connState->serverBump()->act.step2 = bumpAction;
3075  connState->sslBumpMode = bumpAction;
3076  Http::StreamPointer context = connState->pipeline.front();
3077  if (ClientHttpRequest *http = (context ? context->http : nullptr))
3078  http->al->ssl.bumpMode = bumpAction;
3079 
3080  if (bumpAction == Ssl::bumpTerminate) {
3081  connState->clientConnection->close();
3082  } else if (bumpAction != Ssl::bumpSplice) {
3083  connState->startPeekAndSplice();
3084  } else if (!connState->splice())
3085  connState->clientConnection->close();
3086 }
3087 
3088 bool
3090 {
3091  // normally we can splice here, because we just got client hello message
3092 
3093  // fde::ssl/tls_read_method() probably reads from our own inBuf. If so, then
3094  // we should not lose any raw bytes when switching to raw I/O here.
3095  if (fd_table[clientConnection->fd].ssl.get())
3096  fd_table[clientConnection->fd].useDefaultIo();
3097 
3098  // XXX: assuming that there was an HTTP/1.1 CONNECT to begin with...
3099  // reset the current protocol to HTTP/1.1 (was "HTTPS" for the bumping process)
3101  assert(!pipeline.empty());
3102  Http::StreamPointer context = pipeline.front();
3103  Must(context);
3104  Must(context->http);
3105  ClientHttpRequest *http = context->http;
3107  context->finished();
3108  if (transparent()) {
3109  // For transparent connections, make a new fake CONNECT request, now
3110  // with SNI as target. doCallout() checks, adaptations may need that.
3111  return fakeAConnectRequest("splice", preservedClientData);
3112  } else {
3113  // For non transparent connections make a new tunneled CONNECT, which
3114  // also sets the HttpRequest::flags::forceTunnel flag to avoid
3115  // respond with "Connection Established" to the client.
3116  // This fake CONNECT request required to allow use of SNI in
3117  // doCallout() checks and adaptations.
3119  }
3120 }
3121 
3122 void
3124 {
3125  // This is the Step2 of the SSL bumping
3127  Http::StreamPointer context = pipeline.front();
3128  ClientHttpRequest *http = context ? context->http : nullptr;
3129 
3132  // Run a accessList check to check if want to splice or continue bumping
3133 
3135  acl_checklist->al = http ? http->al : nullptr;
3136  //acl_checklist->src_addr = params.conn->remote;
3137  //acl_checklist->my_addr = s->s;
3141  const char *log_uri = http ? http->log_uri : nullptr;
3142  acl_checklist->syncAle(sslServerBump->request.getRaw(), log_uri);
3143  acl_checklist->nonBlockingCheck(httpsSslBumpStep2AccessCheckDone, this);
3144  return;
3145  }
3146 
3147  // will call httpsPeeked() with certificate and connection, eventually
3148  Security::ContextPointer unConfiguredCTX(Ssl::createSSLContext(port->secure.signingCa.cert, port->secure.signingCa.pkey, port->secure));
3149  fd_table[clientConnection->fd].html?amicTlsContext = unConfiguredCTX;
3150 
3151  if (!httpsCreate(this, unConfiguredCTX))
3152  return;
3153 
3154  switchedToHttps_ = true;
3155 
3156  auto ssl = fd_table[clientConnection->fd].ssl.get();
3157  BIO *b = SSL_get_rbio(ssl);
3158  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
3159  bio->setReadBufData(inBuf);
3160  bio->hold(true);
3161 
3162  // Here squid should have all of the client hello message so the
3163  // tlsAttemptHandshake() should return 0.
3164  // This block exist only to force openSSL parse client hello and detect
3165  // ERR_SECURE_ACCEPT_FAIL error, which should be checked and splice if required.
3166  if (tlsAttemptHandshake(this, nullptr) < 0) {
3167  debugs(83, 2, "TLS handshake failed.");
3168  HttpRequest::Pointer request(http ? http->request : nullptr);
3171  return;
3172  }
3173 
3174  // We need to reset inBuf here, to be used by incoming requests in the case
3175  // of SSL bump
3176  inBuf.clear();
3177 
3178  debugs(83, 5, "Peek and splice at step2 done. Start forwarding the request!!! ");
3180 }
3181 
3182 void
3184 {
3185  auto ssl = fd_table[clientConnection->fd].ssl.get();
3186  BIO *b = SSL_get_rbio(ssl);
3187  assert(b);
3188  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
3189 
3190  debugs(33, 5, "PeekAndSplice mode, proceed with client negotiation. Current state:" << SSL_state_string_long(ssl));
3191  bio->hold(false);
3192 
3194  switchedToHttps_ = true;
3195 }
3196 
3197 void
3199 {
3200  Must(sslServerBump != NULL);
3201  Must(sslServerBump->request == pic.request);
3202  Must(pipeline.empty() || pipeline.front()->http == nullptr || pipeline.front()->http->request == pic.request.getRaw());
3203 
3204  if (Comm::IsConnOpen(pic.connection)) {
3206  debugs(33, 5, "bumped HTTPS server: " << tlsConnectHostOrIp);
3207  } else
3208  debugs(33, 5, "Error while bumping: " << tlsConnectHostOrIp);
3209 
3211 }
3212 
3213 #endif /* USE_OPENSSL */
3214 
3215 bool
3216 ConnStateData::initiateTunneledRequest(HttpRequest::Pointer const &cause, Http::MethodType const method, const char *reason, const SBuf &payload)
3217 {
3218  // fake a CONNECT request to force connState to tunnel
3219  SBuf connectHost;
3220  unsigned short connectPort = 0;
3221 
3222  if (pinning.serverConnection != nullptr) {
3223  static char ip[MAX_IPSTRLEN];
3224  connectHost = pinning.serverConnection->remote.toStr(ip, sizeof(ip));
3225  connectPort = pinning.serverConnection->remote.port();
3226  } else if (cause) {
3227  connectHost = cause->url.hostOrIp();
3228  connectPort = cause->url.port();
3229 #if USE_OPENSSL
3230  } else if (!tlsConnectHostOrIp.isEmpty()) {
3231  connectHost = tlsConnectHostOrIp;
3232  connectPort = tlsConnectPort;
3233 #endif
3234  } else if (transparent()) {
3235  static char ip[MAX_IPSTRLEN];
3236  connectHost = clientConnection->local.toStr(ip, sizeof(ip));
3237  connectPort = clientConnection->local.port();
3238  } else {
3239  debugs(33, 2, "Not able to compute URL, abort request tunneling for " << reason);
3240  return false;
3241  }
3242 
3243  debugs(33, 2, "Request tunneling for " << reason);
3244  ClientHttpRequest *http = buildFakeRequest(method, connectHost, connectPort, payload);
3246  request->flags.forceTunnel = true;
3247  http->calloutContext = new ClientRequestContext(http);
3248  http->doCallouts();
3250  return true;
3251 }
3252 
3253 bool
3254 ConnStateData::fakeAConnectRequest(const char *reason, const SBuf &payload)
3255 {
3256  debugs(33, 2, "fake a CONNECT request to force connState to tunnel for " << reason);
3257 
3258  SBuf connectHost;
3259  assert(transparent());
3260  const unsigned short connectPort = clientConnection->local.port();
3261 
3262 #if USE_OPENSSL
3263  if (!tlsClientSni_.isEmpty())
3264  connectHost.assign(tlsClientSni_);
3265  else
3266 #endif
3267  {
3268  static char ip[MAX_IPSTRLEN];
3269  clientConnection->local.toHostStr(ip, sizeof(ip));
3270  connectHost.assign(ip);
3271  }
3272 
3273  ClientHttpRequest *http = buildFakeRequest(Http::METHOD_CONNECT, connectHost, connectPort, payload);
3274 
3275  http->calloutContext = new ClientRequestContext(http);
3277  http->doCallouts();
3279  return true;
3280 }
3281 
3283 ConnStateData::buildFakeRequest(Http::MethodType const method, SBuf &useHost, unsigned short usePort, const SBuf &payload)
3284 {
3285  ClientHttpRequest *http = new ClientHttpRequest(this);
3286  Http::Stream *stream = new Http::Stream(clientConnection, http);
3287 
3288  StoreIOBuffer tempBuffer;
3289  tempBuffer.data = stream->reqbuf;
3290  tempBuffer.length = HTTP_REQBUF_SZ;
3291 
3292  ClientStreamData newServer = new clientReplyContext(http);
3293  ClientStreamData newClient = stream;
3296  clientSocketDetach, newClient, tempBuffer);
3297 
3298  stream->flags.parsed_ok = 1; // Do we need it?
3299  stream->mayUseConnection(true);
3300 
3301  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "clientLifetimeTimeout",
3304 
3305  stream->registerWithConn();
3306 
3309  // Setup Http::Request object. Maybe should be replaced by a call to (modified)
3310  // clientProcessRequest
3313  request->url.setScheme(proto, nullptr);
3314  request->method = method;
3315  request->url.host(useHost.c_str());
3316  request->url.port(usePort);
3317 
3318  http->uri = SBufToCstring(request->effectiveRequestUri());
3319  http->initRequest(request.getRaw());
3320 
3321  request->manager(this, http->al);
3322 
3323  if (proto == AnyP::PROTO_HTTP)
3324  request->header.putStr(Http::HOST, useHost.c_str());
3325 
3326  request->sources |= ((switchedToHttps() || port->transport.protocol == AnyP::PROTO_HTTPS) ? Http::Message::srcHttps : Http::Message::srcHttp);
3327 #if USE_AUTH
3328  if (getAuth())
3329  request->auth_user_request = getAuth();
3330 #endif
3331 
3332  inBuf = payload;
3333  flags.readMore = false;
3334 
3335  return http;
3336 }
3337 
3339 static bool
3341 {
3342  if (!Comm::IsConnOpen(c)) {
3343  Must(NHttpSockets > 0); // we tried to open some
3344  --NHttpSockets; // there will be fewer sockets than planned
3345  Must(HttpSockets[NHttpSockets] < 0); // no extra fds received
3346 
3347  if (!NHttpSockets) // we could not open any listen sockets at all
3348  fatalf("Unable to open %s",FdNote(portType));
3349 
3350  return false;
3351  }
3352  return true;
3353 }
3354 
3356 static bool
3358 {
3359  bool found = false;
3360  for (int i = 0; i < NHttpSockets && !found; ++i) {
3361  if ((found = HttpSockets[i] < 0))
3362  HttpSockets[i] = conn->fd;
3363  }
3364  return found;
3365 }
3366 
3367 static void
3369 {
3370  for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) {
3371  const SBuf &scheme = AnyP::UriScheme(s->transport.protocol).image();
3372 
3374  debugs(1, DBG_IMPORTANT, "WARNING: You have too many '" << scheme << "_port' lines." <<
3375  Debug::Extra << "The limit is " << MAXTCPLISTENPORTS << " HTTP ports.");
3376  continue;
3377  }
3378 
3379 #if USE_OPENSSL
3380  if (s->flags.tunnelSslBumping) {
3381  if (!Config.accessList.ssl_bump) {
3382  debugs(33, DBG_IMPORTANT, "WARNING: No ssl_bump configured. Disabling ssl-bump on " << scheme << "_port " << s->s);
3383  s->flags.tunnelSslBumping = false;
3384  }
3385  if (!s->secure.staticContext && !s->secure.generateHostCertificates) {
3386  debugs(1, DBG_IMPORTANT, "Will not bump SSL at " << scheme << "_port " << s->s << " due to TLS initialization failure.");
3387  s->flags.tunnelSslBumping = false;
3388  if (s->transport.protocol == AnyP::PROTO_HTTP)
3389  s->secure.encryptTransport = false;
3390  }
3391  if (s->flags.tunnelSslBumping) {
3392  // Create ssl_ctx cache for this port.
3393  Ssl::TheGlobalContextStorage.addLocalStorage(s->s, s->secure.html?amicCertMemCacheSize);
3394  }
3395  }
3396 #endif
3397 
3398  if (s->secure.encryptTransport && !s->secure.staticContext) {
3399  debugs(1, DBG_CRITICAL, "ERROR: Ignoring " << scheme << "_port " << s->s << " due to TLS context initialization failure.");
3400  continue;
3401  }
3402 
3403  // Fill out a Comm::Connection which IPC will open as a listener for us
3404  // then pass back when active so we can start a TcpAcceptor subscription.
3405  s->listenConn = new Comm::Connection;
3406  s->listenConn->local = s->s;
3407 
3408  s->listenConn->flags = COMM_NONBLOCKING | (s->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) |
3409  (s->flags.natIntercept ? COMM_INTERCEPTION : 0) |
3410  (s->workerQueues ? COMM_REUSEPORT : 0);
3411 
3412  typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
3413  if (s->transport.protocol == AnyP::PROTO_HTTP) {
3414  // setup the subscriptions such that new connections accepted by listenConn are handled by HTTP
3417 
3418  AsyncCall::Pointer listenCall = asyncCall(33,2, "clientListenerConnectionOpened",
3420  Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpSocket, listenCall);
3421 
3422  } else if (s->transport.protocol == AnyP::PROTO_HTTPS) {
3423  // setup the subscriptions such that new connections accepted by listenConn are handled by HTTPS
3426 
3427  AsyncCall::Pointer listenCall = asyncCall(33, 2, "clientListenerConnectionOpened",
3429  s, Ipc::fdnHttpsSocket, sub));
3430  Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpsSocket, listenCall);
3431  }
3432 
3433  HttpSockets[NHttpSockets] = -1; // set in clientListenerConnectionOpened
3434  ++NHttpSockets;
3435  }
3436 }
3437 
3438 void
3440 {
3441  // Fill out a Comm::Connection which IPC will open as a listener for us
3442  port->listenConn = new Comm::Connection;
3443  port->listenConn->local = port->s;
3444  port->listenConn->flags =
3446  (port->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) |
3447  (port->flags.natIntercept ? COMM_INTERCEPTION : 0);
3448 
3449  // route new connections to subCall
3450  typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
3452  AsyncCall::Pointer listenCall =
3453  asyncCall(33, 2, "clientListenerConnectionOpened",
3455  port, fdNote, sub));
3456  Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, port->listenConn, fdNote, listenCall);
3457 
3459  HttpSockets[NHttpSockets] = -1;
3460  ++NHttpSockets;
3461 }
3462 
3464 static void
3466 {
3467  Must(s != NULL);
3468 
3469  if (!OpenedHttpSocket(s->listenConn, portTypeNote))
3470  return;
3471 
3472  Must(Comm::IsConnOpen(s->listenConn));
3473 
3474  // TCP: setup a job to handle accept() with subscribed handler
3475  AsyncJob::Start(new Comm::TcpAcceptor(s, FdNote(portTypeNote), sub));
3476 
3477  debugs(1, DBG_IMPORTANT, "Accepting " <<
3478  (s->flags.natIntercept ? "NAT intercepted " : "") <<
3479  (s->flags.tproxyIntercept ? "TPROXY intercepted " : "") <<
3480  (s->flags.tunnelSslBumping ? "SSL bumped " : "") <<
3481  (s->flags.accelSurrogate ? "reverse-proxy " : "")
3482  << FdNote(portTypeNote) << " connections at "
3483  << s->listenConn);
3484 
3485  Must(AddOpenedHttpSocket(s->listenConn)); // otherwise, we have received a fd we did not ask for
3486 
3487 #if USE_SYSTEMD
3488  // When the very first port opens, tell systemd we are able to serve connections.
3489  // Subsequent sd_notify() calls, including calls during reconfiguration,
3490  // do nothing because the first call parameter is 1.
3491  // XXX: Send the notification only after opening all configured ports.
3492  if (opt_foreground || opt_no_daemon) {
3493  const auto result = sd_notify(1, "READY=1");
3494  if (result < 0) {
3495  debugs(1, DBG_IMPORTANT, "WARNING: failed to send start-up notification to systemd" <<
3496  Debug::Extra << "sd_notify() error: " << xstrerr(-result));
3497  }
3498  }
3499 #endif
3500 }
3501 
3502 void
3504 {
3507 
3508  if (NHttpSockets < 1)
3509  fatal("No HTTP, HTTPS, or FTP ports configured");
3510 }
3511 
3512 void
3514 {
3515  for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) {
3516  if (s->listenConn != NULL) {
3517  debugs(1, DBG_IMPORTANT, "Closing HTTP(S) port " << s->listenConn->local);
3518  s->listenConn->close();
3519  s->listenConn = NULL;
3520  }
3521  }
3522 
3524 
3525  // TODO see if we can drop HttpSockets array entirely */
3526  for (int i = 0; i < NHttpSockets; ++i) {
3527  HttpSockets[i] = -1;
3528  }
3529 
3530  NHttpSockets = 0;
3531 }
3532 
3533 int
3535 {
3536  SBuf vary(request->vary_headers);
3537  const auto &reply = entry->mem().freshestReply();
3538  auto has_vary = reply.header.has(Http::HdrType::VARY);
3539 #if X_ACCELERATOR_VARY
3540 
3541  has_vary |=
3542  reply.header.has(Http::HdrType::HDR_X_ACCELERATOR_VARY);
3543 #endif
3544 
3545  if (!has_vary || entry->mem_obj->vary_headers.isEmpty()) {
3546  if (!vary.isEmpty()) {
3547  /* Oops... something odd is going on here.. */
3548  debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary object on second attempt, '" <<
3549  entry->mem_obj->urlXXX() << "' '" << vary << "'");
3550  request->vary_headers.clear();
3551  return VARY_CANCEL;
3552  }
3553 
3554  if (!has_vary) {
3555  /* This is not a varying object */
3556  return VARY_NONE;
3557  }
3558 
3559  /* virtual "vary" object found. Calculate the vary key and
3560  * continue the search
3561  */
3562  vary = httpMakeVaryMark(request, &reply);
3563 
3564  if (!vary.isEmpty()) {
3565  request->vary_headers = vary;
3566  return VARY_OTHER;
3567  } else {
3568  /* Ouch.. we cannot handle this kind of variance */
3569  /* XXX This cannot really happen, but just to be complete */
3570  return VARY_CANCEL;
3571  }
3572  } else {
3573  if (vary.isEmpty()) {
3574  vary = httpMakeVaryMark(request, &reply);
3575 
3576  if (!vary.isEmpty())
3577  request->vary_headers = vary;
3578  }
3579 
3580  if (vary.isEmpty()) {
3581  /* Ouch.. we cannot handle this kind of variance */
3582  /* XXX This cannot really happen, but just to be complete */
3583  return VARY_CANCEL;
3584  } else if (vary.cmp(entry->mem_obj->vary_headers) == 0) {
3585  return VARY_MATCH;
3586  } else {
3587  /* Oops.. we have already been here and still haven't
3588  * found the requested variant. Bail out
3589  */
3590  debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary match on second attempt, '" <<
3591  entry->mem_obj->urlXXX() << "' '" << vary << "'");
3592  return VARY_CANCEL;
3593  }
3594  }
3595 }
3596 
3599 {
3600  const auto checklist = new ACLFilledChecklist(acl, nullptr, nullptr);
3601  clientAclChecklistFill(*checklist, http);
3602  return checklist;
3603 }
3604 
3605 void
3607 {
3608  checklist.setRequest(http->request);
3609  checklist.al = http->al;
3610  checklist.syncAle(http->request, http->log_uri);
3611 
3612  // TODO: If http->getConn is always http->request->clientConnectionManager,
3613  // then call setIdent() inside checklist.setRequest(). Otherwise, restore
3614  // USE_IDENT lost in commit 94439e4.
3615  ConnStateData * conn = http->getConn();
3616  const char *ident = (cbdataReferenceValid(conn) &&
3617  conn && conn->clientConnection) ?
3618  conn->clientConnection->rfc931 : dash_str;
3619  checklist.setIdent(ident);
3620 }
3621 
3622 bool
3624 {
3626 }
3627 
3630 {
3631  bodyPipe = new BodyPipe(this);
3632  if (size >= 0)
3634  else
3636  return bodyPipe;
3637 }
3638 
3639 int64_t
3641 {
3642  if (!bodyPipe)
3643  return 0; // request without a body or read/produced all body bytes
3644 
3645  if (!bodyPipe->bodySizeKnown())
3646  return -1; // probably need to read more, but we cannot be sure
3647 
3648  const int64_t needToProduce = bodyPipe->unproducedSize();
3649  const int64_t haveAvailable = static_cast<int64_t>(inBuf.length());
3650 
3651  if (needToProduce <= haveAvailable)
3652  return 0; // we have read what we need (but are waiting for pipe space)
3653 
3654  return needToProduce - haveAvailable;
3655 }
3656 
3657 void
3659 {
3660  debugs(33, 4, HERE << "receiving error (" << clientConnection << "): " << error <<
3661  "; old sending error: " <<
3662  (stoppedSending() ? stoppedSending_ : "none"));
3663 
3664  if (const char *oldError = stoppedReceiving()) {
3665  debugs(33, 3, HERE << "already stopped receiving: " << oldError);
3666  return; // nothing has changed as far as this connection is concerned
3667  }
3668 
3670 
3671  if (const char *sendError = stoppedSending()) {
3672  debugs(33, 3, HERE << "closing because also stopped sending: " << sendError);
3674  }
3675 }
3676 
3677 void
3679 {
3680  if (bodyPipe != NULL) {
3681  debugs(33, 4, HERE << "no consumer for virgin body " << bodyPipe->status());
3683  }
3684 }
3685 
3687 void
3689 {
3690  Must(bodyPipe != NULL);
3691  debugs(33, 5, HERE << "start dechunking" << bodyPipe->status());
3692  assert(!bodyParser);
3694 }
3695 
3697 void
3699 {
3700  debugs(33, 5, HERE << "finish dechunking: " << withSuccess);
3701 
3702  if (bodyPipe != NULL) {
3703  debugs(33, 7, HERE << "dechunked tail: " << bodyPipe->status());
3704  BodyPipe::Pointer myPipe = bodyPipe;
3705  stopProducingFor(bodyPipe, withSuccess); // sets bodyPipe->bodySize()
3706  Must(!bodyPipe); // we rely on it being nil after we are done with body
3707  if (withSuccess) {
3708  Must(myPipe->bodySizeKnown());
3709  Http::StreamPointer context = pipeline.front();
3710  if (context != NULL && context->http && context->http->request)
3711  context->http->request->setContentLength(myPipe->bodySize());
3712  }
3713  }
3714 
3715  delete bodyParser;
3716  bodyParser = NULL;
3717 }
3718 
3719 // XXX: this is an HTTP/1-only operation
3720 void
3722 {
3723  if (const auto context = pipeline.front()) {
3724  if (context->http)
3725  context->http->al->reply = msg.reply;
3726  }
3727 
3728  if (!isOpen()) {
3729  debugs(33, 3, HERE << "ignoring 1xx due to earlier closure");
3730  return;
3731  }
3732 
3733  // HTTP/1 1xx status messages are only valid when there is a transaction to trigger them
3734  if (!pipeline.empty()) {
3735  HttpReply::Pointer rep(msg.reply);
3736  Must(rep);
3737  // remember the callback
3739 
3742 
3743  if (!writeControlMsgAndCall(rep.getRaw(), call)) {
3744  // but still inform the caller (so it may resume its operation)
3746  }
3747  return;
3748  }
3749 
3750  debugs(33, 3, HERE << " closing due to missing context for 1xx");
3752 }
3753 
3754 void
3756 {
3758 
3759  if (Http::StreamPointer deferredRequest = pipeline.front()) {
3760  debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded after control msg wrote");
3761  ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
3762  }
3763 }
3764 
3766 void
3768 {
3769  // FwdState might repin a failed connection sooner than this close
3770  // callback is called for the failed connection.
3771  assert(pinning.serverConnection == io.conn);
3772  pinning.closeHandler = NULL; // Comm unregisters handlers before calling
3773  const bool sawZeroReply = pinning.zeroReply; // reset when unpinning
3774  pinning.serverConnection->noteClosure();
3775  unpinConnection(false);
3776 
3777  if (sawZeroReply && clientConnection != NULL) {
3778  debugs(33, 3, "Closing client connection on pinned zero reply.");
3780  }
3781 
3782 }
3783 
3784 void
3786 {
3787  pinConnection(pinServer, *request);
3788 }
3789 
3790 void
3792 {
3793  Must(pic.connection);
3794  Must(pic.request);
3795  pinConnection(pic.connection, *pic.request);
3796 
3797  // monitor pinned server connection for remote-end closures.
3799 
3800  if (pipeline.empty())
3801  kick(); // in case clientParseRequests() was blocked by a busy pic.connection
3802 }
3803 
3805 void
3807 {
3808  if (Comm::IsConnOpen(pinning.serverConnection) &&
3809  pinning.serverConnection->fd == pinServer->fd) {
3810  debugs(33, 3, "already pinned" << pinServer);
3811  return;
3812  }
3813 
3814  unpinConnection(true); // closes pinned connection, if any, and resets fields
3815 
3816  pinning.serverConnection = pinServer;
3817 
3818  debugs(33, 3, HERE << pinning.serverConnection);
3819 
3820  Must(pinning.serverConnection != NULL);
3821 
3822  const char *pinnedHost = "[unknown]";
3823  pinning.host = xstrdup(request.url.host());
3824  pinning.port = request.url.port();
3825  pinnedHost = pinning.host;
3826  pinning.pinned = true;
3827  if (CachePeer *aPeer = pinServer->getPeer())
3828  pinning.peer = cbdataReference(aPeer);
3829  pinning.auth = request.flags.connectionAuth;
3830  char stmp[MAX_IPSTRLEN];
3831  char desc[FD_DESC_SZ];
3832  snprintf(desc, FD_DESC_SZ, "%s pinned connection for %s (%d)",
3833  (pinning.auth || !pinning.peer) ? pinnedHost : pinning.peer->name,
3835  clientConnection->fd);
3836  fd_note(pinning.serverConnection->fd, desc);
3837 
3839  pinning.closeHandler = JobCallback(33, 5,
3841  // remember the pinned connection so that cb does not unpin a fresher one
3842  typedef CommCloseCbParams Params;
3843  Params &params = GetCommParams<Params>(pinning.closeHandler);
3844  params.conn = pinning.serverConnection;
3845  comm_add_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
3846 }
3847 
3850 void
3852 {
3853  if (pinning.readHandler != NULL)
3854  return; // already monitoring
3855 
3857  pinning.readHandler = JobCallback(33, 3,
3859  Comm::Read(pinning.serverConnection, pinning.readHandler);
3860 }
3861 
3862 void
3864 {
3865  if (pinning.readHandler != NULL) {
3866  Comm::ReadCancel(pinning.serverConnection->fd, pinning.readHandler);
3867  pinning.readHandler = NULL;
3868  }
3869 }
3870 
3871 #if USE_OPENSSL
3872 bool
3874 {
3875  // A ready-for-reading connection means that the TLS server either closed
3876  // the connection, sent us some unexpected HTTP data, or started TLS
3877  // renegotiations. We should close the connection except for the last case.
3878 
3879  Must(pinning.serverConnection != nullptr);
3880  auto ssl = fd_table[pinning.serverConnection->fd].ssl.get();
3881  if (!ssl)
3882  return false;
3883 
3884  char buf[1];
3885  const int readResult = SSL_read(ssl, buf, sizeof(buf));
3886 
3887  if (readResult > 0 || SSL_pending(ssl) > 0) {
3888  debugs(83, 2, pinning.serverConnection << " TLS application data read");
3889  return false;
3890  }
3891 
3892  switch(const int error = SSL_get_error(ssl, readResult)) {
3893  case SSL_ERROR_WANT_WRITE:
3894  debugs(83, DBG_IMPORTANT, pinning.serverConnection << " TLS SSL_ERROR_WANT_WRITE request for idle pinned connection");
3895  // fall through to restart monitoring, for now
3896  case SSL_ERROR_NONE:
3897  case SSL_ERROR_WANT_READ:
3899  return true;
3900 
3901  default:
3902  debugs(83, 2, pinning.serverConnection << " TLS error: " << error);
3903  return false;
3904  }
3905 
3906  // not reached
3907  return true;
3908 }
3909 #endif
3910 
3913 void
3915 {
3916  pinning.readHandler = NULL; // Comm unregisters handlers before calling
3917 
3918  if (io.flag == Comm::ERR_CLOSING)
3919  return; // close handler will clean up
3920 
3921  Must(pinning.serverConnection == io.conn);
3922 
3923 #if USE_OPENSSL
3925  return;
3926 #endif
3927 
3928  const bool clientIsIdle = pipeline.empty();
3929 
3930  debugs(33, 3, "idle pinned " << pinning.serverConnection << " read " <<
3931  io.size << (clientIsIdle ? " with idle client" : ""));
3932 
3933  pinning.serverConnection->close();
3934 
3935  // If we are still sending data to the client, do not close now. When we are done sending,
3936  // ConnStateData::kick() checks pinning.serverConnection and will close.
3937  // However, if we are idle, then we must close to inform the idle client and minimize races.
3938  if (clientIsIdle && clientConnection != NULL)
3940 }
3941 
3944 {
3945  debugs(33, 7, pinning.serverConnection);
3946  Must(request);
3947 
3948  const auto pinningError = [&](const err_type type) {
3949  unpinConnection(true);
3950  HttpRequestPointer requestPointer = request;
3951  return ErrorState::NewForwarding(type, requestPointer, ale);
3952  };
3953 
3954  if (!Comm::IsConnOpen(pinning.serverConnection))
3955  throw pinningError(ERR_ZERO_SIZE_OBJECT);
3956 
3957  if (pinning.auth && pinning.host && strcasecmp(pinning.host, request->url.host()) != 0)
3958  throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_CONFLICT_HOST
3959 
3960  if (pinning.port != request->url.port())
3961  throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_CONFLICT_HOST
3962 
3963  if (pinning.peer && !cbdataReferenceValid(pinning.peer))
3964  throw pinningError(ERR_ZERO_SIZE_OBJECT);
3965 
3966  if (pinning.peerAccessDenied)
3967  throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_FORWARDING_DENIED
3968 
3970  return pinning.serverConnection;
3971 }
3972 
3975 {
3976  if (const auto connManager = request ? request->pinnedConnection() : nullptr)
3977  return connManager->borrowPinnedConnection(request, ale);
3978 
3979  // ERR_CANNOT_FORWARD is somewhat misleading here; we can still forward, but
3980  // there is no point since the client connection is now gone
3981  HttpRequestPointer requestPointer = request;
3982  throw ErrorState::NewForwarding(ERR_CANNOT_FORWARD, requestPointer, ale);
3983 }
3984 
3985 void
3987 {
3988  debugs(33, 3, HERE << pinning.serverConnection);
3989 
3990  if (pinning.peer)
3992 
3993  if (Comm::IsConnOpen(pinning.serverConnection)) {
3994  if (pinning.closeHandler != NULL) {
3995  comm_remove_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
3996  pinning.closeHandler = NULL;
3997  }
3998 
4000 
4001  // close the server side socket if requested
4002  if (andClose)
4003  pinning.serverConnection->close();
4004  pinning.serverConnection = NULL;
4005  }
4006 
4007  safe_free(pinning.host);
4008 
4009  pinning.zeroReply = false;
4010  pinning.peerAccessDenied = false;
4011 
4012  /* NOTE: pinning.pinned should be kept. This combined with fd == -1 at the end of a request indicates that the host
4013  * connection has gone away */
4014 }
4015 
4016 void
4018 {
4019  // if we are parsing request body, its request is responsible for logging
4020  if (bodyPipe)
4021  return;
4022 
4023  // a request currently using this connection is responsible for logging
4024  if (!pipeline.empty() && pipeline.back()->mayUseConnection())
4025  return;
4026 
4027  /* Either we are waiting for the very first transaction, or
4028  * we are done with the Nth transaction and are waiting for N+1st.
4029  * XXX: We assume that if anything was added to inBuf, then it could
4030  * only be consumed by actions already covered by the above checks.
4031  */
4032 
4033  // do not log connections that closed after a transaction (it is normal)
4034  // TODO: access_log needs ACLs to match received-no-bytes connections
4035  if (pipeline.nrequests && inBuf.isEmpty())
4036  return;
4037 
4038  /* Create a temporary ClientHttpRequest object. Its destructor will log. */
4039  ClientHttpRequest http(this);
4040  http.req_sz = inBuf.length();
4041  // XXX: Or we died while waiting for the pinned connection to become idle.
4042  http.setErrorUri("error:transaction-end-before-headers");
4043 }
4044 
4045 bool
4047 {
4048  // PROXY protocol bytes are meant for us and, hence, cannot be tunneled
4050  return false;
4051 
4052  // If our decision here is negative, configuration changes are irrelevant.
4053  // Otherwise, clientTunnelOnError() rechecks configuration before tunneling.
4055  return false;
4056 
4057  // TODO: Figure out whether/how we can support FTP tunneling.
4058  if (port->transport.protocol == AnyP::PROTO_FTP)
4059  return false;
4060 
4061 #if USE_OPENSSL
4062  if (parsingTlsHandshake)
4063  return true;
4064 
4065  // the 1st HTTP request on a bumped connection
4067  return true;
4068 #endif
4069 
4070  // the 1st HTTP request on a connection to a plain intercepting port
4071  if (!pipeline.nrequests && !port->secure.encryptTransport && transparent())
4072  return true;
4073 
4074  return false;
4075 }
4076 
4079 {
4080  if (!theNotes)
4081  theNotes = new NotePairs;
4082  return theNotes;
4083 }
4084 
4085 std::ostream &
4086 operator <<(std::ostream &os, const ConnStateData::PinnedIdleContext &pic)
4087 {
4088  return os << pic.connection << ", request=" << pic.request;
4089 }
4090 
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:46
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:103
#define USER_IDENT_SZ
Definition: defines.h:60
virtual void noteBodyConsumerAborted(BodyPipe::Pointer)=0
#define FQDN_LOOKUP_IF_MISS
Definition: defines.h:48
AnyP::ProtocolVersion transferProtocol
Definition: Server.h:104
char method[16]
Definition: tcp-banger2.c:115
char * buf
Definition: MemBuf.h:134
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:983
void clientAfterReadingRequests()
SBuf tlsClientSni_
TLS client delivered SNI value. Empty string if none has been received.
Definition: client_side.h:424
#define MYNAME
Definition: Debug.h:170
int half_closed_clients
Definition: SquidConfig.h:293
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
SQUIDCEXTERN CSR clientGetMoreData
Definition: client_side.h:463
void IOACB(const CommAcceptCbParams &params)
Definition: CommCalls.h:33
void terminateAll(const int xerrno)
tell everybody about the err, and abort all waiting requests
Definition: Pipeline.cc:52
const char * findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end)
unsigned int major
major version number
int getMyPort(void)
Definition: tools.cc:1003
bool conflictingContentLength() const
Definition: HttpHeader.h:113
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:1199
int incoming_sockets_accepted
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
uint64_t payloadData
total size of payload block(s) excluding transfer encoding overheads
Definition: MessageSizes.h:24
SBuf & assign(const SBuf &S)
Definition: SBuf.cc:83
struct SquidConfig::@113 accessList
void port(unsigned short p)
Definition: Uri.h:92
AnyP::Uri url
the request URI
Definition: HttpRequest.h:115
void stopPinnedConnectionMonitoring()
The caller assumes responsibility for connection closure detection.
SQUIDCEXTERN CSS clientReplyStatus
Definition: client_side.h:464
CertSignAlgorithm
Definition: gadgets.h:150
BodyPipe::Pointer body_pipe
optional pipeline to receive message body
Definition: Message.h:98
enum Http::_method_t MethodType
struct SquidConfig::@107 Addrs
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:175
void clientConnectionsClose()
virtual bool handleReadData()
const_reverse_iterator rbegin() const
Definition: SBuf.h:580
const char * stoppedSending() const
true if we stopped sending the response
Definition: client_side.h:154
Ip::Address src_addr
ACLFilledChecklist * clientAclChecklistCreate(const acl_access *acl, ClientHttpRequest *http)
Security::CertPointer mimicCert
Certificate to mimic.
Definition: gadgets.h:216
static std::ostream & Extra(std::ostream &os)
prefixes each grouped debugs() line after the first one in the group
Definition: Debug.h:104
Security::CertPointer signWithX509
Certificate to sign the generated request.
Definition: gadgets.h:217
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:110
void setAuth(const Auth::UserRequest::Pointer &aur, const char *cause)
Definition: client_side.cc:510
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:21
void fd_note(int fd, const char *s)
Definition: fd.cc:246
HttpHeader header
Definition: Message.h:75
void resetSslCommonName(const char *name)
Definition: client_side.h:258
AsyncCall::Pointer cbControlMsgSent
Call to schedule when the control msg has been sent.
static void clientUpdateHierCounters(HierarchyLogEntry *)
Definition: client_side.cc:269
ByteCounter hit_kbytes_out
Definition: StatCounters.h:47
LogTags logType
the processing tags associated with this request transaction.
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:90
acl_access * on_unsupported_protocol
Definition: SquidConfig.h:403
bool isEmpty() const
Definition: SBuf.h:420
void initRequest(HttpRequest *)
MemObject * mem_obj
Definition: Store.h:209
StatHist nearHitSvcTime
Definition: StatCounters.h:50
void registerWithConn()
register this stream with the Server
Definition: Stream.cc:52
int64_t maxRequestBodySize
Definition: SquidConfig.h:131
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:224
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:91
NotePairs::Pointer theNotes
Definition: client_side.h:439
#define debug_log
change-avoidance macro; new code should call DebugStream() instead
Definition: Debug.h:114
struct node * next
Definition: parse.c:104
int log_mime_hdrs
Definition: SquidConfig.h:288
ConnStateData * getConn() const
int request_entities
Definition: SquidConfig.h:318
char * skipLeadingSpace(char *aString)
Callback cbSuccess
called after successfully writing the 1xx message
void setErrorUri(const char *errorUri)
void setBodySize(uint64_t aSize)
Definition: BodyPipe.cc:147
acl_access * cert_error
Definition: SquidConfig.h:520
MemObject & mem()
Definition: Store.h:52
void banAction(const Acl::Answer &action)
add action to the list of banned actions
Definition: Checklist.cc:402
struct SquidConfig::@98 Timeout
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:752
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:151
char reqbuf[HTTP_REQBUF_SZ]
Definition: Stream.h:134
void error(char *format,...)
static void Submit(CrtdMessage const &message, HLPCB *callback, void *data)
Submit crtd message to external crtd server.
Definition: helper.cc:120
unsigned int minor
minor version number
Ip::Address log_addr
Definition: client_side.h:129
SBuf hostOrIp() const
Definition: Uri.cc:64
void setWriteLimiter(const int aWriteSpeedLimit, const double anInitialBurst, const double aHighWatermark)
Definition: comm.cc:1435
void readNextRequest()
Definition: client_side.cc:859
bool hasContent() const
Definition: MemBuf.h:54
HttpReplyPointer reply
struct ClientHttpRequest::Flags flags
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
void httpRequestFree(void *data)
Definition: client_side.cc:495
bool clientParseRequests()
Traffic parsing.
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:96
Definition: SBuf.h:86
virtual void sendControlMsg(HttpControlMsg)
called to send the 1xx message and notify the Source
BumpMode
Definition: support.h:135
struct timeval stop
Definition: PingData.h:20
Ip::Address client_netmask
Definition: SquidConfig.h:244
BodyPipe::Pointer bodyPipe
set when we are reading request body
Definition: client_side.h:372
bool needsMoreData() const
Definition: Parser.h:66
bool initiateTunneledRequest(HttpRequest::Pointer const &cause, Http::MethodType const method, const char *reason, const SBuf &payload)
generates and sends to tunnel.cc a fake request with a given payload
int commSetConnTimeout(const Comm::ConnectionPointer &conn, int timeout, AsyncCall::Pointer &callback)
Definition: comm.cc:567
void SBufToCstring(char *d, const SBuf &s)
Definition: SBuf.h:741
bool splice()
Splice a bumped client connection on peek-and-splice mode.
const char * stoppedReceiving_
the reason why we no longer read the request or nil
Definition: client_side.h:435
#define xstrdup
void enableAutoConsumption()
start or continue consuming when producing without consumer
Definition: BodyPipe.cc:316
int64_t mayNeedToReadMoreBody() const
void clientdbUpdate(const Ip::Address &addr, const LogTags &ltype, AnyP::ProtocolType p, size_t size)
Definition: client_db.cc:139
Definition: Server.h:28
int clientdbEstablished(const Ip::Address &addr, int delta)
Definition: client_db.cc:183
int fd
FD which the call was about. Set by the async call creator.
Definition: CommCalls.h:90
time_t request_start_timeout
Definition: SquidConfig.h:121
int content_length
Definition: tcp-banger2.c:121
int type
Definition: errorpage.cc:152
C * getRaw() const
Definition: RefCount.h:80
virtual void append(const char *c, int sz)
Definition: MemBuf.cc:216
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37
virtual void dial(AsyncCall &)
Definition: client_side.cc:164
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:412
struct timeval start_time
The time the master transaction started.
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:26
Http1::TeChunkedParser * bodyParser
parses HTTP/1.1 chunked request body
Definition: client_side.h:101
Definition: Flag.h:16
const char * sslGetUserEmail(SSL *ssl)
Definition: support.cc:712
int global_internal_static
Definition: SquidConfig.h:327
std::vector< HttpHdrRangeSpec * >::iterator iterator
struct timeval trTime
The response time.
ClientHttpRequest * buildFakeRequest(Http::MethodType const method, SBuf &useHost, unsigned short usePort, const SBuf &payload)
build a fake http request
int urlCheckRequest(const HttpRequest *r)
Definition: Uri.cc:818
#define SQUID_X509_V_ERR_DOMAIN_MISMATCH
Definition: support.h:44
void StopListening()
reject new connections to any configured ftp_port
Definition: FtpServer.cc:285
void HTTPMSGUNLOCK(M *&a)
Definition: Message.h:149
bool commIsHalfClosed(int fd)
Definition: comm.h:101
void detailError(err_type aType, int aDetail)
sets error detail if no earlier detail was available
Definition: HttpRequest.cc:468
char * toUrl(char *buf, unsigned int len) const
Definition: Address.cc:884
#define DBG_CRITICAL
Definition: Debug.h:45
StatusCode
Definition: StatusCode.h:20
#define SQUIDSTRINGPH
Definition: SquidString.h:21
bool multipartRangeRequest() const
Definition: HttpRequest.cc:437
SBuf sslBumpCertKey
Key to use to store/retrieve generated certificate.
Definition: client_side.h:425
const char * FdNote(int fdNodeId)
converts FdNoteId into a string
Definition: FdNotes.cc:16
Notes notes
note
Definition: SquidConfig.h:482
void StartListening()
accept connections on all configured ftp_ports
Definition: FtpServer.cc:266
class AccessLogEntry::CacheDetails cache
virtual void afterClientRead()
processing to be done after a Comm::Read()
#define cbdataReference(var)
Definition: cbdata.h:341
void * BIO_get_data(BIO *table)
Definition: openssl.h:60
bool add(const Key &key, EntryValue *t)
Add an entry to the map.
Definition: LruMap.h:140
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:329
#define PROF_stop(probename)
Definition: Profiler.h:63
static void sslCrtdHandleReplyWrapper(void *data, const Helper::Reply &reply)
Callback function. It is called when squid receive message from ssl_crtd.
#define DBG_IMPORTANT
Definition: Debug.h:46
int xerrno
The last errno to occur. non-zero if flag is Comm::COMM_ERROR.
Definition: CommCalls.h:88
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
static int port
Definition: ldap_backend.cc:69
bool checkX509ServerValidity(X509 *cert, const char *server)
Definition: support.cc:251
unsigned short tlsConnectPort
The TLS server port number as passed in the CONNECT request.
Definition: client_side.h:420
Pipeline pipeline
set of requests waiting to be serviced
Definition: Server.h:115
void clear()
Definition: SBuf.cc:178
SBuf httpMakeVaryMark(HttpRequest *request, HttpReply const *reply)
Definition: http.cc:609
#define COMM_NONBLOCKING
Definition: Connection.h:46
StoreEntry * entry
Definition: ServerBump.h:54
static const CharacterSet ALPHA
Definition: CharacterSet.h:73
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition: Address.cc:802
int opt_no_daemon
acl_access * stats_collection
Definition: SquidConfig.h:372
virtual void endingShutdown()
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: Debug.h:75
class AccessLogEntry::HttpDetails http
SBuf & chop(size_type pos, size_type n=npos)
Definition: SBuf.cc:540
void clientStreamDetach(clientStreamNode *thisObject, ClientHttpRequest *http)
int HttpSockets[MAXTCPLISTENPORTS]
Definition: PortCfg.cc:25
iterator end()
HttpHdrRangeIter range_iter
void(* Handler)(AnyP::PortCfgPointer &portCfg, const Ipc::FdNoteId note, const Subscription::Pointer &sub)
Definition: client_side.cc:154
Http::Stream * parseHttpRequest(const Http1::RequestParserPointer &)
const char * CertAdaptAlgorithmStr[]
Definition: gadgets.cc:202
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition: forward.h:23
static void Reset()
forgets the current context, setting it to nil/unknown
Definition: CodeContext.cc:75
HttpRequest::Pointer request
faked, minimal request; required by Client API
Definition: ServerBump.h:53
#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:217
IdentConfig TheConfig
Definition: Ident.cc:73
void setIdent(const char *userIdentity)
configure rfc931 user identity for the first time
static int clientIsContentLengthValid(HttpRequest *r)
checks body length of non-chunked requests
Definition: client_side.cc:661
struct StatCounters::@135 cd
size_type rfind(char c, size_type endPos=npos) const
Definition: SBuf.cc:702
bool bodySizeKnown() const
Definition: BodyPipe.h:109
ProtocolType
Definition: ProtocolType.h:23
const char * ErrorString(const ErrorCode code)
Definition: forward.h:96
void syncNotes(HttpRequest *request)
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
Ssl::ServerBump * sslServerBump
HTTPS server cert. fetching state for bump-ssl-server-first.
Definition: client_side.h:428
bool multipartRangeRequest() const
Definition: client_side.cc:695
bool SessionIsResumed(const Security::SessionPointer &)
whether the session is a resumed one
Definition: Session.cc:213
acl_access * proxyProtocol
acceptable PROXY protocol clients
Definition: SquidConfig.h:398
bool mayUseConnection() const
Definition: Stream.h:140
const char * stoppedSending_
the reason why we no longer write the response or nil
Definition: client_side.h:433
void connStateClosed(const CommCloseCbParams &io)
Definition: client_side.cc:503
unsigned int toHostStr(char *buf, const unsigned int len) const
Definition: Address.cc:852
virtual Http::Stream * parseOneRequest()=0
void applyClientMask(const Address &mask)
Definition: Address.cc:105
Http::MethodType id() const
Definition: RequestMethod.h:76
virtual void doneWithControlMsg()
Ssl::CertSignAlgorithm signAlgorithm
The signing algorithm to use.
Definition: client_side.h:429
unsigned short initial
bool needProxyProtocolHeader_
whether PROXY protocol header is still expected
Definition: client_side.h:402
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
virtual void swanSong()
Definition: Server.cc:47
void clearRequest()
resets the current request and log_uri to nil
char rfc931[USER_IDENT_SZ]
Definition: Connection.h:172
StatHist nearMissSvcTime
Definition: StatCounters.h:49
int size
Definition: ModDevPoll.cc:77
Comm::ConnectionPointer tcpClient
the client TCP connection which originated this transaction
Definition: MasterXaction.h:53
const MemBuf & other() const
Definition: Reply.h:42
parameters for the async notePinnedConnectionBecameIdle() call
Definition: client_side.h:170
const char * fqdncache_gethostbyaddr(const Ip::Address &addr, int flags)
Definition: fqdncache.cc:480
#define NULL
Definition: types.h:166
static void httpsAccept(const CommAcceptCbParams &params)
SBuf consume(size_type n=npos)
Definition: SBuf.cc:491
#define xcalloc
Definition: membanger.c:57
void StartListening(int sock_type, int proto, const Comm::ConnectionPointer &listenConn, FdNoteId fdNote, AsyncCall::Pointer &callback)
virtual void handleReply(HttpReply *header, StoreIOBuffer receivedData)=0
Ssl::BumpMode sslBumpMode
ssl_bump decision (Ssl::bumpEnd if n/a).
Definition: client_side.h:269
#define SQUIDSBUFPRINT(s)
Definition: SBuf.h:32
void CTCB(const CommTimeoutCbParams &params)
Definition: CommCalls.h:39
void mustStop(const char *aReason)
Definition: AsyncJob.cc:69
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:128
bundles HTTP 1xx reply and the "successfully forwarded" callback
time_t timeLeft(const time_t idleTimeout) const
Definition: Connection.cc:122
bool verifySslCertificate(Security::ContextPointer &, CertificateProperties const &)
Definition: support.cc:872
SBuf vary_headers
Definition: MemObject.h:208
sslproxy_cert_adapt * cert_adapt
Definition: SquidConfig.h:522
const EVP_MD * DefaultSignHash
Definition: support.cc:43
void clientSocketRecipient(clientStreamNode *node, ClientHttpRequest *http, HttpReply *rep, StoreIOBuffer receivedData)
Definition: client_side.cc:799
static void httpsSslBumpAccessCheckDone(Acl::Answer answer, void *data)
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
bool parsingTlsHandshake
Definition: client_side.h:414
void append(char const *buf, int len)
Definition: String.cc:161
Subscription::Pointer sub
The handler to be subscribed for this connection listener.
Definition: client_side.cc:172
virtual void receivedFirstByte()
Update flags and timeout after the first byte received.
Helper::ResultCode result
The helper response 'result' field.
Definition: Reply.h:59
struct ConnStateData::@39 flags
size_t count() const
how many requests are currently pipelined
Definition: Pipeline.h:53
const Acl::Answer & fastCheck()
Definition: Checklist.cc:336
#define HTTP_REQBUF_SZ
Definition: defines.h:216
http_port or HTTP server
Definition: Message.h:39
std::string compose() const
uint64_t header
Definition: MessageSizes.h:21
static Pointer Start(AsyncJob *job)
starts a freshly created job (i.e., makes the job asynchronous)
Definition: AsyncJob.cc:23
unsigned short port() const
Definition: Address.cc:778
Definition: MemBuf.h:23
SQUIDCEXTERN int tvSubUsec(struct timeval, struct timeval)
Definition: util.c:39
void setReplyToStoreEntry(StoreEntry *e, const char *reason)
replaces current response store entry with the given one
err_type errType
Definition: HttpRequest.h:161
Ip::Address local
Definition: Connection.h:142
clientStreamNode * getClientReplyContext() const
Definition: Stream.cc:549
struct ConnStateData::@40 pinning
CachePeer * getPeer() const
Definition: Connection.cc:100
struct Http::Stream::@80 flags
static char * prepareAcceleratedURL(ConnStateData *conn, const Http1::RequestParserPointer &hp)
static const CharacterSet HEXDIG
Definition: CharacterSet.h:85
int64_t contentLen() const
Definition: Store.h:249
void configureUnconfiguredSslContext(Security::ContextPointer &, Ssl::CertSignAlgorithm signAlgorithm, AnyP::PortCfg &)
Definition: support.cc:822
void clean()
Definition: MemBuf.cc:113
StatHist hitSvcTime
Definition: StatCounters.h:51
void setReplyToError(err_type, Http::StatusCode, const HttpRequestMethod &, char const *, Ip::Address &, HttpRequest *, const char *, Auth::UserRequest::Pointer)
builds error using clientBuildError() and calls setReplyToError() below
virtual void doneWithControlMsg()
static void httpsEstablish(ConnStateData *connState, const Security::ContextPointer &ctx)
Comm::ConnectionPointer clientConnection
bool concurrentRequestQueueFilled() const
Definition: Xaction.cc:47
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:157
acl_access * ssl_bump
Definition: SquidConfig.h:391
AccessLogEntry::Pointer al
access.log entry
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:375
err_type
Definition: err_type.h:12
virtual void print(std::ostream &os) const
Definition: client_side.cc:158
Comm::ConnectionPointer tcpClient
TCP/IP level details about the client connection.
FdNoteId
We cannot send char* FD notes to other processes. Pass int IDs and convert.
Definition: FdNotes.h:20
void const char HLPCB void * data
Definition: stub_helper.cc:16
struct StatCounters::@136 netdb
void stopSending(const char *error)
note response sending error and close as soon as we read the request
Definition: client_side.cc:980
struct ClientHttpRequest::Out out
Comm::ConnectionPointer conn
Definition: CommCalls.h:85
const char * internalHostname(void)
Definition: internal.cc:140
bool handleIdleClientPinnedTlsRead()
#define safe_free(x)
Definition: xalloc.h:73
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)
int tvSubMsec(struct timeval, struct timeval)
Definition: stub_time.cc:20
Ip::Address remote
Definition: Connection.h:145
SBuf tlsConnectHostOrIp
The TLS server host name appears in CONNECT request or the server ip address for the intercepted requ...
Definition: client_side.h:419
NotePairs::Pointer notes()
bool timedout
_TIMEDOUT: terminated due to a lifetime or I/O timeout
Definition: LogTags.h:73
TlsDetails::Pointer details
TLS handshake meta info or nil.
Definition: Handshake.h:70
ClientHttpRequest * http
Definition: Stream.h:132
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:57
CommCbFunPtrCallT< Dialer > * commCbCall(int debugSection, int debugLevel, const char *callName, const Dialer &dialer)
Definition: CommCalls.h:342
Http::Stream * abortRequestParsing(const char *const errUri)
stop parsing the request and create context for relaying error info
iterator begin()
void clientOpenListenSockets(void)
void comm_reset_close(const Comm::ConnectionPointer &conn)
Definition: comm.cc:808
int conn
the current server connection FD
Definition: Transport.cc:26
const char * dash_str
#define assert(EX)
Definition: assert.h:19
#define COMM_REUSEPORT
Definition: Connection.h:52
SBuf ErrorDetail
Definition: Esi.h:29
bool parseHello(const SBuf &data)
Definition: Handshake.cc:517
void prepareLogWithRequestDetails(HttpRequest *, AccessLogEntry::Pointer &)
Definition: client_side.cc:328
StatHist missSvcTime
Definition: StatCounters.h:48
bool transparent() const
void setPayloadBuffer(MemBuf *parsedContent)
set the buffer to be used to store decoded chunk data
SBuf image() const
Definition: UriScheme.h:50
struct ClientHttpRequest::Redirect redirect
bool setValidBefore
Do not mimic "Not Valid Before" field.
Definition: gadgets.h:220
const Security::CertErrors * sslErrors() const
SSL [certificate validation] errors.
Definition: ServerBump.cc:69