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 mustReplyToOptions = false;
1611  bool expectBody = false;
1612 
1613  // We already have the request parsed and checked, so we
1614  // only need to go through the final body/conn setup to doCallouts().
1615  assert(http->request);
1617 
1618  // temporary hack to avoid splitting this huge function with sensitive code
1619  const bool isFtp = !hp;
1620 
1621  // Some blobs below are still HTTP-specific, but we would have to rewrite
1622  // this entire function to remove them from the FTP code path. Connection
1623  // setup and body_pipe preparation blobs are needed for FTP.
1624 
1625  request->manager(conn, http->al);
1626 
1627  request->flags.accelerated = http->flags.accel;
1628  request->flags.sslBumped=conn->switchedToHttps();
1629  // TODO: decouple http->flags.accel from request->flags.sslBumped
1630  request->flags.noDirect = (request->flags.accelerated && !request->flags.sslBumped) ?
1631  !conn->port->allow_direct : 0;
1632  request->sources |= isFtp ? Http::Message::srcFtp :
1633  ((request->flags.sslBumped || conn->port->transport.protocol == AnyP::PROTO_HTTPS) ? Http::Message::srcHttps : Http::Message::srcHttp);
1634 #if USE_AUTH
1635  if (request->flags.sslBumped) {
1636  if (conn->getAuth() != NULL)
1637  request->auth_user_request = conn->getAuth();
1638  }
1639 #endif
1640 
1641  if (internalCheck(request->url.path())) {
1642  if (internalHostnameIs(request->url.host()) && request->url.port() == getMyPort()) {
1643  debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true));
1644  http->flags.internal = true;
1646  debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (global_internal_static on)");
1647  request->url.setScheme(AnyP::PROTO_HTTP, "http");
1648  request->url.host(internalHostname());
1649  request->url.port(getMyPort());
1650  http->flags.internal = true;
1651  http->setLogUriToRequestUri();
1652  } else
1653  debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (not this proxy)");
1654  }
1655 
1656  request->flags.internal = http->flags.internal;
1657 
1658  if (!isFtp) {
1659  // XXX: for non-HTTP messages instantiate a different Http::Message child type
1660  // for now Squid only supports HTTP requests
1661  const AnyP::ProtocolVersion &http_ver = hp->messageProtocol();
1662  assert(request->http_ver.protocol == http_ver.protocol);
1663  request->http_ver.major = http_ver.major;
1664  request->http_ver.minor = http_ver.minor;
1665  }
1666 
1667  const auto unsupportedTe = request->header.unsupportedTe();
1668 
1669  mustReplyToOptions = (request->method == Http::METHOD_OPTIONS) &&
1670  (request->header.getInt64(Http::HdrType::MAX_FORWARDS) == 0);
1671  if (!urlCheckRequest(request.getRaw()) || mustReplyToOptions || unsupportedTe) {
1673  conn->quitAfterError(request.getRaw());
1674  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1675  assert (repContext);
1677  conn, request.getRaw(), nullptr, nullptr);
1678  assert(context->http->out.offset == 0);
1679  context->pullData();
1681  return;
1682  }
1683 
1684  const auto chunked = request->header.chunked();
1685  if (!chunked && !clientIsContentLengthValid(request.getRaw())) {
1687  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1688  assert (repContext);
1689  conn->quitAfterError(request.getRaw());
1690  repContext->setReplyToError(ERR_INVALID_REQ,
1692  conn, request.getRaw(), nullptr, nullptr);
1693  assert(context->http->out.offset == 0);
1694  context->pullData();
1696  return;
1697  }
1698 
1699  clientSetKeepaliveFlag(http);
1700  // Let tunneling code be fully responsible for CONNECT requests
1701  if (http->request->method == Http::METHOD_CONNECT) {
1702  context->mayUseConnection(true);
1703  conn->flags.readMore = false;
1704  }
1705 
1706 #if USE_OPENSSL
1707  if (conn->switchedToHttps() && conn->serveDelayedError(context)) {
1709  return;
1710  }
1711 #endif
1712 
1713  /* Do we expect a request-body? */
1714  expectBody = chunked || request->content_length > 0;
1715  if (!context->mayUseConnection() && expectBody) {
1716  request->body_pipe = conn->expectRequestBody(
1717  chunked ? -1 : request->content_length);
1718 
1719  /* Is it too large? */
1720  if (!chunked && // if chunked, we will check as we accumulate
1723  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1724  assert (repContext);
1725  conn->quitAfterError(request.getRaw());
1726  repContext->setReplyToError(ERR_TOO_BIG,
1728  conn, http->request, nullptr, nullptr);
1729  assert(context->http->out.offset == 0);
1730  context->pullData();
1732  return;
1733  }
1734 
1735  if (!isFtp) {
1736  // We may stop producing, comm_close, and/or call setReplyToError()
1737  // below, so quit on errors to avoid http->doCallouts()
1738  if (!conn->handleRequestBodyData()) {
1740  return;
1741  }
1742 
1743  if (!request->body_pipe->productionEnded()) {
1744  debugs(33, 5, "need more request body");
1745  context->mayUseConnection(true);
1746  assert(conn->flags.readMore);
1747  }
1748  }
1749  }
1750 
1751  http->calloutContext = new ClientRequestContext(http);
1752 
1753  http->doCallouts();
1754 
1756 }
1757 
1758 int
1760 {
1761  // TODO: Support pipelined requests through pinned connections.
1762  if (pinning.pinned)
1763  return 0;
1765 }
1766 
1772 bool
1774 {
1775  const int existingRequestCount = pipeline.count();
1776 
1777  // default to the configured pipeline size.
1778  // add 1 because the head of pipeline is counted in concurrent requests and not prefetch queue
1779 #if USE_OPENSSL
1780  const int internalRequest = (transparent() && sslBumpMode == Ssl::bumpSplice) ? 1 : 0;
1781 #else
1782  const int internalRequest = 0;
1783 #endif
1784  const int concurrentRequestLimit = pipelinePrefetchMax() + 1 + internalRequest;
1785 
1786  // when queue filled already we can't add more.
1787  if (existingRequestCount >= concurrentRequestLimit) {
1788  debugs(33, 3, clientConnection << " max concurrent requests reached (" << concurrentRequestLimit << ")");
1789  debugs(33, 5, clientConnection << " deferring new request until one is done");
1790  return true;
1791  }
1792 
1793  return false;
1794 }
1795 
1801 bool
1803 {
1805  return proxyProtocolError("PROXY client not permitted by default ACL");
1806 
1810  ch.conn(this);
1811 
1812  if (!ch.fastCheck().allowed())
1813  return proxyProtocolError("PROXY client not permitted by ACLs");
1814 
1815  return true;
1816 }
1817 
1823 bool
1825 {
1826  if (msg) {
1827  // This is important to know, but maybe not so much that flooding the log is okay.
1828 #if QUIET_PROXY_PROTOCOL
1829  // display the first of every 32 occurrences at level 1, the others at level 2.
1830  static uint8_t hide = 0;
1831  debugs(33, (hide++ % 32 == 0 ? DBG_IMPORTANT : 2), msg << " from " << clientConnection);
1832 #else
1833  debugs(33, DBG_IMPORTANT, msg << " from " << clientConnection);
1834 #endif
1835  mustStop(msg);
1836  }
1837  return false;
1838 }
1839 
1844 bool
1846 {
1847  try {
1848  const auto parsed = ProxyProtocol::Parse(inBuf);
1849  proxyProtocolHeader_ = parsed.header;
1851  inBuf.consume(parsed.size);
1852  needProxyProtocolHeader_ = false;
1853  if (proxyProtocolHeader_->hasForwardedAddresses()) {
1854  clientConnection->local = proxyProtocolHeader_->destinationAddress;
1855  clientConnection->remote = proxyProtocolHeader_->sourceAddress;
1857  clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
1858  debugs(33, 5, "PROXY/" << proxyProtocolHeader_->version() << " upgrade: " << clientConnection);
1859  }
1860  } catch (const Parser::BinaryTokenizer::InsufficientInput &) {
1861  debugs(33, 3, "PROXY protocol: waiting for more than " << inBuf.length() << " bytes");
1862  return false;
1863  } catch (const std::exception &e) {
1864  return proxyProtocolError(e.what());
1865  }
1866  return true;
1867 }
1868 
1869 void
1871 {
1872  if (receivedFirstByte_)
1873  return;
1874 
1875  receivedFirstByte_ = true;
1876  // Set timeout to Config.Timeout.request
1878  AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
1879  TimeoutDialer, this, ConnStateData::requestTimeout);
1881 }
1882 
1888 bool
1890 {
1891  bool parsed_req = false;
1892 
1893  debugs(33, 5, HERE << clientConnection << ": attempting to parse");
1894 
1895  // Loop while we have read bytes that are not needed for producing the body
1896  // On errors, bodyPipe may become nil, but readMore will be cleared
1897  while (!inBuf.isEmpty() && !bodyPipe && flags.readMore) {
1898 
1899  // Prohibit concurrent requests when using a pinned to-server connection
1900  // because our Client classes do not support request pipelining.
1901  if (pinning.pinned && !pinning.readHandler) {
1902  debugs(33, 3, clientConnection << " waits for busy " << pinning.serverConnection);
1903  break;
1904  }
1905 
1906  /* Limit the number of concurrent requests */
1908  break;
1909 
1910  // try to parse the PROXY protocol header magic bytes
1912  if (!parseProxyProtocolHeader())
1913  break;
1914 
1915  // we have been waiting for PROXY to provide client-IP
1916  // for some lookups, ie rDNS and IDENT.
1918 
1919  // Done with PROXY protocol which has cleared preservingClientData_.
1920  // If the next protocol supports on_unsupported_protocol, then its
1921  // parseOneRequest() must reset preservingClientData_.
1923  }
1924 
1925  if (Http::StreamPointer context = parseOneRequest()) {
1926  debugs(33, 5, clientConnection << ": done parsing a request");
1927 
1928  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "clientLifetimeTimeout",
1929  CommTimeoutCbPtrFun(clientLifetimeTimeout, context->http));
1931 
1932  context->registerWithConn();
1933 
1934 #if USE_OPENSSL
1935  if (switchedToHttps())
1937 #endif
1938 
1939  processParsedRequest(context);
1940 
1941  parsed_req = true; // XXX: do we really need to parse everything right NOW ?
1942 
1943  if (context->mayUseConnection()) {
1944  debugs(33, 3, HERE << "Not parsing new requests, as this request may need the connection");
1945  break;
1946  }
1947  } else {
1948  debugs(33, 5, clientConnection << ": not enough request data: " <<
1949  inBuf.length() << " < " << Config.maxRequestHeaderSize);
1951  break;
1952  }
1953  }
1954 
1955  /* XXX where to 'finish' the parsing pass? */
1956  return parsed_req;
1957 }
1958 
1959 void
1961 {
1962 #if USE_OPENSSL
1963  if (parsingTlsHandshake) {
1965  return;
1966  }
1967 #endif
1968 
1969  /* Process next request */
1970  if (pipeline.empty())
1971  fd_note(clientConnection->fd, "Reading next request");
1972 
1973  if (!clientParseRequests()) {
1974  if (!isOpen())
1975  return;
1976  /*
1977  * If the client here is half closed and we failed
1978  * to parse a request, close the connection.
1979  * The above check with connFinishedWithConn() only
1980  * succeeds _if_ the buffer is empty which it won't
1981  * be if we have an incomplete request.
1982  * XXX: This duplicates ConnStateData::kick
1983  */
1985  debugs(33, 5, clientConnection << ": half-closed connection, no completed request parsed, connection closing.");
1987  return;
1988  }
1989  }
1990 
1991  if (!isOpen())
1992  return;
1993 
1995 }
1996 
2003 bool
2005 {
2006  // if we are reading a body, stuff data into the body pipe
2007  if (bodyPipe != NULL)
2008  return handleRequestBodyData();
2009  return true;
2010 }
2011 
2019 bool
2021 {
2022  assert(bodyPipe != NULL);
2023 
2024  if (bodyParser) { // chunked encoding
2025  if (const err_type error = handleChunkedRequestBody()) {
2027  return false;
2028  }
2029  } else { // identity encoding
2030  debugs(33,5, HERE << "handling plain request body for " << clientConnection);
2031  const size_t putSize = bodyPipe->putMoreData(inBuf.c_str(), inBuf.length());
2032  if (putSize > 0)
2033  consumeInput(putSize);
2034 
2035  if (!bodyPipe->mayNeedMoreData()) {
2036  // BodyPipe will clear us automagically when we produced everything
2037  bodyPipe = NULL;
2038  }
2039  }
2040 
2041  if (!bodyPipe) {
2042  debugs(33,5, HERE << "produced entire request body for " << clientConnection);
2043 
2044  if (const char *reason = stoppedSending()) {
2045  /* we've finished reading like good clients,
2046  * now do the close that initiateClose initiated.
2047  */
2048  debugs(33, 3, HERE << "closing for earlier sending error: " << reason);
2050  return false;
2051  }
2052  }
2053 
2054  return true;
2055 }
2056 
2058 err_type
2060 {
2061  debugs(33, 7, "chunked from " << clientConnection << ": " << inBuf.length());
2062 
2063  try { // the parser will throw on errors
2064 
2065  if (inBuf.isEmpty()) // nothing to do
2066  return ERR_NONE;
2067 
2068  BodyPipeCheckout bpc(*bodyPipe);
2070  const bool parsed = bodyParser->parse(inBuf);
2071  inBuf = bodyParser->remaining(); // sync buffers
2072  bpc.checkIn();
2073 
2074  // dechunk then check: the size limit applies to _dechunked_ content
2076  return ERR_TOO_BIG;
2077 
2078  if (parsed) {
2080  Must(!bodyPipe);
2081  return ERR_NONE; // nil bodyPipe implies body end for the caller
2082  }
2083 
2084  // if chunk parser needs data, then the body pipe must need it too
2086 
2087  // if parser needs more space and we can consume nothing, we will stall
2089  } catch (...) { // TODO: be more specific
2090  debugs(33, 3, HERE << "malformed chunks" << bodyPipe->status());
2091  return ERR_INVALID_REQ;
2092  }
2093 
2094  debugs(33, 7, HERE << "need more chunked data" << *bodyPipe->status());
2095  return ERR_NONE;
2096 }
2097 
2099 void
2101 {
2102  finishDechunkingRequest(false);
2103 
2104  // XXX: The code below works if we fail during initial request parsing,
2105  // but if we fail when the server connection is used already, the server may send
2106  // us its response too, causing various assertions. How to prevent that?
2107 #if WE_KNOW_HOW_TO_SEND_ERRORS
2108  Http::StreamPointer context = pipeline.front();
2109  if (context != NULL && !context->http->out.offset) { // output nothing yet
2110  clientStreamNode *node = context->getClientReplyContext();
2111  clientReplyContext *repContext = dynamic_cast<clientReplyContext*>(node->data.getRaw());
2112  assert(repContext);
2113  const Http::StatusCode scode = (error == ERR_TOO_BIG) ?
2114  Http::scPayloadTooLarge : HTTP_BAD_REQUEST;
2115  repContext->setReplyToError(error, scode,
2116  repContext->http->request->method,
2117  repContext->http->uri,
2118  CachePeer,
2119  repContext->http->request,
2120  inBuf, NULL);
2121  context->pullData();
2122  } else {
2123  // close or otherwise we may get stuck as nobody will notice the error?
2125  }
2126 #else
2127  debugs(33, 3, HERE << "aborting chunked request without error " << error);
2129 #endif
2130  flags.readMore = false;
2131 }
2132 
2133 void
2135 {
2136  // request reader may get stuck waiting for space if nobody consumes body
2137  if (bodyPipe != NULL)
2139 
2140  // kids extend
2141 }
2142 
2144 void
2146 {
2147  if (!Comm::IsConnOpen(io.conn))
2148  return;
2149 
2152  return;
2153 
2154  /*
2155  * Just close the connection to not confuse browsers
2156  * using persistent connections. Some browsers open
2157  * a connection and then do not use it until much
2158  * later (presumeably because the request triggering
2159  * the open has already been completed on another
2160  * connection)
2161  */
2162  debugs(33, 3, "requestTimeout: FD " << io.fd << ": lifetime is expired.");
2163  io.conn->close();
2164 }
2165 
2166 static void
2168 {
2169  ClientHttpRequest *http = static_cast<ClientHttpRequest *>(io.data);
2170  debugs(33, DBG_IMPORTANT, "WARNING: Closing client connection due to lifetime timeout");
2171  debugs(33, DBG_IMPORTANT, "\t" << http->uri);
2172  if (const auto conn = http->getConn())
2173  conn->pipeline.terminateAll(ETIMEDOUT);
2174  if (Comm::IsConnOpen(io.conn))
2175  io.conn->close();
2176 }
2177 
2179  AsyncJob("ConnStateData"), // kids overwrite
2180  Server(xact)
2181 #if USE_OPENSSL
2182  , tlsParser(Security::HandshakeParser::fromClient)
2183 #endif
2184 {
2185  // store the details required for creating more MasterXaction objects as new requests come in
2186  log_addr = xact->tcpClient->remote;
2188 
2189  // register to receive notice of Squid signal events
2190  // which may affect long persisting client connections
2191  registerRunner();
2192 }
2193 
2194 void
2196 {
2199 
2200  if (port->disable_pmtu_discovery != DISABLE_PMTU_OFF &&
2201  (transparent() || port->disable_pmtu_discovery == DISABLE_PMTU_ALWAYS)) {
2202 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
2203  int i = IP_PMTUDISC_DONT;
2204  if (setsockopt(clientConnection->fd, SOL_IP, IP_MTU_DISCOVER, &i, sizeof(i)) < 0) {
2205  int xerrno = errno;
2206  debugs(33, 2, "WARNING: Path MTU discovery disabling failed on " << clientConnection << " : " << xstrerr(xerrno));
2207  }
2208 #else
2209  static bool reported = false;
2210 
2211  if (!reported) {
2212  debugs(33, DBG_IMPORTANT, "NOTICE: Path MTU discovery disabling is not supported on your platform.");
2213  reported = true;
2214  }
2215 #endif
2216  }
2217 
2219  AsyncCall::Pointer call = JobCallback(33, 5, Dialer, this, ConnStateData::connStateClosed);
2221 
2222  needProxyProtocolHeader_ = port->flags.proxySurrogate;
2224  if (!proxyProtocolValidateClient()) // will close the connection on failure
2225  return;
2226  } else
2228 
2229  // requires needProxyProtocolHeader_ which is initialized above
2231 }
2232 
2233 void
2235 {
2236  if (Config.onoff.log_fqdn)
2238 
2239 #if USE_IDENT
2240  if (Ident::TheConfig.identLookup) {
2241  ACLFilledChecklist identChecklist(Ident::TheConfig.identLookup, NULL, NULL);
2242  identChecklist.src_addr = clientConnection->remote;
2243  identChecklist.my_addr = clientConnection->local;
2244  if (identChecklist.fastCheck().allowed())
2246  }
2247 #endif
2248 
2250 
2251 #if USE_DELAY_POOLS
2252  fd_table[clientConnection->fd].clientInfo = NULL;
2253 
2254  if (!Config.onoff.client_db)
2255  return; // client delay pools require client_db
2256 
2257  const auto &pools = ClientDelayPools::Instance()->pools;
2258  if (pools.size()) {
2260 
2261  // TODO: we check early to limit error response bandwidth but we
2262  // should recheck when we can honor delay_pool_uses_indirect
2263  // TODO: we should also pass the port details for myportname here.
2266 
2267  for (unsigned int pool = 0; pool < pools.size(); ++pool) {
2268 
2269  /* pools require explicit 'allow' to assign a client into them */
2270  if (pools[pool]->access) {
2271  ch.changeAcl(pools[pool]->access);
2272  auto answer = ch.fastCheck();
2273  if (answer.allowed()) {
2274 
2275  /* request client information from db after we did all checks
2276  this will save hash lookup if client failed checks */
2278  assert(cli);
2279 
2280  /* put client info in FDE */
2281  fd_table[clientConnection->fd].clientInfo = cli;
2282 
2283  /* setup write limiter for this request */
2284  const double burst = floor(0.5 +
2285  (pools[pool]->highwatermark * Config.ClientDelay.initial)/100.0);
2286  cli->setWriteLimiter(pools[pool]->rate, burst, pools[pool]->highwatermark);
2287  break;
2288  } else {
2289  debugs(83, 4, HERE << "Delay pool " << pool << " skipped because ACL " << answer);
2290  }
2291  }
2292  }
2293  }
2294 #endif
2295 
2296  // kids must extend to actually start doing something (e.g., reading)
2297 }
2298 
2300 void
2302 {
2303  MasterXaction::Pointer xact = params.xaction;
2304  AnyP::PortCfgPointer s = xact->squidPort;
2305 
2306  // NP: it is possible the port was reconfigured when the call or accept() was queued.
2307 
2308  if (params.flag != Comm::OK) {
2309  // Its possible the call was still queued when the client disconnected
2310  debugs(33, 2, s->listenConn << ": accept failure: " << xstrerr(params.xerrno));
2311  return;
2312  }
2313 
2314  debugs(33, 4, params.conn << ": accepted");
2315  fd_note(params.conn->fd, "client http connect");
2316 
2317  if (s->tcp_keepalive.enabled)
2318  commSetTcpKeepalive(params.conn->fd, s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
2319 
2321 
2322  // Socket is ready, setup the connection manager to start using it
2323  auto *srv = Http::NewServer(xact);
2324  AsyncJob::Start(srv); // usually async-calls readSomeData()
2325 }
2326 
2328 static bool
2330 {
2331  const auto conn = connState->clientConnection;
2332  if (Security::CreateServerSession(ctx, conn, connState->port->secure, "client https start")) {
2333  debugs(33, 5, "will negotiate TLS on " << conn);
2334  return true;
2335  }
2336 
2337  debugs(33, DBG_IMPORTANT, "ERROR: could not create TLS server context for " << conn);
2338  conn->close();
2339  return false;
2340 }
2341 
2348 static int
2350 {
2351  // TODO: maybe throw instead of returning -1
2352  // see https://github.com/squid-cache/squid/pull/81#discussion_r153053278
2353  int fd = conn->clientConnection->fd;
2354  auto session = fd_table[fd].ssl.get();
2355 
2356  errno = 0;
2357 
2358 #if USE_OPENSSL
2359  const auto ret = SSL_accept(session);
2360  if (ret > 0)
2361  return 1;
2362 
2363  const int xerrno = errno;
2364  const auto ssl_error = SSL_get_error(session, ret);
2365 
2366  switch (ssl_error) {
2367 
2368  case SSL_ERROR_WANT_READ:
2369  Comm::SetSelect(fd, COMM_SELECT_READ, callback, (callback ? conn : nullptr), 0);
2370  return 0;
2371 
2372  case SSL_ERROR_WANT_WRITE:
2373  Comm::SetSelect(fd, COMM_SELECT_WRITE, callback, (callback ? conn : nullptr), 0);
2374  return 0;
2375 
2376  case SSL_ERROR_SYSCALL:
2377  if (ret == 0) {
2378  debugs(83, 2, "Error negotiating SSL connection on FD " << fd << ": Aborted by client: " << ssl_error);
2379  } else {
2380  debugs(83, (xerrno == ECONNRESET) ? 1 : 2, "Error negotiating SSL connection on FD " << fd << ": " <<
2381  (xerrno == 0 ? Security::ErrorString(ssl_error) : xstrerr(xerrno)));
2382  }
2383  break;
2384 
2385  case SSL_ERROR_ZERO_RETURN:
2386  debugs(83, DBG_IMPORTANT, "Error negotiating SSL connection on FD " << fd << ": Closed by client");
2387  break;
2388 
2389  default:
2390  debugs(83, DBG_IMPORTANT, "Error negotiating SSL connection on FD " <<
2391  fd << ": " << Security::ErrorString(ssl_error) <<
2392  " (" << ssl_error << "/" << ret << ")");
2393  }
2394 
2395 #elif USE_GNUTLS
2396 
2397  const auto x = gnutls_handshake(session);
2398  if (x == GNUTLS_E_SUCCESS)
2399  return 1;
2400 
2401  if (gnutls_error_is_fatal(x)) {
2402  debugs(83, 2, "Error negotiating TLS on " << conn->clientConnection << ": Aborted by client: " << Security::ErrorString(x));
2403 
2404  } else if (x == GNUTLS_E_INTERRUPTED || x == GNUTLS_E_AGAIN) {
2405  const auto ioAction = (gnutls_record_get_direction(session)==0 ? COMM_SELECT_READ : COMM_SELECT_WRITE);
2406  Comm::SetSelect(fd, ioAction, callback, (callback ? conn : nullptr), 0);
2407  return 0;
2408  }
2409 
2410 #else
2411  // Performing TLS handshake should never be reachable without a TLS/SSL library.
2412  (void)session; // avoid compiler and static analysis complaints
2413  fatal("FATAL: HTTPS not supported by this Squid.");
2414 #endif
2415 
2416  return -1;
2417 }
2418 
2420 static void
2421 clientNegotiateSSL(int fd, void *data)
2422 {
2424 
2425  const int ret = tlsAttemptHandshake(conn, clientNegotiateSSL);
2426  if (ret <= 0) {
2427  if (ret < 0) // An error
2428  conn->clientConnection->close();
2429  return;
2430  }
2431 
2432  Security::SessionPointer session(fd_table[fd].ssl);
2433 
2434 #if USE_OPENSSL
2435  if (Security::SessionIsResumed(session)) {
2436  debugs(83, 2, "Session " << SSL_get_session(session.get()) <<
2437  " reused on FD " << fd << " (" << fd_table[fd].ipaddr <<
2438  ":" << (int)fd_table[fd].remote_port << ")");
2439  } else {
2440  if (Debug::Enabled(83, 4)) {
2441  /* Write out the SSL session details.. actually the call below, but
2442  * OpenSSL headers do strange typecasts confusing GCC.. */
2443  /* PEM_write_SSL_SESSION(debug_log, SSL_get_session(ssl)); */
2444 #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00908000L
2445  PEM_ASN1_write(reinterpret_cast<i2d_of_void *>(i2d_SSL_SESSION),
2446  PEM_STRING_SSL_SESSION, debug_log,
2447  reinterpret_cast<char *>(SSL_get_session(session.get())),
2448  nullptr, nullptr, 0, nullptr, nullptr);
2449 
2450 #elif (ALLOW_ALWAYS_SSL_SESSION_DETAIL == 1)
2451 
2452  /* When using gcc 3.3.x and OpenSSL 0.9.7x sometimes a compile error can occur here.
2453  * This is caused by an unpredicatble gcc behaviour on a cast of the first argument
2454  * of PEM_ASN1_write(). For this reason this code section is disabled. To enable it,
2455  * define ALLOW_ALWAYS_SSL_SESSION_DETAIL=1.
2456  * Because there are two possible usable cast, if you get an error here, try the other
2457  * commented line. */
2458 
2459  PEM_ASN1_write((int(*)())i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2460  debug_log,
2461  reinterpret_cast<char *>(SSL_get_session(session.get())),
2462  nullptr, nullptr, 0, nullptr, nullptr);
2463  /* PEM_ASN1_write((int(*)(...))i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2464  debug_log,
2465  reinterpret_cast<char *>(SSL_get_session(session.get())),
2466  nullptr, nullptr, 0, nullptr, nullptr);
2467  */
2468 #else
2469  debugs(83, 4, "With " OPENSSL_VERSION_TEXT ", session details are available only defining ALLOW_ALWAYS_SSL_SESSION_DETAIL=1 in the source.");
2470 
2471 #endif
2472  /* Note: This does not automatically fflush the log file.. */
2473  }
2474 
2475  debugs(83, 2, "New session " << SSL_get_session(session.get()) <<
2476  " on FD " << fd << " (" << fd_table[fd].ipaddr << ":" <<
2477  fd_table[fd].remote_port << ")");
2478  }
2479 #else
2480  debugs(83, 2, "TLS session reuse not yet implemented.");
2481 #endif
2482 
2483  // Connection established. Retrieve TLS connection parameters for logging.
2484  conn->clientConnection->tlsNegotiations()->retrieveNegotiatedInfo(session);
2485 
2486 #if USE_OPENSSL
2487  X509 *client_cert = SSL_get_peer_certificate(session.get());
2488 
2489  if (client_cert) {
2490  debugs(83, 3, "FD " << fd << " client certificate: subject: " <<
2491  X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0));
2492 
2493  debugs(83, 3, "FD " << fd << " client certificate: issuer: " <<
2494  X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0));
2495 
2496  X509_free(client_cert);
2497  } else {
2498  debugs(83, 5, "FD " << fd << " has no client certificate.");
2499  }
2500 #else
2501  debugs(83, 2, "Client certificate requesting not yet implemented.");
2502 #endif
2503 
2504  conn->readSomeData();
2505 }
2506 
2511 static void
2513 {
2514  assert(connState);
2515  const Comm::ConnectionPointer &details = connState->clientConnection;
2516 
2517  if (!ctx || !httpsCreate(connState, ctx))
2518  return;
2519 
2521  AsyncCall::Pointer timeoutCall = JobCallback(33, 5, TimeoutDialer,
2522  connState, ConnStateData::requestTimeout);
2523  commSetConnTimeout(details, Config.Timeout.request, timeoutCall);
2524 
2525  Comm::SetSelect(details->fd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
2526 }
2527 
2528 #if USE_OPENSSL
2529 
2532 static void
2534 {
2535  ConnStateData *connState = (ConnStateData *) data;
2536 
2537  // if the connection is closed or closing, just return.
2538  if (!connState->isOpen())
2539  return;
2540 
2541  if (answer.allowed()) {
2542  debugs(33, 2, "sslBump action " << Ssl::bumpMode(answer.kind) << "needed for " << connState->clientConnection);
2543  connState->sslBumpMode = static_cast<Ssl::BumpMode>(answer.kind);
2544  } else {
2545  debugs(33, 3, "sslBump not needed for " << connState->clientConnection);
2546  connState->sslBumpMode = Ssl::bumpSplice;
2547  }
2548 
2549  if (connState->sslBumpMode == Ssl::bumpTerminate) {
2550  connState->clientConnection->close();
2551  return;
2552  }
2553 
2554  if (!connState->fakeAConnectRequest("ssl-bump", connState->inBuf))
2555  connState->clientConnection->close();
2556 }
2557 #endif
2558 
2560 static void
2562 {
2563  MasterXaction::Pointer xact = params.xaction;
2564  const AnyP::PortCfgPointer s = xact->squidPort;
2565 
2566  // NP: it is possible the port was reconfigured when the call or accept() was queued.
2567 
2568  if (params.flag != Comm::OK) {
2569  // Its possible the call was still queued when the client disconnected
2570  debugs(33, 2, "httpsAccept: " << s->listenConn << ": accept failure: " << xstrerr(params.xerrno));
2571  return;
2572  }
2573 
2574  debugs(33, 4, HERE << params.conn << " accepted, starting SSL negotiation.");
2575  fd_note(params.conn->fd, "client https connect");
2576 
2577  if (s->tcp_keepalive.enabled) {
2578  commSetTcpKeepalive(params.conn->fd, s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
2579  }
2581 
2582  // Socket is ready, setup the connection manager to start using it
2583  auto *srv = Https::NewServer(xact);
2584  AsyncJob::Start(srv); // usually async-calls postHttpsAccept()
2585 }
2586 
2587 void
2589 {
2590  if (port->flags.tunnelSslBumping) {
2591 #if USE_OPENSSL
2592  debugs(33, 5, "accept transparent connection: " << clientConnection);
2593 
2594  if (!Config.accessList.ssl_bump) {
2596  return;
2597  }
2598 
2601  // Create a fake HTTP request and ALE for the ssl_bump ACL check,
2602  // using tproxy/intercept provided destination IP and port.
2603  // XXX: Merge with subsequent fakeAConnectRequest(), buildFakeRequest().
2604  // XXX: Do this earlier (e.g., in Http[s]::One::Server constructor).
2605  HttpRequest *request = new HttpRequest(mx);
2606  static char ip[MAX_IPSTRLEN];
2608  request->url.host(clientConnection->local.toStr(ip, sizeof(ip)));
2610  request->myportname = port->name;
2611  const AccessLogEntry::Pointer connectAle = new AccessLogEntry;
2612  CodeContext::Reset(connectAle);
2613  // TODO: Use these request/ALE when waiting for new bumped transactions.
2614 
2616  acl_checklist->src_addr = clientConnection->remote;
2617  acl_checklist->my_addr = port->s;
2618  // Build a local AccessLogEntry to allow requiresAle() acls work
2619  acl_checklist->al = connectAle;
2620  acl_checklist->al->cache.start_time = current_time;
2621  acl_checklist->al->tcpClient = clientConnection;
2622  acl_checklist->al->cache.port = port;
2623  acl_checklist->al->cache.caddr = log_addr;
2624  acl_checklist->al->proxyProtocolHeader = proxyProtocolHeader_;
2625  HTTPMSGUNLOCK(acl_checklist->al->request);
2626  acl_checklist->al->request = request;
2627  HTTPMSGLOCK(acl_checklist->al->request);
2628  Http::StreamPointer context = pipeline.front();
2629  ClientHttpRequest *http = context ? context->http : nullptr;
2630  const char *log_uri = http ? http->log_uri : nullptr;
2631  acl_checklist->syncAle(request, log_uri);
2632  acl_checklist->nonBlockingCheck(httpsSslBumpAccessCheckDone, this);
2633 #else
2634  fatal("FATAL: SSL-Bump requires --with-openssl");
2635 #endif
2636  return;
2637  } else {
2638  httpsEstablish(this, port->secure.staticContext);
2639  }
2640 }
2641 
2642 #if USE_OPENSSL
2643 void
2645 {
2646  ConnStateData * state_data = (ConnStateData *)(data);
2647  state_data->sslCrtdHandleReply(reply);
2648 }
2649 
2650 void
2652 {
2653  if (!isOpen()) {
2654  debugs(33, 3, "Connection gone while waiting for ssl_crtd helper reply; helper reply:" << reply);
2655  return;
2656  }
2657 
2658  if (reply.result == Helper::BrokenHelper) {
2659  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply);
2660  } else if (!reply.other().hasContent()) {
2661  debugs(1, DBG_IMPORTANT, HERE << "\"ssl_crtd\" helper returned <NULL> reply.");
2662  } else {
2664  if (reply_message.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK) {
2665  debugs(33, 5, "Reply from ssl_crtd for " << tlsConnectHostOrIp << " is incorrect");
2666  } else {
2667  if (reply.result != Helper::Okay) {
2668  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply_message.getBody());
2669  } else {
2670  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " was successfully received from ssl_crtd");
2673  auto ssl = fd_table[clientConnection->fd].ssl.get();
2674  bool ret = Ssl::configureSSLUsingPkeyAndCertFromMemory(ssl, reply_message.getBody().c_str(), *port);
2675  if (!ret)
2676  debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
2677 
2680  } else {
2682  if (ctx && !sslBumpCertKey.isEmpty())
2684  getSslContextDone(ctx);
2685  }
2686  return;
2687  }
2688  }
2689  }
2692 }
2693 
2695 {
2697 
2698  const bool connectedOk = sslServerBump && sslServerBump->connectedOk();
2699  if (connectedOk) {
2700  if (X509 *mimicCert = sslServerBump->serverCert.get())
2701  certProperties.mimicCert.resetAndLock(mimicCert);
2702 
2706 
2707  for (sslproxy_cert_adapt *ca = Config.ssl_client.cert_adapt; ca != NULL; ca = ca->next) {
2708  // If the algorithm already set, then ignore it.
2709  if ((ca->alg == Ssl::algSetCommonName && certProperties.setCommonName) ||
2710  (ca->alg == Ssl::algSetValidAfter && certProperties.setValidAfter) ||
2711  (ca->alg == Ssl::algSetValidBefore && certProperties.setValidBefore) )
2712  continue;
2713 
2714  if (ca->aclList && checklist.fastCheck(ca->aclList).allowed()) {
2715  const char *alg = Ssl::CertAdaptAlgorithmStr[ca->alg];
2716  const char *param = ca->param;
2717 
2718  // For parameterless CN adaptation, use hostname from the
2719  // CONNECT request.
2720  if (ca->alg == Ssl::algSetCommonName) {
2721  if (!param)
2722  param = tlsConnectHostOrIp.c_str();
2723  certProperties.commonName = param;
2724  certProperties.setCommonName = true;
2725  } else if (ca->alg == Ssl::algSetValidAfter)
2726  certProperties.setValidAfter = true;
2727  else if (ca->alg == Ssl::algSetValidBefore)
2728  certProperties.setValidBefore = true;
2729 
2730  debugs(33, 5, HERE << "Matches certificate adaptation aglorithm: " <<
2731  alg << " param: " << (param ? param : "-"));
2732  }
2733  }
2734 
2735  certProperties.signAlgorithm = Ssl::algSignEnd;
2736  for (sslproxy_cert_sign *sg = Config.ssl_client.cert_sign; sg != NULL; sg = sg->next) {
2737  if (sg->aclList && checklist.fastCheck(sg->aclList).allowed()) {
2738  certProperties.signAlgorithm = (Ssl::CertSignAlgorithm)sg->alg;
2739  break;
2740  }
2741  }
2742  } else {// did not try to connect (e.g. client-first) or failed to connect
2743  // In case of an error while connecting to the secure server, use a
2744  // trusted certificate, with no mimicked fields and no adaptation
2745  // algorithms. There is nothing we can mimic, so we want to minimize the
2746  // number of warnings the user will have to see to get to the error page.
2747  // We will close the connection, so that the trust is not extended to
2748  // non-Squid content.
2749  certProperties.signAlgorithm = Ssl::algSignTrusted;
2750  }
2751 
2752  assert(certProperties.signAlgorithm != Ssl::algSignEnd);
2753 
2754  if (certProperties.signAlgorithm == Ssl::algSignUntrusted) {
2755  assert(port->secure.untrustedSigningCa.cert);
2756  certProperties.signWithX509.resetAndLock(port->secure.untrustedSigningCa.cert.get());
2757  certProperties.signWithPkey.resetAndLock(port->secure.untrustedSigningCa.pkey.get());
2758  } else {
2759  assert(port->secure.signingCa.cert.get());
2760  certProperties.signWithX509.resetAndLock(port->secure.signingCa.cert.get());
2761 
2762  if (port->secure.signingCa.pkey)
2763  certProperties.signWithPkey.resetAndLock(port->secure.signingCa.pkey.get());
2764  }
2765  signAlgorithm = certProperties.signAlgorithm;
2766 
2767  certProperties.signHash = Ssl::DefaultSignHash;
2768 }
2769 
2772 {
2773  debugs(33, 5, "Finding SSL certificate for " << cacheKey << " in cache");
2775  if (const auto ctx = ssl_ctx_cache ? ssl_ctx_cache->get(cacheKey) : nullptr) {
2776  if (Ssl::verifySslCertificate(*ctx, certProperties)) {
2777  debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is valid");
2778  return *ctx;
2779  } else {
2780  debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is out of date. Delete this certificate from cache");
2781  if (ssl_ctx_cache)
2782  ssl_ctx_cache->del(cacheKey);
2783  }
2784  }
2785  return Security::ContextPointer(nullptr);
2786 }
2787 
2788 void
2790 {
2792  if (!ssl_ctx_cache || !ssl_ctx_cache->add(cacheKey, ctx)) {
2793  // If it is not in storage delete after using. Else storage deleted it.
2794  fd_table[clientConnection->fd].html?amicTlsContext = ctx;
2795  }
2796 }
2797 
2798 void
2800 {
2801  // If we are called, then CONNECT has succeeded. Finalize it.
2802  if (auto xact = pipeline.front()) {
2803  if (xact->http && xact->http->request && xact->http->request->method == Http::METHOD_CONNECT)
2804  xact->finished();
2805  // cannot proceed with encryption if requests wait for plain responses
2806  Must(pipeline.empty());
2807  }
2808  /* careful: finished() above frees request, host, etc. */
2809 
2810  if (port->secure.generateHostCertificates) {
2811  Ssl::CertificateProperties certProperties;
2812  buildSslCertGenerationParams(certProperties);
2813 
2814  // Disable caching for bumpPeekAndSplice mode
2817  Ssl::InRamCertificateDbKey(certProperties, sslBumpCertKey);
2819 
2821  if (ctx) {
2822  getSslContextDone(ctx);
2823  return;
2824  }
2825  }
2826 
2827 #if USE_SSL_CRTD
2828  try {
2829  debugs(33, 5, HERE << "Generating SSL certificate for " << certProperties.commonName << " using ssl_crtd.");
2832  request_message.composeRequest(certProperties);
2833  debugs(33, 5, HERE << "SSL crtd request: " << request_message.compose().c_str());
2834  Ssl::Helper::Submit(request_message, sslCrtdHandleReplyWrapper, this);
2835  return;
2836  } catch (const std::exception &e) {
2837  debugs(33, DBG_IMPORTANT, "ERROR: Failed to compose ssl_crtd " <<
2838  "request for " << certProperties.commonName <<
2839  " certificate: " << e.what() << "; will now block to " <<
2840  "generate that certificate.");
2841  // fall through to do blocking in-process generation.
2842  }
2843 #endif // USE_SSL_CRTD
2844 
2845  debugs(33, 5, HERE << "Generating SSL certificate for " << certProperties.commonName);
2848  auto ssl = fd_table[clientConnection->fd].ssl.get();
2849  if (!Ssl::configureSSL(ssl, certProperties, *port))
2850  debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
2851 
2854  } else {
2856  if (dynCtx && !sslBumpCertKey.isEmpty())
2858  getSslContextDone(dynCtx);
2859  }
2860  return;
2861  }
2862 
2865 }
2866 
2867 void
2869 {
2870  if (port->secure.generateHostCertificates && !ctx) {
2871  debugs(33, 2, "Failed to generate TLS context for " << tlsConnectHostOrIp);
2872  }
2873 
2874  // If generated ssl context = NULL, try to use static ssl context.
2875  if (!ctx) {
2876  if (!port->secure.staticContext) {
2877  debugs(83, DBG_IMPORTANT, "Closing " << clientConnection->remote << " as lacking TLS context");
2879  return;
2880  } else {
2881  debugs(33, 5, "Using static TLS context.");
2882  ctx = port->secure.staticContext;
2883  }
2884  }
2885 
2886  if (!httpsCreate(this, ctx))
2887  return;
2888 
2889  // bumped intercepted conns should already have Config.Timeout.request set
2890  // but forwarded connections may only have Config.Timeout.lifetime. [Re]set
2891  // to make sure the connection does not get stuck on non-SSL clients.
2893  AsyncCall::Pointer timeoutCall = JobCallback(33, 5, TimeoutDialer,
2896 
2897  switchedToHttps_ = true;
2898 
2899  auto ssl = fd_table[clientConnection->fd].ssl.get();
2900  BIO *b = SSL_get_rbio(ssl);
2901  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
2902  bio->setReadBufData(inBuf);
2903  inBuf.clear();
2905 }
2906 
2907 void
2909 {
2911  Must(http->request);
2912  auto &request = http->request;
2913 
2914  // Depending on receivedFirstByte_, we are at the start of either an
2915  // established CONNECT tunnel with the client or an intercepted TCP (and
2916  // presumably TLS) connection from the client. Expect TLS Client Hello.
2917  const auto insideConnectTunnel = receivedFirstByte_;
2918  debugs(33, 5, (insideConnectTunnel ? "post-CONNECT " : "raw TLS ") << clientConnection);
2919 
2920  tlsConnectHostOrIp = request->url.hostOrIp();
2921  tlsConnectPort = request->url.port();
2922  resetSslCommonName(request->url.host());
2923 
2924  // We are going to read new request
2925  flags.readMore = true;
2926 
2927  // keep version major.minor details the same.
2928  // but we are now performing the HTTPS handshake traffic
2930 
2931  // If sslServerBump is set, then we have decided to deny CONNECT
2932  // and now want to switch to SSL to send the error to the client
2933  // without even peeking at the origin server certificate.
2934  if (bumpServerMode == Ssl::bumpServerFirst && !sslServerBump) {
2935  request->flags.sslPeek = true;
2936  sslServerBump = new Ssl::ServerBump(http);
2937  } else if (bumpServerMode == Ssl::bumpPeek || bumpServerMode == Ssl::bumpStare) {
2938  request->flags.sslPeek = true;
2939  sslServerBump = new Ssl::ServerBump(http, nullptr, bumpServerMode);
2940  }
2941 
2942  // commSetConnTimeout() was called for this request before we switched.
2943  // Fix timeout to request_start_timeout
2945  AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
2946  TimeoutDialer, this, ConnStateData::requestTimeout);
2948  // Also reset receivedFirstByte_ flag to allow this timeout work in the case we have
2949  // a bumbed "connect" request on non transparent port.
2950  receivedFirstByte_ = false;
2951  // Get more data to peek at Tls
2952  parsingTlsHandshake = true;
2953 
2954  // If the protocol has changed, then reset preservingClientData_.
2955  // Otherwise, its value initially set in start() is still valid/fresh.
2956  // shouldPreserveClientData() uses parsingTlsHandshake which is reset above.
2957  if (insideConnectTunnel)
2959 
2960  readSomeData();
2961 }
2962 
2963 void
2965 {
2967 
2968  assert(!inBuf.isEmpty());
2970  fd_note(clientConnection->fd, "Parsing TLS handshake");
2971 
2972  bool unsupportedProtocol = false;
2973  try {
2974  if (!tlsParser.parseHello(inBuf)) {
2975  // need more data to finish parsing
2976  readSomeData();
2977  return;
2978  }
2979  }
2980  catch (const std::exception &ex) {
2981  debugs(83, 2, "error on FD " << clientConnection->fd << ": " << ex.what());
2982  unsupportedProtocol = true;
2983  }
2984 
2985  parsingTlsHandshake = false;
2986 
2987  // client data may be needed for splicing and for
2988  // tunneling unsupportedProtocol after an error
2990 
2991  // Even if the parser failed, each TLS detail should either be set
2992  // correctly or still be "unknown"; copying unknown detail is a no-op.
2995  if (details && !details->serverName.isEmpty()) {
2996  resetSslCommonName(details->serverName.c_str());
2997  tlsClientSni_ = details->serverName;
2998  }
2999 
3000  // We should disable read/write handlers
3002 
3003  if (unsupportedProtocol) {
3004  Http::StreamPointer context = pipeline.front();
3005  Must(context && context->http);
3006  HttpRequest::Pointer request = context->http->request;
3007  debugs(83, 5, "Got something other than TLS Client Hello. Cannot SslBump.");
3009  context->http->al->ssl.bumpMode = Ssl::bumpSplice;
3012  return;
3013  }
3014 
3015  if (!sslServerBump || sslServerBump->act.step1 == Ssl::bumpClientFirst) { // Either means client-first.
3017  return;
3018  } else if (sslServerBump->act.step1 == Ssl::bumpServerFirst) {
3019  Http::StreamPointer context = pipeline.front();
3020  ClientHttpRequest *http = context ? context->http : nullptr;
3021  // will call httpsPeeked() with certificate and connection, eventually
3023  } else {
3026  }
3027 }
3028 
3030 {
3031  ConnStateData *connState = (ConnStateData *) data;
3032 
3033  // if the connection is closed or closing, just return.
3034  if (!connState->isOpen())
3035  return;
3036 
3037  debugs(33, 5, "Answer: " << answer << " kind:" << answer.kind);
3038  assert(connState->serverBump());
3039  Ssl::BumpMode bumpAction;
3040  if (answer.allowed()) {
3041  bumpAction = (Ssl::BumpMode)answer.kind;
3042  } else
3043  bumpAction = Ssl::bumpSplice;
3044 
3045  connState->serverBump()->act.step2 = bumpAction;
3046  connState->sslBumpMode = bumpAction;
3047  Http::StreamPointer context = connState->pipeline.front();
3048  if (ClientHttpRequest *http = (context ? context->http : nullptr))
3049  http->al->ssl.bumpMode = bumpAction;
3050 
3051  if (bumpAction == Ssl::bumpTerminate) {
3052  connState->clientConnection->close();
3053  } else if (bumpAction != Ssl::bumpSplice) {
3054  connState->startPeekAndSplice();
3055  } else if (!connState->splice())
3056  connState->clientConnection->close();
3057 }
3058 
3059 bool
3061 {
3062  // normally we can splice here, because we just got client hello message
3063 
3064  // fde::ssl/tls_read_method() probably reads from our own inBuf. If so, then
3065  // we should not lose any raw bytes when switching to raw I/O here.
3066  if (fd_table[clientConnection->fd].ssl.get())
3067  fd_table[clientConnection->fd].useDefaultIo();
3068 
3069  // XXX: assuming that there was an HTTP/1.1 CONNECT to begin with...
3070  // reset the current protocol to HTTP/1.1 (was "HTTPS" for the bumping process)
3072  assert(!pipeline.empty());
3073  Http::StreamPointer context = pipeline.front();
3074  Must(context);
3075  Must(context->http);
3076  ClientHttpRequest *http = context->http;
3078  context->finished();
3079  if (transparent()) {
3080  // For transparent connections, make a new fake CONNECT request, now
3081  // with SNI as target. doCallout() checks, adaptations may need that.
3082  return fakeAConnectRequest("splice", preservedClientData);
3083  } else {
3084  // For non transparent connections make a new tunneled CONNECT, which
3085  // also sets the HttpRequest::flags::forceTunnel flag to avoid
3086  // respond with "Connection Established" to the client.
3087  // This fake CONNECT request required to allow use of SNI in
3088  // doCallout() checks and adaptations.
3090  }
3091 }
3092 
3093 void
3095 {
3096  // This is the Step2 of the SSL bumping
3098  Http::StreamPointer context = pipeline.front();
3099  ClientHttpRequest *http = context ? context->http : nullptr;
3100 
3103  // Run a accessList check to check if want to splice or continue bumping
3104 
3106  acl_checklist->al = http ? http->al : nullptr;
3107  //acl_checklist->src_addr = params.conn->remote;
3108  //acl_checklist->my_addr = s->s;
3112  const char *log_uri = http ? http->log_uri : nullptr;
3113  acl_checklist->syncAle(sslServerBump->request.getRaw(), log_uri);
3114  acl_checklist->nonBlockingCheck(httpsSslBumpStep2AccessCheckDone, this);
3115  return;
3116  }
3117 
3118  // will call httpsPeeked() with certificate and connection, eventually
3119  Security::ContextPointer unConfiguredCTX(Ssl::createSSLContext(port->secure.signingCa.cert, port->secure.signingCa.pkey, port->secure));
3120  fd_table[clientConnection->fd].html?amicTlsContext = unConfiguredCTX;
3121 
3122  if (!httpsCreate(this, unConfiguredCTX))
3123  return;
3124 
3125  switchedToHttps_ = true;
3126 
3127  auto ssl = fd_table[clientConnection->fd].ssl.get();
3128  BIO *b = SSL_get_rbio(ssl);
3129  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
3130  bio->setReadBufData(inBuf);
3131  bio->hold(true);
3132 
3133  // Here squid should have all of the client hello message so the
3134  // tlsAttemptHandshake() should return 0.
3135  // This block exist only to force openSSL parse client hello and detect
3136  // ERR_SECURE_ACCEPT_FAIL error, which should be checked and splice if required.
3137  if (tlsAttemptHandshake(this, nullptr) < 0) {
3138  debugs(83, 2, "TLS handshake failed.");
3139  HttpRequest::Pointer request(http ? http->request : nullptr);
3142  return;
3143  }
3144 
3145  // We need to reset inBuf here, to be used by incoming requests in the case
3146  // of SSL bump
3147  inBuf.clear();
3148 
3149  debugs(83, 5, "Peek and splice at step2 done. Start forwarding the request!!! ");
3151 }
3152 
3153 void
3155 {
3156  auto ssl = fd_table[clientConnection->fd].ssl.get();
3157  BIO *b = SSL_get_rbio(ssl);
3158  assert(b);
3159  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
3160 
3161  debugs(33, 5, "PeekAndSplice mode, proceed with client negotiation. Current state:" << SSL_state_string_long(ssl));
3162  bio->hold(false);
3163 
3165  switchedToHttps_ = true;
3166 }
3167 
3168 void
3170 {
3171  Must(sslServerBump != NULL);
3172  Must(sslServerBump->request == pic.request);
3173  Must(pipeline.empty() || pipeline.front()->http == nullptr || pipeline.front()->http->request == pic.request.getRaw());
3174 
3175  if (Comm::IsConnOpen(pic.connection)) {
3177  debugs(33, 5, "bumped HTTPS server: " << tlsConnectHostOrIp);
3178  } else
3179  debugs(33, 5, "Error while bumping: " << tlsConnectHostOrIp);
3180 
3182 }
3183 
3184 #endif /* USE_OPENSSL */
3185 
3186 bool
3187 ConnStateData::initiateTunneledRequest(HttpRequest::Pointer const &cause, Http::MethodType const method, const char *reason, const SBuf &payload)
3188 {
3189  // fake a CONNECT request to force connState to tunnel
3190  SBuf connectHost;
3191  unsigned short connectPort = 0;
3192 
3193  if (pinning.serverConnection != nullptr) {
3194  static char ip[MAX_IPSTRLEN];
3195  connectHost = pinning.serverConnection->remote.toStr(ip, sizeof(ip));
3196  connectPort = pinning.serverConnection->remote.port();
3197  } else if (cause) {
3198  connectHost = cause->url.hostOrIp();
3199  connectPort = cause->url.port();
3200 #if USE_OPENSSL
3201  } else if (!tlsConnectHostOrIp.isEmpty()) {
3202  connectHost = tlsConnectHostOrIp;
3203  connectPort = tlsConnectPort;
3204 #endif
3205  } else if (transparent()) {
3206  static char ip[MAX_IPSTRLEN];
3207  connectHost = clientConnection->local.toStr(ip, sizeof(ip));
3208  connectPort = clientConnection->local.port();
3209  } else {
3210  debugs(33, 2, "Not able to compute URL, abort request tunneling for " << reason);
3211  return false;
3212  }
3213 
3214  debugs(33, 2, "Request tunneling for " << reason);
3215  ClientHttpRequest *http = buildFakeRequest(method, connectHost, connectPort, payload);
3217  request->flags.forceTunnel = true;
3218  http->calloutContext = new ClientRequestContext(http);
3219  http->doCallouts();
3221  return true;
3222 }
3223 
3224 bool
3225 ConnStateData::fakeAConnectRequest(const char *reason, const SBuf &payload)
3226 {
3227  debugs(33, 2, "fake a CONNECT request to force connState to tunnel for " << reason);
3228 
3229  SBuf connectHost;
3230  assert(transparent());
3231  const unsigned short connectPort = clientConnection->local.port();
3232 
3233 #if USE_OPENSSL
3234  if (!tlsClientSni_.isEmpty())
3235  connectHost.assign(tlsClientSni_);
3236  else
3237 #endif
3238  {
3239  static char ip[MAX_IPSTRLEN];
3240  clientConnection->local.toHostStr(ip, sizeof(ip));
3241  connectHost.assign(ip);
3242  }
3243 
3244  ClientHttpRequest *http = buildFakeRequest(Http::METHOD_CONNECT, connectHost, connectPort, payload);
3245 
3246  http->calloutContext = new ClientRequestContext(http);
3248  http->doCallouts();
3250  return true;
3251 }
3252 
3254 ConnStateData::buildFakeRequest(Http::MethodType const method, SBuf &useHost, unsigned short usePort, const SBuf &payload)
3255 {
3256  ClientHttpRequest *http = new ClientHttpRequest(this);
3257  Http::Stream *stream = new Http::Stream(clientConnection, http);
3258 
3259  StoreIOBuffer tempBuffer;
3260  tempBuffer.data = stream->reqbuf;
3261  tempBuffer.length = HTTP_REQBUF_SZ;
3262 
3263  ClientStreamData newServer = new clientReplyContext(http);
3264  ClientStreamData newClient = stream;
3267  clientSocketDetach, newClient, tempBuffer);
3268 
3269  stream->flags.parsed_ok = 1; // Do we need it?
3270  stream->mayUseConnection(true);
3271 
3272  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "clientLifetimeTimeout",
3275 
3276  stream->registerWithConn();
3277 
3280  // Setup Http::Request object. Maybe should be replaced by a call to (modified)
3281  // clientProcessRequest
3284  request->url.setScheme(proto, nullptr);
3285  request->method = method;
3286  request->url.host(useHost.c_str());
3287  request->url.port(usePort);
3288 
3289  http->uri = SBufToCstring(request->effectiveRequestUri());
3290  http->initRequest(request.getRaw());
3291 
3292  request->manager(this, http->al);
3293 
3294  if (proto == AnyP::PROTO_HTTP)
3295  request->header.putStr(Http::HOST, useHost.c_str());
3296 
3297  request->sources |= ((switchedToHttps() || port->transport.protocol == AnyP::PROTO_HTTPS) ? Http::Message::srcHttps : Http::Message::srcHttp);
3298 #if USE_AUTH
3299  if (getAuth())
3300  request->auth_user_request = getAuth();
3301 #endif
3302 
3303  inBuf = payload;
3304  flags.readMore = false;
3305 
3306  return http;
3307 }
3308 
3310 static bool
3312 {
3313  if (!Comm::IsConnOpen(c)) {
3314  Must(NHttpSockets > 0); // we tried to open some
3315  --NHttpSockets; // there will be fewer sockets than planned
3316  Must(HttpSockets[NHttpSockets] < 0); // no extra fds received
3317 
3318  if (!NHttpSockets) // we could not open any listen sockets at all
3319  fatalf("Unable to open %s",FdNote(portType));
3320 
3321  return false;
3322  }
3323  return true;
3324 }
3325 
3327 static bool
3329 {
3330  bool found = false;
3331  for (int i = 0; i < NHttpSockets && !found; ++i) {
3332  if ((found = HttpSockets[i] < 0))
3333  HttpSockets[i] = conn->fd;
3334  }
3335  return found;
3336 }
3337 
3338 static void
3340 {
3341  for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) {
3342  const SBuf &scheme = AnyP::UriScheme(s->transport.protocol).image();
3343 
3345  debugs(1, DBG_IMPORTANT, "WARNING: You have too many '" << scheme << "_port' lines." <<
3346  Debug::Extra << "The limit is " << MAXTCPLISTENPORTS << " HTTP ports.");
3347  continue;
3348  }
3349 
3350 #if USE_OPENSSL
3351  if (s->flags.tunnelSslBumping) {
3352  if (!Config.accessList.ssl_bump) {
3353  debugs(33, DBG_IMPORTANT, "WARNING: No ssl_bump configured. Disabling ssl-bump on " << scheme << "_port " << s->s);
3354  s->flags.tunnelSslBumping = false;
3355  }
3356  if (!s->secure.staticContext && !s->secure.generateHostCertificates) {
3357  debugs(1, DBG_IMPORTANT, "Will not bump SSL at " << scheme << "_port " << s->s << " due to TLS initialization failure.");
3358  s->flags.tunnelSslBumping = false;
3359  if (s->transport.protocol == AnyP::PROTO_HTTP)
3360  s->secure.encryptTransport = false;
3361  }
3362  if (s->flags.tunnelSslBumping) {
3363  // Create ssl_ctx cache for this port.
3364  Ssl::TheGlobalContextStorage.addLocalStorage(s->s, s->secure.html?amicCertMemCacheSize);
3365  }
3366  }
3367 #endif
3368 
3369  if (s->secure.encryptTransport && !s->secure.staticContext) {
3370  debugs(1, DBG_CRITICAL, "ERROR: Ignoring " << scheme << "_port " << s->s << " due to TLS context initialization failure.");
3371  continue;
3372  }
3373 
3374  // Fill out a Comm::Connection which IPC will open as a listener for us
3375  // then pass back when active so we can start a TcpAcceptor subscription.
3376  s->listenConn = new Comm::Connection;
3377  s->listenConn->local = s->s;
3378 
3379  s->listenConn->flags = COMM_NONBLOCKING | (s->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) |
3380  (s->flags.natIntercept ? COMM_INTERCEPTION : 0) |
3381  (s->workerQueues ? COMM_REUSEPORT : 0);
3382 
3383  typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
3384  if (s->transport.protocol == AnyP::PROTO_HTTP) {
3385  // setup the subscriptions such that new connections accepted by listenConn are handled by HTTP
3388 
3389  AsyncCall::Pointer listenCall = asyncCall(33,2, "clientListenerConnectionOpened",
3391  Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpSocket, listenCall);
3392 
3393  } else if (s->transport.protocol == AnyP::PROTO_HTTPS) {
3394  // setup the subscriptions such that new connections accepted by listenConn are handled by HTTPS
3397 
3398  AsyncCall::Pointer listenCall = asyncCall(33, 2, "clientListenerConnectionOpened",
3400  s, Ipc::fdnHttpsSocket, sub));
3401  Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpsSocket, listenCall);
3402  }
3403 
3404  HttpSockets[NHttpSockets] = -1; // set in clientListenerConnectionOpened
3405  ++NHttpSockets;
3406  }
3407 }
3408 
3409 void
3411 {
3412  // Fill out a Comm::Connection which IPC will open as a listener for us
3413  port->listenConn = new Comm::Connection;
3414  port->listenConn->local = port->s;
3415  port->listenConn->flags =
3417  (port->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) |
3418  (port->flags.natIntercept ? COMM_INTERCEPTION : 0);
3419 
3420  // route new connections to subCall
3421  typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
3423  AsyncCall::Pointer listenCall =
3424  asyncCall(33, 2, "clientListenerConnectionOpened",
3426  port, fdNote, sub));
3427  Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, port->listenConn, fdNote, listenCall);
3428 
3430  HttpSockets[NHttpSockets] = -1;
3431  ++NHttpSockets;
3432 }
3433 
3435 static void
3437 {
3438  Must(s != NULL);
3439 
3440  if (!OpenedHttpSocket(s->listenConn, portTypeNote))
3441  return;
3442 
3443  Must(Comm::IsConnOpen(s->listenConn));
3444 
3445  // TCP: setup a job to handle accept() with subscribed handler
3446  AsyncJob::Start(new Comm::TcpAcceptor(s, FdNote(portTypeNote), sub));
3447 
3448  debugs(1, DBG_IMPORTANT, "Accepting " <<
3449  (s->flags.natIntercept ? "NAT intercepted " : "") <<
3450  (s->flags.tproxyIntercept ? "TPROXY intercepted " : "") <<
3451  (s->flags.tunnelSslBumping ? "SSL bumped " : "") <<
3452  (s->flags.accelSurrogate ? "reverse-proxy " : "")
3453  << FdNote(portTypeNote) << " connections at "
3454  << s->listenConn);
3455 
3456  Must(AddOpenedHttpSocket(s->listenConn)); // otherwise, we have received a fd we did not ask for
3457 
3458 #if USE_SYSTEMD
3459  // When the very first port opens, tell systemd we are able to serve connections.
3460  // Subsequent sd_notify() calls, including calls during reconfiguration,
3461  // do nothing because the first call parameter is 1.
3462  // XXX: Send the notification only after opening all configured ports.
3463  if (opt_foreground || opt_no_daemon) {
3464  const auto result = sd_notify(1, "READY=1");
3465  if (result < 0) {
3466  debugs(1, DBG_IMPORTANT, "WARNING: failed to send start-up notification to systemd" <<
3467  Debug::Extra << "sd_notify() error: " << xstrerr(-result));
3468  }
3469  }
3470 #endif
3471 }
3472 
3473 void
3475 {
3478 
3479  if (NHttpSockets < 1)
3480  fatal("No HTTP, HTTPS, or FTP ports configured");
3481 }
3482 
3483 void
3485 {
3486  for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) {
3487  if (s->listenConn != NULL) {
3488  debugs(1, DBG_IMPORTANT, "Closing HTTP(S) port " << s->listenConn->local);
3489  s->listenConn->close();
3490  s->listenConn = NULL;
3491  }
3492  }
3493 
3495 
3496  // TODO see if we can drop HttpSockets array entirely */
3497  for (int i = 0; i < NHttpSockets; ++i) {
3498  HttpSockets[i] = -1;
3499  }
3500 
3501  NHttpSockets = 0;
3502 }
3503 
3504 int
3506 {
3507  SBuf vary(request->vary_headers);
3508  const auto &reply = entry->mem().freshestReply();
3509  auto has_vary = reply.header.has(Http::HdrType::VARY);
3510 #if X_ACCELERATOR_VARY
3511 
3512  has_vary |=
3513  reply.header.has(Http::HdrType::HDR_X_ACCELERATOR_VARY);
3514 #endif
3515 
3516  if (!has_vary || entry->mem_obj->vary_headers.isEmpty()) {
3517  if (!vary.isEmpty()) {
3518  /* Oops... something odd is going on here.. */
3519  debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary object on second attempt, '" <<
3520  entry->mem_obj->urlXXX() << "' '" << vary << "'");
3521  request->vary_headers.clear();
3522  return VARY_CANCEL;
3523  }
3524 
3525  if (!has_vary) {
3526  /* This is not a varying object */
3527  return VARY_NONE;
3528  }
3529 
3530  /* virtual "vary" object found. Calculate the vary key and
3531  * continue the search
3532  */
3533  vary = httpMakeVaryMark(request, &reply);
3534 
3535  if (!vary.isEmpty()) {
3536  request->vary_headers = vary;
3537  return VARY_OTHER;
3538  } else {
3539  /* Ouch.. we cannot handle this kind of variance */
3540  /* XXX This cannot really happen, but just to be complete */
3541  return VARY_CANCEL;
3542  }
3543  } else {
3544  if (vary.isEmpty()) {
3545  vary = httpMakeVaryMark(request, &reply);
3546 
3547  if (!vary.isEmpty())
3548  request->vary_headers = vary;
3549  }
3550 
3551  if (vary.isEmpty()) {
3552  /* Ouch.. we cannot handle this kind of variance */
3553  /* XXX This cannot really happen, but just to be complete */
3554  return VARY_CANCEL;
3555  } else if (vary.cmp(entry->mem_obj->vary_headers) == 0) {
3556  return VARY_MATCH;
3557  } else {
3558  /* Oops.. we have already been here and still haven't
3559  * found the requested variant. Bail out
3560  */
3561  debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary match on second attempt, '" <<
3562  entry->mem_obj->urlXXX() << "' '" << vary << "'");
3563  return VARY_CANCEL;
3564  }
3565  }
3566 }
3567 
3570 {
3571  const auto checklist = new ACLFilledChecklist(acl, nullptr, nullptr);
3572  clientAclChecklistFill(*checklist, http);
3573  return checklist;
3574 }
3575 
3576 void
3578 {
3579  checklist.setRequest(http->request);
3580  checklist.al = http->al;
3581  checklist.syncAle(http->request, http->log_uri);
3582 
3583  // TODO: If http->getConn is always http->request->clientConnectionManager,
3584  // then call setIdent() inside checklist.setRequest(). Otherwise, restore
3585  // USE_IDENT lost in commit 94439e4.
3586  ConnStateData * conn = http->getConn();
3587  const char *ident = (cbdataReferenceValid(conn) &&
3588  conn && conn->clientConnection) ?
3589  conn->clientConnection->rfc931 : dash_str;
3590  checklist.setIdent(ident);
3591 }
3592 
3593 bool
3595 {
3597 }
3598 
3601 {
3602  bodyPipe = new BodyPipe(this);
3603  if (size >= 0)
3605  else
3607  return bodyPipe;
3608 }
3609 
3610 int64_t
3612 {
3613  if (!bodyPipe)
3614  return 0; // request without a body or read/produced all body bytes
3615 
3616  if (!bodyPipe->bodySizeKnown())
3617  return -1; // probably need to read more, but we cannot be sure
3618 
3619  const int64_t needToProduce = bodyPipe->unproducedSize();
3620  const int64_t haveAvailable = static_cast<int64_t>(inBuf.length());
3621 
3622  if (needToProduce <= haveAvailable)
3623  return 0; // we have read what we need (but are waiting for pipe space)
3624 
3625  return needToProduce - haveAvailable;
3626 }
3627 
3628 void
3630 {
3631  debugs(33, 4, HERE << "receiving error (" << clientConnection << "): " << error <<
3632  "; old sending error: " <<
3633  (stoppedSending() ? stoppedSending_ : "none"));
3634 
3635  if (const char *oldError = stoppedReceiving()) {
3636  debugs(33, 3, HERE << "already stopped receiving: " << oldError);
3637  return; // nothing has changed as far as this connection is concerned
3638  }
3639 
3641 
3642  if (const char *sendError = stoppedSending()) {
3643  debugs(33, 3, HERE << "closing because also stopped sending: " << sendError);
3645  }
3646 }
3647 
3648 void
3650 {
3651  if (bodyPipe != NULL) {
3652  debugs(33, 4, HERE << "no consumer for virgin body " << bodyPipe->status());
3654  }
3655 }
3656 
3658 void
3660 {
3661  Must(bodyPipe != NULL);
3662  debugs(33, 5, HERE << "start dechunking" << bodyPipe->status());
3663  assert(!bodyParser);
3665 }
3666 
3668 void
3670 {
3671  debugs(33, 5, HERE << "finish dechunking: " << withSuccess);
3672 
3673  if (bodyPipe != NULL) {
3674  debugs(33, 7, HERE << "dechunked tail: " << bodyPipe->status());
3675  BodyPipe::Pointer myPipe = bodyPipe;
3676  stopProducingFor(bodyPipe, withSuccess); // sets bodyPipe->bodySize()
3677  Must(!bodyPipe); // we rely on it being nil after we are done with body
3678  if (withSuccess) {
3679  Must(myPipe->bodySizeKnown());
3680  Http::StreamPointer context = pipeline.front();
3681  if (context != NULL && context->http && context->http->request)
3682  context->http->request->setContentLength(myPipe->bodySize());
3683  }
3684  }
3685 
3686  delete bodyParser;
3687  bodyParser = NULL;
3688 }
3689 
3690 // XXX: this is an HTTP/1-only operation
3691 void
3693 {
3694  if (const auto context = pipeline.front()) {
3695  if (context->http)
3696  context->http->al->reply = msg.reply;
3697  }
3698 
3699  if (!isOpen()) {
3700  debugs(33, 3, HERE << "ignoring 1xx due to earlier closure");
3701  return;
3702  }
3703 
3704  // HTTP/1 1xx status messages are only valid when there is a transaction to trigger them
3705  if (!pipeline.empty()) {
3706  HttpReply::Pointer rep(msg.reply);
3707  Must(rep);
3708  // remember the callback
3710 
3713 
3714  if (!writeControlMsgAndCall(rep.getRaw(), call)) {
3715  // but still inform the caller (so it may resume its operation)
3717  }
3718  return;
3719  }
3720 
3721  debugs(33, 3, HERE << " closing due to missing context for 1xx");
3723 }
3724 
3725 void
3727 {
3729 
3730  if (Http::StreamPointer deferredRequest = pipeline.front()) {
3731  debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded after control msg wrote");
3732  ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
3733  }
3734 }
3735 
3737 void
3739 {
3740  // FwdState might repin a failed connection sooner than this close
3741  // callback is called for the failed connection.
3742  assert(pinning.serverConnection == io.conn);
3743  pinning.closeHandler = NULL; // Comm unregisters handlers before calling
3744  const bool sawZeroReply = pinning.zeroReply; // reset when unpinning
3745  pinning.serverConnection->noteClosure();
3746  unpinConnection(false);
3747 
3748  if (sawZeroReply && clientConnection != NULL) {
3749  debugs(33, 3, "Closing client connection on pinned zero reply.");
3751  }
3752 
3753 }
3754 
3755 void
3757 {
3758  pinConnection(pinServer, *request);
3759 }
3760 
3761 void
3763 {
3764  Must(pic.connection);
3765  Must(pic.request);
3766  pinConnection(pic.connection, *pic.request);
3767 
3768  // monitor pinned server connection for remote-end closures.
3770 
3771  if (pipeline.empty())
3772  kick(); // in case clientParseRequests() was blocked by a busy pic.connection
3773 }
3774 
3776 void
3778 {
3779  if (Comm::IsConnOpen(pinning.serverConnection) &&
3780  pinning.serverConnection->fd == pinServer->fd) {
3781  debugs(33, 3, "already pinned" << pinServer);
3782  return;
3783  }
3784 
3785  unpinConnection(true); // closes pinned connection, if any, and resets fields
3786 
3787  pinning.serverConnection = pinServer;
3788 
3789  debugs(33, 3, HERE << pinning.serverConnection);
3790 
3791  Must(pinning.serverConnection != NULL);
3792 
3793  const char *pinnedHost = "[unknown]";
3794  pinning.host = xstrdup(request.url.host());
3795  pinning.port = request.url.port();
3796  pinnedHost = pinning.host;
3797  pinning.pinned = true;
3798  if (CachePeer *aPeer = pinServer->getPeer())
3799  pinning.peer = cbdataReference(aPeer);
3800  pinning.auth = request.flags.connectionAuth;
3801  char stmp[MAX_IPSTRLEN];
3802  char desc[FD_DESC_SZ];
3803  snprintf(desc, FD_DESC_SZ, "%s pinned connection for %s (%d)",
3804  (pinning.auth || !pinning.peer) ? pinnedHost : pinning.peer->name,
3806  clientConnection->fd);
3807  fd_note(pinning.serverConnection->fd, desc);
3808 
3810  pinning.closeHandler = JobCallback(33, 5,
3812  // remember the pinned connection so that cb does not unpin a fresher one
3813  typedef CommCloseCbParams Params;
3814  Params &params = GetCommParams<Params>(pinning.closeHandler);
3815  params.conn = pinning.serverConnection;
3816  comm_add_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
3817 }
3818 
3821 void
3823 {
3824  if (pinning.readHandler != NULL)
3825  return; // already monitoring
3826 
3828  pinning.readHandler = JobCallback(33, 3,
3830  Comm::Read(pinning.serverConnection, pinning.readHandler);
3831 }
3832 
3833 void
3835 {
3836  if (pinning.readHandler != NULL) {
3837  Comm::ReadCancel(pinning.serverConnection->fd, pinning.readHandler);
3838  pinning.readHandler = NULL;
3839  }
3840 }
3841 
3842 #if USE_OPENSSL
3843 bool
3845 {
3846  // A ready-for-reading connection means that the TLS server either closed
3847  // the connection, sent us some unexpected HTTP data, or started TLS
3848  // renegotiations. We should close the connection except for the last case.
3849 
3850  Must(pinning.serverConnection != nullptr);
3851  auto ssl = fd_table[pinning.serverConnection->fd].ssl.get();
3852  if (!ssl)
3853  return false;
3854 
3855  char buf[1];
3856  const int readResult = SSL_read(ssl, buf, sizeof(buf));
3857 
3858  if (readResult > 0 || SSL_pending(ssl) > 0) {
3859  debugs(83, 2, pinning.serverConnection << " TLS application data read");
3860  return false;
3861  }
3862 
3863  switch(const int error = SSL_get_error(ssl, readResult)) {
3864  case SSL_ERROR_WANT_WRITE:
3865  debugs(83, DBG_IMPORTANT, pinning.serverConnection << " TLS SSL_ERROR_WANT_WRITE request for idle pinned connection");
3866  // fall through to restart monitoring, for now
3867  case SSL_ERROR_NONE:
3868  case SSL_ERROR_WANT_READ:
3870  return true;
3871 
3872  default:
3873  debugs(83, 2, pinning.serverConnection << " TLS error: " << error);
3874  return false;
3875  }
3876 
3877  // not reached
3878  return true;
3879 }
3880 #endif
3881 
3884 void
3886 {
3887  pinning.readHandler = NULL; // Comm unregisters handlers before calling
3888 
3889  if (io.flag == Comm::ERR_CLOSING)
3890  return; // close handler will clean up
3891 
3892  Must(pinning.serverConnection == io.conn);
3893 
3894 #if USE_OPENSSL
3896  return;
3897 #endif
3898 
3899  const bool clientIsIdle = pipeline.empty();
3900 
3901  debugs(33, 3, "idle pinned " << pinning.serverConnection << " read " <<
3902  io.size << (clientIsIdle ? " with idle client" : ""));
3903 
3904  pinning.serverConnection->close();
3905 
3906  // If we are still sending data to the client, do not close now. When we are done sending,
3907  // ConnStateData::kick() checks pinning.serverConnection and will close.
3908  // However, if we are idle, then we must close to inform the idle client and minimize races.
3909  if (clientIsIdle && clientConnection != NULL)
3911 }
3912 
3915 {
3916  debugs(33, 7, pinning.serverConnection);
3917  Must(request);
3918 
3919  const auto pinningError = [&](const err_type type) {
3920  unpinConnection(true);
3921  HttpRequestPointer requestPointer = request;
3922  return ErrorState::NewForwarding(type, requestPointer, ale);
3923  };
3924 
3925  if (!Comm::IsConnOpen(pinning.serverConnection))
3926  throw pinningError(ERR_ZERO_SIZE_OBJECT);
3927 
3928  if (pinning.auth && pinning.host && strcasecmp(pinning.host, request->url.host()) != 0)
3929  throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_CONFLICT_HOST
3930 
3931  if (pinning.port != request->url.port())
3932  throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_CONFLICT_HOST
3933 
3934  if (pinning.peer && !cbdataReferenceValid(pinning.peer))
3935  throw pinningError(ERR_ZERO_SIZE_OBJECT);
3936 
3937  if (pinning.peerAccessDenied)
3938  throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_FORWARDING_DENIED
3939 
3941  return pinning.serverConnection;
3942 }
3943 
3946 {
3947  if (const auto connManager = request ? request->pinnedConnection() : nullptr)
3948  return connManager->borrowPinnedConnection(request, ale);
3949 
3950  // ERR_CANNOT_FORWARD is somewhat misleading here; we can still forward, but
3951  // there is no point since the client connection is now gone
3952  HttpRequestPointer requestPointer = request;
3953  throw ErrorState::NewForwarding(ERR_CANNOT_FORWARD, requestPointer, ale);
3954 }
3955 
3956 void
3958 {
3959  debugs(33, 3, HERE << pinning.serverConnection);
3960 
3961  if (pinning.peer)
3963 
3964  if (Comm::IsConnOpen(pinning.serverConnection)) {
3965  if (pinning.closeHandler != NULL) {
3966  comm_remove_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
3967  pinning.closeHandler = NULL;
3968  }
3969 
3971 
3972  // close the server side socket if requested
3973  if (andClose)
3974  pinning.serverConnection->close();
3975  pinning.serverConnection = NULL;
3976  }
3977 
3978  safe_free(pinning.host);
3979 
3980  pinning.zeroReply = false;
3981  pinning.peerAccessDenied = false;
3982 
3983  /* NOTE: pinning.pinned should be kept. This combined with fd == -1 at the end of a request indicates that the host
3984  * connection has gone away */
3985 }
3986 
3987 void
3989 {
3990  // if we are parsing request body, its request is responsible for logging
3991  if (bodyPipe)
3992  return;
3993 
3994  // a request currently using this connection is responsible for logging
3995  if (!pipeline.empty() && pipeline.back()->mayUseConnection())
3996  return;
3997 
3998  /* Either we are waiting for the very first transaction, or
3999  * we are done with the Nth transaction and are waiting for N+1st.
4000  * XXX: We assume that if anything was added to inBuf, then it could
4001  * only be consumed by actions already covered by the above checks.
4002  */
4003 
4004  // do not log connections that closed after a transaction (it is normal)
4005  // TODO: access_log needs ACLs to match received-no-bytes connections
4006  if (pipeline.nrequests && inBuf.isEmpty())
4007  return;
4008 
4009  /* Create a temporary ClientHttpRequest object. Its destructor will log. */
4010  ClientHttpRequest http(this);
4011  http.req_sz = inBuf.length();
4012  // XXX: Or we died while waiting for the pinned connection to become idle.
4013  http.setErrorUri("error:transaction-end-before-headers");
4014 }
4015 
4016 bool
4018 {
4019  // PROXY protocol bytes are meant for us and, hence, cannot be tunneled
4021  return false;
4022 
4023  // If our decision here is negative, configuration changes are irrelevant.
4024  // Otherwise, clientTunnelOnError() rechecks configuration before tunneling.
4026  return false;
4027 
4028  // TODO: Figure out whether/how we can support FTP tunneling.
4029  if (port->transport.protocol == AnyP::PROTO_FTP)
4030  return false;
4031 
4032 #if USE_OPENSSL
4033  if (parsingTlsHandshake)
4034  return true;
4035 
4036  // the 1st HTTP request on a bumped connection
4038  return true;
4039 #endif
4040 
4041  // the 1st HTTP(S) request on a connection to an intercepting port
4042  if (!pipeline.nrequests && transparent())
4043  return true;
4044 
4045  return false;
4046 }
4047 
4050 {
4051  if (!theNotes)
4052  theNotes = new NotePairs;
4053  return theNotes;
4054 }
4055 
4056 std::ostream &
4057 operator <<(std::ostream &os, const ConnStateData::PinnedIdleContext &pic)
4058 {
4059  return os << pic.connection << ", request=" << pic.request;
4060 }
4061 
4062 std::ostream &
4064 {
4065  return os << scc.conn_ << ", srv_bytes=" << scc.preReadServerBytes.length();
4066 }
4067 
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:441
#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:480
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:481
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:1208
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:275
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:456
#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:389
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:452
#define xstrdup
void enableAutoConsumption()
start or continue consuming when producing without consumer
Definition: BodyPipe.cc:316
void setReplyToError(err_type, Http::StatusCode, const HttpRequestMethod &, char const *, const ConnStateData *, HttpRequest *, const char *, Auth::UserRequest::Pointer)
builds error using clientBuildError() and calls setReplyToError() below
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
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:841
#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:442
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:437
Pipeline pipeline
set of requests waiting to be serviced
Definition: Server.h:115
void clear()
Definition: SBuf.cc:175
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:175
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:537
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:699
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:445
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:450
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:446
unsigned short initial
@ bumpServerFirst
Definition: support.h:136
bool needProxyProtocolHeader_
whether PROXY protocol header is still expected
Definition: client_side.h:419
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:488
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:286
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:431
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:250
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
virtual void doneWithControlMsg()
static void httpsEstablish(ConnStateData *connState, const Security::ContextPointer &ctx)
Comm::ConnectionPointer clientConnection
bool concurrentRequestQueueFilled() const
Definition: ClpMap.h:40
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:392
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:436
NotePairs::Pointer notes()
@ 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
#define COMM_REUSEPORT
Definition: Connection.h:52
@ Okay
Definition: ResultCode.h:18
@ scUriTooLong
Definition: StatusCode.h:58
SBuf ErrorDetail
Definition: Esi.h:29
bool parseHello(const SBuf &data)
Definition: Handshake.cc:645
@ algSetValidAfter
Definition: gadgets.h:188
void prepareLogWithRequestDetails(HttpRequest *, AccessLogEntry::Pointer &)
Definition: client_side.cc:328
StatHist missSvcTime
Definition: StatCounters.h:48
bool transparent() const
void setPayloadBuffer(MemBuf *parsedContent)
set the buffer to be used to store decoded chunk data
void del(const Key &)
Remove the corresponding entry (if any)
Definition: ClpMap.h:255
SBuf image() const
Definition: UriScheme.h:50
bool setValidBefore
Do not mimic "Not Valid Before" field.
Definition: gadgets.h:220
class AccessLogEntry::CacheDetails cache
const Security::CertErrors * sslErrors() const
SSL [certificate validation] errors.
Definition: ServerBump.cc:69
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
HierarchyLogEntry hier
Definition: HttpRequest.h:157