]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/adaptation/Iterator.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / adaptation / Iterator.cc
index 8331f5e13c1f61a001cb149d37586b7c9913ef8a..e32f38bad0b6f7a1016971260c17fea8d7b196e5 100644 (file)
@@ -1,31 +1,45 @@
 /*
- * DEBUG: section 93    Adaptation
+ * 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.
  */
 
+/* DEBUG: section 93    Adaptation */
+
 #include "squid.h"
+#include "adaptation/Answer.h"
 #include "adaptation/Config.h"
 #include "adaptation/Iterator.h"
 #include "adaptation/Service.h"
 #include "adaptation/ServiceFilter.h"
 #include "adaptation/ServiceGroups.h"
 #include "base/TextException.h"
-#include "HttpRequest.h"
-#include "HttpReply.h"
 #include "HttpMsg.h"
-
+#include "HttpReply.h"
+#include "HttpRequest.h"
+#include "sbuf/StringConvert.h"
 
 Adaptation::Iterator::Iterator(
     HttpMsg *aMsg, HttpRequest *aCause,
+    AccessLogEntry::Pointer &alp,
     const ServiceGroupPointer &aGroup):
-        AsyncJob("Iterator"),
-        Adaptation::Initiate("Iterator"),
-        theGroup(aGroup),
-        theMsg(HTTPMSGLOCK(aMsg)),
-        theCause(aCause ? HTTPMSGLOCK(aCause) : NULL),
-        theLauncher(0),
-        iterations(0),
-        adapted(false)
+    AsyncJob("Iterator"),
+    Adaptation::Initiate("Iterator"),
+    theGroup(aGroup),
+    theMsg(aMsg),
+    theCause(aCause),
+    al(alp),
+    theLauncher(0),
+    iterations(0),
+    adapted(false)
 {
+    if (theCause != NULL)
+        HTTPMSGLOCK(theCause);
+
+    if (theMsg != NULL)
+        HTTPMSGLOCK(theMsg);
 }
 
 Adaptation::Iterator::~Iterator()
@@ -40,6 +54,19 @@ void Adaptation::Iterator::start()
     Adaptation::Initiate::start();
 
     thePlan = ServicePlan(theGroup, filter());
+
+    // Add adaptation group name once and now, before
+    // dynamic groups change it at step() time.
+    if (Adaptation::Config::needHistory && !thePlan.exhausted() && (dynamic_cast<ServiceSet *>(theGroup.getRaw()) || dynamic_cast<ServiceChain *>(theGroup.getRaw()))) {
+        HttpRequest *request = dynamic_cast<HttpRequest*>(theMsg);
+        if (!request)
+            request = theCause;
+        Must(request);
+        Adaptation::History::Pointer ah = request->adaptHistory(true);
+        auto gid = StringToSBuf(theGroup->id);
+        ah->recordAdaptationService(gid);
+    }
+
     step();
 }
 
@@ -51,11 +78,17 @@ void Adaptation::Iterator::step()
     Must(!theLauncher);
 
     if (thePlan.exhausted()) { // nothing more to do
-        sendAnswer(theMsg);
+        sendAnswer(Answer::Forward(theMsg));
         Must(done());
         return;
     }
 
+    HttpRequest *request = dynamic_cast<HttpRequest*>(theMsg);
+    if (!request)
+        request = theCause;
+    assert(request);
+    request->clearError();
+
     if (iterations > Adaptation::Config::service_iteration_limit) {
         debugs(93,DBG_CRITICAL, "Adaptation iterations limit (" <<
                Adaptation::Config::service_iteration_limit << ") exceeded:\n" <<
@@ -68,13 +101,38 @@ void Adaptation::Iterator::step()
     Must(service != NULL);
     debugs(93,5, HERE << "using adaptation service: " << service->cfg().key);
 
+    if (Adaptation::Config::needHistory) {
+        Adaptation::History::Pointer ah = request->adaptHistory(true);
+        auto uid = StringToSBuf(thePlan.current()->cfg().key);
+        ah->recordAdaptationService(uid);
+    }
+
     theLauncher = initiateAdaptation(
-                      service->makeXactLauncher(theMsg, theCause));
+                      service->makeXactLauncher(theMsg, theCause, al));
     Must(initiated(theLauncher));
     Must(!done());
 }
 
-void Adaptation::Iterator::noteAdaptationAnswer(HttpMsg *aMsg)
+void
+Adaptation::Iterator::noteAdaptationAnswer(const Answer &answer)
+{
+    switch (answer.kind) {
+    case Answer::akForward:
+        handleAdaptedHeader(const_cast<HttpMsg*>(answer.message.getRaw()));
+        break;
+
+    case Answer::akBlock:
+        handleAdaptationBlock(answer);
+        break;
+
+    case Answer::akError:
+        handleAdaptationError(answer.final);
+        break;
+    }
+}
+
+void
+Adaptation::Iterator::handleAdaptedHeader(HttpMsg *aMsg)
 {
     // set theCause if we switched to request satisfaction mode
     if (!theCause) { // probably sent a request message
@@ -90,7 +148,8 @@ void Adaptation::Iterator::noteAdaptationAnswer(HttpMsg *aMsg)
 
     Must(aMsg);
     HTTPMSGUNLOCK(theMsg);
-    theMsg = HTTPMSGLOCK(aMsg);
+    theMsg = aMsg;
+    HTTPMSGLOCK(theMsg);
     adapted = true;
 
     clearAdaptation(theLauncher);
@@ -106,7 +165,16 @@ void Adaptation::Iterator::noteInitiatorAborted()
     mustStop("initiator gone");
 }
 
-void Adaptation::Iterator::noteAdaptationQueryAbort(bool final)
+void Adaptation::Iterator::handleAdaptationBlock(const Answer &answer)
+{
+    debugs(93,5, HERE << "blocked by " << answer);
+    clearAdaptation(theLauncher);
+    updatePlan(false);
+    sendAnswer(answer);
+    mustStop("blocked");
+}
+
+void Adaptation::Iterator::handleAdaptationError(bool final)
 {
     debugs(93,5, HERE << "final: " << final << " plan: " << thePlan);
     clearAdaptation(theLauncher);
@@ -130,7 +198,7 @@ void Adaptation::Iterator::noteAdaptationQueryAbort(bool final)
 
     if (canIgnore && srcIntact && adapted) {
         debugs(85,3, HERE << "responding with older adapted msg");
-        sendAnswer(theMsg);
+        sendAnswer(Answer::Forward(theMsg));
         mustStop("sent older adapted msg");
         return;
     }
@@ -163,8 +231,10 @@ bool Adaptation::Iterator::updatePlan(bool adopt)
     Must(r);
 
     Adaptation::History::Pointer ah = r->adaptHistory();
-    if (!ah)
+    if (!ah) {
+        debugs(85,9, HERE << "no history to store a service-proposed plan");
         return false; // the feature is not enabled or is not triggered
+    }
 
     String services;
     if (!ah->extractNextServices(services)) { // clears history
@@ -179,9 +249,9 @@ bool Adaptation::Iterator::updatePlan(bool adopt)
 
     debugs(85,3, HERE << "retiring old plan: " << thePlan);
 
-    Adaptation::ServiceFilter filter = this->filter();
+    Adaptation::ServiceFilter f = this->filter();
     DynamicGroupCfg current, future;
-    DynamicServiceChain::Split(filter, services, current, future);
+    DynamicServiceChain::Split(f, services, current, future);
 
     if (!future.empty()) {
         ah->setFutureServices(future);
@@ -189,8 +259,8 @@ bool Adaptation::Iterator::updatePlan(bool adopt)
     }
 
     // use the current config even if it is empty; we must replace the old plan
-    theGroup = new DynamicServiceChain(current, filter); // refcounted
-    thePlan = ServicePlan(theGroup, filter);
+    theGroup = new DynamicServiceChain(current, f); // refcounted
+    thePlan = ServicePlan(theGroup, f);
     debugs(85,3, HERE << "adopted service-proposed plan: " << thePlan);
     return true;
 }
@@ -215,7 +285,8 @@ Adaptation::ServiceFilter Adaptation::Iterator::filter() const
         Must(false); // should not happen
     }
 
-    return ServiceFilter(method, theGroup->point, req, rep);
+    return ServiceFilter(method, theGroup->point, req, rep, al);
 }
 
 CBDATA_NAMESPACED_CLASS_INIT(Adaptation, Iterator);
+