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