Extract header.

This commit is contained in:
Miao Jiang 2013-05-25 16:00:35 +08:00
parent b77ee78afd
commit 8de753eec9
11 changed files with 108 additions and 35 deletions

View file

@ -1,4 +1,4 @@
// Generated by ToffeeScript 1.6.2 // Generated by ToffeeScript 1.6.2-5
(function() { (function() {
var curl, err, p, res, var curl, err, p, res,
_this = this; _this = this;
@ -9,7 +9,8 @@
curl(process.argv[2], { curl(process.argv[2], {
VERBOSE: 1, VERBOSE: 1,
DEBUG: 1 DEBUG: 1,
FOLLOWLOCATION: 1
}, function() { }, function() {
err = arguments[0], res = arguments[1]; err = arguments[0], res = arguments[1];
if (err) { if (err) {

View file

@ -1,7 +1,7 @@
curl = require '../index' curl = require '../index'
p = console.info p = console.info
err, res = curl! process.argv[2], {VERBOSE: 1, DEBUG: 1} err, res = curl! process.argv[2], {VERBOSE: 1, DEBUG: 1, FOLLOWLOCATION: 1}
if err if err
p err p err
else else

View file

@ -1,4 +1,4 @@
// Generated by ToffeeScript 1.6.2 // Generated by ToffeeScript 1.6.2-5
(function() { (function() {
var curl, p; var curl, p;
@ -10,12 +10,19 @@
curl('127.0.0.1/upload.php', { curl('127.0.0.1/upload.php', {
multipart: [ multipart: [
{name: 'file', file: '/home/miao/test.js', type: 'text/html'}, {
{name: 'sumbit', value: 'send'} name: 'file',
file: '/home/miao/test.js',
type: 'text/html'
}, {
name: 'sumbit',
contents: 'send'
}
] ]
}, function(e) { }, function(e) {
console.log(e); console.log(e);
console.log(curl.body); console.log(this.body);
return this.close();
}); });
}).call(this); }).call(this);

View file

@ -1,4 +1,4 @@
// Generated by ToffeeScript 1.4.0 // Generated by ToffeeScript 1.6.2-5
(function() { (function() {
var Curl, assert, i, j, next, _fn, _i; var Curl, assert, i, j, next, _fn, _i;
@ -17,16 +17,15 @@
var curl, once; var curl, once;
curl = Curl.create(); curl = Curl.create();
return (once = function() { return (once = function() {
var _this = this; var err, res,
return curl('localhost/test.html', function(_$$_err, _$$_res) { _this = this;
var err, res; curl('localhost/test.html', function() {
err = _$$_err; err = arguments[0], res = arguments[1];
res = _$$_res;
assert.equal(res.body.length, 1468); assert.equal(res.body.length, 1468);
if (++j % 100 === 0) { if (++j % 100 === 0) {
console.info(j); console.info(j);
} }
if (j < 5000) { if (j < 500000) {
return once(); return once();
} }
}); });

View file

@ -13,6 +13,6 @@ for i in [1..100]
assert.equal res.body.length, 1468 assert.equal res.body.length, 1468
if ++j % 100 == 0 if ++j % 100 == 0
console.info j console.info j
if j < 5000 if j < 500000
once() once()
# res.close() # res.close()

View file

@ -1,4 +1,4 @@
// Generated by ToffeeScript 1.6.2 // Generated by ToffeeScript 1.6.2-5
(function() { (function() {
var cookieFile, curl, err, fs, options, p, stream, util, var cookieFile, curl, err, fs, options, p, stream, util,
_this = this; _this = this;

View file

@ -1,4 +1,4 @@
// Generated by ToffeeScript 1.6.2 // Generated by ToffeeScript 1.6.2-5
(function() { (function() {
var Curl, curls, e, id, m, p, var Curl, curls, e, id, m, p,
__hasProp = {}.hasOwnProperty; __hasProp = {}.hasOwnProperty;
@ -102,6 +102,11 @@
return callback.call(_this, chunk); return callback.call(_this, chunk);
}; };
break; break;
case 'header':
this.on_header = function(chunk) {
return callback.call(_this, chunk);
};
break;
case 'error': case 'error':
this.on_error = function(e) { this.on_error = function(e) {
delete curls[_this.id]; delete curls[_this.id];

View file

@ -78,6 +78,9 @@ Curl::on = (event, callback) ->
# (Buffer chunk) -> # (Buffer chunk) ->
@on_write = (chunk) => @on_write = (chunk) =>
callback.call @, chunk callback.call @, chunk
when 'header'
@on_header = (chunk) =>
callback.call @, chunk
when 'error' when 'error'
# (Error error) -> # (Error error) ->
@on_error = (e) => @on_error = (e) =>

View file

@ -1,4 +1,4 @@
// Generated by ToffeeScript 1.6.2 // Generated by ToffeeScript 1.6.2-5
(function() { (function() {
var Curl, CurlBuilder, e, var Curl, CurlBuilder, e,
__hasProp = {}.hasOwnProperty, __hasProp = {}.hasOwnProperty,
@ -11,6 +11,18 @@
Curl = require(__dirname + '/Curl'); Curl = require(__dirname + '/Curl');
} }
function merge_chunks(chunks, length) {
var chunk, data, position, _i, _len;
data = new Buffer(length);
position = 0;
for (_i = 0, _len = chunks.length; _i < _len; _i++) {
chunk = chunks[_i];
chunk.copy(data, position);
position += chunk.length;
}
return data;
};
CurlBuilder = (function() { CurlBuilder = (function() {
function CurlBuilder() {} function CurlBuilder() {}
@ -31,12 +43,11 @@
}; };
CurlBuilder.create = function(defaultOptions) { CurlBuilder.create = function(defaultOptions) {
var curl; function curl() {
curl = function() {
return curl.perform.apply(curl, arguments); return curl.perform.apply(curl, arguments);
}; };
curl.perform = function() { curl.perform = function() {
var args, c, cb, k, length, v, _ref, _ref1, _ref2, _ref3, _ref4; var args, c, cb, header_length, k, length, v, _ref, _ref1, _ref2, _ref3, _ref4;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (this.running) { if (this.running) {
throw new Error('the cURL session is busy, use curl.create to create another cURL Session'); throw new Error('the cURL session is busy, use curl.create to create another cURL Session');
@ -51,6 +62,7 @@
this.options = {}; this.options = {};
} }
length = 0; length = 0;
header_length = 0;
this.debug = (_ref1 = (_ref2 = this.defaultOptions.DEBUG) != null ? _ref2 : this.options.DEBUG) != null ? _ref1 : this.debug; this.debug = (_ref1 = (_ref2 = this.defaultOptions.DEBUG) != null ? _ref2 : this.options.DEBUG) != null ? _ref1 : this.debug;
this.effectiveOptions = {}; this.effectiveOptions = {};
_ref3 = this.defaultOptions; _ref3 = this.defaultOptions;
@ -69,30 +81,34 @@
}); });
c = this.curl_; c = this.curl_;
c.chunks = []; c.chunks = [];
c.header_chunks = [];
c.on('data', function(chunk) { c.on('data', function(chunk) {
curl.log("receive " + chunk.length + " bytes"); curl.log("receive " + chunk.length + " bytes");
c.chunks.push(chunk); c.chunks.push(chunk);
length += chunk.length; length += chunk.length;
return chunk.length; return chunk.length;
}); });
c.on('header', function(chunk) {
curl.log("receive " + chunk.length + " header");
c.header_chunks.push(chunk);
header_length += chunk.length;
return chunk.length;
});
c.on('end', function() { c.on('end', function() {
var chunk, data, position, _i, _len, _ref5, var data, header,
_this = this; _this = this;
curl.log("receive succeeded."); curl.log("receive succeeded.");
curl.running = false; curl.running = false;
data = new Buffer(length); data = merge_chunks(c.chunks, length);
position = 0; header = merge_chunks(c.header_chunks, header_length);
_ref5 = c.chunks;
for (_i = 0, _len = _ref5.length; _i < _len; _i++) {
chunk = _ref5[_i];
chunk.copy(data, position);
position += chunk.length;
}
c.chunks = []; c.chunks = [];
c.header_chunks = [];
if (c.options.RAW) { if (c.options.RAW) {
curl.body = data; curl.body = data;
curl.header = header;
} else { } else {
curl.body = data.toString(); curl.body = data.toString();
curl.header = header.toString();
} }
curl.status = curl.code = c.getinfo('RESPONSE_CODE'); curl.status = curl.code = c.getinfo('RESPONSE_CODE');
process.nextTick(function() { process.nextTick(function() {

View file

@ -3,6 +3,14 @@ try
catch e catch e
Curl = require __dirname + '/Curl' Curl = require __dirname + '/Curl'
merge_chunks = (chunks, length) ->
data = new Buffer(length)
position = 0
for chunk in chunks
chunk.copy data, position
position += chunk.length
data
class CurlBuilder class CurlBuilder
@curls: {} @curls: {}
@id: 0 @id: 0
@ -31,6 +39,7 @@ class CurlBuilder
@options ?= {} @options ?= {}
length = 0 length = 0
header_length = 0
@debug = @defaultOptions.DEBUG ? @options.DEBUG ? @debug @debug = @defaultOptions.DEBUG ? @options.DEBUG ? @debug
@effectiveOptions = {} @effectiveOptions = {}
@ -45,26 +54,33 @@ class CurlBuilder
c = @curl_ c = @curl_
c.chunks = [] c.chunks = []
c.header_chunks = []
c.on 'data', (chunk) -> c.on 'data', (chunk) ->
curl.log "receive #{chunk.length} bytes" curl.log "receive #{chunk.length} bytes"
c.chunks.push chunk c.chunks.push chunk
length += chunk.length length += chunk.length
chunk.length chunk.length
c.on 'header', (chunk) ->
curl.log "receive #{chunk.length} header"
c.header_chunks.push chunk
header_length += chunk.length
chunk.length
c.on 'end', -> c.on 'end', ->
curl.log "receive succeeded." curl.log "receive succeeded."
curl.running = false curl.running = false
data = new Buffer(length) data = merge_chunks(c.chunks, length)
position = 0 header = merge_chunks(c.header_chunks, header_length)
for chunk in c.chunks
chunk.copy data, position
position += chunk.length
c.chunks = [] c.chunks = []
c.header_chunks = []
if c.options.RAW if c.options.RAW
curl.body = data curl.body = data
curl.header = header
else else
curl.body = data.toString() curl.body = data.toString()
curl.header = header.toString()
curl.status = curl.code = c.getinfo('RESPONSE_CODE') curl.status = curl.code = c.getinfo('RESPONSE_CODE')
# if curl returns to fast, avoid cb recursive call # if curl returns to fast, avoid cb recursive call

View file

@ -132,6 +132,8 @@ class NodeCurl
} }
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_function); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_function);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, this); curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_function);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, this);
curls[curl] = this; curls[curl] = this;
} }
@ -193,6 +195,13 @@ class NodeCurl
return nodecurl->on_write(ptr, size * nmemb); return nodecurl->on_write(ptr, size * nmemb);
} }
static size_t header_function(char *ptr, size_t size, size_t nmemb, void *userdata)
{
transfered += size * nmemb;
NodeCurl *nodecurl = (NodeCurl*)userdata;
return nodecurl->on_header(ptr, size * nmemb);
}
size_t on_write(char *data, size_t n) size_t on_write(char *data, size_t n)
{ {
static v8::Persistent<v8::String> SYM_ON_WRITE = v8::Persistent<v8::String>::New(v8::String::NewSymbol("on_write")); static v8::Persistent<v8::String> SYM_ON_WRITE = v8::Persistent<v8::String>::New(v8::String::NewSymbol("on_write"));
@ -210,6 +219,23 @@ class NodeCurl
return n; return n;
} }
size_t on_header(char *data, size_t n)
{
static v8::Persistent<v8::String> SYM_ON_HEADER = v8::Persistent<v8::String>::New(v8::String::NewSymbol("on_header"));
v8::Handle<v8::Value> cb = handle->Get(SYM_ON_HEADER);
if (cb->IsFunction())
{
node::Buffer * buffer = node::Buffer::New(data, n);
v8::Handle<v8::Value> argv[] = { buffer->handle_ };
v8::Handle<v8::Value> rt = cb->ToObject()->CallAsFunction(handle, 1, argv);
if (rt.IsEmpty())
return 0;
else
return rt->Int32Value();
}
return n;
}
void on_end(CURLMsg *msg) void on_end(CURLMsg *msg)
{ {
static v8::Persistent<v8::String> SYM_ON_END = v8::Persistent<v8::String>::New(v8::String::NewSymbol("on_end")); static v8::Persistent<v8::String> SYM_ON_END = v8::Persistent<v8::String>::New(v8::String::NewSymbol("on_end"));