diff --git a/lib/_utils.js b/lib/_utils.js new file mode 100644 index 0000000..1efd336 --- /dev/null +++ b/lib/_utils.js @@ -0,0 +1,4 @@ +// Returns true if this is a host that closes *before* it ends?!?! +module.exports.isAnEarlyCloseHost= function( hostName ) { + return hostName.match(".*google.com$") +} \ No newline at end of file diff --git a/lib/oauth.js b/lib/oauth.js index c7f3b82..d231b13 100644 --- a/lib/oauth.js +++ b/lib/oauth.js @@ -3,7 +3,8 @@ var crypto= require('crypto'), http= require('http'), https= require('https'), URL= require('url'), - querystring= require('querystring'); + querystring= require('querystring'), + OAuthUtils= require('./_utils'); exports.OAuth= function(requestUrl, accessUrl, consumerKey, consumerSecret, version, authorize_callback, signatureMethod, nonceSize, customHeaders) { this._isEcho = false; @@ -344,12 +345,14 @@ exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_toke if( callback ) { var data=""; var self= this; - request.on('response', function (response) { - response.setEncoding('utf8'); - response.on('data', function (chunk) { - data+=chunk; - }); - response.on('end', function () { + + // Some hosts *cough* google appear to close the connection early / send no content-length header + // allow this behaviour. + var allowEarlyClose= OAuthUtils.isAnEarlyCloseHost( parsedUrl.hostname ); + var callbackCalled= false; + function passBackControl( response ) { + if(!callbackCalled) { + callbackCalled= true; if ( response.statusCode >= 200 && response.statusCode <= 299 ) { callback(null, data, response); } else { @@ -361,10 +364,28 @@ exports.OAuth.prototype._performSecureRequest= function( oauth_token, oauth_toke callback({ statusCode: response.statusCode, data: data }, data, response); } } + } + } + + request.on('response', function (response) { + response.setEncoding('utf8'); + response.on('data', function (chunk) { + data+=chunk; + }); + response.on('end', function () { + passBackControl( response ); + }); + response.on('close', function () { + if( allowEarlyClose ) { + passBackControl( response ); + } }); }); - request.on("error", callback); + request.on("error", function(err) { + callbackCalled= true; + callback( err ) + }); if( (method == "POST" || method =="PUT") && post_body != null && post_body != "" ) { request.write(post_body); diff --git a/lib/oauth2.js b/lib/oauth2.js index 4713192..7b841fa 100644 --- a/lib/oauth2.js +++ b/lib/oauth2.js @@ -1,7 +1,8 @@ var querystring= require('querystring'), crypto= require('crypto'), https= require('https'), - URL= require('url'); + URL= require('url'), + OAuthUtils= require('./_utils'); exports.OAuth2= function(clientId, clientSecret, baseSite, authorizePath, accessTokenPath) { this._clientId= clientId; @@ -61,20 +62,37 @@ exports.OAuth2.prototype._request= function(method, url, headers, access_token, headers: realHeaders }; - request = https.request(options, function (response) { - response.addListener("data", function (chunk) { - result+= chunk - }); - response.addListener("end", function () { + // Some hosts *cough* google appear to close the connection early / send no content-length header + // allow this behaviour. + var allowEarlyClose= OAuthUtils.isAnEarlyCloseHost(options.host); + var callbackCalled= false; + function passBackControl( response, result ) { + if(!callbackCalled) { + callbackCalled=true; if( response.statusCode != 200 ) { callback({ statusCode: response.statusCode, data: result }); } else { callback(null, result, response); } + } + } + + request = https.request(options, function (response) { + response.on("data", function (chunk) { + result+= chunk + }); + response.on("close", function (err) { + if( allowEarlyClose ) { + passBackControl( response, result ); + } + }); + response.addListener("end", function () { + passBackControl( response, result ); }); }); request.on('error', function(e) { + callbackCalled= true; callback(e); });