Squid Web Cache master
Loading...
Searching...
No Matches
client_side_request.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 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 85 Client-side Request Routines */
10
11/*
12 * General logic of request processing:
13 *
14 * We run a series of tests to determine if access will be permitted, and to do
15 * any redirection. Then we call into the result clientStream to retrieve data.
16 * From that point on it's up to reply management.
17 */
18
19#include "squid.h"
20#include "acl/FilledChecklist.h"
21#include "acl/Gadgets.h"
22#include "anyp/PortCfg.h"
23#include "base/AsyncJobCalls.h"
24#include "client_side.h"
25#include "client_side_reply.h"
26#include "client_side_request.h"
28#include "clientStream.h"
29#include "comm/Connection.h"
30#include "comm/Write.h"
31#include "debug/Messages.h"
32#include "error/Detail.h"
33#include "errorpage.h"
34#include "fd.h"
35#include "fde.h"
36#include "format/Token.h"
37#include "FwdState.h"
38#include "helper.h"
39#include "helper/Reply.h"
40#include "http.h"
41#include "http/Stream.h"
42#include "HttpHdrCc.h"
43#include "HttpReply.h"
44#include "HttpRequest.h"
45#include "internal.h"
46#include "ip/NfMarkConfig.h"
47#include "ip/QosConfig.h"
48#include "ipcache.h"
49#include "log/access_log.h"
50#include "MemObject.h"
51#include "Parsing.h"
52#include "proxyp/Header.h"
53#include "redirect.h"
54#include "rfc1738.h"
55#include "sbuf/StringConvert.h"
56#include "SquidConfig.h"
57#include "Store.h"
58#include "StrList.h"
59#include "tools.h"
60#include "wordlist.h"
61#if USE_AUTH
62#include "auth/UserRequest.h"
63#endif
64#if USE_ADAPTATION
66#include "adaptation/Answer.h"
67#include "adaptation/Iterator.h"
68#include "adaptation/Service.h"
69#if ICAP_CLIENT
71#endif
72#endif
73#if USE_OPENSSL
74#include "ssl/ServerBump.h"
75#include "ssl/support.h"
76#endif
77
78#if FOLLOW_X_FORWARDED_FOR
79
80#if !defined(SQUID_X_FORWARDED_FOR_HOP_MAX)
81#define SQUID_X_FORWARDED_FOR_HOP_MAX 64
82#endif
83
84static void clientFollowXForwardedForCheck(Acl::Answer answer, void *data);
85#endif /* FOLLOW_X_FORWARDED_FOR */
86
88
90
91/* Local functions */
92/* other */
93static void clientAccessCheckDoneWrapper(Acl::Answer, void *);
94#if USE_OPENSSL
96#endif
97static int clientHierarchical(ClientHttpRequest * http);
101static void checkNoCacheDoneWrapper(Acl::Answer, void *);
106
108{
110
111 delete error;
112 debugs(85,3, "ClientRequestContext destructed, this=" << this);
113}
114
116 http(cbdataReference(anHttp))
117{
118 debugs(85, 3, "ClientRequestContext constructed, this=" << this);
119}
120
122
125 AsyncJob("ClientHttpRequest"),
126#endif
127 al(new AccessLogEntry()),
128 conn_(cbdataReference(aConn))
129{
132 if (aConn) {
133 al->tcpClient = aConn->clientConnection;
134 al->cache.port = aConn->port;
135 al->cache.caddr = aConn->log_addr;
137 al->updateError(aConn->bareError);
138
139#if USE_OPENSSL
140 if (aConn->clientConnection != nullptr && aConn->clientConnection->isOpen()) {
141 if (auto ssl = fd_table[aConn->clientConnection->fd].ssl.get())
142 al->cache.sslClientCert.resetWithoutLocking(SSL_get_peer_certificate(ssl));
143 }
144#endif
145 }
147}
148
149/*
150 * returns true if client specified that the object must come from the cache
151 * without contacting origin server
152 */
153bool
160
173static void
175{
176 // Can be set at compile time with -D compiler flag
177#ifndef FAILURE_MODE_TIME
178#define FAILURE_MODE_TIME 300
179#endif
180
181 if (hcode == HIER_NONE)
182 return;
183
184 // don't bother when ICP is disabled.
185 if (Config.Port.icp <= 0)
186 return;
187
188 static double magic_factor = 100.0;
189 double n_good;
190 double n_bad;
191
192 n_good = magic_factor / (1.0 + request_failure_ratio);
193
194 n_bad = magic_factor - n_good;
195
196 switch (etype) {
197
198 case ERR_DNS_FAIL:
199
200 case ERR_CONNECT_FAIL:
202
203 case ERR_READ_ERROR:
204 ++n_bad;
205 break;
206
207 default:
208 ++n_good;
209 }
210
211 request_failure_ratio = n_bad / n_good;
212
214 return;
215
216 if (request_failure_ratio < 1.0)
217 return;
218
219 debugs(33, DBG_CRITICAL, "WARNING: Failure Ratio at "<< std::setw(4)<<
220 std::setprecision(3) << request_failure_ratio);
221
222 debugs(33, DBG_CRITICAL, "WARNING: ICP going into HIT-only mode for " <<
223 FAILURE_MODE_TIME / 60 << " minutes...");
224
226
227 request_failure_ratio = 0.8; /* reset to something less than 1.0 */
228}
229
231{
232 debugs(33, 3, "httpRequestFree: " << uri);
233
234 // Even though freeResources() below may destroy the request,
235 // we no longer set request->body_pipe to NULL here
236 // because we did not initiate that pipe (ConnStateData did)
237
238 /* the ICP check here was erroneous
239 * - StoreEntry::releaseRequest was always called if entry was valid
240 */
241
242 logRequest();
243
244 loggingEntry(nullptr);
245
246 if (request)
248
250
251#if USE_ADAPTATION
253
254 if (adaptedBodySource != nullptr)
256#endif
257
258 delete calloutContext;
259
261
262 /* moving to the next connection is handled by the context free */
264}
265
266#if FOLLOW_X_FORWARDED_FOR
281static void
283{
284 ClientRequestContext *calloutContext = (ClientRequestContext *) data;
285 ClientHttpRequest *http = calloutContext->http;
286 HttpRequest *request = http->request;
287
288 if (answer.allowed() && request->x_forwarded_for_iterator.size() != 0) {
289
290 /*
291 * Remove the last comma-delimited element from the
292 * x_forwarded_for_iterator and use it to repeat the cycle.
293 */
294 const char *p;
295 const char *asciiaddr;
296 int l;
297 Ip::Address addr;
298 p = request->x_forwarded_for_iterator.termedBuf();
299 l = request->x_forwarded_for_iterator.size();
300
301 /*
302 * XXX x_forwarded_for_iterator should really be a list of
303 * IP addresses, but it's a String instead. We have to
304 * walk backwards through the String, biting off the last
305 * comma-delimited part each time. As long as the data is in
306 * a String, we should probably implement and use a variant of
307 * strListGetItem() that walks backwards instead of forwards
308 * through a comma-separated list. But we don't even do that;
309 * we just do the work in-line here.
310 */
311 /* skip trailing space and commas */
312 while (l > 0 && (p[l-1] == ',' || xisspace(p[l-1])))
313 --l;
314 request->x_forwarded_for_iterator.cut(l);
315 /* look for start of last item in list */
316 while (l > 0 && ! (p[l-1] == ',' || xisspace(p[l-1])))
317 --l;
318 asciiaddr = p+l;
319 if ((addr = asciiaddr)) {
320 request->indirect_client_addr = addr;
321 request->x_forwarded_for_iterator.cut(l);
324 /* override the default src_addr tested if we have to go deeper than one level into XFF */
325 ch->src_addr = request->indirect_client_addr;
326 }
327 if (++calloutContext->currentXffHopNumber < SQUID_X_FORWARDED_FOR_HOP_MAX) {
329 return;
330 }
332 debugs(28, DBG_CRITICAL, "ERROR: Ignoring trailing " << headerName << " addresses" <<
333 Debug::Extra << "addresses allowed by follow_x_forwarded_for: " << calloutContext->currentXffHopNumber <<
334 Debug::Extra << "last/accepted address: " << request->indirect_client_addr <<
335 Debug::Extra << "ignored trailing addresses: " << request->x_forwarded_for_iterator);
336 // fall through to resume clientAccessCheck() processing
337 }
338 }
339
340 /* clean up, and pass control to clientAccessCheck */
342 /*
343 * Ensure that the access log shows the indirect client
344 * instead of the direct client.
345 */
346 http->al->cache.caddr = request->indirect_client_addr;
347 if (ConnStateData *conn = http->getConn())
348 conn->log_addr = request->indirect_client_addr;
349 }
351 request->flags.done_follow_x_forwarded_for = true;
352
353 if (answer.conflicted()) {
354 debugs(28, DBG_CRITICAL, "ERROR: Processing X-Forwarded-For. Stopping at IP address: " << request->indirect_client_addr );
355 }
356
357 /* process actual access ACL as normal. */
358 calloutContext->clientAccessCheck();
359}
360#endif /* FOLLOW_X_FORWARDED_FOR */
361
362static void
364{
365 ClientRequestContext *c = static_cast<ClientRequestContext*>(data);
366 c->hostHeaderIpVerify(ia, dns);
367}
368
369void
371{
373
374 // note the DNS details for the transaction stats.
376
377 // Is the NAT destination IP in DNS?
378 if (ia && ia->have(clientConn->local)) {
379 debugs(85, 3, "validate IP " << clientConn->local << " possible from Host:");
381 http->doCallouts();
382 return;
383 }
384 debugs(85, 3, "FAIL: validate IP " << clientConn->local << " possible from Host:");
385 hostHeaderVerifyFailed("local IP", "any domain IP");
386}
387
388void
390{
391 // IP address validation for Host: failed. Admin wants to ignore them.
392 // NP: we do not yet handle CONNECT tunnels well, so ignore for them
394 debugs(85, 3, "SECURITY ALERT: Host header forgery detected on " << http->getConn()->clientConnection <<
395 " (" << A << " does not match " << B << ") on URL: " << http->request->effectiveRequestUri());
396
397 // MUST NOT cache (for now). It is tempting to set flags.noCache, but
398 // that flag is about satisfying _this_ request. We are actually OK with
399 // satisfying this request from the cache, but want to prevent _other_
400 // requests from being satisfied using this response.
402
403 // XXX: when we have updated the cache key to base on raw-IP + URI this cacheable limit can go.
404 http->request->flags.hierarchical = false; // MUST NOT pass to peers (for now)
405 // XXX: when we have sorted out the best way to relay requests properly to peers this hierarchical limit can go.
406 http->doCallouts();
407 return;
408 }
409
410 debugs(85, DBG_IMPORTANT, "SECURITY ALERT: Host header forgery detected on " <<
411 http->getConn()->clientConnection << " (" << A << " does not match " << B << ")");
412 if (const char *ua = http->request->header.getStr(Http::HdrType::USER_AGENT))
413 debugs(85, DBG_IMPORTANT, "SECURITY ALERT: By user agent: " << ua);
414 debugs(85, DBG_IMPORTANT, "SECURITY ALERT: on URL: " << http->request->effectiveRequestUri());
415
416 // IP address validation for Host: failed. reject the connection.
418 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
419 assert (repContext);
421 nullptr,
422 http->getConn(),
423 http->request,
424 nullptr,
425#if USE_AUTH
426 http->getConn() != nullptr && http->getConn()->getAuth() != nullptr ?
428#else
429 nullptr);
430#endif
432 clientStreamRead(node, http, node->readBuffer);
433}
434
435void
437{
438 // Require a Host: header.
439 const char *host = http->request->header.getStr(Http::HdrType::HOST);
440
441 if (!host) {
442 // TODO: dump out the HTTP/1.1 error about missing host header.
443 // otherwise this is fine, can't forge a header value when its not even set.
444 debugs(85, 3, "validate skipped with no Host: header present.");
445 http->doCallouts();
446 return;
447 }
448
449 if (http->request->flags.internal) {
450 // TODO: kill this when URL handling allows partial URLs out of accel mode
451 // and we no longer screw with the URL just to add our internal host there
452 debugs(85, 6, "validate skipped due to internal composite URL.");
453 http->doCallouts();
454 return;
455 }
456
457 // TODO: Unify Host value parsing below with AnyP::Uri authority parsing
458 // Locate if there is a port attached, strip ready for IP lookup
459 char *portStr = nullptr;
460 char *hostB = xstrdup(host);
461 host = hostB;
462 if (host[0] == '[') {
463 // IPv6 literal.
464 portStr = strchr(hostB, ']');
465 if (portStr && *(++portStr) != ':') {
466 portStr = nullptr;
467 }
468 } else {
469 // Domain or IPv4 literal with port
470 portStr = strrchr(hostB, ':');
471 }
472
473 uint16_t port = 0;
474 if (portStr) {
475 *portStr = '\0'; // strip the ':'
476 if (*(++portStr) != '\0') {
477 char *end = nullptr;
478 int64_t ret = strtoll(portStr, &end, 10);
479 if (end == portStr || *end != '\0' || ret < 1 || ret > 0xFFFF) {
480 // invalid port details. Replace the ':'
481 *(--portStr) = ':';
482 portStr = nullptr;
483 } else
484 port = (ret & 0xFFFF);
485 }
486 }
487
488 debugs(85, 3, "validate host=" << host << ", port=" << port << ", portStr=" << (portStr?portStr:"NULL"));
490 // verify the Host: port (if any) matches the apparent destination
491 if (portStr && port != http->getConn()->clientConnection->local.port()) {
492 debugs(85, 3, "FAIL on validate port " << http->getConn()->clientConnection->local.port() <<
493 " matches Host: port " << port << " (" << portStr << ")");
494 hostHeaderVerifyFailed("intercepted port", portStr);
495 } else {
496 // XXX: match the scheme default port against the apparent destination
497
498 // verify the destination DNS is one of the Host: headers IPs
500 }
501 } else if (!Config.onoff.hostStrictVerify) {
502 debugs(85, 3, "validate skipped.");
503 http->doCallouts();
504 } else if (strlen(host) != strlen(http->request->url.host())) {
505 // Verify forward-proxy requested URL domain matches the Host: header
506 debugs(85, 3, "FAIL on validate URL domain length " << http->request->url.host() << " matches Host: " << host);
508 } else if (matchDomainName(host, http->request->url.host()) != 0) {
509 // Verify forward-proxy requested URL domain matches the Host: header
510 debugs(85, 3, "FAIL on validate URL domain " << http->request->url.host() << " matches Host: " << host);
512 } else if (portStr && !http->request->url.port()) {
513 debugs(85, 3, "FAIL on validate portless URI matches Host: " << portStr);
514 hostHeaderVerifyFailed("portless URI", portStr);
515 } else if (portStr && port != *http->request->url.port()) {
516 // Verify forward-proxy requested URL domain matches the Host: header
517 debugs(85, 3, "FAIL on validate URL port " << *http->request->url.port() << " matches Host: port " << portStr);
518 hostHeaderVerifyFailed("URL port", portStr);
519 } else if (!portStr && http->request->method != Http::METHOD_CONNECT && http->request->url.port() != http->request->url.getScheme().defaultPort()) {
520 // Verify forward-proxy requested URL domain matches the Host: header
521 // Special case: we don't have a default-port to check for CONNECT. Assume URL is correct.
522 debugs(85, 3, "FAIL on validate URL port " << http->request->url.port().value_or(0) << " matches Host: default port " << http->request->url.getScheme().defaultPort().value_or(0));
523 hostHeaderVerifyFailed("URL port", "default port");
524 } else {
525 // Okay no problem.
526 debugs(85, 3, "validate passed.");
528 http->doCallouts();
529 }
530 safe_free(hostB);
531}
532
533/* This is the entry point for external users of the client_side routines */
534void
536{
537#if FOLLOW_X_FORWARDED_FOR
538 if (!http->request->flags.doneFollowXff() &&
541
542 /* we always trust the direct client address for actual use */
545
546 /* setup the XFF iterator for processing */
548
549 /* begin by checking to see if we trust direct client enough to walk XFF */
552 return;
553 }
554#endif
555
556 if (Config.accessList.http) {
557 auto acl_checklist = clientAclChecklistCreate(Config.accessList.http, http);
559 } else {
560 debugs(0, DBG_CRITICAL, "No http_access configuration found. This will block ALL traffic");
562 }
563}
564
570void
572{
576 } else {
577 debugs(85, 2, "No adapted_http_access configuration. default: ALLOW");
579 }
580}
581
582void
584{
585 ClientRequestContext *calloutContext = (ClientRequestContext *) data;
586 calloutContext->clientAccessCheckDone(answer);
587}
588
589void
591{
592 Http::StatusCode status;
593 debugs(85, 2, "The request " << http->request->method << ' ' <<
594 http->uri << " is " << answer <<
595 "; last ACL checked: " << answer.lastCheckDescription());
596
597#if USE_AUTH
598 char const *proxy_auth_msg = "<null>";
599 if (http->getConn() != nullptr && http->getConn()->getAuth() != nullptr)
600 proxy_auth_msg = http->getConn()->getAuth()->denyMessage("<null>");
601 else if (http->request->auth_user_request != nullptr)
602 proxy_auth_msg = http->request->auth_user_request->denyMessage("<null>");
603#endif
604
605 if (!answer.allowed()) {
606 // auth has a grace period where credentials can be expired but okay not to challenge.
607
608 /* Send an auth challenge or error */
609 // XXX: do we still need aclIsProxyAuth() ?
610 const auto auth_challenge = (answer == ACCESS_AUTH_REQUIRED || aclIsProxyAuth(answer.lastCheckedName));
611 debugs(85, 5, "Access Denied: " << http->uri);
612#if USE_AUTH
613 if (auth_challenge)
614 debugs(33, 5, "Proxy Auth Message = " << (proxy_auth_msg ? proxy_auth_msg : "<null>"));
615#endif
616
617 auto page_id = FindDenyInfoPage(answer, answer != ACCESS_AUTH_REQUIRED);
618
620
621 if (auth_challenge) {
622#if USE_AUTH
623 if (http->request->flags.sslBumped) {
624 /*SSL Bumped request, authentication is not possible*/
625 status = Http::scForbidden;
626 } else if (!http->flags.accel) {
627 /* Proxy authorisation needed */
629 } else {
630 /* WWW authorisation needed */
631 status = Http::scUnauthorized;
632 }
633#else
634 // need auth, but not possible to do.
635 status = Http::scForbidden;
636#endif
637 if (page_id == ERR_NONE)
639 } else {
640 status = Http::scForbidden;
641
642 if (page_id == ERR_NONE)
643 page_id = ERR_ACCESS_DENIED;
644 }
645
646 error = clientBuildError(page_id, status, nullptr, http->getConn(), http->request, http->al);
647
648#if USE_AUTH
650 http->getConn() != nullptr && http->getConn()->getAuth() != nullptr ?
652#endif
653
654 readNextRequest = true;
655 }
656
657 /* ACCESS_ALLOWED continues here ... */
658 xfree(http->uri);
660 http->doCallouts();
661}
662
663#if USE_ADAPTATION
664void
666{
667 debugs(93,3, this << " adaptationAclCheckDone called");
668
669#if ICAP_CLIENT
671 if (ih != nullptr) {
672 if (getConn() != nullptr && getConn()->clientConnection != nullptr) {
673#if USE_OPENSSL
674 if (getConn()->clientConnection->isOpen()) {
675 ih->ssluser = sslGetUserEmail(fd_table[getConn()->clientConnection->fd].ssl.get());
676 }
677#endif
678 }
679 ih->log_uri = log_uri;
680 ih->req_sz = req_sz;
681 }
682#endif
683
684 if (!g) {
685 debugs(85,3, "no adaptation needed");
686 doCallouts();
687 return;
688 }
689
691}
692
693#endif
694
695static void
697{
699 ClientHttpRequest *http = context->http;
700
701 if (answer.allowed())
703 else {
704 Helper::Reply const nilReply(Helper::Error);
705 context->clientRedirectDone(nilReply);
706 }
707}
708
709void
720
725static void
727{
728 ClientRequestContext *context = static_cast<ClientRequestContext *>(data);
729 ClientHttpRequest *http = context->http;
730
731 if (answer.allowed())
733 else {
734 debugs(85, 3, "access denied expected ERR reply handling: " << answer);
735 Helper::Reply const nilReply(Helper::Error);
736 context->clientStoreIdDone(nilReply);
737 }
738}
739
745void
747{
748 debugs(33, 5,"'" << http->uri << "'");
749
753 } else
755}
756
757static int
759{
760 HttpRequest *request = http->request;
761 HttpRequestMethod method = request->method;
762
763 // intercepted requests MUST NOT (yet) be sent to peers unless verified
764 if (!request->flags.hostVerified && (request->flags.intercepted || request->flags.interceptTproxy))
765 return 0;
766
767 /*
768 * IMS needs a private key, so we can use the hierarchy for IMS only if our
769 * neighbors support private keys
770 */
771
772 if (request->flags.ims && !neighbors_do_private_keys)
773 return 0;
774
775 /*
776 * This is incorrect: authenticating requests can be sent via a hierarchy
777 * (they can even be cached if the correct headers are set on the reply)
778 */
779 if (request->flags.auth)
780 return 0;
781
782 if (method == Http::METHOD_TRACE)
783 return 1;
784
785 if (method != Http::METHOD_GET)
786 return 0;
787
788 if (request->flags.loopDetected)
789 return 0;
790
791 if (request->url.getScheme() == AnyP::PROTO_HTTP)
792 return method.respMaybeCacheable();
793
794 return 1;
795}
796
797static void
799{
800 HttpRequest *request = http->request;
801 HttpHeader *req_hdr = &request->header;
802 ConnStateData *http_conn = http->getConn();
803
804 // Internal requests may be without a client connection
805 if (!http_conn)
806 return;
807
808 request->flags.connectionAuthDisabled = http_conn->port->connection_auth_disabled;
809 if (!request->flags.connectionAuthDisabled) {
810 if (Comm::IsConnOpen(http_conn->pinning.serverConnection)) {
811 if (http_conn->pinning.auth) {
812 request->flags.connectionAuth = true;
813 request->flags.auth = true;
814 } else {
815 request->flags.connectionProxyAuth = true;
816 }
817 // These should already be linked correctly.
818 assert(request->clientConnectionManager == http_conn);
819 }
820 }
821
822 /* check if connection auth is used, and flag as candidate for pinning
823 * in such case.
824 * Note: we may need to set flags.connectionAuth even if the connection
825 * is already pinned if it was pinned earlier due to proxy auth
826 */
827 if (!request->flags.connectionAuth) {
831 int may_pin = 0;
832 while ((e = req_hdr->getEntry(&pos))) {
834 const char *value = e->value.rawBuf();
835 if (strncasecmp(value, "NTLM ", 5) == 0
836 ||
837 strncasecmp(value, "Negotiate ", 10) == 0
838 ||
839 strncasecmp(value, "Kerberos ", 9) == 0) {
841 request->flags.connectionAuth = true;
842 may_pin = 1;
843 } else {
844 request->flags.connectionProxyAuth = true;
845 may_pin = 1;
846 }
847 }
848 }
849 }
850 if (may_pin && !request->pinnedConnection()) {
851 // These should already be linked correctly. Just need the ServerConnection to pinn.
852 assert(request->clientConnectionManager == http_conn);
853 }
854 }
855 }
856}
857
858static void
860{
861 HttpRequest *request = http->request;
862 HttpHeader *req_hdr = &request->header;
863 bool no_cache = false;
864
865 request->imslen = -1;
866 request->ims = req_hdr->getTime(Http::HdrType::IF_MODIFIED_SINCE);
867
868 if (request->ims > 0)
869 request->flags.ims = true;
870
871 if (!request->flags.ignoreCc) {
872 if (request->cache_control) {
873 if (request->cache_control->hasNoCache())
874 no_cache=true;
875
876 // RFC 2616: treat Pragma:no-cache as if it was Cache-Control:no-cache when Cache-Control is missing
877 } else if (req_hdr->has(Http::HdrType::PRAGMA))
878 no_cache = req_hdr->hasListMember(Http::HdrType::PRAGMA,"no-cache",',');
879 }
880
881 if (request->method == Http::METHOD_OTHER) {
882 no_cache=true;
883 }
884
885 if (no_cache) {
886#if USE_HTTP_VIOLATIONS
887
889 request->flags.nocacheHack = true;
890 else if (refresh_nocache_hack)
891 request->flags.nocacheHack = true;
892 else
893#endif
894
895 request->flags.noCache = true;
896 }
897
898 /* ignore range header in non-GETs or non-HEADs */
899 if (request->method == Http::METHOD_GET || request->method == Http::METHOD_HEAD) {
900 // XXX: initialize if we got here without HttpRequest::parseHeader()
901 if (!request->range)
902 request->range = req_hdr->getRange();
903
904 if (request->range) {
905 request->flags.isRanged = true;
907 /* XXX: This is suboptimal. We should give the stream the range set,
908 * and thereby let the top of the stream set the offset when the
909 * size becomes known. As it is, we will end up requesting from 0
910 * for every -X range specification.
911 * RBC - this may be somewhat wrong. We should probably set the range
912 * iter up at this point.
913 */
914 node->readBuffer.offset = request->range->lowestOffset(0);
915 }
916 }
917
918 /* Only HEAD and GET requests permit a Range or Request-Range header.
919 * If these headers appear on any other type of request, delete them now.
920 */
921 else {
924 request->ignoreRange("neither HEAD nor GET");
925 }
926
927 if (req_hdr->has(Http::HdrType::AUTHORIZATION))
928 request->flags.auth = true;
929
930 clientCheckPinning(http);
931
932 if (!request->url.userInfo().isEmpty())
933 request->flags.auth = true;
934
935 if (req_hdr->has(Http::HdrType::VIA)) {
936 String s = req_hdr->getList(Http::HdrType::VIA);
937 /*
938 * ThisCache cannot be a member of Via header, "1.1 ThisCache" can.
939 * Note ThisCache2 has a space prepended to the hostname so we don't
940 * accidentally match super-domains.
941 */
942
943 if (strListIsSubstr(&s, ThisCache2, ',')) {
944 request->flags.loopDetected = true;
945 }
946
947#if USE_FORW_VIA_DB
949
950#endif
951
952 s.clean();
953 }
954
955 // headers only relevant to reverse-proxy
956 if (request->flags.accelerated) {
957 // check for a cdn-info member with a cdn-id matching surrogate_id
958 // XXX: HttpHeader::hasListMember() does not handle OWS around ";" yet
960 request->flags.loopDetected = true;
961 }
962
963 if (request->flags.loopDetected) {
964 debugObj(33, DBG_IMPORTANT, "WARNING: Forwarding loop detected for:\n",
965 request, (ObjPackMethod) & httpRequestPack);
966 }
967
968#if USE_FORW_VIA_DB
969
970 if (req_hdr->has(Http::HdrType::X_FORWARDED_FOR)) {
973 s.clean();
974 }
975
976#endif
977
978 if (http->request->maybeCacheable())
979 request->flags.cachable.support();
980 else
981 request->flags.cachable.veto();
982
983 if (clientHierarchical(http))
984 request->flags.hierarchical = true;
985
986 debugs(85, 5, "clientInterpretRequestHeaders: REQ_NOCACHE = " <<
987 (request->flags.noCache ? "SET" : "NOT SET"));
988 debugs(85, 5, "clientInterpretRequestHeaders: REQ_CACHABLE = " <<
989 (request->flags.cachable ? "SET" : "NOT SET"));
990 debugs(85, 5, "clientInterpretRequestHeaders: REQ_HIERARCHICAL = " <<
991 (request->flags.hierarchical ? "SET" : "NOT SET"));
992
993}
994
995void
996clientRedirectDoneWrapper(void *data, const Helper::Reply &result)
997{
998 ClientRequestContext *calloutContext = (ClientRequestContext *)data;
999 calloutContext->clientRedirectDone(result);
1000}
1001
1002void
1003clientStoreIdDoneWrapper(void *data, const Helper::Reply &result)
1004{
1005 ClientRequestContext *calloutContext = (ClientRequestContext *)data;
1006 calloutContext->clientStoreIdDone(result);
1007}
1008
1009void
1011{
1012 HttpRequest *old_request = http->request;
1013 debugs(85, 5, "'" << http->uri << "' result=" << reply);
1016
1017 // Put helper response Notes into the transaction state record (ALE) eventually
1018 // do it early to ensure that no matter what the outcome the notes are present.
1019 if (http->al)
1020 http->al->syncNotes(old_request);
1021
1022 UpdateRequestNotes(http->getConn(), *old_request, reply.notes);
1023
1024 switch (reply.result) {
1025 case Helper::TimedOut:
1027 static const auto d = MakeNamedErrorDetail("REDIRECTOR_TIMEDOUT");
1029 debugs(85, DBG_IMPORTANT, "ERROR: URL rewrite helper: Timedout");
1030 }
1031 break;
1032
1033 case Helper::Unknown:
1034 case Helper::TT:
1035 // Handler in redirect.cc should have already mapped Unknown
1036 // IF it contained valid entry for the old URL-rewrite helper protocol
1037 debugs(85, DBG_IMPORTANT, "ERROR: URL rewrite helper returned invalid result code. Wrong helper? " << reply);
1038 break;
1039
1041 debugs(85, DBG_IMPORTANT, "ERROR: URL rewrite helper: " << reply);
1042 break;
1043
1044 case Helper::Error:
1045 // no change to be done.
1046 break;
1047
1048 case Helper::Okay: {
1049 // #1: redirect with a specific status code OK status=NNN url="..."
1050 // #2: redirect with a default status code OK url="..."
1051 // #3: re-write the URL OK rewrite-url="..."
1052
1053 const char *statusNote = reply.notes.findFirst("status");
1054 const char *urlNote = reply.notes.findFirst("url");
1055
1056 if (urlNote != nullptr) {
1057 // HTTP protocol redirect to be done.
1058
1059 // TODO: change default redirect status for appropriate requests
1060 // Squid defaults to 302 status for now for better compatibility with old clients.
1061 // HTTP/1.0 client should get 302 (Http::scFound)
1062 // HTTP/1.1 client contacting reverse-proxy should get 307 (Http::scTemporaryRedirect)
1063 // HTTP/1.1 client being diverted by forward-proxy should get 303 (Http::scSeeOther)
1065 if (statusNote != nullptr) {
1066 const char * result = statusNote;
1067 status = static_cast<Http::StatusCode>(atoi(result));
1068 }
1069
1070 if (status == Http::scMovedPermanently
1071 || status == Http::scFound
1072 || status == Http::scSeeOther
1073 || status == Http::scPermanentRedirect
1074 || status == Http::scTemporaryRedirect) {
1075 http->redirect.status = status;
1076 http->redirect.location = xstrdup(urlNote);
1077 // TODO: validate the URL produced here is RFC 2616 compliant absolute URI
1078 } else {
1079 debugs(85, DBG_CRITICAL, "ERROR: URL-rewrite produces invalid " << status << " redirect Location: " << urlNote);
1080 }
1081 } else {
1082 // URL-rewrite wanted. Ew.
1083 urlNote = reply.notes.findFirst("rewrite-url");
1084
1085 // prevent broken helpers causing too much damage. If old URL == new URL skip the re-write.
1086 if (urlNote != nullptr && strcmp(urlNote, http->uri)) {
1087 AnyP::Uri tmpUrl;
1088 if (tmpUrl.parse(old_request->method, SBuf(urlNote))) {
1089 HttpRequest *new_request = old_request->clone();
1090 new_request->url = tmpUrl;
1091 debugs(61, 2, "URL-rewriter diverts URL from " << old_request->effectiveRequestUri() << " to " << new_request->effectiveRequestUri());
1092
1093 // unlink bodypipe from the old request. Not needed there any longer.
1094 if (old_request->body_pipe != nullptr) {
1095 old_request->body_pipe = nullptr;
1096 debugs(61,2, "URL-rewriter diverts body_pipe " << new_request->body_pipe <<
1097 " from request " << old_request << " to " << new_request);
1098 }
1099
1100 http->resetRequestXXX(new_request, true);
1101 old_request = nullptr;
1102 } else {
1103 debugs(85, DBG_CRITICAL, "ERROR: URL-rewrite produces invalid request: " <<
1104 old_request->method << " " << urlNote << " " << old_request->http_ver);
1105 }
1106 }
1107 }
1108 }
1109 break;
1110 }
1111
1112 /* XXX PIPELINE: This is inaccurate during pipelining */
1113
1114 if (http->getConn() != nullptr && Comm::IsConnOpen(http->getConn()->clientConnection))
1116
1117 assert(http->uri);
1118
1119 http->doCallouts();
1120}
1121
1125void
1127{
1128 HttpRequest *old_request = http->request;
1129 debugs(85, 5, "'" << http->uri << "' result=" << reply);
1132
1133 // Put helper response Notes into the transaction state record (ALE) eventually
1134 // do it early to ensure that no matter what the outcome the notes are present.
1135 if (http->al)
1136 http->al->syncNotes(old_request);
1137
1138 UpdateRequestNotes(http->getConn(), *old_request, reply.notes);
1139
1140 switch (reply.result) {
1141 case Helper::Unknown:
1142 case Helper::TT:
1143 // Handler in redirect.cc should have already mapped Unknown
1144 // IF it contained valid entry for the old helper protocol
1145 debugs(85, DBG_IMPORTANT, "ERROR: storeID helper returned invalid result code. Wrong helper? " << reply);
1146 break;
1147
1148 case Helper::TimedOut:
1149 // Timeouts for storeID are not implemented
1151 debugs(85, DBG_IMPORTANT, "ERROR: storeID helper: " << reply);
1152 break;
1153
1154 case Helper::Error:
1155 // no change to be done.
1156 break;
1157
1158 case Helper::Okay: {
1159 const char *urlNote = reply.notes.findFirst("store-id");
1160
1161 // prevent broken helpers causing too much damage. If old URL == new URL skip the re-write.
1162 if (urlNote != nullptr && strcmp(urlNote, http->uri) ) {
1163 // Debug section required for some very specific cases.
1164 debugs(85, 9, "Setting storeID with: " << urlNote );
1165 http->request->store_id = urlNote;
1166 http->store_id = urlNote;
1167 }
1168 }
1169 break;
1170 }
1171
1172 http->doCallouts();
1173}
1174
1176void
1178{
1180 auto acl_checklist = clientAclChecklistCreate(Config.accessList.noCache, http);
1181 ACLFilledChecklist::NonBlockingCheck(std::move(acl_checklist), checkNoCacheDoneWrapper, this);
1182 } else {
1183 /* unless otherwise specified, we try to cache. */
1185 }
1186}
1187
1188static void
1190{
1191 ClientRequestContext *calloutContext = (ClientRequestContext *) data;
1192 calloutContext->checkNoCacheDone(answer);
1193}
1194
1195void
1197{
1198 if (answer.denied()) {
1199 http->request->flags.disableCacheUse("a cache deny rule matched");
1200 }
1201 http->doCallouts();
1202}
1203
1204#if USE_OPENSSL
1205bool
1207{
1208 if (!http->getConn()) {
1209 http->al->ssl.bumpMode = Ssl::bumpEnd; // SslBump does not apply; log -
1210 return false;
1211 }
1212
1213 const Ssl::BumpMode bumpMode = http->getConn()->sslBumpMode;
1214 if (http->request->flags.forceTunnel) {
1215 debugs(85, 5, "not needed; already decided to tunnel " << http->getConn());
1216 if (bumpMode != Ssl::bumpEnd)
1217 http->al->ssl.bumpMode = bumpMode; // inherited from bumped connection
1218 return false;
1219 }
1220
1221 // If SSL connection tunneling or bumping decision has been made, obey it.
1222 if (bumpMode != Ssl::bumpEnd) {
1223 debugs(85, 5, "SslBump already decided (" << bumpMode <<
1224 "), " << "ignoring ssl_bump for " << http->getConn());
1225
1226 // We need the following "if" for transparently bumped TLS connection,
1227 // because in this case we are running ssl_bump access list before
1228 // the doCallouts runs. It can be removed after the bug #4340 fixed.
1229 // We do not want to proceed to bumping steps:
1230 // - if the TLS connection with the client is already established
1231 // because we are accepting normal HTTP requests on TLS port,
1232 // or because of the client-first bumping mode
1233 // - When the bumping is already started
1234 if (!http->getConn()->switchedToHttps() &&
1235 !http->getConn()->serverBump())
1236 http->sslBumpNeed(bumpMode); // for processRequest() to bump if needed and not already bumped
1237 http->al->ssl.bumpMode = bumpMode; // inherited from bumped connection
1238 return false;
1239 }
1240
1241 // If we have not decided yet, decide whether to bump now.
1242
1243 // Bumping here can only start with a CONNECT request on a bumping port
1244 // (bumping of intercepted SSL conns is decided before we get 1st request).
1245 // We also do not bump redirected CONNECT requests.
1248 !http->getConn()->port->flags.tunnelSslBumping) {
1249 http->al->ssl.bumpMode = Ssl::bumpEnd; // SslBump does not apply; log -
1250 debugs(85, 5, "cannot SslBump this request");
1251 return false;
1252 }
1253
1254 // Do not bump during authentication: clients would not proxy-authenticate
1255 // if we delay a 407 response and respond with 200 OK to CONNECT.
1257 http->al->ssl.bumpMode = Ssl::bumpEnd; // SslBump does not apply; log -
1258 debugs(85, 5, "no SslBump during proxy authentication");
1259 return false;
1260 }
1261
1262 if (error) {
1263 debugs(85, 5, "SslBump applies. Force bump action on error " << errorTypeName(error->type));
1266 return false;
1267 }
1268
1269 debugs(85, 5, "SslBump possible, checking ACL");
1270
1273 return true;
1274}
1275
1280static void
1282{
1283 ClientRequestContext *calloutContext = static_cast<ClientRequestContext *>(data);
1284 calloutContext->sslBumpAccessCheckDone(answer);
1285}
1286
1287void
1289{
1290 const Ssl::BumpMode bumpMode = answer.allowed() ?
1291 static_cast<Ssl::BumpMode>(answer.kind) : Ssl::bumpSplice;
1292 http->sslBumpNeed(bumpMode); // for processRequest() to bump if needed
1293 http->al->ssl.bumpMode = bumpMode; // for logging
1294
1295 if (bumpMode == Ssl::bumpTerminate) {
1296 const Comm::ConnectionPointer clientConn = http->getConn() ? http->getConn()->clientConnection : nullptr;
1297 if (Comm::IsConnOpen(clientConn)) {
1298 debugs(85, 3, "closing after Ssl::bumpTerminate ");
1299 clientConn->close();
1300 }
1301 return;
1302 }
1303
1304 http->doCallouts();
1305}
1306#endif
1307
1308/*
1309 * Identify requests that do not go through the store and client side stream
1310 * and forward them to the appropriate location. All other requests, request
1311 * them.
1312 */
1313void
1315{
1316 debugs(85, 4, request->method << ' ' << uri);
1317
1318 const bool untouchedConnect = request->method == Http::METHOD_CONNECT && !redirect.status;
1319
1320#if USE_OPENSSL
1321 if (untouchedConnect && sslBumpNeeded()) {
1323 sslBumpStart();
1324 return;
1325 }
1326#endif
1327
1328 if (untouchedConnect || request->flags.forceTunnel) {
1329 getConn()->stopReading(); // tunnels read for themselves
1330 tunnelStart(this);
1331 return;
1332 }
1333
1334 httpStart();
1335}
1336
1337void
1339{
1340 // XXX: Re-initializes rather than updates. Should not be needed at all.
1342 debugs(85, 4, loggingTags().c_str() << " for '" << uri << "'");
1343
1344 /* no one should have touched this */
1345 assert(out.offset == 0);
1346 /* Use the Stream Luke */
1348 clientStreamRead(node, this, node->readBuffer);
1349}
1350
1351#if USE_OPENSSL
1352
1353void
1355{
1356 debugs(83, 3, "sslBump required: "<< Ssl::bumpMode(mode));
1357 sslBumpNeed_ = mode;
1358}
1359
1360// called when comm_write has completed
1361static void
1362SslBumpEstablish(const Comm::ConnectionPointer &, char *, size_t, Comm::Flag errflag, int, void *data)
1363{
1364 ClientHttpRequest *r = static_cast<ClientHttpRequest*>(data);
1365 debugs(85, 5, "responded to CONNECT: " << r << " ? " << errflag);
1366 r->sslBumpEstablish(errflag);
1367}
1368
1369void
1371{
1372 // Bail out quickly on Comm::ERR_CLOSING - close handlers will tidy up
1373 if (errflag == Comm::ERR_CLOSING)
1374 return;
1375
1376 if (errflag) {
1377 debugs(85, 3, "CONNECT response failure in SslBump: " << errflag);
1379 return;
1380 }
1381
1382#if USE_AUTH
1383 // Preserve authentication info for the ssl-bumped request
1384 if (request->auth_user_request != nullptr)
1385 getConn()->setAuth(request->auth_user_request, "SSL-bumped CONNECT");
1386#endif
1387
1390}
1391
1392void
1394{
1395 debugs(85, 5, "Confirming " << Ssl::bumpMode(sslBumpNeed_) <<
1396 "-bumped CONNECT tunnel on FD " << getConn()->clientConnection);
1398
1399 AsyncCall::Pointer bumpCall = commCbCall(85, 5, "ClientSocketContext::sslBumpEstablish",
1401
1403 CommIoCbParams &params = GetCommParams<CommIoCbParams>(bumpCall);
1404 params.flag = Comm::OK;
1405 params.conn = getConn()->clientConnection;
1406 ScheduleCallHere(bumpCall);
1407 return;
1408 }
1409
1411
1412 const auto mb = al->reply->pack();
1413 // send an HTTP 200 response to kick client SSL negotiation
1414 // TODO: Unify with tunnel.cc and add a Server(?) header
1415 Comm::Write(getConn()->clientConnection, mb, bumpCall);
1416 delete mb;
1417}
1418
1419#endif
1420
1421void
1423{
1424 if (request)
1426 else
1428}
1429
1430bool
1432{
1433 // TODO: See also (and unify with) clientReplyContext::storeNotOKTransferDone()
1434 int64_t contentLength =
1436 assert(contentLength >= 0);
1437
1438 if (out.offset < contentLength)
1439 return false;
1440
1441 return true;
1442}
1443
1444void
1446{
1447 entry_ = newEntry;
1448}
1449
1450void
1452{
1453 if (loggingEntry_)
1454 loggingEntry_->unlock("ClientHttpRequest::loggingEntry");
1455
1456 loggingEntry_ = newEntry;
1457
1458 if (loggingEntry_)
1459 loggingEntry_->lock("ClientHttpRequest::loggingEntry");
1460}
1461
1462void
1464{
1465 assignRequest(aRequest);
1466 if (const auto csd = getConn()) {
1467 if (!csd->notes()->empty())
1468 request->notes()->appendNewOnly(csd->notes().getRaw());
1469 }
1470 // al is created in the constructor
1471 assert(al);
1472 if (!al->request) {
1473 al->request = request;
1476 }
1477}
1478
1479void
1481{
1482 const auto uriChanged = request->effectiveRequestUri() != newRequest->effectiveRequestUri();
1483 resetRequestXXX(newRequest, uriChanged);
1484}
1485
1486void
1487ClientHttpRequest::resetRequestXXX(HttpRequest *newRequest, const bool uriChanged)
1488{
1489 assert(request != newRequest);
1490 clearRequest();
1491 assignRequest(newRequest);
1492 xfree(uri);
1494
1495 if (uriChanged) {
1496 request->flags.redirected = true;
1498 }
1499}
1500
1501void
1503{
1504 if (!internalCheck(request->url.path()))
1505 return;
1506
1508 debugs(33, 3, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true));
1509 request->flags.internal = true;
1511 debugs(33, 3, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (global_internal_static on)");
1515 request->flags.internal = true;
1517 } else {
1518 debugs(33, 3, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (not this proxy)");
1519 }
1520
1522 request->flags.disableCacheUse("cache manager URL");
1523}
1524
1525void
1527{
1528 assert(newRequest);
1529 assert(!request);
1530 const_cast<HttpRequest *&>(request) = newRequest;
1533}
1534
1535void
1537{
1538 HttpRequest *oldRequest = request;
1539 HTTPMSGUNLOCK(oldRequest);
1540 const_cast<HttpRequest *&>(request) = nullptr;
1541 absorbLogUri(nullptr);
1542}
1543
1544/*
1545 * doCallouts() - This function controls the order of "callout"
1546 * executions, including non-blocking access control checks, the
1547 * redirector, and ICAP. Previously, these callouts were chained
1548 * together such that "clientAccessCheckDone()" would call
1549 * "clientRedirectStart()" and so on.
1550 *
1551 * The ClientRequestContext (aka calloutContext) class holds certain
1552 * state data for the callout/callback operations. Previously
1553 * ClientHttpRequest would sort of hand off control to ClientRequestContext
1554 * for a short time. ClientRequestContext would then delete itself
1555 * and pass control back to ClientHttpRequest when all callouts
1556 * were finished.
1557 *
1558 * This caused some problems for ICAP because we want to make the
1559 * ICAP callout after checking ACLs, but before checking the no_cache
1560 * list. We can't stuff the ICAP state into the ClientRequestContext
1561 * class because we still need the ICAP state after ClientRequestContext
1562 * goes away.
1563 *
1564 * Note that ClientRequestContext is created before the first call
1565 * to doCallouts().
1566 *
1567 * Note that we set the _done flags here before actually starting
1568 * the callout. This is strictly for convenience.
1569 */
1570
1571void
1573{
1575
1576 if (!calloutContext->error) {
1577 // CVE-2009-0801: verify the Host: header is consistent with other known details.
1579 debugs(83, 3, "Doing calloutContext->hostHeaderVerify()");
1582 return;
1583 }
1584
1586 debugs(83, 3, "Doing calloutContext->clientAccessCheck()");
1589 return;
1590 }
1591
1592#if USE_ADAPTATION
1597 request, nullptr, calloutContext->http->al, this))
1598 return; // will call callback
1599 }
1600#endif
1601
1604
1605 if (Config.Program.redirect) {
1606 debugs(83, 3, "Doing calloutContext->clientRedirectStart()");
1609 return;
1610 }
1611 }
1612
1614 debugs(83, 3, "Doing calloutContext->clientAccessCheck2()");
1617 return;
1618 }
1619
1622
1623 if (Config.Program.store_id) {
1624 debugs(83, 3,"Doing calloutContext->clientStoreIdStart()");
1627 return;
1628 }
1629 }
1630
1632 debugs(83, 3, "Doing clientInterpretRequestHeaders()");
1635 }
1636
1639
1641 debugs(83, 3, "Doing calloutContext->checkNoCache()");
1643 return;
1644 }
1645 }
1646 } // if !calloutContext->error
1647
1648 // Set appropriate MARKs and CONNMARKs if needed.
1649 if (getConn() && Comm::IsConnOpen(getConn()->clientConnection)) {
1650 ACLFilledChecklist ch(nullptr, request);
1651 ch.al = calloutContext->http->al;
1653 ch.my_addr = request->my_addr;
1654 ch.syncAle(request, log_uri);
1655
1658 tos_t tos = aclMapTOS(Ip::Qos::TheConfig.tosToClient, &ch);
1659 if (tos)
1660 Ip::Qos::setSockTos(getConn()->clientConnection, tos);
1661
1662 const auto packetMark = aclFindNfMarkConfig(Ip::Qos::TheConfig.nfmarkToClient, &ch);
1663 if (!packetMark.isEmpty())
1664 Ip::Qos::setSockNfmark(getConn()->clientConnection, packetMark.mark);
1665
1666 const auto connmark = aclFindNfMarkConfig(Ip::Qos::TheConfig.nfConnmarkToClient, &ch);
1667 if (!connmark.isEmpty())
1668 Ip::Qos::setNfConnmark(getConn()->clientConnection, Ip::Qos::dirAccepted, connmark);
1669 }
1670 }
1671
1672#if USE_OPENSSL
1673 // Even with calloutContext->error, we call sslBumpAccessCheck() to decide
1674 // whether SslBump applies to this transaction. If it applies, we will
1675 // attempt to bump the client to serve the error.
1679 return;
1680 /* else no ssl bump required*/
1681 }
1682#endif
1683
1684 if (calloutContext->error) {
1685 // XXX: prformance regression. c_str() reallocates
1686 SBuf storeUriBuf(request->storeId());
1687 const char *storeUri = storeUriBuf.c_str();
1688 StoreEntry *e = storeCreateEntry(storeUri, storeUri, request->flags, request->method);
1689#if USE_OPENSSL
1690 if (sslBumpNeeded()) {
1691 // We have to serve an error, so bump the client first.
1693 // set final error but delay sending until we bump
1694 Ssl::ServerBump *srvBump = new Ssl::ServerBump(this, e, Ssl::bumpClientFirst);
1696 calloutContext->error = nullptr;
1697 getConn()->setServerBump(srvBump);
1698 e->unlock("ClientHttpRequest::doCallouts+sslBumpNeeded");
1699 } else
1700#endif
1701 {
1702 // send the error to the client now
1704 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1705 assert (repContext);
1706 repContext->setReplyToStoreEntry(e, "immediate SslBump error");
1708 calloutContext->error = nullptr;
1710 getConn()->flags.readMore = true; // resume any pipeline reads.
1712 clientStreamRead(node, this, node->readBuffer);
1713 e->unlock("ClientHttpRequest::doCallouts-sslBumpNeeded");
1714 return;
1715 }
1716 }
1717
1718 delete calloutContext;
1719 calloutContext = nullptr;
1720
1721 debugs(83, 3, "calling processRequest()");
1723
1724#if ICAP_CLIENT
1726 if (ih != nullptr)
1727 ih->logType = loggingTags();
1728#endif
1729}
1730
1731void
1733{
1734 assert(request);
1735 const auto canonicalUri = request->canonicalCleanUrl();
1736 absorbLogUri(xstrndup(canonicalUri, MAX_URL));
1737}
1738
1739void
1741{
1742 assert(rawUri);
1743 // Should(!request);
1744
1745 // TODO: SBuf() performance regression, fix by converting rawUri to SBuf
1746 char *canonicalUri = urlCanonicalCleanWithoutRequest(SBuf(rawUri), method, AnyP::UriScheme());
1747
1748 absorbLogUri(AnyP::Uri::cleanup(canonicalUri));
1749
1750 char *cleanedRawUri = AnyP::Uri::cleanup(rawUri);
1751 al->setVirginUrlForMissingRequest(SBuf(cleanedRawUri));
1752 xfree(cleanedRawUri);
1753}
1754
1755void
1757{
1758 xfree(log_uri);
1759 const_cast<char *&>(log_uri) = aUri;
1760}
1761
1762void
1764{
1765 assert(!uri);
1766 assert(aUri);
1767 // Should(!request);
1768
1769 uri = xstrdup(aUri);
1770 // TODO: SBuf() performance regression, fix by converting setErrorUri() parameter to SBuf
1771 const SBuf errorUri(aUri);
1772 const auto canonicalUri = urlCanonicalCleanWithoutRequest(errorUri, HttpRequestMethod(), AnyP::UriScheme());
1773 absorbLogUri(xstrndup(canonicalUri, MAX_URL));
1774
1776}
1777
1778// XXX: This should not be a _request_ method. Move range_iter elsewhere.
1779int64_t
1781{
1782 assert(request);
1784
1788 const auto multipart = request->range->specs.size() > 1;
1789 if (multipart)
1791 range_iter.valid = true; // TODO: Remove.
1792 range_iter.updateSpec(); // TODO: Refactor to initialize rather than update.
1793
1795 const auto &firstRange = *range_iter.pos;
1796 assert(firstRange);
1797 out.offset = firstRange->offset;
1798
1799 return multipart ? mRangeCLen() : firstRange->length;
1800}
1801
1802#if USE_ADAPTATION
1804void
1806{
1807 debugs(85, 3, "adaptation needed for " << this);
1811 new Adaptation::Iterator(request, nullptr, al, g));
1812
1813 // we could try to guess whether we can bypass this adaptation
1814 // initiation failure, but it should not really happen
1816}
1817
1818void
1820{
1823
1824 switch (answer.kind) {
1826 handleAdaptedHeader(const_cast<Http::Message*>(answer.message.getRaw()));
1827 break;
1828
1830 handleAdaptationBlock(answer);
1831 break;
1832
1834 static const auto d = MakeNamedErrorDetail("CLT_REQMOD_ABORT");
1835 handleAdaptationFailure(d, !answer.final);
1836 break;
1837 }
1838 }
1839}
1840
1841void
1843{
1844 assert(msg);
1845
1846 if (HttpRequest *new_req = dynamic_cast<HttpRequest*>(msg)) {
1847 resetRequest(new_req);
1848 assert(request->method.id());
1849 } else if (HttpReply *new_rep = dynamic_cast<HttpReply*>(msg)) {
1850 debugs(85,3, "REQMOD reply is HTTP reply");
1851
1852 // subscribe to receive reply body
1853 if (new_rep->body_pipe != nullptr) {
1854 adaptedBodySource = new_rep->body_pipe;
1855 int consumer_ok = adaptedBodySource->setConsumerIfNotLate(this);
1856 assert(consumer_ok);
1857 }
1858
1860 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1861 assert(repContext);
1863
1866 storeEntry()->replaceHttpReply(new_rep);
1868
1869 al->reply = new_rep;
1870
1871 if (!adaptedBodySource) // no body
1872 storeEntry()->complete();
1873 clientGetMoreData(node, this);
1874 }
1875
1876 // we are done with getting headers (but may be receiving body)
1878
1880 doCallouts();
1881}
1882
1883void
1891
1892void
1900
1901void
1903{
1905 assert(adaptedBodySource != nullptr);
1906
1907 if (size_t contentSize = adaptedBodySource->buf().contentSize()) {
1908 const size_t spaceAvailable = storeEntry()->bytesWanted(Range<size_t>(0,contentSize));
1909
1910 if (spaceAvailable < contentSize ) {
1911 // No or partial body data consuming
1912 typedef NullaryMemFunT<ClientHttpRequest> Dialer;
1913 AsyncCall::Pointer call = asyncCall(93, 5, "ClientHttpRequest::resumeBodyStorage",
1915 storeEntry()->deferProducer(call);
1916 }
1917
1918 if (!spaceAvailable)
1919 return;
1920
1921 if (spaceAvailable < contentSize )
1922 contentSize = spaceAvailable;
1923
1925 const StoreIOBuffer ioBuf(&bpc.buf, request_satisfaction_offset, contentSize);
1926 storeEntry()->write(ioBuf);
1927 // assume StoreEntry::write() writes the entire ioBuf
1929 bpc.buf.consume(contentSize);
1930 bpc.checkIn();
1931 }
1932
1934 // XXX: Setting receivedWholeAdaptedReply here is a workaround for a
1935 // regression, as described in https://bugs.squid-cache.org/show_bug.cgi?id=5187#c6
1937 debugs(85, Important(72), "WARNING: Squid bug 5187 workaround triggered");
1939 }
1940 // else wait for more body data
1941}
1942
1943void
1945{
1947
1948 // distinguish this code path from future noteBodyProducerAborted() that
1949 // would continue storing/delivering (truncated) reply if necessary (TODO)
1951
1952 // should we end request satisfaction now?
1953 if (adaptedBodySource != nullptr && adaptedBodySource->exhausted())
1955}
1956
1957void
1959{
1960 debugs(85,4, this << " ends request satisfaction");
1963
1964 // TODO: anything else needed to end store entry formation correctly?
1966 // We received the entire reply per receivedWholeAdaptedReply.
1967 // We are called when we consumed everything received (per our callers).
1968 // We consume only what we store per noteMoreBodyDataAvailable().
1969 storeEntry()->completeSuccessfully("received, consumed, and, hence, stored the entire REQMOD reply");
1970 } else {
1971 storeEntry()->completeTruncated("REQMOD request satisfaction default");
1972 }
1973}
1974
1975void
1977{
1980
1981 debugs(85,3, "REQMOD body production failed");
1982 if (request_satisfaction_mode) { // too late to recover or serve an error
1983 static const auto d = MakeNamedErrorDetail("CLT_REQMOD_RESP_BODY");
1987 c->close(); // drastic, but we may be writing a response already
1988 } else {
1989 static const auto d = MakeNamedErrorDetail("CLT_REQMOD_REQ_BODY");
1991 }
1992}
1993
1994void
1996{
1997 debugs(85,3, "handleAdaptationFailure(" << bypassable << ")");
1998
1999 const bool usedStore = storeEntry() && !storeEntry()->isEmpty();
2000 const bool usedPipe = request->body_pipe != nullptr &&
2002
2003 if (bypassable && !usedStore && !usedPipe) {
2004 debugs(85,3, "ICAP REQMOD callout failed, bypassing: " << calloutContext);
2005 if (calloutContext)
2006 doCallouts();
2007 return;
2008 }
2009
2010 debugs(85,3, "ICAP REQMOD callout failed, responding with error");
2011
2013 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
2014 assert(repContext);
2015
2016 calloutsError(ERR_ICAP_FAILURE, errDetail);
2017
2018 if (calloutContext)
2019 doCallouts();
2020}
2021
2022void
2023ClientHttpRequest::callException(const std::exception &ex)
2024{
2025 if (const auto clientConn = getConn() ? getConn()->clientConnection : nullptr) {
2026 if (Comm::IsConnOpen(clientConn)) {
2027 debugs(85, 3, "closing after exception: " << ex.what());
2028 clientConn->close(); // initiate orderly top-to-bottom cleanup
2029 return;
2030 }
2031 }
2032 debugs(85, DBG_IMPORTANT, "ClientHttpRequest exception without connection. Ignoring " << ex.what());
2033 // XXX: Normally, we mustStop() but we cannot do that here because it is
2034 // likely to leave Http::Stream and ConnStateData with a dangling http
2035 // pointer. See r13480 or XXX in Http::Stream class description.
2036}
2037#endif
2038
2039// XXX: modify and use with ClientRequestContext::clientAccessCheckDone too.
2040void
2042{
2043 // The original author of the code also wanted to pass an errno to
2044 // setReplyToError, but it seems unlikely that the errno reflects the
2045 // true cause of the error at this point, so I did not pass it.
2046 if (calloutContext) {
2047 ConnStateData * c = getConn();
2049 nullptr, c, request, al);
2050#if USE_AUTH
2052 c != nullptr && c->getAuth() != nullptr ? c->getAuth() : request->auth_user_request;
2053#endif
2054 calloutContext->error->detailError(errDetail);
2056 if (c != nullptr)
2057 c->expectNoForwarding();
2058 }
2059 //else if(calloutContext == NULL) is it possible?
2060}
2061
#define ScheduleCallHere(call)
Definition AsyncCall.h:166
RefCount< AsyncCallT< Dialer > > asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition AsyncCall.h:156
CommCbFunPtrCallT< Dialer > * commCbCall(int debugSection, int debugLevel, const char *callName, const Dialer &dialer)
Definition CommCalls.h:312
ErrorDetail::Pointer MakeNamedErrorDetail(const char *name)
Definition Detail.cc:54
const char * errorTypeName(err_type err)
Definition Error.h:77
Ip::NfMarkConfig aclFindNfMarkConfig(acl_nfmark *head, ACLChecklist *ch)
Checks for a netfilter mark value to apply depending on the ACL.
Definition FwdState.cc:1470
tos_t aclMapTOS(acl_tos *head, ACLChecklist *ch)
Checks for a TOS value to apply depending on the ACL.
Definition FwdState.cc:1458
ssize_t HttpHeaderPos
Definition HttpHeader.h:45
#define HttpHeaderInitPos
Definition HttpHeader.h:48
void UpdateRequestNotes(ConnStateData *csd, HttpRequest &request, NotePairs const &helperNotes)
void httpRequestPack(void *obj, Packable *p)
@ LOG_TCP_DENIED
Definition LogTags.h:55
@ LOG_TAG_NONE
Definition LogTags.h:41
time_t squid_curtime
void SBufToCstring(char *d, const SBuf &s)
Definition SBuf.h:756
class SquidConfig Config
int strListIsSubstr(const String *list, const char *s, char del)
Definition StrList.cc:63
SBuf StringToSBuf(const String &s)
create a new SBuf from a String by copying contents
#define Must(condition)
int matchDomainName(const char *h, const char *d, MatchDomainNameFlags flags)
Definition Uri.cc:903
char * urlCanonicalCleanWithoutRequest(const SBuf &url, const HttpRequestMethod &method, const AnyP::UriScheme &scheme)
Definition Uri.cc:790
void fvdbCountVia(const SBuf &)
void fvdbCountForwarded(const SBuf &)
count occurrences of the given X-Forwarded-For header value
err_type FindDenyInfoPage(const Acl::Answer &answer, const bool redirect_allowed)
Definition Gadgets.cc:34
bool aclIsProxyAuth(const std::optional< SBuf > &name)
Definition Gadgets.cc:62
void error(char *format,...)
#define assert(EX)
Definition assert.h:17
#define USE_AUTH
Definition autoconf.h:1502
#define USE_ADAPTATION
Definition autoconf.h:1496
#define cbdataReferenceDone(var)
Definition cbdata.h:357
#define cbdataReference(var)
Definition cbdata.h:348
#define CBDATA_CLASS_INIT(type)
Definition cbdata.h:325
static void NonBlockingCheck(MakingPointer &&p, ACLCB *cb, void *data)
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
void syncAle(HttpRequest *adaptedRequest, const char *logUri) const override
assigns uninitialized adapted_request and url ALE components
AnyP::PortCfgPointer port
Security::CertPointer sslClientCert
cert received from the client
struct timeval start_time
The time the master transaction started.
int bumpMode
whether and how the request was SslBumped
HttpReplyPointer reply
class AccessLogEntry::CacheDetails cache
HierarchyLogEntry hier
void syncNotes(HttpRequest *request)
Comm::ConnectionPointer tcpClient
TCP/IP level details about the client connection.
HttpRequest * request
void setVirginUrlForMissingRequest(const SBuf &vu)
Remember Client URI (or equivalent) when there is no HttpRequest.
ProxyProtocol::HeaderPointer proxyProtocolHeader
see ConnStateData::proxyProtocolHeader_
class AccessLogEntry::SslDetails ssl
void updateError(const Error &)
sets (or updates the already stored) transaction error as needed
int kind
the matched custom access list verb (or zero)
Definition Acl.h:99
bool denied() const
Definition Acl.h:88
const SBuf & lastCheckDescription() const
describes the ACL that was evaluated last while obtaining this answer (for debugging)
Definition Acl.cc:123
bool conflicted() const
whether Squid is uncertain about the allowed() or denied() answer
Definition Acl.h:91
bool allowed() const
Definition Acl.h:82
std::optional< SBuf > lastCheckedName
the name of the ACL (if any) that was evaluated last while obtaining this answer
Definition Acl.h:105
static bool Start(Method method, VectPoint vp, HttpRequest *req, HttpReply *, const AccessLogEntryPointer &, Adaptation::Initiator *)
summarizes adaptation service answer for the noteAdaptationAnswer() API
Definition Answer.h:25
Acl::Answer blockedToChecklistAnswer() const
creates an Acl::Answer from akBlock answer
Definition Answer.cc:44
Kind kind
the type of the answer
Definition Answer.h:47
Http::MessagePointer message
HTTP request or response to forward.
Definition Answer.h:44
bool final
whether the error, if any, cannot be bypassed
Definition Answer.h:46
@ akForward
forward the supplied adapted HTTP message
Definition Answer.h:29
@ akBlock
block or deny the master xaction; see authority
Definition Answer.h:30
@ akError
no adapted message will come; see bypassable
Definition Answer.h:31
CbcPointer< Initiate > initiateAdaptation(Initiate *x)
< starts freshly created initiate and returns a safe pointer to it
Definition Initiator.cc:23
void clearAdaptation(CbcPointer< Initiate > &x)
clears the pointer (does not call announceInitiatorAbort)
Definition Initiator.cc:32
void announceInitiatorAbort(CbcPointer< Initiate > &x)
inform the transaction about abnormal termination and clear the pointer
Definition Initiator.cc:38
bool initiated(const CbcPointer< AsyncJob > &job) const
Must(initiated(initiate)) instead of Must(initiate.set()), for clarity.
Definition Initiator.h:52
iterates services in ServiceGroup, starting adaptation launchers
Definition Iterator.h:32
Port defaultPort() const
Definition UriScheme.cc:71
AnyP::UriScheme const & getScheme() const
Definition Uri.h:58
SBuf & authority(bool requirePort=false) const
Definition Uri.cc:721
void setScheme(const AnyP::ProtocolType &p, const char *str)
convert the URL scheme to that given
Definition Uri.h:61
void path(const char *p)
Definition Uri.h:96
static char * cleanup(const char *uri)
Definition Uri.cc:1076
void port(const Port p)
reset authority port subcomponent
Definition Uri.h:90
void host(const char *src)
Definition Uri.cc:154
bool parse(const HttpRequestMethod &, const SBuf &url)
Definition Uri.cc:326
void userInfo(const SBuf &s)
Definition Uri.h:70
char const * denyMessage(char const *const default_message=nullptr) const
void stopConsumingFrom(RefCount< BodyPipe > &)
Definition BodyPipe.cc:118
MemBuf & buf
Definition BodyPipe.h:74
const MemBuf & buf() const
Definition BodyPipe.h:137
bool exhausted() const
Definition BodyPipe.cc:174
uint64_t consumedSize() const
Definition BodyPipe.h:111
bool setConsumerIfNotLate(const Consumer::Pointer &aConsumer)
Definition BodyPipe.cc:228
int64_t prepPartialResponseGeneration()
ClientHttpRequest(ConnStateData *)
void noteAdaptationAclCheckDone(Adaptation::ServiceGroupPointer) override
void noteMoreBodyDataAvailable(BodyPipe::Pointer) override
struct ClientHttpRequest::Out out
void clearRequest()
resets the current request and log_uri to nil
HttpRequest *const request
void resumeBodyStorage()
called by StoreEntry when it has more buffer space available
bool receivedWholeAdaptedReply
noteBodyProductionEnded() was called
void noteBodyProductionEnded(BodyPipe::Pointer) override
int64_t mRangeCLen() const
void calloutsError(const err_type, const ErrorDetail::Pointer &)
Build an error reply. For use with the callouts.
void absorbLogUri(char *)
assigns log_uri with aUri without copying the entire C-string
ConnStateData * getConn() const
String rangeBoundaryStr() const
void initRequest(HttpRequest *)
void setLogUriToRequestUri()
sets log_uri when we know the current request
void checkForInternalAccess()
Checks whether the current request is internal and adjusts it accordingly.
void updateError(const Error &)
if necessary, stores new error information (if any)
CbcPointer< Adaptation::Initiate > virginHeadSource
void updateLoggingTags(const LogTags_ot code)
update the code in the transaction processing tags
MemObject * memObject() const
void setLogUriToRawUri(const char *, const HttpRequestMethod &)
size_t req_sz
raw request size on input, not current request size
void setErrorUri(const char *)
BodyPipe::Pointer adaptedBodySource
Ssl::BumpMode sslBumpNeed_
whether (and how) the request needs to be bumped
HttpHdrRangeIter range_iter
void noteAdaptationAnswer(const Adaptation::Answer &) override
void handleAdaptedHeader(Http::Message *)
struct ClientHttpRequest::Flags flags
void resetRequest(HttpRequest *)
void resetRequestXXX(HttpRequest *, bool uriChanged)
void callException(const std::exception &) override
called when the job throws during an async call
void assignRequest(HttpRequest *)
StoreEntry * storeEntry() const
void handleAdaptationBlock(const Adaptation::Answer &)
void noteBodyProducerAborted(BodyPipe::Pointer) override
void sslBumpEstablish(Comm::Flag)
bool sslBumpNeeded() const
returns true if and only if the request needs to be bumped
ClientRequestContext * calloutContext
Ssl::BumpMode sslBumpNeed() const
returns raw sslBump mode value
const LogTags & loggingTags() const
the processing tags associated with this request transaction.
void handleAdaptationFailure(const ErrorDetail::Pointer &, bool bypassable=false)
const AccessLogEntry::Pointer al
access.log entry
StoreEntry * loggingEntry() const
void startAdaptation(const Adaptation::ServiceGroupPointer &)
Initiate an asynchronous adaptation transaction which will call us back.
struct ClientHttpRequest::Redirect redirect
void clientAccessCheckDone(const Acl::Answer &)
void clientStoreIdDone(const Helper::Reply &)
void clientRedirectDone(const Helper::Reply &)
void sslBumpAccessCheckDone(const Acl::Answer &answer)
The callback function for ssl-bump access check list.
ClientRequestContext(ClientHttpRequest *)
bool readNextRequest
whether Squid should read after error handling
ClientHttpRequest * http
void checkNoCache()
applies "cache allow/deny" rules, asynchronously if needed
ErrorState * error
saved error page for centralized/delayed processing
void hostHeaderVerifyFailed(const char *A, const char *B)
size_t currentXffHopNumber
number of X-Forwarded-For header values processed so far
void hostHeaderIpVerify(const ipcache_addrs *, const Dns::LookupDetails &)
void checkNoCacheDone(const Acl::Answer &)
static void Reset()
forgets the current context, setting it to nil/unknown
Comm::Flag flag
comm layer result status.
Definition CommCalls.h:82
Comm::ConnectionPointer conn
Definition CommCalls.h:80
bool isOpen() const
Definition Connection.h:101
Ip::Address local
Definition Connection.h:149
Ssl::ServerBump * serverBump()
struct ConnStateData::@29 pinning
bool auth
pinned for www authentication
bool switchedToHttps() const
const ProxyProtocol::HeaderPointer & proxyProtocolHeader() const
Comm::ConnectionPointer serverConnection
void switchToHttps(ClientHttpRequest *, Ssl::BumpMode bumpServerMode)
void setAuth(const Auth::UserRequest::Pointer &aur, const char *cause)
const Auth::UserRequest::Pointer & getAuth() const
Error bareError
a problem that occurred without a request (e.g., while parsing headers)
void expectNoForwarding()
cleans up virgin request [body] forwarding state
struct ConnStateData::@28 flags
bool isOpen() const
Ip::Address log_addr
Ssl::BumpMode sslBumpMode
ssl_bump decision (Ssl::bumpEnd if n/a).
bool readMore
needs comm_read (for this request or new requests)
AnyP::Port port
destination port of the request that caused serverConnection
void setServerBump(Ssl::ServerBump *srvBump)
static std::ostream & Extra(std::ostream &)
Definition debug.cc:1316
bool have(const Ip::Address &ip, size_t *position=nullptr) const
Definition ipcache.cc:984
encapsulates DNS lookup results
err_type type
Definition errorpage.h:170
void detailError(const ErrorDetail::Pointer &dCode)
set error type-specific detail code
Definition errorpage.h:111
Auth::UserRequest::Pointer auth_user_request
Definition errorpage.h:175
Http::StatusCode httpStatus
Definition errorpage.h:173
a transaction problem
Definition Error.h:27
err_type category
primary error classification (or ERR_NONE)
Definition Error.h:55
void update(const Error &)
if necessary, stores the given error information (if any)
Definition Error.cc:51
NotePairs notes
Definition Reply.h:62
Helper::ResultCode result
The helper response 'result' field.
Definition Reply.h:59
bool hasNoCache(const String **val=nullptr) const
Definition HttpHdrCc.h:89
bool hasOnlyIfCached() const
Definition HttpHdrCc.h:145
HttpHdrRange::iterator pos
HttpHdrRange::iterator end
iterator begin()
iterator end()
std::vector< HttpHdrRangeSpec * > specs
int64_t lowestOffset(int64_t) const
Http::HdrType id
Definition HttpHeader.h:66
int delById(Http::HdrType id)
String getList(Http::HdrType id) const
HttpHeaderEntry * getEntry(HttpHeaderPos *pos) const
const char * getStr(Http::HdrType id) const
time_t getTime(Http::HdrType id) const
HttpHdrRange * getRange() const
int has(Http::HdrType id) const
int hasListMember(Http::HdrType id, const char *member, const char separator) const
MemBuf * pack() const
Definition HttpReply.cc:112
int64_t bodySize(const HttpRequestMethod &) const
Definition HttpReply.cc:377
static HttpReplyPointer MakeConnectionEstablished()
construct and return an HTTP/200 (Connection Established) response
Definition HttpReply.cc:121
bool respMaybeCacheable() const
Http::MethodType id() const
void recordLookup(const Dns::LookupDetails &detail)
HttpHdrRange * range
CbcPointer< ConnStateData > clientConnectionManager
HttpRequestMethod method
HttpRequest * clone() const override
Ip::Address indirect_client_addr
String store_id
RequestFlags flags
String x_forwarded_for_iterator
void detailError(const err_type c, const ErrorDetail::Pointer &d)
sets error detail if no earlier detail was available
NotePairs::Pointer notes()
ConnStateData * pinnedConnection()
void ignoreRange(const char *reason)
forgets about the cached Range header (for a reason)
const SBuf storeId()
bool maybeCacheable()
char * canonicalCleanUrl() const
Ip::Address my_addr
Auth::UserRequest::Pointer auth_user_request
Error error
the first transaction problem encountered (or falsy)
Adaptation::Icap::History::Pointer icapHistory() const
Returns possibly nil history, creating it if icap logging is enabled.
AnyP::Uri url
the request URI
Ip::Address client_addr
const SBuf & effectiveRequestUri() const
RFC 7230 section 5.5 - Effective Request URI.
const HeaderTableRecord & lookup(const char *buf, const std::size_t len) const
look record type up by name (C-string and length)
common parts of HttpRequest and HttpReply
Definition Message.h:26
HttpHeader header
Definition Message.h:74
BodyPipe::Pointer body_pipe
optional pipeline to receive message body
Definition Message.h:97
HttpHdrCc * cache_control
Definition Message.h:76
AnyP::ProtocolVersion http_ver
Definition Message.h:72
unsigned short port() const
Definition Address.cc:790
mb_size_t contentSize() const
available data size
Definition MemBuf.h:47
void consume(mb_size_t sz)
removes sz bytes and "packs" by moving content left
Definition MemBuf.cc:168
const HttpReply & baseReply() const
Definition MemObject.h:60
void appendNewOnly(const NotePairs *src)
Definition Notes.cc:391
const char * findFirst(const char *noteKey) const
Definition Notes.cc:307
Definition Range.h:19
C * getRaw() const
Definition RefCount.h:89
bool doneFollowXff() const
bool interceptTproxy
Set for requests handled by a "tproxy" port.
bool connectionAuth
bool forceTunnel
whether to forward via TunnelStateData (instead of FwdState)
bool connectionProxyAuth
bool done_follow_x_forwarded_for
void disableCacheUse(const char *reason)
bool connectionAuthDisabled
SupportOrVeto cachable
whether the response may be stored in the cache
Definition SBuf.h:94
const char * c_str()
Definition SBuf.cc:516
void resetWithoutLocking(T *t)
Reset raw pointer - unlock any previous one and save new one without locking.
Comm::ConnectionPointer clientConnection
Definition Server.h:100
void stopReading()
cancels Comm::Read() if it is scheduled
Definition Server.cc:60
acl_access * adapted_http
int log_uses_indirect_client
int acl_uses_indirect_client
wordlist * store_id
acl_access * followXFF
acl_access * redirector
int hostStrictVerify
int reload_into_ims
acl_access * http
struct SquidConfig::@83 Program
wordlist * redirect
char * surrogate_id
struct SquidConfig::@90 onoff
unsigned short icp
struct SquidConfig::UrlHelperTimeout onUrlRewriteTimeout
acl_access * ssl_bump
struct SquidConfig::@91 accessList
struct SquidConfig::@78 Port
struct SquidConfig::@84 Accel
acl_access * noCache
int global_internal_static
void completeSuccessfully(const char *whyWeAreSureWeStoredTheWholeReply)
Definition store.cc:1017
size_t bytesWanted(Range< size_t > const aRange, bool ignoreDelayPool=false) const
Definition store.cc:213
void completeTruncated(const char *whyWeConsiderTheReplyTruncated)
Definition store.cc:1024
int unlock(const char *context)
Definition store.cc:469
void complete()
Definition store.cc:1031
void write(StoreIOBuffer)
Definition store.cc:780
void lock(const char *context)
Definition store.cc:445
bool timestampsSet()
Definition store.cc:1387
void replaceHttpReply(const HttpReplyPointer &, const bool andStartWriting=true)
Definition store.cc:1705
bool isEmpty() const
Definition Store.h:65
void deferProducer(const AsyncCall::Pointer &producer)
call back producer when more buffer space is available
Definition store.cc:366
void clean()
Definition String.cc:104
char const * rawBuf() const
Definition SquidString.h:87
void cut(size_type newLength)
Definition String.cc:210
char const * termedBuf() const
Definition SquidString.h:93
size_type size() const
Definition SquidString.h:74
void veto()
makes decision() false regardless of past or future support() calls
void createStoreEntry(const HttpRequestMethod &m, RequestFlags flags)
void setReplyToStoreEntry(StoreEntry *e, const char *reason)
replaces current response store entry with the given one
void setReplyToError(err_type, Http::StatusCode, char const *, const ConnStateData *, HttpRequest *, const char *, Auth::UserRequest::Pointer)
builds error using clientBuildError() and calls setReplyToError() below
void CSD(clientStreamNode *, ClientHttpRequest *)
client stream detach
void CSR(clientStreamNode *, ClientHttpRequest *)
client stream read
clientStream_status_t CSS(clientStreamNode *, ClientHttpRequest *)
ACLFilledChecklist::MakingPointer clientAclChecklistCreate(const acl_access *acl, ClientHttpRequest *http)
CSR clientGetMoreData
ErrorState * clientBuildError(err_type, Http::StatusCode, char const *, const ConnStateData *, HttpRequest *, const AccessLogEntry::Pointer &)
static void clientInterpretRequestHeaders(ClientHttpRequest *http)
static void clientRedirectAccessCheckDone(Acl::Answer answer, void *data)
CSS clientReplyStatus
static void clientFollowXForwardedForCheck(Acl::Answer answer, void *data)
#define FAILURE_MODE_TIME
static void checkNoCacheDoneWrapper(Acl::Answer, void *)
static void sslBumpAccessCheckDoneWrapper(Acl::Answer, void *)
ErrorState * clientBuildError(err_type, Http::StatusCode, char const *url, const ConnStateData *, HttpRequest *, const AccessLogEntry::Pointer &)
static void hostHeaderIpVerifyWrapper(const ipcache_addrs *ia, const Dns::LookupDetails &dns, void *data)
static void clientCheckPinning(ClientHttpRequest *http)
static int clientHierarchical(ClientHttpRequest *http)
static HLPCB clientStoreIdDoneWrapper
static void clientStoreIdAccessCheckDone(Acl::Answer answer, void *data)
static void checkFailureRatio(err_type, hier_code)
static HLPCB clientRedirectDoneWrapper
CSD clientReplyDetach
static void clientAccessCheckDoneWrapper(Acl::Answer, void *)
CSR clientGetMoreData
static void SslBumpEstablish(const Comm::ConnectionPointer &, char *, size_t, Comm::Flag errflag, int, void *data)
#define SQUID_X_FORWARDED_FOR_HOP_MAX
void tunnelStart(ClientHttpRequest *)
Definition tunnel.cc:1259
#define Important(id)
Definition Messages.h:93
#define DBG_IMPORTANT
Definition Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
#define DBG_CRITICAL
Definition Stream.h:37
#define REDIRECT_DONE
Definition defines.h:55
#define REDIRECT_PENDING
Definition defines.h:54
#define MAX_URL
Definition defines.h:76
static int port
err_type
Definition forward.h:14
@ ERR_ACCESS_DENIED
Definition forward.h:18
@ ERR_CONNECT_FAIL
Definition forward.h:30
@ ERR_SECURE_CONNECT_FAIL
Definition forward.h:31
@ ERR_DNS_FAIL
Definition forward.h:35
@ ERR_GATEWAY_FAILURE
Definition forward.h:67
@ ERR_NONE
Definition forward.h:15
@ ERR_ICAP_FAILURE
Definition forward.h:64
@ ERR_CONFLICT_HOST
Definition forward.h:48
@ ERR_READ_ERROR
Definition forward.h:28
@ ERR_CACHE_ACCESS_DENIED
Definition forward.h:19
void fd_note(int fd, const char *s)
Definition fd.cc:211
#define fd_table
Definition fde.h:189
int refresh_nocache_hack
char ThisCache2[RFC2181_MAXHOSTNAMELEN<< 1]
int neighbors_do_private_keys
double request_failure_ratio
time_t hit_only_mode_until
@ ACCESS_AUTH_REQUIRED
Definition Acl.h:46
@ ACCESS_DENIED
Definition Acl.h:41
@ ACCESS_ALLOWED
Definition Acl.h:42
void clientStreamRead(clientStreamNode *thisObject, ClientHttpRequest *http, StoreIOBuffer readBuffer)
void errorAppendEntry(StoreEntry *entry, ErrorState *err)
Definition errorpage.cc:738
void ipcache_nbgethostbyname(const char *name, IPH *handler, void *handlerData)
Definition ipcache.cc:609
const char * bumpMode(int bm)
Definition support.h:144
const char * sslGetUserEmail(SSL *ssl)
Definition support.cc:981
BumpMode
Definition support.h:132
@ bumpTerminate
Definition support.h:132
@ bumpEnd
Definition support.h:132
@ bumpClientFirst
Definition support.h:132
@ bumpSplice
Definition support.h:132
@ bumpBump
Definition support.h:132
void HLPCB(void *, const Helper::Reply &)
Definition forward.h:33
hier_code
Definition hier_code.h:12
@ HIER_NONE
Definition hier_code.h:13
void HTTPMSGUNLOCK(M *&a)
Definition Message.h:150
void HTTPMSGLOCK(Http::Message *a)
Definition Message.h:161
bool ForSomeCacheManager(const SBuf &urlPath)
Definition internal.cc:86
bool internalStaticCheck(const SBuf &urlPath)
Definition internal.cc:79
bool internalCheck(const SBuf &urlPath)
Definition internal.cc:72
const char * internalHostname(void)
Definition internal.cc:149
bool internalHostnameIs(const SBuf &arg)
Definition internal.cc:165
unsigned char tos_t
Definition forward.h:27
@ methodReqmod
Definition Elements.h:17
@ pointPreCache
Definition Elements.h:18
@ PROTO_HTTP
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition Connection.cc:27
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
Definition Write.cc:33
Flag
Definition Flag.h:15
@ OK
Definition Flag.h:16
@ ERR_CLOSING
Definition Flag.h:24
@ Unknown
Definition ResultCode.h:17
@ BrokenHelper
Definition ResultCode.h:20
@ TimedOut
Definition ResultCode.h:21
StatusCode
Definition StatusCode.h:20
@ scForbidden
Definition StatusCode.h:48
@ scUnauthorized
Definition StatusCode.h:46
@ scFound
Definition StatusCode.h:39
@ scInternalServerError
Definition StatusCode.h:73
@ scConflict
Definition StatusCode.h:54
@ scPermanentRedirect
Definition StatusCode.h:44
@ scSeeOther
Definition StatusCode.h:40
@ scProxyAuthenticationRequired
Definition StatusCode.h:52
@ scTemporaryRedirect
Definition StatusCode.h:43
@ scMovedPermanently
Definition StatusCode.h:38
@ METHOD_TRACE
Definition MethodType.h:30
@ METHOD_OTHER
Definition MethodType.h:93
@ METHOD_CONNECT
Definition MethodType.h:29
@ METHOD_GET
Definition MethodType.h:25
@ METHOD_HEAD
Definition MethodType.h:28
@ PROXY_AUTHORIZATION
@ IF_MODIFIED_SINCE
const HeaderLookupTable_t HeaderLookupTable
bool setNfConnmark(Comm::ConnectionPointer &conn, const ConnectionDirection connDir, const NfMarkConfig &cm)
Definition QosConfig.cc:186
@ dirAccepted
accepted (from a client by Squid)
Definition QosConfig.h:71
Config TheConfig
Globally available instance of Qos::Config.
Definition QosConfig.cc:288
int setSockTos(const Comm::ConnectionPointer &conn, tos_t tos)
Definition QosConfig.cc:558
int setSockNfmark(const Comm::ConnectionPointer &conn, nfmark_t mark)
Definition QosConfig.cc:590
#define xfree
#define xstrdup
void storeIdStart(ClientHttpRequest *http, HLPCB *handler, void *data)
Definition redirect.cc:312
void redirectStart(ClientHttpRequest *http, HLPCB *handler, void *data)
Definition redirect.cc:286
@ toutActBypass
Definition redirect.h:16
StoreEntry * storeCreateEntry(const char *url, const char *logUrl, const RequestFlags &flags, const HttpRequestMethod &method)
Definition store.cc:759
int64_t strtoll(const char *nptr, char **endptr, int base)
Definition strtoll.c:61
Definition parse.c:104
struct timeval current_time
the current UNIX time in timeval {seconds, microseconds} format
Definition gadgets.cc:18
int getMyPort(void)
Definition tools.cc:1042
void debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
Definition tools.cc:939
void(* ObjPackMethod)(void *obj, Packable *p)
Definition tools.h:33
#define safe_free(x)
Definition xalloc.h:73
#define xisspace(x)
Definition xis.h:15
char * xstrndup(const char *s, size_t n)
Definition xstring.cc:56