]>
Commit | Line | Data |
---|---|---|
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 | 10 | CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Ecap::XactionRep, XactionRep); |
fdc96a39 AR |
11 | |
12 | ||
574b508c | 13 | Adaptation::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 | 26 | Adaptation::Ecap::XactionRep::~XactionRep() |
fdc96a39 AR |
27 | { |
28 | assert(!theMaster); | |
027320b4 | 29 | delete theCauseRep; |
4d0854d4 | 30 | theAnswerRep.reset(); |
fdc96a39 AR |
31 | } |
32 | ||
33 | void | |
574b508c | 34 | Adaptation::Ecap::XactionRep::master(const AdapterXaction &x) |
fdc96a39 AR |
35 | { |
36 | Must(!theMaster); | |
37 | Must(x != NULL); | |
38 | theMaster = x; | |
39 | } | |
40 | ||
41 | void | |
574b508c | 42 | Adaptation::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 | ||
54 | void | |
574b508c | 55 | Adaptation::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 | 80 | libecap::Message & |
574b508c | 81 | Adaptation::Ecap::XactionRep::virgin() |
fdc96a39 | 82 | { |
7b67e5b6 | 83 | return theVirginRep; |
fdc96a39 AR |
84 | } |
85 | ||
4d0854d4 | 86 | const libecap::Message & |
574b508c | 87 | Adaptation::Ecap::XactionRep::cause() |
fdc96a39 | 88 | { |
4d0854d4 AR |
89 | Must(theCauseRep != NULL); |
90 | return *theCauseRep; | |
fdc96a39 AR |
91 | } |
92 | ||
4d0854d4 | 93 | libecap::Message & |
574b508c | 94 | Adaptation::Ecap::XactionRep::adapted() |
fdc96a39 | 95 | { |
4d0854d4 AR |
96 | Must(theAnswerRep != NULL); |
97 | return *theAnswerRep; | |
98 | } | |
99 | ||
100 | Adaptation::Message & | |
574b508c | 101 | Adaptation::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 | 108 | void |
574b508c | 109 | Adaptation::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 | 118 | bool |
574b508c | 119 | Adaptation::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 | 126 | void |
574b508c | 127 | Adaptation::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 | 143 | void |
574b508c | 144 | Adaptation::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 | 173 | void |
574b508c | 174 | Adaptation::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 | 200 | void |
574b508c | 201 | Adaptation::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 | 209 | void |
574b508c | 210 | Adaptation::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 | 219 | void |
574b508c | 220 | Adaptation::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 | ||
228 | void | |
574b508c | 229 | Adaptation::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 | 236 | libecap::Area |
574b508c | 237 | Adaptation::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 | ||
261 | void | |
574b508c | 262 | Adaptation::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 | ||
276 | void | |
574b508c | 277 | Adaptation::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 | 286 | void |
574b508c | 287 | Adaptation::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 | 294 | void |
574b508c | 295 | Adaptation::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 | |
304 | void | |
574b508c | 305 | Adaptation::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 | 312 | void |
574b508c | 313 | Adaptation::Ecap::XactionRep::adaptationAborted() |
fdc96a39 | 314 | { |
fdc96a39 | 315 | tellQueryAborted(true); // should eCAP support retries? |
ea76d91e | 316 | mustStop("adaptationAborted"); |
fdc96a39 AR |
317 | } |
318 | ||
8679e6c2 | 319 | bool |
574b508c | 320 | Adaptation::Ecap::XactionRep::callable() const |
8679e6c2 AR |
321 | { |
322 | return !done(); | |
323 | } | |
324 | ||
26ac0430 | 325 | void |
574b508c | 326 | Adaptation::Ecap::XactionRep::noteMoreBodySpaceAvailable(RefCount<BodyPipe> bp) |
fdc96a39 | 327 | { |
ea76d91e AR |
328 | Must(proxyingAb == opOn); |
329 | moveAbContent(); | |
fdc96a39 AR |
330 | } |
331 | ||
26ac0430 | 332 | void |
574b508c | 333 | Adaptation::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 | ||
342 | void | |
574b508c | 343 | Adaptation::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 | ||
350 | void | |
574b508c | 351 | Adaptation::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 | ||
359 | void | |
574b508c | 360 | Adaptation::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 | ||
368 | void | |
574b508c | 369 | Adaptation::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 |
375 | void | |
574b508c | 376 | Adaptation::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 | ||
392 | const char * | |
574b508c | 393 | Adaptation::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 | } |