]>
Commit | Line | Data |
---|---|---|
c824c43b | 1 | /* |
bbc27441 AJ |
2 | * Copyright (C) 1996-2014 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. | |
c824c43b | 7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 93 ICAP (RFC 3507) Client */ |
10 | ||
582c2af2 | 11 | #include "squid.h" |
3ff65596 | 12 | #include "acl/FilledChecklist.h" |
1adcebc3 | 13 | #include "adaptation/Answer.h" |
602d9612 | 14 | #include "adaptation/icap/Config.h" |
26cc52cb | 15 | #include "adaptation/icap/Launcher.h" |
26cc52cb | 16 | #include "adaptation/icap/ServiceRep.h" |
602d9612 | 17 | #include "adaptation/icap/Xaction.h" |
3d93a84d | 18 | #include "base/TextException.h" |
582c2af2 | 19 | #include "globals.h" |
3d93a84d | 20 | #include "HttpMsg.h" |
3d93a84d | 21 | #include "HttpReply.h" |
602d9612 | 22 | #include "HttpRequest.h" |
c824c43b | 23 | |
26cc52cb | 24 | Adaptation::Icap::Launcher::Launcher(const char *aTypeName, |
4cb2536f | 25 | Adaptation::ServicePointer &aService): |
f53969cc SM |
26 | AsyncJob(aTypeName), |
27 | Adaptation::Initiate(aTypeName), | |
28 | theService(aService), theXaction(0), theLaunches(0) | |
c824c43b | 29 | { |
30 | } | |
31 | ||
26cc52cb | 32 | Adaptation::Icap::Launcher::~Launcher() |
c824c43b | 33 | { |
34 | assert(!theXaction); | |
35 | } | |
36 | ||
26cc52cb | 37 | void Adaptation::Icap::Launcher::start() |
c824c43b | 38 | { |
0bef8dd7 | 39 | Adaptation::Initiate::start(); |
c824c43b | 40 | |
4299f876 | 41 | Must(theInitiator.set()); |
3ff65596 | 42 | launchXaction("first"); |
c824c43b | 43 | } |
44 | ||
3ff65596 | 45 | void Adaptation::Icap::Launcher::launchXaction(const char *xkind) |
c824c43b | 46 | { |
47 | Must(!theXaction); | |
48 | ++theLaunches; | |
3ff65596 | 49 | debugs(93,4, HERE << "launching " << xkind << " xaction #" << theLaunches); |
26cc52cb | 50 | Adaptation::Icap::Xaction *x = createXaction(); |
3ff65596 | 51 | x->attempts = theLaunches; |
129fe2a1 CT |
52 | if (theLaunches > 1) { |
53 | x->clearError(); | |
c824c43b | 54 | x->disableRetries(); |
129fe2a1 | 55 | } |
3ff65596 AR |
56 | if (theLaunches >= TheConfig.repeat_limit) |
57 | x->disableRepeats("over icap_retry_limit"); | |
0bef8dd7 | 58 | theXaction = initiateAdaptation(x); |
4299f876 | 59 | Must(initiated(theXaction)); |
c824c43b | 60 | } |
61 | ||
3af10ac0 | 62 | void Adaptation::Icap::Launcher::noteAdaptationAnswer(const Answer &answer) |
c824c43b | 63 | { |
3af10ac0 AR |
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); | |
0bef8dd7 | 70 | clearAdaptation(theXaction); |
c824c43b | 71 | Must(done()); |
c824c43b | 72 | } |
73 | ||
26cc52cb | 74 | void Adaptation::Icap::Launcher::noteInitiatorAborted() |
c824c43b | 75 | { |
c824c43b | 76 | |
77 | announceInitiatorAbort(theXaction); // propogate to the transaction | |
78 | clearInitiator(); | |
79 | Must(done()); // should be nothing else to do | |
80 | ||
c824c43b | 81 | } |
82 | ||
4299f876 | 83 | void Adaptation::Icap::Launcher::noteXactAbort(XactAbortInfo info) |
3ff65596 AR |
84 | { |
85 | debugs(93,5, HERE << "theXaction:" << theXaction << " launches: " << theLaunches); | |
c824c43b | 86 | |
e1381638 | 87 | // TODO: add more checks from FwdState::checkRetry()? |
3ff65596 AR |
88 | if (canRetry(info)) { |
89 | clearAdaptation(theXaction); | |
90 | launchXaction("retry"); | |
e1381638 | 91 | } else if (canRepeat(info)) { |
3ff65596 AR |
92 | clearAdaptation(theXaction); |
93 | launchXaction("repeat"); | |
c824c43b | 94 | } else { |
3ff65596 AR |
95 | debugs(93,3, HERE << "cannot retry or repeat a failed transaction"); |
96 | clearAdaptation(theXaction); | |
a22e6cd3 AR |
97 | tellQueryAborted(false); // caller decides based on bypass, consumption |
98 | Must(done()); | |
e1381638 | 99 | } |
c824c43b | 100 | } |
101 | ||
26cc52cb | 102 | bool Adaptation::Icap::Launcher::doneAll() const |
26ac0430 | 103 | { |
0bef8dd7 | 104 | return (!theInitiator || !theXaction) && Adaptation::Initiate::doneAll(); |
c824c43b | 105 | } |
106 | ||
26cc52cb | 107 | void Adaptation::Icap::Launcher::swanSong() |
c824c43b | 108 | { |
4299f876 | 109 | if (theInitiator.set()) |
a22e6cd3 | 110 | tellQueryAborted(true); // always final here because abnormal |
c824c43b | 111 | |
4299f876 | 112 | if (theXaction.set()) |
0bef8dd7 | 113 | clearAdaptation(theXaction); |
c824c43b | 114 | |
0bef8dd7 | 115 | Adaptation::Initiate::swanSong(); |
c824c43b | 116 | } |
3ff65596 AR |
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; | |
e1381638 | 138 | |
9b769c67 AJ |
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 | |
3ff65596 | 143 | return true; |
e1381638 | 144 | |
3ff65596 AR |
145 | ACLFilledChecklist *cl = |
146 | new ACLFilledChecklist(TheConfig.repeat, info.icapRequest, dash_str); | |
b248c2a3 AJ |
147 | cl->reply = info.icapReply; |
148 | HTTPMSGLOCK(cl->reply); | |
e1381638 | 149 | |
2efeb0b7 | 150 | bool result = cl->fastCheck() == ACCESS_ALLOWED; |
3ff65596 AR |
151 | delete cl; |
152 | return result; | |
153 | } | |
154 | ||
155 | /* ICAPXactAbortInfo */ | |
156 | ||
157 | Adaptation::Icap::XactAbortInfo::XactAbortInfo(HttpRequest *anIcapRequest, | |
e1381638 | 158 | HttpReply *anIcapReply, bool beRetriable, bool beRepeatable): |
f53969cc SM |
159 | icapRequest(anIcapRequest), |
160 | icapReply(anIcapReply), | |
161 | isRetriable(beRetriable), | |
162 | isRepeatable(beRepeatable) | |
3ff65596 | 163 | { |
b248c2a3 AJ |
164 | if (icapRequest) |
165 | HTTPMSGLOCK(icapRequest); | |
166 | if (icapReply) | |
167 | HTTPMSGLOCK(icapReply); | |
3ff65596 AR |
168 | } |
169 | ||
170 | Adaptation::Icap::XactAbortInfo::XactAbortInfo(const Adaptation::Icap::XactAbortInfo &i): | |
f53969cc SM |
171 | icapRequest(i.icapRequest), |
172 | icapReply(i.icapReply), | |
173 | isRetriable(i.isRetriable), | |
174 | isRepeatable(i.isRepeatable) | |
3ff65596 | 175 | { |
b248c2a3 AJ |
176 | if (icapRequest) |
177 | HTTPMSGLOCK(icapRequest); | |
178 | if (icapReply) | |
179 | HTTPMSGLOCK(icapReply); | |
3ff65596 AR |
180 | } |
181 | ||
182 | Adaptation::Icap::XactAbortInfo::~XactAbortInfo() | |
183 | { | |
184 | HTTPMSGUNLOCK(icapRequest); | |
185 | HTTPMSGUNLOCK(icapReply); | |
186 | } | |
f53969cc | 187 |