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,9 @@ 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
225+ * MAX_TOKEN_REFRESH_ATTEMPTS. If a valid connection still cannot be made,
226+ * execute the callback with the API error.
221227 *
222228 * @param {object } requestOptions - Request options.
223229 * @param {function= } callback - The callback function.
@@ -227,14 +233,25 @@ Connection.prototype.fetchServiceAccountToken_ = function(callback) {
227233 */
228234Connection . prototype . req = function ( requestOptions , callback ) {
229235 var that = this ;
236+ var tokenRefreshAttempts = 0 ;
230237 callback = callback || util . noop ;
231- this . createAuthorizedReq ( requestOptions , function ( err , authorizedReq ) {
238+ function onAuthorizedReq ( err , authorizedReq ) {
232239 if ( err ) {
233240 callback ( err ) ;
234241 return ;
235242 }
236- that . requester ( authorizedReq , callback ) ;
237- } ) ;
243+ that . requester ( authorizedReq , function ( err ) {
244+ if ( err && err . code === 401 &&
245+ ++ tokenRefreshAttempts <= MAX_TOKEN_REFRESH_ATTEMPTS ) {
246+ // Invalid token. Try to fetch a new one.
247+ that . token = null ;
248+ that . createAuthorizedReq ( requestOptions , onAuthorizedReq ) ;
249+ return ;
250+ }
251+ callback . apply ( null , util . toArray ( arguments ) ) ;
252+ } ) ;
253+ }
254+ this . createAuthorizedReq ( requestOptions , onAuthorizedReq ) ;
238255} ;
239256
240257/**
@@ -246,10 +263,10 @@ Connection.prototype.req = function(requestOptions, callback) {
246263 * @example
247264 * conn.createAuthorizedReq({}, function(err) {});
248265 */
249- Connection . prototype . createAuthorizedReq = function ( reqOpts , callback ) {
266+ Connection . prototype . createAuthorizedReq = function ( requestOptions , callback ) {
250267 var that = this ;
251- // Add user agent.
252- reqOpts . headers = reqOpts . headers || { } ;
268+
269+ var reqOpts = extend ( true , { } , requestOptions , { headers : { } } ) ;
253270
254271 if ( reqOpts . headers [ 'User-Agent' ] ) {
255272 reqOpts . headers [ 'User-Agent' ] += '; ' + USER_AGENT ;
@@ -305,9 +322,11 @@ Connection.prototype.isConnected = function() {
305322 * @return {object } Authorized request options.
306323 */
307324Connection . prototype . authorizeReq = function ( requestOptions ) {
308- requestOptions . headers = requestOptions . headers || { } ;
309- requestOptions . headers . Authorization = 'Bearer ' + this . token . accessToken ;
310- return requestOptions ;
325+ return extend ( true , { } , requestOptions , {
326+ headers : {
327+ Authorization : 'Bearer ' + this . token . accessToken
328+ }
329+ } ) ;
311330} ;
312331
313332/**
0 commit comments