Skip to content

Commit

Permalink
fix handle of non-ascii location on redirects
Browse files Browse the repository at this point in the history
  • Loading branch information
shmuelamar committed Apr 17, 2017
1 parent fd7dcd2 commit 722b1da
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 11 deletions.
13 changes: 11 additions & 2 deletions requests/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from datetime import datetime

from .auth import _basic_auth_str
from .compat import cookielib, OrderedDict, urljoin, urlparse
from .compat import cookielib, is_py3, OrderedDict, urljoin, urlparse
from .cookies import (
cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies)
from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT
Expand Down Expand Up @@ -90,7 +90,16 @@ class SessionRedirectMixin(object):
def get_redirect_target(self, resp):
"""Receives a Response. Returns a redirect URI or ``None``"""
if resp.is_redirect:
return resp.headers['location']
location = resp.headers['location']
# Currently the underlying http module on py3 decode headers
# in latin1, but empirical evidence suggests that latin1 is very
# rarely used with non-ASCII characters in HTTP headers.
# It is more likely to get UTF8 header rather than latin1.
# This causes incorrect handling of UTF8 encoded location headers.
# To solve this, we re-encode the location in latin1.
if is_py3:
location = location.encode('latin1')
return to_native_string(location, 'utf8')
return None

def resolve_redirects(self, resp, req, stream=False, timeout=None,
Expand Down
12 changes: 3 additions & 9 deletions tests/test_lowlevel.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import pytest
import threading
import requests
from requests.compat import quote, is_py3

from tests.testserver.server import Server, consume_socket_content

Expand Down Expand Up @@ -208,8 +207,7 @@ def test_use_proxy_from_environment(httpbin, var, scheme):

def test_redirect_rfc1808_to_non_ascii_location():
path = u'š'
expected_path = quote(path.encode('utf8')).encode('ascii')
expected_path_py3 = b'%C3%85%C2%A1'
expected_path = b'%C5%A1'
redirect_request = [] # stores the second request to the server

def redirect_resp_handler(sock):
Expand All @@ -233,11 +231,7 @@ def redirect_resp_handler(sock):
assert r.status_code == 200
assert len(r.history) == 1
assert r.history[0].status_code == 301

# currently Python3 not handling non-ASCII redirects (issue #3888)
if is_py3:
assert redirect_request[0].startswith(b'GET /' + expected_path_py3 + b' HTTP/1.1')
else:
assert redirect_request[0].startswith(b'GET /' + expected_path + b' HTTP/1.1')
assert redirect_request[0].startswith(b'GET /' + expected_path + b' HTTP/1.1')
assert r.url == u'{0}/{1}'.format(url, expected_path.decode('ascii'))

close_server.set()

0 comments on commit 722b1da

Please sign in to comment.