2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
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.
10 #include "acl/FilledChecklist.h"
11 #include "client_side.h"
12 #include "comm/Connection.h"
13 #include "comm/forward.h"
14 #include "debug/Messages.h"
15 #include "ExternalACLEntry.h"
16 #include "http/Stream.h"
17 #include "HttpReply.h"
18 #include "HttpRequest.h"
19 #include "SquidConfig.h"
21 #include "auth/AclProxyAuth.h"
22 #include "auth/UserRequest.h"
25 CBDATA_CLASS_INIT(ACLFilledChecklist
);
27 ACLFilledChecklist::ACLFilledChecklist() :
30 auth_user_request (nullptr),
33 snmp_community(nullptr),
35 requestErrorType(ERR_MAX
),
38 destinationDomainChecked_(false),
39 sourceDomainChecked_(false)
46 ACLFilledChecklist::~ACLFilledChecklist()
48 assert (!asyncInProgress());
50 safe_free(dst_rdns
); // created by xstrdup().
52 cbdataReferenceDone(conn_
);
54 debugs(28, 4, "ACLFilledChecklist destroyed " << this);
58 showDebugWarning(const char *msg
)
60 static uint16_t count
= 0;
65 debugs(28, Important(58), "ERROR: ALE missing " << msg
);
69 ACLFilledChecklist::verifyAle() const
71 // make sure the ALE fields used by Format::assemble to
72 // fill the old external_acl_type codes are set if any
73 // data on them exists in the Checklist
75 if (!al
->cache
.port
&& conn()) {
76 showDebugWarning("listening port");
77 al
->cache
.port
= conn()->port
;
82 showDebugWarning("HttpRequest object");
83 // XXX: al->request should be original,
84 // but the request may be already adapted
85 al
->request
= request
.getRaw();
86 HTTPMSGLOCK(al
->request
);
89 if (!al
->adapted_request
) {
90 showDebugWarning("adapted HttpRequest object");
91 al
->adapted_request
= request
.getRaw();
92 HTTPMSGLOCK(al
->adapted_request
);
95 if (al
->url
.isEmpty()) {
96 showDebugWarning("URL");
97 // XXX: al->url should be the request URL from client,
98 // but request->url may be different (e.g.,redirected)
99 al
->url
= request
->effectiveRequestUri();
103 if (hasReply() && !al
->reply
) {
104 showDebugWarning("HttpReply object");
110 ACLFilledChecklist::syncAle(HttpRequest
*adaptedRequest
, const char *logUri
) const
114 if (adaptedRequest
&& !al
->adapted_request
) {
115 al
->adapted_request
= adaptedRequest
;
116 HTTPMSGLOCK(al
->adapted_request
);
118 if (logUri
&& al
->url
.isEmpty())
123 ACLFilledChecklist::conn() const
125 return cbdataReferenceValid(conn_
) ? conn_
: nullptr;
129 ACLFilledChecklist::setConn(ConnStateData
*aConn
)
132 return; // no new information
134 // no conn_ replacement/removal to reduce inconsistent fill concerns
138 // To reduce inconsistent fill concerns, we should be the only ones calling
139 // fillConnectionLevelDetails(). Set conn_ first so that the filling method
140 // can detect (some) direct calls from others.
141 conn_
= cbdataReference(aConn
);
142 aConn
->fillConnectionLevelDetails(*this);
146 ACLFilledChecklist::fd() const
148 const auto c
= conn();
149 return (c
&& c
->clientConnection
) ? c
->clientConnection
->fd
: fd_
;
153 ACLFilledChecklist::fd(int aDescriptor
)
155 const auto c
= conn();
156 assert(!c
|| !c
->clientConnection
|| c
->clientConnection
->fd
== aDescriptor
);
161 ACLFilledChecklist::destinationDomainChecked() const
163 return destinationDomainChecked_
;
167 ACLFilledChecklist::markDestinationDomainChecked()
169 assert (!finished() && !destinationDomainChecked());
170 destinationDomainChecked_
= true;
174 ACLFilledChecklist::sourceDomainChecked() const
176 return sourceDomainChecked_
;
180 ACLFilledChecklist::markSourceDomainChecked()
182 assert (!finished() && !sourceDomainChecked());
183 sourceDomainChecked_
= true;
187 * There are two common ACLFilledChecklist lifecycles paths:
189 * "Fast" (always synchronous or "blocking"): The user constructs an
190 * ACLFilledChecklist object on stack, configures it as needed, and calls one
191 * or both of its fastCheck() methods.
193 * "Slow" (usually asynchronous or "non-blocking"): The user allocates an
194 * ACLFilledChecklist object on heap (via Make()), configures it as needed,
195 * and passes it to NonBlockingCheck() while specifying the callback function
196 * to call with check results. NonBlockingCheck() calls the callback function
197 * (if the corresponding cbdata is still valid), either immediately/directly
198 * (XXX) or eventually/asynchronously. After this callback obligations are
199 * fulfilled, checkCallback() deletes the checklist object (i.e. "this").
201 ACLFilledChecklist::ACLFilledChecklist(const acl_access
*A
, HttpRequest
*http_request
):
204 auth_user_request(nullptr),
207 snmp_community(nullptr),
209 requestErrorType(ERR_MAX
),
212 destinationDomainChecked_(false),
213 sourceDomainChecked_(false)
220 setRequest(http_request
);
223 void ACLFilledChecklist::setRequest(HttpRequest
*httpRequest
)
227 request
= httpRequest
;
228 #if FOLLOW_X_FORWARDED_FOR
229 if (Config
.onoff
.acl_uses_indirect_client
)
230 src_addr
= request
->indirect_client_addr
;
232 #endif /* FOLLOW_X_FORWARDED_FOR */
233 src_addr
= request
->client_addr
;
234 my_addr
= request
->my_addr
;
236 if (const auto cmgr
= request
->clientConnectionManager
.get())
242 ACLFilledChecklist::updateAle(const AccessLogEntry::Pointer
&a
)
247 al
= a
; // could have been set already (to a different value)
249 setRequest(a
->request
);
250 updateReply(a
->reply
);
254 ACLFilledChecklist::updateReply(const HttpReply::Pointer
&r
)
257 reply_
= r
; // may already be set, including to r