git-off

git off handles large files in git repos
git clone https://noulin.net/git/git-off.git
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);