2013-02-02 7 views
12

Biblioteka "żądań" Pythona jest obecnie w szał, ze względu na piękny interfejs, który zapewnia wysyłanie żądań HTTP - ale pod nim jest wiele warstw pośrednich - sesje , Adaptery HTTP i wreszcie mechanika urllib3.Używanie Pythona "żądań" z istniejącym połączeniem z gniazdem

Gdzie w tej stosie abstrakcji jest właściwe miejsce do interwencji, jeśli już posiadam otwarte gniazdo i chcę użyć "żądań", aby wysłać odpowiedź HTTP w dół tego gniazda i otrzymać odpowiedź zwrotną?

Bez jakiejś interwencji (lub dostosowania?), Stos spróbuje utworzyć dla mnie nowe gniazdo TCP/IP, ale w mojej konkretnej aplikacji mój kod nie zostanie wywołany, dopóki połączenie nie zostanie już ustanowione w moim imieniu , więc będę musiał przekonać Prośby o rozmowę na tym istniejącym gnieździe, jeśli chcę móc korzystać z funkcji Żądań.

Biblioteka Wnioski:

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

https://github.com/kennethreitz/requests

Odpowiedz

8

Poniższy kod wymaga żądania od git (zwłaszcza requests.packages.urllib3.poolmanager.PoolManager._new_pool())

Testowałem go za pomocą ncat -v -l 127.0.0.1 8000

Problemem jest fakt, że połączenie nie jest otwarty przez urllib3 ale httplib z biblioteki standardowej .

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:

lub bezpośredniego monkeypatching z pula połączeń:

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') 
+0

Ten monkeypatching nie działa dla mnie. Nie jestem pewien, czy to nigdy nie zadziałało, czy też żądania zmieniły się w ciągu ostatnich czterech lat, ale moja klasa nie jest używana (przynajmniej jej metody '__init__' i' connect' nigdy nie są wywoływane). Używam Pythona 3.5 i żądań 2.18.1. – Tom

Powiązane problemy