diff --git a/acme/acme/client.py b/acme/acme/client.py index 4c89458fb..0e9319f9c 100644 --- a/acme/acme/client.py +++ b/acme/acme/client.py @@ -481,11 +481,13 @@ class ClientNetwork(object): JSON_ERROR_CONTENT_TYPE = 'application/problem+json' REPLAY_NONCE_HEADER = 'Replay-Nonce' - def __init__(self, key, alg=jose.RS256, verify_ssl=True): + def __init__(self, key, alg=jose.RS256, verify_ssl=True, + user_agent='acme-python'): self.key = key self.alg = alg self.verify_ssl = verify_ssl self._nonces = set() + self.user_agent = user_agent def _wrap_in_jws(self, obj, nonce): """Wrap `JSONDeSerializable` object in JWS. @@ -578,6 +580,8 @@ class ClientNetwork(object): logging.debug('Sending %s request to %s. args: %r, kwargs: %r', method, url, args, kwargs) kwargs['verify'] = self.verify_ssl + kwargs.setdefault('headers', {}) + kwargs['headers'].setdefault('User-Agent', self.user_agent) response = requests.request(method, url, *args, **kwargs) logging.debug('Received %s. Headers: %s. Content: %r', response, response.headers, response.content) diff --git a/acme/acme/client_test.py b/acme/acme/client_test.py index 7e895218c..2df7b5313 100644 --- a/acme/acme/client_test.py +++ b/acme/acme/client_test.py @@ -396,7 +396,8 @@ class ClientNetworkTest(unittest.TestCase): from acme.client import ClientNetwork self.net = ClientNetwork( - key=KEY, alg=jose.RS256, verify_ssl=self.verify_ssl) + key=KEY, alg=jose.RS256, verify_ssl=self.verify_ssl, + user_agent='acme-python-test') self.response = mock.MagicMock(ok=True, status_code=http_client.OK) self.response.headers = {} @@ -479,7 +480,7 @@ class ClientNetworkTest(unittest.TestCase): self.assertEqual(self.response, self.net._send_request( 'HEAD', 'url', 'foo', bar='baz')) mock_requests.request.assert_called_once_with( - 'HEAD', 'url', 'foo', verify=mock.ANY, bar='baz') + 'HEAD', 'url', 'foo', verify=mock.ANY, bar='baz', headers=mock.ANY) @mock.patch('acme.client.requests') def test_send_request_verify_ssl(self, mock_requests): @@ -492,7 +493,20 @@ class ClientNetworkTest(unittest.TestCase): self.assertEqual( self.response, self.net._send_request('GET', 'url')) mock_requests.request.assert_called_once_with( - 'GET', 'url', verify=verify) + 'GET', 'url', verify=verify, headers=mock.ANY) + + @mock.patch('acme.client.requests') + def test_send_request_user_agent(self, mock_requests): + mock_requests.request.return_value = self.response + # pylint: disable=protected-access + self.net._send_request('GET', 'url', headers={'bar': 'baz'}) + mock_requests.request.assert_called_once_with( + 'GET', 'url', verify=mock.ANY, + headers={'User-Agent': 'acme-python-test', 'bar': 'baz'}) + + self.net._send_request('GET', 'url', headers={'User-Agent': 'foo2'}) + mock_requests.request.assert_called_with( + 'GET', 'url', verify=mock.ANY, headers={'User-Agent': 'foo2'}) @mock.patch('acme.client.requests') def test_requests_error_passthrough(self, mock_requests):