Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AttributeError: 'NoneType' object has no attribute 'get_extra_info' with aiohttp==3.8.3 when using a proxy #6239

Closed
1 task done
john-parton opened this issue Nov 4, 2021 · 31 comments
Labels
bug client need pull request regression Something that used to work stopped working "as before" after upgrade reproducer: present This PR or issue contains code, which reproduce the problem described or clearly understandable STR

Comments

@john-parton
Copy link
Contributor

Describe the bug

Requests involving a proxy server sometimes fail with an AttributeError which were working on versions prior to 3.8.0

To Reproduce

Full test case:

# test_case.py
import asyncio
import aiohttp

async def test_case():
    async with aiohttp.ClientSession() as session:
        async with session.get("https://api.ipify.org", proxy="http://218.235.10.214:8393") as response:
            text = await response.text()

    print(text)


def main():
    asyncio.run(test_case())


if __name__ == "__main__":
    main()

Expected behavior

Expected behavior (confirmed working with aiohttp==3.7.4.post0)

python3 test_case.py
<prints my public ip>

Logs/tracebacks

Traceback (most recent call last):
  File "/home/john/Code/projects/proxywrench/proxywrench/test_case.py", line 17, in <module>
    main()
  File "/home/john/Code/projects/proxywrench/proxywrench/test_case.py", line 13, in main
    asyncio.run(test_case())
  File "/home/john/.pyenv/versions/3.9.7/lib/python3.9/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/home/john/.pyenv/versions/3.9.7/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "/home/john/Code/projects/proxywrench/proxywrench/test_case.py", line 6, in test_case
    async with session.get("https://api.ipify.org", proxy="http://218.235.10.214:8393") as response:
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/client.py", line 1140, in __aenter__
    self._resp = await self._coro
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/client.py", line 535, in _request
    conn = await self._connector.connect(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 543, in connect
    proto = await self._create_connection(req, traces, timeout)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 904, in _create_connection
    _, proto = await self._create_proxy_connection(req, traces, timeout)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 1324, in _create_proxy_connection
    return await self._start_tls_connection(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 1125, in _start_tls_connection
    tls_proto.connection_made(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/base_protocol.py", line 58, in connection_made
    tcp_nodelay(tr, True)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/tcp_helpers.py", line 26, in tcp_nodelay
    sock = transport.get_extra_info("socket")
AttributeError: 'NoneType' object has no attribute 'get_extra_info'

Python Version

$ python --version
Python 3.9.7

aiohttp Version

$ python -m pip show aiohttp
Name: aiohttp
Version: 3.8.0
Summary: Async http client/server framework (asyncio)
Home-page: https://github.com/aio-libs/aiohttp
Author: 
Author-email: 
License: Apache 2
Location: /home/john/.pyenv/versions/3.9.7/envs/proxywrench/lib/python3.9/site-packages
Requires: aiosignal, async-timeout, attrs, charset-normalizer, frozenlist, multidict, yarl
Required-by: aiohttp-socks, aiohttp-utils

multidict Version

$ python -m pip show multidict
Name: multidict
Version: 5.1.0
Summary: multidict implementation
Home-page: https://github.com/aio-libs/multidict
Author: Andrew Svetlov
Author-email: andrew.svetlov@gmail.com
License: Apache 2
Location: /home/john/.pyenv/versions/3.9.7/envs/proxywrench/lib/python3.9/site-packages
Requires: 
Required-by: aiohttp, yarl

yarl Version

$ python -m pip show yarl
Name: yarl
Version: 1.6.3
Summary: Yet another URL library
Home-page: https://github.com/aio-libs/yarl/
Author: Andrew Svetlov
Author-email: andrew.svetlov@gmail.com
License: Apache 2
Location: /home/john/.pyenv/versions/3.9.7/envs/proxywrench/lib/python3.9/site-packages
Requires: idna, multidict
Required-by: aiohttp

OS

Ubuntu 21.10 x64

Related component

Client

Additional context

No response

Code of Conduct

  • I agree to follow the aio-libs Code of Conduct
@john-parton john-parton added the bug label Nov 4, 2021
@webknjaz webknjaz added regression Something that used to work stopped working "as before" after upgrade reproducer: present This PR or issue contains code, which reproduce the problem described or clearly understandable STR labels Nov 4, 2021
@webknjaz
Copy link
Member

webknjaz commented Nov 8, 2021

@bmbouter @jborean93 have you seen this problem after the proxy code update?

@bmbouter
Copy link
Contributor

bmbouter commented Nov 8, 2021

I kind of think I did, but I tested so many permutations it's difficult to say 100%. If I am remembering correctly, if TLS trust was required but one or both of the certs was untrusted from the local trust store, I would get this traceback. Hopefully this is helpful.

@webknjaz
Copy link
Member

webknjaz commented Nov 8, 2021

@bmbouter could you check if the reproducer above works for you locally?

On my machine it's

Traceback (most recent call last):
  File "~/.pyenv/versions/aiohttp-repros-pyenv-py3.9.0/lib/python3.9/site-packages/aiohttp/connector.py", line 985, in _wrap_create_connection
    return await self._loop.create_connection(*args, **kwargs)  # type: ignore[return-value]  # noqa
  File "~/.pyenv/versions/3.9.0/lib/python3.9/asyncio/base_events.py", line 1056, in create_connection
    raise exceptions[0]
  File "~/.pyenv/versions/3.9.0/lib/python3.9/asyncio/base_events.py", line 1041, in create_connection
    sock = await self._connect_sock(
  File "~/.pyenv/versions/3.9.0/lib/python3.9/asyncio/base_events.py", line 955, in _connect_sock
    await self.sock_connect(sock, address)
  File "~/.pyenv/versions/3.9.0/lib/python3.9/asyncio/selector_events.py", line 502, in sock_connect
    return await fut
  File "~/.pyenv/versions/3.9.0/lib/python3.9/asyncio/selector_events.py", line 537, in _sock_connect_cb
    raise OSError(err, f'Connect call failed {address}')
TimeoutError: [Errno 110] Connect call failed ('218.235.10.214', 8393)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "~/.pyenv/versions/3.9.0/lib/python3.9/runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "~/.pyenv/versions/3.9.0/lib/python3.9/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "~/src/experiments/aiohttp-repros/issue-6239/test_case.py", line 17, in <module>
    main()
  File "~/src/experiments/aiohttp-repros/issue-6239/test_case.py", line 13, in main
    asyncio.run(test_case())
  File "~/.pyenv/versions/3.9.0/lib/python3.9/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "~/.pyenv/versions/3.9.0/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "~/src/experiments/aiohttp-repros/issue-6239/test_case.py", line 6, in test_case
    async with session.get("https://api.ipify.org", proxy="http://218.235.10.214:8393") as response:
  File "~/.pyenv/versions/aiohttp-repros-pyenv-py3.9.0/lib/python3.9/site-packages/aiohttp/client.py", line 1140, in __aenter__
    self._resp = await self._coro
  File "~/.pyenv/versions/aiohttp-repros-pyenv-py3.9.0/lib/python3.9/site-packages/aiohttp/client.py", line 535, in _request
    conn = await self._connector.connect(
  File "~/.pyenv/versions/aiohttp-repros-pyenv-py3.9.0/lib/python3.9/site-packages/aiohttp/connector.py", line 543, in connect
    proto = await self._create_connection(req, traces, timeout)
  File "~/.pyenv/versions/aiohttp-repros-pyenv-py3.9.0/lib/python3.9/site-packages/aiohttp/connector.py", line 904, in _create_connection
    _, proto = await self._create_proxy_connection(req, traces, timeout)
  File "~/.pyenv/versions/aiohttp-repros-pyenv-py3.9.0/lib/python3.9/site-packages/aiohttp/connector.py", line 1230, in _create_proxy_connection
    transport, proto = await self._create_direct_connection(
  File "~/.pyenv/versions/aiohttp-repros-pyenv-py3.9.0/lib/python3.9/site-packages/aiohttp/connector.py", line 1205, in _create_direct_connection
    raise last_exc
  File "~/.pyenv/versions/aiohttp-repros-pyenv-py3.9.0/lib/python3.9/site-packages/aiohttp/connector.py", line 1174, in _create_direct_connection
    transp, proto = await self._wrap_create_connection(
  File "~/.pyenv/versions/aiohttp-repros-pyenv-py3.9.0/lib/python3.9/site-packages/aiohttp/connector.py", line 991, in _wrap_create_connection
    raise client_error(req.connection_key, exc) from exc
aiohttp.client_exceptions.ClientProxyConnectionError: Cannot connect to host 218.235.10.214:8393 ssl:default

(looks like the initial report may have missed the first part of the traceback)

@x0day
Copy link

x0day commented Nov 9, 2021

same error here.

  File "/Users/dev/Library/Caches/pypoetry/virtualenvs/proj/lib/python3.7/site-packages/aiohttp/client.py", line 536, in _request
    req, traces=traces, timeout=real_timeout
  File "/Users/dev/Library/Caches/pypoetry/virtualenvs/proj/lib/python3.7/site-packages/aiohttp/connector.py", line 543, in connect
    proto = await self._create_connection(req, traces, timeout)
  File "/Users/dev/Library/Caches/pypoetry/virtualenvs/proj/lib/python3.7/site-packages/aiohttp/connector.py", line 904, in _create_connection
    _, proto = await self._create_proxy_connection(req, traces, timeout)
  File "/Users/dev/Library/Caches/pypoetry/virtualenvs/proj/lib/python3.7/site-packages/aiohttp/connector.py", line 1329, in _create_proxy_connection
    timeout=timeout,
  File "/Users/dev/Library/Caches/pypoetry/virtualenvs/proj/lib/python3.7/site-packages/aiohttp/connector.py", line 1126, in _start_tls_connection
    tls_transport
  File "/Users/dev/Library/Caches/pypoetry/virtualenvs/proj/lib/python3.7/site-packages/aiohttp/base_protocol.py", line 58, in connection_made
    tcp_nodelay(tr, True)
  File "/Users/dev/Library/Caches/pypoetry/virtualenvs/proj/lib/python3.7/site-packages/aiohttp/tcp_helpers.py", line 26, in tcp_nodelay
    sock = transport.get_extra_info("socket")
AttributeError: 'NoneType' object has no attribute 'get_extra_info'

@john-parton
Copy link
Contributor Author

@bmbouter could you check if the reproducer above works for you locally?
(looks like the initial report may have missed the first part of the traceback)

I don't think I did. That proxy server is no longer online. That's why you're getting a Timeout now.

Let me grab another one that reproduces the original issue.

@john-parton
Copy link
Contributor Author

Here's the revised test case with a different proxy.

# test_case.py
import asyncio
import aiohttp

async def test_case():
    async with aiohttp.ClientSession() as session:
        async with session.get("https://api.ipify.org", proxy="http://42.194.222.36:3128") as response:
            text = await response.text()

    print(text)


def main():
    asyncio.run(test_case())


if __name__ == "__main__":
    main()

Here's the copy/pasted output from my terminal. (Full, not truncated.)

(proxywrench) john@john-work:~/Code/projects/proxywrench$ python test_case.py 
Traceback (most recent call last):
  File "/home/john/Code/projects/proxywrench/test_case.py", line 18, in <module>
    main()
  File "/home/john/Code/projects/proxywrench/test_case.py", line 14, in main
    asyncio.run(test_case())
  File "/home/john/.pyenv/versions/3.9.7/lib/python3.9/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/home/john/.pyenv/versions/3.9.7/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "/home/john/Code/projects/proxywrench/test_case.py", line 7, in test_case
    async with session.get("https://api.ipify.org", proxy="http://42.194.222.36:3128") as response:
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/client.py", line 1140, in __aenter__
    self._resp = await self._coro
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/client.py", line 535, in _request
    conn = await self._connector.connect(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 543, in connect
    proto = await self._create_connection(req, traces, timeout)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 904, in _create_connection
    _, proto = await self._create_proxy_connection(req, traces, timeout)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 1324, in _create_proxy_connection
    return await self._start_tls_connection(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 1125, in _start_tls_connection
    tls_proto.connection_made(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/base_protocol.py", line 58, in connection_made
    tcp_nodelay(tr, True)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/tcp_helpers.py", line 26, in tcp_nodelay
    sock = transport.get_extra_info("socket")
AttributeError: 'NoneType' object has no attribute 'get_extra_info'

Here's a screenshot of my terminal:

Screenshot from 2021-11-09 14-51-18

@john-parton
Copy link
Contributor Author

Here's two additional proxies that exhibit the same behavior:

http://42.194.222.36:3128
http://178.32.107.236:3128
http://101.34.116.37:7890

@john-parton
Copy link
Contributor Author

john-parton commented Nov 9, 2021

Note: These proxies may or may not be broken. I'm not totally sure. The real bug isn't that they were necessarily working before 3.8.0, but rather that before 3.8.0 it gave a much more helpful exception than the generic AttributeError.

I don't want my code to have to catch AttributeError because that could mask all kinds of other issues.

Here's a much more detailed output.

Here's the script I'm running

# test_case.py
import asyncio
import traceback

import aiohttp


PROXIES = [
    "http://42.194.222.36:3128",
    "http://178.32.107.236:3128",
    "http://101.34.116.37:7890",
]

async def test_all():
    async with aiohttp.ClientSession() as session:
        for proxy in PROXIES:
            try:
                async with session.get("https://api.apify.org", proxy=proxy) as response:
                    text = await response.text()
            except Exception as e:
                print(f"{proxy} : Error")
                print(traceback.format_exc())
            else:
                print(f"{proxy} : OK")


def main():
    asyncio.run(test_all())


if __name__ == "__main__":
    main()

Here's the output on aiohttp==3.7.4.post0

(Note the very helpful ConnectionResetError, ClientConnectionError, SSLError, ClientConnectorSSLError, etc.)

(proxywrench) john@john-work:~/Code/projects/proxywrench$ python test_case.py 
http://42.194.222.36:3128 : Error
Traceback (most recent call last):
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 969, in _wrap_create_connection
    return await self._loop.create_connection(*args, **kwargs)  # type: ignore  # noqa
  File "/home/john/.pyenv/versions/3.9.7/lib/python3.9/asyncio/base_events.py", line 1081, in create_connection
    transport, protocol = await self._create_connection_transport(
  File "/home/john/.pyenv/versions/3.9.7/lib/python3.9/asyncio/base_events.py", line 1111, in _create_connection_transport
    await waiter
ConnectionResetError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/john/Code/projects/proxywrench/test_case.py", line 18, in test_all
    async with session.get("https://api.apify.org", proxy=proxy) as response:
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/client.py", line 1117, in __aenter__
    self._resp = await self._coro
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/client.py", line 520, in _request
    conn = await self._connector.connect(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 535, in connect
    proto = await self._create_connection(req, traces, timeout)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 890, in _create_connection
    _, proto = await self._create_proxy_connection(req, traces, timeout)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 1139, in _create_proxy_connection
    transport, proto = await self._wrap_create_connection(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 975, in _wrap_create_connection
    raise client_error(req.connection_key, exc) from exc
aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host api.apify.org:443 ssl:default [None]

http://178.32.107.236:3128 : Error
Traceback (most recent call last):
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 969, in _wrap_create_connection
    return await self._loop.create_connection(*args, **kwargs)  # type: ignore  # noqa
  File "/home/john/.pyenv/versions/3.9.7/lib/python3.9/asyncio/base_events.py", line 1081, in create_connection
    transport, protocol = await self._create_connection_transport(
  File "/home/john/.pyenv/versions/3.9.7/lib/python3.9/asyncio/base_events.py", line 1111, in _create_connection_transport
    await waiter
  File "/home/john/.pyenv/versions/3.9.7/lib/python3.9/asyncio/sslproto.py", line 528, in data_received
    ssldata, appdata = self._sslpipe.feed_ssldata(data)
  File "/home/john/.pyenv/versions/3.9.7/lib/python3.9/asyncio/sslproto.py", line 188, in feed_ssldata
    self._sslobj.do_handshake()
  File "/home/john/.pyenv/versions/3.9.7/lib/python3.9/ssl.py", line 944, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1129)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/john/Code/projects/proxywrench/test_case.py", line 18, in test_all
    async with session.get("https://api.apify.org", proxy=proxy) as response:
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/client.py", line 1117, in __aenter__
    self._resp = await self._coro
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/client.py", line 520, in _request
    conn = await self._connector.connect(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 535, in connect
    proto = await self._create_connection(req, traces, timeout)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 890, in _create_connection
    _, proto = await self._create_proxy_connection(req, traces, timeout)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 1139, in _create_proxy_connection
    transport, proto = await self._wrap_create_connection(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 973, in _wrap_create_connection
    raise ClientConnectorSSLError(req.connection_key, exc) from exc
aiohttp.client_exceptions.ClientConnectorSSLError: Cannot connect to host api.apify.org:443 ssl:default [[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1129)]

http://101.34.116.37:7890 : Error
Traceback (most recent call last):
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 969, in _wrap_create_connection
    return await self._loop.create_connection(*args, **kwargs)  # type: ignore  # noqa
  File "/home/john/.pyenv/versions/3.9.7/lib/python3.9/asyncio/base_events.py", line 1081, in create_connection
    transport, protocol = await self._create_connection_transport(
  File "/home/john/.pyenv/versions/3.9.7/lib/python3.9/asyncio/base_events.py", line 1111, in _create_connection_transport
    await waiter
ConnectionResetError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/john/Code/projects/proxywrench/test_case.py", line 18, in test_all
    async with session.get("https://api.apify.org", proxy=proxy) as response:
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/client.py", line 1117, in __aenter__
    self._resp = await self._coro
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/client.py", line 520, in _request
    conn = await self._connector.connect(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 535, in connect
    proto = await self._create_connection(req, traces, timeout)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 890, in _create_connection
    _, proto = await self._create_proxy_connection(req, traces, timeout)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 1139, in _create_proxy_connection
    transport, proto = await self._wrap_create_connection(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 975, in _wrap_create_connection
    raise client_error(req.connection_key, exc) from exc
aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host api.apify.org:443 ssl:default [None]

Here's the output with aiohttp==3.8.0

Note that all of the helpful exceptions disappeared.

(proxywrench) john@john-work:~/Code/projects/proxywrench$ python test_case.py 
http://42.194.222.36:3128 : Error
Traceback (most recent call last):
  File "/home/john/Code/projects/proxywrench/test_case.py", line 18, in test_all
    async with session.get("https://api.apify.org", proxy=proxy) as response:
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/client.py", line 1140, in __aenter__
    self._resp = await self._coro
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/client.py", line 535, in _request
    conn = await self._connector.connect(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 543, in connect
    proto = await self._create_connection(req, traces, timeout)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 904, in _create_connection
    _, proto = await self._create_proxy_connection(req, traces, timeout)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 1324, in _create_proxy_connection
    return await self._start_tls_connection(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 1125, in _start_tls_connection
    tls_proto.connection_made(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/base_protocol.py", line 58, in connection_made
    tcp_nodelay(tr, True)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/tcp_helpers.py", line 26, in tcp_nodelay
    sock = transport.get_extra_info("socket")
AttributeError: 'NoneType' object has no attribute 'get_extra_info'

http://178.32.107.236:3128 : Error
Traceback (most recent call last):
  File "/home/john/Code/projects/proxywrench/test_case.py", line 18, in test_all
    async with session.get("https://api.apify.org", proxy=proxy) as response:
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/client.py", line 1140, in __aenter__
    self._resp = await self._coro
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/client.py", line 535, in _request
    conn = await self._connector.connect(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 543, in connect
    proto = await self._create_connection(req, traces, timeout)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 904, in _create_connection
    _, proto = await self._create_proxy_connection(req, traces, timeout)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 1324, in _create_proxy_connection
    return await self._start_tls_connection(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 1125, in _start_tls_connection
    tls_proto.connection_made(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/base_protocol.py", line 58, in connection_made
    tcp_nodelay(tr, True)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/tcp_helpers.py", line 26, in tcp_nodelay
    sock = transport.get_extra_info("socket")
AttributeError: 'NoneType' object has no attribute 'get_extra_info'

http://101.34.116.37:7890 : Error
Traceback (most recent call last):
  File "/home/john/Code/projects/proxywrench/test_case.py", line 18, in test_all
    async with session.get("https://api.apify.org", proxy=proxy) as response:
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/client.py", line 1140, in __aenter__
    self._resp = await self._coro
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/client.py", line 535, in _request
    conn = await self._connector.connect(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 543, in connect
    proto = await self._create_connection(req, traces, timeout)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 904, in _create_connection
    _, proto = await self._create_proxy_connection(req, traces, timeout)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 1324, in _create_proxy_connection
    return await self._start_tls_connection(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/connector.py", line 1125, in _start_tls_connection
    tls_proto.connection_made(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/base_protocol.py", line 58, in connection_made
    tcp_nodelay(tr, True)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.9/site-packages/aiohttp/tcp_helpers.py", line 26, in tcp_nodelay
    sock = transport.get_extra_info("socket")
AttributeError: 'NoneType' object has no attribute 'get_extra_info'

@webknjaz
Copy link
Member

I don't want my code to have to catch AttributeError because that could mask all kinds of other issues.

Fair enough. FWIW the best place to add regression tests is https://github.com/aio-libs/aiohttp/blob/master/tests/test_proxy_functional.py.

@john-parton
Copy link
Contributor Author

Would you accept a pull request with a failing test, but no fix?

I don't know how to fix this issue, but I could definitely add the test.

@Dreamsorcerer
Copy link
Member

Would you accept a pull request with a failing test, but no fix?

Yes, we do this frequently by marking it with xfail, so we can come back to fix it later on.

@webknjaz
Copy link
Member

Would you accept a pull request with a failing test, but no fix?

I don't know how to fix this issue, but I could definitely add the test.

Yes, we're trying to follow https://pganssle-talks.github.io/xfail-lightning/.

@shadchin
Copy link

this commit breaks - cf641aa

@shadchin
Copy link

After replace https://github.com/aio-libs/aiohttp/blob/3.8/aiohttp/connector.py#L1212
runtime_has_start_tls = self._loop_supports_start_tls() -> runtime_has_start_tls = False
proxy works fine

@john-parton
Copy link
Contributor Author

So it looks like those proxies are trying to support HTTPS (TLS-in-TLS?) but there's some issue with the configuration?

If that's the case, a specific exception(s) would be ideal there

@shadchin
Copy link

perhaps something similar needs to be done here

runtime_has_start_tls = False if req.proxy.scheme != "https" else self._loop_supports_start_tls()

@x0day
Copy link

x0day commented Dec 25, 2021

@Dreamsorcerer any updates?

@Dreamsorcerer
Copy link
Member

No, I'm not familiar with this code. If someone wants to create a PR with a fix, we can take a look at it.

Also doesn't look like anybody created a PR with a test yet, which was suggested before (which makes it more likely that one of the maintainers will then have time to find a fix).

@webknjaz
Copy link
Member

So it looks like those proxies are trying to support HTTPS (TLS-in-TLS?) but there's some issue with the configuration?

Sort of. TLS-in-TLS is tricky in CPython itself and requires monkey-patching of the stdlib to make it work, this is why it's considered a "tech preview". Before the patch, loop.start_tls() wasn't used at all but after this change, it should be used in monkey-patched envs for TLS-in-TLS and maybe for HTTPS over plain HTTP proxy IIRC.

FWIW aiohttp could benefit from more regression tests. Plus a lot of those that exist could be more useful if rewritten using the new proxy.py-based pytest fixture instead of relying on mocks and monkey-patching.

If that's the case, a specific exception(s) would be ideal there

I'm open to proposals.

@john-parton
Copy link
Contributor Author

If that's the case, a specific exception(s) would be ideal there

I'm open to proposals.

If it could raise aiohttp.client_exceptions.ClientConnectorError, that would "fix" this issue as far as I'm concerned.

It's still an issue in 3.8.1

@kewlfft
Copy link

kewlfft commented Feb 2, 2022

I am experience this issue as well, until it is fixed what is the best way to catch this error?

@knaitas
Copy link

knaitas commented May 23, 2022

Also experiencing this issue

@sc0ned
Copy link

sc0ned commented May 25, 2022

As of late I have been experiencing this issue as well using private proxies from the provider "Oxylabs", anyone come up with a fix yet? the edits in the above pr help with providing a better error message but I'm curious as to what is different with these proxies compared to the many others I've used without issue (these actually worked fine just a week ago but now seemingly only dont work in aiohttp)

@john-parton
Copy link
Contributor Author

This #6703 does appear to fix it, but I had trouble getting master to build with that patch. Someone smarter than me should look into it more.

@john-parton john-parton changed the title AttributeError: 'NoneType' object has no attribute 'get_extra_info' with aiohttp==3.8.0 when using a proxy AttributeError: 'NoneType' object has no attribute 'get_extra_info' with aiohttp==3.8.1 when using a proxy Jun 13, 2022
@hazuco
Copy link

hazuco commented Sep 9, 2022

I still see same issue 'NoneType' object has no attribute 'get_extra_info' . I used requests.get with this proxy normally.

@john-parton
Copy link
Contributor Author

john-parton commented Nov 18, 2022

Here's an update as of today. Using python3.11 on ubuntu. New tracebacks make this much easier to read.

Test Code

import asyncio
import aiohttp


async def test_case():
    async with aiohttp.ClientSession() as session:
        async with session.get(
            "https://api.ipify.org", proxy="http://185.38.111.1:8080"
        ) as response:
            text = await response.text()

    print(text)


def main():
    asyncio.run(test_case())


if __name__ == "__main__":
    main()

Expected / Correct Behavior on aiohttp==3.7.4.post0

The code raises an exception that I can catch to recover.

Traceback (most recent call last):
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.11/site-packages/aiohttp/connector.py", line 969, in _wrap_create_connection
    return await self._loop.create_connection(*args, **kwargs)  # type: ignore  # noqa
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/john/.pyenv/versions/3.11.0/lib/python3.11/asyncio/base_events.py", line 1098, in create_connection
    transport, protocol = await self._create_connection_transport(
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/john/.pyenv/versions/3.11.0/lib/python3.11/asyncio/base_events.py", line 1131, in _create_connection_transport
    await waiter
  File "/home/john/.pyenv/versions/3.11.0/lib/python3.11/asyncio/sslproto.py", line 577, in _on_handshake_complete
    raise handshake_exc
  File "/home/john/.pyenv/versions/3.11.0/lib/python3.11/asyncio/sslproto.py", line 559, in _do_handshake
    self._sslobj.do_handshake()
  File "/home/john/.pyenv/versions/3.11.0/lib/python3.11/ssl.py", line 979, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:992)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/john/Code/proxywrench/proxywrench/test_case.py", line 20, in <module>
    main()
  File "/home/john/Code/proxywrench/proxywrench/test_case.py", line 16, in main
    asyncio.run(test_case())
  File "/home/john/.pyenv/versions/3.11.0/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/home/john/.pyenv/versions/3.11.0/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/john/.pyenv/versions/3.11.0/lib/python3.11/asyncio/base_events.py", line 650, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/home/john/Code/proxywrench/proxywrench/test_case.py", line 7, in test_case
    async with session.get(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.11/site-packages/aiohttp/client.py", line 1117, in __aenter__
    self._resp = await self._coro
                 ^^^^^^^^^^^^^^^^
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.11/site-packages/aiohttp/client.py", line 520, in _request
    conn = await self._connector.connect(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.11/site-packages/aiohttp/connector.py", line 535, in connect
    proto = await self._create_connection(req, traces, timeout)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.11/site-packages/aiohttp/connector.py", line 890, in _create_connection
    _, proto = await self._create_proxy_connection(req, traces, timeout)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.11/site-packages/aiohttp/connector.py", line 1139, in _create_proxy_connection
    transport, proto = await self._wrap_create_connection(
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.11/site-packages/aiohttp/connector.py", line 973, in _wrap_create_connection
    raise ClientConnectorSSLError(req.connection_key, exc) from exc
aiohttp.client_exceptions.ClientConnectorSSLError: Cannot connect to host api.ipify.org:443 ssl:default [[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:992)]

Unexpected / Incorrect behavior with aiohttp-3.8.3

A generic AttributeError is raised. If I catch this AttributeError, I will potentially handle unrelated errors.

Traceback (most recent call last):
  File "/home/john/Code/proxywrench/proxywrench/test_case.py", line 20, in <module>
    main()
  File "/home/john/Code/proxywrench/proxywrench/test_case.py", line 16, in main
    asyncio.run(test_case())
  File "/home/john/.pyenv/versions/3.11.0/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/home/john/.pyenv/versions/3.11.0/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/john/.pyenv/versions/3.11.0/lib/python3.11/asyncio/base_events.py", line 650, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/home/john/Code/proxywrench/proxywrench/test_case.py", line 7, in test_case
    async with session.get(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.11/site-packages/aiohttp/client.py", line 1141, in __aenter__
    self._resp = await self._coro
                 ^^^^^^^^^^^^^^^^
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.11/site-packages/aiohttp/client.py", line 536, in _request
    conn = await self._connector.connect(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.11/site-packages/aiohttp/connector.py", line 540, in connect
    proto = await self._create_connection(req, traces, timeout)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.11/site-packages/aiohttp/connector.py", line 899, in _create_connection
    _, proto = await self._create_proxy_connection(req, traces, timeout)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.11/site-packages/aiohttp/connector.py", line 1325, in _create_proxy_connection
    return await self._start_tls_connection(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.11/site-packages/aiohttp/connector.py", line 1124, in _start_tls_connection
    tls_proto.connection_made(
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.11/site-packages/aiohttp/base_protocol.py", line 58, in connection_made
    tcp_nodelay(tr, True)
  File "/home/john/.pyenv/versions/proxywrench/lib/python3.11/site-packages/aiohttp/tcp_helpers.py", line 25, in tcp_nodelay
    sock = transport.get_extra_info("socket")
           ^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get_extra_info'

Edit

The type annotation here

def tcp_nodelay(transport: asyncio.Transport, value: bool) -> None:
suggests that tcp_no_delay should never be called with None as the first parameter. So the base_protocol function is violating the type signature of that function.

It looks like transport here is None

def connection_made(self, transport: asyncio.BaseTransport) -> None:

Appears this code is returning None

aiohttp/aiohttp/connector.py

Lines 1036 to 1042 in d7ebbeb

tls_transport = await self._loop.start_tls(
underlying_transport,
tls_proto,
sslcontext,
server_hostname=req.host,
ssl_handshake_timeout=timeout.total,
)

Edit 2

Here's the start_tls code in cpython

https://github.com/python/cpython/blob/8079bef56f2249ecedafe0be5a6d7a120a7f3ac3/Lib/asyncio/base_events.py#L1231-L1277

Looks like it will return None if ssl_protocol._app_transport is None and doesn't raise an exception

_app_transport is initialized in __init__ by this method: https://github.com/python/cpython/blob/8079bef56f2249ecedafe0be5a6d7a120a7f3ac3/Lib/asyncio/sslproto.py#L373-L379

But is explicitly set back to None if the connection is lost: https://github.com/python/cpython/blob/8079bef56f2249ecedafe0be5a6d7a120a7f3ac3/Lib/asyncio/sslproto.py#L414

@john-parton john-parton changed the title AttributeError: 'NoneType' object has no attribute 'get_extra_info' with aiohttp==3.8.1 when using a proxy AttributeError: 'NoneType' object has no attribute 'get_extra_info' with aiohttp==3.8.3 when using a proxy Nov 26, 2022
@MakStashkevich
Copy link

perhaps something similar needs to be done here

runtime_has_start_tls = False if req.proxy.scheme != "https" else self._loop_supports_start_tls()

That help me, proxy is worked, thanks!

@andig
Copy link

andig commented Jun 18, 2023

Same here, full stacktrace in #3355 (comment). Is there any chance to get this fixed? Regression is two years old now.

@FreekyDev
Copy link

I don't know if this could help fixing the problem but it works on Windows. It fails on debian for me

@coffinonv
Copy link

Any updates?

@Dreamsorcerer
Copy link
Member

I'm closing this because it seems to be a duplicate of #3355. Follow that one for updates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug client need pull request regression Something that used to work stopped working "as before" after upgrade reproducer: present This PR or issue contains code, which reproduce the problem described or clearly understandable STR
Projects
None yet
Development

No branches or pull requests