From a3e597c17112da2d9520e27e09159c29ac4b8351 Mon Sep 17 00:00:00 2001 From: shmuelamar Date: Wed, 12 Apr 2017 19:31:27 +0300 Subject: [PATCH] fix unicode decode error on py2 when handling redirect without scheme --- AUTHORS.rst | 2 +- requests/sessions.py | 2 +- tests/test_lowlevel.py | 39 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 40 insertions(+), 3 deletions(-) mode change 100644 => 100755 AUTHORS.rst mode change 100644 => 100755 requests/sessions.py mode change 100644 => 100755 tests/test_lowlevel.py diff --git a/AUTHORS.rst b/AUTHORS.rst old mode 100644 new mode 100755 index e4a325bf..757feaf5 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -179,4 +179,4 @@ Patches and Suggestions - Matt Kohl (`@mattkohl `_) - Jonathan Vanasco (`@jvanasco `_) - David Fontenot (`@davidfontenot `_) - +- Shmuel Amar (`@shmuelamar `_) diff --git a/requests/sessions.py b/requests/sessions.py old mode 100644 new mode 100755 index 9ad8d84c..88262a23 --- a/requests/sessions.py +++ b/requests/sessions.py @@ -122,7 +122,7 @@ class SessionRedirectMixin(object): # Handle redirection without scheme (see: RFC 1808 Section 4) if url.startswith('//'): parsed_rurl = urlparse(resp.url) - url = '%s:%s' % (parsed_rurl.scheme, url) + url = '%s:%s' % (to_native_string(parsed_rurl.scheme), url) # The scheme should be lower case... parsed = urlparse(url) diff --git a/tests/test_lowlevel.py b/tests/test_lowlevel.py old mode 100644 new mode 100755 index c8de1b1b..59e03865 --- a/tests/test_lowlevel.py +++ b/tests/test_lowlevel.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- -import os import pytest import threading import requests +from requests.compat import quote, is_py3 from tests.testserver.server import Server, consume_socket_content @@ -204,3 +204,40 @@ def test_use_proxy_from_environment(httpbin, var, scheme): # it had actual content (not checking for SOCKS protocol for now) assert len(fake_proxy.handler_results[0]) > 0 + + +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' + redirect_request = [] # stores the second request to the server + + def redirect_resp_handler(sock): + consume_socket_content(sock, timeout=0.5) + location = u'//{0}:{1}/{2}'.format(host, port, path) + sock.send( + b'HTTP/1.1 301 Moved Permanently\r\n' + b'Content-Length: 0\r\n' + b'Location: ' + location.encode('utf8') + b'\r\n' + b'\r\n' + ) + redirect_request.append(consume_socket_content(sock, timeout=0.5)) + sock.send(b'HTTP/1.1 200 OK\r\n\r\n') + + close_server = threading.Event() + server = Server(redirect_resp_handler, wait_to_close_event=close_server) + + with server as (host, port): + url = u'http://{0}:{1}'.format(host, port) + r = requests.get(url=url, allow_redirects=True) + 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') + + close_server.set()