Skip to content

Commit edb2014

Browse files
authored
Add extra_headers after signature (#1242)
Per documentation, adding extra_headers is intended for proxies that strip them, so they should be added after signature. Fixes #1241.
1 parent 0a4ce93 commit edb2014

File tree

3 files changed

+25
-8
lines changed

3 files changed

+25
-8
lines changed

pynamodb/connection/base.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -331,10 +331,9 @@ def send_pre_boto_callback(self, operation_name, req_uuid, table_name):
331331
except Exception:
332332
log.exception("pre_boto callback threw an exception.")
333333

334-
def _before_sign(self, request, **_) -> None:
334+
def _before_send(self, request, **_) -> None:
335335
if self._extra_headers is not None:
336-
for k, v in self._extra_headers.items():
337-
request.headers.add_header(k, v)
336+
request.headers.update(self._extra_headers)
338337

339338
def _make_api_call(self, operation_name: str, operation_kwargs: Dict) -> Dict:
340339
try:
@@ -412,7 +411,7 @@ def client(self) -> BotocoreBaseClientPrivate:
412411
)
413412
self._client = cast(BotocoreBaseClientPrivate, self.session.create_client(SERVICE_NAME, self.region, endpoint_url=self.host, config=config))
414413

415-
self._client.meta.events.register_first('before-sign.*.*', self._before_sign)
414+
self._client.meta.events.register_first('before-send.*.*', self._before_send)
416415
return self._client
417416

418417
def add_meta_table(self, meta_table: MetaTable) -> None:

requirements-dev.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pytest>=6
22
pytest-env
33
pytest-mock
4+
freezegun
45

56
# only used in CI
67
coveralls

tests/test_base_connection.py

+21-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
"""
44
import base64
55
import json
6+
from datetime import datetime
7+
from uuid import UUID
8+
69
import urllib3
710
from unittest import mock
811
from unittest.mock import patch
@@ -13,6 +16,7 @@
1316
from botocore.exceptions import BotoCoreError
1417

1518
import pytest
19+
from freezegun import freeze_time
1620

1721
from pynamodb.connection import Connection
1822
from pynamodb.connection.base import MetaTable
@@ -1515,11 +1519,13 @@ def test_connection__botocore_config():
15151519
assert c.client._client_config.max_pool_connections == 20
15161520

15171521

1518-
@mock.patch('botocore.httpsession.URLLib3Session.send')
1519-
def test_connection_make_api_call___extra_headers(send_mock):
1522+
@freeze_time()
1523+
def test_connection_make_api_call___extra_headers(mocker):
15201524
good_response = mock.Mock(spec=AWSResponse, status_code=200, headers={}, text='{}', content=b'{}')
1525+
send_mock = mocker.patch('botocore.httpsession.URLLib3Session.send', return_value=good_response)
15211526

1522-
send_mock.return_value = good_response
1527+
# return constant UUID
1528+
mocker.patch('uuid.uuid4', return_value=UUID('01FC4BDB-B223-4B86-88F4-DEE79B77F275'))
15231529

15241530
c = Connection(extra_headers={'foo': 'bar'}, max_retry_attempts=0)
15251531
c._make_api_call(
@@ -1529,7 +1535,18 @@ def test_connection_make_api_call___extra_headers(send_mock):
15291535

15301536
assert send_mock.call_count == 1
15311537
request = send_mock.call_args[0][0]
1532-
assert request.headers.get('foo').decode() == 'bar'
1538+
assert request.headers['foo'] == 'bar'
1539+
1540+
c = Connection(extra_headers={'foo': 'baz'}, max_retry_attempts=0)
1541+
c._make_api_call(
1542+
'DescribeTable',
1543+
{'TableName': 'MyTable'},
1544+
)
1545+
1546+
assert send_mock.call_count == 2
1547+
request2 = send_mock.call_args[0][0]
1548+
# all headers, including signatures, and except 'foo', should match
1549+
assert {**request.headers, 'foo': ''} == {**request2.headers, 'foo': ''}
15331550

15341551

15351552
@mock.patch('botocore.httpsession.URLLib3Session.send')

0 commit comments

Comments
 (0)