This commit is contained in:
2023-08-11 10:45:20 +08:00
commit 161ca982f3
31850 changed files with 2706500 additions and 0 deletions

231
node_modules/needle/test/auth_digest_spec.js generated vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

231
node_modules/needle/test/proxy_spec.js generated vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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&amp;platform=wb&amp;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>&lt;---<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("&lt;html&gt;");
out.println("&lt;head&gt;");
out.println("&lt;title&gt;HelloWorld&lt;/title&gt;");
out.println("&lt;/head&gt;");
out.println("&lt;body&gt;");
out.println("&lt;p&gt;");
out.println("<22><><EFBFBD><EFBFBD><EFBFBD>ˤ<EFBFBD><CBA4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
out.println("&lt;/p&gt;");
out.println("&lt;/body&gt;");
out.println("&lt;/html&gt;");
}
}
</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>ʤ顢&lt;%@ page contentType="text/html; <span class="bold">charset=EUC-JP</span>" %&gt;<EFBFBD><EFBFBD>
UTF-8<><38><EFBFBD><EFBFBD><EFBFBD>Ѥ<EFBFBD><D1A4><EFBFBD><EFBFBD>ʤ顢&lt;%@ page contentType="text/html; <span class="bold">charset=UTF-8</span>" %&gt;<EFBFBD><EFBFBD>
</p>
<pre class="dig3 text">
# hello.jsp
<span class="red">&lt;%@ page contentType="text/html; charset=EUC-JP" %&gt;</span>
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;HelloWorld&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p&gt;
&lt;%
out.println("<22><><EFBFBD><EFBFBD><EFBFBD>ˤ<EFBFBD><CBA4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
%&gt;
&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
</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">&lt;---<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">&lt;mime-mapping&gt;</span><EFBFBD><EFBFBD>charset<EFBFBD>ȳ<EFBFBD>ĥ<EFBFBD>Ҥδ<EFBFBD>Ϣ<EFBFBD>դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
</p>
<pre class="dig3 text">
&lt;!--<2D>ʥ<EFBFBD><CAA5><EFBFBD><EFBFBD>ƥ<EFBFBD><C6A5><EFBFBD><EFBFBD>ȥѥ<C8A5><D1A5><EFBFBD>/WEB-INF/web.xml--&gt;
&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;
&lt;!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd"&gt;
&lt;web-app&gt;
<span class="red"> &lt;mime-mapping&gt;
&lt;extension&gt;html&lt;/extension&gt;
&lt;mime-type&gt;text/html; charset=UTF-8&lt;/mime-type&gt;
&lt;/mime-mapping&gt;</span>
&lt;/web-app&gt;
</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">
&lt;!--<2D>ʥ<EFBFBD><CAA5><EFBFBD><EFBFBD>ƥ<EFBFBD><C6A5><EFBFBD><EFBFBD>ȥѥ<C8A5><D1A5><EFBFBD>/WEB-INF/web.xml--&gt;
&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;
&lt;!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd"&gt;
&lt;web-app&gt;
<span class="red">&lt;filter&gt;
&lt;filter-name&gt;Set Character Encoding&lt;/filter-name&gt;
&lt;filter-class&gt;filters.SetCharacterEncodingFilter&lt;/filter-class&gt;
&lt;init-param&gt;
&lt;param-name&gt;encoding&lt;/param-name&gt;
&lt;param-value&gt;UTF-8&lt;/param-value&gt;
&lt;/init-param&gt;
&lt;/filter&gt;
&lt;filter-mapping&gt;
&lt;filter-name&gt;Set Character Encoding&lt;/filter-name&gt;
&lt;url-pattern&gt;/*&lt;/url-pattern&gt;
&lt;/filter-mapping&gt;</span>
&lt;/web-app&gt;
</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
View 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
View 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
View 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
View 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
View 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
View 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();
});
})