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