diff --git a/examples/curl.js b/examples/curl.js index bbe7a43..ae304ad 100644 --- a/examples/curl.js +++ b/examples/curl.js @@ -1,4 +1,4 @@ -// Generated by ToffeeScript 1.6.2 +// Generated by ToffeeScript 1.6.2-5 (function() { var curl, err, p, res, _this = this; @@ -9,7 +9,8 @@ curl(process.argv[2], { VERBOSE: 1, - DEBUG: 1 + DEBUG: 1, + FOLLOWLOCATION: 1 }, function() { err = arguments[0], res = arguments[1]; if (err) { diff --git a/examples/curl.toffee b/examples/curl.toffee index 21171b9..9dee6eb 100644 --- a/examples/curl.toffee +++ b/examples/curl.toffee @@ -1,7 +1,7 @@ curl = require '../index' 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 p err else diff --git a/examples/post-multi-part.js b/examples/post-multi-part.js index 1232c65..85f5084 100644 --- a/examples/post-multi-part.js +++ b/examples/post-multi-part.js @@ -1,4 +1,4 @@ -// Generated by ToffeeScript 1.6.2 +// Generated by ToffeeScript 1.6.2-5 (function() { var curl, p; @@ -10,12 +10,19 @@ curl('127.0.0.1/upload.php', { 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) { console.log(e); - console.log(curl.body); + console.log(this.body); + return this.close(); }); }).call(this); diff --git a/examples/pressure.js b/examples/pressure.js index fbc45c8..665d896 100644 --- a/examples/pressure.js +++ b/examples/pressure.js @@ -1,4 +1,4 @@ -// Generated by ToffeeScript 1.4.0 +// Generated by ToffeeScript 1.6.2-5 (function() { var Curl, assert, i, j, next, _fn, _i; @@ -17,16 +17,15 @@ var curl, once; curl = Curl.create(); return (once = function() { - var _this = this; - return curl('localhost/test.html', function(_$$_err, _$$_res) { - var err, res; - err = _$$_err; - res = _$$_res; + var err, res, + _this = this; + curl('localhost/test.html', function() { + err = arguments[0], res = arguments[1]; assert.equal(res.body.length, 1468); if (++j % 100 === 0) { console.info(j); } - if (j < 5000) { + if (j < 500000) { return once(); } }); diff --git a/examples/pressure.toffee b/examples/pressure.toffee index db466a8..f5a17f6 100644 --- a/examples/pressure.toffee +++ b/examples/pressure.toffee @@ -13,6 +13,6 @@ for i in [1..100] assert.equal res.body.length, 1468 if ++j % 100 == 0 console.info j - if j < 5000 + if j < 500000 once() # res.close() diff --git a/examples/test.js b/examples/test.js index 836edaf..ffc62f7 100644 --- a/examples/test.js +++ b/examples/test.js @@ -1,4 +1,4 @@ -// Generated by ToffeeScript 1.6.2 +// Generated by ToffeeScript 1.6.2-5 (function() { var cookieFile, curl, err, fs, options, p, stream, util, _this = this; diff --git a/lib/Curl.js b/lib/Curl.js index de08b88..a0c4924 100644 --- a/lib/Curl.js +++ b/lib/Curl.js @@ -1,4 +1,4 @@ -// Generated by ToffeeScript 1.6.2 +// Generated by ToffeeScript 1.6.2-5 (function() { var Curl, curls, e, id, m, p, __hasProp = {}.hasOwnProperty; @@ -102,6 +102,11 @@ return callback.call(_this, chunk); }; break; + case 'header': + this.on_header = function(chunk) { + return callback.call(_this, chunk); + }; + break; case 'error': this.on_error = function(e) { delete curls[_this.id]; diff --git a/lib/Curl.toffee b/lib/Curl.toffee index 1ff83cf..c6401f0 100644 --- a/lib/Curl.toffee +++ b/lib/Curl.toffee @@ -78,6 +78,9 @@ Curl::on = (event, callback) -> # (Buffer chunk) -> @on_write = (chunk) => callback.call @, chunk + when 'header' + @on_header = (chunk) => + callback.call @, chunk when 'error' # (Error error) -> @on_error = (e) => diff --git a/lib/CurlBuilder.js b/lib/CurlBuilder.js index f09aed3..244607b 100644 --- a/lib/CurlBuilder.js +++ b/lib/CurlBuilder.js @@ -1,4 +1,4 @@ -// Generated by ToffeeScript 1.6.2 +// Generated by ToffeeScript 1.6.2-5 (function() { var Curl, CurlBuilder, e, __hasProp = {}.hasOwnProperty, @@ -11,6 +11,18 @@ 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() { function CurlBuilder() {} @@ -31,12 +43,11 @@ }; CurlBuilder.create = function(defaultOptions) { - var curl; - curl = function() { + function curl() { return curl.perform.apply(curl, arguments); }; 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) : []; if (this.running) { throw new Error('the cURL session is busy, use curl.create to create another cURL Session'); @@ -51,6 +62,7 @@ this.options = {}; } length = 0; + header_length = 0; this.debug = (_ref1 = (_ref2 = this.defaultOptions.DEBUG) != null ? _ref2 : this.options.DEBUG) != null ? _ref1 : this.debug; this.effectiveOptions = {}; _ref3 = this.defaultOptions; @@ -69,30 +81,34 @@ }); c = this.curl_; c.chunks = []; + c.header_chunks = []; c.on('data', function(chunk) { curl.log("receive " + chunk.length + " bytes"); c.chunks.push(chunk); length += 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() { - var chunk, data, position, _i, _len, _ref5, + var data, header, _this = this; curl.log("receive succeeded."); curl.running = false; - data = new Buffer(length); - position = 0; - _ref5 = c.chunks; - for (_i = 0, _len = _ref5.length; _i < _len; _i++) { - chunk = _ref5[_i]; - chunk.copy(data, position); - position += chunk.length; - } + data = merge_chunks(c.chunks, length); + header = merge_chunks(c.header_chunks, header_length); c.chunks = []; + c.header_chunks = []; if (c.options.RAW) { curl.body = data; + curl.header = header; } else { curl.body = data.toString(); + curl.header = header.toString(); } curl.status = curl.code = c.getinfo('RESPONSE_CODE'); process.nextTick(function() { diff --git a/lib/CurlBuilder.toffee b/lib/CurlBuilder.toffee index 216ad8b..44bc7ff 100644 --- a/lib/CurlBuilder.toffee +++ b/lib/CurlBuilder.toffee @@ -3,6 +3,14 @@ try catch e 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 @curls: {} @id: 0 @@ -31,6 +39,7 @@ class CurlBuilder @options ?= {} length = 0 + header_length = 0 @debug = @defaultOptions.DEBUG ? @options.DEBUG ? @debug @effectiveOptions = {} @@ -45,26 +54,33 @@ class CurlBuilder c = @curl_ c.chunks = [] + c.header_chunks = [] c.on 'data', (chunk) -> curl.log "receive #{chunk.length} bytes" c.chunks.push 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', -> 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 + data = merge_chunks(c.chunks, length) + header = merge_chunks(c.header_chunks, header_length) c.chunks = [] + c.header_chunks = [] if c.options.RAW curl.body = data + curl.header = header else curl.body = data.toString() + curl.header = header.toString() curl.status = curl.code = c.getinfo('RESPONSE_CODE') # if curl returns to fast, avoid cb recursive call diff --git a/src/node-curl.h b/src/node-curl.h index 01ba2dd..ada352d 100644 --- a/src/node-curl.h +++ b/src/node-curl.h @@ -132,6 +132,8 @@ class NodeCurl } curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_function); 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; } @@ -193,6 +195,13 @@ class NodeCurl 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) { static v8::Persistent SYM_ON_WRITE = v8::Persistent::New(v8::String::NewSymbol("on_write")); @@ -210,6 +219,23 @@ class NodeCurl return n; } + size_t on_header(char *data, size_t n) + { + static v8::Persistent SYM_ON_HEADER = v8::Persistent::New(v8::String::NewSymbol("on_header")); + v8::Handle cb = handle->Get(SYM_ON_HEADER); + if (cb->IsFunction()) + { + node::Buffer * buffer = node::Buffer::New(data, n); + v8::Handle argv[] = { buffer->handle_ }; + v8::Handle rt = cb->ToObject()->CallAsFunction(handle, 1, argv); + if (rt.IsEmpty()) + return 0; + else + return rt->Int32Value(); + } + return n; + } + void on_end(CURLMsg *msg) { static v8::Persistent SYM_ON_END = v8::Persistent::New(v8::String::NewSymbol("on_end"));