]>
Commit | Line | Data |
---|---|---|
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 | 14 | CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Ecap::XactionRep, XactionRep); |
fdc96a39 AR |
15 | |
16 | ||
574b508c | 17 | Adaptation::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 | 33 | Adaptation::Ecap::XactionRep::~XactionRep() |
fdc96a39 AR |
34 | { |
35 | assert(!theMaster); | |
027320b4 | 36 | delete theCauseRep; |
4d0854d4 | 37 | theAnswerRep.reset(); |
fdc96a39 AR |
38 | } |
39 | ||
40 | void | |
574b508c | 41 | Adaptation::Ecap::XactionRep::master(const AdapterXaction &x) |
fdc96a39 AR |
42 | { |
43 | Must(!theMaster); | |
44 | Must(x != NULL); | |
45 | theMaster = x; | |
46 | } | |
47 | ||
a22e6cd3 AR |
48 | Adaptation::Service & |
49 | Adaptation::Ecap::XactionRep::service() | |
50 | { | |
51 | Must(theService != NULL); | |
52 | return *theService; | |
53 | } | |
54 | ||
fdc96a39 | 55 | void |
574b508c | 56 | Adaptation::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 | ||
77 | void | |
574b508c | 78 | Adaptation::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 | 111 | libecap::Message & |
574b508c | 112 | Adaptation::Ecap::XactionRep::virgin() |
fdc96a39 | 113 | { |
7b67e5b6 | 114 | return theVirginRep; |
fdc96a39 AR |
115 | } |
116 | ||
4d0854d4 | 117 | const libecap::Message & |
574b508c | 118 | Adaptation::Ecap::XactionRep::cause() |
fdc96a39 | 119 | { |
4d0854d4 AR |
120 | Must(theCauseRep != NULL); |
121 | return *theCauseRep; | |
fdc96a39 AR |
122 | } |
123 | ||
4d0854d4 | 124 | libecap::Message & |
574b508c | 125 | Adaptation::Ecap::XactionRep::adapted() |
fdc96a39 | 126 | { |
4d0854d4 AR |
127 | Must(theAnswerRep != NULL); |
128 | return *theAnswerRep; | |
129 | } | |
130 | ||
131 | Adaptation::Message & | |
574b508c | 132 | Adaptation::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 | 139 | void |
574b508c | 140 | Adaptation::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 | 149 | bool |
574b508c | 150 | Adaptation::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 | 157 | void |
574b508c | 158 | Adaptation::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 | 174 | void |
574b508c | 175 | Adaptation::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 | 203 | void |
574b508c | 204 | Adaptation::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 | 230 | void |
574b508c | 231 | Adaptation::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 | 239 | void |
574b508c | 240 | Adaptation::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 | 249 | void |
574b508c | 250 | Adaptation::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 | ||
258 | void | |
574b508c | 259 | Adaptation::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 | 266 | libecap::Area |
574b508c | 267 | Adaptation::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 | ||
291 | void | |
574b508c | 292 | Adaptation::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 | ||
306 | void | |
574b508c | 307 | Adaptation::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 | 316 | void |
574b508c | 317 | Adaptation::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 | 324 | void |
574b508c | 325 | Adaptation::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 | |
334 | void | |
574b508c | 335 | Adaptation::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 | 342 | void |
574b508c | 343 | Adaptation::Ecap::XactionRep::adaptationAborted() |
fdc96a39 | 344 | { |
fdc96a39 | 345 | tellQueryAborted(true); // should eCAP support retries? |
ea76d91e | 346 | mustStop("adaptationAborted"); |
fdc96a39 AR |
347 | } |
348 | ||
8679e6c2 | 349 | bool |
574b508c | 350 | Adaptation::Ecap::XactionRep::callable() const |
8679e6c2 AR |
351 | { |
352 | return !done(); | |
353 | } | |
354 | ||
26ac0430 | 355 | void |
574b508c | 356 | Adaptation::Ecap::XactionRep::noteMoreBodySpaceAvailable(RefCount<BodyPipe> bp) |
fdc96a39 | 357 | { |
ea76d91e AR |
358 | Must(proxyingAb == opOn); |
359 | moveAbContent(); | |
fdc96a39 AR |
360 | } |
361 | ||
26ac0430 | 362 | void |
574b508c | 363 | Adaptation::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 | ||
372 | void | |
574b508c | 373 | Adaptation::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 | ||
380 | void | |
574b508c | 381 | Adaptation::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 | ||
389 | void | |
574b508c | 390 | Adaptation::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 | ||
398 | void | |
574b508c | 399 | Adaptation::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 |
405 | void | |
574b508c | 406 | Adaptation::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 | ||
421 | const char * | |
574b508c | 422 | Adaptation::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 | } |