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