💾 Archived View for gmi.noulin.net › gitRepositories › git-off › file › src › node_modules › aws-sdk… captured on 2023-07-10 at 16:24:36. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-01-29)

-=-=-=-=-=-=-

git-off

Log

Files

Refs

README

request.js (26488B)

     1 var AWS = require('./core');
     2 var AcceptorStateMachine = require('./state_machine');
     3 var inherit = AWS.util.inherit;
     4 var domain = AWS.util.domain;
     5 var jmespath = require('jmespath');
     6 
     7 /**
     8  * @api private
     9  */
    10 var hardErrorStates = {success: 1, error: 1, complete: 1};
    11 
    12 function isTerminalState(machine) {
    13   return Object.prototype.hasOwnProperty.call(hardErrorStates, machine._asm.currentState);
    14 }
    15 
    16 var fsm = new AcceptorStateMachine();
    17 fsm.setupStates = function() {
    18   var transition = function(_, done) {
    19     var self = this;
    20     self._haltHandlersOnError = false;
    21 
    22     self.emit(self._asm.currentState, function(err) {
    23       if (err) {
    24         if (isTerminalState(self)) {
    25           if (domain && self.domain instanceof domain.Domain) {
    26             err.domainEmitter = self;
    27             err.domain = self.domain;
    28             err.domainThrown = false;
    29             self.domain.emit('error', err);
    30           } else {
    31             throw err;
    32           }
    33         } else {
    34           self.response.error = err;
    35           done(err);
    36         }
    37       } else {
    38         done(self.response.error);
    39       }
    40     });
    41 
    42   };
    43 
    44   this.addState('validate', 'build', 'error', transition);
    45   this.addState('build', 'afterBuild', 'restart', transition);
    46   this.addState('afterBuild', 'sign', 'restart', transition);
    47   this.addState('sign', 'send', 'retry', transition);
    48   this.addState('retry', 'afterRetry', 'afterRetry', transition);
    49   this.addState('afterRetry', 'sign', 'error', transition);
    50   this.addState('send', 'validateResponse', 'retry', transition);
    51   this.addState('validateResponse', 'extractData', 'extractError', transition);
    52   this.addState('extractError', 'extractData', 'retry', transition);
    53   this.addState('extractData', 'success', 'retry', transition);
    54   this.addState('restart', 'build', 'error', transition);
    55   this.addState('success', 'complete', 'complete', transition);
    56   this.addState('error', 'complete', 'complete', transition);
    57   this.addState('complete', null, null, transition);
    58 };
    59 fsm.setupStates();
    60 
    61 /**
    62  * ## Asynchronous Requests
    63  *
    64  * All requests made through the SDK are asynchronous and use a
    65  * callback interface. Each service method that kicks off a request
    66  * returns an `AWS.Request` object that you can use to register
    67  * callbacks.
    68  *
    69  * For example, the following service method returns the request
    70  * object as "request", which can be used to register callbacks:
    71  *
    72  * ```javascript
    73  * // request is an AWS.Request object
    74  * var request = ec2.describeInstances();
    75  *
    76  * // register callbacks on request to retrieve response data
    77  * request.on('success', function(response) {
    78  *   console.log(response.data);
    79  * });
    80  * ```
    81  *
    82  * When a request is ready to be sent, the {send} method should
    83  * be called:
    84  *
    85  * ```javascript
    86  * request.send();
    87  * ```
    88  *
    89  * ## Removing Default Listeners for Events
    90  *
    91  * Request objects are built with default listeners for the various events,
    92  * depending on the service type. In some cases, you may want to remove
    93  * some built-in listeners to customize behaviour. Doing this requires
    94  * access to the built-in listener functions, which are exposed through
    95  * the {AWS.EventListeners.Core} namespace. For instance, you may
    96  * want to customize the HTTP handler used when sending a request. In this
    97  * case, you can remove the built-in listener associated with the 'send'
    98  * event, the {AWS.EventListeners.Core.SEND} listener and add your own.
    99  *
   100  * ## Multiple Callbacks and Chaining
   101  *
   102  * You can register multiple callbacks on any request object. The
   103  * callbacks can be registered for different events, or all for the
   104  * same event. In addition, you can chain callback registration, for
   105  * example:
   106  *
   107  * ```javascript
   108  * request.
   109  *   on('success', function(response) {
   110  *     console.log("Success!");
   111  *   }).
   112  *   on('error', function(response) {
   113  *     console.log("Error!");
   114  *   }).
   115  *   on('complete', function(response) {
   116  *     console.log("Always!");
   117  *   }).
   118  *   send();
   119  * ```
   120  *
   121  * The above example will print either "Success! Always!", or "Error! Always!",
   122  * depending on whether the request succeeded or not.
   123  *
   124  * @!attribute httpRequest
   125  *   @readonly
   126  *   @!group HTTP Properties
   127  *   @return [AWS.HttpRequest] the raw HTTP request object
   128  *     containing request headers and body information
   129  *     sent by the service.
   130  *
   131  * @!attribute startTime
   132  *   @readonly
   133  *   @!group Operation Properties
   134  *   @return [Date] the time that the request started
   135  *
   136  * @!group Request Building Events
   137  *
   138  * @!event validate(request)
   139  *   Triggered when a request is being validated. Listeners
   140  *   should throw an error if the request should not be sent.
   141  *   @param request [Request] the request object being sent
   142  *   @see AWS.EventListeners.Core.VALIDATE_CREDENTIALS
   143  *   @see AWS.EventListeners.Core.VALIDATE_REGION
   144  *   @example Ensuring that a certain parameter is set before sending a request
   145  *     var req = s3.putObject(params);
   146  *     req.on('validate', function() {
   147  *       if (!req.params.Body.match(/^Hello\s/)) {
   148  *         throw new Error('Body must start with "Hello "');
   149  *       }
   150  *     });
   151  *     req.send(function(err, data) { ... });
   152  *
   153  * @!event build(request)
   154  *   Triggered when the request payload is being built. Listeners
   155  *   should fill the necessary information to send the request
   156  *   over HTTP.
   157  *   @param (see AWS.Request~validate)
   158  *   @example Add a custom HTTP header to a request
   159  *     var req = s3.putObject(params);
   160  *     req.on('build', function() {
   161  *       req.httpRequest.headers['Custom-Header'] = 'value';
   162  *     });
   163  *     req.send(function(err, data) { ... });
   164  *
   165  * @!event sign(request)
   166  *   Triggered when the request is being signed. Listeners should
   167  *   add the correct authentication headers and/or adjust the body,
   168  *   depending on the authentication mechanism being used.
   169  *   @param (see AWS.Request~validate)
   170  *
   171  * @!group Request Sending Events
   172  *
   173  * @!event send(response)
   174  *   Triggered when the request is ready to be sent. Listeners
   175  *   should call the underlying transport layer to initiate
   176  *   the sending of the request.
   177  *   @param response [Response] the response object
   178  *   @context [Request] the request object that was sent
   179  *   @see AWS.EventListeners.Core.SEND
   180  *
   181  * @!event retry(response)
   182  *   Triggered when a request failed and might need to be retried or redirected.
   183  *   If the response is retryable, the listener should set the
   184  *   `response.error.retryable` property to `true`, and optionally set
   185  *   `response.error.retryCount` to the millisecond delay for the next attempt.
   186  *   In the case of a redirect, `response.error.redirect` should be set to
   187  *   `true` with `retryCount` set to an optional delay on the next request.
   188  *
   189  *   If a listener decides that a request should not be retried,
   190  *   it should set both `retryable` and `redirect` to false.
   191  *
   192  *   Note that a retryable error will be retried at most
   193  *   {AWS.Config.maxRetries} times (based on the service object's config).
   194  *   Similarly, a request that is redirected will only redirect at most
   195  *   {AWS.Config.maxRedirects} times.
   196  *
   197  *   @param (see AWS.Request~send)
   198  *   @context (see AWS.Request~send)
   199  *   @example Adding a custom retry for a 404 response
   200  *     request.on('retry', function(response) {
   201  *       // this resource is not yet available, wait 10 seconds to get it again
   202  *       if (response.httpResponse.statusCode === 404 && response.error) {
   203  *         response.error.retryable = true;   // retry this error
   204  *         response.error.retryCount = 10000; // wait 10 seconds
   205  *       }
   206  *     });
   207  *
   208  * @!group Data Parsing Events
   209  *
   210  * @!event extractError(response)
   211  *   Triggered on all non-2xx requests so that listeners can extract
   212  *   error details from the response body. Listeners to this event
   213  *   should set the `response.error` property.
   214  *   @param (see AWS.Request~send)
   215  *   @context (see AWS.Request~send)
   216  *
   217  * @!event extractData(response)
   218  *   Triggered in successful requests to allow listeners to
   219  *   de-serialize the response body into `response.data`.
   220  *   @param (see AWS.Request~send)
   221  *   @context (see AWS.Request~send)
   222  *
   223  * @!group Completion Events
   224  *
   225  * @!event success(response)
   226  *   Triggered when the request completed successfully.
   227  *   `response.data` will contain the response data and
   228  *   `response.error` will be null.
   229  *   @param (see AWS.Request~send)
   230  *   @context (see AWS.Request~send)
   231  *
   232  * @!event error(error, response)
   233  *   Triggered when an error occurs at any point during the
   234  *   request. `response.error` will contain details about the error
   235  *   that occurred. `response.data` will be null.
   236  *   @param error [Error] the error object containing details about
   237  *     the error that occurred.
   238  *   @param (see AWS.Request~send)
   239  *   @context (see AWS.Request~send)
   240  *
   241  * @!event complete(response)
   242  *   Triggered whenever a request cycle completes. `response.error`
   243  *   should be checked, since the request may have failed.
   244  *   @param (see AWS.Request~send)
   245  *   @context (see AWS.Request~send)
   246  *
   247  * @!group HTTP Events
   248  *
   249  * @!event httpHeaders(statusCode, headers, response)
   250  *   Triggered when headers are sent by the remote server
   251  *   @param statusCode [Integer] the HTTP response code
   252  *   @param headers [map<String,String>] the response headers
   253  *   @param (see AWS.Request~send)
   254  *   @context (see AWS.Request~send)
   255  *
   256  * @!event httpData(chunk, response)
   257  *   Triggered when data is sent by the remote server
   258  *   @param chunk [Buffer] the buffer data containing the next data chunk
   259  *     from the server
   260  *   @param (see AWS.Request~send)
   261  *   @context (see AWS.Request~send)
   262  *   @see AWS.EventListeners.Core.HTTP_DATA
   263  *
   264  * @!event httpUploadProgress(progress, response)
   265  *   Triggered when the HTTP request has uploaded more data
   266  *   @param progress [map] An object containing the `loaded` and `total` bytes
   267  *     of the request.
   268  *   @param (see AWS.Request~send)
   269  *   @context (see AWS.Request~send)
   270  *   @note This event will not be emitted in Node.js 0.8.x.
   271  *
   272  * @!event httpDownloadProgress(progress, response)
   273  *   Triggered when the HTTP request has downloaded more data
   274  *   @param progress [map] An object containing the `loaded` and `total` bytes
   275  *     of the request.
   276  *   @param (see AWS.Request~send)
   277  *   @context (see AWS.Request~send)
   278  *   @note This event will not be emitted in Node.js 0.8.x.
   279  *
   280  * @!event httpError(error, response)
   281  *   Triggered when the HTTP request failed
   282  *   @param error [Error] the error object that was thrown
   283  *   @param (see AWS.Request~send)
   284  *   @context (see AWS.Request~send)
   285  *
   286  * @!event httpDone(response)
   287  *   Triggered when the server is finished sending data
   288  *   @param (see AWS.Request~send)
   289  *   @context (see AWS.Request~send)
   290  *
   291  * @see AWS.Response
   292  */
   293 AWS.Request = inherit({
   294 
   295   /**
   296    * Creates a request for an operation on a given service with
   297    * a set of input parameters.
   298    *
   299    * @param service [AWS.Service] the service to perform the operation on
   300    * @param operation [String] the operation to perform on the service
   301    * @param params [Object] parameters to send to the operation.
   302    *   See the operation's documentation for the format of the
   303    *   parameters.
   304    */
   305   constructor: function Request(service, operation, params) {
   306     var endpoint = service.endpoint;
   307     var region = service.config.region;
   308     var customUserAgent = service.config.customUserAgent;
   309 
   310     // global endpoints sign as us-east-1
   311     if (service.isGlobalEndpoint) region = 'us-east-1';
   312 
   313     this.domain = domain && domain.active;
   314     this.service = service;
   315     this.operation = operation;
   316     this.params = params || {};
   317     this.httpRequest = new AWS.HttpRequest(endpoint, region, customUserAgent);
   318     this.startTime = AWS.util.date.getDate();
   319 
   320     this.response = new AWS.Response(this);
   321     this._asm = new AcceptorStateMachine(fsm.states, 'validate');
   322     this._haltHandlersOnError = false;
   323 
   324     AWS.SequentialExecutor.call(this);
   325     this.emit = this.emitEvent;
   326   },
   327 
   328   /**
   329    * @!group Sending a Request
   330    */
   331 
   332   /**
   333    * @overload send(callback = null)
   334    *   Sends the request object.
   335    *
   336    *   @callback callback function(err, data)
   337    *     If a callback is supplied, it is called when a response is returned
   338    *     from the service.
   339    *     @context [AWS.Request] the request object being sent.
   340    *     @param err [Error] the error object returned from the request.
   341    *       Set to `null` if the request is successful.
   342    *     @param data [Object] the de-serialized data returned from
   343    *       the request. Set to `null` if a request error occurs.
   344    *   @example Sending a request with a callback
   345    *     request = s3.putObject({Bucket: 'bucket', Key: 'key'});
   346    *     request.send(function(err, data) { console.log(err, data); });
   347    *   @example Sending a request with no callback (using event handlers)
   348    *     request = s3.putObject({Bucket: 'bucket', Key: 'key'});
   349    *     request.on('complete', function(response) { ... }); // register a callback
   350    *     request.send();
   351    */
   352   send: function send(callback) {
   353     if (callback) {
   354       this.on('complete', function (resp) {
   355         callback.call(resp, resp.error, resp.data);
   356       });
   357     }
   358     this.runTo();
   359 
   360     return this.response;
   361   },
   362 
   363   /**
   364    * @!method  promise()
   365    *   Returns a 'thenable' promise.
   366    *
   367    *   Two callbacks can be provided to the `then` method on the returned promise.
   368    *   The first callback will be called if the promise is fulfilled, and the second
   369    *   callback will be called if the promise is rejected.
   370    *   @callback fulfilledCallback function(data)
   371    *     Called if the promise is fulfilled.
   372    *     @param data [Object] the de-serialized data returned from the request.
   373    *   @callback rejectedCallback function(error)
   374    *     Called if the promise is rejected.
   375    *     @param error [Error] the error object returned from the request.
   376    *   @return [Promise] A promise that represents the state of the request.
   377    *   @example Sending a request using promises.
   378    *     var request = s3.putObject({Bucket: 'bucket', Key: 'key'});
   379    *     var result = request.promise();
   380    *     result.then(function(data) { ... }, function(error) { ... });
   381    */
   382 
   383   /**
   384    * @api private
   385    */
   386   build: function build(callback) {
   387     return this.runTo('send', callback);
   388   },
   389 
   390   /**
   391    * @api private
   392    */
   393   runTo: function runTo(state, done) {
   394     this._asm.runTo(state, done, this);
   395     return this;
   396   },
   397 
   398   /**
   399    * Aborts a request, emitting the error and complete events.
   400    *
   401    * @!macro nobrowser
   402    * @example Aborting a request after sending
   403    *   var params = {
   404    *     Bucket: 'bucket', Key: 'key',
   405    *     Body: new Buffer(1024 * 1024 * 5) // 5MB payload
   406    *   };
   407    *   var request = s3.putObject(params);
   408    *   request.send(function (err, data) {
   409    *     if (err) console.log("Error:", err.code, err.message);
   410    *     else console.log(data);
   411    *   });
   412    *
   413    *   // abort request in 1 second
   414    *   setTimeout(request.abort.bind(request), 1000);
   415    *
   416    *   // prints "Error: RequestAbortedError Request aborted by user"
   417    * @return [AWS.Request] the same request object, for chaining.
   418    * @since v1.4.0
   419    */
   420   abort: function abort() {
   421     this.removeAllListeners('validateResponse');
   422     this.removeAllListeners('extractError');
   423     this.on('validateResponse', function addAbortedError(resp) {
   424       resp.error = AWS.util.error(new Error('Request aborted by user'), {
   425          code: 'RequestAbortedError', retryable: false
   426       });
   427     });
   428 
   429     if (this.httpRequest.stream) { // abort HTTP stream
   430       this.httpRequest.stream.abort();
   431       if (this.httpRequest._abortCallback) {
   432          this.httpRequest._abortCallback();
   433       } else {
   434         this.removeAllListeners('send'); // haven't sent yet, so let's not
   435       }
   436     }
   437 
   438     return this;
   439   },
   440 
   441   /**
   442    * Iterates over each page of results given a pageable request, calling
   443    * the provided callback with each page of data. After all pages have been
   444    * retrieved, the callback is called with `null` data.
   445    *
   446    * @note This operation can generate multiple requests to a service.
   447    * @example Iterating over multiple pages of objects in an S3 bucket
   448    *   var pages = 1;
   449    *   s3.listObjects().eachPage(function(err, data) {
   450    *     if (err) return;
   451    *     console.log("Page", pages++);
   452    *     console.log(data);
   453    *   });
   454    * @example Iterating over multiple pages with an asynchronous callback
   455    *   s3.listObjects(params).eachPage(function(err, data, done) {
   456    *     doSomethingAsyncAndOrExpensive(function() {
   457    *       // The next page of results isn't fetched until done is called
   458    *       done();
   459    *     });
   460    *   });
   461    * @callback callback function(err, data, [doneCallback])
   462    *   Called with each page of resulting data from the request. If the
   463    *   optional `doneCallback` is provided in the function, it must be called
   464    *   when the callback is complete.
   465    *
   466    *   @param err [Error] an error object, if an error occurred.
   467    *   @param data [Object] a single page of response data. If there is no
   468    *     more data, this object will be `null`.
   469    *   @param doneCallback [Function] an optional done callback. If this
   470    *     argument is defined in the function declaration, it should be called
   471    *     when the next page is ready to be retrieved. This is useful for
   472    *     controlling serial pagination across asynchronous operations.
   473    *   @return [Boolean] if the callback returns `false`, pagination will
   474    *     stop.
   475    *
   476    * @see AWS.Request.eachItem
   477    * @see AWS.Response.nextPage
   478    * @since v1.4.0
   479    */
   480   eachPage: function eachPage(callback) {
   481     // Make all callbacks async-ish
   482     callback = AWS.util.fn.makeAsync(callback, 3);
   483 
   484     function wrappedCallback(response) {
   485       callback.call(response, response.error, response.data, function (result) {
   486         if (result === false) return;
   487 
   488         if (response.hasNextPage()) {
   489           response.nextPage().on('complete', wrappedCallback).send();
   490         } else {
   491           callback.call(response, null, null, AWS.util.fn.noop);
   492         }
   493       });
   494     }
   495 
   496     this.on('complete', wrappedCallback).send();
   497   },
   498 
   499   /**
   500    * Enumerates over individual items of a request, paging the responses if
   501    * necessary.
   502    *
   503    * @api experimental
   504    * @since v1.4.0
   505    */
   506   eachItem: function eachItem(callback) {
   507     var self = this;
   508     function wrappedCallback(err, data) {
   509       if (err) return callback(err, null);
   510       if (data === null) return callback(null, null);
   511 
   512       var config = self.service.paginationConfig(self.operation);
   513       var resultKey = config.resultKey;
   514       if (Array.isArray(resultKey)) resultKey = resultKey[0];
   515       var items = jmespath.search(data, resultKey);
   516       var continueIteration = true;
   517       AWS.util.arrayEach(items, function(item) {
   518         continueIteration = callback(null, item);
   519         if (continueIteration === false) {
   520           return AWS.util.abort;
   521         }
   522       });
   523       return continueIteration;
   524     }
   525 
   526     this.eachPage(wrappedCallback);
   527   },
   528 
   529   /**
   530    * @return [Boolean] whether the operation can return multiple pages of
   531    *   response data.
   532    * @see AWS.Response.eachPage
   533    * @since v1.4.0
   534    */
   535   isPageable: function isPageable() {
   536     return this.service.paginationConfig(this.operation) ? true : false;
   537   },
   538 
   539   /**
   540    * Converts the request object into a readable stream that
   541    * can be read from or piped into a writable stream.
   542    *
   543    * @note The data read from a readable stream contains only
   544    *   the raw HTTP body contents.
   545    * @example Manually reading from a stream
   546    *   request.createReadStream().on('data', function(data) {
   547    *     console.log("Got data:", data.toString());
   548    *   });
   549    * @example Piping a request body into a file
   550    *   var out = fs.createWriteStream('/path/to/outfile.jpg');
   551    *   s3.service.getObject(params).createReadStream().pipe(out);
   552    * @return [Stream] the readable stream object that can be piped
   553    *   or read from (by registering 'data' event listeners).
   554    * @!macro nobrowser
   555    */
   556   createReadStream: function createReadStream() {
   557     var streams = AWS.util.stream;
   558     var req = this;
   559     var stream = null;
   560 
   561     if (AWS.HttpClient.streamsApiVersion === 2) {
   562       stream = new streams.PassThrough();
   563       req.send();
   564     } else {
   565       stream = new streams.Stream();
   566       stream.readable = true;
   567 
   568       stream.sent = false;
   569       stream.on('newListener', function(event) {
   570         if (!stream.sent && event === 'data') {
   571           stream.sent = true;
   572           process.nextTick(function() { req.send(); });
   573         }
   574       });
   575     }
   576 
   577     this.on('httpHeaders', function streamHeaders(statusCode, headers, resp) {
   578       if (statusCode < 300) {
   579         req.removeListener('httpData', AWS.EventListeners.Core.HTTP_DATA);
   580         req.removeListener('httpError', AWS.EventListeners.Core.HTTP_ERROR);
   581         req.on('httpError', function streamHttpError(error) {
   582           resp.error = error;
   583           resp.error.retryable = false;
   584         });
   585 
   586         var shouldCheckContentLength = false;
   587         var expectedLen;
   588         if (req.httpRequest.method !== 'HEAD') {
   589           expectedLen = parseInt(headers['content-length'], 10);
   590         }
   591         if (expectedLen !== undefined && !isNaN(expectedLen) && expectedLen >= 0) {
   592           shouldCheckContentLength = true;
   593           var receivedLen = 0;
   594         }
   595 
   596         var checkContentLengthAndEmit = function checkContentLengthAndEmit() {
   597           if (shouldCheckContentLength && receivedLen !== expectedLen) {
   598             stream.emit('error', AWS.util.error(
   599               new Error('Stream content length mismatch. Received ' +
   600                 receivedLen + ' of ' + expectedLen + ' bytes.'),
   601               { code: 'StreamContentLengthMismatch' }
   602             ));
   603           } else if (AWS.HttpClient.streamsApiVersion === 2) {
   604             stream.end();
   605           } else {
   606             stream.emit('end')
   607           }
   608         }
   609 
   610         var httpStream = resp.httpResponse.createUnbufferedStream();
   611 
   612         if (AWS.HttpClient.streamsApiVersion === 2) {
   613           if (shouldCheckContentLength) {
   614             var lengthAccumulator = new streams.PassThrough();
   615             lengthAccumulator._write = function(chunk) {
   616               if (chunk && chunk.length) {
   617                 receivedLen += chunk.length;
   618               }
   619               return streams.PassThrough.prototype._write.apply(this, arguments);
   620             };
   621 
   622             lengthAccumulator.on('end', checkContentLengthAndEmit);
   623             httpStream.pipe(lengthAccumulator).pipe(stream, { end: false });
   624           } else {
   625             httpStream.pipe(stream);
   626           }
   627         } else {
   628 
   629           if (shouldCheckContentLength) {
   630             httpStream.on('data', function(arg) {
   631               if (arg && arg.length) {
   632                 receivedLen += arg.length;
   633               }
   634             });
   635           }
   636 
   637           httpStream.on('data', function(arg) {
   638             stream.emit('data', arg);
   639           });
   640           httpStream.on('end', checkContentLengthAndEmit);
   641         }
   642 
   643         httpStream.on('error', function(err) {
   644           shouldCheckContentLength = false;
   645           stream.emit('error', err);
   646         });
   647       }
   648     });
   649 
   650     this.on('error', function(err) {
   651       stream.emit('error', err);
   652     });
   653 
   654     return stream;
   655   },
   656 
   657   /**
   658    * @param [Array,Response] args This should be the response object,
   659    *   or an array of args to send to the event.
   660    * @api private
   661    */
   662   emitEvent: function emit(eventName, args, done) {
   663     if (typeof args === 'function') { done = args; args = null; }
   664     if (!done) done = function() { };
   665     if (!args) args = this.eventParameters(eventName, this.response);
   666 
   667     var origEmit = AWS.SequentialExecutor.prototype.emit;
   668     origEmit.call(this, eventName, args, function (err) {
   669       if (err) this.response.error = err;
   670       done.call(this, err);
   671     });
   672   },
   673 
   674   /**
   675    * @api private
   676    */
   677   eventParameters: function eventParameters(eventName) {
   678     switch (eventName) {
   679       case 'restart':
   680       case 'validate':
   681       case 'sign':
   682       case 'build':
   683       case 'afterValidate':
   684       case 'afterBuild':
   685         return [this];
   686       case 'error':
   687         return [this.response.error, this.response];
   688       default:
   689         return [this.response];
   690     }
   691   },
   692 
   693   /**
   694    * @api private
   695    */
   696   presign: function presign(expires, callback) {
   697     if (!callback && typeof expires === 'function') {
   698       callback = expires;
   699       expires = null;
   700     }
   701     return new AWS.Signers.Presign().sign(this.toGet(), expires, callback);
   702   },
   703 
   704   /**
   705    * @api private
   706    */
   707   isPresigned: function isPresigned() {
   708     return Object.prototype.hasOwnProperty.call(this.httpRequest.headers, 'presigned-expires');
   709   },
   710 
   711   /**
   712    * @api private
   713    */
   714   toUnauthenticated: function toUnauthenticated() {
   715     this.removeListener('validate', AWS.EventListeners.Core.VALIDATE_CREDENTIALS);
   716     this.removeListener('sign', AWS.EventListeners.Core.SIGN);
   717     return this;
   718   },
   719 
   720   /**
   721    * @api private
   722    */
   723   toGet: function toGet() {
   724     if (this.service.api.protocol === 'query' ||
   725         this.service.api.protocol === 'ec2') {
   726       this.removeListener('build', this.buildAsGet);
   727       this.addListener('build', this.buildAsGet);
   728     }
   729     return this;
   730   },
   731 
   732   /**
   733    * @api private
   734    */
   735   buildAsGet: function buildAsGet(request) {
   736     request.httpRequest.method = 'GET';
   737     request.httpRequest.path = request.service.endpoint.path +
   738                                '?' + request.httpRequest.body;
   739     request.httpRequest.body = '';
   740 
   741     // don't need these headers on a GET request
   742     delete request.httpRequest.headers['Content-Length'];
   743     delete request.httpRequest.headers['Content-Type'];
   744   },
   745 
   746   /**
   747    * @api private
   748    */
   749   haltHandlersOnError: function haltHandlersOnError() {
   750     this._haltHandlersOnError = true;
   751   }
   752 });
   753 
   754 /**
   755  * @api private
   756  */
   757 AWS.Request.addPromisesToClass = function addPromisesToClass(PromiseDependency) {
   758   this.prototype.promise = function promise() {
   759     var self = this;
   760     return new PromiseDependency(function(resolve, reject) {
   761       self.on('complete', function(resp) {
   762         if (resp.error) {
   763           reject(resp.error);
   764         } else {
   765           resolve(resp.data);
   766         }
   767       });
   768       self.runTo();
   769     });
   770   };
   771 };
   772 
   773 /**
   774  * @api private
   775  */
   776 AWS.Request.deletePromisesFromClass = function deletePromisesFromClass() {
   777   delete this.prototype.promise;
   778 };
   779 
   780 AWS.util.addPromises(AWS.Request);
   781 
   782 AWS.util.mixin(AWS.Request, AWS.SequentialExecutor);