From 14f47d34d6881f2c4f213e3408413cd5b21f71c6 Mon Sep 17 00:00:00 2001 From: kyleknap Date: Tue, 16 Sep 2014 15:48:04 -0700 Subject: Fixed 403 error from url encoded User-Agent header The User-Agent header value had spaces in it which became url encoded. This caused the header value to differ from actual non-url encoded value in the sigv4 canonical request. --- boto/connection.py | 3 ++- tests/unit/test_connection.py | 27 ++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/boto/connection.py b/boto/connection.py index 8640ec48..a542636a 100644 --- a/boto/connection.py +++ b/boto/connection.py @@ -372,9 +372,10 @@ class HTTPRequest(object): self.headers[key] = quote(val.encode('utf-8'), safe) setattr(self, '_headers_quoted', True) + self.headers['User-Agent'] = UserAgent + connection._auth_handler.add_auth(self, **kwargs) - self.headers['User-Agent'] = UserAgent # I'm not sure if this is still needed, now that add_auth is # setting the content-length for POST requests. if 'Content-Length' not in self.headers: diff --git a/tests/unit/test_connection.py b/tests/unit/test_connection.py index 97514361..89c1186c 100644 --- a/tests/unit/test_connection.py +++ b/tests/unit/test_connection.py @@ -25,8 +25,9 @@ import socket from tests.compat import mock, unittest from httpretty import HTTPretty +from boto import UserAgent from boto.compat import json, parse_qs -from boto.connection import AWSQueryConnection, AWSAuthConnection +from boto.connection import AWSQueryConnection, AWSAuthConnection, HTTPRequest from boto.exception import BotoServerError from boto.regioninfo import RegionInfo @@ -473,5 +474,29 @@ class TestAWSQueryStatus(TestAWSQueryConnection): {'par1': 'foo', 'par2': 'baz'}, 'status') + +class TestHTTPRequest(unittest.TestCase): + def test_user_agent_not_url_encoded(self): + headers = {'Some-Header': u'should be url encoded', + 'User-Agent': UserAgent} + request = HTTPRequest('PUT', 'https', 'amazon.com', 443, None, + None, {}, headers, 'Body') + mock_connection = mock.Mock() + + # Create a method that preserves the headers at the time of + # authorization. + def mock_add_auth(req, **kwargs): + mock_connection.headers_at_auth = req.headers.copy() + + mock_connection._auth_handler.add_auth = mock_add_auth + + request.authorize(mock_connection) + # Ensure the headers at authorization are as expected i.e. + # the user agent header was not url encoded but the other header was. + self.assertEqual(mock_connection.headers_at_auth, + {'Some-Header': 'should%20be%20url%20encoded', + 'User-Agent': UserAgent}) + + if __name__ == '__main__': unittest.main() -- cgit v1.2.1