Index: Doc/library/urllib2.rst =================================================================== --- Doc/library/urllib2.rst (revision 67015) +++ Doc/library/urllib2.rst (working copy) @@ -327,21 +327,42 @@ same functionality using only one header. -.. method:: Request.add_unredirected_header(key, header) +.. method:: Request.add_unredirected_header(key, val) Add a header that will not be added to a redirected request. .. versionadded:: 2.4 -.. method:: Request.has_header(header) +.. method:: Request.has_header(header_name) Return whether the instance has the named header (checks both regular and unredirected). .. versionadded:: 2.4 + .. versionchanged:: 2.7 + Header name is looked up case-insensitively + +.. method:: Request.get_header(header_name) + + Return the value of the named header (checks both regular and unredirected). + + .. versionadded:: 2.4 + + .. versionchanged:: 2.7 + Header name is looked up case-insensitively + + +.. method:: Request.header_items() + + Return list of header (key, val) pairs that have been added to the request + (both regular and unredirected). + + .. versionadded:: 2.4 + + .. method:: Request.get_full_url() Return the URL given in the constructor. Index: Lib/urllib2.py =================================================================== --- Lib/urllib2.py (revision 67015) +++ Lib/urllib2.py (working copy) @@ -273,13 +273,13 @@ self.unredirected_hdrs[key.capitalize()] = val def has_header(self, header_name): - return (header_name in self.headers or - header_name in self.unredirected_hdrs) + return (header_name.capitalize() in self.headers or + header_name.capitalize() in self.unredirected_hdrs) def get_header(self, header_name, default=None): return self.headers.get( - header_name, - self.unredirected_hdrs.get(header_name, default)) + header_name.capitalize(), + self.unredirected_hdrs.get(header_name.capitalize(), default)) def header_items(self): hdrs = self.unredirected_hdrs.copy() Index: Lib/test/test_urllib2.py =================================================================== --- Lib/test/test_urllib2.py (revision 67015) +++ Lib/test/test_urllib2.py (working copy) @@ -63,42 +63,75 @@ interface and also provided access to the "unredirected" headers. It's probably too late to fix that, though. + "Unredirected" headers are not present in the .headers mapping + + >>> url = "http://example.com" + >>> req = urllib2.Request(url) + >>> req.add_header("Spam-eggs", "eggs") + >>> req.add_unredirected_header("Foo-bar", "spam") + >>> req.headers.items() + [('Spam-eggs', 'eggs')] + >>> req.unredirected_hdrs.items() + [('Foo-bar', 'spam')] - Check .capitalize() case normalization: + .headers supports lookup using .capitalize()-normalized case - >>> url = "http://example.com" - >>> Request(url, headers={"Spam-eggs": "blah"}).headers["Spam-eggs"] + >>> def make_request(header_name): + ... return Request("http://example.com", headers={header_name: "blah"}) + + >>> make_request("Spam-eggs").headers["Spam-eggs"] 'blah' - >>> Request(url, headers={"spam-EggS": "blah"}).headers["Spam-eggs"] + >>> make_request("spam-EggS").headers["Spam-eggs"] 'blah' - Currently, Request(url, "Spam-eggs").headers["Spam-Eggs"] raises KeyError, - but that could be changed in future. + .headers currently does not support lookup using + non-.capitalize()-normalized case. This could be changed in future. + >>> make_request("Spam-eggs").headers["Spam-Eggs"] + Traceback (most recent call last): + KeyError: 'Spam-Eggs' + + .unredirected_hdrs works the same way + + >>> def make_request(unredirected_header_name): + ... request = Request("http://example.com") + ... request.add_unredirected_header(unredirected_header_name, "blah") + ... return request + >>> make_request("Spam-eggs").unredirected_hdrs["Spam-eggs"] + 'blah' + >>> make_request("spam-EggS").unredirected_hdrs["Spam-eggs"] + 'blah' + >>> make_request("Spam-eggs").unredirected_hdrs["Spam-Eggs"] + Traceback (most recent call last): + KeyError: 'Spam-Eggs' + """ def test_request_headers_methods(): """ - Note the case normalization of header names here, to .capitalize()-case. - This should be preserved for backwards-compatibility. (In the HTTP case, - normalization to .title()-case is done by urllib2 before sending headers to - httplib). - >>> url = "http://example.com" >>> r = Request(url, headers={"Spam-eggs": "blah"}) + + .has_header and .get_header are case-insensitive + >>> r.has_header("Spam-eggs") True - >>> r.header_items() - [('Spam-eggs', 'blah')] + >>> r.has_header("SPAM-EGGS") + True + >>> r.get_header("Spam-eggs") + 'blah' + >>> r.get_header("SPAM-EGGS") + 'blah' + + .header_items() returns headers in .capitalize()-case. This should be + preserved for backwards-compatibility. (In the HTTP case, normalization to + .title()-case is done by urllib2 before sending headers to httplib). + >>> r.add_header("Foo-Bar", "baz") - >>> items = r.header_items() - >>> items.sort() - >>> items + >>> sorted(r.header_items()) [('Foo-bar', 'baz'), ('Spam-eggs', 'blah')] - Note that e.g. r.has_header("spam-EggS") is currently False, and - r.get_header("spam-EggS") returns None, but that could be changed in - future. + Missing key behaviour >>> r.has_header("Not-there") False