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 
293  if (clientPingHasFinished(i))
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 
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;
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  tlsParser(Security::HandshakeParser::fromClient),
2191 #endif
2192  needProxyProtocolHeader_(false),
2193 #if USE_OPENSSL
2194  switchedToHttps_(false),
2195  parsingTlsHandshake(false),
2196  parsedBumpedRequestCount(0),
2197  tlsConnectPort(0),
2198  sslServerBump(NULL),
2199  signAlgorithm(Ssl::algSignTrusted),
2200 #endif
2201  stoppedSending_(NULL),
2202  stoppedReceiving_(NULL)
2203 {
2204  flags.readMore = true; // kids may overwrite
2205  flags.swanSang = false;
2206 
2207  pinning.host = NULL;
2208  pinning.port = -1;
2209  pinning.pinned = false;
2210  pinning.auth = false;
2211  pinning.zeroReply = false;
2212  pinning.peerAccessDenied = false;
2213  pinning.peer = NULL;
2214 
2215  // store the details required for creating more MasterXaction objects as new requests come in
2216  log_addr = xact->tcpClient->remote;
2218 
2219  // register to receive notice of Squid signal events
2220  // which may affect long persisting client connections
2221  registerRunner();
2222 }
2223 
2224 void
2226 {
2229 
2230  if (port->disable_pmtu_discovery != DISABLE_PMTU_OFF &&
2231  (transparent() || port->disable_pmtu_discovery == DISABLE_PMTU_ALWAYS)) {
2232 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
2233  int i = IP_PMTUDISC_DONT;
2234  if (setsockopt(clientConnection->fd, SOL_IP, IP_MTU_DISCOVER, &i, sizeof(i)) < 0) {
2235  int xerrno = errno;
2236  debugs(33, 2, "WARNING: Path MTU discovery disabling failed on " << clientConnection << " : " << xstrerr(xerrno));
2237  }
2238 #else
2239  static bool reported = false;
2240 
2241  if (!reported) {
2242  debugs(33, DBG_IMPORTANT, "NOTICE: Path MTU discovery disabling is not supported on your platform.");
2243  reported = true;
2244  }
2245 #endif
2246  }
2247 
2249  AsyncCall::Pointer call = JobCallback(33, 5, Dialer, this, ConnStateData::connStateClosed);
2251 
2252  needProxyProtocolHeader_ = port->flags.proxySurrogate;
2254  if (!proxyProtocolValidateClient()) // will close the connection on failure
2255  return;
2256  } else
2258 
2259  // requires needProxyProtocolHeader_ which is initialized above
2261 }
2262 
2263 void
2265 {
2266  if (Config.onoff.log_fqdn)
2268 
2269 #if USE_IDENT
2270  if (Ident::TheConfig.identLookup) {
2271  ACLFilledChecklist identChecklist(Ident::TheConfig.identLookup, NULL, NULL);
2272  identChecklist.src_addr = clientConnection->remote;
2273  identChecklist.my_addr = clientConnection->local;
2274  if (identChecklist.fastCheck().allowed())
2276  }
2277 #endif
2278 
2280 
2281 #if USE_DELAY_POOLS
2282  fd_table[clientConnection->fd].clientInfo = NULL;
2283 
2284  if (!Config.onoff.client_db)
2285  return; // client delay pools require client_db
2286 
2287  const auto &pools = ClientDelayPools::Instance()->pools;
2288  if (pools.size()) {
2290 
2291  // TODO: we check early to limit error response bandwidth but we
2292  // should recheck when we can honor delay_pool_uses_indirect
2293  // TODO: we should also pass the port details for myportname here.
2296 
2297  for (unsigned int pool = 0; pool < pools.size(); ++pool) {
2298 
2299  /* pools require explicit 'allow' to assign a client into them */
2300  if (pools[pool]->access) {
2301  ch.changeAcl(pools[pool]->access);
2302  auto answer = ch.fastCheck();
2303  if (answer.allowed()) {
2304 
2305  /* request client information from db after we did all checks
2306  this will save hash lookup if client failed checks */
2308  assert(cli);
2309 
2310  /* put client info in FDE */
2311  fd_table[clientConnection->fd].clientInfo = cli;
2312 
2313  /* setup write limiter for this request */
2314  const double burst = floor(0.5 +
2315  (pools[pool]->highwatermark * Config.ClientDelay.initial)/100.0);
2316  cli->setWriteLimiter(pools[pool]->rate, burst, pools[pool]->highwatermark);
2317  break;
2318  } else {
2319  debugs(83, 4, HERE << "Delay pool " << pool << " skipped because ACL " << answer);
2320  }
2321  }
2322  }
2323  }
2324 #endif
2325 
2326  // kids must extend to actually start doing something (e.g., reading)
2327 }
2328 
2330 void
2332 {
2333  MasterXaction::Pointer xact = params.xaction;
2334  AnyP::PortCfgPointer s = xact->squidPort;
2335 
2336  // NP: it is possible the port was reconfigured when the call or accept() was queued.
2337 
2338  if (params.flag != Comm::OK) {
2339  // Its possible the call was still queued when the client disconnected
2340  debugs(33, 2, s->listenConn << ": accept failure: " << xstrerr(params.xerrno));
2341  return;
2342  }
2343 
2344  debugs(33, 4, params.conn << ": accepted");
2345  fd_note(params.conn->fd, "client http connect");
2346 
2347  if (s->tcp_keepalive.enabled)
2348  commSetTcpKeepalive(params.conn->fd, s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
2349 
2351 
2352  // Socket is ready, setup the connection manager to start using it
2353  auto *srv = Http::NewServer(xact);
2354  AsyncJob::Start(srv); // usually async-calls readSomeData()
2355 }
2356 
2358 static bool
2360 {
2361  const auto conn = connState->clientConnection;
2362  if (Security::CreateServerSession(ctx, conn, connState->port->secure, "client https start")) {
2363  debugs(33, 5, "will negotiate TLS on " << conn);
2364  return true;
2365  }
2366 
2367  debugs(33, DBG_IMPORTANT, "ERROR: could not create TLS server context for " << conn);
2368  conn->close();
2369  return false;
2370 }
2371 
2378 static int
2380 {
2381  // TODO: maybe throw instead of returning -1
2382  // see https://github.com/squid-cache/squid/pull/81#discussion_r153053278
2383  int fd = conn->clientConnection->fd;
2384  auto session = fd_table[fd].ssl.get();
2385 
2386  errno = 0;
2387 
2388 #if USE_OPENSSL
2389  const auto ret = SSL_accept(session);
2390  if (ret > 0)
2391  return 1;
2392 
2393  const int xerrno = errno;
2394  const auto ssl_error = SSL_get_error(session, ret);
2395 
2396  switch (ssl_error) {
2397 
2398  case SSL_ERROR_WANT_READ:
2399  Comm::SetSelect(fd, COMM_SELECT_READ, callback, (callback ? conn : nullptr), 0);
2400  return 0;
2401 
2402  case SSL_ERROR_WANT_WRITE:
2403  Comm::SetSelect(fd, COMM_SELECT_WRITE, callback, (callback ? conn : nullptr), 0);
2404  return 0;
2405 
2406  case SSL_ERROR_SYSCALL:
2407  if (ret == 0) {
2408  debugs(83, 2, "Error negotiating SSL connection on FD " << fd << ": Aborted by client: " << ssl_error);
2409  } else {
2410  debugs(83, (xerrno == ECONNRESET) ? 1 : 2, "Error negotiating SSL connection on FD " << fd << ": " <<
2411  (xerrno == 0 ? Security::ErrorString(ssl_error) : xstrerr(xerrno)));
2412  }
2413  break;
2414 
2415  case SSL_ERROR_ZERO_RETURN:
2416  debugs(83, DBG_IMPORTANT, "Error negotiating SSL connection on FD " << fd << ": Closed by client");
2417  break;
2418 
2419  default:
2420  debugs(83, DBG_IMPORTANT, "Error negotiating SSL connection on FD " <<
2421  fd << ": " << Security::ErrorString(ssl_error) <<
2422  " (" << ssl_error << "/" << ret << ")");
2423  }
2424 
2425 #elif USE_GNUTLS
2426 
2427  const auto x = gnutls_handshake(session);
2428  if (x == GNUTLS_E_SUCCESS)
2429  return 1;
2430 
2431  if (gnutls_error_is_fatal(x)) {
2432  debugs(83, 2, "Error negotiating TLS on " << conn->clientConnection << ": Aborted by client: " << Security::ErrorString(x));
2433 
2434  } else if (x == GNUTLS_E_INTERRUPTED || x == GNUTLS_E_AGAIN) {
2435  const auto ioAction = (gnutls_record_get_direction(session)==0 ? COMM_SELECT_READ : COMM_SELECT_WRITE);
2436  Comm::SetSelect(fd, ioAction, callback, (callback ? conn : nullptr), 0);
2437  return 0;
2438  }
2439 
2440 #else
2441  // Performing TLS handshake should never be reachable without a TLS/SSL library.
2442  (void)session; // avoid compiler and static analysis complaints
2443  fatal("FATAL: HTTPS not supported by this Squid.");
2444 #endif
2445 
2446  return -1;
2447 }
2448 
2450 static void
2451 clientNegotiateSSL(int fd, void *data)
2452 {
2454 
2455  const int ret = tlsAttemptHandshake(conn, clientNegotiateSSL);
2456  if (ret <= 0) {
2457  if (ret < 0) // An error
2458  conn->clientConnection->close();
2459  return;
2460  }
2461 
2462  Security::SessionPointer session(fd_table[fd].ssl);
2463 
2464 #if USE_OPENSSL
2465  if (Security::SessionIsResumed(session)) {
2466  debugs(83, 2, "Session " << SSL_get_session(session.get()) <<
2467  " reused on FD " << fd << " (" << fd_table[fd].ipaddr <<
2468  ":" << (int)fd_table[fd].remote_port << ")");
2469  } else {
2470  if (Debug::Enabled(83, 4)) {
2471  /* Write out the SSL session details.. actually the call below, but
2472  * OpenSSL headers do strange typecasts confusing GCC.. */
2473  /* PEM_write_SSL_SESSION(debug_log, SSL_get_session(ssl)); */
2474 #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00908000L
2475  PEM_ASN1_write(reinterpret_cast<i2d_of_void *>(i2d_SSL_SESSION),
2476  PEM_STRING_SSL_SESSION, debug_log,
2477  reinterpret_cast<char *>(SSL_get_session(session.get())),
2478  nullptr, nullptr, 0, nullptr, nullptr);
2479 
2480 #elif (ALLOW_ALWAYS_SSL_SESSION_DETAIL == 1)
2481 
2482  /* When using gcc 3.3.x and OpenSSL 0.9.7x sometimes a compile error can occur here.
2483  * This is caused by an unpredicatble gcc behaviour on a cast of the first argument
2484  * of PEM_ASN1_write(). For this reason this code section is disabled. To enable it,
2485  * define ALLOW_ALWAYS_SSL_SESSION_DETAIL=1.
2486  * Because there are two possible usable cast, if you get an error here, try the other
2487  * commented line. */
2488 
2489  PEM_ASN1_write((int(*)())i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2490  debug_log,
2491  reinterpret_cast<char *>(SSL_get_session(session.get())),
2492  nullptr, nullptr, 0, nullptr, nullptr);
2493  /* PEM_ASN1_write((int(*)(...))i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2494  debug_log,
2495  reinterpret_cast<char *>(SSL_get_session(session.get())),
2496  nullptr, nullptr, 0, nullptr, nullptr);
2497  */
2498 #else
2499  debugs(83, 4, "With " OPENSSL_VERSION_TEXT ", session details are available only defining ALLOW_ALWAYS_SSL_SESSION_DETAIL=1 in the source.");
2500 
2501 #endif
2502  /* Note: This does not automatically fflush the log file.. */
2503  }
2504 
2505  debugs(83, 2, "New session " << SSL_get_session(session.get()) <<
2506  " on FD " << fd << " (" << fd_table[fd].ipaddr << ":" <<
2507  fd_table[fd].remote_port << ")");
2508  }
2509 #else
2510  debugs(83, 2, "TLS session reuse not yet implemented.");
2511 #endif
2512 
2513  // Connection established. Retrieve TLS connection parameters for logging.
2514  conn->clientConnection->tlsNegotiations()->retrieveNegotiatedInfo(session);
2515 
2516 #if USE_OPENSSL
2517  X509 *client_cert = SSL_get_peer_certificate(session.get());
2518 
2519  if (client_cert) {
2520  debugs(83, 3, "FD " << fd << " client certificate: subject: " <<
2521  X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0));
2522 
2523  debugs(83, 3, "FD " << fd << " client certificate: issuer: " <<
2524  X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0));
2525 
2526  X509_free(client_cert);
2527  } else {
2528  debugs(83, 5, "FD " << fd << " has no client certificate.");
2529  }
2530 #else
2531  debugs(83, 2, "Client certificate requesting not yet implemented.");
2532 #endif
2533 
2534  conn->readSomeData();
2535 }
2536 
2541 static void
2543 {
2544  assert(connState);
2545  const Comm::ConnectionPointer &details = connState->clientConnection;
2546 
2547  if (!ctx || !httpsCreate(connState, ctx))
2548  return;
2549 
2551  AsyncCall::Pointer timeoutCall = JobCallback(33, 5, TimeoutDialer,
2552  connState, ConnStateData::requestTimeout);
2553  commSetConnTimeout(details, Config.Timeout.request, timeoutCall);
2554 
2555  Comm::SetSelect(details->fd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
2556 }
2557 
2558 #if USE_OPENSSL
2559 
2562 static void
2564 {
2565  ConnStateData *connState = (ConnStateData *) data;
2566 
2567  // if the connection is closed or closing, just return.
2568  if (!connState->isOpen())
2569  return;
2570 
2571  if (answer.allowed()) {
2572  debugs(33, 2, "sslBump action " << Ssl::bumpMode(answer.kind) << "needed for " << connState->clientConnection);
2573  connState->sslBumpMode = static_cast<Ssl::BumpMode>(answer.kind);
2574  } else {
2575  debugs(33, 3, "sslBump not needed for " << connState->clientConnection);
2576  connState->sslBumpMode = Ssl::bumpSplice;
2577  }
2578 
2579  if (connState->sslBumpMode == Ssl::bumpTerminate) {
2580  connState->clientConnection->close();
2581  return;
2582  }
2583 
2584  if (!connState->fakeAConnectRequest("ssl-bump", connState->inBuf))
2585  connState->clientConnection->close();
2586 }
2587 #endif
2588 
2590 static void
2592 {
2593  MasterXaction::Pointer xact = params.xaction;
2594  const AnyP::PortCfgPointer s = xact->squidPort;
2595 
2596  // NP: it is possible the port was reconfigured when the call or accept() was queued.
2597 
2598  if (params.flag != Comm::OK) {
2599  // Its possible the call was still queued when the client disconnected
2600  debugs(33, 2, "httpsAccept: " << s->listenConn << ": accept failure: " << xstrerr(params.xerrno));
2601  return;
2602  }
2603 
2604  debugs(33, 4, HERE << params.conn << " accepted, starting SSL negotiation.");
2605  fd_note(params.conn->fd, "client https connect");
2606 
2607  if (s->tcp_keepalive.enabled) {
2608  commSetTcpKeepalive(params.conn->fd, s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
2609  }
2611 
2612  // Socket is ready, setup the connection manager to start using it
2613  auto *srv = Https::NewServer(xact);
2614  AsyncJob::Start(srv); // usually async-calls postHttpsAccept()
2615 }
2616 
2617 void
2619 {
2620  if (port->flags.tunnelSslBumping) {
2621 #if USE_OPENSSL
2622  debugs(33, 5, "accept transparent connection: " << clientConnection);
2623 
2624  if (!Config.accessList.ssl_bump) {
2626  return;
2627  }
2628 
2631  // Create a fake HTTP request and ALE for the ssl_bump ACL check,
2632  // using tproxy/intercept provided destination IP and port.
2633  // XXX: Merge with subsequent fakeAConnectRequest(), buildFakeRequest().
2634  // XXX: Do this earlier (e.g., in Http[s]::One::Server constructor).
2635  HttpRequest *request = new HttpRequest(mx);
2636  static char ip[MAX_IPSTRLEN];
2638  request->url.host(clientConnection->local.toStr(ip, sizeof(ip)));
2640  request->myportname = port->name;
2641  const AccessLogEntry::Pointer connectAle = new AccessLogEntry;
2642  CodeContext::Reset(connectAle);
2643  // TODO: Use these request/ALE when waiting for new bumped transactions.
2644 
2646  acl_checklist->src_addr = clientConnection->remote;
2647  acl_checklist->my_addr = port->s;
2648  // Build a local AccessLogEntry to allow requiresAle() acls work
2649  acl_checklist->al = connectAle;
2650  acl_checklist->al->cache.start_time = current_time;
2651  acl_checklist->al->tcpClient = clientConnection;
2652  acl_checklist->al->cache.port = port;
2653  acl_checklist->al->cache.caddr = log_addr;
2654  acl_checklist->al->proxyProtocolHeader = proxyProtocolHeader_;
2655  HTTPMSGUNLOCK(acl_checklist->al->request);
2656  acl_checklist->al->request = request;
2657  HTTPMSGLOCK(acl_checklist->al->request);
2658  Http::StreamPointer context = pipeline.front();
2659  ClientHttpRequest *http = context ? context->http : nullptr;
2660  const char *log_uri = http ? http->log_uri : nullptr;
2661  acl_checklist->syncAle(request, log_uri);
2662  acl_checklist->nonBlockingCheck(httpsSslBumpAccessCheckDone, this);
2663 #else
2664  fatal("FATAL: SSL-Bump requires --with-openssl");
2665 #endif
2666  return;
2667  } else {
2668  httpsEstablish(this, port->secure.staticContext);
2669  }
2670 }
2671 
2672 #if USE_OPENSSL
2673 void
2675 {
2676  ConnStateData * state_data = (ConnStateData *)(data);
2677  state_data->sslCrtdHandleReply(reply);
2678 }
2679 
2680 void
2682 {
2683  if (!isOpen()) {
2684  debugs(33, 3, "Connection gone while waiting for ssl_crtd helper reply; helper reply:" << reply);
2685  return;
2686  }
2687 
2688  if (reply.result == Helper::BrokenHelper) {
2689  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply);
2690  } else if (!reply.other().hasContent()) {
2691  debugs(1, DBG_IMPORTANT, HERE << "\"ssl_crtd\" helper returned <NULL> reply.");
2692  } else {
2694  if (reply_message.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK) {
2695  debugs(33, 5, "Reply from ssl_crtd for " << tlsConnectHostOrIp << " is incorrect");
2696  } else {
2697  if (reply.result != Helper::Okay) {
2698  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply_message.getBody());
2699  } else {
2700  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " was successfully received from ssl_crtd");
2703  auto ssl = fd_table[clientConnection->fd].ssl.get();
2704  bool ret = Ssl::configureSSLUsingPkeyAndCertFromMemory(ssl, reply_message.getBody().c_str(), *port);
2705  if (!ret)
2706  debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
2707 
2710  } else {
2712  if (ctx && !sslBumpCertKey.isEmpty())
2714  getSslContextDone(ctx);
2715  }
2716  return;
2717  }
2718  }
2719  }
2722 }
2723 
2725 {
2727 
2728  const bool connectedOk = sslServerBump && sslServerBump->connectedOk();
2729  if (connectedOk) {
2730  if (X509 *mimicCert = sslServerBump->serverCert.get())
2731  certProperties.mimicCert.resetAndLock(mimicCert);
2732 
2736 
2737  for (sslproxy_cert_adapt *ca = Config.ssl_client.cert_adapt; ca != NULL; ca = ca->next) {
2738  // If the algorithm already set, then ignore it.
2739  if ((ca->alg == Ssl::algSetCommonName && certProperties.setCommonName) ||
2740  (ca->alg == Ssl::algSetValidAfter && certProperties.setValidAfter) ||
2741  (ca->alg == Ssl::algSetValidBefore && certProperties.setValidBefore) )
2742  continue;
2743 
2744  if (ca->aclList && checklist.fastCheck(ca->aclList).allowed()) {
2745  const char *alg = Ssl::CertAdaptAlgorithmStr[ca->alg];
2746  const char *param = ca->param;
2747 
2748  // For parameterless CN adaptation, use hostname from the
2749  // CONNECT request.
2750  if (ca->alg == Ssl::algSetCommonName) {
2751  if (!param)
2752  param = tlsConnectHostOrIp.c_str();
2753  certProperties.commonName = param;
2754  certProperties.setCommonName = true;
2755  } else if (ca->alg == Ssl::algSetValidAfter)
2756  certProperties.setValidAfter = true;
2757  else if (ca->alg == Ssl::algSetValidBefore)
2758  certProperties.setValidBefore = true;
2759 
2760  debugs(33, 5, HERE << "Matches certificate adaptation aglorithm: " <<
2761  alg << " param: " << (param ? param : "-"));
2762  }
2763  }
2764 
2765  certProperties.signAlgorithm = Ssl::algSignEnd;
2766  for (sslproxy_cert_sign *sg = Config.ssl_client.cert_sign; sg != NULL; sg = sg->next) {
2767  if (sg->aclList && checklist.fastCheck(sg->aclList).allowed()) {
2768  certProperties.signAlgorithm = (Ssl::CertSignAlgorithm)sg->alg;
2769  break;
2770  }
2771  }
2772  } else {// did not try to connect (e.g. client-first) or failed to connect
2773  // In case of an error while connecting to the secure server, use a
2774  // trusted certificate, with no mimicked fields and no adaptation
2775  // algorithms. There is nothing we can mimic, so we want to minimize the
2776  // number of warnings the user will have to see to get to the error page.
2777  // We will close the connection, so that the trust is not extended to
2778  // non-Squid content.
2779  certProperties.signAlgorithm = Ssl::algSignTrusted;
2780  }
2781 
2782  assert(certProperties.signAlgorithm != Ssl::algSignEnd);
2783 
2784  if (certProperties.signAlgorithm == Ssl::algSignUntrusted) {
2785  assert(port->secure.untrustedSigningCa.cert);
2786  certProperties.signWithX509.resetAndLock(port->secure.untrustedSigningCa.cert.get());
2787  certProperties.signWithPkey.resetAndLock(port->secure.untrustedSigningCa.pkey.get());
2788  } else {
2789  assert(port->secure.signingCa.cert.get());
2790  certProperties.signWithX509.resetAndLock(port->secure.signingCa.cert.get());
2791 
2792  if (port->secure.signingCa.pkey)
2793  certProperties.signWithPkey.resetAndLock(port->secure.signingCa.pkey.get());
2794  }
2795  signAlgorithm = certProperties.signAlgorithm;
2796 
2797  certProperties.signHash = Ssl::DefaultSignHash;
2798 }
2799 
2802 {
2803  debugs(33, 5, "Finding SSL certificate for " << cacheKey << " in cache");
2805  if (const auto ctx = ssl_ctx_cache ? ssl_ctx_cache->get(cacheKey) : nullptr) {
2806  if (Ssl::verifySslCertificate(*ctx, certProperties)) {
2807  debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is valid");
2808  return *ctx;
2809  } else {
2810  debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is out of date. Delete this certificate from cache");
2811  if (ssl_ctx_cache)
2812  ssl_ctx_cache->del(cacheKey);
2813  }
2814  }
2815  return Security::ContextPointer(nullptr);
2816 }
2817 
2818 void
2820 {
2822  if (!ssl_ctx_cache || !ssl_ctx_cache->add(cacheKey, ctx)) {
2823  // If it is not in storage delete after using. Else storage deleted it.
2824  fd_table[clientConnection->fd].html?amicTlsContext = ctx;
2825  }
2826 }
2827 
2828 void
2830 {
2831  // If we are called, then CONNECT has succeeded. Finalize it.
2832  if (auto xact = pipeline.front()) {
2833  if (xact->http && xact->http->request && xact->http->request->method == Http::METHOD_CONNECT)
2834  xact->finished();
2835  // cannot proceed with encryption if requests wait for plain responses
2836  Must(pipeline.empty());
2837  }
2838  /* careful: finished() above frees request, host, etc. */
2839 
2840  if (port->secure.generateHostCertificates) {
2841  Ssl::CertificateProperties certProperties;
2842  buildSslCertGenerationParams(certProperties);
2843 
2844  // Disable caching for bumpPeekAndSplice mode
2847  Ssl::InRamCertificateDbKey(certProperties, sslBumpCertKey);
2849 
2851  if (ctx) {
2852  getSslContextDone(ctx);
2853  return;
2854  }
2855  }
2856 
2857 #if USE_SSL_CRTD
2858  try {
2859  debugs(33, 5, HERE << "Generating SSL certificate for " << certProperties.commonName << " using ssl_crtd.");
2862  request_message.composeRequest(certProperties);
2863  debugs(33, 5, HERE << "SSL crtd request: " << request_message.compose().c_str());
2864  Ssl::Helper::Submit(request_message, sslCrtdHandleReplyWrapper, this);
2865  return;
2866  } catch (const std::exception &e) {
2867  debugs(33, DBG_IMPORTANT, "ERROR: Failed to compose ssl_crtd " <<
2868  "request for " << certProperties.commonName <<
2869  " certificate: " << e.what() << "; will now block to " <<
2870  "generate that certificate.");
2871  // fall through to do blocking in-process generation.
2872  }
2873 #endif // USE_SSL_CRTD
2874 
2875  debugs(33, 5, HERE << "Generating SSL certificate for " << certProperties.commonName);
2878  auto ssl = fd_table[clientConnection->fd].ssl.get();
2879  if (!Ssl::configureSSL(ssl, certProperties, *port))
2880  debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
2881 
2884  } else {
2886  if (dynCtx && !sslBumpCertKey.isEmpty())
2888  getSslContextDone(dynCtx);
2889  }
2890  return;
2891  }
2892 
2895 }
2896 
2897 void
2899 {
2900  if (port->secure.generateHostCertificates && !ctx) {
2901  debugs(33, 2, "Failed to generate TLS context for " << tlsConnectHostOrIp);
2902  }
2903 
2904  // If generated ssl context = NULL, try to use static ssl context.
2905  if (!ctx) {
2906  if (!port->secure.staticContext) {
2907  debugs(83, DBG_IMPORTANT, "Closing " << clientConnection->remote << " as lacking TLS context");
2909  return;
2910  } else {
2911  debugs(33, 5, "Using static TLS context.");
2912  ctx = port->secure.staticContext;
2913  }
2914  }
2915 
2916  if (!httpsCreate(this, ctx))
2917  return;
2918 
2919  // bumped intercepted conns should already have Config.Timeout.request set
2920  // but forwarded connections may only have Config.Timeout.lifetime. [Re]set
2921  // to make sure the connection does not get stuck on non-SSL clients.
2923  AsyncCall::Pointer timeoutCall = JobCallback(33, 5, TimeoutDialer,
2926 
2927  switchedToHttps_ = true;
2928 
2929  auto ssl = fd_table[clientConnection->fd].ssl.get();
2930  BIO *b = SSL_get_rbio(ssl);
2931  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
2932  bio->setReadBufData(inBuf);
2933  inBuf.clear();
2935 }
2936 
2937 void
2939 {
2941  Must(http->request);
2942  auto &request = http->request;
2943 
2944  // Depending on receivedFirstByte_, we are at the start of either an
2945  // established CONNECT tunnel with the client or an intercepted TCP (and
2946  // presumably TLS) connection from the client. Expect TLS Client Hello.
2947  const auto insideConnectTunnel = receivedFirstByte_;
2948  debugs(33, 5, (insideConnectTunnel ? "post-CONNECT " : "raw TLS ") << clientConnection);
2949 
2950  tlsConnectHostOrIp = request->url.hostOrIp();
2951  tlsConnectPort = request->url.port();
2952  resetSslCommonName(request->url.host());
2953 
2954  // We are going to read new request
2955  flags.readMore = true;
2956 
2957  // keep version major.minor details the same.
2958  // but we are now performing the HTTPS handshake traffic
2960 
2961  // If sslServerBump is set, then we have decided to deny CONNECT
2962  // and now want to switch to SSL to send the error to the client
2963  // without even peeking at the origin server certificate.
2964  if (bumpServerMode == Ssl::bumpServerFirst && !sslServerBump) {
2965  request->flags.sslPeek = true;
2966  sslServerBump = new Ssl::ServerBump(http);
2967  } else if (bumpServerMode == Ssl::bumpPeek || bumpServerMode == Ssl::bumpStare) {
2968  request->flags.sslPeek = true;
2969  sslServerBump = new Ssl::ServerBump(http, nullptr, bumpServerMode);
2970  }
2971 
2972  // commSetConnTimeout() was called for this request before we switched.
2973  // Fix timeout to request_start_timeout
2975  AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
2976  TimeoutDialer, this, ConnStateData::requestTimeout);
2978  // Also reset receivedFirstByte_ flag to allow this timeout work in the case we have
2979  // a bumbed "connect" request on non transparent port.
2980  receivedFirstByte_ = false;
2981  // Get more data to peek at Tls
2982  parsingTlsHandshake = true;
2983 
2984  // If the protocol has changed, then reset preservingClientData_.
2985  // Otherwise, its value initially set in start() is still valid/fresh.
2986  // shouldPreserveClientData() uses parsingTlsHandshake which is reset above.
2987  if (insideConnectTunnel)
2989 
2990  readSomeData();
2991 }
2992 
2993 void
2995 {
2997 
2998  assert(!inBuf.isEmpty());
3000  fd_note(clientConnection->fd, "Parsing TLS handshake");
3001 
3002  bool unsupportedProtocol = false;
3003  try {
3004  if (!tlsParser.parseHello(inBuf)) {
3005  // need more data to finish parsing
3006  readSomeData();
3007  return;
3008  }
3009  }
3010  catch (const std::exception &ex) {
3011  debugs(83, 2, "error on FD " << clientConnection->fd << ": " << ex.what());
3012  unsupportedProtocol = true;
3013  }
3014 
3015  parsingTlsHandshake = false;
3016 
3017  // client data may be needed for splicing and for
3018  // tunneling unsupportedProtocol after an error
3020 
3021  // Even if the parser failed, each TLS detail should either be set
3022  // correctly or still be "unknown"; copying unknown detail is a no-op.
3025  if (details && !details->serverName.isEmpty()) {
3026  resetSslCommonName(details->serverName.c_str());
3027  tlsClientSni_ = details->serverName;
3028  }
3029 
3030  // We should disable read/write handlers
3032 
3033  if (unsupportedProtocol) {
3034  Http::StreamPointer context = pipeline.front();
3035  Must(context && context->http);
3036  HttpRequest::Pointer request = context->http->request;
3037  debugs(83, 5, "Got something other than TLS Client Hello. Cannot SslBump.");
3039  context->http->al->ssl.bumpMode = Ssl::bumpSplice;
3042  return;
3043  }
3044 
3045  if (!sslServerBump || sslServerBump->act.step1 == Ssl::bumpClientFirst) { // Either means client-first.
3047  return;
3048  } else if (sslServerBump->act.step1 == Ssl::bumpServerFirst) {
3049  Http::StreamPointer context = pipeline.front();
3050  ClientHttpRequest *http = context ? context->http : nullptr;
3051  // will call httpsPeeked() with certificate and connection, eventually
3053  } else {
3056  }
3057 }
3058 
3060 {
3061  ConnStateData *connState = (ConnStateData *) data;
3062 
3063  // if the connection is closed or closing, just return.
3064  if (!connState->isOpen())
3065  return;
3066 
3067  debugs(33, 5, "Answer: " << answer << " kind:" << answer.kind);
3068  assert(connState->serverBump());
3069  Ssl::BumpMode bumpAction;
3070  if (answer.allowed()) {
3071  bumpAction = (Ssl::BumpMode)answer.kind;
3072  } else
3073  bumpAction = Ssl::bumpSplice;
3074 
3075  connState->serverBump()->act.step2 = bumpAction;
3076  connState->sslBumpMode = bumpAction;
3077  Http::StreamPointer context = connState->pipeline.front();
3078  if (ClientHttpRequest *http = (context ? context->http : nullptr))
3079  http->al->ssl.bumpMode = bumpAction;
3080 
3081  if (bumpAction == Ssl::bumpTerminate) {
3082  connState->clientConnection->close();
3083  } else if (bumpAction != Ssl::bumpSplice) {
3084  connState->startPeekAndSplice();
3085  } else if (!connState->splice())
3086  connState->clientConnection->close();
3087 }
3088 
3089 bool
3091 {
3092  // normally we can splice here, because we just got client hello message
3093 
3094  // fde::ssl/tls_read_method() probably reads from our own inBuf. If so, then
3095  // we should not lose any raw bytes when switching to raw I/O here.
3096  if (fd_table[clientConnection->fd].ssl.get())
3097  fd_table[clientConnection->fd].useDefaultIo();
3098 
3099  // XXX: assuming that there was an HTTP/1.1 CONNECT to begin with...
3100  // reset the current protocol to HTTP/1.1 (was "HTTPS" for the bumping process)
3102  assert(!pipeline.empty());
3103  Http::StreamPointer context = pipeline.front();
3104  Must(context);
3105  Must(context->http);
3106  ClientHttpRequest *http = context->http;
3108  context->finished();
3109  if (transparent()) {
3110  // For transparent connections, make a new fake CONNECT request, now
3111  // with SNI as target. doCallout() checks, adaptations may need that.
3112  return fakeAConnectRequest("splice", preservedClientData);
3113  } else {
3114  // For non transparent connections make a new tunneled CONNECT, which
3115  // also sets the HttpRequest::flags::forceTunnel flag to avoid
3116  // respond with "Connection Established" to the client.
3117  // This fake CONNECT request required to allow use of SNI in
3118  // doCallout() checks and adaptations.
3120  }
3121 }
3122 
3123 void
3125 {
3126  // This is the Step2 of the SSL bumping
3128  Http::StreamPointer context = pipeline.front();
3129  ClientHttpRequest *http = context ? context->http : nullptr;
3130 
3133  // Run a accessList check to check if want to splice or continue bumping
3134 
3136  acl_checklist->al = http ? http->al : nullptr;
3137  //acl_checklist->src_addr = params.conn->remote;
3138  //acl_checklist->my_addr = s->s;
3142  const char *log_uri = http ? http->log_uri : nullptr;
3143  acl_checklist->syncAle(sslServerBump->request.getRaw(), log_uri);
3144  acl_checklist->nonBlockingCheck(httpsSslBumpStep2AccessCheckDone, this);
3145  return;
3146  }
3147 
3148  // will call httpsPeeked() with certificate and connection, eventually
3149  Security::ContextPointer unConfiguredCTX(Ssl::createSSLContext(port->secure.signingCa.cert, port->secure.signingCa.pkey, port->secure));
3150  fd_table[clientConnection->fd].html?amicTlsContext = unConfiguredCTX;
3151 
3152  if (!httpsCreate(this, unConfiguredCTX))
3153  return;
3154 
3155  switchedToHttps_ = true;
3156 
3157  auto ssl = fd_table[clientConnection->fd].ssl.get();
3158  BIO *b = SSL_get_rbio(ssl);
3159  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
3160  bio->setReadBufData(inBuf);
3161  bio->hold(true);
3162 
3163  // Here squid should have all of the client hello message so the
3164  // tlsAttemptHandshake() should return 0.
3165  // This block exist only to force openSSL parse client hello and detect
3166  // ERR_SECURE_ACCEPT_FAIL error, which should be checked and splice if required.
3167  if (tlsAttemptHandshake(this, nullptr) < 0) {
3168  debugs(83, 2, "TLS handshake failed.");
3169  HttpRequest::Pointer request(http ? http->request : nullptr);
3172  return;
3173  }
3174 
3175  // We need to reset inBuf here, to be used by incoming requests in the case
3176  // of SSL bump
3177  inBuf.clear();
3178 
3179  debugs(83, 5, "Peek and splice at step2 done. Start forwarding the request!!! ");
3181 }
3182 
3183 void
3185 {
3186  auto ssl = fd_table[clientConnection->fd].ssl.get();
3187  BIO *b = SSL_get_rbio(ssl);
3188  assert(b);
3189  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
3190 
3191  debugs(33, 5, "PeekAndSplice mode, proceed with client negotiation. Current state:" << SSL_state_string_long(ssl));
3192  bio->hold(false);
3193 
3195  switchedToHttps_ = true;
3196 }
3197 
3198 void
3200 {
3201  Must(sslServerBump != NULL);
3202  Must(sslServerBump->request == pic.request);
3203  Must(pipeline.empty() || pipeline.front()->http == nullptr || pipeline.front()->http->request == pic.request.getRaw());
3204 
3205  if (Comm::IsConnOpen(pic.connection)) {
3207  debugs(33, 5, "bumped HTTPS server: " << tlsConnectHostOrIp);
3208  } else
3209  debugs(33, 5, "Error while bumping: " << tlsConnectHostOrIp);
3210 
3212 }
3213 
3214 #endif /* USE_OPENSSL */
3215 
3216 bool
3217 ConnStateData::initiateTunneledRequest(HttpRequest::Pointer const &cause, Http::MethodType const method, const char *reason, const SBuf &payload)
3218 {
3219  // fake a CONNECT request to force connState to tunnel
3220  SBuf connectHost;
3221  unsigned short connectPort = 0;
3222 
3223  if (pinning.serverConnection != nullptr) {
3224  static char ip[MAX_IPSTRLEN];
3225  connectHost = pinning.serverConnection->remote.toStr(ip, sizeof(ip));
3226  connectPort = pinning.serverConnection->remote.port();
3227  } else if (cause) {
3228  connectHost = cause->url.hostOrIp();
3229  connectPort = cause->url.port();
3230 #if USE_OPENSSL
3231  } else if (!tlsConnectHostOrIp.isEmpty()) {
3232  connectHost = tlsConnectHostOrIp;
3233  connectPort = tlsConnectPort;
3234 #endif
3235  } else if (transparent()) {
3236  static char ip[MAX_IPSTRLEN];
3237  connectHost = clientConnection->local.toStr(ip, sizeof(ip));
3238  connectPort = clientConnection->local.port();
3239  } else {
3240  debugs(33, 2, "Not able to compute URL, abort request tunneling for " << reason);
3241  return false;
3242  }
3243 
3244  debugs(33, 2, "Request tunneling for " << reason);
3245  ClientHttpRequest *http = buildFakeRequest(method, connectHost, connectPort, payload);
3247  request->flags.forceTunnel = true;
3248  http->calloutContext = new ClientRequestContext(http);
3249  http->doCallouts();
3251  return true;
3252 }
3253 
3254 bool
3255 ConnStateData::fakeAConnectRequest(const char *reason, const SBuf &payload)
3256 {
3257  debugs(33, 2, "fake a CONNECT request to force connState to tunnel for " << reason);
3258 
3259  SBuf connectHost;
3260  assert(transparent());
3261  const unsigned short connectPort = clientConnection->local.port();
3262 
3263 #if USE_OPENSSL
3264  if (!tlsClientSni_.isEmpty())
3265  connectHost.assign(tlsClientSni_);
3266  else
3267 #endif
3268  {
3269  static char ip[MAX_IPSTRLEN];
3270  clientConnection->local.toHostStr(ip, sizeof(ip));
3271  connectHost.assign(ip);
3272  }
3273 
3274  ClientHttpRequest *http = buildFakeRequest(Http::METHOD_CONNECT, connectHost, connectPort, payload);
3275 
3276  http->calloutContext = new ClientRequestContext(http);
3278  http->doCallouts();
3280  return true;
3281 }
3282 
3284 ConnStateData::buildFakeRequest(Http::MethodType const method, SBuf &useHost, unsigned short usePort, const SBuf &payload)
3285 {
3286  ClientHttpRequest *http = new ClientHttpRequest(this);
3287  Http::Stream *stream = new Http::Stream(clientConnection, http);
3288 
3289  StoreIOBuffer tempBuffer;
3290  tempBuffer.data = stream->reqbuf;
3291  tempBuffer.length = HTTP_REQBUF_SZ;
3292 
3293  ClientStreamData newServer = new clientReplyContext(http);
3294  ClientStreamData newClient = stream;
3297  clientSocketDetach, newClient, tempBuffer);
3298 
3299  stream->flags.parsed_ok = 1; // Do we need it?
3300  stream->mayUseConnection(true);
3301 
3302  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "clientLifetimeTimeout",
3305 
3306  stream->registerWithConn();
3307 
3310  // Setup Http::Request object. Maybe should be replaced by a call to (modified)
3311  // clientProcessRequest
3314  request->url.setScheme(proto, nullptr);
3315  request->method = method;
3316  request->url.host(useHost.c_str());
3317  request->url.port(usePort);
3318 
3319  http->uri = SBufToCstring(request->effectiveRequestUri());
3320  http->initRequest(request.getRaw());
3321 
3322  request->manager(this, http->al);
3323 
3324  if (proto == AnyP::PROTO_HTTP)
3325  request->header.putStr(Http::HOST, useHost.c_str());
3326 
3327  request->sources |= ((switchedToHttps() || port->transport.protocol == AnyP::PROTO_HTTPS) ? Http::Message::srcHttps : Http::Message::srcHttp);
3328 #if USE_AUTH
3329  if (getAuth())
3330  request->auth_user_request = getAuth();
3331 #endif
3332 
3333  inBuf = payload;
3334  flags.readMore = false;
3335 
3336  return http;
3337 }
3338 
3340 static bool
3342 {
3343  if (!Comm::IsConnOpen(c)) {
3344  Must(NHttpSockets > 0); // we tried to open some
3345  --NHttpSockets; // there will be fewer sockets than planned
3346  Must(HttpSockets[NHttpSockets] < 0); // no extra fds received
3347 
3348  if (!NHttpSockets) // we could not open any listen sockets at all
3349  fatalf("Unable to open %s",FdNote(portType));
3350 
3351  return false;
3352  }
3353  return true;
3354 }
3355 
3357 static bool
3359 {
3360  bool found = false;
3361  for (int i = 0; i < NHttpSockets && !found; ++i) {
3362  if ((found = HttpSockets[i] < 0))
3363  HttpSockets[i] = conn->fd;
3364  }
3365  return found;
3366 }
3367 
3368 static void
3370 {
3371  for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) {
3372  const SBuf &scheme = AnyP::UriScheme(s->transport.protocol).image();
3373 
3375  debugs(1, DBG_IMPORTANT, "WARNING: You have too many '" << scheme << "_port' lines." <<
3376  Debug::Extra << "The limit is " << MAXTCPLISTENPORTS << " HTTP ports.");
3377  continue;
3378  }
3379 
3380 #if USE_OPENSSL
3381  if (s->flags.tunnelSslBumping) {
3382  if (!Config.accessList.ssl_bump) {
3383  debugs(33, DBG_IMPORTANT, "WARNING: No ssl_bump configured. Disabling ssl-bump on " << scheme << "_port " << s->s);
3384  s->flags.tunnelSslBumping = false;
3385  }
3386  if (!s->secure.staticContext && !s->secure.generateHostCertificates) {
3387  debugs(1, DBG_IMPORTANT, "Will not bump SSL at " << scheme << "_port " << s->s << " due to TLS initialization failure.");
3388  s->flags.tunnelSslBumping = false;
3389  if (s->transport.protocol == AnyP::PROTO_HTTP)
3390  s->secure.encryptTransport = false;
3391  }
3392  if (s->flags.tunnelSslBumping) {
3393  // Create ssl_ctx cache for this port.
3394  Ssl::TheGlobalContextStorage.addLocalStorage(s->s, s->secure.html?amicCertMemCacheSize);
3395  }
3396  }
3397 #endif
3398 
3399  if (s->secure.encryptTransport && !s->secure.staticContext) {
3400  debugs(1, DBG_CRITICAL, "ERROR: Ignoring " << scheme << "_port " << s->s << " due to TLS context initialization failure.");
3401  continue;
3402  }
3403 
3404  // Fill out a Comm::Connection which IPC will open as a listener for us
3405  // then pass back when active so we can start a TcpAcceptor subscription.
3406  s->listenConn = new Comm::Connection;
3407  s->listenConn->local = s->s;
3408 
3409  s->listenConn->flags = COMM_NONBLOCKING | (s->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) |
3410  (s->flags.natIntercept ? COMM_INTERCEPTION : 0) |
3411  (s->workerQueues ? COMM_REUSEPORT : 0);
3412 
3413  typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
3414  if (s->transport.protocol == AnyP::PROTO_HTTP) {
3415  // setup the subscriptions such that new connections accepted by listenConn are handled by HTTP
3418 
3419  AsyncCall::Pointer listenCall = asyncCall(33,2, "clientListenerConnectionOpened",
3421  Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpSocket, listenCall);
3422 
3423  } else if (s->transport.protocol == AnyP::PROTO_HTTPS) {
3424  // setup the subscriptions such that new connections accepted by listenConn are handled by HTTPS
3427 
3428  AsyncCall::Pointer listenCall = asyncCall(33, 2, "clientListenerConnectionOpened",
3430  s, Ipc::fdnHttpsSocket, sub));
3431  Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpsSocket, listenCall);
3432  }
3433 
3434  HttpSockets[NHttpSockets] = -1; // set in clientListenerConnectionOpened
3435  ++NHttpSockets;
3436  }
3437 }
3438 
3439 void
3441 {
3442  // Fill out a Comm::Connection which IPC will open as a listener for us
3443  port->listenConn = new Comm::Connection;
3444  port->listenConn->local = port->s;
3445  port->listenConn->flags =
3447  (port->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) |
3448  (port->flags.natIntercept ? COMM_INTERCEPTION : 0);
3449 
3450  // route new connections to subCall
3451  typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
3453  AsyncCall::Pointer listenCall =
3454  asyncCall(33, 2, "clientListenerConnectionOpened",
3456  port, fdNote, sub));
3457  Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, port->listenConn, fdNote, listenCall);
3458 
3460  HttpSockets[NHttpSockets] = -1;
3461  ++NHttpSockets;
3462 }
3463 
3465 static void
3467 {
3468  Must(s != NULL);
3469 
3470  if (!OpenedHttpSocket(s->listenConn, portTypeNote))
3471  return;
3472 
3473  Must(Comm::IsConnOpen(s->listenConn));
3474 
3475  // TCP: setup a job to handle accept() with subscribed handler
3476  AsyncJob::Start(new Comm::TcpAcceptor(s, FdNote(portTypeNote), sub));
3477 
3478  debugs(1, DBG_IMPORTANT, "Accepting " <<
3479  (s->flags.natIntercept ? "NAT intercepted " : "") <<
3480  (s->flags.tproxyIntercept ? "TPROXY intercepted " : "") <<
3481  (s->flags.tunnelSslBumping ? "SSL bumped " : "") <<
3482  (s->flags.accelSurrogate ? "reverse-proxy " : "")
3483  << FdNote(portTypeNote) << " connections at "
3484  << s->listenConn);
3485 
3486  Must(AddOpenedHttpSocket(s->listenConn)); // otherwise, we have received a fd we did not ask for
3487 
3488 #if USE_SYSTEMD
3489  // When the very first port opens, tell systemd we are able to serve connections.
3490  // Subsequent sd_notify() calls, including calls during reconfiguration,
3491  // do nothing because the first call parameter is 1.
3492  // XXX: Send the notification only after opening all configured ports.
3493  if (opt_foreground || opt_no_daemon) {
3494  const auto result = sd_notify(1, "READY=1");
3495  if (result < 0) {
3496  debugs(1, DBG_IMPORTANT, "WARNING: failed to send start-up notification to systemd" <<
3497  Debug::Extra << "sd_notify() error: " << xstrerr(-result));
3498  }
3499  }
3500 #endif
3501 }
3502 
3503 void
3505 {
3508 
3509  if (NHttpSockets < 1)
3510  fatal("No HTTP, HTTPS, or FTP ports configured");
3511 }
3512 
3513 void
3515 {
3516  for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) {
3517  if (s->listenConn != NULL) {
3518  debugs(1, DBG_IMPORTANT, "Closing HTTP(S) port " << s->listenConn->local);
3519  s->listenConn->close();
3520  s->listenConn = NULL;
3521  }
3522  }
3523 
3525 
3526  // TODO see if we can drop HttpSockets array entirely */
3527  for (int i = 0; i < NHttpSockets; ++i) {
3528  HttpSockets[i] = -1;
3529  }
3530 
3531  NHttpSockets = 0;
3532 }
3533 
3534 int
3536 {
3537  SBuf vary(request->vary_headers);
3538  const auto &reply = entry->mem().freshestReply();
3539  auto has_vary = reply.header.has(Http::HdrType::VARY);
3540 #if X_ACCELERATOR_VARY
3541 
3542  has_vary |=
3543  reply.header.has(Http::HdrType::HDR_X_ACCELERATOR_VARY);
3544 #endif
3545 
3546  if (!has_vary || entry->mem_obj->vary_headers.isEmpty()) {
3547  if (!vary.isEmpty()) {
3548  /* Oops... something odd is going on here.. */
3549  debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary object on second attempt, '" <<
3550  entry->mem_obj->urlXXX() << "' '" << vary << "'");
3551  request->vary_headers.clear();
3552  return VARY_CANCEL;
3553  }
3554 
3555  if (!has_vary) {
3556  /* This is not a varying object */
3557  return VARY_NONE;
3558  }
3559 
3560  /* virtual "vary" object found. Calculate the vary key and
3561  * continue the search
3562  */
3563  vary = httpMakeVaryMark(request, &reply);
3564 
3565  if (!vary.isEmpty()) {
3566  request->vary_headers = vary;
3567  return VARY_OTHER;
3568  } else {
3569  /* Ouch.. we cannot handle this kind of variance */
3570  /* XXX This cannot really happen, but just to be complete */
3571  return VARY_CANCEL;
3572  }
3573  } else {
3574  if (vary.isEmpty()) {
3575  vary = httpMakeVaryMark(request, &reply);
3576 
3577  if (!vary.isEmpty())
3578  request->vary_headers = vary;
3579  }
3580 
3581  if (vary.isEmpty()) {
3582  /* Ouch.. we cannot handle this kind of variance */
3583  /* XXX This cannot really happen, but just to be complete */
3584  return VARY_CANCEL;
3585  } else if (vary.cmp(entry->mem_obj->vary_headers) == 0) {
3586  return VARY_MATCH;
3587  } else {
3588  /* Oops.. we have already been here and still haven't
3589  * found the requested variant. Bail out
3590  */
3591  debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary match on second attempt, '" <<
3592  entry->mem_obj->urlXXX() << "' '" << vary << "'");
3593  return VARY_CANCEL;
3594  }
3595  }
3596 }
3597 
3600 {
3601  const auto checklist = new ACLFilledChecklist(acl, nullptr, nullptr);
3602  clientAclChecklistFill(*checklist, http);
3603  return checklist;
3604 }
3605 
3606 void
3608 {
3609  checklist.setRequest(http->request);
3610  checklist.al = http->al;
3611  checklist.syncAle(http->request, http->log_uri);
3612 
3613  // TODO: If http->getConn is always http->request->clientConnectionManager,
3614  // then call setIdent() inside checklist.setRequest(). Otherwise, restore
3615  // USE_IDENT lost in commit 94439e4.
3616  ConnStateData * conn = http->getConn();
3617  const char *ident = (cbdataReferenceValid(conn) &&
3618  conn && conn->clientConnection) ?
3619  conn->clientConnection->rfc931 : dash_str;
3620  checklist.setIdent(ident);
3621 }
3622 
3623 bool
3625 {
3627 }
3628 
3631 {
3632  bodyPipe = new BodyPipe(this);
3633  if (size >= 0)
3635  else
3637  return bodyPipe;
3638 }
3639 
3640 int64_t
3642 {
3643  if (!bodyPipe)
3644  return 0; // request without a body or read/produced all body bytes
3645 
3646  if (!bodyPipe->bodySizeKnown())
3647  return -1; // probably need to read more, but we cannot be sure
3648 
3649  const int64_t needToProduce = bodyPipe->unproducedSize();
3650  const int64_t haveAvailable = static_cast<int64_t>(inBuf.length());
3651 
3652  if (needToProduce <= haveAvailable)
3653  return 0; // we have read what we need (but are waiting for pipe space)
3654 
3655  return needToProduce - haveAvailable;
3656 }
3657 
3658 void
3660 {
3661  debugs(33, 4, HERE << "receiving error (" << clientConnection << "): " << error <<
3662  "; old sending error: " <<
3663  (stoppedSending() ? stoppedSending_ : "none"));
3664 
3665  if (const char *oldError = stoppedReceiving()) {
3666  debugs(33, 3, HERE << "already stopped receiving: " << oldError);
3667  return; // nothing has changed as far as this connection is concerned
3668  }
3669 
3671 
3672  if (const char *sendError = stoppedSending()) {
3673  debugs(33, 3, HERE << "closing because also stopped sending: " << sendError);
3675  }
3676 }
3677 
3678 void
3680 {
3681  if (bodyPipe != NULL) {
3682  debugs(33, 4, HERE << "no consumer for virgin body " << bodyPipe->status());
3684  }
3685 }
3686 
3688 void
3690 {
3691  Must(bodyPipe != NULL);
3692  debugs(33, 5, HERE << "start dechunking" << bodyPipe->status());
3693  assert(!bodyParser);
3695 }
3696 
3698 void
3700 {
3701  debugs(33, 5, HERE << "finish dechunking: " << withSuccess);
3702 
3703  if (bodyPipe != NULL) {
3704  debugs(33, 7, HERE << "dechunked tail: " << bodyPipe->status());
3705  BodyPipe::Pointer myPipe = bodyPipe;
3706  stopProducingFor(bodyPipe, withSuccess); // sets bodyPipe->bodySize()
3707  Must(!bodyPipe); // we rely on it being nil after we are done with body
3708  if (withSuccess) {
3709  Must(myPipe->bodySizeKnown());
3710  Http::StreamPointer context = pipeline.front();
3711  if (context != NULL && context->http && context->http->request)
3712  context->http->request->setContentLength(myPipe->bodySize());
3713  }
3714  }
3715 
3716  delete bodyParser;
3717  bodyParser = NULL;
3718 }
3719 
3720 // XXX: this is an HTTP/1-only operation
3721 void
3723 {
3724  if (const auto context = pipeline.front()) {
3725  if (context->http)
3726  context->http->al->reply = msg.reply;
3727  }
3728 
3729  if (!isOpen()) {
3730  debugs(33, 3, HERE << "ignoring 1xx due to earlier closure");
3731  return;
3732  }
3733 
3734  // HTTP/1 1xx status messages are only valid when there is a transaction to trigger them
3735  if (!pipeline.empty()) {
3736  HttpReply::Pointer rep(msg.reply);
3737  Must(rep);
3738  // remember the callback
3740 
3743 
3744  if (!writeControlMsgAndCall(rep.getRaw(), call)) {
3745  // but still inform the caller (so it may resume its operation)
3747  }
3748  return;
3749  }
3750 
3751  debugs(33, 3, HERE << " closing due to missing context for 1xx");
3753 }
3754 
3755 void
3757 {
3759 
3760  if (Http::StreamPointer deferredRequest = pipeline.front()) {
3761  debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded after control msg wrote");
3762  ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
3763  }
3764 }
3765 
3767 void
3769 {
3770  // FwdState might repin a failed connection sooner than this close
3771  // callback is called for the failed connection.
3772  assert(pinning.serverConnection == io.conn);
3773  pinning.closeHandler = NULL; // Comm unregisters handlers before calling
3774  const bool sawZeroReply = pinning.zeroReply; // reset when unpinning
3775  pinning.serverConnection->noteClosure();
3776  unpinConnection(false);
3777 
3778  if (sawZeroReply && clientConnection != NULL) {
3779  debugs(33, 3, "Closing client connection on pinned zero reply.");
3781  }
3782 
3783 }
3784 
3785 void
3787 {
3788  pinConnection(pinServer, *request);
3789 }
3790 
3791 void
3793 {
3794  Must(pic.connection);
3795  Must(pic.request);
3796  pinConnection(pic.connection, *pic.request);
3797 
3798  // monitor pinned server connection for remote-end closures.
3800 
3801  if (pipeline.empty())
3802  kick(); // in case clientParseRequests() was blocked by a busy pic.connection
3803 }
3804 
3806 void
3808 {
3809  if (Comm::IsConnOpen(pinning.serverConnection) &&
3810  pinning.serverConnection->fd == pinServer->fd) {
3811  debugs(33, 3, "already pinned" << pinServer);
3812  return;
3813  }
3814 
3815  unpinConnection(true); // closes pinned connection, if any, and resets fields
3816 
3817  pinning.serverConnection = pinServer;
3818 
3819  debugs(33, 3, HERE << pinning.serverConnection);
3820 
3821  Must(pinning.serverConnection != NULL);
3822 
3823  const char *pinnedHost = "[unknown]";
3824  pinning.host = xstrdup(request.url.host());
3825  pinning.port = request.url.port();
3826  pinnedHost = pinning.host;
3827  pinning.pinned = true;
3828  if (CachePeer *aPeer = pinServer->getPeer())
3829  pinning.peer = cbdataReference(aPeer);
3830  pinning.auth = request.flags.connectionAuth;
3831  char stmp[MAX_IPSTRLEN];
3832  char desc[FD_DESC_SZ];
3833  snprintf(desc, FD_DESC_SZ, "%s pinned connection for %s (%d)",
3834  (pinning.auth || !pinning.peer) ? pinnedHost : pinning.peer->name,
3836  clientConnection->fd);
3837  fd_note(pinning.serverConnection->fd, desc);
3838 
3840  pinning.closeHandler = JobCallback(33, 5,
3842  // remember the pinned connection so that cb does not unpin a fresher one
3843  typedef CommCloseCbParams Params;
3844  Params &params = GetCommParams<Params>(pinning.closeHandler);
3845  params.conn = pinning.serverConnection;
3846  comm_add_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
3847 }
3848 
3851 void
3853 {
3854  if (pinning.readHandler != NULL)
3855  return; // already monitoring
3856 
3858  pinning.readHandler = JobCallback(33, 3,
3860  Comm::Read(pinning.serverConnection, pinning.readHandler);
3861 }
3862 
3863 void
3865 {
3866  if (pinning.readHandler != NULL) {
3867  Comm::ReadCancel(pinning.serverConnection->fd, pinning.readHandler);
3868  pinning.readHandler = NULL;
3869  }
3870 }
3871 
3872 #if USE_OPENSSL
3873 bool
3875 {
3876  // A ready-for-reading connection means that the TLS server either closed
3877  // the connection, sent us some unexpected HTTP data, or started TLS
3878  // renegotiations. We should close the connection except for the last case.
3879 
3880  Must(pinning.serverConnection != nullptr);
3881  auto ssl = fd_table[pinning.serverConnection->fd].ssl.get();
3882  if (!ssl)
3883  return false;
3884 
3885  char buf[1];
3886  const int readResult = SSL_read(ssl, buf, sizeof(buf));
3887 
3888  if (readResult > 0 || SSL_pending(ssl) > 0) {
3889  debugs(83, 2, pinning.serverConnection << " TLS application data read");
3890  return false;
3891  }
3892 
3893  switch(const int error = SSL_get_error(ssl, readResult)) {
3894  case SSL_ERROR_WANT_WRITE:
3895  debugs(83, DBG_IMPORTANT, pinning.serverConnection << " TLS SSL_ERROR_WANT_WRITE request for idle pinned connection");
3896  // fall through to restart monitoring, for now
3897  case SSL_ERROR_NONE:
3898  case SSL_ERROR_WANT_READ:
3900  return true;
3901 
3902  default:
3903  debugs(83, 2, pinning.serverConnection << " TLS error: " << error);
3904  return false;
3905  }
3906 
3907  // not reached
3908  return true;
3909 }
3910 #endif
3911 
3914 void
3916 {
3917  pinning.readHandler = NULL; // Comm unregisters handlers before calling
3918 
3919  if (io.flag == Comm::ERR_CLOSING)
3920  return; // close handler will clean up
3921 
3922  Must(pinning.serverConnection == io.conn);
3923 
3924 #if USE_OPENSSL
3926  return;
3927 #endif
3928 
3929  const bool clientIsIdle = pipeline.empty();
3930 
3931  debugs(33, 3, "idle pinned " << pinning.serverConnection << " read " <<
3932  io.size << (clientIsIdle ? " with idle client" : ""));
3933 
3934  pinning.serverConnection->close();
3935 
3936  // If we are still sending data to the client, do not close now. When we are done sending,
3937  // ConnStateData::kick() checks pinning.serverConnection and will close.
3938  // However, if we are idle, then we must close to inform the idle client and minimize races.
3939  if (clientIsIdle && clientConnection != NULL)
3941 }
3942 
3945 {
3946  debugs(33, 7, pinning.serverConnection);
3947  Must(request);
3948 
3949  const auto pinningError = [&](const err_type type) {
3950  unpinConnection(true);
3951  HttpRequestPointer requestPointer = request;
3952  return ErrorState::NewForwarding(type, requestPointer, ale);
3953  };
3954 
3955  if (!Comm::IsConnOpen(pinning.serverConnection))
3956  throw pinningError(ERR_ZERO_SIZE_OBJECT);
3957 
3958  if (pinning.auth && pinning.host && strcasecmp(pinning.host, request->url.host()) != 0)
3959  throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_CONFLICT_HOST
3960 
3961  if (pinning.port != request->url.port())
3962  throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_CONFLICT_HOST
3963 
3964  if (pinning.peer && !cbdataReferenceValid(pinning.peer))
3965  throw pinningError(ERR_ZERO_SIZE_OBJECT);
3966 
3967  if (pinning.peerAccessDenied)
3968  throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_FORWARDING_DENIED
3969 
3971  return pinning.serverConnection;
3972 }
3973 
3976 {
3977  if (const auto connManager = request ? request->pinnedConnection() : nullptr)
3978  return connManager->borrowPinnedConnection(request, ale);
3979 
3980  // ERR_CANNOT_FORWARD is somewhat misleading here; we can still forward, but
3981  // there is no point since the client connection is now gone
3982  HttpRequestPointer requestPointer = request;
3983  throw ErrorState::NewForwarding(ERR_CANNOT_FORWARD, requestPointer, ale);
3984 }
3985 
3986 void
3988 {
3989  debugs(33, 3, HERE << pinning.serverConnection);
3990 
3991  if (pinning.peer)
3993 
3994  if (Comm::IsConnOpen(pinning.serverConnection)) {
3995  if (pinning.closeHandler != NULL) {
3996  comm_remove_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
3997  pinning.closeHandler = NULL;
3998  }
3999 
4001 
4002  // close the server side socket if requested
4003  if (andClose)
4004  pinning.serverConnection->close();
4005  pinning.serverConnection = NULL;
4006  }
4007 
4008  safe_free(pinning.host);
4009 
4010  pinning.zeroReply = false;
4011  pinning.peerAccessDenied = false;
4012 
4013  /* NOTE: pinning.pinned should be kept. This combined with fd == -1 at the end of a request indicates that the host
4014  * connection has gone away */
4015 }
4016 
4017 void
4019 {
4020  // if we are parsing request body, its request is responsible for logging
4021  if (bodyPipe)
4022  return;
4023 
4024  // a request currently using this connection is responsible for logging
4025  if (!pipeline.empty() && pipeline.back()->mayUseConnection())
4026  return;
4027 
4028  /* Either we are waiting for the very first transaction, or
4029  * we are done with the Nth transaction and are waiting for N+1st.
4030  * XXX: We assume that if anything was added to inBuf, then it could
4031  * only be consumed by actions already covered by the above checks.
4032  */
4033 
4034  // do not log connections that closed after a transaction (it is normal)
4035  // TODO: access_log needs ACLs to match received-no-bytes connections
4036  if (pipeline.nrequests && inBuf.isEmpty())
4037  return;
4038 
4039  /* Create a temporary ClientHttpRequest object. Its destructor will log. */
4040  ClientHttpRequest http(this);
4041  http.req_sz = inBuf.length();
4042  // XXX: Or we died while waiting for the pinned connection to become idle.
4043  http.setErrorUri("error:transaction-end-before-headers");
4044 }
4045 
4046 bool
4048 {
4049  // PROXY protocol bytes are meant for us and, hence, cannot be tunneled
4051  return false;
4052 
4053  // If our decision here is negative, configuration changes are irrelevant.
4054  // Otherwise, clientTunnelOnError() rechecks configuration before tunneling.
4056  return false;
4057 
4058  // TODO: Figure out whether/how we can support FTP tunneling.
4059  if (port->transport.protocol == AnyP::PROTO_FTP)
4060  return false;
4061 
4062 #if USE_OPENSSL
4063  if (parsingTlsHandshake)
4064  return true;
4065 
4066  // the 1st HTTP request on a bumped connection
4068  return true;
4069 #endif
4070 
4071  // the 1st HTTP(S) request on a connection to an intercepting port
4072  if (!pipeline.nrequests && transparent())
4073  return true;
4074 
4075  return false;
4076 }
4077 
4080 {
4081  if (!theNotes)
4082  theNotes = new NotePairs;
4083  return theNotes;
4084 }
4085 
4086 std::ostream &
4087 operator <<(std::ostream &os, const ConnStateData::PinnedIdleContext &pic)
4088 {
4089  return os << pic.connection << ", request=" << pic.request;
4090 }
4091 
4092 std::ostream &
4094 {
4095  return os << scc.conn_ << ", srv_bytes=" << scc.preReadServerBytes.length();
4096 }
4097 
const MemBuf & buf() const
Definition: BodyPipe.h:137
void Read(const Comm::ConnectionPointer &conn, AsyncCall::Pointer &callback)
Definition: Read.cc:40
@ initClient
HTTP or FTP client.
#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:104
#define USER_IDENT_SZ
Definition: defines.h:60
virtual void noteBodyConsumerAborted(BodyPipe::Pointer)=0
@ bumpPeek
Definition: support.h:136
#define FQDN_LOOKUP_IF_MISS
Definition: defines.h:48
@ LOG_TCP_IMS_HIT
Definition: LogTags.h:32
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:443
#define MYNAME
Definition: Debug.h:170
int half_closed_clients
Definition: SquidConfig.h:294
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:482
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
@ hoReply
Definition: HttpHeader.h:37
const char * findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end)
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:72
unsigned int major
major version number
int getMyPort(void)
Definition: tools.cc:1003
@ scMethodNotAllowed
Definition: StatusCode.h:49
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)
struct StatCounters::@131 icp
void InRamCertificateDbKey(const Ssl::CertificateProperties &certProperties, SBuf &key)
Definition: support.cc:1221
int incoming_sockets_accepted
@ HDR_X_ACCELERATOR_VARY
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
@ scPayloadTooLarge
Definition: StatusCode.h:57
@ METHOD_HEAD
Definition: MethodType.h:28
SBuf & assign(const SBuf &S)
Definition: SBuf.cc:83
@ CLOSEST_PARENT_MISS
Definition: hier_code.h:21
void port(unsigned short p)
Definition: Uri.h:94
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:483
CertSignAlgorithm
Definition: gadgets.h:150
BodyPipe::Pointer body_pipe
optional pipeline to receive message body
Definition: Message.h:98
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()
@ VARY_NONE
Definition: enums.h:193
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
@ scBadRequest
Definition: StatusCode.h:44
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
const char * getStr(Http::HdrType id) const
Definition: HttpHeader.cc:1165
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
struct ClientHttpRequest::Redirect redirect
mb_size_t size
Definition: MemBuf.h:135
void retrieveParsedInfo(Security::TlsDetails::Pointer const &details)
Extract information from parser stored in TlsDetails object.
AnyP::PortCfgPointer HttpPortList
list of Squid http(s)_port configured
Definition: PortCfg.cc: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:277
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
@ PARENT_HIT
Definition: hier_code.h:16
acl_access * on_unsupported_protocol
Definition: SquidConfig.h:404
bool isEmpty() const
Definition: SBuf.h:420
void initRequest(HttpRequest *)
MemObject * mem_obj
Definition: Store.h:213
StatHist nearHitSvcTime
Definition: StatCounters.h:50
void registerWithConn()
register this stream with the Server
Definition: Stream.cc:52
int64_t maxRequestBodySize
Definition: SquidConfig.h:132
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
@ scLengthRequired
Definition: StatusCode.h:55
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:458
#define debug_log
change-avoidance macro; new code should call DebugStream() instead
Definition: Debug.h:114
struct node * next
Definition: parse.c:105
int log_mime_hdrs
Definition: SquidConfig.h:289
struct SquidConfig::@123 ssl_client
ConnStateData * getConn() const
int request_entities
Definition: SquidConfig.h:319
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
struct ConnStateData::@39 flags
acl_access * cert_error
Definition: SquidConfig.h:523
MemObject & mem()
Definition: Store.h:52
void banAction(const Acl::Answer &action)
add action to the list of banned actions
Definition: Checklist.cc:403
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:774
@ ERR_NONE
Definition: err_type.h:13
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,...)
struct SquidConfig::@113 accessList
static void Submit(CrtdMessage const &message, HLPCB *callback, void *data)
Submit crtd message to external crtd server.
Definition: helper.cc:123
unsigned int minor
minor version number
Ip::Address log_addr
Definition: client_side.h:129
SBuf hostOrIp() const
Definition: Uri.cc:114
void setWriteLimiter(const int aWriteSpeedLimit, const double anInitialBurst, const double aHighWatermark)
Definition: comm.cc:1443
void readNextRequest()
Definition: client_side.cc:859
bool hasContent() const
Definition: MemBuf.h:54
HttpReplyPointer reply
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:136
struct timeval stop
Definition: PingData.h:37
Ip::Address client_netmask
Definition: SquidConfig.h:245
BodyPipe::Pointer bodyPipe
set when we are reading request body
Definition: client_side.h:391
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:454
#define xstrdup
void enableAutoConsumption()
start or continue consuming when producing without consumer
Definition: BodyPipe.cc:316
int64_t mayNeedToReadMoreBody() const
@ bumpTerminate
Definition: support.h:136
struct ClientHttpRequest::Flags flags
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
@ LOG_TCP_CLIENT_REFRESH_MISS
Definition: LogTags.h:31
@ bumpEnd
Definition: support.h:136
int fd
FD which the call was about. Set by the async call creator.
Definition: CommCalls.h:90
@ ERR_REQUEST_PARSE_TIMEOUT
Definition: err_type.h:79
time_t request_start_timeout
Definition: SquidConfig.h:122
@ METHOD_PRI
Definition: MethodType.h:91
int content_length
Definition: tcp-banger2.c:121
int type
Definition: errorpage.cc:152
struct ClientHttpRequest::Out out
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
struct Http::Stream::@80 flags
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
@ OK
Definition: Flag.h:16
const char * sslGetUserEmail(SSL *ssl)
Definition: support.cc:734
int global_internal_static
Definition: SquidConfig.h:328
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:845
#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
@ ERR_SECURE_CONNECT_FAIL
Definition: err_type.h:29
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
@ CLOSEST_PARENT
Definition: hier_code.h:22
#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:444
const char * FdNote(int fdNodeId)
converts FdNoteId into a string
Definition: FdNotes.cc:16
Notes notes
note
Definition: SquidConfig.h:485
void StartListening()
accept connections on all configured ftp_ports
Definition: FtpServer.cc:266
@ ERR_CLOSING
Definition: Flag.h:25
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
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:343
#define PROF_stop(probename)
Definition: Profiler.h:63
@ ERR_CANNOT_FORWARD
Definition: err_type.h:21
@ LOG_TCP_HIT
Definition: LogTags.h:24
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
@ LOG_TCP_MISS
Definition: LogTags.h:25
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:439
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:612
#define COMM_NONBLOCKING
Definition: Connection.h:46
StoreEntry * entry
Definition: ServerBump.h:54
static const CharacterSet ALPHA
Definition: CharacterSet.h:76
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition: Address.cc:802
const Value * get(const Key &)
Definition: ClpMap.h:176
class AccessLogEntry::HttpDetails http
int opt_no_daemon
acl_access * stats_collection
Definition: SquidConfig.h:373
virtual void endingShutdown()
@ METHOD_OPTIONS
Definition: MethodType.h:31
void startPinnedConnectionMonitoring()
void finishDechunkingRequest(bool withSuccess)
put parsed content into input buffer and clean up
void stopReceiving(const char *error)
note request receiving error and close as soon as we write the response
static bool Enabled(const int section, const int level)
whether debugging the given section and the given level produces output
Definition: Debug.h:75
SBuf & chop(size_type pos, size_type n=npos)
Definition: SBuf.cc:540
void clientStreamDetach(clientStreamNode *thisObject, ClientHttpRequest *http)
class AccessLogEntry::IcpDetails icp
int HttpSockets[MAXTCPLISTENPORTS]
Definition: PortCfg.cc:25
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
@ ERR_INVALID_REQ
Definition: err_type.h:41
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
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:97
@ SIBLING_HIT
Definition: hier_code.h:15
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:447
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:399
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:452
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()
@ ICP_INVALID
Definition: icp_opcode.h:15
Ssl::CertSignAlgorithm signAlgorithm
The signing algorithm to use.
Definition: client_side.h:448
unsigned short initial
@ bumpServerFirst
Definition: support.h:136
bool needProxyProtocolHeader_
whether PROXY protocol header is still expected
Definition: client_side.h:421
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:186
uint64_t bodySize() const
Definition: BodyPipe.cc:161
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)
@ algSignTrusted
Definition: gadgets.h:150
SBuf consume(size_type n=npos)
Definition: SBuf.cc:491
iterator end()
void StartListening(int sock_type, int proto, const Comm::ConnectionPointer &listenConn, FdNoteId fdNote, AsyncCall::Pointer &callback)
virtual void handleReply(HttpReply *header, StoreIOBuffer receivedData)=0
@ DISABLE_PMTU_ALWAYS
Definition: enums.h:233
Ssl::BumpMode sslBumpMode
ssl_bump decision (Ssl::bumpEnd if n/a).
Definition: client_side.h:288
ICP probing of cache_peers during peer selection.
Definition: PingData.h:25
#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:127
SBuf vary_headers
Definition: MemObject.h:204
sslproxy_cert_adapt * cert_adapt
Definition: SquidConfig.h:525
const EVP_MD * DefaultSignHash
Definition: support.cc:43
void clientSocketRecipient(clientStreamNode *node, ClientHttpRequest *http, HttpReply *rep, StoreIOBuffer receivedData)
Definition: client_side.cc:799
@ scNotImplemented
Definition: StatusCode.h:72
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:433
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
size_t count() const
how many requests are currently pipelined
Definition: Pipeline.h:53
const Acl::Answer & fastCheck()
Definition: Checklist.cc:336
@ algSignEnd
Definition: gadgets.h:150
@ LOG_TAG_NONE
Definition: LogTags.h:23
#define HTTP_REQBUF_SZ
Definition: defines.h:216
@ srcHttp
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:156
clientStreamNode * getClientReplyContext() const
Definition: Stream.cc:549
CachePeer * getPeer() const
Definition: Connection.cc:105
static char * prepareAcceleratedURL(ConnStateData *conn, const Http1::RequestParserPointer &hp)
static const CharacterSet HEXDIG
Definition: CharacterSet.h:88
int64_t contentLen() const
Definition: Store.h:253
void configureUnconfiguredSslContext(Security::ContextPointer &, Ssl::CertSignAlgorithm signAlgorithm, AnyP::PortCfg &)
Definition: support.cc:844
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: ClpMap.h:40
Definition: Xaction.cc:47
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:157
acl_access * ssl_bump
Definition: SquidConfig.h:392
AccessLogEntry::Pointer al
access.log entry
@ FIRST_PARENT_MISS
Definition: hier_code.h:20
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:394
err_type
Definition: err_type.h:12
@ METHOD_CONNECT
Definition: MethodType.h:29
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
void stopSending(const char *error)
note response sending error and close as soon as we read the request
Definition: client_side.cc:980
@ ERR_UNSUP_REQ
Definition: err_type.h:42
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
@ LOG_TCP_REFRESH_UNMODIFIED
Definition: LogTags.h:26
@ srcFtp
ftp_port or FTP server
Definition: Message.h:40
virtual int pipelinePrefetchMax() const
returning N allows a pipeline of 1+N requests (see pipeline_prefetch)
int tvSubMsec(struct timeval, struct timeval)
Definition: time.cc:37
Ip::Address remote
Definition: Connection.h:159
SBuf tlsConnectHostOrIp
The TLS server host name appears in CONNECT request or the server ip address for the intercepted requ...
Definition: client_side.h:438
NotePairs::Pointer notes()
bool timedout
_TIMEDOUT: terminated due to a lifetime or I/O timeout
Definition: LogTags.h:73
@ scRequestHeaderFieldsTooLarge
Definition: StatusCode.h:69
TlsDetails::Pointer details
TLS handshake meta info. Never nil.
Definition: Handshake.h:77
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
void clientOpenListenSockets(void)
void comm_reset_close(const Comm::ConnectionPointer &conn)
Definition: comm.cc:808
struct ConnStateData::@40 pinning
int conn
the current server connection FD
Definition: Transport.cc:26
const char * dash_str
#define assert(EX)
Definition: assert.h:19