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