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