2013-02-02 46 views
12

Python的「請求」圖書館是目前所有的憤怒,因爲漂亮的界面,它提供了HTTP請求的 - 但它的下面似乎有間接的許多層 - 會話,HTTP適配器,最後是urllib3的機制。使用Python「請求」與現有的插座連接

凡在這個堆棧的抽象的是,如果我已經持有一個開放的插座,想用「請求」派下來的套接字的HTTP響應,並收到回覆給介入正確的地方?

如果沒有某種干預(或定製?),堆棧會嘗試爲我創建一個新的TCP/IP套接字,但在我的特定應用程序中,我的代碼不會被調用,直到代表我建立了一個連接,所以如果我希望能夠使用Requests的功能,我需要說服請求在現有套接字上進行通信。

的請求庫:

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

https://github.com/kennethreitz/requests

回答

8

下面的代碼使用ncat -v -l 127.0.0.1 8000

的問題是事實,需要從混帳(尤其是requests.packages.urllib3.poolmanager.PoolManager._new_pool()

我測試了它的請求,該連接不會被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') 

編輯:

或者直接的連接池的的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') 
+0

這的monkeypatching不會爲我工作。我不確定它在過去四年中是否無效或請求發生了變化,但我的類沒有被使用(至少,它的'__init__'和'connect'方法從未被調用過)。我正在使用python 3.5並請求2.18.1。 – Tom