ACLFilledChecklist ch(DelayPools::delay_data[pool].access, r, nullptr);
clientAclChecklistFill(ch, http);
- if (!ch.reply && reply) {
- ch.reply = reply;
- HTTPMSGLOCK(reply);
- }
+ ch.updateReply(reply);
// overwrite ACLFilledChecklist acl_uses_indirect_client-based decision
#if FOLLOW_X_FORWARDED_FOR
if (Config.onoff.delay_pool_uses_indirect_client)
}
ACLFilledChecklist checklist(hm->access_list, request, nullptr);
-
- checklist.al = al;
- if (al && al->reply) {
- checklist.reply = al->reply.getRaw();
- HTTPMSGLOCK(checklist.reply);
- }
+ checklist.updateAle(al);
// XXX: The two "It was denied" clauses below mishandle cases with no
// matching rules, violating the "If no rules within the set have matching
httpHdrAdd(HttpHeader *heads, HttpRequest *request, const AccessLogEntryPointer &al, HeaderWithAclList &headersAdd)
{
ACLFilledChecklist checklist(nullptr, request, nullptr);
-
- checklist.al = al;
- if (al && al->reply) {
- checklist.reply = al->reply.getRaw();
- HTTPMSGLOCK(checklist.reply);
- }
+ checklist.updateAle(al);
for (HeaderWithAclList::const_iterator hwa = headersAdd.begin(); hwa != headersAdd.end(); ++hwa) {
if (!hwa->aclList || checklist.fastCheck(hwa->aclList).allowed()) {
return;
ACLFilledChecklist ch(nullptr, &request, nullptr);
- // XXX: cont-cast becomes irrelevant when checklist is HttpReply::Pointer
- ch.reply = const_cast<HttpReply *>(this);
- HTTPMSGLOCK(ch.reply);
+ ch.updateReply(this);
for (AclSizeLimit *l = Config.ReplyBodySize; l; l = l -> next) {
/* if there is no ACL list or if the ACLs listed match use this size value */
if (!l->aclList || ch.fastCheck(l->aclList).allowed()) {
Note::match(HttpRequest *request, HttpReply *reply, const AccessLogEntry::Pointer &al, SBuf &matched)
{
ACLFilledChecklist ch(nullptr, request, nullptr);
- ch.al = al;
- ch.reply = reply;
+ ch.updateAle(al);
+ ch.updateReply(reply);
ch.syncAle(request, nullptr);
- if (reply)
- HTTPMSGLOCK(ch.reply);
for (const auto &v: values) {
assert(v->aclList);
const bool safeRequest =
!(filled->request->sources & Http::Message::srcUnsafe);
- const bool safeReply = !filled->reply ||
- !(filled->reply->sources & Http::Message::srcUnsafe);
+ const bool safeReply = !filled->hasReply() ||
+ !(filled->reply().sources & Http::Message::srcUnsafe);
return (safeRequest && safeReply) ? 1 : 0;
}
ACLFilledChecklist::ACLFilledChecklist() :
dst_rdns(nullptr),
- reply (nullptr),
#if USE_AUTH
auth_user_request (nullptr),
#endif
safe_free(dst_rdns); // created by xstrdup().
- HTTPMSGUNLOCK(reply);
-
cbdataReferenceDone(conn_);
debugs(28, 4, "ACLFilledChecklist destroyed " << this);
}
}
- if (reply && !al->reply) {
+ if (hasReply() && !al->reply) {
showDebugWarning("HttpReply object");
- al->reply = reply;
+ al->reply = reply_;
}
#if USE_IDENT
*/
ACLFilledChecklist::ACLFilledChecklist(const acl_access *A, HttpRequest *http_request, const char *ident):
dst_rdns(nullptr),
- reply(nullptr),
#if USE_AUTH
auth_user_request(nullptr),
#endif
#endif
}
+void
+ACLFilledChecklist::updateAle(const AccessLogEntry::Pointer &a)
+{
+ if (!a)
+ return;
+
+ al = a; // could have been set already (to a different value)
+ if (!request)
+ setRequest(a->request);
+ updateReply(a->reply);
+}
+
+void
+ACLFilledChecklist::updateReply(const HttpReply::Pointer &r)
+{
+ if (r)
+ reply_ = r; // may already be set, including to r
+}
+
#include "acl/forward.h"
#include "base/CbcPointer.h"
#include "error/forward.h"
+#include "HttpReply.h"
#include "HttpRequest.h"
#include "ip/Address.h"
#if USE_AUTH
/// configure rfc931 user identity for the first time
void setIdent(const char *userIdentity);
+ /// Remembers the given ALE (if it is not nil) or does nothing (otherwise).
+ /// When (and only when) remembering ALE, populates other still-unset fields
+ /// with ALE-derived information, so that the caller does not have to.
+ void updateAle(const AccessLogEntry::Pointer &);
+
public:
/// The client connection manager
ConnStateData * conn() const;
/// set the client side FD
void fd(int aDescriptor);
+ /// response added by updateReply()
+ /// \prec hasReply()
+ const HttpReply &reply() const { return *reply_; }
+
+ /// Remembers the given response (if it is not nil) or does nothing
+ /// (otherwise).
+ void updateReply(const HttpReply::Pointer &);
+
bool destinationDomainChecked() const;
void markDestinationDomainChecked();
bool sourceDomainChecked() const;
// ACLChecklist API
bool hasRequest() const override { return request != nullptr; }
- bool hasReply() const override { return reply != nullptr; }
+ bool hasReply() const override { return reply_ != nullptr; }
bool hasAle() const override { return al != nullptr; }
void syncAle(HttpRequest *adaptedRequest, const char *logUri) const override;
void verifyAle() const override;
char *dst_rdns;
HttpRequest::Pointer request;
- HttpReply *reply;
char rfc931[USER_IDENT_SZ];
#if USE_AUTH
private:
ConnStateData * conn_; /**< hack for ident and NTLM */
int fd_; /**< may be available when conn_ is not */
+
+ HttpReply::Pointer reply_; ///< response added by updateReply() or nil
+
bool destinationDomainChecked_;
bool sourceDomainChecked_;
/// not implemented; will cause link failures if used
int
Acl::HttpRepHeaderCheck::match(ACLChecklist * const ch)
{
- return data->match(Filled(ch)->reply->header);
+ return data->match(Filled(ch)->reply().header);
}
int
ACLHTTPStatus::match(ACLChecklist *checklist)
{
- return aclMatchHTTPStatus(&data, Filled(checklist)->reply->sline.status());
+ return aclMatchHTTPStatus(&data, Filled(checklist)->reply().sline.status());
}
int
{
const auto checklist = Filled(ch);
- char const *theHeader = checklist->reply->header.getStr(header);
+ const auto theHeader = checklist->reply().header.getStr(header);
if (nullptr == theHeader)
return 0;
{
const auto checklist = Filled(ch);
- char const *theHeader = checklist->reply->header.getStr(Http::HdrType::CONTENT_TYPE);
+ auto theHeader = checklist->reply().header.getStr(Http::HdrType::CONTENT_TYPE);
if (nullptr == theHeader)
theHeader = "";
/* BUG 2526: what to do when r->acl is empty?? */
// XXX: we do not have access to conn->rfc931 here.
acl_checklist = new ACLFilledChecklist(r->acl, filter.request, dash_str);
- if ((acl_checklist->reply = filter.reply))
- HTTPMSGLOCK(acl_checklist->reply);
- acl_checklist->al = filter.al;
+ acl_checklist->updateAle(filter.al);
+ acl_checklist->updateReply(filter.reply);
acl_checklist->syncAle(filter.request, nullptr);
acl_checklist->nonBlockingCheck(AccessCheckCallbackWrapper, this);
return;
ACLFilledChecklist *cl =
new ACLFilledChecklist(TheConfig.repeat, info.icapRequest, dash_str);
- cl->reply = info.icapReply;
- HTTPMSGLOCK(cl->reply);
+ cl->updateReply(info.icapReply);
bool result = cl->fastCheck().allowed();
delete cl;
{
if (IcapLogfileStatus == LOG_ENABLE) {
ACLFilledChecklist checklist(nullptr, al->adapted_request, nullptr);
- if (al->reply) {
- checklist.reply = al->reply.getRaw();
- HTTPMSGLOCK(checklist.reply);
- }
+ checklist.updateAle(al);
accessLogLogTo(Config.Log.icaplogs, al, &checklist);
}
}
{
if (!Auth::TheConfig.schemeLists.empty() && Auth::TheConfig.schemeAccess) {
ACLFilledChecklist ch(nullptr, request, nullptr);
- ch.reply = rep;
- HTTPMSGLOCK(ch.reply);
+ ch.updateReply(rep);
const auto answer = ch.fastCheck(Auth::TheConfig.schemeAccess);
if (answer.allowed())
return Auth::TheConfig.schemeLists.at(answer.kind).authConfigs;
#endif
- /* Add notes (if we have a request to annotate) */
if (request) {
SBuf matched;
for (auto h: Config.notes) {
}
// The al->notes and request->notes must point to the same object.
al->syncNotes(request);
- }
- ACLFilledChecklist checklist(nullptr, request, nullptr);
- if (al->reply) {
- checklist.reply = al->reply.getRaw();
- HTTPMSGLOCK(checklist.reply);
- }
-
- if (request) {
HTTPMSGUNLOCK(al->adapted_request);
al->adapted_request = request;
HTTPMSGLOCK(al->adapted_request);
}
+
+ ACLFilledChecklist checklist(nullptr, request, nullptr);
+ checklist.updateAle(al);
// no need checklist.syncAle(): already synced
- checklist.al = al;
accessLogLog(al, &checklist);
bool updatePerformanceCounters = true;
if (Config.accessList.stats_collection) {
ACLFilledChecklist statsCheck(Config.accessList.stats_collection, request, nullptr);
- statsCheck.al = al;
- if (al->reply) {
- statsCheck.reply = al->reply.getRaw();
- HTTPMSGLOCK(statsCheck.reply);
- }
+ statsCheck.updateAle(al);
updatePerformanceCounters = statsCheck.fastCheck().allowed();
}
checklist.setRequest(http->request);
if (!checklist.al && http->al) {
- checklist.al = http->al;
+ checklist.updateAle(http->al);
checklist.syncAle(http->request, http->log_uri);
- if (!checklist.reply && http->al->reply) {
- checklist.reply = http->al->reply.getRaw();
- HTTPMSGLOCK(checklist.reply);
- }
}
if (const auto conn = http->getConn())
if (http->request->flags.internal)
return false; // internal content "hits" cannot be blocked
- const auto &rep = http->storeEntry()->mem().freshestReply();
{
std::unique_ptr<ACLFilledChecklist> chl(clientAclChecklistCreate(Config.accessList.sendHit, http));
- chl->reply = const_cast<HttpReply*>(&rep); // ACLChecklist API bug
- HTTPMSGLOCK(chl->reply);
+ chl->updateReply(&http->storeEntry()->mem().freshestReply());
return !chl->fastCheck().allowed(); // when in doubt, block
}
}
/** Process http_reply_access lists */
ACLFilledChecklist *replyChecklist =
clientAclChecklistCreate(Config.accessList.reply, http);
- replyChecklist->reply = reply;
- HTTPMSGLOCK(replyChecklist->reply);
+ replyChecklist->updateReply(reply);
replyChecklist->nonBlockingCheck(ProcessReplyAccessResult, this);
}
// This relatively expensive check is not in StoreEntry::checkCachable:
// That method lacks HttpRequest and may be called too many times.
ACLFilledChecklist ch(acl, originalRequest().getRaw());
- ch.reply = const_cast<HttpReply*>(&entry->mem().freshestReply()); // ACLFilledChecklist API bug
- HTTPMSGLOCK(ch.reply);
- ch.al = fwd->al;
+ ch.updateAle(fwd->al);
+ ch.updateReply(&entry->mem().freshestReply());
if (!ch.fastCheck().allowed()) { // when in doubt, block
debugs(20, 3, "store_miss prohibits caching");
return true;
// check whether the 1xx response forwarding is allowed by squid.conf
if (Config.accessList.reply) {
ACLFilledChecklist ch(Config.accessList.reply, originalRequest().getRaw());
- ch.al = fwd->al;
- ch.reply = reply.getRaw();
+ ch.updateAle(fwd->al);
+ ch.updateReply(reply);
ch.syncAle(originalRequest().getRaw(), nullptr);
- HTTPMSGLOCK(ch.reply);
if (!ch.fastCheck().allowed()) // TODO: support slow lookups?
return drop1xx("http_reply_access blocked it");
}
for (const auto &pool: MessageDelayPools::Instance()->pools) {
if (pool->access) {
std::unique_ptr<ACLFilledChecklist> chl(clientAclChecklistCreate(pool->access, http));
- chl->reply = rep;
- HTTPMSGLOCK(chl->reply);
+ chl->updateReply(rep);
const auto answer = chl->fastCheck();
if (answer.allowed()) {
writeQuotaHandler = pool->createBucket();
return true;
ACLFilledChecklist checklist(p->access, request, nullptr);
- checklist.al = ps->al;
- if (ps->al && ps->al->reply) {
- checklist.reply = ps->al->reply.getRaw();
- HTTPMSGLOCK(checklist.reply);
- }
+ checklist.updateAle(ps->al);
checklist.syncAle(request, nullptr);
return checklist.fastCheck().allowed();
}