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