]> git.ipfire.org Git - thirdparty/squid.git/blob - src/adaptation/icap/Launcher.cc
Merge from trunk
[thirdparty/squid.git] / src / adaptation / icap / Launcher.cc
1 /*
2 * DEBUG: section 93 ICAP (RFC 3507) Client
3 */
4
5 #include "squid.h"
6 #include "TextException.h"
7 #include "HttpRequest.h"
8 #include "HttpReply.h"
9 #include "acl/FilledChecklist.h"
10 #include "HttpMsg.h"
11 #include "adaptation/icap/Launcher.h"
12 #include "adaptation/icap/Xaction.h"
13 #include "adaptation/icap/ServiceRep.h"
14 #include "adaptation/icap/Config.h"
15
16
17 Adaptation::Icap::Launcher::Launcher(const char *aTypeName,
18 Adaptation::Initiator *anInitiator, Adaptation::ServicePointer &aService):
19 AsyncJob(aTypeName),
20 Adaptation::Initiate(aTypeName, anInitiator),
21 theService(aService), theXaction(0), theLaunches(0)
22 {
23 }
24
25 Adaptation::Icap::Launcher::~Launcher()
26 {
27 assert(!theXaction);
28 }
29
30 void Adaptation::Icap::Launcher::start()
31 {
32 Adaptation::Initiate::start();
33
34 Must(theInitiator);
35 launchXaction("first");
36 }
37
38 void Adaptation::Icap::Launcher::launchXaction(const char *xkind)
39 {
40 Must(!theXaction);
41 ++theLaunches;
42 debugs(93,4, HERE << "launching " << xkind << " xaction #" << theLaunches);
43 Adaptation::Icap::Xaction *x = createXaction();
44 x->attempts = theLaunches;
45 if (theLaunches > 1)
46 x->disableRetries();
47 if (theLaunches >= TheConfig.repeat_limit)
48 x->disableRepeats("over icap_retry_limit");
49 theXaction = initiateAdaptation(x);
50 Must(theXaction);
51 }
52
53 void Adaptation::Icap::Launcher::noteAdaptationAnswer(HttpMsg *message)
54 {
55 sendAnswer(message);
56 clearAdaptation(theXaction);
57 Must(done());
58 debugs(93,3, HERE << "Adaptation::Icap::Launcher::noteAdaptationAnswer exiting ");
59 }
60
61 void Adaptation::Icap::Launcher::noteInitiatorAborted()
62 {
63
64 announceInitiatorAbort(theXaction); // propogate to the transaction
65 clearInitiator();
66 Must(done()); // should be nothing else to do
67
68 }
69
70 // XXX: this call is unused by ICAPXaction in favor of ICAPLauncher::noteXactAbort
71 void Adaptation::Icap::Launcher::noteAdaptationQueryAbort(bool final)
72 {
73 debugs(93,5, HERE << "launches: " << theLaunches << "; final: " << final);
74 clearAdaptation(theXaction);
75
76 Must(done()); // swanSong will notify the initiator
77 }
78
79 void Adaptation::Icap::Launcher::noteXactAbort(XactAbortInfo &info)
80 {
81 debugs(93,5, HERE << "theXaction:" << theXaction << " launches: " << theLaunches);
82
83 // TODO: add more checks from FwdState::checkRetry()?
84 if (canRetry(info)) {
85 clearAdaptation(theXaction);
86 launchXaction("retry");
87 }
88 else if (canRepeat(info)) {
89 clearAdaptation(theXaction);
90 launchXaction("repeat");
91 } else {
92 debugs(93,3, HERE << "cannot retry or repeat a failed transaction");
93 clearAdaptation(theXaction);
94 tellQueryAborted(false); // caller decides based on bypass, consumption
95 Must(done());
96 }
97 }
98
99 bool Adaptation::Icap::Launcher::doneAll() const
100 {
101 return (!theInitiator || !theXaction) && Adaptation::Initiate::doneAll();
102 }
103
104 void Adaptation::Icap::Launcher::swanSong()
105 {
106 if (theInitiator)
107 tellQueryAborted(true); // always final here because abnormal
108
109 if (theXaction)
110 clearAdaptation(theXaction);
111
112 Adaptation::Initiate::swanSong();
113 }
114
115 bool Adaptation::Icap::Launcher::canRetry(Adaptation::Icap::XactAbortInfo &info) const
116 {
117 // We do not check and can exceed zero repeat limit when retrying.
118 // This is by design as the limit does not apply to pconn retrying.
119 return !shutting_down && info.isRetriable;
120 }
121
122 bool Adaptation::Icap::Launcher::canRepeat(Adaptation::Icap::XactAbortInfo &info) const
123 {
124 debugs(93,9, HERE << shutting_down);
125 if (theLaunches >= TheConfig.repeat_limit || shutting_down)
126 return false;
127
128 debugs(93,9, HERE << info.isRepeatable); // TODO: update and use status()
129 if (!info.isRepeatable)
130 return false;
131
132 debugs(93,9, HERE << info.icapReply);
133 if (!info.icapReply) // did not get to read an ICAP reply; a timeout?
134 return true;
135
136 debugs(93,9, HERE << info.icapReply->sline.status);
137 if (!info.icapReply->sline.status) // failed to parse the reply; I/O err
138 return true;
139
140 ACLFilledChecklist *cl =
141 new ACLFilledChecklist(TheConfig.repeat, info.icapRequest, dash_str);
142 cl->reply = HTTPMSGLOCK(info.icapReply);
143
144 const bool result = cl->fastCheck();
145 delete cl;
146 return result;
147 }
148
149 /* ICAPXactAbortInfo */
150
151 Adaptation::Icap::XactAbortInfo::XactAbortInfo(HttpRequest *anIcapRequest,
152 HttpReply *anIcapReply, bool beRetriable, bool beRepeatable):
153 icapRequest(anIcapRequest ? HTTPMSGLOCK(anIcapRequest) : NULL),
154 icapReply(anIcapReply ? HTTPMSGLOCK(anIcapReply) : NULL),
155 isRetriable(beRetriable), isRepeatable(beRepeatable)
156 {
157 }
158
159 Adaptation::Icap::XactAbortInfo::XactAbortInfo(const Adaptation::Icap::XactAbortInfo &i):
160 icapRequest(i.icapRequest ? HTTPMSGLOCK(i.icapRequest) : NULL),
161 icapReply(i.icapReply ? HTTPMSGLOCK(i.icapReply) : NULL),
162 isRetriable(i.isRetriable), isRepeatable(i.isRepeatable)
163 {
164 }
165
166 Adaptation::Icap::XactAbortInfo::~XactAbortInfo()
167 {
168 HTTPMSGUNLOCK(icapRequest);
169 HTTPMSGUNLOCK(icapReply);
170 }