Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
284 additions
and
102 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,82 @@ | ||
curling | ||
======= | ||
|
||
A node wrapper for curl with a very simple api. | ||
A node wrapper for curl with a very simple api. | ||
|
||
## API | ||
|
||
Exports only two methods `connect` and `run` | ||
|
||
### run(command, cb) | ||
|
||
You shouldn't have to use `run` but is in there just as a convenience or if you need to do something crazy that is not possible to do via the connection object. | ||
|
||
It pretty much allow you to send any command with any option to curl. It used internally by connect and the connection object. | ||
|
||
Ex: | ||
|
||
var curl = require('curling'); | ||
curl.run("--GET http://www.cnn.com", function (err, result) { | ||
console.log(result.payload); // should output the html for the cnn page to console. | ||
console.log(result.stats); // should output some of the statistics on downloading the page | ||
}); | ||
|
||
### connect(options) | ||
|
||
This method takes an `options` object with general options for the connection like the username and password in case you are using basic auth to connect to an end point. | ||
|
||
var options = {username: "hernan", password: "secret"}; | ||
|
||
At the moment those are the only options that connect knows how to deal with. | ||
|
||
It returns a connection object. | ||
|
||
### Connection object API | ||
|
||
It has five methods, each corresponding to an HTTP verb. They all have the same signature: `method(url, options, cb)`. The method are: | ||
|
||
head(); | ||
get(); | ||
post(); | ||
put(); | ||
del(); //DELETE | ||
|
||
The callback takes two parameters `cb(err, result)` where the result is a `curl-result` object. | ||
|
||
|
||
### curl-result | ||
|
||
It has two properties, `payload` and `stats`. The payload contains the data returned in the stdout by curl while the stats is an object that parse as the content of stderr. | ||
|
||
Stats is of the form: | ||
|
||
{ | ||
totalSize: 0, | ||
received: 0, | ||
xferd: 0, | ||
averageDownloadSpeed: 0, | ||
averageUploadSpeed: 0, | ||
totalTime: 0, | ||
timeSpent: 0, | ||
timeLeft: 0, | ||
currentSpeed: '0 Kb' | ||
} | ||
|
||
The time properties are converted to milliseconds, the rest of the properties are of type `Number` in the same units as returned by curl except for the `currentSpeed` that is a string with the unit at the end (again as returned by curl). | ||
|
||
## Passing options. | ||
|
||
There are two ways to pass options and data to a request. | ||
You can use the `options` for the `connect` method and this options will be used in each and every request. | ||
You can also use the `options` object in each of the verb methods. | ||
|
||
The `options` object is actually a hash where the keys should be the name of the flag in a curl command, for example to set an Accept header and pass some data you could pass an `options` as the following. | ||
|
||
var options = { | ||
header: "Accept: text/html", | ||
data: ["name=hernan", "last=garcia"] | ||
}; | ||
|
||
The keys in an `options` object can be one of the following types, String, Array or null. | ||
|
||
Strings are useful when you only need to set a single value, arrays are used to pass multiple values, like data, header and so. Null is a specialcase and is used for empty flags, like `--false`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
exports.connect = require('./lib/curl-transport').connect; | ||
exports.run = require('./lib/curl-transport').run; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,77 +1,119 @@ | ||
"use strict"; | ||
var exec = require('child_process').exec; | ||
var qs = require('querystring'); | ||
|
||
exports.connect = function (connOptions) { | ||
function run(command, cb) { | ||
exec(command, function (error, stdout, stderr) { | ||
try { | ||
if (connOptions.json) { | ||
cb(null, JSON.parse(stdout)); | ||
} else { | ||
cb(null, stdout); | ||
} | ||
} catch (e) { | ||
cb(e, null); | ||
} | ||
}) | ||
.on('error', function (err) { | ||
cb(err, null); | ||
}); | ||
function parseStats(stderr) { | ||
var lines = []; | ||
var items = []; | ||
var stats = {}; | ||
var propMap = [ | ||
{index: 1, name: 'totalSize', val: 0}, | ||
{index: 3, name: 'received', val: 0}, | ||
{index: 5, name: 'xferd', val: 0}, | ||
{index: 6, name: 'averageDownloadSpeed', val: 0}, | ||
{index: 7, name: 'averageUploadSpeed', val: 0}, | ||
{index: 8, name: 'totalTime', val: "--:--:--"}, | ||
{index: 9, name: 'timeSpent', val: "--:--:--"}, | ||
{index: 10, name: 'timeLeft', val: "--:--:--"}, | ||
{index: 11, name: 'currentSpeed', val: 0} | ||
]; | ||
|
||
if (stderr) { | ||
try { | ||
lines = stderr.split("\r"); | ||
items = lines[2].replace("\n", "").split(" ").filter(function (item) { return item; }); | ||
} catch (e) {} | ||
} | ||
|
||
function getCredentials(connOptions) { | ||
if (connOptions.username && connOptions.password) { | ||
return " --user " + connOptions.username + ":" + connOptions.password; | ||
function getValue(prop) { | ||
if (items.length > prop.index) { | ||
return items[prop.index]; | ||
} | ||
return ""; | ||
return prop.val; | ||
} | ||
|
||
function getData(options) { | ||
if (options.data) { | ||
if (options.data.toLowerCase) { | ||
return " --data \"" + options.data + "\""; | ||
} else { | ||
return " --data '" + JSON.stringify(options.data) + "'"; | ||
} | ||
propMap.forEach(function (prop) { | ||
stats[prop.name] = getValue(prop); | ||
}); | ||
|
||
return stats; | ||
} | ||
|
||
|
||
exports.run = function (command, cb) { | ||
exec("curl " + command, function (error, stdout, stderr) { | ||
cb(null, {payload: stdout, stats: parseStats(stderr)}); | ||
}) | ||
.on('error', function (err) { | ||
cb(err, null); | ||
}); | ||
}; | ||
|
||
exports.connect = function (connOptions) { | ||
|
||
var ctx = this; | ||
|
||
function getEmptyOption(option) { | ||
if (option.length === 1) { | ||
return " -" + option; | ||
} | ||
return ""; | ||
return " --" + option; | ||
} | ||
|
||
function getHeaders(options) { | ||
if (options.headers) { | ||
var headers = ""; | ||
Object.keys(options.headers).forEach(function (key) { | ||
headers += " -H " + key + ":\"" + options.headers[key] + "\""; | ||
function getStringOption(option, value) { | ||
return getEmptyOption(option) + " \"" + value + "\""; | ||
} | ||
|
||
function processOptions(options) { | ||
var tmp = ""; | ||
if (options) { | ||
Object.keys(options).forEach(function (option) { | ||
var values = options[option]; | ||
if (!values) { | ||
tmp += getEmptyOption(option) | ||
} else if (values.toLowerCase) { | ||
tmp += getStringOption(option, values); | ||
} else if (Array.isArray(values)) { | ||
values.forEach(function (value) { | ||
tmp += getStringOption(option, value); | ||
}); | ||
} | ||
}); | ||
return headers; | ||
} | ||
return ""; | ||
return tmp; | ||
} | ||
|
||
function getUrlForCommand(url, connOptions) { | ||
return getCredentials(connOptions) + " " + url; | ||
function getOptions(options) { | ||
return processOptions(connOptions) + processOptions(options); | ||
} | ||
|
||
function getCommand(url, options) { | ||
return url + getOptions(options); | ||
} | ||
|
||
return { | ||
head: function (url, options, cb) { | ||
var command = "--HEAD " + getCommand(url, options); | ||
ctx.run(command, cb); | ||
}, | ||
|
||
get: function (url, options, cb) { | ||
var command = "curl --GET" + getUrlForCommand(url, connOptions) + getHeaders(options) + getData(options); | ||
run(command, cb); | ||
var command = "--GET " + getCommand(url, options); | ||
ctx.run(command, cb); | ||
}, | ||
|
||
post: function (url, options, cb) { | ||
var command = "curl" + getUrlForCommand(url, connOptions) + getHeaders(options) + getData(options); | ||
run(command, cb); | ||
var command = getCommand(url, options); | ||
ctx.run(command, cb); | ||
}, | ||
|
||
put: function (url, options, cb) { | ||
var command = "curl --request PUT" + getUrlForCommand(url, connOptions) + getHeaders(options) + getData(options); | ||
run(command, cb); | ||
var command = "--request PUT " + getCommand(url, options); | ||
ctx.run(command, cb); | ||
}, | ||
|
||
del: function (url, options, cb) { | ||
var command = "curl --include --request DELETE" + getUrlForCommand(url, connOptions) + getHeaders(options); | ||
run(command, cb, true); | ||
var command = "--include --request DELETE" + getCommand(url, options); | ||
ctx.run(command, cb, true); | ||
} | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.