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