mirror of
https://github.com/certbot/certbot.git
synced 2026-08-02 00:22:28 +02:00
Merge pull request #4113 from certbot/auto-retry
Automatically retry after getting badNonce error
This commit is contained in:
+19
-2
@@ -674,8 +674,25 @@ class ClientNetwork(object): # pylint: disable=too-many-instance-attributes
|
|||||||
self._add_nonce(self.head(url))
|
self._add_nonce(self.head(url))
|
||||||
return self._nonces.pop()
|
return self._nonces.pop()
|
||||||
|
|
||||||
def post(self, url, obj, content_type=JOSE_CONTENT_TYPE, **kwargs):
|
def post(self, *args, **kwargs):
|
||||||
"""POST object wrapped in `.JWS` and check response."""
|
"""POST object wrapped in `.JWS` and check response.
|
||||||
|
|
||||||
|
If the server responded with a badNonce error, the request will
|
||||||
|
be retried once.
|
||||||
|
|
||||||
|
"""
|
||||||
|
should_retry = True
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
return self._post_once(*args, **kwargs)
|
||||||
|
except messages.Error as error:
|
||||||
|
if should_retry and error.code == 'badNonce':
|
||||||
|
logger.debug('Retrying request after error:\n%s', error)
|
||||||
|
should_retry = False
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
def _post_once(self, url, obj, content_type=JOSE_CONTENT_TYPE, **kwargs):
|
||||||
data = self._wrap_in_jws(obj, self._get_nonce(url))
|
data = self._wrap_in_jws(obj, self._get_nonce(url))
|
||||||
kwargs.setdefault('headers', {'Content-Type': content_type})
|
kwargs.setdefault('headers', {'Content-Type': content_type})
|
||||||
response = self._send_request('POST', url, data=data, **kwargs)
|
response = self._send_request('POST', url, data=data, **kwargs)
|
||||||
|
|||||||
@@ -642,7 +642,9 @@ class ClientNetworkWithMockedResponseTest(unittest.TestCase):
|
|||||||
self.wrapped_obj = mock.MagicMock()
|
self.wrapped_obj = mock.MagicMock()
|
||||||
self.content_type = mock.sentinel.content_type
|
self.content_type = mock.sentinel.content_type
|
||||||
|
|
||||||
self.all_nonces = [jose.b64encode(b'Nonce'), jose.b64encode(b'Nonce2')]
|
self.all_nonces = [
|
||||||
|
jose.b64encode(b'Nonce'),
|
||||||
|
jose.b64encode(b'Nonce2'), jose.b64encode(b'Nonce3')]
|
||||||
self.available_nonces = self.all_nonces[:]
|
self.available_nonces = self.all_nonces[:]
|
||||||
|
|
||||||
def send_request(*args, **kwargs):
|
def send_request(*args, **kwargs):
|
||||||
@@ -690,7 +692,7 @@ class ClientNetworkWithMockedResponseTest(unittest.TestCase):
|
|||||||
self.net._wrap_in_jws.assert_called_once_with(
|
self.net._wrap_in_jws.assert_called_once_with(
|
||||||
self.obj, jose.b64decode(self.all_nonces.pop()))
|
self.obj, jose.b64decode(self.all_nonces.pop()))
|
||||||
|
|
||||||
assert not self.available_nonces
|
self.available_nonces = []
|
||||||
self.assertRaises(errors.MissingNonce, self.net.post,
|
self.assertRaises(errors.MissingNonce, self.net.post,
|
||||||
'uri', self.obj, content_type=self.content_type)
|
'uri', self.obj, content_type=self.content_type)
|
||||||
self.net._wrap_in_jws.assert_called_with(
|
self.net._wrap_in_jws.assert_called_with(
|
||||||
@@ -706,6 +708,25 @@ class ClientNetworkWithMockedResponseTest(unittest.TestCase):
|
|||||||
self.assertRaises(errors.BadNonce, self.net.post, 'uri',
|
self.assertRaises(errors.BadNonce, self.net.post, 'uri',
|
||||||
self.obj, content_type=self.content_type)
|
self.obj, content_type=self.content_type)
|
||||||
|
|
||||||
|
def test_post_failed_retry(self):
|
||||||
|
check_response = mock.MagicMock()
|
||||||
|
check_response.side_effect = messages.Error.with_code('badNonce')
|
||||||
|
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
self.net._check_response = check_response
|
||||||
|
self.assertRaises(messages.Error, self.net.post, 'uri',
|
||||||
|
self.obj, content_type=self.content_type)
|
||||||
|
|
||||||
|
def test_post_successful_retry(self):
|
||||||
|
check_response = mock.MagicMock()
|
||||||
|
check_response.side_effect = [messages.Error.with_code('badNonce'),
|
||||||
|
self.checked_response]
|
||||||
|
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
self.net._check_response = check_response
|
||||||
|
self.assertEqual(self.checked_response, self.net.post(
|
||||||
|
'uri', self.obj, content_type=self.content_type))
|
||||||
|
|
||||||
def test_head_get_post_error_passthrough(self):
|
def test_head_get_post_error_passthrough(self):
|
||||||
self.send_request.side_effect = requests.exceptions.RequestException
|
self.send_request.side_effect = requests.exceptions.RequestException
|
||||||
for method in self.net.head, self.net.get:
|
for method in self.net.head, self.net.get:
|
||||||
|
|||||||
Reference in New Issue
Block a user