/*
- * DEBUG: section 93 ICAP (RFC 3507) Client
+ * Copyright (C) 1996-2021 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 ICAP (RFC 3507) Client */
+
#include "squid.h"
-#include "HttpMsg.h"
-#include "adaptation/Service.h"
-#include "adaptation/Initiator.h"
+#include "adaptation/Answer.h"
#include "adaptation/Initiate.h"
+#include "adaptation/Initiator.h"
+#include "base/AsyncJobCalls.h"
+#include "http/Message.h"
-namespace Adaptation {
-
-// AdaptInitiator::noteAdaptionAnswer Dialer locks/unlocks the message in transit
-// TODO: replace HTTPMSGLOCK with general RefCounting and delete this class
-class AnswerDialer: public UnaryMemFunT<Initiator, HttpMsg*>
+namespace Adaptation
+{
+typedef UnaryMemFunT<Initiator, Answer, const Answer &> AnswerDialer;
+/// Calls expectNoConsumption() if noteAdaptationAnswer async call is
+/// scheduled but never fired (e.g., because the HTTP transaction aborts).
+class AnswerCall: public AsyncCallT<AnswerDialer>
{
public:
- typedef UnaryMemFunT<Initiator, HttpMsg*> Parent;
+ AnswerCall(const char *aName, const AnswerDialer &aDialer) :
+ AsyncCallT<AnswerDialer>(93, 5, aName, aDialer), fired(false) {}
+ virtual void fire() {
+ fired = true;
+ AsyncCallT<AnswerDialer>::fire();
+ }
+ virtual ~AnswerCall() {
+ if (!fired && dialer.arg1.message != NULL && dialer.arg1.message->body_pipe != NULL)
+ dialer.arg1.message->body_pipe->expectNoConsumption();
+ }
- AnswerDialer(Initiator *obj, Parent::Method meth, HttpMsg *msg):
- Parent(obj, meth, msg) { HTTPMSGLOCK(arg1); }
- AnswerDialer(const AnswerDialer &d):
- Parent(d) { HTTPMSGLOCK(arg1); }
- virtual ~AnswerDialer() { HTTPMSGUNLOCK(arg1); }
+private:
+ bool fired; ///< whether we fired the call
};
+}
-} // namespace Adaptation
-
-
-/* Initiate */
-
-Adaptation::Initiate::Initiate(const char *aTypeName,
- Initiator *anInitiator, ServicePointer aService):
- AsyncJob(aTypeName), theInitiator(anInitiator), theService(aService)
+Adaptation::Initiate::Initiate(const char *aTypeName): AsyncJob(aTypeName)
{
- assert(theService != NULL);
- assert(theInitiator);
}
Adaptation::Initiate::~Initiate()
// can assert(!(wasStarted && theInitiator)).
}
+void
+Adaptation::Initiate::initiator(const CbcPointer<Initiator> &i)
+{
+ Must(!theInitiator);
+ Must(i.valid());
+ theInitiator = i;
+}
+
// internal cleanup
void Adaptation::Initiate::swanSong()
{
debugs(93, 5, HERE << "swan sings" << status());
- if (theInitiator) {
+ if (theInitiator.set()) {
debugs(93, 3, HERE << "fatal failure; sending abort notification");
tellQueryAborted(true); // final by default
}
void Adaptation::Initiate::clearInitiator()
{
- if (theInitiator)
- theInitiator.clear();
+ theInitiator.clear();
}
-void Adaptation::Initiate::sendAnswer(HttpMsg *msg)
+void Adaptation::Initiate::sendAnswer(const Answer &answer)
{
- assert(msg);
- if (theInitiator.isThere()) {
- CallJob(93, 5, __FILE__, __LINE__, "Initiator::noteAdaptAnswer",
- AnswerDialer(theInitiator.ptr(), &Initiator::noteAdaptationAnswer, msg));
- }
+ AsyncCall::Pointer call = new AnswerCall("Initiator::noteAdaptationAnswer",
+ AnswerDialer(theInitiator, &Initiator::noteAdaptationAnswer, answer));
+ ScheduleCallHere(call);
clearInitiator();
}
-
void Adaptation::Initiate::tellQueryAborted(bool final)
{
- if (theInitiator.isThere()) {
- CallJobHere1(93, 5, theInitiator.ptr(),
- Initiator::noteAdaptationQueryAbort, final);
- }
- clearInitiator();
+ sendAnswer(Answer::Error(final));
}
-Adaptation::Service &
-Adaptation::Initiate::service()
+const char *Adaptation::Initiate::status() const
{
- assert(theService != NULL);
- return *theService;
-}
-
-const char *Adaptation::Initiate::status() const {
return AsyncJob::status(); // for now
}
-
-/* InitiatorHolder */
-
-Adaptation::InitiatorHolder::InitiatorHolder(Initiator *anInitiator):
- prime(0), cbdata(0)
-{
- if (anInitiator) {
- cbdata = cbdataReference(anInitiator->toCbdata());
- prime = anInitiator;
- }
-}
-
-Adaptation::InitiatorHolder::InitiatorHolder(const InitiatorHolder &anInitiator):
- prime(0), cbdata(0)
-{
- if (anInitiator != NULL && cbdataReferenceValid(anInitiator.cbdata)) {
- cbdata = cbdataReference(anInitiator.cbdata);
- prime = anInitiator.prime;
- }
-}
-
-Adaptation::InitiatorHolder::~InitiatorHolder()
-{
- clear();
-}
-
-void Adaptation::InitiatorHolder::clear() {
- if (prime) {
- prime = NULL;
- cbdataReferenceDone(cbdata);
- }
-}
-
-Adaptation::Initiator *Adaptation::InitiatorHolder::ptr()
-{
- assert(isThere());
- return prime;
-}
-
-bool
-Adaptation::InitiatorHolder::isThere() {
- return prime && cbdataReferenceValid(cbdata);
-}
-
-// should not be used
-Adaptation::InitiatorHolder &
-Adaptation::InitiatorHolder::operator =(const InitiatorHolder &anInitiator)
-{
- assert(false);
- return *this;
-}