Comparing version 0.2.9 to 0.3.0
@@ -26,22 +26,22 @@ ////////////////////////////////////////// | ||
var parsers = { | ||
'application/json': function(data, callback){ | ||
callback(data && JSON.parse(data)); | ||
} | ||
'application/json': function(data, callback){ | ||
callback(data && JSON.parse(data)); | ||
} | ||
}; | ||
try { | ||
var xml2js = require('xml2js'); | ||
parsers['application/xml'] = function(data, callback){ | ||
var xml2js = require('xml2js'); | ||
parsers['application/xml'] = function(data, callback){ | ||
var xml_parser = new xml2js.Parser(); | ||
var xml_parser = new xml2js.Parser(); | ||
xml_parser.on('end', callback); | ||
xml_parser.on('error', function(result) { | ||
throw("Error parsing XML!") | ||
// callback(null); | ||
}); | ||
xml_parser.on('end', callback); | ||
xml_parser.on('error', function(result) { | ||
throw("Error parsing XML!") | ||
// callback(null); | ||
}); | ||
xml_parser.parseString(data); | ||
xml_parser.parseString(data); | ||
}; | ||
}; | ||
} catch(e) { } | ||
@@ -51,15 +51,15 @@ | ||
function flatten(object, into, prefix){ | ||
into = into || {}; | ||
into = into || {}; | ||
for(key in object){ | ||
var prefix_key = prefix ? prefix + "[" + key + "]" : key; | ||
var prop = object[key]; | ||
for(key in object){ | ||
var prefix_key = prefix ? prefix + "[" + key + "]" : key; | ||
var prop = object[key]; | ||
if(prop && typeof prop === "object" && !((prop.buffer || prop.file) && prop.content_type)) | ||
flatten(prop, into, prefix_key) | ||
else | ||
into[prefix_key] = prop; | ||
} | ||
if(prop && typeof prop === "object" && !((prop.buffer || prop.file) && prop.content_type)) | ||
flatten(prop, into, prefix_key) | ||
else | ||
into[prefix_key] = prop; | ||
} | ||
return into; | ||
return into; | ||
} | ||
@@ -69,218 +69,218 @@ | ||
default_boundary: '--------------------NODENEEDLEHTTPCLIENT', | ||
default_user_agent: default_user_agent, | ||
default_boundary: '--------------------NODENEEDLEHTTPCLIENT', | ||
default_user_agent: default_user_agent, | ||
request: function(uri, method, data, options, callback){ | ||
request: function(uri, method, data, options, callback){ | ||
var self = this, post_data = null; | ||
var callback = (typeof options == 'function') ? options : callback; | ||
var options = options || {}; | ||
if(uri.indexOf('http') == -1) uri = 'http://' + uri; | ||
var self = this, post_data = null; | ||
var callback = (typeof options == 'function') ? options : callback; | ||
var options = options || {}; | ||
if(uri.indexOf('http') == -1) uri = 'http://' + uri; | ||
var method = options.method || 'GET'; | ||
var method = options.method || 'GET'; | ||
var config = { | ||
base_opts: {}, | ||
proxy: options.proxy, | ||
encoding: options.encoding || (options.multipart ? 'binary' : 'utf8'), | ||
parse_response: options.parse === false ? false : true, | ||
follow: options.follow === false ? 0 : options.follow || 10, // 10 by default | ||
timeout: (typeof options.timeout == 'number') ? options.timeout : 10000 | ||
} | ||
var config = { | ||
base_opts: {}, | ||
proxy: options.proxy, | ||
encoding: options.encoding || (options.multipart ? 'binary' : 'utf8'), | ||
parse_response: options.parse === false ? false : true, | ||
follow: options.follow === false ? 0 : options.follow || 10, // 10 by default | ||
timeout: (typeof options.timeout == 'number') ? options.timeout : 10000 | ||
} | ||
additional_http_opts.forEach(function(key){ | ||
if(typeof options[key] != 'undefined') | ||
config.base_opts[key] = options[key]; | ||
}); | ||
additional_http_opts.forEach(function(key){ | ||
if(typeof options[key] != 'undefined') | ||
config.base_opts[key] = options[key]; | ||
}); | ||
config.headers = { | ||
"User-Agent": options.user_agent || this.default_user_agent, | ||
"Connection": "close", | ||
"Accept": "*/*" | ||
} | ||
config.headers = { | ||
"User-Agent": options.user_agent || this.default_user_agent, | ||
"Connection": "close", | ||
"Accept": "*/*" | ||
} | ||
if (options.compressed && typeof unzip != 'undefined') | ||
config.headers['Accept-Encoding'] = 'gzip,deflate'; | ||
if (options.compressed && typeof unzip != 'undefined') | ||
config.headers['Accept-Encoding'] = 'gzip,deflate'; | ||
for(h in options.headers) | ||
config.headers[h] = options.headers[h]; | ||
for(h in options.headers) | ||
config.headers[h] = options.headers[h]; | ||
if(options.username && options.password){ | ||
var b = new Buffer([options.username, options.password].join(':')); | ||
config.headers['Authorization'] = "Basic " + b.toString('base64'); | ||
} | ||
if(options.username && options.password){ | ||
var b = new Buffer([options.username, options.password].join(':')); | ||
config.headers['Authorization'] = "Basic " + b.toString('base64'); | ||
} | ||
if(data) { | ||
if(options.multipart){ | ||
if(data) { | ||
if(options.multipart){ | ||
var boundary = options.boundary || this.default_boundary; | ||
return this.build_multipart_body(data, boundary, function(err, body){ | ||
var boundary = options.boundary || this.default_boundary; | ||
return this.build_multipart_body(data, boundary, function(err, body){ | ||
if(err) throw(err); | ||
config.headers['Content-Type'] = 'multipart/form-data; boundary=' + boundary; | ||
config.headers['Content-Length'] = body.length; | ||
self.send_request(1, method, uri, config, body, callback); | ||
if(err) throw(err); | ||
config.headers['Content-Type'] = 'multipart/form-data; boundary=' + boundary; | ||
config.headers['Content-Length'] = body.length; | ||
self.send_request(1, method, uri, config, body, callback); | ||
}); | ||
}); | ||
} else { | ||
post_data = (typeof(data) === "string") ? data : stringify(data); | ||
config.headers['Content-Type'] = 'application/x-www-form-urlencoded'; | ||
config.headers['Content-Length'] = post_data.length; | ||
} | ||
} else { | ||
post_data = (typeof(data) === "string") ? data : stringify(data); | ||
config.headers['Content-Type'] = 'application/x-www-form-urlencoded'; | ||
config.headers['Content-Length'] = post_data.length; | ||
} | ||
} | ||
} | ||
this.send_request(1, method, uri, config, post_data, callback); | ||
this.send_request(1, method, uri, config, post_data, callback); | ||
}, | ||
}, | ||
get_request_opts: function(method, uri, config){ | ||
get_request_opts: function(method, uri, config){ | ||
var opts = config.base_opts, proxy = config.proxy; | ||
var remote = proxy ? url.parse(proxy) : url.parse(uri); | ||
var opts = config.base_opts, proxy = config.proxy; | ||
var remote = proxy ? url.parse(proxy) : url.parse(uri); | ||
opts.host = remote.hostname; | ||
opts.port = remote.port || (remote.protocol == 'https:' ? 443 : 80); | ||
opts.protocol = remote.protocol; | ||
opts.path = proxy ? uri : remote.pathname + (remote.search || ''); | ||
opts.method = method; | ||
opts.headers = config.headers; | ||
opts.headers["Host"] = proxy ? url.parse(uri).hostname : remote.hostname; | ||
opts.host = remote.hostname; | ||
opts.port = remote.port || (remote.protocol == 'https:' ? 443 : 80); | ||
opts.protocol = remote.protocol; | ||
opts.path = proxy ? uri : remote.pathname + (remote.search || ''); | ||
opts.method = method; | ||
opts.headers = config.headers; | ||
opts.headers["Host"] = proxy ? url.parse(uri).hostname : remote.hostname; | ||
return opts; | ||
}, | ||
return opts; | ||
}, | ||
send_request: function(count, method, uri, config, post_data, callback){ | ||
send_request: function(count, method, uri, config, post_data, callback){ | ||
var self = this, timer, response_opts = {parse_response: config.parse_response}; | ||
var request_opts = this.get_request_opts(method, uri, config); | ||
var self = this, timer, response_opts = {parse_response: config.parse_response}; | ||
var request_opts = this.get_request_opts(method, uri, config); | ||
var protocol = request_opts.protocol == 'https:' ? https : http; | ||
var request = protocol.request(request_opts, function(response){ | ||
var protocol = request_opts.protocol == 'https:' ? https : http; | ||
var request = protocol.request(request_opts, function(response){ | ||
if(timer) clearTimeout(timer); | ||
if(timer) clearTimeout(timer); | ||
if((response.statusCode == 301 || response.statusCode == 302) && response.headers.location){ | ||
if(count <= config.follow) | ||
return self.send_request(++count, 'GET', response.headers.location, config, null, callback); | ||
else if(config.follow > 0) | ||
return callback(new Error("Too many redirects. Possible redirect loop in " + response.headers.location)) | ||
} | ||
if((response.statusCode == 301 || response.statusCode == 302) && response.headers.location){ | ||
if(count <= config.follow) | ||
return self.send_request(++count, 'GET', response.headers.location, config, null, callback); | ||
else if(config.follow > 0) | ||
return callback(new Error("Too many redirects. Possible redirect loop in " + response.headers.location)) | ||
} | ||
var body = ''; | ||
var compressed = /gzip|deflate/.test(response.headers['content-encoding']); | ||
response.setEncoding(compressed ? 'binary' : 'utf8'); | ||
var body = ''; | ||
var compressed = /gzip|deflate/.test(response.headers['content-encoding']); | ||
response.setEncoding(compressed ? 'binary' : 'utf8'); | ||
response.on('data', function(chunk){ | ||
body += chunk; | ||
}); | ||
response.on('data', function(chunk){ | ||
body += chunk; | ||
}); | ||
response.on('end', function(){ | ||
if(typeof unzip != 'undefined' && compressed) | ||
unzip(new Buffer(body, 'binary'), function(err, buff){ | ||
self.response_end(response_opts, response, buff.toString(), callback); | ||
}); | ||
else | ||
self.response_end(response_opts, response, body, callback); | ||
response.on('end', function(){ | ||
if(typeof unzip != 'undefined' && compressed) | ||
unzip(new Buffer(body, 'binary'), function(err, buff){ | ||
self.response_end(response_opts, response, buff.toString(), callback); | ||
}); | ||
else | ||
self.response_end(response_opts, response, body, callback); | ||
}); | ||
}); | ||
}); | ||
}); | ||
if(config.timeout > 0) { | ||
timer = setTimeout(function() { | ||
request.abort(); | ||
}, config.timeout) | ||
} | ||
if(config.timeout > 0) { | ||
timer = setTimeout(function() { | ||
request.abort(); | ||
}, config.timeout) | ||
} | ||
request.on('error', function(err) { | ||
if(process.env.DEBUG) console.log('Error on request: ' + err.toString()); | ||
if(timer) clearTimeout(timer); | ||
if(callback) callback(err || new Error("Unkown error on request.")); | ||
}); | ||
request.on('error', function(err) { | ||
if(process.env.DEBUG) console.log('Error on request: ' + err.toString()); | ||
if(timer) clearTimeout(timer); | ||
if(callback) callback(err || new Error("Unkown error on request.")); | ||
}); | ||
if(post_data) request.write(post_data, config.encoding); | ||
request.end(); | ||
if(post_data) request.write(post_data, config.encoding); | ||
request.end(); | ||
}, | ||
}, | ||
response_end: function(opts, response, body, callback){ | ||
response_end: function(opts, response, body, callback){ | ||
if(process.env.DEBUG) console.log(response.headers); | ||
if(!callback) return; | ||
var content_type = response.headers['content-type'] && response.headers['content-type'].split(';')[0]; | ||
if(process.env.DEBUG) console.log(response.headers); | ||
if(!callback) return; | ||
var content_type = response.headers['content-type'] && response.headers['content-type'].split(';')[0]; | ||
if(opts.parse_response && parsers[content_type]) { | ||
parsers[content_type](body, function(result){ | ||
callback(null, response, result); | ||
}); | ||
} else { | ||
callback(null, response, body); | ||
} | ||
if(opts.parse_response && parsers[content_type]) { | ||
parsers[content_type](body, function(result){ | ||
callback(null, response, result); | ||
}); | ||
} else { | ||
callback(null, response, body); | ||
} | ||
}, | ||
}, | ||
build_multipart_body: function(data, boundary, callback){ | ||
build_multipart_body: function(data, boundary, callback){ | ||
var body = ''; | ||
var object = flatten(data); | ||
var count = Object.keys(object).length; | ||
var body = ''; | ||
var object = flatten(data); | ||
var count = Object.keys(object).length; | ||
for(var key in object){ | ||
for(var key in object){ | ||
var value = object[key]; | ||
if(value === null || typeof value == 'undefined') return --count; | ||
var value = object[key]; | ||
if(value === null || typeof value == 'undefined') return --count; | ||
var part = (value.buffer || value.file) && value.content_type ? value : {value: value}; | ||
var part = (value.buffer || value.file) && value.content_type ? value : {value: value}; | ||
this.generate_part(key, part, boundary, function(err, section){ | ||
if(err) return callback(err); | ||
body += section; | ||
--count || callback(null, body + '--' + boundary + '--'); | ||
}); | ||
this.generate_part(key, part, boundary, function(err, section){ | ||
if(err) return callback(err); | ||
body += section; | ||
--count || callback(null, body + '--' + boundary + '--'); | ||
}); | ||
} | ||
} | ||
}, | ||
}, | ||
generate_part: function(name, part, boundary, callback){ | ||
generate_part: function(name, part, boundary, callback){ | ||
var return_part = '--' + boundary + "\r\n"; | ||
return_part += "Content-Disposition: form-data; name=\"" + name + "\""; | ||
var return_part = '--' + boundary + "\r\n"; | ||
return_part += "Content-Disposition: form-data; name=\"" + name + "\""; | ||
var append = function(data, filename){ | ||
var append = function(data, filename){ | ||
if(data){ | ||
return_part += "; filename=\"" + encodeURIComponent(filename) + "\"\r\n"; | ||
return_part += "Content-Type: " + part.content_type + "\r\n\r\n"; | ||
return_part += (part.content_type.indexOf('text') == -1) | ||
? data.toString('binary') | ||
: data.toString('utf8'); | ||
} | ||
if(data){ | ||
return_part += "; filename=\"" + encodeURIComponent(filename) + "\"\r\n"; | ||
return_part += "Content-Type: " + part.content_type + "\r\n\r\n"; | ||
return_part += (part.content_type.indexOf('text') == -1) | ||
? data.toString('binary') | ||
: data.toString('utf8'); | ||
} | ||
callback(null, return_part + '\r\n'); | ||
}; | ||
callback(null, return_part + '\r\n'); | ||
}; | ||
if((part.file || part.buffer) && part.content_type){ | ||
if((part.file || part.buffer) && part.content_type){ | ||
var filename = part.filename ? part.filename : part.file ? path.basename(part.file) : name; | ||
if(part.buffer) return append(part.buffer, filename); | ||
var filename = part.filename ? part.filename : part.file ? path.basename(part.file) : name; | ||
if(part.buffer) return append(part.buffer, filename); | ||
fs.readFile(part.file, function(err, data){ | ||
fs.readFile(part.file, function(err, data){ | ||
if(err) return callback(err); | ||
append(data, filename); | ||
if(err) return callback(err); | ||
append(data, filename); | ||
}); | ||
}); | ||
} else { | ||
} else { | ||
return_part += "\r\n\r\n"; | ||
return_part += part.value; | ||
append(); | ||
return_part += "\r\n\r\n"; | ||
return_part += part.value; | ||
append(); | ||
} | ||
} | ||
} | ||
} | ||
@@ -290,21 +290,21 @@ } | ||
exports.head = function(uri, options, callback){ | ||
return Needle.request(uri, 'HEAD', null, options, callback); | ||
return Needle.request(uri, 'HEAD', null, options, callback); | ||
} | ||
exports.get = function(uri, options, callback){ | ||
return Needle.request(uri, 'GET', null, options, callback); | ||
return Needle.request(uri, 'GET', null, options, callback); | ||
} | ||
exports.post = function(uri, data, options, callback){ | ||
if(!data) throw('POST request expects data.'); | ||
return Needle.request(uri, 'POST', data, options, callback); | ||
if(!data) throw('POST request expects data.'); | ||
return Needle.request(uri, 'POST', data, options, callback); | ||
} | ||
exports.put = function(uri, data, options, callback){ | ||
if(!data) throw('PUT request expects data.'); | ||
return Needle.request(uri, 'PUT', data, options, callback); | ||
if(!data) throw('PUT request expects data.'); | ||
return Needle.request(uri, 'PUT', data, options, callback); | ||
} | ||
exports.delete = function(uri, data, options, callback){ | ||
return Needle.request(uri, 'DELETE', null, options, callback); | ||
return Needle.request(uri, 'DELETE', null, options, callback); | ||
} |
{ | ||
"name": "needle" | ||
, "version": "0.2.9" | ||
, "version": "0.3.0" | ||
, "description": "Tiny yet feature-packed HTTP client. With deflate & multipart support." | ||
@@ -15,3 +15,3 @@ , "keywords": ["http", "https", "client", "multipart", "deflate", "timeout", "basic-auth", "simple"] | ||
, "bin": {"needle": "./bin/needle"} | ||
, "engines": { "node": ">= 0.4.x < 0.7.0" } | ||
, "engines": { "node": ">= 0.4.x" } | ||
} |
Needle | ||
====== | ||
Async HTTP client for Node.js. Supports SSL, basic authentication, proxied | ||
requests, multipart form POSTs, gzip/deflate compression and redirect following. | ||
The most handsome HTTP client in the Nodelands. Supports SSL, basic authentication, proxied | ||
requests, multipart form POSTs, gzip/deflate compression and, as you would expect, follows | ||
redirects. Simple, nimble and to the point. | ||
@@ -28,4 +29,4 @@ Usage | ||
- `follow`: Whether to follow redirects or not. Can be a number (of max redirects), `false` or `true` (default, which translates to 10). | ||
- `timeout`: Returns error if response takes more than X. Defaults to `10000` (10 secs). Set to 0 for no timeout. | ||
- `timeout`: Returns error if response takes more than X milisecs. Defaults to `10000` (10 secs). `0` means no timeout. | ||
- `follow`: When `false`, Needle won't follow redirects. Can also be a number or `true` (the default, 10 max). | ||
- `compressed`: Whether to ask for a deflated or gzipped response or not. Defaults to `false`. | ||
@@ -32,0 +33,0 @@ - `parse`: Whether to parse XML or JSON response bodies automagically. Defaults to `true`. |
Sorry, the diff of this file is not supported yet
Non-existent author
Supply chain riskThe package was published by an npm account that no longer exists.
Found 1 instance in 1 package
29841
159
1