]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/adaptation/AccessCheck.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / adaptation / AccessCheck.cc
index e3350a466b3d4546ce87e96977b77fec1fd315d8..6ce6d91975710d6c1af7d75f3c93d1bfbb88a8d4 100644 (file)
@@ -1,30 +1,42 @@
-#include "squid.h"
-#include "structs.h"
+/*
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
 
-#include "ConfigParser.h"
-#include "HttpRequest.h"
-#include "HttpReply.h"
+#include "squid.h"
+#include "AccessLogEntry.h"
 #include "acl/FilledChecklist.h"
-#include "adaptation/Service.h"
-#include "adaptation/ServiceGroups.h"
+#include "adaptation/AccessCheck.h"
 #include "adaptation/AccessRule.h"
 #include "adaptation/Config.h"
-#include "adaptation/AccessCheck.h"
-
+#include "adaptation/Initiator.h"
+#include "adaptation/Service.h"
+#include "adaptation/ServiceGroups.h"
+#include "base/AsyncJobCalls.h"
+#include "base/TextException.h"
+#include "ConfigParser.h"
+#include "globals.h"
+#include "HttpReply.h"
+#include "HttpRequest.h"
 
-/** \cond AUTODOCS-IGNORE */
+/** \cond AUTODOCS_IGNORE */
 cbdata_type Adaptation::AccessCheck::CBDATA_AccessCheck = CBDATA_UNKNOWN;
 /** \endcond */
 
 bool
 Adaptation::AccessCheck::Start(Method method, VectPoint vp,
-                               HttpRequest *req, HttpReply *rep, AccessCheckCallback *cb, void *cbdata)
+                               HttpRequest *req, HttpReply *rep,
+                               AccessLogEntry::Pointer &al, Adaptation::Initiator *initiator)
 {
 
     if (Config::Enabled) {
         // the new check will call the callback and delete self, eventually
-        return AsyncStart(new AccessCheck(
-            ServiceFilter(method, vp, req, rep), cb, cbdata));
+        AsyncJob::Start(new AccessCheck( // we do not store so not a CbcPointer
+                            ServiceFilter(method, vp, req, rep, al), initiator));
+        return true;
     }
 
     debugs(83, 3, HERE << "adaptation off, skipping");
@@ -32,11 +44,9 @@ Adaptation::AccessCheck::Start(Method method, VectPoint vp,
 }
 
 Adaptation::AccessCheck::AccessCheck(const ServiceFilter &aFilter,
-                                     AccessCheckCallback *aCallback,
-                                     void *aCallbackData):
+                                     Adaptation::Initiator *initiator):
     AsyncJob("AccessCheck"), filter(aFilter),
-    callback(aCallback),
-    callback_data(cbdataReference(aCallbackData)),
+    theInitiator(initiator),
     acl_checklist(NULL)
 {
 #if ICAP_CLIENT
@@ -46,7 +56,7 @@ Adaptation::AccessCheck::AccessCheck(const ServiceFilter &aFilter,
 #endif
 
     debugs(93, 5, HERE << "AccessCheck constructed for " <<
-        methodStr(filter.method) << " " << vectPointStr(filter.point));
+           methodStr(filter.method) << " " << vectPointStr(filter.point));
 }
 
 Adaptation::AccessCheck::~AccessCheck()
@@ -56,14 +66,37 @@ Adaptation::AccessCheck::~AccessCheck()
     if (h != NULL)
         h->stop("ACL");
 #endif
-    if (callback_data)
-        cbdataReferenceDone(callback_data);
 }
 
 void
-Adaptation::AccessCheck::start() {
-       AsyncJob::start();
-       check();
+Adaptation::AccessCheck::start()
+{
+    AsyncJob::start();
+
+    if (!usedDynamicRules())
+        check();
+}
+
+/// returns true if previous services configured dynamic chaining "rules"
+bool
+Adaptation::AccessCheck::usedDynamicRules()
+{
+    Adaptation::History::Pointer ah = filter.request->adaptHistory();
+    if (!ah)
+        return false; // dynamic rules not enabled or not triggered
+
+    DynamicGroupCfg services;
+    if (!ah->extractFutureServices(services)) { // clears history
+        debugs(85,9, HERE << "no service-proposed rules stored");
+        return false; // earlier service did not plan for the future
+    }
+
+    debugs(85,3, HERE << "using stored service-proposed rules: " << services);
+
+    ServiceGroupPointer g = new DynamicServiceChain(services, filter);
+    callBack(g);
+    Must(done());
+    return true;
 }
 
 /// Walk the access rules list to find rules with applicable service groups
@@ -77,7 +110,7 @@ Adaptation::AccessCheck::check()
         AccessRule *r = *i;
         if (isCandidate(*r)) {
             debugs(93, 5, HERE << "check: rule '" << r->id << "' is a candidate");
-            candidates += r->id;
+            candidates.push_back(r->id);
         }
     }
 
@@ -99,12 +132,14 @@ Adaptation::AccessCheck::checkCandidates()
             /* 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);
-            acl_checklist->reply = filter.reply ? HTTPMSGLOCK(filter.reply) : NULL;
+            if ((acl_checklist->reply = filter.reply))
+                HTTPMSGLOCK(acl_checklist->reply);
+            acl_checklist->al = filter.al;
             acl_checklist->nonBlockingCheck(AccessCheckCallbackWrapper, this);
             return;
         }
 
-        candidates.shift(); // the rule apparently went away (reconfigure)
+        candidates.erase(candidates.begin()); // the rule apparently went away (reconfigure)
     }
 
     debugs(93, 4, HERE << "NO candidates left");
@@ -113,26 +148,33 @@ Adaptation::AccessCheck::checkCandidates()
 }
 
 void
-Adaptation::AccessCheck::AccessCheckCallbackWrapper(int answer, void *data)
+Adaptation::AccessCheck::AccessCheckCallbackWrapper(allow_t answer, void *data)
 {
     debugs(93, 8, HERE << "callback answer=" << answer);
     AccessCheck *ac = (AccessCheck*)data;
 
-    /** \todo AYJ 2008-06-12: If answer == ACCESS_REQ_PROXY_AUTH
+    /** \todo AYJ 2008-06-12: If answer == ACCESS_AUTH_REQUIRED
      * we should be kicking off an authentication before continuing
      * with this request. see bug 2400 for details.
      */
-    ac->noteAnswer(answer==ACCESS_ALLOWED);
+
+    // convert to async call to get async call protections and features
+    typedef UnaryMemFunT<AccessCheck, allow_t> MyDialer;
+    AsyncCall::Pointer call =
+        asyncCall(93,7, "Adaptation::AccessCheck::noteAnswer",
+                  MyDialer(ac, &Adaptation::AccessCheck::noteAnswer, answer));
+    ScheduleCallHere(call);
+
 }
 
 /// process the results of the ACL check
 void
-Adaptation::AccessCheck::noteAnswer(int answer)
+Adaptation::AccessCheck::noteAnswer(allow_t answer)
 {
     Must(!candidates.empty()); // the candidate we were checking must be there
     debugs(93,5, HERE << topCandidate() << " answer=" << answer);
 
-    if (answer) { // the rule matched
+    if (answer == ACCESS_ALLOWED) { // the rule matched
         ServiceGroupPointer g = topGroup();
         if (g != NULL) { // the corresponding group found
             callBack(g);
@@ -142,7 +184,7 @@ Adaptation::AccessCheck::noteAnswer(int answer)
     }
 
     // no match or the group disappeared during reconfiguration
-    candidates.shift();
+    candidates.erase(candidates.begin());
     checkCandidates();
 }
 
@@ -152,11 +194,8 @@ void
 Adaptation::AccessCheck::callBack(const ServiceGroupPointer &g)
 {
     debugs(93,3, HERE << g);
-
-    void *validated_cbdata;
-    if (cbdataReferenceValidDone(callback_data, &validated_cbdata)) {
-        callback(g, validated_cbdata);
-    }
+    CallJobHere1(93, 5, theInitiator, Adaptation::Initiator,
+                 noteAdaptationAclCheckDone, g);
     mustStop("done"); // called back or will never be able to call back
 }
 
@@ -184,7 +223,7 @@ bool
 Adaptation::AccessCheck::isCandidate(AccessRule &r)
 {
     debugs(93,7,HERE << "checking candidacy of " << r.id << ", group " <<
-        r.groupId);
+           r.groupId);
 
     ServiceGroupPointer g = FindGroup(r.groupId);
 
@@ -197,3 +236,4 @@ Adaptation::AccessCheck::isCandidate(AccessRule &r)
     debugs(93,7,HERE << r.groupId << (wants ? " wants" : " ignores"));
     return wants;
 }
+