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