Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

asynchronous aiohttp requests fails, but synchronous requests succeed

With the following code I get Cannot connect to host ...:443 ssl:True when I use the asynchronous aiohttp. When I use synchronous requests, it succeeds.

The whitehouse.gov links fail, but the google.com succeeds for both async and sync cases.

What is going wrong? This is with python 3.4.2 on FreeBSD8, aiohttp 0.14.4, requests 2.5.3

import asyncio
import aiohttp
import requests

urls = [
    'http://www.whitehouse.gov/cea/', 
    'http://www.whitehouse.gov/omb', 
    'http://www.google.com']


def test_sync():
    for url in urls:
        r = requests.get(url)
        print(r.status_code)


def test_async():
    for url in urls:
        try:
            r = yield from aiohttp.request('get', url)
        except aiohttp.errors.ClientOSError as e:
            print('bad eternal link %s: %s' % (url, e))
        else:
            print(r.status)


if __name__ == '__main__':
    print('async')
    asyncio.get_event_loop().run_until_complete(test_async())
    print('sync')
    test_sync()

The output from this is:

async
bad eternal link http://www.whitehouse.gov/cea: Cannot connect to host www.whitehouse.gov:443 ssl:True
bad eternal link http://www.whitehouse.gov/omb: Cannot connect to host www.whitehouse.gov:443 ssl:True
200
sync
200
200
200
like image 723
Tim Avatar asked Apr 23 '15 15:04

Tim


2 Answers

I had the same problem on an old Linux server with out of date CA root certificates, and loading certifi CA certificate bundle in a SSLContext fixed the issue.

import aiohttp
import ssl
import certifi

ssl_context = ssl.create_default_context(cafile=certifi.where())
async with aiohttp.ClientSession() as session:
    async with session.get('https://some.foo/bar/', ssl=ssl_context) as response:
        print(await response.text())
like image 157
Le Hibou Avatar answered Nov 07 '22 10:11

Le Hibou


I suspect certificate validation chain is broken on your machine. On Ubuntu everything is working, as @dano mentioned.

Anyway, you may disable ssl validation by creating custom Connector instance:

import asyncio
import aiohttp

urls = [
    'http://www.whitehouse.gov/cea/',
    'http://www.whitehouse.gov/omb',
    'http://www.google.com']


def test_async():
    connector = aiohttp.TCPConnector(verify_ssl=False)
    for url in urls:
        try:
            r = yield from aiohttp.request('get', url, connector=connector)
        except aiohttp.errors.ClientOSError as e:
            print('bad eternal link %s: %s' % (url, e))
        else:
            print(r.status)


if __name__ == '__main__':
    print('async')
    asyncio.get_event_loop().run_until_complete(test_async())

BTW, requests library is shipped with own certificate bundle. Maybe we need to do the same for aiohttp?

UPD. See also https://github.com/aio-libs/aiohttp/issues/341

like image 17
Andrew Svetlov Avatar answered Nov 07 '22 11:11

Andrew Svetlov