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