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