125 lines
5.1 KiB
Diff
125 lines
5.1 KiB
Diff
diff --git a/awscli/botocore/awsrequest.py b/awscli/botocore/awsrequest.py
|
|
index 4ce0449..2b14009 100644
|
|
--- a/awscli/botocore/awsrequest.py
|
|
+++ b/awscli/botocore/awsrequest.py
|
|
@@ -14,6 +14,7 @@
|
|
import functools
|
|
import io
|
|
import logging
|
|
+from collections.abc import Mapping
|
|
import socket
|
|
import sys
|
|
|
|
@@ -24,6 +25,7 @@ from botocore.compat import (
|
|
HTTPResponse,
|
|
MutableMapping,
|
|
urlencode,
|
|
+ urlparse,
|
|
urlsplit,
|
|
urlunsplit,
|
|
)
|
|
@@ -66,32 +68,34 @@ class AWSConnection:
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self._original_response_cls = self.response_class
|
|
- # We'd ideally hook into httplib's states, but they're all
|
|
- # __mangled_vars so we use our own state var. This variable is set
|
|
- # when we receive an early response from the server. If this value is
|
|
- # set to True, any calls to send() are noops. This value is reset to
|
|
- # false every time _send_request is called. This is to workaround the
|
|
- # fact that py2.6 (and only py2.6) has a separate send() call for the
|
|
- # body in _send_request, as opposed to endheaders(), which is where the
|
|
- # body is sent in all versions > 2.6.
|
|
+ # This variable is set when we receive an early response from the
|
|
+ # server. If this value is set to True, any calls to send() are noops.
|
|
+ # This value is reset to false every time _send_request is called.
|
|
+ # This is to workaround changes in urllib3 2.0 which uses separate
|
|
+ # send() calls in request() instead of delegating to endheaders(),
|
|
+ # which is where the body is sent in CPython's HTTPConnection.
|
|
self._response_received = False
|
|
self._expect_header_set = False
|
|
+ self._send_called = False
|
|
|
|
def close(self):
|
|
super().close()
|
|
# Reset all of our instance state we were tracking.
|
|
self._response_received = False
|
|
self._expect_header_set = False
|
|
+ self._send_called = False
|
|
self.response_class = self._original_response_cls
|
|
|
|
- def _send_request(self, method, url, body, headers, *args, **kwargs):
|
|
+ def request(self, method, url, body=None, headers=None, *args, **kwargs):
|
|
+ if headers is None:
|
|
+ headers = {}
|
|
self._response_received = False
|
|
if headers.get('Expect', b'') == b'100-continue':
|
|
self._expect_header_set = True
|
|
else:
|
|
self._expect_header_set = False
|
|
self.response_class = self._original_response_cls
|
|
- rval = super()._send_request(
|
|
+ rval = super().request(
|
|
method, url, body, headers, *args, **kwargs
|
|
)
|
|
self._expect_header_set = False
|
|
@@ -210,10 +214,13 @@ class AWSConnection:
|
|
|
|
def send(self, str):
|
|
if self._response_received:
|
|
- logger.debug(
|
|
- "send() called, but reseponse already received. "
|
|
- "Not sending data."
|
|
- )
|
|
+ if not self._send_called:
|
|
+ # urllib3 2.0 chunks and calls send potentially
|
|
+ # thousands of times inside `request` unlike the
|
|
+ # standard library. Only log this once for sanity.
|
|
+ logger.debug("send() called, but reseponse already received. "
|
|
+ "Not sending data.")
|
|
+ self._send_called = True
|
|
return
|
|
return super().send(str)
|
|
|
|
@@ -370,8 +377,14 @@ class AWSRequestPreparer:
|
|
def _prepare_url(self, original):
|
|
url = original.url
|
|
if original.params:
|
|
- params = urlencode(list(original.params.items()), doseq=True)
|
|
- url = f'{url}?{params}'
|
|
+ url_parts = urlparse(url)
|
|
+ delim = '&' if url_parts.query else '?'
|
|
+ if isinstance(original.params, Mapping):
|
|
+ params_to_encode = list(original.params.items())
|
|
+ else:
|
|
+ params_to_encode = original.params
|
|
+ params = urlencode(params_to_encode, doseq=True)
|
|
+ url = delim.join((url, params))
|
|
return url
|
|
|
|
def _prepare_headers(self, original, prepared_body=None):
|
|
diff --git a/awscli/botocore/httpsession.py b/awscli/botocore/httpsession.py
|
|
index 516bb3f..25f982d 100644
|
|
--- a/awscli/botocore/httpsession.py
|
|
+++ b/awscli/botocore/httpsession.py
|
|
@@ -328,7 +328,6 @@ class URLLib3Session:
|
|
|
|
def _get_pool_manager_kwargs(self, **extra_kwargs):
|
|
pool_manager_kwargs = {
|
|
- 'strict': True,
|
|
'timeout': self._timeout,
|
|
'maxsize': self._max_pool_connections,
|
|
'ssl_context': self._get_ssl_context(),
|
|
diff --git a/tests/unit/botocore/test_http_session.py b/tests/unit/botocore/test_http_session.py
|
|
index 90ed7d4..0a10c15 100644
|
|
--- a/tests/unit/botocore/test_http_session.py
|
|
+++ b/tests/unit/botocore/test_http_session.py
|
|
@@ -148,7 +148,6 @@ class TestURLLib3Session(unittest.TestCase):
|
|
|
|
def _assert_manager_call(self, manager, *assert_args, **assert_kwargs):
|
|
call_kwargs = {
|
|
- 'strict': True,
|
|
'maxsize': mock.ANY,
|
|
'timeout': mock.ANY,
|
|
'ssl_context': mock.ANY,
|