{
const XactOutcome xoUnknown = "ICAP_ERR_UNKNOWN";
+const XactOutcome xoRace = "ICAP_ERR_RACE";
const XactOutcome xoError = "ICAP_ERR_OTHER";
const XactOutcome xoOpt = "ICAP_OPT";
const XactOutcome xoEcho = "ICAP_ECHO";
typedef const char *XactOutcome; ///< transaction result for logging
extern const XactOutcome xoUnknown; ///< initial value: outcome was not set
+extern const XactOutcome xoRace; ///< ICAP server closed pconn when we started
extern const XactOutcome xoError; ///< all kinds of transaction errors
extern const XactOutcome xoOpt; ///< OPTION transaction
extern const XactOutcome xoEcho; ///< preserved virgin message (ICAP 204)
theService->cfg().methodStr() << " " <<
theService->cfg().uri << status());
reuseConnection = false;
- throw TexcHere(connector != NULL ?
+ const bool whileConnecting = connector != NULL;
+ closeConnection(); // so that late Comm callbacks do not disturb bypass
+ throw TexcHere(whileConnecting ?
"timed out while connecting to the ICAP service" :
"timed out while talking to the ICAP service");
}
Must(io.flag == COMM_OK);
Must(io.size >= 0);
+ if (!io.size) {
+ commEof = true;
+ reuseConnection = false;
+
+ // detect a pconn race condition: eof on the first pconn read
+ if (!al.icap.bytesRead && retriable()) {
+ setOutcome(xoRace);
+ mustStop("pconn race");
+ return;
+ }
+ } else {
+
al.icap.bytesRead+=io.size;
updateTimeout();
* here instead of reading directly into readBuf.buf.
*/
- if (io.size > 0) {
readBuf.append(commBuf, io.size);
disableRetries(); // because pconn did not fail
- } else {
- reuseConnection = false;
- commEof = true;
}
handleCommRead(io.size);