]> git.ipfire.org Git - thirdparty/squid.git/blob - src/client_side.cc
Cleanup pipeline handling on 1xx message sending
[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 * ClientKeepAliveNextRequest 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::connIsFinished()
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.pop();
264 conn->kick(); // kick anything which was waiting for us to finish
265 }
266
267 ClientSocketContext::ClientSocketContext(const Comm::ConnectionPointer &aConn, ClientHttpRequest *aReq) :
268 clientConnection(aConn),
269 http(aReq),
270 reply(NULL),
271 writtenToSocket(0),
272 mayUseConnection_ (false),
273 connRegistered_ (false)
274 {
275 assert(http != NULL);
276 memset (reqbuf, '\0', sizeof (reqbuf));
277 flags.deferred = 0;
278 flags.parsed_ok = 0;
279 deferredparams.node = NULL;
280 deferredparams.rep = NULL;
281 }
282
283 void
284 ClientSocketContext::writeControlMsg(HttpControlMsg &msg)
285 {
286 HttpReply::Pointer rep(msg.reply);
287 Must(rep != NULL);
288
289 // remember the callback
290 cbControlMsgSent = msg.cbSuccess;
291
292 AsyncCall::Pointer call = commCbCall(33, 5, "ClientSocketContext::wroteControlMsg",
293 CommIoCbPtrFun(&WroteControlMsg, this));
294
295 getConn()->writeControlMsgAndCall(this, rep.getRaw(), call);
296 }
297
298 /// called when we wrote the 1xx response
299 void
300 ClientSocketContext::wroteControlMsg(const Comm::ConnectionPointer &conn, char *, size_t, Comm::Flag errflag, int xerrno)
301 {
302 if (errflag == Comm::ERR_CLOSING)
303 return;
304
305 if (errflag == Comm::OK) {
306 ScheduleCallHere(cbControlMsgSent);
307 return;
308 }
309
310 debugs(33, 3, HERE << "1xx writing failed: " << xstrerr(xerrno));
311 // no error notification: see HttpControlMsg.h for rationale and
312 // note that some errors are detected elsewhere (e.g., close handler)
313
314 // close on 1xx errors to be conservative and to simplify the code
315 // (if we do not close, we must notify the source of a failure!)
316 conn->close();
317
318 // XXX: writeControlMsgAndCall() should handle writer-specific writing
319 // results, including errors and then call us with success/failure outcome.
320 }
321
322 /// wroteControlMsg() wrapper: ClientSocketContext is not an AsyncJob
323 void
324 ClientSocketContext::WroteControlMsg(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, Comm::Flag errflag, int xerrno, void *data)
325 {
326 ClientSocketContext *context = static_cast<ClientSocketContext*>(data);
327 context->wroteControlMsg(conn, bufnotused, size, errflag, xerrno);
328 }
329
330 #if USE_IDENT
331 static void
332 clientIdentDone(const char *ident, void *data)
333 {
334 ConnStateData *conn = (ConnStateData *)data;
335 xstrncpy(conn->clientConnection->rfc931, ident ? ident : dash_str, USER_IDENT_SZ);
336 }
337 #endif
338
339 void
340 clientUpdateStatCounters(const LogTags &logType)
341 {
342 ++statCounter.client_http.requests;
343
344 if (logType.isTcpHit())
345 ++statCounter.client_http.hits;
346
347 if (logType.oldType == LOG_TCP_HIT)
348 ++statCounter.client_http.disk_hits;
349 else if (logType.oldType == LOG_TCP_MEM_HIT)
350 ++statCounter.client_http.mem_hits;
351 }
352
353 void
354 clientUpdateStatHistCounters(const LogTags &logType, int svc_time)
355 {
356 statCounter.client_http.allSvcTime.count(svc_time);
357 /**
358 * The idea here is not to be complete, but to get service times
359 * for only well-defined types. For example, we don't include
360 * LOG_TCP_REFRESH_FAIL because its not really a cache hit
361 * (we *tried* to validate it, but failed).
362 */
363
364 switch (logType.oldType) {
365
366 case LOG_TCP_REFRESH_UNMODIFIED:
367 statCounter.client_http.nearHitSvcTime.count(svc_time);
368 break;
369
370 case LOG_TCP_IMS_HIT:
371 statCounter.client_http.nearMissSvcTime.count(svc_time);
372 break;
373
374 case LOG_TCP_HIT:
375
376 case LOG_TCP_MEM_HIT:
377
378 case LOG_TCP_OFFLINE_HIT:
379 statCounter.client_http.hitSvcTime.count(svc_time);
380 break;
381
382 case LOG_TCP_MISS:
383
384 case LOG_TCP_CLIENT_REFRESH_MISS:
385 statCounter.client_http.missSvcTime.count(svc_time);
386 break;
387
388 default:
389 /* make compiler warnings go away */
390 break;
391 }
392 }
393
394 bool
395 clientPingHasFinished(ping_data const *aPing)
396 {
397 if (0 != aPing->stop.tv_sec && 0 != aPing->start.tv_sec)
398 return true;
399
400 return false;
401 }
402
403 void
404 clientUpdateHierCounters(HierarchyLogEntry * someEntry)
405 {
406 ping_data *i;
407
408 switch (someEntry->code) {
409 #if USE_CACHE_DIGESTS
410
411 case CD_PARENT_HIT:
412
413 case CD_SIBLING_HIT:
414 ++ statCounter.cd.times_used;
415 break;
416 #endif
417
418 case SIBLING_HIT:
419
420 case PARENT_HIT:
421
422 case FIRST_PARENT_MISS:
423
424 case CLOSEST_PARENT_MISS:
425 ++ statCounter.icp.times_used;
426 i = &someEntry->ping;
427
428 if (clientPingHasFinished(i))
429 statCounter.icp.querySvcTime.count(tvSubUsec(i->start, i->stop));
430
431 if (i->timeout)
432 ++ statCounter.icp.query_timeouts;
433
434 break;
435
436 case CLOSEST_PARENT:
437
438 case CLOSEST_DIRECT:
439 ++ statCounter.netdb.times_used;
440
441 break;
442
443 default:
444 break;
445 }
446 }
447
448 void
449 ClientHttpRequest::updateCounters()
450 {
451 clientUpdateStatCounters(logType);
452
453 if (request->errType != ERR_NONE)
454 ++ statCounter.client_http.errors;
455
456 clientUpdateStatHistCounters(logType,
457 tvSubMsec(al->cache.start_time, current_time));
458
459 clientUpdateHierCounters(&request->hier);
460 }
461
462 void
463 prepareLogWithRequestDetails(HttpRequest * request, AccessLogEntry::Pointer &aLogEntry)
464 {
465 assert(request);
466 assert(aLogEntry != NULL);
467
468 if (Config.onoff.log_mime_hdrs) {
469 MemBuf mb;
470 mb.init();
471 request->header.packInto(&mb);
472 //This is the request after adaptation or redirection
473 aLogEntry->headers.adapted_request = xstrdup(mb.buf);
474
475 // the virgin request is saved to aLogEntry->request
476 if (aLogEntry->request) {
477 mb.reset();
478 aLogEntry->request->header.packInto(&mb);
479 aLogEntry->headers.request = xstrdup(mb.buf);
480 }
481
482 #if USE_ADAPTATION
483 const Adaptation::History::Pointer ah = request->adaptLogHistory();
484 if (ah != NULL) {
485 mb.reset();
486 ah->lastMeta.packInto(&mb);
487 aLogEntry->adapt.last_meta = xstrdup(mb.buf);
488 }
489 #endif
490
491 mb.clean();
492 }
493
494 #if ICAP_CLIENT
495 const Adaptation::Icap::History::Pointer ih = request->icapHistory();
496 if (ih != NULL)
497 ih->processingTime(aLogEntry->icap.processingTime);
498 #endif
499
500 aLogEntry->http.method = request->method;
501 aLogEntry->http.version = request->http_ver;
502 aLogEntry->hier = request->hier;
503 if (request->content_length > 0) // negative when no body or unknown length
504 aLogEntry->http.clientRequestSz.payloadData += request->content_length; // XXX: actually adaptedRequest payload size ??
505 aLogEntry->cache.extuser = request->extacl_user.termedBuf();
506
507 // Adapted request, if any, inherits and then collects all the stats, but
508 // the virgin request gets logged instead; copy the stats to log them.
509 // TODO: avoid losses by keeping these stats in a shared history object?
510 if (aLogEntry->request) {
511 aLogEntry->request->dnsWait = request->dnsWait;
512 aLogEntry->request->errType = request->errType;
513 aLogEntry->request->errDetail = request->errDetail;
514 }
515 }
516
517 void
518 ClientHttpRequest::logRequest()
519 {
520 if (!out.size && logType.oldType == LOG_TAG_NONE)
521 debugs(33, 5, "logging half-baked transaction: " << log_uri);
522
523 al->icp.opcode = ICP_INVALID;
524 al->url = log_uri;
525 debugs(33, 9, "clientLogRequest: al.url='" << al->url << "'");
526
527 if (al->reply) {
528 al->http.code = al->reply->sline.status();
529 al->http.content_type = al->reply->content_type.termedBuf();
530 } else if (loggingEntry() && loggingEntry()->mem_obj) {
531 al->http.code = loggingEntry()->mem_obj->getReply()->sline.status();
532 al->http.content_type = loggingEntry()->mem_obj->getReply()->content_type.termedBuf();
533 }
534
535 debugs(33, 9, "clientLogRequest: http.code='" << al->http.code << "'");
536
537 if (loggingEntry() && loggingEntry()->mem_obj && loggingEntry()->objectLen() >= 0)
538 al->cache.objectSize = loggingEntry()->contentLen(); // payload duplicate ?? with or without TE ?
539
540 al->http.clientRequestSz.header = req_sz;
541 al->http.clientReplySz.header = out.headers_sz;
542 // XXX: calculate without payload encoding or headers !!
543 al->http.clientReplySz.payloadData = out.size - out.headers_sz; // pretend its all un-encoded data for now.
544
545 al->cache.highOffset = out.offset;
546
547 al->cache.code = logType;
548
549 tvSub(al->cache.trTime, al->cache.start_time, current_time);
550
551 if (request)
552 prepareLogWithRequestDetails(request, al);
553
554 if (getConn() != NULL && getConn()->clientConnection != NULL && getConn()->clientConnection->rfc931[0])
555 al->cache.rfc931 = getConn()->clientConnection->rfc931;
556
557 #if USE_OPENSSL && 0
558
559 /* This is broken. Fails if the connection has been closed. Needs
560 * to snarf the ssl details some place earlier..
561 */
562 if (getConn() != NULL)
563 al->cache.ssluser = sslGetUserEmail(fd_table[getConn()->fd].ssl);
564
565 #endif
566
567 /* Add notes (if we have a request to annotate) */
568 if (request) {
569 // The al->notes and request->notes must point to the same object.
570 (void)SyncNotes(*al, *request);
571 for (auto i = Config.notes.begin(); i != Config.notes.end(); ++i) {
572 if (const char *value = (*i)->match(request, al->reply, NULL)) {
573 NotePairs &notes = SyncNotes(*al, *request);
574 notes.add((*i)->key.termedBuf(), value);
575 debugs(33, 3, (*i)->key.termedBuf() << " " << value);
576 }
577 }
578 }
579
580 ACLFilledChecklist checklist(NULL, request, NULL);
581 if (al->reply) {
582 checklist.reply = al->reply;
583 HTTPMSGLOCK(checklist.reply);
584 }
585
586 if (request) {
587 al->adapted_request = request;
588 HTTPMSGLOCK(al->adapted_request);
589 }
590 accessLogLog(al, &checklist);
591
592 bool updatePerformanceCounters = true;
593 if (Config.accessList.stats_collection) {
594 ACLFilledChecklist statsCheck(Config.accessList.stats_collection, request, NULL);
595 if (al->reply) {
596 statsCheck.reply = al->reply;
597 HTTPMSGLOCK(statsCheck.reply);
598 }
599 updatePerformanceCounters = (statsCheck.fastCheck() == ACCESS_ALLOWED);
600 }
601
602 if (updatePerformanceCounters) {
603 if (request)
604 updateCounters();
605
606 if (getConn() != NULL && getConn()->clientConnection != NULL)
607 clientdbUpdate(getConn()->clientConnection->remote, logType, AnyP::PROTO_HTTP, out.size);
608 }
609 }
610
611 void
612 ClientHttpRequest::freeResources()
613 {
614 safe_free(uri);
615 safe_free(log_uri);
616 safe_free(redirect.location);
617 range_iter.boundary.clean();
618 HTTPMSGUNLOCK(request);
619
620 if (client_stream.tail)
621 clientStreamAbort((clientStreamNode *)client_stream.tail->data, this);
622 }
623
624 void
625 httpRequestFree(void *data)
626 {
627 ClientHttpRequest *http = (ClientHttpRequest *)data;
628 assert(http != NULL);
629 delete http;
630 }
631
632 /* This is a handler normally called by comm_close() */
633 void ConnStateData::connStateClosed(const CommCloseCbParams &)
634 {
635 deleteThis("ConnStateData::connStateClosed");
636 }
637
638 #if USE_AUTH
639 void
640 ConnStateData::setAuth(const Auth::UserRequest::Pointer &aur, const char *by)
641 {
642 if (auth_ == NULL) {
643 if (aur != NULL) {
644 debugs(33, 2, "Adding connection-auth to " << clientConnection << " from " << by);
645 auth_ = aur;
646 }
647 return;
648 }
649
650 // clobered with self-pointer
651 // NP: something nasty is going on in Squid, but harmless.
652 if (aur == auth_) {
653 debugs(33, 2, "WARNING: Ignoring duplicate connection-auth for " << clientConnection << " from " << by);
654 return;
655 }
656
657 /*
658 * Connection-auth relies on a single set of credentials being preserved
659 * for all requests on a connection once they have been setup.
660 * There are several things which need to happen to preserve security
661 * when connection-auth credentials change unexpectedly or are unset.
662 *
663 * 1) auth helper released from any active state
664 *
665 * They can only be reserved by a handshake process which this
666 * connection can now never complete.
667 * This prevents helpers hanging when their connections close.
668 *
669 * 2) pinning is expected to be removed and server conn closed
670 *
671 * The upstream link is authenticated with the same credentials.
672 * Expecting the same level of consistency we should have received.
673 * This prevents upstream being faced with multiple or missing
674 * credentials after authentication.
675 * NP: un-pin is left to the cleanup in ConnStateData::swanSong()
676 * we just trigger that cleanup here via comm_reset_close() or
677 * ConnStateData::stopReceiving()
678 *
679 * 3) the connection needs to close.
680 *
681 * This prevents attackers injecting requests into a connection,
682 * or gateways wrongly multiplexing users into a single connection.
683 *
684 * When credentials are missing closure needs to follow an auth
685 * challenge for best recovery by the client.
686 *
687 * When credentials change there is nothing we can do but abort as
688 * fast as possible. Sending TCP RST instead of an HTTP response
689 * is the best-case action.
690 */
691
692 // clobbered with nul-pointer
693 if (aur == NULL) {
694 debugs(33, 2, "WARNING: Graceful closure on " << clientConnection << " due to connection-auth erase from " << by);
695 auth_->releaseAuthServer();
696 auth_ = NULL;
697 // XXX: need to test whether the connection re-auth challenge is sent. If not, how to trigger it from here.
698 // NP: the current situation seems to fix challenge loops in Safari without visible issues in others.
699 // we stop receiving more traffic but can leave the Job running to terminate after the error or challenge is delivered.
700 stopReceiving("connection-auth removed");
701 return;
702 }
703
704 // clobbered with alternative credentials
705 if (aur != auth_) {
706 debugs(33, 2, "ERROR: Closing " << clientConnection << " due to change of connection-auth from " << by);
707 auth_->releaseAuthServer();
708 auth_ = NULL;
709 // this is a fatal type of problem.
710 // Close the connection immediately with TCP RST to abort all traffic flow
711 comm_reset_close(clientConnection);
712 return;
713 }
714
715 /* NOT REACHABLE */
716 }
717 #endif
718
719 // cleans up before destructor is called
720 void
721 ConnStateData::swanSong()
722 {
723 debugs(33, 2, HERE << clientConnection);
724 flags.readMore = false;
725 DeregisterRunner(this);
726 clientdbEstablished(clientConnection->remote, -1); /* decrement */
727 pipeline.terminateAll(0);
728
729 unpinConnection(true);
730
731 Server::swanSong(); // closes the client connection
732
733 #if USE_AUTH
734 // NP: do this bit after closing the connections to avoid side effects from unwanted TCP RST
735 setAuth(NULL, "ConnStateData::SwanSong cleanup");
736 #endif
737
738 flags.swanSang = true;
739 }
740
741 bool
742 ConnStateData::isOpen() const
743 {
744 return cbdataReferenceValid(this) && // XXX: checking "this" in a method
745 Comm::IsConnOpen(clientConnection) &&
746 !fd_table[clientConnection->fd].closing();
747 }
748
749 ConnStateData::~ConnStateData()
750 {
751 debugs(33, 3, HERE << clientConnection);
752
753 if (isOpen())
754 debugs(33, DBG_IMPORTANT, "BUG: ConnStateData did not close " << clientConnection);
755
756 if (!flags.swanSang)
757 debugs(33, DBG_IMPORTANT, "BUG: ConnStateData was not destroyed properly; " << clientConnection);
758
759 if (bodyPipe != NULL)
760 stopProducingFor(bodyPipe, false);
761
762 delete bodyParser; // TODO: pool
763
764 #if USE_OPENSSL
765 delete sslServerBump;
766 #endif
767 }
768
769 /**
770 * clientSetKeepaliveFlag() sets request->flags.proxyKeepalive.
771 * This is the client-side persistent connection flag. We need
772 * to set this relatively early in the request processing
773 * to handle hacks for broken servers and clients.
774 */
775 void
776 clientSetKeepaliveFlag(ClientHttpRequest * http)
777 {
778 HttpRequest *request = http->request;
779
780 debugs(33, 3, "http_ver = " << request->http_ver);
781 debugs(33, 3, "method = " << request->method);
782
783 // TODO: move to HttpRequest::hdrCacheInit, just like HttpReply.
784 request->flags.proxyKeepalive = request->persistent();
785 }
786
787 /// checks body length of non-chunked requests
788 static int
789 clientIsContentLengthValid(HttpRequest * r)
790 {
791 // No Content-Length means this request just has no body, but conflicting
792 // Content-Lengths mean a message framing error (RFC 7230 Section 3.3.3 #4).
793 if (r->header.conflictingContentLength())
794 return 0;
795
796 switch (r->method.id()) {
797
798 case Http::METHOD_GET:
799
800 case Http::METHOD_HEAD:
801 /* We do not want to see a request entity on GET/HEAD requests */
802 return (r->content_length <= 0 || Config.onoff.request_entities);
803
804 default:
805 /* For other types of requests we don't care */
806 return 1;
807 }
808
809 /* NOT REACHED */
810 }
811
812 int
813 clientIsRequestBodyTooLargeForPolicy(int64_t bodyLength)
814 {
815 if (Config.maxRequestBodySize &&
816 bodyLength > Config.maxRequestBodySize)
817 return 1; /* too large */
818
819 return 0;
820 }
821
822 void
823 ClientSocketContext::deferRecipientForLater(clientStreamNode * node, HttpReply * rep, StoreIOBuffer receivedData)
824 {
825 debugs(33, 2, "clientSocketRecipient: Deferring request " << http->uri);
826 assert(flags.deferred == 0);
827 flags.deferred = 1;
828 deferredparams.node = node;
829 deferredparams.rep = rep;
830 deferredparams.queuedBuffer = receivedData;
831 return;
832 }
833
834 bool
835 ClientSocketContext::startOfOutput() const
836 {
837 return http->out.size == 0;
838 }
839
840 size_t
841 ClientSocketContext::lengthToSend(Range<int64_t> const &available)
842 {
843 /*the size of available range can always fit in a size_t type*/
844 size_t maximum = (size_t)available.size();
845
846 if (!http->request->range)
847 return maximum;
848
849 assert (canPackMoreRanges());
850
851 if (http->range_iter.debt() == -1)
852 return maximum;
853
854 assert (http->range_iter.debt() > 0);
855
856 /* TODO this + the last line could be a range intersection calculation */
857 if (available.start < http->range_iter.currentSpec()->offset)
858 return 0;
859
860 return min(http->range_iter.debt(), (int64_t)maximum);
861 }
862
863 void
864 ClientSocketContext::noteSentBodyBytes(size_t bytes)
865 {
866 debugs(33, 7, bytes << " body bytes");
867
868 http->out.offset += bytes;
869
870 if (!http->request->range)
871 return;
872
873 if (http->range_iter.debt() != -1) {
874 http->range_iter.debt(http->range_iter.debt() - bytes);
875 assert (http->range_iter.debt() >= 0);
876 }
877
878 /* debt() always stops at -1, below that is a bug */
879 assert (http->range_iter.debt() >= -1);
880 }
881
882 bool
883 ClientHttpRequest::multipartRangeRequest() const
884 {
885 return request->multipartRangeRequest();
886 }
887
888 bool
889 ClientSocketContext::multipartRangeRequest() const
890 {
891 return http->multipartRangeRequest();
892 }
893
894 void
895 ClientSocketContext::sendBody(HttpReply * rep, StoreIOBuffer bodyData)
896 {
897 assert(rep == NULL);
898
899 if (!multipartRangeRequest() && !http->request->flags.chunkedReply) {
900 size_t length = lengthToSend(bodyData.range());
901 noteSentBodyBytes (length);
902 AsyncCall::Pointer call = commCbCall(33, 5, "clientWriteBodyComplete",
903 CommIoCbPtrFun(clientWriteBodyComplete, this));
904 Comm::Write(clientConnection, bodyData.data, length, call, NULL);
905 return;
906 }
907
908 MemBuf mb;
909 mb.init();
910 if (multipartRangeRequest())
911 packRange(bodyData, &mb);
912 else
913 packChunk(bodyData, mb);
914
915 if (mb.contentSize()) {
916 /* write */
917 AsyncCall::Pointer call = commCbCall(33, 5, "clientWriteComplete",
918 CommIoCbPtrFun(clientWriteComplete, this));
919 Comm::Write(clientConnection, &mb, call);
920 } else
921 writeComplete(clientConnection, NULL, 0, Comm::OK);
922 }
923
924 /**
925 * Packs bodyData into mb using chunked encoding. Packs the last-chunk
926 * if bodyData is empty.
927 */
928 void
929 ClientSocketContext::packChunk(const StoreIOBuffer &bodyData, MemBuf &mb)
930 {
931 const uint64_t length =
932 static_cast<uint64_t>(lengthToSend(bodyData.range()));
933 noteSentBodyBytes(length);
934
935 mb.appendf("%" PRIX64 "\r\n", length);
936 mb.append(bodyData.data, length);
937 mb.append("\r\n", 2);
938 }
939
940 /** put terminating boundary for multiparts */
941 static void
942 clientPackTermBound(String boundary, MemBuf * mb)
943 {
944 mb->appendf("\r\n--" SQUIDSTRINGPH "--\r\n", SQUIDSTRINGPRINT(boundary));
945 debugs(33, 6, "clientPackTermBound: buf offset: " << mb->size);
946 }
947
948 /** appends a "part" HTTP header (as in a multi-part/range reply) to the buffer */
949 static void
950 clientPackRangeHdr(const HttpReply * rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb)
951 {
952 HttpHeader hdr(hoReply);
953 assert(rep);
954 assert(spec);
955
956 /* put boundary */
957 debugs(33, 5, "clientPackRangeHdr: appending boundary: " << boundary);
958 /* rfc2046 requires to _prepend_ boundary with <crlf>! */
959 mb->appendf("\r\n--" SQUIDSTRINGPH "\r\n", SQUIDSTRINGPRINT(boundary));
960
961 /* stuff the header with required entries and pack it */
962
963 if (rep->header.has(Http::HdrType::CONTENT_TYPE))
964 hdr.putStr(Http::HdrType::CONTENT_TYPE, rep->header.getStr(Http::HdrType::CONTENT_TYPE));
965
966 httpHeaderAddContRange(&hdr, *spec, rep->content_length);
967
968 hdr.packInto(mb);
969 hdr.clean();
970
971 /* append <crlf> (we packed a header, not a reply) */
972 mb->append("\r\n", 2);
973 }
974
975 /**
976 * extracts a "range" from *buf and appends them to mb, updating
977 * all offsets and such.
978 */
979 void
980 ClientSocketContext::packRange(StoreIOBuffer const &source, MemBuf * mb)
981 {
982 HttpHdrRangeIter * i = &http->range_iter;
983 Range<int64_t> available (source.range());
984 char const *buf = source.data;
985
986 while (i->currentSpec() && available.size()) {
987 const size_t copy_sz = lengthToSend(available);
988
989 if (copy_sz) {
990 /*
991 * intersection of "have" and "need" ranges must not be empty
992 */
993 assert(http->out.offset < i->currentSpec()->offset + i->currentSpec()->length);
994 assert(http->out.offset + (int64_t)available.size() > i->currentSpec()->offset);
995
996 /*
997 * put boundary and headers at the beginning of a range in a
998 * multi-range
999 */
1000
1001 if (http->multipartRangeRequest() && i->debt() == i->currentSpec()->length) {
1002 assert(http->memObject());
1003 clientPackRangeHdr(
1004 http->memObject()->getReply(), /* original reply */
1005 i->currentSpec(), /* current range */
1006 i->boundary, /* boundary, the same for all */
1007 mb);
1008 }
1009
1010 /*
1011 * append content
1012 */
1013 debugs(33, 3, "clientPackRange: appending " << copy_sz << " bytes");
1014
1015 noteSentBodyBytes (copy_sz);
1016
1017 mb->append(buf, copy_sz);
1018
1019 /*
1020 * update offsets
1021 */
1022 available.start += copy_sz;
1023
1024 buf += copy_sz;
1025
1026 }
1027
1028 if (!canPackMoreRanges()) {
1029 debugs(33, 3, "clientPackRange: Returning because !canPackMoreRanges.");
1030
1031 if (i->debt() == 0)
1032 /* put terminating boundary for multiparts */
1033 clientPackTermBound(i->boundary, mb);
1034
1035 return;
1036 }
1037
1038 int64_t nextOffset = getNextRangeOffset();
1039
1040 assert (nextOffset >= http->out.offset);
1041
1042 int64_t skip = nextOffset - http->out.offset;
1043
1044 /* adjust for not to be transmitted bytes */
1045 http->out.offset = nextOffset;
1046
1047 if (available.size() <= (uint64_t)skip)
1048 return;
1049
1050 available.start += skip;
1051
1052 buf += skip;
1053
1054 if (copy_sz == 0)
1055 return;
1056 }
1057 }
1058
1059 /** returns expected content length for multi-range replies
1060 * note: assumes that httpHdrRangeCanonize has already been called
1061 * warning: assumes that HTTP headers for individual ranges at the
1062 * time of the actuall assembly will be exactly the same as
1063 * the headers when clientMRangeCLen() is called */
1064 int
1065 ClientHttpRequest::mRangeCLen()
1066 {
1067 int64_t clen = 0;
1068 MemBuf mb;
1069
1070 assert(memObject());
1071
1072 mb.init();
1073 HttpHdrRange::iterator pos = request->range->begin();
1074
1075 while (pos != request->range->end()) {
1076 /* account for headers for this range */
1077 mb.reset();
1078 clientPackRangeHdr(memObject()->getReply(),
1079 *pos, range_iter.boundary, &mb);
1080 clen += mb.size;
1081
1082 /* account for range content */
1083 clen += (*pos)->length;
1084
1085 debugs(33, 6, "clientMRangeCLen: (clen += " << mb.size << " + " << (*pos)->length << ") == " << clen);
1086 ++pos;
1087 }
1088
1089 /* account for the terminating boundary */
1090 mb.reset();
1091
1092 clientPackTermBound(range_iter.boundary, &mb);
1093
1094 clen += mb.size;
1095
1096 mb.clean();
1097
1098 return clen;
1099 }
1100
1101 /**
1102 * returns true if If-Range specs match reply, false otherwise
1103 */
1104 static int
1105 clientIfRangeMatch(ClientHttpRequest * http, HttpReply * rep)
1106 {
1107 const TimeOrTag spec = http->request->header.getTimeOrTag(Http::HdrType::IF_RANGE);
1108 /* check for parsing falure */
1109
1110 if (!spec.valid)
1111 return 0;
1112
1113 /* got an ETag? */
1114 if (spec.tag.str) {
1115 ETag rep_tag = rep->header.getETag(Http::HdrType::ETAG);
1116 debugs(33, 3, "clientIfRangeMatch: ETags: " << spec.tag.str << " and " <<
1117 (rep_tag.str ? rep_tag.str : "<none>"));
1118
1119 if (!rep_tag.str)
1120 return 0; /* entity has no etag to compare with! */
1121
1122 if (spec.tag.weak || rep_tag.weak) {
1123 debugs(33, DBG_IMPORTANT, "clientIfRangeMatch: Weak ETags are not allowed in If-Range: " << spec.tag.str << " ? " << rep_tag.str);
1124 return 0; /* must use strong validator for sub-range requests */
1125 }
1126
1127 return etagIsStrongEqual(rep_tag, spec.tag);
1128 }
1129
1130 /* got modification time? */
1131 if (spec.time >= 0) {
1132 return http->storeEntry()->lastmod <= spec.time;
1133 }
1134
1135 assert(0); /* should not happen */
1136 return 0;
1137 }
1138
1139 /**
1140 * generates a "unique" boundary string for multipart responses
1141 * the caller is responsible for cleaning the string */
1142 String
1143 ClientHttpRequest::rangeBoundaryStr() const
1144 {
1145 const char *key;
1146 String b(APP_FULLNAME);
1147 b.append(":",1);
1148 key = storeEntry()->getMD5Text();
1149 b.append(key, strlen(key));
1150 return b;
1151 }
1152
1153 /** adds appropriate Range headers if needed */
1154 void
1155 ClientSocketContext::buildRangeHeader(HttpReply * rep)
1156 {
1157 HttpHeader *hdr = rep ? &rep->header : 0;
1158 const char *range_err = NULL;
1159 HttpRequest *request = http->request;
1160 assert(request->range);
1161 /* check if we still want to do ranges */
1162
1163 int64_t roffLimit = request->getRangeOffsetLimit();
1164
1165 if (!rep)
1166 range_err = "no [parse-able] reply";
1167 else if ((rep->sline.status() != Http::scOkay) && (rep->sline.status() != Http::scPartialContent))
1168 range_err = "wrong status code";
1169 else if (hdr->has(Http::HdrType::CONTENT_RANGE))
1170 range_err = "origin server does ranges";
1171 else if (rep->content_length < 0)
1172 range_err = "unknown length";
1173 else if (rep->content_length != http->memObject()->getReply()->content_length)
1174 range_err = "INCONSISTENT length"; /* a bug? */
1175
1176 /* hits only - upstream CachePeer determines correct behaviour on misses, and client_side_reply determines
1177 * hits candidates
1178 */
1179 else if (http->logType.isTcpHit() && http->request->header.has(Http::HdrType::IF_RANGE) && !clientIfRangeMatch(http, rep))
1180 range_err = "If-Range match failed";
1181 else if (!http->request->range->canonize(rep))
1182 range_err = "canonization failed";
1183 else if (http->request->range->isComplex())
1184 range_err = "too complex range header";
1185 else if (!http->logType.isTcpHit() && http->request->range->offsetLimitExceeded(roffLimit))
1186 range_err = "range outside range_offset_limit";
1187
1188 /* get rid of our range specs on error */
1189 if (range_err) {
1190 /* XXX We do this here because we need canonisation etc. However, this current
1191 * code will lead to incorrect store offset requests - the store will have the
1192 * offset data, but we won't be requesting it.
1193 * So, we can either re-request, or generate an error
1194 */
1195 http->request->ignoreRange(range_err);
1196 } else {
1197 /* XXX: TODO: Review, this unconditional set may be wrong. */
1198 rep->sline.set(rep->sline.version, Http::scPartialContent);
1199 // web server responded with a valid, but unexpected range.
1200 // will (try-to) forward as-is.
1201 //TODO: we should cope with multirange request/responses
1202 bool replyMatchRequest = rep->content_range != NULL ?
1203 request->range->contains(rep->content_range->spec) :
1204 true;
1205 const int spec_count = http->request->range->specs.size();
1206 int64_t actual_clen = -1;
1207
1208 debugs(33, 3, "clientBuildRangeHeader: range spec count: " <<
1209 spec_count << " virgin clen: " << rep->content_length);
1210 assert(spec_count > 0);
1211 /* append appropriate header(s) */
1212
1213 if (spec_count == 1) {
1214 if (!replyMatchRequest) {
1215 hdr->delById(Http::HdrType::CONTENT_RANGE);
1216 hdr->putContRange(rep->content_range);
1217 actual_clen = rep->content_length;
1218 //http->range_iter.pos = rep->content_range->spec.begin();
1219 (*http->range_iter.pos)->offset = rep->content_range->spec.offset;
1220 (*http->range_iter.pos)->length = rep->content_range->spec.length;
1221
1222 } else {
1223 HttpHdrRange::iterator pos = http->request->range->begin();
1224 assert(*pos);
1225 /* append Content-Range */
1226
1227 if (!hdr->has(Http::HdrType::CONTENT_RANGE)) {
1228 /* No content range, so this was a full object we are
1229 * sending parts of.
1230 */
1231 httpHeaderAddContRange(hdr, **pos, rep->content_length);
1232 }
1233
1234 /* set new Content-Length to the actual number of bytes
1235 * transmitted in the message-body */
1236 actual_clen = (*pos)->length;
1237 }
1238 } else {
1239 /* multipart! */
1240 /* generate boundary string */
1241 http->range_iter.boundary = http->rangeBoundaryStr();
1242 /* delete old Content-Type, add ours */
1243 hdr->delById(Http::HdrType::CONTENT_TYPE);
1244 httpHeaderPutStrf(hdr, Http::HdrType::CONTENT_TYPE,
1245 "multipart/byteranges; boundary=\"" SQUIDSTRINGPH "\"",
1246 SQUIDSTRINGPRINT(http->range_iter.boundary));
1247 /* Content-Length is not required in multipart responses
1248 * but it is always nice to have one */
1249 actual_clen = http->mRangeCLen();
1250 /* http->out needs to start where we want data at */
1251 http->out.offset = http->range_iter.currentSpec()->offset;
1252 }
1253
1254 /* replace Content-Length header */
1255 assert(actual_clen >= 0);
1256
1257 hdr->delById(Http::HdrType::CONTENT_LENGTH);
1258
1259 hdr->putInt64(Http::HdrType::CONTENT_LENGTH, actual_clen);
1260
1261 debugs(33, 3, "clientBuildRangeHeader: actual content length: " << actual_clen);
1262
1263 /* And start the range iter off */
1264 http->range_iter.updateSpec();
1265 }
1266 }
1267
1268 void
1269 ClientSocketContext::prepareReply(HttpReply * rep)
1270 {
1271 reply = rep;
1272
1273 if (http->request->range)
1274 buildRangeHeader(rep);
1275 }
1276
1277 void
1278 ClientSocketContext::sendStartOfMessage(HttpReply * rep, StoreIOBuffer bodyData)
1279 {
1280 prepareReply(rep);
1281 assert (rep);
1282 MemBuf *mb = rep->pack();
1283
1284 // dump now, so we dont output any body.
1285 debugs(11, 2, "HTTP Client " << clientConnection);
1286 debugs(11, 2, "HTTP Client REPLY:\n---------\n" << mb->buf << "\n----------");
1287
1288 /* Save length of headers for persistent conn checks */
1289 http->out.headers_sz = mb->contentSize();
1290 #if HEADERS_LOG
1291
1292 headersLog(0, 0, http->request->method, rep);
1293 #endif
1294
1295 if (bodyData.data && bodyData.length) {
1296 if (multipartRangeRequest())
1297 packRange(bodyData, mb);
1298 else if (http->request->flags.chunkedReply) {
1299 packChunk(bodyData, *mb);
1300 } else {
1301 size_t length = lengthToSend(bodyData.range());
1302 noteSentBodyBytes (length);
1303
1304 mb->append(bodyData.data, length);
1305 }
1306 }
1307
1308 /* write */
1309 debugs(33,7, HERE << "sendStartOfMessage schedules clientWriteComplete");
1310 AsyncCall::Pointer call = commCbCall(33, 5, "clientWriteComplete",
1311 CommIoCbPtrFun(clientWriteComplete, this));
1312 Comm::Write(clientConnection, mb, call);
1313 delete mb;
1314 }
1315
1316 /**
1317 * Write a chunk of data to a client socket. If the reply is present,
1318 * send the reply headers down the wire too, and clean them up when
1319 * finished.
1320 * Pre-condition:
1321 * The request is one backed by a connection, not an internal request.
1322 * data context is not NULL
1323 * There are no more entries in the stream chain.
1324 */
1325 void
1326 clientSocketRecipient(clientStreamNode * node, ClientHttpRequest * http,
1327 HttpReply * rep, StoreIOBuffer receivedData)
1328 {
1329 // dont tryt to deliver if client already ABORTED
1330 if (!http->getConn() || !cbdataReferenceValid(http->getConn()) || !Comm::IsConnOpen(http->getConn()->clientConnection))
1331 return;
1332
1333 /* Test preconditions */
1334 assert(node != NULL);
1335 PROF_start(clientSocketRecipient);
1336 /* TODO: handle this rather than asserting
1337 * - it should only ever happen if we cause an abort and
1338 * the callback chain loops back to here, so we can simply return.
1339 * However, that itself shouldn't happen, so it stays as an assert for now.
1340 */
1341 assert(cbdataReferenceValid(node));
1342 assert(node->node.next == NULL);
1343 ClientSocketContext::Pointer context = dynamic_cast<ClientSocketContext *>(node->data.getRaw());
1344 assert(context != NULL);
1345
1346 /* TODO: check offset is what we asked for */
1347
1348 // TODO: enforces HTTP/1 MUST on pipeline order, but is irrelevant to HTTP/2
1349 if (context != http->getConn()->pipeline.front())
1350 context->deferRecipientForLater(node, rep, receivedData);
1351 else
1352 http->getConn()->handleReply(rep, receivedData);
1353
1354 PROF_stop(clientSocketRecipient);
1355 }
1356
1357 /**
1358 * Called when a downstream node is no longer interested in
1359 * our data. As we are a terminal node, this means on aborts
1360 * only
1361 */
1362 void
1363 clientSocketDetach(clientStreamNode * node, ClientHttpRequest * http)
1364 {
1365 /* Test preconditions */
1366 assert(node != NULL);
1367 /* TODO: handle this rather than asserting
1368 * - it should only ever happen if we cause an abort and
1369 * the callback chain loops back to here, so we can simply return.
1370 * However, that itself shouldn't happen, so it stays as an assert for now.
1371 */
1372 assert(cbdataReferenceValid(node));
1373 /* Set null by ContextFree */
1374 assert(node->node.next == NULL);
1375 /* this is the assert discussed above */
1376 assert(NULL == dynamic_cast<ClientSocketContext *>(node->data.getRaw()));
1377 /* We are only called when the client socket shutsdown.
1378 * Tell the prev pipeline member we're finished
1379 */
1380 clientStreamDetach(node, http);
1381 }
1382
1383 static void
1384 clientWriteBodyComplete(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag errflag, int xerrno, void *data)
1385 {
1386 debugs(33,7, "schedule clientWriteComplete");
1387 clientWriteComplete(conn, NULL, size, errflag, xerrno, data);
1388 }
1389
1390 void
1391 ConnStateData::readNextRequest()
1392 {
1393 debugs(33, 5, HERE << clientConnection << " reading next req");
1394
1395 fd_note(clientConnection->fd, "Idle client: Waiting for next request");
1396 /**
1397 * Set the timeout BEFORE calling readSomeData().
1398 */
1399 typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
1400 AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
1401 TimeoutDialer, this, ConnStateData::requestTimeout);
1402 commSetConnTimeout(clientConnection, clientConnection->timeLeft(idleTimeout()), timeoutCall);
1403
1404 readSomeData();
1405 /** Please don't do anything with the FD past here! */
1406 }
1407
1408 static void
1409 ClientSocketContextPushDeferredIfNeeded(ClientSocketContext::Pointer deferredRequest, ConnStateData * conn)
1410 {
1411 debugs(33, 2, HERE << conn->clientConnection << " Sending next");
1412
1413 /** If the client stream is waiting on a socket write to occur, then */
1414
1415 if (deferredRequest->flags.deferred) {
1416 /** NO data is allowed to have been sent. */
1417 assert(deferredRequest->http->out.size == 0);
1418 /** defer now. */
1419 clientSocketRecipient(deferredRequest->deferredparams.node,
1420 deferredRequest->http,
1421 deferredRequest->deferredparams.rep,
1422 deferredRequest->deferredparams.queuedBuffer);
1423 }
1424
1425 /** otherwise, the request is still active in a callbacksomewhere,
1426 * and we are done
1427 */
1428 }
1429
1430 /// called when we have successfully finished writing the response
1431 void
1432 ClientSocketContext::keepaliveNextRequest()
1433 {
1434 debugs(33, 3, "ConnnStateData(" << http->getConn()->clientConnection << "), Context(" << clientConnection << ")");
1435
1436 // mark ourselves as completed
1437 connIsFinished();
1438 }
1439
1440 void
1441 ConnStateData::kick()
1442 {
1443 if (pinning.pinned && !Comm::IsConnOpen(pinning.serverConnection)) {
1444 debugs(33, 2, clientConnection << " Connection was pinned but server side gone. Terminating client connection");
1445 clientConnection->close();
1446 return;
1447 }
1448
1449 /** \par
1450 * We are done with the response, and we are either still receiving request
1451 * body (early response!) or have already stopped receiving anything.
1452 *
1453 * If we are still receiving, then clientParseRequest() below will fail.
1454 * (XXX: but then we will call readNextRequest() which may succeed and
1455 * execute a smuggled request as we are not done with the current request).
1456 *
1457 * If we stopped because we got everything, then try the next request.
1458 *
1459 * If we stopped receiving because of an error, then close now to avoid
1460 * getting stuck and to prevent accidental request smuggling.
1461 */
1462
1463 if (const char *reason = stoppedReceiving()) {
1464 debugs(33, 3, "closing for earlier request error: " << reason);
1465 clientConnection->close();
1466 return;
1467 }
1468
1469 /** \par
1470 * Attempt to parse a request from the request buffer.
1471 * If we've been fed a pipelined request it may already
1472 * be in our read buffer.
1473 *
1474 \par
1475 * This needs to fall through - if we're unlucky and parse the _last_ request
1476 * from our read buffer we may never re-register for another client read.
1477 */
1478
1479 if (clientParseRequests()) {
1480 debugs(33, 3, clientConnection << ": parsed next request from buffer");
1481 }
1482
1483 /** \par
1484 * Either we need to kick-start another read or, if we have
1485 * a half-closed connection, kill it after the last request.
1486 * This saves waiting for half-closed connections to finished being
1487 * half-closed _AND_ then, sometimes, spending "Timeout" time in
1488 * the keepalive "Waiting for next request" state.
1489 */
1490 if (commIsHalfClosed(clientConnection->fd) && pipeline.empty()) {
1491 debugs(33, 3, "half-closed client with no pending requests, closing");
1492 clientConnection->close();
1493 return;
1494 }
1495
1496 /** \par
1497 * At this point we either have a parsed request (which we've
1498 * kicked off the processing for) or not. If we have a deferred
1499 * request (parsed but deferred for pipeling processing reasons)
1500 * then look at processing it. If not, simply kickstart
1501 * another read.
1502 */
1503 ClientSocketContext::Pointer deferredRequest = pipeline.front();
1504 if (deferredRequest != nullptr) {
1505 debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded");
1506 ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
1507 } else if (flags.readMore) {
1508 debugs(33, 3, clientConnection << ": calling readNextRequest()");
1509 readNextRequest();
1510 } else {
1511 // XXX: Can this happen? CONNECT tunnels have deferredRequest set.
1512 debugs(33, DBG_IMPORTANT, MYNAME << "abandoning " << clientConnection);
1513 }
1514 }
1515
1516 void
1517 clientUpdateSocketStats(const LogTags &logType, size_t size)
1518 {
1519 if (size == 0)
1520 return;
1521
1522 statCounter.client_http.kbytes_out += size;
1523
1524 if (logType.isTcpHit())
1525 statCounter.client_http.hit_kbytes_out += size;
1526 }
1527
1528 /**
1529 * increments iterator "i"
1530 * used by clientPackMoreRanges
1531 *
1532 \retval true there is still data available to pack more ranges
1533 \retval false
1534 */
1535 bool
1536 ClientSocketContext::canPackMoreRanges() const
1537 {
1538 /** first update iterator "i" if needed */
1539
1540 if (!http->range_iter.debt()) {
1541 debugs(33, 5, HERE << "At end of current range spec for " << clientConnection);
1542
1543 if (http->range_iter.pos != http->range_iter.end)
1544 ++http->range_iter.pos;
1545
1546 http->range_iter.updateSpec();
1547 }
1548
1549 assert(!http->range_iter.debt() == !http->range_iter.currentSpec());
1550
1551 /* paranoid sync condition */
1552 /* continue condition: need_more_data */
1553 debugs(33, 5, "ClientSocketContext::canPackMoreRanges: returning " << (http->range_iter.currentSpec() ? true : false));
1554 return http->range_iter.currentSpec() ? true : false;
1555 }
1556
1557 int64_t
1558 ClientSocketContext::getNextRangeOffset() const
1559 {
1560 debugs (33, 5, "range: " << http->request->range <<
1561 "; http offset " << http->out.offset <<
1562 "; reply " << reply);
1563
1564 // XXX: This method is called from many places, including pullData() which
1565 // may be called before prepareReply() [on some Squid-generated errors].
1566 // Hence, we may not even know yet whether we should honor/do ranges.
1567
1568 if (http->request->range) {
1569 /* offset in range specs does not count the prefix of an http msg */
1570 /* check: reply was parsed and range iterator was initialized */
1571 assert(http->range_iter.valid);
1572 /* filter out data according to range specs */
1573 assert (canPackMoreRanges());
1574 {
1575 int64_t start; /* offset of still missing data */
1576 assert(http->range_iter.currentSpec());
1577 start = http->range_iter.currentSpec()->offset + http->range_iter.currentSpec()->length - http->range_iter.debt();
1578 debugs(33, 3, "clientPackMoreRanges: in: offset: " << http->out.offset);
1579 debugs(33, 3, "clientPackMoreRanges: out:"
1580 " start: " << start <<
1581 " spec[" << http->range_iter.pos - http->request->range->begin() << "]:" <<
1582 " [" << http->range_iter.currentSpec()->offset <<
1583 ", " << http->range_iter.currentSpec()->offset + http->range_iter.currentSpec()->length << "),"
1584 " len: " << http->range_iter.currentSpec()->length <<
1585 " debt: " << http->range_iter.debt());
1586 if (http->range_iter.currentSpec()->length != -1)
1587 assert(http->out.offset <= start); /* we did not miss it */
1588
1589 return start;
1590 }
1591
1592 } else if (reply && reply->content_range) {
1593 /* request does not have ranges, but reply does */
1594 /** \todo FIXME: should use range_iter_pos on reply, as soon as reply->content_range
1595 * becomes HttpHdrRange rather than HttpHdrRangeSpec.
1596 */
1597 return http->out.offset + reply->content_range->spec.offset;
1598 }
1599
1600 return http->out.offset;
1601 }
1602
1603 void
1604 ClientSocketContext::pullData()
1605 {
1606 debugs(33, 5, reply << " written " << http->out.size << " into " << clientConnection);
1607
1608 /* More data will be coming from the stream. */
1609 StoreIOBuffer readBuffer;
1610 /* XXX: Next requested byte in the range sequence */
1611 /* XXX: length = getmaximumrangelenfgth */
1612 readBuffer.offset = getNextRangeOffset();
1613 readBuffer.length = HTTP_REQBUF_SZ;
1614 readBuffer.data = reqbuf;
1615 /* we may note we have reached the end of the wanted ranges */
1616 clientStreamRead(getTail(), http, readBuffer);
1617 }
1618
1619 /** Adapt stream status to account for Range cases
1620 *
1621 */
1622 clientStream_status_t
1623 ClientSocketContext::socketState()
1624 {
1625 switch (clientStreamStatus(getTail(), http)) {
1626
1627 case STREAM_NONE:
1628 /* check for range support ending */
1629
1630 if (http->request->range) {
1631 /* check: reply was parsed and range iterator was initialized */
1632 assert(http->range_iter.valid);
1633 /* filter out data according to range specs */
1634
1635 if (!canPackMoreRanges()) {
1636 debugs(33, 5, HERE << "Range request at end of returnable " <<
1637 "range sequence on " << clientConnection);
1638 // we got everything we wanted from the store
1639 return STREAM_COMPLETE;
1640 }
1641 } else if (reply && reply->content_range) {
1642 /* reply has content-range, but Squid is not managing ranges */
1643 const int64_t &bytesSent = http->out.offset;
1644 const int64_t &bytesExpected = reply->content_range->spec.length;
1645
1646 debugs(33, 7, HERE << "body bytes sent vs. expected: " <<
1647 bytesSent << " ? " << bytesExpected << " (+" <<
1648 reply->content_range->spec.offset << ")");
1649
1650 // did we get at least what we expected, based on range specs?
1651
1652 if (bytesSent == bytesExpected) // got everything
1653 return STREAM_COMPLETE;
1654
1655 if (bytesSent > bytesExpected) // Error: Sent more than expected
1656 return STREAM_UNPLANNED_COMPLETE;
1657 }
1658
1659 return STREAM_NONE;
1660
1661 case STREAM_COMPLETE:
1662 return STREAM_COMPLETE;
1663
1664 case STREAM_UNPLANNED_COMPLETE:
1665 return STREAM_UNPLANNED_COMPLETE;
1666
1667 case STREAM_FAILED:
1668 return STREAM_FAILED;
1669 }
1670
1671 fatal ("unreachable code\n");
1672 return STREAM_NONE;
1673 }
1674
1675 /**
1676 * A write has just completed to the client, or we have just realised there is
1677 * no more data to send.
1678 */
1679 void
1680 clientWriteComplete(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, Comm::Flag errflag, int, void *data)
1681 {
1682 ClientSocketContext *context = (ClientSocketContext *)data;
1683 context->writeComplete(conn, bufnotused, size, errflag);
1684 }
1685
1686 /// remembers the abnormal connection termination for logging purposes
1687 void
1688 ClientSocketContext::noteIoError(const int xerrno)
1689 {
1690 if (http) {
1691 http->logType.err.timedout = (xerrno == ETIMEDOUT);
1692 // aborted even if xerrno is zero (which means read abort/eof)
1693 http->logType.err.aborted = (xerrno != ETIMEDOUT);
1694 }
1695 }
1696
1697 void
1698 ClientSocketContext::doClose()
1699 {
1700 clientConnection->close();
1701 }
1702
1703 /// called when we encounter a response-related error
1704 void
1705 ClientSocketContext::initiateClose(const char *reason)
1706 {
1707 http->getConn()->stopSending(reason); // closes ASAP
1708 }
1709
1710 void
1711 ConnStateData::stopSending(const char *error)
1712 {
1713 debugs(33, 4, HERE << "sending error (" << clientConnection << "): " << error <<
1714 "; old receiving error: " <<
1715 (stoppedReceiving() ? stoppedReceiving_ : "none"));
1716
1717 if (const char *oldError = stoppedSending()) {
1718 debugs(33, 3, HERE << "already stopped sending: " << oldError);
1719 return; // nothing has changed as far as this connection is concerned
1720 }
1721 stoppedSending_ = error;
1722
1723 if (!stoppedReceiving()) {
1724 if (const int64_t expecting = mayNeedToReadMoreBody()) {
1725 debugs(33, 5, HERE << "must still read " << expecting <<
1726 " request body bytes with " << inBuf.length() << " unused");
1727 return; // wait for the request receiver to finish reading
1728 }
1729 }
1730
1731 clientConnection->close();
1732 }
1733
1734 void
1735 ClientSocketContext::writeComplete(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag errflag)
1736 {
1737 const StoreEntry *entry = http->storeEntry();
1738 http->out.size += size;
1739 debugs(33, 5, HERE << conn << ", sz " << size <<
1740 ", err " << errflag << ", off " << http->out.size << ", len " <<
1741 (entry ? entry->objectLen() : 0));
1742 clientUpdateSocketStats(http->logType, size);
1743
1744 /* Bail out quickly on Comm::ERR_CLOSING - close handlers will tidy up */
1745
1746 if (errflag == Comm::ERR_CLOSING || !Comm::IsConnOpen(conn))
1747 return;
1748
1749 if (errflag || clientHttpRequestStatus(conn->fd, http)) {
1750 initiateClose("failure or true request status");
1751 /* Do we leak here ? */
1752 return;
1753 }
1754
1755 switch (socketState()) {
1756
1757 case STREAM_NONE:
1758 pullData();
1759 break;
1760
1761 case STREAM_COMPLETE:
1762 debugs(33, 5, conn << " Stream complete, keepalive is " << http->request->flags.proxyKeepalive);
1763 if (http->request->flags.proxyKeepalive)
1764 keepaliveNextRequest();
1765 else
1766 initiateClose("STREAM_COMPLETE NOKEEPALIVE");
1767 return;
1768
1769 case STREAM_UNPLANNED_COMPLETE:
1770 initiateClose("STREAM_UNPLANNED_COMPLETE");
1771 return;
1772
1773 case STREAM_FAILED:
1774 initiateClose("STREAM_FAILED");
1775 return;
1776
1777 default:
1778 fatal("Hit unreachable code in clientWriteComplete\n");
1779 }
1780 }
1781
1782 ClientSocketContext *
1783 ConnStateData::abortRequestParsing(const char *const uri)
1784 {
1785 ClientHttpRequest *http = new ClientHttpRequest(this);
1786 http->req_sz = inBuf.length();
1787 http->uri = xstrdup(uri);
1788 setLogUri (http, uri);
1789 ClientSocketContext *context = new ClientSocketContext(clientConnection, http);
1790 StoreIOBuffer tempBuffer;
1791 tempBuffer.data = context->reqbuf;
1792 tempBuffer.length = HTTP_REQBUF_SZ;
1793 clientStreamInit(&http->client_stream, clientGetMoreData, clientReplyDetach,
1794 clientReplyStatus, new clientReplyContext(http), clientSocketRecipient,
1795 clientSocketDetach, context, tempBuffer);
1796 return context;
1797 }
1798
1799 void
1800 ConnStateData::startShutdown()
1801 {
1802 // RegisteredRunner API callback - Squid has been shut down
1803
1804 // if connection is idle terminate it now,
1805 // otherwise wait for grace period to end
1806 if (pipeline.empty())
1807 endingShutdown();
1808 }
1809
1810 void
1811 ConnStateData::endingShutdown()
1812 {
1813 // RegisteredRunner API callback - Squid shutdown grace period is over
1814
1815 // force the client connection to close immediately
1816 // swanSong() in the close handler will cleanup.
1817 if (Comm::IsConnOpen(clientConnection))
1818 clientConnection->close();
1819
1820 // deregister now to ensure finalShutdown() does not kill us prematurely.
1821 // fd_table purge will cleanup if close handler was not fast enough.
1822 DeregisterRunner(this);
1823 }
1824
1825 char *
1826 skipLeadingSpace(char *aString)
1827 {
1828 char *result = aString;
1829
1830 while (xisspace(*aString))
1831 ++aString;
1832
1833 return result;
1834 }
1835
1836 /**
1837 * 'end' defaults to NULL for backwards compatibility
1838 * remove default value if we ever get rid of NULL-terminated
1839 * request buffers.
1840 */
1841 const char *
1842 findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end)
1843 {
1844 if (NULL == end) {
1845 end = uriAndHTTPVersion + strcspn(uriAndHTTPVersion, "\r\n");
1846 assert(end);
1847 }
1848
1849 for (; end > uriAndHTTPVersion; --end) {
1850 if (*end == '\n' || *end == '\r')
1851 continue;
1852
1853 if (xisspace(*end)) {
1854 if (strncasecmp(end + 1, "HTTP/", 5) == 0)
1855 return end + 1;
1856 else
1857 break;
1858 }
1859 }
1860
1861 return NULL;
1862 }
1863
1864 void
1865 setLogUri(ClientHttpRequest * http, char const *uri, bool cleanUrl)
1866 {
1867 safe_free(http->log_uri);
1868
1869 if (!cleanUrl)
1870 // The uri is already clean just dump it.
1871 http->log_uri = xstrndup(uri, MAX_URL);
1872 else {
1873 int flags = 0;
1874 switch (Config.uri_whitespace) {
1875 case URI_WHITESPACE_ALLOW:
1876 flags |= RFC1738_ESCAPE_NOSPACE;
1877
1878 case URI_WHITESPACE_ENCODE:
1879 flags |= RFC1738_ESCAPE_UNESCAPED;
1880 http->log_uri = xstrndup(rfc1738_do_escape(uri, flags), MAX_URL);
1881 break;
1882
1883 case URI_WHITESPACE_CHOP: {
1884 flags |= RFC1738_ESCAPE_NOSPACE;
1885 flags |= RFC1738_ESCAPE_UNESCAPED;
1886 http->log_uri = xstrndup(rfc1738_do_escape(uri, flags), MAX_URL);
1887 int pos = strcspn(http->log_uri, w_space);
1888 http->log_uri[pos] = '\0';
1889 }
1890 break;
1891
1892 case URI_WHITESPACE_DENY:
1893 case URI_WHITESPACE_STRIP:
1894 default: {
1895 const char *t;
1896 char *tmp_uri = static_cast<char*>(xmalloc(strlen(uri) + 1));
1897 char *q = tmp_uri;
1898 t = uri;
1899 while (*t) {
1900 if (!xisspace(*t)) {
1901 *q = *t;
1902 ++q;
1903 }
1904 ++t;
1905 }
1906 *q = '\0';
1907 http->log_uri = xstrndup(rfc1738_escape_unescaped(tmp_uri), MAX_URL);
1908 xfree(tmp_uri);
1909 }
1910 break;
1911 }
1912 }
1913 }
1914
1915 static void
1916 prepareAcceleratedURL(ConnStateData * conn, ClientHttpRequest *http, const Http1::RequestParserPointer &hp)
1917 {
1918 int vhost = conn->port->vhost;
1919 int vport = conn->port->vport;
1920 static char ipbuf[MAX_IPSTRLEN];
1921
1922 http->flags.accel = true;
1923
1924 /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
1925
1926 static const SBuf cache_object("cache_object://");
1927 if (hp->requestUri().startsWith(cache_object))
1928 return; /* already in good shape */
1929
1930 // XXX: re-use proper URL parser for this
1931 SBuf url = hp->requestUri(); // use full provided URI if we abort
1932 do { // use a loop so we can break out of it
1933 ::Parser::Tokenizer tok(url);
1934 if (tok.skip('/')) // origin-form URL already.
1935 break;
1936
1937 if (conn->port->vhost)
1938 return; /* already in good shape */
1939
1940 // skip the URI scheme
1941 static const CharacterSet uriScheme = CharacterSet("URI-scheme","+-.") + CharacterSet::ALPHA + CharacterSet::DIGIT;
1942 static const SBuf uriSchemeEnd("://");
1943 if (!tok.skipAll(uriScheme) || !tok.skip(uriSchemeEnd))
1944 break;
1945
1946 // skip the authority segment
1947 // RFC 3986 complex nested ABNF for "authority" boils down to this:
1948 static const CharacterSet authority = CharacterSet("authority","-._~%:@[]!$&'()*+,;=") +
1949 CharacterSet::HEXDIG + CharacterSet::ALPHA + CharacterSet::DIGIT;
1950 if (!tok.skipAll(authority))
1951 break;
1952
1953 static const SBuf slashUri("/");
1954 const SBuf t = tok.remaining();
1955 if (t.isEmpty())
1956 url = slashUri;
1957 else if (t[0]=='/') // looks like path
1958 url = t;
1959 else if (t[0]=='?' || t[0]=='#') { // looks like query or fragment. fix '/'
1960 url = slashUri;
1961 url.append(t);
1962 } // else do nothing. invalid path
1963
1964 } while(false);
1965
1966 #if SHOULD_REJECT_UNKNOWN_URLS
1967 // reject URI which are not well-formed even after the processing above
1968 if (url.isEmpty() || url[0] != '/') {
1969 hp->parseStatusCode = Http::scBadRequest;
1970 return conn->abortRequestParsing("error:invalid-request");
1971 }
1972 #endif
1973
1974 if (vport < 0)
1975 vport = http->getConn()->clientConnection->local.port();
1976
1977 const bool switchedToHttps = conn->switchedToHttps();
1978 const bool tryHostHeader = vhost || switchedToHttps;
1979 char *host = NULL;
1980 if (tryHostHeader && (host = hp->getHeaderField("Host"))) {
1981 debugs(33, 5, "ACCEL VHOST REWRITE: vhost=" << host << " + vport=" << vport);
1982 char thost[256];
1983 if (vport > 0) {
1984 thost[0] = '\0';
1985 char *t = NULL;
1986 if (host[strlen(host)] != ']' && (t = strrchr(host,':')) != NULL) {
1987 strncpy(thost, host, (t-host));
1988 snprintf(thost+(t-host), sizeof(thost)-(t-host), ":%d", vport);
1989 host = thost;
1990 } else if (!t) {
1991 snprintf(thost, sizeof(thost), "%s:%d",host, vport);
1992 host = thost;
1993 }
1994 } // else nothing to alter port-wise.
1995 const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen + strlen(host);
1996 http->uri = (char *)xcalloc(url_sz, 1);
1997 snprintf(http->uri, url_sz, "%s://%s" SQUIDSBUFPH, AnyP::UriScheme(conn->transferProtocol.protocol).c_str(), host, SQUIDSBUFPRINT(url));
1998 debugs(33, 5, "ACCEL VHOST REWRITE: " << http->uri);
1999 } else if (conn->port->defaultsite /* && !vhost */) {
2000 debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: defaultsite=" << conn->port->defaultsite << " + vport=" << vport);
2001 const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen +
2002 strlen(conn->port->defaultsite);
2003 http->uri = (char *)xcalloc(url_sz, 1);
2004 char vportStr[32];
2005 vportStr[0] = '\0';
2006 if (vport > 0) {
2007 snprintf(vportStr, sizeof(vportStr),":%d",vport);
2008 }
2009 snprintf(http->uri, url_sz, "%s://%s%s" SQUIDSBUFPH,
2010 AnyP::UriScheme(conn->transferProtocol.protocol).c_str(), conn->port->defaultsite, vportStr, SQUIDSBUFPRINT(url));
2011 debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: " << http->uri);
2012 } else if (vport > 0 /* && (!vhost || no Host:) */) {
2013 debugs(33, 5, "ACCEL VPORT REWRITE: *_port IP + vport=" << vport);
2014 /* Put the local socket IP address as the hostname, with whatever vport we found */
2015 const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen;
2016 http->uri = (char *)xcalloc(url_sz, 1);
2017 http->getConn()->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN);
2018 snprintf(http->uri, url_sz, "%s://%s:%d" SQUIDSBUFPH,
2019 AnyP::UriScheme(conn->transferProtocol.protocol).c_str(),
2020 ipbuf, vport, SQUIDSBUFPRINT(url));
2021 debugs(33, 5, "ACCEL VPORT REWRITE: " << http->uri);
2022 }
2023 }
2024
2025 static void
2026 prepareTransparentURL(ConnStateData * conn, ClientHttpRequest *http, const Http1::RequestParserPointer &hp)
2027 {
2028 // TODO Must() on URI !empty when the parser supports throw. For now avoid assert().
2029 if (!hp->requestUri().isEmpty() && hp->requestUri()[0] != '/')
2030 return; /* already in good shape */
2031
2032 /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
2033
2034 if (const char *host = hp->getHeaderField("Host")) {
2035 const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen +
2036 strlen(host);
2037 http->uri = (char *)xcalloc(url_sz, 1);
2038 snprintf(http->uri, url_sz, "%s://%s" SQUIDSBUFPH,
2039 AnyP::UriScheme(conn->transferProtocol.protocol).c_str(), host, SQUIDSBUFPRINT(hp->requestUri()));
2040 debugs(33, 5, "TRANSPARENT HOST REWRITE: " << http->uri);
2041 } else {
2042 /* Put the local socket IP address as the hostname. */
2043 const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen;
2044 http->uri = (char *)xcalloc(url_sz, 1);
2045 static char ipbuf[MAX_IPSTRLEN];
2046 http->getConn()->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN);
2047 snprintf(http->uri, url_sz, "%s://%s:%d" SQUIDSBUFPH,
2048 AnyP::UriScheme(http->getConn()->transferProtocol.protocol).c_str(),
2049 ipbuf, http->getConn()->clientConnection->local.port(), SQUIDSBUFPRINT(hp->requestUri()));
2050 debugs(33, 5, "TRANSPARENT REWRITE: " << http->uri);
2051 }
2052 }
2053
2054 /** Parse an HTTP request
2055 *
2056 * \note Sets result->flags.parsed_ok to 0 if failed to parse the request,
2057 * to 1 if the request was correctly parsed.
2058 * \param[in] csd a ConnStateData. The caller must make sure it is not null
2059 * \param[in] hp an Http1::RequestParser
2060 * \param[out] mehtod_p will be set as a side-effect of the parsing.
2061 * Pointed-to value will be set to Http::METHOD_NONE in case of
2062 * parsing failure
2063 * \param[out] http_ver will be set as a side-effect of the parsing
2064 * \return NULL on incomplete requests,
2065 * a ClientSocketContext structure on success or failure.
2066 */
2067 ClientSocketContext *
2068 parseHttpRequest(ConnStateData *csd, const Http1::RequestParserPointer &hp)
2069 {
2070 /* Attempt to parse the first line; this will define where the method, url, version and header begin */
2071 {
2072 const bool parsedOk = hp->parse(csd->inBuf);
2073
2074 if (csd->port->flags.isIntercepted() && Config.accessList.on_unsupported_protocol)
2075 csd->preservedClientData = csd->inBuf;
2076 // sync the buffers after parsing.
2077 csd->inBuf = hp->remaining();
2078
2079 if (hp->needsMoreData()) {
2080 debugs(33, 5, "Incomplete request, waiting for end of request line");
2081 return NULL;
2082 }
2083
2084 if (!parsedOk) {
2085 if (hp->parseStatusCode == Http::scRequestHeaderFieldsTooLarge || hp->parseStatusCode == Http::scUriTooLong)
2086 return csd->abortRequestParsing("error:request-too-large");
2087
2088 return csd->abortRequestParsing("error:invalid-request");
2089 }
2090 }
2091
2092 /* We know the whole request is in parser now */
2093 debugs(11, 2, "HTTP Client " << csd->clientConnection);
2094 debugs(11, 2, "HTTP Client REQUEST:\n---------\n" <<
2095 hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol() << "\n" <<
2096 hp->mimeHeader() <<
2097 "\n----------");
2098
2099 /* deny CONNECT via accelerated ports */
2100 if (hp->method() == Http::METHOD_CONNECT && csd->port != NULL && csd->port->flags.accelSurrogate) {
2101 debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << csd->transferProtocol << " Accelerator port " << csd->port->s.port());
2102 debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
2103 hp->parseStatusCode = Http::scMethodNotAllowed;
2104 return csd->abortRequestParsing("error:method-not-allowed");
2105 }
2106
2107 /* RFC 7540 section 11.6 registers the method PRI as HTTP/2 specific
2108 * Deny "PRI" method if used in HTTP/1.x or 0.9 versions.
2109 * If seen it signals a broken client or proxy has corrupted the traffic.
2110 */
2111 if (hp->method() == Http::METHOD_PRI && hp->messageProtocol() < Http::ProtocolVersion(2,0)) {
2112 debugs(33, DBG_IMPORTANT, "WARNING: PRI method received on " << csd->transferProtocol << " port " << csd->port->s.port());
2113 debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
2114 hp->parseStatusCode = Http::scMethodNotAllowed;
2115 return csd->abortRequestParsing("error:method-not-allowed");
2116 }
2117
2118 if (hp->method() == Http::METHOD_NONE) {
2119 debugs(33, DBG_IMPORTANT, "WARNING: Unsupported method: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
2120 hp->parseStatusCode = Http::scMethodNotAllowed;
2121 return csd->abortRequestParsing("error:unsupported-request-method");
2122 }
2123
2124 // Process headers after request line
2125 debugs(33, 3, "complete request received. " <<
2126 "prefix_sz = " << hp->messageHeaderSize() <<
2127 ", request-line-size=" << hp->firstLineSize() <<
2128 ", mime-header-size=" << hp->headerBlockSize() <<
2129 ", mime header block:\n" << hp->mimeHeader() << "\n----------");
2130
2131 /* Ok, all headers are received */
2132 ClientHttpRequest *http = new ClientHttpRequest(csd);
2133
2134 http->req_sz = hp->messageHeaderSize();
2135 ClientSocketContext *result = new ClientSocketContext(csd->clientConnection, http);
2136
2137 StoreIOBuffer tempBuffer;
2138 tempBuffer.data = result->reqbuf;
2139 tempBuffer.length = HTTP_REQBUF_SZ;
2140
2141 ClientStreamData newServer = new clientReplyContext(http);
2142 ClientStreamData newClient = result;
2143 clientStreamInit(&http->client_stream, clientGetMoreData, clientReplyDetach,
2144 clientReplyStatus, newServer, clientSocketRecipient,
2145 clientSocketDetach, newClient, tempBuffer);
2146
2147 /* set url */
2148 debugs(33,5, "Prepare absolute URL from " <<
2149 (csd->transparent()?"intercept":(csd->port->flags.accelSurrogate ? "accel":"")));
2150 /* Rewrite the URL in transparent or accelerator mode */
2151 /* NP: there are several cases to traverse here:
2152 * - standard mode (forward proxy)
2153 * - transparent mode (TPROXY)
2154 * - transparent mode with failures
2155 * - intercept mode (NAT)
2156 * - intercept mode with failures
2157 * - accelerator mode (reverse proxy)
2158 * - internal relative-URL
2159 * - mixed combos of the above with internal URL
2160 * - remote interception with PROXY protocol
2161 * - remote reverse-proxy with PROXY protocol
2162 */
2163 if (csd->transparent()) {
2164 /* intercept or transparent mode, properly working with no failures */
2165 prepareTransparentURL(csd, http, hp);
2166
2167 } else if (internalCheck(hp->requestUri())) { // NP: only matches relative-URI
2168 /* internal URL mode */
2169 /* prepend our name & port */
2170 http->uri = xstrdup(internalLocalUri(NULL, hp->requestUri()));
2171 // We just re-wrote the URL. Must replace the Host: header.
2172 // But have not parsed there yet!! flag for local-only handling.
2173 http->flags.internal = true;
2174
2175 } else if (csd->port->flags.accelSurrogate || csd->switchedToHttps()) {
2176 /* accelerator mode */
2177 prepareAcceleratedURL(csd, http, hp);
2178 }
2179
2180 if (!http->uri) {
2181 /* No special rewrites have been applied above, use the
2182 * requested url. may be rewritten later, so make extra room */
2183 int url_sz = hp->requestUri().length() + Config.appendDomainLen + 5;
2184 http->uri = (char *)xcalloc(url_sz, 1);
2185 SBufToCstring(http->uri, hp->requestUri());
2186 }
2187
2188 result->flags.parsed_ok = 1;
2189 return result;
2190 }
2191
2192 bool
2193 ConnStateData::connFinishedWithConn(int size)
2194 {
2195 if (size == 0) {
2196 if (pipeline.empty() && inBuf.isEmpty()) {
2197 /* no current or pending requests */
2198 debugs(33, 4, HERE << clientConnection << " closed");
2199 return true;
2200 } else if (!Config.onoff.half_closed_clients) {
2201 /* admin doesn't want to support half-closed client sockets */
2202 debugs(33, 3, HERE << clientConnection << " aborted (half_closed_clients disabled)");
2203 pipeline.terminateAll(0);
2204 return true;
2205 }
2206 }
2207
2208 return false;
2209 }
2210
2211 void
2212 ConnStateData::consumeInput(const size_t byteCount)
2213 {
2214 assert(byteCount > 0 && byteCount <= inBuf.length());
2215 inBuf.consume(byteCount);
2216 debugs(33, 5, "inBuf has " << inBuf.length() << " unused bytes");
2217 }
2218
2219 void
2220 ConnStateData::clientAfterReadingRequests()
2221 {
2222 // Were we expecting to read more request body from half-closed connection?
2223 if (mayNeedToReadMoreBody() && commIsHalfClosed(clientConnection->fd)) {
2224 debugs(33, 3, HERE << "truncated body: closing half-closed " << clientConnection);
2225 clientConnection->close();
2226 return;
2227 }
2228
2229 if (flags.readMore)
2230 readSomeData();
2231 }
2232
2233 void
2234 ConnStateData::quitAfterError(HttpRequest *request)
2235 {
2236 // From HTTP p.o.v., we do not have to close after every error detected
2237 // at the client-side, but many such errors do require closure and the
2238 // client-side code is bad at handling errors so we play it safe.
2239 if (request)
2240 request->flags.proxyKeepalive = false;
2241 flags.readMore = false;
2242 debugs(33,4, HERE << "Will close after error: " << clientConnection);
2243 }
2244
2245 #if USE_OPENSSL
2246 bool ConnStateData::serveDelayedError(ClientSocketContext *context)
2247 {
2248 ClientHttpRequest *http = context->http;
2249
2250 if (!sslServerBump)
2251 return false;
2252
2253 assert(sslServerBump->entry);
2254 // Did we create an error entry while processing CONNECT?
2255 if (!sslServerBump->entry->isEmpty()) {
2256 quitAfterError(http->request);
2257
2258 // Get the saved error entry and send it to the client by replacing the
2259 // ClientHttpRequest store entry with it.
2260 clientStreamNode *node = context->getClientReplyContext();
2261 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
2262 assert(repContext);
2263 debugs(33, 5, "Responding with delated error for " << http->uri);
2264 repContext->setReplyToStoreEntry(sslServerBump->entry, "delayed SslBump error");
2265
2266 // save the original request for logging purposes
2267 if (!context->http->al->request) {
2268 context->http->al->request = http->request;
2269 HTTPMSGLOCK(context->http->al->request);
2270 }
2271
2272 // Get error details from the fake certificate-peeking request.
2273 http->request->detailError(sslServerBump->request->errType, sslServerBump->request->errDetail);
2274 context->pullData();
2275 return true;
2276 }
2277
2278 // In bump-server-first mode, we have not necessarily seen the intended
2279 // server name at certificate-peeking time. Check for domain mismatch now,
2280 // when we can extract the intended name from the bumped HTTP request.
2281 if (X509 *srvCert = sslServerBump->serverCert.get()) {
2282 HttpRequest *request = http->request;
2283 if (!Ssl::checkX509ServerValidity(srvCert, request->url.host())) {
2284 debugs(33, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " <<
2285 "does not match domainname " << request->url.host());
2286
2287 bool allowDomainMismatch = false;
2288 if (Config.ssl_client.cert_error) {
2289 ACLFilledChecklist check(Config.ssl_client.cert_error, request, dash_str);
2290 check.sslErrors = new Ssl::CertErrors(Ssl::CertError(SQUID_X509_V_ERR_DOMAIN_MISMATCH, srvCert));
2291 allowDomainMismatch = (check.fastCheck() == ACCESS_ALLOWED);
2292 delete check.sslErrors;
2293 check.sslErrors = NULL;
2294 }
2295
2296 if (!allowDomainMismatch) {
2297 quitAfterError(request);
2298
2299 clientStreamNode *node = context->getClientReplyContext();
2300 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
2301 assert (repContext);
2302
2303 // Fill the server IP and hostname for error page generation.
2304 HttpRequest::Pointer const & peekerRequest = sslServerBump->request;
2305 request->hier.note(peekerRequest->hier.tcpServer, request->url.host());
2306
2307 // Create an error object and fill it
2308 ErrorState *err = new ErrorState(ERR_SECURE_CONNECT_FAIL, Http::scServiceUnavailable, request);
2309 err->src_addr = clientConnection->remote;
2310 Ssl::ErrorDetail *errDetail = new Ssl::ErrorDetail(
2311 SQUID_X509_V_ERR_DOMAIN_MISMATCH,
2312 srvCert, NULL);
2313 err->detail = errDetail;
2314 // Save the original request for logging purposes.
2315 if (!context->http->al->request) {
2316 context->http->al->request = request;
2317 HTTPMSGLOCK(context->http->al->request);
2318 }
2319 repContext->setReplyToError(request->method, err);
2320 assert(context->http->out.offset == 0);
2321 context->pullData();
2322 return true;
2323 }
2324 }
2325 }
2326
2327 return false;
2328 }
2329 #endif // USE_OPENSSL
2330
2331 /**
2332 * Check on_unsupported_protocol checklist and return true if tunnel mode selected
2333 * or false otherwise
2334 */
2335 bool
2336 clientTunnelOnError(ConnStateData *conn, ClientSocketContext *context, HttpRequest *request, const HttpRequestMethod& method, err_type requestError, Http::StatusCode errStatusCode, const char *requestErrorBytes)
2337 {
2338 if (conn->port->flags.isIntercepted() &&
2339 Config.accessList.on_unsupported_protocol && conn->pipeline.nrequests <= 1) {
2340 ACLFilledChecklist checklist(Config.accessList.on_unsupported_protocol, request, NULL);
2341 checklist.requestErrorType = requestError;
2342 checklist.src_addr = conn->clientConnection->remote;
2343 checklist.my_addr = conn->clientConnection->local;
2344 checklist.conn(conn);
2345 allow_t answer = checklist.fastCheck();
2346 if (answer == ACCESS_ALLOWED && answer.kind == 1) {
2347 debugs(33, 3, "Request will be tunneled to server");
2348 if (context) {
2349 assert(conn->pipeline.front() == context); // XXX: still assumes HTTP/1 semantics
2350 conn->pipeline.pop();
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 if (MAXTCPLISTENPORTS == NHttpSockets) {
4176 debugs(1, DBG_IMPORTANT, "WARNING: You have too many 'http_port' lines.");
4177 debugs(1, DBG_IMPORTANT, " The limit is " << MAXTCPLISTENPORTS << " HTTP ports.");
4178 continue;
4179 }
4180
4181 #if USE_OPENSSL
4182 if (s->flags.tunnelSslBumping && !Config.accessList.ssl_bump) {
4183 debugs(33, DBG_IMPORTANT, "WARNING: No ssl_bump configured. Disabling ssl-bump on " << AnyP::UriScheme(s->transport.protocol) << "_port " << s->s);
4184 s->flags.tunnelSslBumping = false;
4185 }
4186
4187 if (s->flags.tunnelSslBumping &&
4188 !s->staticSslContext &&
4189 !s->generateHostCertificates) {
4190 debugs(1, DBG_IMPORTANT, "Will not bump SSL at http_port " << s->s << " due to SSL initialization failure.");
4191 s->flags.tunnelSslBumping = false;
4192 }
4193 if (s->flags.tunnelSslBumping) {
4194 // Create ssl_ctx cache for this port.
4195 Ssl::TheGlobalContextStorage.addLocalStorage(s->s, s->dynamicCertMemCacheSize == std::numeric_limits<size_t>::max() ? 4194304 : s->dynamicCertMemCacheSize);
4196 }
4197 #endif
4198
4199 // Fill out a Comm::Connection which IPC will open as a listener for us
4200 // then pass back when active so we can start a TcpAcceptor subscription.
4201 s->listenConn = new Comm::Connection;
4202 s->listenConn->local = s->s;
4203 s->listenConn->flags = COMM_NONBLOCKING | (s->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) | (s->flags.natIntercept ? COMM_INTERCEPTION : 0);
4204
4205 // setup the subscriptions such that new connections accepted by listenConn are handled by HTTP
4206 typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
4207 RefCount<AcceptCall> subCall = commCbCall(5, 5, "httpAccept", CommAcceptCbPtrFun(httpAccept, CommAcceptCbParams(NULL)));
4208 Subscription::Pointer sub = new CallSubscription<AcceptCall>(subCall);
4209
4210 AsyncCall::Pointer listenCall = asyncCall(33,2, "clientListenerConnectionOpened",
4211 ListeningStartedDialer(&clientListenerConnectionOpened, s, Ipc::fdnHttpSocket, sub));
4212 Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpSocket, listenCall);
4213
4214 HttpSockets[NHttpSockets] = -1; // set in clientListenerConnectionOpened
4215 ++NHttpSockets;
4216 }
4217 }
4218
4219 #if USE_OPENSSL
4220 static void
4221 clientHttpsConnectionsOpen(void)
4222 {
4223 for (AnyP::PortCfgPointer s = HttpsPortList; s != NULL; s = s->next) {
4224 if (MAXTCPLISTENPORTS == NHttpSockets) {
4225 debugs(1, DBG_IMPORTANT, "Ignoring 'https_port' lines exceeding the limit.");
4226 debugs(1, DBG_IMPORTANT, "The limit is " << MAXTCPLISTENPORTS << " HTTPS ports.");
4227 continue;
4228 }
4229
4230 if (!s->staticSslContext) {
4231 debugs(1, DBG_IMPORTANT, "Ignoring https_port " << s->s <<
4232 " due to SSL initialization failure.");
4233 continue;
4234 }
4235
4236 // TODO: merge with similar code in clientHttpConnectionsOpen()
4237 if (s->flags.tunnelSslBumping && !Config.accessList.ssl_bump) {
4238 debugs(33, DBG_IMPORTANT, "WARNING: No ssl_bump configured. Disabling ssl-bump on " << AnyP::UriScheme(s->transport.protocol) << "_port " << s->s);
4239 s->flags.tunnelSslBumping = false;
4240 }
4241
4242 if (s->flags.tunnelSslBumping && !s->staticSslContext && !s->generateHostCertificates) {
4243 debugs(1, DBG_IMPORTANT, "Will not bump SSL at https_port " << s->s << " due to SSL initialization failure.");
4244 s->flags.tunnelSslBumping = false;
4245 }
4246
4247 if (s->flags.tunnelSslBumping) {
4248 // Create ssl_ctx cache for this port.
4249 Ssl::TheGlobalContextStorage.addLocalStorage(s->s, s->dynamicCertMemCacheSize == std::numeric_limits<size_t>::max() ? 4194304 : s->dynamicCertMemCacheSize);
4250 }
4251
4252 // Fill out a Comm::Connection which IPC will open as a listener for us
4253 s->listenConn = new Comm::Connection;
4254 s->listenConn->local = s->s;
4255 s->listenConn->flags = COMM_NONBLOCKING | (s->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) |
4256 (s->flags.natIntercept ? COMM_INTERCEPTION : 0);
4257
4258 // setup the subscriptions such that new connections accepted by listenConn are handled by HTTPS
4259 typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
4260 RefCount<AcceptCall> subCall = commCbCall(5, 5, "httpsAccept", CommAcceptCbPtrFun(httpsAccept, CommAcceptCbParams(NULL)));
4261 Subscription::Pointer sub = new CallSubscription<AcceptCall>(subCall);
4262
4263 AsyncCall::Pointer listenCall = asyncCall(33, 2, "clientListenerConnectionOpened",
4264 ListeningStartedDialer(&clientListenerConnectionOpened,
4265 s, Ipc::fdnHttpsSocket, sub));
4266 Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpsSocket, listenCall);
4267 HttpSockets[NHttpSockets] = -1;
4268 ++NHttpSockets;
4269 }
4270 }
4271 #endif
4272
4273 void
4274 clientStartListeningOn(AnyP::PortCfgPointer &port, const RefCount< CommCbFunPtrCallT<CommAcceptCbPtrFun> > &subCall, const Ipc::FdNoteId fdNote)
4275 {
4276 // Fill out a Comm::Connection which IPC will open as a listener for us
4277 port->listenConn = new Comm::Connection;
4278 port->listenConn->local = port->s;
4279 port->listenConn->flags =
4280 COMM_NONBLOCKING |
4281 (port->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) |
4282 (port->flags.natIntercept ? COMM_INTERCEPTION : 0);
4283
4284 // route new connections to subCall
4285 typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
4286 Subscription::Pointer sub = new CallSubscription<AcceptCall>(subCall);
4287 AsyncCall::Pointer listenCall =
4288 asyncCall(33, 2, "clientListenerConnectionOpened",
4289 ListeningStartedDialer(&clientListenerConnectionOpened,
4290 port, fdNote, sub));
4291 Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, port->listenConn, fdNote, listenCall);
4292
4293 assert(NHttpSockets < MAXTCPLISTENPORTS);
4294 HttpSockets[NHttpSockets] = -1;
4295 ++NHttpSockets;
4296 }
4297
4298 /// process clientHttpConnectionsOpen result
4299 static void
4300 clientListenerConnectionOpened(AnyP::PortCfgPointer &s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub)
4301 {
4302 Must(s != NULL);
4303
4304 if (!OpenedHttpSocket(s->listenConn, portTypeNote))
4305 return;
4306
4307 Must(Comm::IsConnOpen(s->listenConn));
4308
4309 // TCP: setup a job to handle accept() with subscribed handler
4310 AsyncJob::Start(new Comm::TcpAcceptor(s, FdNote(portTypeNote), sub));
4311
4312 debugs(1, DBG_IMPORTANT, "Accepting " <<
4313 (s->flags.natIntercept ? "NAT intercepted " : "") <<
4314 (s->flags.tproxyIntercept ? "TPROXY intercepted " : "") <<
4315 (s->flags.tunnelSslBumping ? "SSL bumped " : "") <<
4316 (s->flags.accelSurrogate ? "reverse-proxy " : "")
4317 << FdNote(portTypeNote) << " connections at "
4318 << s->listenConn);
4319
4320 Must(AddOpenedHttpSocket(s->listenConn)); // otherwise, we have received a fd we did not ask for
4321 }
4322
4323 void
4324 clientOpenListenSockets(void)
4325 {
4326 clientHttpConnectionsOpen();
4327 #if USE_OPENSSL
4328 clientHttpsConnectionsOpen();
4329 #endif
4330 Ftp::StartListening();
4331
4332 if (NHttpSockets < 1)
4333 fatal("No HTTP, HTTPS, or FTP ports configured");
4334 }
4335
4336 void
4337 clientConnectionsClose()
4338 {
4339 for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) {
4340 if (s->listenConn != NULL) {
4341 debugs(1, DBG_IMPORTANT, "Closing HTTP port " << s->listenConn->local);
4342 s->listenConn->close();
4343 s->listenConn = NULL;
4344 }
4345 }
4346
4347 #if USE_OPENSSL
4348 for (AnyP::PortCfgPointer s = HttpsPortList; s != NULL; s = s->next) {
4349 if (s->listenConn != NULL) {
4350 debugs(1, DBG_IMPORTANT, "Closing HTTPS port " << s->listenConn->local);
4351 s->listenConn->close();
4352 s->listenConn = NULL;
4353 }
4354 }
4355 #endif
4356
4357 Ftp::StopListening();
4358
4359 // TODO see if we can drop HttpSockets array entirely */
4360 for (int i = 0; i < NHttpSockets; ++i) {
4361 HttpSockets[i] = -1;
4362 }
4363
4364 NHttpSockets = 0;
4365 }
4366
4367 int
4368 varyEvaluateMatch(StoreEntry * entry, HttpRequest * request)
4369 {
4370 const char *vary = request->vary_headers;
4371 int has_vary = entry->getReply()->header.has(Http::HdrType::VARY);
4372 #if X_ACCELERATOR_VARY
4373
4374 has_vary |=
4375 entry->getReply()->header.has(Http::HdrType::HDR_X_ACCELERATOR_VARY);
4376 #endif
4377
4378 if (!has_vary || !entry->mem_obj->vary_headers) {
4379 if (vary) {
4380 /* Oops... something odd is going on here.. */
4381 debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary object on second attempt, '" <<
4382 entry->mem_obj->urlXXX() << "' '" << vary << "'");
4383 safe_free(request->vary_headers);
4384 return VARY_CANCEL;
4385 }
4386
4387 if (!has_vary) {
4388 /* This is not a varying object */
4389 return VARY_NONE;
4390 }
4391
4392 /* virtual "vary" object found. Calculate the vary key and
4393 * continue the search
4394 */
4395 vary = httpMakeVaryMark(request, entry->getReply());
4396
4397 if (vary) {
4398 request->vary_headers = xstrdup(vary);
4399 return VARY_OTHER;
4400 } else {
4401 /* Ouch.. we cannot handle this kind of variance */
4402 /* XXX This cannot really happen, but just to be complete */
4403 return VARY_CANCEL;
4404 }
4405 } else {
4406 if (!vary) {
4407 vary = httpMakeVaryMark(request, entry->getReply());
4408
4409 if (vary)
4410 request->vary_headers = xstrdup(vary);
4411 }
4412
4413 if (!vary) {
4414 /* Ouch.. we cannot handle this kind of variance */
4415 /* XXX This cannot really happen, but just to be complete */
4416 return VARY_CANCEL;
4417 } else if (strcmp(vary, entry->mem_obj->vary_headers) == 0) {
4418 return VARY_MATCH;
4419 } else {
4420 /* Oops.. we have already been here and still haven't
4421 * found the requested variant. Bail out
4422 */
4423 debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary match on second attempt, '" <<
4424 entry->mem_obj->urlXXX() << "' '" << vary << "'");
4425 return VARY_CANCEL;
4426 }
4427 }
4428 }
4429
4430 ACLFilledChecklist *
4431 clientAclChecklistCreate(const acl_access * acl, ClientHttpRequest * http)
4432 {
4433 ConnStateData * conn = http->getConn();
4434 ACLFilledChecklist *ch = new ACLFilledChecklist(acl, http->request,
4435 cbdataReferenceValid(conn) && conn != NULL && conn->clientConnection != NULL ? conn->clientConnection->rfc931 : dash_str);
4436 ch->al = http->al;
4437 /*
4438 * hack for ident ACL. It needs to get full addresses, and a place to store
4439 * the ident result on persistent connections...
4440 */
4441 /* connection oriented auth also needs these two lines for it's operation. */
4442 return ch;
4443 }
4444
4445 bool
4446 ConnStateData::transparent() const
4447 {
4448 return clientConnection != NULL && (clientConnection->flags & (COMM_TRANSPARENT|COMM_INTERCEPTION));
4449 }
4450
4451 BodyPipe::Pointer
4452 ConnStateData::expectRequestBody(int64_t size)
4453 {
4454 bodyPipe = new BodyPipe(this);
4455 if (size >= 0)
4456 bodyPipe->setBodySize(size);
4457 else
4458 startDechunkingRequest();
4459 return bodyPipe;
4460 }
4461
4462 int64_t
4463 ConnStateData::mayNeedToReadMoreBody() const
4464 {
4465 if (!bodyPipe)
4466 return 0; // request without a body or read/produced all body bytes
4467
4468 if (!bodyPipe->bodySizeKnown())
4469 return -1; // probably need to read more, but we cannot be sure
4470
4471 const int64_t needToProduce = bodyPipe->unproducedSize();
4472 const int64_t haveAvailable = static_cast<int64_t>(inBuf.length());
4473
4474 if (needToProduce <= haveAvailable)
4475 return 0; // we have read what we need (but are waiting for pipe space)
4476
4477 return needToProduce - haveAvailable;
4478 }
4479
4480 void
4481 ConnStateData::stopReceiving(const char *error)
4482 {
4483 debugs(33, 4, HERE << "receiving error (" << clientConnection << "): " << error <<
4484 "; old sending error: " <<
4485 (stoppedSending() ? stoppedSending_ : "none"));
4486
4487 if (const char *oldError = stoppedReceiving()) {
4488 debugs(33, 3, HERE << "already stopped receiving: " << oldError);
4489 return; // nothing has changed as far as this connection is concerned
4490 }
4491
4492 stoppedReceiving_ = error;
4493
4494 if (const char *sendError = stoppedSending()) {
4495 debugs(33, 3, HERE << "closing because also stopped sending: " << sendError);
4496 clientConnection->close();
4497 }
4498 }
4499
4500 void
4501 ConnStateData::expectNoForwarding()
4502 {
4503 if (bodyPipe != NULL) {
4504 debugs(33, 4, HERE << "no consumer for virgin body " << bodyPipe->status());
4505 bodyPipe->expectNoConsumption();
4506 }
4507 }
4508
4509 /// initialize dechunking state
4510 void
4511 ConnStateData::startDechunkingRequest()
4512 {
4513 Must(bodyPipe != NULL);
4514 debugs(33, 5, HERE << "start dechunking" << bodyPipe->status());
4515 assert(!bodyParser);
4516 bodyParser = new Http1::TeChunkedParser;
4517 }
4518
4519 /// put parsed content into input buffer and clean up
4520 void
4521 ConnStateData::finishDechunkingRequest(bool withSuccess)
4522 {
4523 debugs(33, 5, HERE << "finish dechunking: " << withSuccess);
4524
4525 if (bodyPipe != NULL) {
4526 debugs(33, 7, HERE << "dechunked tail: " << bodyPipe->status());
4527 BodyPipe::Pointer myPipe = bodyPipe;
4528 stopProducingFor(bodyPipe, withSuccess); // sets bodyPipe->bodySize()
4529 Must(!bodyPipe); // we rely on it being nil after we are done with body
4530 if (withSuccess) {
4531 Must(myPipe->bodySizeKnown());
4532 ClientSocketContext::Pointer context = pipeline.front();
4533 if (context != NULL && context->http && context->http->request)
4534 context->http->request->setContentLength(myPipe->bodySize());
4535 }
4536 }
4537
4538 delete bodyParser;
4539 bodyParser = NULL;
4540 }
4541
4542 // XXX: this is an HTTP/1-only operation
4543 void
4544 ConnStateData::sendControlMsg(HttpControlMsg msg)
4545 {
4546 if (!isOpen()) {
4547 debugs(33, 3, HERE << "ignoring 1xx due to earlier closure");
4548 return;
4549 }
4550
4551 if (!pipeline.empty()) {
4552 pipeline.front()->writeControlMsg(msg); // will call msg.cbSuccess
4553 return;
4554 }
4555
4556 debugs(33, 3, HERE << " closing due to missing context for 1xx");
4557 clientConnection->close();
4558 }
4559
4560 /// Our close handler called by Comm when the pinned connection is closed
4561 void
4562 ConnStateData::clientPinnedConnectionClosed(const CommCloseCbParams &io)
4563 {
4564 // FwdState might repin a failed connection sooner than this close
4565 // callback is called for the failed connection.
4566 assert(pinning.serverConnection == io.conn);
4567 pinning.closeHandler = NULL; // Comm unregisters handlers before calling
4568 const bool sawZeroReply = pinning.zeroReply; // reset when unpinning
4569 pinning.serverConnection->noteClosure();
4570 unpinConnection(false);
4571
4572 if (sawZeroReply && clientConnection != NULL) {
4573 debugs(33, 3, "Closing client connection on pinned zero reply.");
4574 clientConnection->close();
4575 }
4576
4577 }
4578
4579 void
4580 ConnStateData::pinConnection(const Comm::ConnectionPointer &pinServer, HttpRequest *request, CachePeer *aPeer, bool auth, bool monitor)
4581 {
4582 if (!Comm::IsConnOpen(pinning.serverConnection) ||
4583 pinning.serverConnection->fd != pinServer->fd)
4584 pinNewConnection(pinServer, request, aPeer, auth);
4585
4586 if (monitor)
4587 startPinnedConnectionMonitoring();
4588 }
4589
4590 void
4591 ConnStateData::pinNewConnection(const Comm::ConnectionPointer &pinServer, HttpRequest *request, CachePeer *aPeer, bool auth)
4592 {
4593 unpinConnection(true); // closes pinned connection, if any, and resets fields
4594
4595 pinning.serverConnection = pinServer;
4596
4597 debugs(33, 3, HERE << pinning.serverConnection);
4598
4599 Must(pinning.serverConnection != NULL);
4600
4601 // when pinning an SSL bumped connection, the request may be NULL
4602 const char *pinnedHost = "[unknown]";
4603 if (request) {
4604 pinning.host = xstrdup(request->url.host());
4605 pinning.port = request->url.port();
4606 pinnedHost = pinning.host;
4607 } else {
4608 pinning.port = pinServer->remote.port();
4609 }
4610 pinning.pinned = true;
4611 if (aPeer)
4612 pinning.peer = cbdataReference(aPeer);
4613 pinning.auth = auth;
4614 char stmp[MAX_IPSTRLEN];
4615 char desc[FD_DESC_SZ];
4616 snprintf(desc, FD_DESC_SZ, "%s pinned connection for %s (%d)",
4617 (auth || !aPeer) ? pinnedHost : aPeer->name,
4618 clientConnection->remote.toUrl(stmp,MAX_IPSTRLEN),
4619 clientConnection->fd);
4620 fd_note(pinning.serverConnection->fd, desc);
4621
4622 typedef CommCbMemFunT<ConnStateData, CommCloseCbParams> Dialer;
4623 pinning.closeHandler = JobCallback(33, 5,
4624 Dialer, this, ConnStateData::clientPinnedConnectionClosed);
4625 // remember the pinned connection so that cb does not unpin a fresher one
4626 typedef CommCloseCbParams Params;
4627 Params &params = GetCommParams<Params>(pinning.closeHandler);
4628 params.conn = pinning.serverConnection;
4629 comm_add_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
4630 }
4631
4632 /// [re]start monitoring pinned connection for peer closures so that we can
4633 /// propagate them to an _idle_ client pinned to that peer
4634 void
4635 ConnStateData::startPinnedConnectionMonitoring()
4636 {
4637 if (pinning.readHandler != NULL)
4638 return; // already monitoring
4639
4640 typedef CommCbMemFunT<ConnStateData, CommIoCbParams> Dialer;
4641 pinning.readHandler = JobCallback(33, 3,
4642 Dialer, this, ConnStateData::clientPinnedConnectionRead);
4643 Comm::Read(pinning.serverConnection, pinning.readHandler);
4644 }
4645
4646 void
4647 ConnStateData::stopPinnedConnectionMonitoring()
4648 {
4649 if (pinning.readHandler != NULL) {
4650 Comm::ReadCancel(pinning.serverConnection->fd, pinning.readHandler);
4651 pinning.readHandler = NULL;
4652 }
4653 }
4654
4655 #if USE_OPENSSL
4656 bool
4657 ConnStateData::handleIdleClientPinnedTlsRead()
4658 {
4659 // A ready-for-reading connection means that the TLS server either closed
4660 // the connection, sent us some unexpected HTTP data, or started TLS
4661 // renegotiations. We should close the connection except for the last case.
4662
4663 Must(pinning.serverConnection != nullptr);
4664 SSL *ssl = fd_table[pinning.serverConnection->fd].ssl;
4665 if (!ssl)
4666 return false;
4667
4668 char buf[1];
4669 const int readResult = SSL_read(ssl, buf, sizeof(buf));
4670
4671 if (readResult > 0 || SSL_pending(ssl) > 0) {
4672 debugs(83, 2, pinning.serverConnection << " TLS application data read");
4673 return false;
4674 }
4675
4676 switch(const int error = SSL_get_error(ssl, readResult)) {
4677 case SSL_ERROR_WANT_WRITE:
4678 debugs(83, DBG_IMPORTANT, pinning.serverConnection << " TLS SSL_ERROR_WANT_WRITE request for idle pinned connection");
4679 // fall through to restart monitoring, for now
4680 case SSL_ERROR_NONE:
4681 case SSL_ERROR_WANT_READ:
4682 startPinnedConnectionMonitoring();
4683 return true;
4684
4685 default:
4686 debugs(83, 2, pinning.serverConnection << " TLS error: " << error);
4687 return false;
4688 }
4689
4690 // not reached
4691 return true;
4692 }
4693 #endif
4694
4695 /// Our read handler called by Comm when the server either closes an idle pinned connection or
4696 /// perhaps unexpectedly sends something on that idle (from Squid p.o.v.) connection.
4697 void
4698 ConnStateData::clientPinnedConnectionRead(const CommIoCbParams &io)
4699 {
4700 pinning.readHandler = NULL; // Comm unregisters handlers before calling
4701
4702 if (io.flag == Comm::ERR_CLOSING)
4703 return; // close handler will clean up
4704
4705 Must(pinning.serverConnection == io.conn);
4706
4707 #if USE_OPENSSL
4708 if (handleIdleClientPinnedTlsRead())
4709 return;
4710 #endif
4711
4712 const bool clientIsIdle = pipeline.empty();
4713
4714 debugs(33, 3, "idle pinned " << pinning.serverConnection << " read " <<
4715 io.size << (clientIsIdle ? " with idle client" : ""));
4716
4717 pinning.serverConnection->close();
4718
4719 // If we are still sending data to the client, do not close now. When we are done sending,
4720 // ClientSocketContext::keepaliveNextRequest() checks pinning.serverConnection and will close.
4721 // However, if we are idle, then we must close to inform the idle client and minimize races.
4722 if (clientIsIdle && clientConnection != NULL)
4723 clientConnection->close();
4724 }
4725
4726 const Comm::ConnectionPointer
4727 ConnStateData::validatePinnedConnection(HttpRequest *request, const CachePeer *aPeer)
4728 {
4729 debugs(33, 7, HERE << pinning.serverConnection);
4730
4731 bool valid = true;
4732 if (!Comm::IsConnOpen(pinning.serverConnection))
4733 valid = false;
4734 else if (pinning.auth && pinning.host && request && strcasecmp(pinning.host, request->url.host()) != 0)
4735 valid = false;
4736 else if (request && pinning.port != request->url.port())
4737 valid = false;
4738 else if (pinning.peer && !cbdataReferenceValid(pinning.peer))
4739 valid = false;
4740 else if (aPeer != pinning.peer)
4741 valid = false;
4742
4743 if (!valid) {
4744 /* The pinning info is not safe, remove any pinning info */
4745 unpinConnection(true);
4746 }
4747
4748 return pinning.serverConnection;
4749 }
4750
4751 Comm::ConnectionPointer
4752 ConnStateData::borrowPinnedConnection(HttpRequest *request, const CachePeer *aPeer)
4753 {
4754 debugs(33, 7, pinning.serverConnection);
4755 if (validatePinnedConnection(request, aPeer) != NULL)
4756 stopPinnedConnectionMonitoring();
4757
4758 return pinning.serverConnection; // closed if validation failed
4759 }
4760
4761 void
4762 ConnStateData::unpinConnection(const bool andClose)
4763 {
4764 debugs(33, 3, HERE << pinning.serverConnection);
4765
4766 if (pinning.peer)
4767 cbdataReferenceDone(pinning.peer);
4768
4769 if (Comm::IsConnOpen(pinning.serverConnection)) {
4770 if (pinning.closeHandler != NULL) {
4771 comm_remove_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
4772 pinning.closeHandler = NULL;
4773 }
4774
4775 stopPinnedConnectionMonitoring();
4776
4777 // close the server side socket if requested
4778 if (andClose)
4779 pinning.serverConnection->close();
4780 pinning.serverConnection = NULL;
4781 }
4782
4783 safe_free(pinning.host);
4784
4785 pinning.zeroReply = false;
4786
4787 /* NOTE: pinning.pinned should be kept. This combined with fd == -1 at the end of a request indicates that the host
4788 * connection has gone away */
4789 }
4790