Skip to content

Commit 23174be

Browse files
GarciatGabriel Garcia
authored andcommitted
Refresh empty OAuth2 credentials in batch request
Batch request serialization requires the credentials in the http object to be applied to every individual request *prior* to actually invoking http.request(). This circumvents the self-refresh logic in the request() function monkey-patched by the OAuth2 credentials, thus resulting in the use of an uninitialized credentials object. The fix here is to detect when OAuth2-like credentials are being used and to force a refresh in case the access token is not initialized yet. Resolves: #211
1 parent 08357b2 commit 23174be

File tree

2 files changed

+36
-0
lines changed

2 files changed

+36
-0
lines changed

googleapiclient/http.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,6 +1394,14 @@ def execute(self, http=None):
13941394
if http is None:
13951395
raise ValueError("Missing a valid http object.")
13961396

1397+
# Special case for OAuth2Credentials-style objects which have not yet been
1398+
# refreshed with an initial access_token.
1399+
if getattr(http.request, 'credentials', None) is not None:
1400+
creds = http.request.credentials
1401+
if not getattr(creds, 'access_token', None):
1402+
LOGGER.info('Attempting refresh to obtain initial access_token')
1403+
creds.refresh(http)
1404+
13971405
self._execute(http, self._order, self._requests)
13981406

13991407
# Loop over all the requests and check for 401s. For each 401 request the

tests/test_http.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,34 @@ def test_execute_request_body(self):
10721072
header = parts[1].splitlines()[1]
10731073
self.assertEqual('Content-Type: application/http', header)
10741074

1075+
def test_execute_initial_refresh_oauth2(self):
1076+
batch = BatchHttpRequest()
1077+
callbacks = Callbacks()
1078+
cred = MockCredentials('Foo')
1079+
1080+
# Pretend this is a OAuth2Credentials object
1081+
cred.access_token = None
1082+
1083+
http = HttpMockSequence([
1084+
({'status': '200',
1085+
'content-type': 'multipart/mixed; boundary="batch_foobarbaz"'},
1086+
BATCH_SINGLE_RESPONSE),
1087+
])
1088+
1089+
cred.authorize(http)
1090+
1091+
batch.add(self.request1, callback=callbacks.f)
1092+
batch.execute(http=http)
1093+
1094+
self.assertEqual({'foo': 42}, callbacks.responses['1'])
1095+
self.assertIsNone(callbacks.exceptions['1'])
1096+
1097+
self.assertEqual(1, cred._refreshed)
1098+
1099+
self.assertEqual(1, cred._authorized)
1100+
1101+
self.assertEqual(1, cred._applied)
1102+
10751103
def test_execute_refresh_and_retry_on_401(self):
10761104
batch = BatchHttpRequest()
10771105
callbacks = Callbacks()

0 commit comments

Comments
 (0)