Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Refactor HTTP client to use HttpRequest objects directly

  • Loading branch information...
commit cfc48396b37ae1b66ad744f2eb6846f77f45ff58 1 parent 79c63bf
@lsegal lsegal authored
View
21 lib/event_listeners.js
@@ -146,7 +146,26 @@ AWS.EventListeners = {
});
add('SEND', 'send', function SEND(resp) {
- AWS.HttpClient.getInstance().handleRequest(this, resp);
+ function callback(httpResp) {
+ var headers = [httpResp.statusCode, httpResp.headers, resp];
+ resp.request.emitEvent('httpHeaders', headers);
+
+ httpResp.on('data', function onData(data) {
+ resp.request.emitEvent('httpData', [data, resp]);
+ });
+
+ httpResp.on('end', function onEnd() {
+ resp.request.emitEvent('httpDone', [resp]);
+ });
+ }
+
+ function error(err) {
+ err = AWS.util.error(err, {code: 'NetworkingError', retryable: true});
+ resp.request.emitEvent('httpError', [err, resp]);
+ }
+
+ var http = AWS.HttpClient.getInstance();
+ http.handleRequest(this.httpRequest, callback, error);
});
add('HTTP_HEADERS', 'httpHeaders',
View
74 lib/http.js
@@ -155,62 +155,50 @@ AWS.HttpResponse = inherit({
* @api private
*/
AWS.NodeHttpClient = inherit({
- handleRequest: function handleRequest(request, response) {
+ handleRequest: function handleRequest(httpRequest, callback, errCallback) {
+ var useSSL = httpRequest.endpoint.protocol === 'https:';
+ var http = useSSL ? require('https') : require('http');
var options = {
- host: request.httpRequest.endpoint.hostname,
- port: request.httpRequest.endpoint.port,
- method: request.httpRequest.method,
- headers: request.httpRequest.headers,
- path: request.httpRequest.path
+ host: httpRequest.endpoint.hostname,
+ port: httpRequest.endpoint.port,
+ method: httpRequest.method,
+ headers: httpRequest.headers,
+ path: httpRequest.path
};
- var useSSL = request.httpRequest.endpoint.protocol === 'https:';
- var client = useSSL ? require('https') : require('http');
if (useSSL) {
- if (!AWS.NodeHttpClient.sslAgent) {
- // cache certificate bundle
- var bundleLocation = __dirname + '/../ca-bundle.crt';
- AWS.NodeHttpClient.certBundle = AWS.util.readFileSync(bundleLocation);
-
- // cache sslAgent
- AWS.NodeHttpClient.sslAgent = new client.Agent({
- rejectUnauthorized: true,
- cert: AWS.NodeHttpClient.certBundle
- });
- }
-
- options.agent = AWS.NodeHttpClient.sslAgent;
+ options.agent = this.sslAgent(http);
}
- var stream = this.setupEvents(client, options, request, response);
- if (request.httpRequest.body instanceof Stream) {
- request.httpRequest.body.pipe(stream, {end: false});
- } else if (request.httpRequest.body) {
- stream.write(request.httpRequest.body);
+ var stream = http.request(options, callback);
+ stream.on('error', errCallback);
+ this.writeBody(stream, httpRequest);
+ return stream;
+ },
+
+ writeBody: function writeBody(stream, httpRequest) {
+ if (httpRequest.body instanceof Stream) {
+ httpRequest.body.pipe(stream, {end: false});
+ } else if (httpRequest.body) {
+ stream.write(httpRequest.body);
}
stream.end();
},
- setupEvents: function setupEvents(client, options, request, response) {
- var stream = client.request(options, function onResponse(httpResponse) {
- request.emitEvent('httpHeaders', [httpResponse.statusCode,
- httpResponse.headers, response]);
-
- httpResponse.on('data', function onData(data) {
- request.emitEvent('httpData', [data, response]);
- });
+ sslAgent: function sslAgent(http) {
+ if (!AWS.NodeHttpClient.sslAgent) {
+ // cache certificate bundle
+ var bundleLocation = __dirname + '/../ca-bundle.crt';
+ AWS.NodeHttpClient.certBundle = AWS.util.readFileSync(bundleLocation);
- httpResponse.on('end', function onEnd() {
- request.emitEvent('httpDone', [response]);
+ // cache sslAgent
+ AWS.NodeHttpClient.sslAgent = new http.Agent({
+ rejectUnauthorized: true,
+ cert: AWS.NodeHttpClient.certBundle
});
- });
-
- stream.on('error', function (err) {
- var error = AWS.util.error(err, {code: 'NetworkingError', retryable: true});
- request.emitEvent('httpError', [error, response]);
- });
+ }
- return stream;
+ return AWS.NodeHttpClient.sslAgent;
}
});
View
43 test/helpers.coffee
@@ -12,6 +12,7 @@
# language governing permissions and limitations under the License.
AWS = require('../lib/aws')
+EventEmitter = require('events').EventEmitter
# Mock credentials
AWS.config.update
@@ -62,29 +63,41 @@ MockService = AWS.util.inherit AWS.Service,
MockService.Client = MockClient
+mockHttpSuccessfulResponse = (status, headers, data, cb) ->
+ httpResp = new EventEmitter()
+ httpResp.statusCode = status
+ httpResp.headers = headers
+
+ cb(httpResp)
+
+ if !Array.isArray(data)
+ data = [data]
+ AWS.util.arrayEach data, (str) ->
+ httpResp.emit('data', new Buffer(str))
+
+ httpResp.emit('end')
+
mockHttpResponse = (status, headers, data) ->
+ stream = new EventEmitter()
spyOn(AWS.HttpClient, 'getInstance')
- AWS.HttpClient.getInstance.andReturn handleRequest: (req, resp) ->
+ AWS.HttpClient.getInstance.andReturn handleRequest: (req, cb, errCb) ->
if typeof status == 'number'
- req.emit('httpHeaders', [status, headers, resp])
- str = str instanceof Array ? str : [str]
- AWS.util.arrayEach data, (str) ->
- req.emit('httpData', [new Buffer(str), resp])
- req.emit('httpDone', [resp])
+ mockHttpSuccessfulResponse status, headers, data, cb
else
- req.emit('httpError', [status, resp])
+ errCb(status)
+
+ return stream
mockIntermittentFailureResponse = (numFailures, status, headers, data) ->
+ retryCount = 0
spyOn(AWS.HttpClient, 'getInstance')
- AWS.HttpClient.getInstance.andReturn handleRequest: (req, resp) ->
- if resp.retryCount < numFailures
- req.emit('httpError', [{code: 'NetworkingError', message: 'FAIL!'}, resp])
+ AWS.HttpClient.getInstance.andReturn handleRequest: (req, cb, errCb) ->
+ if retryCount < numFailures
+ retryCount += 1
+ errCb code: 'NetworkingError', message: 'FAIL!'
else
- req.emit('httpHeaders', [(resp.retryCount < numFailures ? 500 : status), headers, resp])
- str = str instanceof Array ? str : [str]
- AWS.util.arrayEach data, (str) ->
- req.emit('httpData', [new Buffer(str), resp])
- req.emit('httpDone', [resp])
+ statusCode = retryCount < numFailures ? 500 : status
+ mockHttpSuccessfulResponse statusCode, headers, data, cb
module.exports =
AWS: AWS
View
16 test/node_http_client.spec.coffee
@@ -13,21 +13,17 @@
helpers = require('./helpers')
AWS = helpers.AWS
-MockClient = helpers.MockClient
describe 'AWS.NodeHttpClient', ->
http = new AWS.NodeHttpClient()
describe 'handleRequest', ->
- it 'emits httpError in error event', ->
+ it 'emits error event', ->
done = false
endpoint = new AWS.Endpoint('http://invalid')
- req = new AWS.Request(endpoint: endpoint, config: region: 'empty')
- resp = new AWS.Response(req)
- req.on 'httpError', (cbErr, cbResp) ->
- expect(cbErr instanceof Error).toBeTruthy()
- expect(cbResp).toBe(resp)
- done = true
-
- runs -> http.handleRequest(req, resp)
+ req = endpoint: endpoint
+ runs ->
+ stream = http.handleRequest req, null, (err) ->
+ expect(err.code).toEqual 'ENOTFOUND'
+ done = true
waitsFor -> done
View
33 test/request.spec.coffee
@@ -12,6 +12,7 @@
# language governing permissions and limitations under the License.
helpers = require('./helpers')
+EventEmitter = require('events').EventEmitter
AWS = helpers.AWS
MockClient = helpers.MockClient
@@ -65,11 +66,14 @@ describe 'AWS.Request', ->
it 'streams partial data and raises an error', ->
data = ''; error = null; reqError = null; done = false
spyOn(AWS.HttpClient, 'getInstance')
- AWS.HttpClient.getInstance.andReturn handleRequest: (req, resp) ->
- req.emit('httpHeaders', [200, {}, resp])
+ AWS.HttpClient.getInstance.andReturn handleRequest: (req, cb, errCb) ->
+ req = new EventEmitter()
+ req.statusCode = 200
+ req.headers = {}
+ cb(req)
AWS.util.arrayEach ['FOO', 'BAR', 'BAZ'], (str) ->
- req.emit('httpData', [new Buffer(str), resp])
- req.emit('httpError', [new Error('fail'), resp])
+ req.emit 'data', new Buffer(str)
+ errCb new Error('fail')
runs ->
request = client.makeRequest('mockMethod')
@@ -86,21 +90,24 @@ describe 'AWS.Request', ->
it 'fails if retry occurs in the middle of a failing stream', ->
data = ''; error = null; reqError = null; resp = null
+ retryCount = 0
spyOn(AWS.HttpClient, 'getInstance')
- AWS.HttpClient.getInstance.andReturn handleRequest: (req, resp) ->
+ AWS.HttpClient.getInstance.andReturn handleRequest: (req, cb, errCb) ->
+ req = new EventEmitter()
+ req.statusCode = 200
+ req.headers = {}
process.nextTick ->
- req.emit('httpHeaders', [200, {}, resp])
+ cb(req)
AWS.util.arrayEach ['FOO', 'BAR', 'BAZ', 'QUX'], (str) ->
- if str == 'BAZ' and resp.retryCount < 1
+ if str == 'BAZ' and retryCount < 1
process.nextTick ->
- req.emit('httpError', [{code: 'NetworkingError', message: 'FAIL!', retryable: true}, resp])
+ retryCount += 1
+ errCb code: 'NetworkingError', message: 'FAIL!', retryable: true
return AWS.util.abort
else
- process.nextTick ->
- req.emit('httpData', [new Buffer(str), resp])
- if resp.retryCount >= 1
- process.nextTick ->
- req.emit('httpDone', [resp])
+ process.nextTick -> req.emit 'data', new Buffer(str)
+ if retryCount >= 1
+ process.nextTick -> req.emit('end')
runs ->
request = client.makeRequest('mockMethod')
Please sign in to comment.
Something went wrong with that request. Please try again.