Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2243529

Browse files
i-maravicJon Wayne Parrott
authored and
Jon Wayne Parrott
committed
Set default HTTP timeout of 60s (googleapis#320)
1 parent 811d570 commit 2243529

File tree

8 files changed

+105
-23
lines changed

8 files changed

+105
-23
lines changed

describe.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
from googleapiclient.discovery import build
3535
from googleapiclient.discovery import build_from_document
3636
from googleapiclient.discovery import UnknownApiNameOrVersion
37-
import httplib2
37+
from googleapiclient.http import build_http
3838
import uritemplate
3939

4040
CSS = """<style>
@@ -346,6 +346,7 @@ def document_api(name, version):
346346
print 'Warning: {} {} found but could not be built.'.format(name, version)
347347
return
348348

349+
http = build_http()
349350
response, content = http.request(
350351
uritemplate.expand(
351352
FLAGS.discovery_uri_template, {
@@ -366,7 +367,7 @@ def document_api_from_discovery_document(uri):
366367
Args:
367368
uri: string, URI of discovery document.
368369
"""
369-
http = httplib2.Http()
370+
http = build_http()
370371
response, content = http.request(FLAGS.discovery_uri)
371372
discovery = json.loads(content)
372373

@@ -384,7 +385,7 @@ def document_api_from_discovery_document(uri):
384385
if FLAGS.discovery_uri:
385386
document_api_from_discovery_document(FLAGS.discovery_uri)
386387
else:
387-
http = httplib2.Http()
388+
http = build_http()
388389
resp, content = http.request(
389390
FLAGS.directory_uri,
390391
headers={'X-User-IP': '0.0.0.0'})

googleapiclient/_auth.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414

1515
"""Helpers for authentication using oauth2client or google-auth."""
1616

17-
import httplib2
18-
1917
try:
2018
import google.auth
2119
import google.auth.credentials
@@ -31,6 +29,8 @@
3129
except ImportError: # pragma: NO COVER
3230
HAS_OAUTH2CLIENT = False
3331

32+
from googleapiclient.http import build_http
33+
3434

3535
def default_credentials():
3636
"""Returns Application Default Credentials."""
@@ -86,6 +86,7 @@ def authorized_http(credentials):
8686
"""
8787
if HAS_GOOGLE_AUTH and isinstance(
8888
credentials, google.auth.credentials.Credentials):
89-
return google_auth_httplib2.AuthorizedHttp(credentials)
89+
return google_auth_httplib2.AuthorizedHttp(credentials,
90+
http=build_http())
9091
else:
91-
return credentials.authorize(httplib2.Http())
92+
return credentials.authorize(build_http())

googleapiclient/discovery.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
from googleapiclient.errors import UnacceptableMimeTypeError
6262
from googleapiclient.errors import UnknownApiNameOrVersion
6363
from googleapiclient.errors import UnknownFileType
64+
from googleapiclient.http import build_http
6465
from googleapiclient.http import BatchHttpRequest
6566
from googleapiclient.http import HttpMock
6667
from googleapiclient.http import HttpMockSequence
@@ -97,6 +98,7 @@
9798
'version={apiVersion}')
9899
DEFAULT_METHOD_DOC = 'A description of how to use this function'
99100
HTTP_PAYLOAD_METHODS = frozenset(['PUT', 'POST', 'PATCH'])
101+
100102
_MEDIA_SIZE_BIT_SHIFTS = {'KB': 10, 'MB': 20, 'GB': 30, 'TB': 40}
101103
BODY_PARAMETER_DEFAULT_VALUE = {
102104
'description': 'The request body.',
@@ -213,7 +215,10 @@ def build(serviceName,
213215
'apiVersion': version
214216
}
215217

216-
discovery_http = http if http is not None else httplib2.Http()
218+
if http is None:
219+
discovery_http = build_http()
220+
else:
221+
discovery_http = http
217222

218223
for discovery_url in (discoveryServiceUrl, V2_DISCOVERY_URI,):
219224
requested_url = uritemplate.expand(discovery_url, params)
@@ -366,7 +371,7 @@ def build_from_document(
366371
# If the service doesn't require scopes then there is no need for
367372
# authentication.
368373
else:
369-
http = httplib2.Http()
374+
http = build_http()
370375

371376
if model is None:
372377
features = service.get('features', [])

googleapiclient/http.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@
8080

8181
_TOO_MANY_REQUESTS = 429
8282

83+
DEFAULT_HTTP_TIMEOUT_SEC = 60
84+
8385

8486
def _should_retry_response(resp_status, content):
8587
"""Determines whether a response should be retried.
@@ -1732,3 +1734,21 @@ def new_request(uri, method='GET', body=None, headers=None,
17321734

17331735
http.request = new_request
17341736
return http
1737+
1738+
1739+
def build_http():
1740+
"""Builds httplib2.Http object
1741+
1742+
Returns:
1743+
A httplib2.Http object, which is used to make http requests, and which has timeout set by default.
1744+
To override default timeout call
1745+
1746+
socket.setdefaulttimeout(timeout_in_sec)
1747+
1748+
before interacting with this method.
1749+
"""
1750+
if socket.getdefaulttimeout() is not None:
1751+
http_timeout = socket.getdefaulttimeout()
1752+
else:
1753+
http_timeout = DEFAULT_HTTP_TIMEOUT_SEC
1754+
return httplib2.Http(timeout=http_timeout)

googleapiclient/sample_tools.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@
2323

2424

2525
import argparse
26-
import httplib2
2726
import os
2827

2928
from googleapiclient import discovery
29+
from googleapiclient.http import build_http
3030
from oauth2client import client
3131
from oauth2client import file
3232
from oauth2client import tools
@@ -88,7 +88,7 @@ def init(argv, name, version, doc, filename, scope=None, parents=[], discovery_f
8888
credentials = storage.get()
8989
if credentials is None or credentials.invalid:
9090
credentials = tools.run_flow(flow, storage, flags)
91-
http = credentials.authorize(http = httplib2.Http())
91+
http = credentials.authorize(http=build_http())
9292

9393
if discovery_filename is None:
9494
# Construct a service object via the discovery service.

tests/test__auth.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,13 @@ class CredentialsWithScopes(
6666
def test_authorized_http(self):
6767
credentials = mock.Mock(spec=google.auth.credentials.Credentials)
6868

69-
http = _auth.authorized_http(credentials)
69+
authorized_http = _auth.authorized_http(credentials)
7070

71-
self.assertIsInstance(http, google_auth_httplib2.AuthorizedHttp)
72-
self.assertEqual(http.credentials, credentials)
71+
self.assertIsInstance(authorized_http, google_auth_httplib2.AuthorizedHttp)
72+
self.assertEqual(authorized_http.credentials, credentials)
73+
self.assertIsInstance(authorized_http.http, httplib2.Http)
74+
self.assertIsInstance(authorized_http.http.timeout, int)
75+
self.assertGreater(authorized_http.http.timeout, 0)
7376

7477

7578
class TestAuthWithOAuth2Client(unittest2.TestCase):
@@ -112,11 +115,14 @@ def test_with_scopes_scoped(self):
112115
def test_authorized_http(self):
113116
credentials = mock.Mock(spec=oauth2client.client.Credentials)
114117

115-
http = _auth.authorized_http(credentials)
118+
authorized_http = _auth.authorized_http(credentials)
116119

117-
self.assertEqual(http, credentials.authorize.return_value)
118-
self.assertIsInstance(
119-
credentials.authorize.call_args[0][0], httplib2.Http)
120+
http = credentials.authorize.call_args[0][0]
121+
122+
self.assertEqual(authorized_http, credentials.authorize.return_value)
123+
self.assertIsInstance(http, httplib2.Http)
124+
self.assertIsInstance(http.timeout, int)
125+
self.assertGreater(http.timeout, 0)
120126

121127

122128
class TestAuthWithoutAuth(unittest2.TestCase):

tests/test_discovery.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
from googleapiclient.errors import UnacceptableMimeTypeError
6666
from googleapiclient.errors import UnknownApiNameOrVersion
6767
from googleapiclient.errors import UnknownFileType
68+
from googleapiclient.http import build_http
6869
from googleapiclient.http import BatchHttpRequest
6970
from googleapiclient.http import HttpMock
7071
from googleapiclient.http import HttpMockSequence
@@ -402,13 +403,32 @@ def test_building_with_base_remembers_base(self):
402403
discovery, base=base, credentials=self.MOCK_CREDENTIALS)
403404
self.assertEquals("https://www.googleapis.com/plus/v1/", plus._baseUrl)
404405

405-
def test_building_with_optional_http(self):
406+
def test_building_with_optional_http_with_authorization(self):
406407
discovery = open(datafile('plus.json')).read()
407408
plus = build_from_document(
408409
discovery, base="https://www.googleapis.com/",
409410
credentials=self.MOCK_CREDENTIALS)
410-
self.assertIsInstance(
411-
plus._http, (httplib2.Http, google_auth_httplib2.AuthorizedHttp))
411+
412+
# plus service requires Authorization, hence we expect to see AuthorizedHttp object here
413+
self.assertIsInstance(plus._http, google_auth_httplib2.AuthorizedHttp)
414+
self.assertIsInstance(plus._http.http, httplib2.Http)
415+
self.assertIsInstance(plus._http.http.timeout, int)
416+
self.assertGreater(plus._http.http.timeout, 0)
417+
418+
def test_building_with_optional_http_with_no_authorization(self):
419+
discovery = open(datafile('plus.json')).read()
420+
# Cleanup auth field, so we would use plain http client
421+
discovery = json.loads(discovery)
422+
discovery['auth'] = {}
423+
discovery = json.dumps(discovery)
424+
425+
plus = build_from_document(
426+
discovery, base="https://www.googleapis.com/",
427+
credentials=self.MOCK_CREDENTIALS)
428+
# plus service requires Authorization
429+
self.assertIsInstance(plus._http, httplib2.Http)
430+
self.assertIsInstance(plus._http.timeout, int)
431+
self.assertGreater(plus._http.timeout, 0)
412432

413433
def test_building_with_explicit_http(self):
414434
http = HttpMock()
@@ -1316,7 +1336,7 @@ def _dummy_zoo_request(self):
13161336
zoo_uri = util._add_query_parameter(zoo_uri, 'userIp',
13171337
os.environ['REMOTE_ADDR'])
13181338

1319-
http = httplib2.Http()
1339+
http = build_http()
13201340
original_request = http.request
13211341
def wrapped_request(uri, method='GET', *args, **kwargs):
13221342
if uri == zoo_uri:

tests/test_http.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
from googleapiclient.errors import BatchError
4444
from googleapiclient.errors import HttpError
4545
from googleapiclient.errors import InvalidChunkSizeError
46+
from googleapiclient.http import build_http
4647
from googleapiclient.http import BatchHttpRequest
4748
from googleapiclient.http import HttpMock
4849
from googleapiclient.http import HttpMockSequence
@@ -235,7 +236,7 @@ def test_http_request_to_from_json(self):
235236
def _postproc(*kwargs):
236237
pass
237238

238-
http = httplib2.Http()
239+
http = build_http()
239240
media_upload = MediaFileUpload(
240241
datafile('small.png'), chunksize=500, resumable=True)
241242
req = HttpRequest(
@@ -1341,6 +1342,34 @@ def test_error_response(self):
13411342
self.assertRaises(HttpError, request.execute)
13421343

13431344

1345+
class TestHttpBuild(unittest.TestCase):
1346+
original_socket_default_timeout = None
1347+
1348+
@classmethod
1349+
def setUpClass(cls):
1350+
cls.original_socket_default_timeout = socket.getdefaulttimeout()
1351+
1352+
@classmethod
1353+
def tearDownClass(cls):
1354+
socket.setdefaulttimeout(cls.original_socket_default_timeout)
1355+
1356+
def test_build_http_sets_default_timeout_if_none_specified(self):
1357+
socket.setdefaulttimeout(None)
1358+
http = build_http()
1359+
self.assertIsInstance(http.timeout, int)
1360+
self.assertGreater(http.timeout, 0)
1361+
1362+
def test_build_http_default_timeout_can_be_overridden(self):
1363+
socket.setdefaulttimeout(1.5)
1364+
http = build_http()
1365+
self.assertAlmostEqual(http.timeout, 1.5, delta=0.001)
1366+
1367+
def test_build_http_default_timeout_can_be_set_to_zero(self):
1368+
socket.setdefaulttimeout(0)
1369+
http = build_http()
1370+
self.assertEquals(http.timeout, 0)
1371+
1372+
13441373
if __name__ == '__main__':
13451374
logging.getLogger().setLevel(logging.ERROR)
13461375
unittest.main()

0 commit comments

Comments
 (0)