-
-
Save ishiduca/2280639 to your computer and use it in GitHub Desktop.
var events,http, url, path; | |
events = require('events'); | |
http = require('http'); | |
url = require('url'); | |
path = require('path'); | |
var agents = {}; | |
agent.onSocketsLengthChange; | |
if (http.getAgent) { | |
agents.onSocketsLengthChange = function (agent) { | |
var helper; | |
while (agent.sockets.length < agent.maxSockets && agent.waitRequests.length > 0) { | |
helper = agent.waitRequests.shift(); | |
helper(); | |
} | |
agent.sockets.forEach(function (socket, i) { | |
if (! socket.hasOnCloseListener) { | |
socket.hasOnCloseListener = 1; | |
socket.once('close', function (had_error) { | |
if (had_error) { | |
console.log('sockets[' + i + '/' + agent.sockets.length + '] is closing by error'); | |
} | |
agents.onSocketsLengthChange(agent); | |
}); | |
console.log('set agent.sockets[' + i + '] "hasOnCloseListener"'); | |
} | |
}); | |
}; | |
} | |
function httpRequest (/* getURL, method, options, onResponse */) { | |
var that, agentid, helper, | |
args, getURL, uri, uriPath, method, options, headers, body, requestOptions; | |
that = this; | |
args = Array.prototype.slice.apply(arguments); | |
getURL = args.shift(); | |
onResponse = args.pop(); | |
method = args.shift() || 'GET'; | |
method = method.toUpperCase(); | |
options = args.shift() || {}; | |
if (options.body) { | |
body = options.body || null; | |
delete options.body; | |
} | |
headers = options; | |
uri = url.parse(getURL()); | |
uriPath = (! uri.pathname) ? '/' | |
: (uri.pathname.slice(0, 1) === '/') ? uri.pathname | |
: '/' + uri.pathname; | |
if (uri.search) uriPath += uri.search; | |
if (method === 'POST') { | |
headers['content-type'] = headers['content-type'] || 'application/x-www-form-urlencoded'; | |
headers['content-length'] = (body) ? Buffer.byteLength(body) : 0; | |
} | |
if (! headers.referer && this.referer) headers.referer = this.referer; | |
if (! headers.cookie && this.cookie) headers.cookie = this.cookie; | |
requestOptions = { | |
method : method, | |
host : uri.host, | |
port : (uri.port) ? uri.port : (uri.protocol === 'https') ? '443' : '80', | |
path : uriPath, | |
headers : headers | |
}; | |
helper = function () { | |
var req; | |
req = http.request(requestOptions); | |
req.on('error', function (error) { | |
console.log(error); | |
process.exit(1); | |
}); | |
req.on('response', function (response) { | |
var statusCode, responseHeaders, _onResponse; | |
statusCode = response.statusCode; | |
responseHeaders = response.headers; | |
if (responseHeaders['set-cookie']) that.cookie = responseHeaders['set-cookie'][0]; | |
that.referer = uri.href; | |
if (that.redirect && statusCode >= 300 && statusCode < 400 && responseHeaders.location) { | |
_onResponse = onResponse; | |
httpRequest( | |
function () { return responseHeaders.location; }, 'GET', | |
{ referer : that.referer, cookie : that.cookie }, | |
function (response, request) { | |
_onResponse(response, request); | |
} | |
) | |
return; | |
} | |
onResponse(response, [ uri.href, headers, body ]); | |
}); | |
if (body) req.write(body); | |
req.end(); | |
}; | |
if (agents.onSocketsLengthChange) { | |
agentid = [ requestOptions.host, requestOptions.port ].join(':'); | |
if (! agents[agentid]) { | |
agents[agentid] = http.getAgent(requestOptions.host, requestOptions.port); | |
agents[agentid].waitRequests = []; | |
agents[agentid].maxSockets = 2; | |
} | |
agents[agentid].waitRequests.push(helper); | |
agents.onSocketsLengthChange(agents[agentid]); | |
return; | |
} | |
helper(); | |
} | |
exports.httpRequest = httpRequest; |
node 0.5.3 以降には、HTTP クライアントリクエストのソケットを プーリングするために新しい HTTP Agent の実装が存在します。
以前は、エージェントの一つのインスタンスが一つのホスト + ポートのプールを 助けていましたが、現在の実装では任意の数のホストに対するソケットを 保持できるようになりました。
現在の HTTP Agent では、クライアントリクエストはデフォルトで Connection:keep-alive を使うようにもなりました。 ソケットを待ってペンディングになっている HTTP リクエストがなければ、 ソケットはクローズされます。 これは、node のプールは高負荷時に keep-alive のメリットを持ちながら、 keep-alive を使用する HTTP クライアントを開発者が手動でクローズする 必要がないことを意味します。
ということなので、v5.3+ だとこんな処理の必要がない
追記: v5.3+ 以上でもエラーが起きないように対応した 2012.04.03
勉強になりました。助かりました、ありがとうございます。
var httpRequest = function(/* getURL, method, options, onResponse */)
{
//..
}
のほうが良いように思います。WebStormでは、コンスタントなバリューをエクスポートしようとしているというエラーがでました。
kenokabe
ご指摘ありがとうございます。
WebStrom は使ったことなかったので見直したいと思います。
どういたしまして、
あと、どうしてもわからないので、教えていただきたいのですが、
Cannot read property 'onSocketsLengthChange' of undefined
という例外がでまして、
それは多分agentがundefinedなのだと思いますが、
特に、ライブラリの
var agents;
if (http.getAgent) {
agents = {};
agents.onSocketsLengthChange = function (agent) {
......
の部分は、
続くダウンローダーサンプルのように、
httpRequest = require('./httpclient').httpRequest;
としても、けしてリーチできないブロックにあるのではないでしょうか?
node のバージョンはなんでしょうか?
v0.4.12 では agents.onSocketsLengthChange は正常に呼び出されてるんで、なんだろう...
追記:
バグでした。直しました。
v0.6.17(現時点で最新のバージョン)です。
IRCでこの辺よくわからず質問したところ、このバージョンでhttp周りのメモリリークなど多くの改善がされているようです。
修正どうもありがとうございました。
こちらこそ勉強になりました
8行目の
var agents;
の所で、 agents が定義されていないのが問題だったので
var agents = {};
agents.onSocketsLengthChange;
とすることでバグを回避しました。
実際の所、古いバージョンを使わない限り agent 周りは弄る必要がないので、不要な部分は削除していいと思います
ダウンローダーのサンプル