]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/adaptation/icap/ModXact.cc
Merge form trunk
[thirdparty/squid.git] / src / adaptation / icap / ModXact.cc
index f08abdf32812d56983dddcd2283032acf23fd956..6aee947d77900044a72b9e69d155a0dc817f4856 100644 (file)
 #include "adaptation/Initiator.h"
 #include "auth/UserRequest.h"
 #include "base/TextException.h"
+#include "base64.h"
 #include "ChunkedCodingParser.h"
 #include "comm.h"
+#include "comm/Connection.h"
 #include "HttpMsg.h"
 #include "HttpRequest.h"
 #include "HttpReply.h"
 #include "SquidTime.h"
+#include "err_detail_type.h"
 
 // flow and terminology:
 //     HTTP| --> receive --> encode --> write --> |network
@@ -160,11 +163,14 @@ void Adaptation::Icap::ModXact::handleCommWroteHeaders()
     Must(state.writing == State::writingHeaders);
 
     // determine next step
-    if (preview.enabled())
-        state.writing = preview.done() ? State::writingPaused : State::writingPreview;
-    else if (virginBody.expected())
+    if (preview.enabled()) {
+        if (preview.done())
+            decideWritingAfterPreview("zero-size");
+        else
+            state.writing = State::writingPreview;
+    } else if (virginBody.expected()) {
         state.writing = State::writingPrime;
-    else {
+    else {
         stopWriting(true);
         return;
     }
@@ -223,14 +229,22 @@ void Adaptation::Icap::ModXact::writePreviewBody()
 
     // change state once preview is written
 
-    if (preview.done()) {
-        debugs(93, 7, HERE << "wrote entire Preview body" << status());
+    if (preview.done())
+        decideWritingAfterPreview("body");
+}
 
-        if (preview.ieof())
-            stopWriting(true);
-        else
-            state.writing = State::writingPaused;
-    }
+/// determine state.writing after we wrote the entire preview
+void Adaptation::Icap::ModXact::decideWritingAfterPreview(const char *kind)
+{
+    if (preview.ieof()) // nothing more to write
+        stopWriting(true);
+    else if (state.parsing == State::psIcapHeader) // did not get a reply yet
+        state.writing = State::writingPaused; // wait for the ICAP server reply
+    else
+        stopWriting(true); // ICAP server reply implies no post-preview writing
+
+    debugs(93, 6, HERE << "decided on writing after " << kind << " preview" <<
+           status());
 }
 
 void Adaptation::Icap::ModXact::writePrimeBody()
@@ -465,7 +479,7 @@ bool Adaptation::Icap::ModXact::doneAll() const
 
 void Adaptation::Icap::ModXact::startReading()
 {
-    Must(connection >= 0);
+    Must(haveConnection());
     Must(!reader);
     Must(!adapted.header);
     Must(!adapted.body_pipe);
@@ -594,6 +608,12 @@ void Adaptation::Icap::ModXact::parseMore()
 void Adaptation::Icap::ModXact::callException(const std::exception &e)
 {
     if (!canStartBypass || isRetriable) {
+        if (!isRetriable) {
+            if (const TextException *te = dynamic_cast<const TextException *>(&e))
+                detailError(ERR_DETAIL_EXCEPTION_START + te->id());
+            else
+                detailError(ERR_DETAIL_EXCEPTION_OTHER);
+        }
         Adaptation::Icap::Xaction::callException(e);
         return;
     }
@@ -602,7 +622,11 @@ void Adaptation::Icap::ModXact::callException(const std::exception &e)
         debugs(93, 3, HERE << "bypassing " << inCall << " exception: " <<
                e.what() << ' ' << status());
         bypassFailure();
+    } catch (const TextException &bypassTe) {
+        detailError(ERR_DETAIL_EXCEPTION_START + bypassTe.id());
+        Adaptation::Icap::Xaction::callException(bypassTe);
     } catch (const std::exception &bypassE) {
+        detailError(ERR_DETAIL_EXCEPTION_OTHER);
         Adaptation::Icap::Xaction::callException(bypassE);
     }
 }
@@ -623,7 +647,7 @@ void Adaptation::Icap::ModXact::bypassFailure()
     stopParsing();
 
     stopWriting(true); // or should we force it?
-    if (connection >= 0) {
+    if (haveConnection()) {
         reuseConnection = false; // be conservative
         cancelRead(); // may not work; and we cannot stop connecting either
         if (!doneWithIo())
@@ -1150,6 +1174,7 @@ void Adaptation::Icap::ModXact::noteMoreBodySpaceAvailable(BodyPipe::Pointer)
 // adapted body consumer aborted
 void Adaptation::Icap::ModXact::noteBodyConsumerAborted(BodyPipe::Pointer)
 {
+    detailError(ERR_DETAIL_ICAP_XACT_BODY_CONSUMER_ABORT);
     mustStop("adapted body consumer aborted");
 }
 
@@ -1166,6 +1191,9 @@ void Adaptation::Icap::ModXact::swanSong()
     stopWriting(false);
     stopSending(false);
 
+    if (theInitiator.set()) // we have not sent the answer to the initiator
+        detailError(ERR_DETAIL_ICAP_XACT_OTHER);
+
     // update adaptation history if start was called and we reserved a slot
     Adaptation::History::Pointer ah = virginRequest().adaptLogHistory();
     if (ah != NULL && adaptHistoryId >= 0)
@@ -1573,7 +1601,7 @@ void Adaptation::Icap::ModXact::fillPendingStatus(MemBuf &buf) const
     if (virgin.body_pipe != NULL)
         buf.append("R", 1);
 
-    if (connection > 0 && !doneReading())
+    if (haveConnection() && !doneReading())
         buf.append("r", 1);
 
     if (!state.doneWriting() && state.writing != State::writingInit)
@@ -1812,6 +1840,13 @@ bool Adaptation::Icap::ModXact::fillVirginHttpHeader(MemBuf &mb) const
     return true;
 }
 
+void Adaptation::Icap::ModXact::detailError(int errDetail)
+{
+    if (HttpRequest *request = virgin.cause ?
+                               virgin.cause : dynamic_cast<HttpRequest*>(virgin.header)) {
+        request->detailError(ERR_ICAP_FAILURE, errDetail);
+    }
+}
 
 /* Adaptation::Icap::ModXactLauncher */