]> git.ipfire.org Git - thirdparty/squid.git/blame - src/adaptation/icap/Xaction.cc
Polish: Drop redundant HttpMsgPointerT template
[thirdparty/squid.git] / src / adaptation / icap / Xaction.cc
CommitLineData
774c051c 1/*
507d0a78 2 * DEBUG: section 93 ICAP (RFC 3507) Client
774c051c 3 */
4
582c2af2
FC
5#include "squid.h"
6#include "acl/FilledChecklist.h"
7#include "adaptation/icap/Config.h"
8#include "adaptation/icap/Launcher.h"
9#include "adaptation/icap/Xaction.h"
10#include "base/TextException.h"
774c051c 11#include "comm.h"
d6327017 12#include "comm/Connection.h"
aed188fd 13#include "comm/ConnOpener.h"
ec41b64c 14#include "comm/Write.h"
bd7f2ede 15#include "CommCalls.h"
582c2af2
FC
16#include "err_detail_type.h"
17#include "fde.h"
28618087 18#include "forward.h"
582c2af2 19#include "globals.h"
5f8252d2 20#include "HttpMsg.h"
3ff65596 21#include "HttpReply.h"
582c2af2 22#include "HttpRequest.h"
3ff65596 23#include "icap_log.h"
582c2af2 24#include "ipcache.h"
8a89c28f 25#include "Mem.h"
582c2af2 26#include "pconn.h"
4d5904f7 27#include "SquidConfig.h"
3ff65596 28#include "SquidTime.h"
781ce8ff 29
26cc52cb 30//CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Icap, Xaction);
5f8252d2 31
d1c7f781 32Adaptation::Icap::Xaction::Xaction(const char *aTypeName, Adaptation::Icap::ServiceRep::Pointer &aService):
bd7f2ede 33 AsyncJob(aTypeName),
4299f876 34 Adaptation::Initiate(aTypeName),
3ff65596
AR
35 icapRequest(NULL),
36 icapReply(NULL),
37 attempts(0),
2413d60a 38 connection(NULL),
a22e6cd3 39 theService(aService),
774c051c 40 commBuf(NULL), commBufSize(0),
41 commEof(false),
2dfede9e 42 reuseConnection(true),
c824c43b 43 isRetriable(true),
3ff65596 44 isRepeatable(true),
cfc68405 45 ignoreLastWrite(false),
41ebd397
CT
46 connector(NULL), reader(NULL), writer(NULL), closer(NULL),
47 alep(new AccessLogEntry),
d471b08a
AK
48 al(*alep),
49 cs(NULL)
774c051c 50{
5f8252d2 51 debugs(93,3, typeName << " constructed, this=" << this <<
9e008dda 52 " [icapx" << id << ']'); // we should not call virtual status() here
b248c2a3
AJ
53 icapRequest = new HttpRequest;
54 HTTPMSGLOCK(icapRequest);
3ff65596 55 icap_tr_start = current_time;
774c051c 56}
57
26cc52cb 58Adaptation::Icap::Xaction::~Xaction()
774c051c 59{
5f8252d2 60 debugs(93,3, typeName << " destructed, this=" << this <<
9e008dda 61 " [icapx" << id << ']'); // we should not call virtual status() here
3ff65596 62 HTTPMSGUNLOCK(icapRequest);
5f8252d2 63}
64
26cc52cb
AR
65Adaptation::Icap::ServiceRep &
66Adaptation::Icap::Xaction::service()
0bef8dd7 67{
a22e6cd3
AR
68 Must(theService != NULL);
69 return *theService;
0bef8dd7
AR
70}
71
26cc52cb 72void Adaptation::Icap::Xaction::disableRetries()
9e008dda 73{
3ff65596
AR
74 debugs(93,5, typeName << (isRetriable ? " from now on" : " still") <<
75 " cannot be retried " << status());
c824c43b 76 isRetriable = false;
77}
78
3ff65596
AR
79void Adaptation::Icap::Xaction::disableRepeats(const char *reason)
80{
81 debugs(93,5, typeName << (isRepeatable ? " from now on" : " still") <<
82 " cannot be repeated because " << reason << status());
83 isRepeatable = false;
84}
85
26cc52cb 86void Adaptation::Icap::Xaction::start()
5f8252d2 87{
0bef8dd7 88 Adaptation::Initiate::start();
5f8252d2 89
90 readBuf.init(SQUID_TCP_SO_RCVBUF, SQUID_TCP_SO_RCVBUF);
91 commBuf = (char*)memAllocBuf(SQUID_TCP_SO_RCVBUF, &commBufSize);
92 // make sure maximum readBuf space does not exceed commBuf size
93 Must(static_cast<size_t>(readBuf.potentialSpaceSize()) <= commBufSize);
774c051c 94}
95
fb505fa1
CT
96static void
97icapLookupDnsResults(const ipcache_addrs *ia, const DnsLookupDetails &, void *data)
98{
99 Adaptation::Icap::Xaction *xa = static_cast<Adaptation::Icap::Xaction *>(data);
100 xa->dnsLookupDone(ia);
101}
102
774c051c 103// TODO: obey service-specific, OPTIONS-reported connection limit
642a305c
AJ
104void
105Adaptation::Icap::Xaction::openConnection()
774c051c 106{
aed188fd 107 Must(!haveConnection());
c824c43b 108
2dba5b8e 109 Adaptation::Icap::ServiceRep &s = service();
774c051c 110
26cc52cb 111 if (!TheConfig.reuse_connections)
560d7d2d 112 disableRetries(); // this will also safely drain pconn pool
113
2dba5b8e
CT
114 bool wasReused = false;
115 connection = s.getConnection(isRetriable, wasReused);
2413d60a 116
983983ce 117 if (wasReused && Comm::IsConnOpen(connection)) {
2dba5b8e 118 // Set comm Close handler
bd7f2ede 119 // fake the connect callback
26cc52cb
AR
120 // TODO: can we sync call Adaptation::Icap::Xaction::noteCommConnected here instead?
121 typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommConnectCbParams> Dialer;
4299f876
AR
122 CbcPointer<Xaction> self(this);
123 Dialer dialer(self, &Adaptation::Icap::Xaction::noteCommConnected);
642a305c 124 dialer.params.conn = connection;
bd7f2ede 125 dialer.params.flag = COMM_OK;
126 // fake other parameters by copying from the existing connection
26cc52cb 127 connector = asyncCall(93,3, "Adaptation::Icap::Xaction::noteCommConnected", dialer);
9e008dda 128 ScheduleCallHere(connector);
c8ceec27 129 return;
2dfede9e 130 }
131
c8ceec27 132 disableRetries(); // we only retry pconn failures
133
983983ce 134 // Attempt to open a new connection...
2dba5b8e 135 debugs(93,3, typeName << " opens connection to " << s.cfg().host.termedBuf() << ":" << s.cfg().port);
774c051c 136
fb505fa1
CT
137 // Locate the Service IP(s) to open
138 ipcache_nbgethostbyname(s.cfg().host.termedBuf(), icapLookupDnsResults, this);
139}
919fc80d 140
fb505fa1
CT
141void
142Adaptation::Icap::Xaction::dnsLookupDone(const ipcache_addrs *ia)
143{
144 Adaptation::Icap::ServiceRep &s = service();
2dba5b8e 145
fb505fa1
CT
146 if (ia == NULL) {
147 debugs(44, DBG_IMPORTANT, "ICAP: Unknown service host: " << s.cfg().host);
774c051c 148
fb505fa1
CT
149#if WHEN_IPCACHE_NBGETHOSTBYNAME_USES_ASYNC_CALLS
150 dieOnConnectionFailure(); // throws
151#else // take a step back into protected Async call dialing.
152 // fake the connect callback
153 typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommConnectCbParams> Dialer;
154 CbcPointer<Xaction> self(this);
155 Dialer dialer(self, &Adaptation::Icap::Xaction::noteCommConnected);
156 dialer.params.conn = connection;
157 dialer.params.flag = COMM_ERROR;
158 // fake other parameters by copying from the existing connection
159 connector = asyncCall(93,3, "Adaptation::Icap::Xaction::noteCommConnected", dialer);
160 ScheduleCallHere(connector);
161#endif
162 return;
163 }
bd7f2ede 164
fb505fa1
CT
165 assert(ia->cur < ia->count);
166
167 connection = new Comm::Connection;
168 connection->remote = ia->in_addrs[ia->cur];
169 connection->remote.SetPort(s.cfg().port);
170 getOutgoingAddress(NULL, connection);
171
172 // TODO: service bypass status may differ from that of a transaction
26cc52cb 173 typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommConnectCbParams> ConnectDialer;
d1c7f781 174 connector = JobCallback(93,3, ConnectDialer, this, Adaptation::Icap::Xaction::noteCommConnected);
d471b08a 175 cs = new Comm::ConnOpener(connection, connector, TheConfig.connect_timeout(service().cfg().bypass));
aed188fd 176 cs->setHost(s.cfg().host.termedBuf());
a42bff56 177 AsyncJob::Start(cs);
774c051c 178}
179
2dfede9e 180/*
181 * This event handler is necessary to work around the no-rentry policy
26cc52cb 182 * of Adaptation::Icap::Xaction::callStart()
2dfede9e 183 */
bd7f2ede 184#if 0
2dfede9e 185void
26cc52cb 186Adaptation::Icap::Xaction::reusedConnection(void *data)
2dfede9e 187{
192378eb 188 debugs(93, 5, HERE << "reused connection");
26cc52cb 189 Adaptation::Icap::Xaction *x = (Adaptation::Icap::Xaction*)data;
2dfede9e 190 x->noteCommConnected(COMM_OK);
191}
bd7f2ede 192#endif
2dfede9e 193
26cc52cb 194void Adaptation::Icap::Xaction::closeConnection()
774c051c 195{
aed188fd 196 if (haveConnection()) {
774c051c 197
bd7f2ede 198 if (closer != NULL) {
2413d60a 199 comm_remove_close_handler(connection->fd, closer);
774c051c 200 closer = NULL;
201 }
202
c99de607 203 cancelRead(); // may not work
204
5f8252d2 205 if (reuseConnection && !doneWithIo()) {
dd6e6148 206 //status() adds leading spaces.
5f8252d2 207 debugs(93,5, HERE << "not reusing pconn due to pending I/O" << status());
c99de607 208 reuseConnection = false;
209 }
774c051c 210
2dba5b8e 211 if (reuseConnection)
c824c43b 212 disableRetries();
2dba5b8e 213
a32c060f 214 const bool reset = !reuseConnection &&
ee5216b8 215 (al.icap.outcome == xoGone || al.icap.outcome == xoError);
a32c060f 216
2dba5b8e 217 Adaptation::Icap::ServiceRep &s = service();
a32c060f 218 s.putConnection(connection, reuseConnection, reset, status());
774c051c 219
c99de607 220 writer = NULL;
221 reader = NULL;
774c051c 222 connector = NULL;
5d779c44 223 connection = NULL;
774c051c 224 }
225}
226
227// connection with the ICAP service established
26cc52cb 228void Adaptation::Icap::Xaction::noteCommConnected(const CommConnectCbParams &io)
774c051c 229{
d471b08a
AK
230 cs = NULL;
231
cfd66529
AJ
232 if (io.flag == COMM_TIMEOUT) {
233 handleCommTimedout();
234 return;
235 }
236
bd7f2ede 237 Must(connector != NULL);
774c051c 238 connector = NULL;
c99de607 239
bd7f2ede 240 if (io.flag != COMM_OK)
c99de607 241 dieOnConnectionFailure(); // throws
242
fb505fa1
CT
243 typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommTimeoutCbParams> TimeoutDialer;
244 AsyncCall::Pointer timeoutCall = asyncCall(93, 5, "Adaptation::Icap::Xaction::noteCommTimedout",
245 TimeoutDialer(this,&Adaptation::Icap::Xaction::noteCommTimedout));
933dd095 246 commSetConnTimeout(io.conn, TheConfig.connect_timeout(service().cfg().bypass), timeoutCall);
fb505fa1 247
cfd66529
AJ
248 typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommCloseCbParams> CloseDialer;
249 closer = asyncCall(93, 5, "Adaptation::Icap::Xaction::noteCommClosed",
250 CloseDialer(this,&Adaptation::Icap::Xaction::noteCommClosed));
251 comm_add_close_handler(io.conn->fd, closer);
252
983983ce 253// ?? fd_table[io.conn->fd].noteUse(icapPconnPool);
2dba5b8e 254 service().noteConnectionUse(connection);
774c051c 255
256 handleCommConnected();
774c051c 257}
258
26cc52cb 259void Adaptation::Icap::Xaction::dieOnConnectionFailure()
9e008dda 260{
4932ad93 261 debugs(93, 2, HERE << typeName <<
9e008dda 262 " failed to connect to " << service().cfg().uri);
fb505fa1 263 service().noteConnectionFailed("failure");
64b66b76 264 detailError(ERR_DETAIL_ICAP_XACT_START);
c99de607 265 throw TexcHere("cannot connect to the ICAP service");
266}
267
26cc52cb 268void Adaptation::Icap::Xaction::scheduleWrite(MemBuf &buf)
774c051c 269{
aed188fd
AJ
270 Must(haveConnection());
271
774c051c 272 // comm module will free the buffer
26cc52cb 273 typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommIoCbParams> Dialer;
1b76e6c1 274 writer = JobCallback(93, 3,
4cb2536f 275 Dialer, this, Adaptation::Icap::Xaction::noteCommWrote);
bd7f2ede 276
ec41b64c 277 Comm::Write(connection, &buf, writer);
c99de607 278 updateTimeout();
774c051c 279}
280
26cc52cb 281void Adaptation::Icap::Xaction::noteCommWrote(const CommIoCbParams &io)
774c051c 282{
bd7f2ede 283 Must(writer != NULL);
774c051c 284 writer = NULL;
9e008dda 285
cfc68405 286 if (ignoreLastWrite) {
287 // a hack due to comm inability to cancel a pending write
9e008dda 288 ignoreLastWrite = false;
bd7f2ede 289 debugs(93, 7, HERE << "ignoring last write; status: " << io.flag);
cfc68405 290 } else {
bd7f2ede 291 Must(io.flag == COMM_OK);
3ff65596 292 al.icap.bytesSent += io.size;
cfc68405 293 updateTimeout();
bd7f2ede 294 handleCommWrote(io.size);
cfc68405 295 }
774c051c 296}
297
298// communication timeout with the ICAP service
26cc52cb 299void Adaptation::Icap::Xaction::noteCommTimedout(const CommTimeoutCbParams &io)
774c051c 300{
774c051c 301 handleCommTimedout();
774c051c 302}
303
26cc52cb 304void Adaptation::Icap::Xaction::handleCommTimedout()
774c051c 305{
4932ad93 306 debugs(93, 2, HERE << typeName << " failed: timeout with " <<
9e008dda 307 theService->cfg().methodStr() << " " <<
a7a42b14 308 theService->cfg().uri << status());
fe3e2600 309 reuseConnection = false;
3f832a99 310 const bool whileConnecting = connector != NULL;
fb505fa1
CT
311 if (whileConnecting) {
312 assert(!haveConnection());
313 theService->noteConnectionFailed("timedout");
314 } else
315 closeConnection(); // so that late Comm callbacks do not disturb bypass
3f832a99 316 throw TexcHere(whileConnecting ?
9e008dda
AJ
317 "timed out while connecting to the ICAP service" :
318 "timed out while talking to the ICAP service");
774c051c 319}
320
321// unexpected connection close while talking to the ICAP service
26cc52cb 322void Adaptation::Icap::Xaction::noteCommClosed(const CommCloseCbParams &io)
774c051c 323{
324 closer = NULL;
774c051c 325 handleCommClosed();
774c051c 326}
327
26cc52cb 328void Adaptation::Icap::Xaction::handleCommClosed()
774c051c 329{
64b66b76 330 detailError(ERR_DETAIL_ICAP_XACT_CLOSE);
774c051c 331 mustStop("ICAP service connection externally closed");
332}
333
3ff65596
AR
334void Adaptation::Icap::Xaction::callException(const std::exception &e)
335{
336 setOutcome(xoError);
8277060a 337 service().noteFailure();
3ff65596
AR
338 Adaptation::Initiate::callException(e);
339}
340
26cc52cb 341void Adaptation::Icap::Xaction::callEnd()
774c051c 342{
c824c43b 343 if (doneWithIo()) {
344 debugs(93, 5, HERE << typeName << " done with I/O" << status());
345 closeConnection();
346 }
0bef8dd7 347 Adaptation::Initiate::callEnd(); // may destroy us
774c051c 348}
349
26cc52cb 350bool Adaptation::Icap::Xaction::doneAll() const
774c051c 351{
0bef8dd7 352 return !connector && !reader && !writer && Adaptation::Initiate::doneAll();
774c051c 353}
354
26cc52cb 355void Adaptation::Icap::Xaction::updateTimeout()
9e008dda 356{
aed188fd
AJ
357 Must(haveConnection());
358
bd7f2ede 359 if (reader != NULL || writer != NULL) {
c99de607 360 // restart the timeout before each I/O
361 // XXX: why does Config.Timeout lacks a write timeout?
cfc68405 362 // TODO: service bypass status may differ from that of a transaction
26cc52cb 363 typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommTimeoutCbParams> TimeoutDialer;
d1c7f781 364 AsyncCall::Pointer call = JobCallback(93, 5, TimeoutDialer, this, Adaptation::Icap::Xaction::noteCommTimedout);
8d77a37c 365 commSetConnTimeout(connection, TheConfig.io_timeout(service().cfg().bypass), call);
c99de607 366 } else {
367 // clear timeout when there is no I/O
368 // Do we need a lifetime timeout?
8d77a37c 369 commUnsetConnTimeout(connection);
c99de607 370 }
371}
372
26cc52cb 373void Adaptation::Icap::Xaction::scheduleRead()
774c051c 374{
aed188fd 375 Must(haveConnection());
774c051c 376 Must(!reader);
377 Must(readBuf.hasSpace());
378
774c051c 379 /*
26cc52cb 380 * See comments in Adaptation::Icap::Xaction.h about why we use commBuf
bb790702 381 * here instead of reading directly into readBuf.buf.
774c051c 382 */
26cc52cb 383 typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommIoCbParams> Dialer;
1b76e6c1 384 reader = JobCallback(93, 3,
4cb2536f 385 Dialer, this, Adaptation::Icap::Xaction::noteCommRead);
774c051c 386
ec20038e 387 comm_read(connection, commBuf, readBuf.spaceSize(), reader);
c99de607 388 updateTimeout();
774c051c 389}
390
391// comm module read a portion of the ICAP response for us
26cc52cb 392void Adaptation::Icap::Xaction::noteCommRead(const CommIoCbParams &io)
774c051c 393{
bd7f2ede 394 Must(reader != NULL);
774c051c 395 reader = NULL;
396
bd7f2ede 397 Must(io.flag == COMM_OK);
774c051c 398
3f832a99
AR
399 if (!io.size) {
400 commEof = true;
401 reuseConnection = false;
3ff65596 402
3f832a99
AR
403 // detect a pconn race condition: eof on the first pconn read
404 if (!al.icap.bytesRead && retriable()) {
405 setOutcome(xoRace);
406 mustStop("pconn race");
407 return;
408 }
409 } else {
c99de607 410
5be49f98 411 al.icap.bytesRead+=io.size;
774c051c 412
5be49f98 413 updateTimeout();
c99de607 414
5be49f98 415 debugs(93, 3, HERE << "read " << io.size << " bytes");
774c051c 416
5be49f98
A
417 /*
418 * See comments in Adaptation::Icap::Xaction.h about why we use commBuf
419 * here instead of reading directly into readBuf.buf.
420 */
774c051c 421
bd7f2ede 422 readBuf.append(commBuf, io.size);
c824c43b 423 disableRetries(); // because pconn did not fail
c824c43b 424 }
774c051c 425
bd7f2ede 426 handleCommRead(io.size);
774c051c 427}
428
26cc52cb 429void Adaptation::Icap::Xaction::cancelRead()
774c051c 430{
bd7f2ede 431 if (reader != NULL) {
aed188fd 432 Must(haveConnection());
2413d60a 433 comm_read_cancel(connection->fd, reader);
bd7f2ede 434 reader = NULL;
774c051c 435 }
436}
437
26cc52cb 438bool Adaptation::Icap::Xaction::parseHttpMsg(HttpMsg *msg)
774c051c 439{
def17b6a 440 debugs(93, 5, HERE << "have " << readBuf.contentSize() << " head bytes to parse");
774c051c 441
442 http_status error = HTTP_STATUS_NONE;
443 const bool parsed = msg->parse(&readBuf, commEof, &error);
444 Must(parsed || !error); // success or need more data
445
446 if (!parsed) { // need more data
447 Must(mayReadMore());
448 msg->reset();
449 return false;
450 }
451
452 readBuf.consume(msg->hdr_sz);
453 return true;
454}
455
26cc52cb 456bool Adaptation::Icap::Xaction::mayReadMore() const
774c051c 457{
458 return !doneReading() && // will read more data
459 readBuf.hasSpace(); // have space for more data
460}
461
26cc52cb 462bool Adaptation::Icap::Xaction::doneReading() const
774c051c 463{
464 return commEof;
465}
466
26cc52cb 467bool Adaptation::Icap::Xaction::doneWriting() const
c99de607 468{
469 return !writer;
470}
471
26cc52cb 472bool Adaptation::Icap::Xaction::doneWithIo() const
c99de607 473{
aed188fd 474 return haveConnection() &&
9e008dda
AJ
475 !connector && !reader && !writer && // fast checks, some redundant
476 doneReading() && doneWriting();
c99de607 477}
478
aed188fd
AJ
479bool Adaptation::Icap::Xaction::haveConnection() const
480{
481 return connection != NULL && connection->isOpen();
482}
483
c824c43b 484// initiator aborted
26cc52cb 485void Adaptation::Icap::Xaction::noteInitiatorAborted()
774c051c 486{
c824c43b 487
4299f876 488 if (theInitiator.set()) {
07e72f8e 489 debugs(93,4, HERE << "Initiator gone before ICAP transaction ended");
c824c43b 490 clearInitiator();
64b66b76 491 detailError(ERR_DETAIL_ICAP_INIT_GONE);
07e72f8e 492 setOutcome(xoGone);
c824c43b 493 mustStop("initiator aborted");
c99de607 494 }
c824c43b 495
774c051c 496}
497
3ff65596
AR
498void Adaptation::Icap::Xaction::setOutcome(const Adaptation::Icap::XactOutcome &xo)
499{
500 if (al.icap.outcome != xoUnknown) {
501 debugs(93, 3, HERE << "Warning: reseting outcome: from " <<
e1381638 502 al.icap.outcome << " to " << xo);
3ff65596
AR
503 } else {
504 debugs(93, 4, HERE << xo);
505 }
506 al.icap.outcome = xo;
507}
508
5f8252d2 509// This 'last chance' method is called before a 'done' transaction is deleted.
510// It is wrong to call virtual methods from a destructor. Besides, this call
511// indicates that the transaction will terminate as planned.
26cc52cb 512void Adaptation::Icap::Xaction::swanSong()
774c051c 513{
5f8252d2 514 // kids should sing first and then call the parent method.
45f2e27f
A
515 if (cs) {
516 debugs(93,6, HERE << id << " about to notify ConnOpener!");
517 CallJobHere(93, 3, cs, Comm::ConnOpener, noteAbort);
518 cs = NULL;
519 service().noteConnectionFailed("abort");
d471b08a 520 }
5f8252d2 521
522 closeConnection(); // TODO: rename because we do not always close
523
524 if (!readBuf.isNull())
525 readBuf.clean();
526
527 if (commBuf)
528 memFreeBuf(commBufSize, commBuf);
774c051c 529
4299f876 530 tellQueryAborted();
3ff65596
AR
531
532 maybeLog();
774c051c 533
0bef8dd7 534 Adaptation::Initiate::swanSong();
774c051c 535}
536
e1381638
AJ
537void Adaptation::Icap::Xaction::tellQueryAborted()
538{
4299f876 539 if (theInitiator.set()) {
b248c2a3 540 Adaptation::Icap::XactAbortInfo abortInfo(icapRequest, icapReply.getRaw(),
4cb2536f 541 retriable(), repeatable());
4299f876
AR
542 Launcher *launcher = dynamic_cast<Launcher*>(theInitiator.get());
543 // launcher may be nil if initiator is invalid
544 CallJobHere1(91,5, CbcPointer<Launcher>(launcher),
4cb2536f 545 Launcher, noteXactAbort, abortInfo);
4299f876
AR
546 clearInitiator();
547 }
3ff65596
AR
548}
549
e1381638
AJ
550void Adaptation::Icap::Xaction::maybeLog()
551{
552 if (IcapLogfileStatus == LOG_ENABLE) {
3ff65596 553 ACLChecklist *checklist = new ACLFilledChecklist(::Config.accessList.icap, al.request, dash_str);
2efeb0b7 554 if (!::Config.accessList.icap || checklist->fastCheck() == ACCESS_ALLOWED) {
3ff65596 555 finalizeLogInfo();
41ebd397 556 icapLogLog(alep, checklist);
3ff65596 557 }
3ff65596
AR
558 delete checklist;
559 }
560}
561
562void Adaptation::Icap::Xaction::finalizeLogInfo()
563{
564 //prepare log data
565 al.icp.opcode = ICP_INVALID;
e1381638 566
3ff65596
AR
567 const Adaptation::Icap::ServiceRep &s = service();
568 al.icap.hostAddr = s.cfg().host.termedBuf();
569 al.icap.serviceName = s.cfg().key;
570 al.icap.reqUri = s.cfg().uri;
e1381638 571
3ff65596
AR
572 al.icap.ioTime = tvSubMsec(icap_tio_start, icap_tio_finish);
573 al.icap.trTime = tvSubMsec(icap_tr_start, current_time);
574
b248c2a3
AJ
575 al.icap.request = icapRequest;
576 HTTPMSGLOCK(al.icap.request);
577 if (icapReply != NULL) {
578 al.icap.reply = icapReply.getRaw();
579 HTTPMSGLOCK(al.icap.reply);
3ff65596
AR
580 al.icap.resStatus = icapReply->sline.status;
581 }
582}
583
774c051c 584// returns a temporary string depicting transaction status, for debugging
26cc52cb 585const char *Adaptation::Icap::Xaction::status() const
774c051c 586{
587 static MemBuf buf;
588 buf.reset();
589
5f8252d2 590 buf.append(" [", 2);
774c051c 591
592 fillPendingStatus(buf);
593 buf.append("/", 1);
594 fillDoneStatus(buf);
595
52ed047a 596 buf.Printf(" %s%u]", id.Prefix, id.value);
774c051c 597
598 buf.terminate();
599
600 return buf.content();
601}
602
26cc52cb 603void Adaptation::Icap::Xaction::fillPendingStatus(MemBuf &buf) const
774c051c 604{
aed188fd 605 if (haveConnection()) {
2413d60a 606 buf.Printf("FD %d", connection->fd);
774c051c 607
bd7f2ede 608 if (writer != NULL)
774c051c 609 buf.append("w", 1);
610
bd7f2ede 611 if (reader != NULL)
774c051c 612 buf.append("r", 1);
613
5f8252d2 614 buf.append(";", 1);
774c051c 615 }
616}
617
26cc52cb 618void Adaptation::Icap::Xaction::fillDoneStatus(MemBuf &buf) const
774c051c 619{
aed188fd 620 if (haveConnection() && commEof)
2413d60a 621 buf.Printf("Comm(%d)", connection->fd);
774c051c 622
623 if (stopReason != NULL)
624 buf.Printf("Stopped");
625}
3cfc19b3 626
26cc52cb 627bool Adaptation::Icap::Xaction::fillVirginHttpHeader(MemBuf &buf) const
3cfc19b3 628{
629 return false;
630}