def request(self, httxreq): ''' Send the L{HttxRequest} httxreq to the specified server inside the request It does get a connection or create one and relay the request down to it, taking into account the HTTP keepalive timeout @param httxreq: Request or url to be executed @type httxreq: L{HttxRequest} or url (string) @return: sock @rtype: opaque type for the caller (a Python sock) ''' with self.lock: try: httxconn = self.httxconnque.pop() # Check if the HTTP keepalive timeout has been exceeded if (tclock() - httxconn.timestamp) >= self.options.keepalive: # Simulate that no connection was available raise IndexError # The connection is no longer in any container, it will be discarded except IndexError: # use self.url and not the request url ... to be able to proxy connections httxconn = HttxConnection(self.url, options=self.options) # keep a copy of this dangling connecion in a set to avoid missing it if # we are cloning an object and some threads find themselves issuing requests self.inopcache.add(httxconn) try: sock = httxconn.request(httxreq) except: # let it be reused httxconn.reset() with self.lock: # no longer in operation self.inopcache.discard(httxconn) # back to conn queue self.httxconnque.appendleft(httxconn) # let the exception propagate raise # Remove the cache from the in-operation cache and place it in the # cache for connections with pending network activity with self.lock: self.inopcache.discard(httxconn) self.httxconncache[sock] = httxconn return sock
def createconnection(self, url, sock=None, plaintunnel=False): ''' Helper function to enable delayed creation of the underlying connection if needed. Called from the L{__init__} and from L{request} in order to ensure an underlying connection is created or recreated if tunneling It initializes the member variables: I{url}, I{parsed}, L{conn}, I{clock} In the case of https connections it will also set variables in the underlying connection object to ensure certificates and validation are used if requested and appropriate for the domain @param url: url to open a connection to @type url: str @param sock: socket for a tunneled connection @type sock: socket (Default: None) @param plaintunnel: if tunnel should not be sslized (connections are fake that do nothing or ssl_wrap) @type plaintunnel: bool (Default: False) ''' if not url: self.conn = None return self.url = url self.parsed = urlsplit(self.url) if not sock: self.conn = self.connFactory[self.parsed.scheme](self.parsed.hostname, self.parsed.port, timeout=self.options.timeout) else: self.conn = self.tunnelFactory[self.parsed.scheme](sock, self.parsed.hostname, self.parsed.port, timeout=self.options.timeout) if not sock or not plaintunnel: self.doconnect() self.timestamp = tclock()
url = httxreq.get_full_url() else: # use the short version of the url (less problematic if not proxying) url = httxreq.get_selector() # Execute the request try: self.conn.request(httxreq.get_method(), url, httxreq.body, httxreq.allheaders) except SocketError, e: raise SocketException(*e.args) # If no exception, we may save the request to be used by getresponse self.lastreq = httxreq # Update the timestamp self.timestamp = tclock() # Async applications need something to wait on. Return our socket return self.conn.sock def getresponse(self, sock): ''' Recover a L{HttxResponse} The sock parameter is not used but the function follows the abstract definition of L{HttxBase} and the implementations of L{HttxManager} and L{HttxNetLocation} Checks for authentication requests or redirectionare made. If the options allow to process those requests, new requests (with potentially