Подтвердить что ты не робот

Использование "запросов" Python с существующим подключением сокетов

Библиотека запросов "Python" в настоящее время является полной яростью из-за красивого интерфейса, который он обеспечивает для создания HTTP-запросов, - но под ним, похоже, много слоев косвенных сеансов, HTTP-адаптеров и, наконец, механика urllib3.

Где в этом степе абстракций есть подходящее место для вмешательства, если я уже держу открытый сокет и хочу использовать "запросы" для отправки HTTP-ответа по этому сокету и получения ответа?

Без какого-либо вмешательства (или настройки?), стек попытается создать для меня новый сокет TCP/IP, но в моем конкретном приложении мой код не вызывается до тех пор, пока соединение уже не будет создано от моего имени, поэтому мне нужно будет убедить Запросы говорить об этом существующем сокете, если я хочу иметь возможность использовать функции Запросов.

Библиотека запросов:

http://pypi.python.org/pypi/requests

https://github.com/kennethreitz/requests

4b9b3361

Ответ 1

Следующий код нуждается в запросах от git (особенно requests.packages.urllib3.poolmanager.PoolManager._new_pool())

Я тестировал его с помощью ncat -v -l 127.0.0.1 8000

Проблема заключается в том, что соединение не открывается urllib3, а httplib из стандартной библиотеки.

import socket
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3 import PoolManager, HTTPConnectionPool

try:
    from http.client import HTTPConnection
except ImportError:
    from httplib import HTTPConnection


class MyAdapter(HTTPAdapter):
    def init_poolmanager(self, connections, maxsize):
        self.poolmanager = MyPoolManager(num_pools=connections,
                                         maxsize=maxsize)


class MyPoolManager(PoolManager):
    def _new_pool(self, scheme, host, port):
        # Important!
        if scheme == 'http' and host == my_host and port == my_port:
            return MyHTTPConnectionPool(host, port, **self.connection_pool_kw)
        return super(PoolManager, self)._new_pool(self, scheme, host, port)


class MyHTTPConnectionPool(HTTPConnectionPool):
    def _new_conn(self):
        self.num_connections += 1
        return MyHTTPConnection(host=self.host,
                            port=self.port,
                            strict=self.strict)


class MyHTTPConnection(HTTPConnection):
    def connect(self):
        """Connect to the host and port specified in __init__."""
        # Original
        # self.sock = socket.create_connection((self.host, self.port),
        #                                    self.timeout, self.source_address)
        # Important!
        self.sock = my_socket
        if self._tunnel_host:
            self._tunnel()


if __name__ == '__main__':
    import time

    my_host = '127.0.0.1'
    my_port = 8000

    my_socket = socket.create_connection((my_host, my_port))
    time.sleep(4)
    s = requests.Session()
    s.mount('http://', MyAdapter())
    s.get('http://127.0.0.1:8000/foo')

Edit:

Или прямая передача monkeypatching соединения:

class MyHTTPConnection(HTTPConnection):
    def connect(self):
        self.sock = my_socket
        if self._tunnel_host:
            self._tunnel()

requests.packages.urllib3.connectionpool.HTTPConnection = MyHTTPConnection

if __name__ == '__main__':
    my_host = '127.0.0.1'
    my_port = 8000

    my_socket = socket.create_connection((my_host, my_port))
    requests.get('http://127.0.0.1:8000/foo')

Ответ 2

Идите прямо в библиотеку urllib3; он содержит пул соединений в модуле urllib3.connectionpool.

Вы можете заменить пул или настроить его, взломав poolmanager модуль.