Merge "py3: Stop using stdlib's putrequest(); it only does ASCII"
This commit is contained in:
commit
1c899f78d4
@ -111,6 +111,91 @@ def listing_items(method):
|
||||
items = []
|
||||
|
||||
|
||||
def putrequest(self, method, url, skip_host=False, skip_accept_encoding=False):
|
||||
'''Send a request to the server.
|
||||
|
||||
This is mostly a regurgitation of CPython's HTTPConnection.putrequest,
|
||||
but fixed up so we can still send arbitrary bytes in the request line
|
||||
on py3. See also: https://bugs.python.org/issue36274
|
||||
|
||||
To use, swap out a HTTP(S)Connection's putrequest with something like::
|
||||
|
||||
conn.putrequest = putrequest.__get__(conn)
|
||||
|
||||
:param method: specifies an HTTP request method, e.g. 'GET'.
|
||||
:param url: specifies the object being requested, e.g. '/index.html'.
|
||||
:param skip_host: if True does not add automatically a 'Host:' header
|
||||
:param skip_accept_encoding: if True does not add automatically an
|
||||
'Accept-Encoding:' header
|
||||
'''
|
||||
# (Mostly) inline the HTTPConnection implementation; just fix it
|
||||
# so we can send non-ascii request lines. For comparison, see
|
||||
# https://github.com/python/cpython/blob/v2.7.16/Lib/httplib.py#L888-L1003
|
||||
# and https://github.com/python/cpython/blob/v3.7.2/
|
||||
# Lib/http/client.py#L1061-L1183
|
||||
if self._HTTPConnection__response \
|
||||
and self._HTTPConnection__response.isclosed():
|
||||
self._HTTPConnection__response = None
|
||||
|
||||
if self._HTTPConnection__state == http_client._CS_IDLE:
|
||||
self._HTTPConnection__state = http_client._CS_REQ_STARTED
|
||||
else:
|
||||
raise http_client.CannotSendRequest(self._HTTPConnection__state)
|
||||
|
||||
self._method = method
|
||||
if not url:
|
||||
url = '/'
|
||||
self._path = url
|
||||
request = '%s %s %s' % (method, url, self._http_vsn_str)
|
||||
if not isinstance(request, bytes):
|
||||
# This choice of encoding is the whole reason we copy/paste from
|
||||
# cpython. When making backend requests, it should never be
|
||||
# necessary; however, we have some functional tests that want
|
||||
# to send non-ascii bytes.
|
||||
# TODO: when https://bugs.python.org/issue36274 is resolved, make
|
||||
# sure we fix up our API to match whatever upstream chooses to do
|
||||
self._output(request.encode('latin1'))
|
||||
else:
|
||||
self._output(request)
|
||||
|
||||
if self._http_vsn == 11:
|
||||
if not skip_host:
|
||||
netloc = ''
|
||||
if url.startswith('http'):
|
||||
nil, netloc, nil, nil, nil = urllib.parse.urlsplit(url)
|
||||
|
||||
if netloc:
|
||||
try:
|
||||
netloc_enc = netloc.encode("ascii")
|
||||
except UnicodeEncodeError:
|
||||
netloc_enc = netloc.encode("idna")
|
||||
self.putheader('Host', netloc_enc)
|
||||
else:
|
||||
if self._tunnel_host:
|
||||
host = self._tunnel_host
|
||||
port = self._tunnel_port
|
||||
else:
|
||||
host = self.host
|
||||
port = self.port
|
||||
|
||||
try:
|
||||
host_enc = host.encode("ascii")
|
||||
except UnicodeEncodeError:
|
||||
host_enc = host.encode("idna")
|
||||
|
||||
if host.find(':') >= 0:
|
||||
host_enc = b'[' + host_enc + b']'
|
||||
|
||||
if port == self.default_port:
|
||||
self.putheader('Host', host_enc)
|
||||
else:
|
||||
host_enc = host_enc.decode("ascii")
|
||||
self.putheader('Host', "%s:%s" % (host_enc, port))
|
||||
|
||||
if not skip_accept_encoding:
|
||||
self.putheader('Accept-Encoding', 'identity')
|
||||
|
||||
|
||||
class Connection(object):
|
||||
def __init__(self, config):
|
||||
for key in 'auth_host auth_port auth_ssl username password'.split():
|
||||
@ -132,6 +217,7 @@ class Connection(object):
|
||||
self.storage_netloc = None
|
||||
self.storage_path = None
|
||||
self.conn_class = None
|
||||
self.connection = None # until you call .http_connect()
|
||||
|
||||
@property
|
||||
def storage_url(self):
|
||||
@ -235,6 +321,7 @@ class Connection(object):
|
||||
context=ssl._create_unverified_context())
|
||||
else:
|
||||
self.connection = self.conn_class(self.storage_netloc)
|
||||
self.connection.putrequest = putrequest.__get__(self.connection)
|
||||
|
||||
def make_path(self, path=None, cfg=None):
|
||||
if path is None:
|
||||
|
Loading…
Reference in New Issue
Block a user