]> git.ipfire.org Git - thirdparty/squid.git/blame - src/adaptation/ecap/XactionRep.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / adaptation / ecap / XactionRep.cc
CommitLineData
b510f3a1 1/*
f70aedc4 2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
bbc27441
AJ
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.
b510f3a1 7 */
bbc27441
AJ
8
9/* DEBUG: section 93 eCAP Interface */
10
582c2af2 11#include "squid.h"
4d0854d4
AR
12#include <libecap/common/area.h>
13#include <libecap/common/delay.h>
22fff3bf
AR
14#include <libecap/common/named_values.h>
15#include <libecap/common/names.h>
fdc96a39 16#include <libecap/adapter/xaction.h>
1adcebc3 17#include "adaptation/Answer.h"
22fff3bf 18#include "adaptation/ecap/Config.h"
602d9612 19#include "adaptation/ecap/XactionRep.h"
3af10ac0 20#include "adaptation/Initiator.h"
0a720258 21#include "base/AsyncJobCalls.h"
3d93a84d 22#include "base/TextException.h"
af0ded40 23#include "format/Format.h"
602d9612
A
24#include "HttpReply.h"
25#include "HttpRequest.h"
5ceaee75 26#include "MasterXaction.h"
602d9612 27#include "SquidTime.h"
fdc96a39 28
574b508c 29CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Ecap::XactionRep, XactionRep);
fdc96a39 30
5038f9d8
AR
31/// a libecap Visitor for converting adapter transaction options to HttpHeader
32class OptionsExtractor: public libecap::NamedValueVisitor
33{
34public:
35 typedef libecap::Name Name;
36 typedef libecap::Area Area;
37
38 OptionsExtractor(HttpHeader &aMeta): meta(aMeta) {}
39
40 // libecap::NamedValueVisitor API
ec4d1a1d 41 virtual void visit(const Name &name, const Area &value) {
5038f9d8
AR
42 meta.putExt(name.image().c_str(), value.toString().c_str());
43 }
44
45 HttpHeader &meta; ///< where to put extracted options
46};
47
4299f876 48Adaptation::Ecap::XactionRep::XactionRep(
63df1d28 49 Http::Message *virginHeader, HttpRequest *virginCause, AccessLogEntry::Pointer &alp,
4cb2536f 50 const Adaptation::ServicePointer &aService):
f53969cc
SM
51 AsyncJob("Adaptation::Ecap::XactionRep"),
52 Adaptation::Initiate("Adaptation::Ecap::XactionRep"),
53 theService(aService),
54 theVirginRep(virginHeader), theCauseRep(NULL),
55 makingVb(opUndecided), proxyingAb(opUndecided),
56 adaptHistoryId(-1),
57 vbProductionFinished(false),
58 abProductionFinished(false), abProductionAtEnd(false),
59 al(alp)
fdc96a39 60{
027320b4 61 if (virginCause)
4d0854d4 62 theCauseRep = new MessageRep(virginCause);
fdc96a39
AR
63}
64
574b508c 65Adaptation::Ecap::XactionRep::~XactionRep()
fdc96a39
AR
66{
67 assert(!theMaster);
027320b4 68 delete theCauseRep;
4d0854d4 69 theAnswerRep.reset();
fdc96a39
AR
70}
71
72void
574b508c 73Adaptation::Ecap::XactionRep::master(const AdapterXaction &x)
fdc96a39
AR
74{
75 Must(!theMaster);
0c276d50 76 Must(x);
fdc96a39
AR
77 theMaster = x;
78}
79
a22e6cd3
AR
80Adaptation::Service &
81Adaptation::Ecap::XactionRep::service()
82{
83 Must(theService != NULL);
84 return *theService;
85}
86
22fff3bf
AR
87const libecap::Area
88Adaptation::Ecap::XactionRep::option(const libecap::Name &name) const
89{
90 if (name == libecap::metaClientIp)
91 return clientIpValue();
92 if (name == libecap::metaUserName)
93 return usernameValue();
71be37e0 94 if (Adaptation::Config::masterx_shared_name && name == Adaptation::Config::masterx_shared_name)
5038f9d8
AR
95 return masterxSharedValue(name);
96
97 // TODO: metaServerIp, metaAuthenticatedUser, and metaAuthenticatedGroups
71be37e0 98
2f8abb64 99 // If the name is unknown, metaValue returns an empty area
71be37e0 100 return metaValue(name);
22fff3bf
AR
101}
102
103void
104Adaptation::Ecap::XactionRep::visitEachOption(libecap::NamedValueVisitor &visitor) const
105{
106 if (const libecap::Area value = clientIpValue())
ec4d1a1d 107 visitor.visit(libecap::metaClientIp, value);
22fff3bf 108 if (const libecap::Area value = usernameValue())
ec4d1a1d 109 visitor.visit(libecap::metaUserName, value);
5038f9d8
AR
110
111 if (Adaptation::Config::masterx_shared_name) {
ec4d1a1d
A
112 const libecap::Name name(Adaptation::Config::masterx_shared_name);
113 if (const libecap::Area value = masterxSharedValue(name))
114 visitor.visit(name, value);
5038f9d8 115 }
71ee0835 116
71be37e0 117 visitEachMetaHeader(visitor);
5038f9d8
AR
118
119 // TODO: metaServerIp, metaAuthenticatedUser, and metaAuthenticatedGroups
22fff3bf
AR
120}
121
122const libecap::Area
123Adaptation::Ecap::XactionRep::clientIpValue() const
124{
125 const HttpRequest *request = dynamic_cast<const HttpRequest*>(theCauseRep ?
126 theCauseRep->raw().header : theVirginRep.raw().header);
127 Must(request);
128 // TODO: move this logic into HttpRequest::clientIp(bool) and
129 // HttpRequest::clientIpString(bool) and reuse everywhere
130 if (TheConfig.send_client_ip && request) {
131 Ip::Address client_addr;
132#if FOLLOW_X_FORWARDED_FOR
133 if (TheConfig.use_indirect_client) {
134 client_addr = request->indirect_client_addr;
ec4d1a1d 135 } else
22fff3bf
AR
136#endif
137 client_addr = request->client_addr;
4dd643d5 138 if (!client_addr.isAnyAddr() && !client_addr.isNoAddr()) {
22fff3bf 139 char ntoabuf[MAX_IPSTRLEN] = "";
4dd643d5 140 client_addr.toStr(ntoabuf,MAX_IPSTRLEN);
22fff3bf
AR
141 return libecap::Area::FromTempBuffer(ntoabuf, strlen(ntoabuf));
142 }
ec4d1a1d 143 }
22fff3bf
AR
144 return libecap::Area();
145}
146
147const libecap::Area
148Adaptation::Ecap::XactionRep::usernameValue() const
149{
321f219c 150#if USE_AUTH
22fff3bf
AR
151 const HttpRequest *request = dynamic_cast<const HttpRequest*>(theCauseRep ?
152 theCauseRep->raw().header : theVirginRep.raw().header);
153 Must(request);
154 if (request->auth_user_request != NULL) {
155 if (char const *name = request->auth_user_request->username())
156 return libecap::Area::FromTempBuffer(name, strlen(name));
b38b26cb 157 else if (request->extacl_user.size() > 0)
8661a1d0 158 return libecap::Area::FromTempBuffer(request->extacl_user.rawBuf(),
cb72cd25 159 request->extacl_user.size());
ec4d1a1d 160 }
321f219c 161#endif
22fff3bf
AR
162 return libecap::Area();
163}
164
5038f9d8
AR
165const libecap::Area
166Adaptation::Ecap::XactionRep::masterxSharedValue(const libecap::Name &name) const
167{
168 const HttpRequest *request = dynamic_cast<const HttpRequest*>(theCauseRep ?
169 theCauseRep->raw().header : theVirginRep.raw().header);
170 Must(request);
171 if (name.known()) { // must check to avoid empty names matching unset cfg
172 Adaptation::History::Pointer ah = request->adaptHistory(false);
173 if (ah != NULL) {
174 String name, value;
175 if (ah->getXxRecord(name, value))
176 return libecap::Area::FromTempBuffer(value.rawBuf(), value.size());
177 }
178 }
179 return libecap::Area();
180}
181
71be37e0
CT
182const libecap::Area
183Adaptation::Ecap::XactionRep::metaValue(const libecap::Name &name) const
184{
185 HttpRequest *request = dynamic_cast<HttpRequest*>(theCauseRep ?
71ee0835 186 theCauseRep->raw().header : theVirginRep.raw().header);
71be37e0
CT
187 Must(request);
188 HttpReply *reply = dynamic_cast<HttpReply*>(theVirginRep.raw().header);
189
190 if (name.known()) { // must check to avoid empty names matching unset cfg
d7f4a0b7 191 typedef Notes::iterator ACAMLI;
75d47340
CT
192 for (auto h: Adaptation::Config::metaHeaders) {
193 if (name == h->key().toStdString()) {
194 SBuf matched;
195 if (h->match(request, reply, al, matched))
196 return libecap::Area::FromTempString(matched.toStdString());
71be37e0
CT
197 else
198 return libecap::Area();
199 }
200 }
201 }
202
203 return libecap::Area();
204}
205
71ee0835 206void
71be37e0
CT
207Adaptation::Ecap::XactionRep::visitEachMetaHeader(libecap::NamedValueVisitor &visitor) const
208{
209 HttpRequest *request = dynamic_cast<HttpRequest*>(theCauseRep ?
71ee0835 210 theCauseRep->raw().header : theVirginRep.raw().header);
71be37e0
CT
211 Must(request);
212 HttpReply *reply = dynamic_cast<HttpReply*>(theVirginRep.raw().header);
71ee0835 213
75d47340
CT
214 for (auto h: Adaptation::Config::metaHeaders) {
215 SBuf matched;
216 if (h->match(request, reply, al, matched)) {
217 const libecap::Name name(h->key().toStdString());
218 const libecap::Area value = libecap::Area::FromTempString(matched.toStdString());
71be37e0
CT
219 visitor.visit(name, value);
220 }
221 }
222}
223
fdc96a39 224void
574b508c 225Adaptation::Ecap::XactionRep::start()
fdc96a39
AR
226{
227 Must(theMaster);
4d0854d4 228
e1e90d26
AR
229 if (!theVirginRep.raw().body_pipe)
230 makingVb = opNever; // there is nothing to deliver
4d0854d4 231
d7f4a0b7 232 HttpRequest *request = dynamic_cast<HttpRequest*> (theCauseRep ?
ffb82151 233 theCauseRep->raw().header : theVirginRep.raw().header);
3ff65596 234 Must(request);
d7f4a0b7
CT
235
236 HttpReply *reply = dynamic_cast<HttpReply*>(theVirginRep.raw().header);
237
a22e6cd3 238 Adaptation::History::Pointer ah = request->adaptLogHistory();
e1381638 239 if (ah != NULL) {
3ff65596
AR
240 // retrying=false because ecap never retries transactions
241 adaptHistoryId = ah->recordXactStart(service().cfg().key, current_time, false);
75d47340
CT
242 SBuf matched;
243 for (auto h: Adaptation::Config::metaHeaders) {
244 if (h->match(request, reply, al, matched)) {
cf9f0261
CT
245 if (ah->metaHeaders == NULL)
246 ah->metaHeaders = new NotePairs();
75d47340
CT
247 if (!ah->metaHeaders->hasPair(h->key(), matched))
248 ah->metaHeaders->add(h->key(), matched);
d7f4a0b7
CT
249 }
250 }
3ff65596
AR
251 }
252
fdc96a39
AR
253 theMaster->start();
254}
255
256void
574b508c 257Adaptation::Ecap::XactionRep::swanSong()
fdc96a39 258{
506a0530 259 // clear body_pipes, if any
ea76d91e 260 // this code does not maintain proxying* and canAccessVb states; should it?
506a0530 261
0c276d50 262 if (theAnswerRep) {
f1a768b2
AR
263 BodyPipe::Pointer body_pipe = answer().body_pipe;
264 if (body_pipe != NULL) {
265 Must(body_pipe->stillProducing(this));
266 stopProducingFor(body_pipe, false);
267 }
268 }
506a0530 269
e1e90d26
AR
270 BodyPipe::Pointer &body_pipe = theVirginRep.raw().body_pipe;
271 if (body_pipe != NULL && body_pipe->stillConsuming(this))
272 stopConsumingFrom(body_pipe);
506a0530 273
fdc96a39 274 terminateMaster();
3ff65596
AR
275
276 const HttpRequest *request = dynamic_cast<const HttpRequest*>(theCauseRep ?
e1381638 277 theCauseRep->raw().header : theVirginRep.raw().header);
3ff65596 278 Must(request);
a22e6cd3 279 Adaptation::History::Pointer ah = request->adaptLogHistory();
3ff65596
AR
280 if (ah != NULL && adaptHistoryId >= 0)
281 ah->recordXactFinish(adaptHistoryId);
282
fdc96a39
AR
283 Adaptation::Initiate::swanSong();
284}
285
0a720258
AR
286void
287Adaptation::Ecap::XactionRep::resume()
288{
289 // go async to gain exception protection and done()-based job destruction
290 typedef NullaryMemFunT<Adaptation::Ecap::XactionRep> Dialer;
291 AsyncCall::Pointer call = asyncCall(93, 5, "Adaptation::Ecap::XactionRep::doResume",
292 Dialer(this, &Adaptation::Ecap::XactionRep::doResume));
293 ScheduleCallHere(call);
294}
295
296/// the guts of libecap::host::Xaction::resume() API implementation
297/// which just goes async in Adaptation::Ecap::XactionRep::resume().
298void
299Adaptation::Ecap::XactionRep::doResume()
300{
301 Must(theMaster);
302 theMaster->resume();
303}
304
fdc96a39 305libecap::Message &
574b508c 306Adaptation::Ecap::XactionRep::virgin()
fdc96a39 307{
7b67e5b6 308 return theVirginRep;
fdc96a39
AR
309}
310
4d0854d4 311const libecap::Message &
574b508c 312Adaptation::Ecap::XactionRep::cause()
fdc96a39 313{
4d0854d4
AR
314 Must(theCauseRep != NULL);
315 return *theCauseRep;
fdc96a39
AR
316}
317
4d0854d4 318libecap::Message &
574b508c 319Adaptation::Ecap::XactionRep::adapted()
fdc96a39 320{
0c276d50 321 Must(theAnswerRep);
4d0854d4
AR
322 return *theAnswerRep;
323}
324
325Adaptation::Message &
574b508c 326Adaptation::Ecap::XactionRep::answer()
4d0854d4 327{
f1a768b2
AR
328 MessageRep *rep = dynamic_cast<MessageRep*>(theAnswerRep.get());
329 Must(rep);
4d0854d4
AR
330 return rep->raw();
331}
332
ea76d91e 333void
574b508c 334Adaptation::Ecap::XactionRep::terminateMaster()
4d0854d4
AR
335{
336 if (theMaster) {
ea76d91e
AR
337 AdapterXaction x = theMaster;
338 theMaster.reset();
339 x->stop();
f1a768b2 340 }
4d0854d4
AR
341}
342
4d0854d4 343bool
574b508c 344Adaptation::Ecap::XactionRep::doneAll() const
4d0854d4 345{
e1e90d26 346 return makingVb >= opComplete && proxyingAb >= opComplete &&
26ac0430 347 Adaptation::Initiate::doneAll();
4d0854d4
AR
348}
349
e1e90d26 350// stops receiving virgin and enables auto-consumption, dropping any vb bytes
4d0854d4 351void
e1e90d26 352Adaptation::Ecap::XactionRep::sinkVb(const char *reason)
4d0854d4 353{
e1e90d26 354 debugs(93,4, HERE << "sink for " << reason << "; status:" << status());
4d0854d4 355
e1e90d26
AR
356 // we reset raw().body_pipe when we are done, so use this one for checking
357 const BodyPipePointer &permPipe = theVirginRep.raw().header->body_pipe;
358 if (permPipe != NULL)
359 permPipe->enableAutoConsumption();
3af10ac0 360
e1e90d26
AR
361 forgetVb(reason);
362}
363
364// stops receiving virgin but preserves it for others to use
365void
366Adaptation::Ecap::XactionRep::preserveVb(const char *reason)
367{
368 debugs(93,4, HERE << "preserve for " << reason << "; status:" << status());
369
370 // we reset raw().body_pipe when we are done, so use this one for checking
371 const BodyPipePointer &permPipe = theVirginRep.raw().header->body_pipe;
372 if (permPipe != NULL) {
373 // if libecap consumed, we cannot preserve
374 Must(!permPipe->consumedSize());
3af10ac0
AR
375 }
376
e1e90d26
AR
377 forgetVb(reason);
378}
379
380// disassociates us from vb; the last step of sinking or preserving vb
381void
382Adaptation::Ecap::XactionRep::forgetVb(const char *reason)
383{
384 debugs(93,9, HERE << "forget vb " << reason << "; status:" << status());
ea76d91e 385
e1e90d26
AR
386 BodyPipePointer &p = theVirginRep.raw().body_pipe;
387 if (p != NULL && p->stillConsuming(this))
388 stopConsumingFrom(p);
389
390 if (makingVb == opUndecided)
391 makingVb = opNever;
392 else if (makingVb == opOn)
393 makingVb = opComplete;
fdc96a39
AR
394}
395
26ac0430 396void
574b508c 397Adaptation::Ecap::XactionRep::useVirgin()
fdc96a39 398{
4d0854d4 399 debugs(93,3, HERE << status());
ea76d91e
AR
400 Must(proxyingAb == opUndecided);
401 proxyingAb = opNever;
4d0854d4 402
e1e90d26 403 preserveVb("useVirgin");
2874d9e3 404
63df1d28 405 Http::Message *clone = theVirginRep.raw().header->clone();
2874d9e3 406 // check that clone() copies the pipe so that we do not have to
e1e90d26 407 Must(!theVirginRep.raw().header->body_pipe == !clone->body_pipe);
ea76d91e 408
aaf0559d 409 updateHistory(clone);
3af10ac0 410 sendAnswer(Answer::Forward(clone));
4d0854d4 411 Must(done());
fdc96a39
AR
412}
413
26ac0430 414void
574b508c 415Adaptation::Ecap::XactionRep::useAdapted(const libecap::shared_ptr<libecap::Message> &m)
fdc96a39 416{
4d0854d4 417 debugs(93,3, HERE << status());
ea76d91e 418 Must(m);
4d0854d4 419 theAnswerRep = m;
ea76d91e
AR
420 Must(proxyingAb == opUndecided);
421
63df1d28 422 Http::Message *msg = answer().header;
88df846b 423 updateSources(msg);
ea76d91e
AR
424 if (!theAnswerRep->body()) { // final, bodyless answer
425 proxyingAb = opNever;
aaf0559d 426 updateHistory(msg);
3af10ac0 427 sendAnswer(Answer::Forward(msg));
f1a768b2 428 } else { // got answer headers but need to handle body
ea76d91e 429 proxyingAb = opOn;
f1a768b2 430 Must(!msg->body_pipe); // only host can set body pipes
ea76d91e 431 MessageRep *rep = dynamic_cast<MessageRep*>(theAnswerRep.get());
f1a768b2
AR
432 Must(rep);
433 rep->tieBody(this); // sets us as a producer
434 Must(msg->body_pipe != NULL); // check tieBody
ea76d91e 435
aaf0559d 436 updateHistory(msg);
3af10ac0 437 sendAnswer(Answer::Forward(msg));
ea76d91e 438
4d0854d4 439 debugs(93,4, HERE << "adapter will produce body" << status());
8679e6c2 440 theMaster->abMake(); // libecap will produce
4d0854d4 441 }
fdc96a39
AR
442}
443
3af10ac0
AR
444void
445Adaptation::Ecap::XactionRep::blockVirgin()
446{
447 debugs(93,3, HERE << status());
448 Must(proxyingAb == opUndecided);
449 proxyingAb = opNever;
450
e1e90d26 451 sinkVb("blockVirgin");
3af10ac0 452
aaf0559d 453 updateHistory(NULL);
3af10ac0
AR
454 sendAnswer(Answer::Block(service().cfg().key));
455 Must(done());
456}
457
5038f9d8
AR
458/// Called just before sendAnswer() to record adapter meta-information
459/// which may affect answer processing and may be needed for logging.
460void
63df1d28 461Adaptation::Ecap::XactionRep::updateHistory(Http::Message *adapted)
5038f9d8
AR
462{
463 if (!theMaster) // all updates rely on being able to query the adapter
464 return;
465
466 const HttpRequest *request = dynamic_cast<const HttpRequest*>(theCauseRep ?
467 theCauseRep->raw().header : theVirginRep.raw().header);
468 Must(request);
469
470 // TODO: move common ICAP/eCAP logic to Adaptation::Xaction or similar
471 // TODO: optimize Area-to-String conversion
472
473 // update the cross-transactional database if needed
474 if (const char *xxNameStr = Adaptation::Config::masterx_shared_name) {
475 Adaptation::History::Pointer ah = request->adaptHistory(true);
476 if (ah != NULL) {
477 libecap::Name xxName(xxNameStr); // TODO: optimize?
478 if (const libecap::Area val = theMaster->option(xxName))
479 ah->updateXxRecord(xxNameStr, val.toString().c_str());
480 }
481 }
482
483 // update the adaptation plan if needed
484 if (service().cfg().routing) {
485 String services;
486 if (const libecap::Area services = theMaster->option(libecap::metaNextServices)) {
487 Adaptation::History::Pointer ah = request->adaptHistory(true);
488 if (ah != NULL)
489 ah->updateNextServices(services.toString().c_str());
490 }
491 } // TODO: else warn (occasionally!) if we got libecap::metaNextServices
492
493 // Store received meta headers for adapt::<last_h logformat code use.
494 // If we already have stored headers from a previous adaptation transaction
495 // related to the same master transction, they will be replaced.
496 Adaptation::History::Pointer ah = request->adaptLogHistory();
497 if (ah != NULL) {
498 HttpHeader meta(hoReply);
499 OptionsExtractor extractor(meta);
500 theMaster->visitEachOption(extractor);
501 ah->recordMeta(&meta);
502 }
aaf0559d
AR
503
504 // Add just-created history to the adapted/cloned request that lacks it.
505 if (HttpRequest *adaptedReq = dynamic_cast<HttpRequest*>(adapted))
506 adaptedReq->adaptHistoryImport(*request);
5038f9d8
AR
507}
508
4d0854d4 509void
574b508c 510Adaptation::Ecap::XactionRep::vbDiscard()
fdc96a39 511{
e1e90d26 512 Must(makingVb == opUndecided);
8679e6c2 513 // if adapter does not need vb, we do not need to send it
e1e90d26
AR
514 sinkVb("vbDiscard");
515 Must(makingVb == opNever);
fdc96a39
AR
516}
517
4d0854d4 518void
574b508c 519Adaptation::Ecap::XactionRep::vbMake()
fdc96a39 520{
e1e90d26 521 Must(makingVb == opUndecided);
ea76d91e
AR
522 BodyPipePointer &p = theVirginRep.raw().body_pipe;
523 Must(p != NULL);
e1e90d26
AR
524 Must(p->setConsumerIfNotLate(this)); // to deliver vb, we must receive vb
525 makingVb = opOn;
fdc96a39
AR
526}
527
4d0854d4 528void
574b508c 529Adaptation::Ecap::XactionRep::vbStopMaking()
fdc96a39 530{
e1e90d26 531 Must(makingVb == opOn);
ea76d91e 532 // if adapter does not need vb, we do not need to receive it
e1e90d26
AR
533 sinkVb("vbStopMaking");
534 Must(makingVb == opComplete);
4d0854d4
AR
535}
536
537void
574b508c 538Adaptation::Ecap::XactionRep::vbMakeMore()
4d0854d4 539{
e1e90d26 540 Must(makingVb == opOn); // cannot make more if done proxying
ea76d91e 541 // we cannot guarantee more vb, but we can check that there is a chance
e1e90d26
AR
542 const BodyPipePointer &p = theVirginRep.raw().body_pipe;
543 Must(p != NULL && p->stillConsuming(this)); // we are plugged in
544 Must(!p->productionEnded() && p->mayNeedMoreData()); // and may get more
4d0854d4
AR
545}
546
8679e6c2 547libecap::Area
574b508c 548Adaptation::Ecap::XactionRep::vbContent(libecap::size_type o, libecap::size_type s)
4d0854d4 549{
e1e90d26 550 // We may not be makingVb yet. It should be OK, but see vbContentShift().
ea76d91e 551
8679e6c2 552 const BodyPipePointer &p = theVirginRep.raw().body_pipe;
ea76d91e
AR
553 Must(p != NULL);
554
555 // TODO: make MemBuf use size_t?
556 const size_t haveSize = static_cast<size_t>(p->buf().contentSize());
4d0854d4 557
8679e6c2
AR
558 // convert to Squid types; XXX: check for overflow
559 const uint64_t offset = static_cast<uint64_t>(o);
560 Must(offset <= haveSize); // equal iff at the end of content
561
562 // nsize means no size limit: all content starting from offset
563 const size_t size = s == libecap::nsize ?
26ac0430 564 haveSize - offset : static_cast<size_t>(s);
8679e6c2 565
8679e6c2
AR
566 // XXX: optimize by making theBody a shared_ptr (see Area::FromTemp*() src)
567 return libecap::Area::FromTempBuffer(p->buf().content() + offset,
26ac0430 568 min(static_cast<size_t>(haveSize - offset), size));
4d0854d4
AR
569}
570
571void
574b508c 572Adaptation::Ecap::XactionRep::vbContentShift(libecap::size_type n)
4d0854d4 573{
e1e90d26 574 // We may not be makingVb yet. It should be OK now, but if BodyPipe
ea76d91e
AR
575 // consume() requirements change, we would have to return empty vbContent
576 // until the adapter registers as a consumer
577
8679e6c2
AR
578 BodyPipePointer &p = theVirginRep.raw().body_pipe;
579 Must(p != NULL);
580 const size_t size = static_cast<size_t>(n); // XXX: check for overflow
581 const size_t haveSize = static_cast<size_t>(p->buf().contentSize()); // TODO: make MemBuf use size_t?
582 p->consume(min(size, haveSize));
4d0854d4
AR
583}
584
585void
574b508c 586Adaptation::Ecap::XactionRep::noteAbContentDone(bool atEnd)
4d0854d4 587{
7477a343
AR
588 Must(proxyingAb == opOn && !abProductionFinished);
589 abProductionFinished = true;
590 abProductionAtEnd = atEnd; // store until ready to stop producing ourselves
591 debugs(93,5, HERE << "adapted body production ended");
592 moveAbContent();
4d0854d4
AR
593}
594
8679e6c2 595void
574b508c 596Adaptation::Ecap::XactionRep::noteAbContentAvailable()
4d0854d4 597{
7477a343 598 Must(proxyingAb == opOn && !abProductionFinished);
8679e6c2 599 moveAbContent();
4d0854d4
AR
600}
601
ea76d91e 602#if 0 /* XXX: implement */
4d0854d4 603void
574b508c 604Adaptation::Ecap::XactionRep::setAdaptedBodySize(const libecap::BodySize &size)
4d0854d4
AR
605{
606 Must(answer().body_pipe != NULL);
8679e6c2
AR
607 if (size.known())
608 answer().body_pipe->setBodySize(size.value());
609 // else the piped body size is unknown by default
4d0854d4 610}
8679e6c2 611#endif
4d0854d4
AR
612
613void
574b508c 614Adaptation::Ecap::XactionRep::adaptationDelayed(const libecap::Delay &d)
4d0854d4
AR
615{
616 debugs(93,3, HERE << "adapter needs time: " <<
26ac0430 617 d.state << '/' << d.progress);
4d0854d4 618 // XXX: set timeout?
fdc96a39
AR
619}
620
26ac0430 621void
574b508c 622Adaptation::Ecap::XactionRep::adaptationAborted()
fdc96a39 623{
fdc96a39 624 tellQueryAborted(true); // should eCAP support retries?
ea76d91e 625 mustStop("adaptationAborted");
fdc96a39
AR
626}
627
26ac0430 628void
574b508c 629Adaptation::Ecap::XactionRep::noteMoreBodySpaceAvailable(RefCount<BodyPipe> bp)
fdc96a39 630{
ea76d91e
AR
631 Must(proxyingAb == opOn);
632 moveAbContent();
fdc96a39
AR
633}
634
26ac0430 635void
574b508c 636Adaptation::Ecap::XactionRep::noteBodyConsumerAborted(RefCount<BodyPipe> bp)
fdc96a39 637{
ea76d91e
AR
638 Must(proxyingAb == opOn);
639 stopProducingFor(answer().body_pipe, false);
640 Must(theMaster);
641 theMaster->abStopMaking();
642 proxyingAb = opComplete;
fdc96a39
AR
643}
644
645void
574b508c 646Adaptation::Ecap::XactionRep::noteMoreBodyDataAvailable(RefCount<BodyPipe> bp)
fdc96a39 647{
e1e90d26 648 Must(makingVb == opOn); // or we would not be registered as a consumer
fdc96a39 649 Must(theMaster);
8679e6c2 650 theMaster->noteVbContentAvailable();
fdc96a39
AR
651}
652
653void
574b508c 654Adaptation::Ecap::XactionRep::noteBodyProductionEnded(RefCount<BodyPipe> bp)
fdc96a39 655{
e1e90d26 656 Must(makingVb == opOn); // or we would not be registered as a consumer
fdc96a39 657 Must(theMaster);
8679e6c2 658 theMaster->noteVbContentDone(true);
e1e90d26 659 vbProductionFinished = true;
fdc96a39
AR
660}
661
662void
574b508c 663Adaptation::Ecap::XactionRep::noteBodyProducerAborted(RefCount<BodyPipe> bp)
fdc96a39 664{
e1e90d26 665 Must(makingVb == opOn); // or we would not be registered as a consumer
8679e6c2
AR
666 Must(theMaster);
667 theMaster->noteVbContentDone(false);
e1e90d26 668 vbProductionFinished = true;
fdc96a39
AR
669}
670
671void
574b508c 672Adaptation::Ecap::XactionRep::noteInitiatorAborted()
fdc96a39
AR
673{
674 mustStop("initiator aborted");
675}
676
8679e6c2
AR
677// get content from the adapter and put it into the adapted pipe
678void
574b508c 679Adaptation::Ecap::XactionRep::moveAbContent()
8679e6c2 680{
ea76d91e 681 Must(proxyingAb == opOn);
8679e6c2 682 const libecap::Area c = theMaster->abContent(0, libecap::nsize);
7477a343
AR
683 debugs(93,5, HERE << "up to " << c.size << " bytes");
684 if (c.size == 0 && abProductionFinished) { // no ab now and in the future
685 stopProducingFor(answer().body_pipe, abProductionAtEnd);
686 proxyingAb = opComplete;
687 debugs(93,5, HERE << "last adapted body data retrieved");
e1381638 688 } else if (c.size > 0) {
7477a343
AR
689 if (const size_t used = answer().body_pipe->putMoreData(c.start, c.size))
690 theMaster->abContentShift(used);
691 }
8679e6c2
AR
692}
693
694const char *
574b508c 695Adaptation::Ecap::XactionRep::status() const
fdc96a39 696{
4d0854d4
AR
697 static MemBuf buf;
698 buf.reset();
699
700 buf.append(" [", 2);
701
e1e90d26 702 if (makingVb)
721dcff0 703 buf.appendf("M%d", static_cast<int>(makingVb));
e1e90d26
AR
704
705 const BodyPipePointer &vp = theVirginRep.raw().body_pipe;
706 if (!vp)
707 buf.append(" !V", 3);
ec4d1a1d 708 else if (vp->stillConsuming(const_cast<XactionRep*>(this)))
e1e90d26
AR
709 buf.append(" Vc", 3);
710 else
711 buf.append(" V?", 3);
712
713 if (vbProductionFinished)
714 buf.append(".", 1);
715
721dcff0 716 buf.appendf(" A%d", static_cast<int>(proxyingAb));
506a0530 717
ea76d91e
AR
718 if (proxyingAb == opOn) {
719 MessageRep *rep = dynamic_cast<MessageRep*>(theAnswerRep.get());
720 Must(rep);
f1a768b2 721 const BodyPipePointer &ap = rep->raw().body_pipe;
e1e90d26
AR
722 if (!ap)
723 buf.append(" !A", 3);
724 else if (ap->stillProducing(const_cast<XactionRep*>(this)))
725 buf.append(" Ap", 3);
726 else
727 buf.append(" A?", 3);
f1a768b2 728 }
4d0854d4 729
1083f207 730 buf.appendf(" %s%u]", id.prefix(), id.value);
4d0854d4
AR
731
732 buf.terminate();
733
734 return buf.content();
fdc96a39 735}
f53969cc 736
88df846b 737void
63df1d28 738Adaptation::Ecap::XactionRep::updateSources(Http::Message *adapted)
88df846b 739{
63df1d28 740 adapted->sources |= service().cfg().connectionEncryption ? Http::Message::srcEcaps : Http::Message::srcEcap;
5ceaee75
CT
741
742 // Update masterXaction object for adapted HTTP requests.
743 if (HttpRequest *adaptedReq = dynamic_cast<HttpRequest*>(adapted)) {
744 HttpRequest *request = dynamic_cast<HttpRequest*> (theCauseRep ?
745 theCauseRep->raw().header : theVirginRep.raw().header);
746 Must(request);
747 adaptedReq->masterXaction = request->masterXaction;
748 }
88df846b 749}
ff89bfa0 750