|
|
|
class CookieLibAgent(Agent): |
|
|
|
def __init__(self, cookieJar, *args, **kwargs): |
|
Agent.__init__(self, reactor, *args, **kwargs) |
|
self.jar = cookieJar |
|
|
|
def request(self, method, uri, headers=None, bodyProducer=None): |
|
""" |
|
Issue a new request. |
|
|
|
@param method: The request method to send. |
|
@type method: C{str} |
|
|
|
@param uri: The request URI send. |
|
@type uri: C{str} |
|
|
|
@param headers: The request headers to send. If no I{Host} header is |
|
included, one will be added based on the request URI. |
|
@type headers: L{Headers} |
|
|
|
@param bodyProducer: An object which will produce the request body or, |
|
if the request body is to be empty, L{None}. |
|
@type bodyProducer: L{IBodyProducer} provider |
|
|
|
@return: A L{Deferred} which fires with the result of the request (a |
|
L{Response} instance), or fails if there is a problem setting up a |
|
connection over which to issue the request. It may also fail with |
|
L{SchemeNotSupported} if the scheme of the given URI is not |
|
supported. |
|
@rtype: L{Deferred} |
|
""" |
|
scheme, host, port, path = _parse(uri) |
|
if headers is None: |
|
headers = Headers() |
|
if not headers.hasHeader('host'): |
|
# This is a lot of copying. It might be nice if there were a bit |
|
# less. |
|
headers = Headers(dict(headers.getAllRawHeaders())) |
|
headers.addRawHeader( |
|
'host', self._computeHostValue(scheme, host, port)) |
|
# settings cookie header explicitly will disable cookie jar functionality |
|
if not headers.hasHeader('cookie'): |
|
# TODO: figure out how to pass last_req to extract cookies |
|
# in a way that respects HTTP pipelining |
|
self.last_req = self._urllib2Request(uri) |
|
# construct urllib2 request to allow interfacing with cookielib cookiejar |
|
self.jar.add_cookie_header(self.last_req) |
|
cookie_header = self.last_req.get_header('Cookie', None) |
|
if cookie_header is not None: |
|
headers.addRawHeader('cookie', cookie_header) |
|
if self.persistent: |
|
sem = self._semaphores.get((scheme, host, port)) |
|
if sem is None: |
|
sem = defer.DeferredSemaphore(self.maxConnections) |
|
self._semaphores[scheme, host, port] = sem |
|
d = sem.run(self._request, method, scheme, host, port, path, |
|
headers, bodyProducer) |
|
d.addCallback(self._extractCookies) |
|
return d |
|
else: |
|
d = self._request( |
|
method, scheme, host, port, path, headers, bodyProducer) |
|
d.addCallback(self._extractCookies) |
|
return d |
|
|
|
def _urllib2Request(self, url): |
|
return urllib2.Request(url) |
|
|
|
def _extractCookies(self, response): |
|
# mock urllib2 response object |
|
class _Response(object): |
|
def info(self): |
|
class _Meta(object): |
|
def getheaders(self, name): |
|
return response.headers.getRawHeaders(name.lower(), []) |
|
return _Meta() |
|
# construct and deref the urllib2 request/response objects |
|
req = self.last_req |
|
resp = _Response() |
|
self.jar.extract_cookies(resp, req) |
|
return response |