diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -176,19 +176,36 @@ class OtherNetworkTests(unittest.TestCas url = "http://www.example.com" with support.transient_internet(url): opener = urllib.request.build_opener() request = urllib.request.Request(url) self.assertFalse(request.header_items()) opener.open(request) self.assertTrue(request.header_items()) self.assertTrue(request.has_header('User-agent')) - request.add_header('User-Agent','Test-Agent') + request.add_header('User-Agent', 'Test-Agent') opener.open(request) - self.assertEqual(request.get_header('User-agent'),'Test-Agent') + self.assertEqual(request.get_header('User-Agent'), 'Test-Agent') + + def test_headers_case_sensitivity(self): + url = "http://www.example.com" + with support.transient_internet(url): + opener = urllib.request.build_opener() + request = urllib.request.Request(url) + headers = [("Content-Type", "text/plain"), ] + opener.addheaders = headers + opener.open(request) + self.assertTrue(request.has_header('Content-type')) + self.assertTrue(request.has_header('Content-Type')) + self.assertTrue(request.has_header('content-type')) + self.assertTrue(request.has_header('CoNtEnT-tYpE')) + self.assertEqual(request.get_header('Content-type'), 'text/plain') + self.assertEqual(request.get_header('Content-Type'), 'text/plain') + self.assertEqual(request.get_header('content-type'), 'text/plain') + self.assertEqual(request.get_header('CoNtEnT-tYpE'), 'text/plain') def test_sites_no_connection_close(self): # Some sites do not send Connection: close header. # Verify that those work properly. (#issue12576) URL = 'http://www.imdb.com' # mangles Connection:close with support.transient_internet(URL): diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -346,23 +346,30 @@ class Request: # useful for something like authentication self.headers[key.capitalize()] = val def add_unredirected_header(self, key, val): # will not be added to a redirected request 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) + lower_hdr = header_name.lower() + return (lower_hdr in [key.lower() for key in self.headers] or + lower_hdr in [key.lower() for key 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)) + lower_hdr = header_name.lower() + hdr_value = [value for key, value in self.headers.items() + if key.lower() == lower_hdr] or None + if not hdr_value: + hdr_value = [value for key, value in self.unredirected_hdrs.items() + if key.lower() == lower_hdr] or None + if hdr_value: + return hdr_value[0] + return hdr_value def remove_header(self, header_name): self.headers.pop(header_name, None) self.unredirected_hdrs.pop(header_name, None) def header_items(self): hdrs = self.unredirected_hdrs.copy() hdrs.update(self.headers)