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