From 177c81745da7996b5e64a8d7e49b4158ced042b1 Mon Sep 17 00:00:00 2001 From: Alexandru Cepoi Date: Mon, 18 Jun 2012 02:10:43 +0200 Subject: [PATCH] domain and path support for request cookies --- docs/topics/request-response.rst | 15 +++++++++-- .../contrib/downloadermiddleware/cookies.py | 24 ++++++++++++++--- .../test_downloadermiddleware_cookies.py | 26 +++++++++++++++++++ 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/docs/topics/request-response.rst b/docs/topics/request-response.rst index c7d7a91fd..ec02a50e8 100644 --- a/docs/topics/request-response.rst +++ b/docs/topics/request-response.rst @@ -51,10 +51,21 @@ Request objects (for single valued headers) or lists (for multi-valued headers). :type headers: dict - :param cookies: the request cookies. Example:: + :param cookies: the request cookies. These can be sent in two forms:: request_with_cookies = Request(url="http://www.example.com", cookies={'currency': 'USD', 'country': 'UY'}) + :: + + request_with_cookies = Request(url="http://www.example.com", + cookies=[{'name': 'currency', + 'value': 'USD', + 'domain': 'example.com', + 'path': '/currency'}]) + + The latter form allows for customizing the ``domain`` and ``path`` + attributes of the cookie. These is only useful if the cookies are saved + for later requests. When some site returns cookies (in a response) those are stored in the cookies for that domain and will be sent again in future requests. That's @@ -70,7 +81,7 @@ Request objects meta={'dont_merge_cookies': True}) For more info see :ref:`cookies-mw`. - :type cookies: dict + :type cookies: dict or list :param encoding: the encoding of this request (defaults to ``'utf-8'``). This encoding will be used to percent-encode the URL and to convert the diff --git a/scrapy/contrib/downloadermiddleware/cookies.py b/scrapy/contrib/downloadermiddleware/cookies.py index 191b7c4d6..ed61a89f9 100644 --- a/scrapy/contrib/downloadermiddleware/cookies.py +++ b/scrapy/contrib/downloadermiddleware/cookies.py @@ -60,10 +60,26 @@ class CookiesMiddleware(object): msg += os.linesep.join("Set-Cookie: %s" % c for c in cl) log.msg(msg, spider=spider, level=log.DEBUG) + def _format_cookie(self, cookie): + # build cookie string + cookie_str = '%s=%s' % (cookie['name'], cookie['value']) + + if cookie.get('path', None): + cookie_str += '; Path=%s' % cookie['path'] + if cookie.get('domain', None): + cookie_str += '; Domain=%s' % cookie['domain'] + + return cookie_str + def _get_request_cookies(self, jar, request): - headers = {'Set-Cookie': ['%s=%s;' % (k, v) for k, v in request.cookies.iteritems()]} + if isinstance(request.cookies, dict): + cookie_list = [{'name': k, 'value': v} for k, v in \ + request.cookies.iteritems()] + else: + cookie_list = request.cookies + + cookies = map(self._format_cookie, cookie_list) + headers = {'Set-Cookie': cookies} response = Response(request.url, headers=headers) - cookies = jar.make_cookies(response, request) - return cookies - + return jar.make_cookies(response, request) diff --git a/scrapy/tests/test_downloadermiddleware_cookies.py b/scrapy/tests/test_downloadermiddleware_cookies.py index 1a64c5347..d9ed476f1 100644 --- a/scrapy/tests/test_downloadermiddleware_cookies.py +++ b/scrapy/tests/test_downloadermiddleware_cookies.py @@ -49,6 +49,32 @@ class CookiesMiddlewareTest(TestCase): assert self.mw.process_request(req, self.spider) is None self.assertEquals(req.headers.get('Cookie'), 'C1=value1') + def test_complex_cookies(self): + # merge some cookies into jar + cookies = [{'name': 'C1', 'value': 'value1', 'path': '/foo', 'domain': 'scrapytest.org'}, + {'name': 'C2', 'value': 'value2', 'path': '/bar', 'domain': 'scrapytest.org'}, + {'name': 'C3', 'value': 'value3', 'path': '/foo', 'domain': 'scrapytest.org'}, + {'name': 'C4', 'value': 'value4', 'path': '/foo', 'domain': 'scrapy.org'}] + + + req = Request('http://scrapytest.org/', cookies=cookies) + self.mw.process_request(req, self.spider) + + # embed C1 and C3 for scrapytest.org/foo + req = Request('http://scrapytest.org/foo') + self.mw.process_request(req, self.spider) + assert req.headers.get('Cookie') in ('C1=value1; C3=value3', 'C3=value3; C1=value1') + + # embed C2 for scrapytest.org/bar + req = Request('http://scrapytest.org/bar') + self.mw.process_request(req, self.spider) + self.assertEquals(req.headers.get('Cookie'), 'C2=value2') + + # embed nothing for scrapytest.org/baz + req = Request('http://scrapytest.org/baz') + self.mw.process_request(req, self.spider) + assert 'Cookie' not in req.headers + def test_merge_request_cookies(self): req = Request('http://scrapytest.org/', cookies={'galleta': 'salada'}) assert self.mw.process_request(req, self.spider) is None