]> git.ipfire.org Git - thirdparty/squid.git/blame - src/client_side.cc
Improve AnyP::Uri::port_ and related port storage types (#1255)
[thirdparty/squid.git] / src / client_side.cc
CommitLineData
dd11e0b7 1/*
b8ae064d 2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
dd11e0b7 3 *
bbc27441
AJ
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.
dd11e0b7 7 */
f88bb09c 8
bbc27441
AJ
9/* DEBUG: section 33 Client-side Routines */
10
63be0a78 11/**
12 \defgroup ClientSide Client-Side Logics
13 *
d85b8894 14 \section cserrors Errors and client side
edce4d98 15 *
63be0a78 16 \par Problem the first:
17 * the store entry is no longer authoritative on the
edce4d98 18 * reply status. EBITTEST (E_ABORT) is no longer a valid test outside
19 * of client_side_reply.c.
20 * Problem the second: resources are wasted if we delay in cleaning up.
21 * Problem the third we can't depend on a connection close to clean up.
9e008dda 22 *
63be0a78 23 \par Nice thing the first:
9e008dda 24 * Any step in the stream can callback with data
edce4d98 25 * representing an error.
26 * Nice thing the second: once you stop requesting reads from upstream,
27 * upstream can be stopped too.
28 *
63be0a78 29 \par Solution #1:
30 * Error has a callback mechanism to hand over a membuf
9e008dda 31 * with the error content. The failing node pushes that back as the
edce4d98 32 * reply. Can this be generalised to reduce duplicate efforts?
33 * A: Possibly. For now, only one location uses this.
34 * How to deal with pre-stream errors?
35 * Tell client_side_reply that we *want* an error page before any
36 * stream calls occur. Then we simply read as normal.
63be0a78 37 *
38 *
d85b8894 39 \section pconn_logic Persistent connection logic:
63be0a78 40 *
41 \par
42 * requests (httpClientRequest structs) get added to the connection
43 * list, with the current one being chr
9e008dda 44 *
63be0a78 45 \par
46 * The request is *immediately* kicked off, and data flows through
47 * to clientSocketRecipient.
9e008dda 48 *
63be0a78 49 \par
50 * If the data that arrives at clientSocketRecipient is not for the current
51 * request, clientSocketRecipient simply returns, without requesting more
52 * data, or sending it.
53 *
54 \par
4a4fbcef 55 * ConnStateData::kick() will then detect the presence of data in
9e008dda 56 * the next ClientHttpRequest, and will send it, restablishing the
63be0a78 57 * data flow.
edce4d98 58 */
59
582c2af2 60#include "squid.h"
04f55905 61#include "acl/FilledChecklist.h"
65d448bc 62#include "anyp/PortCfg.h"
e5ddd4ce 63#include "base/AsyncCallbacks.h"
00406b24 64#include "base/Subscription.h"
d841c88d 65#include "base/TextException.h"
a011edee 66#include "CachePeer.h"
95e6d864 67#include "client_db.h"
602d9612 68#include "client_side.h"
04f55905
AJ
69#include "client_side_reply.h"
70#include "client_side_request.h"
71#include "ClientRequestContext.h"
c8be6d7b 72#include "clientStream.h"
c4b7a5a9 73#include "comm.h"
cfd66529 74#include "comm/Connection.h"
d841c88d 75#include "comm/Loops.h"
7e66d5e2 76#include "comm/Read.h"
cbff89ba 77#include "comm/TcpAcceptor.h"
582c2af2
FC
78#include "comm/Write.h"
79#include "CommCalls.h"
675b8408 80#include "debug/Messages.h"
83b053a0 81#include "error/ExceptionErrorDetail.h"
8eb0a7ee 82#include "errorpage.h"
c4ad1349 83#include "fd.h"
04f55905 84#include "fde.h"
95e6d864 85#include "fqdncache.h"
eb13c21e 86#include "FwdState.h"
67679543 87#include "globals.h"
24438ec5
AJ
88#include "helper.h"
89#include "helper/Reply.h"
5c0c642e 90#include "http.h"
c99510dd 91#include "http/one/RequestParser.h"
db1720f8 92#include "http/one/TeChunkedParser.h"
d3dddfb5 93#include "http/Stream.h"
25b6a907 94#include "HttpHdrContRange.h"
a5bac1d2 95#include "HttpHeaderTools.h"
528b2c61 96#include "HttpReply.h"
97#include "HttpRequest.h"
4daaf3cb
AJ
98#include "ident/Config.h"
99#include "ident/Ident.h"
308e60be 100#include "internal.h"
cbff89ba 101#include "ipc/FdNotes.h"
fe090a86 102#include "ipc/StartListening.h"
1c7ae5ff 103#include "log/access_log.h"
0eb49b6d 104#include "MemBuf.h"
04f55905 105#include "MemObject.h"
b6149797 106#include "mime_header.h"
b1cef121 107#include "parser/Tokenizer.h"
36c774f7
EB
108#include "proxyp/Header.h"
109#include "proxyp/Parser.h"
83b053a0 110#include "sbuf/Stream.h"
907831e6 111#include "security/Certificate.h"
e227da8d 112#include "security/CommunicationSecrets.h"
4106be3f 113#include "security/Io.h"
e227da8d 114#include "security/KeyLog.h"
4106be3f 115#include "security/NegotiationHistory.h"
92ae4c86 116#include "servers/forward.h"
4d5904f7 117#include "SquidConfig.h"
e1656dc4 118#include "StatCounters.h"
00a7574e 119#include "StatHist.h"
582c2af2
FC
120#include "Store.h"
121#include "TimeOrTag.h"
4e540555 122#include "tools.h"
582c2af2
FC
123
124#if USE_AUTH
125#include "auth/UserRequest.h"
126#endif
127#if USE_DELAY_POOLS
128#include "ClientInfo.h"
b27668ec 129#include "MessageDelayPools.h"
582c2af2 130#endif
cb4f4424 131#if USE_OPENSSL
d620ae0e 132#include "ssl/bio.h"
95d2589c 133#include "ssl/context_storage.h"
602d9612 134#include "ssl/gadgets.h"
95d2589c 135#include "ssl/helper.h"
602d9612 136#include "ssl/ProxyCerts.h"
fd4624d7 137#include "ssl/ServerBump.h"
4db984be 138#include "ssl/support.h"
95d2589c 139#endif
95d2589c 140
074d6a40
AJ
141#include <climits>
142#include <cmath>
95d2589c 143#include <limits>
95d2589c 144
6fa8c664
MM
145#if HAVE_SYSTEMD_SD_DAEMON_H
146#include <systemd/sd-daemon.h>
147#endif
148
e5ddd4ce
AR
149// TODO: Remove this custom dialer and simplify by creating the TcpAcceptor
150// subscription later, inside clientListenerConnectionOpened() callback, just
151// like htcpOpenPorts(), icpOpenPorts(), and snmpPortOpened() do it.
cbff89ba 152/// dials clientListenerConnectionOpened call
e5ddd4ce
AR
153class ListeningStartedDialer:
154 public CallDialer,
155 public WithAnswer<Ipc::StartListeningAnswer>
fe090a86
AR
156{
157public:
fa720bfb
AJ
158 typedef void (*Handler)(AnyP::PortCfgPointer &portCfg, const Ipc::FdNoteId note, const Subscription::Pointer &sub);
159 ListeningStartedDialer(Handler aHandler, AnyP::PortCfgPointer &aPortCfg, const Ipc::FdNoteId note, const Subscription::Pointer &aSub):
f53969cc 160 handler(aHandler), portCfg(aPortCfg), portTypeNote(note), sub(aSub) {}
fe090a86 161
e5ddd4ce 162 /* CallDialer API */
337b9aa4 163 void print(std::ostream &os) const override {
e5ddd4ce 164 os << '(' << answer_ << ", " << FdNote(portTypeNote) << " port=" << (void*)&portCfg << ')';
5667a628 165 }
fe090a86
AR
166
167 virtual bool canDial(AsyncCall &) const { return true; }
8bbb16e3 168 virtual void dial(AsyncCall &) { (handler)(portCfg, portTypeNote, sub); }
fe090a86 169
e5ddd4ce 170 /* WithAnswer API */
337b9aa4 171 Ipc::StartListeningAnswer &answer() override { return answer_; }
e5ddd4ce 172
fe090a86
AR
173public:
174 Handler handler;
175
176private:
e5ddd4ce
AR
177 // answer_.conn (set/updated by IPC code) is portCfg.listenConn (used by us)
178 Ipc::StartListeningAnswer answer_; ///< StartListening() results
fa720bfb 179 AnyP::PortCfgPointer portCfg; ///< from HttpPortList
cbff89ba 180 Ipc::FdNoteId portTypeNote; ///< Type of IPC socket being opened
2f8abb64 181 Subscription::Pointer sub; ///< The handler to be subscribed for this connection listener
fe090a86
AR
182};
183
fa720bfb 184static void clientListenerConnectionOpened(AnyP::PortCfgPointer &s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub);
fe090a86 185
e0d28505 186static IOACB httpAccept;
3898f57f 187#if USE_IDENT
05832ae1 188static IDCB clientIdentDone;
3898f57f 189#endif
47f6e231 190static int clientIsRequestBodyTooLargeForPolicy(int64_t bodyLength);
50c09fc4 191
91369933
AJ
192static void clientUpdateStatHistCounters(const LogTags &logType, int svc_time);
193static void clientUpdateStatCounters(const LogTags &logType);
c8be6d7b 194static void clientUpdateHierCounters(HierarchyLogEntry *);
528b2c61 195static bool clientPingHasFinished(ping_data const *aPing);
63ed9e8e 196void prepareLogWithRequestDetails(HttpRequest *, const AccessLogEntryPointer &);
d3dddfb5 197static void ClientSocketContextPushDeferredIfNeeded(Http::StreamPointer deferredRequest, ConnStateData * conn);
c8be6d7b 198
84cc2635 199char *skipLeadingSpace(char *aString);
62e76326 200
edce4d98 201#if USE_IDENT
4d55827a 202static void
edce4d98 203clientIdentDone(const char *ident, void *data)
4d55827a 204{
cc59d02a 205 ConnStateData *conn = (ConnStateData *)data;
73c36fd9 206 xstrncpy(conn->clientConnection->rfc931, ident ? ident : dash_str, USER_IDENT_SZ);
e81957b7 207}
447e176b 208#endif
7a2f978b 209
c8be6d7b 210void
91369933 211clientUpdateStatCounters(const LogTags &logType)
a7c05555 212{
e4f1fdae 213 ++statCounter.client_http.requests;
62e76326 214
91369933 215 if (logType.isTcpHit())
e4f1fdae 216 ++statCounter.client_http.hits;
62e76326 217
91369933 218 if (logType.oldType == LOG_TCP_HIT)
e4f1fdae 219 ++statCounter.client_http.disk_hits;
91369933 220 else if (logType.oldType == LOG_TCP_MEM_HIT)
e4f1fdae 221 ++statCounter.client_http.mem_hits;
c8be6d7b 222}
223
224void
91369933 225clientUpdateStatHistCounters(const LogTags &logType, int svc_time)
c8be6d7b 226{
e8baef82 227 statCounter.client_http.allSvcTime.count(svc_time);
63be0a78 228 /**
ee1679df 229 * The idea here is not to be complete, but to get service times
230 * for only well-defined types. For example, we don't include
1d7ab0f4 231 * LOG_TCP_REFRESH_FAIL because its not really a cache hit
ee1679df 232 * (we *tried* to validate it, but failed).
233 */
62e76326 234
91369933 235 switch (logType.oldType) {
62e76326 236
1d7ab0f4 237 case LOG_TCP_REFRESH_UNMODIFIED:
e8baef82 238 statCounter.client_http.nearHitSvcTime.count(svc_time);
62e76326 239 break;
240
787ea68c 241 case LOG_TCP_INM_HIT:
ee1679df 242 case LOG_TCP_IMS_HIT:
e8baef82 243 statCounter.client_http.nearMissSvcTime.count(svc_time);
62e76326 244 break;
245
ee1679df 246 case LOG_TCP_HIT:
62e76326 247
ee1679df 248 case LOG_TCP_MEM_HIT:
62e76326 249
b540e168 250 case LOG_TCP_OFFLINE_HIT:
e8baef82 251 statCounter.client_http.hitSvcTime.count(svc_time);
62e76326 252 break;
253
ee1679df 254 case LOG_TCP_MISS:
62e76326 255
ee1679df 256 case LOG_TCP_CLIENT_REFRESH_MISS:
e8baef82 257 statCounter.client_http.missSvcTime.count(svc_time);
62e76326 258 break;
259
ee1679df 260 default:
62e76326 261 /* make compiler warnings go away */
262 break;
ee1679df 263 }
c8be6d7b 264}
265
528b2c61 266bool
c8be6d7b 267clientPingHasFinished(ping_data const *aPing)
268{
269 if (0 != aPing->stop.tv_sec && 0 != aPing->start.tv_sec)
62e76326 270 return true;
271
528b2c61 272 return false;
c8be6d7b 273}
274
275void
276clientUpdateHierCounters(HierarchyLogEntry * someEntry)
277{
278 ping_data *i;
62e76326 279
c8547a11 280 switch (someEntry->code) {
281#if USE_CACHE_DIGESTS
62e76326 282
c8547a11 283 case CD_PARENT_HIT:
62e76326 284
a196e1e4 285 case CD_SIBLING_HIT:
95dc7ff4 286 ++ statCounter.cd.times_used;
62e76326 287 break;
c8547a11 288#endif
62e76326 289
c8547a11 290 case SIBLING_HIT:
62e76326 291
c8547a11 292 case PARENT_HIT:
62e76326 293
c8547a11 294 case FIRST_PARENT_MISS:
62e76326 295
c8547a11 296 case CLOSEST_PARENT_MISS:
95dc7ff4 297 ++ statCounter.icp.times_used;
62e76326 298 i = &someEntry->ping;
299
300 if (clientPingHasFinished(i))
e8baef82 301 statCounter.icp.querySvcTime.count(tvSubUsec(i->start, i->stop));
62e76326 302
303 if (i->timeout)
95dc7ff4 304 ++ statCounter.icp.query_timeouts;
62e76326 305
306 break;
307
c8547a11 308 case CLOSEST_PARENT:
62e76326 309
c8547a11 310 case CLOSEST_DIRECT:
95dc7ff4 311 ++ statCounter.netdb.times_used;
62e76326 312
313 break;
314
69c95dd3 315 default:
62e76326 316 break;
17b6e784 317 }
a7c05555 318}
319
528b2c61 320void
321ClientHttpRequest::updateCounters()
c8be6d7b 322{
12f5a662 323 clientUpdateStatCounters(loggingTags());
62e76326 324
83b053a0 325 if (request->error)
95dc7ff4 326 ++ statCounter.client_http.errors;
62e76326 327
12f5a662 328 clientUpdateStatHistCounters(loggingTags(),
af0ded40 329 tvSubMsec(al->cache.start_time, current_time));
62e76326 330
528b2c61 331 clientUpdateHierCounters(&request->hier);
c8be6d7b 332}
333
edce4d98 334void
63ed9e8e 335prepareLogWithRequestDetails(HttpRequest *request, const AccessLogEntryPointer &aLogEntry)
7a2f978b 336{
c8be6d7b 337 assert(request);
aee3523a 338 assert(aLogEntry != nullptr);
7684c4b1 339
340 if (Config.onoff.log_mime_hdrs) {
7684c4b1 341 MemBuf mb;
2fe7eff9 342 mb.init();
10201568 343 request->header.packInto(&mb);
105d1937
A
344 //This is the request after adaptation or redirection
345 aLogEntry->headers.adapted_request = xstrdup(mb.buf);
346
347 // the virgin request is saved to aLogEntry->request
348 if (aLogEntry->request) {
105d1937 349 mb.reset();
10201568 350 aLogEntry->request->header.packInto(&mb);
105d1937
A
351 aLogEntry->headers.request = xstrdup(mb.buf);
352 }
3ff65596 353
5038f9d8
AR
354#if USE_ADAPTATION
355 const Adaptation::History::Pointer ah = request->adaptLogHistory();
aee3523a 356 if (ah != nullptr) {
5038f9d8 357 mb.reset();
10201568 358 ah->lastMeta.packInto(&mb);
99690f32 359 aLogEntry->adapt.last_meta = xstrdup(mb.buf);
5038f9d8 360 }
3ff65596
AR
361#endif
362
2fe7eff9 363 mb.clean();
7684c4b1 364 }
365
3ff65596 366#if ICAP_CLIENT
5038f9d8 367 const Adaptation::Icap::History::Pointer ih = request->icapHistory();
aee3523a 368 if (ih != nullptr)
01bd87d8 369 ih->processingTime(aLogEntry->icap.processingTime);
3ff65596
AR
370#endif
371
c8be6d7b 372 aLogEntry->http.method = request->method;
373 aLogEntry->http.version = request->http_ver;
c8be6d7b 374 aLogEntry->hier = request->hier;
5b4117d8 375 aLogEntry->cache.extuser = request->extacl_user.termedBuf();
abb929f0 376
a119c6ad
AR
377 // Adapted request, if any, inherits and then collects all the stats, but
378 // the virgin request gets logged instead; copy the stats to log them.
379 // TODO: avoid losses by keeping these stats in a shared history object?
64b66b76 380 if (aLogEntry->request) {
a119c6ad 381 aLogEntry->request->dnsWait = request->dnsWait;
83b053a0 382 aLogEntry->request->error = request->error;
64b66b76 383 }
c8be6d7b 384}
385
386void
528b2c61 387ClientHttpRequest::logRequest()
388{
12f5a662 389 if (!out.size && loggingTags().oldType == LOG_TAG_NONE)
91369933 390 debugs(33, 5, "logging half-baked transaction: " << log_uri);
6fd1086a 391
41ebd397
CT
392 al->icp.opcode = ICP_INVALID;
393 al->url = log_uri;
394 debugs(33, 9, "clientLogRequest: al.url='" << al->url << "'");
62e76326 395
66d51f4f
AR
396 const auto findReply = [this]() -> const HttpReply * {
397 if (al->reply)
398 return al->reply.getRaw();
399 if (const auto le = loggingEntry())
400 return le->hasFreshestReply();
401 return nullptr;
402 };
403 if (const auto reply = findReply()) {
404 al->http.code = reply->sline.status();
405 al->http.content_type = reply->content_type.termedBuf();
6fd1086a 406 }
5f8252d2 407
41ebd397 408 debugs(33, 9, "clientLogRequest: http.code='" << al->http.code << "'");
90a8964c 409
3a646078 410 if (loggingEntry() && loggingEntry()->mem_obj && loggingEntry()->objectLen() >= 0)
d6df21d2 411 al->cache.objectSize = loggingEntry()->contentLen(); // payload duplicate ?? with or without TE ?
90a8964c 412
cc0ca3b9 413 al->http.clientRequestSz.header = req_sz;
bd59d61c
EB
414 // the virgin request is saved to al->request
415 if (al->request && al->request->body_pipe)
416 al->http.clientRequestSz.payloadData = al->request->body_pipe->producedSize();
cc0ca3b9 417 al->http.clientReplySz.header = out.headers_sz;
d6df21d2 418 // XXX: calculate without payload encoding or headers !!
cc0ca3b9 419 al->http.clientReplySz.payloadData = out.size - out.headers_sz; // pretend its all un-encoded data for now.
90a8964c 420
41ebd397 421 al->cache.highOffset = out.offset;
90a8964c 422
01bd87d8 423 tvSub(al->cache.trTime, al->cache.start_time, current_time);
62e76326 424
6fd1086a 425 if (request)
41ebd397 426 prepareLogWithRequestDetails(request, al);
62e76326 427
cb4f4424 428#if USE_OPENSSL && 0
62e76326 429
6fd1086a
AR
430 /* This is broken. Fails if the connection has been closed. Needs
431 * to snarf the ssl details some place earlier..
432 */
433 if (getConn() != NULL)
41ebd397 434 al->cache.ssluser = sslGetUserEmail(fd_table[getConn()->fd].ssl);
62e76326 435
a7ad6e4e 436#endif
62e76326 437
f8a2338f
AJ
438 /* Add notes (if we have a request to annotate) */
439 if (request) {
75d47340
CT
440 SBuf matched;
441 for (auto h: Config.notes) {
49f57088 442 if (h->match(request, al->reply.getRaw(), al, matched)) {
75d47340
CT
443 request->notes()->add(h->key(), matched);
444 debugs(33, 3, h->key() << " " << matched);
f8a2338f 445 }
d7f4a0b7 446 }
75d47340
CT
447 // The al->notes and request->notes must point to the same object.
448 al->syncNotes(request);
d7f4a0b7
CT
449 }
450
aee3523a 451 ACLFilledChecklist checklist(nullptr, request, nullptr);
b248c2a3 452 if (al->reply) {
49f57088 453 checklist.reply = al->reply.getRaw();
8ebad780 454 HTTPMSGLOCK(checklist.reply);
b248c2a3 455 }
62e76326 456
8ebad780 457 if (request) {
542e1a7a 458 HTTPMSGUNLOCK(al->adapted_request);
8ebad780
CT
459 al->adapted_request = request;
460 HTTPMSGLOCK(al->adapted_request);
461 }
cb365059
EB
462 // no need checklist.syncAle(): already synced
463 checklist.al = al;
8ebad780
CT
464 accessLogLog(al, &checklist);
465
466 bool updatePerformanceCounters = true;
467 if (Config.accessList.stats_collection) {
aee3523a 468 ACLFilledChecklist statsCheck(Config.accessList.stats_collection, request, nullptr);
cb365059 469 statsCheck.al = al;
8ebad780 470 if (al->reply) {
49f57088 471 statsCheck.reply = al->reply.getRaw();
8ebad780 472 HTTPMSGLOCK(statsCheck.reply);
b248c2a3 473 }
06bf5384 474 updatePerformanceCounters = statsCheck.fastCheck().allowed();
8ebad780
CT
475 }
476
477 if (updatePerformanceCounters) {
2ae98e09
TH
478 if (request)
479 updateCounters();
7684c4b1 480
aee3523a 481 if (getConn() != nullptr && getConn()->clientConnection != nullptr)
12f5a662 482 clientdbUpdate(getConn()->clientConnection->remote, loggingTags(), AnyP::PROTO_HTTP, out.size);
7a2f978b 483 }
c8be6d7b 484}
485
486void
528b2c61 487ClientHttpRequest::freeResources()
c8be6d7b 488{
528b2c61 489 safe_free(uri);
528b2c61 490 safe_free(redirect.location);
30abd221 491 range_iter.boundary.clean();
bec110e4 492 clearRequest();
62e76326 493
528b2c61 494 if (client_stream.tail)
62e76326 495 clientStreamAbort((clientStreamNode *)client_stream.tail->data, this);
c8be6d7b 496}
497
498void
499httpRequestFree(void *data)
500{
59a1efb2 501 ClientHttpRequest *http = (ClientHttpRequest *)data;
aee3523a 502 assert(http != nullptr);
528b2c61 503 delete http;
7a2f978b 504}
505
506/* This is a handler normally called by comm_close() */
ced8def3 507void ConnStateData::connStateClosed(const CommCloseCbParams &)
7a2f978b 508{
2b6b1bcb
AR
509 if (clientConnection) {
510 clientConnection->noteClosure();
511 // keep closed clientConnection for logging, clientdb cleanup, etc.
512 }
6e1d409c 513 deleteThis("ConnStateData::connStateClosed");
a46d2c0e 514}
62e76326 515
cc1e110a
AJ
516#if USE_AUTH
517void
518ConnStateData::setAuth(const Auth::UserRequest::Pointer &aur, const char *by)
519{
aee3523a
AR
520 if (auth_ == nullptr) {
521 if (aur != nullptr) {
cc1e110a
AJ
522 debugs(33, 2, "Adding connection-auth to " << clientConnection << " from " << by);
523 auth_ = aur;
524 }
525 return;
526 }
527
528 // clobered with self-pointer
529 // NP: something nasty is going on in Squid, but harmless.
530 if (aur == auth_) {
531 debugs(33, 2, "WARNING: Ignoring duplicate connection-auth for " << clientConnection << " from " << by);
532 return;
533 }
534
535 /*
536 * Connection-auth relies on a single set of credentials being preserved
537 * for all requests on a connection once they have been setup.
538 * There are several things which need to happen to preserve security
539 * when connection-auth credentials change unexpectedly or are unset.
540 *
541 * 1) auth helper released from any active state
542 *
543 * They can only be reserved by a handshake process which this
544 * connection can now never complete.
545 * This prevents helpers hanging when their connections close.
546 *
547 * 2) pinning is expected to be removed and server conn closed
548 *
549 * The upstream link is authenticated with the same credentials.
550 * Expecting the same level of consistency we should have received.
551 * This prevents upstream being faced with multiple or missing
552 * credentials after authentication.
553 * NP: un-pin is left to the cleanup in ConnStateData::swanSong()
554 * we just trigger that cleanup here via comm_reset_close() or
555 * ConnStateData::stopReceiving()
556 *
557 * 3) the connection needs to close.
558 *
559 * This prevents attackers injecting requests into a connection,
560 * or gateways wrongly multiplexing users into a single connection.
561 *
562 * When credentials are missing closure needs to follow an auth
563 * challenge for best recovery by the client.
564 *
565 * When credentials change there is nothing we can do but abort as
566 * fast as possible. Sending TCP RST instead of an HTTP response
567 * is the best-case action.
568 */
569
570 // clobbered with nul-pointer
aee3523a 571 if (aur == nullptr) {
cc1e110a
AJ
572 debugs(33, 2, "WARNING: Graceful closure on " << clientConnection << " due to connection-auth erase from " << by);
573 auth_->releaseAuthServer();
aee3523a 574 auth_ = nullptr;
cc1e110a
AJ
575 // XXX: need to test whether the connection re-auth challenge is sent. If not, how to trigger it from here.
576 // NP: the current situation seems to fix challenge loops in Safari without visible issues in others.
577 // we stop receiving more traffic but can leave the Job running to terminate after the error or challenge is delivered.
578 stopReceiving("connection-auth removed");
579 return;
580 }
581
582 // clobbered with alternative credentials
583 if (aur != auth_) {
584 debugs(33, 2, "ERROR: Closing " << clientConnection << " due to change of connection-auth from " << by);
585 auth_->releaseAuthServer();
aee3523a 586 auth_ = nullptr;
cc1e110a
AJ
587 // this is a fatal type of problem.
588 // Close the connection immediately with TCP RST to abort all traffic flow
589 comm_reset_close(clientConnection);
590 return;
591 }
592
593 /* NOT REACHABLE */
594}
595#endif
596
83b053a0
CT
597void
598ConnStateData::resetReadTimeout(const time_t timeout)
599{
600 typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
601 AsyncCall::Pointer callback = JobCallback(33, 5, TimeoutDialer, this, ConnStateData::requestTimeout);
602 commSetConnTimeout(clientConnection, timeout, callback);
603}
604
605void
606ConnStateData::extendLifetime()
607{
608 typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
609 AsyncCall::Pointer callback = JobCallback(5, 4, TimeoutDialer, this, ConnStateData::lifetimeTimeout);
610 commSetConnTimeout(clientConnection, Config.Timeout.lifetime, callback);
611}
612
6e1d409c 613// cleans up before destructor is called
a2ac85d9 614void
6e1d409c 615ConnStateData::swanSong()
a46d2c0e 616{
bf95c10a 617 debugs(33, 2, clientConnection);
da6dbcd1 618
f35961af 619 flags.readMore = false;
f53969cc 620 clientdbEstablished(clientConnection->remote, -1); /* decrement */
83b053a0
CT
621
622 terminateAll(ERR_NONE, LogTagsErrors());
623 checkLogging();
6e1d409c 624
801cfc26 625 // XXX: Closing pinned conn is too harsh: The Client may want to continue!
89b1d7a2 626 unpinConnection(true);
e3a4aecc 627
83b053a0 628 Server::swanSong();
d67acb4e 629
cc1e110a
AJ
630#if USE_AUTH
631 // NP: do this bit after closing the connections to avoid side effects from unwanted TCP RST
aee3523a 632 setAuth(nullptr, "ConnStateData::SwanSong cleanup");
cc1e110a
AJ
633#endif
634
6e1d409c 635 flags.swanSang = true;
a2ac85d9 636}
637
83b053a0
CT
638void
639ConnStateData::callException(const std::exception &ex)
640{
641 Server::callException(ex); // logs ex and stops the job
642
643 ErrorDetail::Pointer errorDetail;
644 if (const auto tex = dynamic_cast<const TextException*>(&ex))
645 errorDetail = new ExceptionErrorDetail(tex->id());
646 else
647 errorDetail = new ExceptionErrorDetail(Here().id());
648 updateError(ERR_GATEWAY_FAILURE, errorDetail);
649}
650
651void
652ConnStateData::updateError(const Error &error)
653{
654 if (const auto context = pipeline.front()) {
655 const auto http = context->http;
656 assert(http);
657 http->updateError(error);
658 } else {
659 bareError.update(error);
660 }
661}
662
a2ac85d9 663bool
664ConnStateData::isOpen() const
665{
10b06767 666 return cbdataReferenceValid(this) && // XXX: checking "this" in a method
73c36fd9
AJ
667 Comm::IsConnOpen(clientConnection) &&
668 !fd_table[clientConnection->fd].closing();
a2ac85d9 669}
670
671ConnStateData::~ConnStateData()
672{
bf95c10a 673 debugs(33, 3, clientConnection);
a2ac85d9 674
675 if (isOpen())
d816f28d 676 debugs(33, DBG_IMPORTANT, "ERROR: Squid BUG: ConnStateData did not close " << clientConnection);
6e1d409c
AR
677
678 if (!flags.swanSang)
d816f28d 679 debugs(33, DBG_IMPORTANT, "ERROR: Squid BUG: ConnStateData was not destroyed properly; " << clientConnection);
62e76326 680
aee3523a 681 if (bodyPipe != nullptr)
279152e7 682 stopProducingFor(bodyPipe, false);
87f237a9 683
fcc444e3
AJ
684 delete bodyParser; // TODO: pool
685
cb4f4424 686#if USE_OPENSSL
fd4624d7 687 delete sslServerBump;
8a7fe008 688#endif
7a2f978b 689}
690
63be0a78 691/**
450fe1cb 692 * clientSetKeepaliveFlag() sets request->flags.proxyKeepalive.
c68e9c6b 693 * This is the client-side persistent connection flag. We need
694 * to set this relatively early in the request processing
695 * to handle hacks for broken servers and clients.
696 */
92ae4c86 697void
59a1efb2 698clientSetKeepaliveFlag(ClientHttpRequest * http)
c68e9c6b 699{
190154cf 700 HttpRequest *request = http->request;
f6329bc3 701
7f06a3d8
AJ
702 debugs(33, 3, "http_ver = " << request->http_ver);
703 debugs(33, 3, "method = " << request->method);
62e76326 704
4a1acc56 705 // TODO: move to HttpRequest::hdrCacheInit, just like HttpReply.
e857372a 706 request->flags.proxyKeepalive = request->persistent();
c68e9c6b 707}
708
c8be6d7b 709int
47f6e231 710clientIsRequestBodyTooLargeForPolicy(int64_t bodyLength)
efd900cb 711{
c8be6d7b 712 if (Config.maxRequestBodySize &&
62e76326 713 bodyLength > Config.maxRequestBodySize)
f53969cc 714 return 1; /* too large */
62e76326 715
efd900cb 716 return 0;
717}
718
528b2c61 719bool
720ClientHttpRequest::multipartRangeRequest() const
721{
722 return request->multipartRangeRequest();
723}
724
4ad60609 725void
d6fdeb41 726clientPackTermBound(String boundary, MemBuf *mb)
528b2c61 727{
4391cd15 728 mb->appendf("\r\n--" SQUIDSTRINGPH "--\r\n", SQUIDSTRINGPRINT(boundary));
d6fdeb41 729 debugs(33, 6, "buf offset: " << mb->size);
528b2c61 730}
731
d6fdeb41 732void
a0c227a9 733clientPackRangeHdr(const HttpReplyPointer &rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb)
528b2c61 734{
75faaa7a 735 HttpHeader hdr(hoReply);
528b2c61 736 assert(rep);
737 assert(spec);
738
739 /* put boundary */
d6fdeb41 740 debugs(33, 5, "appending boundary: " << boundary);
528b2c61 741 /* rfc2046 requires to _prepend_ boundary with <crlf>! */
4391cd15 742 mb->appendf("\r\n--" SQUIDSTRINGPH "\r\n", SQUIDSTRINGPRINT(boundary));
528b2c61 743
744 /* stuff the header with required entries and pack it */
62e76326 745
789217a2
FC
746 if (rep->header.has(Http::HdrType::CONTENT_TYPE))
747 hdr.putStr(Http::HdrType::CONTENT_TYPE, rep->header.getStr(Http::HdrType::CONTENT_TYPE));
62e76326 748
528b2c61 749 httpHeaderAddContRange(&hdr, *spec, rep->content_length);
62e76326 750
10201568 751 hdr.packInto(mb);
519e0948 752 hdr.clean();
528b2c61 753
754 /* append <crlf> (we packed a header, not a reply) */
10201568 755 mb->append("\r\n", 2);
528b2c61 756}
757
63be0a78 758/** returns expected content length for multi-range replies
528b2c61 759 * note: assumes that httpHdrRangeCanonize has already been called
760 * warning: assumes that HTTP headers for individual ranges at the
761 * time of the actuall assembly will be exactly the same as
762 * the headers when clientMRangeCLen() is called */
7024fb73
AR
763int64_t
764ClientHttpRequest::mRangeCLen() const
c8be6d7b 765{
47f6e231 766 int64_t clen = 0;
c8be6d7b 767 MemBuf mb;
528b2c61 768
86a2f789 769 assert(memObject());
528b2c61 770
2fe7eff9 771 mb.init();
528b2c61 772 HttpHdrRange::iterator pos = request->range->begin();
62e76326 773
528b2c61 774 while (pos != request->range->end()) {
62e76326 775 /* account for headers for this range */
2fe7eff9 776 mb.reset();
66d51f4f 777 clientPackRangeHdr(&storeEntry()->mem().freshestReply(),
62e76326 778 *pos, range_iter.boundary, &mb);
779 clen += mb.size;
528b2c61 780
62e76326 781 /* account for range content */
782 clen += (*pos)->length;
528b2c61 783
4a7a3d56 784 debugs(33, 6, "clientMRangeCLen: (clen += " << mb.size << " + " << (*pos)->length << ") == " << clen);
62e76326 785 ++pos;
528b2c61 786 }
62e76326 787
528b2c61 788 /* account for the terminating boundary */
2fe7eff9 789 mb.reset();
62e76326 790
528b2c61 791 clientPackTermBound(range_iter.boundary, &mb);
62e76326 792
528b2c61 793 clen += mb.size;
794
2fe7eff9 795 mb.clean();
62e76326 796
528b2c61 797 return clen;
798}
799
63be0a78 800/**
801 * generates a "unique" boundary string for multipart responses
528b2c61 802 * the caller is responsible for cleaning the string */
30abd221 803String
528b2c61 804ClientHttpRequest::rangeBoundaryStr() const
805{
528b2c61 806 const char *key;
c81de627 807 String b(visible_appname_string);
7dbca7a4 808 b.append(":",1);
86a2f789 809 key = storeEntry()->getMD5Text();
528b2c61 810 b.append(key, strlen(key));
811 return b;
812}
813
63be0a78 814/**
7dc5f514 815 * Write a chunk of data to a client socket. If the reply is present,
816 * send the reply headers down the wire too, and clean them up when
817 * finished.
9e008dda 818 * Pre-condition:
edce4d98 819 * The request is one backed by a connection, not an internal request.
820 * data context is not NULL
821 * There are no more entries in the stream chain.
2246b732 822 */
92ae4c86 823void
59a1efb2 824clientSocketRecipient(clientStreamNode * node, ClientHttpRequest * http,
2324cda2 825 HttpReply * rep, StoreIOBuffer receivedData)
edce4d98 826{
61beade2 827 // do not try to deliver if client already ABORTED
51571330
AJ
828 if (!http->getConn() || !cbdataReferenceValid(http->getConn()) || !Comm::IsConnOpen(http->getConn()->clientConnection))
829 return;
830
edce4d98 831 /* Test preconditions */
aee3523a 832 assert(node != nullptr);
62e76326 833 /* TODO: handle this rather than asserting
9e008dda
AJ
834 * - it should only ever happen if we cause an abort and
835 * the callback chain loops back to here, so we can simply return.
836 * However, that itself shouldn't happen, so it stays as an assert for now.
edce4d98 837 */
838 assert(cbdataReferenceValid(node));
aee3523a 839 assert(node->node.next == nullptr);
d3dddfb5 840 Http::StreamPointer context = dynamic_cast<Http::Stream *>(node->data.getRaw());
aee3523a 841 assert(context != nullptr);
5c336a3b 842
528b2c61 843 /* TODO: check offset is what we asked for */
62e76326 844
efd5e784
AJ
845 // TODO: enforces HTTP/1 MUST on pipeline order, but is irrelevant to HTTP/2
846 if (context != http->getConn()->pipeline.front())
2324cda2 847 context->deferRecipientForLater(node, rep, receivedData);
24e1fd72
CT
848 else if (http->getConn()->cbControlMsgSent) // 1xx to the user is pending
849 context->deferRecipientForLater(node, rep, receivedData);
92ae4c86
AR
850 else
851 http->getConn()->handleReply(rep, receivedData);
edce4d98 852}
853
63be0a78 854/**
855 * Called when a downstream node is no longer interested in
edce4d98 856 * our data. As we are a terminal node, this means on aborts
857 * only
858 */
859void
59a1efb2 860clientSocketDetach(clientStreamNode * node, ClientHttpRequest * http)
edce4d98 861{
edce4d98 862 /* Test preconditions */
aee3523a 863 assert(node != nullptr);
62e76326 864 /* TODO: handle this rather than asserting
9e008dda
AJ
865 * - it should only ever happen if we cause an abort and
866 * the callback chain loops back to here, so we can simply return.
edce4d98 867 * However, that itself shouldn't happen, so it stays as an assert for now.
868 */
869 assert(cbdataReferenceValid(node));
870 /* Set null by ContextFree */
aee3523a 871 assert(node->node.next == nullptr);
0655fa4d 872 /* this is the assert discussed above */
aee3523a 873 assert(nullptr == dynamic_cast<Http::Stream *>(node->data.getRaw()));
edce4d98 874 /* We are only called when the client socket shutsdown.
875 * Tell the prev pipeline member we're finished
876 */
877 clientStreamDetach(node, http);
7a2f978b 878}
879
c8be6d7b 880void
a46d2c0e 881ConnStateData::readNextRequest()
c8be6d7b 882{
bf95c10a 883 debugs(33, 5, clientConnection << " reading next req");
bf8fe701 884
97b32442 885 fd_note(clientConnection->fd, "Idle client: Waiting for next request");
63be0a78 886 /**
5ddf7edc 887 * Set the timeout BEFORE calling readSomeData().
c8be6d7b 888 */
83b053a0 889 resetReadTimeout(clientConnection->timeLeft(idleTimeout()));
1cf238db 890
a46d2c0e 891 readSomeData();
63be0a78 892 /** Please don't do anything with the FD past here! */
c8be6d7b 893}
894
09d3938c 895static void
d3dddfb5 896ClientSocketContextPushDeferredIfNeeded(Http::StreamPointer deferredRequest, ConnStateData * conn)
c8be6d7b 897{
bf95c10a 898 debugs(33, 2, conn->clientConnection << " Sending next");
bf8fe701 899
63be0a78 900 /** If the client stream is waiting on a socket write to occur, then */
62e76326 901
c8be6d7b 902 if (deferredRequest->flags.deferred) {
63be0a78 903 /** NO data is allowed to have been sent. */
62e76326 904 assert(deferredRequest->http->out.size == 0);
63be0a78 905 /** defer now. */
62e76326 906 clientSocketRecipient(deferredRequest->deferredparams.node,
907 deferredRequest->http,
908 deferredRequest->deferredparams.rep,
909 deferredRequest->deferredparams.queuedBuffer);
c8be6d7b 910 }
62e76326 911
63be0a78 912 /** otherwise, the request is still active in a callbacksomewhere,
c8be6d7b 913 * and we are done
f4f278b5 914 */
f4f278b5 915}
916
0655fa4d 917void
f4a53cf7 918ConnStateData::kick()
1a92a1e2 919{
4a4fbcef
AJ
920 if (!Comm::IsConnOpen(clientConnection)) {
921 debugs(33, 2, clientConnection << " Connection was closed");
922 return;
923 }
0655fa4d 924
f4a53cf7
AJ
925 if (pinning.pinned && !Comm::IsConnOpen(pinning.serverConnection)) {
926 debugs(33, 2, clientConnection << " Connection was pinned but server side gone. Terminating client connection");
927 clientConnection->close();
d67acb4e
AJ
928 return;
929 }
930
cf6eb29e
CT
931 /** \par
932 * We are done with the response, and we are either still receiving request
933 * body (early response!) or have already stopped receiving anything.
934 *
935 * If we are still receiving, then clientParseRequest() below will fail.
936 * (XXX: but then we will call readNextRequest() which may succeed and
937 * execute a smuggled request as we are not done with the current request).
938 *
939 * If we stopped because we got everything, then try the next request.
940 *
941 * If we stopped receiving because of an error, then close now to avoid
942 * getting stuck and to prevent accidental request smuggling.
943 */
944
f4a53cf7
AJ
945 if (const char *reason = stoppedReceiving()) {
946 debugs(33, 3, "closing for earlier request error: " << reason);
947 clientConnection->close();
cf6eb29e
CT
948 return;
949 }
950
63be0a78 951 /** \par
f900210a 952 * Attempt to parse a request from the request buffer.
953 * If we've been fed a pipelined request it may already
954 * be in our read buffer.
955 *
63be0a78 956 \par
f900210a 957 * This needs to fall through - if we're unlucky and parse the _last_ request
958 * from our read buffer we may never re-register for another client read.
959 */
960
f4a53cf7
AJ
961 if (clientParseRequests()) {
962 debugs(33, 3, clientConnection << ": parsed next request from buffer");
f900210a 963 }
964
63be0a78 965 /** \par
f900210a 966 * Either we need to kick-start another read or, if we have
967 * a half-closed connection, kill it after the last request.
968 * This saves waiting for half-closed connections to finished being
969 * half-closed _AND_ then, sometimes, spending "Timeout" time in
970 * the keepalive "Waiting for next request" state.
971 */
f4a53cf7 972 if (commIsHalfClosed(clientConnection->fd) && pipeline.empty()) {
e500cc89 973 debugs(33, 3, "half-closed client with no pending requests, closing");
f4a53cf7 974 clientConnection->close();
f900210a 975 return;
976 }
977
63be0a78 978 /** \par
f900210a 979 * At this point we either have a parsed request (which we've
980 * kicked off the processing for) or not. If we have a deferred
981 * request (parsed but deferred for pipeling processing reasons)
982 * then look at processing it. If not, simply kickstart
983 * another read.
984 */
d3dddfb5 985 Http::StreamPointer deferredRequest = pipeline.front();
efd5e784 986 if (deferredRequest != nullptr) {
f4a53cf7
AJ
987 debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded");
988 ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
989 } else if (flags.readMore) {
990 debugs(33, 3, clientConnection << ": calling readNextRequest()");
991 readNextRequest();
f35961af
AR
992 } else {
993 // XXX: Can this happen? CONNECT tunnels have deferredRequest set.
f4a53cf7 994 debugs(33, DBG_IMPORTANT, MYNAME << "abandoning " << clientConnection);
f900210a 995 }
1a92a1e2 996}
997
cf6eb29e
CT
998void
999ConnStateData::stopSending(const char *error)
1000{
bf95c10a 1001 debugs(33, 4, "sending error (" << clientConnection << "): " << error <<
cf6eb29e
CT
1002 "; old receiving error: " <<
1003 (stoppedReceiving() ? stoppedReceiving_ : "none"));
fc68f6b1 1004
cf6eb29e 1005 if (const char *oldError = stoppedSending()) {
bf95c10a 1006 debugs(33, 3, "already stopped sending: " << oldError);
cf6eb29e
CT
1007 return; // nothing has changed as far as this connection is concerned
1008 }
1009 stoppedSending_ = error;
fc68f6b1 1010
cf6eb29e
CT
1011 if (!stoppedReceiving()) {
1012 if (const int64_t expecting = mayNeedToReadMoreBody()) {
bf95c10a 1013 debugs(33, 5, "must still read " << expecting <<
fcc444e3 1014 " request body bytes with " << inBuf.length() << " unused");
cf6eb29e 1015 return; // wait for the request receiver to finish reading
3b299123 1016 }
55e44db9 1017 }
1018
cf6eb29e 1019 clientConnection->close();
55e44db9 1020}
1021
0655fa4d 1022void
21cd3227
AJ
1023ConnStateData::afterClientWrite(size_t size)
1024{
1025 if (pipeline.empty())
1026 return;
1027
d6fdeb41
AJ
1028 auto ctx = pipeline.front();
1029 if (size) {
1030 statCounter.client_http.kbytes_out += size;
12f5a662 1031 if (ctx->http->loggingTags().isTcpHit())
d6fdeb41 1032 statCounter.client_http.hit_kbytes_out += size;
7a2f978b 1033 }
d6fdeb41 1034 ctx->writeComplete(size);
7a2f978b 1035}
1036
d3dddfb5 1037Http::Stream *
eacfca83 1038ConnStateData::abortRequestParsing(const char *const uri)
038eb4ed 1039{
eacfca83 1040 ClientHttpRequest *http = new ClientHttpRequest(this);
fcc444e3 1041 http->req_sz = inBuf.length();
bec110e4 1042 http->setErrorUri(uri);
d3dddfb5 1043 auto *context = new Http::Stream(clientConnection, http);
942b1c39
AJ
1044 StoreIOBuffer tempBuffer;
1045 tempBuffer.data = context->reqbuf;
1046 tempBuffer.length = HTTP_REQBUF_SZ;
edce4d98 1047 clientStreamInit(&http->client_stream, clientGetMoreData, clientReplyDetach,
0655fa4d 1048 clientReplyStatus, new clientReplyContext(http), clientSocketRecipient,
942b1c39 1049 clientSocketDetach, context, tempBuffer);
edce4d98 1050 return context;
038eb4ed 1051}
1052
d442618d
AJ
1053void
1054ConnStateData::startShutdown()
1055{
1056 // RegisteredRunner API callback - Squid has been shut down
1057
1058 // if connection is idle terminate it now,
1059 // otherwise wait for grace period to end
e500cc89 1060 if (pipeline.empty())
d442618d
AJ
1061 endingShutdown();
1062}
1063
1064void
1065ConnStateData::endingShutdown()
1066{
1067 // RegisteredRunner API callback - Squid shutdown grace period is over
1068
1069 // force the client connection to close immediately
1070 // swanSong() in the close handler will cleanup.
1071 if (Comm::IsConnOpen(clientConnection))
1072 clientConnection->close();
d442618d
AJ
1073}
1074
c8be6d7b 1075char *
1076skipLeadingSpace(char *aString)
1077{
1078 char *result = aString;
62e76326 1079
c8be6d7b 1080 while (xisspace(*aString))
62e76326 1081 ++aString;
1082
c8be6d7b 1083 return result;
1084}
1085
63be0a78 1086/**
d4a04ed5 1087 * 'end' defaults to NULL for backwards compatibility
1088 * remove default value if we ever get rid of NULL-terminated
1089 * request buffers.
1090 */
1091const char *
1092findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end)
c8be6d7b 1093{
aee3523a 1094 if (nullptr == end) {
d4a04ed5 1095 end = uriAndHTTPVersion + strcspn(uriAndHTTPVersion, "\r\n");
1096 assert(end);
1097 }
62e76326 1098
5e263176 1099 for (; end > uriAndHTTPVersion; --end) {
d4a04ed5 1100 if (*end == '\n' || *end == '\r')
62e76326 1101 continue;
1102
d4a04ed5 1103 if (xisspace(*end)) {
1104 if (strncasecmp(end + 1, "HTTP/", 5) == 0)
1105 return end + 1;
62e76326 1106 else
1107 break;
1108 }
c8be6d7b 1109 }
62e76326 1110
aee3523a 1111 return nullptr;
c8be6d7b 1112}
1113
0a57a661
CT
1114static char *
1115prepareAcceleratedURL(ConnStateData * conn, const Http1::RequestParserPointer &hp)
62e76326 1116{
3f38a55e 1117 int vhost = conn->port->vhost;
1118 int vport = conn->port->vport;
9ff1b8ca 1119 static char ipbuf[MAX_IPSTRLEN];
c8be6d7b 1120
3f38a55e 1121 /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
c8be6d7b 1122
5f3cc9a2 1123 static const SBuf cache_object("cache_object://");
9bafa70d 1124 if (hp->requestUri().startsWith(cache_object))
0a57a661 1125 return nullptr; /* already in good shape */
34399323 1126
b1cef121 1127 // XXX: re-use proper URL parser for this
9bafa70d 1128 SBuf url = hp->requestUri(); // use full provided URI if we abort
b1cef121
AJ
1129 do { // use a loop so we can break out of it
1130 ::Parser::Tokenizer tok(url);
f9688132 1131 if (tok.skip('/')) // origin-form URL already.
b1cef121
AJ
1132 break;
1133
62e76326 1134 if (conn->port->vhost)
0a57a661 1135 return nullptr; /* already in good shape */
62e76326 1136
b1cef121 1137 // skip the URI scheme
9bafa70d 1138 static const CharacterSet uriScheme = CharacterSet("URI-scheme","+-.") + CharacterSet::ALPHA + CharacterSet::DIGIT;
b1cef121 1139 static const SBuf uriSchemeEnd("://");
9bafa70d 1140 if (!tok.skipAll(uriScheme) || !tok.skip(uriSchemeEnd))
b1cef121 1141 break;
62e76326 1142
b1cef121
AJ
1143 // skip the authority segment
1144 // RFC 3986 complex nested ABNF for "authority" boils down to this:
1145 static const CharacterSet authority = CharacterSet("authority","-._~%:@[]!$&'()*+,;=") +
f53969cc 1146 CharacterSet::HEXDIG + CharacterSet::ALPHA + CharacterSet::DIGIT;
9bafa70d 1147 if (!tok.skipAll(authority))
b1cef121 1148 break;
62e76326 1149
63ccea28 1150 static const SBuf slashUri("/");
83e3a594 1151 const SBuf t = tok.remaining();
b1cef121 1152 if (t.isEmpty())
63ccea28 1153 url = slashUri;
b1cef121
AJ
1154 else if (t[0]=='/') // looks like path
1155 url = t;
1156 else if (t[0]=='?' || t[0]=='#') { // looks like query or fragment. fix '/'
63ccea28 1157 url = slashUri;
b1cef121
AJ
1158 url.append(t);
1159 } // else do nothing. invalid path
62e76326 1160
b1cef121 1161 } while(false);
62e76326 1162
b1cef121
AJ
1163#if SHOULD_REJECT_UNKNOWN_URLS
1164 // reject URI which are not well-formed even after the processing above
f9688132 1165 if (url.isEmpty() || url[0] != '/') {
f1d5359e 1166 hp->parseStatusCode = Http::scBadRequest;
943cdf6d 1167 return conn->abortRequestParsing("error:invalid-request");
3f38a55e 1168 }
b1cef121 1169#endif
3f38a55e 1170
5463e4b9 1171 if (vport < 0)
0a57a661 1172 vport = conn->clientConnection->local.port();
5463e4b9 1173
8df30f0b
GV
1174 char *receivedHost = nullptr;
1175 if (vhost && (receivedHost = hp->getHostHeaderField())) {
1176 SBuf host(receivedHost);
5463e4b9 1177 debugs(33, 5, "ACCEL VHOST REWRITE: vhost=" << host << " + vport=" << vport);
5463e4b9 1178 if (vport > 0) {
8df30f0b
GV
1179 // remove existing :port (if any), cope with IPv6+ without port
1180 const auto lastColonPos = host.rfind(':');
1181 if (lastColonPos != SBuf::npos && *host.rbegin() != ']') {
1182 host.chop(0, lastColonPos); // truncate until the last colon
5463e4b9 1183 }
8df30f0b 1184 host.appendf(":%d", vport);
5463e4b9 1185 } // else nothing to alter port-wise.
d31d59d8 1186 const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
8df30f0b 1187 const auto url_sz = scheme.length() + host.length() + url.length() + 32;
0a57a661 1188 char *uri = static_cast<char *>(xcalloc(url_sz, 1));
8df30f0b 1189 snprintf(uri, url_sz, SQUIDSBUFPH "://" SQUIDSBUFPH SQUIDSBUFPH, SQUIDSBUFPRINT(scheme), SQUIDSBUFPRINT(host), SQUIDSBUFPRINT(url));
0a57a661
CT
1190 debugs(33, 5, "ACCEL VHOST REWRITE: " << uri);
1191 return uri;
5463e4b9
AJ
1192 } else if (conn->port->defaultsite /* && !vhost */) {
1193 debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: defaultsite=" << conn->port->defaultsite << " + vport=" << vport);
5463e4b9
AJ
1194 char vportStr[32];
1195 vportStr[0] = '\0';
1196 if (vport > 0) {
1197 snprintf(vportStr, sizeof(vportStr),":%d",vport);
1198 }
d31d59d8 1199 const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
0a57a661
CT
1200 const int url_sz = scheme.length() + strlen(conn->port->defaultsite) + sizeof(vportStr) + url.length() + 32;
1201 char *uri = static_cast<char *>(xcalloc(url_sz, 1));
1202 snprintf(uri, url_sz, SQUIDSBUFPH "://%s%s" SQUIDSBUFPH,
d31d59d8 1203 SQUIDSBUFPRINT(scheme), conn->port->defaultsite, vportStr, SQUIDSBUFPRINT(url));
0a57a661
CT
1204 debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: " << uri);
1205 return uri;
5463e4b9 1206 } else if (vport > 0 /* && (!vhost || no Host:) */) {
3cc0f4e7 1207 debugs(33, 5, "ACCEL VPORT REWRITE: *_port IP + vport=" << vport);
5463e4b9 1208 /* Put the local socket IP address as the hostname, with whatever vport we found */
0a57a661 1209 conn->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN);
d31d59d8 1210 const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
0a57a661
CT
1211 const int url_sz = scheme.length() + sizeof(ipbuf) + url.length() + 32;
1212 char *uri = static_cast<char *>(xcalloc(url_sz, 1));
1213 snprintf(uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
d31d59d8 1214 SQUIDSBUFPRINT(scheme), ipbuf, vport, SQUIDSBUFPRINT(url));
0a57a661
CT
1215 debugs(33, 5, "ACCEL VPORT REWRITE: " << uri);
1216 return uri;
3f38a55e 1217 }
0a57a661
CT
1218
1219 return nullptr;
3f38a55e 1220}
1221
0a57a661
CT
1222static char *
1223buildUrlFromHost(ConnStateData * conn, const Http1::RequestParserPointer &hp)
62e76326 1224{
0a57a661 1225 char *uri = nullptr;
3f38a55e 1226 /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
2a51e34e 1227 if (const char *host = hp->getHostHeaderField()) {
d31d59d8 1228 const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
0a57a661
CT
1229 const int url_sz = scheme.length() + strlen(host) + hp->requestUri().length() + 32;
1230 uri = static_cast<char *>(xcalloc(url_sz, 1));
1231 snprintf(uri, url_sz, SQUIDSBUFPH "://%s" SQUIDSBUFPH,
1232 SQUIDSBUFPRINT(scheme),
1233 host,
1234 SQUIDSBUFPRINT(hp->requestUri()));
1235 }
1236 return uri;
1237}
1238
1239char *
1240ConnStateData::prepareTlsSwitchingURL(const Http1::RequestParserPointer &hp)
1241{
1242 Must(switchedToHttps());
1243
1244 if (!hp->requestUri().isEmpty() && hp->requestUri()[0] != '/')
1245 return nullptr; /* already in good shape */
1246
1247 char *uri = buildUrlFromHost(this, hp);
1248#if USE_OPENSSL
1249 if (!uri) {
1250 Must(tlsConnectPort);
9ce4a1eb 1251 Must(!tlsConnectHostOrIp.isEmpty());
0a57a661
CT
1252 SBuf useHost;
1253 if (!tlsClientSni().isEmpty())
1254 useHost = tlsClientSni();
1255 else
9ce4a1eb 1256 useHost = tlsConnectHostOrIp;
0a57a661
CT
1257
1258 const SBuf &scheme = AnyP::UriScheme(transferProtocol.protocol).image();
1259 const int url_sz = scheme.length() + useHost.length() + hp->requestUri().length() + 32;
1260 uri = static_cast<char *>(xcalloc(url_sz, 1));
380b09ae 1261 snprintf(uri, url_sz, SQUIDSBUFPH "://" SQUIDSBUFPH ":%hu" SQUIDSBUFPH,
0a57a661
CT
1262 SQUIDSBUFPRINT(scheme),
1263 SQUIDSBUFPRINT(useHost),
380b09ae 1264 *tlsConnectPort,
0a57a661
CT
1265 SQUIDSBUFPRINT(hp->requestUri()));
1266 }
1267#endif
1268 if (uri)
1269 debugs(33, 5, "TLS switching host rewrite: " << uri);
1270 return uri;
1271}
1272
1273static char *
1274prepareTransparentURL(ConnStateData * conn, const Http1::RequestParserPointer &hp)
1275{
1276 // TODO Must() on URI !empty when the parser supports throw. For now avoid assert().
1277 if (!hp->requestUri().isEmpty() && hp->requestUri()[0] != '/')
1278 return nullptr; /* already in good shape */
1279
1280 char *uri = buildUrlFromHost(conn, hp);
1281 if (!uri) {
62e76326 1282 /* Put the local socket IP address as the hostname. */
f9688132 1283 static char ipbuf[MAX_IPSTRLEN];
0a57a661
CT
1284 conn->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN);
1285 const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1286 const int url_sz = sizeof(ipbuf) + hp->requestUri().length() + 32;
1287 uri = static_cast<char *>(xcalloc(url_sz, 1));
1288 snprintf(uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
d31d59d8 1289 SQUIDSBUFPRINT(scheme),
0a57a661 1290 ipbuf, conn->clientConnection->local.port(), SQUIDSBUFPRINT(hp->requestUri()));
c8be6d7b 1291 }
0a57a661
CT
1292
1293 if (uri)
1294 debugs(33, 5, "TRANSPARENT REWRITE: " << uri);
1295 return uri;
c8be6d7b 1296}
1297
d3dddfb5 1298Http::Stream *
9ce4a1eb 1299ConnStateData::parseHttpRequest(const Http1::RequestParserPointer &hp)
7a2f978b 1300{
87abd755
AJ
1301 /* Attempt to parse the first line; this will define where the method, url, version and header begin */
1302 {
9ce4a1eb
CT
1303 Must(hp);
1304
1305 if (preservingClientData_)
1306 preservedClientData = inBuf;
1307
1308 const bool parsedOk = hp->parse(inBuf);
fc68f6b1 1309
36a9c964 1310 // sync the buffers after parsing.
9ce4a1eb 1311 inBuf = hp->remaining();
7a4fa6a0 1312
9bafa70d 1313 if (hp->needsMoreData()) {
87abd755 1314 debugs(33, 5, "Incomplete request, waiting for end of request line");
aee3523a 1315 return nullptr;
87abd755 1316 }
fc68f6b1 1317
016a316b 1318 if (!parsedOk) {
fc10bc7d
AR
1319 const bool tooBig =
1320 hp->parseStatusCode == Http::scRequestHeaderFieldsTooLarge ||
1321 hp->parseStatusCode == Http::scUriTooLong;
9ce4a1eb 1322 auto result = abortRequestParsing(
a70e75b7 1323 tooBig ? "error:request-too-large" : "error:invalid-request");
fc10bc7d 1324 // assume that remaining leftovers belong to this bad request
9ce4a1eb
CT
1325 if (!inBuf.isEmpty())
1326 consumeInput(inBuf.length());
fc10bc7d 1327 return result;
016a316b 1328 }
84cc2635 1329 }
fc68f6b1 1330
6d0613b2 1331 /* We know the whole request is in parser now */
9ce4a1eb 1332 debugs(11, 2, "HTTP Client " << clientConnection);
6d0613b2 1333 debugs(11, 2, "HTTP Client REQUEST:\n---------\n" <<
9bafa70d
AJ
1334 hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol() << "\n" <<
1335 hp->mimeHeader() <<
6d0613b2 1336 "\n----------");
fc68f6b1 1337
adf29627 1338 /* deny CONNECT via accelerated ports */
aee3523a 1339 if (hp->method() == Http::METHOD_CONNECT && port != nullptr && port->flags.accelSurrogate) {
9ce4a1eb 1340 debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << transferProtocol << " Accelerator port " << port->s.port());
9bafa70d 1341 debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
f1d5359e 1342 hp->parseStatusCode = Http::scMethodNotAllowed;
9ce4a1eb 1343 return abortRequestParsing("error:method-not-allowed");
adf29627
AJ
1344 }
1345
25237905 1346 /* HTTP/2 connection magic prefix starts with "PRI ".
5de5c2d0
AJ
1347 * Deny "PRI" method if used in HTTP/1.x or 0.9 versions.
1348 * If seen it signals a broken client or proxy has corrupted the traffic.
1349 */
1350 if (hp->method() == Http::METHOD_PRI && hp->messageProtocol() < Http::ProtocolVersion(2,0)) {
9ce4a1eb 1351 debugs(33, DBG_IMPORTANT, "WARNING: PRI method received on " << transferProtocol << " port " << port->s.port());
5de5c2d0 1352 debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
093c6381 1353 hp->parseStatusCode = Http::scMethodNotAllowed;
9ce4a1eb 1354 return abortRequestParsing("error:method-not-allowed");
5de5c2d0
AJ
1355 }
1356
9bafa70d
AJ
1357 if (hp->method() == Http::METHOD_NONE) {
1358 debugs(33, DBG_IMPORTANT, "WARNING: Unsupported method: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
f1d5359e 1359 hp->parseStatusCode = Http::scMethodNotAllowed;
9ce4a1eb 1360 return abortRequestParsing("error:unsupported-request-method");
3f38a55e 1361 }
7a2f978b 1362
6d0613b2
AJ
1363 // Process headers after request line
1364 debugs(33, 3, "complete request received. " <<
9bafa70d
AJ
1365 "prefix_sz = " << hp->messageHeaderSize() <<
1366 ", request-line-size=" << hp->firstLineSize() <<
1367 ", mime-header-size=" << hp->headerBlockSize() <<
1368 ", mime header block:\n" << hp->mimeHeader() << "\n----------");
62e76326 1369
7a2f978b 1370 /* Ok, all headers are received */
9ce4a1eb 1371 ClientHttpRequest *http = new ClientHttpRequest(this);
9ff1b8ca 1372
9bafa70d 1373 http->req_sz = hp->messageHeaderSize();
9ce4a1eb 1374 Http::Stream *result = new Http::Stream(clientConnection, http);
62e76326 1375
942b1c39
AJ
1376 StoreIOBuffer tempBuffer;
1377 tempBuffer.data = result->reqbuf;
1378 tempBuffer.length = HTTP_REQBUF_SZ;
1379
0655fa4d 1380 ClientStreamData newServer = new clientReplyContext(http);
0655fa4d 1381 ClientStreamData newClient = result;
edce4d98 1382 clientStreamInit(&http->client_stream, clientGetMoreData, clientReplyDetach,
0655fa4d 1383 clientReplyStatus, newServer, clientSocketRecipient,
942b1c39 1384 clientSocketDetach, newClient, tempBuffer);
62e76326 1385
3ff65596 1386 /* set url */
450e09f9 1387 debugs(33,5, "Prepare absolute URL from " <<
9ce4a1eb 1388 (transparent()?"intercept":(port->flags.accelSurrogate ? "accel":"")));
3f38a55e 1389 /* Rewrite the URL in transparent or accelerator mode */
89272111
AJ
1390 /* NP: there are several cases to traverse here:
1391 * - standard mode (forward proxy)
1392 * - transparent mode (TPROXY)
1393 * - transparent mode with failures
1394 * - intercept mode (NAT)
1395 * - intercept mode with failures
1396 * - accelerator mode (reverse proxy)
51b5dcf5 1397 * - internal relative-URL
89272111 1398 * - mixed combos of the above with internal URL
151ba0d4
AJ
1399 * - remote interception with PROXY protocol
1400 * - remote reverse-proxy with PROXY protocol
89272111 1401 */
9ce4a1eb
CT
1402 if (switchedToHttps()) {
1403 http->uri = prepareTlsSwitchingURL(hp);
1404 } else if (transparent()) {
89272111 1405 /* intercept or transparent mode, properly working with no failures */
9ce4a1eb 1406 http->uri = prepareTransparentURL(this, hp);
89272111 1407
51b5dcf5 1408 } else if (internalCheck(hp->requestUri())) { // NP: only matches relative-URI
89272111 1409 /* internal URL mode */
2f2749d7 1410 /* prepend our name & port */
aee3523a 1411 http->uri = xstrdup(internalLocalUri(nullptr, hp->requestUri()));
59c59acf
AJ
1412 // We just re-wrote the URL. Must replace the Host: header.
1413 // But have not parsed there yet!! flag for local-only handling.
be4d35dc 1414 http->flags.internal = true;
59c59acf 1415
9ce4a1eb 1416 } else if (port->flags.accelSurrogate) {
59c59acf 1417 /* accelerator mode */
9ce4a1eb 1418 http->uri = prepareAcceleratedURL(this, hp);
0a57a661 1419 http->flags.accel = true;
3f38a55e 1420 }
1421
1422 if (!http->uri) {
62e76326 1423 /* No special rewrites have been applied above, use the
1424 * requested url. may be rewritten later, so make extra room */
9bafa70d 1425 int url_sz = hp->requestUri().length() + Config.appendDomainLen + 5;
62e76326 1426 http->uri = (char *)xcalloc(url_sz, 1);
3f0e38d6 1427 SBufToCstring(http->uri, hp->requestUri());
3f38a55e 1428 }
62e76326 1429
c4b7a5a9 1430 result->flags.parsed_ok = 1;
c8be6d7b 1431 return result;
7a2f978b 1432}
1433
fcc444e3 1434bool
83b053a0
CT
1435ConnStateData::shouldCloseOnEof() const
1436{
1437 if (pipeline.empty() && inBuf.isEmpty()) {
1438 debugs(33, 4, "yes, without active requests and unparsed input");
1439 return true;
1440 }
1441
1442 if (!Config.onoff.half_closed_clients) {
1443 debugs(33, 3, "yes, without half_closed_clients");
1444 return true;
c8be6d7b 1445 }
62e76326 1446
83b053a0
CT
1447 // Squid currently tries to parse (possibly again) a partially received
1448 // request after an EOF with half_closed_clients. To give that last parse in
1449 // afterClientRead() a chance, we ignore partially parsed requests here.
1450 debugs(33, 3, "no, honoring half_closed_clients");
fcc444e3 1451 return false;
c8be6d7b 1452}
1453
92ae4c86
AR
1454void
1455ConnStateData::consumeInput(const size_t byteCount)
1456{
fcc444e3
AJ
1457 assert(byteCount > 0 && byteCount <= inBuf.length());
1458 inBuf.consume(byteCount);
1459 debugs(33, 5, "inBuf has " << inBuf.length() << " unused bytes");
92ae4c86
AR
1460}
1461
1cf238db 1462void
f35961af 1463ConnStateData::clientAfterReadingRequests()
c4b7a5a9 1464{
39cb8c41 1465 // Were we expecting to read more request body from half-closed connection?
73c36fd9 1466 if (mayNeedToReadMoreBody() && commIsHalfClosed(clientConnection->fd)) {
bf95c10a 1467 debugs(33, 3, "truncated body: closing half-closed " << clientConnection);
73c36fd9 1468 clientConnection->close();
39cb8c41 1469 return;
c4b7a5a9 1470 }
1471
f35961af
AR
1472 if (flags.readMore)
1473 readSomeData();
c4b7a5a9 1474}
1475
84c77748
AR
1476void
1477ConnStateData::quitAfterError(HttpRequest *request)
1478{
1479 // From HTTP p.o.v., we do not have to close after every error detected
1480 // at the client-side, but many such errors do require closure and the
1481 // client-side code is bad at handling errors so we play it safe.
1482 if (request)
e857372a 1483 request->flags.proxyKeepalive = false;
84c77748 1484 flags.readMore = false;
bf95c10a 1485 debugs(33,4, "Will close after error: " << clientConnection);
84c77748
AR
1486}
1487
cb4f4424 1488#if USE_OPENSSL
d3dddfb5 1489bool ConnStateData::serveDelayedError(Http::Stream *context)
8eb0a7ee
CT
1490{
1491 ClientHttpRequest *http = context->http;
fd4624d7
CT
1492
1493 if (!sslServerBump)
8eb0a7ee
CT
1494 return false;
1495
fd4624d7 1496 assert(sslServerBump->entry);
7a957a93 1497 // Did we create an error entry while processing CONNECT?
fd4624d7 1498 if (!sslServerBump->entry->isEmpty()) {
84c77748
AR
1499 quitAfterError(http->request);
1500
7a957a93
AR
1501 // Get the saved error entry and send it to the client by replacing the
1502 // ClientHttpRequest store entry with it.
8eb0a7ee
CT
1503 clientStreamNode *node = context->getClientReplyContext();
1504 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
7a957a93
AR
1505 assert(repContext);
1506 debugs(33, 5, "Responding with delated error for " << http->uri);
f0baf149 1507 repContext->setReplyToStoreEntry(sslServerBump->entry, "delayed SslBump error");
7a957a93 1508
7a957a93 1509 // Get error details from the fake certificate-peeking request.
83b053a0 1510 http->request->error.update(sslServerBump->request->error);
8eb0a7ee 1511 context->pullData();
8eb0a7ee
CT
1512 return true;
1513 }
1514
7a957a93
AR
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.
92e3827b 1518 if (const Security::CertPointer &srvCert = sslServerBump->serverCert) {
8eb0a7ee 1519 HttpRequest *request = http->request;
92e3827b 1520 if (!Ssl::checkX509ServerValidity(srvCert.get(), request->url.host())) {
7a957a93 1521 debugs(33, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " <<
5c51bffb 1522 "does not match domainname " << request->url.host());
8eb0a7ee 1523
d4a56c34 1524 bool allowDomainMismatch = false;
638402dd 1525 if (Config.ssl_client.cert_error) {
e227da8d 1526 ACLFilledChecklist check(Config.ssl_client.cert_error, nullptr);
92e3827b 1527 check.sslErrors = new Security::CertErrors(Security::CertError(SQUID_X509_V_ERR_DOMAIN_MISMATCH, srvCert));
e227da8d 1528 clientAclChecklistFill(check, http);
06bf5384 1529 allowDomainMismatch = check.fastCheck().allowed();
638402dd 1530 delete check.sslErrors;
aee3523a 1531 check.sslErrors = nullptr;
638402dd 1532 }
8eb0a7ee 1533
7d82c5b8 1534 if (!allowDomainMismatch) {
84c77748
AR
1535 quitAfterError(request);
1536
8eb0a7ee
CT
1537 clientStreamNode *node = context->getClientReplyContext();
1538 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1539 assert (repContext);
1540
d8165775 1541 request->hier = sslServerBump->request->hier;
7a957a93 1542
8eb0a7ee 1543 // Create an error object and fill it
7e6eabbc 1544 const auto err = new ErrorState(ERR_SECURE_CONNECT_FAIL, Http::scServiceUnavailable, request, http->al);
8eb0a7ee 1545 err->src_addr = clientConnection->remote;
83b053a0 1546 const Security::ErrorDetail::Pointer errDetail = new Security::ErrorDetail(
7a957a93 1547 SQUID_X509_V_ERR_DOMAIN_MISMATCH,
83b053a0
CT
1548 srvCert, nullptr);
1549 updateError(ERR_SECURE_CONNECT_FAIL, errDetail);
8eb0a7ee
CT
1550 repContext->setReplyToError(request->method, err);
1551 assert(context->http->out.offset == 0);
1552 context->pullData();
8eb0a7ee
CT
1553 return true;
1554 }
1555 }
1556 }
1557
1558 return false;
1559}
cb4f4424 1560#endif // USE_OPENSSL
8eb0a7ee 1561
9ce4a1eb
CT
1562/// initiate tunneling if possible or return false otherwise
1563bool
eb026889 1564ConnStateData::tunnelOnError(const err_type requestError)
9ce4a1eb
CT
1565{
1566 if (!Config.accessList.on_unsupported_protocol) {
1567 debugs(33, 5, "disabled; send error: " << requestError);
1568 return false;
3248e962
CT
1569 }
1570
9ce4a1eb
CT
1571 if (!preservingClientData_) {
1572 debugs(33, 3, "may have forgotten client data; send error: " << requestError);
1573 return false;
1574 }
1575
e227da8d 1576 ACLFilledChecklist checklist(Config.accessList.on_unsupported_protocol, nullptr);
9ce4a1eb 1577 checklist.requestErrorType = requestError;
e227da8d 1578 fillChecklist(checklist);
9ce4a1eb
CT
1579 auto answer = checklist.fastCheck();
1580 if (answer.allowed() && answer.kind == 1) {
1581 debugs(33, 3, "Request will be tunneled to server");
e227da8d
AR
1582 const auto context = pipeline.front();
1583 const auto http = context ? context->http : nullptr;
1584 const auto request = http ? http->request : nullptr;
9ce4a1eb
CT
1585 if (context)
1586 context->finished(); // Will remove from pipeline queue
aee3523a 1587 Comm::SetSelect(clientConnection->fd, COMM_SELECT_READ, nullptr, nullptr, 0);
eb026889 1588 return initiateTunneledRequest(request, "unknown-protocol", preservedClientData);
9ce4a1eb
CT
1589 }
1590 debugs(33, 3, "denied; send error: " << requestError);
3248e962
CT
1591 return false;
1592}
1593
ec69bdb2 1594void
28fd6d0b
AJ
1595clientProcessRequestFinished(ConnStateData *conn, const HttpRequest::Pointer &request)
1596{
1597 /*
1598 * DPW 2007-05-18
1599 * Moved the TCP_RESET feature from clientReplyContext::sendMoreData
1600 * to here because calling comm_reset_close() causes http to
48a37aee 1601 * be freed before accessing.
28fd6d0b 1602 */
aee3523a 1603 if (request != nullptr && request->flags.resetTcp && Comm::IsConnOpen(conn->clientConnection)) {
bf95c10a 1604 debugs(33, 3, "Sending TCP RST on " << conn->clientConnection);
28fd6d0b
AJ
1605 conn->flags.readMore = false;
1606 comm_reset_close(conn->clientConnection);
1607 }
1608}
1609
9bafa70d 1610void
d3dddfb5 1611clientProcessRequest(ConnStateData *conn, const Http1::RequestParserPointer &hp, Http::Stream *context)
c4b7a5a9 1612{
59a1efb2 1613 ClientHttpRequest *http = context->http;
e18b8316 1614 bool mustReplyToOptions = false;
39cb8c41 1615 bool expectBody = false;
5f8252d2 1616
ec69bdb2
CT
1617 // We already have the request parsed and checked, so we
1618 // only need to go through the final body/conn setup to doCallouts().
1619 assert(http->request);
1620 HttpRequest::Pointer request = http->request;
1621
92ae4c86 1622 // temporary hack to avoid splitting this huge function with sensitive code
f9688132 1623 const bool isFtp = !hp;
9bafa70d 1624
92ae4c86
AR
1625 // Some blobs below are still HTTP-specific, but we would have to rewrite
1626 // this entire function to remove them from the FTP code path. Connection
1627 // setup and body_pipe preparation blobs are needed for FTP.
1628
cd4a5c60 1629 request->manager(conn, http->al);
40d34a62 1630
c4b7a5a9 1631 request->flags.accelerated = http->flags.accel;
450fe1cb 1632 request->flags.sslBumped=conn->switchedToHttps();
7fb65ee4 1633 // TODO: decouple http->flags.accel from request->flags.sslBumped
450fe1cb 1634 request->flags.noDirect = (request->flags.accelerated && !request->flags.sslBumped) ?
e4a14600 1635 !conn->port->allow_direct : 0;
63df1d28
AJ
1636 request->sources |= isFtp ? Http::Message::srcFtp :
1637 ((request->flags.sslBumped || conn->port->transport.protocol == AnyP::PROTO_HTTPS) ? Http::Message::srcHttps : Http::Message::srcHttp);
21512911
CT
1638#if USE_AUTH
1639 if (request->flags.sslBumped) {
aee3523a 1640 if (conn->getAuth() != nullptr)
cc1e110a 1641 request->auth_user_request = conn->getAuth();
21512911
CT
1642 }
1643#endif
2ad20b4f 1644
51b5dcf5 1645 if (internalCheck(request->url.path())) {
5c51bffb
AJ
1646 if (internalHostnameIs(request->url.host()) && request->url.port() == getMyPort()) {
1647 debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true));
be4d35dc 1648 http->flags.internal = true;
51b5dcf5 1649 } else if (Config.onoff.global_internal_static && internalStaticCheck(request->url.path())) {
5c51bffb 1650 debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (global_internal_static on)");
d31d59d8 1651 request->url.setScheme(AnyP::PROTO_HTTP, "http");
851feda6 1652 request->url.host(internalHostname());
5c51bffb 1653 request->url.port(getMyPort());
be4d35dc 1654 http->flags.internal = true;
bec110e4 1655 http->setLogUriToRequestUri();
4e3f4dc7 1656 } else
5c51bffb 1657 debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (not this proxy)");
f024c970 1658 }
e72a0ec0 1659
c4b7a5a9 1660 request->flags.internal = http->flags.internal;
9bafa70d
AJ
1661
1662 if (!isFtp) {
63df1d28 1663 // XXX: for non-HTTP messages instantiate a different Http::Message child type
9bafa70d
AJ
1664 // for now Squid only supports HTTP requests
1665 const AnyP::ProtocolVersion &http_ver = hp->messageProtocol();
1666 assert(request->http_ver.protocol == http_ver.protocol);
1667 request->http_ver.major = http_ver.major;
1668 request->http_ver.minor = http_ver.minor;
1669 }
62e76326 1670
f9688132 1671 mustReplyToOptions = (request->method == Http::METHOD_OPTIONS) &&
789217a2 1672 (request->header.getInt64(Http::HdrType::MAX_FORWARDS) == 0);
4bd88eb4 1673 if (!urlCheckRequest(request.getRaw()) || mustReplyToOptions) {
62e76326 1674 clientStreamNode *node = context->getClientReplyContext();
b248c2a3 1675 conn->quitAfterError(request.getRaw());
0655fa4d 1676 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1677 assert (repContext);
eb026889 1678 repContext->setReplyToError(ERR_UNSUP_REQ, Http::scNotImplemented, nullptr,
7976fed3 1679 conn, request.getRaw(), nullptr, nullptr);
62e76326 1680 assert(context->http->out.offset == 0);
1681 context->pullData();
28fd6d0b
AJ
1682 clientProcessRequestFinished(conn, request);
1683 return;
c4b7a5a9 1684 }
1685
4bd88eb4
AJ
1686 const auto frameStatus = request->checkEntityFraming();
1687 if (frameStatus != Http::scNone) {
62e76326 1688 clientStreamNode *node = context->getClientReplyContext();
0655fa4d 1689 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1690 assert (repContext);
b248c2a3 1691 conn->quitAfterError(request.getRaw());
eb026889 1692 repContext->setReplyToError(ERR_INVALID_REQ, frameStatus, nullptr, conn, request.getRaw(), nullptr, nullptr);
62e76326 1693 assert(context->http->out.offset == 0);
1694 context->pullData();
28fd6d0b
AJ
1695 clientProcessRequestFinished(conn, request);
1696 return;
c4b7a5a9 1697 }
1698
92ae4c86 1699 clientSetKeepaliveFlag(http);
f35961af 1700 // Let tunneling code be fully responsible for CONNECT requests
c2a7cefd 1701 if (http->request->method == Http::METHOD_CONNECT) {
b66e0e86 1702 context->mayUseConnection(true);
f35961af
AR
1703 conn->flags.readMore = false;
1704 }
fc68f6b1 1705
cb4f4424 1706#if USE_OPENSSL
28fd6d0b 1707 if (conn->switchedToHttps() && conn->serveDelayedError(context)) {
28fd6d0b
AJ
1708 clientProcessRequestFinished(conn, request);
1709 return;
1710 }
061bbdec
CT
1711#endif
1712
b66e0e86 1713 /* Do we expect a request-body? */
4bd88eb4 1714 const auto chunked = request->header.chunked();
39cb8c41
AR
1715 expectBody = chunked || request->content_length > 0;
1716 if (!context->mayUseConnection() && expectBody) {
1717 request->body_pipe = conn->expectRequestBody(
de48b288 1718 chunked ? -1 : request->content_length);
5f8252d2 1719
62e76326 1720 /* Is it too large? */
39cb8c41 1721 if (!chunked && // if chunked, we will check as we accumulate
de48b288 1722 clientIsRequestBodyTooLargeForPolicy(request->content_length)) {
62e76326 1723 clientStreamNode *node = context->getClientReplyContext();
0655fa4d 1724 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1725 assert (repContext);
b248c2a3 1726 conn->quitAfterError(request.getRaw());
0655fa4d 1727 repContext->setReplyToError(ERR_TOO_BIG,
5a3b42b1 1728 Http::scContentTooLarge, nullptr,
7976fed3 1729 conn, http->request, nullptr, nullptr);
62e76326 1730 assert(context->http->out.offset == 0);
1731 context->pullData();
28fd6d0b
AJ
1732 clientProcessRequestFinished(conn, request);
1733 return;
62e76326 1734 }
1735
92ae4c86 1736 if (!isFtp) {
a5d444a5
DK
1737 // We may stop producing, comm_close, and/or call setReplyToError()
1738 // below, so quit on errors to avoid http->doCallouts()
28fd6d0b
AJ
1739 if (!conn->handleRequestBodyData()) {
1740 clientProcessRequestFinished(conn, request);
1741 return;
1742 }
39cb8c41 1743
a5d444a5 1744 if (!request->body_pipe->productionEnded()) {
e7ce227f 1745 debugs(33, 5, "need more request body");
a5d444a5
DK
1746 context->mayUseConnection(true);
1747 assert(conn->flags.readMore);
1748 }
f35961af 1749 }
c4b7a5a9 1750 }
1751
de31d06f 1752 http->calloutContext = new ClientRequestContext(http);
1753
1754 http->doCallouts();
9e008dda 1755
28fd6d0b 1756 clientProcessRequestFinished(conn, request);
c4b7a5a9 1757}
1758
83b053a0
CT
1759void
1760ConnStateData::add(const Http::StreamPointer &context)
1761{
1762 debugs(33, 3, context << " to " << pipeline.count() << '/' << pipeline.nrequests);
1763 if (bareError) {
1764 debugs(33, 5, "assigning " << bareError);
1765 assert(context);
1766 assert(context->http);
1767 context->http->updateError(bareError);
1768 bareError.clear();
1769 }
1770 pipeline.add(context);
1771}
1772
92ae4c86
AR
1773int
1774ConnStateData::pipelinePrefetchMax() const
1775{
efbea402
CT
1776 // TODO: Support pipelined requests through pinned connections.
1777 if (pinning.pinned)
1778 return 0;
92ae4c86
AR
1779 return Config.pipeline_max_prefetch;
1780}
1781
079a8480
AJ
1782/**
1783 * Limit the number of concurrent requests.
1784 * \return true when there are available position(s) in the pipeline queue for another request.
1785 * \return false when the pipeline queue is full or disabled.
1786 */
1787bool
1788ConnStateData::concurrentRequestQueueFilled() const
c4b7a5a9 1789{
e500cc89 1790 const int existingRequestCount = pipeline.count();
079a8480
AJ
1791
1792 // default to the configured pipeline size.
1793 // add 1 because the head of pipeline is counted in concurrent requests and not prefetch queue
0de57497 1794#if USE_OPENSSL
43b43c46 1795 const int internalRequest = (transparent() && sslBumpMode == Ssl::bumpSplice) ? 1 : 0;
0de57497 1796#else
06211564 1797 const int internalRequest = 0;
0de57497 1798#endif
43b43c46 1799 const int concurrentRequestLimit = pipelinePrefetchMax() + 1 + internalRequest;
62e76326 1800
2f8abb64 1801 // when queue filled already we can't add more.
079a8480
AJ
1802 if (existingRequestCount >= concurrentRequestLimit) {
1803 debugs(33, 3, clientConnection << " max concurrent requests reached (" << concurrentRequestLimit << ")");
1804 debugs(33, 5, clientConnection << " deferring new request until one is done");
1805 return true;
c4b7a5a9 1806 }
62e76326 1807
079a8480 1808 return false;
c4b7a5a9 1809}
1810
00d0ce87 1811/**
d3d92daa 1812 * Perform proxy_protocol_access ACL tests on the client which
3bd97e7e
AJ
1813 * connected to PROXY protocol port to see if we trust the
1814 * sender enough to accept their PROXY header claim.
00d0ce87 1815 */
6658cc16 1816bool
00d0ce87
AJ
1817ConnStateData::proxyProtocolValidateClient()
1818{
d3d92daa
AJ
1819 if (!Config.accessList.proxyProtocol)
1820 return proxyProtocolError("PROXY client not permitted by default ACL");
1821
e227da8d
AR
1822 ACLFilledChecklist ch(Config.accessList.proxyProtocol, nullptr);
1823 fillChecklist(ch);
06bf5384 1824 if (!ch.fastCheck().allowed())
3bd97e7e
AJ
1825 return proxyProtocolError("PROXY client not permitted by ACLs");
1826
6658cc16 1827 return true;
00d0ce87
AJ
1828}
1829
1830/**
1831 * Perform cleanup on PROXY protocol errors.
1832 * If header parsing hits a fatal error terminate the connection,
1833 * otherwise wait for more data.
1834 */
1835bool
3bd97e7e 1836ConnStateData::proxyProtocolError(const char *msg)
00d0ce87 1837{
3c082dbe 1838 if (msg) {
70a16fea
AJ
1839 // This is important to know, but maybe not so much that flooding the log is okay.
1840#if QUIET_PROXY_PROTOCOL
2f8abb64 1841 // display the first of every 32 occurrences at level 1, the others at level 2.
70a16fea
AJ
1842 static uint8_t hide = 0;
1843 debugs(33, (hide++ % 32 == 0 ? DBG_IMPORTANT : 2), msg << " from " << clientConnection);
1844#else
1845 debugs(33, DBG_IMPORTANT, msg << " from " << clientConnection);
1846#endif
3bd97e7e 1847 mustStop(msg);
3c082dbe 1848 }
00d0ce87
AJ
1849 return false;
1850}
1851
36c774f7
EB
1852/// Attempts to extract a PROXY protocol header from the input buffer and,
1853/// upon success, stores the parsed header in proxyProtocolHeader_.
1854/// \returns true if the header was successfully parsed
1855/// \returns false if more data is needed to parse the header or on error
00d0ce87 1856bool
3d74cb1f 1857ConnStateData::parseProxyProtocolHeader()
00d0ce87 1858{
36c774f7
EB
1859 try {
1860 const auto parsed = ProxyProtocol::Parse(inBuf);
1861 proxyProtocolHeader_ = parsed.header;
1862 assert(bool(proxyProtocolHeader_));
1863 inBuf.consume(parsed.size);
1864 needProxyProtocolHeader_ = false;
1865 if (proxyProtocolHeader_->hasForwardedAddresses()) {
1866 clientConnection->local = proxyProtocolHeader_->destinationAddress;
1867 clientConnection->remote = proxyProtocolHeader_->sourceAddress;
1868 if ((clientConnection->flags & COMM_TRANSPARENT))
1869 clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
1870 debugs(33, 5, "PROXY/" << proxyProtocolHeader_->version() << " upgrade: " << clientConnection);
1871 }
1872 } catch (const Parser::BinaryTokenizer::InsufficientInput &) {
1873 debugs(33, 3, "PROXY protocol: waiting for more than " << inBuf.length() << " bytes");
1874 return false;
1875 } catch (const std::exception &e) {
1876 return proxyProtocolError(e.what());
00d0ce87 1877 }
3bd97e7e 1878 return true;
00d0ce87
AJ
1879}
1880
3248e962
CT
1881void
1882ConnStateData::receivedFirstByte()
1883{
1884 if (receivedFirstByte_)
1885 return;
1886
1887 receivedFirstByte_ = true;
83b053a0 1888 resetReadTimeout(Config.Timeout.request);
3248e962
CT
1889}
1890
63be0a78 1891/**
f900210a 1892 * Attempt to parse one or more requests from the input buffer.
eacfca83
AR
1893 * Returns true after completing parsing of at least one request [header]. That
1894 * includes cases where parsing ended with an error (e.g., a huge request).
f900210a 1895 */
4959e21e 1896bool
f35961af 1897ConnStateData::clientParseRequests()
f900210a 1898{
f900210a 1899 bool parsed_req = false;
1900
bf95c10a 1901 debugs(33, 5, clientConnection << ": attempting to parse");
f900210a 1902
39cb8c41 1903 // Loop while we have read bytes that are not needed for producing the body
f35961af 1904 // On errors, bodyPipe may become nil, but readMore will be cleared
fcc444e3 1905 while (!inBuf.isEmpty() && !bodyPipe && flags.readMore) {
f900210a 1906
801cfc26
CT
1907 // Prohibit concurrent requests when using a pinned to-server connection
1908 // because our Client classes do not support request pipelining.
1909 if (pinning.pinned && !pinning.readHandler) {
1910 debugs(33, 3, clientConnection << " waits for busy " << pinning.serverConnection);
1911 break;
1912 }
1913
079a8480
AJ
1914 /* Limit the number of concurrent requests */
1915 if (concurrentRequestQueueFilled())
f900210a 1916 break;
f900210a 1917
00d0ce87 1918 // try to parse the PROXY protocol header magic bytes
42cbf844
AJ
1919 if (needProxyProtocolHeader_) {
1920 if (!parseProxyProtocolHeader())
1921 break;
1922
1923 // we have been waiting for PROXY to provide client-IP
1924 // for some lookups, ie rDNS and IDENT.
1925 whenClientIpKnown();
9ce4a1eb
CT
1926
1927 // Done with PROXY protocol which has cleared preservingClientData_.
1928 // If the next protocol supports on_unsupported_protocol, then its
1929 // parseOneRequest() must reset preservingClientData_.
1930 assert(!preservingClientData_);
42cbf844 1931 }
00d0ce87 1932
6b2b6cfe 1933 if (Http::StreamPointer context = parseOneRequest()) {
eacfca83 1934 debugs(33, 5, clientConnection << ": done parsing a request");
83b053a0 1935 extendLifetime();
eacfca83
AR
1936 context->registerWithConn();
1937
9ce4a1eb
CT
1938#if USE_OPENSSL
1939 if (switchedToHttps())
1940 parsedBumpedRequestCount++;
1941#endif
1942
9bafa70d 1943 processParsedRequest(context);
f900210a 1944
4959e21e 1945 parsed_req = true; // XXX: do we really need to parse everything right NOW ?
f900210a 1946
1947 if (context->mayUseConnection()) {
bf95c10a 1948 debugs(33, 3, "Not parsing new requests, as this request may need the connection");
f900210a 1949 break;
1950 }
eacfca83
AR
1951 } else {
1952 debugs(33, 5, clientConnection << ": not enough request data: " <<
fcc444e3
AJ
1953 inBuf.length() << " < " << Config.maxRequestHeaderSize);
1954 Must(inBuf.length() < Config.maxRequestHeaderSize);
eacfca83 1955 break;
f900210a 1956 }
39cb8c41 1957 }
fc68f6b1 1958
a5baffba 1959 /* XXX where to 'finish' the parsing pass? */
f900210a 1960 return parsed_req;
1961}
1962
1cf238db 1963void
fcc444e3 1964ConnStateData::afterClientRead()
c4b7a5a9 1965{
3cae14a6 1966#if USE_OPENSSL
d20cf186
AR
1967 if (parsingTlsHandshake) {
1968 parseTlsHandshake();
3cae14a6
CT
1969 return;
1970 }
1971#endif
d20cf186 1972
94439e4e 1973 /* Process next request */
e500cc89 1974 if (pipeline.empty())
fcc444e3 1975 fd_note(clientConnection->fd, "Reading next request");
c8be6d7b 1976
f35961af 1977 if (!clientParseRequests()) {
9e008dda
AJ
1978 if (!isOpen())
1979 return;
83b053a0
CT
1980 // We may get here if the client half-closed after sending a partial
1981 // request. See doClientRead() and shouldCloseOnEof().
1982 // XXX: This partially duplicates ConnStateData::kick().
e500cc89 1983 if (pipeline.empty() && commIsHalfClosed(clientConnection->fd)) {
fcc444e3 1984 debugs(33, 5, clientConnection << ": half-closed connection, no completed request parsed, connection closing.");
73c36fd9 1985 clientConnection->close();
ee6f0213 1986 return;
62e76326 1987 }
f900210a 1988 }
ee6f0213 1989
1cf238db 1990 if (!isOpen())
2e216b1d 1991 return;
1992
f35961af 1993 clientAfterReadingRequests();
94439e4e 1994}
1995
63be0a78 1996/**
1997 * called when new request data has been read from the socket
39cb8c41
AR
1998 *
1999 * \retval false called comm_close or setReplyToError (the caller should bail)
2000 * \retval true we did not call comm_close or setReplyToError
63be0a78 2001 */
39cb8c41 2002bool
7e66d5e2 2003ConnStateData::handleReadData()
94439e4e 2004{
5f8252d2 2005 // if we are reading a body, stuff data into the body pipe
aee3523a 2006 if (bodyPipe != nullptr)
39cb8c41
AR
2007 return handleRequestBodyData();
2008 return true;
94439e4e 2009}
2010
63be0a78 2011/**
fcc444e3 2012 * called when new request body data has been buffered in inBuf
63be0a78 2013 * may close the connection if we were closing and piped everything out
39cb8c41
AR
2014 *
2015 * \retval false called comm_close or setReplyToError (the caller should bail)
2016 * \retval true we did not call comm_close or setReplyToError
63be0a78 2017 */
39cb8c41 2018bool
5f8252d2 2019ConnStateData::handleRequestBodyData()
94439e4e 2020{
aee3523a 2021 assert(bodyPipe != nullptr);
5f8252d2 2022
fcc444e3 2023 if (bodyParser) { // chunked encoding
be29ee33 2024 if (const err_type error = handleChunkedRequestBody()) {
39cb8c41
AR
2025 abortChunkedRequestBody(error);
2026 return false;
3ff65596 2027 }
39cb8c41 2028 } else { // identity encoding
bf95c10a 2029 debugs(33,5, "handling plain request body for " << clientConnection);
fcc444e3 2030 const size_t putSize = bodyPipe->putMoreData(inBuf.c_str(), inBuf.length());
be29ee33
AJ
2031 if (putSize > 0)
2032 consumeInput(putSize);
2033
3ff65596
AR
2034 if (!bodyPipe->mayNeedMoreData()) {
2035 // BodyPipe will clear us automagically when we produced everything
aee3523a 2036 bodyPipe = nullptr;
3ff65596
AR
2037 }
2038 }
2039
3ff65596 2040 if (!bodyPipe) {
bf95c10a 2041 debugs(33,5, "produced entire request body for " << clientConnection);
62e76326 2042
cf6eb29e 2043 if (const char *reason = stoppedSending()) {
5f8252d2 2044 /* we've finished reading like good clients,
2045 * now do the close that initiateClose initiated.
5f8252d2 2046 */
bf95c10a 2047 debugs(33, 3, "closing for earlier sending error: " << reason);
73c36fd9 2048 clientConnection->close();
39cb8c41
AR
2049 return false;
2050 }
2051 }
2052
2053 return true;
2054}
2055
2056/// parses available chunked encoded body bytes, checks size, returns errors
2057err_type
be29ee33 2058ConnStateData::handleChunkedRequestBody()
39cb8c41 2059{
fcc444e3 2060 debugs(33, 7, "chunked from " << clientConnection << ": " << inBuf.length());
39cb8c41
AR
2061
2062 try { // the parser will throw on errors
2063
fcc444e3 2064 if (inBuf.isEmpty()) // nothing to do
39cb8c41
AR
2065 return ERR_NONE;
2066
39cb8c41 2067 BodyPipeCheckout bpc(*bodyPipe);
fcc444e3
AJ
2068 bodyParser->setPayloadBuffer(&bpc.buf);
2069 const bool parsed = bodyParser->parse(inBuf);
2070 inBuf = bodyParser->remaining(); // sync buffers
39cb8c41 2071 bpc.checkIn();
39cb8c41
AR
2072
2073 // dechunk then check: the size limit applies to _dechunked_ content
2074 if (clientIsRequestBodyTooLargeForPolicy(bodyPipe->producedSize()))
2075 return ERR_TOO_BIG;
2076
2077 if (parsed) {
2078 finishDechunkingRequest(true);
2079 Must(!bodyPipe);
2080 return ERR_NONE; // nil bodyPipe implies body end for the caller
5f8252d2 2081 }
39cb8c41
AR
2082
2083 // if chunk parser needs data, then the body pipe must need it too
fcc444e3 2084 Must(!bodyParser->needsMoreData() || bodyPipe->mayNeedMoreData());
39cb8c41
AR
2085
2086 // if parser needs more space and we can consume nothing, we will stall
fcc444e3 2087 Must(!bodyParser->needsMoreSpace() || bodyPipe->buf().hasContent());
39cb8c41 2088 } catch (...) { // TODO: be more specific
bf95c10a 2089 debugs(33, 3, "malformed chunks" << bodyPipe->status());
39cb8c41 2090 return ERR_INVALID_REQ;
94439e4e 2091 }
39cb8c41 2092
bf95c10a 2093 debugs(33, 7, "need more chunked data" << *bodyPipe->status());
39cb8c41
AR
2094 return ERR_NONE;
2095}
2096
2097/// quit on errors related to chunked request body handling
2098void
2099ConnStateData::abortChunkedRequestBody(const err_type error)
2100{
2101 finishDechunkingRequest(false);
2102
2103 // XXX: The code below works if we fail during initial request parsing,
d5430dc8 2104 // but if we fail when the server connection is used already, the server may send
39cb8c41
AR
2105 // us its response too, causing various assertions. How to prevent that?
2106#if WE_KNOW_HOW_TO_SEND_ERRORS
d3dddfb5 2107 Http::StreamPointer context = pipeline.front();
39cb8c41
AR
2108 if (context != NULL && !context->http->out.offset) { // output nothing yet
2109 clientStreamNode *node = context->getClientReplyContext();
2110 clientReplyContext *repContext = dynamic_cast<clientReplyContext*>(node->data.getRaw());
2111 assert(repContext);
955394ce 2112 const Http::StatusCode scode = (error == ERR_TOO_BIG) ?
5a3b42b1 2113 Http::scContentTooLarge : HTTP_BAD_REQUEST;
39cb8c41 2114 repContext->setReplyToError(error, scode,
39cb8c41 2115 repContext->http->uri,
a3c6762c 2116 CachePeer,
39cb8c41 2117 repContext->http->request,
fcc444e3 2118 inBuf, NULL);
39cb8c41
AR
2119 context->pullData();
2120 } else {
2121 // close or otherwise we may get stuck as nobody will notice the error?
73c36fd9 2122 comm_reset_close(clientConnection);
39cb8c41
AR
2123 }
2124#else
bf95c10a 2125 debugs(33, 3, "aborting chunked request without error " << error);
73c36fd9 2126 comm_reset_close(clientConnection);
39cb8c41 2127#endif
f35961af 2128 flags.readMore = false;
5f8252d2 2129}
55e44db9 2130
5f8252d2 2131void
1cf238db 2132ConnStateData::noteBodyConsumerAborted(BodyPipe::Pointer )
5f8252d2 2133{
cf6eb29e 2134 // request reader may get stuck waiting for space if nobody consumes body
aee3523a 2135 if (bodyPipe != nullptr)
cf6eb29e
CT
2136 bodyPipe->enableAutoConsumption();
2137
92ae4c86 2138 // kids extend
94439e4e 2139}
2140
63be0a78 2141/** general lifetime handler for HTTP requests */
1cf238db 2142void
2143ConnStateData::requestTimeout(const CommTimeoutCbParams &io)
7a2f978b 2144{
d5b97346
AJ
2145 if (!Comm::IsConnOpen(io.conn))
2146 return;
2147
9ce4a1eb 2148 const err_type error = receivedFirstByte_ ? ERR_REQUEST_PARSE_TIMEOUT : ERR_REQUEST_START_TIMEOUT;
83b053a0 2149 updateError(error);
eb026889 2150 if (tunnelOnError(error))
9ce4a1eb
CT
2151 return;
2152
af57a2e3 2153 /*
62e76326 2154 * Just close the connection to not confuse browsers
6177a89f
HN
2155 * using persistent connections. Some browsers open
2156 * a connection and then do not use it until much
62e76326 2157 * later (presumeably because the request triggering
2158 * the open has already been completed on another
2159 * connection)
2160 */
1cf238db 2161 debugs(33, 3, "requestTimeout: FD " << io.fd << ": lifetime is expired.");
8d77a37c 2162 io.conn->close();
7a2f978b 2163}
2164
83b053a0
CT
2165void
2166ConnStateData::lifetimeTimeout(const CommTimeoutCbParams &io)
b5c39993 2167{
83b053a0
CT
2168 debugs(33, DBG_IMPORTANT, "WARNING: Closing client connection due to lifetime timeout" <<
2169 Debug::Extra << "connection: " << io.conn);
2170
2171 LogTagsErrors lte;
2172 lte.timedout = true;
2173 terminateAll(ERR_LIFETIME_EXP, lte);
b5c39993 2174}
2175
94bfd31f 2176ConnStateData::ConnStateData(const MasterXaction::Pointer &xact) :
f53969cc 2177 AsyncJob("ConnStateData"), // kids overwrite
ca0d7ed6 2178 Server(xact)
cb4f4424 2179#if USE_OPENSSL
ca0d7ed6 2180 , tlsParser(Security::HandshakeParser::fromClient)
4579a6d0 2181#endif
c8be6d7b 2182{
94bfd31f 2183 // store the details required for creating more MasterXaction objects as new requests come in
94bfd31f 2184 log_addr = xact->tcpClient->remote;
36c774f7 2185 log_addr.applyClientMask(Config.Addrs.client_netmask);
d442618d
AJ
2186
2187 // register to receive notice of Squid signal events
2188 // which may affect long persisting client connections
b856803f 2189 registerRunner();
92ae4c86
AR
2190}
2191
2192void
2193ConnStateData::start()
2194{
2195 BodyProducer::start();
2196 HttpControlMsgSink::start();
2197
5529ca8a 2198 if (port->disable_pmtu_discovery != DISABLE_PMTU_OFF &&
94bfd31f 2199 (transparent() || port->disable_pmtu_discovery == DISABLE_PMTU_ALWAYS)) {
5529ca8a 2200#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
2201 int i = IP_PMTUDISC_DONT;
b69e9ffa
AJ
2202 if (setsockopt(clientConnection->fd, SOL_IP, IP_MTU_DISCOVER, &i, sizeof(i)) < 0) {
2203 int xerrno = errno;
2204 debugs(33, 2, "WARNING: Path MTU discovery disabling failed on " << clientConnection << " : " << xstrerr(xerrno));
2205 }
5529ca8a 2206#else
9bb67276 2207 static bool reported = false;
5529ca8a 2208
2209 if (!reported) {
d816f28d 2210 debugs(33, DBG_IMPORTANT, "WARNING: Path MTU discovery disabling is not supported on your platform.");
9bb67276 2211 reported = true;
5529ca8a 2212 }
89aec9b6
AJ
2213#endif
2214 }
5529ca8a 2215
89aec9b6 2216 typedef CommCbMemFunT<ConnStateData, CommCloseCbParams> Dialer;
94bfd31f
AJ
2217 AsyncCall::Pointer call = JobCallback(33, 5, Dialer, this, ConnStateData::connStateClosed);
2218 comm_add_close_handler(clientConnection->fd, call);
5529ca8a 2219
42cbf844
AJ
2220 needProxyProtocolHeader_ = port->flags.proxySurrogate;
2221 if (needProxyProtocolHeader_) {
2222 if (!proxyProtocolValidateClient()) // will close the connection on failure
2223 return;
2224 } else
2225 whenClientIpKnown();
2226
9ce4a1eb
CT
2227 // requires needProxyProtocolHeader_ which is initialized above
2228 preservingClientData_ = shouldPreserveClientData();
42cbf844
AJ
2229}
2230
2231void
2232ConnStateData::whenClientIpKnown()
2233{
a8c7a110
AR
2234 debugs(33, 7, clientConnection->remote);
2235 if (Dns::ResolveClientAddressesAsap)
94bfd31f 2236 fqdncache_gethostbyaddr(clientConnection->remote, FQDN_LOOKUP_IF_MISS);
89aec9b6
AJ
2237
2238#if USE_IDENT
2239 if (Ident::TheConfig.identLookup) {
aee3523a 2240 ACLFilledChecklist identChecklist(Ident::TheConfig.identLookup, nullptr, nullptr);
e227da8d 2241 fillChecklist(identChecklist);
06bf5384 2242 if (identChecklist.fastCheck().allowed())
92ae4c86 2243 Ident::Start(clientConnection, clientIdentDone, this);
89aec9b6 2244 }
5529ca8a 2245#endif
2246
94bfd31f 2247 clientdbEstablished(clientConnection->remote, 1);
5529ca8a 2248
9a0a18de 2249#if USE_DELAY_POOLS
aee3523a 2250 fd_table[clientConnection->fd].clientInfo = nullptr;
b4cd430a 2251
e37f1cd4
EB
2252 if (!Config.onoff.client_db)
2253 return; // client delay pools require client_db
b4cd430a 2254
e37f1cd4
EB
2255 const auto &pools = ClientDelayPools::Instance()->pools;
2256 if (pools.size()) {
aee3523a 2257 ACLFilledChecklist ch(nullptr, nullptr, nullptr);
e227da8d 2258 fillChecklist(ch);
2f8abb64 2259 // TODO: we check early to limit error response bandwidth but we
2efeb0b7 2260 // should recheck when we can honor delay_pool_uses_indirect
95dc7ff4 2261 for (unsigned int pool = 0; pool < pools.size(); ++pool) {
b4cd430a 2262
2efeb0b7 2263 /* pools require explicit 'allow' to assign a client into them */
b27668ec
EB
2264 if (pools[pool]->access) {
2265 ch.changeAcl(pools[pool]->access);
329c128c 2266 auto answer = ch.fastCheck();
06bf5384 2267 if (answer.allowed()) {
2efeb0b7
AJ
2268
2269 /* request client information from db after we did all checks
2270 this will save hash lookup if client failed checks */
92ae4c86 2271 ClientInfo * cli = clientdbGetInfo(clientConnection->remote);
2efeb0b7
AJ
2272 assert(cli);
2273
2274 /* put client info in FDE */
92ae4c86 2275 fd_table[clientConnection->fd].clientInfo = cli;
2efeb0b7
AJ
2276
2277 /* setup write limiter for this request */
2278 const double burst = floor(0.5 +
b27668ec
EB
2279 (pools[pool]->highwatermark * Config.ClientDelay.initial)/100.0);
2280 cli->setWriteLimiter(pools[pool]->rate, burst, pools[pool]->highwatermark);
2efeb0b7
AJ
2281 break;
2282 } else {
bf95c10a 2283 debugs(83, 4, "Delay pool " << pool << " skipped because ACL " << answer);
2efeb0b7 2284 }
b4cd430a
CT
2285 }
2286 }
2287 }
2288#endif
92ae4c86
AR
2289
2290 // kids must extend to actually start doing something (e.g., reading)
7a2f978b 2291}
2292
e227da8d
AR
2293Security::IoResult
2294ConnStateData::acceptTls()
2295{
2296 const auto handshakeResult = Security::Accept(*clientConnection);
2297
2298#if USE_OPENSSL
2299 // log ASAP, even if the handshake has not completed (or failed)
2300 const auto fd = clientConnection->fd;
2301 assert(fd >= 0);
2302 keyLogger.checkpoint(*fd_table[fd].ssl, *this);
2303#else
2304 // TODO: Support fd_table[fd].ssl dereference in other builds.
2305#endif
2306
2307 return handshakeResult;
2308}
2309
e7ce227f 2310/** Handle a new connection on an HTTP socket. */
92ae4c86
AR
2311void
2312httpAccept(const CommAcceptCbParams &params)
6afea0a4 2313{
ad05b958 2314 Assure(params.port);
6afea0a4
AR
2315
2316 // NP: it is possible the port was reconfigured when the call or accept() was queued.
2317
2318 if (params.flag != Comm::OK) {
2319 // Its possible the call was still queued when the client disconnected
ad05b958 2320 debugs(33, 2, params.port->listenConn << ": accept failure: " << xstrerr(params.xerrno));
6afea0a4
AR
2321 return;
2322 }
2323
e7ce227f 2324 debugs(33, 4, params.conn << ": accepted");
92ae4c86 2325 fd_note(params.conn->fd, "client http connect");
ad05b958
EB
2326 const auto xact = MasterXaction::MakePortful(params.port);
2327 xact->tcpClient = params.conn;
6afea0a4 2328
6afea0a4 2329 // Socket is ready, setup the connection manager to start using it
5e77f674 2330 auto *srv = Http::NewServer(xact);
ad05b958 2331 // XXX: do not abandon the MasterXaction object
5e77f674 2332 AsyncJob::Start(srv); // usually async-calls readSomeData()
7a2f978b 2333}
2334
86f77270 2335/// Create TLS connection structure and update fd_table
157c5ace 2336static bool
60fcfadf 2337httpsCreate(const ConnStateData *connState, const Security::ContextPointer &ctx)
ae7ff0b8 2338{
60fcfadf
AJ
2339 const auto conn = connState->clientConnection;
2340 if (Security::CreateServerSession(ctx, conn, connState->port->secure, "client https start")) {
ca2526bd 2341 debugs(33, 5, "will negotiate TLS on " << conn);
157c5ace 2342 return true;
ae7ff0b8 2343 }
2344
51e09c08 2345 debugs(33, DBG_IMPORTANT, "ERROR: could not create TLS server context for " << conn);
b3a8ae1b 2346 conn->close();
157c5ace 2347 return false;
ae7ff0b8 2348}
2349
d620ae0e
CT
2350/** negotiate an SSL connection */
2351static void
2352clientNegotiateSSL(int fd, void *data)
2353{
2354 ConnStateData *conn = (ConnStateData *)data;
51e09c08 2355
e227da8d 2356 const auto handshakeResult = conn->acceptTls();
83b053a0
CT
2357 switch (handshakeResult.category) {
2358 case Security::IoResult::ioSuccess:
2359 break;
2360
2361 case Security::IoResult::ioWantRead:
2362 Comm::SetSelect(conn->clientConnection->fd, COMM_SELECT_READ, clientNegotiateSSL, conn, 0);
2363 return;
2364
2365 case Security::IoResult::ioWantWrite:
2366 Comm::SetSelect(conn->clientConnection->fd, COMM_SELECT_WRITE, clientNegotiateSSL, conn, 0);
2367 return;
2368
2369 case Security::IoResult::ioError:
c59baaa8 2370 debugs(83, (handshakeResult.important ? Important(62) : 2), "ERROR: " << handshakeResult.errorDescription <<
83b053a0
CT
2371 " while accepting a TLS connection on " << conn->clientConnection << ": " << handshakeResult.errorDetail);
2372 // TODO: No ConnStateData::tunnelOnError() on this forward-proxy code
2373 // path because we cannot know the intended connection target?
2374 conn->updateError(ERR_SECURE_ACCEPT_FAIL, handshakeResult.errorDetail);
2375 conn->clientConnection->close();
d620ae0e 2376 return;
1700fab7 2377 }
62e76326 2378
ad23e748 2379 Security::SessionPointer session(fd_table[fd].ssl);
51e09c08
AJ
2380
2381#if USE_OPENSSL
ad23e748
AJ
2382 if (Security::SessionIsResumed(session)) {
2383 debugs(83, 2, "Session " << SSL_get_session(session.get()) <<
2384 " reused on FD " << fd << " (" << fd_table[fd].ipaddr <<
2385 ":" << (int)fd_table[fd].remote_port << ")");
6de9e64b 2386 } else {
014adac1 2387 if (Debug::Enabled(83, 4)) {
6de9e64b 2388 /* Write out the SSL session details.. actually the call below, but
2389 * OpenSSL headers do strange typecasts confusing GCC.. */
2390 /* PEM_write_SSL_SESSION(debug_log, SSL_get_session(ssl)); */
afdd443f 2391#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00908000L
ad23e748
AJ
2392 PEM_ASN1_write(reinterpret_cast<i2d_of_void *>(i2d_SSL_SESSION),
2393 PEM_STRING_SSL_SESSION, debug_log,
bba00f17 2394 reinterpret_cast<char *>(SSL_get_session(session.get())),
ad23e748 2395 nullptr, nullptr, 0, nullptr, nullptr);
2930f303 2396
0fd2205b 2397#elif (ALLOW_ALWAYS_SSL_SESSION_DETAIL == 1)
2930f303 2398
0fd2205b 2399 /* When using gcc 3.3.x and OpenSSL 0.9.7x sometimes a compile error can occur here.
2400 * This is caused by an unpredicatble gcc behaviour on a cast of the first argument
2401 * of PEM_ASN1_write(). For this reason this code section is disabled. To enable it,
2402 * define ALLOW_ALWAYS_SSL_SESSION_DETAIL=1.
2403 * Because there are two possible usable cast, if you get an error here, try the other
2404 * commented line. */
2405
ad23e748
AJ
2406 PEM_ASN1_write((int(*)())i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2407 debug_log,
bba00f17 2408 reinterpret_cast<char *>(SSL_get_session(session.get())),
ad23e748
AJ
2409 nullptr, nullptr, 0, nullptr, nullptr);
2410 /* PEM_ASN1_write((int(*)(...))i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2411 debug_log,
bba00f17 2412 reinterpret_cast<char *>(SSL_get_session(session.get())),
ad23e748
AJ
2413 nullptr, nullptr, 0, nullptr, nullptr);
2414 */
0e33d58c 2415#else
ad23e748 2416 debugs(83, 4, "With " OPENSSL_VERSION_TEXT ", session details are available only defining ALLOW_ALWAYS_SSL_SESSION_DETAIL=1 in the source.");
0fd2205b 2417
0e33d58c 2418#endif
6de9e64b 2419 /* Note: This does not automatically fflush the log file.. */
2420 }
2421
ad23e748
AJ
2422 debugs(83, 2, "New session " << SSL_get_session(session.get()) <<
2423 " on FD " << fd << " (" << fd_table[fd].ipaddr << ":" <<
2424 fd_table[fd].remote_port << ")");
6de9e64b 2425 }
51e09c08
AJ
2426#else
2427 debugs(83, 2, "TLS session reuse not yet implemented.");
2428#endif
6de9e64b 2429
2bcab852 2430 // Connection established. Retrieve TLS connection parameters for logging.
ad23e748 2431 conn->clientConnection->tlsNegotiations()->retrieveNegotiatedInfo(session);
1f7c9178 2432
51e09c08 2433#if USE_OPENSSL
ad23e748 2434 X509 *client_cert = SSL_get_peer_certificate(session.get());
62e76326 2435
ad23e748
AJ
2436 if (client_cert) {
2437 debugs(83, 3, "FD " << fd << " client certificate: subject: " <<
907831e6 2438 Security::SubjectName(*client_cert));
bf8fe701 2439
ad23e748 2440 debugs(83, 3, "FD " << fd << " client certificate: issuer: " <<
907831e6 2441 Security::IssuerName(*client_cert));
1f7c9178 2442
62e76326 2443 X509_free(client_cert);
1f7c9178 2444 } else {
51e09c08 2445 debugs(83, 5, "FD " << fd << " has no client certificate.");
1f7c9178 2446 }
51e09c08
AJ
2447#else
2448 debugs(83, 2, "Client certificate requesting not yet implemented.");
2449#endif
1f7c9178 2450
83b053a0
CT
2451 // If we are called, then bumped CONNECT has succeeded. Finalize it.
2452 if (auto xact = conn->pipeline.front()) {
2453 if (xact->http && xact->http->request && xact->http->request->method == Http::METHOD_CONNECT)
2454 xact->finished();
2455 // cannot proceed with encryption if requests wait for plain responses
2456 Must(conn->pipeline.empty());
2457 }
2458 /* careful: finished() above frees request, host, etc. */
2459
a46d2c0e 2460 conn->readSomeData();
1f7c9178 2461}
2462
379e8c1c 2463/**
0476ec45
AJ
2464 * If Security::ContextPointer is given, starts reading the TLS handshake.
2465 * Otherwise, calls switchToHttps to generate a dynamic Security::ContextPointer.
379e8c1c
AR
2466 */
2467static void
0476ec45 2468httpsEstablish(ConnStateData *connState, const Security::ContextPointer &ctx)
379e8c1c 2469{
379e8c1c
AR
2470 assert(connState);
2471 const Comm::ConnectionPointer &details = connState->clientConnection;
2472
60fcfadf 2473 if (!ctx || !httpsCreate(connState, ctx))
379e8c1c
AR
2474 return;
2475
83b053a0 2476 connState->resetReadTimeout(Config.Timeout.request);
379e8c1c 2477
36048c42 2478 Comm::SetSelect(details->fd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
379e8c1c
AR
2479}
2480
51e09c08 2481#if USE_OPENSSL
379e8c1c 2482/**
87f237a9 2483 * A callback function to use with the ACLFilledChecklist callback.
379e8c1c
AR
2484 */
2485static void
329c128c 2486httpsSslBumpAccessCheckDone(Acl::Answer answer, void *data)
379e8c1c
AR
2487{
2488 ConnStateData *connState = (ConnStateData *) data;
2489
7a957a93 2490 // if the connection is closed or closing, just return.
379e8c1c
AR
2491 if (!connState->isOpen())
2492 return;
2493
06bf5384 2494 if (answer.allowed()) {
bf352fb2 2495 debugs(33, 2, "sslBump action " << Ssl::bumpMode(answer.kind) << "needed for " << connState->clientConnection);
08097970 2496 connState->sslBumpMode = static_cast<Ssl::BumpMode>(answer.kind);
379e8c1c 2497 } else {
bf352fb2
CT
2498 debugs(33, 3, "sslBump not needed for " << connState->clientConnection);
2499 connState->sslBumpMode = Ssl::bumpSplice;
2500 }
2501
2502 if (connState->sslBumpMode == Ssl::bumpTerminate) {
2503 connState->clientConnection->close();
2504 return;
9e104535 2505 }
bf352fb2 2506
efda53c5
CT
2507 if (!connState->fakeAConnectRequest("ssl-bump", connState->inBuf))
2508 connState->clientConnection->close();
a30b692c 2509}
51e09c08 2510#endif
379e8c1c 2511
63be0a78 2512/** handle a new HTTPS connection */
1f7c9178 2513static void
449f0115 2514httpsAccept(const CommAcceptCbParams &params)
1f7c9178 2515{
ad05b958 2516 Assure(params.port);
94bfd31f 2517
c0ff709f 2518 // NP: it is possible the port was reconfigured when the call or accept() was queued.
c4b7a5a9 2519
c8407295 2520 if (params.flag != Comm::OK) {
cbff89ba 2521 // Its possible the call was still queued when the client disconnected
ad05b958 2522 debugs(33, 2, "httpsAccept: " << params.port->listenConn << ": accept failure: " << xstrerr(params.xerrno));
62e76326 2523 return;
c4b7a5a9 2524 }
62e76326 2525
ad05b958
EB
2526 const auto xact = MasterXaction::MakePortful(params.port);
2527 xact->tcpClient = params.conn;
2528
bf95c10a 2529 debugs(33, 4, params.conn << " accepted, starting SSL negotiation.");
449f0115 2530 fd_note(params.conn->fd, "client https connect");
62e76326 2531
89aec9b6 2532 // Socket is ready, setup the connection manager to start using it
5e77f674 2533 auto *srv = Https::NewServer(xact);
ad05b958 2534 // XXX: do not abandon the MasterXaction object
5e77f674 2535 AsyncJob::Start(srv); // usually async-calls postHttpsAccept()
92ae4c86 2536}
62e76326 2537
92ae4c86
AR
2538void
2539ConnStateData::postHttpsAccept()
2540{
b3cb9958 2541 if (port->flags.tunnelSslBumping) {
51e09c08 2542#if USE_OPENSSL
e7ce227f 2543 debugs(33, 5, "accept transparent connection: " << clientConnection);
62e76326 2544
379e8c1c 2545 if (!Config.accessList.ssl_bump) {
b3cb9958 2546 httpsSslBumpAccessCheckDone(ACCESS_DENIED, this);
379e8c1c
AR
2547 return;
2548 }
87f237a9 2549
ad05b958 2550 const auto mx = MasterXaction::MakePortful(port);
5ceaee75 2551 mx->tcpClient = clientConnection;
ccfbe8f4 2552 // Create a fake HTTP request and ALE for the ssl_bump ACL check,
38450a50 2553 // using tproxy/intercept provided destination IP and port.
ccfbe8f4
AR
2554 // XXX: Merge with subsequent fakeAConnectRequest(), buildFakeRequest().
2555 // XXX: Do this earlier (e.g., in Http[s]::One::Server constructor).
5ceaee75 2556 HttpRequest *request = new HttpRequest(mx);
379e8c1c 2557 static char ip[MAX_IPSTRLEN];
92ae4c86 2558 assert(clientConnection->flags & (COMM_TRANSPARENT | COMM_INTERCEPTION));
851feda6 2559 request->url.host(clientConnection->local.toStr(ip, sizeof(ip)));
5c51bffb 2560 request->url.port(clientConnection->local.port());
b3cb9958 2561 request->myportname = port->name;
ccfbe8f4
AR
2562 const AccessLogEntry::Pointer connectAle = new AccessLogEntry;
2563 CodeContext::Reset(connectAle);
2564 // TODO: Use these request/ALE when waiting for new bumped transactions.
87f237a9 2565
aee3523a 2566 ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(Config.accessList.ssl_bump, request, nullptr);
e227da8d 2567 fillChecklist(*acl_checklist);
d4ddb3e6 2568 // Build a local AccessLogEntry to allow requiresAle() acls work
ccfbe8f4 2569 acl_checklist->al = connectAle;
d4ddb3e6
CT
2570 acl_checklist->al->cache.start_time = current_time;
2571 acl_checklist->al->tcpClient = clientConnection;
2572 acl_checklist->al->cache.port = port;
2573 acl_checklist->al->cache.caddr = log_addr;
36c774f7 2574 acl_checklist->al->proxyProtocolHeader = proxyProtocolHeader_;
83b053a0 2575 acl_checklist->al->updateError(bareError);
542e1a7a 2576 HTTPMSGUNLOCK(acl_checklist->al->request);
d4ddb3e6
CT
2577 acl_checklist->al->request = request;
2578 HTTPMSGLOCK(acl_checklist->al->request);
cb365059
EB
2579 Http::StreamPointer context = pipeline.front();
2580 ClientHttpRequest *http = context ? context->http : nullptr;
2581 const char *log_uri = http ? http->log_uri : nullptr;
2582 acl_checklist->syncAle(request, log_uri);
b3cb9958 2583 acl_checklist->nonBlockingCheck(httpsSslBumpAccessCheckDone, this);
51e09c08
AJ
2584#else
2585 fatal("FATAL: SSL-Bump requires --with-openssl");
2586#endif
379e8c1c
AR
2587 return;
2588 } else {
0476ec45 2589 httpsEstablish(this, port->secure.staticContext);
379e8c1c 2590 }
1f7c9178 2591}
2592
51e09c08 2593#if USE_OPENSSL
95d2589c 2594void
24438ec5 2595ConnStateData::sslCrtdHandleReplyWrapper(void *data, const Helper::Reply &reply)
ae7ff0b8 2596{
95d2589c
CT
2597 ConnStateData * state_data = (ConnStateData *)(data);
2598 state_data->sslCrtdHandleReply(reply);
2599}
ae7ff0b8 2600
95d2589c 2601void
24438ec5 2602ConnStateData::sslCrtdHandleReply(const Helper::Reply &reply)
95d2589c 2603{
b418d9c8
CT
2604 if (!isOpen()) {
2605 debugs(33, 3, "Connection gone while waiting for ssl_crtd helper reply; helper reply:" << reply);
2606 return;
2607 }
2608
2428ce02 2609 if (reply.result == Helper::BrokenHelper) {
9ce4a1eb 2610 debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply);
5955f162 2611 } else if (!reply.other().hasContent()) {
bf95c10a 2612 debugs(1, DBG_IMPORTANT, "\"ssl_crtd\" helper returned <NULL> reply.");
95d2589c 2613 } else {
ff2d7d92 2614 Ssl::CrtdMessage reply_message(Ssl::CrtdMessage::REPLY);
0272dd08 2615 if (reply_message.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK) {
9ce4a1eb 2616 debugs(33, 5, "Reply from ssl_crtd for " << tlsConnectHostOrIp << " is incorrect");
95d2589c 2617 } else {
2428ce02 2618 if (reply.result != Helper::Okay) {
9ce4a1eb 2619 debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply_message.getBody());
95d2589c 2620 } else {
2f8abb64 2621 debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " was successfully received from ssl_crtd");
a9c2dd2f 2622 if (sslServerBump && (sslServerBump->act.step1 == Ssl::bumpPeek || sslServerBump->act.step1 == Ssl::bumpStare)) {
d620ae0e 2623 doPeekAndSpliceStep();
33cc0629 2624 auto ssl = fd_table[clientConnection->fd].ssl.get();
d620ae0e
CT
2625 bool ret = Ssl::configureSSLUsingPkeyAndCertFromMemory(ssl, reply_message.getBody().c_str(), *port);
2626 if (!ret)
e4f14091 2627 debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
d8f0ceab 2628
1c1fae0f 2629 Security::ContextPointer ctx(Security::GetFrom(fd_table[clientConnection->fd].ssl));
b23f5f9c 2630 Ssl::configureUnconfiguredSslContext(ctx, signAlgorithm, *port);
d620ae0e 2631 } else {
cf487124 2632 Security::ContextPointer ctx(Ssl::GenerateSslContextUsingPkeyAndCertFromMemory(reply_message.getBody().c_str(), port->secure, (signAlgorithm == Ssl::algSignTrusted)));
5107d2c4
CT
2633 if (ctx && !sslBumpCertKey.isEmpty())
2634 storeTlsContextToCache(sslBumpCertKey, ctx);
2635 getSslContextDone(ctx);
d620ae0e 2636 }
95d2589c
CT
2637 return;
2638 }
2639 }
2640 }
0476ec45
AJ
2641 Security::ContextPointer nil;
2642 getSslContextDone(nil);
95d2589c 2643}
ae7ff0b8 2644
06997a38 2645void ConnStateData::buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties)
fb2178bb 2646{
9ce4a1eb 2647 certProperties.commonName = sslCommonName_.isEmpty() ? tlsConnectHostOrIp.c_str() : sslCommonName_.c_str();
fb2178bb 2648
5107d2c4
CT
2649 const bool connectedOk = sslServerBump && sslServerBump->connectedOk();
2650 if (connectedOk) {
fd4624d7 2651 if (X509 *mimicCert = sslServerBump->serverCert.get())
59a49556
CT
2652 certProperties.mimicCert.resetAndLock(mimicCert);
2653
e227da8d
AR
2654 ACLFilledChecklist checklist(nullptr, sslServerBump->request.getRaw());
2655 fillChecklist(checklist);
59a49556 2656
aee3523a 2657 for (sslproxy_cert_adapt *ca = Config.ssl_client.cert_adapt; ca != nullptr; ca = ca->next) {
7a957a93 2658 // If the algorithm already set, then ignore it.
a06042fa 2659 if ((ca->alg == Ssl::algSetCommonName && certProperties.setCommonName) ||
87f237a9
A
2660 (ca->alg == Ssl::algSetValidAfter && certProperties.setValidAfter) ||
2661 (ca->alg == Ssl::algSetValidBefore && certProperties.setValidBefore) )
a06042fa
CT
2662 continue;
2663
06bf5384 2664 if (ca->aclList && checklist.fastCheck(ca->aclList).allowed()) {
59a49556
CT
2665 const char *alg = Ssl::CertAdaptAlgorithmStr[ca->alg];
2666 const char *param = ca->param;
87f237a9 2667
7a957a93
AR
2668 // For parameterless CN adaptation, use hostname from the
2669 // CONNECT request.
a06042fa 2670 if (ca->alg == Ssl::algSetCommonName) {
59a49556 2671 if (!param)
9ce4a1eb 2672 param = tlsConnectHostOrIp.c_str();
59a49556
CT
2673 certProperties.commonName = param;
2674 certProperties.setCommonName = true;
87f237a9 2675 } else if (ca->alg == Ssl::algSetValidAfter)
59a49556 2676 certProperties.setValidAfter = true;
87f237a9 2677 else if (ca->alg == Ssl::algSetValidBefore)
59a49556
CT
2678 certProperties.setValidBefore = true;
2679
bf95c10a 2680 debugs(33, 5, "Matches certificate adaptation aglorithm: " <<
8f9720ce 2681 alg << " param: " << (param ? param : "-"));
aebe6888 2682 }
fb2178bb 2683 }
aebe6888 2684
59a49556 2685 certProperties.signAlgorithm = Ssl::algSignEnd;
aee3523a 2686 for (sslproxy_cert_sign *sg = Config.ssl_client.cert_sign; sg != nullptr; sg = sg->next) {
06bf5384 2687 if (sg->aclList && checklist.fastCheck(sg->aclList).allowed()) {
59a49556
CT
2688 certProperties.signAlgorithm = (Ssl::CertSignAlgorithm)sg->alg;
2689 break;
2690 }
aebe6888 2691 }
6b2b6cfe
CT
2692 } else {// did not try to connect (e.g. client-first) or failed to connect
2693 // In case of an error while connecting to the secure server, use a
2694 // trusted certificate, with no mimicked fields and no adaptation
2695 // algorithms. There is nothing we can mimic, so we want to minimize the
2696 // number of warnings the user will have to see to get to the error page.
2697 // We will close the connection, so that the trust is not extended to
2698 // non-Squid content.
59a49556 2699 certProperties.signAlgorithm = Ssl::algSignTrusted;
aebe6888
CT
2700 }
2701
10d914f6 2702 assert(certProperties.signAlgorithm != Ssl::algSignEnd);
aebe6888
CT
2703
2704 if (certProperties.signAlgorithm == Ssl::algSignUntrusted) {
51e09c08
AJ
2705 assert(port->secure.untrustedSigningCa.cert);
2706 certProperties.signWithX509.resetAndLock(port->secure.untrustedSigningCa.cert.get());
2707 certProperties.signWithPkey.resetAndLock(port->secure.untrustedSigningCa.pkey.get());
87f237a9 2708 } else {
51e09c08
AJ
2709 assert(port->secure.signingCa.cert.get());
2710 certProperties.signWithX509.resetAndLock(port->secure.signingCa.cert.get());
aebe6888 2711
51e09c08
AJ
2712 if (port->secure.signingCa.pkey)
2713 certProperties.signWithPkey.resetAndLock(port->secure.signingCa.pkey.get());
aebe6888
CT
2714 }
2715 signAlgorithm = certProperties.signAlgorithm;
3c26b00a
CT
2716
2717 certProperties.signHash = Ssl::DefaultSignHash;
fb2178bb
CT
2718}
2719
5107d2c4
CT
2720Security::ContextPointer
2721ConnStateData::getTlsContextFromCache(const SBuf &cacheKey, const Ssl::CertificateProperties &certProperties)
2722{
2723 debugs(33, 5, "Finding SSL certificate for " << cacheKey << " in cache");
2724 Ssl::LocalContextStorage * ssl_ctx_cache = Ssl::TheGlobalContextStorage.getLocalStorage(port->s);
72247610 2725 if (const auto ctx = ssl_ctx_cache ? ssl_ctx_cache->get(cacheKey) : nullptr) {
5107d2c4
CT
2726 if (Ssl::verifySslCertificate(*ctx, certProperties)) {
2727 debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is valid");
2728 return *ctx;
2729 } else {
2730 debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is out of date. Delete this certificate from cache");
2731 if (ssl_ctx_cache)
2732 ssl_ctx_cache->del(cacheKey);
2733 }
2734 }
2735 return Security::ContextPointer(nullptr);
2736}
2737
2738void
2739ConnStateData::storeTlsContextToCache(const SBuf &cacheKey, Security::ContextPointer &ctx)
2740{
2741 Ssl::LocalContextStorage *ssl_ctx_cache = Ssl::TheGlobalContextStorage.getLocalStorage(port->s);
72247610 2742 if (!ssl_ctx_cache || !ssl_ctx_cache->add(cacheKey, ctx)) {
5107d2c4
CT
2743 // If it is not in storage delete after using. Else storage deleted it.
2744 fd_table[clientConnection->fd].dynamicTlsContext = ctx;
2745 }
2746}
2747
1ce2822d 2748void
95d2589c
CT
2749ConnStateData::getSslContextStart()
2750{
cf487124 2751 if (port->secure.generateHostCertificates) {
aebe6888 2752 Ssl::CertificateProperties certProperties;
06997a38 2753 buildSslCertGenerationParams(certProperties);
fb2178bb 2754
d620ae0e 2755 // Disable caching for bumpPeekAndSplice mode
a9c2dd2f 2756 if (!(sslServerBump && (sslServerBump->act.step1 == Ssl::bumpPeek || sslServerBump->act.step1 == Ssl::bumpStare))) {
5107d2c4
CT
2757 sslBumpCertKey.clear();
2758 Ssl::InRamCertificateDbKey(certProperties, sslBumpCertKey);
2759 assert(!sslBumpCertKey.isEmpty());
2760
2761 Security::ContextPointer ctx(getTlsContextFromCache(sslBumpCertKey, certProperties));
2762 if (ctx) {
2763 getSslContextDone(ctx);
2764 return;
95d2589c 2765 }
95d2589c
CT
2766 }
2767
b5faa519 2768#if USE_SSL_CRTD
00fc192d 2769 try {
bf95c10a 2770 debugs(33, 5, "Generating SSL certificate for " << certProperties.commonName << " using ssl_crtd.");
ff2d7d92 2771 Ssl::CrtdMessage request_message(Ssl::CrtdMessage::REQUEST);
87f237a9
A
2772 request_message.setCode(Ssl::CrtdMessage::code_new_certificate);
2773 request_message.composeRequest(certProperties);
bf95c10a 2774 debugs(33, 5, "SSL crtd request: " << request_message.compose().c_str());
23da195f 2775 Ssl::Helper::Submit(request_message, sslCrtdHandleReplyWrapper, this);
87f237a9
A
2776 return;
2777 } catch (const std::exception &e) {
00fc192d
AR
2778 debugs(33, DBG_IMPORTANT, "ERROR: Failed to compose ssl_crtd " <<
2779 "request for " << certProperties.commonName <<
2780 " certificate: " << e.what() << "; will now block to " <<
2781 "generate that certificate.");
2782 // fall through to do blocking in-process generation.
2783 }
2784#endif // USE_SSL_CRTD
2785
bf95c10a 2786 debugs(33, 5, "Generating SSL certificate for " << certProperties.commonName);
a9c2dd2f 2787 if (sslServerBump && (sslServerBump->act.step1 == Ssl::bumpPeek || sslServerBump->act.step1 == Ssl::bumpStare)) {
d620ae0e 2788 doPeekAndSpliceStep();
33cc0629 2789 auto ssl = fd_table[clientConnection->fd].ssl.get();
d620ae0e 2790 if (!Ssl::configureSSL(ssl, certProperties, *port))
e4f14091 2791 debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
d8f0ceab 2792
1c1fae0f 2793 Security::ContextPointer ctx(Security::GetFrom(fd_table[clientConnection->fd].ssl));
b23f5f9c 2794 Ssl::configureUnconfiguredSslContext(ctx, certProperties.signAlgorithm, *port);
d620ae0e 2795 } else {
cf487124 2796 Security::ContextPointer dynCtx(Ssl::GenerateSslContext(certProperties, port->secure, (signAlgorithm == Ssl::algSignTrusted)));
5107d2c4
CT
2797 if (dynCtx && !sslBumpCertKey.isEmpty())
2798 storeTlsContextToCache(sslBumpCertKey, dynCtx);
2799 getSslContextDone(dynCtx);
d620ae0e 2800 }
1ce2822d 2801 return;
95d2589c 2802 }
0476ec45
AJ
2803
2804 Security::ContextPointer nil;
2805 getSslContextDone(nil);
95d2589c
CT
2806}
2807
1ce2822d 2808void
5107d2c4 2809ConnStateData::getSslContextDone(Security::ContextPointer &ctx)
95d2589c 2810{
cf487124 2811 if (port->secure.generateHostCertificates && !ctx) {
9ce4a1eb 2812 debugs(33, 2, "Failed to generate TLS context for " << tlsConnectHostOrIp);
95d2589c
CT
2813 }
2814
2815 // If generated ssl context = NULL, try to use static ssl context.
0476ec45 2816 if (!ctx) {
80b5995a
AJ
2817 if (!port->secure.staticContext) {
2818 debugs(83, DBG_IMPORTANT, "Closing " << clientConnection->remote << " as lacking TLS context");
73c36fd9 2819 clientConnection->close();
1ce2822d 2820 return;
95d2589c 2821 } else {
80b5995a 2822 debugs(33, 5, "Using static TLS context.");
0476ec45 2823 ctx = port->secure.staticContext;
95d2589c
CT
2824 }
2825 }
ae7ff0b8 2826
60fcfadf 2827 if (!httpsCreate(this, ctx))
1ce2822d 2828 return;
ae7ff0b8 2829
4e67d484
CT
2830 // bumped intercepted conns should already have Config.Timeout.request set
2831 // but forwarded connections may only have Config.Timeout.lifetime. [Re]set
2832 // to make sure the connection does not get stuck on non-SSL clients.
83b053a0 2833 resetReadTimeout(Config.Timeout.request);
ae7ff0b8 2834
ae7ff0b8 2835 switchedToHttps_ = true;
36698640
CT
2836
2837 auto ssl = fd_table[clientConnection->fd].ssl.get();
2838 BIO *b = SSL_get_rbio(ssl);
2a268a06 2839 Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
36698640
CT
2840 bio->setReadBufData(inBuf);
2841 inBuf.clear();
2842 clientNegotiateSSL(clientConnection->fd, this);
ae7ff0b8 2843}
2844
1ce2822d 2845void
f5e17947 2846ConnStateData::switchToHttps(ClientHttpRequest *http, Ssl::BumpMode bumpServerMode)
95d2589c
CT
2847{
2848 assert(!switchedToHttps_);
f5e17947
CT
2849 Must(http->request);
2850 auto &request = http->request;
95d2589c 2851
9ce4a1eb
CT
2852 // Depending on receivedFirstByte_, we are at the start of either an
2853 // established CONNECT tunnel with the client or an intercepted TCP (and
2854 // presumably TLS) connection from the client. Expect TLS Client Hello.
2855 const auto insideConnectTunnel = receivedFirstByte_;
2856 debugs(33, 5, (insideConnectTunnel ? "post-CONNECT " : "raw TLS ") << clientConnection);
2857
2858 tlsConnectHostOrIp = request->url.hostOrIp();
0a57a661 2859 tlsConnectPort = request->url.port();
5c51bffb 2860 resetSslCommonName(request->url.host());
95d2589c 2861
83d4cd15
CT
2862 // We are going to read new request
2863 flags.readMore = true;
95d2589c 2864
4599cded
AJ
2865 // keep version major.minor details the same.
2866 // but we are now performing the HTTPS handshake traffic
2867 transferProtocol.protocol = AnyP::PROTO_HTTPS;
2868
2bd84e5f
CT
2869 // If sslServerBump is set, then we have decided to deny CONNECT
2870 // and now want to switch to SSL to send the error to the client
2871 // without even peeking at the origin server certificate.
caf3666d 2872 if (bumpServerMode == Ssl::bumpServerFirst && !sslServerBump) {
e857372a 2873 request->flags.sslPeek = true;
f5e17947 2874 sslServerBump = new Ssl::ServerBump(http);
e1f72a8b 2875 } else if (bumpServerMode == Ssl::bumpPeek || bumpServerMode == Ssl::bumpStare) {
d620ae0e 2876 request->flags.sslPeek = true;
f5e17947 2877 sslServerBump = new Ssl::ServerBump(http, nullptr, bumpServerMode);
36698640 2878 }
3cae14a6 2879
36698640
CT
2880 // commSetConnTimeout() was called for this request before we switched.
2881 // Fix timeout to request_start_timeout
83b053a0 2882 resetReadTimeout(Config.Timeout.request_start_timeout);
36698640
CT
2883 // Also reset receivedFirstByte_ flag to allow this timeout work in the case we have
2884 // a bumbed "connect" request on non transparent port.
2885 receivedFirstByte_ = false;
2886 // Get more data to peek at Tls
d20cf186 2887 parsingTlsHandshake = true;
9ce4a1eb
CT
2888
2889 // If the protocol has changed, then reset preservingClientData_.
2890 // Otherwise, its value initially set in start() is still valid/fresh.
2891 // shouldPreserveClientData() uses parsingTlsHandshake which is reset above.
2892 if (insideConnectTunnel)
2893 preservingClientData_ = shouldPreserveClientData();
2894
36698640
CT
2895 readSomeData();
2896}
2897
2898void
d20cf186 2899ConnStateData::parseTlsHandshake()
36698640 2900{
d20cf186
AR
2901 Must(parsingTlsHandshake);
2902
2903 assert(!inBuf.isEmpty());
36698640 2904 receivedFirstByte();
d20cf186
AR
2905 fd_note(clientConnection->fd, "Parsing TLS handshake");
2906
83b053a0
CT
2907 // stops being nil if we fail to parse the handshake
2908 ErrorDetail::Pointer parseErrorDetails;
2909
d20cf186
AR
2910 try {
2911 if (!tlsParser.parseHello(inBuf)) {
2912 // need more data to finish parsing
2913 readSomeData();
2914 return;
2915 }
2916 }
83b053a0
CT
2917 catch (const TextException &ex) {
2918 debugs(83, 2, "exception: " << ex);
2919 parseErrorDetails = new ExceptionErrorDetail(ex.id());
2920 }
2921 catch (...) {
2922 debugs(83, 2, "exception: " << CurrentException);
2923 static const auto d = MakeNamedErrorDetail("TLS_ACCEPT_PARSE");
2924 parseErrorDetails = d;
d20cf186 2925 }
36698640 2926
d20cf186 2927 parsingTlsHandshake = false;
36698640 2928
75f6c253
CT
2929 // client data may be needed for splicing and for
2930 // tunneling unsupportedProtocol after an error
2931 preservedClientData = inBuf;
6b2b6cfe 2932
d20cf186
AR
2933 // Even if the parser failed, each TLS detail should either be set
2934 // correctly or still be "unknown"; copying unknown detail is a no-op.
8d9e6d7f
CT
2935 Security::TlsDetails::Pointer const &details = tlsParser.details;
2936 clientConnection->tlsNegotiations()->retrieveParsedInfo(details);
2937 if (details && !details->serverName.isEmpty()) {
2938 resetSslCommonName(details->serverName.c_str());
4f6990ec 2939 tlsClientSni_ = details->serverName;
8d9e6d7f 2940 }
36698640
CT
2941
2942 // We should disable read/write handlers
508e3438 2943 Comm::ResetSelect(clientConnection->fd);
36698640 2944
83b053a0 2945 if (parseErrorDetails) {
6b2b6cfe
CT
2946 Http::StreamPointer context = pipeline.front();
2947 Must(context && context->http);
2948 HttpRequest::Pointer request = context->http->request;
2949 debugs(83, 5, "Got something other than TLS Client Hello. Cannot SslBump.");
83b053a0 2950 updateError(ERR_PROTOCOL_UNKNOWN, parseErrorDetails);
eb026889 2951 if (!tunnelOnError(ERR_PROTOCOL_UNKNOWN))
6b2b6cfe
CT
2952 clientConnection->close();
2953 return;
2954 }
2955
2956 if (!sslServerBump || sslServerBump->act.step1 == Ssl::bumpClientFirst) { // Either means client-first.
36698640 2957 getSslContextStart();
e1f72a8b 2958 return;
36698640 2959 } else if (sslServerBump->act.step1 == Ssl::bumpServerFirst) {
4647c8bd
CT
2960 debugs(83, 5, "server-first skips step2; start forwarding the request");
2961 sslServerBump->step = XactionStep::tlsBump3;
f5e17947
CT
2962 Http::StreamPointer context = pipeline.front();
2963 ClientHttpRequest *http = context ? context->http : nullptr;
36698640 2964 // will call httpsPeeked() with certificate and connection, eventually
f5e17947 2965 FwdState::Start(clientConnection, sslServerBump->entry, sslServerBump->request.getRaw(), http ? http->al : nullptr);
36698640
CT
2966 } else {
2967 Must(sslServerBump->act.step1 == Ssl::bumpPeek || sslServerBump->act.step1 == Ssl::bumpStare);
6b2b6cfe 2968 startPeekAndSplice();
3248e962 2969 }
d620ae0e
CT
2970}
2971
8b082ed9
FC
2972static void
2973httpsSslBumpStep2AccessCheckDone(Acl::Answer answer, void *data)
5d65362c
CT
2974{
2975 ConnStateData *connState = (ConnStateData *) data;
2976
2977 // if the connection is closed or closing, just return.
2978 if (!connState->isOpen())
2979 return;
2980
e4f14091 2981 debugs(33, 5, "Answer: " << answer << " kind:" << answer.kind);
a9c2dd2f
CT
2982 assert(connState->serverBump());
2983 Ssl::BumpMode bumpAction;
06bf5384 2984 if (answer.allowed()) {
640fe8fb 2985 bumpAction = (Ssl::BumpMode)answer.kind;
a9c2dd2f
CT
2986 } else
2987 bumpAction = Ssl::bumpSplice;
2988
2989 connState->serverBump()->act.step2 = bumpAction;
2990 connState->sslBumpMode = bumpAction;
bf352fb2
CT
2991 Http::StreamPointer context = connState->pipeline.front();
2992 if (ClientHttpRequest *http = (context ? context->http : nullptr))
2993 http->al->ssl.bumpMode = bumpAction;
a9c2dd2f
CT
2994
2995 if (bumpAction == Ssl::bumpTerminate) {
b54a7c5a 2996 connState->clientConnection->close();
a9c2dd2f 2997 } else if (bumpAction != Ssl::bumpSplice) {
6b2b6cfe 2998 connState->startPeekAndSplice();
efda53c5
CT
2999 } else if (!connState->splice())
3000 connState->clientConnection->close();
3248e962 3001}
5d65362c 3002
efda53c5 3003bool
3248e962
CT
3004ConnStateData::splice()
3005{
33cc0629 3006 // normally we can splice here, because we just got client hello message
2bcab852 3007
ed4c6863
EB
3008 // fde::ssl/tls_read_method() probably reads from our own inBuf. If so, then
3009 // we should not lose any raw bytes when switching to raw I/O here.
3010 if (fd_table[clientConnection->fd].ssl.get())
3011 fd_table[clientConnection->fd].useDefaultIo();
3248e962 3012
6b2b6cfe
CT
3013 // XXX: assuming that there was an HTTP/1.1 CONNECT to begin with...
3014 // reset the current protocol to HTTP/1.1 (was "HTTPS" for the bumping process)
3015 transferProtocol = Http::ProtocolVersion();
3016 assert(!pipeline.empty());
3017 Http::StreamPointer context = pipeline.front();
75f6c253
CT
3018 Must(context);
3019 Must(context->http);
6b2b6cfe 3020 ClientHttpRequest *http = context->http;
75f6c253
CT
3021 HttpRequest::Pointer request = http->request;
3022 context->finished();
3023 if (transparent()) {
3024 // For transparent connections, make a new fake CONNECT request, now
3025 // with SNI as target. doCallout() checks, adaptations may need that.
3026 return fakeAConnectRequest("splice", preservedClientData);
3027 } else {
3028 // For non transparent connections make a new tunneled CONNECT, which
3029 // also sets the HttpRequest::flags::forceTunnel flag to avoid
3030 // respond with "Connection Established" to the client.
3031 // This fake CONNECT request required to allow use of SNI in
3032 // doCallout() checks and adaptations.
eb026889 3033 return initiateTunneledRequest(request, "splice", preservedClientData);
75f6c253 3034 }
5d65362c
CT
3035}
3036
d620ae0e 3037void
6b2b6cfe 3038ConnStateData::startPeekAndSplice()
d620ae0e 3039{
5d65362c
CT
3040 // This is the Step2 of the SSL bumping
3041 assert(sslServerBump);
d4ddb3e6 3042 Http::StreamPointer context = pipeline.front();
2f0d171f 3043 ClientHttpRequest *http = context ? context->http : nullptr;
d4ddb3e6 3044
090f1d3c
CT
3045 if (sslServerBump->at(XactionStep::tlsBump1)) {
3046 sslServerBump->step = XactionStep::tlsBump2;
5d65362c
CT
3047 // Run a accessList check to check if want to splice or continue bumping
3048
2f0d171f 3049 ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(Config.accessList.ssl_bump, sslServerBump->request.getRaw(), nullptr);
329c128c 3050 acl_checklist->banAction(Acl::Answer(ACCESS_ALLOWED, Ssl::bumpNone));
3051 acl_checklist->banAction(Acl::Answer(ACCESS_ALLOWED, Ssl::bumpClientFirst));
3052 acl_checklist->banAction(Acl::Answer(ACCESS_ALLOWED, Ssl::bumpServerFirst));
e227da8d 3053 fillChecklist(*acl_checklist);
5d65362c
CT
3054 acl_checklist->nonBlockingCheck(httpsSslBumpStep2AccessCheckDone, this);
3055 return;
3056 }
3057
3cae14a6 3058 // will call httpsPeeked() with certificate and connection, eventually
51e09c08 3059 Security::ContextPointer unConfiguredCTX(Ssl::createSSLContext(port->secure.signingCa.cert, port->secure.signingCa.pkey, port->secure));
0476ec45 3060 fd_table[clientConnection->fd].dynamicTlsContext = unConfiguredCTX;
3cae14a6 3061
60fcfadf 3062 if (!httpsCreate(this, unConfiguredCTX))
3cae14a6
CT
3063 return;
3064
3065 switchedToHttps_ = true;
3066
3067 auto ssl = fd_table[clientConnection->fd].ssl.get();
3068 BIO *b = SSL_get_rbio(ssl);
2a268a06 3069 Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
3cae14a6 3070 bio->setReadBufData(inBuf);
3cae14a6
CT
3071 bio->hold(true);
3072
83b053a0
CT
3073 // We have successfully parsed client Hello, but our TLS handshake parser is
3074 // forgiving. Now we use a TLS library to parse the same bytes, so that we
3075 // can honor on_unsupported_protocol if needed. If there are no errors, we
3076 // expect Security::Accept() to ask us to write (our) TLS server Hello. We
3077 // also allow an ioWantRead result in case some fancy TLS extension that
3078 // Squid does not yet understand requires reading post-Hello client bytes.
e227da8d 3079 const auto handshakeResult = acceptTls();
83b053a0
CT
3080 if (!handshakeResult.wantsIo())
3081 return handleSslBumpHandshakeError(handshakeResult);
3cae14a6 3082
56dacaca
CT
3083 // We need to reset inBuf here, to be used by incoming requests in the case
3084 // of SSL bump
8abcff99 3085 inBuf.clear();
3cae14a6
CT
3086
3087 debugs(83, 5, "Peek and splice at step2 done. Start forwarding the request!!! ");
4647c8bd 3088 sslServerBump->step = XactionStep::tlsBump3;
aee3523a 3089 FwdState::Start(clientConnection, sslServerBump->entry, sslServerBump->request.getRaw(), http ? http->al : nullptr);
d620ae0e
CT
3090}
3091
83b053a0
CT
3092/// process a problematic Security::Accept() result on the SslBump code path
3093void
3094ConnStateData::handleSslBumpHandshakeError(const Security::IoResult &handshakeResult)
3095{
3096 auto errCategory = ERR_NONE;
3097
3098 switch (handshakeResult.category) {
3099 case Security::IoResult::ioSuccess: {
3100 static const auto d = MakeNamedErrorDetail("TLS_ACCEPT_UNEXPECTED_SUCCESS");
3101 updateError(errCategory = ERR_GATEWAY_FAILURE, d);
3102 break;
3103 }
3104
3105 case Security::IoResult::ioWantRead: {
3106 static const auto d = MakeNamedErrorDetail("TLS_ACCEPT_UNEXPECTED_READ");
3107 updateError(errCategory = ERR_GATEWAY_FAILURE, d);
3108 break;
3109 }
3110
3111 case Security::IoResult::ioWantWrite: {
3112 static const auto d = MakeNamedErrorDetail("TLS_ACCEPT_UNEXPECTED_WRITE");
3113 updateError(errCategory = ERR_GATEWAY_FAILURE, d);
3114 break;
3115 }
3116
3117 case Security::IoResult::ioError:
3118 debugs(83, (handshakeResult.important ? DBG_IMPORTANT : 2), "ERROR: " << handshakeResult.errorDescription <<
3119 " while SslBump-accepting a TLS connection on " << clientConnection << ": " << handshakeResult.errorDetail);
3120 updateError(errCategory = ERR_SECURE_ACCEPT_FAIL, handshakeResult.errorDetail);
3121 break;
3122
3123 }
3124
eb026889 3125 if (!tunnelOnError(errCategory))
83b053a0
CT
3126 clientConnection->close();
3127}
3128
d620ae0e
CT
3129void
3130ConnStateData::doPeekAndSpliceStep()
3131{
33cc0629 3132 auto ssl = fd_table[clientConnection->fd].ssl.get();
d620ae0e
CT
3133 BIO *b = SSL_get_rbio(ssl);
3134 assert(b);
2a268a06 3135 Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
d620ae0e 3136
2f8abb64 3137 debugs(33, 5, "PeekAndSplice mode, proceed with client negotiation. Current state:" << SSL_state_string_long(ssl));
d620ae0e
CT
3138 bio->hold(false);
3139
3140 Comm::SetSelect(clientConnection->fd, COMM_SELECT_WRITE, clientNegotiateSSL, this, 0);
3141 switchedToHttps_ = true;
3142}
3143
d7ce0bcd 3144void
801cfc26 3145ConnStateData::httpsPeeked(PinnedIdleContext pic)
d7ce0bcd 3146{
aee3523a 3147 Must(sslServerBump != nullptr);
801cfc26
CT
3148 Must(sslServerBump->request == pic.request);
3149 Must(pipeline.empty() || pipeline.front()->http == nullptr || pipeline.front()->http->request == pic.request.getRaw());
819c207f 3150
801cfc26
CT
3151 if (Comm::IsConnOpen(pic.connection)) {
3152 notePinnedConnectionBecameIdle(pic);
9ce4a1eb 3153 debugs(33, 5, "bumped HTTPS server: " << tlsConnectHostOrIp);
801cfc26 3154 } else
9ce4a1eb 3155 debugs(33, 5, "Error while bumping: " << tlsConnectHostOrIp);
129fe2a1 3156
1ce2822d 3157 getSslContextStart();
95d2589c
CT
3158}
3159
cb4f4424 3160#endif /* USE_OPENSSL */
1f7c9178 3161
efda53c5 3162bool
eb026889 3163ConnStateData::initiateTunneledRequest(HttpRequest::Pointer const &cause, const char *reason, const SBuf &payload)
0bd3c2a3
AJ
3164{
3165 // fake a CONNECT request to force connState to tunnel
e88bdb0e 3166 SBuf connectHost;
380b09ae 3167 AnyP::Port connectPort;
6b2b6cfe
CT
3168
3169 if (pinning.serverConnection != nullptr) {
3170 static char ip[MAX_IPSTRLEN];
9ce4a1eb 3171 connectHost = pinning.serverConnection->remote.toStr(ip, sizeof(ip));
380b09ae
AR
3172 if (const auto remotePort = pinning.serverConnection->remote.port())
3173 connectPort = remotePort;
9ce4a1eb
CT
3174 } else if (cause) {
3175 connectHost = cause->url.hostOrIp();
6b2b6cfe 3176 connectPort = cause->url.port();
9ce4a1eb
CT
3177#if USE_OPENSSL
3178 } else if (!tlsConnectHostOrIp.isEmpty()) {
3179 connectHost = tlsConnectHostOrIp;
3180 connectPort = tlsConnectPort;
3181#endif
3182 } else if (transparent()) {
3183 static char ip[MAX_IPSTRLEN];
3184 connectHost = clientConnection->local.toStr(ip, sizeof(ip));
3185 connectPort = clientConnection->local.port();
380b09ae
AR
3186 }
3187
3188 if (!connectPort) {
83b053a0
CT
3189 // Typical cases are malformed HTTP requests on http_port and malformed
3190 // TLS handshakes on non-bumping https_port. TODO: Discover these
3191 // problems earlier so that they can be classified/detailed better.
6b2b6cfe 3192 debugs(33, 2, "Not able to compute URL, abort request tunneling for " << reason);
83b053a0
CT
3193 // TODO: throw when nonBlockingCheck() callbacks gain job protections
3194 static const auto d = MakeNamedErrorDetail("TUNNEL_TARGET");
3195 updateError(ERR_INVALID_REQ, d);
6b2b6cfe
CT
3196 return false;
3197 }
3198
3199 debugs(33, 2, "Request tunneling for " << reason);
380b09ae 3200 const auto http = buildFakeRequest(connectHost, *connectPort, payload);
6b2b6cfe
CT
3201 HttpRequest::Pointer request = http->request;
3202 request->flags.forceTunnel = true;
3203 http->calloutContext = new ClientRequestContext(http);
3204 http->doCallouts();
3205 clientProcessRequestFinished(this, request);
3206 return true;
3207}
3208
3209bool
3210ConnStateData::fakeAConnectRequest(const char *reason, const SBuf &payload)
3211{
3212 debugs(33, 2, "fake a CONNECT request to force connState to tunnel for " << reason);
3213
3214 SBuf connectHost;
3215 assert(transparent());
3216 const unsigned short connectPort = clientConnection->local.port();
3217
65e0c910 3218#if USE_OPENSSL
4f6990ec
CT
3219 if (!tlsClientSni_.isEmpty())
3220 connectHost.assign(tlsClientSni_);
6b2b6cfe 3221 else
65e0c910
CT
3222#endif
3223 {
e88bdb0e 3224 static char ip[MAX_IPSTRLEN];
e9b219a0
TA
3225 clientConnection->local.toHostStr(ip, sizeof(ip));
3226 connectHost.assign(ip);
0bd3c2a3 3227 }
6b2b6cfe 3228
eb026889 3229 ClientHttpRequest *http = buildFakeRequest(connectHost, connectPort, payload);
6b2b6cfe
CT
3230
3231 http->calloutContext = new ClientRequestContext(http);
3232 HttpRequest::Pointer request = http->request;
3233 http->doCallouts();
3234 clientProcessRequestFinished(this, request);
efda53c5 3235 return true;
0bd3c2a3
AJ
3236}
3237
6b2b6cfe 3238ClientHttpRequest *
380b09ae 3239ConnStateData::buildFakeRequest(SBuf &useHost, const AnyP::KnownPort usePort, const SBuf &payload)
6b2b6cfe
CT
3240{
3241 ClientHttpRequest *http = new ClientHttpRequest(this);
3242 Http::Stream *stream = new Http::Stream(clientConnection, http);
3243
3244 StoreIOBuffer tempBuffer;
3245 tempBuffer.data = stream->reqbuf;
3246 tempBuffer.length = HTTP_REQBUF_SZ;
3247
3248 ClientStreamData newServer = new clientReplyContext(http);
3249 ClientStreamData newClient = stream;
3250 clientStreamInit(&http->client_stream, clientGetMoreData, clientReplyDetach,
3251 clientReplyStatus, newServer, clientSocketRecipient,
3252 clientSocketDetach, newClient, tempBuffer);
3253
6b2b6cfe
CT
3254 stream->flags.parsed_ok = 1; // Do we need it?
3255 stream->mayUseConnection(true);
83b053a0 3256 extendLifetime();
6b2b6cfe
CT
3257 stream->registerWithConn();
3258
ad05b958 3259 const auto mx = MasterXaction::MakePortful(port);
5ceaee75 3260 mx->tcpClient = clientConnection;
6b2b6cfe
CT
3261 // Setup Http::Request object. Maybe should be replaced by a call to (modified)
3262 // clientProcessRequest
5ceaee75 3263 HttpRequest::Pointer request = new HttpRequest(mx);
eb026889
CT
3264 request->url.setScheme(AnyP::PROTO_AUTHORITY_FORM, nullptr);
3265 request->method = Http::METHOD_CONNECT;
6b2b6cfe
CT
3266 request->url.host(useHost.c_str());
3267 request->url.port(usePort);
9ce4a1eb
CT
3268
3269 http->uri = SBufToCstring(request->effectiveRequestUri());
bec110e4 3270 http->initRequest(request.getRaw());
6b2b6cfe 3271
cd4a5c60 3272 request->manager(this, http->al);
6b2b6cfe 3273
eb026889 3274 request->header.putStr(Http::HOST, useHost.c_str());
cd4a5c60 3275
63df1d28 3276 request->sources |= ((switchedToHttps() || port->transport.protocol == AnyP::PROTO_HTTPS) ? Http::Message::srcHttps : Http::Message::srcHttp);
6b2b6cfe
CT
3277#if USE_AUTH
3278 if (getAuth())
3279 request->auth_user_request = getAuth();
3280#endif
6b2b6cfe
CT
3281
3282 inBuf = payload;
3283 flags.readMore = false;
3284
6b2b6cfe
CT
3285 return http;
3286}
3287
00516be1
AR
3288/// check FD after clientHttp[s]ConnectionOpened, adjust HttpSockets as needed
3289static bool
73c36fd9 3290OpenedHttpSocket(const Comm::ConnectionPointer &c, const Ipc::FdNoteId portType)
00516be1 3291{
73c36fd9 3292 if (!Comm::IsConnOpen(c)) {
00516be1
AR
3293 Must(NHttpSockets > 0); // we tried to open some
3294 --NHttpSockets; // there will be fewer sockets than planned
3295 Must(HttpSockets[NHttpSockets] < 0); // no extra fds received
3296
3297 if (!NHttpSockets) // we could not open any listen sockets at all
cbff89ba 3298 fatalf("Unable to open %s",FdNote(portType));
00516be1
AR
3299
3300 return false;
3301 }
3302 return true;
3303}
3304
3305/// find any unused HttpSockets[] slot and store fd there or return false
3306static bool
e0d28505 3307AddOpenedHttpSocket(const Comm::ConnectionPointer &conn)
00516be1
AR
3308{
3309 bool found = false;
95dc7ff4 3310 for (int i = 0; i < NHttpSockets && !found; ++i) {
00516be1 3311 if ((found = HttpSockets[i] < 0))
e0d28505 3312 HttpSockets[i] = conn->fd;
00516be1
AR
3313 }
3314 return found;
3315}
15df8349 3316
d193a436 3317static void
15df8349 3318clientHttpConnectionsOpen(void)
3319{
f38db639 3320 const auto savedContext = CodeContext::Current();
aee3523a 3321 for (AnyP::PortCfgPointer s = HttpPortList; s != nullptr; s = s->next) {
f38db639 3322 CodeContext::Reset(s);
d31d59d8 3323 const SBuf &scheme = AnyP::UriScheme(s->transport.protocol).image();
339e4d7a 3324
65d448bc 3325 if (MAXTCPLISTENPORTS == NHttpSockets) {
ccfbe8f4
AR
3326 debugs(1, DBG_IMPORTANT, "WARNING: You have too many '" << scheme << "_port' lines." <<
3327 Debug::Extra << "The limit is " << MAXTCPLISTENPORTS << " HTTP ports.");
62e76326 3328 continue;
3329 }
3330
cb4f4424 3331#if USE_OPENSSL
6a25a046 3332 if (s->flags.tunnelSslBumping) {
339e4d7a
AJ
3333 if (!Config.accessList.ssl_bump) {
3334 debugs(33, DBG_IMPORTANT, "WARNING: No ssl_bump configured. Disabling ssl-bump on " << scheme << "_port " << s->s);
3335 s->flags.tunnelSslBumping = false;
3336 }
cf487124 3337 if (!s->secure.staticContext && !s->secure.generateHostCertificates) {
339e4d7a
AJ
3338 debugs(1, DBG_IMPORTANT, "Will not bump SSL at " << scheme << "_port " << s->s << " due to TLS initialization failure.");
3339 s->flags.tunnelSslBumping = false;
3340 if (s->transport.protocol == AnyP::PROTO_HTTP)
3341 s->secure.encryptTransport = false;
3342 }
3343 if (s->flags.tunnelSslBumping) {
3344 // Create ssl_ctx cache for this port.
cf487124 3345 Ssl::TheGlobalContextStorage.addLocalStorage(s->s, s->secure.dynamicCertMemCacheSize);
339e4d7a 3346 }
95d2589c 3347 }
51e09c08 3348#endif
ae7ff0b8 3349
80b5995a 3350 if (s->secure.encryptTransport && !s->secure.staticContext) {
339e4d7a
AJ
3351 debugs(1, DBG_CRITICAL, "ERROR: Ignoring " << scheme << "_port " << s->s << " due to TLS context initialization failure.");
3352 continue;
3353 }
3354
71ddbf2a
EB
3355 const auto protocol = s->transport.protocol;
3356 assert(protocol == AnyP::PROTO_HTTP || protocol == AnyP::PROTO_HTTPS);
3357 const auto isHttps = protocol == AnyP::PROTO_HTTPS;
3358 using AcceptCall = CommCbFunPtrCallT<CommAcceptCbPtrFun>;
3359 RefCount<AcceptCall> subCall = commCbCall(5, 5, isHttps ? "httpsAccept" : "httpAccept",
bb4cc8e6 3360 CommAcceptCbPtrFun(isHttps ? httpsAccept : httpAccept, CommAcceptCbParams(nullptr)));
71ddbf2a 3361 clientStartListeningOn(s, subCall, isHttps ? Ipc::fdnHttpsSocket : Ipc::fdnHttpSocket);
cbff89ba 3362 }
f38db639 3363 CodeContext::Reset(savedContext);
d193a436 3364}
d193a436 3365
92ae4c86 3366void
27c841f6
AR
3367clientStartListeningOn(AnyP::PortCfgPointer &port, const RefCount< CommCbFunPtrCallT<CommAcceptCbPtrFun> > &subCall, const Ipc::FdNoteId fdNote)
3368{
92ae4c86
AR
3369 // Fill out a Comm::Connection which IPC will open as a listener for us
3370 port->listenConn = new Comm::Connection;
3371 port->listenConn->local = port->s;
e7ce227f
AR
3372 port->listenConn->flags =
3373 COMM_NONBLOCKING |
3374 (port->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) |
049eeeb4
EB
3375 (port->flags.natIntercept ? COMM_INTERCEPTION : 0) |
3376 (port->workerQueues ? COMM_REUSEPORT : 0);
92ae4c86
AR
3377
3378 // route new connections to subCall
3379 typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
3380 Subscription::Pointer sub = new CallSubscription<AcceptCall>(subCall);
e5ddd4ce 3381 const auto listenCall =
e7ce227f
AR
3382 asyncCall(33, 2, "clientListenerConnectionOpened",
3383 ListeningStartedDialer(&clientListenerConnectionOpened,
3384 port, fdNote, sub));
e5ddd4ce
AR
3385 AsyncCallback<Ipc::StartListeningAnswer> callback(listenCall);
3386 Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, port->listenConn, fdNote, callback);
434a79b0 3387
92ae4c86
AR
3388 assert(NHttpSockets < MAXTCPLISTENPORTS);
3389 HttpSockets[NHttpSockets] = -1;
3390 ++NHttpSockets;
434a79b0
DK
3391}
3392
e0d28505 3393/// process clientHttpConnectionsOpen result
00516be1 3394static void
fa720bfb 3395clientListenerConnectionOpened(AnyP::PortCfgPointer &s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub)
00516be1 3396{
aee3523a 3397 Must(s != nullptr);
fa720bfb 3398
8bbb16e3 3399 if (!OpenedHttpSocket(s->listenConn, portTypeNote))
00516be1 3400 return;
62e76326 3401
e0d28505 3402 Must(Comm::IsConnOpen(s->listenConn));
62e76326 3403
8bbb16e3 3404 // TCP: setup a job to handle accept() with subscribed handler
fa720bfb 3405 AsyncJob::Start(new Comm::TcpAcceptor(s, FdNote(portTypeNote), sub));
8bbb16e3 3406
c59baaa8 3407 debugs(1, Important(13), "Accepting " <<
6a25a046 3408 (s->flags.natIntercept ? "NAT intercepted " : "") <<
0d901ef4 3409 (s->flags.tproxyIntercept ? "TPROXY intercepted " : "") <<
6a25a046
FC
3410 (s->flags.tunnelSslBumping ? "SSL bumped " : "") <<
3411 (s->flags.accelSurrogate ? "reverse-proxy " : "")
8bbb16e3
AJ
3412 << FdNote(portTypeNote) << " connections at "
3413 << s->listenConn);
62e76326 3414
e0d28505 3415 Must(AddOpenedHttpSocket(s->listenConn)); // otherwise, we have received a fd we did not ask for
6fa8c664
MM
3416
3417#if USE_SYSTEMD
3418 // When the very first port opens, tell systemd we are able to serve connections.
3419 // Subsequent sd_notify() calls, including calls during reconfiguration,
3420 // do nothing because the first call parameter is 1.
3421 // XXX: Send the notification only after opening all configured ports.
3422 if (opt_foreground || opt_no_daemon) {
3423 const auto result = sd_notify(1, "READY=1");
3424 if (result < 0) {
3425 debugs(1, DBG_IMPORTANT, "WARNING: failed to send start-up notification to systemd" <<
3426 Debug::Extra << "sd_notify() error: " << xstrerr(-result));
3427 }
3428 }
3429#endif
d193a436 3430}
3431
d193a436 3432void
3433clientOpenListenSockets(void)
3434{
3435 clientHttpConnectionsOpen();
92ae4c86 3436 Ftp::StartListening();
62e76326 3437
15df8349 3438 if (NHttpSockets < 1)
e7ce227f 3439 fatal("No HTTP, HTTPS, or FTP ports configured");
15df8349 3440}
edce4d98 3441
c0fbae16 3442void
e7ce227f 3443clientConnectionsClose()
c0fbae16 3444{
f38db639 3445 const auto savedContext = CodeContext::Current();
aee3523a 3446 for (AnyP::PortCfgPointer s = HttpPortList; s != nullptr; s = s->next) {
f38db639 3447 CodeContext::Reset(s);
aee3523a 3448 if (s->listenConn != nullptr) {
c59baaa8 3449 debugs(1, Important(14), "Closing HTTP(S) port " << s->listenConn->local);
00406b24 3450 s->listenConn->close();
aee3523a 3451 s->listenConn = nullptr;
04f55905
AJ
3452 }
3453 }
f38db639 3454 CodeContext::Reset(savedContext);
62e76326 3455
92ae4c86 3456 Ftp::StopListening();
434a79b0 3457
04f55905 3458 // TODO see if we can drop HttpSockets array entirely */
95dc7ff4 3459 for (int i = 0; i < NHttpSockets; ++i) {
04f55905
AJ
3460 HttpSockets[i] = -1;
3461 }
62e76326 3462
c0fbae16 3463 NHttpSockets = 0;
3464}
f66a9ef4 3465
3466int
190154cf 3467varyEvaluateMatch(StoreEntry * entry, HttpRequest * request)
f66a9ef4 3468{
90ab8f20 3469 SBuf vary(request->vary_headers);
66d51f4f
AR
3470 const auto &reply = entry->mem().freshestReply();
3471 auto has_vary = reply.header.has(Http::HdrType::VARY);
f66a9ef4 3472#if X_ACCELERATOR_VARY
62e76326 3473
edce4d98 3474 has_vary |=
66d51f4f 3475 reply.header.has(Http::HdrType::HDR_X_ACCELERATOR_VARY);
f66a9ef4 3476#endif
62e76326 3477
90ab8f20
AJ
3478 if (!has_vary || entry->mem_obj->vary_headers.isEmpty()) {
3479 if (!vary.isEmpty()) {
62e76326 3480 /* Oops... something odd is going on here.. */
e0236918 3481 debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary object on second attempt, '" <<
c877c0bc 3482 entry->mem_obj->urlXXX() << "' '" << vary << "'");
90ab8f20 3483 request->vary_headers.clear();
62e76326 3484 return VARY_CANCEL;
3485 }
3486
3487 if (!has_vary) {
3488 /* This is not a varying object */
3489 return VARY_NONE;
3490 }
3491
3492 /* virtual "vary" object found. Calculate the vary key and
3493 * continue the search
3494 */
66d51f4f 3495 vary = httpMakeVaryMark(request, &reply);
62e76326 3496
90ab8f20
AJ
3497 if (!vary.isEmpty()) {
3498 request->vary_headers = vary;
62e76326 3499 return VARY_OTHER;
3500 } else {
3501 /* Ouch.. we cannot handle this kind of variance */
3502 /* XXX This cannot really happen, but just to be complete */
3503 return VARY_CANCEL;
3504 }
f66a9ef4 3505 } else {
90ab8f20 3506 if (vary.isEmpty()) {
66d51f4f 3507 vary = httpMakeVaryMark(request, &reply);
62e76326 3508
90ab8f20
AJ
3509 if (!vary.isEmpty())
3510 request->vary_headers = vary;
62e76326 3511 }
3512
90ab8f20 3513 if (vary.isEmpty()) {
62e76326 3514 /* Ouch.. we cannot handle this kind of variance */
3515 /* XXX This cannot really happen, but just to be complete */
3516 return VARY_CANCEL;
90ab8f20 3517 } else if (vary.cmp(entry->mem_obj->vary_headers) == 0) {
62e76326 3518 return VARY_MATCH;
3519 } else {
3520 /* Oops.. we have already been here and still haven't
3521 * found the requested variant. Bail out
3522 */
e0236918 3523 debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary match on second attempt, '" <<
c877c0bc 3524 entry->mem_obj->urlXXX() << "' '" << vary << "'");
62e76326 3525 return VARY_CANCEL;
3526 }
f66a9ef4 3527 }
3528}
28d4805a 3529
c0941a6a 3530ACLFilledChecklist *
59a1efb2 3531clientAclChecklistCreate(const acl_access * acl, ClientHttpRequest * http)
28d4805a 3532{
819be284
EB
3533 const auto checklist = new ACLFilledChecklist(acl, nullptr, nullptr);
3534 clientAclChecklistFill(*checklist, http);
3535 return checklist;
3536}
3537
3538void
3539clientAclChecklistFill(ACLFilledChecklist &checklist, ClientHttpRequest *http)
3540{
e227da8d
AR
3541 assert(http);
3542
3543 if (!checklist.request && http->request)
3544 checklist.setRequest(http->request);
3545
3546 if (!checklist.al && http->al) {
3547 checklist.al = http->al;
3548 checklist.syncAle(http->request, http->log_uri);
3549 if (!checklist.reply && http->al->reply) {
3550 checklist.reply = http->al->reply.getRaw();
3551 HTTPMSGLOCK(checklist.reply);
3552 }
3553 }
3554
3555 if (const auto conn = http->getConn())
3556 checklist.setConn(conn); // may already be set
3557}
3558
3559void
3560ConnStateData::fillChecklist(ACLFilledChecklist &checklist) const
3561{
3562 const auto context = pipeline.front();
3563 if (const auto http = context ? context->http : nullptr)
3564 return clientAclChecklistFill(checklist, http); // calls checklist.setConn()
3565
3566 // no requests, but we always have connection-level details
3567 // TODO: ACL checks should not require a mutable ConnStateData. Adjust the
3568 // code that accidentally violates that principle to remove this const_cast!
3569 checklist.setConn(const_cast<ConnStateData*>(this));
3570
3571 // Set other checklist fields inside our fillConnectionLevelDetails() rather
3572 // than here because clientAclChecklistFill() code path calls that method
3573 // (via ACLFilledChecklist::setConn()) rather than calling us directly.
3574}
3575
3576void
3577ConnStateData::fillConnectionLevelDetails(ACLFilledChecklist &checklist) const
3578{
3579 assert(checklist.conn() == this);
3580 assert(clientConnection);
3581
3582 if (!checklist.request) { // preserve (better) addresses supplied by setRequest()
3583 checklist.src_addr = clientConnection->remote;
3584 checklist.my_addr = clientConnection->local; // TODO: or port->s?
3585 }
3586
3587#if USE_OPENSSL
3588 if (!checklist.sslErrors && sslServerBump)
3589 checklist.sslErrors = cbdataReference(sslServerBump->sslErrors());
3590#endif
3591
3592 if (!checklist.rfc931[0]) // checklist creator may have supplied it already
3593 checklist.setIdent(clientConnection->rfc931);
3594
28d4805a 3595}
a46d2c0e 3596
a46d2c0e 3597bool
3598ConnStateData::transparent() const
3599{
aee3523a 3600 return clientConnection != nullptr && (clientConnection->flags & (COMM_TRANSPARENT|COMM_INTERCEPTION));
a46d2c0e 3601}
3602
5f8252d2 3603BodyPipe::Pointer
3e62bd58 3604ConnStateData::expectRequestBody(int64_t size)
5f8252d2 3605{
3606 bodyPipe = new BodyPipe(this);
39cb8c41
AR
3607 if (size >= 0)
3608 bodyPipe->setBodySize(size);
3609 else
3610 startDechunkingRequest();
5f8252d2 3611 return bodyPipe;
3612}
3613
39cb8c41
AR
3614int64_t
3615ConnStateData::mayNeedToReadMoreBody() const
3616{
3617 if (!bodyPipe)
3618 return 0; // request without a body or read/produced all body bytes
3619
3620 if (!bodyPipe->bodySizeKnown())
3621 return -1; // probably need to read more, but we cannot be sure
3622
3623 const int64_t needToProduce = bodyPipe->unproducedSize();
fcc444e3 3624 const int64_t haveAvailable = static_cast<int64_t>(inBuf.length());
39cb8c41
AR
3625
3626 if (needToProduce <= haveAvailable)
3627 return 0; // we have read what we need (but are waiting for pipe space)
3628
3629 return needToProduce - haveAvailable;
3630}
3631
55e44db9 3632void
cf6eb29e 3633ConnStateData::stopReceiving(const char *error)
55e44db9 3634{
bf95c10a 3635 debugs(33, 4, "receiving error (" << clientConnection << "): " << error <<
cf6eb29e
CT
3636 "; old sending error: " <<
3637 (stoppedSending() ? stoppedSending_ : "none"));
5f8252d2 3638
cf6eb29e 3639 if (const char *oldError = stoppedReceiving()) {
bf95c10a 3640 debugs(33, 3, "already stopped receiving: " << oldError);
cf6eb29e
CT
3641 return; // nothing has changed as far as this connection is concerned
3642 }
5f8252d2 3643
cf6eb29e 3644 stoppedReceiving_ = error;
5f8252d2 3645
cf6eb29e 3646 if (const char *sendError = stoppedSending()) {
bf95c10a 3647 debugs(33, 3, "closing because also stopped sending: " << sendError);
cf6eb29e
CT
3648 clientConnection->close();
3649 }
55e44db9 3650}
3651
eb44b2d7 3652void
e29ccb57
A
3653ConnStateData::expectNoForwarding()
3654{
aee3523a 3655 if (bodyPipe != nullptr) {
bf95c10a 3656 debugs(33, 4, "no consumer for virgin body " << bodyPipe->status());
eb44b2d7
CT
3657 bodyPipe->expectNoConsumption();
3658 }
3659}
3660
39cb8c41 3661/// initialize dechunking state
3ff65596 3662void
39cb8c41 3663ConnStateData::startDechunkingRequest()
3ff65596 3664{
aee3523a 3665 Must(bodyPipe != nullptr);
bf95c10a 3666 debugs(33, 5, "start dechunking" << bodyPipe->status());
fcc444e3
AJ
3667 assert(!bodyParser);
3668 bodyParser = new Http1::TeChunkedParser;
3ff65596
AR
3669}
3670
39cb8c41 3671/// put parsed content into input buffer and clean up
3ff65596 3672void
39cb8c41 3673ConnStateData::finishDechunkingRequest(bool withSuccess)
3ff65596 3674{
bf95c10a 3675 debugs(33, 5, "finish dechunking: " << withSuccess);
3ff65596 3676
aee3523a 3677 if (bodyPipe != nullptr) {
bf95c10a 3678 debugs(33, 7, "dechunked tail: " << bodyPipe->status());
39cb8c41
AR
3679 BodyPipe::Pointer myPipe = bodyPipe;
3680 stopProducingFor(bodyPipe, withSuccess); // sets bodyPipe->bodySize()
3681 Must(!bodyPipe); // we rely on it being nil after we are done with body
3682 if (withSuccess) {
3683 Must(myPipe->bodySizeKnown());
d3dddfb5 3684 Http::StreamPointer context = pipeline.front();
aee3523a 3685 if (context != nullptr && context->http && context->http->request)
39cb8c41
AR
3686 context->http->request->setContentLength(myPipe->bodySize());
3687 }
3ff65596 3688 }
3ff65596 3689
fcc444e3 3690 delete bodyParser;
aee3523a 3691 bodyParser = nullptr;
a46d2c0e 3692}
d67acb4e 3693
139a1d68 3694// XXX: this is an HTTP/1-only operation
655daa06
AR
3695void
3696ConnStateData::sendControlMsg(HttpControlMsg msg)
3697{
49f57088
EB
3698 if (const auto context = pipeline.front()) {
3699 if (context->http)
3700 context->http->al->reply = msg.reply;
3701 }
3702
eedd4182 3703 if (!isOpen()) {
bf95c10a 3704 debugs(33, 3, "ignoring 1xx due to earlier closure");
655daa06
AR
3705 return;
3706 }
3707
84540b47 3708 // HTTP/1 1xx status messages are only valid when there is a transaction to trigger them
139a1d68 3709 if (!pipeline.empty()) {
84540b47
AJ
3710 HttpReply::Pointer rep(msg.reply);
3711 Must(rep);
3712 // remember the callback
3713 cbControlMsgSent = msg.cbSuccess;
3714
3715 typedef CommCbMemFunT<HttpControlMsgSink, CommIoCbParams> Dialer;
3716 AsyncCall::Pointer call = JobCallback(33, 5, Dialer, this, HttpControlMsgSink::wroteControlMsg);
3717
2f97ab10
CT
3718 if (!writeControlMsgAndCall(rep.getRaw(), call)) {
3719 // but still inform the caller (so it may resume its operation)
3720 doneWithControlMsg();
3721 }
655daa06
AR
3722 return;
3723 }
3724
bf95c10a 3725 debugs(33, 3, " closing due to missing context for 1xx");
73c36fd9 3726 clientConnection->close();
655daa06
AR
3727}
3728
24e1fd72 3729void
2f97ab10 3730ConnStateData::doneWithControlMsg()
24e1fd72 3731{
2f97ab10 3732 HttpControlMsgSink::doneWithControlMsg();
24e1fd72
CT
3733
3734 if (Http::StreamPointer deferredRequest = pipeline.front()) {
3735 debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded after control msg wrote");
3736 ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
3737 }
3738}
3739
d7ce0bcd 3740/// Our close handler called by Comm when the pinned connection is closed
d67acb4e
AJ
3741void
3742ConnStateData::clientPinnedConnectionClosed(const CommCloseCbParams &io)
3743{
7a957a93
AR
3744 // FwdState might repin a failed connection sooner than this close
3745 // callback is called for the failed connection.
693cb033 3746 assert(pinning.serverConnection == io.conn);
aee3523a 3747 pinning.closeHandler = nullptr; // Comm unregisters handlers before calling
693cb033 3748 const bool sawZeroReply = pinning.zeroReply; // reset when unpinning
b54a7c5a 3749 pinning.serverConnection->noteClosure();
89b1d7a2 3750 unpinConnection(false);
f8e4867b 3751
aee3523a 3752 if (sawZeroReply && clientConnection != nullptr) {
693cb033
CT
3753 debugs(33, 3, "Closing client connection on pinned zero reply.");
3754 clientConnection->close();
85563fd9 3755 }
f8e4867b 3756
d67acb4e
AJ
3757}
3758
b1cf2350 3759void
801cfc26 3760ConnStateData::pinBusyConnection(const Comm::ConnectionPointer &pinServer, const HttpRequest::Pointer &request)
9e008dda 3761{
801cfc26
CT
3762 pinConnection(pinServer, *request);
3763}
d67acb4e 3764
801cfc26
CT
3765void
3766ConnStateData::notePinnedConnectionBecameIdle(PinnedIdleContext pic)
3767{
3768 Must(pic.connection);
3769 Must(pic.request);
3770 pinConnection(pic.connection, *pic.request);
3771
3772 // monitor pinned server connection for remote-end closures.
3773 startPinnedConnectionMonitoring();
3774
3775 if (pipeline.empty())
3776 kick(); // in case clientParseRequests() was blocked by a busy pic.connection
89b1d7a2 3777}
9e008dda 3778
801cfc26 3779/// Forward future client requests using the given server connection.
89b1d7a2 3780void
801cfc26 3781ConnStateData::pinConnection(const Comm::ConnectionPointer &pinServer, const HttpRequest &request)
89b1d7a2 3782{
801cfc26
CT
3783 if (Comm::IsConnOpen(pinning.serverConnection) &&
3784 pinning.serverConnection->fd == pinServer->fd) {
3785 debugs(33, 3, "already pinned" << pinServer);
3786 return;
3787 }
3788
89b1d7a2 3789 unpinConnection(true); // closes pinned connection, if any, and resets fields
9e008dda 3790
73c36fd9 3791 pinning.serverConnection = pinServer;
d7ce0bcd 3792
bf95c10a 3793 debugs(33, 3, pinning.serverConnection);
85563fd9 3794
aee3523a 3795 Must(pinning.serverConnection != nullptr);
89b1d7a2 3796
d7ce0bcd 3797 const char *pinnedHost = "[unknown]";
801cfc26
CT
3798 pinning.host = xstrdup(request.url.host());
3799 pinning.port = request.url.port();
3800 pinnedHost = pinning.host;
d67acb4e 3801 pinning.pinned = true;
801cfc26 3802 if (CachePeer *aPeer = pinServer->getPeer())
8bcf08e0 3803 pinning.peer = cbdataReference(aPeer);
801cfc26 3804 pinning.auth = request.flags.connectionAuth;
e3a4aecc 3805 char stmp[MAX_IPSTRLEN];
89b1d7a2 3806 char desc[FD_DESC_SZ];
e3a4aecc 3807 snprintf(desc, FD_DESC_SZ, "%s pinned connection for %s (%d)",
801cfc26 3808 (pinning.auth || !pinning.peer) ? pinnedHost : pinning.peer->name,
4dd643d5 3809 clientConnection->remote.toUrl(stmp,MAX_IPSTRLEN),
d7ce0bcd 3810 clientConnection->fd);
73c36fd9 3811 fd_note(pinning.serverConnection->fd, desc);
9e008dda 3812
d67acb4e 3813 typedef CommCbMemFunT<ConnStateData, CommCloseCbParams> Dialer;
4299f876 3814 pinning.closeHandler = JobCallback(33, 5,
4cb2536f 3815 Dialer, this, ConnStateData::clientPinnedConnectionClosed);
85563fd9
AR
3816 // remember the pinned connection so that cb does not unpin a fresher one
3817 typedef CommCloseCbParams Params;
3818 Params &params = GetCommParams<Params>(pinning.closeHandler);
3819 params.conn = pinning.serverConnection;
73c36fd9 3820 comm_add_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
7ac40923
AR
3821}
3822
e7ce227f
AR
3823/// [re]start monitoring pinned connection for peer closures so that we can
3824/// propagate them to an _idle_ client pinned to that peer
7ac40923
AR
3825void
3826ConnStateData::startPinnedConnectionMonitoring()
3827{
aee3523a 3828 if (pinning.readHandler != nullptr)
7ac40923
AR
3829 return; // already monitoring
3830
3831 typedef CommCbMemFunT<ConnStateData, CommIoCbParams> Dialer;
3832 pinning.readHandler = JobCallback(33, 3,
3833 Dialer, this, ConnStateData::clientPinnedConnectionRead);
7e66d5e2 3834 Comm::Read(pinning.serverConnection, pinning.readHandler);
7ac40923
AR
3835}
3836
3837void
3838ConnStateData::stopPinnedConnectionMonitoring()
3839{
aee3523a 3840 if (pinning.readHandler != nullptr) {
7e66d5e2 3841 Comm::ReadCancel(pinning.serverConnection->fd, pinning.readHandler);
aee3523a 3842 pinning.readHandler = nullptr;
7ac40923
AR
3843 }
3844}
3845
96aedee5
CT
3846#if USE_OPENSSL
3847bool
3848ConnStateData::handleIdleClientPinnedTlsRead()
3849{
3850 // A ready-for-reading connection means that the TLS server either closed
3851 // the connection, sent us some unexpected HTTP data, or started TLS
3852 // renegotiations. We should close the connection except for the last case.
3853
3854 Must(pinning.serverConnection != nullptr);
33cc0629 3855 auto ssl = fd_table[pinning.serverConnection->fd].ssl.get();
96aedee5
CT
3856 if (!ssl)
3857 return false;
3858
3859 char buf[1];
3860 const int readResult = SSL_read(ssl, buf, sizeof(buf));
3861
3862 if (readResult > 0 || SSL_pending(ssl) > 0) {
3863 debugs(83, 2, pinning.serverConnection << " TLS application data read");
3864 return false;
3865 }
3866
3867 switch(const int error = SSL_get_error(ssl, readResult)) {
3868 case SSL_ERROR_WANT_WRITE:
3869 debugs(83, DBG_IMPORTANT, pinning.serverConnection << " TLS SSL_ERROR_WANT_WRITE request for idle pinned connection");
09835feb
AR
3870 [[fallthrough]]; // to restart monitoring, for now
3871
96aedee5
CT
3872 case SSL_ERROR_NONE:
3873 case SSL_ERROR_WANT_READ:
3874 startPinnedConnectionMonitoring();
3875 return true;
3876
3877 default:
3878 debugs(83, 2, pinning.serverConnection << " TLS error: " << error);
3879 return false;
3880 }
3881
3882 // not reached
3883 return true;
3884}
3885#endif
3886
7ac40923
AR
3887/// Our read handler called by Comm when the server either closes an idle pinned connection or
3888/// perhaps unexpectedly sends something on that idle (from Squid p.o.v.) connection.
3889void
3890ConnStateData::clientPinnedConnectionRead(const CommIoCbParams &io)
3891{
aee3523a 3892 pinning.readHandler = nullptr; // Comm unregisters handlers before calling
7ac40923 3893
c8407295 3894 if (io.flag == Comm::ERR_CLOSING)
7ac40923
AR
3895 return; // close handler will clean up
3896
96aedee5
CT
3897 Must(pinning.serverConnection == io.conn);
3898
3899#if USE_OPENSSL
3900 if (handleIdleClientPinnedTlsRead())
3901 return;
3902#endif
3903
e500cc89 3904 const bool clientIsIdle = pipeline.empty();
7ac40923
AR
3905
3906 debugs(33, 3, "idle pinned " << pinning.serverConnection << " read " <<
3907 io.size << (clientIsIdle ? " with idle client" : ""));
3908
7ac40923
AR
3909 pinning.serverConnection->close();
3910
3911 // If we are still sending data to the client, do not close now. When we are done sending,
4a4fbcef 3912 // ConnStateData::kick() checks pinning.serverConnection and will close.
7ac40923 3913 // However, if we are idle, then we must close to inform the idle client and minimize races.
aee3523a 3914 if (clientIsIdle && clientConnection != nullptr)
7ac40923 3915 clientConnection->close();
d67acb4e
AJ
3916}
3917
daf80700
CT
3918Comm::ConnectionPointer
3919ConnStateData::borrowPinnedConnection(HttpRequest *request, const AccessLogEntryPointer &ale)
d67acb4e 3920{
daf80700
CT
3921 debugs(33, 7, pinning.serverConnection);
3922 Must(request);
85563fd9 3923
daf80700 3924 const auto pinningError = [&](const err_type type) {
89b1d7a2 3925 unpinConnection(true);
daf80700
CT
3926 HttpRequestPointer requestPointer = request;
3927 return ErrorState::NewForwarding(type, requestPointer, ale);
3928 };
3929
3930 if (!Comm::IsConnOpen(pinning.serverConnection))
3931 throw pinningError(ERR_ZERO_SIZE_OBJECT);
d67acb4e 3932
daf80700
CT
3933 if (pinning.auth && pinning.host && strcasecmp(pinning.host, request->url.host()) != 0)
3934 throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_CONFLICT_HOST
3935
3936 if (pinning.port != request->url.port())
3937 throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_CONFLICT_HOST
3938
3939 if (pinning.peer && !cbdataReferenceValid(pinning.peer))
3940 throw pinningError(ERR_ZERO_SIZE_OBJECT);
3941
3942 if (pinning.peerAccessDenied)
3943 throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_FORWARDING_DENIED
3944
3945 stopPinnedConnectionMonitoring();
73c36fd9 3946 return pinning.serverConnection;
d67acb4e
AJ
3947}
3948
89b1d7a2 3949Comm::ConnectionPointer
daf80700 3950ConnStateData::BorrowPinnedConnection(HttpRequest *request, const AccessLogEntryPointer &ale)
89b1d7a2 3951{
daf80700
CT
3952 if (const auto connManager = request ? request->pinnedConnection() : nullptr)
3953 return connManager->borrowPinnedConnection(request, ale);
89b1d7a2 3954
daf80700
CT
3955 // ERR_CANNOT_FORWARD is somewhat misleading here; we can still forward, but
3956 // there is no point since the client connection is now gone
3957 HttpRequestPointer requestPointer = request;
3958 throw ErrorState::NewForwarding(ERR_CANNOT_FORWARD, requestPointer, ale);
89b1d7a2
AR
3959}
3960
b1cf2350 3961void
89b1d7a2 3962ConnStateData::unpinConnection(const bool andClose)
d67acb4e 3963{
bf95c10a 3964 debugs(33, 3, pinning.serverConnection);
85563fd9 3965
9e008dda
AJ
3966 if (pinning.peer)
3967 cbdataReferenceDone(pinning.peer);
d67acb4e 3968
d7ce0bcd 3969 if (Comm::IsConnOpen(pinning.serverConnection)) {
aee3523a 3970 if (pinning.closeHandler != nullptr) {
87f237a9 3971 comm_remove_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
aee3523a 3972 pinning.closeHandler = nullptr;
87f237a9 3973 }
89b1d7a2 3974
f8e4867b 3975 stopPinnedConnectionMonitoring();
89b1d7a2
AR
3976
3977 // close the server side socket if requested
3978 if (andClose)
3979 pinning.serverConnection->close();
aee3523a 3980 pinning.serverConnection = nullptr;
d67acb4e 3981 }
d7ce0bcd 3982
d67acb4e 3983 safe_free(pinning.host);
e3a4aecc 3984
693cb033 3985 pinning.zeroReply = false;
daf80700 3986 pinning.peerAccessDenied = false;
693cb033 3987
e3a4aecc
AJ
3988 /* NOTE: pinning.pinned should be kept. This combined with fd == -1 at the end of a request indicates that the host
3989 * connection has gone away */
d67acb4e 3990}
44352c16 3991
da6dbcd1 3992void
ba3fe8d9 3993ConnStateData::terminateAll(const Error &rawError, const LogTagsErrors &lte)
da6dbcd1 3994{
ba3fe8d9
EB
3995 auto error = rawError; // (cheap) copy so that we can detail
3996 // We detail even ERR_NONE: There should be no transactions left, and
3997 // detailed ERR_NONE will be unused. Otherwise, this detail helps in triage.
3998 if (!error.detail) {
3999 static const auto d = MakeNamedErrorDetail("WITH_CLIENT");
4000 error.detail = d;
4001 }
4002
83b053a0 4003 debugs(33, 3, pipeline.count() << '/' << pipeline.nrequests << " after " << error);
da6dbcd1 4004
83b053a0
CT
4005 if (pipeline.empty()) {
4006 bareError.update(error); // XXX: bareLogTagsErrors
4007 } else {
4008 // We terminate the current CONNECT/PUT/etc. context below, logging any
4009 // error details, but that context may leave unparsed bytes behind.
4010 // Consume them to stop checkLogging() from logging them again later.
4011 const auto intputToConsume =
4012#if USE_OPENSSL
4013 parsingTlsHandshake ? "TLS handshake" : // more specific than CONNECT
4014#endif
4015 bodyPipe ? "HTTP request body" :
4016 pipeline.back()->mayUseConnection() ? "HTTP CONNECT" :
4017 nullptr;
4018
4019 while (const auto context = pipeline.front()) {
4020 context->noteIoError(error, lte);
4021 context->finished(); // cleanup and self-deregister
4022 assert(context != pipeline.front());
4023 }
da6dbcd1 4024
83b053a0
CT
4025 if (intputToConsume && !inBuf.isEmpty()) {
4026 debugs(83, 5, "forgetting client " << intputToConsume << " bytes: " << inBuf.length());
4027 inBuf.clear();
4028 }
4029 }
4030
4031 clientConnection->close();
4032}
4033
4034/// log the last (attempt at) transaction if nobody else did
4035void
4036ConnStateData::checkLogging()
4037{
4038 // to simplify our logic, we assume that terminateAll() has been called
4039 assert(pipeline.empty());
da6dbcd1
EB
4040
4041 // do not log connections that closed after a transaction (it is normal)
4042 // TODO: access_log needs ACLs to match received-no-bytes connections
6b2b6cfe 4043 if (pipeline.nrequests && inBuf.isEmpty())
da6dbcd1
EB
4044 return;
4045
4046 /* Create a temporary ClientHttpRequest object. Its destructor will log. */
4047 ClientHttpRequest http(this);
4048 http.req_sz = inBuf.length();
801cfc26 4049 // XXX: Or we died while waiting for the pinned connection to become idle.
bec110e4 4050 http.setErrorUri("error:transaction-end-before-headers");
83b053a0 4051 http.updateError(bareError);
da6dbcd1 4052}
a6678149 4053
6b2b6cfe 4054bool
9ce4a1eb 4055ConnStateData::shouldPreserveClientData() const
6b2b6cfe 4056{
9ce4a1eb
CT
4057 // PROXY protocol bytes are meant for us and, hence, cannot be tunneled
4058 if (needProxyProtocolHeader_)
4059 return false;
4060
4061 // If our decision here is negative, configuration changes are irrelevant.
4062 // Otherwise, clientTunnelOnError() rechecks configuration before tunneling.
4063 if (!Config.accessList.on_unsupported_protocol)
4064 return false;
4065
4066 // TODO: Figure out whether/how we can support FTP tunneling.
4067 if (port->transport.protocol == AnyP::PROTO_FTP)
4068 return false;
4069
6b2b6cfe 4070#if USE_OPENSSL
9ce4a1eb
CT
4071 if (parsingTlsHandshake)
4072 return true;
4073
4074 // the 1st HTTP request on a bumped connection
4075 if (!parsedBumpedRequestCount && switchedToHttps())
4076 return true;
6b2b6cfe 4077#endif
9ce4a1eb 4078
6ed68767
AR
4079 // the 1st HTTP(S) request on a connection to an intercepting port
4080 if (!pipeline.nrequests && transparent())
9ce4a1eb
CT
4081 return true;
4082
4083 return false;
6b2b6cfe 4084}
aff439e0 4085
75d47340
CT
4086NotePairs::Pointer
4087ConnStateData::notes()
4088{
4089 if (!theNotes)
4090 theNotes = new NotePairs;
4091 return theNotes;
4092}
4093
801cfc26
CT
4094std::ostream &
4095operator <<(std::ostream &os, const ConnStateData::PinnedIdleContext &pic)
4096{
4097 return os << pic.connection << ", request=" << pic.request;
4098}
9f107d9a 4099
1c2b4465
CT
4100std::ostream &
4101operator <<(std::ostream &os, const ConnStateData::ServerConnectionContext &scc)
4102{
4103 return os << scc.conn_ << ", srv_bytes=" << scc.preReadServerBytes.length();
4104}
4105