#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
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;
}
// 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()
void Adaptation::Icap::ModXact::startReading()
{
- Must(connection >= 0);
+ Must(haveConnection());
Must(!reader);
Must(!adapted.header);
Must(!adapted.body_pipe);
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;
}
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);
}
}
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())
// adapted body consumer aborted
void Adaptation::Icap::ModXact::noteBodyConsumerAborted(BodyPipe::Pointer)
{
+ detailError(ERR_DETAIL_ICAP_XACT_BODY_CONSUMER_ABORT);
mustStop("adapted body consumer aborted");
}
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)
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)
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 */