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