Add http_timeout config option
Otherwise, requests may wait forever for a response. Now, we will wait at most 10 seconds by default, and allow operators to adjust that to between 0 and 60 seconds. This option closely mirrors the http_connect_timeout option in Keystone's authtoken middleware. Change-Id: I43fe784551abe6de790c781d0addfa25519a1f55
This commit is contained in:
@@ -149,6 +149,9 @@ reseller_prefix = AUTH_
|
|||||||
# Keystone server details
|
# Keystone server details
|
||||||
auth_uri = http://keystonehost:35357/
|
auth_uri = http://keystonehost:35357/
|
||||||
|
|
||||||
|
# Connect/read timeout to use when communicating with Keystone
|
||||||
|
http_timeout = 10.0
|
||||||
|
|
||||||
# SSL-related options
|
# SSL-related options
|
||||||
#insecure = False
|
#insecure = False
|
||||||
#certfile =
|
#certfile =
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ class S3Token(object):
|
|||||||
self._app = app
|
self._app = app
|
||||||
self._logger = logging.getLogger(conf.get('log_name', __name__))
|
self._logger = logging.getLogger(conf.get('log_name', __name__))
|
||||||
self._logger.debug('Starting the %s component', PROTOCOL_NAME)
|
self._logger.debug('Starting the %s component', PROTOCOL_NAME)
|
||||||
|
self._timeout = float(conf.get('http_timeout', '10.0'))
|
||||||
|
if not (0 < self._timeout <= 60):
|
||||||
|
raise ValueError('http_timeout must be between 0 and 60 seconds')
|
||||||
self._reseller_prefix = conf.get('reseller_prefix', 'AUTH_')
|
self._reseller_prefix = conf.get('reseller_prefix', 'AUTH_')
|
||||||
# where to find the auth service (we use this to validate tokens)
|
# where to find the auth service (we use this to validate tokens)
|
||||||
|
|
||||||
@@ -119,7 +122,8 @@ class S3Token(object):
|
|||||||
try:
|
try:
|
||||||
response = requests.post('%s/v2.0/s3tokens' % self._request_uri,
|
response = requests.post('%s/v2.0/s3tokens' % self._request_uri,
|
||||||
headers=headers, data=creds_json,
|
headers=headers, data=creds_json,
|
||||||
verify=self._verify)
|
verify=self._verify,
|
||||||
|
timeout=self._timeout)
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
self._logger.info('HTTP connection exception: %s', e)
|
self._logger.info('HTTP connection exception: %s', e)
|
||||||
resp = self._deny_request('InvalidURI')
|
resp = self._deny_request('InvalidURI')
|
||||||
|
|||||||
@@ -255,6 +255,53 @@ class S3TokenMiddlewareTestGood(S3TokenMiddlewareTestBase):
|
|||||||
self.assertEqual('Either auth_uri or auth_host required',
|
self.assertEqual('Either auth_uri or auth_host required',
|
||||||
cm.exception.message)
|
cm.exception.message)
|
||||||
|
|
||||||
|
@mock.patch.object(requests, 'post')
|
||||||
|
def test_http_timeout(self, MOCK_REQUEST):
|
||||||
|
self.middleware = s3_token.filter_factory({
|
||||||
|
'http_timeout': '2',
|
||||||
|
'auth_uri': 'http://example.com',
|
||||||
|
})(FakeApp())
|
||||||
|
|
||||||
|
MOCK_REQUEST.return_value = TestResponse({
|
||||||
|
'status_code': 201,
|
||||||
|
'text': json.dumps(GOOD_RESPONSE)})
|
||||||
|
|
||||||
|
req = Request.blank('/v1/AUTH_cfa/c/o')
|
||||||
|
req.headers['Authorization'] = 'AWS access:signature'
|
||||||
|
req.headers['X-Storage-Token'] = 'token'
|
||||||
|
req.get_response(self.middleware)
|
||||||
|
|
||||||
|
self.assertTrue(MOCK_REQUEST.called)
|
||||||
|
mock_args, mock_kwargs = MOCK_REQUEST.call_args
|
||||||
|
self.assertEqual(mock_kwargs['timeout'], 2)
|
||||||
|
|
||||||
|
def test_http_timeout_option(self):
|
||||||
|
good_values = ['1', '5.3', '10', '.001']
|
||||||
|
for val in good_values:
|
||||||
|
middleware = s3_token.filter_factory({
|
||||||
|
'http_timeout': val,
|
||||||
|
'auth_uri': 'http://example.com',
|
||||||
|
})(FakeApp())
|
||||||
|
self.assertEqual(float(val), middleware._timeout)
|
||||||
|
|
||||||
|
bad_values = ['1, 4', '-3', '100', 'foo', '0']
|
||||||
|
for val in bad_values:
|
||||||
|
with self.assertRaises(ValueError) as ctx:
|
||||||
|
s3_token.filter_factory({
|
||||||
|
'http_timeout': val,
|
||||||
|
'auth_uri': 'http://example.com',
|
||||||
|
})(FakeApp())
|
||||||
|
self.assertTrue(ctx.exception.args[0].startswith((
|
||||||
|
'invalid literal for float():',
|
||||||
|
'could not convert string to float:',
|
||||||
|
'http_timeout must be between 0 and 60 seconds',
|
||||||
|
)), 'Unexpected error message: %s' % ctx.exception)
|
||||||
|
|
||||||
|
# default is 10 seconds
|
||||||
|
middleware = s3_token.filter_factory({
|
||||||
|
'auth_uri': 'http://example.com'})(FakeApp())
|
||||||
|
self.assertEqual(10, middleware._timeout)
|
||||||
|
|
||||||
def test_unicode_path(self):
|
def test_unicode_path(self):
|
||||||
url = u'/v1/AUTH_cfa/c/euro\u20ac'.encode('utf8')
|
url = u'/v1/AUTH_cfa/c/euro\u20ac'.encode('utf8')
|
||||||
req = Request.blank(urllib.parse.quote(url))
|
req = Request.blank(urllib.parse.quote(url))
|
||||||
|
|||||||
Reference in New Issue
Block a user