Skip to content

Commit

Permalink
Fix #1985: Keep a reference to ClientSession in response object (#1988)
Browse files Browse the repository at this point in the history
* Fix #1985: Keep a reference to ClientSession in response object

* Reset a reference to session in ClientResponse._cleanup_writer
  • Loading branch information
asvetlov authored Jun 20, 2017
1 parent 99423d5 commit 179bf0a
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 62 deletions.
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ Changes

- Fix BadStatusLine caused by extra `CRLF` after `POST` data #1792

- Keep a reference to ClientSession in response object #1985

-

- Deprecate undocumented app.on_loop_available signal #1978
Expand Down
10 changes: 2 additions & 8 deletions aiohttp/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,8 @@ def _request(self, method, url, *,
compress=compress, chunked=chunked,
expect100=expect100, loop=self._loop,
response_class=self._response_class,
proxy=proxy, proxy_auth=proxy_auth, timer=timer)
proxy=proxy, proxy_auth=proxy_auth, timer=timer,
session=self)

# connection timeout
try:
Expand Down Expand Up @@ -688,13 +689,6 @@ def __await__(self):
self._session.close()
raise

def __del__(self):
# in case of "resp = aiohttp.request(...)"
# _SessionRequestContextManager get destroyed before resp get processed
# and connection has to stay alive during this time
# ClientSession.detach just cleans up connector attribute
self._session.detach()


def request(method, url, *,
params=None,
Expand Down
11 changes: 7 additions & 4 deletions aiohttp/client_reqrep.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ def __init__(self, method, url, *,
chunked=None, expect100=False,
loop=None, response_class=None,
proxy=None, proxy_auth=None, proxy_from_env=False,
timer=None):
timer=None, session=None):

if loop is None:
loop = asyncio.get_event_loop()

assert isinstance(url, URL), url
assert isinstance(proxy, (URL, type(None))), proxy

self._session = session
if params:
q = MultiDict(url.query)
url2 = url.with_query(params)
Expand Down Expand Up @@ -409,7 +409,7 @@ def send(self, conn):
request_info=self.request_info
)

self.response._post_init(self.loop)
self.response._post_init(self.loop, self._session)
return self.response

@asyncio.coroutine
Expand Down Expand Up @@ -446,6 +446,7 @@ class ClientResponse(HeadersMixin):
# post-init stage allows to not change ctor signature
_loop = None
_closed = True # to allow __del__ for non-initialized properly response
_session = None

def __init__(self, method, url, *,
writer=None, continue100=None, timer=None,
Expand Down Expand Up @@ -487,8 +488,9 @@ def _headers(self):
def request_info(self):
return self._request_info

def _post_init(self, loop):
def _post_init(self, loop, session):
self._loop = loop
self._session = session # store a reference to session #1985
if loop.get_debug():
self._source_traceback = traceback.extract_stack(sys._getframe(1))

Expand Down Expand Up @@ -654,6 +656,7 @@ def _cleanup_writer(self):
if self._writer is not None and not self._writer.done():
self._writer.cancel()
self._writer = None
self._session = None

def _notify_content(self):
content = self.content
Expand Down
2 changes: 1 addition & 1 deletion tests/test_client_proto.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def test_client_protocol_readuntil_eof(loop):
proto.data_received(b'HTTP/1.1 200 Ok\r\n\r\n')

response = ClientResponse('get', URL('http://def-cl-resp.org'))
response._post_init(loop)
response._post_init(loop, mock.Mock())
yield from response.start(conn, read_until_eof=True)

assert not response.content.is_eof()
Expand Down
2 changes: 1 addition & 1 deletion tests/test_client_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -1104,7 +1104,7 @@ def send(self, conn):
self.url,
writer=self._writer,
continue100=self._continue)
resp._post_init(self.loop)
resp._post_init(self.loop, mock.Mock())
self.response = resp
nonlocal called
called = True
Expand Down
Loading

0 comments on commit 179bf0a

Please sign in to comment.