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