diff --git a/requests/models.py b/requests/models.py index cb44eddd..91555b58 100644 --- a/requests/models.py +++ b/requests/models.py @@ -347,9 +347,9 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin): url = url.lstrip() # Don't do any URL preparation for non-HTTP schemes like `mailto`, - # `data`, `http+unix` etc to work around exceptions from `url_parse`, - # which handles RFC 3986 only. - if ':' in url and not url.lower().startswith(('http://', 'https://')): + # `data` etc to work around exceptions from `url_parse`, which + # handles RFC 3986 only. + if ':' in url and not url.lower().startswith('http'): self.url = url return diff --git a/tests/test_requests.py b/tests/test_requests.py index ca90297e..2c298bab 100755 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -2177,18 +2177,72 @@ class TestPreparingURLs(object): r.prepare() @pytest.mark.parametrize( - 'protocol, url', + 'input, expected', ( - ("http+unix://", b"http+unix://%2Fvar%2Frun%2Fsocket/path"), - ("http+unix://", u"http+unix://%2Fvar%2Frun%2Fsocket/path"), - ("mailto", b"mailto:user@example.org"), - ("mailto", u"mailto:user@example.org"), - ("data", b"data:SSDimaUgUHl0aG9uIQ=="), + ( + b"http+unix://%2Fvar%2Frun%2Fsocket/path", + u"http+unix://%2fvar%2frun%2fsocket/path", + ), + ( + u"http+unix://%2Fvar%2Frun%2Fsocket/path", + u"http+unix://%2fvar%2frun%2fsocket/path", + ), + ( + b"mailto:user@example.org", + u"mailto:user@example.org", + ), + ( + u"mailto:user@example.org", + u"mailto:user@example.org", + ), + ( + b"data:SSDimaUgUHl0aG9uIQ==", + u"data:SSDimaUgUHl0aG9uIQ==", + ) ) ) - def test_url_passthrough(self, protocol, url): - session = requests.Session() - session.mount(protocol, HTTPAdapter()) - p = requests.Request('GET', url=url) - p.prepare() - assert p.url == url + def test_url_mutation(self, input, expected): + """ + This test validates that we correctly exclude some URLs from + preparation, and that we handle others. Specifically, it tests that + any URL whose scheme doesn't begin with "http" is left alone, and + those whose scheme *does* begin with "http" are mutated. + """ + r = requests.Request('GET', url=input) + p = r.prepare() + assert p.url == expected + + @pytest.mark.parametrize( + 'input, params, expected', + ( + ( + b"http+unix://%2Fvar%2Frun%2Fsocket/path", + {"key": "value"}, + u"http+unix://%2fvar%2frun%2fsocket/path?key=value", + ), + ( + u"http+unix://%2Fvar%2Frun%2Fsocket/path", + {"key": "value"}, + u"http+unix://%2fvar%2frun%2fsocket/path?key=value", + ), + ( + b"mailto:user@example.org", + {"key": "value"}, + u"mailto:user@example.org", + ), + ( + u"mailto:user@example.org", + {"key": "value"}, + u"mailto:user@example.org", + ), + ) + ) + def test_parameters_for_nonstandard_schemes(self, input, params, expected): + """ + Setting paramters for nonstandard schemes is allowed if those schemes + begin with "http", and is forbidden otherwise. + """ + r = requests.Request('GET', url=input, params=params) + p = r.prepare() + assert p.url == expected +