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