id	summary	reporter	owner	description	type	status	priority	milestone	component	resolution	keywords	cc	branch	branch_author	launchpad_bug
3207	new t.web2.client.http.HTTPClientChannelRequest.connectionLost loops and errbacks incorrectly	camrdale	camrdale	"The twisted.web2.client.http.HTTPClientChannelRequest.connectionLost function introduced in this revision is broken:

{{{
Revision 21366, 11.2 kB  (checked in by therve, 6 months ago)
Merge web2-client-connectionlost-2304
Author: therve
Reviewer: dreid
Fixes #2304
Fix the connectionLost method of web2 client request so that errors are
propagated to the response deferred. Also it handles the case where the headers
are sent and the error happens during the streaming (after the response
deferred).
}}}

Firstly, the call to _error() will cause a loop as it calls the channels abortParse(), which calls setReadPersistent() to set it to False, which calls connectionLost(), etc.... This causes an errback to be called multiple times, leading to tracebacks such as:

{{{
Traceback (most recent call last):
  File ""/usr/lib/python2.5/site-packages/twisted/application/app.py"", line 269, in runReactorWithLogging
    reactor.run()
  File ""/usr/lib/python2.5/site-packages/twisted/internet/posixbase.py"", line 223, in run
    self.mainLoop()
  File ""/usr/lib/python2.5/site-packages/twisted/internet/posixbase.py"", line 234, in mainLoop
    self.doIteration(t)
  File ""/usr/lib/python2.5/site-packages/twisted/internet/selectreactor.py"", line 140, in doSelect
    _logrun(selectable, _drdw, selectable, method, dict)
--- <exception caught here> ---
  File ""/usr/lib/python2.5/site-packages/twisted/python/log.py"", line 51, in callWithLogger
    return callWithContext({""system"": lp}, func, *args, **kw)
  File ""/usr/lib/python2.5/site-packages/twisted/python/log.py"", line 36, in callWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
  File ""/usr/lib/python2.5/site-packages/twisted/python/context.py"", line 59, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File ""/usr/lib/python2.5/site-packages/twisted/python/context.py"", line 37, in callWithContext
    return func(*args,**kw)
  File ""/usr/lib/python2.5/site-packages/twisted/internet/selectreactor.py"", line 156, in _doReadOrWrite
    self._disconnectSelectable(selectable, why, method==""doRead"")
  File ""/usr/lib/python2.5/site-packages/twisted/internet/posixbase.py"", line 262, in _disconnectSelectable
    selectable.connectionLost(failure.Failure(why))
  File ""/usr/lib/python2.5/site-packages/twisted/internet/tcp.py"", line 576, in connectionLost
    Connection.connectionLost(self, reason)
  File ""/usr/lib/python2.5/site-packages/twisted/internet/tcp.py"", line 416, in connectionLost
    protocol.connectionLost(reason)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/client/http.py"", line 363, in connectionLost
    request.connectionLost(reason)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/client/http.py"", line 168, in connectionLost
    self._error(reason)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/client/http.py"", line 155, in _error
    self.abortParse()
  File ""/usr/lib/python2.5/site-packages/twisted/web2/channel/http.py"", line 330, in abortParse
    self.channel.setReadPersistent(False)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/client/http.py"", line 353, in setReadPersistent
    request.connectionLost(None)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/client/http.py"", line 168, in connectionLost
    self._error(reason)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/client/http.py"", line 155, in _error
    self.abortParse()
  File ""/usr/lib/python2.5/site-packages/twisted/web2/channel/http.py"", line 330, in abortParse
    self.channel.setReadPersistent(False)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/client/http.py"", line 353, in setReadPersistent
    request.connectionLost(None)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/client/http.py"", line 168, in connectionLost
    self._error(reason)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/client/http.py"", line 159, in _error
    self.responseDefer.errback(err)
  File ""/usr/lib/python2.5/site-packages/twisted/internet/defer.py"", line 264, in errback
    self._startRunCallbacks(fail)
  File ""/usr/lib/python2.5/site-packages/twisted/internet/defer.py"", line 293, in _startRunCallbacks
    raise AlreadyCalledError
twisted.internet.defer.AlreadyCalledError:
}}}

Secondly, the call to connectionLost() on line 353 in the setReadPersistent() function now needs to send a failure as argument rather than None, as this gets passed down to an errback eventually which generates this error:

{{{
Traceback (most recent call last):
  File ""/usr/lib/python2.5/site-packages/twisted/python/log.py"", line 51, in callWithLogger
    return callWithContext({""system"": lp}, func, *args, **kw)
  File ""/usr/lib/python2.5/site-packages/twisted/python/log.py"", line 36, in callWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
  File ""/usr/lib/python2.5/site-packages/twisted/python/context.py"", line 59, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File ""/usr/lib/python2.5/site-packages/twisted/python/context.py"", line 37, in callWithContext
    return func(*args,**kw)
--- <exception caught here> ---
  File ""/usr/lib/python2.5/site-packages/twisted/internet/selectreactor.py"", line 146, in _doReadOrWrite
    why = getattr(selectable, method)()
  File ""/usr/lib/python2.5/site-packages/twisted/internet/tcp.py"", line 362, in doRead
    return self.protocol.dataReceived(data)
  File ""/usr/lib/python2.5/site-packages/twisted/protocols/basic.py"", line 239, in dataReceived
    return self.rawDataReceived(data)
  File ""/var/lib/python-support/python2.5/apt_p2p/HTTPDownloader.py"", line 37, in rawDataReceived
    HTTPClientProtocol.rawDataReceived(self, data)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/client/http.py"", line 293, in rawDataReceived
    self.inRequests[0].rawDataReceived(data)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/channel/http.py"", line 173, in rawDataReceived
    channel.setLineMode(extraneous)
  File ""/usr/lib/python2.5/site-packages/twisted/protocols/basic.py"", line 254, in setLineMode
    return self.dataReceived(extra)
  File ""/usr/lib/python2.5/site-packages/twisted/protocols/basic.py"", line 231, in dataReceived
    why = self.lineReceived(line)
  File ""/var/lib/python-support/python2.5/apt_p2p/HTTPDownloader.py"", line 32, in lineReceived
    HTTPClientProtocol.lineReceived(self, line)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/client/http.py"", line 281, in lineReceived
    self.inRequests[0].lineReceived(line)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/channel/http.py"", line 130, in lineReceived
    self.allHeadersReceived()    # can set chunkedIn
  File ""/usr/lib/python2.5/site-packages/twisted/web2/channel/http.py"", line 193, in allHeadersReceived
    self.setConnectionParams(connHeaders)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/channel/http.py"", line 324, in setConnectionParams
    self.channel.setReadPersistent(readPersistent)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/client/http.py"", line 353, in setReadPersistent
    request.connectionLost(None)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/client/http.py"", line 168, in connectionLost
    self._error(reason)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/client/http.py"", line 155, in _error
    self.abortParse()
  File ""/usr/lib/python2.5/site-packages/twisted/web2/channel/http.py"", line 330, in abortParse
    self.channel.setReadPersistent(False)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/client/http.py"", line 353, in setReadPersistent
    request.connectionLost(None)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/client/http.py"", line 168, in connectionLost
    self._error(reason)
  File ""/usr/lib/python2.5/site-packages/twisted/web2/client/http.py"", line 159, in _error
    self.responseDefer.errback(err)
  File ""/usr/lib/python2.5/site-packages/twisted/internet/defer.py"", line 262, in errback
    fail = failure.Failure(fail)
  File ""/usr/lib/python2.5/site-packages/twisted/python/failure.py"", line 173, in __init__
    raise NoCurrentExceptionError()
twisted.python.failure.NoCurrentExceptionError:
}}}
"	defect	closed	normal		web2	wontfix		therve exarkun dreid	branches/web2-client-connectionlost-loop-3207	exarkun	
