client_side.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2018 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 "rfc1738.h"
108 #include "servers/forward.h"
109 #include "SquidConfig.h"
110 #include "SquidTime.h"
111 #include "StatCounters.h"
112 #include "StatHist.h"
113 #include "Store.h"
114 #include "TimeOrTag.h"
115 #include "tools.h"
116 
117 #if USE_AUTH
118 #include "auth/UserRequest.h"
119 #endif
120 #if USE_DELAY_POOLS
121 #include "ClientInfo.h"
122 #include "MessageDelayPools.h"
123 #endif
124 #if USE_OPENSSL
125 #include "ssl/bio.h"
126 #include "ssl/context_storage.h"
127 #include "ssl/gadgets.h"
128 #include "ssl/helper.h"
129 #include "ssl/ProxyCerts.h"
130 #include "ssl/ServerBump.h"
131 #include "ssl/support.h"
132 #endif
133 
134 // for tvSubUsec() which should be in SquidTime.h
135 #include "util.h"
136 
137 #include <climits>
138 #include <cmath>
139 #include <limits>
140 
141 #if LINGERING_CLOSE
142 #define comm_close comm_lingering_close
143 #endif
144 
147 {
148 public:
151  handler(aHandler), portCfg(aPortCfg), portTypeNote(note), sub(aSub) {}
152 
153  virtual void print(std::ostream &os) const {
154  startPrint(os) <<
155  ", " << FdNote(portTypeNote) << " port=" << (void*)&portCfg << ')';
156  }
157 
158  virtual bool canDial(AsyncCall &) const { return true; }
159  virtual void dial(AsyncCall &) { (handler)(portCfg, portTypeNote, sub); }
160 
161 public:
163 
164 private:
168 };
169 
170 static void clientListenerConnectionOpened(AnyP::PortCfgPointer &s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub);
171 
174 #if USE_IDENT
176 #endif
178 static int clientIsRequestBodyTooLargeForPolicy(int64_t bodyLength);
179 
180 static void clientUpdateStatHistCounters(const LogTags &logType, int svc_time);
181 static void clientUpdateStatCounters(const LogTags &logType);
183 static bool clientPingHasFinished(ping_data const *aPing);
186 
187 char *skipLeadingSpace(char *aString);
188 
189 #if USE_IDENT
190 static void
191 clientIdentDone(const char *ident, void *data)
192 {
193  ConnStateData *conn = (ConnStateData *)data;
194  xstrncpy(conn->clientConnection->rfc931, ident ? ident : dash_str, USER_IDENT_SZ);
195 }
196 #endif
197 
198 void
200 {
202 
203  if (logType.isTcpHit())
205 
206  if (logType.oldType == LOG_TCP_HIT)
208  else if (logType.oldType == LOG_TCP_MEM_HIT)
210 }
211 
212 void
213 clientUpdateStatHistCounters(const LogTags &logType, int svc_time)
214 {
223  switch (logType.oldType) {
224 
227  break;
228 
229  case LOG_TCP_INM_HIT:
230  case LOG_TCP_IMS_HIT:
232  break;
233 
234  case LOG_TCP_HIT:
235 
236  case LOG_TCP_MEM_HIT:
237 
238  case LOG_TCP_OFFLINE_HIT:
240  break;
241 
242  case LOG_TCP_MISS:
243 
246  break;
247 
248  default:
249  /* make compiler warnings go away */
250  break;
251  }
252 }
253 
254 bool
256 {
257  if (0 != aPing->stop.tv_sec && 0 != aPing->start.tv_sec)
258  return true;
259 
260  return false;
261 }
262 
263 void
265 {
266  ping_data *i;
267 
268  switch (someEntry->code) {
269 #if USE_CACHE_DIGESTS
270 
271  case CD_PARENT_HIT:
272 
273  case CD_SIBLING_HIT:
275  break;
276 #endif
277 
278  case SIBLING_HIT:
279 
280  case PARENT_HIT:
281 
282  case FIRST_PARENT_MISS:
283 
284  case CLOSEST_PARENT_MISS:
286  i = &someEntry->ping;
287 
288  if (clientPingHasFinished(i))
290 
291  if (i->timeout)
293 
294  break;
295 
296  case CLOSEST_PARENT:
297 
298  case CLOSEST_DIRECT:
300 
301  break;
302 
303  default:
304  break;
305  }
306 }
307 
308 void
310 {
312 
313  if (request->errType != ERR_NONE)
315 
318 
320 }
321 
322 void
324 {
325  assert(request);
326  assert(aLogEntry != NULL);
327 
328  if (Config.onoff.log_mime_hdrs) {
329  MemBuf mb;
330  mb.init();
331  request->header.packInto(&mb);
332  //This is the request after adaptation or redirection
333  aLogEntry->headers.adapted_request = xstrdup(mb.buf);
334 
335  // the virgin request is saved to aLogEntry->request
336  if (aLogEntry->request) {
337  mb.reset();
338  aLogEntry->request->header.packInto(&mb);
339  aLogEntry->headers.request = xstrdup(mb.buf);
340  }
341 
342 #if USE_ADAPTATION
343  const Adaptation::History::Pointer ah = request->adaptLogHistory();
344  if (ah != NULL) {
345  mb.reset();
346  ah->lastMeta.packInto(&mb);
347  aLogEntry->adapt.last_meta = xstrdup(mb.buf);
348  }
349 #endif
350 
351  mb.clean();
352  }
353 
354 #if ICAP_CLIENT
355  const Adaptation::Icap::History::Pointer ih = request->icapHistory();
356  if (ih != NULL)
357  ih->processingTime(aLogEntry->icap.processingTime);
358 #endif
359 
360  aLogEntry->http.method = request->method;
361  aLogEntry->http.version = request->http_ver;
362  aLogEntry->hier = request->hier;
363  aLogEntry->cache.extuser = request->extacl_user.termedBuf();
364 
365  // Adapted request, if any, inherits and then collects all the stats, but
366  // the virgin request gets logged instead; copy the stats to log them.
367  // TODO: avoid losses by keeping these stats in a shared history object?
368  if (aLogEntry->request) {
369  aLogEntry->request->dnsWait = request->dnsWait;
370  aLogEntry->request->errType = request->errType;
371  aLogEntry->request->errDetail = request->errDetail;
372  }
373 }
374 
375 void
377 {
378  if (!out.size && logType.oldType == LOG_TAG_NONE)
379  debugs(33, 5, "logging half-baked transaction: " << log_uri);
380 
382  al->url = log_uri;
383  debugs(33, 9, "clientLogRequest: al.url='" << al->url << "'");
384 
385  if (al->reply) {
386  al->http.code = al->reply->sline.status();
388  } else if (loggingEntry() && loggingEntry()->mem_obj) {
391  }
392 
393  debugs(33, 9, "clientLogRequest: http.code='" << al->http.code << "'");
394 
395  if (loggingEntry() && loggingEntry()->mem_obj && loggingEntry()->objectLen() >= 0)
396  al->cache.objectSize = loggingEntry()->contentLen(); // payload duplicate ?? with or without TE ?
397 
399  // the virgin request is saved to al->request
400  if (al->request && al->request->body_pipe)
403  // XXX: calculate without payload encoding or headers !!
404  al->http.clientReplySz.payloadData = out.size - out.headers_sz; // pretend its all un-encoded data for now.
405 
407 
408  al->cache.code = logType;
409 
411 
412  if (request)
414 
415 #if USE_OPENSSL && 0
416 
417  /* This is broken. Fails if the connection has been closed. Needs
418  * to snarf the ssl details some place earlier..
419  */
420  if (getConn() != NULL)
422 
423 #endif
424 
425  /* Add notes (if we have a request to annotate) */
426  if (request) {
427  SBuf matched;
428  for (auto h: Config.notes) {
429  if (h->match(request, al->reply, NULL, matched)) {
430  request->notes()->add(h->key(), matched);
431  debugs(33, 3, h->key() << " " << matched);
432  }
433  }
434  // The al->notes and request->notes must point to the same object.
435  al->syncNotes(request);
436  }
437 
438  ACLFilledChecklist checklist(NULL, request, NULL);
439  if (al->reply) {
440  checklist.reply = al->reply;
441  HTTPMSGLOCK(checklist.reply);
442  }
443 
444  if (request) {
448  }
449  // no need checklist.syncAle(): already synced
450  checklist.al = al;
451  accessLogLog(al, &checklist);
452 
453  bool updatePerformanceCounters = true;
456  statsCheck.al = al;
457  if (al->reply) {
458  statsCheck.reply = al->reply;
459  HTTPMSGLOCK(statsCheck.reply);
460  }
461  updatePerformanceCounters = statsCheck.fastCheck().allowed();
462  }
463 
464  if (updatePerformanceCounters) {
465  if (request)
466  updateCounters();
467 
468  if (getConn() != NULL && getConn()->clientConnection != NULL)
470  }
471 }
472 
473 void
475 {
476  safe_free(uri);
481 
482  if (client_stream.tail)
484 }
485 
486 void
488 {
489  ClientHttpRequest *http = (ClientHttpRequest *)data;
490  assert(http != NULL);
491  delete http;
492 }
493 
494 /* This is a handler normally called by comm_close() */
496 {
497  deleteThis("ConnStateData::connStateClosed");
498 }
499 
500 #if USE_AUTH
501 void
503 {
504  if (auth_ == NULL) {
505  if (aur != NULL) {
506  debugs(33, 2, "Adding connection-auth to " << clientConnection << " from " << by);
507  auth_ = aur;
508  }
509  return;
510  }
511 
512  // clobered with self-pointer
513  // NP: something nasty is going on in Squid, but harmless.
514  if (aur == auth_) {
515  debugs(33, 2, "WARNING: Ignoring duplicate connection-auth for " << clientConnection << " from " << by);
516  return;
517  }
518 
519  /*
520  * Connection-auth relies on a single set of credentials being preserved
521  * for all requests on a connection once they have been setup.
522  * There are several things which need to happen to preserve security
523  * when connection-auth credentials change unexpectedly or are unset.
524  *
525  * 1) auth helper released from any active state
526  *
527  * They can only be reserved by a handshake process which this
528  * connection can now never complete.
529  * This prevents helpers hanging when their connections close.
530  *
531  * 2) pinning is expected to be removed and server conn closed
532  *
533  * The upstream link is authenticated with the same credentials.
534  * Expecting the same level of consistency we should have received.
535  * This prevents upstream being faced with multiple or missing
536  * credentials after authentication.
537  * NP: un-pin is left to the cleanup in ConnStateData::swanSong()
538  * we just trigger that cleanup here via comm_reset_close() or
539  * ConnStateData::stopReceiving()
540  *
541  * 3) the connection needs to close.
542  *
543  * This prevents attackers injecting requests into a connection,
544  * or gateways wrongly multiplexing users into a single connection.
545  *
546  * When credentials are missing closure needs to follow an auth
547  * challenge for best recovery by the client.
548  *
549  * When credentials change there is nothing we can do but abort as
550  * fast as possible. Sending TCP RST instead of an HTTP response
551  * is the best-case action.
552  */
553 
554  // clobbered with nul-pointer
555  if (aur == NULL) {
556  debugs(33, 2, "WARNING: Graceful closure on " << clientConnection << " due to connection-auth erase from " << by);
558  auth_ = NULL;
559  // XXX: need to test whether the connection re-auth challenge is sent. If not, how to trigger it from here.
560  // NP: the current situation seems to fix challenge loops in Safari without visible issues in others.
561  // we stop receiving more traffic but can leave the Job running to terminate after the error or challenge is delivered.
562  stopReceiving("connection-auth removed");
563  return;
564  }
565 
566  // clobbered with alternative credentials
567  if (aur != auth_) {
568  debugs(33, 2, "ERROR: Closing " << clientConnection << " due to change of connection-auth from " << by);
570  auth_ = NULL;
571  // this is a fatal type of problem.
572  // Close the connection immediately with TCP RST to abort all traffic flow
574  return;
575  }
576 
577  /* NOT REACHABLE */
578 }
579 #endif
580 
581 // cleans up before destructor is called
582 void
584 {
585  debugs(33, 2, HERE << clientConnection);
586  checkLogging();
587 
588  flags.readMore = false;
589  clientdbEstablished(clientConnection->remote, -1); /* decrement */
591 
592  // XXX: Closing pinned conn is too harsh: The Client may want to continue!
593  unpinConnection(true);
594 
595  Server::swanSong(); // closes the client connection
596 
597 #if USE_AUTH
598  // NP: do this bit after closing the connections to avoid side effects from unwanted TCP RST
599  setAuth(NULL, "ConnStateData::SwanSong cleanup");
600 #endif
601 
602  flags.swanSang = true;
603 }
604 
605 bool
607 {
608  return cbdataReferenceValid(this) && // XXX: checking "this" in a method
610  !fd_table[clientConnection->fd].closing();
611 }
612 
614 {
615  debugs(33, 3, HERE << clientConnection);
616 
617  if (isOpen())
618  debugs(33, DBG_IMPORTANT, "BUG: ConnStateData did not close " << clientConnection);
619 
620  if (!flags.swanSang)
621  debugs(33, DBG_IMPORTANT, "BUG: ConnStateData was not destroyed properly; " << clientConnection);
622 
623  if (bodyPipe != NULL)
624  stopProducingFor(bodyPipe, false);
625 
626  delete bodyParser; // TODO: pool
627 
628 #if USE_OPENSSL
629  delete sslServerBump;
630 #endif
631 }
632 
639 void
641 {
642  HttpRequest *request = http->request;
643 
644  debugs(33, 3, "http_ver = " << request->http_ver);
645  debugs(33, 3, "method = " << request->method);
646 
647  // TODO: move to HttpRequest::hdrCacheInit, just like HttpReply.
648  request->flags.proxyKeepalive = request->persistent();
649 }
650 
652 static int
654 {
655  // No Content-Length means this request just has no body, but conflicting
656  // Content-Lengths mean a message framing error (RFC 7230 Section 3.3.3 #4).
658  return 0;
659 
660  switch (r->method.id()) {
661 
662  case Http::METHOD_GET:
663 
664  case Http::METHOD_HEAD:
665  /* We do not want to see a request entity on GET/HEAD requests */
666  return (r->content_length <= 0 || Config.onoff.request_entities);
667 
668  default:
669  /* For other types of requests we don't care */
670  return 1;
671  }
672 
673  /* NOT REACHED */
674 }
675 
676 int
678 {
680  bodyLength > Config.maxRequestBodySize)
681  return 1; /* too large */
682 
683  return 0;
684 }
685 
686 bool
688 {
689  return request->multipartRangeRequest();
690 }
691 
692 void
694 {
695  mb->appendf("\r\n--" SQUIDSTRINGPH "--\r\n", SQUIDSTRINGPRINT(boundary));
696  debugs(33, 6, "buf offset: " << mb->size);
697 }
698 
699 void
700 clientPackRangeHdr(const HttpReplyPointer &rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb)
701 {
702  HttpHeader hdr(hoReply);
703  assert(rep);
704  assert(spec);
705 
706  /* put boundary */
707  debugs(33, 5, "appending boundary: " << boundary);
708  /* rfc2046 requires to _prepend_ boundary with <crlf>! */
709  mb->appendf("\r\n--" SQUIDSTRINGPH "\r\n", SQUIDSTRINGPRINT(boundary));
710 
711  /* stuff the header with required entries and pack it */
712 
713  if (rep->header.has(Http::HdrType::CONTENT_TYPE))
715 
716  httpHeaderAddContRange(&hdr, *spec, rep->content_length);
717 
718  hdr.packInto(mb);
719  hdr.clean();
720 
721  /* append <crlf> (we packed a header, not a reply) */
722  mb->append("\r\n", 2);
723 }
724 
730 int
732 {
733  int64_t clen = 0;
734  MemBuf mb;
735 
736  assert(memObject());
737 
738  mb.init();
740 
741  while (pos != request->range->end()) {
742  /* account for headers for this range */
743  mb.reset();
744  clientPackRangeHdr(memObject()->getReply(),
745  *pos, range_iter.boundary, &mb);
746  clen += mb.size;
747 
748  /* account for range content */
749  clen += (*pos)->length;
750 
751  debugs(33, 6, "clientMRangeCLen: (clen += " << mb.size << " + " << (*pos)->length << ") == " << clen);
752  ++pos;
753  }
754 
755  /* account for the terminating boundary */
756  mb.reset();
757 
759 
760  clen += mb.size;
761 
762  mb.clean();
763 
764  return clen;
765 }
766 
770 String
772 {
773  const char *key;
774  String b(APP_FULLNAME);
775  b.append(":",1);
776  key = storeEntry()->getMD5Text();
777  b.append(key, strlen(key));
778  return b;
779 }
780 
790 void
792  HttpReply * rep, StoreIOBuffer receivedData)
793 {
794  // do not try to deliver if client already ABORTED
795  if (!http->getConn() || !cbdataReferenceValid(http->getConn()) || !Comm::IsConnOpen(http->getConn()->clientConnection))
796  return;
797 
798  /* Test preconditions */
799  assert(node != NULL);
801  /* TODO: handle this rather than asserting
802  * - it should only ever happen if we cause an abort and
803  * the callback chain loops back to here, so we can simply return.
804  * However, that itself shouldn't happen, so it stays as an assert for now.
805  */
807  assert(node->node.next == NULL);
808  Http::StreamPointer context = dynamic_cast<Http::Stream *>(node->data.getRaw());
809  assert(context != NULL);
810 
811  /* TODO: check offset is what we asked for */
812 
813  // TODO: enforces HTTP/1 MUST on pipeline order, but is irrelevant to HTTP/2
814  if (context != http->getConn()->pipeline.front())
815  context->deferRecipientForLater(node, rep, receivedData);
816  else if (http->getConn()->cbControlMsgSent) // 1xx to the user is pending
817  context->deferRecipientForLater(node, rep, receivedData);
818  else
819  http->getConn()->handleReply(rep, receivedData);
820 
822 }
823 
829 void
831 {
832  /* Test preconditions */
833  assert(node != NULL);
834  /* TODO: handle this rather than asserting
835  * - it should only ever happen if we cause an abort and
836  * the callback chain loops back to here, so we can simply return.
837  * However, that itself shouldn't happen, so it stays as an assert for now.
838  */
840  /* Set null by ContextFree */
841  assert(node->node.next == NULL);
842  /* this is the assert discussed above */
843  assert(NULL == dynamic_cast<Http::Stream *>(node->data.getRaw()));
844  /* We are only called when the client socket shutsdown.
845  * Tell the prev pipeline member we're finished
846  */
847  clientStreamDetach(node, http);
848 }
849 
850 void
852 {
853  debugs(33, 5, HERE << clientConnection << " reading next req");
854 
855  fd_note(clientConnection->fd, "Idle client: Waiting for next request");
860  AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
861  TimeoutDialer, this, ConnStateData::requestTimeout);
863 
864  readSomeData();
866 }
867 
868 static void
870 {
871  debugs(33, 2, HERE << conn->clientConnection << " Sending next");
872 
875  if (deferredRequest->flags.deferred) {
877  assert(deferredRequest->http->out.size == 0);
879  clientSocketRecipient(deferredRequest->deferredparams.node,
880  deferredRequest->http,
881  deferredRequest->deferredparams.rep,
882  deferredRequest->deferredparams.queuedBuffer);
883  }
884 
888 }
889 
890 void
892 {
894  debugs(33, 2, clientConnection << " Connection was closed");
895  return;
896  }
897 
898  if (pinning.pinned && !Comm::IsConnOpen(pinning.serverConnection)) {
899  debugs(33, 2, clientConnection << " Connection was pinned but server side gone. Terminating client connection");
901  return;
902  }
903 
918  if (const char *reason = stoppedReceiving()) {
919  debugs(33, 3, "closing for earlier request error: " << reason);
921  return;
922  }
923 
934  if (clientParseRequests()) {
935  debugs(33, 3, clientConnection << ": parsed next request from buffer");
936  }
937 
946  debugs(33, 3, "half-closed client with no pending requests, closing");
948  return;
949  }
950 
958  Http::StreamPointer deferredRequest = pipeline.front();
959  if (deferredRequest != nullptr) {
960  debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded");
961  ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
962  } else if (flags.readMore) {
963  debugs(33, 3, clientConnection << ": calling readNextRequest()");
964  readNextRequest();
965  } else {
966  // XXX: Can this happen? CONNECT tunnels have deferredRequest set.
967  debugs(33, DBG_IMPORTANT, MYNAME << "abandoning " << clientConnection);
968  }
969 }
970 
971 void
973 {
974  debugs(33, 4, HERE << "sending error (" << clientConnection << "): " << error <<
975  "; old receiving error: " <<
976  (stoppedReceiving() ? stoppedReceiving_ : "none"));
977 
978  if (const char *oldError = stoppedSending()) {
979  debugs(33, 3, HERE << "already stopped sending: " << oldError);
980  return; // nothing has changed as far as this connection is concerned
981  }
983 
984  if (!stoppedReceiving()) {
985  if (const int64_t expecting = mayNeedToReadMoreBody()) {
986  debugs(33, 5, HERE << "must still read " << expecting <<
987  " request body bytes with " << inBuf.length() << " unused");
988  return; // wait for the request receiver to finish reading
989  }
990  }
991 
993 }
994 
995 void
997 {
998  if (pipeline.empty())
999  return;
1000 
1001  auto ctx = pipeline.front();
1002  if (size) {
1004  if (ctx->http->logType.isTcpHit())
1006  }
1007  ctx->writeComplete(size);
1008 }
1009 
1010 Http::Stream *
1012 {
1013  ClientHttpRequest *http = new ClientHttpRequest(this);
1014  http->req_sz = inBuf.length();
1015  http->uri = xstrdup(uri);
1016  setLogUri (http, uri);
1017  auto *context = new Http::Stream(clientConnection, http);
1018  StoreIOBuffer tempBuffer;
1019  tempBuffer.data = context->reqbuf;
1020  tempBuffer.length = HTTP_REQBUF_SZ;
1023  clientSocketDetach, context, tempBuffer);
1024  return context;
1025 }
1026 
1027 void
1029 {
1030  // RegisteredRunner API callback - Squid has been shut down
1031 
1032  // if connection is idle terminate it now,
1033  // otherwise wait for grace period to end
1034  if (pipeline.empty())
1035  endingShutdown();
1036 }
1037 
1038 void
1040 {
1041  // RegisteredRunner API callback - Squid shutdown grace period is over
1042 
1043  // force the client connection to close immediately
1044  // swanSong() in the close handler will cleanup.
1047 }
1048 
1049 char *
1050 skipLeadingSpace(char *aString)
1051 {
1052  char *result = aString;
1053 
1054  while (xisspace(*aString))
1055  ++aString;
1056 
1057  return result;
1058 }
1059 
1065 const char *
1066 findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end)
1067 {
1068  if (NULL == end) {
1069  end = uriAndHTTPVersion + strcspn(uriAndHTTPVersion, "\r\n");
1070  assert(end);
1071  }
1072 
1073  for (; end > uriAndHTTPVersion; --end) {
1074  if (*end == '\n' || *end == '\r')
1075  continue;
1076 
1077  if (xisspace(*end)) {
1078  if (strncasecmp(end + 1, "HTTP/", 5) == 0)
1079  return end + 1;
1080  else
1081  break;
1082  }
1083  }
1084 
1085  return NULL;
1086 }
1087 
1088 void
1089 setLogUri(ClientHttpRequest * http, char const *uri, bool cleanUrl)
1090 {
1091  safe_free(http->log_uri);
1092 
1093  if (!cleanUrl)
1094  // The uri is already clean just dump it.
1095  http->log_uri = xstrndup(uri, MAX_URL);
1096  else {
1097  int flags = 0;
1098  switch (Config.uri_whitespace) {
1099  case URI_WHITESPACE_ALLOW:
1100  flags |= RFC1738_ESCAPE_NOSPACE;
1101 
1102  case URI_WHITESPACE_ENCODE:
1103  flags |= RFC1738_ESCAPE_UNESCAPED;
1104  http->log_uri = xstrndup(rfc1738_do_escape(uri, flags), MAX_URL);
1105  break;
1106 
1107  case URI_WHITESPACE_CHOP: {
1108  flags |= RFC1738_ESCAPE_NOSPACE;
1109  flags |= RFC1738_ESCAPE_UNESCAPED;
1110  http->log_uri = xstrndup(rfc1738_do_escape(uri, flags), MAX_URL);
1111  int pos = strcspn(http->log_uri, w_space);
1112  http->log_uri[pos] = '\0';
1113  }
1114  break;
1115 
1116  case URI_WHITESPACE_DENY:
1117  case URI_WHITESPACE_STRIP:
1118  default: {
1119  const char *t;
1120  char *tmp_uri = static_cast<char*>(xmalloc(strlen(uri) + 1));
1121  char *q = tmp_uri;
1122  t = uri;
1123  while (*t) {
1124  if (!xisspace(*t)) {
1125  *q = *t;
1126  ++q;
1127  }
1128  ++t;
1129  }
1130  *q = '\0';
1131  http->log_uri = xstrndup(rfc1738_escape_unescaped(tmp_uri), MAX_URL);
1132  xfree(tmp_uri);
1133  }
1134  break;
1135  }
1136  }
1137 }
1138 
1139 static void
1141 {
1142  int vhost = conn->port->vhost;
1143  int vport = conn->port->vport;
1144  static char ipbuf[MAX_IPSTRLEN];
1145 
1146  http->flags.accel = true;
1147 
1148  /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
1149 
1150  static const SBuf cache_object("cache_object://");
1151  if (hp->requestUri().startsWith(cache_object))
1152  return; /* already in good shape */
1153 
1154  // XXX: re-use proper URL parser for this
1155  SBuf url = hp->requestUri(); // use full provided URI if we abort
1156  do { // use a loop so we can break out of it
1157  ::Parser::Tokenizer tok(url);
1158  if (tok.skip('/')) // origin-form URL already.
1159  break;
1160 
1161  if (conn->port->vhost)
1162  return; /* already in good shape */
1163 
1164  // skip the URI scheme
1165  static const CharacterSet uriScheme = CharacterSet("URI-scheme","+-.") + CharacterSet::ALPHA + CharacterSet::DIGIT;
1166  static const SBuf uriSchemeEnd("://");
1167  if (!tok.skipAll(uriScheme) || !tok.skip(uriSchemeEnd))
1168  break;
1169 
1170  // skip the authority segment
1171  // RFC 3986 complex nested ABNF for "authority" boils down to this:
1172  static const CharacterSet authority = CharacterSet("authority","-._~%:@[]!$&'()*+,;=") +
1174  if (!tok.skipAll(authority))
1175  break;
1176 
1177  static const SBuf slashUri("/");
1178  const SBuf t = tok.remaining();
1179  if (t.isEmpty())
1180  url = slashUri;
1181  else if (t[0]=='/') // looks like path
1182  url = t;
1183  else if (t[0]=='?' || t[0]=='#') { // looks like query or fragment. fix '/'
1184  url = slashUri;
1185  url.append(t);
1186  } // else do nothing. invalid path
1187 
1188  } while(false);
1189 
1190 #if SHOULD_REJECT_UNKNOWN_URLS
1191  // reject URI which are not well-formed even after the processing above
1192  if (url.isEmpty() || url[0] != '/') {
1193  hp->parseStatusCode = Http::scBadRequest;
1194  return conn->abortRequestParsing("error:invalid-request");
1195  }
1196 #endif
1197 
1198  if (vport < 0)
1199  vport = http->getConn()->clientConnection->local.port();
1200 
1201  const bool switchedToHttps = conn->switchedToHttps();
1202  const bool tryHostHeader = vhost || switchedToHttps;
1203  char *host = NULL;
1204  if (tryHostHeader && (host = hp->getHeaderField("Host"))) {
1205  debugs(33, 5, "ACCEL VHOST REWRITE: vhost=" << host << " + vport=" << vport);
1206  char thost[256];
1207  if (vport > 0) {
1208  thost[0] = '\0';
1209  char *t = NULL;
1210  if (host[strlen(host)] != ']' && (t = strrchr(host,':')) != NULL) {
1211  strncpy(thost, host, (t-host));
1212  snprintf(thost+(t-host), sizeof(thost)-(t-host), ":%d", vport);
1213  host = thost;
1214  } else if (!t) {
1215  snprintf(thost, sizeof(thost), "%s:%d",host, vport);
1216  host = thost;
1217  }
1218  } // else nothing to alter port-wise.
1219  const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen + strlen(host);
1220  http->uri = (char *)xcalloc(url_sz, 1);
1221  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1222  snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s" SQUIDSBUFPH, SQUIDSBUFPRINT(scheme), host, SQUIDSBUFPRINT(url));
1223  debugs(33, 5, "ACCEL VHOST REWRITE: " << http->uri);
1224  } else if (conn->port->defaultsite /* && !vhost */) {
1225  debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: defaultsite=" << conn->port->defaultsite << " + vport=" << vport);
1226  const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen +
1227  strlen(conn->port->defaultsite);
1228  http->uri = (char *)xcalloc(url_sz, 1);
1229  char vportStr[32];
1230  vportStr[0] = '\0';
1231  if (vport > 0) {
1232  snprintf(vportStr, sizeof(vportStr),":%d",vport);
1233  }
1234  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1235  snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s%s" SQUIDSBUFPH,
1236  SQUIDSBUFPRINT(scheme), conn->port->defaultsite, vportStr, SQUIDSBUFPRINT(url));
1237  debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: " << http->uri);
1238  } else if (vport > 0 /* && (!vhost || no Host:) */) {
1239  debugs(33, 5, "ACCEL VPORT REWRITE: *_port IP + vport=" << vport);
1240  /* Put the local socket IP address as the hostname, with whatever vport we found */
1241  const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen;
1242  http->uri = (char *)xcalloc(url_sz, 1);
1244  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1245  snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
1246  SQUIDSBUFPRINT(scheme), ipbuf, vport, SQUIDSBUFPRINT(url));
1247  debugs(33, 5, "ACCEL VPORT REWRITE: " << http->uri);
1248  }
1249 }
1250 
1251 static void
1253 {
1254  // TODO Must() on URI !empty when the parser supports throw. For now avoid assert().
1255  if (!hp->requestUri().isEmpty() && hp->requestUri()[0] != '/')
1256  return; /* already in good shape */
1257 
1258  /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
1259 
1260  if (const char *host = hp->getHeaderField("Host")) {
1261  const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen +
1262  strlen(host);
1263  http->uri = (char *)xcalloc(url_sz, 1);
1264  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1265  snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s" SQUIDSBUFPH,
1266  SQUIDSBUFPRINT(scheme), host, SQUIDSBUFPRINT(hp->requestUri()));
1267  debugs(33, 5, "TRANSPARENT HOST REWRITE: " << http->uri);
1268  } else {
1269  /* Put the local socket IP address as the hostname. */
1270  const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen;
1271  http->uri = (char *)xcalloc(url_sz, 1);
1272  static char ipbuf[MAX_IPSTRLEN];
1274  const SBuf &scheme = AnyP::UriScheme(http->getConn()->transferProtocol.protocol).image();
1275  snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
1276  SQUIDSBUFPRINT(scheme),
1277  ipbuf, http->getConn()->clientConnection->local.port(), SQUIDSBUFPRINT(hp->requestUri()));
1278  debugs(33, 5, "TRANSPARENT REWRITE: " << http->uri);
1279  }
1280 }
1281 
1295 Http::Stream *
1297 {
1298  /* Attempt to parse the first line; this will define where the method, url, version and header begin */
1299  {
1300  const bool parsedOk = hp->parse(csd->inBuf);
1301 
1302  // sync the buffers after parsing.
1303  csd->inBuf = hp->remaining();
1304 
1305  if (hp->needsMoreData()) {
1306  debugs(33, 5, "Incomplete request, waiting for end of request line");
1307  return NULL;
1308  }
1309 
1310  if (csd->mayTunnelUnsupportedProto()) {
1311  csd->preservedClientData = hp->parsed();
1312  csd->preservedClientData.append(csd->inBuf);
1313  }
1314 
1315  if (!parsedOk) {
1316  const bool tooBig =
1317  hp->parseStatusCode == Http::scRequestHeaderFieldsTooLarge ||
1318  hp->parseStatusCode == Http::scUriTooLong;
1319  auto result = csd->abortRequestParsing(
1320  tooBig ? "error:request-too-large" : "error:invalid-request");
1321  // assume that remaining leftovers belong to this bad request
1322  if (!csd->inBuf.isEmpty())
1323  csd->consumeInput(csd->inBuf.length());
1324  return result;
1325  }
1326  }
1327 
1328  /* We know the whole request is in parser now */
1329  debugs(11, 2, "HTTP Client " << csd->clientConnection);
1330  debugs(11, 2, "HTTP Client REQUEST:\n---------\n" <<
1331  hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol() << "\n" <<
1332  hp->mimeHeader() <<
1333  "\n----------");
1334 
1335  /* deny CONNECT via accelerated ports */
1336  if (hp->method() == Http::METHOD_CONNECT && csd->port != NULL && csd->port->flags.accelSurrogate) {
1337  debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << csd->transferProtocol << " Accelerator port " << csd->port->s.port());
1338  debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1339  hp->parseStatusCode = Http::scMethodNotAllowed;
1340  return csd->abortRequestParsing("error:method-not-allowed");
1341  }
1342 
1343  /* RFC 7540 section 11.6 registers the method PRI as HTTP/2 specific
1344  * Deny "PRI" method if used in HTTP/1.x or 0.9 versions.
1345  * If seen it signals a broken client or proxy has corrupted the traffic.
1346  */
1347  if (hp->method() == Http::METHOD_PRI && hp->messageProtocol() < Http::ProtocolVersion(2,0)) {
1348  debugs(33, DBG_IMPORTANT, "WARNING: PRI method received on " << csd->transferProtocol << " port " << csd->port->s.port());
1349  debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1350  hp->parseStatusCode = Http::scMethodNotAllowed;
1351  return csd->abortRequestParsing("error:method-not-allowed");
1352  }
1353 
1354  if (hp->method() == Http::METHOD_NONE) {
1355  debugs(33, DBG_IMPORTANT, "WARNING: Unsupported method: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1356  hp->parseStatusCode = Http::scMethodNotAllowed;
1357  return csd->abortRequestParsing("error:unsupported-request-method");
1358  }
1359 
1360  // Process headers after request line
1361  debugs(33, 3, "complete request received. " <<
1362  "prefix_sz = " << hp->messageHeaderSize() <<
1363  ", request-line-size=" << hp->firstLineSize() <<
1364  ", mime-header-size=" << hp->headerBlockSize() <<
1365  ", mime header block:\n" << hp->mimeHeader() << "\n----------");
1366 
1367  /* Ok, all headers are received */
1368  ClientHttpRequest *http = new ClientHttpRequest(csd);
1369 
1370  http->req_sz = hp->messageHeaderSize();
1371  Http::Stream *result = new Http::Stream(csd->clientConnection, http);
1372 
1373  StoreIOBuffer tempBuffer;
1374  tempBuffer.data = result->reqbuf;
1375  tempBuffer.length = HTTP_REQBUF_SZ;
1376 
1377  ClientStreamData newServer = new clientReplyContext(http);
1378  ClientStreamData newClient = result;
1379  clientStreamInit(&http->client_stream, clientGetMoreData, clientReplyDetach,
1381  clientSocketDetach, newClient, tempBuffer);
1382 
1383  /* set url */
1384  debugs(33,5, "Prepare absolute URL from " <<
1385  (csd->transparent()?"intercept":(csd->port->flags.accelSurrogate ? "accel":"")));
1386  /* Rewrite the URL in transparent or accelerator mode */
1387  /* NP: there are several cases to traverse here:
1388  * - standard mode (forward proxy)
1389  * - transparent mode (TPROXY)
1390  * - transparent mode with failures
1391  * - intercept mode (NAT)
1392  * - intercept mode with failures
1393  * - accelerator mode (reverse proxy)
1394  * - internal relative-URL
1395  * - mixed combos of the above with internal URL
1396  * - remote interception with PROXY protocol
1397  * - remote reverse-proxy with PROXY protocol
1398  */
1399  if (csd->transparent()) {
1400  /* intercept or transparent mode, properly working with no failures */
1401  prepareTransparentURL(csd, http, hp);
1402 
1403  } else if (internalCheck(hp->requestUri())) { // NP: only matches relative-URI
1404  /* internal URL mode */
1405  /* prepend our name & port */
1406  http->uri = xstrdup(internalLocalUri(NULL, hp->requestUri()));
1407  // We just re-wrote the URL. Must replace the Host: header.
1408  // But have not parsed there yet!! flag for local-only handling.
1409  http->flags.internal = true;
1410 
1411  } else if (csd->port->flags.accelSurrogate || csd->switchedToHttps()) {
1412  /* accelerator mode */
1413  prepareAcceleratedURL(csd, http, hp);
1414  }
1415 
1416  if (!http->uri) {
1417  /* No special rewrites have been applied above, use the
1418  * requested url. may be rewritten later, so make extra room */
1419  int url_sz = hp->requestUri().length() + Config.appendDomainLen + 5;
1420  http->uri = (char *)xcalloc(url_sz, 1);
1421  SBufToCstring(http->uri, hp->requestUri());
1422  }
1423 
1424  result->flags.parsed_ok = 1;
1425  return result;
1426 }
1427 
1428 bool
1430 {
1431  if (size == 0) {
1432  if (pipeline.empty() && inBuf.isEmpty()) {
1433  /* no current or pending requests */
1434  debugs(33, 4, HERE << clientConnection << " closed");
1435  return true;
1436  } else if (!Config.onoff.half_closed_clients) {
1437  /* admin doesn't want to support half-closed client sockets */
1438  debugs(33, 3, HERE << clientConnection << " aborted (half_closed_clients disabled)");
1440  return true;
1441  }
1442  }
1443 
1444  return false;
1445 }
1446 
1447 void
1448 ConnStateData::consumeInput(const size_t byteCount)
1449 {
1450  assert(byteCount > 0 && byteCount <= inBuf.length());
1451  inBuf.consume(byteCount);
1452  debugs(33, 5, "inBuf has " << inBuf.length() << " unused bytes");
1453 }
1454 
1455 void
1457 {
1458  // Were we expecting to read more request body from half-closed connection?
1460  debugs(33, 3, HERE << "truncated body: closing half-closed " << clientConnection);
1462  return;
1463  }
1464 
1465  if (flags.readMore)
1466  readSomeData();
1467 }
1468 
1469 void
1471 {
1472  // From HTTP p.o.v., we do not have to close after every error detected
1473  // at the client-side, but many such errors do require closure and the
1474  // client-side code is bad at handling errors so we play it safe.
1475  if (request)
1476  request->flags.proxyKeepalive = false;
1477  flags.readMore = false;
1478  debugs(33,4, HERE << "Will close after error: " << clientConnection);
1479 }
1480 
1481 #if USE_OPENSSL
1483 {
1484  ClientHttpRequest *http = context->http;
1485 
1486  if (!sslServerBump)
1487  return false;
1488 
1490  // Did we create an error entry while processing CONNECT?
1491  if (!sslServerBump->entry->isEmpty()) {
1492  quitAfterError(http->request);
1493 
1494  // Get the saved error entry and send it to the client by replacing the
1495  // ClientHttpRequest store entry with it.
1497  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1498  assert(repContext);
1499  debugs(33, 5, "Responding with delated error for " << http->uri);
1500  repContext->setReplyToStoreEntry(sslServerBump->entry, "delayed SslBump error");
1501 
1502  // save the original request for logging purposes
1503  if (!context->http->al->request) {
1504  context->http->al->request = http->request;
1505  HTTPMSGLOCK(context->http->al->request);
1506  }
1507 
1508  // Get error details from the fake certificate-peeking request.
1510  context->pullData();
1511  return true;
1512  }
1513 
1514  // In bump-server-first mode, we have not necessarily seen the intended
1515  // server name at certificate-peeking time. Check for domain mismatch now,
1516  // when we can extract the intended name from the bumped HTTP request.
1517  if (const Security::CertPointer &srvCert = sslServerBump->serverCert) {
1518  HttpRequest *request = http->request;
1519  if (!Ssl::checkX509ServerValidity(srvCert.get(), request->url.host())) {
1520  debugs(33, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " <<
1521  "does not match domainname " << request->url.host());
1522 
1523  bool allowDomainMismatch = false;
1526  check.al = http->al;
1528  check.syncAle(request, http->log_uri);
1529  allowDomainMismatch = check.fastCheck().allowed();
1530  delete check.sslErrors;
1531  check.sslErrors = NULL;
1532  }
1533 
1534  if (!allowDomainMismatch) {
1535  quitAfterError(request);
1536 
1538  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1539  assert (repContext);
1540 
1541  request->hier = sslServerBump->request->hier;
1542 
1543  // Create an error object and fill it
1546  Ssl::ErrorDetail *errDetail = new Ssl::ErrorDetail(
1548  srvCert.get(), nullptr);
1549  err->detail = errDetail;
1550  // Save the original request for logging purposes.
1551  if (!context->http->al->request) {
1552  context->http->al->request = request;
1553  HTTPMSGLOCK(context->http->al->request);
1554  }
1555  repContext->setReplyToError(request->method, err);
1556  assert(context->http->out.offset == 0);
1557  context->pullData();
1558  return true;
1559  }
1560  }
1561  }
1562 
1563  return false;
1564 }
1565 #endif // USE_OPENSSL
1566 
1571 bool
1573 {
1574  if (conn->mayTunnelUnsupportedProto()) {
1575  ACLFilledChecklist checklist(Config.accessList.on_unsupported_protocol, request.getRaw(), nullptr);
1576  checklist.al = (context && context->http) ? context->http->al : nullptr;
1577  checklist.requestErrorType = requestError;
1578  checklist.src_addr = conn->clientConnection->remote;
1579  checklist.my_addr = conn->clientConnection->local;
1580  checklist.conn(conn);
1581  ClientHttpRequest *http = context ? context->http : nullptr;
1582  const char *log_uri = http ? http->log_uri : nullptr;
1583  checklist.syncAle(request.getRaw(), log_uri);
1584  allow_t answer = checklist.fastCheck();
1585  if (answer.allowed() && answer.kind == 1) {
1586  debugs(33, 3, "Request will be tunneled to server");
1587  if (context) {
1588  assert(conn->pipeline.front() == context); // XXX: still assumes HTTP/1 semantics
1589  context->finished(); // Will remove from conn->pipeline queue
1590  }
1592  return conn->initiateTunneledRequest(request, Http::METHOD_NONE, "unknown-protocol", conn->preservedClientData);
1593  } else {
1594  debugs(33, 3, "Continue with returning the error: " << requestError);
1595  }
1596  }
1597 
1598  return false;
1599 }
1600 
1601 void
1603 {
1604  /*
1605  * DPW 2007-05-18
1606  * Moved the TCP_RESET feature from clientReplyContext::sendMoreData
1607  * to here because calling comm_reset_close() causes http to
1608  * be freed before accessing.
1609  */
1610  if (request != NULL && request->flags.resetTcp && Comm::IsConnOpen(conn->clientConnection)) {
1611  debugs(33, 3, HERE << "Sending TCP RST on " << conn->clientConnection);
1612  conn->flags.readMore = false;
1614  }
1615 }
1616 
1617 void
1619 {
1620  ClientHttpRequest *http = context->http;
1621  bool chunked = false;
1622  bool mustReplyToOptions = false;
1623  bool unsupportedTe = false;
1624  bool expectBody = false;
1625 
1626  // We already have the request parsed and checked, so we
1627  // only need to go through the final body/conn setup to doCallouts().
1628  assert(http->request);
1630 
1631  // temporary hack to avoid splitting this huge function with sensitive code
1632  const bool isFtp = !hp;
1633 
1634  // Some blobs below are still HTTP-specific, but we would have to rewrite
1635  // this entire function to remove them from the FTP code path. Connection
1636  // setup and body_pipe preparation blobs are needed for FTP.
1637 
1638  request->manager(conn, http->al);
1639 
1640  request->flags.accelerated = http->flags.accel;
1641  request->flags.sslBumped=conn->switchedToHttps();
1642  // TODO: decouple http->flags.accel from request->flags.sslBumped
1643  request->flags.noDirect = (request->flags.accelerated && !request->flags.sslBumped) ?
1644  !conn->port->allow_direct : 0;
1645  request->sources |= isFtp ? Http::Message::srcFtp :
1646  ((request->flags.sslBumped || conn->port->transport.protocol == AnyP::PROTO_HTTPS) ? Http::Message::srcHttps : Http::Message::srcHttp);
1647 #if USE_AUTH
1648  if (request->flags.sslBumped) {
1649  if (conn->getAuth() != NULL)
1650  request->auth_user_request = conn->getAuth();
1651  }
1652 #endif
1653 
1654  if (internalCheck(request->url.path())) {
1655  if (internalHostnameIs(request->url.host()) && request->url.port() == getMyPort()) {
1656  debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true));
1657  http->flags.internal = true;
1658  } else if (Config.onoff.global_internal_static && internalStaticCheck(request->url.path())) {
1659  debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (global_internal_static on)");
1660  request->url.setScheme(AnyP::PROTO_HTTP, "http");
1661  request->url.host(internalHostname());
1662  request->url.port(getMyPort());
1663  http->flags.internal = true;
1664  } else
1665  debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (not this proxy)");
1666  }
1667 
1668  request->flags.internal = http->flags.internal;
1669  setLogUri (http, urlCanonicalClean(request.getRaw()));
1670 
1671  if (!isFtp) {
1672  // XXX: for non-HTTP messages instantiate a different Http::Message child type
1673  // for now Squid only supports HTTP requests
1674  const AnyP::ProtocolVersion &http_ver = hp->messageProtocol();
1675  assert(request->http_ver.protocol == http_ver.protocol);
1676  request->http_ver.major = http_ver.major;
1677  request->http_ver.minor = http_ver.minor;
1678  }
1679 
1680  if (request->header.chunked()) {
1681  chunked = true;
1682  } else if (request->header.has(Http::HdrType::TRANSFER_ENCODING)) {
1684  // HTTP/1.1 requires chunking to be the last encoding if there is one
1685  unsupportedTe = te.size() && te != "identity";
1686  } // else implied identity coding
1687 
1688  mustReplyToOptions = (request->method == Http::METHOD_OPTIONS) &&
1689  (request->header.getInt64(Http::HdrType::MAX_FORWARDS) == 0);
1690  if (!urlCheckRequest(request.getRaw()) || mustReplyToOptions || unsupportedTe) {
1692  conn->quitAfterError(request.getRaw());
1693  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1694  assert (repContext);
1696  conn->clientConnection->remote, request.getRaw(), NULL, NULL);
1697  assert(context->http->out.offset == 0);
1698  context->pullData();
1699  clientProcessRequestFinished(conn, request);
1700  return;
1701  }
1702 
1703  if (!chunked && !clientIsContentLengthValid(request.getRaw())) {
1705  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1706  assert (repContext);
1707  conn->quitAfterError(request.getRaw());
1708  repContext->setReplyToError(ERR_INVALID_REQ,
1709  Http::scLengthRequired, request->method, NULL,
1710  conn->clientConnection->remote, request.getRaw(), NULL, NULL);
1711  assert(context->http->out.offset == 0);
1712  context->pullData();
1713  clientProcessRequestFinished(conn, request);
1714  return;
1715  }
1716 
1717  clientSetKeepaliveFlag(http);
1718  // Let tunneling code be fully responsible for CONNECT requests
1719  if (http->request->method == Http::METHOD_CONNECT) {
1720  context->mayUseConnection(true);
1721  conn->flags.readMore = false;
1722  }
1723 
1724 #if USE_OPENSSL
1725  if (conn->switchedToHttps() && conn->serveDelayedError(context)) {
1726  clientProcessRequestFinished(conn, request);
1727  return;
1728  }
1729 #endif
1730 
1731  /* Do we expect a request-body? */
1732  expectBody = chunked || request->content_length > 0;
1733  if (!context->mayUseConnection() && expectBody) {
1734  request->body_pipe = conn->expectRequestBody(
1735  chunked ? -1 : request->content_length);
1736 
1737  /* Is it too large? */
1738  if (!chunked && // if chunked, we will check as we accumulate
1741  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1742  assert (repContext);
1743  conn->quitAfterError(request.getRaw());
1744  repContext->setReplyToError(ERR_TOO_BIG,
1746  conn->clientConnection->remote, http->request, NULL, NULL);
1747  assert(context->http->out.offset == 0);
1748  context->pullData();
1749  clientProcessRequestFinished(conn, request);
1750  return;
1751  }
1752 
1753  if (!isFtp) {
1754  // We may stop producing, comm_close, and/or call setReplyToError()
1755  // below, so quit on errors to avoid http->doCallouts()
1756  if (!conn->handleRequestBodyData()) {
1757  clientProcessRequestFinished(conn, request);
1758  return;
1759  }
1760 
1761  if (!request->body_pipe->productionEnded()) {
1762  debugs(33, 5, "need more request body");
1763  context->mayUseConnection(true);
1764  assert(conn->flags.readMore);
1765  }
1766  }
1767  }
1768 
1769  http->calloutContext = new ClientRequestContext(http);
1770 
1771  http->doCallouts();
1772 
1773  clientProcessRequestFinished(conn, request);
1774 }
1775 
1776 int
1778 {
1779  // TODO: Support pipelined requests through pinned connections.
1780  if (pinning.pinned)
1781  return 0;
1783 }
1784 
1790 bool
1792 {
1793  const int existingRequestCount = pipeline.count();
1794 
1795  // default to the configured pipeline size.
1796  // add 1 because the head of pipeline is counted in concurrent requests and not prefetch queue
1797 #if USE_OPENSSL
1798  const int internalRequest = (transparent() && sslBumpMode == Ssl::bumpSplice) ? 1 : 0;
1799 #else
1800  const int internalRequest = 0;
1801 #endif
1802  const int concurrentRequestLimit = pipelinePrefetchMax() + 1 + internalRequest;
1803 
1804  // when queue filled already we cant add more.
1805  if (existingRequestCount >= concurrentRequestLimit) {
1806  debugs(33, 3, clientConnection << " max concurrent requests reached (" << concurrentRequestLimit << ")");
1807  debugs(33, 5, clientConnection << " deferring new request until one is done");
1808  return true;
1809  }
1810 
1811  return false;
1812 }
1813 
1819 bool
1821 {
1823  return proxyProtocolError("PROXY client not permitted by default ACL");
1824 
1828  ch.conn(this);
1829 
1830  if (!ch.fastCheck().allowed())
1831  return proxyProtocolError("PROXY client not permitted by ACLs");
1832 
1833  return true;
1834 }
1835 
1841 bool
1843 {
1844  if (msg) {
1845  // This is important to know, but maybe not so much that flooding the log is okay.
1846 #if QUIET_PROXY_PROTOCOL
1847  // display the first of every 32 occurances at level 1, the others at level 2.
1848  static uint8_t hide = 0;
1849  debugs(33, (hide++ % 32 == 0 ? DBG_IMPORTANT : 2), msg << " from " << clientConnection);
1850 #else
1851  debugs(33, DBG_IMPORTANT, msg << " from " << clientConnection);
1852 #endif
1853  mustStop(msg);
1854  }
1855  return false;
1856 }
1857 
1859 static const SBuf Proxy1p0magic("PROXY ", 6);
1860 
1862 static const SBuf Proxy2p0magic("\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A", 12);
1863 
1868 bool
1870 {
1871  // http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
1872 
1873  // detect and parse PROXY/2.0 protocol header
1875  return parseProxy2p0();
1876 
1877  // detect and parse PROXY/1.0 protocol header
1879  return parseProxy1p0();
1880 
1881  // detect and terminate other protocols
1882  if (inBuf.length() >= Proxy2p0magic.length()) {
1883  // PROXY/1.0 magic is shorter, so we know that
1884  // the input does not start with any PROXY magic
1885  return proxyProtocolError("PROXY protocol error: invalid header");
1886  }
1887 
1888  // TODO: detect short non-magic prefixes earlier to avoid
1889  // waiting for more data which may never come
1890 
1891  // not enough bytes to parse yet.
1892  return false;
1893 }
1894 
1896 bool
1898 {
1900  tok.skip(Proxy1p0magic);
1901 
1902  // skip to first LF (assumes it is part of CRLF)
1903  static const CharacterSet lineContent = CharacterSet::LF.complement("non-LF");
1904  SBuf line;
1905  if (tok.prefix(line, lineContent, 107-Proxy1p0magic.length())) {
1906  if (tok.skip('\n')) {
1907  // found valid header
1908  inBuf = tok.remaining();
1909  needProxyProtocolHeader_ = false;
1910  // reset the tokenizer to work on found line only.
1911  tok.reset(line);
1912  } else
1913  return false; // no LF yet
1914 
1915  } else // protocol error only if there are more than 107 bytes prefix header
1916  return proxyProtocolError(inBuf.length() > 107? "PROXY/1.0 error: missing CRLF" : NULL);
1917 
1918  static const SBuf unknown("UNKNOWN"), tcpName("TCP");
1919  if (tok.skip(tcpName)) {
1920 
1921  // skip TCP/IP version number
1922  static const CharacterSet tcpVersions("TCP-version","46");
1923  if (!tok.skipOne(tcpVersions))
1924  return proxyProtocolError("PROXY/1.0 error: missing TCP version");
1925 
1926  // skip SP after protocol version
1927  if (!tok.skip(' '))
1928  return proxyProtocolError("PROXY/1.0 error: missing SP");
1929 
1930  SBuf ipa, ipb;
1931  int64_t porta, portb;
1932  static const CharacterSet ipChars = CharacterSet("IP Address",".:") + CharacterSet::HEXDIG;
1933 
1934  // parse: src-IP SP dst-IP SP src-port SP dst-port CR
1935  // leave the LF until later.
1936  const bool correct = tok.prefix(ipa, ipChars) && tok.skip(' ') &&
1937  tok.prefix(ipb, ipChars) && tok.skip(' ') &&
1938  tok.int64(porta) && tok.skip(' ') &&
1939  tok.int64(portb) &&
1940  tok.skip('\r');
1941  if (!correct)
1942  return proxyProtocolError("PROXY/1.0 error: invalid syntax");
1943 
1944  // parse IP and port strings
1945  Ip::Address originalClient, originalDest;
1946 
1947  if (!originalClient.GetHostByName(ipa.c_str()))
1948  return proxyProtocolError("PROXY/1.0 error: invalid src-IP address");
1949 
1950  if (!originalDest.GetHostByName(ipb.c_str()))
1951  return proxyProtocolError("PROXY/1.0 error: invalid dst-IP address");
1952 
1953  if (porta > 0 && porta <= 0xFFFF) // max uint16_t
1954  originalClient.port(static_cast<uint16_t>(porta));
1955  else
1956  return proxyProtocolError("PROXY/1.0 error: invalid src port");
1957 
1958  if (portb > 0 && portb <= 0xFFFF) // max uint16_t
1959  originalDest.port(static_cast<uint16_t>(portb));
1960  else
1961  return proxyProtocolError("PROXY/1.0 error: invalid dst port");
1962 
1963  // we have original client and destination details now
1964  // replace the client connection values
1965  debugs(33, 5, "PROXY/1.0 protocol on connection " << clientConnection);
1966  clientConnection->local = originalDest;
1967  clientConnection->remote = originalClient;
1969  clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
1970  debugs(33, 5, "PROXY/1.0 upgrade: " << clientConnection);
1971  return true;
1972 
1973  } else if (tok.skip(unknown)) {
1974  // found valid but unusable header
1975  return true;
1976 
1977  } else
1978  return proxyProtocolError("PROXY/1.0 error: invalid protocol family");
1979 
1980  return false;
1981 }
1982 
1984 bool
1986 {
1987  static const SBuf::size_type prefixLen = Proxy2p0magic.length();
1988  if (inBuf.length() < prefixLen + 4)
1989  return false; // need more bytes
1990 
1991  if ((inBuf[prefixLen] & 0xF0) != 0x20) // version == 2 is mandatory
1992  return proxyProtocolError("PROXY/2.0 error: invalid version");
1993 
1994  const char command = (inBuf[prefixLen] & 0x0F);
1995  if ((command & 0xFE) != 0x00) // values other than 0x0-0x1 are invalid
1996  return proxyProtocolError("PROXY/2.0 error: invalid command");
1997 
1998  const char family = (inBuf[prefixLen+1] & 0xF0) >>4;
1999  if (family > 0x3) // values other than 0x0-0x3 are invalid
2000  return proxyProtocolError("PROXY/2.0 error: invalid family");
2001 
2002  const char proto = (inBuf[prefixLen+1] & 0x0F);
2003  if (proto > 0x2) // values other than 0x0-0x2 are invalid
2004  return proxyProtocolError("PROXY/2.0 error: invalid protocol type");
2005 
2006  const char *clen = inBuf.rawContent() + prefixLen + 2;
2007  uint16_t len;
2008  memcpy(&len, clen, sizeof(len));
2009  len = ntohs(len);
2010 
2011  if (inBuf.length() < prefixLen + 4 + len)
2012  return false; // need more bytes
2013 
2014  inBuf.consume(prefixLen + 4); // 4 being the extra bytes
2015  const SBuf extra = inBuf.consume(len);
2016  needProxyProtocolHeader_ = false; // found successfully
2017 
2018  // LOCAL connections do nothing with the extras
2019  if (command == 0x00/* LOCAL*/)
2020  return true;
2021 
2022  union pax {
2023  struct { /* for TCP/UDP over IPv4, len = 12 */
2024  struct in_addr src_addr;
2025  struct in_addr dst_addr;
2026  uint16_t src_port;
2027  uint16_t dst_port;
2028  } ipv4_addr;
2029  struct { /* for TCP/UDP over IPv6, len = 36 */
2030  struct in6_addr src_addr;
2031  struct in6_addr dst_addr;
2032  uint16_t src_port;
2033  uint16_t dst_port;
2034  } ipv6_addr;
2035 #if NOT_SUPPORTED
2036  struct { /* for AF_UNIX sockets, len = 216 */
2037  uint8_t src_addr[108];
2038  uint8_t dst_addr[108];
2039  } unix_addr;
2040 #endif
2041  };
2042 
2043  pax ipu;
2044  memcpy(&ipu, extra.rawContent(), sizeof(pax));
2045 
2046  // replace the client connection values
2047  debugs(33, 5, "PROXY/2.0 protocol on connection " << clientConnection);
2048  switch (family) {
2049  case 0x1: // IPv4
2050  clientConnection->local = ipu.ipv4_addr.dst_addr;
2051  clientConnection->local.port(ntohs(ipu.ipv4_addr.dst_port));
2052  clientConnection->remote = ipu.ipv4_addr.src_addr;
2053  clientConnection->remote.port(ntohs(ipu.ipv4_addr.src_port));
2055  clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
2056  break;
2057  case 0x2: // IPv6
2058  clientConnection->local = ipu.ipv6_addr.dst_addr;
2059  clientConnection->local.port(ntohs(ipu.ipv6_addr.dst_port));
2060  clientConnection->remote = ipu.ipv6_addr.src_addr;
2061  clientConnection->remote.port(ntohs(ipu.ipv6_addr.src_port));
2063  clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
2064  break;
2065  default: // do nothing
2066  break;
2067  }
2068  debugs(33, 5, "PROXY/2.0 upgrade: " << clientConnection);
2069  return true;
2070 }
2071 
2072 void
2074 {
2075  if (receivedFirstByte_)
2076  return;
2077 
2078  receivedFirstByte_ = true;
2079  // Set timeout to Config.Timeout.request
2081  AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
2082  TimeoutDialer, this, ConnStateData::requestTimeout);
2084 }
2085 
2091 bool
2093 {
2094  bool parsed_req = false;
2095 
2096  debugs(33, 5, HERE << clientConnection << ": attempting to parse");
2097 
2098  // Loop while we have read bytes that are not needed for producing the body
2099  // On errors, bodyPipe may become nil, but readMore will be cleared
2100  while (!inBuf.isEmpty() && !bodyPipe && flags.readMore) {
2101 
2102  // Prohibit concurrent requests when using a pinned to-server connection
2103  // because our Client classes do not support request pipelining.
2104  if (pinning.pinned && !pinning.readHandler) {
2105  debugs(33, 3, clientConnection << " waits for busy " << pinning.serverConnection);
2106  break;
2107  }
2108 
2109  /* Limit the number of concurrent requests */
2111  break;
2112 
2113  // try to parse the PROXY protocol header magic bytes
2115  if (!parseProxyProtocolHeader())
2116  break;
2117 
2118  // we have been waiting for PROXY to provide client-IP
2119  // for some lookups, ie rDNS and IDENT.
2121  }
2122 
2123  if (Http::StreamPointer context = parseOneRequest()) {
2124  debugs(33, 5, clientConnection << ": done parsing a request");
2125 
2126  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "clientLifetimeTimeout",
2127  CommTimeoutCbPtrFun(clientLifetimeTimeout, context->http));
2129 
2130  context->registerWithConn();
2131 
2132  processParsedRequest(context);
2133 
2134  parsed_req = true; // XXX: do we really need to parse everything right NOW ?
2135 
2136  if (context->mayUseConnection()) {
2137  debugs(33, 3, HERE << "Not parsing new requests, as this request may need the connection");
2138  break;
2139  }
2140  } else {
2141  debugs(33, 5, clientConnection << ": not enough request data: " <<
2142  inBuf.length() << " < " << Config.maxRequestHeaderSize);
2144  break;
2145  }
2146  }
2147 
2148  /* XXX where to 'finish' the parsing pass? */
2149  return parsed_req;
2150 }
2151 
2152 void
2154 {
2155 #if USE_OPENSSL
2156  if (parsingTlsHandshake) {
2158  return;
2159  }
2160 #endif
2161 
2162  /* Process next request */
2163  if (pipeline.empty())
2164  fd_note(clientConnection->fd, "Reading next request");
2165 
2166  if (!clientParseRequests()) {
2167  if (!isOpen())
2168  return;
2169  /*
2170  * If the client here is half closed and we failed
2171  * to parse a request, close the connection.
2172  * The above check with connFinishedWithConn() only
2173  * succeeds _if_ the buffer is empty which it won't
2174  * be if we have an incomplete request.
2175  * XXX: This duplicates ConnStateData::kick
2176  */
2178  debugs(33, 5, clientConnection << ": half-closed connection, no completed request parsed, connection closing.");
2180  return;
2181  }
2182  }
2183 
2184  if (!isOpen())
2185  return;
2186 
2188 }
2189 
2196 bool
2198 {
2199  // if we are reading a body, stuff data into the body pipe
2200  if (bodyPipe != NULL)
2201  return handleRequestBodyData();
2202  return true;
2203 }
2204 
2212 bool
2214 {
2215  assert(bodyPipe != NULL);
2216 
2217  if (bodyParser) { // chunked encoding
2218  if (const err_type error = handleChunkedRequestBody()) {
2220  return false;
2221  }
2222  } else { // identity encoding
2223  debugs(33,5, HERE << "handling plain request body for " << clientConnection);
2224  const size_t putSize = bodyPipe->putMoreData(inBuf.c_str(), inBuf.length());
2225  if (putSize > 0)
2226  consumeInput(putSize);
2227 
2228  if (!bodyPipe->mayNeedMoreData()) {
2229  // BodyPipe will clear us automagically when we produced everything
2230  bodyPipe = NULL;
2231  }
2232  }
2233 
2234  if (!bodyPipe) {
2235  debugs(33,5, HERE << "produced entire request body for " << clientConnection);
2236 
2237  if (const char *reason = stoppedSending()) {
2238  /* we've finished reading like good clients,
2239  * now do the close that initiateClose initiated.
2240  */
2241  debugs(33, 3, HERE << "closing for earlier sending error: " << reason);
2243  return false;
2244  }
2245  }
2246 
2247  return true;
2248 }
2249 
2251 err_type
2253 {
2254  debugs(33, 7, "chunked from " << clientConnection << ": " << inBuf.length());
2255 
2256  try { // the parser will throw on errors
2257 
2258  if (inBuf.isEmpty()) // nothing to do
2259  return ERR_NONE;
2260 
2261  BodyPipeCheckout bpc(*bodyPipe);
2263  const bool parsed = bodyParser->parse(inBuf);
2264  inBuf = bodyParser->remaining(); // sync buffers
2265  bpc.checkIn();
2266 
2267  // dechunk then check: the size limit applies to _dechunked_ content
2269  return ERR_TOO_BIG;
2270 
2271  if (parsed) {
2273  Must(!bodyPipe);
2274  return ERR_NONE; // nil bodyPipe implies body end for the caller
2275  }
2276 
2277  // if chunk parser needs data, then the body pipe must need it too
2279 
2280  // if parser needs more space and we can consume nothing, we will stall
2282  } catch (...) { // TODO: be more specific
2283  debugs(33, 3, HERE << "malformed chunks" << bodyPipe->status());
2284  return ERR_INVALID_REQ;
2285  }
2286 
2287  debugs(33, 7, HERE << "need more chunked data" << *bodyPipe->status());
2288  return ERR_NONE;
2289 }
2290 
2292 void
2294 {
2295  finishDechunkingRequest(false);
2296 
2297  // XXX: The code below works if we fail during initial request parsing,
2298  // but if we fail when the server connection is used already, the server may send
2299  // us its response too, causing various assertions. How to prevent that?
2300 #if WE_KNOW_HOW_TO_SEND_ERRORS
2301  Http::StreamPointer context = pipeline.front();
2302  if (context != NULL && !context->http->out.offset) { // output nothing yet
2303  clientStreamNode *node = context->getClientReplyContext();
2304  clientReplyContext *repContext = dynamic_cast<clientReplyContext*>(node->data.getRaw());
2305  assert(repContext);
2306  const Http::StatusCode scode = (error == ERR_TOO_BIG) ?
2307  Http::scPayloadTooLarge : HTTP_BAD_REQUEST;
2308  repContext->setReplyToError(error, scode,
2309  repContext->http->request->method,
2310  repContext->http->uri,
2311  CachePeer,
2312  repContext->http->request,
2313  inBuf, NULL);
2314  context->pullData();
2315  } else {
2316  // close or otherwise we may get stuck as nobody will notice the error?
2318  }
2319 #else
2320  debugs(33, 3, HERE << "aborting chunked request without error " << error);
2322 #endif
2323  flags.readMore = false;
2324 }
2325 
2326 void
2328 {
2329  // request reader may get stuck waiting for space if nobody consumes body
2330  if (bodyPipe != NULL)
2332 
2333  // kids extend
2334 }
2335 
2337 void
2339 {
2340  if (!Comm::IsConnOpen(io.conn))
2341  return;
2342 
2344  Http::StreamPointer context = pipeline.front();
2345  Must(context && context->http);
2346  HttpRequest::Pointer request = context->http->request;
2347  if (clientTunnelOnError(this, context, request, HttpRequestMethod(), ERR_REQUEST_START_TIMEOUT))
2348  return;
2349  }
2350  /*
2351  * Just close the connection to not confuse browsers
2352  * using persistent connections. Some browsers open
2353  * a connection and then do not use it until much
2354  * later (presumeably because the request triggering
2355  * the open has already been completed on another
2356  * connection)
2357  */
2358  debugs(33, 3, "requestTimeout: FD " << io.fd << ": lifetime is expired.");
2359  io.conn->close();
2360 }
2361 
2362 static void
2364 {
2365  ClientHttpRequest *http = static_cast<ClientHttpRequest *>(io.data);
2366  debugs(33, DBG_IMPORTANT, "WARNING: Closing client connection due to lifetime timeout");
2367  debugs(33, DBG_IMPORTANT, "\t" << http->uri);
2368  http->logType.err.timedout = true;
2369  if (Comm::IsConnOpen(io.conn))
2370  io.conn->close();
2371 }
2372 
2374  AsyncJob("ConnStateData"), // kids overwrite
2375  Server(xact),
2376  bodyParser(nullptr),
2377 #if USE_OPENSSL
2378  sslBumpMode(Ssl::bumpEnd),
2379 #endif
2380  needProxyProtocolHeader_(false),
2381 #if USE_OPENSSL
2382  switchedToHttps_(false),
2383  parsingTlsHandshake(false),
2384  sslServerBump(NULL),
2385  signAlgorithm(Ssl::algSignTrusted),
2386 #endif
2387  stoppedSending_(NULL),
2388  stoppedReceiving_(NULL)
2389 {
2390  flags.readMore = true; // kids may overwrite
2391  flags.swanSang = false;
2392 
2393  pinning.host = NULL;
2394  pinning.port = -1;
2395  pinning.pinned = false;
2396  pinning.auth = false;
2397  pinning.zeroReply = false;
2398  pinning.peer = NULL;
2399 
2400  // store the details required for creating more MasterXaction objects as new requests come in
2401  log_addr = xact->tcpClient->remote;
2403 
2404  // register to receive notice of Squid signal events
2405  // which may affect long persisting client connections
2406  registerRunner();
2407 }
2408 
2409 void
2411 {
2414 
2415  if (port->disable_pmtu_discovery != DISABLE_PMTU_OFF &&
2416  (transparent() || port->disable_pmtu_discovery == DISABLE_PMTU_ALWAYS)) {
2417 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
2418  int i = IP_PMTUDISC_DONT;
2419  if (setsockopt(clientConnection->fd, SOL_IP, IP_MTU_DISCOVER, &i, sizeof(i)) < 0) {
2420  int xerrno = errno;
2421  debugs(33, 2, "WARNING: Path MTU discovery disabling failed on " << clientConnection << " : " << xstrerr(xerrno));
2422  }
2423 #else
2424  static bool reported = false;
2425 
2426  if (!reported) {
2427  debugs(33, DBG_IMPORTANT, "NOTICE: Path MTU discovery disabling is not supported on your platform.");
2428  reported = true;
2429  }
2430 #endif
2431  }
2432 
2434  AsyncCall::Pointer call = JobCallback(33, 5, Dialer, this, ConnStateData::connStateClosed);
2436 
2437  needProxyProtocolHeader_ = port->flags.proxySurrogate;
2439  if (!proxyProtocolValidateClient()) // will close the connection on failure
2440  return;
2441  } else
2443 
2444 }
2445 
2446 void
2448 {
2449  if (Config.onoff.log_fqdn)
2451 
2452 #if USE_IDENT
2453  if (Ident::TheConfig.identLookup) {
2454  ACLFilledChecklist identChecklist(Ident::TheConfig.identLookup, NULL, NULL);
2455  identChecklist.src_addr = clientConnection->remote;
2456  identChecklist.my_addr = clientConnection->local;
2457  if (identChecklist.fastCheck().allowed())
2459  }
2460 #endif
2461 
2463 
2464 #if USE_DELAY_POOLS
2465  fd_table[clientConnection->fd].clientInfo = NULL;
2466 
2467  if (Config.onoff.client_db) {
2468  /* it was said several times that client write limiter does not work if client_db is disabled */
2469 
2470  auto &pools = ClientDelayPools::Instance()->pools;
2472 
2473  // TODO: we check early to limit error response bandwith but we
2474  // should recheck when we can honor delay_pool_uses_indirect
2475  // TODO: we should also pass the port details for myportname here.
2478 
2479  for (unsigned int pool = 0; pool < pools.size(); ++pool) {
2480 
2481  /* pools require explicit 'allow' to assign a client into them */
2482  if (pools[pool]->access) {
2483  ch.changeAcl(pools[pool]->access);
2484  allow_t answer = ch.fastCheck();
2485  if (answer.allowed()) {
2486 
2487  /* request client information from db after we did all checks
2488  this will save hash lookup if client failed checks */
2490  assert(cli);
2491 
2492  /* put client info in FDE */
2493  fd_table[clientConnection->fd].clientInfo = cli;
2494 
2495  /* setup write limiter for this request */
2496  const double burst = floor(0.5 +
2497  (pools[pool]->highwatermark * Config.ClientDelay.initial)/100.0);
2498  cli->setWriteLimiter(pools[pool]->rate, burst, pools[pool]->highwatermark);
2499  break;
2500  } else {
2501  debugs(83, 4, HERE << "Delay pool " << pool << " skipped because ACL " << answer);
2502  }
2503  }
2504  }
2505  }
2506 #endif
2507 
2508  // kids must extend to actually start doing something (e.g., reading)
2509 }
2510 
2512 void
2514 {
2515  MasterXaction::Pointer xact = params.xaction;
2516  AnyP::PortCfgPointer s = xact->squidPort;
2517 
2518  // NP: it is possible the port was reconfigured when the call or accept() was queued.
2519 
2520  if (params.flag != Comm::OK) {
2521  // Its possible the call was still queued when the client disconnected
2522  debugs(33, 2, s->listenConn << ": accept failure: " << xstrerr(params.xerrno));
2523  return;
2524  }
2525 
2526  debugs(33, 4, params.conn << ": accepted");
2527  fd_note(params.conn->fd, "client http connect");
2528 
2529  if (s->tcp_keepalive.enabled)
2530  commSetTcpKeepalive(params.conn->fd, s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
2531 
2533 
2534  // Socket is ready, setup the connection manager to start using it
2535  auto *srv = Http::NewServer(xact);
2536  AsyncJob::Start(srv); // usually async-calls readSomeData()
2537 }
2538 
2540 static bool
2542 {
2543  if (Security::CreateServerSession(ctx, conn, "client https start")) {
2544  debugs(33, 5, "will negotiate TLS on " << conn);
2545  return true;
2546  }
2547 
2548  debugs(33, DBG_IMPORTANT, "ERROR: could not create TLS server context for " << conn);
2549  conn->close();
2550  return false;
2551 }
2552 
2559 static int
2561 {
2562  // TODO: maybe throw instead of returning -1
2563  // see https://github.com/squid-cache/squid/pull/81#discussion_r153053278
2564  int fd = conn->clientConnection->fd;
2565  auto session = fd_table[fd].ssl.get();
2566 
2567  errno = 0;
2568 
2569 #if USE_OPENSSL
2570  const auto ret = SSL_accept(session);
2571  if (ret > 0)
2572  return 1;
2573 
2574  const int xerrno = errno;
2575  const auto ssl_error = SSL_get_error(session, ret);
2576 
2577  switch (ssl_error) {
2578 
2579  case SSL_ERROR_WANT_READ:
2580  Comm::SetSelect(fd, COMM_SELECT_READ, callback, (callback ? conn : nullptr), 0);
2581  return 0;
2582 
2583  case SSL_ERROR_WANT_WRITE:
2584  Comm::SetSelect(fd, COMM_SELECT_WRITE, callback, (callback ? conn : nullptr), 0);
2585  return 0;
2586 
2587  case SSL_ERROR_SYSCALL:
2588  if (ret == 0) {
2589  debugs(83, 2, "Error negotiating SSL connection on FD " << fd << ": Aborted by client: " << ssl_error);
2590  } else {
2591  debugs(83, (xerrno == ECONNRESET) ? 1 : 2, "Error negotiating SSL connection on FD " << fd << ": " <<
2592  (xerrno == 0 ? Security::ErrorString(ssl_error) : xstrerr(xerrno)));
2593  }
2594  break;
2595 
2596  case SSL_ERROR_ZERO_RETURN:
2597  debugs(83, DBG_IMPORTANT, "Error negotiating SSL connection on FD " << fd << ": Closed by client");
2598  break;
2599 
2600  default:
2601  debugs(83, DBG_IMPORTANT, "Error negotiating SSL connection on FD " <<
2602  fd << ": " << Security::ErrorString(ssl_error) <<
2603  " (" << ssl_error << "/" << ret << ")");
2604  }
2605 
2606 #elif USE_GNUTLS
2607 
2608  const auto x = gnutls_handshake(session);
2609  if (x == GNUTLS_E_SUCCESS)
2610  return 1;
2611 
2612  if (gnutls_error_is_fatal(x)) {
2613  debugs(83, 2, "Error negotiating TLS on " << conn->clientConnection << ": Aborted by client: " << Security::ErrorString(x));
2614 
2615  } else if (x == GNUTLS_E_INTERRUPTED || x == GNUTLS_E_AGAIN) {
2616  const auto ioAction = (gnutls_record_get_direction(session)==0 ? COMM_SELECT_READ : COMM_SELECT_WRITE);
2617  Comm::SetSelect(fd, ioAction, callback, (callback ? conn : nullptr), 0);
2618  return 0;
2619  }
2620 
2621 #else
2622  // Performing TLS handshake should never be reachable without a TLS/SSL library.
2623  (void)session; // avoid compiler and static analysis complaints
2624  fatal("FATAL: HTTPS not supported by this Squid.");
2625 #endif
2626 
2627  return -1;
2628 }
2629 
2631 static void
2632 clientNegotiateSSL(int fd, void *data)
2633 {
2634  ConnStateData *conn = (ConnStateData *)data;
2635 
2636  const int ret = tlsAttemptHandshake(conn, clientNegotiateSSL);
2637  if (ret <= 0) {
2638  if (ret < 0) // An error
2639  conn->clientConnection->close();
2640  return;
2641  }
2642 
2643  Security::SessionPointer session(fd_table[fd].ssl);
2644 
2645 #if USE_OPENSSL
2646  if (Security::SessionIsResumed(session)) {
2647  debugs(83, 2, "Session " << SSL_get_session(session.get()) <<
2648  " reused on FD " << fd << " (" << fd_table[fd].ipaddr <<
2649  ":" << (int)fd_table[fd].remote_port << ")");
2650  } else {
2651  if (Debug::Enabled(83, 4)) {
2652  /* Write out the SSL session details.. actually the call below, but
2653  * OpenSSL headers do strange typecasts confusing GCC.. */
2654  /* PEM_write_SSL_SESSION(debug_log, SSL_get_session(ssl)); */
2655 #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00908000L
2656  PEM_ASN1_write(reinterpret_cast<i2d_of_void *>(i2d_SSL_SESSION),
2657  PEM_STRING_SSL_SESSION, debug_log,
2658  reinterpret_cast<char *>(SSL_get_session(session.get())),
2659  nullptr, nullptr, 0, nullptr, nullptr);
2660 
2661 #elif (ALLOW_ALWAYS_SSL_SESSION_DETAIL == 1)
2662 
2663  /* When using gcc 3.3.x and OpenSSL 0.9.7x sometimes a compile error can occur here.
2664  * This is caused by an unpredicatble gcc behaviour on a cast of the first argument
2665  * of PEM_ASN1_write(). For this reason this code section is disabled. To enable it,
2666  * define ALLOW_ALWAYS_SSL_SESSION_DETAIL=1.
2667  * Because there are two possible usable cast, if you get an error here, try the other
2668  * commented line. */
2669 
2670  PEM_ASN1_write((int(*)())i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2671  debug_log,
2672  reinterpret_cast<char *>(SSL_get_session(session.get())),
2673  nullptr, nullptr, 0, nullptr, nullptr);
2674  /* PEM_ASN1_write((int(*)(...))i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2675  debug_log,
2676  reinterpret_cast<char *>(SSL_get_session(session.get())),
2677  nullptr, nullptr, 0, nullptr, nullptr);
2678  */
2679 #else
2680  debugs(83, 4, "With " OPENSSL_VERSION_TEXT ", session details are available only defining ALLOW_ALWAYS_SSL_SESSION_DETAIL=1 in the source.");
2681 
2682 #endif
2683  /* Note: This does not automatically fflush the log file.. */
2684  }
2685 
2686  debugs(83, 2, "New session " << SSL_get_session(session.get()) <<
2687  " on FD " << fd << " (" << fd_table[fd].ipaddr << ":" <<
2688  fd_table[fd].remote_port << ")");
2689  }
2690 #else
2691  debugs(83, 2, "TLS session reuse not yet implemented.");
2692 #endif
2693 
2694  // Connection established. Retrieve TLS connection parameters for logging.
2696 
2697 #if USE_OPENSSL
2698  X509 *client_cert = SSL_get_peer_certificate(session.get());
2699 
2700  if (client_cert) {
2701  debugs(83, 3, "FD " << fd << " client certificate: subject: " <<
2702  X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0));
2703 
2704  debugs(83, 3, "FD " << fd << " client certificate: issuer: " <<
2705  X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0));
2706 
2707  X509_free(client_cert);
2708  } else {
2709  debugs(83, 5, "FD " << fd << " has no client certificate.");
2710  }
2711 #else
2712  debugs(83, 2, "Client certificate requesting not yet implemented.");
2713 #endif
2714 
2715  conn->readSomeData();
2716 }
2717 
2722 static void
2724 {
2725  assert(connState);
2726  const Comm::ConnectionPointer &details = connState->clientConnection;
2727 
2728  if (!ctx || !httpsCreate(details, ctx))
2729  return;
2730 
2732  AsyncCall::Pointer timeoutCall = JobCallback(33, 5, TimeoutDialer,
2733  connState, ConnStateData::requestTimeout);
2734  commSetConnTimeout(details, Config.Timeout.request, timeoutCall);
2735 
2736  Comm::SetSelect(details->fd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
2737 }
2738 
2739 #if USE_OPENSSL
2740 
2743 static void
2745 {
2746  ConnStateData *connState = (ConnStateData *) data;
2747 
2748  // if the connection is closed or closing, just return.
2749  if (!connState->isOpen())
2750  return;
2751 
2752  if (answer.allowed()) {
2753  debugs(33, 2, "sslBump action " << Ssl::bumpMode(answer.kind) << "needed for " << connState->clientConnection);
2754  connState->sslBumpMode = static_cast<Ssl::BumpMode>(answer.kind);
2755  } else {
2756  debugs(33, 3, "sslBump not needed for " << connState->clientConnection);
2757  connState->sslBumpMode = Ssl::bumpSplice;
2758  }
2759 
2760  if (connState->sslBumpMode == Ssl::bumpTerminate) {
2761  connState->clientConnection->close();
2762  return;
2763  }
2764 
2765  if (!connState->fakeAConnectRequest("ssl-bump", connState->inBuf))
2766  connState->clientConnection->close();
2767 }
2768 #endif
2769 
2771 static void
2773 {
2774  MasterXaction::Pointer xact = params.xaction;
2775  const AnyP::PortCfgPointer s = xact->squidPort;
2776 
2777  // NP: it is possible the port was reconfigured when the call or accept() was queued.
2778 
2779  if (params.flag != Comm::OK) {
2780  // Its possible the call was still queued when the client disconnected
2781  debugs(33, 2, "httpsAccept: " << s->listenConn << ": accept failure: " << xstrerr(params.xerrno));
2782  return;
2783  }
2784 
2785  debugs(33, 4, HERE << params.conn << " accepted, starting SSL negotiation.");
2786  fd_note(params.conn->fd, "client https connect");
2787 
2788  if (s->tcp_keepalive.enabled) {
2789  commSetTcpKeepalive(params.conn->fd, s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
2790  }
2792 
2793  // Socket is ready, setup the connection manager to start using it
2794  auto *srv = Https::NewServer(xact);
2795  AsyncJob::Start(srv); // usually async-calls postHttpsAccept()
2796 }
2797 
2798 void
2800 {
2801  if (port->flags.tunnelSslBumping) {
2802 #if USE_OPENSSL
2803  debugs(33, 5, "accept transparent connection: " << clientConnection);
2804 
2805  if (!Config.accessList.ssl_bump) {
2807  return;
2808  }
2809 
2812  // Create a fake HTTP request for ssl_bump ACL check,
2813  // using tproxy/intercept provided destination IP and port.
2814  HttpRequest *request = new HttpRequest(mx);
2815  static char ip[MAX_IPSTRLEN];
2817  request->url.host(clientConnection->local.toStr(ip, sizeof(ip)));
2818  request->url.port(clientConnection->local.port());
2819  request->myportname = port->name;
2820 
2821  ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(Config.accessList.ssl_bump, request, NULL);
2822  acl_checklist->src_addr = clientConnection->remote;
2823  acl_checklist->my_addr = port->s;
2824  // Build a local AccessLogEntry to allow requiresAle() acls work
2825  acl_checklist->al = new AccessLogEntry;
2826  acl_checklist->al->cache.start_time = current_time;
2827  acl_checklist->al->tcpClient = clientConnection;
2828  acl_checklist->al->cache.port = port;
2829  acl_checklist->al->cache.caddr = log_addr;
2830  HTTPMSGUNLOCK(acl_checklist->al->request);
2831  acl_checklist->al->request = request;
2832  HTTPMSGLOCK(acl_checklist->al->request);
2833  Http::StreamPointer context = pipeline.front();
2834  ClientHttpRequest *http = context ? context->http : nullptr;
2835  const char *log_uri = http ? http->log_uri : nullptr;
2836  acl_checklist->syncAle(request, log_uri);
2837  acl_checklist->nonBlockingCheck(httpsSslBumpAccessCheckDone, this);
2838 #else
2839  fatal("FATAL: SSL-Bump requires --with-openssl");
2840 #endif
2841  return;
2842  } else {
2843  httpsEstablish(this, port->secure.staticContext);
2844  }
2845 }
2846 
2847 #if USE_OPENSSL
2848 void
2850 {
2851  ConnStateData * state_data = (ConnStateData *)(data);
2852  state_data->sslCrtdHandleReply(reply);
2853 }
2854 
2855 void
2857 {
2858  if (!isOpen()) {
2859  debugs(33, 3, "Connection gone while waiting for ssl_crtd helper reply; helper reply:" << reply);
2860  return;
2861  }
2862 
2863  if (reply.result == Helper::BrokenHelper) {
2864  debugs(33, 5, HERE << "Certificate for " << sslConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply);
2865  } else if (!reply.other().hasContent()) {
2866  debugs(1, DBG_IMPORTANT, HERE << "\"ssl_crtd\" helper returned <NULL> reply.");
2867  } else {
2869  if (reply_message.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK) {
2870  debugs(33, 5, HERE << "Reply from ssl_crtd for " << sslConnectHostOrIp << " is incorrect");
2871  } else {
2872  if (reply.result != Helper::Okay) {
2873  debugs(33, 5, HERE << "Certificate for " << sslConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply_message.getBody());
2874  } else {
2875  debugs(33, 5, HERE << "Certificate for " << sslConnectHostOrIp << " was successfully recieved from ssl_crtd");
2878  auto ssl = fd_table[clientConnection->fd].ssl.get();
2879  bool ret = Ssl::configureSSLUsingPkeyAndCertFromMemory(ssl, reply_message.getBody().c_str(), *port);
2880  if (!ret)
2881  debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
2882 
2885  } else {
2887  if (ctx && !sslBumpCertKey.isEmpty())
2889  getSslContextDone(ctx);
2890  }
2891  return;
2892  }
2893  }
2894  }
2896  getSslContextDone(nil);
2897 }
2898 
2900 {
2902 
2903  const bool connectedOk = sslServerBump && sslServerBump->connectedOk();
2904  if (connectedOk) {
2905  if (X509 *mimicCert = sslServerBump->serverCert.get())
2906  certProperties.mimicCert.resetAndLock(mimicCert);
2907 
2911 
2912  for (sslproxy_cert_adapt *ca = Config.ssl_client.cert_adapt; ca != NULL; ca = ca->next) {
2913  // If the algorithm already set, then ignore it.
2914  if ((ca->alg == Ssl::algSetCommonName && certProperties.setCommonName) ||
2915  (ca->alg == Ssl::algSetValidAfter && certProperties.setValidAfter) ||
2916  (ca->alg == Ssl::algSetValidBefore && certProperties.setValidBefore) )
2917  continue;
2918 
2919  if (ca->aclList && checklist.fastCheck(ca->aclList).allowed()) {
2920  const char *alg = Ssl::CertAdaptAlgorithmStr[ca->alg];
2921  const char *param = ca->param;
2922 
2923  // For parameterless CN adaptation, use hostname from the
2924  // CONNECT request.
2925  if (ca->alg == Ssl::algSetCommonName) {
2926  if (!param)
2927  param = sslConnectHostOrIp.termedBuf();
2928  certProperties.commonName = param;
2929  certProperties.setCommonName = true;
2930  } else if (ca->alg == Ssl::algSetValidAfter)
2931  certProperties.setValidAfter = true;
2932  else if (ca->alg == Ssl::algSetValidBefore)
2933  certProperties.setValidBefore = true;
2934 
2935  debugs(33, 5, HERE << "Matches certificate adaptation aglorithm: " <<
2936  alg << " param: " << (param ? param : "-"));
2937  }
2938  }
2939 
2940  certProperties.signAlgorithm = Ssl::algSignEnd;
2941  for (sslproxy_cert_sign *sg = Config.ssl_client.cert_sign; sg != NULL; sg = sg->next) {
2942  if (sg->aclList && checklist.fastCheck(sg->aclList).allowed()) {
2943  certProperties.signAlgorithm = (Ssl::CertSignAlgorithm)sg->alg;
2944  break;
2945  }
2946  }
2947  } else {// did not try to connect (e.g. client-first) or failed to connect
2948  // In case of an error while connecting to the secure server, use a
2949  // trusted certificate, with no mimicked fields and no adaptation
2950  // algorithms. There is nothing we can mimic, so we want to minimize the
2951  // number of warnings the user will have to see to get to the error page.
2952  // We will close the connection, so that the trust is not extended to
2953  // non-Squid content.
2954  certProperties.signAlgorithm = Ssl::algSignTrusted;
2955  }
2956 
2957  assert(certProperties.signAlgorithm != Ssl::algSignEnd);
2958 
2959  if (certProperties.signAlgorithm == Ssl::algSignUntrusted) {
2960  assert(port->secure.untrustedSigningCa.cert);
2961  certProperties.signWithX509.resetAndLock(port->secure.untrustedSigningCa.cert.get());
2962  certProperties.signWithPkey.resetAndLock(port->secure.untrustedSigningCa.pkey.get());
2963  } else {
2964  assert(port->secure.signingCa.cert.get());
2965  certProperties.signWithX509.resetAndLock(port->secure.signingCa.cert.get());
2966 
2967  if (port->secure.signingCa.pkey)
2968  certProperties.signWithPkey.resetAndLock(port->secure.signingCa.pkey.get());
2969  }
2970  signAlgorithm = certProperties.signAlgorithm;
2971 
2972  certProperties.signHash = Ssl::DefaultSignHash;
2973 }
2974 
2977 {
2978  debugs(33, 5, "Finding SSL certificate for " << cacheKey << " in cache");
2980  if (Security::ContextPointer *ctx = ssl_ctx_cache ? ssl_ctx_cache->get(cacheKey) : nullptr) {
2981  if (Ssl::verifySslCertificate(*ctx, certProperties)) {
2982  debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is valid");
2983  return *ctx;
2984  } else {
2985  debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is out of date. Delete this certificate from cache");
2986  if (ssl_ctx_cache)
2987  ssl_ctx_cache->del(cacheKey);
2988  }
2989  }
2990  return Security::ContextPointer(nullptr);
2991 }
2992 
2993 void
2995 {
2997  if (!ssl_ctx_cache || !ssl_ctx_cache->add(cacheKey, new Security::ContextPointer(ctx))) {
2998  // If it is not in storage delete after using. Else storage deleted it.
2999  fd_table[clientConnection->fd].html?amicTlsContext = ctx;
3000  }
3001 }
3002 
3003 void
3005 {
3006  // If we are called, then CONNECT has succeeded. Finalize it.
3007  if (auto xact = pipeline.front()) {
3008  if (xact->http && xact->http->request && xact->http->request->method == Http::METHOD_CONNECT)
3009  xact->finished();
3010  // cannot proceed with encryption if requests wait for plain responses
3011  Must(pipeline.empty());
3012  }
3013  /* careful: finished() above frees request, host, etc. */
3014 
3015  if (port->secure.generateHostCertificates) {
3016  Ssl::CertificateProperties certProperties;
3017  buildSslCertGenerationParams(certProperties);
3018 
3019  // Disable caching for bumpPeekAndSplice mode
3022  Ssl::InRamCertificateDbKey(certProperties, sslBumpCertKey);
3024 
3026  if (ctx) {
3027  getSslContextDone(ctx);
3028  return;
3029  }
3030  }
3031 
3032 #if USE_SSL_CRTD
3033  try {
3034  debugs(33, 5, HERE << "Generating SSL certificate for " << certProperties.commonName << " using ssl_crtd.");
3037  request_message.composeRequest(certProperties);
3038  debugs(33, 5, HERE << "SSL crtd request: " << request_message.compose().c_str());
3039  Ssl::Helper::Submit(request_message, sslCrtdHandleReplyWrapper, this);
3040  return;
3041  } catch (const std::exception &e) {
3042  debugs(33, DBG_IMPORTANT, "ERROR: Failed to compose ssl_crtd " <<
3043  "request for " << certProperties.commonName <<
3044  " certificate: " << e.what() << "; will now block to " <<
3045  "generate that certificate.");
3046  // fall through to do blocking in-process generation.
3047  }
3048 #endif // USE_SSL_CRTD
3049 
3050  debugs(33, 5, HERE << "Generating SSL certificate for " << certProperties.commonName);
3053  auto ssl = fd_table[clientConnection->fd].ssl.get();
3054  if (!Ssl::configureSSL(ssl, certProperties, *port))
3055  debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
3056 
3059  } else {
3061  if (dynCtx && !sslBumpCertKey.isEmpty())
3063  getSslContextDone(dynCtx);
3064  }
3065  return;
3066  }
3067 
3069  getSslContextDone(nil);
3070 }
3071 
3072 void
3074 {
3075  if (port->secure.generateHostCertificates && !ctx) {
3076  debugs(33, 2, "Failed to generate TLS context for " << sslConnectHostOrIp);
3077  }
3078 
3079  // If generated ssl context = NULL, try to use static ssl context.
3080  if (!ctx) {
3081  if (!port->secure.staticContext) {
3082  debugs(83, DBG_IMPORTANT, "Closing " << clientConnection->remote << " as lacking TLS context");
3084  return;
3085  } else {
3086  debugs(33, 5, "Using static TLS context.");
3087  ctx = port->secure.staticContext;
3088  }
3089  }
3090 
3091  if (!httpsCreate(clientConnection, ctx))
3092  return;
3093 
3094  // bumped intercepted conns should already have Config.Timeout.request set
3095  // but forwarded connections may only have Config.Timeout.lifetime. [Re]set
3096  // to make sure the connection does not get stuck on non-SSL clients.
3098  AsyncCall::Pointer timeoutCall = JobCallback(33, 5, TimeoutDialer,
3101 
3102  switchedToHttps_ = true;
3103 
3104  auto ssl = fd_table[clientConnection->fd].ssl.get();
3105  BIO *b = SSL_get_rbio(ssl);
3106  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
3107  bio->setReadBufData(inBuf);
3108  inBuf.clear();
3110 }
3111 
3112 void
3114 {
3116 
3117  sslConnectHostOrIp = request->url.host();
3118  resetSslCommonName(request->url.host());
3119 
3120  // We are going to read new request
3121  flags.readMore = true;
3122  debugs(33, 5, HERE << "converting " << clientConnection << " to SSL");
3123 
3124  // keep version major.minor details the same.
3125  // but we are now performing the HTTPS handshake traffic
3127 
3128  // If sslServerBump is set, then we have decided to deny CONNECT
3129  // and now want to switch to SSL to send the error to the client
3130  // without even peeking at the origin server certificate.
3131  if (bumpServerMode == Ssl::bumpServerFirst && !sslServerBump) {
3132  request->flags.sslPeek = true;
3133  sslServerBump = new Ssl::ServerBump(request);
3134  } else if (bumpServerMode == Ssl::bumpPeek || bumpServerMode == Ssl::bumpStare) {
3135  request->flags.sslPeek = true;
3136  sslServerBump = new Ssl::ServerBump(request, NULL, bumpServerMode);
3137  }
3138 
3139  // commSetConnTimeout() was called for this request before we switched.
3140  // Fix timeout to request_start_timeout
3142  AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
3143  TimeoutDialer, this, ConnStateData::requestTimeout);
3145  // Also reset receivedFirstByte_ flag to allow this timeout work in the case we have
3146  // a bumbed "connect" request on non transparent port.
3147  receivedFirstByte_ = false;
3148  // Get more data to peek at Tls
3149  parsingTlsHandshake = true;
3150  readSomeData();
3151 }
3152 
3153 void
3155 {
3157 
3158  assert(!inBuf.isEmpty());
3160  fd_note(clientConnection->fd, "Parsing TLS handshake");
3161 
3162  bool unsupportedProtocol = false;
3163  try {
3164  if (!tlsParser.parseHello(inBuf)) {
3165  // need more data to finish parsing
3166  readSomeData();
3167  return;
3168  }
3169  }
3170  catch (const std::exception &ex) {
3171  debugs(83, 2, "error on FD " << clientConnection->fd << ": " << ex.what());
3172  unsupportedProtocol = true;
3173  }
3174 
3175  parsingTlsHandshake = false;
3176 
3177  // client data may be needed for splicing and for
3178  // tunneling unsupportedProtocol after an error
3180 
3181  // Even if the parser failed, each TLS detail should either be set
3182  // correctly or still be "unknown"; copying unknown detail is a no-op.
3185  if (details && !details->serverName.isEmpty()) {
3186  resetSslCommonName(details->serverName.c_str());
3187  tlsClientSni_ = details->serverName;
3188  }
3189 
3190  // We should disable read/write handlers
3193 
3194  if (unsupportedProtocol) {
3195  Http::StreamPointer context = pipeline.front();
3196  Must(context && context->http);
3197  HttpRequest::Pointer request = context->http->request;
3198  debugs(83, 5, "Got something other than TLS Client Hello. Cannot SslBump.");
3200  context->http->al->ssl.bumpMode = Ssl::bumpSplice;
3201  if (!clientTunnelOnError(this, context, request, HttpRequestMethod(), ERR_PROTOCOL_UNKNOWN))
3203  return;
3204  }
3205 
3206  if (!sslServerBump || sslServerBump->act.step1 == Ssl::bumpClientFirst) { // Either means client-first.
3208  return;
3209  } else if (sslServerBump->act.step1 == Ssl::bumpServerFirst) {
3210  // will call httpsPeeked() with certificate and connection, eventually
3212  } else {
3215  }
3216 }
3217 
3219 {
3220  ConnStateData *connState = (ConnStateData *) data;
3221 
3222  // if the connection is closed or closing, just return.
3223  if (!connState->isOpen())
3224  return;
3225 
3226  debugs(33, 5, "Answer: " << answer << " kind:" << answer.kind);
3227  assert(connState->serverBump());
3228  Ssl::BumpMode bumpAction;
3229  if (answer.allowed()) {
3230  bumpAction = (Ssl::BumpMode)answer.kind;
3231  } else
3232  bumpAction = Ssl::bumpSplice;
3233 
3234  connState->serverBump()->act.step2 = bumpAction;
3235  connState->sslBumpMode = bumpAction;
3236  Http::StreamPointer context = connState->pipeline.front();
3237  if (ClientHttpRequest *http = (context ? context->http : nullptr))
3238  http->al->ssl.bumpMode = bumpAction;
3239 
3240  if (bumpAction == Ssl::bumpTerminate) {
3241  connState->clientConnection->close();
3242  } else if (bumpAction != Ssl::bumpSplice) {
3243  connState->startPeekAndSplice();
3244  } else if (!connState->splice())
3245  connState->clientConnection->close();
3246 }
3247 
3248 bool
3250 {
3251  // normally we can splice here, because we just got client hello message
3252 
3253  if (fd_table[clientConnection->fd].ssl.get()) {
3254  // Restore default read methods
3257  }
3258 
3259  // XXX: assuming that there was an HTTP/1.1 CONNECT to begin with...
3260  // reset the current protocol to HTTP/1.1 (was "HTTPS" for the bumping process)
3262  assert(!pipeline.empty());
3263  Http::StreamPointer context = pipeline.front();
3264  Must(context);
3265  Must(context->http);
3266  ClientHttpRequest *http = context->http;
3268  context->finished();
3269  if (transparent()) {
3270  // For transparent connections, make a new fake CONNECT request, now
3271  // with SNI as target. doCallout() checks, adaptations may need that.
3272  return fakeAConnectRequest("splice", preservedClientData);
3273  } else {
3274  // For non transparent connections make a new tunneled CONNECT, which
3275  // also sets the HttpRequest::flags::forceTunnel flag to avoid
3276  // respond with "Connection Established" to the client.
3277  // This fake CONNECT request required to allow use of SNI in
3278  // doCallout() checks and adaptations.
3280  }
3281 }
3282 
3283 void
3285 {
3286  // This is the Step2 of the SSL bumping
3288  Http::StreamPointer context = pipeline.front();
3289  ClientHttpRequest *http = context ? context->http : nullptr;
3290 
3291  if (sslServerBump->step == Ssl::bumpStep1) {
3293  // Run a accessList check to check if want to splice or continue bumping
3294 
3296  acl_checklist->al = http ? http->al : nullptr;
3297  //acl_checklist->src_addr = params.conn->remote;
3298  //acl_checklist->my_addr = s->s;
3299  acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpNone));
3302  const char *log_uri = http ? http->log_uri : nullptr;
3303  acl_checklist->syncAle(sslServerBump->request.getRaw(), log_uri);
3304  acl_checklist->nonBlockingCheck(httpsSslBumpStep2AccessCheckDone, this);
3305  return;
3306  }
3307 
3308  // will call httpsPeeked() with certificate and connection, eventually
3309  Security::ContextPointer unConfiguredCTX(Ssl::createSSLContext(port->secure.signingCa.cert, port->secure.signingCa.pkey, port->secure));
3310  fd_table[clientConnection->fd].html?amicTlsContext = unConfiguredCTX;
3311 
3312  if (!httpsCreate(clientConnection, unConfiguredCTX))
3313  return;
3314 
3315  switchedToHttps_ = true;
3316 
3317  auto ssl = fd_table[clientConnection->fd].ssl.get();
3318  BIO *b = SSL_get_rbio(ssl);
3319  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
3320  bio->setReadBufData(inBuf);
3321  bio->hold(true);
3322 
3323  // Here squid should have all of the client hello message so the
3324  // tlsAttemptHandshake() should return 0.
3325  // This block exist only to force openSSL parse client hello and detect
3326  // ERR_SECURE_ACCEPT_FAIL error, which should be checked and splice if required.
3327  if (tlsAttemptHandshake(this, nullptr) < 0) {
3328  debugs(83, 2, "TLS handshake failed.");
3329  HttpRequest::Pointer request(http ? http->request : nullptr);
3330  if (!clientTunnelOnError(this, context, request, HttpRequestMethod(), ERR_SECURE_ACCEPT_FAIL))
3332  return;
3333  }
3334 
3335  // We need to reset inBuf here, to be used by incoming requests in the case
3336  // of SSL bump
3337  inBuf.clear();
3338 
3339  debugs(83, 5, "Peek and splice at step2 done. Start forwarding the request!!! ");
3341 }
3342 
3343 void
3345 {
3346  auto ssl = fd_table[clientConnection->fd].ssl.get();
3347  BIO *b = SSL_get_rbio(ssl);
3348  assert(b);
3349  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
3350 
3351  debugs(33, 5, "PeekAndSplice mode, proceed with client negotiation. Currrent state:" << SSL_state_string_long(ssl));
3352  bio->hold(false);
3353 
3355  switchedToHttps_ = true;
3356 }
3357 
3358 void
3360 {
3361  Must(sslServerBump != NULL);
3362  Must(sslServerBump->request == pic.request);
3363  Must(pipeline.empty() || pipeline.front()->http == nullptr || pipeline.front()->http->request == pic.request.getRaw());
3364 
3365  if (Comm::IsConnOpen(pic.connection)) {
3367  debugs(33, 5, HERE << "bumped HTTPS server: " << sslConnectHostOrIp);
3368  } else
3369  debugs(33, 5, HERE << "Error while bumping: " << sslConnectHostOrIp);
3370 
3372 }
3373 
3374 #endif /* USE_OPENSSL */
3375 
3376 bool
3377 ConnStateData::initiateTunneledRequest(HttpRequest::Pointer const &cause, Http::MethodType const method, const char *reason, const SBuf &payload)
3378 {
3379  // fake a CONNECT request to force connState to tunnel
3380  SBuf connectHost;
3381  unsigned short connectPort = 0;
3382 
3383  if (pinning.serverConnection != nullptr) {
3384  static char ip[MAX_IPSTRLEN];
3385  pinning.serverConnection->remote.toHostStr(ip, sizeof(ip));
3386  connectHost.assign(ip);
3387  connectPort = pinning.serverConnection->remote.port();
3388  } else if (cause && cause->method == Http::METHOD_CONNECT) {
3389  // We are inside a (not fully established) CONNECT request
3390  connectHost = cause->url.host();
3391  connectPort = cause->url.port();
3392  } else {
3393  debugs(33, 2, "Not able to compute URL, abort request tunneling for " << reason);
3394  return false;
3395  }
3396 
3397  debugs(33, 2, "Request tunneling for " << reason);
3398  ClientHttpRequest *http = buildFakeRequest(method, connectHost, connectPort, payload);
3400  request->flags.forceTunnel = true;
3401  http->calloutContext = new ClientRequestContext(http);
3402  http->doCallouts();
3403  clientProcessRequestFinished(this, request);
3404  return true;
3405 }
3406 
3407 bool
3408 ConnStateData::fakeAConnectRequest(const char *reason, const SBuf &payload)
3409 {
3410  debugs(33, 2, "fake a CONNECT request to force connState to tunnel for " << reason);
3411 
3412  SBuf connectHost;
3413  assert(transparent());
3414  const unsigned short connectPort = clientConnection->local.port();
3415 
3416 #if USE_OPENSSL
3417  if (!tlsClientSni_.isEmpty())
3418  connectHost.assign(tlsClientSni_);
3419  else
3420 #endif
3421  {
3422  static char ip[MAX_IPSTRLEN];
3423  clientConnection->local.toHostStr(ip, sizeof(ip));
3424  connectHost.assign(ip);
3425  }
3426 
3427  ClientHttpRequest *http = buildFakeRequest(Http::METHOD_CONNECT, connectHost, connectPort, payload);
3428 
3429  http->calloutContext = new ClientRequestContext(http);
3431  http->doCallouts();
3432  clientProcessRequestFinished(this, request);
3433  return true;
3434 }
3435 
3437 ConnStateData::buildFakeRequest(Http::MethodType const method, SBuf &useHost, unsigned short usePort, const SBuf &payload)
3438 {
3439  ClientHttpRequest *http = new ClientHttpRequest(this);
3440  Http::Stream *stream = new Http::Stream(clientConnection, http);
3441 
3442  StoreIOBuffer tempBuffer;
3443  tempBuffer.data = stream->reqbuf;
3444  tempBuffer.length = HTTP_REQBUF_SZ;
3445 
3446  ClientStreamData newServer = new clientReplyContext(http);
3447  ClientStreamData newClient = stream;
3450  clientSocketDetach, newClient, tempBuffer);
3451 
3452  http->uri = SBufToCstring(useHost);
3453  stream->flags.parsed_ok = 1; // Do we need it?
3454  stream->mayUseConnection(true);
3455 
3456  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "clientLifetimeTimeout",
3459 
3460  stream->registerWithConn();
3461 
3464  // Setup Http::Request object. Maybe should be replaced by a call to (modified)
3465  // clientProcessRequest
3468  request->url.setScheme(proto, nullptr);
3469  request->method = method;
3470  request->url.host(useHost.c_str());
3471  request->url.port(usePort);
3472  http->request = request.getRaw();
3473  HTTPMSGLOCK(http->request);
3474 
3475  request->manager(this, http->al);
3476 
3477  if (proto == AnyP::PROTO_HTTP)
3478  request->header.putStr(Http::HOST, useHost.c_str());
3479 
3480  request->sources |= ((switchedToHttps() || port->transport.protocol == AnyP::PROTO_HTTPS) ? Http::Message::srcHttps : Http::Message::srcHttp);
3481 #if USE_AUTH
3482  if (getAuth())
3483  request->auth_user_request = getAuth();
3484 #endif
3485 
3486  inBuf = payload;
3487  flags.readMore = false;
3488 
3489  setLogUri(http, urlCanonicalClean(request.getRaw()));
3490  return http;
3491 }
3492 
3494 static bool
3496 {
3497  if (!Comm::IsConnOpen(c)) {
3498  Must(NHttpSockets > 0); // we tried to open some
3499  --NHttpSockets; // there will be fewer sockets than planned
3500  Must(HttpSockets[NHttpSockets] < 0); // no extra fds received
3501 
3502  if (!NHttpSockets) // we could not open any listen sockets at all
3503  fatalf("Unable to open %s",FdNote(portType));
3504 
3505  return false;
3506  }
3507  return true;
3508 }
3509 
3511 static bool
3513 {
3514  bool found = false;
3515  for (int i = 0; i < NHttpSockets && !found; ++i) {
3516  if ((found = HttpSockets[i] < 0))
3517  HttpSockets[i] = conn->fd;
3518  }
3519  return found;
3520 }
3521 
3522 static void
3524 {
3525  for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) {
3526  const SBuf &scheme = AnyP::UriScheme(s->transport.protocol).image();
3527 
3529  debugs(1, DBG_IMPORTANT, "WARNING: You have too many '" << scheme << "_port' lines.");
3530  debugs(1, DBG_IMPORTANT, " The limit is " << MAXTCPLISTENPORTS << " HTTP ports.");
3531  continue;
3532  }
3533 
3534 #if USE_OPENSSL
3535  if (s->flags.tunnelSslBumping) {
3536  if (!Config.accessList.ssl_bump) {
3537  debugs(33, DBG_IMPORTANT, "WARNING: No ssl_bump configured. Disabling ssl-bump on " << scheme << "_port " << s->s);
3538  s->flags.tunnelSslBumping = false;
3539  }
3540  if (!s->secure.staticContext && !s->secure.generateHostCertificates) {
3541  debugs(1, DBG_IMPORTANT, "Will not bump SSL at " << scheme << "_port " << s->s << " due to TLS initialization failure.");
3542  s->flags.tunnelSslBumping = false;
3543  if (s->transport.protocol == AnyP::PROTO_HTTP)
3544  s->secure.encryptTransport = false;
3545  }
3546  if (s->flags.tunnelSslBumping) {
3547  // Create ssl_ctx cache for this port.
3548  Ssl::TheGlobalContextStorage.addLocalStorage(s->s, s->secure.html?amicCertMemCacheSize);
3549  }
3550  }
3551 #endif
3552 
3553  if (s->secure.encryptTransport && !s->secure.staticContext) {
3554  debugs(1, DBG_CRITICAL, "ERROR: Ignoring " << scheme << "_port " << s->s << " due to TLS context initialization failure.");
3555  continue;
3556  }
3557 
3558  // Fill out a Comm::Connection which IPC will open as a listener for us
3559  // then pass back when active so we can start a TcpAcceptor subscription.
3560  s->listenConn = new Comm::Connection;
3561  s->listenConn->local = s->s;
3562 
3563  s->listenConn->flags = COMM_NONBLOCKING | (s->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) |
3564  (s->flags.natIntercept ? COMM_INTERCEPTION : 0);
3565 
3566  typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
3567  if (s->transport.protocol == AnyP::PROTO_HTTP) {
3568  // setup the subscriptions such that new connections accepted by listenConn are handled by HTTP
3571 
3572  AsyncCall::Pointer listenCall = asyncCall(33,2, "clientListenerConnectionOpened",
3574  Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpSocket, listenCall);
3575 
3576  } else if (s->transport.protocol == AnyP::PROTO_HTTPS) {
3577  // setup the subscriptions such that new connections accepted by listenConn are handled by HTTPS
3580 
3581  AsyncCall::Pointer listenCall = asyncCall(33, 2, "clientListenerConnectionOpened",
3583  s, Ipc::fdnHttpsSocket, sub));
3584  Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpsSocket, listenCall);
3585  }
3586 
3587  HttpSockets[NHttpSockets] = -1; // set in clientListenerConnectionOpened
3588  ++NHttpSockets;
3589  }
3590 }
3591 
3592 void
3594 {
3595  // Fill out a Comm::Connection which IPC will open as a listener for us
3596  port->listenConn = new Comm::Connection;
3597  port->listenConn->local = port->s;
3598  port->listenConn->flags =
3600  (port->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) |
3601  (port->flags.natIntercept ? COMM_INTERCEPTION : 0);
3602 
3603  // route new connections to subCall
3604  typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
3606  AsyncCall::Pointer listenCall =
3607  asyncCall(33, 2, "clientListenerConnectionOpened",
3609  port, fdNote, sub));
3610  Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, port->listenConn, fdNote, listenCall);
3611 
3613  HttpSockets[NHttpSockets] = -1;
3614  ++NHttpSockets;
3615 }
3616 
3618 static void
3620 {
3621  Must(s != NULL);
3622 
3623  if (!OpenedHttpSocket(s->listenConn, portTypeNote))
3624  return;
3625 
3626  Must(Comm::IsConnOpen(s->listenConn));
3627 
3628  // TCP: setup a job to handle accept() with subscribed handler
3629  AsyncJob::Start(new Comm::TcpAcceptor(s, FdNote(portTypeNote), sub));
3630 
3631  debugs(1, DBG_IMPORTANT, "Accepting " <<
3632  (s->flags.natIntercept ? "NAT intercepted " : "") <<
3633  (s->flags.tproxyIntercept ? "TPROXY intercepted " : "") <<
3634  (s->flags.tunnelSslBumping ? "SSL bumped " : "") <<
3635  (s->flags.accelSurrogate ? "reverse-proxy " : "")
3636  << FdNote(portTypeNote) << " connections at "
3637  << s->listenConn);
3638 
3639  Must(AddOpenedHttpSocket(s->listenConn)); // otherwise, we have received a fd we did not ask for
3640 }
3641 
3642 void
3644 {
3647 
3648  if (NHttpSockets < 1)
3649  fatal("No HTTP, HTTPS, or FTP ports configured");
3650 }
3651 
3652 void
3654 {
3655  for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) {
3656  if (s->listenConn != NULL) {
3657  debugs(1, DBG_IMPORTANT, "Closing HTTP(S) port " << s->listenConn->local);
3658  s->listenConn->close();
3659  s->listenConn = NULL;
3660  }
3661  }
3662 
3664 
3665  // TODO see if we can drop HttpSockets array entirely */
3666  for (int i = 0; i < NHttpSockets; ++i) {
3667  HttpSockets[i] = -1;
3668  }
3669 
3670  NHttpSockets = 0;
3671 }
3672 
3673 int
3675 {
3676  SBuf vary(request->vary_headers);
3677  int has_vary = entry->getReply()->header.has(Http::HdrType::VARY);
3678 #if X_ACCELERATOR_VARY
3679 
3680  has_vary |=
3682 #endif
3683 
3684  if (!has_vary || entry->mem_obj->vary_headers.isEmpty()) {
3685  if (!vary.isEmpty()) {
3686  /* Oops... something odd is going on here.. */
3687  debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary object on second attempt, '" <<
3688  entry->mem_obj->urlXXX() << "' '" << vary << "'");
3689  request->vary_headers.clear();
3690  return VARY_CANCEL;
3691  }
3692 
3693  if (!has_vary) {
3694  /* This is not a varying object */
3695  return VARY_NONE;
3696  }
3697 
3698  /* virtual "vary" object found. Calculate the vary key and
3699  * continue the search
3700  */
3701  vary = httpMakeVaryMark(request, entry->getReply());
3702 
3703  if (!vary.isEmpty()) {
3704  request->vary_headers = vary;
3705  return VARY_OTHER;
3706  } else {
3707  /* Ouch.. we cannot handle this kind of variance */
3708  /* XXX This cannot really happen, but just to be complete */
3709  return VARY_CANCEL;
3710  }
3711  } else {
3712  if (vary.isEmpty()) {
3713  vary = httpMakeVaryMark(request, entry->getReply());
3714 
3715  if (!vary.isEmpty())
3716  request->vary_headers = vary;
3717  }
3718 
3719  if (vary.isEmpty()) {
3720  /* Ouch.. we cannot handle this kind of variance */
3721  /* XXX This cannot really happen, but just to be complete */
3722  return VARY_CANCEL;
3723  } else if (vary.cmp(entry->mem_obj->vary_headers) == 0) {
3724  return VARY_MATCH;
3725  } else {
3726  /* Oops.. we have already been here and still haven't
3727  * found the requested variant. Bail out
3728  */
3729  debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary match on second attempt, '" <<
3730  entry->mem_obj->urlXXX() << "' '" << vary << "'");
3731  return VARY_CANCEL;
3732  }
3733  }
3734 }
3735 
3738 {
3739  const auto checklist = new ACLFilledChecklist(acl, nullptr, nullptr);
3740  clientAclChecklistFill(*checklist, http);
3741  return checklist;
3742 }
3743 
3744 void
3746 {
3747  checklist.setRequest(http->request);
3748  checklist.al = http->al;
3749  checklist.syncAle(http->request, http->log_uri);
3750 
3751  // TODO: If http->getConn is always http->request->clientConnectionManager,
3752  // then call setIdent() inside checklist.setRequest(). Otherwise, restore
3753  // USE_IDENT lost in commit 94439e4.
3754  ConnStateData * conn = http->getConn();
3755  const char *ident = (cbdataReferenceValid(conn) &&
3756  conn && conn->clientConnection) ?
3757  conn->clientConnection->rfc931 : dash_str;
3758  checklist.setIdent(ident);
3759 }
3760 
3761 bool
3763 {
3765 }
3766 
3769 {
3770  bodyPipe = new BodyPipe(this);
3771  if (size >= 0)
3772  bodyPipe->setBodySize(size);
3773  else
3775  return bodyPipe;
3776 }
3777 
3778 int64_t
3780 {
3781  if (!bodyPipe)
3782  return 0; // request without a body or read/produced all body bytes
3783 
3784  if (!bodyPipe->bodySizeKnown())
3785  return -1; // probably need to read more, but we cannot be sure
3786 
3787  const int64_t needToProduce = bodyPipe->unproducedSize();
3788  const int64_t haveAvailable = static_cast<int64_t>(inBuf.length());
3789 
3790  if (needToProduce <= haveAvailable)
3791  return 0; // we have read what we need (but are waiting for pipe space)
3792 
3793  return needToProduce - haveAvailable;
3794 }
3795 
3796 void
3798 {
3799  debugs(33, 4, HERE << "receiving error (" << clientConnection << "): " << error <<
3800  "; old sending error: " <<
3801  (stoppedSending() ? stoppedSending_ : "none"));
3802 
3803  if (const char *oldError = stoppedReceiving()) {
3804  debugs(33, 3, HERE << "already stopped receiving: " << oldError);
3805  return; // nothing has changed as far as this connection is concerned
3806  }
3807 
3809 
3810  if (const char *sendError = stoppedSending()) {
3811  debugs(33, 3, HERE << "closing because also stopped sending: " << sendError);
3813  }
3814 }
3815 
3816 void
3818 {
3819  if (bodyPipe != NULL) {
3820  debugs(33, 4, HERE << "no consumer for virgin body " << bodyPipe->status());
3822  }
3823 }
3824 
3826 void
3828 {
3829  Must(bodyPipe != NULL);
3830  debugs(33, 5, HERE << "start dechunking" << bodyPipe->status());
3831  assert(!bodyParser);
3833 }
3834 
3836 void
3838 {
3839  debugs(33, 5, HERE << "finish dechunking: " << withSuccess);
3840 
3841  if (bodyPipe != NULL) {
3842  debugs(33, 7, HERE << "dechunked tail: " << bodyPipe->status());
3843  BodyPipe::Pointer myPipe = bodyPipe;
3844  stopProducingFor(bodyPipe, withSuccess); // sets bodyPipe->bodySize()
3845  Must(!bodyPipe); // we rely on it being nil after we are done with body
3846  if (withSuccess) {
3847  Must(myPipe->bodySizeKnown());
3848  Http::StreamPointer context = pipeline.front();
3849  if (context != NULL && context->http && context->http->request)
3850  context->http->request->setContentLength(myPipe->bodySize());
3851  }
3852  }
3853 
3854  delete bodyParser;
3855  bodyParser = NULL;
3856 }
3857 
3858 // XXX: this is an HTTP/1-only operation
3859 void
3861 {
3862  if (!isOpen()) {
3863  debugs(33, 3, HERE << "ignoring 1xx due to earlier closure");
3864  return;
3865  }
3866 
3867  // HTTP/1 1xx status messages are only valid when there is a transaction to trigger them
3868  if (!pipeline.empty()) {
3869  HttpReply::Pointer rep(msg.reply);
3870  Must(rep);
3871  // remember the callback
3873 
3876 
3877  if (!writeControlMsgAndCall(rep.getRaw(), call)) {
3878  // but still inform the caller (so it may resume its operation)
3880  }
3881  return;
3882  }
3883 
3884  debugs(33, 3, HERE << " closing due to missing context for 1xx");
3886 }
3887 
3888 void
3890 {
3892 
3893  if (Http::StreamPointer deferredRequest = pipeline.front()) {
3894  debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded after control msg wrote");
3895  ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
3896  }
3897 }
3898 
3900 void
3902 {
3903  // FwdState might repin a failed connection sooner than this close
3904  // callback is called for the failed connection.
3905  assert(pinning.serverConnection == io.conn);
3906  pinning.closeHandler = NULL; // Comm unregisters handlers before calling
3907  const bool sawZeroReply = pinning.zeroReply; // reset when unpinning
3908  pinning.serverConnection->noteClosure();
3909  unpinConnection(false);
3910 
3911  if (sawZeroReply && clientConnection != NULL) {
3912  debugs(33, 3, "Closing client connection on pinned zero reply.");
3914  }
3915 
3916 }
3917 
3918 void
3920 {
3921  pinConnection(pinServer, *request);
3922 }
3923 
3924 void
3926 {
3927  Must(pic.connection);
3928  Must(pic.request);
3929  pinConnection(pic.connection, *pic.request);
3930 
3931  // monitor pinned server connection for remote-end closures.
3933 
3934  if (pipeline.empty())
3935  kick(); // in case clientParseRequests() was blocked by a busy pic.connection
3936 }
3937 
3939 void
3941 {
3942  if (Comm::IsConnOpen(pinning.serverConnection) &&
3943  pinning.serverConnection->fd == pinServer->fd) {
3944  debugs(33, 3, "already pinned" << pinServer);
3945  return;
3946  }
3947 
3948  unpinConnection(true); // closes pinned connection, if any, and resets fields
3949 
3950  pinning.serverConnection = pinServer;
3951 
3952  debugs(33, 3, HERE << pinning.serverConnection);
3953 
3954  Must(pinning.serverConnection != NULL);
3955 
3956  const char *pinnedHost = "[unknown]";
3957  pinning.host = xstrdup(request.url.host());
3958  pinning.port = request.url.port();
3959  pinnedHost = pinning.host;
3960  pinning.pinned = true;
3961  if (CachePeer *aPeer = pinServer->getPeer())
3962  pinning.peer = cbdataReference(aPeer);
3963  pinning.auth = request.flags.connectionAuth;
3964  char stmp[MAX_IPSTRLEN];
3965  char desc[FD_DESC_SZ];
3966  snprintf(desc, FD_DESC_SZ, "%s pinned connection for %s (%d)",
3967  (pinning.auth || !pinning.peer) ? pinnedHost : pinning.peer->name,
3969  clientConnection->fd);
3970  fd_note(pinning.serverConnection->fd, desc);
3971 
3973  pinning.closeHandler = JobCallback(33, 5,
3975  // remember the pinned connection so that cb does not unpin a fresher one
3976  typedef CommCloseCbParams Params;
3977  Params &params = GetCommParams<Params>(pinning.closeHandler);
3978  params.conn = pinning.serverConnection;
3979  comm_add_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
3980 }
3981 
3984 void
3986 {
3987  if (pinning.readHandler != NULL)
3988  return; // already monitoring
3989 
3991  pinning.readHandler = JobCallback(33, 3,
3993  Comm::Read(pinning.serverConnection, pinning.readHandler);
3994 }
3995 
3996 void
3998 {
3999  if (pinning.readHandler != NULL) {
4000  Comm::ReadCancel(pinning.serverConnection->fd, pinning.readHandler);
4001  pinning.readHandler = NULL;
4002  }
4003 }
4004 
4005 #if USE_OPENSSL
4006 bool
4008 {
4009  // A ready-for-reading connection means that the TLS server either closed
4010  // the connection, sent us some unexpected HTTP data, or started TLS
4011  // renegotiations. We should close the connection except for the last case.
4012 
4013  Must(pinning.serverConnection != nullptr);
4014  auto ssl = fd_table[pinning.serverConnection->fd].ssl.get();
4015  if (!ssl)
4016  return false;
4017 
4018  char buf[1];
4019  const int readResult = SSL_read(ssl, buf, sizeof(buf));
4020 
4021  if (readResult > 0 || SSL_pending(ssl) > 0) {
4022  debugs(83, 2, pinning.serverConnection << " TLS application data read");
4023  return false;
4024  }
4025 
4026  switch(const int error = SSL_get_error(ssl, readResult)) {
4027  case SSL_ERROR_WANT_WRITE:
4028  debugs(83, DBG_IMPORTANT, pinning.serverConnection << " TLS SSL_ERROR_WANT_WRITE request for idle pinned connection");
4029  // fall through to restart monitoring, for now
4030  case SSL_ERROR_NONE:
4031  case SSL_ERROR_WANT_READ:
4033  return true;
4034 
4035  default:
4036  debugs(83, 2, pinning.serverConnection << " TLS error: " << error);
4037  return false;
4038  }
4039 
4040  // not reached
4041  return true;
4042 }
4043 #endif
4044 
4047 void
4049 {
4050  pinning.readHandler = NULL; // Comm unregisters handlers before calling
4051 
4052  if (io.flag == Comm::ERR_CLOSING)
4053  return; // close handler will clean up
4054 
4055  Must(pinning.serverConnection == io.conn);
4056 
4057 #if USE_OPENSSL
4059  return;
4060 #endif
4061 
4062  const bool clientIsIdle = pipeline.empty();
4063 
4064  debugs(33, 3, "idle pinned " << pinning.serverConnection << " read " <<
4065  io.size << (clientIsIdle ? " with idle client" : ""));
4066 
4067  pinning.serverConnection->close();
4068 
4069  // If we are still sending data to the client, do not close now. When we are done sending,
4070  // ConnStateData::kick() checks pinning.serverConnection and will close.
4071  // However, if we are idle, then we must close to inform the idle client and minimize races.
4072  if (clientIsIdle && clientConnection != NULL)
4074 }
4075 
4078 {
4079  debugs(33, 7, HERE << pinning.serverConnection);
4080 
4081  bool valid = true;
4082  if (!Comm::IsConnOpen(pinning.serverConnection))
4083  valid = false;
4084  else if (pinning.auth && pinning.host && request && strcasecmp(pinning.host, request->url.host()) != 0)
4085  valid = false;
4086  else if (request && pinning.port != request->url.port())
4087  valid = false;
4088  else if (pinning.peer && !cbdataReferenceValid(pinning.peer))
4089  valid = false;
4090  else if (aPeer != pinning.peer)
4091  valid = false;
4092 
4093  if (!valid) {
4094  /* The pinning info is not safe, remove any pinning info */
4095  unpinConnection(true);
4096  }
4097 
4098  return pinning.serverConnection;
4099 }
4100 
4103 {
4104  debugs(33, 7, pinning.serverConnection);
4105  if (validatePinnedConnection(request, aPeer) != NULL)
4107 
4108  return pinning.serverConnection; // closed if validation failed
4109 }
4110 
4111 void
4113 {
4114  debugs(33, 3, HERE << pinning.serverConnection);
4115 
4116  if (pinning.peer)
4118 
4119  if (Comm::IsConnOpen(pinning.serverConnection)) {
4120  if (pinning.closeHandler != NULL) {
4121  comm_remove_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
4122  pinning.closeHandler = NULL;
4123  }
4124 
4126 
4127  // close the server side socket if requested
4128  if (andClose)
4129  pinning.serverConnection->close();
4130  pinning.serverConnection = NULL;
4131  }
4132 
4133  safe_free(pinning.host);
4134 
4135  pinning.zeroReply = false;
4136 
4137  /* NOTE: pinning.pinned should be kept. This combined with fd == -1 at the end of a request indicates that the host
4138  * connection has gone away */
4139 }
4140 
4141 void
4143 {
4144  // if we are parsing request body, its request is responsible for logging
4145  if (bodyPipe)
4146  return;
4147 
4148  // a request currently using this connection is responsible for logging
4149  if (!pipeline.empty() && pipeline.back()->mayUseConnection())
4150  return;
4151 
4152  /* Either we are waiting for the very first transaction, or
4153  * we are done with the Nth transaction and are waiting for N+1st.
4154  * XXX: We assume that if anything was added to inBuf, then it could
4155  * only be consumed by actions already covered by the above checks.
4156  */
4157 
4158  // do not log connections that closed after a transaction (it is normal)
4159  // TODO: access_log needs ACLs to match received-no-bytes connections
4160  if (pipeline.nrequests && inBuf.isEmpty())
4161  return;
4162 
4163  /* Create a temporary ClientHttpRequest object. Its destructor will log. */
4164  ClientHttpRequest http(this);
4165  http.req_sz = inBuf.length();
4166  // XXX: Or we died while waiting for the pinned connection to become idle.
4167  char const *uri = "error:transaction-end-before-headers";
4168  http.uri = xstrdup(uri);
4169  setLogUri(&http, uri);
4170 }
4171 
4172 bool
4174 {
4176 #if USE_OPENSSL
4177  &&
4178  ((port->flags.isIntercepted() && port->flags.tunnelSslBumping)
4179  || (serverBump() && pinning.serverConnection))
4180 #endif
4181  ;
4182 }
4183 
4186 {
4187  if (!theNotes)
4188  theNotes = new NotePairs;
4189  return theNotes;
4190 }
4191 
4192 std::ostream &
4193 operator <<(std::ostream &os, const ConnStateData::PinnedIdleContext &pic)
4194 {
4195  return os << pic.connection << ", request=" << pic.request;
4196 }
4197 
virtual void print(std::ostream &os) const
Definition: client_side.cc:153
bool switchedToHttps() const
Definition: client_side.h:252
sslproxy_cert_adapt * cert_adapt
Definition: SquidConfig.h:515
static void clientHttpConnectionsOpen(void)
void nonBlockingCheck(ACLCB *callback, void *callback_data)
Definition: Checklist.cc:238
int internalHostnameIs(const char *arg)
Definition: internal.cc:156
bool setCommonName
Replace the CN field of the mimicing subject with the given.
Definition: gadgets.h:221
HierarchyLogEntry hier
Definition: HttpRequest.h:145
bool splice()
Splice a bumped client connection on peek-and-splice mode.
virtual ~ConnStateData()
Definition: client_side.cc:613
time_t timeLeft(const time_t idleTimeout) const
Definition: Connection.cc:120
AnyP::ProtocolVersion ProtocolVersion(unsigned int aMajor, unsigned int aMinor)
HTTP version label information.
char * skipLeadingSpace(char *aString)
int has(Http::HdrType id) const
Definition: HttpHeader.cc:1002
void clientProcessRequestFinished(ConnStateData *conn, const HttpRequest::Pointer &request)
#define debug_log
change-avoidance macro; new code should call DebugStream() instead
Definition: Debug.h:110
#define HTTP_REQBUF_SZ
Definition: defines.h:216
static bool clientPingHasFinished(ping_data const *aPing)
Definition: client_side.cc:255
#define JobCallback(dbgSection, dbgLevel, Dialer, job, method)
Convenience macro to create a Dialer-based job callback.
Definition: AsyncJobCalls.h:68
IdentConfig TheConfig
Definition: Ident.cc:73
#define SQUIDSTRINGPH
Definition: SquidString.h:21
const char * FdNote(int fdNodeId)
converts FdNoteId into a string
Definition: FdNotes.cc:16
err_type errType
Definition: HttpRequest.h:149
void count(double val)
Definition: StatHist.cc:57
#define rfc1738_escape_unescaped(x)
Definition: rfc1738.h:59
bool mayUseConnection() const
Definition: Stream.h:140
static CTCB clientLifetimeTimeout
Definition: client_side.cc:173
void setAuth(const Auth::UserRequest::Pointer &aur, const char *cause)
Definition: client_side.cc:502
#define fd_table
Definition: fde.h:157
Ssl::ServerBump * serverBump()
Definition: client_side.h:253
bool setValidAfter
Do not mimic "Not Valid After" field.
Definition: gadgets.h:219
int timeout
Definition: PingData.h:24
NotePairs::Pointer theNotes
Definition: client_side.h:418
#define COMM_SELECT_READ
Definition: defines.h:36
void StartListening(int sock_type, int proto, const Comm::ConnectionPointer &listenConn, FdNoteId fdNote, AsyncCall::Pointer &callback)
HttpHdrRange * range
Definition: HttpRequest.h:131
StatCounters statCounter
Definition: StatCounters.cc:12
#define assert(EX)
Definition: assert.h:17
Http::StreamPointer front() const
get the first request context in the pipeline
Definition: Pipeline.cc:28
void const char HLPCB * callback
Definition: stub_helper.cc:16
#define SQUIDSTRINGPRINT(s)
Definition: SquidString.h:22
void clientStreamInit(dlink_list *list, CSR *func, CSD *rdetach, CSS *readstatus, ClientStreamData readdata, CSCB *callback, CSD *cdetach, ClientStreamData callbackdata, StoreIOBuffer tailBuffer)
time_t request
Definition: SquidConfig.h:108
bool setValidBefore
Do not mimic "Not Valid Before" field.
Definition: gadgets.h:220
static int tlsAttemptHandshake(ConnStateData *conn, PF *callback)
SBuf & assign(const SBuf &S)
Definition: SBuf.cc:83
bool timedout
_TIMEDOUT: terminated due to a lifetime or I/O timeout
Definition: LogTags.h:71
bool verifySslCertificate(Security::ContextPointer &, CertificateProperties const &)
Definition: support.cc:889
ConnStateData * getConn() const
bool concurrentRequestQueueFilled() const
#define cbdataReferenceDone(var)
Definition: cbdata.h:350
char reqbuf[HTTP_REQBUF_SZ]
Definition: Stream.h:134
void enableAutoConsumption()
Definition: BodyPipe.cc:319
Ssl::BumpMode step1
The SSL bump mode at step1.
Definition: ServerBump.h:49
virtual void append(const char *c, int sz)
Definition: MemBuf.cc:216
https_port or bumped http_port tunnel; HTTPS server
Definition: Message.h:32
Security::NegotiationHistory * tlsNegotiations()
Definition: Connection.cc:130
void terminateAll(const int xerrno)
tell everybody about the err, and abort all waiting requests
Definition: Pipeline.cc:52
static const CharacterSet LF
Definition: CharacterSet.h:89
std::string const & getBody() const
Current body. If parsing is not finished the method returns incompleted body.
bool isTcpHit() const
determine if the log tag code indicates a cache HIT
Definition: LogTags.cc:72
ConnStateData * NewServer(MasterXactionPointer &xact)
create a new HTTP connection handler; never returns NULL
Definition: Http1Server.cc:350
bool internalCheck(const SBuf &urlPath)
Definition: internal.cc:68
std::vector< HttpHdrRangeSpec * >::iterator iterator
int errDetail
errType-specific detail about the transaction error
Definition: HttpRequest.h:150
void parseTlsHandshake()
Http::StreamPointer back() const
get the last request context in the pipeline
Definition: Pipeline.cc:40
virtual Http::Stream * parseOneRequest()=0
void fd_note(int fd, const char *s)
Definition: fd.cc:251
Definition: Server.h:28
const char * status() const
Definition: BodyPipe.cc:440
err_type handleChunkedRequestBody()
parses available chunked encoded body bytes, checks size, returns errors
void setReplyToError(err_type, Http::StatusCode, const HttpRequestMethod &, char const *, Ip::Address &, HttpRequest *, const char *, Auth::UserRequest::Pointer)
builds error using clientBuildError() and calls setReplyToError() below
struct ClientHttpRequest::Redirect redirect
void CTCB(const CommTimeoutCbParams &params)
Definition: CommCalls.h:39
SBuf vary_headers
The variant second-stage cache key. Generated from Vary header pattern for this request.
Definition: HttpRequest.h:159
ConnStateData(const MasterXactionPointer &xact)
void accessLogLog(AccessLogEntry::Pointer &, ACLChecklist *checklist)
Definition: access_log.cc:144
static void clientUpdateStatHistCounters(const LogTags &logType, int svc_time)
Definition: client_side.cc:213
HttpRequest::Pointer request
to-server request that initiated serverConnection
Definition: client_side.h:173
virtual int64_t contentLen() const
Definition: store.cc:1680
bool needProxyProtocolHeader_
whether PROXY protocol header is still expected
Definition: client_side.h:384
int NHttpSockets
Definition: PortCfg.cc:24
virtual void afterClientRead()
processing to be done after a Comm::Read()
void resetSslCommonName(const char *name)
Definition: client_side.h:261
Definition: Acl.h:113
void mustStop(const char *aReason)
Definition: AsyncJob.cc:69
void path(const char *p)
Definition: Uri.h:83
Definition: SBuf.h:86
struct SquidConfig::@113 onoff
bool fakeAConnectRequest(const char *reason, const SBuf &payload)
void configureUnconfiguredSslContext(Security::ContextPointer &, Ssl::CertSignAlgorithm signAlgorithm, AnyP::PortCfg &)
Definition: support.cc:839
void startPinnedConnectionMonitoring()
SBuf image() const
Definition: UriScheme.h:50
virtual void swanSong()
Definition: Server.cc:47
SQUIDCEXTERN CSD clientReplyDetach
Definition: client_side.h:446
ClientHttpRequest * buildFakeRequest(Http::MethodType const method, SBuf &useHost, unsigned short usePort, const SBuf &payload)
build a fake http request
Subscription::Pointer sub
The handler to be subscribed for this connetion listener.
Definition: client_side.cc:167
#define xcalloc
Definition: membanger.c:57
static void httpsAccept(const CommAcceptCbParams &params)
std::ostream & startPrint(std::ostream &os) const
starts printing arguments, return os
ByteCounter hit_kbytes_out
Definition: StatCounters.h:45
#define RFC1738_ESCAPE_UNESCAPED
Definition: rfc1738.h:25
Ip::Address src_addr
Comm::ConnectionPointer clientConnection
struct SquidConfig::@124 ssl_client
bool transparent() const
HttpRequestMethod method
Definition: HttpRequest.h:102
virtual bool connFinishedWithConn(int size)
??
void setLogUri(ClientHttpRequest *http, char const *uri, bool cleanUrl)
Ssl::ServerBump * sslServerBump
HTTPS server cert. fetching state for bump-ssl-server-first.
Definition: client_side.h:407
const MemBuf & buf() const
Definition: BodyPipe.h:137
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
void add(const SBuf &key, const SBuf &value)
Definition: Notes.cc:280
void error(char *format,...)
int default_read_method(int, char *, int)
Definition: fd.cc:147
int i
Definition: membanger.c:49
SBuf sslBumpCertKey
Key to use to store/retrieve generated certificate.
Definition: client_side.h:404
void banAction(const allow_t &action)
add action to the list of banned actions
Definition: Checklist.cc:402
#define xstrdup
SBuf & append(const SBuf &S)
Definition: SBuf.cc:195
SBuf preservedClientData
Definition: client_side.h:311
virtual void dial(AsyncCall &)
Definition: client_side.cc:159
#define SQUID_X509_V_ERR_DOMAIN_MISMATCH
Definition: support.h:43
ListeningStartedDialer(Handler aHandler, AnyP::PortCfgPointer &aPortCfg, const Ipc::FdNoteId note, const Subscription::Pointer &aSub)
Definition: client_side.cc:150
String sslConnectHostOrIp
The SSL server host name appears in CONNECT request or the server ip address for the intercepted requ...
Definition: client_side.h:399
int HttpSockets[MAXTCPLISTENPORTS]
Definition: PortCfg.cc:25
int clientdbEstablished(const Ip::Address &addr, int delta)
Definition: client_db.cc:183
char * xstrndup(const char *s, size_t n)
Definition: xstring.cc:56
struct timeval start_time
The time the master transaction started.
#define safe_free(x)
Definition: xalloc.h:73
void stopPinnedConnectionMonitoring()
The caller assumes responsibility for connection closure detection.
const char * bumpMode(int bm)
Definition: support.h:144
bool mayTunnelUnsupportedProto()
whether tunneling of unsupported protocol is allowed for this connection
Definition: Flag.h:16
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
struct SquidConfig::@108 Addrs
MessageSizes clientReplySz
counters for the response sent to client
Auth::UserRequest::Pointer auth_
some user details that can be used to perform authentication on this connection
Definition: client_side.h:388
void StopListening()
reject new connections to any configured ftp_port
Definition: FtpServer.cc:285
virtual void swanSong()
Definition: client_side.cc:583
http_port or HTTP server
Definition: Message.h:38
struct timeval trTime
The response time.
void HTTPMSGLOCK(Http::Message *a)
Definition: Message.h:154
void clientdbUpdate(const Ip::Address &addr, const LogTags &ltype, AnyP::ProtocolType p, size_t size)
Definition: client_db.cc:139
void registerWithConn()
register this stream with the Server
Definition: Stream.cc:52
Ssl::BumpMode step2
The SSL bump mode at step2.
Definition: ServerBump.h:50
std::string commonName
A CN to use for the generated certificate.
Definition: gadgets.h:222
void clear()
Definition: SBuf.cc:178
bool persistent() const
Definition: Message.cc:257
void clientStreamAbort(clientStreamNode *thisObject, ClientHttpRequest *http)
clientStreamNode * getClientReplyContext() const
Definition: Stream.cc:547
void doPeekAndSpliceStep()
#define Must(condition)
Like assert() but throws an exception instead of aborting the process.
Definition: TextException.h:69
#define COMM_INTERCEPTION
Definition: Connection.h:49
int applyMask(const Address &mask)
Definition: Address.cc:87
size_t count() const
how many requests are currently pipelined
Definition: Pipeline.h:53
Comm::ConnectionPointer tcpClient
TCP/IP level details about the client connection.
bool SessionIsResumed(const Security::SessionPointer &)
whether the session is a resumed one
Definition: Session.cc:210
const char * CertAdaptAlgorithmStr[]
Definition: gadgets.cc:207
AnyP::ProtocolVersion http_ver
Definition: Message.h:72
#define xisspace(x)
Definition: xis.h:17
bool isEmpty() const
Definition: SBuf.h:420
#define DBG_CRITICAL
Definition: Debug.h:45
struct timeval stop
Definition: PingData.h:20
int conn
the current server connection FD
Definition: Transport.cc:26
static bool httpsCreate(const Comm::ConnectionPointer &conn, const Security::ContextPointer &ctx)
Create TLS connection structure and update fd_table.
void setBodySize(uint64_t aSize)
Definition: BodyPipe.cc:147
AnyP::PortCfgPointer HttpPortList
list of Squid http(s)_port configured
Definition: PortCfg.cc:21
void SBufToCstring(char *d, const SBuf &s)
Definition: SBuf.h:741
void expectNoConsumption()
there will be no more setConsumer() calls
Definition: BodyPipe.cc:267
void notePinnedConnectionBecameIdle(PinnedIdleContext pic)
Called when a pinned connection becomes available for forwarding the next request.
void connStateClosed(const CommCloseCbParams &io)
Definition: client_side.cc:495
static const CharacterSet ALPHA
Definition: CharacterSet.h:73
static void clientListenerConnectionOpened(AnyP::PortCfgPointer &s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub)
process clientHttpConnectionsOpen result
Ssl::CertSignAlgorithm signAlgorithm
The signing algorithm to use.
Definition: client_side.h:408
Ip::Address log_addr
Definition: client_side.h:127
struct timeval current_time
Definition: stub_time.cc:15
void prepareLogWithRequestDetails(HttpRequest *, AccessLogEntry::Pointer &)
Definition: client_side.cc:323
void(* Handler)(AnyP::PortCfgPointer &portCfg, const Ipc::FdNoteId note, const Subscription::Pointer &sub)
Definition: client_side.cc:149
void clientAclChecklistFill(ACLFilledChecklist &checklist, ClientHttpRequest *http)
size_type size() const
Definition: SquidString.h:72
int default_write_method(int, const char *, int)
Definition: fd.cc:157
iterator end()
void setReplyToStoreEntry(StoreEntry *e, const char *reason)
replaces current response store entry with the given one
void requestTimeout(const CommTimeoutCbParams &params)
ConnStateData * conn() const
The client connection manager.
void append(char const *buf, int len)
Definition: String.cc:161
SBuf httpMakeVaryMark(HttpRequest *request, HttpReply const *reply)
Definition: http.cc:605
Security::CertPointer serverCert
Definition: ServerBump.h:47
const char * findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end)
void clientSetKeepaliveFlag(ClientHttpRequest *http)
decide whether to expect multiple requests on the corresponding connection
Definition: client_side.cc:640
Security::ContextPointer GenerateSslContextUsingPkeyAndCertFromMemory(const char *data, Security::ServerOptions &, bool trusted)
Definition: support.cc:786
void finishDechunkingRequest(bool withSuccess)
put parsed content into input buffer and clean up
size_t putMoreData(const char *buf, size_t size)
Definition: BodyPipe.cc:213
#define w_space
bool readMore
needs comm_read (for this request or new requests)
Definition: client_side.h:130
StatHist hitSvcTime
Definition: StatCounters.h:49
ftp_port or FTP server
Definition: Message.h:39
void startPeekAndSplice()
Initializes and starts a peek-and-splice negotiation with the SSL client.
void stopSending(const char *error)
note response sending error and close as soon as we read the request
Definition: client_side.cc:972
HttpHdrRangeIter range_iter
bool connectionAuth
Definition: RequestFlags.h:78
static void fwdStart(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *)
Same as Start() but no master xaction info (AccessLogEntry) available.
Definition: FwdState.cc:394
struct StatCounters::@135 cd
AsyncCall * asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition: AsyncCall.h:156
FdNoteId
We cannot send char* FD notes to other processes. Pass int IDs and convert.
Definition: FdNotes.h:20
Helper::ResultCode result
The helper response 'result' field.
Definition: Reply.h:58
void manager(const CbcPointer< ConnStateData > &aMgr, const AccessLogEntryPointer &al)
associates the request with a from-client connection manager
Definition: HttpRequest.cc:702
MemObject * memObject() const
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:96
static const CharacterSet HEXDIG
Definition: CharacterSet.h:85
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
void Read(const Comm::ConnectionPointer &conn, AsyncCall::Pointer &callback)
Definition: Read.cc:39
bool productionEnded() const
Definition: BodyPipe.h:113
sslproxy_cert_sign * cert_sign
Definition: SquidConfig.h:514
Security::ContextPointer getTlsContextFromCache(const SBuf &cacheKey, const Ssl::CertificateProperties &certProperties)
static const std::string code_new_certificate
String code for "new_certificate" messages.
Definition: crtd_message.h:76
Security::ContextPointer GenerateSslContext(CertificateProperties const &, Security::ServerOptions &, bool trusted)
Definition: support.cc:800
size_t appendDomainLen
Definition: SquidConfig.h:212
bool multipartRangeRequest() const
Definition: client_side.cc:687
const char * stoppedSending() const
true if we stopped sending the response
Definition: client_side.h:151
Security::PrivateKeyPointer signWithPkey
The key of the signing certificate.
Definition: gadgets.h:218
static Pointer Start(AsyncJob *job)
starts a freshly created job (i.e., makes the job asynchronous)
Definition: AsyncJob.cc:23
parameters for the async notePinnedConnectionBecameIdle() call
Definition: client_side.h:167
char * rfc1738_do_escape(const char *url, int flags)
Definition: rfc1738.c:56
void IOACB(const CommAcceptCbParams &params)
Definition: CommCalls.h:33
uint64_t unproducedSize() const
Definition: BodyPipe.cc:179
std::vector< ClientDelayPool::Pointer > pools
NotePairs::Pointer notes()
Definition: HttpRequest.cc:680
HttpRequest * adapted_request
ACLFilledChecklist * clientAclChecklistCreate(const acl_access *acl, ClientHttpRequest *http)
time_t lifetime
Definition: SquidConfig.h:104
int tvSubMsec(struct timeval, struct timeval)
Definition: stub_time.cc:20
Comm::ConnectionPointer conn
Definition: CommCalls.h:85
const char * xstrerr(int error)
Definition: xstrerror.cc:83
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:24
static void clientUpdateHierCounters(HierarchyLogEntry *)
Definition: client_side.cc:264
common API for all StartListening() callbacks
void storeTlsContextToCache(const SBuf &cacheKey, Security::ContextPointer &ctx)
unsigned int major
major version number
bool CreateServerSession(const Security::ContextPointer &, const Comm::ConnectionPointer &, const char *squidCtx)
Definition: Session.cc:191
const char * stoppedReceiving_
the reason why we no longer read the request or nil
Definition: client_side.h:414
int pipeline_max_prefetch
Definition: SquidConfig.h:347
virtual time_t idleTimeout() const =0
timeout to use when waiting for the next request
void const char HLPCB void * data
Definition: stub_helper.cc:16
bool configureSSLUsingPkeyAndCertFromMemory(SSL *ssl, const char *data, AnyP::PortCfg &port)
Definition: support.cc:869
CbDataList< Security::CertError > CertErrors
Holds a list of X.509 certificate errors.
Definition: forward.h:81
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:404
LogTags logType
the processing tags associated with this request transaction.
Definition: parse.c:104
static int clientIsContentLengthValid(HttpRequest *r)
checks body length of non-chunked requests
Definition: client_side.cc:653
iterator begin()
int urlCheckRequest(const HttpRequest *r)
Definition: Uri.cc:757
struct Ssl::ServerBump::@128 act
bumping actions at various bumping steps
StatusCode
Definition: StatusCode.h:20
bool parseProxy2p0()
parse the PROXY/2.0 protocol header from the connection read buffer
bool hasContent() const
Definition: MemBuf.h:54
int fd
FD which the call was about. Set by the async call creator.
Definition: CommCalls.h:90
uint64_t producedSize() const
Definition: BodyPipe.h:112
int64_t content_length
Definition: Message.h:83
virtual void clientPinnedConnectionClosed(const CommCloseCbParams &io)
Our close handler called by Comm when the pinned connection is closed.
int getMyPort(void)
Definition: tools.cc:1003
void port(unsigned short p)
Definition: Uri.h:80
virtual void sendControlMsg(HttpControlMsg)
called to send the 1xx message and notify the Source
void httpsSslBumpStep2AccessCheckDone(allow_t answer, void *data)
bool parseProxyProtocolHeader()
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
#define cbdataReference(var)
Definition: cbdata.h:341
Http1::TeChunkedParser * bodyParser
parses HTTP/1.1 chunked request body
Definition: client_side.h:99
void setIdent(const char *userIdentity)
configure rfc931 user identity for the first time
HttpReply * reply
void sslCrtdHandleReply(const Helper::Reply &reply)
Proccess response from ssl_crtd.
#define DBG_IMPORTANT
Definition: Debug.h:46
void readSomeData()
maybe grow the inBuf and schedule Comm::Read()
Definition: Server.cc:85
void clientProcessRequest(ConnStateData *conn, const Http1::RequestParserPointer &hp, Http::Stream *context)
void SetSelect(int, unsigned int, PF *, void *, time_t)
Mark an FD to be watched for its IO status.
Definition: ModDevPoll.cc:225
Security::ContextPointer GetFrom(Security::SessionPointer &s)
Helper function to retrieve a (non-locked) ContextPointer from a SessionPointer.
Definition: Session.h:87
ConnStateData * NewServer(MasterXactionPointer &xact)
create a new HTTPS connection handler; never returns NULL
Definition: Http1Server.cc:356
#define URI_WHITESPACE_ALLOW
Definition: defines.h:195
GlobalContextStorage TheGlobalContextStorage
Global cache for store all SSL server certificates.
virtual bool writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call)=0
handle a control message received by context from a peer and call back
Security::CertPointer mimicCert
Certificate to mimic.
Definition: gadgets.h:216
void httpHeaderAddContRange(HttpHeader *, HttpHdrRangeSpec, int64_t)
static const CharacterSet DIGIT
Definition: CharacterSet.h:81
struct StatCounters::@136 netdb
bool mayNeedMoreData() const
Definition: BodyPipe.h:118
String content_type
Definition: HttpReply.h:50
#define FD_DESC_SZ
Definition: defines.h:46
AnyP::ProtocolVersion transferProtocol
Definition: Server.h:104
NotePairs::Pointer notes()
bool add(const Key &key, EntryValue *t)
Add an entry to the map.
Definition: LruMap.h:140
void unpinConnection(const bool andClose)
Undo pinConnection() and, optionally, close the pinned connection.
bool parseHello(const SBuf &data)
Definition: Handshake.cc:516
void reset()
Definition: MemBuf.cc:132
void setScheme(const AnyP::ProtocolType &p, const char *str)
convert the URL scheme to that given
Definition: Uri.h:67
void expectNoForwarding()
cleans up virgin request [body] forwarding state
Definition: c