first
This commit is contained in:
231
node_modules/needle/test/auth_digest_spec.js
generated
vendored
Normal file
231
node_modules/needle/test/auth_digest_spec.js
generated
vendored
Normal file
@ -0,0 +1,231 @@
|
||||
var needle = require('../'),
|
||||
auth = require('../lib/auth'),
|
||||
sinon = require('sinon'),
|
||||
should = require('should'),
|
||||
http = require('http'),
|
||||
helpers = require('./helpers');
|
||||
|
||||
var createHash = require('crypto').createHash;
|
||||
|
||||
function md5(string) {
|
||||
return createHash('md5').update(string).digest('hex');
|
||||
}
|
||||
|
||||
function parse_header(header) {
|
||||
var challenge = {},
|
||||
matches = header.match(/([a-z0-9_-]+)="?([a-z0-9=\/\.@\s-\+]+)"?/gi);
|
||||
|
||||
for (var i = 0, l = matches.length; i < l; i++) {
|
||||
var parts = matches[i].split('='),
|
||||
key = parts.shift(),
|
||||
val = parts.join('=').replace(/^"/, '').replace(/"$/, '');
|
||||
|
||||
challenge[key] = val;
|
||||
}
|
||||
|
||||
return challenge;
|
||||
}
|
||||
|
||||
describe('auth_digest', function() {
|
||||
describe('With qop (RFC 2617)', function() {
|
||||
it('should generate a proper header', function() {
|
||||
// from https://tools.ietf.org/html/rfc2617
|
||||
var performDigest = function() {
|
||||
var header = 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"';
|
||||
var user = 'Mufasa';
|
||||
var pass = 'Circle Of Life';
|
||||
var method = 'get';
|
||||
var path = '/dir/index.html';
|
||||
|
||||
var updatedHeader = auth.digest(header, user, pass, method, path);
|
||||
var parsedUpdatedHeader = parse_header(updatedHeader);
|
||||
|
||||
var ha1 = md5(user + ':' + parsedUpdatedHeader.realm + ':' + pass);
|
||||
var ha2 = md5(method.toUpperCase() + ':' + path);
|
||||
var expectedResponse = md5([
|
||||
ha1,
|
||||
parsedUpdatedHeader.nonce,
|
||||
parsedUpdatedHeader.nc,
|
||||
parsedUpdatedHeader.cnonce,
|
||||
parsedUpdatedHeader.qop,
|
||||
ha2
|
||||
].join(':'));
|
||||
|
||||
return {
|
||||
header: updatedHeader,
|
||||
parsed: parsedUpdatedHeader,
|
||||
expectedResponse: expectedResponse,
|
||||
}
|
||||
}
|
||||
|
||||
const result = performDigest();
|
||||
|
||||
(result.header).should
|
||||
.match(/qop="auth"/)
|
||||
.match(/uri="\/dir\/index.html"/)
|
||||
.match(/opaque="5ccc069c403ebaf9f0171e9517f40e41"/)
|
||||
.match(/realm="testrealm@host\.com"/)
|
||||
.match(/response=/)
|
||||
.match(/nc=/)
|
||||
.match(/nonce=/)
|
||||
.match(/cnonce=/);
|
||||
|
||||
(result.parsed.response).should.be.eql(result.expectedResponse);
|
||||
});
|
||||
});
|
||||
|
||||
describe('With plus character in nonce header', function() {
|
||||
it('should generate a proper header', function() {
|
||||
// from https://tools.ietf.org/html/rfc2617
|
||||
var performDigest = function() {
|
||||
var header = 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f6+00bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"';
|
||||
var user = 'Mufasa';
|
||||
var pass = 'Circle Of Life';
|
||||
var method = 'get';
|
||||
var path = '/dir/index.html';
|
||||
|
||||
var updatedHeader = auth.digest(header, user, pass, method, path);
|
||||
var parsedUpdatedHeader = parse_header(updatedHeader);
|
||||
|
||||
var ha1 = md5(user + ':' + parsedUpdatedHeader.realm + ':' + pass);
|
||||
var ha2 = md5(method.toUpperCase() + ':' + path);
|
||||
var expectedResponse = md5([
|
||||
ha1,
|
||||
parsedUpdatedHeader.nonce,
|
||||
parsedUpdatedHeader.nc,
|
||||
parsedUpdatedHeader.cnonce,
|
||||
parsedUpdatedHeader.qop,
|
||||
ha2
|
||||
].join(':'));
|
||||
|
||||
return {
|
||||
header: updatedHeader,
|
||||
parsed: parsedUpdatedHeader,
|
||||
expectedResponse: expectedResponse,
|
||||
}
|
||||
}
|
||||
|
||||
const result = performDigest();
|
||||
|
||||
(result.header).should
|
||||
.match(/nonce="dcd98b7102dd2f0e8b11d0f6\+00bfb0c093"/)
|
||||
});
|
||||
});
|
||||
|
||||
describe('With colon character in nonce header', function() {
|
||||
it('should generate a proper header', function() {
|
||||
// from https://tools.ietf.org/html/rfc2617
|
||||
var performDigest = function() {
|
||||
var header = 'Digest realm="IP Camera", charset="UTF-8", algorithm="MD5", nonce="636144c2:2970b5fdd41b5ac6b669848f43d2d22b", qop="auth"';
|
||||
var user = 'Mufasa';
|
||||
var pass = 'Circle Of Life';
|
||||
var method = 'get';
|
||||
var path = '/dir/index.html';
|
||||
|
||||
var updatedHeader = auth.digest(header, user, pass, method, path);
|
||||
var parsedUpdatedHeader = parse_header(updatedHeader);
|
||||
|
||||
var ha1 = md5(user + ':' + parsedUpdatedHeader.realm + ':' + pass);
|
||||
var ha2 = md5(method.toUpperCase() + ':' + path);
|
||||
var expectedResponse = md5([
|
||||
ha1,
|
||||
parsedUpdatedHeader.nonce,
|
||||
parsedUpdatedHeader.nc,
|
||||
parsedUpdatedHeader.cnonce,
|
||||
parsedUpdatedHeader.qop,
|
||||
ha2
|
||||
].join(':'));
|
||||
|
||||
return {
|
||||
header: updatedHeader,
|
||||
parsed: parsedUpdatedHeader,
|
||||
expectedResponse: expectedResponse,
|
||||
}
|
||||
}
|
||||
|
||||
const result = performDigest();
|
||||
|
||||
(result.header).should
|
||||
.match(/nonce="636144c2:2970b5fdd41b5ac6b669848f43d2d22b"/)
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('With brackets in realm header', function() {
|
||||
it('should generate a proper header', function() {
|
||||
// from https://tools.ietf.org/html/rfc2617
|
||||
var performDigest = function() {
|
||||
var header = 'Digest qop="auth", realm="IP Camera(76475)", nonce="4e4449794d575269597a706b5a575935595441324d673d3d", stale="FALSE", Basic realm="IP Camera(76475)"';
|
||||
var user = 'Mufasa';
|
||||
var pass = 'Circle Of Life';
|
||||
var method = 'get';
|
||||
var path = '/dir/index.html';
|
||||
|
||||
var updatedHeader = auth.digest(header, user, pass, method, path);
|
||||
var parsedUpdatedHeader = parse_header(updatedHeader);
|
||||
|
||||
var ha1 = md5(user + ':' + parsedUpdatedHeader.realm + ':' + pass);
|
||||
var ha2 = md5(method.toUpperCase() + ':' + path);
|
||||
var expectedResponse = md5([
|
||||
ha1,
|
||||
parsedUpdatedHeader.nonce,
|
||||
parsedUpdatedHeader.nc,
|
||||
parsedUpdatedHeader.cnonce,
|
||||
parsedUpdatedHeader.qop,
|
||||
ha2
|
||||
].join(':'));
|
||||
|
||||
return {
|
||||
header: updatedHeader,
|
||||
parsed: parsedUpdatedHeader,
|
||||
expectedResponse: expectedResponse,
|
||||
}
|
||||
}
|
||||
|
||||
const result = performDigest();
|
||||
|
||||
(result.header).should
|
||||
.match(/realm="IP Camera\(76475\)"/)
|
||||
});
|
||||
});
|
||||
|
||||
describe('Without qop (RFC 2617)', function() {
|
||||
it('should generate a proper header', function() {
|
||||
// from https://tools.ietf.org/html/rfc2069
|
||||
var performDigest = function() {
|
||||
var header = 'Digest realm="testrealm@host.com", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"';
|
||||
var user = 'Mufasa';
|
||||
var pass = 'Circle Of Life';
|
||||
var method = 'get';
|
||||
var path = '/dir/index.html';
|
||||
|
||||
var updatedHeader = auth.digest(header, user, pass, method, path);
|
||||
var parsedUpdatedHeader = parse_header(updatedHeader);
|
||||
|
||||
var ha1 = md5(user + ':' + parsedUpdatedHeader.realm + ':' + pass);
|
||||
var ha2 = md5(method.toUpperCase() + ':' + path);
|
||||
var expectedResponse = md5([ha1, parsedUpdatedHeader.nonce, ha2].join(':'));
|
||||
|
||||
return {
|
||||
header: updatedHeader,
|
||||
parsed: parsedUpdatedHeader,
|
||||
expectedResponse: expectedResponse,
|
||||
}
|
||||
}
|
||||
|
||||
const result = performDigest();
|
||||
|
||||
(result.header).should
|
||||
.not.match(/qop=/)
|
||||
.match(/uri="\/dir\/index.html"/)
|
||||
.match(/opaque="5ccc069c403ebaf9f0171e9517f40e41"/)
|
||||
.match(/realm="testrealm@host\.com"/)
|
||||
.match(/response=/)
|
||||
.not.match(/nc=/)
|
||||
.match(/nonce=/)
|
||||
.not.match(/cnonce=/);
|
||||
|
||||
(result.parsed.response).should.be.eql(result.expectedResponse);
|
||||
});
|
||||
});
|
||||
})
|
196
node_modules/needle/test/basic_auth_spec.js
generated
vendored
Normal file
196
node_modules/needle/test/basic_auth_spec.js
generated
vendored
Normal file
@ -0,0 +1,196 @@
|
||||
var helpers = require('./helpers'),
|
||||
should = require('should'),
|
||||
needle = require('./../'),
|
||||
server;
|
||||
|
||||
var port = 7707;
|
||||
|
||||
describe('Basic Auth', function() {
|
||||
|
||||
before(function(done) {
|
||||
server = helpers.server({ port: port }, done);
|
||||
})
|
||||
|
||||
after(function(done) {
|
||||
server.close(done);
|
||||
})
|
||||
|
||||
///////////////// helpers
|
||||
|
||||
var get_auth = function(header) {
|
||||
var token = header.split(/\s+/).pop();
|
||||
return token && Buffer.from(token, 'base64').toString().split(':');
|
||||
}
|
||||
|
||||
describe('when neither username or password are passed', function() {
|
||||
|
||||
it('doesnt send any Authorization headers', function(done) {
|
||||
needle.get('localhost:' + port, { parse: true }, function(err, resp) {
|
||||
var sent_headers = resp.body.headers;
|
||||
Object.keys(sent_headers).should.not.containEql('authorization');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('when username is an empty string, and password is a valid string', function() {
|
||||
|
||||
var opts = { username: '', password: 'foobar', parse: true };
|
||||
|
||||
it('doesnt send any Authorization headers', function(done) {
|
||||
needle.get('localhost:' + port, { parse: true }, function(err, resp) {
|
||||
var sent_headers = resp.body.headers;
|
||||
Object.keys(sent_headers).should.not.containEql('authorization');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
describe('when username is a valid string, but no username is passed', function() {
|
||||
|
||||
var opts = { username: 'foobar', parse: true };
|
||||
|
||||
it('sends Authorization header', function(done) {
|
||||
needle.get('localhost:' + port, opts, function(err, resp) {
|
||||
var sent_headers = resp.body.headers;
|
||||
Object.keys(sent_headers).should.containEql('authorization');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('Basic Auth only includes username, without colon', function(done) {
|
||||
needle.get('localhost:' + port, opts, function(err, resp) {
|
||||
var sent_headers = resp.body.headers;
|
||||
var auth = get_auth(sent_headers['authorization']);
|
||||
auth[0].should.equal('foobar');
|
||||
auth.should.have.lengthOf(1);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('when username is a valid string, and password is null', function() {
|
||||
|
||||
var opts = { username: 'foobar', password: null, parse: true };
|
||||
|
||||
it('sends Authorization header', function(done) {
|
||||
needle.get('localhost:' + port, opts, function(err, resp) {
|
||||
var sent_headers = resp.body.headers;
|
||||
Object.keys(sent_headers).should.containEql('authorization');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('Basic Auth only includes both username and password', function(done) {
|
||||
needle.get('localhost:' + port, opts, function(err, resp) {
|
||||
var sent_headers = resp.body.headers;
|
||||
var auth = get_auth(sent_headers['authorization']);
|
||||
auth[0].should.equal('foobar');
|
||||
auth[1].should.equal('');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('when username is a valid string, and password is an empty string', function() {
|
||||
|
||||
var opts = { username: 'foobar', password: '', parse: true };
|
||||
|
||||
it('sends Authorization header', function(done) {
|
||||
needle.get('localhost:' + port, opts, function(err, resp) {
|
||||
var sent_headers = resp.body.headers;
|
||||
Object.keys(sent_headers).should.containEql('authorization');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('Basic Auth only includes both username and password', function(done) {
|
||||
needle.get('localhost:' + port, opts, function(err, resp) {
|
||||
var sent_headers = resp.body.headers;
|
||||
var auth = get_auth(sent_headers['authorization']);
|
||||
auth[0].should.equal('foobar');
|
||||
auth[1].should.equal('');
|
||||
auth.should.have.lengthOf(2);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('when username AND password are non empty strings', function() {
|
||||
|
||||
var opts = { username: 'foobar', password: 'jakub', parse: true };
|
||||
|
||||
it('sends Authorization header', function(done) {
|
||||
needle.get('localhost:' + port, opts, function(err, resp) {
|
||||
var sent_headers = resp.body.headers;
|
||||
Object.keys(sent_headers).should.containEql('authorization');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('Basic Auth only includes both user and password', function(done) {
|
||||
needle.get('localhost:' + port, opts, function(err, resp) {
|
||||
var sent_headers = resp.body.headers;
|
||||
var auth = get_auth(sent_headers['authorization']);
|
||||
auth[0].should.equal('foobar');
|
||||
auth[1].should.equal('jakub');
|
||||
auth.should.have.lengthOf(2);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('URL with @ but not username/pass', function() {
|
||||
it('doesnt send Authorization header', function(done) {
|
||||
var url = 'localhost:' + port + '/abc/@def/xyz.zip';
|
||||
|
||||
needle.get(url, {}, function(err, resp) {
|
||||
var sent_headers = resp.body.headers;
|
||||
Object.keys(sent_headers).should.not.containEql('authorization');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('sends user:pass headers if passed via options', function(done) {
|
||||
var url = 'localhost:' + port + '/abc/@def/xyz.zip';
|
||||
|
||||
needle.get(url, { username: 'foo' }, function(err, resp) {
|
||||
var sent_headers = resp.body.headers;
|
||||
Object.keys(sent_headers).should.containEql('authorization');
|
||||
sent_headers['authorization'].should.eql('Basic Zm9v')
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when username/password are included in URL', function() {
|
||||
var opts = { parse: true };
|
||||
|
||||
it('sends Authorization header', function(done) {
|
||||
needle.get('foobar:jakub@localhost:' + port, opts, function(err, resp) {
|
||||
var sent_headers = resp.body.headers;
|
||||
Object.keys(sent_headers).should.containEql('authorization');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('Basic Auth only includes both user and password', function(done) {
|
||||
needle.get('foobar:jakub@localhost:' + port, opts, function(err, resp) {
|
||||
var sent_headers = resp.body.headers;
|
||||
var auth = get_auth(sent_headers['authorization']);
|
||||
auth[0].should.equal('foobar');
|
||||
auth[1].should.equal('jakub');
|
||||
auth.should.have.lengthOf(2);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
112
node_modules/needle/test/compression_spec.js
generated
vendored
Normal file
112
node_modules/needle/test/compression_spec.js
generated
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
var should = require('should'),
|
||||
needle = require('./../'),
|
||||
http = require('http'),
|
||||
zlib = require('zlib'),
|
||||
stream = require('stream'),
|
||||
port = 11123,
|
||||
server;
|
||||
|
||||
describe('compression', function(){
|
||||
|
||||
require.bind(null, 'zlib').should.not.throw()
|
||||
|
||||
var jsonData = '{"foo":"bar"}';
|
||||
|
||||
describe('when server supports compression', function(){
|
||||
|
||||
before(function(){
|
||||
server = http.createServer(function(req, res) {
|
||||
var raw = new stream.PassThrough();
|
||||
|
||||
var acceptEncoding = req.headers['accept-encoding'];
|
||||
if (!acceptEncoding) {
|
||||
acceptEncoding = '';
|
||||
}
|
||||
|
||||
if (acceptEncoding.match(/\bdeflate\b/)) {
|
||||
res.setHeader('Content-Encoding', 'deflate');
|
||||
raw.pipe(zlib.createDeflate()).pipe(res);
|
||||
} else if (acceptEncoding.match(/\bgzip\b/)) {
|
||||
res.setHeader('Content-Encoding', 'gzip');
|
||||
raw.pipe(zlib.createGzip()).pipe(res);
|
||||
} else if (acceptEncoding.match(/\bbr\b/)) {
|
||||
res.setHeader('Content-Encoding', 'br');
|
||||
raw.pipe(zlib.createBrotliCompress()).pipe(res);
|
||||
} else {
|
||||
raw.pipe(res);
|
||||
}
|
||||
|
||||
res.setHeader('Content-Type', 'application/json')
|
||||
if (req.headers['with-bad']) {
|
||||
res.end('foo'); // end, no deflate data
|
||||
} else {
|
||||
raw.end(jsonData)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
server.listen(port);
|
||||
});
|
||||
|
||||
after(function(done){
|
||||
server.close(done);
|
||||
})
|
||||
|
||||
describe('and client requests no compression', function() {
|
||||
it('should have the body decompressed', function(done){
|
||||
needle.get('localhost:' + port, function(err, response, body){
|
||||
should.ifError(err);
|
||||
body.should.have.property('foo', 'bar');
|
||||
response.bytes.should.equal(jsonData.length);
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('and client requests gzip compression', function() {
|
||||
it('should have the body decompressed', function(done){
|
||||
needle.get('localhost:' + port, {headers: {'Accept-Encoding': 'gzip'}}, function(err, response, body){
|
||||
should.ifError(err);
|
||||
body.should.have.property('foo', 'bar');
|
||||
response.bytes.should.not.equal(jsonData.length);
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('and client requests deflate compression', function() {
|
||||
it('should have the body decompressed', function(done){
|
||||
needle.get('localhost:' + port, {headers: {'Accept-Encoding': 'deflate'}}, function(err, response, body){
|
||||
should.ifError(err);
|
||||
body.should.have.property('foo', 'bar');
|
||||
response.bytes.should.not.equal(jsonData.length);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should rethrow errors from decompressors', function(done){
|
||||
needle.get('localhost:' + port, {headers: {'Accept-Encoding': 'deflate', 'With-Bad': 'true'}}, function(err, response, body) {
|
||||
should.exist(err);
|
||||
err.message.should.equal("incorrect header check");
|
||||
err.code.should.equal("Z_DATA_ERROR")
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('and client requests brotli compression', function() {
|
||||
it('should have the body decompressed', function(done){
|
||||
// Skip this test if Brotli is not supported
|
||||
if (typeof zlib.BrotliDecompress !== 'function') {
|
||||
return done();
|
||||
}
|
||||
needle.get('localhost:' + port, {headers: {'Accept-Encoding': 'br'}}, function(err, response, body){
|
||||
should.ifError(err);
|
||||
body.should.have.property('foo', 'bar');
|
||||
response.bytes.should.not.equal(jsonData.length);
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
396
node_modules/needle/test/cookies_spec.js
generated
vendored
Normal file
396
node_modules/needle/test/cookies_spec.js
generated
vendored
Normal file
@ -0,0 +1,396 @@
|
||||
var needle = require('../'),
|
||||
cookies = require('../lib/cookies'),
|
||||
sinon = require('sinon'),
|
||||
http = require('http'),
|
||||
should = require('should');
|
||||
|
||||
var WEIRD_COOKIE_NAME = 'wc',
|
||||
BASE64_COOKIE_NAME = 'bc',
|
||||
FORBIDDEN_COOKIE_NAME = 'fc',
|
||||
NUMBER_COOKIE_NAME = 'nc';
|
||||
|
||||
var WEIRD_COOKIE_VALUE = '!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~',
|
||||
BASE64_COOKIE_VALUE = 'Y29va2llCg==',
|
||||
FORBIDDEN_COOKIE_VALUE = ' ;"\\,',
|
||||
NUMBER_COOKIE_VALUE = 12354342;
|
||||
|
||||
var NO_COOKIES_TEST_PORT = 11112,
|
||||
ALL_COOKIES_TEST_PORT = 11113;
|
||||
|
||||
describe('cookies', function() {
|
||||
|
||||
var setCookieHeader, headers, server, opts;
|
||||
|
||||
function decode(str) {
|
||||
return decodeURIComponent(str);
|
||||
}
|
||||
|
||||
function encode(str) {
|
||||
str = str.toString().replace(/[\x00-\x1F\x7F]/g, encodeURIComponent);
|
||||
return str.replace(/[\s\"\,;\\%]/g, encodeURIComponent);
|
||||
}
|
||||
|
||||
before(function() {
|
||||
setCookieHeader = [
|
||||
WEIRD_COOKIE_NAME + '=' + encode(WEIRD_COOKIE_VALUE) + ';',
|
||||
BASE64_COOKIE_NAME + '=' + encode(BASE64_COOKIE_VALUE) + ';',
|
||||
FORBIDDEN_COOKIE_NAME + '=' + encode(FORBIDDEN_COOKIE_VALUE) + ';',
|
||||
NUMBER_COOKIE_NAME + '=' + encode(NUMBER_COOKIE_VALUE) + ';'
|
||||
];
|
||||
});
|
||||
|
||||
before(function(done) {
|
||||
serverAllCookies = http.createServer(function(req, res) {
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
res.setHeader('Set-Cookie', setCookieHeader);
|
||||
res.end('200');
|
||||
}).listen(ALL_COOKIES_TEST_PORT, done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
serverAllCookies.close(done);
|
||||
});
|
||||
|
||||
describe('with default options', function() {
|
||||
it('no cookie header is set on request', function(done) {
|
||||
needle.get(
|
||||
'localhost:' + ALL_COOKIES_TEST_PORT, function(err, response) {
|
||||
should.not.exist(response.req._headers.cookie);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('if response does not contain cookies', function() {
|
||||
before(function(done) {
|
||||
serverNoCookies = http.createServer(function(req, res) {
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
res.end('200');
|
||||
}).listen(NO_COOKIES_TEST_PORT, done);
|
||||
});
|
||||
|
||||
it('response.cookies is undefined', function(done) {
|
||||
needle.get(
|
||||
'localhost:' + NO_COOKIES_TEST_PORT, function(error, response) {
|
||||
should.not.exist(response.cookies);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
serverNoCookies.close(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('if response contains cookies', function() {
|
||||
|
||||
it('puts them on resp.cookies', function(done) {
|
||||
needle.get(
|
||||
'localhost:' + ALL_COOKIES_TEST_PORT, function(error, response) {
|
||||
response.should.have.property('cookies');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('parses them as a object', function(done) {
|
||||
needle.get(
|
||||
'localhost:' + ALL_COOKIES_TEST_PORT, function(error, response) {
|
||||
response.cookies.should.be.an.instanceOf(Object)
|
||||
.and.have.property(WEIRD_COOKIE_NAME);
|
||||
response.cookies.should.have.property(BASE64_COOKIE_NAME);
|
||||
response.cookies.should.have.property(FORBIDDEN_COOKIE_NAME);
|
||||
response.cookies.should.have.property(NUMBER_COOKIE_NAME);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('must decode it', function(done) {
|
||||
needle.get(
|
||||
'localhost:' + ALL_COOKIES_TEST_PORT, function(error, response) {
|
||||
response.cookies.wc.should.be.eql(WEIRD_COOKIE_VALUE);
|
||||
response.cookies.bc.should.be.eql(BASE64_COOKIE_VALUE);
|
||||
response.cookies.fc.should.be.eql(FORBIDDEN_COOKIE_VALUE);
|
||||
response.cookies.nc.should.be.eql(NUMBER_COOKIE_VALUE.toString());
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when a cookie value is invalid', function() {
|
||||
|
||||
before(function() {
|
||||
setCookieHeader = [
|
||||
'geo_city=%D1%E0%ED%EA%F2-%CF%E5%F2%E5%F0%E1%F3%F0%E3'
|
||||
];
|
||||
})
|
||||
|
||||
it('doesnt blow up', function(done) {
|
||||
needle.get('localhost:' + ALL_COOKIES_TEST_PORT, function(error, response) {
|
||||
should.not.exist(error)
|
||||
var whatever = 'efbfbdefbfbdefbfbdefbfbdefbfbd2defbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbd';
|
||||
Buffer.from(response.cookies.geo_city).toString('hex').should.eql(whatever)
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and response is a redirect', function() {
|
||||
|
||||
var redirectServer, testPort = 22222;
|
||||
var requestCookies = [];
|
||||
|
||||
var responseCookies = [
|
||||
[ // first req
|
||||
WEIRD_COOKIE_NAME + '=' + encode(WEIRD_COOKIE_VALUE) + ';',
|
||||
BASE64_COOKIE_NAME + '=' + encode(BASE64_COOKIE_VALUE) + ';',
|
||||
'FOO=123;'
|
||||
], [ // second req
|
||||
FORBIDDEN_COOKIE_NAME + '=' + encode(FORBIDDEN_COOKIE_VALUE) + ';',
|
||||
NUMBER_COOKIE_NAME + '=' + encode(NUMBER_COOKIE_VALUE) + ';'
|
||||
], [ // third red
|
||||
'FOO=BAR;'
|
||||
]
|
||||
]
|
||||
|
||||
before(function(done) {
|
||||
redirectServer = http.createServer(function(req, res) {
|
||||
var number = parseInt(req.url.replace('/', ''));
|
||||
var nextUrl = 'http://' + 'localhost:' + testPort + '/' + (number + 1);
|
||||
|
||||
if (number == 0) requestCookies = []; // reset
|
||||
requestCookies.push(req.headers['cookie']);
|
||||
|
||||
if (responseCookies[number]) { // we should send cookies for this request
|
||||
res.statusCode = 302;
|
||||
res.setHeader('Set-Cookie', responseCookies[number]);
|
||||
res.setHeader('Location', nextUrl);
|
||||
} else if (number == 3) {
|
||||
res.statusCode = 302; // redirect but without cookies
|
||||
res.setHeader('Location', nextUrl);
|
||||
}
|
||||
|
||||
res.end('OK');
|
||||
}).listen(22222, done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
redirectServer.close(done);
|
||||
})
|
||||
|
||||
describe('and follow_set_cookies is false', function() {
|
||||
|
||||
describe('with original request cookie', function() {
|
||||
|
||||
var opts = {
|
||||
follow_set_cookies: false,
|
||||
follow_max: 4,
|
||||
cookies: { 'xxx': 123 }
|
||||
};
|
||||
|
||||
it('request cookie is not passed to redirects', function(done) {
|
||||
needle.get('localhost:' + testPort + '/0', opts, function(err, resp) {
|
||||
requestCookies.should.eql(["xxx=123", undefined, undefined, undefined, undefined])
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('response cookies are not passed either', function(done) {
|
||||
needle.get('localhost:' + testPort + '/0', opts, function(err, resp) {
|
||||
should.not.exist(resp.cookies);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
describe('without original request cookie', function() {
|
||||
|
||||
var opts = {
|
||||
follow_set_cookies: false,
|
||||
follow_max: 4,
|
||||
};
|
||||
|
||||
it('no request cookies are sent', function(done) {
|
||||
needle.get('localhost:' + testPort + '/0', opts, function(err, resp) {
|
||||
requestCookies.should.eql([undefined, undefined, undefined, undefined, undefined])
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('response cookies are not passed either', function(done) {
|
||||
needle.get('localhost:' + testPort + '/0', opts, function(err, resp) {
|
||||
should.not.exist(resp.cookies);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
describe('and follow_set_cookies is true', function() {
|
||||
|
||||
describe('with original request cookie', function() {
|
||||
|
||||
var opts = {
|
||||
follow_set_cookies: true,
|
||||
follow_max: 4,
|
||||
cookies: { 'xxx': 123 }
|
||||
};
|
||||
|
||||
it('request cookie is passed passed to redirects, and response cookies are added too', function(done) {
|
||||
needle.get('localhost:' + testPort + '/0', opts, function(err, resp) {
|
||||
requestCookies.should.eql([
|
||||
"xxx=123",
|
||||
"xxx=123; wc=!'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=123",
|
||||
"xxx=123; wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=123; fc=%20%3B%22%5C%2C; nc=12354342",
|
||||
"xxx=123; wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=BAR; fc=%20%3B%22%5C%2C; nc=12354342",
|
||||
"xxx=123; wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=BAR; fc=%20%3B%22%5C%2C; nc=12354342"
|
||||
])
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('response cookies are passed as well', function(done) {
|
||||
needle.get('localhost:' + testPort + '/0', opts, function(err, resp) {
|
||||
resp.cookies.should.have.property(WEIRD_COOKIE_NAME);
|
||||
resp.cookies.should.have.property(BASE64_COOKIE_NAME);
|
||||
resp.cookies.should.have.property(FORBIDDEN_COOKIE_NAME);
|
||||
resp.cookies.should.have.property(NUMBER_COOKIE_NAME);
|
||||
resp.cookies.should.have.property('FOO');
|
||||
resp.cookies.FOO.should.eql('BAR'); // should overwrite previous one
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
describe('without original request cookie', function() {
|
||||
|
||||
var opts = {
|
||||
follow_set_cookies: true,
|
||||
follow_max: 4,
|
||||
};
|
||||
|
||||
it('response cookies are passed to redirects', function(done) {
|
||||
needle.get('localhost:' + testPort + '/0', opts, function(err, resp) {
|
||||
requestCookies.should.eql([
|
||||
undefined,
|
||||
"wc=!'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=123",
|
||||
"wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=123; fc=%20%3B%22%5C%2C; nc=12354342",
|
||||
"wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=BAR; fc=%20%3B%22%5C%2C; nc=12354342",
|
||||
"wc=!\'*+#()&-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~; bc=Y29va2llCg==; FOO=BAR; fc=%20%3B%22%5C%2C; nc=12354342"
|
||||
])
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('response cookies are passed as well', function(done) {
|
||||
needle.get('localhost:' + testPort + '/0', opts, function(err, resp) {
|
||||
// resp.cookies.should.have.property(WEIRD_COOKIE_NAME);
|
||||
// resp.cookies.should.have.property(BASE64_COOKIE_NAME);
|
||||
// resp.cookies.should.have.property(FORBIDDEN_COOKIE_NAME);
|
||||
// resp.cookies.should.have.property(NUMBER_COOKIE_NAME);
|
||||
// resp.cookies.should.have.property('FOO');
|
||||
// resp.cookies.FOO.should.eql('BAR'); // should overwrite previous one
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('with parse_cookies = false', function() {
|
||||
it('does not parse them', function(done) {
|
||||
needle.get(
|
||||
'localhost:' + ALL_COOKIES_TEST_PORT, { parse_cookies: false }, function(error, response) {
|
||||
should.not.exist(response.cookies);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('if request contains cookie header', function() {
|
||||
var opts = {
|
||||
cookies: {}
|
||||
};
|
||||
|
||||
before(function() {
|
||||
opts.cookies[WEIRD_COOKIE_NAME] = WEIRD_COOKIE_VALUE;
|
||||
opts.cookies[BASE64_COOKIE_NAME] = BASE64_COOKIE_VALUE;
|
||||
opts.cookies[FORBIDDEN_COOKIE_NAME] = FORBIDDEN_COOKIE_VALUE;
|
||||
opts.cookies[NUMBER_COOKIE_NAME] = NUMBER_COOKIE_VALUE;
|
||||
});
|
||||
|
||||
it('must be a valid cookie string', function(done) {
|
||||
var COOKIE_PAIR = /^([^=\s]+)\s*=\s*("?)\s*(.*)\s*\2\s*$/;
|
||||
|
||||
var full_header = [
|
||||
WEIRD_COOKIE_NAME + '=' + WEIRD_COOKIE_VALUE,
|
||||
BASE64_COOKIE_NAME + '=' + BASE64_COOKIE_VALUE,
|
||||
FORBIDDEN_COOKIE_NAME + '=' + encode(FORBIDDEN_COOKIE_VALUE),
|
||||
NUMBER_COOKIE_NAME + '=' + NUMBER_COOKIE_VALUE
|
||||
].join('; ')
|
||||
|
||||
needle.get('localhost:' + ALL_COOKIES_TEST_PORT, opts, function(error, response) {
|
||||
var cookieString = response.req._headers.cookie;
|
||||
cookieString.should.be.type('string');
|
||||
|
||||
cookieString.split(/\s*;\s*/).forEach(function(pair) {
|
||||
COOKIE_PAIR.test(pair).should.be.exactly(true);
|
||||
});
|
||||
|
||||
cookieString.should.be.exactly(full_header);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('dont have to encode allowed characters', function(done) {
|
||||
var COOKIE_PAIR = /^([^=\s]+)\s*=\s*("?)\s*(.*)\s*\2\s*$/,
|
||||
KEY_INDEX = 1,
|
||||
VALUE_INEX = 3;
|
||||
|
||||
needle.get('localhost:' + ALL_COOKIES_TEST_PORT, opts, function(error, response) {
|
||||
var cookieObj = {},
|
||||
cookieString = response.req._headers.cookie;
|
||||
|
||||
cookieString.split(/\s*;\s*/).forEach(function(str) {
|
||||
var pair = COOKIE_PAIR.exec(str);
|
||||
cookieObj[pair[KEY_INDEX]] = pair[VALUE_INEX];
|
||||
});
|
||||
|
||||
cookieObj[WEIRD_COOKIE_NAME].should.be.exactly(WEIRD_COOKIE_VALUE);
|
||||
cookieObj[BASE64_COOKIE_NAME].should.be.exactly(BASE64_COOKIE_VALUE);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('must encode forbidden characters', function(done) {
|
||||
var COOKIE_PAIR = /^([^=\s]+)\s*=\s*("?)\s*(.*)\s*\2\s*$/,
|
||||
KEY_INDEX = 1,
|
||||
VALUE_INEX = 3;
|
||||
|
||||
needle.get('localhost:' + ALL_COOKIES_TEST_PORT, opts, function(error, response) {
|
||||
var cookieObj = {},
|
||||
cookieString = response.req._headers.cookie;
|
||||
|
||||
cookieString.split(/\s*;\s*/).forEach(function(str) {
|
||||
var pair = COOKIE_PAIR.exec(str);
|
||||
cookieObj[pair[KEY_INDEX]] = pair[VALUE_INEX];
|
||||
});
|
||||
|
||||
cookieObj[FORBIDDEN_COOKIE_NAME].should.not.be.eql(
|
||||
FORBIDDEN_COOKIE_VALUE);
|
||||
cookieObj[FORBIDDEN_COOKIE_NAME].should.be.exactly(
|
||||
encode(FORBIDDEN_COOKIE_VALUE));
|
||||
cookieObj[FORBIDDEN_COOKIE_NAME].should.be.exactly(
|
||||
encodeURIComponent(FORBIDDEN_COOKIE_VALUE));
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
248
node_modules/needle/test/decoder_spec.js
generated
vendored
Normal file
248
node_modules/needle/test/decoder_spec.js
generated
vendored
Normal file
@ -0,0 +1,248 @@
|
||||
var should = require('should'),
|
||||
needle = require('./../'),
|
||||
decoder = require('./../lib/decoder'),
|
||||
Q = require('q'),
|
||||
chardet = require('jschardet'),
|
||||
fs = require('fs'),
|
||||
http = require('http'),
|
||||
helpers = require('./helpers');
|
||||
|
||||
describe('character encoding', function() {
|
||||
|
||||
this.timeout(5000);
|
||||
|
||||
describe('Given content-type: "text/html; charset=EUC-JP"', function() {
|
||||
|
||||
var port = 2233;
|
||||
var server;
|
||||
|
||||
function createServer() {
|
||||
return http.createServer(function(req, res) {
|
||||
|
||||
req.on('data', function(chunk) {})
|
||||
|
||||
req.on('end', function() {
|
||||
// We used to pull from a particular site that is no longer up.
|
||||
// This is a local mirror pulled from archive.org
|
||||
// https://web.archive.org/web/20181003202907/http://www.nina.jp/server/slackware/webapp/tomcat_charset.html
|
||||
fs.readFile('test/tomcat_charset.html', function(err, data) {
|
||||
if (err) {
|
||||
res.writeHead(404);
|
||||
res.end(JSON.stringify(err));
|
||||
return;
|
||||
}
|
||||
res.writeHeader(200, { 'Content-Type': 'text/html; charset=EUC-JP' })
|
||||
res.end(data);
|
||||
});
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
before(function(done) {
|
||||
server = createServer();
|
||||
server.listen(port, done)
|
||||
url = 'http://localhost:' + port;
|
||||
})
|
||||
|
||||
after(function(done) {
|
||||
server.close(done)
|
||||
})
|
||||
|
||||
describe('with decode = false', function() {
|
||||
|
||||
it('does not decode', function(done) {
|
||||
|
||||
needle.get(url, { decode: false }, function(err, resp) {
|
||||
resp.body.should.be.a.String;
|
||||
chardet.detect(resp.body).encoding.should.eql('windows-1252');
|
||||
resp.body.indexOf('EUCを使う').should.eql(-1);
|
||||
done();
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('with decode = true', function() {
|
||||
|
||||
it('decodes', function(done) {
|
||||
|
||||
needle.get(url, { decode: true }, function(err, resp) {
|
||||
resp.body.should.be.a.String;
|
||||
chardet.detect(resp.body).encoding.should.eql('ascii');
|
||||
resp.body.indexOf('EUCを使う').should.not.eql(-1);
|
||||
done();
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('Given content-type: "text/html but file is charset: gb2312', function() {
|
||||
|
||||
it('encodes to UTF-8', function(done) {
|
||||
|
||||
// Our Needle wrapper that requests a chinese website.
|
||||
var task = Q.nbind(needle.get, needle, 'http://www.chinesetop100.com/');
|
||||
|
||||
// Different instantiations of this task
|
||||
var tasks = [Q.fcall(task, {decode: true}),
|
||||
Q.fcall(task, {decode: false})];
|
||||
|
||||
var results = tasks.map(function(task) {
|
||||
return task.then(function(obj) {
|
||||
return obj[0].body;
|
||||
});
|
||||
});
|
||||
|
||||
// Execute all requests concurrently
|
||||
Q.all(results).done(function(bodies) {
|
||||
|
||||
var charsets = [
|
||||
chardet.detect(bodies[0]).encoding,
|
||||
chardet.detect(bodies[1]).encoding,
|
||||
]
|
||||
|
||||
// We wanted to decode our first stream as specified by options
|
||||
charsets[0].should.equal('ascii');
|
||||
bodies[0].indexOf('全球中文网站前二十强').should.not.equal(-1);
|
||||
|
||||
// But not our second stream
|
||||
charsets[1].should.equal('windows-1252');
|
||||
bodies[1].indexOf('全球中文网站前二十强').should.equal(-1);
|
||||
|
||||
done();
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
describe('Given content-type: "text/html"', function () {
|
||||
|
||||
var server,
|
||||
port = 54321,
|
||||
text = 'Magyarországi Fióktelepe'
|
||||
|
||||
before(function(done) {
|
||||
server = helpers.server({
|
||||
port: port,
|
||||
response: text,
|
||||
headers: { 'Content-Type': 'text/html' }
|
||||
}, done);
|
||||
})
|
||||
|
||||
after(function(done) {
|
||||
server.close(done)
|
||||
})
|
||||
|
||||
describe('with decode = false', function () {
|
||||
it('decodes by default to utf-8', function (done) {
|
||||
|
||||
needle.get('http://localhost:' + port, { decode: false }, function (err, resp) {
|
||||
resp.body.should.be.a.String;
|
||||
chardet.detect(resp.body).encoding.should.eql('ISO-8859-2');
|
||||
resp.body.should.eql('Magyarországi Fióktelepe')
|
||||
done();
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('multibyte characters split across chunks', function () {
|
||||
|
||||
describe('with encoding = utf-8', function() {
|
||||
|
||||
var d,
|
||||
result = Buffer.allocUnsafe(0);
|
||||
|
||||
before(function(done) {
|
||||
d = decoder('utf-8');
|
||||
done();
|
||||
});
|
||||
|
||||
it('reassembles split multibyte characters', function (done) {
|
||||
|
||||
d.on("data", function(chunk){
|
||||
result = Buffer.concat([ result, chunk ]);
|
||||
});
|
||||
|
||||
d.on("end", function(){
|
||||
result.toString("utf-8").should.eql('慶');
|
||||
done();
|
||||
});
|
||||
|
||||
// write '慶' in utf-8 split across chunks
|
||||
d.write(Buffer.from([0xE6]));
|
||||
d.write(Buffer.from([0x85]));
|
||||
d.write(Buffer.from([0xB6]));
|
||||
d.end();
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
describe('with encoding = euc-jp', function() {
|
||||
|
||||
var d,
|
||||
result = Buffer.allocUnsafe(0);
|
||||
|
||||
before(function(done) {
|
||||
d = decoder('euc-jp');
|
||||
done();
|
||||
});
|
||||
|
||||
it('reassembles split multibyte characters', function (done) {
|
||||
|
||||
d.on("data", function(chunk){
|
||||
result = Buffer.concat([ result, chunk ]);
|
||||
});
|
||||
|
||||
d.on("end", function(){
|
||||
result.toString("utf-8").should.eql('慶');
|
||||
done();
|
||||
});
|
||||
|
||||
// write '慶' in euc-jp split across chunks
|
||||
d.write(Buffer.from([0xB7]));
|
||||
d.write(Buffer.from([0xC4]));
|
||||
d.end();
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
describe('with encoding = gb18030', function() {
|
||||
|
||||
var d,
|
||||
result = Buffer.allocUnsafe(0);
|
||||
|
||||
before(function(done) {
|
||||
d = decoder('gb18030');
|
||||
done();
|
||||
});
|
||||
|
||||
it('reassembles split multibyte characters', function (done) {
|
||||
|
||||
d.on("data", function(chunk){
|
||||
result = Buffer.concat([ result, chunk ]);
|
||||
});
|
||||
|
||||
d.on("end", function(){
|
||||
result.toString("utf-8").should.eql('慶');
|
||||
done();
|
||||
});
|
||||
|
||||
// write '慶' in gb18030 split across chunks
|
||||
d.write(Buffer.from([0x91]));
|
||||
d.write(Buffer.from([0x63]));
|
||||
d.end();
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
272
node_modules/needle/test/errors_spec.js
generated
vendored
Normal file
272
node_modules/needle/test/errors_spec.js
generated
vendored
Normal file
@ -0,0 +1,272 @@
|
||||
var needle = require('../'),
|
||||
sinon = require('sinon'),
|
||||
should = require('should'),
|
||||
http = require('http'),
|
||||
Emitter = require('events').EventEmitter,
|
||||
helpers = require('./helpers');
|
||||
|
||||
var get_catch = function(url, opts) {
|
||||
var err;
|
||||
try {
|
||||
needle.get(url, opts);
|
||||
} catch(e) {
|
||||
err = e;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
describe('errors', function() {
|
||||
|
||||
after(function(done) {
|
||||
setTimeout(done, 100)
|
||||
})
|
||||
|
||||
describe('when host does not exist', function() {
|
||||
|
||||
var url = 'http://unexistinghost/foo';
|
||||
|
||||
describe('with callback', function() {
|
||||
|
||||
it('does not throw', function() {
|
||||
var ex = get_catch(url);
|
||||
should.not.exist(ex);
|
||||
})
|
||||
|
||||
it('callbacks an error', function(done) {
|
||||
needle.get(url, function(err) {
|
||||
err.should.be.a.Error;
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('error should be ENOTFOUND or EADDRINFO or EAI_AGAIN', function(done) {
|
||||
needle.get(url, function(err) {
|
||||
err.code.should.match(/ENOTFOUND|EADDRINFO|EAI_AGAIN/)
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('does not callback a response', function(done) {
|
||||
needle.get(url, function(err, resp) {
|
||||
should.not.exist(resp);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('does not emit an error event', function(done) {
|
||||
var emitted = false;
|
||||
var req = needle.get(url, function(err, resp) { })
|
||||
|
||||
req.on('error', function() {
|
||||
emitted = true;
|
||||
})
|
||||
|
||||
setTimeout(function() {
|
||||
emitted.should.eql(false);
|
||||
done();
|
||||
}, 100);
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('without callback', function() {
|
||||
|
||||
it('does not throw', function() {
|
||||
var ex = get_catch(url);
|
||||
should.not.exist(ex);
|
||||
})
|
||||
|
||||
it('emits end event once, with error', function(done) {
|
||||
var callcount = 0,
|
||||
stream = needle.get(url);
|
||||
|
||||
stream.on('done', function(err) {
|
||||
err.code.should.match(/ENOTFOUND|EADDRINFO|EAI_AGAIN/)
|
||||
callcount++;
|
||||
})
|
||||
|
||||
setTimeout(function() {
|
||||
callcount.should.equal(1);
|
||||
done();
|
||||
}, 200)
|
||||
})
|
||||
|
||||
it('does not emit a readable event', function(done) {
|
||||
var called = false,
|
||||
stream = needle.get(url);
|
||||
|
||||
stream.on('readable', function() {
|
||||
called = true;
|
||||
})
|
||||
|
||||
stream.on('done', function(err) {
|
||||
called.should.be.false;
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('does not emit an error event', function(done) {
|
||||
var emitted = false,
|
||||
stream = needle.get(url);
|
||||
|
||||
stream.on('error', function() {
|
||||
emitted = true;
|
||||
})
|
||||
|
||||
stream.on('done', function(err) {
|
||||
emitted.should.eql(false);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('when request times out waiting for response', function() {
|
||||
|
||||
var server,
|
||||
url = 'http://localhost:3333/foo';
|
||||
|
||||
var send_request = function(cb) {
|
||||
return needle.get(url, { response_timeout: 200 }, cb);
|
||||
}
|
||||
|
||||
before(function() {
|
||||
server = helpers.server({ port: 3333, wait: 1000 });
|
||||
})
|
||||
|
||||
after(function() {
|
||||
server.close();
|
||||
})
|
||||
|
||||
describe('with callback', function() {
|
||||
|
||||
it('aborts the request', function(done) {
|
||||
|
||||
var time = new Date();
|
||||
|
||||
send_request(function(err) {
|
||||
var timediff = (new Date() - time);
|
||||
timediff.should.be.within(200, 300);
|
||||
done();
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
it('callbacks an error', function(done) {
|
||||
send_request(function(err) {
|
||||
err.should.be.a.Error;
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('error should be ECONNRESET', function(done) {
|
||||
send_request(function(err) {
|
||||
err.code.should.equal('ECONNRESET')
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('does not callback a response', function(done) {
|
||||
send_request(function(err, resp) {
|
||||
should.not.exist(resp);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('does not emit an error event', function(done) {
|
||||
var emitted = false;
|
||||
|
||||
var req = send_request(function(err, resp) {
|
||||
should.not.exist(resp);
|
||||
})
|
||||
|
||||
req.on('error', function() {
|
||||
emitted = true;
|
||||
})
|
||||
|
||||
setTimeout(function() {
|
||||
emitted.should.eql(false);
|
||||
done();
|
||||
}, 350);
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('without callback', function() {
|
||||
|
||||
it('emits done event once, with error', function(done) {
|
||||
var error,
|
||||
called = 0,
|
||||
stream = send_request();
|
||||
|
||||
stream.on('done', function(err) {
|
||||
err.code.should.equal('ECONNRESET');
|
||||
called++;
|
||||
})
|
||||
|
||||
setTimeout(function() {
|
||||
called.should.equal(1);
|
||||
done();
|
||||
}, 250)
|
||||
})
|
||||
|
||||
it('aborts the request', function(done) {
|
||||
|
||||
var time = new Date();
|
||||
var stream = send_request();
|
||||
|
||||
stream.on('done', function(err) {
|
||||
var timediff = (new Date() - time);
|
||||
timediff.should.be.within(200, 300);
|
||||
done();
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
it('error should be ECONNRESET', function(done) {
|
||||
var error,
|
||||
stream = send_request();
|
||||
|
||||
stream.on('done', function(err) {
|
||||
err.code.should.equal('ECONNRESET')
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('does not emit a readable event', function(done) {
|
||||
var called = false,
|
||||
stream = send_request();
|
||||
|
||||
stream.on('readable', function() {
|
||||
called = true;
|
||||
})
|
||||
|
||||
stream.on('done', function(err) {
|
||||
called.should.be.false;
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('does not emit an error event', function(done) {
|
||||
var emitted = false;
|
||||
var stream = send_request();
|
||||
|
||||
stream.on('error', function() {
|
||||
emitted = true;
|
||||
})
|
||||
|
||||
stream.on('done', function(err) {
|
||||
err.should.be.a.Error;
|
||||
err.code.should.equal('ECONNRESET')
|
||||
emitted.should.eql(false);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
320
node_modules/needle/test/headers_spec.js
generated
vendored
Normal file
320
node_modules/needle/test/headers_spec.js
generated
vendored
Normal file
@ -0,0 +1,320 @@
|
||||
var http = require('http'),
|
||||
helpers = require('./helpers'),
|
||||
should = require('should');
|
||||
|
||||
var port = 54321;
|
||||
|
||||
|
||||
describe('request headers', function() {
|
||||
|
||||
var needle,
|
||||
server,
|
||||
existing_sockets,
|
||||
original_defaultMaxSockets;
|
||||
|
||||
before(function(done) {
|
||||
setTimeout(function() {
|
||||
existing_sockets = get_active_sockets().length;
|
||||
server = helpers.server({ port: port }, done);
|
||||
}, 100);
|
||||
})
|
||||
|
||||
after(function(done) {
|
||||
server.close(done);
|
||||
})
|
||||
|
||||
function send_request(opts, cb) {
|
||||
needle.get('http://localhost:' + port, opts, cb);
|
||||
}
|
||||
|
||||
function get_active_sockets() {
|
||||
var handles = process._getActiveHandles();
|
||||
|
||||
return handles.filter(function(el) {
|
||||
if (el.constructor.name.toString() == 'Socket') {
|
||||
return el.destroyed !== true;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
describe('old node versions (<0.11.4) with persistent keep-alive connections', function() {
|
||||
|
||||
// emulate old node behaviour
|
||||
before(function() {
|
||||
delete require.cache[require.resolve('..')] // in case it was already loaded
|
||||
original_defaultMaxSockets = http.Agent.defaultMaxSockets;
|
||||
http.Agent.defaultMaxSockets = 5;
|
||||
needle = require('..');
|
||||
})
|
||||
|
||||
after(function() {
|
||||
http.Agent.defaultMaxSockets = original_defaultMaxSockets;
|
||||
delete require.cache[require.resolve('..')]
|
||||
})
|
||||
|
||||
describe('default options', function() {
|
||||
|
||||
it('sends a Connection: close header', function(done) {
|
||||
send_request({}, function(err, resp) {
|
||||
resp.body.headers['connection'].should.eql('close');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('no open sockets remain after request', function(done) {
|
||||
send_request({}, function(err, resp) {
|
||||
setTimeout(function() {
|
||||
get_active_sockets().length.should.eql(existing_sockets);
|
||||
done();
|
||||
}, 10)
|
||||
});
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('passing connection: close', function() {
|
||||
|
||||
it('sends a Connection: close header', function(done) {
|
||||
send_request({ connection: 'close' }, function(err, resp) {
|
||||
resp.body.headers['connection'].should.eql('close');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('no open sockets remain after request', function(done) {
|
||||
send_request({ connection: 'close' }, function(err, resp) {
|
||||
setTimeout(function() {
|
||||
get_active_sockets().length.should.eql(existing_sockets);
|
||||
done();
|
||||
}, 10)
|
||||
});
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('passing connection: keep-alive', function() {
|
||||
|
||||
it('sends a Connection: keep-alive header (using options.headers.connection)', function(done) {
|
||||
send_request({ headers: { connection: 'keep-alive' }}, function(err, resp) {
|
||||
resp.body.headers['connection'].should.eql('keep-alive');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('sends a Connection: keep-alive header (using options.connection)', function(done) {
|
||||
send_request({ connection: 'keep-alive' }, function(err, resp) {
|
||||
resp.body.headers['connection'].should.eql('keep-alive');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('one open socket remain after request', function(done) {
|
||||
send_request({ connection: 'keep-alive' }, function(err, resp) {
|
||||
get_active_sockets().length.should.eql(existing_sockets + 1);
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('new node versions with smarter connection disposing', function() {
|
||||
|
||||
before(function() {
|
||||
delete require.cache[require.resolve('..')]
|
||||
original_defaultMaxSockets = http.Agent.defaultMaxSockets;
|
||||
http.Agent.defaultMaxSockets = Infinity;
|
||||
needle = require('..');
|
||||
})
|
||||
|
||||
after(function() {
|
||||
http.Agent.defaultMaxSockets = original_defaultMaxSockets;
|
||||
delete require.cache[require.resolve('..')]
|
||||
})
|
||||
|
||||
describe('default options', function() {
|
||||
|
||||
var node_major_ver = process.version.split('.')[0].replace('v', '');
|
||||
|
||||
if (parseInt(node_major_ver) >= 4) {
|
||||
|
||||
it('sets Connection header to close (> v4)', function(done) {
|
||||
send_request({}, function(err, resp) {
|
||||
resp.body.headers['connection'].should.eql('close');
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
it('sets Connection header to keep-alive (< v4)', function(done) {
|
||||
send_request({}, function(err, resp) {
|
||||
resp.body.headers['connection'].should.eql('keep-alive');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
if (parseInt(node_major_ver) >= 14) {
|
||||
|
||||
// TODO: figure out why this happens
|
||||
it('two open sockets remains after request (>= v14)', function(done) {
|
||||
send_request({}, function(err, resp) {
|
||||
get_active_sockets().length.should.eql(existing_sockets + 2);
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
} else if (parseInt(node_major_ver) >= 8 || parseInt(node_major_ver) == 0) {
|
||||
|
||||
it('one open socket remains after request (> v8 && v0.10)', function(done) {
|
||||
send_request({}, function(err, resp) {
|
||||
get_active_sockets().length.should.eql(existing_sockets + 1);
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
it('no open sockets remain after request (> v0.10 && < v8)', function(done) {
|
||||
send_request({}, function(err, resp) {
|
||||
get_active_sockets().length.should.eql(existing_sockets);
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
describe('passing connection: close', function() {
|
||||
|
||||
it('sends a Connection: close header', function(done) {
|
||||
send_request({ connection: 'close' }, function(err, resp) {
|
||||
resp.body.headers['connection'].should.eql('close');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('no open sockets remain after request', function(done) {
|
||||
send_request({ connection: 'close' }, function(err, resp) {
|
||||
setTimeout(function() {
|
||||
get_active_sockets().length.should.eql(existing_sockets);
|
||||
done();
|
||||
}, 10);
|
||||
});
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('passing connection: keep-alive', function() {
|
||||
|
||||
it('sends a Connection: keep-alive header (using options.headers.connection)', function(done) {
|
||||
send_request({ headers: { connection: 'keep-alive' }}, function(err, resp) {
|
||||
resp.body.headers['connection'].should.eql('keep-alive');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('sends a Connection: keep-alive header (using options.connection)', function(done) {
|
||||
send_request({ connection: 'keep-alive' }, function(err, resp) {
|
||||
resp.body.headers['connection'].should.eql('keep-alive');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('one open socket remain after request', function(done) {
|
||||
send_request({ connection: 'keep-alive' }, function(err, resp) {
|
||||
get_active_sockets().length.should.eql(existing_sockets + 1);
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('using shared keep-alive agent', function() {
|
||||
|
||||
before(function() {
|
||||
needle.defaults({ agent: http.Agent({ keepAlive: true }) })
|
||||
})
|
||||
|
||||
after(function() {
|
||||
needle.defaults().agent.destroy(); // close existing connections
|
||||
needle.defaults({ agent: null }); // and reset default value
|
||||
})
|
||||
|
||||
describe('default options', function() {
|
||||
|
||||
it('sends a Connection: keep-alive header', function(done) {
|
||||
send_request({}, function(err, resp) {
|
||||
resp.body.headers['connection'].should.eql('keep-alive');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('one open socket remain after request', function(done) {
|
||||
send_request({ connection: 'keep-alive' }, function(err, resp) {
|
||||
setTimeout(function() {
|
||||
get_active_sockets().length.should.eql(existing_sockets + 1);
|
||||
done();
|
||||
}, 10);
|
||||
});
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('passing connection: close', function() {
|
||||
|
||||
it('sends a Connection: close header', function(done) {
|
||||
send_request({ connection: 'close' }, function(err, resp) {
|
||||
resp.body.headers['connection'].should.eql('close');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('no open sockets remain after request', function(done) {
|
||||
send_request({ connection: 'close' }, function(err, resp) {
|
||||
setTimeout(function() {
|
||||
get_active_sockets().length.should.eql(existing_sockets);
|
||||
done();
|
||||
}, 10)
|
||||
});
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('passing connection: keep-alive', function() {
|
||||
|
||||
it('sends a Connection: keep-alive header (using options.headers.connection)', function(done) {
|
||||
send_request({ headers: { connection: 'keep-alive' }}, function(err, resp) {
|
||||
resp.body.headers['connection'].should.eql('keep-alive');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('sends a Connection: keep-alive header (using options.connection)', function(done) {
|
||||
send_request({ connection: 'keep-alive' }, function(err, resp) {
|
||||
resp.body.headers['connection'].should.eql('keep-alive');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('one open socket remain after request', function(done) {
|
||||
send_request({ connection: 'keep-alive' }, function(err, resp) {
|
||||
setTimeout(function() {
|
||||
get_active_sockets().length.should.eql(existing_sockets + 1);
|
||||
done();
|
||||
}, 10);
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
|
||||
})
|
74
node_modules/needle/test/helpers.js
generated
vendored
Normal file
74
node_modules/needle/test/helpers.js
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
var fs = require('fs');
|
||||
|
||||
var protocols = {
|
||||
http : require('http'),
|
||||
https : require('https')
|
||||
}
|
||||
|
||||
var keys = {
|
||||
cert : fs.readFileSync(__dirname + '/keys/ssl.cert'),
|
||||
key : fs.readFileSync(__dirname + '/keys/ssl.key')
|
||||
}
|
||||
|
||||
var helpers = {};
|
||||
|
||||
helpers.server = function(opts, cb) {
|
||||
|
||||
var defaults = {
|
||||
code : 200,
|
||||
headers : {'Content-Type': 'application/json'}
|
||||
}
|
||||
|
||||
var mirror_response = function(req) {
|
||||
return JSON.stringify({
|
||||
headers: req.headers,
|
||||
body: req.body
|
||||
})
|
||||
}
|
||||
|
||||
var get = function(what) {
|
||||
if (!opts[what])
|
||||
return defaults[what];
|
||||
|
||||
if (typeof opts[what] == 'function')
|
||||
return opts[what](); // set them at runtime
|
||||
else
|
||||
return opts[what];
|
||||
}
|
||||
|
||||
var finish = function(req, res) {
|
||||
if (opts.handler) return opts.handler(req, res);
|
||||
|
||||
res.writeHead(get('code'), get('headers'));
|
||||
res.end(opts.response || mirror_response(req));
|
||||
}
|
||||
|
||||
var handler = function(req, res) {
|
||||
|
||||
req.setEncoding('utf8'); // get as string
|
||||
req.body = '';
|
||||
req.on('data', function(str) { req.body += str })
|
||||
req.socket.on('error', function(e) {
|
||||
// res.writeHead(500, {'Content-Type': 'text/plain'});
|
||||
// res.end('Error: ' + e.message);
|
||||
})
|
||||
|
||||
setTimeout(function(){
|
||||
finish(req, res);
|
||||
}, opts.wait || 0);
|
||||
|
||||
};
|
||||
|
||||
var protocol = opts.protocol || 'http';
|
||||
var server;
|
||||
|
||||
if (protocol == 'https')
|
||||
server = protocols[protocol].createServer(keys, handler);
|
||||
else
|
||||
server = protocols[protocol].createServer(handler);
|
||||
|
||||
server.listen(opts.port, cb);
|
||||
return server;
|
||||
}
|
||||
|
||||
module.exports = helpers;
|
43
node_modules/needle/test/long_string_spec.js
generated
vendored
Normal file
43
node_modules/needle/test/long_string_spec.js
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
var needle = require('../'),
|
||||
should = require('should');
|
||||
|
||||
describe('when posting a very long string', function() {
|
||||
|
||||
this.timeout(20000);
|
||||
|
||||
function get_string(length) {
|
||||
var str = '';
|
||||
for (var i = 0; i < length; i++) {
|
||||
str += 'x';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
var major_version = process.version.split('.')[0];
|
||||
|
||||
it("shouldn't throw an EPIPE error out of nowhere", function(done) {
|
||||
|
||||
// for some reason this test fails in Github Actions with Node v8.x
|
||||
// although in my Linux box passes without issues
|
||||
if (process.env.CI && (major_version == 'v8' || major_version == 'v6')) {
|
||||
return done();
|
||||
}
|
||||
|
||||
var error;
|
||||
|
||||
function finished() {
|
||||
setTimeout(function() {
|
||||
should.not.exist(error);
|
||||
done();
|
||||
}, 300);
|
||||
}
|
||||
|
||||
try {
|
||||
needle.post('https://google.com', { data: get_string(Math.pow(2, 20)) }, finished)
|
||||
} catch(e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
})
|
81
node_modules/needle/test/mimetype.js
generated
vendored
Normal file
81
node_modules/needle/test/mimetype.js
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
var should = require('should'),
|
||||
needle = require('./../'),
|
||||
helpers = require('./helpers');
|
||||
|
||||
describe('receiving json and xml content as string', function() {
|
||||
|
||||
this.timeout(5000);
|
||||
|
||||
["text/plain", "application/json", "application/ld+json", "application/xml", "image/svg+xml"].forEach(function(mimetype, offset){
|
||||
|
||||
describe('Given content-type: "'+mimetype+'"', function () {
|
||||
|
||||
var server, port = 54330+offset;
|
||||
|
||||
before(function(done) {
|
||||
server = helpers.server({
|
||||
port: port,
|
||||
response: 'content',
|
||||
headers: { 'Content-Type': mimetype }
|
||||
}, done);
|
||||
})
|
||||
|
||||
after(function(done) {
|
||||
server.close(done)
|
||||
})
|
||||
|
||||
describe('with parse = false', function () {
|
||||
it('delivers by default as string', function (done) {
|
||||
|
||||
needle.get('http://localhost:' + port, { parse: false }, function (err, resp) {
|
||||
|
||||
resp.body.should.be.a.String;
|
||||
(typeof resp.body).should.eql('string')
|
||||
done();
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
["application/octet-stream", "image/png"].forEach(function(mimetype, offset){
|
||||
|
||||
describe('Given content-type: "'+mimetype+'"', function () {
|
||||
|
||||
var server, port = 54340+offset;
|
||||
|
||||
before(function(done) {
|
||||
server = helpers.server({
|
||||
port: port,
|
||||
response: 'content',
|
||||
headers: { 'Content-Type': mimetype }
|
||||
}, done);
|
||||
})
|
||||
|
||||
after(function(done) {
|
||||
server.close(done)
|
||||
})
|
||||
|
||||
describe('with parse = false', function () {
|
||||
it('delivers by default as Buffer', function (done) {
|
||||
|
||||
needle.get('http://localhost:' + port, { parse: false }, function (err, resp) {
|
||||
|
||||
resp.body.should.be.a.Buffer;
|
||||
(resp.body instanceof Buffer).should.eql(true)
|
||||
done();
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
263
node_modules/needle/test/output_spec.js
generated
vendored
Normal file
263
node_modules/needle/test/output_spec.js
generated
vendored
Normal file
@ -0,0 +1,263 @@
|
||||
// this lets us run tests in ancient node versions (v0.10.x)
|
||||
if (process.version.split('.')[0] == 'v0' && !Buffer.from) {
|
||||
Buffer.from = function(args) {
|
||||
return new Buffer(args);
|
||||
}
|
||||
}
|
||||
|
||||
var should = require('should'),
|
||||
needle = require('./../'),
|
||||
http = require('http'),
|
||||
sinon = require('sinon'),
|
||||
stream = require('stream'),
|
||||
fs = require('fs'),
|
||||
port = 11111,
|
||||
server;
|
||||
|
||||
describe('with output option', function() {
|
||||
|
||||
var server, handler, file = '/tmp/foobar.out';
|
||||
|
||||
function send_request_cb(where, cb) {
|
||||
var url = 'http://localhost:' + port + '/whatever.file';
|
||||
return needle.get(url, { output: where }, cb);
|
||||
}
|
||||
|
||||
function send_request_stream(where, cb) {
|
||||
var url = 'http://localhost:' + port + '/whatever.file';
|
||||
var stream = needle.get(url, { output: where });
|
||||
stream.on('end', cb);
|
||||
}
|
||||
|
||||
// this will only work in UNICES
|
||||
function get_open_file_descriptors() {
|
||||
var list = fs.readdirSync('/proc/self/fd');
|
||||
return list.length;
|
||||
}
|
||||
|
||||
var send_request = send_request_cb;
|
||||
|
||||
before(function(){
|
||||
server = http.createServer(function(req, res) {
|
||||
handler(req, res);
|
||||
}).listen(port);
|
||||
});
|
||||
|
||||
after(function() {
|
||||
server.close();
|
||||
})
|
||||
|
||||
beforeEach(function() {
|
||||
try { fs.unlinkSync(file) } catch(e) { };
|
||||
})
|
||||
|
||||
describe('and a 404 response', function() {
|
||||
|
||||
before(function() {
|
||||
handler = function(req, res) {
|
||||
res.writeHead(404, {'Content-Type': 'text/plain' });
|
||||
res.end();
|
||||
}
|
||||
})
|
||||
|
||||
it('doesnt attempt to write a file', function(done) {
|
||||
var spy = sinon.spy(fs, 'createWriteStream');
|
||||
send_request(file, function(err, resp) {
|
||||
resp.statusCode.should.eql(404);
|
||||
spy.called.should.eql(false);
|
||||
spy.restore();
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('doesnt actually write a file', function(done) {
|
||||
send_request(file, function(err, resp) {
|
||||
resp.statusCode.should.eql(404);
|
||||
fs.existsSync(file).should.eql(false);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and a 200 response', function() {
|
||||
|
||||
describe('for an empty response', function() {
|
||||
|
||||
before(function() {
|
||||
handler = function(req, res) {
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
res.end();
|
||||
}
|
||||
})
|
||||
|
||||
it('uses a writableStream', function(done) {
|
||||
var spy = sinon.spy(fs, 'createWriteStream');
|
||||
send_request(file, function(err, resp) {
|
||||
resp.statusCode.should.eql(200);
|
||||
spy.called.should.eql(true);
|
||||
spy.restore();
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('writes a file', function(done) {
|
||||
fs.existsSync(file).should.eql(false);
|
||||
send_request(file, function(err, resp) {
|
||||
fs.existsSync(file).should.eql(true);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('file is zero bytes in length', function(done) {
|
||||
send_request(file, function(err, resp) {
|
||||
fs.statSync(file).size.should.equal(0);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
if (process.platform == 'linux') {
|
||||
it('closes the file descriptor', function(done) {
|
||||
var open_descriptors = get_open_file_descriptors();
|
||||
send_request(file + Math.random(), function(err, resp) {
|
||||
var current_descriptors = get_open_file_descriptors();
|
||||
open_descriptors.should.eql(current_descriptors);
|
||||
done()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
describe('for a JSON response', function() {
|
||||
|
||||
before(function() {
|
||||
handler = function(req, res) {
|
||||
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
||||
res.end(JSON.stringify({foo: 'bar'}));
|
||||
}
|
||||
})
|
||||
|
||||
it('uses a writableStream', function(done) {
|
||||
var spy = sinon.spy(fs, 'createWriteStream');
|
||||
send_request(file, function(err, resp) {
|
||||
resp.statusCode.should.eql(200);
|
||||
spy.called.should.eql(true);
|
||||
spy.restore();
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('writes a file', function(done) {
|
||||
fs.existsSync(file).should.eql(false);
|
||||
send_request(file, function(err, resp) {
|
||||
fs.existsSync(file).should.eql(true);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('file size equals response length', function(done) {
|
||||
send_request(file, function(err, resp) {
|
||||
fs.statSync(file).size.should.equal(resp.bytes);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('response pipeline is honoured (JSON is decoded by default)', function(done) {
|
||||
send_request_stream(file, function(err, resp) {
|
||||
// we need to wait a bit since writing to config.output
|
||||
// happens independently of needle's callback logic.
|
||||
setTimeout(function() {
|
||||
fs.readFileSync(file).toString().should.eql('{\"foo\":\"bar\"}');
|
||||
done();
|
||||
}, 20);
|
||||
})
|
||||
})
|
||||
|
||||
if (process.platform == 'linux') {
|
||||
it('closes the file descriptor', function(done) {
|
||||
var open_descriptors = get_open_file_descriptors();
|
||||
send_request(file + Math.random(), function(err, resp) {
|
||||
var current_descriptors = get_open_file_descriptors();
|
||||
open_descriptors.should.eql(current_descriptors);
|
||||
done()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
describe('for a binary file', function() {
|
||||
|
||||
var pixel = Buffer.from("base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs", "base64");
|
||||
|
||||
before(function() {
|
||||
handler = function(req, res) {
|
||||
res.writeHead(200, { 'Content-Type': 'application/octet-stream', 'Transfer-Encoding': 'chunked' });
|
||||
res.write(pixel.slice(0, 10));
|
||||
res.write(pixel.slice(10, 20));
|
||||
res.write(pixel.slice(20, 30));
|
||||
res.write(pixel.slice(30));
|
||||
res.end();
|
||||
}
|
||||
})
|
||||
|
||||
it('uses a writableStream', function(done) {
|
||||
var spy = sinon.spy(fs, 'createWriteStream');
|
||||
send_request(file, function(err, resp) {
|
||||
resp.statusCode.should.eql(200);
|
||||
spy.called.should.eql(true);
|
||||
spy.restore();
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('writes a file', function(done) {
|
||||
fs.existsSync(file).should.eql(false);
|
||||
send_request(file, function(err, resp) {
|
||||
fs.existsSync(file).should.eql(true);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('file size equals response length', function(done) {
|
||||
send_request(file, function(err, resp) {
|
||||
fs.statSync(file).size.should.equal(resp.bytes);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('file is equal to original buffer', function(done) {
|
||||
send_request(file, function(err, resp) {
|
||||
// we need to wait a bit since writing to config.output
|
||||
// happens independently of needle's callback logic.
|
||||
setTimeout(function() {
|
||||
fs.readFileSync(file).should.eql(pixel);
|
||||
done();
|
||||
}, 20);
|
||||
})
|
||||
})
|
||||
|
||||
it('returns the data in resp.body too', function(done) {
|
||||
send_request(file, function(err, resp) {
|
||||
resp.body.should.eql(pixel);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
if (process.platform == 'linux') {
|
||||
it('closes the file descriptor', function(done) {
|
||||
var open_descriptors = get_open_file_descriptors();
|
||||
send_request(file + Math.random(), function(err, resp) {
|
||||
var current_descriptors = get_open_file_descriptors();
|
||||
open_descriptors.should.eql(current_descriptors);
|
||||
done()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
547
node_modules/needle/test/parsing_spec.js
generated
vendored
Normal file
547
node_modules/needle/test/parsing_spec.js
generated
vendored
Normal file
@ -0,0 +1,547 @@
|
||||
var should = require('should'),
|
||||
needle = require('./../'),
|
||||
http = require('http'),
|
||||
port = 11111,
|
||||
server;
|
||||
|
||||
describe('parsing', function(){
|
||||
|
||||
describe('when response is an JSON string', function(){
|
||||
|
||||
var json_string = '{"foo":"bar"}';
|
||||
|
||||
before(function(done){
|
||||
server = http.createServer(function(req, res) {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
res.end(json_string);
|
||||
}).listen(port, done);
|
||||
});
|
||||
|
||||
after(function(done){
|
||||
server.close(done);
|
||||
})
|
||||
|
||||
describe('and parse option is not passed', function() {
|
||||
|
||||
describe('with default parse_response', function() {
|
||||
|
||||
before(function() {
|
||||
needle.defaults().parse_response.should.eql('all')
|
||||
})
|
||||
|
||||
it('should return object', function(done){
|
||||
needle.get('localhost:' + port, function(err, response, body){
|
||||
should.ifError(err);
|
||||
body.should.have.property('foo', 'bar');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and default parse_response is set to false', function() {
|
||||
|
||||
it('does NOT return object when disabled using .defaults', function(done){
|
||||
needle.defaults({ parse_response: false })
|
||||
|
||||
needle.get('localhost:' + port, function(err, response, body) {
|
||||
should.not.exist(err);
|
||||
body.should.be.an.instanceof(String)
|
||||
body.toString().should.eql('{"foo":"bar"}');
|
||||
|
||||
needle.defaults({ parse_response: 'all' });
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and parse option is true', function() {
|
||||
|
||||
describe('and JSON is valid', function() {
|
||||
|
||||
it('should return object', function(done) {
|
||||
needle.get('localhost:' + port, { parse: true }, function(err, response, body){
|
||||
should.not.exist(err);
|
||||
body.should.have.property('foo', 'bar')
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should have a .parser = json property', function(done) {
|
||||
needle.get('localhost:' + port, { parse: true }, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
resp.parser.should.eql('json');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
describe('and response is empty', function() {
|
||||
|
||||
var old_json_string;
|
||||
|
||||
before(function() {
|
||||
old_json_string = json_string;
|
||||
json_string = "";
|
||||
});
|
||||
|
||||
after(function() {
|
||||
json_string = old_json_string;
|
||||
});
|
||||
|
||||
it('should return an empty string', function(done) {
|
||||
needle.get('localhost:' + port, { parse: true }, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
resp.body.should.equal('');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and JSON is invalid', function() {
|
||||
|
||||
var old_json_string;
|
||||
|
||||
before(function() {
|
||||
old_json_string = json_string;
|
||||
json_string = "this is not going to work";
|
||||
});
|
||||
|
||||
after(function() {
|
||||
json_string = old_json_string;
|
||||
});
|
||||
|
||||
it('does not throw', function(done) {
|
||||
(function(){
|
||||
needle.get('localhost:' + port, { parse: true }, done);
|
||||
}).should.not.throw();
|
||||
});
|
||||
|
||||
it('does NOT return object', function(done) {
|
||||
needle.get('localhost:' + port, { parse: true }, function(err, response, body) {
|
||||
should.not.exist(err);
|
||||
body.should.be.a.String;
|
||||
body.toString().should.eql('this is not going to work');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
describe('and parse option is false', function() {
|
||||
|
||||
it('does NOT return object', function(done){
|
||||
needle.get('localhost:' + port, { parse: false }, function(err, response, body) {
|
||||
should.not.exist(err);
|
||||
body.should.be.an.instanceof(String)
|
||||
body.toString().should.eql('{"foo":"bar"}');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should NOT have a .parser = json property', function(done) {
|
||||
needle.get('localhost:' + port, { parse: false }, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
should.not.exist(resp.parser);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and parse option is "xml"', function() {
|
||||
|
||||
it('does NOT return object', function(done){
|
||||
needle.get('localhost:' + port, { parse: 'xml' }, function(err, response, body) {
|
||||
should.not.exist(err);
|
||||
body.should.be.an.instanceof(String)
|
||||
body.toString().should.eql('{"foo":"bar"}');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should NOT have a .parser = json property', function(done) {
|
||||
needle.get('localhost:' + port, { parse: 'xml' }, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
should.not.exist(resp.parser);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
describe('when response is JSON \'false\'', function(){
|
||||
|
||||
var json_string = 'false';
|
||||
|
||||
before(function(done){
|
||||
server = http.createServer(function(req, res) {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
res.end(json_string);
|
||||
}).listen(port, done);
|
||||
});
|
||||
|
||||
after(function(done){
|
||||
server.close(done);
|
||||
})
|
||||
|
||||
describe('and parse option is not passed', function() {
|
||||
|
||||
it('should return object', function(done){
|
||||
needle.get('localhost:' + port, function(err, response, body){
|
||||
should.ifError(err);
|
||||
body.should.equal(false);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and parse option is true', function() {
|
||||
|
||||
describe('and JSON is valid', function() {
|
||||
|
||||
it('should return object', function(done){
|
||||
needle.get('localhost:' + port, { parse: true }, function(err, response, body){
|
||||
should.not.exist(err);
|
||||
body.should.equal(false)
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
describe('and response is empty', function() {
|
||||
|
||||
var old_json_string;
|
||||
|
||||
before(function() {
|
||||
old_json_string = json_string;
|
||||
json_string = "";
|
||||
});
|
||||
|
||||
after(function() {
|
||||
json_string = old_json_string;
|
||||
});
|
||||
|
||||
it('should return an empty string', function(done) {
|
||||
needle.get('localhost:' + port, { parse: true }, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
resp.body.should.equal('');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and JSON is invalid', function() {
|
||||
|
||||
var old_json_string;
|
||||
|
||||
before(function() {
|
||||
old_json_string = json_string;
|
||||
json_string = "this is not going to work";
|
||||
});
|
||||
|
||||
after(function() {
|
||||
json_string = old_json_string;
|
||||
});
|
||||
|
||||
it('does not throw', function(done) {
|
||||
(function(){
|
||||
needle.get('localhost:' + port, { parse: true }, done);
|
||||
}).should.not.throw();
|
||||
});
|
||||
|
||||
it('does NOT return object', function(done) {
|
||||
needle.get('localhost:' + port, { parse: true }, function(err, response, body) {
|
||||
should.not.exist(err);
|
||||
body.should.be.a.String;
|
||||
body.toString().should.eql('this is not going to work');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
describe('and parse option is false', function() {
|
||||
|
||||
it('does NOT return object', function(done){
|
||||
needle.get('localhost:' + port, { parse: false }, function(err, response, body) {
|
||||
should.not.exist(err);
|
||||
body.should.be.an.instanceof(String)
|
||||
body.toString().should.eql('false');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and parse option is "xml"', function() {
|
||||
|
||||
it('does NOT return object', function(done){
|
||||
needle.get('localhost:' + port, { parse: 'xml' }, function(err, response, body) {
|
||||
should.not.exist(err);
|
||||
body.should.be.an.instanceof(String)
|
||||
body.toString().should.eql('false');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe('when response is an invalid XML string', function(){
|
||||
|
||||
before(function(done){
|
||||
server = http.createServer(function(req, res) {
|
||||
res.writeHeader(200, {'Content-Type': 'application/xml'})
|
||||
res.end("<post><body there11post>")
|
||||
}).listen(port, done);
|
||||
});
|
||||
|
||||
after(function(done){
|
||||
server.close(done);
|
||||
})
|
||||
|
||||
describe('and parse_response is true', function(){
|
||||
|
||||
it('should return original string', function(done) {
|
||||
needle.get('localhost:' + port, { parse_response: true }, function(err, response, body) {
|
||||
should.not.exist(err);
|
||||
body.should.eql('<post><body there11post>')
|
||||
should.not.exist(body.name);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should not have a .parser = xml property', function(done) {
|
||||
needle.get('localhost:' + port, { parse_response: true }, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
should.not.exist(resp.parser);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and parse response is false', function(){
|
||||
|
||||
it('should return valid object', function(done) {
|
||||
needle.get('localhost:' + port, { parse_response: false }, function(err, response, body){
|
||||
should.not.exist(err);
|
||||
body.toString().should.eql('<post><body there11post>')
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should not have a .parser property', function(done) {
|
||||
needle.get('localhost:' + port, { parse_response: false }, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
should.not.exist(resp.parser)
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('when response is a valid XML string', function(){
|
||||
|
||||
before(function(done) {
|
||||
server = http.createServer(function(req, res) {
|
||||
res.writeHeader(200, {'Content-Type': 'application/xml'})
|
||||
res.end("<post><p>hello</p><p><![CDATA[world]]></p></post>")
|
||||
}).listen(port, done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
server.close(done);
|
||||
})
|
||||
|
||||
describe('and parse_response is true', function(){
|
||||
|
||||
it('should return valid object', function(done) {
|
||||
needle.get('localhost:' + port, { parse_response: true }, function(err, response, body) {
|
||||
should.not.exist(err);
|
||||
body.name.should.eql('post')
|
||||
body.children[0].name.should.eql('p')
|
||||
body.children[0].value.should.eql('hello')
|
||||
|
||||
body.children[1].name.should.eql('p')
|
||||
body.children[1].value.should.eql('world')
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should have a .parser = xml property', function(done) {
|
||||
needle.get('localhost:' + port, { parse_response: true }, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
resp.parser.should.eql('xml');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and parse response is false', function(){
|
||||
|
||||
it('should return valid object', function(done) {
|
||||
needle.get('localhost:' + port, { parse_response: false }, function(err, response, body){
|
||||
should.not.exist(err);
|
||||
body.toString().should.eql('<post><p>hello</p><p><![CDATA[world]]></p></post>')
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should not have a .parser property', function(done) {
|
||||
needle.get('localhost:' + port, { parse_response: false }, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
should.not.exist(resp.parser)
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('valid XML, using xml2js', function() {
|
||||
|
||||
var parsers, origParser;
|
||||
|
||||
before(function(done) {
|
||||
var xml2js = require('xml2js')
|
||||
parsers = require('../lib/parsers');
|
||||
origParser = parsers['application/xml'];
|
||||
|
||||
var customParser = require('xml2js').parseString;
|
||||
parsers.use('xml2js', ['application/xml'], function(buff, cb) {
|
||||
var opts = { explicitRoot: true, explicitArray: false };
|
||||
customParser(buff, opts, cb);
|
||||
})
|
||||
|
||||
server = http.createServer(function(req, res) {
|
||||
res.writeHeader(200, {'Content-Type': 'application/xml'})
|
||||
res.end("<post><p>hello</p><p>world</p></post>")
|
||||
}).listen(port, done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
parsers['application/xml'] = origParser;
|
||||
server.close(done);
|
||||
})
|
||||
|
||||
describe('and parse_response is true', function(){
|
||||
|
||||
it('should return valid object', function(done) {
|
||||
needle.get('localhost:' + port, { parse_response: true }, function(err, response, body) {
|
||||
should.not.exist(err);
|
||||
body.should.eql({ post: { p: ['hello', 'world' ]}})
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should have a .parser = xml property', function(done) {
|
||||
needle.get('localhost:' + port, { parse_response: true }, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
resp.parser.should.eql('xml2js');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and parse response is false', function(){
|
||||
|
||||
it('should return valid object', function(done) {
|
||||
needle.get('localhost:' + port, { parse_response: false }, function(err, response, body){
|
||||
should.not.exist(err);
|
||||
body.toString().should.eql('<post><p>hello</p><p>world</p></post>')
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should not have a .parser property', function(done) {
|
||||
needle.get('localhost:' + port, { parse_response: false }, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
should.not.exist(resp.parser)
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('when response is a JSON API flavored JSON string', function () {
|
||||
|
||||
var json_string = '{"data":[{"type":"articles","id":"1","attributes":{"title":"Needle","body":"The leanest and most handsome HTTP client in the Nodelands."}}],"included":[{"type":"people","id":"42","attributes":{"name":"Tomás"}}]}';
|
||||
|
||||
before(function(done){
|
||||
server = http.createServer(function(req, res) {
|
||||
res.setHeader('Content-Type', 'application/vnd.api+json');
|
||||
res.end(json_string);
|
||||
}).listen(port, done);
|
||||
});
|
||||
|
||||
after(function(done){
|
||||
server.close(done);
|
||||
});
|
||||
|
||||
describe('and parse option is not passed', function() {
|
||||
|
||||
describe('with default parse_response', function() {
|
||||
|
||||
before(function() {
|
||||
needle.defaults().parse_response.should.eql('all')
|
||||
})
|
||||
|
||||
it('should return object', function(done){
|
||||
needle.get('localhost:' + port, function(err, response, body){
|
||||
should.ifError(err);
|
||||
body.should.deepEqual({
|
||||
"data": [{
|
||||
"type": "articles",
|
||||
"id": "1",
|
||||
"attributes": {
|
||||
"title": "Needle",
|
||||
"body": "The leanest and most handsome HTTP client in the Nodelands."
|
||||
}
|
||||
}],
|
||||
"included": [
|
||||
{
|
||||
"type": "people",
|
||||
"id": "42",
|
||||
"attributes": {
|
||||
"name": "Tomás"
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
})
|
1021
node_modules/needle/test/post_data_spec.js
generated
vendored
Normal file
1021
node_modules/needle/test/post_data_spec.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
231
node_modules/needle/test/proxy_spec.js
generated
vendored
Normal file
231
node_modules/needle/test/proxy_spec.js
generated
vendored
Normal file
@ -0,0 +1,231 @@
|
||||
var helpers = require('./helpers'),
|
||||
should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
http = require('http'),
|
||||
needle = require('./../');
|
||||
|
||||
var port = 7707;
|
||||
var url = 'localhost:' + port;
|
||||
var nonexisting_host = 'awepfokawepofawe.com';
|
||||
|
||||
describe('proxy option', function() {
|
||||
|
||||
var spy, opts;
|
||||
|
||||
function send_request(opts, done) {
|
||||
if (spy) spy.restore();
|
||||
spy = sinon.spy(http, 'request');
|
||||
needle.get(url, opts, done);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// proxy opts helpers
|
||||
|
||||
function not_proxied(done) {
|
||||
return function(err, resp) {
|
||||
var path = spy.args[0][0].path;
|
||||
path.should.eql('/'); // not the full original URI
|
||||
spy.restore();
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
function proxied(host, port, done) {
|
||||
return function(err, resp) {
|
||||
var path = spy.args[0][0].path;
|
||||
path.should.eql('http://' + url); // the full original URI
|
||||
|
||||
var http_host = spy.args[0][0].host;
|
||||
if (http_host) http_host.should.eql(host);
|
||||
|
||||
var http_port = spy.args[0][0].port;
|
||||
if (http_port) http_port.should.eql(port);
|
||||
|
||||
spy.restore();
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// auth helpers
|
||||
|
||||
function get_auth(header) {
|
||||
var token = header.split(/\s+/).pop();
|
||||
return token && Buffer.from(token, 'base64').toString().split(':');
|
||||
}
|
||||
|
||||
function no_proxy_auth(done) {
|
||||
return function(err, resp) {
|
||||
var headers = spy.args[0][0].headers;
|
||||
Object.keys(headers).should.not.containEql('proxy-authorization');
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
function header_set(name, user, pass, done) {
|
||||
return function(err, resp) {
|
||||
var headers = spy.args[0][0].headers;
|
||||
var auth = get_auth(headers[name]);
|
||||
auth[0].should.eql(user);
|
||||
auth[1].should.eql(pass);
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
function proxy_auth_set(user, pass, done) {
|
||||
return header_set('proxy-authorization', user, pass, done);
|
||||
}
|
||||
|
||||
function basic_auth_set(user, pass, done) {
|
||||
return header_set('authorization', user, pass, done);
|
||||
}
|
||||
|
||||
after(function() {
|
||||
spy.restore();
|
||||
})
|
||||
|
||||
describe('when null proxy is passed', function() {
|
||||
|
||||
it('does not proxy', function(done) {
|
||||
send_request({ proxy: null }, not_proxied(done))
|
||||
})
|
||||
|
||||
describe('but defaults has been set', function() {
|
||||
|
||||
before(function() {
|
||||
needle.defaults({ proxy: 'foobar' });
|
||||
})
|
||||
|
||||
after(function() {
|
||||
needle.defaults({ proxy: null });
|
||||
})
|
||||
|
||||
it('tries to proxy anyway', function(done) {
|
||||
send_request({}, proxied('foobar', 80, done))
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('when weird string is passed', function() {
|
||||
|
||||
it('tries to proxy anyway', function(done) {
|
||||
send_request({ proxy: 'alfalfa' }, proxied('alfalfa', 80, done))
|
||||
})
|
||||
})
|
||||
|
||||
describe('when valid url is passed', function() {
|
||||
|
||||
describe('without NO_PROXY env var set', function() {
|
||||
it('proxies request', function(done) {
|
||||
send_request({ proxy: nonexisting_host + ':123/done' }, proxied(nonexisting_host, '123', done))
|
||||
})
|
||||
|
||||
it('does not set a Proxy-Authorization header', function(done) {
|
||||
send_request({ proxy: nonexisting_host + ':123/done' }, no_proxy_auth(done));
|
||||
})
|
||||
})
|
||||
|
||||
describe('with NO_PROXY env var set', function() {
|
||||
|
||||
it('proxies request if matching host not found in list', function(done) {
|
||||
process.env.NO_PROXY = 'foo';
|
||||
send_request({ proxy: nonexisting_host + ':123/done' }, proxied(nonexisting_host, '123', function() {
|
||||
delete process.env.NO_PROXY;
|
||||
done();
|
||||
}))
|
||||
})
|
||||
|
||||
it('does not proxy request if matching host in list and just has a different port', function(done) {
|
||||
process.env.NO_PROXY = 'localhost';
|
||||
send_request({ proxy: nonexisting_host + ':123/done' }, not_proxied(function() {
|
||||
delete process.env.NO_PROXY;
|
||||
done();
|
||||
}))
|
||||
})
|
||||
|
||||
it('does not proxy if matching host found in list', function(done) {
|
||||
process.env.NO_PROXY = 'foo,' + url;
|
||||
send_request({ proxy: nonexisting_host + ':123/done' }, not_proxied(function() {
|
||||
delete process.env.NO_PROXY;
|
||||
done();
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
describe('and proxy url contains user:pass', function() {
|
||||
|
||||
before(function() {
|
||||
opts = {
|
||||
proxy: 'http://mj:x@' + nonexisting_host + ':123/done'
|
||||
}
|
||||
})
|
||||
|
||||
it('proxies request', function(done) {
|
||||
send_request(opts, proxied(nonexisting_host, '123', done))
|
||||
})
|
||||
|
||||
it('sets Proxy-Authorization header', function(done) {
|
||||
send_request(opts, proxy_auth_set('mj', 'x', done));
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and a proxy_user is passed', function() {
|
||||
|
||||
before(function() {
|
||||
opts = {
|
||||
proxy: nonexisting_host + ':123',
|
||||
proxy_user: 'someone',
|
||||
proxy_pass: 'else'
|
||||
}
|
||||
})
|
||||
|
||||
it('proxies request', function(done) {
|
||||
send_request(opts, proxied(nonexisting_host, '123', done))
|
||||
})
|
||||
|
||||
it('sets Proxy-Authorization header', function(done) {
|
||||
send_request(opts, proxy_auth_set('someone', 'else', done));
|
||||
})
|
||||
|
||||
describe('and url also contains user:pass', function() {
|
||||
|
||||
it('url user:pass wins', function(done) {
|
||||
var opts = {
|
||||
proxy: 'http://xxx:yyy@' + nonexisting_host + ':123',
|
||||
proxy_user: 'someone',
|
||||
proxy_pass: 'else'
|
||||
}
|
||||
|
||||
send_request(opts, proxy_auth_set('xxx', 'yyy', done));
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and options.username is also present', function() {
|
||||
|
||||
before(function() {
|
||||
opts = { proxy_user: 'foobar', username: 'someone' };
|
||||
})
|
||||
|
||||
it('a separate Authorization header is set', function(done) {
|
||||
var opts = {
|
||||
proxy: nonexisting_host + ':123',
|
||||
proxy_user: 'someone',
|
||||
proxy_pass: 'else',
|
||||
username: 'test',
|
||||
password: 'X'
|
||||
}
|
||||
|
||||
send_request(opts, basic_auth_set('test', 'X', done));
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
128
node_modules/needle/test/querystring_spec.js
generated
vendored
Normal file
128
node_modules/needle/test/querystring_spec.js
generated
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
var should = require('should'),
|
||||
stringify = require('../lib/querystring').build;
|
||||
|
||||
describe('stringify', function() {
|
||||
|
||||
describe('with null', function() {
|
||||
|
||||
it('throws', function() {
|
||||
(function() {
|
||||
var res = stringify(null);
|
||||
}).should.throw();
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('with a number', function() {
|
||||
|
||||
it('throws', function() {
|
||||
(function() {
|
||||
var res = stringify(100);
|
||||
}).should.throw();
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('with a string', function() {
|
||||
|
||||
describe('that is empty', function() {
|
||||
|
||||
it('throws', function() {
|
||||
(function() {
|
||||
var res = stringify('');
|
||||
}).should.throw();
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('that doesnt contain an equal sign', function() {
|
||||
|
||||
it('throws', function() {
|
||||
(function() {
|
||||
var res = stringify('boomshagalaga');
|
||||
}).should.throw();
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('that contains an equal sign', function() {
|
||||
|
||||
it('works', function() {
|
||||
var res = stringify('hello=123');
|
||||
res.should.eql('hello=123');
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('with an array', function() {
|
||||
|
||||
describe('with key val objects', function() {
|
||||
|
||||
it('works', function() {
|
||||
var res = stringify([ {foo: 'bar'} ]);
|
||||
res.should.eql('foo=bar');
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('where all elements are strings with an equal sign', function() {
|
||||
|
||||
it('works', function() {
|
||||
var res = stringify([ 'bar=123', 'quux=' ]);
|
||||
res.should.eql('bar=123&quux=');
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('with random words', function() {
|
||||
|
||||
it('throws', function() {
|
||||
(function() {
|
||||
var res = stringify(['hello', 'there']);
|
||||
}).should.throw();
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('with integers', function() {
|
||||
|
||||
it('throws', function() {
|
||||
(function() {
|
||||
var res = stringify([123, 432]);
|
||||
}).should.throw();
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('with an object', function() {
|
||||
|
||||
it('works', function() {
|
||||
var res = stringify({ test: 100 });
|
||||
res.should.eql('test=100');
|
||||
})
|
||||
|
||||
describe('with object where val is an array', function() {
|
||||
|
||||
it('works', function() {
|
||||
var res = stringify({ foo: ['bar', 'baz'] });
|
||||
res.should.eql('foo[]=bar&foo[]=baz');
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('with object where val is an array of key val objects', function() {
|
||||
|
||||
it('works', function() {
|
||||
var res = stringify({ foo: [{'1': 'bar'}, {'2': 'baz'}] });
|
||||
res.should.eql('foo[][1]=bar&foo[][2]=baz');
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
465
node_modules/needle/test/redirect_spec.js
generated
vendored
Normal file
465
node_modules/needle/test/redirect_spec.js
generated
vendored
Normal file
@ -0,0 +1,465 @@
|
||||
var helpers = require('./helpers'),
|
||||
should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
needle = require('./../');
|
||||
|
||||
var ports = {
|
||||
http : 8888,
|
||||
https : 9999
|
||||
}
|
||||
|
||||
var protocols = {
|
||||
http : require('http'),
|
||||
https : require('https')
|
||||
}
|
||||
|
||||
var code = 301;
|
||||
var location; // var to set the response location
|
||||
|
||||
function response_code() {
|
||||
return code;
|
||||
}
|
||||
|
||||
function response_headers() {
|
||||
return { 'Content-Type': 'text/plain', 'Location': location }
|
||||
}
|
||||
|
||||
describe('redirects', function() {
|
||||
|
||||
var spies = {},
|
||||
servers = {};
|
||||
|
||||
var current_protocol;
|
||||
var hostname = require('os').hostname();
|
||||
|
||||
// open two servers, one that responds to a redirect
|
||||
before(function(done) {
|
||||
|
||||
var conf = {
|
||||
port : ports.http,
|
||||
code : response_code,
|
||||
headers : response_headers
|
||||
}
|
||||
|
||||
servers.http = helpers.server(conf, function() {
|
||||
conf.port = ports.https;
|
||||
conf.protocol = 'https';
|
||||
servers.https = helpers.server(conf, done);
|
||||
});
|
||||
})
|
||||
|
||||
after(function(done) {
|
||||
servers.http.close(function() {
|
||||
servers.https.close(done);
|
||||
});
|
||||
})
|
||||
|
||||
var prots = {'http': 'https'};
|
||||
Object.keys(prots).forEach(function(protocol) {
|
||||
|
||||
current_protocol = protocol;
|
||||
var other_protocol = protocol == 'http' ? 'https' : 'http';
|
||||
|
||||
var opts, // each test will modify this
|
||||
host = '127.0.0.1',
|
||||
url = protocol + '://' + host + ':' + ports[protocol] + '/hello';
|
||||
|
||||
function send_request(opts, cb) {
|
||||
if (protocol == 'https') opts.rejectUnauthorized = false;
|
||||
// console.log(' -- sending request ' + url + ' -- redirect to ' + location);
|
||||
needle.post(url, { foo: 'bar' }, opts, cb);
|
||||
}
|
||||
|
||||
function not_followed(done) {
|
||||
send_request(opts, function(err, resp) {
|
||||
resp.statusCode.should.eql(301);
|
||||
if (current_protocol == 'http') {
|
||||
spies.http.callCount.should.eql(1); // only original request
|
||||
spies.https.callCount.should.eql(0);
|
||||
} else {
|
||||
spies.http.callCount.should.eql(0);
|
||||
spies.https.callCount.should.eql(1); // only original request
|
||||
}
|
||||
done();
|
||||
})
|
||||
}
|
||||
|
||||
function followed_same_protocol(done) {
|
||||
send_request(opts, function(err, resp) {
|
||||
// the original request plus the redirect one
|
||||
spies[current_protocol].callCount.should.eql(2);
|
||||
done();
|
||||
})
|
||||
}
|
||||
|
||||
function followed_other_protocol(done) {
|
||||
send_request(opts, function(err, resp) {
|
||||
// on new-ish node versions, https.request calls http.request internally,
|
||||
// so we need to amount for that additional call.
|
||||
// update: this doesn't happen on node > 10.x
|
||||
|
||||
var node_major_ver = process.version.split('.')[0].replace('v', '');
|
||||
var http_calls = protocols.http.Agent.defaultMaxSockets == Infinity && parseInt(node_major_ver) < 10 ? 2 : 1;
|
||||
|
||||
spies.http.callCount.should.eql(http_calls); // the one(s) from http.request
|
||||
spies.https.callCount.should.eql(1); // the one from https.request (redirect)
|
||||
done();
|
||||
})
|
||||
}
|
||||
|
||||
// set a spy on [protocol].request
|
||||
// so we can see how many times a request was made
|
||||
before(function() {
|
||||
spies.http = sinon.spy(protocols.http, 'request');
|
||||
spies.https = sinon.spy(protocols.https, 'request');
|
||||
})
|
||||
|
||||
// and make sure it is restored after each test
|
||||
afterEach(function() {
|
||||
spies.http.reset();
|
||||
spies.https.reset();
|
||||
})
|
||||
|
||||
after(function() {
|
||||
spies.http.restore();
|
||||
spies.https.restore();
|
||||
})
|
||||
|
||||
describe('when overriding defaults', function() {
|
||||
|
||||
before(function() {
|
||||
needle.defaults({ follow_max: 10 });
|
||||
opts = {};
|
||||
})
|
||||
|
||||
after(function() {
|
||||
// reset values to previous
|
||||
needle.defaults({ follow_max: 0 });
|
||||
})
|
||||
|
||||
describe('and redirected to the same path on same host and protocol', function() {
|
||||
before(function() {
|
||||
location = url;
|
||||
})
|
||||
it('does not follow redirect', not_followed);
|
||||
})
|
||||
|
||||
describe('and redirected to the same path on same host and different protocol', function() {
|
||||
before(function() {
|
||||
location = url.replace(protocol, other_protocol).replace(ports[protocol], ports[other_protocol]);
|
||||
})
|
||||
|
||||
it('follows redirect', followed_other_protocol);
|
||||
})
|
||||
|
||||
describe('and redirected to a different path on same host, same protocol', function() {
|
||||
before(function() {
|
||||
location = url.replace('/hello', '/goodbye');
|
||||
})
|
||||
it('follows redirect', followed_same_protocol);
|
||||
})
|
||||
|
||||
describe('and redirected to a different path on same host, different protocol', function() {
|
||||
before(function() {
|
||||
location = url.replace('/hello', '/goodbye').replace(protocol, other_protocol).replace(ports[protocol], ports[other_protocol]);
|
||||
})
|
||||
it('follows redirect', followed_other_protocol);
|
||||
})
|
||||
|
||||
describe('and redirected to same path on another host, same protocol', function() {
|
||||
before(function() {
|
||||
location = url.replace(host, hostname);
|
||||
})
|
||||
it('follows redirect', followed_same_protocol);
|
||||
})
|
||||
|
||||
describe('and redirected to same path on another host, different protocol', function() {
|
||||
before(function() {
|
||||
location = url.replace(host, hostname).replace(protocol, other_protocol).replace(ports[protocol], ports[other_protocol]);
|
||||
})
|
||||
it('follows redirect', followed_other_protocol);
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
// false and null have the same result
|
||||
var values = [false, null];
|
||||
values.forEach(function(value) {
|
||||
|
||||
describe('when follow is ' + value, function() {
|
||||
|
||||
before(function() {
|
||||
opts = { follow: value };
|
||||
})
|
||||
|
||||
describe('and redirected to the same path on same host and protocol', function() {
|
||||
before(function() {
|
||||
location = url;
|
||||
})
|
||||
|
||||
it('throws an error', function() {
|
||||
(function() {
|
||||
send_request(opts, function() { });
|
||||
}).should.throw;
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('when follow is true', function() {
|
||||
|
||||
before(function() {
|
||||
opts = { follow: true };
|
||||
})
|
||||
|
||||
describe('and redirected to the same path on same host and protocol', function() {
|
||||
before(function() { location = url })
|
||||
|
||||
it('throws an error', function() {
|
||||
(function() {
|
||||
send_request(opts, function() { });
|
||||
}).should.throw;
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('when follow is > 0', function() {
|
||||
|
||||
before(function() {
|
||||
needle.defaults({ follow: 10 });
|
||||
})
|
||||
|
||||
after(function() {
|
||||
needle.defaults({ follow: 0 });
|
||||
})
|
||||
|
||||
describe('when keep_method is false', function() {
|
||||
|
||||
before(function() {
|
||||
opts = { follow_keep_method: false };
|
||||
})
|
||||
|
||||
// defaults to follow host and protocol
|
||||
describe('and redirected to the same path on same host and different protocol', function() {
|
||||
|
||||
before(function() {
|
||||
location = url.replace(protocol, other_protocol);
|
||||
})
|
||||
|
||||
it('follows redirect', followed_other_protocol);
|
||||
|
||||
it('sends a GET request with no data', function(done) {
|
||||
send_request(opts, function(err, resp) {
|
||||
// spy.args[0][3].should.eql(null);
|
||||
spies.http.args[0][0].method.should.eql('GET');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('does not resend cookies if follow_set_cookies is false', function(done) {
|
||||
opts.cookies = {foo: 'bar'};
|
||||
opts.follow_set_cookies = false;
|
||||
send_request(opts, function(err, resp) {
|
||||
should.not.exist(spies.http.args[0][0].headers['cookie']);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('resends cookies if follow_set_cookies is true', function(done) {
|
||||
opts.cookies = {foo: 'bar'};
|
||||
opts.follow_set_cookies = true;
|
||||
send_request(opts, function(err, resp) {
|
||||
spies.http.args[0][0].headers['cookie'].should.eql('foo=bar')
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and set_referer is true', function() {
|
||||
|
||||
before(function() {
|
||||
opts = { follow_set_referer: true };
|
||||
})
|
||||
|
||||
// defaults to follow host and protocol
|
||||
describe('and redirected to the same path on same host and different protocol', function() {
|
||||
|
||||
before(function() {
|
||||
location = url.replace(protocol, other_protocol);
|
||||
})
|
||||
|
||||
it('follows redirect', followed_other_protocol);
|
||||
|
||||
it('sets Referer header when following redirect', function(done) {
|
||||
send_request(opts, function(err, resp) {
|
||||
// spies.http.args[0][3].should.eql({ foo: 'bar'});
|
||||
spies.http.args[0][0].headers['referer'].should.eql("http://" + host + ":8888/hello");
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('does not resend cookies if follow_set_cookies is false', function(done) {
|
||||
opts.cookies = {foo: 'bar'};
|
||||
opts.follow_set_cookies = false;
|
||||
send_request(opts, function(err, resp) {
|
||||
should.not.exist(spies.http.args[0][0].headers['cookie']);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('resends cookies if follow_set_cookies is true', function(done) {
|
||||
opts.cookies = {foo: 'bar'};
|
||||
opts.follow_set_cookies = true;
|
||||
send_request(opts, function(err, resp) {
|
||||
spies.http.args[0][0].headers['cookie'].should.eql('foo=bar')
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and keep_method is true', function() {
|
||||
|
||||
before(function() {
|
||||
opts = { follow_keep_method: true };
|
||||
})
|
||||
|
||||
// defaults to follow host and protocol
|
||||
describe('and redirected to the same path on same host and different protocol', function() {
|
||||
|
||||
before(function() {
|
||||
location = url.replace(protocol, other_protocol);
|
||||
})
|
||||
|
||||
it('follows redirect', followed_other_protocol);
|
||||
|
||||
it('sends a POST request with the original data', function(done) {
|
||||
send_request(opts, function(err, resp) {
|
||||
spies.http.args[0][0].method.should.eql('post');
|
||||
// spies.http.args[0][3].should.eql({ foo: 'bar'});
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('does not resend cookies if follow_set_cookies is false', function(done) {
|
||||
opts.cookies = {foo: 'bar'};
|
||||
opts.follow_set_cookies = false;
|
||||
send_request(opts, function(err, resp) {
|
||||
should.not.exist(spies.http.args[0][0].headers['cookie']);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('resends cookies if follow_set_cookies is true', function(done) {
|
||||
opts.cookies = {foo: 'bar'};
|
||||
opts.follow_set_cookies = true;
|
||||
send_request(opts, function(err, resp) {
|
||||
spies.http.args[0][0].headers['cookie'].should.eql('foo=bar')
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and if_same_host is false', function() {
|
||||
|
||||
before(function() {
|
||||
opts = { follow_if_same_host: false };
|
||||
})
|
||||
|
||||
// by default it will follow other protocols
|
||||
describe('and redirected to same path on another domain, same protocol', function() {
|
||||
before(function() {
|
||||
location = url.replace(host, hostname);
|
||||
})
|
||||
|
||||
it('follows redirect', followed_same_protocol);
|
||||
|
||||
it('does not resend cookies even if follow_set_cookies is true', function(done) {
|
||||
opts.cookies = {foo: 'bar'};
|
||||
opts.follow_set_cookies = true;
|
||||
send_request(opts, function(err, resp) {
|
||||
should.not.exist(spies.http.args[0][0].headers['cookie']);
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and if_same_host is true', function() {
|
||||
|
||||
before(function() {
|
||||
opts = { follow_if_same_host: true };
|
||||
})
|
||||
|
||||
// by default it will follow other protocols
|
||||
describe('and redirected to same path on another domain, same protocol', function() {
|
||||
before(function() {
|
||||
location = url.replace(host, hostname);
|
||||
})
|
||||
|
||||
it('does not follow redirect', not_followed);
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and if_same_protocol is false', function() {
|
||||
|
||||
before(function() {
|
||||
opts = { follow_if_same_protocol: false };
|
||||
})
|
||||
|
||||
// by default it will follow other hosts
|
||||
describe('and redirected to same path on another domain, different protocol', function() {
|
||||
before(function() {
|
||||
location = url.replace(host, hostname).replace(protocol, other_protocol).replace(ports[protocol], ports[other_protocol]);
|
||||
})
|
||||
|
||||
it('follows redirect', followed_other_protocol);
|
||||
|
||||
it('does not resend cookies even if follow_set_cookies is true', function(done) {
|
||||
opts.cookies = {foo: 'bar'};
|
||||
opts.follow_set_cookies = true;
|
||||
send_request(opts, function(err, resp) {
|
||||
should.not.exist(spies.http.args[0][0].headers['cookie']);
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and if_same_protocol is true', function() {
|
||||
|
||||
before(function() {
|
||||
opts = { follow_if_same_protocol: true };
|
||||
})
|
||||
|
||||
// by default it will follow other hosts
|
||||
describe('and redirected to same path on another domain, different protocol', function() {
|
||||
before(function() {
|
||||
location = url.replace(host, hostname).replace(protocol, other_protocol).replace(ports[protocol], ports[other_protocol]);
|
||||
})
|
||||
it('does not follow redirect', not_followed);
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
});
|
45
node_modules/needle/test/redirect_with_timeout.js
generated
vendored
Normal file
45
node_modules/needle/test/redirect_with_timeout.js
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
var should = require('should')
|
||||
var needle = require('./../')
|
||||
|
||||
describe('follow redirects when read_timeout is set', function () {
|
||||
|
||||
it('clear timeout before following redirect', function (done) {
|
||||
var opts = {
|
||||
open_timeout: 1000,
|
||||
read_timeout: 3000,
|
||||
follow: 5,
|
||||
user_agent: 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36'
|
||||
}
|
||||
|
||||
var timedOut = 0
|
||||
var redirects = 0
|
||||
|
||||
var timer = setTimeout(function () {
|
||||
var hasRedirects = redirects > 0
|
||||
hasRedirects.should.equal(true)
|
||||
done()
|
||||
}, opts.read_timeout || 3000)
|
||||
|
||||
var resp = needle.get('http://google.com/', opts, function (err, resp, body) {
|
||||
var noErr = err === null
|
||||
var hasBody = body.length > 0
|
||||
noErr.should.equal(true);
|
||||
hasBody.should.equal(true);
|
||||
});
|
||||
|
||||
resp.on('redirect', function (location) {
|
||||
redirects++
|
||||
// console.info(' Redirected to ', location)
|
||||
})
|
||||
|
||||
resp.on('timeout', function (type) {
|
||||
timedOut++
|
||||
timedOut.should.equal(0)
|
||||
// console.error(' ', type, 'timeout')
|
||||
clearTimeout(timer)
|
||||
done()
|
||||
})
|
||||
|
||||
}).timeout(30000)
|
||||
|
||||
})
|
164
node_modules/needle/test/request_stream_spec.js
generated
vendored
Normal file
164
node_modules/needle/test/request_stream_spec.js
generated
vendored
Normal file
@ -0,0 +1,164 @@
|
||||
var fs = require('fs'),
|
||||
needle = require('..'),
|
||||
stream = require('stream'),
|
||||
http = require('http'),
|
||||
should = require('should'),
|
||||
sinon = require('sinon');
|
||||
|
||||
var port = 2233;
|
||||
|
||||
var node_major_ver = parseInt(process.version.split('.')[0].replace('v', ''));
|
||||
var node_minor_ver = parseInt(process.version.split('.')[1]);
|
||||
|
||||
describe('request stream length', function() {
|
||||
|
||||
var server, writable;
|
||||
|
||||
function createServer() {
|
||||
return http.createServer(function(req, res) {
|
||||
|
||||
req.on('data', function(chunk) {
|
||||
// console.log(chunk.length);
|
||||
})
|
||||
|
||||
req.on('end', function() {
|
||||
res.writeHeader(200, { 'Content-Type': 'application/json'})
|
||||
res.end(JSON.stringify({ headers: req.headers }))
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
before(function(done) {
|
||||
server = createServer();
|
||||
server.listen(port, done)
|
||||
})
|
||||
|
||||
beforeEach(function() {
|
||||
writable = new stream.Readable();
|
||||
writable._read = function() {
|
||||
this.push('hello world');
|
||||
this.push(null);
|
||||
}
|
||||
})
|
||||
|
||||
after(function(done) {
|
||||
server.close(done)
|
||||
})
|
||||
|
||||
function send_request(opts, cb) {
|
||||
needle.post('http://localhost:' + port, writable, opts, cb)
|
||||
}
|
||||
|
||||
describe('no stream_length set', function() {
|
||||
|
||||
it('doesnt set Content-Length header', function(done) {
|
||||
send_request({}, function(err, resp) {
|
||||
should.not.exist(resp.body.headers['content-length']);
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('works if Transfer-Encoding is not set', function(done) {
|
||||
send_request({}, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
resp.statusCode.should.eql(200);
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('stream_length is set to valid value', function() {
|
||||
|
||||
it('sets Content-Length header to that value', function(done) {
|
||||
send_request({ stream_length: 11 }, function(err, resp) {
|
||||
resp.body.headers['content-length'].should.eql('11');
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('works if Transfer-Encoding is set to a blank string', function(done) {
|
||||
send_request({ stream_length: 11, headers: { 'Transfer-Encoding': '' }}, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
var code = node_major_ver == 10 && node_minor_ver > 15 ? 400 : 200;
|
||||
resp.statusCode.should.eql(code);
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('works if Transfer-Encoding is not set', function(done) {
|
||||
send_request({ stream_length: 11 }, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
resp.statusCode.should.eql(200);
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
|
||||
describe('stream_length set to 0', function() {
|
||||
|
||||
describe('stream with path', function() {
|
||||
|
||||
var stub;
|
||||
|
||||
beforeEach(function() {
|
||||
writable.path = '/foo/bar';
|
||||
stub = sinon.stub(fs, 'stat').callsFake(function(path, cb) {
|
||||
cb(null, { size: 11 })
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(function() {
|
||||
stub.restore();
|
||||
})
|
||||
|
||||
it('sets Content-Length header to streams length', function(done) {
|
||||
send_request({ stream_length: 0 }, function(err, resp) {
|
||||
resp.body.headers['content-length'].should.eql('11');
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('works if Transfer-Encoding is set to a blank string', function(done) {
|
||||
send_request({ stream_length: 0, headers: { 'Transfer-Encoding': '' }}, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
var code = node_major_ver == 10 && node_minor_ver > 15 ? 400 : 200;
|
||||
resp.statusCode.should.eql(code);
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('works if Transfer-Encoding is not set', function(done) {
|
||||
send_request({ stream_length: 0 }, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
resp.statusCode.should.eql(200);
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('stream without path', function() {
|
||||
|
||||
it('does not set Content-Length header', function(done) {
|
||||
send_request({ stream_length: 0 }, function(err, resp) {
|
||||
should.not.exist(resp.body.headers['content-length']);
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('works if Transfer-Encoding is not set', function(done) {
|
||||
send_request({ stream_length: 0 }, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
resp.statusCode.should.eql(200);
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
138
node_modules/needle/test/response_stream_spec.js
generated
vendored
Normal file
138
node_modules/needle/test/response_stream_spec.js
generated
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
var should = require('should'),
|
||||
needle = require('./../'),
|
||||
http = require('http'),
|
||||
stream = require('stream'),
|
||||
fs = require('fs'),
|
||||
port = 11111,
|
||||
server;
|
||||
|
||||
describe('response streams', function() {
|
||||
|
||||
describe('when the server sends back json', function(){
|
||||
|
||||
before(function(done) {
|
||||
server = http.createServer(function(req, res) {
|
||||
res.setHeader('Content-Type', 'application/json')
|
||||
res.end('{"foo":"bar"}')
|
||||
}).listen(port, done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
server.close(done);
|
||||
})
|
||||
|
||||
describe('and the client uses streams', function(){
|
||||
|
||||
it('creates a proper streams2 stream', function(done) {
|
||||
var stream = needle.get('localhost:' + port)
|
||||
|
||||
// newer node versions set this to null instead of false
|
||||
var bool = !!stream._readableState.flowing;
|
||||
should.equal(false, bool);
|
||||
|
||||
var readableCalled = false;
|
||||
stream.on('readable', function() {
|
||||
readableCalled = true;
|
||||
})
|
||||
|
||||
stream.on('finish', function() {
|
||||
readableCalled.should.be.true;
|
||||
done();
|
||||
});
|
||||
|
||||
stream.resume();
|
||||
})
|
||||
|
||||
it('emits a single data item which is our JSON object', function(done) {
|
||||
var stream = needle.get('localhost:' + port)
|
||||
|
||||
var chunks = [];
|
||||
stream.on('readable', function () {
|
||||
while (chunk = this.read()) {
|
||||
chunk.should.be.an.Object;
|
||||
chunks.push(chunk);
|
||||
}
|
||||
})
|
||||
|
||||
stream.on('done', function () {
|
||||
chunks.should.have.length(1)
|
||||
chunks[0].should.have.property('foo', 'bar');
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
it('emits a raw buffer if we do not want to parse JSON', function(done) {
|
||||
var stream = needle.get('localhost:' + port, { parse: false })
|
||||
|
||||
var chunks = [];
|
||||
stream.on('readable', function () {
|
||||
while (chunk = this.read()) {
|
||||
Buffer.isBuffer(chunk).should.be.true;
|
||||
chunks.push(chunk);
|
||||
}
|
||||
})
|
||||
|
||||
stream.on('done', function() {
|
||||
var body = Buffer.concat(chunks).toString();
|
||||
body.should.equal('{"foo":"bar"}')
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the server sends back what was posted to it', function () {
|
||||
var file = 'asdf.txt';
|
||||
|
||||
before(function(done){
|
||||
server = http.createServer(function(req, res) {
|
||||
res.setHeader('Content-Type', 'application/octet')
|
||||
req.pipe(res);
|
||||
}).listen(port);
|
||||
|
||||
fs.writeFile(file, 'contents of stream', done);
|
||||
});
|
||||
|
||||
after(function(done){
|
||||
server.close();
|
||||
fs.unlink(file, done);
|
||||
})
|
||||
|
||||
it('can PUT a stream', function (done) {
|
||||
var stream = needle.put('localhost:' + port, fs.createReadStream(file), { stream: true });
|
||||
|
||||
var chunks = [];
|
||||
stream.on('readable', function () {
|
||||
while (chunk = this.read()) {
|
||||
Buffer.isBuffer(chunk).should.be.true;
|
||||
chunks.push(chunk);
|
||||
}
|
||||
})
|
||||
|
||||
stream.on('end', function () {
|
||||
var body = Buffer.concat(chunks).toString();
|
||||
body.should.equal('contents of stream')
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('can PATCH a stream', function (done) {
|
||||
var stream = needle.patch('localhost:' + port, fs.createReadStream(file), { stream: true });
|
||||
|
||||
var chunks = [];
|
||||
stream.on('readable', function () {
|
||||
while (chunk = this.read()) {
|
||||
Buffer.isBuffer(chunk).should.be.true;
|
||||
chunks.push(chunk);
|
||||
}
|
||||
})
|
||||
|
||||
stream.on('end', function () {
|
||||
var body = Buffer.concat(chunks).toString();
|
||||
body.should.equal('contents of stream')
|
||||
done();
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
79
node_modules/needle/test/socket_cleanup_spec.js
generated
vendored
Normal file
79
node_modules/needle/test/socket_cleanup_spec.js
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
var should = require('should'),
|
||||
needle = require('./../'),
|
||||
fs = require('fs'),
|
||||
https = require('https'),
|
||||
stream = require('stream');
|
||||
|
||||
describe('socket cleanup', function(){
|
||||
|
||||
var outFile = 'test/tmp';
|
||||
var httpAgent, readStream, writeStream
|
||||
|
||||
var file = 'ubuntu-21.04-desktop-amd64.iso',
|
||||
url = 'https://releases.ubuntu.com/21.04/' + file;
|
||||
|
||||
function getActiveSockets() {
|
||||
return Object.keys(httpAgent.sockets).length
|
||||
}
|
||||
|
||||
before(function() {
|
||||
httpAgent = new https.Agent({
|
||||
keepAlive : true,
|
||||
maxSockets : 1
|
||||
});
|
||||
})
|
||||
|
||||
after(function() {
|
||||
httpAgent.destroy()
|
||||
fs.unlinkSync(outFile);
|
||||
})
|
||||
|
||||
it('should cleanup sockets on ERR_STREAM_PREMATURE_CLOSE (using .pipe)', function(done) {
|
||||
getActiveSockets().should.eql(0);
|
||||
|
||||
var resp = needle.get(url, { agent: httpAgent });
|
||||
var writable = fs.createWriteStream(outFile);
|
||||
resp.pipe(writable);
|
||||
|
||||
writable.on('close', function(e) {
|
||||
if (!resp.done) resp.abort();
|
||||
})
|
||||
|
||||
setTimeout(function() {
|
||||
getActiveSockets().should.eql(1);
|
||||
writable.destroy();
|
||||
}, 50);
|
||||
|
||||
setTimeout(function() {
|
||||
getActiveSockets().should.eql(0);
|
||||
done();
|
||||
}, 500); // takes a bit
|
||||
})
|
||||
|
||||
it('should cleanup sockets on ERR_STREAM_PREMATURE_CLOSE (using stream.pipeline)', function(done) {
|
||||
if (!stream.pipeline)
|
||||
return done()
|
||||
|
||||
getActiveSockets().should.eql(0);
|
||||
|
||||
var resp = needle.get(url, { agent: httpAgent });
|
||||
var writable = fs.createWriteStream(outFile);
|
||||
|
||||
stream.pipeline(resp, writable, function(err) {
|
||||
err.code.should.eql('ERR_STREAM_PREMATURE_CLOSE')
|
||||
if (err) resp.request.destroy();
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
getActiveSockets().should.eql(1);
|
||||
writable.destroy();
|
||||
}, 50);
|
||||
|
||||
setTimeout(function() {
|
||||
getActiveSockets().should.eql(0);
|
||||
done();
|
||||
}, 1000); // takes a bit
|
||||
|
||||
})
|
||||
|
||||
})
|
67
node_modules/needle/test/socket_pool_spec.js
generated
vendored
Normal file
67
node_modules/needle/test/socket_pool_spec.js
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
var needle = require('../'),
|
||||
should = require('should'),
|
||||
http = require('http');
|
||||
|
||||
var server, port = 11112;
|
||||
|
||||
describe('socket reuse', function() {
|
||||
|
||||
var httpAgent = new http.Agent({
|
||||
keepAlive : true,
|
||||
maxSockets : 1
|
||||
});
|
||||
|
||||
before(function(done) {
|
||||
server = http.createServer(function(req, res) {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
setTimeout(function() {
|
||||
res.end('{"foo":"bar"}');
|
||||
}, 50);
|
||||
}).listen(port, done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
httpAgent.destroy();
|
||||
server.close(done);
|
||||
});
|
||||
|
||||
describe('when sockets are reused', function() {
|
||||
|
||||
it('does not duplicate listeners on .end', function(done) {
|
||||
|
||||
var last_error;
|
||||
var count = 10;
|
||||
|
||||
function completed(err) {
|
||||
--count || done(last_error);
|
||||
}
|
||||
|
||||
function send() {
|
||||
needle.get('localhost:' + port, { agent: httpAgent }, function(err, resp) {
|
||||
if (err)
|
||||
throw new Error("Unexpected error: " + err);
|
||||
|
||||
// lets go through all sockets and inspect all socket objects
|
||||
for (hostTarget in httpAgent.sockets) {
|
||||
httpAgent.sockets[hostTarget].forEach(function(socket) {
|
||||
// normally, there are 2 internal listeners and 1 needle sets up,
|
||||
// but to be sure the test does not fail even if newer node versions
|
||||
// introduce additional listeners, we use a higher limit.
|
||||
try {
|
||||
socket.listeners('end').length.should.be.below(5, "too many listeners on the socket object's end event");
|
||||
} catch (e) {
|
||||
last_error = e;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
completed();
|
||||
});
|
||||
}
|
||||
|
||||
for (var i = 0; i < count; i++) {
|
||||
send();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
144
node_modules/needle/test/stream_events_spec.js
generated
vendored
Normal file
144
node_modules/needle/test/stream_events_spec.js
generated
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
var needle = require('../'),
|
||||
fs = require('fs'),
|
||||
should = require('should'),
|
||||
helpers = require('./helpers');
|
||||
|
||||
describe('stream events', function() {
|
||||
|
||||
var server,
|
||||
port = 3456,
|
||||
responseData,
|
||||
serverOpts = {},
|
||||
requestHandler = function(req, res) { res.end('OK') }
|
||||
|
||||
before(function() {
|
||||
var opts = {
|
||||
port: port,
|
||||
handler: function(req, res) { requestHandler(req, res) }
|
||||
}
|
||||
server = helpers.server(opts);
|
||||
})
|
||||
|
||||
after(function() {
|
||||
server.close();
|
||||
})
|
||||
|
||||
beforeEach(function() {
|
||||
responseData = '';
|
||||
})
|
||||
|
||||
describe('when consuming data directly', function() {
|
||||
|
||||
function send_request(opts, cb) {
|
||||
return needle
|
||||
.get('http://localhost:' + port, opts)
|
||||
.on('data', function(data) { responseData += data })
|
||||
}
|
||||
|
||||
describe('and request stream fails', function() {
|
||||
|
||||
it('emits done event with error', function(done) {
|
||||
requestHandler = function(req, res) { req.socket.destroy() }
|
||||
|
||||
send_request({}).on('done', function(err) {
|
||||
err.code.should.eql('ECONNRESET');
|
||||
responseData.should.eql('');
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and request succeeds but decoding fails', function() {
|
||||
|
||||
it('emits done event without error', function(done) {
|
||||
requestHandler = function(req, res) {
|
||||
res.setHeader('Content-Type', 'application/json')
|
||||
res.end('invalid:json')
|
||||
}
|
||||
|
||||
send_request({ json: true }).on('done', function(err) {
|
||||
should.not.exist(err);
|
||||
responseData.should.eql('invalid:json');
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and request succeeds and pipeline works ok', function() {
|
||||
|
||||
it('emits done event without error', function(done) {
|
||||
requestHandler = function(req, res) { res.end('{"ok":1}') }
|
||||
|
||||
send_request({ json: true }).on('done', function(err) {
|
||||
should.not.exist(err);
|
||||
responseData.should.eql('{"ok":1}');
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('when piping to a fs writableStream', function() {
|
||||
|
||||
var outFile = 'test/tmp.dat';
|
||||
|
||||
function send_request(opts, cb) {
|
||||
return needle
|
||||
.get('http://localhost:' + port, opts)
|
||||
.pipe(fs.createWriteStream(outFile))
|
||||
.on('data', function(data) { responseData += data })
|
||||
}
|
||||
|
||||
after(function(done) {
|
||||
fs.unlink(outFile, done)
|
||||
})
|
||||
|
||||
describe('and request stream fails', function() {
|
||||
|
||||
it('final stream emits done event with error', function(done) {
|
||||
requestHandler = function(req, res) { req.socket.destroy() }
|
||||
|
||||
send_request({}).on('done', function(err) {
|
||||
err.code.should.eql('ECONNRESET');
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and request succeeds but decoding fails', function() {
|
||||
|
||||
it('final stream emits done event without error', function(done) {
|
||||
requestHandler = function(req, res) {
|
||||
res.setHeader('Content-Type', 'application/json')
|
||||
res.end('invalid:json')
|
||||
}
|
||||
|
||||
send_request({ json: true }).on('done', function(err) {
|
||||
should.not.exist(err);
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('and request succeeds and pipeline works ok', function() {
|
||||
|
||||
it('final stream emits done event without error', function(done) {
|
||||
requestHandler = function(req, res) { res.end('{"ok":1}') }
|
||||
|
||||
send_request({ json: true }).on('done', function(err) {
|
||||
should.not.exist(err);
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
57
node_modules/needle/test/tls_options_spec.js
generated
vendored
Normal file
57
node_modules/needle/test/tls_options_spec.js
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
var needle = require('..'),
|
||||
https = require('https'),
|
||||
helpers = require('./helpers'),
|
||||
should = require('should');
|
||||
|
||||
describe('tls options', function() {
|
||||
|
||||
describe('rejectUnauthorized: false', function() {
|
||||
|
||||
var url = 'https://expired-rsa-dv.ssl.com/';
|
||||
|
||||
it('is an expired cert', function(done) {
|
||||
needle.get(url, function(err, resp) {
|
||||
err.code.should.eql('CERT_HAS_EXPIRED')
|
||||
should.not.exist(resp)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('allows fetching pages under expired certificates', function(done) {
|
||||
needle.get(url, { rejectUnauthorized: false }, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
resp.statusCode.should.eql(200);
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('also works when using custom agent', function(done) {
|
||||
var agent = new https.Agent({ rejectUnauthorized: true })
|
||||
|
||||
// should overwrite value from custom agent
|
||||
needle.get(url, { rejectUnauthorized: false }, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
resp.statusCode.should.eql(200);
|
||||
done()
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
it('also works with shared/default agent', function(done) {
|
||||
var agent = new https.Agent({ rejectUnauthorized: true })
|
||||
needle.defaults({ agent: agent })
|
||||
|
||||
// should overwrite value from custom agent
|
||||
needle.get(url, { rejectUnauthorized: false }, function(err, resp) {
|
||||
should.not.exist(err);
|
||||
resp.statusCode.should.eql(200);
|
||||
|
||||
needle.defaults({ agent: null })
|
||||
done()
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
342
node_modules/needle/test/tomcat_charset.html
generated
vendored
Normal file
342
node_modules/needle/test/tomcat_charset.html
generated
vendored
Normal file
@ -0,0 +1,342 @@
|
||||
<?xml version="1.0" encoding="EUC-JP"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
|
||||
<head><script src="//archive.org/includes/analytics.js?v=cf34f82" type="text/javascript"></script>
|
||||
<script type="text/javascript">window.addEventListener('DOMContentLoaded',function(){var v=archive_analytics.values;v.service='wb';v.server_name='wwwb-app224.us.archive.org';v.server_ms=381;archive_analytics.send_pageview({});});</script>
|
||||
<script type="text/javascript" src="/_static/js/bundle-playback.js?v=poeZ53Bz" charset="utf-8"></script>
|
||||
<script type="text/javascript" src="/_static/js/wombat.js?v=UHAOicsW" charset="utf-8"></script>
|
||||
<script type="text/javascript">
|
||||
__wm.init("https://web.archive.org/web");
|
||||
__wm.wombat("http://www.nina.jp:80/server/slackware/webapp/tomcat_charset.html","20181003202907","https://web.archive.org/","web","/_static/",
|
||||
"1538598547");
|
||||
</script>
|
||||
<link rel="stylesheet" type="text/css" href="/_static/css/banner-styles.css?v=fantwOh2" />
|
||||
<link rel="stylesheet" type="text/css" href="/_static/css/iconochive.css?v=qtvMKcIJ" />
|
||||
<!-- End Wayback Rewrite JS Include -->
|
||||
|
||||
<meta http-equiv="content-type" content="text/html"/>
|
||||
<meta http-equiv="content-style-type" content="text/css"/>
|
||||
<title>Tomcat<EFBFBD><EFBFBD>UTF-8/EUC<55><43><EFBFBD>Ȥ<EFBFBD></title>
|
||||
<link rel="stylesheet" type="text/css" href="/web/20181003202907cs_/http://www.nina.jp/html.css"/>
|
||||
<link rel="shortcut icon" href="https://web.archive.org/web/20181003202907im_/http://www.nina.jp/img/nina.ico"/>
|
||||
</head>
|
||||
<body><!-- BEGIN WAYBACK TOOLBAR INSERT -->
|
||||
<style type="text/css">
|
||||
body {
|
||||
margin-top:0 !important;
|
||||
padding-top:0 !important;
|
||||
/*min-width:800px !important;*/
|
||||
}
|
||||
</style>
|
||||
<script>__wm.rw(0);</script>
|
||||
<div id="wm-ipp-base" lang="en" style="display:none;direction:ltr;">
|
||||
<div id="wm-ipp" style="position:fixed;left:0;top:0;right:0;">
|
||||
<div id="donato" style="position:relative;width:100%;">
|
||||
<div id="donato-base">
|
||||
<iframe id="donato-if" src="https://archive.org/includes/donate.php?as_page=1&platform=wb&referer=https%3A//web.archive.org/web/20181003202907/http%3A//www.nina.jp/server/slackware/webapp/tomcat_charset.html"
|
||||
scrolling="no" frameborder="0" style="width:100%; height:100%">
|
||||
</iframe>
|
||||
</div>
|
||||
</div><div id="wm-ipp-inside">
|
||||
<div id="wm-toolbar" style="position:relative;display:flex;flex-flow:row nowrap;justify-content:space-between;">
|
||||
<div id="wm-logo" style="/*width:110px;*/padding-top:12px;">
|
||||
<a href="/web/" title="Wayback Machine home page"><img src="/_static/images/toolbar/wayback-toolbar-logo-200.png" srcset="/_static/images/toolbar/wayback-toolbar-logo-100.png, /_static/images/toolbar/wayback-toolbar-logo-150.png 1.5x, /_static/images/toolbar/wayback-toolbar-logo-200.png 2x" alt="Wayback Machine" style="width:100px" border="0" /></a>
|
||||
</div>
|
||||
<div class="c" style="display:flex;flex-flow:column nowrap;justify-content:space-between;flex:1;">
|
||||
<form class="u" style="display:flex;flex-direction:row;flex-wrap:nowrap;" target="_top" method="get" action="/web/submit" name="wmtb" id="wmtb"><input type="text" name="url" id="wmtbURL" value="http://www.nina.jp/server/slackware/webapp/tomcat_charset.html" onfocus="this.focus();this.select();" style="flex:1;"/><input type="hidden" name="type" value="replay" /><input type="hidden" name="date" value="20181003202907" /><input type="submit" value="Go" />
|
||||
</form>
|
||||
<div style="display:flex;flex-flow:row nowrap;align-items:flex-end;">
|
||||
<div class="s" id="wm-nav-captures">
|
||||
<a class="t" href="/web/20181003202907*/http://www.nina.jp/server/slackware/webapp/tomcat_charset.html" title="See a list of every capture for this URL">5 captures</a>
|
||||
<div class="r" title="Timespan for captures of this URL">10 Jan 2012 - 03 Oct 2018</div>
|
||||
</div>
|
||||
<div class="k" style="flex:1;">
|
||||
<a href="" id="wm-graph-anchor">
|
||||
<div id="wm-ipp-sparkline" title="Explore captures for this URL" style="position: relative">
|
||||
<canvas id="wm-sparkline-canvas" width="675" height="27" border="0"></canvas>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="n">
|
||||
<table>
|
||||
<tbody>
|
||||
<!-- NEXT/PREV MONTH NAV AND MONTH INDICATOR -->
|
||||
<tr class="m">
|
||||
<td class="b" nowrap="nowrap"><a href="https://web.archive.org/web/20160912162501/http://www.nina.jp:80/server/slackware/webapp/tomcat_charset.html" title="12 Sep 2016"><strong>Sep</strong></a></td>
|
||||
<td class="c" id="displayMonthEl" title="You are here: 20:29:07 Oct 03, 2018">OCT</td>
|
||||
<td class="f" nowrap="nowrap">Nov</td>
|
||||
</tr>
|
||||
<!-- NEXT/PREV CAPTURE NAV AND DAY OF MONTH INDICATOR -->
|
||||
<tr class="d">
|
||||
<td class="b" nowrap="nowrap"><a href="https://web.archive.org/web/20160912162501/http://www.nina.jp:80/server/slackware/webapp/tomcat_charset.html" title="16:25:01 Sep 12, 2016"><img src="/_static/images/toolbar/wm_tb_prv_on.png" alt="Previous capture" width="14" height="16" border="0" /></a></td>
|
||||
<td class="c" id="displayDayEl" style="width:34px;font-size:22px;white-space:nowrap;" title="You are here: 20:29:07 Oct 03, 2018">03</td>
|
||||
<td class="f" nowrap="nowrap"><img src="/_static/images/toolbar/wm_tb_nxt_off.png" alt="Next capture" width="14" height="16" border="0" /></td>
|
||||
</tr>
|
||||
<!-- NEXT/PREV YEAR NAV AND YEAR INDICATOR -->
|
||||
<tr class="y">
|
||||
<td class="b" nowrap="nowrap"><a href="https://web.archive.org/web/20160912162501/http://www.nina.jp:80/server/slackware/webapp/tomcat_charset.html" title="12 Sep 2016"><strong>2016</strong></a></td>
|
||||
<td class="c" id="displayYearEl" title="You are here: 20:29:07 Oct 03, 2018">2018</td>
|
||||
<td class="f" nowrap="nowrap">2019</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="r" style="display:flex;flex-flow:column nowrap;align-items:flex-end;justify-content:space-between;">
|
||||
<div id="wm-btns" style="text-align:right;height:23px;">
|
||||
<span class="xxs">
|
||||
<div id="wm-save-snapshot-success">success</div>
|
||||
<div id="wm-save-snapshot-fail">fail</div>
|
||||
<a id="wm-save-snapshot-open" href="#"
|
||||
title="Share via My Web Archive" >
|
||||
<span class="iconochive-web"></span>
|
||||
</a>
|
||||
<a href="https://archive.org/account/login.php" title="Sign In" id="wm-sign-in">
|
||||
<span class="iconochive-person"></span>
|
||||
</a>
|
||||
<span id="wm-save-snapshot-in-progress" class="iconochive-web"></span>
|
||||
</span>
|
||||
<a class="xxs" href="http://faq.web.archive.org/" title="Get some help using the Wayback Machine" style="top:-6px;"><span class="iconochive-question" style="color:rgb(87,186,244);font-size:160%;"></span></a>
|
||||
<a id="wm-tb-close" href="#close" style="top:-2px;" title="Close the toolbar"><span class="iconochive-remove-circle" style="color:#888888;font-size:240%;"></span></a>
|
||||
</div>
|
||||
<div id="wm-share" class="xxs">
|
||||
<a href="/web/20181003202907/http://web.archive.org/screenshot/http://www.nina.jp/server/slackware/webapp/tomcat_charset.html"
|
||||
id="wm-screenshot"
|
||||
title="screenshot">
|
||||
<span class="wm-icon-screen-shot"></span>
|
||||
</a>
|
||||
<a href="#" id="wm-video" title="video">
|
||||
<span class="iconochive-movies"></span>
|
||||
</a>
|
||||
<a id="wm-share-facebook" href="#" data-url="https://web.archive.org/web/20181003202907/http://www.nina.jp:80/server/slackware/webapp/tomcat_charset.html" title="Share on Facebook" style="margin-right:5px;" target="_blank"><span class="iconochive-facebook" style="color:#3b5998;font-size:160%;"></span></a>
|
||||
<a id="wm-share-twitter" href="#" data-url="https://web.archive.org/web/20181003202907/http://www.nina.jp:80/server/slackware/webapp/tomcat_charset.html" title="Share on Twitter" style="margin-right:5px;" target="_blank"><span class="iconochive-twitter" style="color:#1dcaff;font-size:160%;"></span></a>
|
||||
</div>
|
||||
<div style="padding-right:2px;text-align:right;white-space:nowrap;">
|
||||
<a id="wm-expand" class="wm-btn wm-closed" href="#expand" onclick="__wm.ex(event);return false;"><span id="wm-expand-icon" class="iconochive-down-solid"></span> <span class="xxs" style="font-size:80%;">About this capture</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="wm-capinfo" style="border-top:1px solid #777;display:none; overflow: hidden">
|
||||
<div id="wm-capinfo-collected-by">
|
||||
<div style="background-color:#666;color:#fff;font-weight:bold;text-align:center">COLLECTED BY</div>
|
||||
<div style="padding:3px;position:relative" id="wm-collected-by-content">
|
||||
<div style="display:inline-block;vertical-align:top;width:50%;">
|
||||
<span class="c-logo" style="background-image:url(https://archive.org/services/img/alexacrawls);"></span>
|
||||
Organization: <a style="color:#33f;" href="https://archive.org/details/alexacrawls" target="_new"><span class="wm-title">Alexa Crawls</span></a>
|
||||
<div style="max-height:75px;overflow:hidden;position:relative;">
|
||||
<div style="position:absolute;top:0;left:0;width:100%;height:75px;background:linear-gradient(to bottom,rgba(255,255,255,0) 0%,rgba(255,255,255,0) 90%,rgba(255,255,255,255) 100%);"></div>
|
||||
Starting in 1996, <a href="http://www.alexa.com/">Alexa Internet</a> has been donating their crawl data to the Internet Archive. Flowing in every day, these data are added to the <a href="http://web.archive.org/">Wayback Machine</a> after an embargo period.
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:inline-block;vertical-align:top;width:49%;">
|
||||
<span class="c-logo" style="background-image:url(https://archive.org/services/img/alexacrawls)"></span>
|
||||
<div>Collection: <a style="color:#33f;" href="https://archive.org/details/alexacrawls" target="_new"><span class="wm-title">Alexa Crawls</span></a></div>
|
||||
<div style="max-height:75px;overflow:hidden;position:relative;">
|
||||
<div style="position:absolute;top:0;left:0;width:100%;height:75px;background:linear-gradient(to bottom,rgba(255,255,255,0) 0%,rgba(255,255,255,0) 90%,rgba(255,255,255,255) 100%);"></div>
|
||||
Starting in 1996, <a href="http://www.alexa.com/">Alexa Internet</a> has been donating their crawl data to the Internet Archive. Flowing in every day, these data are added to the <a href="http://web.archive.org/">Wayback Machine</a> after an embargo period.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="wm-capinfo-timestamps">
|
||||
<div style="background-color:#666;color:#fff;font-weight:bold;text-align:center" title="Timestamps for the elements of this page">TIMESTAMPS</div>
|
||||
<div>
|
||||
<div id="wm-capresources" style="margin:0 5px 5px 5px;max-height:250px;overflow-y:scroll !important"></div>
|
||||
<div id="wm-capresources-loading" style="text-align:left;margin:0 20px 5px 5px;display:none"><img src="/_static/images/loading.gif" alt="loading" /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div></div></div></div><div id="wm-ipp-print">The Wayback Machine - https://web.archive.org/web/20181003202907/http://www.nina.jp:80/server/slackware/webapp/tomcat_charset.html</div>
|
||||
<script type="text/javascript">
|
||||
__wm.bt(675,27,25,2,"web","http://www.nina.jp/server/slackware/webapp/tomcat_charset.html","20181003202907",1996,"/_static/",["/_static/css/banner-styles.css?v=fantwOh2","/_static/css/iconochive.css?v=qtvMKcIJ"], false);
|
||||
__wm.rw(1);
|
||||
</script>
|
||||
<!-- END WAYBACK TOOLBAR INSERT -->
|
||||
<p class="dig1"><span class="title1">Tomcat<EFBFBD><EFBFBD>UTF-8/EUC-JP<4A><50><EFBFBD>Ȥ<EFBFBD></span></p>
|
||||
<p class="dig1">
|
||||
[<a href="/web/20181003202907/http://www.nina.jp/server/index-slackware.html"><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Фμ¸<EFBFBD><EFBFBD><EFBFBD> Slackware</a>]
|
||||
</p>
|
||||
<p class="right">
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> : 2004/12/31
|
||||
</p>
|
||||
<form action="/web/20181003202907/http://www.nina.jp/namazu/namazu.cgi" method="get">
|
||||
<p class="right">
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD>Фμ¸<CEBC><C2B8><EFBFBD>"<22>θ<EFBFBD><CEB8><EFBFBD>
|
||||
<input type="text" name="query" size="25" value=""/>
|
||||
<input type="submit" value="<22><><EFBFBD><EFBFBD>"/>
|
||||
<input type="reset" value="<22><><EFBFBD>ꥢ"/>
|
||||
</p>
|
||||
</form>
|
||||
<hr/>
|
||||
|
||||
<p class="dig2">
|
||||
Tomcat<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֤<EFBFBD><EFBFBD><EFBFBD><EFBFBD>륭<EFBFBD><EFBFBD><EFBFBD>饯<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>åȤξ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϡ<EFBFBD><span class="bold">httpd.conf</span><EFBFBD>Υ롼<EFBFBD>Ȥǻ<EFBFBD><EFBFBD>ꤷ<EFBFBD><EFBFBD>AddDefaultCharset<EFBFBD><EFBFBD><EFBFBD>ͤ<EFBFBD>Ʊ<EFBFBD><EFBFBD><EFBFBD>ˤʤ<EFBFBD><EFBFBD>餷<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
Directory<EFBFBD>ǥ<EFBFBD><EFBFBD>쥯<EFBFBD>ƥ<EFBFBD><EFBFBD>֤<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǻ<EFBFBD><EFBFBD>ꤷ<EFBFBD><EFBFBD>AddDefaultCharset<EFBFBD><EFBFBD>̵<EFBFBD>뤵<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>äݤ<EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD>Ĥ<EFBFBD><EFBFBD>Ǥˡ<EFBFBD>meta<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̵<EFBFBD>뤵<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߤ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<span class="blue"><EFBFBD><EFBFBD><---<2D><><EFBFBD>Τؤ<D8A4><F3A1A2B8>Ҥ<EFBFBD>SetCharacterEncodingFilter<65><72><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ư<EFBFBD><EFBFBD>ʤ<EFBFBD><CAA4><EFBFBD><EFBFBD>Ȥ⤢<C8A4>ꡢ<EFBFBD><EAA1A2><EFBFBD><EFBFBD><EFBFBD>ʤ<EFBFBD>...<2E><></span>
|
||||
</p>
|
||||
|
||||
<p class="dig2">
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>WEB<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Фϥ롼<EFBFBD>Ȥ<EFBFBD>AddDefaultCharset<EFBFBD><EFBFBD>EUC-JP<4A><50><EFBFBD><EFBFBD><EFBFBD>Ƥ<F2A4B7A4><C6A4>ꡢ<EFBFBD><EAA1A2><EFBFBD><EFBFBD><EFBFBD>ƥ<EFBFBD><C6A5><EFBFBD><EFBFBD>ȥѥ<C8A5><D1A5>ʲ<EFBFBD><CAB2><EFBFBD>UTF-8<>ˤ<EFBFBD><CBA4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Τǡ<CEA4><C7A1>ʤ<EFBFBD><CAA4>餫<EFBFBD><E9A4AB><EFBFBD>к<EFBFBD><D0BA>ʤ<F2A4B7A4><CAA4><EFBFBD>ʸ<EFBFBD><CAB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƥ<EFBFBD><C6A4>ޤ<EFBFBD><DEA4><EFBFBD>
|
||||
</p>
|
||||
|
||||
<p class="dig1"><span class="title2"><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֥<EFBFBD><EFBFBD>åȤξ<EFBFBD><EFBFBD><EFBFBD></span></p>
|
||||
<p class="dig2">
|
||||
<span class="bold">response.setContentType</span><EFBFBD>ǥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>饯<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>åȤ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ꤹ<EFBFBD>롣
|
||||
EUC-JP<4A><50><EFBFBD><EFBFBD><EFBFBD>Ѥ<EFBFBD><D1A4><EFBFBD><EFBFBD>ʤ顢response.setContentType("text/html; <span class="bold">charset=EUC-JP</span>")<29><>
|
||||
UTF-8<><38><EFBFBD><EFBFBD><EFBFBD>Ѥ<EFBFBD><D1A4><EFBFBD><EFBFBD>ʤ顢response.setContentType("text/html; <span class="bold">charset=UTF-8</span>")<29><>
|
||||
</p>
|
||||
<pre class="dig3 text">
|
||||
# HelloWorld.java
|
||||
|
||||
import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.*;
|
||||
|
||||
public class HelloWorld extends HttpServlet {
|
||||
|
||||
public void doGet(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
<span class="red">response.setContentType("text/html; charset=EUC-JP");</span>
|
||||
PrintWriter out = response.getWriter();
|
||||
|
||||
out.println("<html>");
|
||||
out.println("<head>");
|
||||
out.println("<title>HelloWorld</title>");
|
||||
out.println("</head>");
|
||||
out.println("<body>");
|
||||
out.println("<p>");
|
||||
out.println("<22><><EFBFBD><EFBFBD><EFBFBD>ˤ<EFBFBD><CBA4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
|
||||
out.println("</p>");
|
||||
out.println("</body>");
|
||||
out.println("</html>");
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
<p class="dig2">
|
||||
JAVA<EFBFBD><EFBFBD>UTF-8<>ǽ<EFBFBD><C7BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԥ<EFBFBD><D4A4>Τǡ<CEA4><C7A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʳ<EFBFBD><CAB3><EFBFBD>EUC-JP<4A>ʤɤ<CAA4><C9A4><EFBFBD><EFBFBD>Ѥ<EFBFBD><D1A4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϡ<EFBFBD><CFA1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѥ<EFBFBD><D1A5>뤹<EFBFBD><EBA4B9><EFBFBD>Ȥ<EFBFBD><C8A4><EFBFBD><span class="bold">-encoding</span><EFBFBD><EFBFBD><EFBFBD>Ĥ<EFBFBD><EFBFBD>뤳<EFBFBD>ȡ<EFBFBD>
|
||||
</p>
|
||||
<pre class="dig3 shell">
|
||||
# <span class="bold">javac <span class="red">-encoding EUC-JP</span> -classpath .:$CATALINA_HOME/common/lib/servlet-api.jar HelloWorld.java</span>
|
||||
</pre>
|
||||
|
||||
<p class="dig1"><span class="title2">JSP<EFBFBD>ξ<EFBFBD><EFBFBD><EFBFBD></span></p>
|
||||
<p class="dig2">
|
||||
<EFBFBD>ǥ<EFBFBD><EFBFBD>쥯<EFBFBD>ƥ<EFBFBD><EFBFBD>֤ǥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>饯<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>åȤ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ꤹ<EFBFBD>롣
|
||||
EUC-JP<4A><50><EFBFBD><EFBFBD><EFBFBD>Ѥ<EFBFBD><D1A4><EFBFBD><EFBFBD>ʤ顢<%@ page contentType="text/html; <span class="bold">charset=EUC-JP</span>" %><EFBFBD><EFBFBD>
|
||||
UTF-8<><38><EFBFBD><EFBFBD><EFBFBD>Ѥ<EFBFBD><D1A4><EFBFBD><EFBFBD>ʤ顢<%@ page contentType="text/html; <span class="bold">charset=UTF-8</span>" %><EFBFBD><EFBFBD>
|
||||
</p>
|
||||
<pre class="dig3 text">
|
||||
# hello.jsp
|
||||
|
||||
<span class="red"><%@ page contentType="text/html; charset=EUC-JP" %></span>
|
||||
<html>
|
||||
<head>
|
||||
<title>HelloWorld</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
<%
|
||||
out.println("<22><><EFBFBD><EFBFBD><EFBFBD>ˤ<EFBFBD><CBA4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
|
||||
%>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</pre>
|
||||
|
||||
<p class="dig1"><span class="title2"><EFBFBD><EFBFBD>Ū<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƥ<EFBFBD><EFBFBD>ġ<EFBFBD>HTML<EFBFBD>ˤξ<EFBFBD><EFBFBD><EFBFBD></span></p>
|
||||
<p class="dig2">
|
||||
<span class="bold">workers2.propeties</span><EFBFBD>ե<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȥѥ<EFBFBD><EFBFBD>ʲ<EFBFBD><EFBFBD>Τ<EFBFBD><EFBFBD>٤ƤΥե<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Tomcat<EFBFBD><EFBFBD><EFBFBD>Ϥ<EFBFBD><EFBFBD>褦<EFBFBD><EFBFBD><EFBFBD>ꤷ<EFBFBD>Ƥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>硢<EFBFBD><EFBFBD>Ū<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƥ<EFBFBD><EFBFBD>ĤˤĤ<EFBFBD><EFBFBD>Ƥ⤳<EFBFBD>Υڡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD>˽<EFBFBD><EFBFBD>褦<EFBFBD>ʥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>饯<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>åȾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֤<EFBFBD><EFBFBD><EFBFBD><EFBFBD>롣
|
||||
HTML<EFBFBD><EFBFBD>meta<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>charset<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ꤷ<EFBFBD>Ƥ<EFBFBD>̵<EFBFBD>뤵<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Τǡ<EFBFBD><EFBFBD>ɥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȥ롼<EFBFBD>Ȥȥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȥѥ<EFBFBD><EFBFBD>ǰۤʤ륭<EFBFBD><EFBFBD><EFBFBD>饯<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>åȤ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ѥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>դ<EFBFBD>ɬ<EFBFBD>ס<EFBFBD>
|
||||
</p>
|
||||
<pre class="dig3 text">
|
||||
# workers2.properties
|
||||
|
||||
[uri:/hoge/*] <span class="blue"><---<2D><><EFBFBD>٤ƤΥե<CEA5><D5A5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Tomcat<61>˽<EFBFBD><CBBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></span>
|
||||
</pre>
|
||||
<p class="dig2">
|
||||
<EFBFBD>̾<EFBFBD><EFBFBD><EFBFBD><span class="bold">SetCharacterEncodingFilter</span><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ѥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Τ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʤΤ褦<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɤ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>äƤ<EFBFBD>charset<EFBFBD><EFBFBD><EFBFBD>֤<EFBFBD><EFBFBD>Ƥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʤ<EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʤ<EFBFBD><EFBFBD>Τǡ<EFBFBD><span class="bold">web.xml</span><EFBFBD><EFBFBD><span class="bold"><mime-mapping></span><EFBFBD><EFBFBD>charset<EFBFBD>ȳ<EFBFBD>ĥ<EFBFBD>Ҥδ<EFBFBD>Ϣ<EFBFBD>դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ꤷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
</p>
|
||||
<pre class="dig3 text">
|
||||
<!--<2D>ʥ<EFBFBD><CAA5><EFBFBD><EFBFBD>ƥ<EFBFBD><C6A5><EFBFBD><EFBFBD>ȥѥ<C8A5><D1A5><EFBFBD>/WEB-INF/web.xml-->
|
||||
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE web-app
|
||||
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
|
||||
"http://java.sun.com/dtd/web-app_2_3.dtd">
|
||||
<web-app>
|
||||
<span class="red"> <mime-mapping>
|
||||
<extension>html</extension>
|
||||
<mime-type>text/html; charset=UTF-8</mime-type>
|
||||
</mime-mapping></span>
|
||||
</web-app>
|
||||
</pre>
|
||||
<p class="dig2">
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><span class="bold">SetCharacterEncodingFilter</span><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ѥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ˡ<EFBFBD><EFBFBD><EFBFBD>Ƥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD>$CATALINA_HOME/webapps/jsp-examples/WEB-INF/classes/filters<72>ǥ<EFBFBD><C7A5>쥯<EFBFBD>ȥ<EFBFBD><C8A5>ˤ<EFBFBD><CBA4><EFBFBD><span class="bold">SetCharacterEncodingFilter.java</span><EFBFBD><EFBFBD><EFBFBD>ѥ<EFBFBD><EFBFBD>뤷<EFBFBD>ơ<EFBFBD>
|
||||
</p>
|
||||
<pre class="dig3 shell">
|
||||
# <span class="bold">cd $CATALINA_HOME/webapps/jsp-examples/WEB-INF/classes</span>
|
||||
# <span class="bold">javac -classpath .:$CATALINA_HOME/common/lib/servlet-api.jar filters.SetCharacterEncodingFilter.java</span>
|
||||
</pre>
|
||||
<p class="dig2">
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>줿<EFBFBD><EFBFBD><EFBFBD>饹<EFBFBD>ե<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><span class="bold"><EFBFBD>ʥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȥѥ<EFBFBD><EFBFBD><EFBFBD>/WEB-INF/classes/filters</span><EFBFBD>ǥ<EFBFBD><EFBFBD>쥯<EFBFBD>ȥ<EFBFBD><EFBFBD>˥<EFBFBD><EFBFBD>ԡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ơ<EFBFBD><span class="bold"><EFBFBD>ʥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȥѥ<EFBFBD><EFBFBD><EFBFBD>/WEB-INF/web.xml</span><EFBFBD>˥ե<EFBFBD><EFBFBD>륿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>餷<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
</p>
|
||||
<pre class="dig3 text">
|
||||
<!--<2D>ʥ<EFBFBD><CAA5><EFBFBD><EFBFBD>ƥ<EFBFBD><C6A5><EFBFBD><EFBFBD>ȥѥ<C8A5><D1A5><EFBFBD>/WEB-INF/web.xml-->
|
||||
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE web-app
|
||||
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
|
||||
"http://java.sun.com/dtd/web-app_2_3.dtd">
|
||||
<web-app>
|
||||
<span class="red"><filter>
|
||||
<filter-name>Set Character Encoding</filter-name>
|
||||
<filter-class>filters.SetCharacterEncodingFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>encoding</param-name>
|
||||
<param-value>UTF-8</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
<filter-mapping>
|
||||
<filter-name>Set Character Encoding</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping></span>
|
||||
</web-app>
|
||||
</pre>
|
||||
<p class="dig2">
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>...
|
||||
</p>
|
||||
|
||||
<hr/>
|
||||
<p class="dig1">
|
||||
[<a href="/web/20181003202907/http://www.nina.jp/server/index-slackware.html"><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Фμ¸<EFBFBD><EFBFBD><EFBFBD> Slackware</a>]
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<!--
|
||||
FILE ARCHIVED ON 20:29:07 Oct 03, 2018 AND RETRIEVED FROM THE
|
||||
INTERNET ARCHIVE ON 23:27:21 Mar 21, 2022.
|
||||
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
|
||||
|
||||
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
|
||||
SECTION 108(a)(3)).
|
||||
-->
|
||||
<!--
|
||||
playback timings (ms):
|
||||
captures_list: 133.209
|
||||
exclusion.robots: 0.289
|
||||
exclusion.robots.policy: 0.278
|
||||
RedisCDXSource: 6.152
|
||||
esindex: 0.009
|
||||
LoadShardBlock: 108.809 (3)
|
||||
PetaboxLoader3.datanode: 290.581 (4)
|
||||
CDXLines.iter: 15.789 (3)
|
||||
load_resource: 242.738
|
||||
PetaboxLoader3.resolve: 57.13
|
||||
-->
|
46
node_modules/needle/test/uri_modifier_spec.js
generated
vendored
Normal file
46
node_modules/needle/test/uri_modifier_spec.js
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
var needle = require('../'),
|
||||
sinon = require('sinon'),
|
||||
should = require('should'),
|
||||
http = require('http'),
|
||||
helpers = require('./helpers');
|
||||
|
||||
var port = 3456;
|
||||
|
||||
describe('uri_modifier config parameter function', function() {
|
||||
|
||||
var server, uri;
|
||||
|
||||
function send_request(mw, cb) {
|
||||
needle.get(uri, { uri_modifier: mw }, cb);
|
||||
}
|
||||
|
||||
before(function(done){
|
||||
server = helpers.server({ port: port }, done);
|
||||
})
|
||||
|
||||
after(function(done) {
|
||||
server.close(done);
|
||||
})
|
||||
|
||||
describe('modifies uri', function() {
|
||||
|
||||
var path = '/foo/replace';
|
||||
|
||||
before(function() {
|
||||
uri = 'localhost:' + port + path
|
||||
});
|
||||
|
||||
it('should modify path', function(done) {
|
||||
send_request(function(uri) {
|
||||
return uri.replace('/replace', '');
|
||||
}, function(err, res) {
|
||||
should.not.exist(err);
|
||||
should(res.req.path).be.exactly('/foo');
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
})
|
155
node_modules/needle/test/url_spec.js
generated
vendored
Normal file
155
node_modules/needle/test/url_spec.js
generated
vendored
Normal file
@ -0,0 +1,155 @@
|
||||
var needle = require('../'),
|
||||
sinon = require('sinon'),
|
||||
should = require('should'),
|
||||
http = require('http'),
|
||||
helpers = require('./helpers');
|
||||
|
||||
var port = 3456;
|
||||
|
||||
describe('urls', function() {
|
||||
|
||||
var server, url;
|
||||
|
||||
function send_request(cb) {
|
||||
return needle.get(url, cb);
|
||||
}
|
||||
|
||||
before(function(done){
|
||||
server = helpers.server({ port: port }, done);
|
||||
})
|
||||
|
||||
after(function(done) {
|
||||
server.close(done);
|
||||
})
|
||||
|
||||
describe('null URL', function(){
|
||||
|
||||
it('throws', function(){
|
||||
(function() {
|
||||
send_request()
|
||||
}).should.throw();
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('invalid protocol', function(){
|
||||
|
||||
before(function() {
|
||||
url = 'foo://google.com/what'
|
||||
})
|
||||
|
||||
it('does not throw', function(done) {
|
||||
(function() {
|
||||
send_request(function(err) {
|
||||
done();
|
||||
})
|
||||
}).should.not.throw()
|
||||
})
|
||||
|
||||
it('returns an error', function(done) {
|
||||
send_request(function(err) {
|
||||
err.should.be.an.Error;
|
||||
err.code.should.match(/ENOTFOUND|EADDRINFO|EAI_AGAIN/)
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('invalid host', function(){
|
||||
|
||||
before(function() {
|
||||
url = 'http://s1\\\u0002.com/'
|
||||
})
|
||||
|
||||
it('fails', function(done) {
|
||||
(function() {
|
||||
send_request(function(){ })
|
||||
}.should.throw(TypeError))
|
||||
done()
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
/*
|
||||
describe('invalid path', function(){
|
||||
|
||||
before(function() {
|
||||
url = 'http://www.google.com\\\/x\\\ %^&*() /x2.com/'
|
||||
})
|
||||
|
||||
it('fails', function(done) {
|
||||
send_request(function(err) {
|
||||
err.should.be.an.Error;
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
*/
|
||||
|
||||
describe('valid protocol and path', function() {
|
||||
|
||||
before(function() {
|
||||
url = 'http://localhost:' + port + '/foo';
|
||||
})
|
||||
|
||||
it('works', function(done) {
|
||||
send_request(function(err){
|
||||
should.not.exist(err);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('no protocol but with slashes and valid path', function() {
|
||||
|
||||
before(function() {
|
||||
url = '//localhost:' + port + '/foo';
|
||||
})
|
||||
|
||||
it('works', function(done) {
|
||||
send_request(function(err){
|
||||
should.not.exist(err);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('no protocol nor slashes and valid path', function() {
|
||||
|
||||
before(function() {
|
||||
url = 'localhost:' + port + '/foo';
|
||||
})
|
||||
|
||||
it('works', function(done) {
|
||||
send_request(function(err){
|
||||
should.not.exist(err);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('double encoding', function() {
|
||||
|
||||
var path = '/foo?email=' + encodeURIComponent('what-ever@Example.Com');
|
||||
|
||||
before(function() {
|
||||
url = 'localhost:' + port + path
|
||||
});
|
||||
|
||||
it('should not occur', function(done) {
|
||||
send_request(function(err, res) {
|
||||
should.not.exist(err);
|
||||
should(res.req.path).be.exactly(path);
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
})
|
17
node_modules/needle/test/utils/formidable.js
generated
vendored
Normal file
17
node_modules/needle/test/utils/formidable.js
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
var formidable = require('formidable'),
|
||||
http = require('http'),
|
||||
util = require('util');
|
||||
|
||||
var port = process.argv[2] || 8888;
|
||||
|
||||
http.createServer(function(req, res) {
|
||||
var form = new formidable.IncomingForm();
|
||||
form.parse(req, function(err, fields, files) {
|
||||
res.writeHead(200, {'content-type': 'text/plain'});
|
||||
res.write('received upload:\n\n');
|
||||
console.log(util.inspect({fields: fields, files: files}))
|
||||
res.end(util.inspect({fields: fields, files: files}));
|
||||
});
|
||||
}).listen(port);
|
||||
|
||||
console.log('HTTP server listening on port ' + port);
|
62
node_modules/needle/test/utils/proxy.js
generated
vendored
Normal file
62
node_modules/needle/test/utils/proxy.js
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
var http = require('http'),
|
||||
https = require('https'),
|
||||
url = require('url');
|
||||
|
||||
var port = 1234,
|
||||
log = true,
|
||||
request_auth = false;
|
||||
|
||||
http.createServer(function(request, response) {
|
||||
|
||||
console.log(request.headers);
|
||||
console.log("Got request: " + request.url);
|
||||
console.log("Forwarding request to " + request.headers['host']);
|
||||
|
||||
if (request_auth) {
|
||||
if (!request.headers['proxy-authorization']) {
|
||||
response.writeHead(407, {'Proxy-Authenticate': 'Basic realm="proxy.com"'})
|
||||
return response.end('Hello.');
|
||||
}
|
||||
}
|
||||
|
||||
var remote = url.parse(request.url);
|
||||
var protocol = remote.protocol == 'https:' ? https : http;
|
||||
|
||||
var opts = {
|
||||
host: request.headers['host'],
|
||||
port: remote.port || (remote.protocol == 'https:' ? 443 : 80),
|
||||
method: request.method,
|
||||
path: remote.pathname,
|
||||
headers: request.headers
|
||||
}
|
||||
|
||||
var proxy_request = protocol.request(opts, function(proxy_response){
|
||||
|
||||
proxy_response.on('data', function(chunk) {
|
||||
if (log) console.log(chunk.toString());
|
||||
response.write(chunk, 'binary');
|
||||
});
|
||||
proxy_response.on('end', function() {
|
||||
response.end();
|
||||
});
|
||||
|
||||
response.writeHead(proxy_response.statusCode, proxy_response.headers);
|
||||
});
|
||||
|
||||
request.on('data', function(chunk) {
|
||||
if (log) console.log(chunk.toString());
|
||||
proxy_request.write(chunk, 'binary');
|
||||
});
|
||||
|
||||
request.on('end', function() {
|
||||
proxy_request.end();
|
||||
});
|
||||
|
||||
}).listen(port);
|
||||
|
||||
process.on('uncaughtException', function(err){
|
||||
console.log('Uncaught exception!');
|
||||
console.log(err);
|
||||
});
|
||||
|
||||
console.log("Proxy server listening on port " + port);
|
104
node_modules/needle/test/utils/test.js
generated
vendored
Normal file
104
node_modules/needle/test/utils/test.js
generated
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
// TODO: write specs. :)
|
||||
|
||||
var fs = require('fs'),
|
||||
client = require('./../../');
|
||||
|
||||
process.env.DEBUG = true;
|
||||
|
||||
var response_callback = function(err, resp, body){
|
||||
console.log(err);
|
||||
if(resp) console.log("Got status code " + resp.statusCode)
|
||||
console.log(body);
|
||||
}
|
||||
|
||||
function simple_head(){
|
||||
client.head('http://www.amazon.com', response_callback);
|
||||
}
|
||||
|
||||
function simple_get(){
|
||||
client.get('http://www.nodejs.org', response_callback);
|
||||
}
|
||||
|
||||
function proxy_get(){
|
||||
client.get('https://www.google.com/search?q=nodejs', {proxy: 'http://localhost:1234'}, response_callback);
|
||||
}
|
||||
|
||||
function auth_get(){
|
||||
client.get('https://www.twitter.com', {username: 'asd', password: '123'}, response_callback);
|
||||
}
|
||||
|
||||
function simple_post(url){
|
||||
|
||||
var data = {
|
||||
foo: 'bar',
|
||||
baz: {
|
||||
nested: 'attribute'
|
||||
}
|
||||
}
|
||||
|
||||
client.post(url, data, response_callback);
|
||||
|
||||
}
|
||||
|
||||
function multipart_post(url){
|
||||
|
||||
var filename = 'test_file.txt';
|
||||
var data = 'Plain text data.\nLorem ipsum dolor sit amet.\nBla bla bla.\n';
|
||||
fs.writeFileSync(filename, data);
|
||||
|
||||
var black_pixel = Buffer.from("data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=".replace(/^data:image\/\w+;base64,/, ""), "base64");
|
||||
|
||||
var data = {
|
||||
foo: 'bar',
|
||||
bar: 'baz',
|
||||
nested: {
|
||||
my_document: { file: filename, content_type: 'text/plain' },
|
||||
even: {
|
||||
more: 'nesting'
|
||||
}
|
||||
},
|
||||
pixel: { filename: 'black_pixel.gif', buffer: black_pixel, content_type: 'image/gif' },
|
||||
field2: {value: JSON.stringify({"json":[ {"one":1}, {"two":2} ]}), content_type: 'application/json' }
|
||||
}
|
||||
|
||||
client.post(url, data, {multipart: true}, function(err, resp, body){
|
||||
|
||||
console.log(err);
|
||||
console.log("Got status code " + resp.statusCode)
|
||||
console.log(body);
|
||||
fs.unlink(filename);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
switch(process.argv[2]){
|
||||
case 'head':
|
||||
simple_head();
|
||||
break;
|
||||
case 'get':
|
||||
simple_get();
|
||||
break;
|
||||
case 'auth':
|
||||
auth_get();
|
||||
break;
|
||||
case 'proxy':
|
||||
proxy_get();
|
||||
break;
|
||||
case 'post':
|
||||
simple_post(process.argv[3] || 'http://posttestserver.com/post.php');
|
||||
break;
|
||||
case 'multipart':
|
||||
multipart_post(process.argv[3] || 'http://posttestserver.com/post.php?dir=example');
|
||||
break;
|
||||
case 'all':
|
||||
simple_head();
|
||||
simple_get();
|
||||
auth_get();
|
||||
proxy_get();
|
||||
simple_post(process.argv[3] || 'http://posttestserver.com/post.php');
|
||||
multipart_post(process.argv[3] || 'http://posttestserver.com/post.php?dir=example');
|
||||
break;
|
||||
default:
|
||||
console.log("Usage: ./test.js [head|get|auth|proxy|multipart]")
|
||||
}
|
105
node_modules/needle/test/utils_spec.js
generated
vendored
Normal file
105
node_modules/needle/test/utils_spec.js
generated
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
var helpers = require('./helpers'),
|
||||
should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
utils = require('./../lib/utils');
|
||||
|
||||
describe('utils.should_proxy_to()', function() {
|
||||
|
||||
var should_proxy_to = utils.should_proxy_to;
|
||||
|
||||
var noProxy = ".ic1.mycorp,localhost,127.0.0.1,*.mycorp.org";
|
||||
var noProxyWithPorts = " ,.mycorp.org:1234,.ic1.mycorp,localhost,127.0.0.1";
|
||||
|
||||
var uris = {
|
||||
hostname: "http://registry.random.opr.mycorp.org",
|
||||
with_port: "http://registry.random.opr.mycorp.org:9874",
|
||||
with_another_port: "http://registry.random.opr.mycorp.org:1234",
|
||||
localhost: "http://localhost",
|
||||
ip: "http://127.0.0.1"
|
||||
}
|
||||
|
||||
it("returns true if NO_PROXY is undefined", function(done) {
|
||||
process.env.NO_PROXY = undefined;
|
||||
should_proxy_to(uris.hostname).should.true()
|
||||
delete process.env.NO_PROXY;
|
||||
done();
|
||||
});
|
||||
|
||||
it("returns true if NO_PROXY is empty", function(done) {
|
||||
process.env.NO_PROXY = "";
|
||||
should_proxy_to(uris.hostname).should.true()
|
||||
delete process.env.NO_PROXY;
|
||||
done();
|
||||
});
|
||||
|
||||
it("returns false if NO_PROXY is a wildcard", function(done) {
|
||||
process.env.NO_PROXY = "*";
|
||||
should_proxy_to(uris.hostname).should.false()
|
||||
delete process.env.NO_PROXY;
|
||||
done();
|
||||
});
|
||||
|
||||
it("returns true if the host matches and the ports don't (URI doesn't have port specified)", function(done) {
|
||||
process.env.NO_PROXY = noProxyWithPorts;
|
||||
should_proxy_to(uris.hostname).should.true()
|
||||
delete process.env.NO_PROXY;
|
||||
done();
|
||||
});
|
||||
|
||||
it("returns true if the host matches and the ports don't (both have a port specified but just different values)", function(done) {
|
||||
process.env.NO_PROXY = noProxyWithPorts;
|
||||
should_proxy_to(uris.with_port).should.true()
|
||||
delete process.env.NO_PROXY;
|
||||
done();
|
||||
});
|
||||
|
||||
it("returns false if the host matches and the ports don't (no_proxy pattern doesn't have a port)", function(done) {
|
||||
process.env.NO_PROXY = noProxy;
|
||||
should_proxy_to(uris.with_port).should.false()
|
||||
delete process.env.NO_PROXY;
|
||||
done();
|
||||
});
|
||||
|
||||
it("returns false if host matches", function(done) {
|
||||
process.env.NO_PROXY = noProxy;
|
||||
should_proxy_to(uris.hostname).should.false()
|
||||
delete process.env.NO_PROXY;
|
||||
done();
|
||||
});
|
||||
|
||||
it("returns false if the host and port matches", function(done) {
|
||||
process.env.NO_PROXY = noProxyWithPorts;
|
||||
should_proxy_to(uris.with_another_port).should.false()
|
||||
delete process.env.NO_PROXY;
|
||||
done();
|
||||
});
|
||||
|
||||
it("returns false if the host matches (localhost)", function(done) {
|
||||
process.env.NO_PROXY = noProxy;
|
||||
should_proxy_to(uris.localhost).should.false()
|
||||
delete process.env.NO_PROXY;
|
||||
done();
|
||||
});
|
||||
|
||||
it("returns false if the host matches (ip)", function(done) {
|
||||
process.env.NO_PROXY = noProxy;
|
||||
should_proxy_to(uris.ip).should.false()
|
||||
delete process.env.NO_PROXY;
|
||||
done();
|
||||
});
|
||||
|
||||
it("returns false if the host matches (ip)", function(done) {
|
||||
process.env.NO_PROXY = noProxy.replace(/,g/, " ");
|
||||
should_proxy_to(uris.ip).should.false()
|
||||
delete process.env.NO_PROXY;
|
||||
done();
|
||||
});
|
||||
|
||||
it("returns false if the host matches (ip)", function(done) {
|
||||
process.env.NO_PROXY = noProxy.replace(/,g/, " ");
|
||||
should_proxy_to(uris.ip).should.false()
|
||||
delete process.env.NO_PROXY;
|
||||
done();
|
||||
});
|
||||
|
||||
})
|
Reference in New Issue
Block a user