Skip to main content

Asynchronous HTTP library.

Project description

Aioreq is a Python low-level asynchronous HTTP client library. It is built on top of TCP sockets and implements the HTTP protocol entirely on his own.


Documentation

Click here

Install

$ pip install aioreq

Usage

Basic usage


>>> import aioreq
>>> import asyncio
>>>
>>> cl = aioreq.Client()
>>>
>>> resp = asyncio.run(
...	cl.get('https://www.google.com')
...	)
>>> resp
<Response 200 OK>
>>> resp.status
200
>>> resp.status_message
'OK'
>>> resp.request
<Request GET https://www.google.com>
>>> headers = resp.headers # dict
>>> body = resp.content # bytes object

Alternatively, the best practice is to use a Context manager.

>>> import aioreq
>>> import asyncio
>>>
>>> async def main():
...     async with aioreq.Client() as cl:
...         return await cl.get('https://google.com')
>>> asyncio.run(main())
<Response 200 OK>

More advanced usage


This code will asynchronously send 100 get requests to google.com, which is much faster than synchronous libraries. Also, the client persistent connection mechanism was disabled, so that a connection would be opened for each request.

>>> import asyncio
>>> import aioreq
>>>
>>> async def main():
...     async with aioreq.http.Client(persistent_connections=False) as cl:
...         tasks = []
...         for j in range(100):
...             tasks.append(
...                 asyncio.create_task(
...                     cl.get('https://www.google.com/', )
...                 )
...             )
...         await asyncio.gather(*tasks)
>>> asyncio.run(main())

Streams


We occasionally use the HTTP protocol to download videos, photos, and possibly files. When downloading very large files, Stream must be used instead of the default Client. When a client downloads videos or files, the server responds with all information including headers, status code, status message, and full body, which can be very large. As a result, we cannot store it in RAM. Stream only returns a portion of the body per iteration, allowing us to write it to disk, then receive another portion and solve the ram overflow problem.

There is some fundamental Stream usage.

>>> import aioreq
>>> import asyncio
>>> 
>>> async def main():
...        async with aioreq.StreamClient() as cl:
...                # This code iterates through the message and yields each received chunk separately.
...                async for chunk in cl.get('https://google.com'):
...                        ...
>>> asyncio.run(main())

Middlewares

Aioreq now supports 'middleware' power.

The first steps with middleware

Aioreq provides default middlewares to each client. We can see that middlewares by importing 'default_middlewares' variable.

>>> import aioreq
>>> aioreq.middlewares.default_middlewares
('RetryMiddleWare', 'RedirectMiddleWare', 'DecodeMiddleWare', 'AuthenticationMiddleWare')

The first item on this list represents the first middleware that should handle our request (i.e. the closest middleware to our client), while the last index represents the closest middleware to the server.

To override the default middlewares, we can pass our middlewares to the Client.

>>> client = aioreq.Client(middlewares=aioreq.middlewares.default_middlewares[2:])

This client will no longer redirect or retry responses.

Also, because aioreq stores middlewares in Client objects as linked lists, we can simply change the head of that linked list to skip the first middleware.

>>> client = aioreq.Client()
>>> client.middlewares.__class__.__name__
'RetryMiddleWare'
>>>
>>> client.middlewares = client.middlewares.next_middleware
>>> client.middlewares.__class__.__name__
'RedirectMiddleWare'
>>> 
>>> client.middlewares = client.middlewares.next_middleware
>>> client.middlewares.__class__.__name__
'DecodeMiddleWare'
>>> # It's like 'list = list.next.next',

or

>>> client = aioreq.Client()
>>> client.middlewares = client.middlewares.next_middleware.next_middleware
>>> # alternative for client = aioreq.Client(middlewares=aioreq.middlewares.default_middlewares[2:])

Create your own middlewares!

All 'aioreq' middlewares must be subclasses of the class 'middlewares.MiddleWare'

MiddleWare below would add 'test-md' header if request domain is 'www.example.com'

>>> import aioreq
>>>
>>> class CustomMiddleWare(aioreq.middlewares.MiddleWare):
...     async def process(self, request, client):
...         if request.host == 'www.example.com':
...             request.headers['test_md'] = 'test'
...
>>> client = aioreq.Client()
>>> client.middlewares = CustomMiddleWare(next_middleware=client.middlewares)

Our CustomMiddleWare will now be the first middleware (i.e. closest to the client). Because 'aioreq' middlewares are stored as linked lists, this pattern works (i.e. same as linked list insert method).

Alternatively, we can alter the list of middlewares that the client receives.

>>> client = aioreq.Client(middlewares = (CustomMiddleWare, ) + aioreq.middlewares.default_middlewares)
>>> client.middlewares.__class__.__name__
'CustomMiddleWare'

Benchmarks

Aioreq is a very fast library, and we compared it to other Python libraries to demonstrate its speed.

I used httpx to compare speed.


Benchmark run

First, clone aioreq repository.

Then...

$ cd aioreq
$ python -m venv venv
$ source ./venv/bin/activate
$ pip install '.[benchmarks]'
$ cd benchmarks
$ ./run_tests

Benchmark results

This is the average execution time of each library for 200 asynchronous requests where responses was received without chunked transfer encoding.

Benchmark settings.

With Content-Length

$ cd becnhmarks
$ ./run_tests
Tests with module loading
---------------------------
aioreq benchmark

real    0m1.893s
user    0m0.777s
sys     0m0.063s
---------------------------
httpx benchmark

real    0m2.448s
user    0m0.840s
sys     0m0.151s

With Transfer-Encoding: Chunked

This is the average execution time of each library for 200 asynchronous requests where responses was received with chunked transfer encoding.

Benchmark settings.

$ cd benchmarks
$ ./run_tests
Tests with module loading
---------------------------
aioreq benchmark

real    0m2.444s
user    0m1.090s
sys     0m0.089s
---------------------------
httpx benchmark

real    0m2.990s
user    0m1.254s
sys     0m0.127s

As you can see, the synchronous code lags far behind when we make many requests at the same time.

Keylog

If the SSLKEYLOGFILE environment variable is set, Aioreq will write keylogs to it.

$ export SSLKEYLOGFILE=logs

Then just run python script.

$ python aioreq_app.py
$ ls -l
total 8
-rw-r--r-- 1 user user  94 Dec  5 17:19 aioreq_app.py
-rw-r--r-- 1 user user 406 Dec  5 17:19 logs

Now, the 'logs' file contains keylogs that can be used to decrypt your TLS/SSL traffic with a tool such as 'wireshark'.

Authentication

If the auth parameter is included in the request, Aioreq will handle authentication.

>>> import aioreq
>>> import asyncio
>>> async def send_req():
...     async with aioreq.Client() as cl:
...         return await cl.get('http://httpbin.org/basic-auth/foo/bar', auth=('foo', 'bar'))
>>> resp = asyncio.run(send_req())
>>> resp.status
200

Parameter 'auth' should be a tuple with two elements: password and login.

Authentication is enabled by 'AuthenticationMiddleWare,' so exercise caution when managing middlewares manually.

Supported Features

Aioreq support basic features to work with HTTP/1.1.
More functionality will be avaliable in future realeases.
This is the latest version features.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aioreq-1.0.1.tar.gz (21.8 kB view details)

Uploaded Source

Built Distribution

aioreq-1.0.1-py3-none-any.whl (29.0 kB view details)

Uploaded Python 3

File details

Details for the file aioreq-1.0.1.tar.gz.

File metadata

  • Download URL: aioreq-1.0.1.tar.gz
  • Upload date:
  • Size: 21.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-httpx/0.23.3

File hashes

Hashes for aioreq-1.0.1.tar.gz
Algorithm Hash digest
SHA256 e66b66c7ce755fdedcc73503793740b743e3747c940337a4c5b19f1b5b9a9e6a
MD5 6b30dcc7ceb1d066bb6ef6dbc319c364
BLAKE2b-256 b9e2d7cb0aea7cba9c7eb886355d3877e65cfa5e49a59527548f72a7c0374559

See more details on using hashes here.

File details

Details for the file aioreq-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: aioreq-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 29.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-httpx/0.23.3

File hashes

Hashes for aioreq-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 04dd682c610c4d42d7902d70fd01b20aaed705c7e4441bd817a88798003eb5d7
MD5 4e40116433be5c1be1ba710ffbffd35a
BLAKE2b-256 b27b1366d1e06e6ccf79b39a0671deb6a712abbfbbcc9b8517d15892c21f5a27

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page