fixes #2 CookieList returning same data for each cookie

new structure for node-curl
This commit is contained in:
jiangfriend@gmail.com 2012-05-28 19:55:17 +08:00
parent e791a14c6e
commit 90f3135c8c
11 changed files with 461 additions and 237 deletions

193
lib/CurlBuilder.js Normal file
View file

@ -0,0 +1,193 @@
// Generated by ToffeeScript 1.3.3
(function() {
var Curl, CurlBuilder,
__hasProp = {}.hasOwnProperty,
__slice = [].slice;
try {
Curl = require(__dirname + '/../build/Release/node-curl').Curl;
} catch (e) {
Curl = require(__dirname + '/../build/default/node-curl').Curl;
}
CurlBuilder = (function() {
function CurlBuilder() {}
CurlBuilder.curls = {};
CurlBuilder.id = 0;
CurlBuilder.close_all = function() {
var curl, id, _ref;
_ref = CurlBuilder.curls;
for (id in _ref) {
if (!__hasProp.call(_ref, id)) continue;
curl = _ref[id];
curl.end();
delete CurlBuilder.curls[id];
}
return CurlBuilder;
};
CurlBuilder.create = function(defaultOptions) {
var curl;
curl = function() {
return curl.perform.apply(curl, arguments);
};
curl.perform = function() {
var args, c, cb, length, options, url;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (this.running) {
throw new Error('the cURL session is busy, use CurlBuilder.create to create another cURL Session');
}
if (!this.curl_) {
throw new Error('the cURL is closed.');
}
this.running = true;
cb = args.pop();
url = args[0], options = args[1];
if (options == null) {
options = {};
}
c = this.curl_;
options['URL'] = url;
c.chunks = [];
length = 0;
this.setOptions(options);
c.on_write = function(chunk) {
curl.log("receive " + chunk.length + " bytes");
c.chunks.push(chunk);
return length += chunk.length;
};
c.on_end = function() {
var chunk, data, position, _i, _len, _ref,
_this = this;
curl.log("receive succeeded.");
curl.running = false;
data = new Buffer(length);
position = 0;
_ref = c.chunks;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
chunk = _ref[_i];
chunk.copy(data, position);
position += chunk.length;
}
c.chunks = [];
if (c.options.RAW) {
curl.body = data;
} else {
curl.body = data.toString();
}
curl.status = curl.code = c.getinfo('RESPONSE_CODE');
return process.nextTick(function() {
return cb.call(curl, null, curl);
});
};
c.on_error = function(err) {
var _this = this;
curl.log("receive failed: " + err.message);
curl.running = false;
return process.nextTick(function() {
return cb.call(curl, err, null);
});
};
this.log('perform');
return c.perform();
};
curl.setDefaultOptions = function(options, reset) {
if (options == null) {
options = {};
}
if (reset == null) {
reset = true;
}
defaultOptions = options;
if (reset) {
this.log('Set default options and reset cURL');
return this.reset();
}
};
curl.log = function(text) {
if (this.debug) {
return console.info(("[cURL " + this.id + "] ") + text);
}
};
curl.setOptions = function(options) {
var k, v;
if (options == null) {
options = {};
}
for (k in options) {
if (!__hasProp.call(options, k)) continue;
v = options[k];
this.log("Set option '" + k + "' to '" + v + "'");
this.curl_.setopt(k, v);
}
return this;
};
curl.setopts = function(options) {
if (options == null) {
options = {};
}
return this.setOptions(options);
};
curl.info = function(info) {
if (this.curl_ == null) {
throw new Error('curl is closed');
}
return this.curl_.getinfo(info);
};
curl.end = function() {
if (this.curl_ != null) {
this.curl_.close();
}
this.curl_ = null;
this.body = null;
delete CurlBuilder.curls[this.id];
return this.log("closed.");
};
curl.close = function() {
return this.end();
};
curl.open = function() {
if (curl.id == null) {
curl.id = ++CurlBuilder.id;
}
this.log("opening.");
this.curl_ = new Curl();
this.curl_.options = {};
this.setOptions(defaultOptions);
CurlBuilder.curls[curl.id] = curl;
return this.log("opened.");
};
curl.reset = function() {
this.log('reset');
if (this.curl_) {
this.end();
}
return this.open();
};
curl.Curl = Curl;
curl.Builder = CurlBuilder;
curl.create = function(defaultOptions) {
return CurlBuilder.create(defaultOptions);
};
curl.get_count = function() {
return Curl.get_count();
};
curl.open();
return curl;
};
return CurlBuilder;
}).call(this);
process.on('exit', function() {
return CurlBuilder.close_all();
});
module.exports = CurlBuilder;
}).call(this);

136
lib/CurlBuilder.toffee Normal file
View file

@ -0,0 +1,136 @@
try
{Curl} = require __dirname + '/../build/Release/node-curl'
catch e
{Curl} = require __dirname + '/../build/default/node-curl'
class CurlBuilder
@curls: {}
@id: 0
@close_all: =>
for own id, curl of @curls
curl.end()
delete @curls[id]
@
@create: (defaultOptions) =>
curl = ->
curl.perform.apply curl, arguments
curl.perform = (args...) ->
if @running
throw new Error 'the cURL session is busy, use CurlBuilder.create to create another cURL Session'
if !@curl_
throw new Error 'the cURL is closed.'
@running = true
cb = args.pop()
[url, options] = args
options ?= {}
c = @curl_
options['URL'] = url
c.chunks = []
length = 0
@setOptions options
c.on_write = (chunk) ->
curl.log "receive #{chunk.length} bytes"
c.chunks.push chunk
length += chunk.length
c.on_end = ->
curl.log "receive succeeded."
curl.running = false
data = new Buffer(length)
position = 0
for chunk in c.chunks
chunk.copy data, position
position += chunk.length
c.chunks = []
if c.options.RAW
curl.body = data
else
curl.body = data.toString()
curl.status = curl.code = c.getinfo('RESPONSE_CODE')
# if curl returns to fast, avoid cb recursive call
process.nextTick!
cb.call curl, null, curl
c.on_error = (err)->
curl.log "receive failed: #{err.message}"
curl.running = false
process.nextTick!
cb.call curl, err, null
@log 'perform'
c.perform()
curl.setDefaultOptions = (options = {}, reset = true) ->
defaultOptions = options
if reset
@log 'Set default options and reset cURL'
@reset()
curl.log = (text) ->
if @debug
console.info "[cURL #{@id}] " + text
curl.setOptions = (options = {}) ->
for own k, v of options
@log "Set option '#{k}' to '#{v}'"
@curl_.setopt k, v
@
curl.setopts = (options = {}) ->
@setOptions options
curl.info = (info)->
unless @curl_?
throw new Error('curl is closed')
@curl_.getinfo(info)
curl.end = ->
@curl_.close() if @curl_?
@curl_ = null
@body = null
delete CurlBuilder.curls[@id]
@log "closed."
curl.close = ->
@end()
curl.open = ->
unless curl.id?
curl.id = ++CurlBuilder.id
@log "opening."
@curl_ = new Curl()
@curl_.options = {}
@setOptions defaultOptions
CurlBuilder.curls[curl.id] = curl
@log "opened."
curl.reset = ->
@log 'reset'
if @curl_
@end()
@open()
curl.Curl = Curl
curl.Builder = CurlBuilder
curl.create = (defaultOptions) ->
CurlBuilder.create(defaultOptions)
curl.get_count = ->
Curl.get_count()
curl.open()
curl
process.on 'exit', ->
CurlBuilder.close_all()
module.exports = CurlBuilder

View file

@ -1,8 +1,6 @@
// Generated by ToffeeScript 1.2.0-0
// Generated by ToffeeScript 1.3.3
(function() {
var Curl, curl, curl_id, curls,
__slice = [].slice,
__hasProp = {}.hasOwnProperty;
var Curl, CurlBuilder, curl;
try {
Curl = require(__dirname + '/../build/Release/node-curl').Curl;
@ -10,6 +8,8 @@
Curl = require(__dirname + '/../build/default/node-curl').Curl;
}
CurlBuilder = require(__dirname + '/CurlBuilder');
Curl.prototype.setopt_user_ = function(option_id, value) {
return this.options[option_id] = value;
};
@ -46,18 +46,20 @@
}
};
Curl.user_options = {
RAW: 'RAW'
};
Curl.prototype.perform = function() {
this.perform_();
return Curl.process();
};
Curl.user_options = {
RAW: 'RAW'
};
Curl.process = function() {
var once;
if (Curl.in_process) return;
if (Curl.in_process) {
return;
}
return (once = function() {
var num;
num = Curl.process_();
@ -70,85 +72,7 @@
})();
};
curl_id = 0;
curls = {};
curl = function() {
var args, c, cb, k, length, options, url, v;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
cb = args.pop();
url = args[0], options = args[1];
if (options == null) options = {};
c = new Curl();
c.options = {};
c.id = ++curl_id;
curls[c.id] = c;
c.setopt('FOLLOWLOCATION', 1);
c.setopt('ACCEPT_ENCODING', 'gzip');
c.chunks = [];
length = 0;
for (k in options) {
if (!__hasProp.call(options, k)) continue;
v = options[k];
c.setopt(k, v);
}
c.on_write = function(chunk) {
c.chunks.push(chunk);
return length += chunk.length;
};
c.on_end = function() {
var chunk, data, position, res, _i, _len, _ref,
_this = this;
data = new Buffer(length);
position = 0;
_ref = c.chunks;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
chunk = _ref[_i];
chunk.copy(data, position);
position += chunk.length;
}
c.chunks = [];
res = {};
res.curl_ = c;
delete curls[c.id];
if (c.options.RAW) {
res.body = data;
} else {
res.body = data.toString();
}
res.status = res.code = c.getinfo('RESPONSE_CODE');
res.info = function(info) {
if (this.curl_ == null) throw new Error('curl is closed');
return this.curl_.getinfo(info);
};
res.close = function() {
if (this.curl_ != null) this.curl_.close();
this.curl_ = null;
return this.body = null;
};
return process.nextTick(function() {
return cb(null, res);
});
};
c.on_error = function(err) {
var _this = this;
curls[c.id].close();
delete curls[c.id];
return process.nextTick(function() {
return cb(err, null);
});
};
c.setopt('URL', url);
c.perform();
return c;
};
curl.Curl = Curl;
curl.get_count = function() {
return Curl.get_count();
};
curl = CurlBuilder.create();
module.exports = curl;

View file

@ -3,6 +3,8 @@ try
catch e
{Curl} = require __dirname + '/../build/default/node-curl'
CurlBuilder = require __dirname + '/CurlBuilder'
Curl::setopt_user_ = (option_id, value) ->
@options[option_id] = value
@ -35,13 +37,13 @@ Curl::getinfo = (oinfo) ->
else
throw new Error("unsupported info #{oinfo}")
Curl.user_options =
RAW: 'RAW'
Curl::perform = ->
@perform_()
Curl.process()
Curl.user_options =
RAW: 'RAW'
Curl.process = ->
if Curl.in_process
return
@ -53,77 +55,5 @@ Curl.process = ->
else
Curl.in_process = false
# url, [options], cb
curl_id = 0
curls = {}
curl = (args...) ->
cb = args.pop()
[url, options] = args
options ?= {}
c = new Curl()
c.options = {}
c.id = ++curl_id
# after the scope c will not valid any more, so add to curls to keep c alive
curls[c.id] = c
c.setopt 'FOLLOWLOCATION', 1
c.setopt 'ACCEPT_ENCODING', 'gzip'
c.chunks = []
length = 0
for own k, v of options
c.setopt k, v
c.on_write = (chunk) ->
c.chunks.push chunk
length += chunk.length
c.on_end = ->
data = new Buffer(length)
position = 0
for chunk in c.chunks
chunk.copy data, position
position += chunk.length
c.chunks = []
res = {}
# now the c is in res.curl, delete curl in curls
# if res destruct, curl will be destruct after gc
res.curl_ = c
delete curls[c.id]
if c.options.RAW
res.body = data
else
res.body = data.toString() #.toString()
res.status = res.code = c.getinfo('RESPONSE_CODE')
res.info = (info)->
unless @curl_?
throw new Error('curl is closed')
@curl_.getinfo(info)
res.close = ->
@curl_.close() if @curl_?
@curl_ = null
@body = null
# if curl returns to fast, avoid cb recursive call
process.nextTick!
cb null, res
c.on_error = (err)->
curls[c.id].close()
delete curls[c.id]
process.nextTick!
cb err, null
c.setopt('URL', url)
c.perform()
c
curl.Curl = Curl
curl.get_count = ->
Curl.get_count()
curl = CurlBuilder.create()
module.exports = curl