Commit f5b1abbb authored by Jason R. Coombs's avatar Jason R. Coombs Committed by Benjamin Peterson

[2.7] bpo-38216, bpo-36274: Allow subclasses to separately override validation...

[2.7] bpo-38216, bpo-36274: Allow subclasses to separately override validation and encoding behavior (GH-16476)

Backporting this change, I observe a couple of things:

1. The _encode_request call is no longer meaningful because the request construction will implicitly encode the request using the default encoding when the format string is used (request = '%s %s %s'...). In order to keep the code as consistent as possible, I decided to include the call as a pass-through. I'd be just as happy to remove it entirely, but I'll leave that up to the reviewer to decide. It's okay that this functionality is disabled on Python 2 because this functionality was mainly around bpo-36274, which was mainly a concern with the transition to Python 3.
2. Because _encode_request is no longer meaningful, neither is the test for it, so I've removed that test. Therefore, the meaningful part of this test is that for bpo-38216, adding a (underscore-protected) hook to customize/disable validation.

(cherry picked from commit 7774d7831e8809795c64ce27f7df52674581d298)
Co-authored-by: default avatarJason R. Coombs <jaraco@jaraco.com>
parent e7e58fe0
......@@ -933,19 +933,15 @@ class HTTPConnection:
else:
raise CannotSendRequest()
# Save the method we use, we need it later in the response phase
# Save the method for use later in the response phase
self._method = method
if not url:
url = '/'
# Prevent CVE-2019-9740.
match = _contains_disallowed_url_pchar_re.search(url)
if match:
raise InvalidURL("URL can't contain control characters. %r "
"(found at least %r)"
% (url, match.group()))
hdr = '%s %s %s' % (method, url, self._http_vsn_str)
self._output(hdr)
url = url or '/'
self._validate_path(url)
request = '%s %s %s' % (method, url, self._http_vsn_str)
self._output(self._encode_request(request))
if self._http_vsn == 11:
# Issue some standard headers for better HTTP/1.1 compliance
......@@ -1018,6 +1014,21 @@ class HTTPConnection:
# For HTTP/1.0, the server will assume "not chunked"
pass
def _encode_request(self, request):
# On Python 2, request is already encoded (default)
return request
def _validate_path(self, url):
"""Validate a url for putrequest."""
# Prevent CVE-2019-9740.
match = _contains_disallowed_url_pchar_re.search(url)
if match:
msg = (
"URL can't contain control characters. {url!r} "
"(found at least {matched!r})"
).format(matched=match.group(), url=url)
raise InvalidURL(msg)
def putheader(self, header, *values):
"""Send a request header line to the server.
......
......@@ -702,6 +702,20 @@ class BasicTest(TestCase):
with self.assertRaisesRegexp(socket.error, "Invalid response"):
conn._tunnel()
def test_putrequest_override_validation(self):
"""
It should be possible to override the default validation
behavior in putrequest (bpo-38216).
"""
class UnsafeHTTPConnection(httplib.HTTPConnection):
def _validate_path(self, url):
pass
conn = UnsafeHTTPConnection('example.com')
conn.sock = FakeSocket('')
conn.putrequest('GET', '/\x00')
class OfflineTest(TestCase):
def test_responses(self):
self.assertEqual(httplib.responses[httplib.NOT_FOUND], "Not Found")
......
Allow the rare code that wants to send invalid http requests from the
`http.client` library a way to do so. The fixes for bpo-30458 led to
breakage for some projects that were relying on this ability to test their
own behavior in the face of bad requests.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment