Merge pull request #3417 from nateprewitt/2939_multiple_location_headers

raise InvalidHeader on multiple Location values
This commit is contained in:
Ian Cordasco
2016-08-22 11:49:36 -05:00
committed by GitHub
4 changed files with 37 additions and 3 deletions
+4
View File
@@ -83,6 +83,10 @@ class InvalidURL(RequestException, ValueError):
""" The URL provided was somehow invalid. """
class InvalidHeader(RequestException, ValueError):
"""The header value provided was somehow invalid."""
class ChunkedEncodingError(RequestException):
"""The server declared chunked encoding but sent an invalid chunk."""
+7 -2
View File
@@ -20,7 +20,8 @@ from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT
from .hooks import default_hooks, dispatch_hook
from .utils import to_key_val_list, default_headers, to_native_string
from .exceptions import (
TooManyRedirects, InvalidScheme, ChunkedEncodingError, ContentDecodingError)
TooManyRedirects, InvalidScheme, ChunkedEncodingError,
ContentDecodingError, InvalidHeader)
from .packages.urllib3._collections import RecentlyUsedContainer
from .structures import CaseInsensitiveDict
@@ -28,7 +29,7 @@ from .adapters import HTTPAdapter
from .utils import (
requote_uri, get_environ_proxies, get_netrc_auth, should_bypass_proxies,
get_auth_from_url
get_auth_from_url, is_valid_location
)
from .status_codes import codes
@@ -98,6 +99,10 @@ class SessionRedirectMixin(object):
request = response.request
while response.is_redirect:
if not is_valid_location(response):
raise InvalidHeader('Response contains multiple Location headers. '
'Unable to perform redirect.')
prepared_request = request.copy()
if redirect_count > 0:
+11
View File
@@ -665,6 +665,17 @@ def parse_header_links(value):
return links
def is_valid_location(response):
"""Verify that multiple Location headers weren't
returned from the last response.
"""
headers = getattr(response.raw, 'headers', None)
if headers is not None:
getlist = getattr(headers, 'getlist', None)
if getlist is not None:
return len(getlist('location')) <= 1
# If response.raw isn't urllib3-like we can't reliably check this
return True
# Null bytes; no need to recreate these on each call to guess_json_utf
_null = '\x00'.encode('ascii') # encoding to ASCII for Python 3
+15 -1
View File
@@ -22,7 +22,7 @@ from requests.cookies import cookiejar_from_dict, morsel_to_cookie
from requests.exceptions import (
ConnectionError, ConnectTimeout, InvalidScheme, InvalidURL,
MissingScheme, ReadTimeout, Timeout, RetryError, TooManyRedirects,
ProxyError)
ProxyError, InvalidHeader)
from requests.models import PreparedRequest
from requests.structures import CaseInsensitiveDict
from requests.sessions import SessionRedirectMixin
@@ -222,6 +222,20 @@ class TestRequests:
assert r.history[0].status_code == 303
assert r.history[0].is_redirect
def test_multiple_location_headers(self, httpbin):
headers = [('Location', 'http://example.com'),
('Location', 'https://example.com/1')]
params = '&'.join(['%s=%s' % (k, v) for k, v in headers])
ses = requests.Session()
req = requests.Request('GET', httpbin('response-headers?%s' % params))
prep = ses.prepare_request(req)
resp = ses.send(prep)
# change response to redirect
resp.status_code = 302
with pytest.raises(InvalidHeader):
# next triggers yield on generator
next(ses.resolve_redirects(resp, prep))
# def test_HTTP_302_ALLOW_REDIRECT_POST(self):
# r = requests.post(httpbin('status', '302'), data={'some': 'data'})
# self.assertEqual(r.status_code, 200)