]> git.ipfire.org Git - thirdparty/squid.git/blame - src/adaptation/ecap/XactionRep.cc
Update squidclient manual and usage documentation.
[thirdparty/squid.git] / src / adaptation / ecap / XactionRep.cc
CommitLineData
fdc96a39 1#include "squid.h"
4d0854d4
AR
2#include <libecap/common/area.h>
3#include <libecap/common/delay.h>
fdc96a39
AR
4#include <libecap/adapter/xaction.h>
5#include "TextException.h"
fdc96a39
AR
6#include "HttpRequest.h"
7#include "HttpReply.h"
1f3c65fc 8#include "adaptation/ecap/XactionRep.h"
fdc96a39 9
574b508c 10CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Ecap::XactionRep, XactionRep);
fdc96a39
AR
11
12
574b508c 13Adaptation::Ecap::XactionRep::XactionRep(Adaptation::Initiator *anInitiator,
af6a12ee
AJ
14 HttpMsg *virginHeader, HttpRequest *virginCause,
15 const Adaptation::ServicePointer &aService):
574b508c
AR
16 AsyncJob("Adaptation::Ecap::XactionRep"),
17 Adaptation::Initiate("Adaptation::Ecap::XactionRep", anInitiator, aService),
26ac0430 18 theVirginRep(virginHeader), theCauseRep(NULL),
7477a343
AR
19 proxyingVb(opUndecided), proxyingAb(opUndecided), canAccessVb(false),
20 abProductionFinished(false), abProductionAtEnd(false)
fdc96a39 21{
027320b4 22 if (virginCause)
4d0854d4 23 theCauseRep = new MessageRep(virginCause);
fdc96a39
AR
24}
25
574b508c 26Adaptation::Ecap::XactionRep::~XactionRep()
fdc96a39
AR
27{
28 assert(!theMaster);
027320b4 29 delete theCauseRep;
4d0854d4 30 theAnswerRep.reset();
fdc96a39
AR
31}
32
33void
574b508c 34Adaptation::Ecap::XactionRep::master(const AdapterXaction &x)
fdc96a39
AR
35{
36 Must(!theMaster);
37 Must(x != NULL);
38 theMaster = x;
39}
40
41void
574b508c 42Adaptation::Ecap::XactionRep::start()
fdc96a39
AR
43{
44 Must(theMaster);
4d0854d4 45
ea76d91e
AR
46 if (theVirginRep.raw().body_pipe != NULL)
47 canAccessVb = true; /// assumes nobody is consuming; \todo check
48 else
49 proxyingVb = opNever;
4d0854d4 50
fdc96a39
AR
51 theMaster->start();
52}
53
54void
574b508c 55Adaptation::Ecap::XactionRep::swanSong()
fdc96a39 56{
506a0530 57 // clear body_pipes, if any
ea76d91e 58 // this code does not maintain proxying* and canAccessVb states; should it?
506a0530
AR
59
60 if (theAnswerRep != NULL) {
f1a768b2
AR
61 BodyPipe::Pointer body_pipe = answer().body_pipe;
62 if (body_pipe != NULL) {
63 Must(body_pipe->stillProducing(this));
64 stopProducingFor(body_pipe, false);
65 }
66 }
506a0530
AR
67
68 {
f1a768b2
AR
69 BodyPipe::Pointer body_pipe = theVirginRep.raw().body_pipe;
70 if (body_pipe != NULL) {
71 Must(body_pipe->stillConsuming(this));
72 stopConsumingFrom(body_pipe);
73 }
74 }
506a0530 75
fdc96a39
AR
76 terminateMaster();
77 Adaptation::Initiate::swanSong();
78}
79
fdc96a39 80libecap::Message &
574b508c 81Adaptation::Ecap::XactionRep::virgin()
fdc96a39 82{
7b67e5b6 83 return theVirginRep;
fdc96a39
AR
84}
85
4d0854d4 86const libecap::Message &
574b508c 87Adaptation::Ecap::XactionRep::cause()
fdc96a39 88{
4d0854d4
AR
89 Must(theCauseRep != NULL);
90 return *theCauseRep;
fdc96a39
AR
91}
92
4d0854d4 93libecap::Message &
574b508c 94Adaptation::Ecap::XactionRep::adapted()
fdc96a39 95{
4d0854d4
AR
96 Must(theAnswerRep != NULL);
97 return *theAnswerRep;
98}
99
100Adaptation::Message &
574b508c 101Adaptation::Ecap::XactionRep::answer()
4d0854d4 102{
f1a768b2
AR
103 MessageRep *rep = dynamic_cast<MessageRep*>(theAnswerRep.get());
104 Must(rep);
4d0854d4
AR
105 return rep->raw();
106}
107
ea76d91e 108void
574b508c 109Adaptation::Ecap::XactionRep::terminateMaster()
4d0854d4
AR
110{
111 if (theMaster) {
ea76d91e
AR
112 AdapterXaction x = theMaster;
113 theMaster.reset();
114 x->stop();
f1a768b2 115 }
4d0854d4
AR
116}
117
4d0854d4 118bool
574b508c 119Adaptation::Ecap::XactionRep::doneAll() const
4d0854d4 120{
ea76d91e 121 return proxyingVb >= opComplete && proxyingAb >= opComplete &&
26ac0430 122 Adaptation::Initiate::doneAll();
4d0854d4
AR
123}
124
ea76d91e 125// stops receiving virgin and enables auto-consumption
4d0854d4 126void
574b508c 127Adaptation::Ecap::XactionRep::dropVirgin(const char *reason)
4d0854d4 128{
ea76d91e
AR
129 debugs(93,4, HERE << "because " << reason << "; status:" << status());
130 Must(proxyingVb = opOn);
4d0854d4
AR
131
132 BodyPipePointer &p = theVirginRep.raw().body_pipe;
133 Must(p != NULL);
134 Must(p->stillConsuming(this));
135 stopConsumingFrom(p);
136 p->enableAutoConsumption();
ea76d91e
AR
137 proxyingVb = opComplete;
138 canAccessVb = false;
139
140 // called from adapter handler so does not inform adapter
fdc96a39
AR
141}
142
26ac0430 143void
574b508c 144Adaptation::Ecap::XactionRep::useVirgin()
fdc96a39 145{
4d0854d4 146 debugs(93,3, HERE << status());
ea76d91e
AR
147 Must(proxyingAb == opUndecided);
148 proxyingAb = opNever;
4d0854d4 149
ea76d91e 150 BodyPipePointer &vbody_pipe = theVirginRep.raw().body_pipe;
2874d9e3
AR
151
152 HttpMsg *clone = theVirginRep.raw().header->clone();
153 // check that clone() copies the pipe so that we do not have to
154 Must(!vbody_pipe == !clone->body_pipe);
155
ea76d91e
AR
156 if (proxyingVb == opOn) {
157 Must(vbody_pipe->stillConsuming(this));
4d0854d4 158 // if libecap consumed, we cannot shortcircuit
ea76d91e
AR
159 Must(!vbody_pipe->consumedSize());
160 stopConsumingFrom(vbody_pipe);
161 canAccessVb = false;
162 proxyingVb = opComplete;
163 } else
26ac0430
AJ
164 if (proxyingVb == opUndecided) {
165 vbody_pipe = NULL; // it is not our pipe anymore
166 proxyingVb = opNever;
167 }
ea76d91e 168
ea76d91e 169 sendAnswer(clone);
4d0854d4 170 Must(done());
fdc96a39
AR
171}
172
26ac0430 173void
574b508c 174Adaptation::Ecap::XactionRep::useAdapted(const libecap::shared_ptr<libecap::Message> &m)
fdc96a39 175{
4d0854d4 176 debugs(93,3, HERE << status());
ea76d91e 177 Must(m);
4d0854d4 178 theAnswerRep = m;
ea76d91e
AR
179 Must(proxyingAb == opUndecided);
180
f1a768b2 181 HttpMsg *msg = answer().header;
ea76d91e
AR
182 if (!theAnswerRep->body()) { // final, bodyless answer
183 proxyingAb = opNever;
184 sendAnswer(msg);
f1a768b2 185 } else { // got answer headers but need to handle body
ea76d91e 186 proxyingAb = opOn;
f1a768b2 187 Must(!msg->body_pipe); // only host can set body pipes
ea76d91e 188 MessageRep *rep = dynamic_cast<MessageRep*>(theAnswerRep.get());
f1a768b2
AR
189 Must(rep);
190 rep->tieBody(this); // sets us as a producer
191 Must(msg->body_pipe != NULL); // check tieBody
ea76d91e
AR
192
193 sendAnswer(msg);
194
4d0854d4 195 debugs(93,4, HERE << "adapter will produce body" << status());
8679e6c2 196 theMaster->abMake(); // libecap will produce
4d0854d4 197 }
fdc96a39
AR
198}
199
4d0854d4 200void
574b508c 201Adaptation::Ecap::XactionRep::vbDiscard()
fdc96a39 202{
ea76d91e 203 Must(proxyingVb == opUndecided);
8679e6c2 204 // if adapter does not need vb, we do not need to send it
a96661a8 205 dropVirgin("vbDiscard");
ea76d91e 206 Must(proxyingVb == opNever);
fdc96a39
AR
207}
208
4d0854d4 209void
574b508c 210Adaptation::Ecap::XactionRep::vbMake()
fdc96a39 211{
ea76d91e
AR
212 Must(proxyingVb == opUndecided);
213 BodyPipePointer &p = theVirginRep.raw().body_pipe;
214 Must(p != NULL);
215 Must(p->setConsumerIfNotLate(this)); // to make vb, we must receive vb
216 proxyingVb = opOn;
fdc96a39
AR
217}
218
4d0854d4 219void
574b508c 220Adaptation::Ecap::XactionRep::vbStopMaking()
fdc96a39 221{
ea76d91e
AR
222 // if adapter does not need vb, we do not need to receive it
223 if (proxyingVb == opOn)
224 dropVirgin("vbStopMaking");
225 Must(proxyingVb == opComplete);
4d0854d4
AR
226}
227
228void
574b508c 229Adaptation::Ecap::XactionRep::vbMakeMore()
4d0854d4 230{
ea76d91e
AR
231 Must(proxyingVb == opOn); // cannot make more if done proxying
232 // we cannot guarantee more vb, but we can check that there is a chance
233 Must(!theVirginRep.raw().body_pipe->exhausted());
4d0854d4
AR
234}
235
8679e6c2 236libecap::Area
574b508c 237Adaptation::Ecap::XactionRep::vbContent(libecap::size_type o, libecap::size_type s)
4d0854d4 238{
ea76d91e
AR
239 Must(canAccessVb);
240 // We may not be proxyingVb yet. It should be OK, but see vbContentShift().
241
8679e6c2 242 const BodyPipePointer &p = theVirginRep.raw().body_pipe;
ea76d91e
AR
243 Must(p != NULL);
244
245 // TODO: make MemBuf use size_t?
246 const size_t haveSize = static_cast<size_t>(p->buf().contentSize());
4d0854d4 247
8679e6c2
AR
248 // convert to Squid types; XXX: check for overflow
249 const uint64_t offset = static_cast<uint64_t>(o);
250 Must(offset <= haveSize); // equal iff at the end of content
251
252 // nsize means no size limit: all content starting from offset
253 const size_t size = s == libecap::nsize ?
26ac0430 254 haveSize - offset : static_cast<size_t>(s);
8679e6c2 255
8679e6c2
AR
256 // XXX: optimize by making theBody a shared_ptr (see Area::FromTemp*() src)
257 return libecap::Area::FromTempBuffer(p->buf().content() + offset,
26ac0430 258 min(static_cast<size_t>(haveSize - offset), size));
4d0854d4
AR
259}
260
261void
574b508c 262Adaptation::Ecap::XactionRep::vbContentShift(libecap::size_type n)
4d0854d4 263{
ea76d91e
AR
264 Must(canAccessVb);
265 // We may not be proxyingVb yet. It should be OK now, but if BodyPipe
266 // consume() requirements change, we would have to return empty vbContent
267 // until the adapter registers as a consumer
268
8679e6c2
AR
269 BodyPipePointer &p = theVirginRep.raw().body_pipe;
270 Must(p != NULL);
271 const size_t size = static_cast<size_t>(n); // XXX: check for overflow
272 const size_t haveSize = static_cast<size_t>(p->buf().contentSize()); // TODO: make MemBuf use size_t?
273 p->consume(min(size, haveSize));
4d0854d4
AR
274}
275
276void
574b508c 277Adaptation::Ecap::XactionRep::noteAbContentDone(bool atEnd)
4d0854d4 278{
7477a343
AR
279 Must(proxyingAb == opOn && !abProductionFinished);
280 abProductionFinished = true;
281 abProductionAtEnd = atEnd; // store until ready to stop producing ourselves
282 debugs(93,5, HERE << "adapted body production ended");
283 moveAbContent();
4d0854d4
AR
284}
285
8679e6c2 286void
574b508c 287Adaptation::Ecap::XactionRep::noteAbContentAvailable()
4d0854d4 288{
7477a343 289 Must(proxyingAb == opOn && !abProductionFinished);
8679e6c2 290 moveAbContent();
4d0854d4
AR
291}
292
ea76d91e 293#if 0 /* XXX: implement */
4d0854d4 294void
574b508c 295Adaptation::Ecap::XactionRep::setAdaptedBodySize(const libecap::BodySize &size)
4d0854d4
AR
296{
297 Must(answer().body_pipe != NULL);
8679e6c2
AR
298 if (size.known())
299 answer().body_pipe->setBodySize(size.value());
300 // else the piped body size is unknown by default
4d0854d4 301}
8679e6c2 302#endif
4d0854d4
AR
303
304void
574b508c 305Adaptation::Ecap::XactionRep::adaptationDelayed(const libecap::Delay &d)
4d0854d4
AR
306{
307 debugs(93,3, HERE << "adapter needs time: " <<
26ac0430 308 d.state << '/' << d.progress);
4d0854d4 309 // XXX: set timeout?
fdc96a39
AR
310}
311
26ac0430 312void
574b508c 313Adaptation::Ecap::XactionRep::adaptationAborted()
fdc96a39 314{
fdc96a39 315 tellQueryAborted(true); // should eCAP support retries?
ea76d91e 316 mustStop("adaptationAborted");
fdc96a39
AR
317}
318
8679e6c2 319bool
574b508c 320Adaptation::Ecap::XactionRep::callable() const
8679e6c2
AR
321{
322 return !done();
323}
324
26ac0430 325void
574b508c 326Adaptation::Ecap::XactionRep::noteMoreBodySpaceAvailable(RefCount<BodyPipe> bp)
fdc96a39 327{
ea76d91e
AR
328 Must(proxyingAb == opOn);
329 moveAbContent();
fdc96a39
AR
330}
331
26ac0430 332void
574b508c 333Adaptation::Ecap::XactionRep::noteBodyConsumerAborted(RefCount<BodyPipe> bp)
fdc96a39 334{
ea76d91e
AR
335 Must(proxyingAb == opOn);
336 stopProducingFor(answer().body_pipe, false);
337 Must(theMaster);
338 theMaster->abStopMaking();
339 proxyingAb = opComplete;
fdc96a39
AR
340}
341
342void
574b508c 343Adaptation::Ecap::XactionRep::noteMoreBodyDataAvailable(RefCount<BodyPipe> bp)
fdc96a39 344{
ea76d91e 345 Must(proxyingVb == opOn);
fdc96a39 346 Must(theMaster);
8679e6c2 347 theMaster->noteVbContentAvailable();
fdc96a39
AR
348}
349
350void
574b508c 351Adaptation::Ecap::XactionRep::noteBodyProductionEnded(RefCount<BodyPipe> bp)
fdc96a39 352{
ea76d91e 353 Must(proxyingVb == opOn);
fdc96a39 354 Must(theMaster);
8679e6c2 355 theMaster->noteVbContentDone(true);
ea76d91e 356 proxyingVb = opComplete;
fdc96a39
AR
357}
358
359void
574b508c 360Adaptation::Ecap::XactionRep::noteBodyProducerAborted(RefCount<BodyPipe> bp)
fdc96a39 361{
ea76d91e 362 Must(proxyingVb == opOn);
8679e6c2
AR
363 Must(theMaster);
364 theMaster->noteVbContentDone(false);
ea76d91e 365 proxyingVb = opComplete;
fdc96a39
AR
366}
367
368void
574b508c 369Adaptation::Ecap::XactionRep::noteInitiatorAborted()
fdc96a39
AR
370{
371 mustStop("initiator aborted");
372}
373
8679e6c2
AR
374// get content from the adapter and put it into the adapted pipe
375void
574b508c 376Adaptation::Ecap::XactionRep::moveAbContent()
8679e6c2 377{
ea76d91e 378 Must(proxyingAb == opOn);
8679e6c2 379 const libecap::Area c = theMaster->abContent(0, libecap::nsize);
7477a343
AR
380 debugs(93,5, HERE << "up to " << c.size << " bytes");
381 if (c.size == 0 && abProductionFinished) { // no ab now and in the future
382 stopProducingFor(answer().body_pipe, abProductionAtEnd);
383 proxyingAb = opComplete;
384 debugs(93,5, HERE << "last adapted body data retrieved");
385 } else
386 if (c.size > 0) {
387 if (const size_t used = answer().body_pipe->putMoreData(c.start, c.size))
388 theMaster->abContentShift(used);
389 }
8679e6c2
AR
390}
391
392const char *
574b508c 393Adaptation::Ecap::XactionRep::status() const
fdc96a39 394{
4d0854d4
AR
395 static MemBuf buf;
396 buf.reset();
397
398 buf.append(" [", 2);
399
ea76d91e
AR
400 if (proxyingVb == opOn) {
401 const BodyPipePointer &vp = theVirginRep.raw().body_pipe;
402 if (!canAccessVb)
403 buf.append("x", 1);
404 if (vp != NULL && vp->stillConsuming(this)) {
f1a768b2 405 buf.append("Vb", 2);
ea76d91e 406 buf.append(vp->status(), strlen(vp->status())); // XXX
f1a768b2 407 } else
ea76d91e 408 buf.append("V.", 2);
f1a768b2 409 }
506a0530 410
ea76d91e
AR
411 if (proxyingAb == opOn) {
412 MessageRep *rep = dynamic_cast<MessageRep*>(theAnswerRep.get());
413 Must(rep);
f1a768b2
AR
414 const BodyPipePointer &ap = rep->raw().body_pipe;
415 if (ap != NULL && ap->stillProducing(this)) {
416 buf.append(" Ab", 3);
417 buf.append(ap->status(), strlen(ap->status())); // XXX
418 } else
419 buf.append(" A.", 3);
420 }
4d0854d4 421
4d0854d4
AR
422 buf.Printf(" ecapx%d]", id);
423
424 buf.terminate();
425
426 return buf.content();
fdc96a39 427}