void
Http::Tunneler::handleConnectionClosure(const CommCloseCbParams ¶ms)
{
+ closer = nullptr;
if (connection) {
+ countFailingConnection();
connection->noteClosure();
- // TODO: Properly get rid of connection here instead of keeping a closed
- // connection object for peerConnectFailed(),noteUses() in bailWith().
+ connection = nullptr;
}
- closer = nullptr;
bailWith(new ErrorState(ERR_CONNECT_FAIL, Http::scBadGateway, request.getRaw(), al));
}
Must(error);
answer().squidError = error;
- if (const auto p = connection->getPeer())
- peerConnectFailed(p);
-
- callBack();
- disconnect();
-
- // TODO: Close before callBack(); do not pretend to send an open connection.
- if (Comm::IsConnOpen(connection)) {
- if (noteFwdPconnUse)
- fwdPconnPool->noteUses(fd_table[connection->fd].pconn.uses);
+ if (const auto failingConnection = connection) {
// TODO: Reuse to-peer connections after a CONNECT error response.
-
- assert(!closer); // the above disconnect() removes it
- connection->close();
+ countFailingConnection();
+ disconnect();
+ failingConnection->close();
}
- connection = nullptr;
+
+ callBack();
}
void
Http::Tunneler::sendSuccess()
{
assert(answer().positive());
- callBack();
+ assert(Comm::IsConnOpen(connection));
+ answer().conn = connection;
disconnect();
+ callBack();
+}
+
+
+void
+Http::Tunneler::countFailingConnection()
+{
+ assert(connection);
+ if (const auto p = connection->getPeer())
+ peerConnectFailed(p);
+ if (noteFwdPconnUse && connection->isOpen())
+ fwdPconnPool->noteUses(fd_table[connection->fd].pconn.uses);
}
void
Http::Tunneler::disconnect()
{
+ const auto stillOpen = Comm::IsConnOpen(connection);
+
if (closer) {
- comm_remove_close_handler(connection->fd, closer);
+ if (stillOpen)
+ comm_remove_close_handler(connection->fd, closer);
closer = nullptr;
}
if (reader) {
- if (Comm::IsConnOpen(connection))
+ if (stillOpen)
Comm::ReadCancel(connection->fd, reader);
reader = nullptr;
}
- if (Comm::IsConnOpen(connection))
+ if (stillOpen)
commUnsetConnTimeout(connection);
+
+ connection = nullptr; // may still be open
}
void
Http::Tunneler::callBack()
{
- debugs(83, 5, connection << status());
- if (answer().positive())
- answer().conn = connection;
+ debugs(83, 5, answer().conn << status());
+ assert(!connection); // returned inside answer() or gone
auto cb = callback;
callback = nullptr;
ScheduleCallHere(cb);
void handleResponse(const bool eof);
void bailOnResponseError(const char *error, HttpReply *);
+private:
/// sends the given error to the initiator
void bailWith(ErrorState*);
/// a bailWith(), sendSuccess() helper: sends results to the initiator
void callBack();
- /// a bailWith(), sendSuccess() helper: stops monitoring the connection
+ /// stops monitoring the connection
void disconnect();
+ /// updates connection usage history before the connection is closed
+ void countFailingConnection();
+
TunnelerAnswer &answer();
-private:
AsyncCall::Pointer writer; ///< called when the request has been written
AsyncCall::Pointer reader; ///< called when the response should be read
AsyncCall::Pointer closer; ///< called when the connection is being closed