22
22
'use strict' ;
23
23
24
24
var events = require ( 'events' ) ;
25
+ var extend = require ( 'extend' ) ;
25
26
var fs = require ( 'fs' ) ;
26
27
var GAPIToken = require ( 'gapitoken' ) ;
27
28
var nodeutil = require ( 'util' ) ;
@@ -35,6 +36,9 @@ var METADATA_TOKEN_URL =
35
36
'http://metadata/computeMetadata/v1/instance/service-accounts/default/' +
36
37
'token' ;
37
38
39
+ /** @const {number} Maximum amount of times to attempt refreshing a token. */
40
+ var MAX_TOKEN_REFRESH_ATTEMPTS = 1 ;
41
+
38
42
/** @const {object} gcloud-node's package.json file. */
39
43
var PKG = require ( '../../package.json' ) ;
40
44
@@ -217,7 +221,8 @@ Connection.prototype.fetchServiceAccountToken_ = function(callback) {
217
221
218
222
/**
219
223
* Make an authorized request if the current connection token is still valid. If
220
- * it's not, try to reconnect.
224
+ * it's not, try to reconnect to the limit specified by MAX_ATTEMPTS. If a valid
225
+ * connection still cannot be made, execute the callback with the API error.
221
226
*
222
227
* @param {object } requestOptions - Request options.
223
228
* @param {function= } callback - The callback function.
@@ -227,14 +232,25 @@ Connection.prototype.fetchServiceAccountToken_ = function(callback) {
227
232
*/
228
233
Connection . prototype . req = function ( requestOptions , callback ) {
229
234
var that = this ;
235
+ var tokenRefreshAttempts = 0 ;
230
236
callback = callback || util . noop ;
231
- this . createAuthorizedReq ( requestOptions , function ( err , authorizedReq ) {
237
+ function onAuthorized ( err , authorizedReq ) {
232
238
if ( err ) {
233
239
callback ( err ) ;
234
240
return ;
235
241
}
236
- that . requester ( authorizedReq , callback ) ;
237
- } ) ;
242
+ that . requester ( authorizedReq , function ( err ) {
243
+ if ( err && err . code === 401 &&
244
+ ++ tokenRefreshAttempts <= MAX_TOKEN_REFRESH_ATTEMPTS ) {
245
+ // Invalid token. Try to fetch a new one.
246
+ that . token = null ;
247
+ that . createAuthorizedReq ( requestOptions , onAuthorized ) ;
248
+ return ;
249
+ }
250
+ callback . apply ( null , util . toArray ( arguments ) ) ;
251
+ } ) ;
252
+ }
253
+ this . createAuthorizedReq ( requestOptions , onAuthorized ) ;
238
254
} ;
239
255
240
256
/**
@@ -246,10 +262,10 @@ Connection.prototype.req = function(requestOptions, callback) {
246
262
* @example
247
263
* conn.createAuthorizedReq({}, function(err) {});
248
264
*/
249
- Connection . prototype . createAuthorizedReq = function ( reqOpts , callback ) {
265
+ Connection . prototype . createAuthorizedReq = function ( requestOptions , callback ) {
250
266
var that = this ;
251
- // Add user agent.
252
- reqOpts . headers = reqOpts . headers || { } ;
267
+
268
+ var reqOpts = extend ( true , { } , requestOptions , { headers : { } } ) ;
253
269
254
270
if ( reqOpts . headers [ 'User-Agent' ] ) {
255
271
reqOpts . headers [ 'User-Agent' ] += '; ' + USER_AGENT ;
@@ -305,9 +321,11 @@ Connection.prototype.isConnected = function() {
305
321
* @return {object } Authorized request options.
306
322
*/
307
323
Connection . prototype . authorizeReq = function ( requestOptions ) {
308
- requestOptions . headers = requestOptions . headers || { } ;
309
- requestOptions . headers . Authorization = 'Bearer ' + this . token . accessToken ;
310
- return requestOptions ;
324
+ return extend ( true , { } , requestOptions , {
325
+ headers : {
326
+ Authorization : 'Bearer ' + this . token . accessToken
327
+ }
328
+ } ) ;
311
329
} ;
312
330
313
331
/**
0 commit comments