2222'use strict' ;
2323
2424var events = require ( 'events' ) ;
25+ var extend = require ( 'extend' ) ;
2526var fs = require ( 'fs' ) ;
2627var GAPIToken = require ( 'gapitoken' ) ;
2728var nodeutil = require ( 'util' ) ;
@@ -35,6 +36,9 @@ var METADATA_TOKEN_URL =
3536 'http://metadata/computeMetadata/v1/instance/service-accounts/default/' +
3637 'token' ;
3738
39+ /** @const {number} Maximum amount of times to attempt refreshing a token. */
40+ var MAX_TOKEN_REFRESH_ATTEMPTS = 1 ;
41+
3842/** @const {object} gcloud-node's package.json file. */
3943var PKG = require ( '../../package.json' ) ;
4044
@@ -217,7 +221,8 @@ Connection.prototype.fetchServiceAccountToken_ = function(callback) {
217221
218222/**
219223 * 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.
221226 *
222227 * @param {object } requestOptions - Request options.
223228 * @param {function= } callback - The callback function.
@@ -227,14 +232,25 @@ Connection.prototype.fetchServiceAccountToken_ = function(callback) {
227232 */
228233Connection . prototype . req = function ( requestOptions , callback ) {
229234 var that = this ;
235+ var tokenRefreshAttempts = 0 ;
230236 callback = callback || util . noop ;
231- this . createAuthorizedReq ( requestOptions , function ( err , authorizedReq ) {
237+ function onAuthorizedReq ( err , authorizedReq ) {
232238 if ( err ) {
233239 callback ( err ) ;
234240 return ;
235241 }
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 , onAuthorizedReq ) ;
248+ return ;
249+ }
250+ callback . apply ( null , util . toArray ( arguments ) ) ;
251+ } ) ;
252+ }
253+ this . createAuthorizedReq ( requestOptions , onAuthorizedReq ) ;
238254} ;
239255
240256/**
@@ -246,10 +262,10 @@ Connection.prototype.req = function(requestOptions, callback) {
246262 * @example
247263 * conn.createAuthorizedReq({}, function(err) {});
248264 */
249- Connection . prototype . createAuthorizedReq = function ( reqOpts , callback ) {
265+ Connection . prototype . createAuthorizedReq = function ( requestOptions , callback ) {
250266 var that = this ;
251- // Add user agent.
252- reqOpts . headers = reqOpts . headers || { } ;
267+
268+ var reqOpts = extend ( true , { } , requestOptions , { headers : { } } ) ;
253269
254270 if ( reqOpts . headers [ 'User-Agent' ] ) {
255271 reqOpts . headers [ 'User-Agent' ] += '; ' + USER_AGENT ;
@@ -305,9 +321,11 @@ Connection.prototype.isConnected = function() {
305321 * @return {object } Authorized request options.
306322 */
307323Connection . 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+ } ) ;
311329} ;
312330
313331/**
0 commit comments