Compare commits

...

79 commits

Author SHA1 Message Date
Josh Sherman
b12a319ebb Consider STRINGPOINT as string_options
URL changed from being an OBJECT to being a STRINGPOINT so when building
URL was being thrown as an invalid option. This resolves that but has
left me with a segfault :-/
2016-10-12 15:28:50 -05:00
Josh Sherman
98bd3a7e61 Updated to more recent variable name 2016-10-12 14:32:05 -05:00
Miao Jiang
288400f616 Bump version to 0.3.3 2014-09-03 15:41:04 +08:00
Miao Jiang
ce4a60be91 Merge branch 'master' of git://github.com/briancsparks/node-curl 2014-09-03 15:32:32 +08:00
Miao Jiang
1f3a2f1bad Fixes free incorrect variable. 2014-09-03 15:31:35 +08:00
Brian C Sparks
5e2abee688 Fix for 64-bit segfault 2014-06-12 14:20:58 -07:00
Miao Jiang
171f5bc3a6 Update package version. 2013-05-25 16:19:28 +08:00
Miao Jiang
05b8345650 Update README. 2013-05-25 16:19:07 +08:00
Miao Jiang
f02c0a6fbf Always make string copy for multi postdata. 2013-05-25 16:07:18 +08:00
Miao Jiang
8de753eec9 Extract header. 2013-05-25 16:00:35 +08:00
Miao Jiang
b77ee78afd Update README. 2013-04-14 18:40:44 +08:00
Miao Jiang
5c6e4b0b49 Bump version to 0.3.1. 2013-04-10 16:36:59 +08:00
Miao Jiang
e9e17fc940 Hotfix, release resource. 2013-04-10 16:36:52 +08:00
Miao Jiang
5e48419e18 Add string.h for strndup. 2013-04-10 03:40:16 +08:00
Miao Jiang
1ba3bb2329 Update travis to test for 0.8, 0.10 2013-04-10 03:31:26 +08:00
Miao Jiang
3a42f7f05e Bump version to 0.3.0. 2013-04-10 03:27:54 +08:00
Miao Jiang
788459bc7d Update README. 2013-04-10 03:22:32 +08:00
Miao Jiang
b337b6d4fb Rename value to contents. 2013-04-10 03:19:00 +08:00
Miao Jiang
9c1cbb81c9 Fix #15, Support multipart post. 2013-04-10 03:09:25 +08:00
Miao Jiang
e318a72006 bump version to 0.2.3 2013-03-01 14:42:56 +08:00
Miao Jiang
8f707b34b1 Catch exception. 2013-02-22 02:07:26 +08:00
Miao Jiang
279e9f04cc bump version to 0.2.2 2013-02-21 19:13:09 +08:00
Miao Jiang
78a53743de Improve code. 2013-02-21 19:05:32 +08:00
Miao Jiang
648e170fa8 Update README 2013-02-20 03:30:36 +08:00
Miao Jiang
91f39f4652 bump version to v0.2.1 2013-02-20 02:59:40 +08:00
Miao Jiang
745124ebd6 Fixes #11 Segmentation fault. 2013-02-20 02:58:50 +08:00
Miao Jiang
01dbe4e0ce Update README. 2013-02-19 21:27:30 +08:00
Miao Jiang
44fb876123 Update README. 2013-02-19 21:26:38 +08:00
Miao Jiang
286b62cc2e bump version to 0.2.0 2013-02-19 21:17:52 +08:00
Miao Jiang
e25785eb3f Update low level Curl help. 2013-02-19 21:17:12 +08:00
Miao Jiang
2884985e9a Add curl.js example. 2013-02-19 21:12:21 +08:00
Miao Jiang
7c776b81a5 Check option. 2013-02-19 21:09:39 +08:00
Miao Jiang
decb16d790 Remove Curl class from CurlBuilder. 2013-02-19 21:03:13 +08:00
Miao Jiang
ccfb0d4595 Add Curl.js. 2013-02-19 21:02:54 +08:00
Miao Jiang
1061e177b2 Improve performance. 2013-02-19 20:54:47 +08:00
Miao Jiang
02ba0f25d3 expose low level curl. 2013-02-19 20:12:33 +08:00
Miao Jiang
d25438bdf0 Add comments. 2013-02-19 17:31:59 +08:00
Miao Jiang
2c414d1469 Update Curl file structure. 2013-02-19 17:30:16 +08:00
Miao Jiang
1057195bf5 Transfer can be interrupted when streaming. #11 2013-02-19 01:04:42 +08:00
Miao Jiang
09c4caae42 bump version to v0.1.8 2013-01-06 03:40:31 +08:00
Miao Jiang
3b1ba2a279 Try node-gyp first. 2013-01-06 03:30:32 +08:00
Miao Jiang
579481cac9 Add NODE_MODULE exports. 2013-01-05 22:17:40 +08:00
Miao Jiang
9e50c006be bump to v0.1.7 2013-01-05 21:22:30 +08:00
Miao Jiang
54e981182b use -O1 instead of -O2 2013-01-05 21:22:22 +08:00
Miao Jiang
03e419747d Add binding.gyp for node v0.9 2013-01-05 21:22:11 +08:00
Miao Jiang
afab82abcf Remove travis node v0.7, add v0.8 v0.9 2012-12-24 21:13:49 +08:00
Miao Jiang
bf0b6555a8 stop building when curl.h isn't found. 2012-12-24 20:50:03 +08:00
Miao Jiang
4a7a5feacf fixes #13 scan curl.h
scan order
environment NODE_CURL_H,
path /usr/local/include/curl/curl.h
path /usr/include/curl/curl.h
2012-12-24 20:38:59 +08:00
Miao Jiang
b273758a40 Rename effective_options to effectiveOptions. 2012-12-01 21:39:13 +08:00
Miao Jiang
e37f47a072 bump version to v0.1.6 2012-11-29 17:07:04 +08:00
Miao Jiang
51dfa0ebdf Rename effective_options to effectiveOptions. 2012-11-29 17:04:28 +08:00
Miao Jiang
368cc3402b update README. 2012-11-29 17:03:23 +08:00
Miao Jiang
5dc00f43dc Rename effective_options to effectiveOptions. 2012-11-29 17:03:12 +08:00
Miao Jiang
a21831a17e ignore *.tgz. 2012-11-29 16:36:18 +08:00
Miao Jiang
2d5e67377b Regenerate js files. 2012-11-29 16:36:04 +08:00
Miao Jiang
9fe5666c9f fixes #9 compatible with old version libcurl. 2012-11-29 16:35:30 +08:00
Miao Jiang
6f9d7e24fa Get info test. 2012-11-29 16:34:10 +08:00
Miao Jiang
829db634a0 Keep quick-start.js simple. 2012-11-29 16:33:43 +08:00
Miao Jiang
d138705419 Add User Option: DEBUG. 2012-11-29 16:33:25 +08:00
Miao Jiang
13f1f69dbc Save url, options, defaultOptions in curl. 2012-11-29 16:33:10 +08:00
Miao Jiang
8e0d95d812 Save url to curl.url. 2012-11-29 14:55:56 +08:00
Miao Jiang
e796b240da Merge pull request #10 from kdridi/master
Fix access violation on mac OS X
2012-11-28 22:04:48 -08:00
Karim DRIDI
441b622709 Minor bug: Segmentation fault on getinfo for a unfilled value 2012-11-29 00:36:54 +01:00
Karim DRIDI
e089e15d85 BUG #6: Fix access violation on mac OS X 2012-11-28 23:28:39 +01:00
Miao Jiang
d92324115c bump to v0.1.5 2012-11-24 13:50:42 +08:00
Miao Jiang
844c70636b Remove date option for issue #8. 2012-11-24 13:45:33 +08:00
jiangfriend@gmail.com
c2708fa8a5 bump to v0.1.4 2012-06-26 20:04:46 +08:00
jiangfriend@gmail.com
7774b9103b fixes issue #3 2012-06-18 18:49:20 +08:00
jiangfriend@gmail.com
e941a326d9 comptible with node-curl v0.1.3 2012-05-28 21:41:09 +08:00
jiangfriend@gmail.com
34c42b0ebd bump to v0.1.3 2012-05-28 20:17:42 +08:00
jiangfriend@gmail.com
c0808d3799 update README 2012-05-28 20:17:33 +08:00
jiangfriend@gmail.com
f6bfa11f6e close curl before process.on 'exit' 2012-05-28 20:17:15 +08:00
jiangfriend@gmail.com
90f3135c8c fixes #2 CookieList returning same data for each cookie
new structure for node-curl
2012-05-28 19:55:17 +08:00
jiangfriend@gmail.com
e791a14c6e remove select totally for timeout cannot work properly 2012-03-08 00:47:10 +08:00
jiangfriend@gmail.com
49db24b7d4 add travis status icon 2012-03-08 00:21:52 +08:00
jiangfriend@gmail.com
58acd92ea9 dynamic generate curl include file 2012-03-08 00:15:51 +08:00
jiangfriend@gmail.com
f51c05676c add travis file 2012-03-07 23:48:38 +08:00
jiangfriend@gmail.com
94cef17bf8 bump to version 0.1.1 2012-02-17 22:21:03 +08:00
jiangfriend@gmail.com
f65257623b fixes failed on curl_multi_perform cause curl_multi_remove failed 2012-02-16 00:25:55 +08:00
35 changed files with 1374 additions and 674 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
raw
build
.lock-wscript
node_modules

View file

@ -2,3 +2,6 @@
raw/
build/
build/.*
src/*_infos.h
src/*_options.h
*.tgz

4
.travis.yml Normal file
View file

@ -0,0 +1,4 @@
language: node_js
node_js:
- 0.8
- 0.10

22
LICENSE-MIT Normal file
View file

@ -0,0 +1,22 @@
Copyright (c) 2012 Miao Jiang
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

152
README.md
View file

@ -1,4 +1,4 @@
node-curl
node-curl [![Build Status](https://secure.travis-ci.org/jiangmiao/node-curl.png?branch=master)](http://travis-ci.org/jiangmiao/node-curl)
=========
node cURL wrapper, support all options and infos.
@ -9,66 +9,95 @@ Quick Start
* quick start
curl = require('node-curl');
curl('www.google.com', function(err, res) {
console.info(res.status);
curl('www.google.com', function(err) {
console.info(this.status);
console.info('-----');
console.info(res.body);
console.info(this.body);
console.info('-----');
console.info(res.info('SIZE_DOWNLOAD'));
res.close();
console.info(this.info('SIZE_DOWNLOAD'));
});
* with options
curl = require('node-curl')
curl('www.google.com', {VERBOSE: 1, RAW: 1}, function(err, res) {
console.info(res);
res.close();
curl('www.google.com', {VERBOSE: 1, RAW: 1}, function(err) {
console.info(this);
});
* run the example/test.js
node examples/test.js
Usage
-----
* curl
curl(url, [options = {}], callback)
callback includes 2 parameters (error, result)
callback includes 1 parameters (error)
result is stored in curl
* result in callback
* Retrieve Data from curl
members:
status - Http Response code
body - Http body
status - Http Response code
body - Http body
header - Http header
url - the url set by curl(...)
options - the options set by curl(...)
defaultOptions - the defaultOptions
effectiveOptions - the options curl used
methods:
info(name) - Get information of result, see 'info' section
REMARK:
If the http is redirected, then header will contain at least 2 http headers.
* Curl Control
members
debug (default: false)
- logging node-curl debug info
methods:
void reset()
- reset curl and set options to default options
void setDefaultOptions(options, reset = true)
- set default options
curl create(defaultOptions)
- create a new curl with default options
Options
-------
* Any Curl Easy Options
* Any cURL Easy Options
eg: CURLOPT_VERBOSE will be VERBOSE, CURLOPT_HEADER will be HEADER
Full list at http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
Full list at http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
* node-curl Extra Options
RAW - Returns Buffer instead of String in result.body
RAW - Returns Buffer instead of String in result.body
DEBUG - Replace curl.debug
* About slist parameters
node-curl support slist which map to Javascript Array
eg:
HTTP_HEADER: ['FOO', 'BAR']
HTTP_HEADER: 'FOO'
eg:
HTTPHEADER: ['FOO', 'BAR']
HTTPHEADER: 'FOO'
any non-array parameter will convert to [ parameter.toString() ]
Infos
-----
* Any Curl Info options
* Any cURL Info options
eg: CURLINFO_EFFECTIVE_URL will be EFFETCTIVE_URL
@ -80,9 +109,82 @@ Infos
slist will be returns in Array
eg: CURLINFO_COOKIELIST
MultiPart Upload
----------------
Use MULTIPART option
Hints
-----
close the result to release resource of curl immediately.
There are 4 options in MULTIPART, `name`, `file`, `type`, `contents`
or the resource will not release until gc performed.
```javascript
curl('127.0.0.1/upload.php', {
MULTIPART: [
{name: 'file', file: '/file/path', type: 'text/html'},
{name: 'sumbit', contents: 'send'}
]
}, function(e) {
console.log(e);
console.log(this.body);
this.close()
});
```
Low Level Curl Usage
--------------------
require 'node-curl/lib/Curl'
Methods:
Curl setopt(optionName, optionValue)
Curl perform()
Curl on(eventType, callback)
Mixed getinfo(infoName)
Events:
'data', function(Buffer chunk) {}
'header', function(Buffer chunk) {}
'error', function(Error error) {}
'end', function() {}
Example: examples/low-level.js
var Curl = require('node-curl/lib/Curl')
var p = console.log;
var url = process.argv[2];
var curl = new Curl();
if (!url)
url = 'www.yahoo.com';
curl.setopt('URL', url);
curl.setopt('CONNECTTIMEOUT', 2);
// on 'data' must be returns chunk.length, or means interrupt the transfer
curl.on('data', function(chunk) {
p("receive " + chunk.length);
return chunk.length;
});
curl.on('header', function(chunk) {
p("receive header " + chunk.length);
return chunk.length;
})
// curl.close() should be called in event 'error' and 'end' if the curl won't use any more.
// or the resource will not release until V8 garbage mark sweep.
curl.on('error', function(e) {
p("error: " + e.message);
curl.close();
});
curl.on('end', function() {
p('code: ' + curl.getinfo('RESPONSE_CODE'));
p('done.');
curl.close();
});
curl.perform();

11
binding.gyp Normal file
View file

@ -0,0 +1,11 @@
{
'targets': [
{
'target_name': 'node-curl',
'cflags': ['-Wall', '-O1', '-g', '-fno-inline-functions'],
'cflags_cc': ['-Wall', '-O1', '-g', '-fno-inline-functions'],
'sources': ['src/node-curl.cc'],
'libraries': ['-lcurl']
}
]
}

23
examples/curl.js Normal file
View file

@ -0,0 +1,23 @@
// Generated by ToffeeScript 1.6.2-5
(function() {
var curl, err, p, res,
_this = this;
curl = require('../index');
p = console.info;
curl(process.argv[2], {
VERBOSE: 1,
DEBUG: 1,
FOLLOWLOCATION: 1
}, function() {
err = arguments[0], res = arguments[1];
if (err) {
return p(err);
} else {
return p(res);
}
});
}).call(this);

8
examples/curl.toffee Normal file
View file

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

40
examples/low-level.js Normal file
View file

@ -0,0 +1,40 @@
var Curl = require('../lib/Curl');
var p = console.log;
var url = process.argv[2];
var curl = new Curl();
if (!url)
url = 'www.yahoo.com';
curl.setopt('URL', url);
curl.setopt('CONNECTTIMEOUT', 2);
curl.setopt('VERBOSE', 1);
// on 'data' must be returns chunk.length, or means interrupt the transfer
curl.on('data', function(chunk) {
p("receive " + chunk.length);
return chunk.length;
});
curl.on('header', function(chunk) {
p("receive header " + chunk.length);
return chunk.length;
})
// curl.close() should be called in event 'error' and 'end' if the curl won't use any more.
// or the resource will not release until V8 garbage mark sweep.
curl.on('error', function(e) {
p("error: " + e.message);
curl.close();
});
curl.on('end', function() {
p('code: ' + curl.getinfo('RESPONSE_CODE'));
p('done.');
curl.close();
});
curl.perform();

View file

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

View file

@ -0,0 +1,13 @@
curl = require '../index'
p = console.log
p 'start'
curl '127.0.0.1/upload.php', {
multipart: [
{name: 'file', file: '/home/miao/test.js', type: 'text/html'},
{name: 'sumbit', contents: 'send'}
],
}, (e) ->
console.log e
console.log @body
@close()

View file

@ -1,30 +1,38 @@
// Generated by ToffeeScript 1.1.4-4
// Generated by ToffeeScript 1.6.2-5
(function() {
var assert, curl, i, j, next, once, _i;
var Curl, assert, i, j, next, _fn, _i;
curl = require('../index');
Curl = require('../index');
assert = require('assert');
j = 0;
(next = function() {
console.info("curl instances: ", curl.get_count());
console.info("curl instances: ", Curl.get_count());
return setTimeout(next, 1000);
})();
for (i = _i = 1; _i <= 100; i = ++_i) {
(once = function() {
var _this = this;
return curl('localhost/test.html', function(_$$_err, _$$_res) {
var err, res;
err = _$$_err;
res = _$$_res;
_fn = function() {
var curl, once;
curl = Curl.create();
return (once = function() {
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 < 20000) return once();
if (++j % 100 === 0) {
console.info(j);
}
if (j < 500000) {
return once();
}
});
})();
};
for (i = _i = 1; _i <= 100; i = ++_i) {
_fn();
}
}).call(this);

View file

@ -1,16 +1,18 @@
curl = require '../index'
Curl = require '../index'
assert = require 'assert'
j = 0;
do next = ->
console.info "curl instances: ", curl.get_count()
console.info "curl instances: ", Curl.get_count()
setTimeout next, 1000
for i in [1..100]
do once = ->
err, res = curl! 'localhost/test.html'
assert.equal res.body.length, 1468
if ++j % 100 == 0
console.info j
if j < 20000
once()
# res.close()
do ->
curl = Curl.create()
do once = ->
err, res = curl! 'localhost/test.html'
assert.equal res.body.length, 1468
if ++j % 100 == 0
console.info j
if j < 500000
once()
# res.close()

View file

@ -1,28 +1,28 @@
curl = require('../index');
url = 'www.nodejs.org';
options = {CONNECTTIMEOUT: 2, VERBOSE: 1};
curl(url, options, function(err, res) {
console.info("\x1b[33meffetcive url: " + res.info('EFFECTIVE_URL') + "\x1b[0m");
console.info("body length: " + res.body.length);
res.close();
// second argument 'options' is omitted.
url = 'www.google.com';
console.info("GET " + url);
curl('www.google.com', function(err) {
console.info("\x1b[32mGet " + this.url + " finished.\x1b[0m");
console.info("\tstatus: " + this.status);
console.info("\tbody length: " + this.body.length);
console.info("\tinfo SIZE_DOWNLOAD: " + this.info('SIZE_DOWNLOAD'));
console.info("\tinfo EFFECTIVE_URL " + this.info('EFFECTIVE_URL'));
this.close();
});
url = 'www.yahoo.com'
curl(url, options, function(err, res) {
console.info("\x1b[33meffetcive url: " + res.info('EFFECTIVE_URL') + "\x1b[0m");
console.info("body length: " + res.body.length);
res.close();
// because we uses curl in parallel. and each curl is only for one session.
// so use curl.create(defaultOptions = {}) to create new curl/session.
curl2 = curl.create({RAW: 1});
url2 = 'www.google.com';
options2 = {FOLLOWLOCATION: 1};
console.info("GET " + url + " with default options " + JSON.stringify(curl2.defaultOptions) + ' and options ' + JSON.stringify(options2));
curl2(url2, options2, function(err) {
console.info("\x1b[32mGet " + this.url + " with " + JSON.stringify(this.effectiveOptions) + " finished.\x1b[0m");
console.info("\tstatus: " + this.status);
console.info("\tbody length: " + this.body.length);
console.info("\tinfo SIZE_DOWNLOAD: " + this.info('SIZE_DOWNLOAD'));
console.info("\tinfo EFFECTIVE_URL " + this.info('EFFECTIVE_URL'));
this.close();
});
curl('https://www.google.com', {VERBOSE: 1, RAW: 1}, function(err, res) {
console.info("\x1b[33meffetcive url: " + res.info('EFFECTIVE_URL') + "\x1b[0m");
console.info(res);
res.close();
});
/*
console.info('-----');
console.info("status: " + res.status);
console.info('-----');
console.info("size download: " + res.info('SIZE_DOWNLOAD'));
*/

45
examples/test-get-info.js Normal file
View file

@ -0,0 +1,45 @@
Curl = require('../index');
defaultOptions = {CONNECTTIMEOUT: 2};
keys = ["EFFECTIVE_URL", "CONTENT_TYPE", "PRIVATE", "FTP_ENTRY_PATH", "REDIRECT_URL", "PRIMARY_IP", "RTSP_SESSION_ID", "LOCAL_IP"];
function print(text, color) {
if (!/^\d+$/.test(color)) {
color = {red: 31, green: 32, yellow: 33}[color];
}
if (!color)
return console.info(text);
console.info("\x1b[" + color + "m" + text + "\x1b[0m");
}
requests = [
['www.nodejs.org'],
['www.yahoo.com'],
['https://www.google.com', {VERBOSE: 1, RAW: 1}]
];
requests.forEach(function(request) {
url = request[0];
options = request[1];
if (!options)
options = {};
curl = Curl.create(defaultOptions);
print('GET ' + url, 'green')
curl(url, options, function(err) {
print('GET ' + this.url + ' ' + JSON.stringify(this.effectiveOptions) + " finished.", 'green');
if (err)
return print(err, 'red');
self = this;
keys.forEach(function(key) {
print("\t" + key + ": [" + self.info(key) + "]", 'yellow');
})
print("\tbody length: " + this.body.length);
this.close();
});
});

View file

@ -1,6 +1,6 @@
// Generated by ToffeeScript 1.1.4-4
// Generated by ToffeeScript 1.6.2-5
(function() {
var curl, fs, p, url, util,
var cookieFile, curl, err, fs, options, p, stream, util,
_this = this;
curl = require('../index');
@ -11,29 +11,41 @@
p = console.info;
url = 'www.google.com';
cookieFile = 'node-curl-cookie.txt';
curl(url, {
HTTPHEADER: 'BAR',
options = {
VERBOSE: 1,
COOKIEFILE: 'node-curl-cookie.txt'
}, function(_$$_err, _$$_res) {
var err, res;
err = _$$_err;
res = _$$_res;
p("\x1b[33m" + util.inspect(res.info('COOKIELIST')) + "\x1b[0m");
url = 'www.yahoo.com';
return curl(url, {
HTTPHEADER: ['foo', 'bar'],
VERBOSE: 1,
COOKIEFILE: 'node-curl-cookie.txt',
RAW: 1
}, function(_$$_err, _$$_res) {
err = _$$_err;
res = _$$_res;
p("\x1b[33m" + util.inspect(res.info('COOKIELIST')) + "\x1b[0m");
p(res.body);
return fs.unlink('node-curl-cookie.txt');
COOKIEFILE: cookieFile,
COOKIEJAR: cookieFile,
ACCEPT_ENCODING: 'gzip',
RAW: 1
};
curl.debug = 1;
curl.setDefaultOptions(options);
curl('www.google.com', function() {
err = arguments[0];
p("\x1b[33m" + util.inspect(curl.info('COOKIELIST')) + "\x1b[0m");
curl.reset();
curl('www.yahoo.com', function() {
err = arguments[0];
p("\x1b[33m" + util.inspect(curl.info('COOKIELIST')) + "\x1b[0m");
p("body length " + curl.body.length);
p("\x1b[33mText in " + cookieFile + "\x1b[0m");
p("----");
stream = fs.createReadStream(cookieFile);
stream.pipe(process.stdout);
return stream.on('end', function() {
var _this = this;
p("----");
curl.close();
p("deleting " + cookieFile);
fs.unlink(cookieFile, function() {
return p("done.");
});
});
});
});

View file

@ -3,20 +3,29 @@ fs = require 'fs'
util = require 'util'
p = console.info
url = 'www.google.com'
err, res = curl! url,
HTTPHEADER: 'BAR'
cookieFile = 'node-curl-cookie.txt'
options = {
VERBOSE: 1
COOKIEFILE: 'node-curl-cookie.txt'
p "\x1b[33m" + util.inspect(res.info('COOKIELIST')) + "\x1b[0m"
url = 'www.yahoo.com'
err, res = curl! url,
HTTPHEADER: ['foo', 'bar']
VERBOSE: 1
COOKIEFILE: 'node-curl-cookie.txt'
COOKIEFILE: cookieFile
COOKIEJAR: cookieFile
ACCEPT_ENCODING: 'gzip'
RAW: 1
p "\x1b[33m" + util.inspect(res.info('COOKIELIST')) + "\x1b[0m"
p res.body
fs.unlink 'node-curl-cookie.txt'
}
curl.debug = 1
curl.setDefaultOptions options
err = curl! 'www.google.com'
p "\x1b[33m" + util.inspect(curl.info('COOKIELIST')) + "\x1b[0m"
curl.reset()
err = curl! 'www.yahoo.com'
p "\x1b[33m" + util.inspect(curl.info('COOKIELIST')) + "\x1b[0m"
p "body length #{curl.body.length}"
p "\x1b[33mText in #{cookieFile}\x1b[0m"
p "----"
stream = fs.createReadStream(cookieFile)
stream.pipe(process.stdout)
stream.on 'end', ->
p "----"
curl.close()
p "deleting #{cookieFile}"
fs.unlink! cookieFile
p "done."

View file

@ -1,6 +1,9 @@
// Generated by CoffeeScript 1.1.4-3
// Generated by ToffeeScript 1.4.0
(function() {
var CurlBuilder;
module.exports = require('./lib/curl');
CurlBuilder = require('./lib/CurlBuilder');
module.exports = CurlBuilder.create();
}).call(this);

View file

@ -1 +1,2 @@
module.exports = require './lib/curl'
CurlBuilder = require './lib/CurlBuilder'
module.exports = CurlBuilder.create()

174
lib/Curl.js Normal file
View file

@ -0,0 +1,174 @@
// Generated by ToffeeScript 1.6.2-5
(function() {
var Curl, curls, e, id, m, p,
__hasProp = {}.hasOwnProperty;
try {
Curl = require(__dirname + '/../build/Release/node-curl').Curl;
} catch (_error) {
e = _error;
Curl = require(__dirname + '/../build/default/node-curl').Curl;
}
Curl.prototype.setopt_user_ = function(option_id, value) {
return this.options[option_id] = value;
};
Curl.prototype.setopt_httppost = function(rows) {
var cols, k, option_id, row, v;
this.httppost = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = rows.length; _i < _len; _i++) {
row = rows[_i];
cols = [];
for (k in row) {
if (!__hasProp.call(row, k)) continue;
v = row[k];
k = k.toUpperCase();
if ((option_id = Curl.httppost_options[k]) != null) {
cols.push(option_id);
if (!(v instanceof Buffer)) {
v = new Buffer(v.toString());
}
cols.push(v);
} else {
throw new Error("invalid http post option " + k);
}
}
_results.push(cols);
}
return _results;
})();
this.setopt_httppost_(this.httppost);
return this;
};
Curl.prototype.setopt = function(option_name, value) {
var option, option_id;
option = option_name.toUpperCase();
if ((option_id = Curl.user_options[option]) != null) {
if (option === 'MULTIPART') {
this.setopt_httppost(value);
} else {
this.setopt_user_(option_id, value);
}
} else if ((option_id = Curl.slist_options[option]) != null) {
this.setopt_slist_(option_id, value);
} else if ((option_id = Curl.integer_options[option]) != null) {
this.setopt_int_(option_id, value >> 0);
} else if ((option_id = Curl.string_options[option]) != null) {
if (value == null) {
throw new Error("Cannot set option " + option_name + " to " + value + ".");
}
this.setopt_str_(option_id, value.toString());
} else {
throw new Error("unsupported option " + option);
}
return this;
};
Curl.prototype.getinfo = function(oinfo) {
var info, info_id;
info = oinfo.toUpperCase();
if ((info_id = Curl.slist_infos[info]) != null) {
return this.getinfo_slist_(info_id);
} else if ((info_id = Curl.integer_infos[info]) != null) {
return this.getinfo_int_(info_id);
} else if ((info_id = Curl.string_infos[info]) != null) {
return this.getinfo_str_(info_id);
} else if ((info_id = Curl.double_infos[info]) != null) {
return this.getinfo_double_(info_id);
} else {
throw new Error("unsupported info " + oinfo);
}
};
Curl.user_options = {
RAW: 'RAW',
DEBUG: 'DEBUG',
MULTIPART: 'MULTIPART'
};
id = 0;
curls = {};
Curl.prototype.on = function(event, callback) {
var _this = this;
switch (event) {
case 'data':
this.on_write = function(chunk) {
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];
return callback.call(_this, e);
};
break;
case 'end':
this.on_end = function() {
delete curls[_this.id];
return callback.call(_this);
};
break;
default:
throw new Error("invalid event type " + event);
}
return this;
};
Curl.prototype.close = function() {
delete curls[this.id];
return this.close_();
};
Curl.prototype.perform = function() {
this.id = ++id;
curls[this.id] = this;
this.perform_();
Curl.process();
return this;
};
m = 0;
p = console.log;
Curl.process = function() {
var once;
if (Curl.in_process) {
return;
}
return (once = function() {
var n, w;
n = Curl.process_();
if (n > 0) {
Curl.in_process = true;
if (n > 8192 && m < 10) {
++m;
return process.nextTick(once);
} else {
m = 0;
w = (8192 - n) * 80 / 8192 >> 0;
if (w < 0) {
w = 0;
}
return setTimeout(once, w);
}
} else {
return Curl.in_process = false;
}
})();
};
module.exports = Curl;
}).call(this);

133
lib/Curl.toffee Normal file
View file

@ -0,0 +1,133 @@
try
{Curl} = require __dirname + '/../build/Release/node-curl'
catch e
{Curl} = require __dirname + '/../build/default/node-curl'
Curl::setopt_user_ = (option_id, value) ->
@options[option_id] = value
Curl::setopt_httppost = (rows) ->
# convert object-rows to array-rows
# format
# [
# [OPTION_ID, VALUE]
# ]
@httppost = for row in rows
cols = []
for own k, v of row
k = k.toUpperCase()
if (option_id = Curl.httppost_options[k])?
cols.push option_id
unless v instanceof Buffer
v = new Buffer(v.toString())
cols.push v
else
throw new Error("invalid http post option #{k}")
cols
@setopt_httppost_(@httppost)
@
Curl::setopt = (option_name, value) ->
option = option_name.toUpperCase()
# slist must be at the top of condition
# the option exists in string_options too
if (option_id = Curl.user_options[option])?
if (option == 'MULTIPART')
@setopt_httppost value
else
@setopt_user_ option_id, value
else if (option_id = Curl.slist_options[option])?
@setopt_slist_ option_id, value
else if (option_id = Curl.integer_options[option])?
@setopt_int_ option_id, value >> 0
else if (option_id = Curl.string_options[option])?
if !value?
throw new Error("Cannot set option #{option_name} to #{value}.")
@setopt_str_ option_id, value.toString()
else
throw new Error("unsupported option #{option}")
@
Curl::getinfo = (oinfo) ->
info = oinfo.toUpperCase()
if (info_id = Curl.slist_infos[info])?
@getinfo_slist_(info_id)
else if (info_id = Curl.integer_infos[info])?
@getinfo_int_(info_id)
else if (info_id = Curl.string_infos[info])?
@getinfo_str_(info_id)
else if (info_id = Curl.double_infos[info])?
@getinfo_double_(info_id)
else
throw new Error("unsupported info #{oinfo}")
Curl.user_options =
RAW: 'RAW'
DEBUG: 'DEBUG'
MULTIPART: 'MULTIPART'
id = 0
curls = {}
# on 'data' must be returns the chunk length
Curl::on = (event, callback) ->
switch event
when 'data'
# (Buffer chunk) ->
@on_write = (chunk) =>
callback.call @, chunk
when 'header'
@on_header = (chunk) =>
callback.call @, chunk
when 'error'
# (Error error) ->
@on_error = (e) =>
delete curls[@id]
callback.call @, e
when 'end'
# () ->
@on_end = =>
delete curls[@id]
callback.call @
else
throw new Error("invalid event type #{event}")
@
Curl::close = () ->
delete curls[@id]
@close_()
Curl::perform = ->
@id = ++id
curls[@id] = @
@perform_()
Curl.process()
@
m = 0
p = console.log
Curl.process = ->
if Curl.in_process
return
do once = ->
n = Curl.process_()
if n > 0
Curl.in_process = true
if n > 8192 && m < 10
++m
process.nextTick once
else
m = 0
w = (8192 - n) * 80 / 8192 >> 0
if w < 0
w = 0
setTimeout once, w
else
Curl.in_process = false
module.exports = Curl
# vim: sw=2 ts=2 sts=2 expandtab :

222
lib/CurlBuilder.js Normal file
View file

@ -0,0 +1,222 @@
// Generated by ToffeeScript 1.6.2-5
(function() {
var Curl, CurlBuilder, e,
__hasProp = {}.hasOwnProperty,
__slice = [].slice;
try {
Curl = require(__dirname + '/Curl');
} catch (_error) {
e = _error;
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() {}
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) {
function curl() {
return curl.perform.apply(curl, arguments);
};
curl.perform = function() {
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');
}
if (!this.curl_) {
throw new Error('the cURL is closed.');
}
this.running = true;
cb = args.pop();
this.url = args[0], this.options = args[1];
if ((_ref = this.options) == null) {
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;
for (k in _ref3) {
v = _ref3[k];
this.effectiveOptions[k] = v;
}
_ref4 = this.options;
for (k in _ref4) {
v = _ref4[k];
this.effectiveOptions[k] = v;
}
this.setOptions(this.effectiveOptions);
this.setOptions({
URL: this.url
});
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 data, header,
_this = this;
curl.log("receive succeeded.");
curl.running = false;
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() {
return cb.call(curl, null, curl);
});
});
c.on('error', function(err) {
var _this = this;
curl.log("receive failed: " + err.message);
curl.running = false;
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.defaultOptions = defaultOptions != null ? 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.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);

165
lib/CurlBuilder.toffee Normal file
View file

@ -0,0 +1,165 @@
try
Curl = require __dirname + '/Curl'
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
@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 curl.create to create another cURL Session'
if !@curl_
throw new Error 'the cURL is closed.'
@running = true
# pop arguments (url, [options = {}], callback)
cb = args.pop()
[@url, @options] = args
@options ?= {}
length = 0
header_length = 0
@debug = @defaultOptions.DEBUG ? @options.DEBUG ? @debug
@effectiveOptions = {}
for k, v of @defaultOptions
@effectiveOptions[k] = v
for k, v of @options
@effectiveOptions[k] = v
@setOptions @effectiveOptions
@setOptions {URL: @url}
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 = 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
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 = {}
@defaultOptions = defaultOptions ? {}
CurlBuilder.curls[curl.id] = curl
@log "opened."
curl.reset = ->
@log 'reset'
if @curl_
@end()
@open()
curl.create = (defaultOptions) ->
CurlBuilder.create(defaultOptions)
curl.get_count = ->
Curl.get_count()
curl.open()
curl
process.on 'exit', ->
CurlBuilder.close_all()
module.exports = CurlBuilder
# vim: sw=2 ts=2 sts=2 expandtab :

View file

@ -1,155 +0,0 @@
// Generated by ToffeeScript 1.1.4-4
(function() {
var Curl, curl, curl_id, curls,
__slice = [].slice,
__hasProp = {}.hasOwnProperty;
try {
Curl = require(__dirname + '/../build/Release/node-curl').Curl;
} catch (e) {
Curl = require(__dirname + '/../build/default/node-curl').Curl;
}
Curl.prototype.setopt_user_ = function(option_id, value) {
return this.options[option_id] = value;
};
Curl.prototype.setopt = function(ooption, value) {
var option, option_id;
option = ooption.toUpperCase();
if ((option_id = Curl.user_options[option]) != null) {
return this.setopt_user_(option_id, value);
} else if ((option_id = Curl.slist_options[option]) != null) {
return this.setopt_slist_(option_id, value);
} else if ((option_id = Curl.integer_options[option]) != null) {
return this.setopt_int_(option_id, value >> 0);
} else if ((option_id = Curl.string_options[option]) != null) {
return this.setopt_str_(option_id, value.toString());
} else {
throw new Error("unsupported option " + option);
}
};
Curl.prototype.getinfo = function(oinfo) {
var info, info_id;
info = oinfo.toUpperCase();
if ((info_id = Curl.slist_infos[info]) != null) {
return this.getinfo_slist_(info_id);
} else if ((info_id = Curl.integer_infos[info]) != null) {
return this.getinfo_int_(info_id);
} else if ((info_id = Curl.string_infos[info]) != null) {
return this.getinfo_str_(info_id);
} else if ((info_id = Curl.double_infos[info]) != null) {
return this.getinfo_double_(info_id);
} else {
throw new Error("unsupported info " + oinfo);
}
};
Curl.prototype.perform = function() {
this.perform_();
return Curl.process();
};
Curl.user_options = {
RAW: 'RAW'
};
Curl.process = function() {
var once;
if (Curl.in_process) return;
return (once = function() {
var num;
num = Curl.process_();
if (num > 0) {
Curl.in_process = true;
return setTimeout(once, 80);
} else {
return Curl.in_process = false;
}
})();
};
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();
};
module.exports = curl;
}).call(this);

View file

@ -1,129 +0,0 @@
try
{Curl} = require __dirname + '/../build/Release/node-curl'
catch e
{Curl} = require __dirname + '/../build/default/node-curl'
Curl::setopt_user_ = (option_id, value) ->
@options[option_id] = value
Curl::setopt = (ooption, value) ->
option = ooption.toUpperCase()
# slist must be at the top of condition
# the option exists in string_options too
if (option_id = Curl.user_options[option])?
@setopt_user_ option_id, value
else if (option_id = Curl.slist_options[option])?
@setopt_slist_ option_id, value
else if (option_id = Curl.integer_options[option])?
@setopt_int_ option_id, value >> 0
else if (option_id = Curl.string_options[option])?
@setopt_str_ option_id, value.toString()
else
throw new Error("unsupported option #{option}")
Curl::getinfo = (oinfo) ->
info = oinfo.toUpperCase()
if (info_id = Curl.slist_infos[info])?
@getinfo_slist_(info_id)
else if (info_id = Curl.integer_infos[info])?
@getinfo_int_(info_id)
else if (info_id = Curl.string_infos[info])?
@getinfo_str_(info_id)
else if (info_id = Curl.double_infos[info])?
@getinfo_double_(info_id)
else
throw new Error("unsupported info #{oinfo}")
Curl::perform = ->
@perform_()
Curl.process()
Curl.user_options =
RAW: 'RAW'
Curl.process = ->
if Curl.in_process
return
do once = ->
num = Curl.process_()
if num > 0
Curl.in_process = true
setTimeout once, 80
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()
module.exports = curl

View file

@ -1,8 +1,8 @@
{
"name": "node-curl",
"version": "0.1.0",
"version": "0.3.3",
"author" : "Jiang Miao <jiangfriend@gmail.com>",
"description": "node wrapper for multi curl, full implemented.",
"description": "node wrapper for multi curl, fully implemented.",
"keywords" : ["node-curl", "curl", "multi-curl", "mcurl"],
"homepage": "http://github.com/jiangmiao/node-curl",
"repository" : {
@ -10,8 +10,8 @@
"url" : "git://github.com/jiangmiao/node-curl.git"
},
"main" : "./lib",
"scripts" : {
"install" : "node-waf configure build || true"
"scripts" : {
"install" : "sh src/generate_curl_options_list.sh && (node-gyp rebuild || node-waf configure build)"
},
"engines" : { "node": ">= 0.6.0" }
}

View file

@ -1,16 +0,0 @@
// generated by generate_curl_options_list.sh at Mon, 13 Feb 2012 21:40:10 +0800
CurlOption double_infos[] = {
{"TOTAL_TIME", CURLINFO_TOTAL_TIME},
{"NAMELOOKUP_TIME", CURLINFO_NAMELOOKUP_TIME},
{"CONNECT_TIME", CURLINFO_CONNECT_TIME},
{"PRETRANSFER_TIME", CURLINFO_PRETRANSFER_TIME},
{"SIZE_UPLOAD", CURLINFO_SIZE_UPLOAD},
{"SIZE_DOWNLOAD", CURLINFO_SIZE_DOWNLOAD},
{"SPEED_DOWNLOAD", CURLINFO_SPEED_DOWNLOAD},
{"SPEED_UPLOAD", CURLINFO_SPEED_UPLOAD},
{"CONTENT_LENGTH_DOWNLOAD", CURLINFO_CONTENT_LENGTH_DOWNLOAD},
{"CONTENT_LENGTH_UPLOAD", CURLINFO_CONTENT_LENGTH_UPLOAD},
{"STARTTRANSFER_TIME", CURLINFO_STARTTRANSFER_TIME},
{"REDIRECT_TIME", CURLINFO_REDIRECT_TIME},
{"APPCONNECT_TIME", CURLINFO_APPCONNECT_TIME},
};

26
src/generate_curl_options_list.sh Normal file → Executable file
View file

@ -1,18 +1,36 @@
#!/bin/sh
root=`dirname $0`
if [ "$NODE_CURL_H" != "" ] ; then
curl_header=$NODE_CURL_H
elif [ -f "/usr/local/include/curl/curl.h" ] ; then
curl_header="/usr/local/include/curl/curl.h"
elif [ -f "/usr/include/curl/curl.h" ] ; then
curl_header="/usr/include/curl/curl.h"
fi
if [ ! -f $curl_header ] ; then
echo "cannot find curl's header file $curl_header"
exit 1
else
echo "extract constants from $curl_header"
fi
generate() {
name=$1
pattern=$2
prefix=$3
echo "generate $root/$name.h"
(
echo "// generated by $0 at $(date -R)"
echo "// generated by $0 at $(date)"
echo "CurlOption $name[] = {"
cat /usr/include/curl/curl.h|perl -ne "/$pattern/i && print \"\t{\\\"\$1\\\", CURL${prefix}_\$1},\n\""
cat "$curl_header"|perl -ne "/$pattern/i && print \"\t{\\\"\$1\\\", CURL${prefix}_\$1},\n\""
echo '};'
) > $name.h
) > $root/$name.h
}
generate integer_options 'CINIT\((\w+).*LONG' OPT
generate string_options 'CINIT\((\w+).*OBJECT' OPT
generate string_options 'CINIT\((\w+).*(STRINGPOINT|OBJECT)' OPT
generate integer_infos 'CURLINFO_(\w+).*LONG' INFO
generate string_infos 'CURLINFO_(\w+).*STRING' INFO

View file

@ -1,21 +0,0 @@
// generated by generate_curl_options_list.sh at Mon, 13 Feb 2012 21:40:10 +0800
CurlOption integer_infos[] = {
{"RESPONSE_CODE", CURLINFO_RESPONSE_CODE},
{"HEADER_SIZE", CURLINFO_HEADER_SIZE},
{"REQUEST_SIZE", CURLINFO_REQUEST_SIZE},
{"SSL_VERIFYRESULT", CURLINFO_SSL_VERIFYRESULT},
{"FILETIME", CURLINFO_FILETIME},
{"REDIRECT_COUNT", CURLINFO_REDIRECT_COUNT},
{"HTTP_CONNECTCODE", CURLINFO_HTTP_CONNECTCODE},
{"HTTPAUTH_AVAIL", CURLINFO_HTTPAUTH_AVAIL},
{"PROXYAUTH_AVAIL", CURLINFO_PROXYAUTH_AVAIL},
{"OS_ERRNO", CURLINFO_OS_ERRNO},
{"NUM_CONNECTS", CURLINFO_NUM_CONNECTS},
{"LASTSOCKET", CURLINFO_LASTSOCKET},
{"CONDITION_UNMET", CURLINFO_CONDITION_UNMET},
{"RTSP_CLIENT_CSEQ", CURLINFO_RTSP_CLIENT_CSEQ},
{"RTSP_SERVER_CSEQ", CURLINFO_RTSP_SERVER_CSEQ},
{"RTSP_CSEQ_RECV", CURLINFO_RTSP_CSEQ_RECV},
{"PRIMARY_PORT", CURLINFO_PRIMARY_PORT},
{"LOCAL_PORT", CURLINFO_LOCAL_PORT},
};

View file

@ -1,91 +0,0 @@
// generated by generate_curl_options_list.sh at Mon, 13 Feb 2012 21:40:10 +0800
CurlOption integer_options[] = {
{"PORT", CURLOPT_PORT},
{"TIMEOUT", CURLOPT_TIMEOUT},
{"INFILESIZE", CURLOPT_INFILESIZE},
{"LOW_SPEED_LIMIT", CURLOPT_LOW_SPEED_LIMIT},
{"LOW_SPEED_TIME", CURLOPT_LOW_SPEED_TIME},
{"RESUME_FROM", CURLOPT_RESUME_FROM},
{"CRLF", CURLOPT_CRLF},
{"SSLVERSION", CURLOPT_SSLVERSION},
{"TIMECONDITION", CURLOPT_TIMECONDITION},
{"TIMEVALUE", CURLOPT_TIMEVALUE},
{"VERBOSE", CURLOPT_VERBOSE},
{"HEADER", CURLOPT_HEADER},
{"NOPROGRESS", CURLOPT_NOPROGRESS},
{"NOBODY", CURLOPT_NOBODY},
{"FAILONERROR", CURLOPT_FAILONERROR},
{"UPLOAD", CURLOPT_UPLOAD},
{"POST", CURLOPT_POST},
{"DIRLISTONLY", CURLOPT_DIRLISTONLY},
{"APPEND", CURLOPT_APPEND},
{"NETRC", CURLOPT_NETRC},
{"FOLLOWLOCATION", CURLOPT_FOLLOWLOCATION},
{"TRANSFERTEXT", CURLOPT_TRANSFERTEXT},
{"PUT", CURLOPT_PUT},
{"AUTOREFERER", CURLOPT_AUTOREFERER},
{"PROXYPORT", CURLOPT_PROXYPORT},
{"POSTFIELDSIZE", CURLOPT_POSTFIELDSIZE},
{"HTTPPROXYTUNNEL", CURLOPT_HTTPPROXYTUNNEL},
{"SSL_VERIFYPEER", CURLOPT_SSL_VERIFYPEER},
{"MAXREDIRS", CURLOPT_MAXREDIRS},
{"FILETIME", CURLOPT_FILETIME},
{"MAXCONNECTS", CURLOPT_MAXCONNECTS},
{"CLOSEPOLICY", CURLOPT_CLOSEPOLICY},
{"FRESH_CONNECT", CURLOPT_FRESH_CONNECT},
{"FORBID_REUSE", CURLOPT_FORBID_REUSE},
{"CONNECTTIMEOUT", CURLOPT_CONNECTTIMEOUT},
{"HTTPGET", CURLOPT_HTTPGET},
{"SSL_VERIFYHOST", CURLOPT_SSL_VERIFYHOST},
{"HTTP_VERSION", CURLOPT_HTTP_VERSION},
{"FTP_USE_EPSV", CURLOPT_FTP_USE_EPSV},
{"SSLENGINE_DEFAULT", CURLOPT_SSLENGINE_DEFAULT},
{"DNS_USE_GLOBAL_CACHE", CURLOPT_DNS_USE_GLOBAL_CACHE},
{"DNS_CACHE_TIMEOUT", CURLOPT_DNS_CACHE_TIMEOUT},
{"COOKIESESSION", CURLOPT_COOKIESESSION},
{"BUFFERSIZE", CURLOPT_BUFFERSIZE},
{"NOSIGNAL", CURLOPT_NOSIGNAL},
{"PROXYTYPE", CURLOPT_PROXYTYPE},
{"UNRESTRICTED_AUTH", CURLOPT_UNRESTRICTED_AUTH},
{"FTP_USE_EPRT", CURLOPT_FTP_USE_EPRT},
{"HTTPAUTH", CURLOPT_HTTPAUTH},
{"FTP_CREATE_MISSING_DIRS", CURLOPT_FTP_CREATE_MISSING_DIRS},
{"PROXYAUTH", CURLOPT_PROXYAUTH},
{"FTP_RESPONSE_TIMEOUT", CURLOPT_FTP_RESPONSE_TIMEOUT},
{"IPRESOLVE", CURLOPT_IPRESOLVE},
{"MAXFILESIZE", CURLOPT_MAXFILESIZE},
{"USE_SSL", CURLOPT_USE_SSL},
{"TCP_NODELAY", CURLOPT_TCP_NODELAY},
{"FTPSSLAUTH", CURLOPT_FTPSSLAUTH},
{"IGNORE_CONTENT_LENGTH", CURLOPT_IGNORE_CONTENT_LENGTH},
{"FTP_SKIP_PASV_IP", CURLOPT_FTP_SKIP_PASV_IP},
{"FTP_FILEMETHOD", CURLOPT_FTP_FILEMETHOD},
{"LOCALPORT", CURLOPT_LOCALPORT},
{"LOCALPORTRANGE", CURLOPT_LOCALPORTRANGE},
{"CONNECT_ONLY", CURLOPT_CONNECT_ONLY},
{"SSL_SESSIONID_CACHE", CURLOPT_SSL_SESSIONID_CACHE},
{"SSH_AUTH_TYPES", CURLOPT_SSH_AUTH_TYPES},
{"FTP_SSL_CCC", CURLOPT_FTP_SSL_CCC},
{"TIMEOUT_MS", CURLOPT_TIMEOUT_MS},
{"CONNECTTIMEOUT_MS", CURLOPT_CONNECTTIMEOUT_MS},
{"HTTP_TRANSFER_DECODING", CURLOPT_HTTP_TRANSFER_DECODING},
{"HTTP_CONTENT_DECODING", CURLOPT_HTTP_CONTENT_DECODING},
{"NEW_FILE_PERMS", CURLOPT_NEW_FILE_PERMS},
{"NEW_DIRECTORY_PERMS", CURLOPT_NEW_DIRECTORY_PERMS},
{"POSTREDIR", CURLOPT_POSTREDIR},
{"PROXY_TRANSFER_MODE", CURLOPT_PROXY_TRANSFER_MODE},
{"ADDRESS_SCOPE", CURLOPT_ADDRESS_SCOPE},
{"CERTINFO", CURLOPT_CERTINFO},
{"TFTP_BLKSIZE", CURLOPT_TFTP_BLKSIZE},
{"SOCKS5_GSSAPI_NEC", CURLOPT_SOCKS5_GSSAPI_NEC},
{"PROTOCOLS", CURLOPT_PROTOCOLS},
{"REDIR_PROTOCOLS", CURLOPT_REDIR_PROTOCOLS},
{"FTP_USE_PRET", CURLOPT_FTP_USE_PRET},
{"RTSP_REQUEST", CURLOPT_RTSP_REQUEST},
{"RTSP_CLIENT_CSEQ", CURLOPT_RTSP_CLIENT_CSEQ},
{"RTSP_SERVER_CSEQ", CURLOPT_RTSP_SERVER_CSEQ},
{"WILDCARDMATCH", CURLOPT_WILDCARDMATCH},
{"TRANSFER_ENCODING", CURLOPT_TRANSFER_ENCODING},
{"GSSAPI_DELEGATION", CURLOPT_GSSAPI_DELEGATION},
{"ACCEPTTIMEOUT_MS", CURLOPT_ACCEPTTIMEOUT_MS},
};

View file

@ -5,3 +5,7 @@ void init(v8::Handle<v8::Object> target)
{
NodeCurl::Initialize(target);
}
#ifdef NODE_MODULE
NODE_MODULE(node_curl, init)
#endif

View file

@ -1,20 +1,102 @@
#ifndef NODE_CURL_NOHE_CURL_H
#define NODE_CURL_NOHE_CURL_H
#include <unistd.h>
#include <v8.h>
#include <node.h>
#include <node_buffer.h>
#include <curl/curl.h>
#include <map>
#include <vector>
#include <string>
#include <stdlib.h>
#include <string.h>
#define NODE_CURL_EXPORT(name) export_curl_options(t, #name, name, sizeof(name) / sizeof(CurlOption));
class NodeCurlHttppost
{
public:
curl_httppost *first;
curl_httppost *last;
public:
NodeCurlHttppost()
: first(NULL), last(NULL)
{
reset();
}
~NodeCurlHttppost()
{
reset();
}
void reset()
{
curl_httppost *cur = first;
while (cur) {
curl_httppost *next = cur->next;
if (cur->contenttype)
free(cur->contenttype);
if (cur->contents)
free(cur->contents);
if (cur->buffer)
free(cur->buffer);
if (cur->name)
free(cur->name);
free(cur);
cur = next;
}
first = NULL;
last = NULL;
}
void append()
{
if (!first) {
first = (curl_httppost*)calloc(1, sizeof(curl_httppost));
last = first;
} else {
last->next = (curl_httppost*)calloc(1, sizeof(curl_httppost));
last = last->next;
}
}
enum {
NAME,
FILE,
CONTENTS,
TYPE
};
void set(int field, char *value, long length)
{
value = strndup(value, length);
switch (field) {
case NAME:
last->name = value;
last->namelength = length;
break;
case TYPE:
last->contenttype = value;
break;
case FILE:
last->flags |= CURL_HTTPPOST_FILENAME;
case CONTENTS:
last->contents = value;
last->contentslength = length;
break;
default:
// `default` should never be reached.
free(value);
break;
}
}
};
class NodeCurl
{
struct CurlOption
struct CurlOption
{
const char *name;
int value;
@ -25,11 +107,15 @@ class NodeCurl
static bool is_ref;
static std::map< CURL*, NodeCurl* > curls;
static int count;
static int transfered;
CURL * curl;
v8::Persistent<v8::Object> handle;
bool in_curlm;
std::vector<curl_slist*> slists;
std::map<int, std::string> strings;
NodeCurlHttppost httppost;
NodeCurl(v8::Handle<v8::Object> object)
: in_curlm(false)
@ -48,6 +134,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;
}
@ -104,10 +192,18 @@ class NodeCurl
// curl write function mapping
static size_t write_function(char *ptr, size_t size, size_t nmemb, void *userdata)
{
transfered += size * nmemb;
NodeCurl *nodecurl = (NodeCurl*)userdata;
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<v8::String> SYM_ON_WRITE = v8::Persistent<v8::String>::New(v8::String::NewSymbol("on_write"));
@ -116,7 +212,28 @@ class NodeCurl
{
node::Buffer * buffer = node::Buffer::New(data, n);
v8::Handle<v8::Value> argv[] = { buffer->handle_ };
cb->ToObject()->CallAsFunction(handle, 1, argv);
v8::Handle<v8::Value> rt = cb->ToObject()->CallAsFunction(handle, 1, argv);
if (rt.IsEmpty())
return 0;
else
return rt->Int32Value();
}
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;
}
@ -155,12 +272,12 @@ class NodeCurl
{
return raise("curl_easy_getinfo failed", curl_easy_strerror(code));
}
return JsClass::New(result);
return result ? JsClass::New(result) : v8::Null();
}
static v8::Handle<v8::Value> getinfo_int(const v8::Arguments & args)
{
return getinfo<int, v8::Integer>(args);
return getinfo<long, v8::Integer>(args);
}
static v8::Handle<v8::Value> getinfo_str(const v8::Arguments & args)
@ -189,7 +306,7 @@ class NodeCurl
cur = slist;
while (cur)
{
array->Set(array->Length(), v8::String::New(slist->data));
array->Set(array->Length(), v8::String::New(cur->data));
cur = cur->next;
}
curl_slist_free_all(slist);
@ -204,7 +321,7 @@ class NodeCurl
return v8::Integer::New(
curl_easy_setopt(
curl,
(CURLoption)option->Int32Value(),
(CURLoption)option->Int32Value(),
value
)
);
@ -217,7 +334,14 @@ class NodeCurl
static v8::Handle<v8::Value> setopt_str(const v8::Arguments & args)
{
return unwrap(args.This())->setopt(args[0], *v8::String::Utf8Value(args[1]) );
// Create a string copy
// https://github.com/jiangmiao/node-curl/issues/3
NodeCurl * node_curl = unwrap(args.This());
int key = args[0]->Int32Value();
v8::String::Utf8Value value(args[1]);
int length = value.length();
node_curl->strings[key] = std::string(*value, length);
return unwrap(args.This())->setopt(args[0], node_curl->strings[key].c_str() );
}
static v8::Handle<v8::Value> setopt_slist(const v8::Arguments & args)
@ -228,6 +352,30 @@ class NodeCurl
return node_curl->setopt(args[0], slist);
}
static v8::Handle<v8::Value> setopt_httppost(const v8::Arguments & args)
{
NodeCurl * node_curl = unwrap(args.This());
NodeCurlHttppost &httppost = node_curl->httppost;
v8::Handle<v8::Array> rows = v8::Handle<v8::Array>::Cast(args[0]);
httppost.reset();
for (uint32_t i=0, len = rows->Length(); i<len; ++i)
{
v8::Handle<v8::Array> cols = v8::Handle<v8::Array>::Cast(rows->Get(i));
uint32_t j=0, cols_len = cols->Length();
httppost.append();
while (j<cols_len)
{
int field = cols->Get(j++)->Int32Value();
v8::Handle<v8::Object> buffer = cols->Get(j++)->ToObject();
char *value = node::Buffer::Data(buffer);
int length = node::Buffer::Length(buffer);
httppost.set(field, value, length);
}
}
curl_easy_setopt(node_curl->curl, CURLOPT_HTTPPOST, node_curl->httppost.first);
return args.This();
}
static curl_slist * value_to_slist(v8::Handle<v8::Value> value)
{
curl_slist * slist = NULL;
@ -284,32 +432,11 @@ class NodeCurl
// int process()
static v8::Handle<v8::Value> process(const v8::Arguments & args)
{
transfered = 0;
if (running_handles > 0)
{
CURLMcode code;
int max_fd = FD_SETSIZE;
fd_set read_fds;
fd_set write_fds;
fd_set error_fds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&error_fds);
// use select because of libuv didn't support sockfd well
code = curl_multi_fdset(curlm, &read_fds, &write_fds, &error_fds, &max_fd);
if (code != CURLM_OK)
{
return raise("curl_multi_fdset failed", curl_multi_strerror(code));
}
if (max_fd > 0)
{
timeval tv = {0};
int n = select(max_fd+1, &read_fds, &write_fds, &error_fds, &tv);
if (n == 0)
{
return v8::Integer::New(running_handles);
}
}
// remove select totally for timeout doesn't work properly
do
{
code = curl_multi_perform(curlm, &running_handles);
@ -327,35 +454,42 @@ class NodeCurl
if (msg->msg == CURLMSG_DONE)
{
NodeCurl * curl = curls[msg->easy_handle];
// ensure curl still exists,
// gc will delete the curl if there is no reference.
if (msg->data.result == CURLE_OK)
curl->on_end(msg);
else
curl->on_error(msg);
CURLMsg msg_copy = *msg;
code = curl_multi_remove_handle(curlm, msg->easy_handle);
curl->in_curlm = false;
if (code != CURLM_OK)
{
return raise("curl_multi_remove_handle failed", curl_multi_strerror(code));
}
if (msg_copy.data.result == CURLE_OK)
curl->on_end(&msg_copy);
else
curl->on_error(&msg_copy);
}
}
}
return v8::Integer::New(running_handles);
return v8::Integer::New(transfered + (int)(running_handles > 0));
}
// perform()
static v8::Handle<v8::Value> perform(const v8::Arguments & args)
{
NodeCurl *curl = unwrap(args.This());
if (!curl)
return raise("curl is closed.");
if (curl->in_curlm)
return raise("curl session is running.");
CURLMcode code = curl_multi_add_handle(curlm, curl->curl);
curl->in_curlm = true;
if (code != CURLM_OK)
{
return raise("curl_multi_add_handle failed", curl_multi_strerror(code));
}
curl->in_curlm = true;
++running_handles;
return args.This();
}
@ -389,18 +523,19 @@ class NodeCurl
NODE_SET_PROTOTYPE_METHOD(t , "setopt_int_" , setopt_int);
NODE_SET_PROTOTYPE_METHOD(t , "setopt_str_" , setopt_str);
NODE_SET_PROTOTYPE_METHOD(t , "setopt_slist_" , setopt_slist);
NODE_SET_PROTOTYPE_METHOD(t , "setopt_httppost_" , setopt_httppost);
NODE_SET_PROTOTYPE_METHOD(t , "getinfo_int_" , getinfo_int);
NODE_SET_PROTOTYPE_METHOD(t , "getinfo_str_" , getinfo_str);
NODE_SET_PROTOTYPE_METHOD(t , "getinfo_double_" , getinfo_double);
NODE_SET_PROTOTYPE_METHOD(t , "getinfo_slist_" , getinfo_slist);
NODE_SET_PROTOTYPE_METHOD(t, "close", close);
NODE_SET_PROTOTYPE_METHOD(t, "close_", close);
NODE_SET_METHOD(t , "process_" , process);
NODE_SET_METHOD(t , "get_count" , get_count);
// Set curl constants
// Set curl constants
#include "string_options.h"
#include "integer_options.h"
#include "string_infos.h"
@ -409,13 +544,22 @@ class NodeCurl
#define X(name) {#name, CURLOPT_##name}
CurlOption slist_options[] = {
#if LIBCURL_VERSION_NUM >= 0x070a03
X(HTTP200ALIASES),
#endif
#if LIBCURL_VERSION_NUM >= 0x071400
X(MAIL_RCPT),
#endif
#if LIBCURL_VERSION_NUM >= 0x071503
X(RESOLVE),
#endif
X(HTTPHEADER),
X(HTTP200ALIASES),
X(MAIL_RCPT),
X(QUOTE),
X(POSTQUOTE),
X(PREQUOTE),
X(RESOLVE),
X(TELNETOPTIONS)
};
#undef X
@ -425,6 +569,15 @@ class NodeCurl
X(SSL_ENGINES),
X(COOKIELIST)
};
#undef X
#define X(name) {#name, NodeCurlHttppost::name}
CurlOption httppost_options[] = {
X(NAME),
X(FILE),
X(CONTENTS),
X(TYPE)
};
#undef X
NODE_CURL_EXPORT(string_options);
@ -436,6 +589,8 @@ class NodeCurl
NODE_CURL_EXPORT(double_infos);
NODE_CURL_EXPORT(slist_infos);
NODE_CURL_EXPORT(httppost_options);
target->Set(v8::String::NewSymbol("Curl"), t->GetFunction());
return target;
}
@ -446,5 +601,6 @@ int NodeCurl::running_handles = 0;
bool NodeCurl::is_ref = false;
std::map< CURL*, NodeCurl* > NodeCurl::curls;
int NodeCurl::count = 0;
int NodeCurl::transfered = 0;
#endif

View file

@ -1,11 +0,0 @@
// generated by generate_curl_options_list.sh at Mon, 13 Feb 2012 21:40:10 +0800
CurlOption string_infos[] = {
{"EFFECTIVE_URL", CURLINFO_EFFECTIVE_URL},
{"CONTENT_TYPE", CURLINFO_CONTENT_TYPE},
{"PRIVATE", CURLINFO_PRIVATE},
{"FTP_ENTRY_PATH", CURLINFO_FTP_ENTRY_PATH},
{"REDIRECT_URL", CURLINFO_REDIRECT_URL},
{"PRIMARY_IP", CURLINFO_PRIMARY_IP},
{"RTSP_SESSION_ID", CURLINFO_RTSP_SESSION_ID},
{"LOCAL_IP", CURLINFO_LOCAL_IP},
};

View file

@ -1,84 +0,0 @@
// generated by generate_curl_options_list.sh at Mon, 13 Feb 2012 21:40:10 +0800
CurlOption string_options[] = {
{"FILE", CURLOPT_FILE},
{"URL", CURLOPT_URL},
{"PROXY", CURLOPT_PROXY},
{"USERPWD", CURLOPT_USERPWD},
{"PROXYUSERPWD", CURLOPT_PROXYUSERPWD},
{"RANGE", CURLOPT_RANGE},
{"INFILE", CURLOPT_INFILE},
{"ERRORBUFFER", CURLOPT_ERRORBUFFER},
{"POSTFIELDS", CURLOPT_POSTFIELDS},
{"REFERER", CURLOPT_REFERER},
{"FTPPORT", CURLOPT_FTPPORT},
{"USERAGENT", CURLOPT_USERAGENT},
{"COOKIE", CURLOPT_COOKIE},
{"HTTPHEADER", CURLOPT_HTTPHEADER},
{"HTTPPOST", CURLOPT_HTTPPOST},
{"SSLCERT", CURLOPT_SSLCERT},
{"KEYPASSWD", CURLOPT_KEYPASSWD},
{"QUOTE", CURLOPT_QUOTE},
{"WRITEHEADER", CURLOPT_WRITEHEADER},
{"COOKIEFILE", CURLOPT_COOKIEFILE},
{"CUSTOMREQUEST", CURLOPT_CUSTOMREQUEST},
{"STDERR", CURLOPT_STDERR},
{"POSTQUOTE", CURLOPT_POSTQUOTE},
{"WRITEINFO", CURLOPT_WRITEINFO},
{"PROGRESSDATA", CURLOPT_PROGRESSDATA},
{"INTERFACE", CURLOPT_INTERFACE},
{"KRBLEVEL", CURLOPT_KRBLEVEL},
{"CAINFO", CURLOPT_CAINFO},
{"TELNETOPTIONS", CURLOPT_TELNETOPTIONS},
{"RANDOM_FILE", CURLOPT_RANDOM_FILE},
{"EGDSOCKET", CURLOPT_EGDSOCKET},
{"COOKIEJAR", CURLOPT_COOKIEJAR},
{"SSL_CIPHER_LIST", CURLOPT_SSL_CIPHER_LIST},
{"SSLCERTTYPE", CURLOPT_SSLCERTTYPE},
{"SSLKEY", CURLOPT_SSLKEY},
{"SSLKEYTYPE", CURLOPT_SSLKEYTYPE},
{"SSLENGINE", CURLOPT_SSLENGINE},
{"PREQUOTE", CURLOPT_PREQUOTE},
{"DEBUGDATA", CURLOPT_DEBUGDATA},
{"CAPATH", CURLOPT_CAPATH},
{"SHARE", CURLOPT_SHARE},
{"ACCEPT_ENCODING", CURLOPT_ACCEPT_ENCODING},
{"PRIVATE", CURLOPT_PRIVATE},
{"HTTP200ALIASES", CURLOPT_HTTP200ALIASES},
{"SSL_CTX_DATA", CURLOPT_SSL_CTX_DATA},
{"NETRC_FILE", CURLOPT_NETRC_FILE},
{"IOCTLDATA", CURLOPT_IOCTLDATA},
{"FTP_ACCOUNT", CURLOPT_FTP_ACCOUNT},
{"COOKIELIST", CURLOPT_COOKIELIST},
{"FTP_ALTERNATIVE_TO_USER", CURLOPT_FTP_ALTERNATIVE_TO_USER},
{"SOCKOPTDATA", CURLOPT_SOCKOPTDATA},
{"SSH_PUBLIC_KEYFILE", CURLOPT_SSH_PUBLIC_KEYFILE},
{"SSH_PRIVATE_KEYFILE", CURLOPT_SSH_PRIVATE_KEYFILE},
{"SSH_HOST_PUBLIC_KEY_MD5", CURLOPT_SSH_HOST_PUBLIC_KEY_MD5},
{"OPENSOCKETDATA", CURLOPT_OPENSOCKETDATA},
{"COPYPOSTFIELDS", CURLOPT_COPYPOSTFIELDS},
{"SEEKDATA", CURLOPT_SEEKDATA},
{"CRLFILE", CURLOPT_CRLFILE},
{"ISSUERCERT", CURLOPT_ISSUERCERT},
{"USERNAME", CURLOPT_USERNAME},
{"PASSWORD", CURLOPT_PASSWORD},
{"PROXYUSERNAME", CURLOPT_PROXYUSERNAME},
{"PROXYPASSWORD", CURLOPT_PROXYPASSWORD},
{"NOPROXY", CURLOPT_NOPROXY},
{"SOCKS5_GSSAPI_SERVICE", CURLOPT_SOCKS5_GSSAPI_SERVICE},
{"SSH_KNOWNHOSTS", CURLOPT_SSH_KNOWNHOSTS},
{"SSH_KEYDATA", CURLOPT_SSH_KEYDATA},
{"MAIL_FROM", CURLOPT_MAIL_FROM},
{"MAIL_RCPT", CURLOPT_MAIL_RCPT},
{"RTSP_SESSION_ID", CURLOPT_RTSP_SESSION_ID},
{"RTSP_STREAM_URI", CURLOPT_RTSP_STREAM_URI},
{"RTSP_TRANSPORT", CURLOPT_RTSP_TRANSPORT},
{"INTERLEAVEDATA", CURLOPT_INTERLEAVEDATA},
{"CHUNK_DATA", CURLOPT_CHUNK_DATA},
{"FNMATCH_DATA", CURLOPT_FNMATCH_DATA},
{"RESOLVE", CURLOPT_RESOLVE},
{"TLSAUTH_USERNAME", CURLOPT_TLSAUTH_USERNAME},
{"TLSAUTH_PASSWORD", CURLOPT_TLSAUTH_PASSWORD},
{"TLSAUTH_TYPE", CURLOPT_TLSAUTH_TYPE},
{"CLOSESOCKETDATA", CURLOPT_CLOSESOCKETDATA},
{"DNS_SERVERS", CURLOPT_DNS_SERVERS},
};

View file

@ -4,7 +4,7 @@ def set_options(opt):
def configure(conf):
conf.check_tool('compiler_cxx')
conf.check_tool('node_addon')
conf.env.append_unique('CXXFLAGS', ['-Wall', '-O2'])
conf.env.append_unique('CXXFLAGS', ['-Wall', '-O1', '-fno-inline-functions'])
conf.env['LIB_CURL'] = 'curl'
def build(bld):