UNPKG

chai-http

Version:

Extend Chai Assertion library with tests for http apis

1,676 lines (1,517 loc) 236 kB
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.chaiHttp = f()}})(function(){var define,module,exports;return (function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}return e})()({1:[function(require,module,exports){ /*! * chai-http * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com> * MIT Licensed */ /** * ## Assertions * * The Chai HTTP module provides a number of assertions * for the `expect` and `should` interfaces. */ module.exports = function (chai, _) { /*! * Module dependencies. */ var net = require('net'); var qs = require('qs'); var url = require('url'); var Cookie = require('cookiejar'); var charset = require("charset"); /*! * Aliases. */ var Assertion = chai.Assertion , i = _.inspect; /*! * Expose request builder */ chai.request = require('./request'); /*! * Content types hash. Used to * define `Assertion` properties. * * @type {Object} */ var contentTypes = { json: 'application/json' , text: 'text/plain' , html: 'text/html' }; /*! * Return a header from `Request` or `Response` object. * * @param {Request|Response} object * @param {String} Header * @returns {String|Undefined} */ function getHeader(obj, key) { if (key) key = key.toLowerCase(); if (obj.getHeader) return obj.getHeader(key); if (obj.headers) return obj.headers[key]; }; /** * ### .status (code) * * Assert that a response has a supplied status. * * ```js * expect(res).to.have.status(200); * ``` * * @param {Number} status number * @name status * @api public */ Assertion.addMethod('status', function (code) { var hasStatus = Boolean('status' in this._obj || 'statusCode' in this._obj); new Assertion(hasStatus).assert( hasStatus , "expected #{act} to have keys 'status', or 'statusCode'" , null // never negated , hasStatus // expected , this._obj // actual , false // no diff ); var status = this._obj.status || this._obj.statusCode; this.assert( status == code , 'expected #{this} to have status code #{exp} but got #{act}' , 'expected #{this} to not have status code #{act}' , code , status ); }); /** * ### .header (key[, value]) * * Assert that a `Response` or `Request` object has a header. * If a value is provided, equality to value will be asserted. * You may also pass a regular expression to check. * * __Note:__ When running in a web browser, the * [same-origin policy](https://tools.ietf.org/html/rfc6454#section-3) * only allows Chai HTTP to read * [certain headers](https://www.w3.org/TR/cors/#simple-response-header), * which can cause assertions to fail. * * ```js * expect(req).to.have.header('x-api-key'); * expect(req).to.have.header('content-type', 'text/plain'); * expect(req).to.have.header('content-type', /^text/); * ``` * * @param {String} header key (case insensitive) * @param {String|RegExp} header value (optional) * @name header * @api public */ Assertion.addMethod('header', function (key, value) { var header = getHeader(this._obj, key); if (arguments.length < 2) { this.assert( 'undefined' !== typeof header || null === header , 'expected header \'' + key + '\' to exist' , 'expected header \'' + key + '\' to not exist' ); } else if (arguments[1] instanceof RegExp) { this.assert( value.test(header) , 'expected header \'' + key + '\' to match ' + value + ' but got ' + i(header) , 'expected header \'' + key + '\' not to match ' + value + ' but got ' + i(header) , value , header ); } else { this.assert( header == value , 'expected header \'' + key + '\' to have value ' + value + ' but got ' + i(header) , 'expected header \'' + key + '\' to not have value ' + value , value , header ); } }); /** * ### .headers * * Assert that a `Response` or `Request` object has headers. * * __Note:__ When running in a web browser, the * [same-origin policy](https://tools.ietf.org/html/rfc6454#section-3) * only allows Chai HTTP to read * [certain headers](https://www.w3.org/TR/cors/#simple-response-header), * which can cause assertions to fail. * * ```js * expect(req).to.have.headers; * ``` * * @name headers * @api public */ Assertion.addProperty('headers', function () { this.assert( this._obj.headers || this._obj.getHeader , 'expected #{this} to have headers or getHeader method' , 'expected #{this} to not have headers or getHeader method' ); }); /** * ### .ip * * Assert that a string represents valid ip address. * * ```js * expect('127.0.0.1').to.be.an.ip; * expect('2001:0db8:85a3:0000:0000:8a2e:0370:7334').to.be.an.ip; * ``` * * @name ip * @api public */ Assertion.addProperty('ip', function () { this.assert( net.isIP(this._obj) , 'expected #{this} to be an ip' , 'expected #{this} to not be an ip' ); }); /** * ### .json / .text / .html * * Assert that a `Response` or `Request` object has a given content-type. * * ```js * expect(req).to.be.json; * expect(req).to.be.html; * expect(req).to.be.text; * ``` * * @name json * @name html * @name text * @api public */ function checkContentType (name) { var val = contentTypes[name]; Assertion.addProperty(name, function () { new Assertion(this._obj).to.have.headers; var ct = getHeader(this._obj, 'content-type') , ins = i(ct) === 'undefined' ? 'headers' : i(ct); this.assert( ct && ~ct.indexOf(val) , 'expected ' + ins + ' to include \'' + val + '\'' , 'expected ' + ins + ' to not include \'' + val + '\'' ); }); } Object .keys(contentTypes) .forEach(checkContentType); /** * ### .charset * * Assert that a `Response` or `Request` object has a given charset. * * ```js * expect(req).to.have.charset('utf-8'); * ``` * * @name charset * @api public */ Assertion.addMethod('charset', function (value) { value = value.toLowerCase(); var headers = this._obj.headers; var cs = charset(headers); /* * Fix charset() treating "utf8" as a special case * See https://github.com/node-modules/charset/issues/12 */ if (cs === "utf8") { cs = "utf-8"; } this.assert( cs != null && value === cs , 'expected content type to have ' + value + ' charset' , 'expected content type to not have ' + value + ' charset' ) }); /** * ### .redirect * * Assert that a `Response` object has a redirect status code. * * ```js * expect(res).to.redirect; * ``` * * @name redirect * @api public */ Assertion.addProperty('redirect', function() { var redirectCodes = [301, 302, 303, 307, 308] , status = this._obj.status , redirects = this._obj.redirects; this.assert( redirectCodes.indexOf(status) >= 0 || redirects && redirects.length , "expected redirect with 30X status code but got " + status , "expected not to redirect but got " + status + " status" ); }); /** * ### .redirectTo * * Assert that a `Response` object redirects to the supplied location. * * ```js * expect(res).to.redirectTo('http://example.com'); * ``` * * @param {String|RegExp} location url * @name redirectTo * @api public */ Assertion.addMethod('redirectTo', function(destination) { var redirects = this._obj.redirects; new Assertion(this._obj).to.redirect; if(redirects && redirects.length) { var hasRedirected; if (Object.prototype.toString.call(destination) === '[object RegExp]') { hasRedirected = redirects.some(redirect => destination.test(redirect)); } else { hasRedirected = redirects.indexOf(destination) > -1; } this.assert( hasRedirected , 'expected redirect to ' + destination + ' but got ' + redirects.join(' then ') , 'expected not to redirect to ' + destination + ' but got ' + redirects.join(' then ') ); } else { var assertion = new Assertion(this._obj); _.transferFlags(this, assertion); assertion.with.header('location', destination); } }); /** * ### .param * * Assert that a `Request` object has a query string parameter with a given * key, (optionally) equal to value * * ```js * expect(req).to.have.param('orderby'); * expect(req).to.have.param('orderby', 'date'); * expect(req).to.not.have.param('limit'); * ``` * * @param {String} parameter name * @param {String} parameter value * @name param * @api public */ Assertion.addMethod('param', function(name, value) { var assertion = new Assertion(); _.transferFlags(this, assertion); assertion._obj = qs.parse(url.parse(this._obj.url).query); assertion.property.apply(assertion, arguments); }); /** * ### .cookie * * Assert that a `Request`, `Response` or `Agent` object has a cookie header with a * given key, (optionally) equal to value * * ```js * expect(req).to.have.cookie('session_id'); * expect(req).to.have.cookie('session_id', '1234'); * expect(req).to.not.have.cookie('PHPSESSID'); * expect(res).to.have.cookie('session_id'); * expect(res).to.have.cookie('session_id', '1234'); * expect(res).to.not.have.cookie('PHPSESSID'); * expect(agent).to.have.cookie('session_id'); * expect(agent).to.have.cookie('session_id', '1234'); * expect(agent).to.not.have.cookie('PHPSESSID'); * ``` * * @param {String} parameter name * @param {String} parameter value * @name param * @api public */ Assertion.addMethod('cookie', function (key, value) { var header = getHeader(this._obj, 'set-cookie') , cookie; if (!header) { header = (getHeader(this._obj, 'cookie') || '').split(';'); } if (this._obj instanceof chai.request.agent && this._obj.jar) { cookie = this._obj.jar.getCookie(key, Cookie.CookieAccessInfo.All); } else { cookie = Cookie.CookieJar(); cookie.setCookies(header); cookie = cookie.getCookie(key, Cookie.CookieAccessInfo.All); } if (arguments.length === 2) { this.assert( cookie.value == value , 'expected cookie \'' + key + '\' to have value #{exp} but got #{act}' , 'expected cookie \'' + key + '\' to not have value #{exp}' , value , cookie.value ); } else { this.assert( 'undefined' !== typeof cookie || null === cookie , 'expected cookie \'' + key + '\' to exist' , 'expected cookie \'' + key + '\' to not exist' ); } }); }; },{"./request":3,"charset":7,"cookiejar":8,"net":2,"qs":24,"url":38}],2:[function(require,module,exports){ /*! * chai-http - request helper * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com> * MIT Licensed */ /*! * net.isIP shim for browsers */ var isIP = require('is-ip'); exports.isIP = isIP; exports.isIPv4 = isIP.v4; exports.isIPv6 = isIP.v6; },{"is-ip":18}],3:[function(require,module,exports){ /*! * chai-http - request helper * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com> * MIT Licensed */ /*! * Module dependancies */ var http = require('http') , https = require('https') , methods = require('methods') , superagent = require('superagent') , Agent = superagent.agent , Request = superagent.Request , util = require('util'); /** * ## Integration Testing * * Chai HTTP provides an interface for live integration * testing via [superagent](https://github.com/visionmedia/superagent). * To do this, you must first * construct a request to an application or url. * * Upon construction you are provided a chainable api that * allows you to specify the http VERB request (get, post, etc) * that you wish to invoke. * * #### Application / Server * * You may use a function (such as an express or connect app) * or a node.js http(s) server as the foundation for your request. * If the server is not running, chai-http will find a suitable * port to listen on for a given test. * * __Note:__ This feature is only supported on Node.js, not in web browsers. * * ```js * chai.request(app) * .get('/') * ``` * * #### URL * * You may also use a base url as the foundation of your request. * * ```js * chai.request('http://localhost:8080') * .get('/') * ``` * * #### Setting up requests * * Once a request is created with a given VERB, it can have headers, form data, * json, or even file attachments added to it, all with a simple API: * * ```js * // Send some JSON * chai.request(app) * .put('/user/me') * .set('X-API-Key', 'foobar') * .send({ password: '123', confirmPassword: '123' }) * ``` * * ```js * // Send some Form Data * chai.request(app) * .post('/user/me') * .type('form') * .send({'_method': 'put'}) * .send({'password': '123'}) * .send({'confirmPassword', '123'}) * ``` * * ```js * // Attach a file * chai.request(app) * .post('/user/avatar') * .attach('imageField', fs.readFileSync('avatar.png'), 'avatar.png') * ``` * * ```js * // Authenticate with Basic authentication * chai.request(app) * .get('/protected') * .auth('user', 'pass') * ``` * * ```js * // Chain some GET query parameters * chai.request(app) * .get('/search') * .query({name: 'foo', limit: 10}) // /search?name=foo&limit=10 * ``` * * #### Dealing with the response - traditional * * To make the request and assert on its response, the `end` method can be used: * * ```js * chai.request(app) * .put('/user/me') * .send({ password: '123', confirmPassword: '123' }) * .end(function (err, res) { * expect(err).to.be.null; * expect(res).to.have.status(200); * }); * ``` * ##### Caveat * Because the `end` function is passed a callback, assertions are run * asynchronously. Therefore, a mechanism must be used to notify the testing * framework that the callback has completed. Otherwise, the test will pass before * the assertions are checked. * * For example, in the [Mocha test framework](http://mochajs.org/), this is * accomplished using the * [`done` callback](https://mochajs.org/#asynchronous-code), which signal that the * callback has completed, and the assertions can be verified: * * ```js * it('fails, as expected', function(done) { // <= Pass in done callback * chai.request('http://localhost:8080') * .get('/') * .end(function(err, res) { * expect(res).to.have.status(123); * done(); // <= Call done to signal callback end * }); * }) ; * * it('succeeds silently!', function() { // <= No done callback * chai.request('http://localhost:8080') * .get('/') * .end(function(err, res) { * expect(res).to.have.status(123); // <= Test completes before this runs * }); * }) ; * ``` * * When `done` is passed in, Mocha will wait until the call to `done()`, or until * the [timeout](http://mochajs.org/#timeouts) expires. `done` also accepts an * error parameter when signaling completion. * * #### Dealing with the response - Promises * * If `Promise` is available, `request()` becomes a Promise capable library - * and chaining of `then`s becomes possible: * * ```js * chai.request(app) * .put('/user/me') * .send({ password: '123', confirmPassword: '123' }) * .then(function (res) { * expect(res).to.have.status(200); * }) * .catch(function (err) { * throw err; * }) * ``` * * __Note:__ Node.js version 0.10.x and some older web browsers do not have * native promise support. You can use any spec compliant library, such as: * - [kriskowal/q](https://github.com/kriskowal/q) * - [stefanpenner/es6-promise](https://github.com/stefanpenner/es6-promise) * - [petkaantonov/bluebird](https://github.com/petkaantonov/bluebird) * - [then/promise](https://github.com/then/promise) * You will need to set the library you use to `global.Promise`, before * requiring in chai-http. For example: * * ```js * // Add promise support if this does not exist natively. * if (!global.Promise) { * global.Promise = require('q'); * } * var chai = require('chai'); * chai.use(require('chai-http')); * * ``` * * #### Retaining cookies with each request * * Sometimes you need to keep cookies from one request, and send them with the * next. For this, `.request.agent()` is available: * * ```js * // Log in * var agent = chai.request.agent(app) * agent * .post('/session') * .send({ username: 'me', password: '123' }) * .then(function (res) { * expect(res).to.have.cookie('sessionid'); * // The `agent` now has the sessionid cookie saved, and will send it * // back to the server in the next request: * return agent.get('/user/me') * .then(function (res) { * expect(res).to.have.status(200); * }) * }) * ``` * */ module.exports = function (app) { /*! * @param {Mixed} function or server * @returns {Object} API */ var server = ('function' === typeof app) ? http.createServer(app) : app , obj = {}; var keepOpen = false if (typeof server !== 'string' && server && server.listen && server.address) { if (!server.address()) { server = server.listen(0) } } obj.keepOpen = function() { keepOpen = true return this } obj.close = function(callback) { if (server && server.close) { server.close(callback); } else if(callback) { callback(); } return this } methods.forEach(function (method) { obj[method] = function (path) { return new Test(server, method, path) .on('end', function() { if(keepOpen === false) { obj.close(); } }); }; }); obj.del = obj.delete; return obj; }; module.exports.Test = Test; module.exports.Request = Test; module.exports.agent = TestAgent; /*! * Test * * An extension of superagent.Request, * this provides the same chainable api * as superagent so all things can be modified. * * @param {Object|String} server, app, or url * @param {String} method * @param {String} path * @api private */ function Test (app, method, path) { Request.call(this, method, path); this.app = app; this.url = typeof app === 'string' ? app + path : serverAddress(app, path); this.ok(function() { return true; }); } util.inherits(Test, Request); function serverAddress (app, path) { if ('string' === typeof app) { return app + path; } var addr = app.address(); if (!addr) { throw new Error('Server is not listening') } var protocol = (app instanceof https.Server) ? 'https' : 'http'; // If address is "unroutable" IPv4/6 address, then set to localhost if (addr.address === '0.0.0.0' || addr.address === '::') { addr.address = '127.0.0.1'; } return protocol + '://' + addr.address + ':' + addr.port + path; } /*! * agent * * Follows the same API as superagent.Request, * but allows persisting of cookies between requests. * * @param {Object|String} server, app, or url * @param {String} method * @param {String} path * @api private */ function TestAgent(app) { if (!(this instanceof TestAgent)) return new TestAgent(app); if (typeof app === 'function') app = http.createServer(app); (Agent || Request).call(this); this.app = app; if (typeof app !== 'string' && app && app.listen && app.address && !app.address()) { this.app = app.listen(0) } } util.inherits(TestAgent, Agent || Request); TestAgent.prototype.close = function close(callback) { if (this.app && this.app.close) { this.app.close(callback) } return this } TestAgent.prototype.keepOpen = function keepOpen() { return this } // override HTTP verb methods methods.forEach(function(method){ TestAgent.prototype[method] = function(url){ var req = new Test(this.app, method, url) , self = this; if (Agent) { // When running in Node, cookies are managed via // `Agent._saveCookies()` and `Agent._attachCookies()`. req.on('response', function (res) { self._saveCookies(res); }); req.on('redirect', function (res) { self._saveCookies(res); }); req.on('redirect', function () { self._attachCookies(req); }); this._attachCookies(req); } else { // When running in a web browser, cookies are managed via `Request.withCredentials()`. // The browser will attach cookies based on same-origin policy. // https://tools.ietf.org/html/rfc6454#section-3 req.withCredentials(); } return req; }; }); TestAgent.prototype.del = TestAgent.prototype.delete; },{"http":4,"https":4,"methods":19,"superagent":33,"util":42}],4:[function(require,module,exports){ },{}],5:[function(require,module,exports){ 'use strict'; var GetIntrinsic = require('get-intrinsic'); var callBind = require('./'); var $indexOf = callBind(GetIntrinsic('String.prototype.indexOf')); module.exports = function callBoundIntrinsic(name, allowMissing) { var intrinsic = GetIntrinsic(name, !!allowMissing); if (typeof intrinsic === 'function' && $indexOf(name, '.prototype.') > -1) { return callBind(intrinsic); } return intrinsic; }; },{"./":6,"get-intrinsic":12}],6:[function(require,module,exports){ 'use strict'; var bind = require('function-bind'); var GetIntrinsic = require('get-intrinsic'); var $apply = GetIntrinsic('%Function.prototype.apply%'); var $call = GetIntrinsic('%Function.prototype.call%'); var $reflectApply = GetIntrinsic('%Reflect.apply%', true) || bind.call($call, $apply); var $gOPD = GetIntrinsic('%Object.getOwnPropertyDescriptor%', true); var $defineProperty = GetIntrinsic('%Object.defineProperty%', true); var $max = GetIntrinsic('%Math.max%'); if ($defineProperty) { try { $defineProperty({}, 'a', { value: 1 }); } catch (e) { // IE 8 has a broken defineProperty $defineProperty = null; } } module.exports = function callBind(originalFunction) { var func = $reflectApply(bind, $call, arguments); if ($gOPD && $defineProperty) { var desc = $gOPD(func, 'length'); if (desc.configurable) { // original length, plus the receiver, minus any additional arguments (after the receiver) $defineProperty( func, 'length', { value: 1 + $max(0, originalFunction.length - (arguments.length - 1)) } ); } } return func; }; var applyBind = function applyBind() { return $reflectApply(bind, $apply, arguments); }; if ($defineProperty) { $defineProperty(module.exports, 'apply', { value: applyBind }); } else { module.exports.apply = applyBind; } },{"function-bind":11,"get-intrinsic":12}],7:[function(require,module,exports){ 'use strict'; const CHARTSET_RE = /(?:charset|encoding)\s{0,10}=\s{0,10}['"]? {0,10}([\w\-]{1,100})/i; module.exports = charset; /** * guest data charset from req.headers, xml, html content-type meta tag * headers: * 'content-type': 'text/html;charset=gbk' * meta tag: * <meta http-equiv="Content-Type" content="text/html; charset=xxxx"/> * xml file: * <?xml version="1.0" encoding="UTF-8"?> * * @param {Object} obj `Content-Type` String, or `res.headers`, or `res` Object * @param {Buffer} [data] content buffer * @param {Number} [peekSize] max content peek size, default is 512 * @return {String} charset, lower case, e.g.: utf8, gbk, gb2312, .... * If can\'t guest, return null * @api public */ function charset(obj, data, peekSize) { let matchs = null; let end = 0; if (data) { peekSize = peekSize || 512; // https://github.com/node-modules/charset/issues/4 end = data.length > peekSize ? peekSize : data.length; } // charset('text/html;charset=gbk') let contentType = obj; if (contentType && typeof contentType !== 'string') { // charset(res.headers) let headers = obj; if (obj.headers) { // charset(res) headers = obj.headers; } contentType = headers['content-type'] || headers['Content-Type']; } if (contentType) { // guest from obj first matchs = CHARTSET_RE.exec(contentType); } if (!matchs && end > 0) { // guest from content body (html/xml) header contentType = data.slice(0, end).toString(); matchs = CHARTSET_RE.exec(contentType); } let cs = null; if (matchs) { cs = matchs[1].toLowerCase(); if (cs === 'utf-8') { cs = 'utf8'; } } return cs; } },{}],8:[function(require,module,exports){ /* jshint node: true */ (function () { "use strict"; function CookieAccessInfo(domain, path, secure, script) { if (this instanceof CookieAccessInfo) { this.domain = domain || undefined; this.path = path || "/"; this.secure = !!secure; this.script = !!script; return this; } return new CookieAccessInfo(domain, path, secure, script); } CookieAccessInfo.All = Object.freeze(Object.create(null)); exports.CookieAccessInfo = CookieAccessInfo; function Cookie(cookiestr, request_domain, request_path) { if (cookiestr instanceof Cookie) { return cookiestr; } if (this instanceof Cookie) { this.name = null; this.value = null; this.expiration_date = Infinity; this.path = String(request_path || "/"); this.explicit_path = false; this.domain = request_domain || null; this.explicit_domain = false; this.secure = false; //how to define default? this.noscript = false; //httponly if (cookiestr) { this.parse(cookiestr, request_domain, request_path); } return this; } return new Cookie(cookiestr, request_domain, request_path); } exports.Cookie = Cookie; Cookie.prototype.toString = function toString() { var str = [this.name + "=" + this.value]; if (this.expiration_date !== Infinity) { str.push("expires=" + (new Date(this.expiration_date)).toGMTString()); } if (this.domain) { str.push("domain=" + this.domain); } if (this.path) { str.push("path=" + this.path); } if (this.secure) { str.push("secure"); } if (this.noscript) { str.push("httponly"); } return str.join("; "); }; Cookie.prototype.toValueString = function toValueString() { return this.name + "=" + this.value; }; var cookie_str_splitter = /[:](?=\s*[a-zA-Z0-9_\-]+\s*[=])/g; Cookie.prototype.parse = function parse(str, request_domain, request_path) { if (this instanceof Cookie) { if ( str.length > 32768 ) { console.warn("Cookie too long for parsing (>32768 characters)"); return; } var parts = str.split(";").filter(function (value) { return !!value; }); var i; var pair = parts[0].match(/([^=]+)=([\s\S]*)/); if (!pair) { console.warn("Invalid cookie header encountered. Header: '"+str+"'"); return; } var key = pair[1]; var value = pair[2]; if ( typeof key !== 'string' || key.length === 0 || typeof value !== 'string' ) { console.warn("Unable to extract values from cookie header. Cookie: '"+str+"'"); return; } this.name = key; this.value = value; for (i = 1; i < parts.length; i += 1) { pair = parts[i].match(/([^=]+)(?:=([\s\S]*))?/); key = pair[1].trim().toLowerCase(); value = pair[2]; switch (key) { case "httponly": this.noscript = true; break; case "expires": this.expiration_date = value ? Number(Date.parse(value)) : Infinity; break; case "path": this.path = value ? value.trim() : ""; this.explicit_path = true; break; case "domain": this.domain = value ? value.trim() : ""; this.explicit_domain = !!this.domain; break; case "secure": this.secure = true; break; } } if (!this.explicit_path) { this.path = request_path || "/"; } if (!this.explicit_domain) { this.domain = request_domain; } return this; } return new Cookie().parse(str, request_domain, request_path); }; Cookie.prototype.matches = function matches(access_info) { if (access_info === CookieAccessInfo.All) { return true; } if (this.noscript && access_info.script || this.secure && !access_info.secure || !this.collidesWith(access_info)) { return false; } return true; }; Cookie.prototype.collidesWith = function collidesWith(access_info) { if ((this.path && !access_info.path) || (this.domain && !access_info.domain)) { return false; } if (this.path && access_info.path.indexOf(this.path) !== 0) { return false; } if (this.explicit_path && access_info.path.indexOf( this.path ) !== 0) { return false; } var access_domain = access_info.domain && access_info.domain.replace(/^[\.]/,''); var cookie_domain = this.domain && this.domain.replace(/^[\.]/,''); if (cookie_domain === access_domain) { return true; } if (cookie_domain) { if (!this.explicit_domain) { return false; // we already checked if the domains were exactly the same } var wildcard = access_domain.indexOf(cookie_domain); if (wildcard === -1 || wildcard !== access_domain.length - cookie_domain.length) { return false; } return true; } return true; }; function CookieJar() { var cookies, cookies_list, collidable_cookie; if (this instanceof CookieJar) { cookies = Object.create(null); //name: [Cookie] this.setCookie = function setCookie(cookie, request_domain, request_path) { var remove, i; cookie = new Cookie(cookie, request_domain, request_path); //Delete the cookie if the set is past the current time remove = cookie.expiration_date <= Date.now(); if (cookies[cookie.name] !== undefined) { cookies_list = cookies[cookie.name]; for (i = 0; i < cookies_list.length; i += 1) { collidable_cookie = cookies_list[i]; if (collidable_cookie.collidesWith(cookie)) { if (remove) { cookies_list.splice(i, 1); if (cookies_list.length === 0) { delete cookies[cookie.name]; } return false; } cookies_list[i] = cookie; return cookie; } } if (remove) { return false; } cookies_list.push(cookie); return cookie; } if (remove) { return false; } cookies[cookie.name] = [cookie]; return cookies[cookie.name]; }; //returns a cookie this.getCookie = function getCookie(cookie_name, access_info) { var cookie, i; cookies_list = cookies[cookie_name]; if (!cookies_list) { return; } for (i = 0; i < cookies_list.length; i += 1) { cookie = cookies_list[i]; if (cookie.expiration_date <= Date.now()) { if (cookies_list.length === 0) { delete cookies[cookie.name]; } continue; } if (cookie.matches(access_info)) { return cookie; } } }; //returns a list of cookies this.getCookies = function getCookies(access_info) { var matches = [], cookie_name, cookie; for (cookie_name in cookies) { cookie = this.getCookie(cookie_name, access_info); if (cookie) { matches.push(cookie); } } matches.toString = function toString() { return matches.join(":"); }; matches.toValueString = function toValueString() { return matches.map(function (c) { return c.toValueString(); }).join('; '); }; return matches; }; return this; } return new CookieJar(); } exports.CookieJar = CookieJar; //returns list of cookies that were set correctly. Cookies that are expired and removed are not returned. CookieJar.prototype.setCookies = function setCookies(cookies, request_domain, request_path) { cookies = Array.isArray(cookies) ? cookies : cookies.split(cookie_str_splitter); var successful = [], i, cookie; cookies = cookies.map(function(item){ return new Cookie(item, request_domain, request_path); }); for (i = 0; i < cookies.length; i += 1) { cookie = cookies[i]; if (this.setCookie(cookie, request_domain, request_path)) { successful.push(cookie); } } return successful; }; }()); },{}],9:[function(require,module,exports){ module.exports = stringify stringify.default = stringify stringify.stable = deterministicStringify stringify.stableStringify = deterministicStringify var LIMIT_REPLACE_NODE = '[...]' var CIRCULAR_REPLACE_NODE = '[Circular]' var arr = [] var replacerStack = [] function defaultOptions () { return { depthLimit: Number.MAX_SAFE_INTEGER, edgesLimit: Number.MAX_SAFE_INTEGER } } // Regular stringify function stringify (obj, replacer, spacer, options) { if (typeof options === 'undefined') { options = defaultOptions() } decirc(obj, '', 0, [], undefined, 0, options) var res try { if (replacerStack.length === 0) { res = JSON.stringify(obj, replacer, spacer) } else { res = JSON.stringify(obj, replaceGetterValues(replacer), spacer) } } catch (_) { return JSON.stringify('[unable to serialize, circular reference is too complex to analyze]') } finally { while (arr.length !== 0) { var part = arr.pop() if (part.length === 4) { Object.defineProperty(part[0], part[1], part[3]) } else { part[0][part[1]] = part[2] } } } return res } function setReplace (replace, val, k, parent) { var propertyDescriptor = Object.getOwnPropertyDescriptor(parent, k) if (propertyDescriptor.get !== undefined) { if (propertyDescriptor.configurable) { Object.defineProperty(parent, k, { value: replace }) arr.push([parent, k, val, propertyDescriptor]) } else { replacerStack.push([val, k, replace]) } } else { parent[k] = replace arr.push([parent, k, val]) } } function decirc (val, k, edgeIndex, stack, parent, depth, options) { depth += 1 var i if (typeof val === 'object' && val !== null) { for (i = 0; i < stack.length; i++) { if (stack[i] === val) { setReplace(CIRCULAR_REPLACE_NODE, val, k, parent) return } } if ( typeof options.depthLimit !== 'undefined' && depth > options.depthLimit ) { setReplace(LIMIT_REPLACE_NODE, val, k, parent) return } if ( typeof options.edgesLimit !== 'undefined' && edgeIndex + 1 > options.edgesLimit ) { setReplace(LIMIT_REPLACE_NODE, val, k, parent) return } stack.push(val) // Optimize for Arrays. Big arrays could kill the performance otherwise! if (Array.isArray(val)) { for (i = 0; i < val.length; i++) { decirc(val[i], i, i, stack, val, depth, options) } } else { var keys = Object.keys(val) for (i = 0; i < keys.length; i++) { var key = keys[i] decirc(val[key], key, i, stack, val, depth, options) } } stack.pop() } } // Stable-stringify function compareFunction (a, b) { if (a < b) { return -1 } if (a > b) { return 1 } return 0 } function deterministicStringify (obj, replacer, spacer, options) { if (typeof options === 'undefined') { options = defaultOptions() } var tmp = deterministicDecirc(obj, '', 0, [], undefined, 0, options) || obj var res try { if (replacerStack.length === 0) { res = JSON.stringify(tmp, replacer, spacer) } else { res = JSON.stringify(tmp, replaceGetterValues(replacer), spacer) } } catch (_) { return JSON.stringify('[unable to serialize, circular reference is too complex to analyze]') } finally { // Ensure that we restore the object as it was. while (arr.length !== 0) { var part = arr.pop() if (part.length === 4) { Object.defineProperty(part[0], part[1], part[3]) } else { part[0][part[1]] = part[2] } } } return res } function deterministicDecirc (val, k, edgeIndex, stack, parent, depth, options) { depth += 1 var i if (typeof val === 'object' && val !== null) { for (i = 0; i < stack.length; i++) { if (stack[i] === val) { setReplace(CIRCULAR_REPLACE_NODE, val, k, parent) return } } try { if (typeof val.toJSON === 'function') { return } } catch (_) { return } if ( typeof options.depthLimit !== 'undefined' && depth > options.depthLimit ) { setReplace(LIMIT_REPLACE_NODE, val, k, parent) return } if ( typeof options.edgesLimit !== 'undefined' && edgeIndex + 1 > options.edgesLimit ) { setReplace(LIMIT_REPLACE_NODE, val, k, parent) return } stack.push(val) // Optimize for Arrays. Big arrays could kill the performance otherwise! if (Array.isArray(val)) { for (i = 0; i < val.length; i++) { deterministicDecirc(val[i], i, i, stack, val, depth, options) } } else { // Create a temporary object in the required way var tmp = {} var keys = Object.keys(val).sort(compareFunction) for (i = 0; i < keys.length; i++) { var key = keys[i] deterministicDecirc(val[key], key, i, stack, val, depth, options) tmp[key] = val[key] } if (typeof parent !== 'undefined') { arr.push([parent, k, val]) parent[k] = tmp } else { return tmp } } stack.pop() } } // wraps replacer function to handle values we couldn't replace // and mark them as replaced value function replaceGetterValues (replacer) { replacer = typeof replacer !== 'undefined' ? replacer : function (k, v) { return v } return function (key, val) { if (replacerStack.length > 0) { for (var i = 0; i < replacerStack.length; i++) { var part = replacerStack[i] if (part[1] === key && part[0] === val) { val = part[2] replacerStack.splice(i, 1) break } } } return replacer.call(this, key, val) } } },{}],10:[function(require,module,exports){ 'use strict'; /* eslint no-invalid-this: 1 */ var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible '; var slice = Array.prototype.slice; var toStr = Object.prototype.toString; var funcType = '[object Function]'; module.exports = function bind(that) { var target = this; if (typeof target !== 'function' || toStr.call(target) !== funcType) { throw new TypeError(ERROR_MESSAGE + target); } var args = slice.call(arguments, 1); var bound; var binder = function () { if (this instanceof bound) { var result = target.apply( this, args.concat(slice.call(arguments)) ); if (Object(result) === result) { return result; } return this; } else { return target.apply( that, args.concat(slice.call(arguments)) ); } }; var boundLength = Math.max(0, target.length - args.length); var boundArgs = []; for (var i = 0; i < boundLength; i++) { boundArgs.push('$' + i); } bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder); if (target.prototype) { var Empty = function Empty() {}; Empty.prototype = target.prototype; bound.prototype = new Empty(); Empty.prototype = null; } return bound; }; },{}],11:[function(require,module,exports){ 'use strict'; var implementation = require('./implementation'); module.exports = Function.prototype.bind || implementation; },{"./implementation":10}],12:[function(require,module,exports){ 'use strict'; var undefined; var $SyntaxError = SyntaxError; var $Function = Function; var $TypeError = TypeError; // eslint-disable-next-line consistent-return var getEvalledConstructor = function (expressionSyntax) { try { return $Function('"use strict"; return (' + expressionSyntax + ').constructor;')(); } catch (e) {} }; var $gOPD = Object.getOwnPropertyDescriptor; if ($gOPD) { try { $gOPD({}, ''); } catch (e) { $gOPD = null; // this is IE 8, which has a broken gOPD } } var throwTypeError = function () { throw new $TypeError(); }; var ThrowTypeError = $gOPD ? (function () { try { // eslint-disable-next-line no-unused-expressions, no-caller, no-restricted-properties arguments.callee; // IE 8 does not throw here return throwTypeError; } catch (calleeThrows) { try { // IE 8 throws on Object.getOwnPropertyDescriptor(arguments, '') return $gOPD(arguments, 'callee').get; } catch (gOPDthrows) { return throwTypeError; } } }()) : throwTypeError; var hasSymbols = require('has-symbols')(); var hasProto = require('has-proto')(); var getProto = Object.getPrototypeOf || ( hasProto ? function (x) { return x.__proto__; } // eslint-disable-line no-proto : null ); var needsEval = {}; var TypedArray = typeof Uint8Array === 'undefined' || !getProto ? undefined : getProto(Uint8Array); var INTRINSICS = { '%AggregateError%': typeof AggregateError === 'undefined' ? undefined : AggregateError, '%Array%': Array, '%ArrayBuffer%': typeof ArrayBuffer === 'undefined' ? undefined : ArrayBuffer, '%ArrayIteratorPrototype%': hasSymbols && getProto ? getProto([][Symbol.iterator]()) : undefined, '%AsyncFromSyncIteratorPrototype%': undefined, '%AsyncFunction%': needsEval, '%AsyncGenerator%': needsEval, '%AsyncGeneratorFunction%': needsEval, '%AsyncIteratorPrototype%': needsEval, '%Atomics%': typeof Atomics === 'undefined' ? undefined : Atomics, '%BigInt%': typeof BigInt === 'undefined' ? undefined : BigInt, '%BigInt64Array%': typeof BigInt64Array === 'undefined' ? undefined : BigInt64Array, '%BigUint64Array%': typeof BigUint64Array === 'undefined' ? undefined : BigUint64Array, '%Boolean%': Boolean, '%DataView%': typeof DataView === 'undefined' ? undefined : DataView, '%Date%': Date, '%decodeURI%': decodeURI, '%decodeURIComponent%': decodeURIComponent, '%encodeURI%': encodeURI, '%encodeURIComponent%': encodeURIComponent, '%Error%': Error, '%eval%': eval, // eslint-disable-line no-eval '%EvalError%': EvalError, '%Float32Array%': typeof Float32Array === 'undefined' ? undefined : Float32Array, '%Float64Array%': typeof Float64Array === 'undefined' ? undefined : Float64Array, '%FinalizationRegistry%': typeof FinalizationRegistry === 'undefined' ? undefined : FinalizationRegistry, '%Function%': $Function, '%GeneratorFunction%': needsEval, '%Int8Array%': typeof Int8Array === 'undefined' ? undefined : Int8Array, '%Int16Array%': typeof Int16Array === 'undefined' ? undefined : Int16Array, '%Int32Array%': typeof Int32Array === 'undefined' ? undefined : Int32Array, '%isFinite%': isFinite, '%isNaN%': isNaN, '%IteratorPrototype%': hasSymbols && getProto ? getProto(getProto([][Symbol.iterator]())) : undefined, '%JSON%': typeof JSON === 'object' ? JSON : undefined, '%Map%': typeof Map === 'undefined' ? undefined : Map, '%MapIteratorPrototype%': typeof Map === 'undefined' || !hasSymbols || !getProto ? undefined : getProto(new Map()[Symbol.iterator]()), '%Math%': Math, '%Number%': Number, '%Object%': Object, '%parseFloat%': parseFloat, '%parseInt%': parseInt, '%Promise%': typeof Promise === 'undefined' ? undefined : Promise, '%Proxy%': typeof Proxy === 'undefined' ? undefined : Proxy, '%RangeError%': RangeError, '%ReferenceError%': ReferenceError, '%Reflect%': typeof Reflect === 'undefined' ? undefined : Reflect, '%RegExp%': RegExp, '%Set%': typeof Set === 'undefined' ? undefined : Set, '%SetIteratorPrototype%': typeof Set === 'undefined' || !hasSymbols || !getProto ? undefined : getProto(new Set()[Symbol.iterator]()), '%SharedArrayBuffer%': typeof SharedArrayBuffer === 'undefined' ? undefined : SharedArrayBuffer, '%String%': String, '%StringIteratorPrototype%': hasSymbols && getProto ? getProto(''[Symbol.iterator]()) : undefined, '%Symbol%': hasSymbols ? Symbol : undefined, '%SyntaxError%': $SyntaxError, '%ThrowTypeError%': ThrowTypeError, '%TypedArray%': TypedArray, '%TypeError%': $TypeError, '%Uint8Array%': typeof Uint8Array === 'undefined' ? undefined : Uint8Array, '%Uint8ClampedArray%': typeof Uint8ClampedArray === 'undefined' ? undefined : Uint8ClampedArray, '%Uint16Array%': typeof Uint16Array === 'undefined' ? undefined : Uint16Array, '%Uint32Array%': typeof Uint32Array === 'undefined' ? undefined : Uint32Array, '%URIError%': URIError, '%WeakMap%': typeof WeakMap === 'undefined' ? undefined : WeakMap, '%WeakRef%': typeof WeakRef === 'undefined' ? undefined : WeakRef, '%WeakSet%': typeof WeakSet === 'undefined' ? undefined : WeakSet }; if (getProto) { try { null.error; // eslint-disable-line no-unused-expressions } catch (e) { // https://github.com/tc39/proposal-shadowrealm/pull/384#issuecomment-1364264229 var errorProto = getProto(getProto(e)); INTRINSICS['%Error.prototype%'] = errorProto; } } var doEval = function doEval(name) { var value; if (name === '%AsyncFunction%') { value = getEvalledConstructor('async function () {}'); } else if (name === '%GeneratorFunction%') { value = getEvalledConstructor('function* () {}'); } else if (name === '%AsyncGeneratorFunction%') { value = getEvalledConstructor('async function* () {}'); } else if (name === '%AsyncGenerator%') { var fn = doEval('%AsyncGeneratorFunction%'); if (fn) { value = fn.prototype; } } else if (name === '%AsyncIteratorPrototype%') { var gen = doEval('%AsyncGenerator%'); if (gen && getProto) { value = getProto(gen.prototype); } } INTRINSICS[name] = value; return value; }; var LEGACY_ALIASES = { '%ArrayBufferPrototype%': ['ArrayBuffer', 'prototype'], '%ArrayPrototype%': ['Array', 'prototype'], '%ArrayProto_entries%': ['Array', 'prototype', 'entries'], '%ArrayProto_forEach%': ['Array', 'prototype', 'forEach'], '%ArrayProto_keys%': ['Array', 'prototype', 'keys'], '%ArrayProto_values%': ['Array', 'prototype', 'values'], '%AsyncFunctionPrototype%': ['AsyncFunction', 'prototype'], '%AsyncGenerator%': ['AsyncGeneratorFunction', 'prototype'], '%AsyncGeneratorPrototype%': ['AsyncGeneratorFunction', 'prototype', 'prototype'], '%BooleanPrototype%': ['Boolean', 'prototype'], '%DataViewPrototype%': ['DataView', 'prototype'], '%DatePrototype%': ['Date', 'prototype'],