aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAldo Cortesi <aldo@nullcube.com>2016-06-03 14:55:35 +1200
committerAldo Cortesi <aldo@nullcube.com>2016-06-03 14:55:35 +1200
commit08e4cd2a40778a1a10eef1bba0d2c167f6edeea9 (patch)
treea36d0a637ae2a46c8425c56439927ff04392b5ef
parent25671b91bd16d7c355742a6094addad00e331af5 (diff)
parenta2d13714a6d73595820e8ca7bdada3a4eabec36e (diff)
downloadmitmproxy-08e4cd2a40778a1a10eef1bba0d2c167f6edeea9.tar.gz
mitmproxy-08e4cd2a40778a1a10eef1bba0d2c167f6edeea9.tar.bz2
mitmproxy-08e4cd2a40778a1a10eef1bba0d2c167f6edeea9.zip
Merge remote-tracking branch 'upstream/master'
-rw-r--r--.travis.yml4
-rw-r--r--README.rst45
-rwxr-xr-xdev.sh5
-rw-r--r--mitmproxy/web/static/vendor.js897
-rw-r--r--netlib/tcp.py43
-rw-r--r--pathod/language/generators.py57
-rw-r--r--pathod/pathoc.py3
-rw-r--r--pathod/pathod.py18
-rw-r--r--pathod/protocols/websockets.py2
-rw-r--r--pathod/test.py49
-rw-r--r--setup.cfg3
-rw-r--r--test/pathod/test_app.py6
-rw-r--r--test/pathod/test_language_generators.py13
-rw-r--r--test/pathod/test_pathod.py22
-rw-r--r--test/pathod/test_test.py4
-rw-r--r--test/pathod/tutils.py48
-rw-r--r--web/.babelrc2
-rw-r--r--web/package.json1
18 files changed, 604 insertions, 618 deletions
diff --git a/.travis.yml b/.travis.yml
index 9d4dea88..5ec8b3bd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -22,9 +22,9 @@ matrix:
git:
depth: 9999999
- python: 3.5
- env: SCOPE="netlib ./test/mitmproxy/script ./test/pathod/test_utils.py ./test/pathod/test_log.py"
+ env: SCOPE="netlib ./test/mitmproxy/script ./test/pathod/test_utils.py ./test/pathod/test_log.py ./test/pathod/test_language_generators.py"
- python: 3.5
- env: SCOPE="netlib ./test/mitmproxy/script ./test/pathod/test_utils.py ./test/pathod/test_log.py" NO_ALPN=1
+ env: SCOPE="netlib ./test/mitmproxy/script ./test/pathod/test_utils.py ./test/pathod/test_log.py ./test/pathod/test_language_generators.py" NO_ALPN=1
- python: 2.7
env: DOCS=1
script: 'cd docs && make html'
diff --git a/README.rst b/README.rst
index 854c4ae6..4f84effd 100644
--- a/README.rst
+++ b/README.rst
@@ -3,19 +3,24 @@ mitmproxy
|travis| |coveralls| |latest_release| |python_versions|
-This repository contains the **mitmproxy** and **pathod** projects, as well as their shared networking library, **netlib**.
+This repository contains the **mitmproxy** and **pathod** projects, as well as
+their shared networking library, **netlib**.
-``mitmproxy`` is an interactive, SSL-capable intercepting proxy with a console interface.
+``mitmproxy`` is an interactive, SSL-capable intercepting proxy with a console
+interface.
``mitmdump`` is the command-line version of mitmproxy. Think tcpdump for HTTP.
-``pathoc`` and ``pathod`` are perverse HTTP client and server applications designed to let you craft almost any conceivable HTTP request, including ones that creatively violate the standards.
+``pathoc`` and ``pathod`` are perverse HTTP client and server applications
+designed to let you craft almost any conceivable HTTP request, including ones
+that creatively violate the standards.
Documentation & Help
--------------------
-Documentation, tutorials and precompiled binaries can be found on the mitmproxy and pathod websites.
+Documentation, tutorials and precompiled binaries can be found on the mitmproxy
+and pathod websites.
|mitmproxy_site| |pathod_site|
@@ -28,12 +33,19 @@ You can join our developer chat on Slack.
|slack|
+Installation
+------------
+
+The installation instructions are `here <http://docs.mitmproxy.org/en/stable/install.html>`_.
+If you want to contribute changes, keep on reading.
+
+
Hacking
-------
To get started hacking on mitmproxy, make sure you have Python_ 2.7.x. with
-virtualenv_ installed (you can find installation instructions for virtualenv here_).
-Then do the following:
+virtualenv_ installed (you can find installation instructions for virtualenv
+here_). Then do the following:
.. code-block:: text
@@ -42,10 +54,11 @@ Then do the following:
./dev.sh
-The *dev* script will create a virtualenv environment in a directory called "venv",
-and install all mandatory and optional dependencies into it.
-The primary mitmproxy components - mitmproxy, netlib and pathod - are installed as "editable",
-so any changes to the source in the repository will be reflected live in the virtualenv.
+The *dev* script will create a virtualenv environment in a directory called
+"venv", and install all mandatory and optional dependencies into it. The
+primary mitmproxy components - mitmproxy, netlib and pathod - are installed as
+"editable", so any changes to the source in the repository will be reflected
+live in the virtualenv.
To confirm that you're up and running, activate the virtualenv, and run the
mitmproxy test suite:
@@ -56,9 +69,9 @@ mitmproxy test suite:
py.test
Note that the main executables for the project - ``mitmdump``, ``mitmproxy``,
-``mitmweb``, ``pathod``, and ``pathoc`` - are all created within the virtualenv. After activating the
-virtualenv, they will be on your $PATH, and you can run them like any other
-command:
+``mitmweb``, ``pathod``, and ``pathoc`` - are all created within the
+virtualenv. After activating the virtualenv, they will be on your $PATH, and
+you can run them like any other command:
.. code-block:: text
@@ -85,9 +98,9 @@ suite. The project tries to maintain 100% test coverage.
Documentation
-------------
-The mitmproxy documentation is build using Sphinx_, which is installed automatically if you set up a development
-environment as described above.
-After installation, you can render the documentation like this:
+The mitmproxy documentation is build using Sphinx_, which is installed
+automatically if you set up a development environment as described above. After
+installation, you can render the documentation like this:
.. code-block:: text
diff --git a/dev.sh b/dev.sh
index 111f09bc..889ffecb 100755
--- a/dev.sh
+++ b/dev.sh
@@ -1,5 +1,6 @@
#!/bin/sh
set -e
+set -x
PYVERSION=$1
VENV="venv$1"
@@ -8,8 +9,8 @@ echo "Creating dev environment in $VENV using Python $PYVERSION"
python$PYVERSION -m virtualenv "$VENV" --always-copy
. "$VENV/bin/activate"
-pip$PYVERSION install -q -U pip setuptools
-pip$PYVERSION install -q -r requirements.txt
+pip$PYVERSION install -U pip setuptools
+pip$PYVERSION install -r requirements.txt
echo ""
echo "* Virtualenv created in $VENV and all dependencies installed."
diff --git a/mitmproxy/web/static/vendor.js b/mitmproxy/web/static/vendor.js
index 4b2ff6bf..efe6f2b4 100644
--- a/mitmproxy/web/static/vendor.js
+++ b/mitmproxy/web/static/vendor.js
@@ -2116,15 +2116,13 @@ var KNOWN_STATICS = {
};
module.exports = function hoistNonReactStatics(targetComponent, sourceComponent) {
- if (typeof sourceComponent !== 'string') { // don't hoist over string (html) components
- var keys = Object.getOwnPropertyNames(sourceComponent);
- for (var i=0; i<keys.length; ++i) {
- if (!REACT_STATICS[keys[i]] && !KNOWN_STATICS[keys[i]]) {
- try {
- targetComponent[keys[i]] = sourceComponent[keys[i]];
- } catch (error) {
-
- }
+ var keys = Object.getOwnPropertyNames(sourceComponent);
+ for (var i=0; i<keys.length; ++i) {
+ if (!REACT_STATICS[keys[i]] && !KNOWN_STATICS[keys[i]]) {
+ try {
+ targetComponent[keys[i]] = sourceComponent[keys[i]];
+ } catch (error) {
+
}
}
}
@@ -3087,9 +3085,6 @@ var currentQueue;
var queueIndex = -1;
function cleanUpNextTick() {
- if (!draining || !currentQueue) {
- return;
- }
draining = false;
if (currentQueue.length) {
queue = currentQueue.concat(queue);
@@ -3894,7 +3889,6 @@ function compilePattern(pattern) {
* - ** Consumes (greedy) all characters up to the next character
* in the pattern, or to the end of the URL if there is none
*
- * The function calls callback(error, matched) when finished.
* The return value is an object with the following properties:
*
* - remainingPathname
@@ -6094,17 +6088,13 @@ function matchRouteDeep(route, location, remainingPathname, paramNames, paramVal
// Only try to match the path if the route actually has a pattern, and if
// we're not just searching for potential nested absolute paths.
if (remainingPathname !== null && pattern) {
- try {
- var matched = (0, _PatternUtils.matchPattern)(pattern, remainingPathname);
- if (matched) {
- remainingPathname = matched.remainingPathname;
- paramNames = [].concat(paramNames, matched.paramNames);
- paramValues = [].concat(paramValues, matched.paramValues);
- } else {
- remainingPathname = null;
- }
- } catch (error) {
- callback(error);
+ var matched = (0, _PatternUtils.matchPattern)(pattern, remainingPathname);
+ if (matched) {
+ remainingPathname = matched.remainingPathname;
+ paramNames = [].concat(paramNames, matched.paramNames);
+ paramValues = [].concat(paramValues, matched.paramValues);
+ } else {
+ remainingPathname = null;
}
// By assumption, pattern is non-empty here, which is the prerequisite for
@@ -35727,7 +35717,8 @@ return jQuery;
(function (global){
/**
* @license
- * lodash <https://lodash.com/>
+ * lodash 4.11.2 (Custom Build) <https://lodash.com/>
+ * Build: `lodash -d -o ./foo/lodash.js`
* Copyright jQuery Foundation and other contributors <https://jquery.org/>
* Released under MIT license <https://lodash.com/license>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
@@ -35739,7 +35730,7 @@ return jQuery;
var undefined;
/** Used as the semantic version number. */
- var VERSION = '4.12.0';
+ var VERSION = '4.11.2';
/** Used as the size to enable large array optimizations. */
var LARGE_ARRAY_SIZE = 200;
@@ -36184,6 +36175,30 @@ return jQuery;
}
/**
+ * Creates a new array concatenating `array` with `other`.
+ *
+ * @private
+ * @param {Array} array The first array to concatenate.
+ * @param {Array} other The second array to concatenate.
+ * @returns {Array} Returns the new concatenated array.
+ */
+ function arrayConcat(array, other) {
+ var index = -1,
+ length = array.length,
+ othIndex = -1,
+ othLength = other.length,
+ result = Array(length + othLength);
+
+ while (++index < length) {
+ result[index] = array[index];
+ }
+ while (++othIndex < othLength) {
+ result[index++] = other[othIndex];
+ }
+ return result;
+ }
+
+ /**
* A specialized version of `_.forEach` for arrays without support for
* iteratee shorthands.
*
@@ -36610,7 +36625,7 @@ return jQuery;
* @private
* @param {Object} object The object to query.
* @param {Array} props The property names to get values for.
- * @returns {Object} Returns the key-value pairs.
+ * @returns {Object} Returns the new array of key-value pairs.
*/
function baseToPairs(object, props) {
return arrayMap(props, function(key) {
@@ -36623,7 +36638,7 @@ return jQuery;
*
* @private
* @param {Function} func The function to cap arguments for.
- * @returns {Function} Returns the new capped function.
+ * @returns {Function} Returns the new function.
*/
function baseUnary(func) {
return function(value) {
@@ -36648,18 +36663,6 @@ return jQuery;
}
/**
- * Checks if a cache value for `key` exists.
- *
- * @private
- * @param {Object} cache The cache to query.
- * @param {string} key The key of the entry to check.
- * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
- */
- function cacheHas(cache, key) {
- return cache.has(key);
- }
-
- /**
* Used by `_.trim` and `_.trimStart` to get the index of the first string symbol
* that is not found in the character symbols.
*
@@ -36815,11 +36818,11 @@ return jQuery;
}
/**
- * Converts `map` to its key-value pairs.
+ * Converts `map` to an array.
*
* @private
* @param {Object} map The map to convert.
- * @returns {Array} Returns the key-value pairs.
+ * @returns {Array} Returns the converted array.
*/
function mapToArray(map) {
var index = -1,
@@ -36857,11 +36860,11 @@ return jQuery;
}
/**
- * Converts `set` to an array of its values.
+ * Converts `set` to an array.
*
* @private
* @param {Object} set The set to convert.
- * @returns {Array} Returns the values.
+ * @returns {Array} Returns the converted array.
*/
function setToArray(set) {
var index = -1,
@@ -36874,23 +36877,6 @@ return jQuery;
}
/**
- * Converts `set` to its value-value pairs.
- *
- * @private
- * @param {Object} set The set to convert.
- * @returns {Array} Returns the value-value pairs.
- */
- function setToPairs(set) {
- var index = -1,
- result = Array(set.size);
-
- set.forEach(function(value) {
- result[++index] = [value, value];
- });
- return result;
- }
-
- /**
* Gets the number of symbols in `string`.
*
* @private
@@ -37143,10 +37129,10 @@ return jQuery;
* `floor`, `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`,
* `forOwnRight`, `get`, `gt`, `gte`, `has`, `hasIn`, `head`, `identity`,
* `includes`, `indexOf`, `inRange`, `invoke`, `isArguments`, `isArray`,
- * `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, `isBoolean`,
- * `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`, `isEqualWith`,
- * `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`, `isMap`,
- * `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, `isNumber`,
+ * `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, `isBoolean`, `isBuffer`,
+ * `isDate`, `isElement`, `isEmpty`, `isEqual`, `isEqualWith`, `isError`,
+ * `isFinite`, `isFunction`, `isInteger`, `isLength`, `isMap`, `isMatch`,
+ * `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, `isNumber`,
* `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, `isSafeInteger`,
* `isSet`, `isString`, `isUndefined`, `isTypedArray`, `isWeakMap`, `isWeakSet`,
* `join`, `kebabCase`, `last`, `lastIndexOf`, `lowerCase`, `lowerFirst`,
@@ -37155,9 +37141,9 @@ return jQuery;
* `pop`, `random`, `reduce`, `reduceRight`, `repeat`, `result`, `round`,
* `runInContext`, `sample`, `shift`, `size`, `snakeCase`, `some`, `sortedIndex`,
* `sortedIndexBy`, `sortedLastIndex`, `sortedLastIndexBy`, `startCase`,
- * `startsWith`, `subtract`, `sum`, `sumBy`, `template`, `times`, `toFinite`,
- * `toInteger`, `toJSON`, `toLength`, `toLower`, `toNumber`, `toSafeInteger`,
- * `toString`, `toUpper`, `trim`, `trimEnd`, `trimStart`, `truncate`, `unescape`,
+ * `startsWith`, `subtract`, `sum`, `sumBy`, `template`, `times`, `toInteger`,
+ * `toJSON`, `toLength`, `toLower`, `toNumber`, `toSafeInteger`, `toString`,
+ * `toUpper`, `trim`, `trimEnd`, `trimStart`, `truncate`, `unescape`,
* `uniqueId`, `upperCase`, `upperFirst`, `value`, and `words`
*
* @name _
@@ -37417,212 +37403,64 @@ return jQuery;
*
* @private
* @constructor
- * @param {Array} [entries] The key-value pairs to cache.
- */
- function Hash(entries) {
- var index = -1,
- length = entries ? entries.length : 0;
-
- this.clear();
- while (++index < length) {
- var entry = entries[index];
- this.set(entry[0], entry[1]);
- }
- }
-
- /**
- * Removes all key-value entries from the hash.
- *
- * @private
- * @name clear
- * @memberOf Hash
+ * @returns {Object} Returns the new hash object.
*/
- function hashClear() {
- this.__data__ = nativeCreate ? nativeCreate(null) : {};
- }
+ function Hash() {}
/**
* Removes `key` and its value from the hash.
*
* @private
- * @name delete
- * @memberOf Hash
* @param {Object} hash The hash to modify.
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
- function hashDelete(key) {
- return this.has(key) && delete this.__data__[key];
+ function hashDelete(hash, key) {
+ return hashHas(hash, key) && delete hash[key];
}
/**
* Gets the hash value for `key`.
*
* @private
- * @name get
- * @memberOf Hash
+ * @param {Object} hash The hash to query.
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
- function hashGet(key) {
- var data = this.__data__;
+ function hashGet(hash, key) {
if (nativeCreate) {
- var result = data[key];
+ var result = hash[key];
return result === HASH_UNDEFINED ? undefined : result;
}
- return hasOwnProperty.call(data, key) ? data[key] : undefined;
+ return hasOwnProperty.call(hash, key) ? hash[key] : undefined;
}
/**
* Checks if a hash value for `key` exists.
*
* @private
- * @name has
- * @memberOf Hash
+ * @param {Object} hash The hash to query.
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
- function hashHas(key) {
- var data = this.__data__;
- return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);
+ function hashHas(hash, key) {
+ return nativeCreate ? hash[key] !== undefined : hasOwnProperty.call(hash, key);
}
/**
* Sets the hash `key` to `value`.
*
* @private
- * @name set
- * @memberOf Hash
- * @param {string} key The key of the value to set.
- * @param {*} value The value to set.
- * @returns {Object} Returns the hash instance.
- */
- function hashSet(key, value) {
- var data = this.__data__;
- data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
- return this;
- }
-
- // Add methods to `Hash`.
- Hash.prototype.clear = hashClear;
- Hash.prototype['delete'] = hashDelete;
- Hash.prototype.get = hashGet;
- Hash.prototype.has = hashHas;
- Hash.prototype.set = hashSet;
-
- /*------------------------------------------------------------------------*/
-
- /**
- * Creates an list cache object.
- *
- * @private
- * @constructor
- * @param {Array} [entries] The key-value pairs to cache.
- */
- function ListCache(entries) {
- var index = -1,
- length = entries ? entries.length : 0;
-
- this.clear();
- while (++index < length) {
- var entry = entries[index];
- this.set(entry[0], entry[1]);
- }
- }
-
- /**
- * Removes all key-value entries from the list cache.
- *
- * @private
- * @name clear
- * @memberOf ListCache
- */
- function listCacheClear() {
- this.__data__ = [];
- }
-
- /**
- * Removes `key` and its value from the list cache.
- *
- * @private
- * @name delete
- * @memberOf ListCache
- * @param {string} key The key of the value to remove.
- * @returns {boolean} Returns `true` if the entry was removed, else `false`.
- */
- function listCacheDelete(key) {
- var data = this.__data__,
- index = assocIndexOf(data, key);
-
- if (index < 0) {
- return false;
- }
- var lastIndex = data.length - 1;
- if (index == lastIndex) {
- data.pop();
- } else {
- splice.call(data, index, 1);
- }
- return true;
- }
-
- /**
- * Gets the list cache value for `key`.
- *
- * @private
- * @name get
- * @memberOf ListCache
- * @param {string} key The key of the value to get.
- * @returns {*} Returns the entry value.
- */
- function listCacheGet(key) {
- var data = this.__data__,
- index = assocIndexOf(data, key);
-
- return index < 0 ? undefined : data[index][1];
- }
-
- /**
- * Checks if a list cache value for `key` exists.
- *
- * @private
- * @name has
- * @memberOf ListCache
- * @param {string} key The key of the entry to check.
- * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
- */
- function listCacheHas(key) {
- return assocIndexOf(this.__data__, key) > -1;
- }
-
- /**
- * Sets the list cache `key` to `value`.
- *
- * @private
- * @name set
- * @memberOf ListCache
+ * @param {Object} hash The hash to modify.
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
- * @returns {Object} Returns the list cache instance.
*/
- function listCacheSet(key, value) {
- var data = this.__data__,
- index = assocIndexOf(data, key);
-
- if (index < 0) {
- data.push([key, value]);
- } else {
- data[index][1] = value;
- }
- return this;
+ function hashSet(hash, key, value) {
+ hash[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
}
- // Add methods to `ListCache`.
- ListCache.prototype.clear = listCacheClear;
- ListCache.prototype['delete'] = listCacheDelete;
- ListCache.prototype.get = listCacheGet;
- ListCache.prototype.has = listCacheHas;
- ListCache.prototype.set = listCacheSet;
+ // Avoid inheriting from `Object.prototype` when possible.
+ Hash.prototype = nativeCreate ? nativeCreate(null) : objectProto;
/*------------------------------------------------------------------------*/
@@ -37631,15 +37469,15 @@ return jQuery;
*
* @private
* @constructor
- * @param {Array} [entries] The key-value pairs to cache.
+ * @param {Array} [values] The values to cache.
*/
- function MapCache(entries) {
+ function MapCache(values) {
var index = -1,
- length = entries ? entries.length : 0;
+ length = values ? values.length : 0;
this.clear();
while (++index < length) {
- var entry = entries[index];
+ var entry = values[index];
this.set(entry[0], entry[1]);
}
}
@@ -37651,10 +37489,10 @@ return jQuery;
* @name clear
* @memberOf MapCache
*/
- function mapCacheClear() {
+ function mapClear() {
this.__data__ = {
'hash': new Hash,
- 'map': new (Map || ListCache),
+ 'map': Map ? new Map : [],
'string': new Hash
};
}
@@ -37668,8 +37506,12 @@ return jQuery;
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
- function mapCacheDelete(key) {
- return getMapData(this, key)['delete'](key);
+ function mapDelete(key) {
+ var data = this.__data__;
+ if (isKeyable(key)) {
+ return hashDelete(typeof key == 'string' ? data.string : data.hash, key);
+ }
+ return Map ? data.map['delete'](key) : assocDelete(data.map, key);
}
/**
@@ -37681,8 +37523,12 @@ return jQuery;
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
- function mapCacheGet(key) {
- return getMapData(this, key).get(key);
+ function mapGet(key) {
+ var data = this.__data__;
+ if (isKeyable(key)) {
+ return hashGet(typeof key == 'string' ? data.string : data.hash, key);
+ }
+ return Map ? data.map.get(key) : assocGet(data.map, key);
}
/**
@@ -37694,8 +37540,12 @@ return jQuery;
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
- function mapCacheHas(key) {
- return getMapData(this, key).has(key);
+ function mapHas(key) {
+ var data = this.__data__;
+ if (isKeyable(key)) {
+ return hashHas(typeof key == 'string' ? data.string : data.hash, key);
+ }
+ return Map ? data.map.has(key) : assocHas(data.map, key);
}
/**
@@ -37708,23 +37558,30 @@ return jQuery;
* @param {*} value The value to set.
* @returns {Object} Returns the map cache instance.
*/
- function mapCacheSet(key, value) {
- getMapData(this, key).set(key, value);
+ function mapSet(key, value) {
+ var data = this.__data__;
+ if (isKeyable(key)) {
+ hashSet(typeof key == 'string' ? data.string : data.hash, key, value);
+ } else if (Map) {
+ data.map.set(key, value);
+ } else {
+ assocSet(data.map, key, value);
+ }
return this;
}
// Add methods to `MapCache`.
- MapCache.prototype.clear = mapCacheClear;
- MapCache.prototype['delete'] = mapCacheDelete;
- MapCache.prototype.get = mapCacheGet;
- MapCache.prototype.has = mapCacheHas;
- MapCache.prototype.set = mapCacheSet;
+ MapCache.prototype.clear = mapClear;
+ MapCache.prototype['delete'] = mapDelete;
+ MapCache.prototype.get = mapGet;
+ MapCache.prototype.has = mapHas;
+ MapCache.prototype.set = mapSet;
/*------------------------------------------------------------------------*/
/**
*
- * Creates an array cache object to store unique values.
+ * Creates a set cache object to store unique values.
*
* @private
* @constructor
@@ -37736,41 +37593,52 @@ return jQuery;
this.__data__ = new MapCache;
while (++index < length) {
- this.add(values[index]);
+ this.push(values[index]);
}
}
/**
- * Adds `value` to the array cache.
+ * Checks if `value` is in `cache`.
*
* @private
- * @name add
- * @memberOf SetCache
- * @alias push
- * @param {*} value The value to cache.
- * @returns {Object} Returns the cache instance.
+ * @param {Object} cache The set cache to search.
+ * @param {*} value The value to search for.
+ * @returns {number} Returns `true` if `value` is found, else `false`.
*/
- function setCacheAdd(value) {
- this.__data__.set(value, HASH_UNDEFINED);
- return this;
+ function cacheHas(cache, value) {
+ var map = cache.__data__;
+ if (isKeyable(value)) {
+ var data = map.__data__,
+ hash = typeof value == 'string' ? data.string : data.hash;
+
+ return hash[value] === HASH_UNDEFINED;
+ }
+ return map.has(value);
}
/**
- * Checks if `value` is in the array cache.
+ * Adds `value` to the set cache.
*
* @private
- * @name has
+ * @name push
* @memberOf SetCache
- * @param {*} value The value to search for.
- * @returns {number} Returns `true` if `value` is found, else `false`.
+ * @param {*} value The value to cache.
*/
- function setCacheHas(value) {
- return this.__data__.has(value);
+ function cachePush(value) {
+ var map = this.__data__;
+ if (isKeyable(value)) {
+ var data = map.__data__,
+ hash = typeof value == 'string' ? data.string : data.hash;
+
+ hash[value] = HASH_UNDEFINED;
+ }
+ else {
+ map.set(value, HASH_UNDEFINED);
+ }
}
// Add methods to `SetCache`.
- SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
- SetCache.prototype.has = setCacheHas;
+ SetCache.prototype.push = cachePush;
/*------------------------------------------------------------------------*/
@@ -37779,10 +37647,17 @@ return jQuery;
*
* @private
* @constructor
- * @param {Array} [entries] The key-value pairs to cache.
+ * @param {Array} [values] The values to cache.
*/
- function Stack(entries) {
- this.__data__ = new ListCache(entries);
+ function Stack(values) {
+ var index = -1,
+ length = values ? values.length : 0;
+
+ this.clear();
+ while (++index < length) {
+ var entry = values[index];
+ this.set(entry[0], entry[1]);
+ }
}
/**
@@ -37793,7 +37668,7 @@ return jQuery;
* @memberOf Stack
*/
function stackClear() {
- this.__data__ = new ListCache;
+ this.__data__ = { 'array': [], 'map': null };
}
/**
@@ -37806,7 +37681,10 @@ return jQuery;
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function stackDelete(key) {
- return this.__data__['delete'](key);
+ var data = this.__data__,
+ array = data.array;
+
+ return array ? assocDelete(array, key) : data.map['delete'](key);
}
/**
@@ -37819,7 +37697,10 @@ return jQuery;
* @returns {*} Returns the entry value.
*/
function stackGet(key) {
- return this.__data__.get(key);
+ var data = this.__data__,
+ array = data.array;
+
+ return array ? assocGet(array, key) : data.map.get(key);
}
/**
@@ -37832,7 +37713,10 @@ return jQuery;
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function stackHas(key) {
- return this.__data__.has(key);
+ var data = this.__data__,
+ array = data.array;
+
+ return array ? assocHas(array, key) : data.map.has(key);
}
/**
@@ -37846,11 +37730,21 @@ return jQuery;
* @returns {Object} Returns the stack cache instance.
*/
function stackSet(key, value) {
- var cache = this.__data__;
- if (cache instanceof ListCache && cache.__data__.length == LARGE_ARRAY_SIZE) {
- cache = this.__data__ = new MapCache(cache.__data__);
+ var data = this.__data__,
+ array = data.array;
+
+ if (array) {
+ if (array.length < (LARGE_ARRAY_SIZE - 1)) {
+ assocSet(array, key, value);
+ } else {
+ data.array = null;
+ data.map = new MapCache(array);
+ }
+ }
+ var map = data.map;
+ if (map) {
+ map.set(key, value);
}
- cache.set(key, value);
return this;
}
@@ -37864,6 +37758,90 @@ return jQuery;
/*------------------------------------------------------------------------*/
/**
+ * Removes `key` and its value from the associative array.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function assocDelete(array, key) {
+ var index = assocIndexOf(array, key);
+ if (index < 0) {
+ return false;
+ }
+ var lastIndex = array.length - 1;
+ if (index == lastIndex) {
+ array.pop();
+ } else {
+ splice.call(array, index, 1);
+ }
+ return true;
+ }
+
+ /**
+ * Gets the associative array value for `key`.
+ *
+ * @private
+ * @param {Array} array The array to query.
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function assocGet(array, key) {
+ var index = assocIndexOf(array, key);
+ return index < 0 ? undefined : array[index][1];
+ }
+
+ /**
+ * Checks if an associative array value for `key` exists.
+ *
+ * @private
+ * @param {Array} array The array to query.
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function assocHas(array, key) {
+ return assocIndexOf(array, key) > -1;
+ }
+
+ /**
+ * Gets the index at which the `key` is found in `array` of key-value pairs.
+ *
+ * @private
+ * @param {Array} array The array to search.
+ * @param {*} key The key to search for.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function assocIndexOf(array, key) {
+ var length = array.length;
+ while (length--) {
+ if (eq(array[length][0], key)) {
+ return length;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Sets the associative array `key` to `value`.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ */
+ function assocSet(array, key, value) {
+ var index = assocIndexOf(array, key);
+ if (index < 0) {
+ array.push([key, value]);
+ } else {
+ array[index][1] = value;
+ }
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ /**
* Used by `_.defaults` to customize its `_.assignIn` use.
*
* @private
@@ -37916,24 +37894,6 @@ return jQuery;
}
/**
- * Gets the index at which the `key` is found in `array` of key-value pairs.
- *
- * @private
- * @param {Array} array The array to search.
- * @param {*} key The key to search for.
- * @returns {number} Returns the index of the matched value, else `-1`.
- */
- function assocIndexOf(array, key) {
- var length = array.length;
- while (length--) {
- if (eq(array[length][0], key)) {
- return length;
- }
- }
- return -1;
- }
-
- /**
* Aggregates elements of `collection` on `accumulator` with keys transformed
* by `iteratee` and values set by `setter`.
*
@@ -37970,7 +37930,7 @@ return jQuery;
* @private
* @param {Object} object The object to iterate over.
* @param {string[]} paths The property paths of elements to pick.
- * @returns {Array} Returns the picked elements.
+ * @returns {Array} Returns the new array of picked elements.
*/
function baseAt(object, paths) {
var index = -1,
@@ -38085,7 +38045,7 @@ return jQuery;
*
* @private
* @param {Object} source The object of property predicates to conform to.
- * @returns {Function} Returns the new spec function.
+ * @returns {Function} Returns the new function.
*/
function baseConforms(source) {
var props = keys(source),
@@ -38398,7 +38358,7 @@ return jQuery;
* @private
* @param {Object} object The object to inspect.
* @param {Array} props The property names to filter.
- * @returns {Array} Returns the function names.
+ * @returns {Array} Returns the new array of filtered property names.
*/
function baseFunctions(object, props) {
return arrayFilter(props, function(key) {
@@ -38439,7 +38399,9 @@ return jQuery;
*/
function baseGetAllKeys(object, keysFunc, symbolsFunc) {
var result = keysFunc(object);
- return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
+ return isArray(object)
+ ? result
+ : arrayPush(result, symbolsFunc(object));
}
/**
@@ -38831,7 +38793,7 @@ return jQuery;
*
* @private
* @param {Object} source The object of property values to match.
- * @returns {Function} Returns the new spec function.
+ * @returns {Function} Returns the new function.
*/
function baseMatches(source) {
var matchData = getMatchData(source);
@@ -38849,7 +38811,7 @@ return jQuery;
* @private
* @param {string} path The path of the property to get.
* @param {*} srcValue The value to match.
- * @returns {Function} Returns the new spec function.
+ * @returns {Function} Returns the new function.
*/
function baseMatchesProperty(path, srcValue) {
if (isKey(path) && isStrictComparable(srcValue)) {
@@ -39064,7 +39026,7 @@ return jQuery;
*
* @private
* @param {string} key The key of the property to get.
- * @returns {Function} Returns the new accessor function.
+ * @returns {Function} Returns the new function.
*/
function baseProperty(key) {
return function(object) {
@@ -39077,7 +39039,7 @@ return jQuery;
*
* @private
* @param {Array|string} path The path of the property to get.
- * @returns {Function} Returns the new accessor function.
+ * @returns {Function} Returns the new function.
*/
function basePropertyDeep(path) {
return function(object) {
@@ -39178,7 +39140,7 @@ return jQuery;
* @param {number} end The end of the range.
* @param {number} step The value to increment or decrement by.
* @param {boolean} [fromRight] Specify iterating from right to left.
- * @returns {Array} Returns the range of numbers.
+ * @returns {Array} Returns the new array of numbers.
*/
function baseRange(start, end, step, fromRight) {
var index = -1,
@@ -39892,7 +39854,7 @@ return jQuery;
* placeholders, and provided arguments into a single array of arguments.
*
* @private
- * @param {Array} args The provided arguments.
+ * @param {Array|Object} args The provided arguments.
* @param {Array} partials The arguments to prepend to those provided.
* @param {Array} holders The `partials` placeholder indexes.
* @params {boolean} [isCurried] Specify composing for a curried function.
@@ -39927,7 +39889,7 @@ return jQuery;
* is tailored for `_.partialRight`.
*
* @private
- * @param {Array} args The provided arguments.
+ * @param {Array|Object} args The provided arguments.
* @param {Array} partials The arguments to append to those provided.
* @param {Array} holders The `partials` placeholder indexes.
* @params {boolean} [isCurried] Specify composing for a curried function.
@@ -40049,7 +40011,7 @@ return jQuery;
customizer = length > 1 ? sources[length - 1] : undefined,
guard = length > 2 ? sources[2] : undefined;
- customizer = (assigner.length > 3 && typeof customizer == 'function')
+ customizer = typeof customizer == 'function'
? (length--, customizer)
: undefined;
@@ -40148,7 +40110,7 @@ return jQuery;
*
* @private
* @param {string} methodName The name of the `String` case method to use.
- * @returns {Function} Returns the new case function.
+ * @returns {Function} Returns the new function.
*/
function createCaseFirst(methodName) {
return function(string) {
@@ -40233,7 +40195,7 @@ return jQuery;
var length = arguments.length,
args = Array(length),
index = length,
- placeholder = getHolder(wrapper);
+ placeholder = getPlaceholder(wrapper);
while (index--) {
args[index] = arguments[index];
@@ -40348,14 +40310,14 @@ return jQuery;
function wrapper() {
var length = arguments.length,
- args = Array(length),
- index = length;
+ index = length,
+ args = Array(length);
while (index--) {
args[index] = arguments[index];
}
if (isCurried) {
- var placeholder = getHolder(wrapper),
+ var placeholder = getPlaceholder(wrapper),
holdersCount = countHolders(args, placeholder);
}
if (partials) {
@@ -40444,7 +40406,7 @@ return jQuery;
*
* @private
* @param {Function} arrayFunc The function to iterate over iteratees.
- * @returns {Function} Returns the new over function.
+ * @returns {Function} Returns the new invoker function.
*/
function createOver(arrayFunc) {
return rest(function(iteratees) {
@@ -40643,26 +40605,6 @@ return jQuery;
};
/**
- * Creates a `_.toPairs` or `_.toPairsIn` function.
- *
- * @private
- * @param {Function} keysFunc The function to get the keys of a given object.
- * @returns {Function} Returns the new pairs function.
- */
- function createToPairs(keysFunc) {
- return function(object) {
- var tag = getTag(object);
- if (tag == mapTag) {
- return mapToArray(object);
- }
- if (tag == setTag) {
- return setToPairs(object);
- }
- return baseToPairs(object, keysFunc(object));
- };
- }
-
- /**
* Creates a function that either curries or invokes `func` with optional
* `this` binding and partially applied arguments.
*
@@ -40679,7 +40621,6 @@ return jQuery;
* 64 - `_.partialRight`
* 128 - `_.rearg`
* 256 - `_.ary`
- * 512 - `_.flip`
* @param {*} [thisArg] The `this` binding of `func`.
* @param {Array} [partials] The arguments to be partially applied.
* @param {Array} [holders] The `partials` placeholder indexes.
@@ -40758,7 +40699,9 @@ return jQuery;
* @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
*/
function equalArrays(array, other, equalFunc, customizer, bitmask, stack) {
- var isPartial = bitmask & PARTIAL_COMPARE_FLAG,
+ var index = -1,
+ isPartial = bitmask & PARTIAL_COMPARE_FLAG,
+ isUnordered = bitmask & UNORDERED_COMPARE_FLAG,
arrLength = array.length,
othLength = other.length;
@@ -40770,10 +40713,7 @@ return jQuery;
if (stacked) {
return stacked == other;
}
- var index = -1,
- result = true,
- seen = (bitmask & UNORDERED_COMPARE_FLAG) ? new SetCache : undefined;
-
+ var result = true;
stack.set(array, other);
// Ignore non-index properties.
@@ -40794,12 +40734,10 @@ return jQuery;
break;
}
// Recursively compare arrays (susceptible to call stack limits).
- if (seen) {
- if (!arraySome(other, function(othValue, othIndex) {
- if (!seen.has(othIndex) &&
- (arrValue === othValue || equalFunc(arrValue, othValue, customizer, bitmask, stack))) {
- return seen.add(othIndex);
- }
+ if (isUnordered) {
+ if (!arraySome(other, function(othValue) {
+ return arrValue === othValue ||
+ equalFunc(arrValue, othValue, customizer, bitmask, stack);
})) {
result = false;
break;
@@ -41034,18 +40972,6 @@ return jQuery;
}
/**
- * Gets the argument placeholder value for `func`.
- *
- * @private
- * @param {Function} func The function to inspect.
- * @returns {*} Returns the placeholder value.
- */
- function getHolder(func) {
- var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func;
- return object.placeholder;
- }
-
- /**
* Gets the appropriate "iteratee" function. If `_.iteratee` is customized,
* this function returns the custom method, otherwise it returns `baseIteratee`.
* If arguments are provided, the chosen function is invoked with them and
@@ -41076,21 +41002,6 @@ return jQuery;
var getLength = baseProperty('length');
/**
- * Gets the data for `map`.
- *
- * @private
- * @param {Object} map The map to query.
- * @param {string} key The reference key.
- * @returns {*} Returns the map data.
- */
- function getMapData(map, key) {
- var data = map.__data__;
- return isKeyable(key)
- ? data[typeof key == 'string' ? 'string' : 'hash']
- : data.map;
- }
-
- /**
* Gets the property names, values, and compare flags of `object`.
*
* @private
@@ -41121,6 +41032,18 @@ return jQuery;
}
/**
+ * Gets the argument placeholder value for `func`.
+ *
+ * @private
+ * @param {Function} func The function to inspect.
+ * @returns {*} Returns the placeholder value.
+ */
+ function getPlaceholder(func) {
+ var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func;
+ return object.placeholder;
+ }
+
+ /**
* Gets the `[[Prototype]]` of `value`.
*
* @private
@@ -41369,7 +41292,7 @@ return jQuery;
* @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
*/
function isFlattenable(value) {
- return isArray(value) || isArguments(value);
+ return isArrayLikeObject(value) && (isArray(value) || isArguments(value));
}
/**
@@ -41513,7 +41436,7 @@ return jQuery;
* @private
* @param {string} key The key of the property to get.
* @param {*} srcValue The value to match.
- * @returns {Function} Returns the new spec function.
+ * @returns {Function} Returns the new function.
*/
function matchesStrictComparable(key, srcValue) {
return function(object) {
@@ -41765,7 +41688,7 @@ return jQuery;
* @param {Array} array The array to process.
* @param {number} [size=1] The length of each chunk
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
- * @returns {Array} Returns the new array of chunks.
+ * @returns {Array} Returns the new array containing chunks.
* @example
*
* _.chunk(['a', 'b', 'c', 'd'], 2);
@@ -41848,16 +41771,16 @@ return jQuery;
*/
function concat() {
var length = arguments.length,
- args = Array(length ? length - 1 : 0),
- array = arguments[0],
- index = length;
+ array = castArray(arguments[0]);
- while (index--) {
- args[index - 1] = arguments[index];
+ if (length < 2) {
+ return length ? copyArray(array) : [];
}
- return length
- ? arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1))
- : [];
+ var args = Array(length - 1);
+ while (length--) {
+ args[length - 1] = arguments[length];
+ }
+ return arrayConcat(array, baseFlatten(args, 1));
}
/**
@@ -42576,8 +42499,8 @@ return jQuery;
}
/**
- * Gets the element at `n` index of `array`. If `n` is negative, the nth
- * element from the end is returned.
+ * Gets the nth element of `array`. If `n` is negative, the nth element
+ * from the end is returned.
*
* @static
* @memberOf _
@@ -43457,7 +43380,7 @@ return jQuery;
* @memberOf _
* @since 0.1.0
* @category Array
- * @param {Array} array The array to inspect.
+ * @param {Array} array The array to filter.
* @param {...*} [values] The values to exclude.
* @returns {Array} Returns the new array of filtered values.
* @see _.difference, _.xor
@@ -43483,7 +43406,7 @@ return jQuery;
* @since 2.4.0
* @category Array
* @param {...Array} [arrays] The arrays to inspect.
- * @returns {Array} Returns the new array of filtered values.
+ * @returns {Array} Returns the new array of values.
* @see _.difference, _.without
* @example
*
@@ -43507,7 +43430,7 @@ return jQuery;
* @param {...Array} [arrays] The arrays to inspect.
* @param {Array|Function|Object|string} [iteratee=_.identity]
* The iteratee invoked per element.
- * @returns {Array} Returns the new array of filtered values.
+ * @returns {Array} Returns the new array of values.
* @example
*
* _.xorBy([2.1, 1.2], [4.3, 2.4], Math.floor);
@@ -43536,7 +43459,7 @@ return jQuery;
* @category Array
* @param {...Array} [arrays] The arrays to inspect.
* @param {Function} [comparator] The comparator invoked per element.
- * @returns {Array} Returns the new array of filtered values.
+ * @returns {Array} Returns the new array of values.
* @example
*
* var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
@@ -44284,8 +44207,9 @@ return jQuery;
* // => Logs 'a' then 'b' (iteration order is not guaranteed).
*/
function forEach(collection, iteratee) {
- var func = isArray(collection) ? arrayEach : baseEach;
- return func(collection, getIteratee(iteratee, 3));
+ return (typeof iteratee == 'function' && isArray(collection))
+ ? arrayEach(collection, iteratee)
+ : baseEach(collection, getIteratee(iteratee));
}
/**
@@ -44309,8 +44233,9 @@ return jQuery;
* // => Logs `2` then `1`.
*/
function forEachRight(collection, iteratee) {
- var func = isArray(collection) ? arrayEachRight : baseEachRight;
- return func(collection, getIteratee(iteratee, 3));
+ return (typeof iteratee == 'function' && isArray(collection))
+ ? arrayEachRight(collection, iteratee)
+ : baseEachRight(collection, getIteratee(iteratee));
}
/**
@@ -44991,7 +44916,7 @@ return jQuery;
* @param {Function} func The function to cap arguments for.
* @param {number} [n=func.length] The arity cap.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
- * @returns {Function} Returns the new capped function.
+ * @returns {Function} Returns the new function.
* @example
*
* _.map(['6', '8', '10'], _.ary(parseInt, 1));
@@ -45075,7 +45000,7 @@ return jQuery;
var bind = rest(function(func, thisArg, partials) {
var bitmask = BIND_FLAG;
if (partials.length) {
- var holders = replaceHolders(partials, getHolder(bind));
+ var holders = replaceHolders(partials, getPlaceholder(bind));
bitmask |= PARTIAL_FLAG;
}
return createWrapper(func, bitmask, thisArg, partials, holders);
@@ -45129,7 +45054,7 @@ return jQuery;
var bindKey = rest(function(object, key, partials) {
var bitmask = BIND_FLAG | BIND_KEY_FLAG;
if (partials.length) {
- var holders = replaceHolders(partials, getHolder(bindKey));
+ var holders = replaceHolders(partials, getPlaceholder(bindKey));
bitmask |= PARTIAL_FLAG;
}
return createWrapper(key, bitmask, object, partials, holders);
@@ -45455,7 +45380,7 @@ return jQuery;
* @since 4.0.0
* @category Function
* @param {Function} func The function to flip arguments for.
- * @returns {Function} Returns the new flipped function.
+ * @returns {Function} Returns the new function.
* @example
*
* var flipped = _.flip(function() {
@@ -45488,7 +45413,7 @@ return jQuery;
* @category Function
* @param {Function} func The function to have its output memoized.
* @param {Function} [resolver] The function to resolve the cache key.
- * @returns {Function} Returns the new memoized function.
+ * @returns {Function} Returns the new memoizing function.
* @example
*
* var object = { 'a': 1, 'b': 2 };
@@ -45546,7 +45471,7 @@ return jQuery;
* @since 3.0.0
* @category Function
* @param {Function} predicate The predicate to negate.
- * @returns {Function} Returns the new negated function.
+ * @returns {Function} Returns the new function.
* @example
*
* function isEven(n) {
@@ -45670,7 +45595,7 @@ return jQuery;
* // => 'hi fred'
*/
var partial = rest(function(func, partials) {
- var holders = replaceHolders(partials, getHolder(partial));
+ var holders = replaceHolders(partials, getPlaceholder(partial));
return createWrapper(func, PARTIAL_FLAG, undefined, partials, holders);
});
@@ -45707,7 +45632,7 @@ return jQuery;
* // => 'hello fred'
*/
var partialRight = rest(function(func, partials) {
- var holders = replaceHolders(partials, getHolder(partialRight));
+ var holders = replaceHolders(partials, getPlaceholder(partialRight));
return createWrapper(func, PARTIAL_RIGHT_FLAG, undefined, partials, holders);
});
@@ -45909,7 +45834,7 @@ return jQuery;
* @since 4.0.0
* @category Function
* @param {Function} func The function to cap arguments for.
- * @returns {Function} Returns the new capped function.
+ * @returns {Function} Returns the new function.
* @example
*
* _.map(['6', '8', '10'], _.unary(parseInt));
@@ -46585,13 +46510,13 @@ return jQuery;
* _.isFinite(3);
* // => true
*
- * _.isFinite(Number.MIN_VALUE);
+ * _.isFinite(Number.MAX_VALUE);
* // => true
*
- * _.isFinite(Infinity);
- * // => false
+ * _.isFinite(3.14);
+ * // => true
*
- * _.isFinite('3');
+ * _.isFinite(Infinity);
* // => false
*/
function isFinite(value) {
@@ -47314,41 +47239,6 @@ return jQuery;
}
/**
- * Converts `value` to a finite number.
- *
- * @static
- * @memberOf _
- * @since 4.12.0
- * @category Lang
- * @param {*} value The value to convert.
- * @returns {number} Returns the converted number.
- * @example
- *
- * _.toFinite(3.2);
- * // => 3.2
- *
- * _.toFinite(Number.MIN_VALUE);
- * // => 5e-324
- *
- * _.toFinite(Infinity);
- * // => 1.7976931348623157e+308
- *
- * _.toFinite('3.2');
- * // => 3.2
- */
- function toFinite(value) {
- if (!value) {
- return value === 0 ? value : 0;
- }
- value = toNumber(value);
- if (value === INFINITY || value === -INFINITY) {
- var sign = (value < 0 ? -1 : 1);
- return sign * MAX_INTEGER;
- }
- return value === value ? value : 0;
- }
-
- /**
* Converts `value` to an integer.
*
* **Note:** This function is loosely based on
@@ -47362,7 +47252,7 @@ return jQuery;
* @returns {number} Returns the converted integer.
* @example
*
- * _.toInteger(3.2);
+ * _.toInteger(3);
* // => 3
*
* _.toInteger(Number.MIN_VALUE);
@@ -47371,14 +47261,20 @@ return jQuery;
* _.toInteger(Infinity);
* // => 1.7976931348623157e+308
*
- * _.toInteger('3.2');
+ * _.toInteger('3');
* // => 3
*/
function toInteger(value) {
- var result = toFinite(value),
- remainder = result % 1;
-
- return result === result ? (remainder ? result - remainder : result) : 0;
+ if (!value) {
+ return value === 0 ? value : 0;
+ }
+ value = toNumber(value);
+ if (value === INFINITY || value === -INFINITY) {
+ var sign = (value < 0 ? -1 : 1);
+ return sign * MAX_INTEGER;
+ }
+ var remainder = value % 1;
+ return value === value ? (remainder ? value - remainder : value) : 0;
}
/**
@@ -47396,7 +47292,7 @@ return jQuery;
* @returns {number} Returns the converted integer.
* @example
*
- * _.toLength(3.2);
+ * _.toLength(3);
* // => 3
*
* _.toLength(Number.MIN_VALUE);
@@ -47405,7 +47301,7 @@ return jQuery;
* _.toLength(Infinity);
* // => 4294967295
*
- * _.toLength('3.2');
+ * _.toLength('3');
* // => 3
*/
function toLength(value) {
@@ -47423,8 +47319,8 @@ return jQuery;
* @returns {number} Returns the number.
* @example
*
- * _.toNumber(3.2);
- * // => 3.2
+ * _.toNumber(3);
+ * // => 3
*
* _.toNumber(Number.MIN_VALUE);
* // => 5e-324
@@ -47432,8 +47328,8 @@ return jQuery;
* _.toNumber(Infinity);
* // => Infinity
*
- * _.toNumber('3.2');
- * // => 3.2
+ * _.toNumber('3');
+ * // => 3
*/
function toNumber(value) {
if (typeof value == 'number') {
@@ -47496,7 +47392,7 @@ return jQuery;
* @returns {number} Returns the converted integer.
* @example
*
- * _.toSafeInteger(3.2);
+ * _.toSafeInteger(3);
* // => 3
*
* _.toSafeInteger(Number.MIN_VALUE);
@@ -47505,7 +47401,7 @@ return jQuery;
* _.toSafeInteger(Infinity);
* // => 9007199254740991
*
- * _.toSafeInteger('3.2');
+ * _.toSafeInteger('3');
* // => 3
*/
function toSafeInteger(value) {
@@ -47698,7 +47594,7 @@ return jQuery;
* @category Object
* @param {Object} object The object to iterate over.
* @param {...(string|string[])} [paths] The property paths of elements to pick.
- * @returns {Array} Returns the picked values.
+ * @returns {Array} Returns the new array of picked elements.
* @example
*
* var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
@@ -47914,7 +47810,7 @@ return jQuery;
function forIn(object, iteratee) {
return object == null
? object
- : baseFor(object, getIteratee(iteratee, 3), keysIn);
+ : baseFor(object, getIteratee(iteratee), keysIn);
}
/**
@@ -47946,7 +47842,7 @@ return jQuery;
function forInRight(object, iteratee) {
return object == null
? object
- : baseForRight(object, getIteratee(iteratee, 3), keysIn);
+ : baseForRight(object, getIteratee(iteratee), keysIn);
}
/**
@@ -47978,7 +47874,7 @@ return jQuery;
* // => Logs 'a' then 'b' (iteration order is not guaranteed).
*/
function forOwn(object, iteratee) {
- return object && baseForOwn(object, getIteratee(iteratee, 3));
+ return object && baseForOwn(object, getIteratee(iteratee));
}
/**
@@ -48008,7 +47904,7 @@ return jQuery;
* // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'.
*/
function forOwnRight(object, iteratee) {
- return object && baseForOwnRight(object, getIteratee(iteratee, 3));
+ return object && baseForOwnRight(object, getIteratee(iteratee));
}
/**
@@ -48020,7 +47916,7 @@ return jQuery;
* @memberOf _
* @category Object
* @param {Object} object The object to inspect.
- * @returns {Array} Returns the function names.
+ * @returns {Array} Returns the new array of property names.
* @see _.functionsIn
* @example
*
@@ -48047,7 +47943,7 @@ return jQuery;
* @since 4.0.0
* @category Object
* @param {Object} object The object to inspect.
- * @returns {Array} Returns the function names.
+ * @returns {Array} Returns the new array of property names.
* @see _.functions
* @example
*
@@ -48400,7 +48296,7 @@ return jQuery;
* inherited enumerable string keyed properties of source objects into the
* destination object. Source properties that resolve to `undefined` are
* skipped if a destination value exists. Array and plain object properties
- * are merged recursively. Other objects and value types are overridden by
+ * are merged recursively.Other objects and value types are overridden by
* assignment. Source objects are applied from left to right. Subsequent
* sources overwrite property assignments of previous sources.
*
@@ -48685,8 +48581,7 @@ return jQuery;
/**
* Creates an array of own enumerable string keyed-value pairs for `object`
- * which can be consumed by `_.fromPairs`. If `object` is a map or set, its
- * entries are returned.
+ * which can be consumed by `_.fromPairs`.
*
* @static
* @memberOf _
@@ -48694,7 +48589,7 @@ return jQuery;
* @alias entries
* @category Object
* @param {Object} object The object to query.
- * @returns {Array} Returns the key-value pairs.
+ * @returns {Array} Returns the new array of key-value pairs.
* @example
*
* function Foo() {
@@ -48707,12 +48602,13 @@ return jQuery;
* _.toPairs(new Foo);
* // => [['a', 1], ['b', 2]] (iteration order is not guaranteed)
*/
- var toPairs = createToPairs(keys);
+ function toPairs(object) {
+ return baseToPairs(object, keys(object));
+ }
/**
* Creates an array of own and inherited enumerable string keyed-value pairs
- * for `object` which can be consumed by `_.fromPairs`. If `object` is a map
- * or set, its entries are returned.
+ * for `object` which can be consumed by `_.fromPairs`.
*
* @static
* @memberOf _
@@ -48720,7 +48616,7 @@ return jQuery;
* @alias entriesIn
* @category Object
* @param {Object} object The object to query.
- * @returns {Array} Returns the key-value pairs.
+ * @returns {Array} Returns the new array of key-value pairs.
* @example
*
* function Foo() {
@@ -48731,9 +48627,11 @@ return jQuery;
* Foo.prototype.c = 3;
*
* _.toPairsIn(new Foo);
- * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed)
+ * // => [['a', 1], ['b', 2], ['c', 1]] (iteration order is not guaranteed)
*/
- var toPairsIn = createToPairs(keysIn);
+ function toPairsIn(object) {
+ return baseToPairs(object, keysIn(object));
+ }
/**
* An alternative to `_.reduce`; this method transforms `object` to a new
@@ -49563,7 +49461,7 @@ return jQuery;
* @param {string} [string=''] The string to split.
* @param {RegExp|string} separator The separator pattern to split by.
* @param {number} [limit] The length to truncate results to.
- * @returns {Array} Returns the string segments.
+ * @returns {Array} Returns the new array of string segments.
* @example
*
* _.split('a-b-c', '-', 2);
@@ -49708,6 +49606,12 @@ return jQuery;
* compiled({ 'user': 'pebbles' });
* // => 'hello pebbles!'
*
+ * // Use custom template delimiters.
+ * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
+ * var compiled = _.template('hello {{ user }}!');
+ * compiled({ 'user': 'mustache' });
+ * // => 'hello mustache!'
+ *
* // Use backslashes to treat delimiters as plain text.
* var compiled = _.template('<%= "\\<%- value %\\>" %>');
* compiled({ 'value': 'ignored' });
@@ -49733,15 +49637,9 @@ return jQuery;
* // return __p;
* // }
*
- * // Use custom template delimiters.
- * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
- * var compiled = _.template('hello {{ user }}!');
- * compiled({ 'user': 'mustache' });
- * // => 'hello mustache!'
- *
* // Use the `source` property to inline compiled templates for meaningful
* // line numbers in error messages and stack traces.
- * fs.writeFileSync(path.join(process.cwd(), 'jst.js'), '\
+ * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
* var JST = {\
* "main": ' + _.template(mainText).source + '\
* };\
@@ -50277,7 +50175,7 @@ return jQuery;
* @since 4.0.0
* @category Util
* @param {Array} pairs The predicate-function pairs.
- * @returns {Function} Returns the new composite function.
+ * @returns {Function} Returns the new function.
* @example
*
* var func = _.cond([
@@ -50327,7 +50225,7 @@ return jQuery;
* @since 4.0.0
* @category Util
* @param {Object} source The object of property predicates to conform to.
- * @returns {Function} Returns the new spec function.
+ * @returns {Function} Returns the new function.
* @example
*
* var users = [
@@ -50350,7 +50248,7 @@ return jQuery;
* @since 2.4.0
* @category Util
* @param {*} value The value to return from the new function.
- * @returns {Function} Returns the new constant function.
+ * @returns {Function} Returns the new function.
* @example
*
* var object = { 'user': 'fred' };
@@ -50375,7 +50273,7 @@ return jQuery;
* @since 3.0.0
* @category Util
* @param {...(Function|Function[])} [funcs] Functions to invoke.
- * @returns {Function} Returns the new composite function.
+ * @returns {Function} Returns the new function.
* @see _.flowRight
* @example
*
@@ -50398,7 +50296,7 @@ return jQuery;
* @memberOf _
* @category Util
* @param {...(Function|Function[])} [funcs] Functions to invoke.
- * @returns {Function} Returns the new composite function.
+ * @returns {Function} Returns the new function.
* @see _.flow
* @example
*
@@ -50491,7 +50389,7 @@ return jQuery;
* @since 3.0.0
* @category Util
* @param {Object} source The object of property values to match.
- * @returns {Function} Returns the new spec function.
+ * @returns {Function} Returns the new function.
* @example
*
* var users = [
@@ -50519,7 +50417,7 @@ return jQuery;
* @category Util
* @param {Array|string} path The path of the property to get.
* @param {*} srcValue The value to match.
- * @returns {Function} Returns the new spec function.
+ * @returns {Function} Returns the new function.
* @example
*
* var users = [
@@ -50544,7 +50442,7 @@ return jQuery;
* @category Util
* @param {Array|string} path The path of the method to invoke.
* @param {...*} [args] The arguments to invoke the method with.
- * @returns {Function} Returns the new invoker function.
+ * @returns {Function} Returns the new function.
* @example
*
* var objects = [
@@ -50575,7 +50473,7 @@ return jQuery;
* @category Util
* @param {Object} object The object to query.
* @param {...*} [args] The arguments to invoke the method with.
- * @returns {Function} Returns the new invoker function.
+ * @returns {Function} Returns the new function.
* @example
*
* var array = _.times(3, _.constant),
@@ -50705,7 +50603,7 @@ return jQuery;
}
/**
- * Creates a function that gets the argument at `n` index. If `n` is negative,
+ * Creates a function that returns its nth argument. If `n` is negative,
* the nth argument from the end is returned.
*
* @static
@@ -50713,7 +50611,7 @@ return jQuery;
* @since 4.0.0
* @category Util
* @param {number} [n=0] The index of the argument to return.
- * @returns {Function} Returns the new pass-thru function.
+ * @returns {Function} Returns the new function.
* @example
*
* var func = _.nthArg(1);
@@ -50811,7 +50709,7 @@ return jQuery;
* @since 2.4.0
* @category Util
* @param {Array|string} path The path of the property to get.
- * @returns {Function} Returns the new accessor function.
+ * @returns {Function} Returns the new function.
* @example
*
* var objects = [
@@ -50838,7 +50736,7 @@ return jQuery;
* @since 3.0.0
* @category Util
* @param {Object} object The object to query.
- * @returns {Function} Returns the new accessor function.
+ * @returns {Function} Returns the new function.
* @example
*
* var array = [0, 1, 2],
@@ -50872,7 +50770,7 @@ return jQuery;
* @param {number} [start=0] The start of the range.
* @param {number} end The end of the range.
* @param {number} [step=1] The value to increment or decrement by.
- * @returns {Array} Returns the range of numbers.
+ * @returns {Array} Returns the new array of numbers.
* @see _.inRange, _.rangeRight
* @example
*
@@ -50910,7 +50808,7 @@ return jQuery;
* @param {number} [start=0] The start of the range.
* @param {number} end The end of the range.
* @param {number} [step=1] The value to increment or decrement by.
- * @returns {Array} Returns the range of numbers.
+ * @returns {Array} Returns the new array of numbers.
* @see _.inRange, _.range
* @example
*
@@ -51671,7 +51569,6 @@ return jQuery;
lodash.sumBy = sumBy;
lodash.template = template;
lodash.times = times;
- lodash.toFinite = toFinite;
lodash.toInteger = toInteger;
lodash.toLength = toLength;
lodash.toLower = toLower;
diff --git a/netlib/tcp.py b/netlib/tcp.py
index 914aa701..de12102e 100644
--- a/netlib/tcp.py
+++ b/netlib/tcp.py
@@ -6,6 +6,7 @@ import sys
import threading
import time
import traceback
+import contextlib
import binascii
from six.moves import range
@@ -577,6 +578,12 @@ class _Connection(object):
return context
+@contextlib.contextmanager
+def _closer(client):
+ yield
+ client.close()
+
+
class TCPClient(_Connection):
def __init__(self, address, source_address=None):
@@ -708,6 +715,7 @@ class TCPClient(_Connection):
self.connection = connection
self.ip_address = Address(connection.getpeername())
self._makefile()
+ return _closer(self)
def settimeout(self, n):
self.connection.settimeout(n)
@@ -833,6 +841,25 @@ class BaseHandler(_Connection):
return b""
+class Counter:
+ def __init__(self):
+ self._count = 0
+ self._lock = threading.Lock()
+
+ @property
+ def count(self):
+ with self._lock:
+ return self._count
+
+ def __enter__(self):
+ with self._lock:
+ self._count += 1
+
+ def __exit__(self, *args):
+ with self._lock:
+ self._count -= 1
+
+
class TCPServer(object):
request_queue_size = 20
@@ -845,15 +872,17 @@ class TCPServer(object):
self.socket.bind(self.address())
self.address = Address.wrap(self.socket.getsockname())
self.socket.listen(self.request_queue_size)
+ self.handler_counter = Counter()
def connection_thread(self, connection, client_address):
- client_address = Address(client_address)
- try:
- self.handle_client_connection(connection, client_address)
- except:
- self.handle_error(connection, client_address)
- finally:
- close_socket(connection)
+ with self.handler_counter:
+ client_address = Address(client_address)
+ try:
+ self.handle_client_connection(connection, client_address)
+ except:
+ self.handle_error(connection, client_address)
+ finally:
+ close_socket(connection)
def serve_forever(self, poll_interval=0.1):
self.__is_shut_down.clear()
diff --git a/pathod/language/generators.py b/pathod/language/generators.py
index a17e7052..9fff3082 100644
--- a/pathod/language/generators.py
+++ b/pathod/language/generators.py
@@ -2,17 +2,19 @@ import string
import random
import mmap
+import six
+
DATATYPES = dict(
- ascii_letters=string.ascii_letters,
- ascii_lowercase=string.ascii_lowercase,
- ascii_uppercase=string.ascii_uppercase,
- digits=string.digits,
- hexdigits=string.hexdigits,
- octdigits=string.octdigits,
- punctuation=string.punctuation,
- whitespace=string.whitespace,
- ascii=string.printable,
- bytes="".join(chr(i) for i in range(256))
+ ascii_letters=string.ascii_letters.encode(),
+ ascii_lowercase=string.ascii_lowercase.encode(),
+ ascii_uppercase=string.ascii_uppercase.encode(),
+ digits=string.digits.encode(),
+ hexdigits=string.hexdigits.encode(),
+ octdigits=string.octdigits.encode(),
+ punctuation=string.punctuation.encode(),
+ whitespace=string.whitespace.encode(),
+ ascii=string.printable.encode(),
+ bytes=bytes(bytearray(range(256)))
)
@@ -35,16 +37,25 @@ class TransformGenerator(object):
def __getitem__(self, x):
d = self.gen.__getitem__(x)
+ if isinstance(x, slice):
+ return self.transform(x.start, d)
return self.transform(x, d)
- def __getslice__(self, a, b):
- d = self.gen.__getslice__(a, b)
- return self.transform(a, d)
-
def __repr__(self):
return "'transform(%s)'" % self.gen
+def rand_byte(chars):
+ """
+ Return a random character as byte from a charset.
+ """
+ # bytearray has consistent behaviour on both Python 2 and 3
+ # while bytes does not
+ if six.PY2:
+ return random.choice(chars)
+ return bytes([random.choice(chars)])
+
+
class RandomGenerator(object):
def __init__(self, dtype, length):
@@ -55,12 +66,10 @@ class RandomGenerator(object):
return self.length
def __getitem__(self, x):
- return random.choice(DATATYPES[self.dtype])
-
- def __getslice__(self, a, b):
- b = min(b, self.length)
chars = DATATYPES[self.dtype]
- return "".join(random.choice(chars) for x in range(a, b))
+ if isinstance(x, slice):
+ return b"".join(rand_byte(chars) for _ in range(*x.indices(self.length)))
+ return rand_byte(chars)
def __repr__(self):
return "%s random from %s" % (self.length, self.dtype)
@@ -70,17 +79,17 @@ class FileGenerator(object):
def __init__(self, path):
self.path = path
- self.fp = file(path, "rb")
+ self.fp = open(path, "rb")
self.map = mmap.mmap(self.fp.fileno(), 0, access=mmap.ACCESS_READ)
def __len__(self):
return len(self.map)
def __getitem__(self, x):
- return self.map.__getitem__(x)
-
- def __getslice__(self, a, b):
- return self.map.__getslice__(a, b)
+ if isinstance(x, slice):
+ return self.map.__getitem__(x)
+ # A slice of length 1 returns a byte object (not an integer)
+ return self.map.__getitem__(slice(x, x + 1 or self.map.size()))
def __repr__(self):
return "<%s" % self.path
diff --git a/pathod/pathoc.py b/pathod/pathoc.py
index 2b7d053c..5cfb4591 100644
--- a/pathod/pathoc.py
+++ b/pathod/pathoc.py
@@ -286,7 +286,7 @@ class Pathoc(tcp.TCPClient):
if self.use_http2 and not self.ssl:
raise NotImplementedError("HTTP2 without SSL is not supported.")
- tcp.TCPClient.connect(self)
+ ret = tcp.TCPClient.connect(self)
if connect_to:
self.http_connect(connect_to)
@@ -324,6 +324,7 @@ class Pathoc(tcp.TCPClient):
if self.timeout:
self.settimeout(self.timeout)
+ return ret
def stop(self):
if self.ws_framereader:
diff --git a/pathod/pathod.py b/pathod/pathod.py
index 7795df0e..0449c0c1 100644
--- a/pathod/pathod.py
+++ b/pathod/pathod.py
@@ -353,6 +353,8 @@ class Pathod(tcp.TCPServer):
staticdir=self.staticdir
)
+ self.loglock = threading.Lock()
+
def check_policy(self, req, settings):
"""
A policy check that verifies the request size is within limits.
@@ -403,8 +405,7 @@ class Pathod(tcp.TCPServer):
def add_log(self, d):
if not self.noapi:
- lock = threading.Lock()
- with lock:
+ with self.loglock:
d["id"] = self.logid
self.log.insert(0, d)
if len(self.log) > self.LOGBUF:
@@ -413,17 +414,18 @@ class Pathod(tcp.TCPServer):
return d["id"]
def clear_log(self):
- lock = threading.Lock()
- with lock:
+ with self.loglock:
self.log = []
def log_by_id(self, identifier):
- for i in self.log:
- if i["id"] == identifier:
- return i
+ with self.loglock:
+ for i in self.log:
+ if i["id"] == identifier:
+ return i
def get_log(self):
- return self.log
+ with self.loglock:
+ return self.log
def main(args): # pragma: no cover
diff --git a/pathod/protocols/websockets.py b/pathod/protocols/websockets.py
index 134d27bc..2b60e618 100644
--- a/pathod/protocols/websockets.py
+++ b/pathod/protocols/websockets.py
@@ -18,7 +18,7 @@ class WebsocketsProtocol:
frm = websockets.Frame.from_file(self.pathod_handler.rfile)
except NetlibException as e:
lg("Error reading websocket frame: %s" % e)
- break
+ return None, None
ended = time.time()
lg(frm.human_readable())
retlog = dict(
diff --git a/pathod/test.py b/pathod/test.py
index 23b7a5b6..11462729 100644
--- a/pathod/test.py
+++ b/pathod/test.py
@@ -1,12 +1,14 @@
from six.moves import cStringIO as StringIO
import threading
+import time
+
from six.moves import queue
-import requests
-import requests.packages.urllib3
from . import pathod
-requests.packages.urllib3.disable_warnings()
+
+class TimeoutError(Exception):
+ pass
class Daemon:
@@ -39,39 +41,51 @@ class Daemon:
"""
return "%s/p/%s" % (self.urlbase, spec)
- def info(self):
- """
- Return some basic info about the remote daemon.
- """
- resp = requests.get("%s/api/info" % self.urlbase, verify=False)
- return resp.json()
-
def text_log(self):
return self.logfp.getvalue()
+ def wait_for_silence(self, timeout=5):
+ start = time.time()
+ while 1:
+ if time.time() - start >= timeout:
+ raise TimeoutError(
+ "%s service threads still alive" %
+ self.thread.server.handler_counter.count
+ )
+ if self.thread.server.handler_counter.count == 0:
+ return
+
+ def expect_log(self, n, timeout=5):
+ l = []
+ start = time.time()
+ while True:
+ l = self.log()
+ if time.time() - start >= timeout:
+ return None
+ if len(l) >= n:
+ break
+ return l
+
def last_log(self):
"""
Returns the last logged request, or None.
"""
- l = self.log()
+ l = self.expect_log(1)
if not l:
return None
- return l[0]
+ return l[-1]
def log(self):
"""
Return the log buffer as a list of dictionaries.
"""
- resp = requests.get("%s/api/log" % self.urlbase, verify=False)
- return resp.json()["log"]
+ return self.thread.server.get_log()
def clear_log(self):
"""
Clear the log.
"""
- self.logfp.truncate(0)
- resp = requests.get("%s/api/clear_log" % self.urlbase, verify=False)
- return resp.ok
+ return self.thread.server.clear_log()
def shutdown(self):
"""
@@ -88,6 +102,7 @@ class _PaThread(threading.Thread):
self.name = "PathodThread"
self.iface, self.q, self.ssl = iface, q, ssl
self.daemonargs = daemonargs
+ self.server = None
def run(self):
self.server = pathod.Pathod(
diff --git a/setup.cfg b/setup.cfg
index e83ca0ab..eeaac0c8 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -11,8 +11,7 @@ addopts = --capture=no
[coverage:run]
branch = True
-include = *mitmproxy*, *netlib*, *pathod*
-omit = *contrib*, *tnetstring*, *platform*, *console*, *main.py
+omit = *contrib*, *tnetstring*, *platform*, *main.py
[coverage:report]
show_missing = True
diff --git a/test/pathod/test_app.py b/test/pathod/test_app.py
index ac89c44c..fbaa773c 100644
--- a/test/pathod/test_app.py
+++ b/test/pathod/test_app.py
@@ -11,11 +11,11 @@ class TestApp(tutils.DaemonTests):
def test_about(self):
r = self.getpath("/about")
- assert r.ok
+ assert r.status_code == 200
def test_download(self):
r = self.getpath("/download")
- assert r.ok
+ assert r.status_code == 200
def test_docs(self):
assert self.getpath("/docs/pathod").status_code == 200
@@ -27,7 +27,7 @@ class TestApp(tutils.DaemonTests):
def test_log(self):
assert self.getpath("/log").status_code == 200
assert self.get("200:da").status_code == 200
- id = self.d.log()[0]["id"]
+ id = self.d.expect_log(1)[0]["id"]
assert self.getpath("/log").status_code == 200
assert self.getpath("/log/%s" % id).status_code == 200
assert self.getpath("/log/9999999").status_code == 404
diff --git a/test/pathod/test_language_generators.py b/test/pathod/test_language_generators.py
index 0fceae85..51f55991 100644
--- a/test/pathod/test_language_generators.py
+++ b/test/pathod/test_language_generators.py
@@ -7,24 +7,27 @@ import tutils
def test_randomgenerator():
g = generators.RandomGenerator("bytes", 100)
assert repr(g)
+ assert g[0]
+ assert len(g[0]) == 1
assert len(g[:10]) == 10
assert len(g[1:10]) == 9
assert len(g[:1000]) == 100
assert len(g[1000:1001]) == 0
- assert g[0]
def test_filegenerator():
with tutils.tmpdir() as t:
path = os.path.join(t, "foo")
f = open(path, "wb")
- f.write("x" * 10000)
+ f.write(b"x" * 10000)
f.close()
g = generators.FileGenerator(path)
assert len(g) == 10000
- assert g[0] == "x"
- assert g[-1] == "x"
- assert g[0:5] == "xxxxx"
+ assert g[0] == b"x"
+ assert g[-1] == b"x"
+ assert g[0:5] == b"xxxxx"
+ assert len(g[1:10]) == 9
+ assert len(g[10000:10001]) == 0
assert repr(g)
# remove all references to FileGenerator instance to close the file
# handle.
diff --git a/test/pathod/test_pathod.py b/test/pathod/test_pathod.py
index 4d969158..ec9c169f 100644
--- a/test/pathod/test_pathod.py
+++ b/test/pathod/test_pathod.py
@@ -1,7 +1,6 @@
from six.moves import cStringIO as StringIO
-import pytest
-from pathod import pathod, version
+from pathod import pathod
from netlib import tcp
from netlib.exceptions import HttpException, TlsException
import tutils
@@ -129,7 +128,6 @@ class CommonTests(tutils.DaemonTests):
assert self.d.last_log()
# FIXME: Other binary data elements
- @pytest.mark.skip(reason="race condition")
def test_sizelimit(self):
r = self.get("200:b@1g")
assert r.status_code == 800
@@ -140,21 +138,15 @@ class CommonTests(tutils.DaemonTests):
r, _ = self.pathoc([r"get:'/p/200':i0,'\r\n'"])
assert r[0].status_code == 200
- def test_info(self):
- assert tuple(self.d.info()["version"]) == version.IVERSION
-
- @pytest.mark.skip(reason="race condition")
def test_logs(self):
- assert self.d.clear_log()
- assert not self.d.last_log()
+ self.d.clear_log()
assert self.get("202:da")
- assert len(self.d.log()) == 1
- assert self.d.clear_log()
+ assert self.d.expect_log(1)
+ self.d.clear_log()
assert len(self.d.log()) == 0
def test_disconnect(self):
- rsp = self.get("202:b@100k:d200")
- assert len(rsp.content) < 200
+ tutils.raises("unexpected eof", self.get, "202:b@100k:d200")
def test_parserr(self):
rsp = self.get("400:msg,b:")
@@ -166,7 +158,7 @@ class CommonTests(tutils.DaemonTests):
assert rsp.content.strip() == "testfile"
def test_anchor(self):
- rsp = self.getpath("anchor/foo")
+ rsp = self.getpath("/anchor/foo")
assert rsp.status_code == 202
def test_invalid_first_line(self):
@@ -223,7 +215,6 @@ class CommonTests(tutils.DaemonTests):
)
assert r[1].payload == "test"
- @pytest.mark.skip(reason="race condition")
def test_websocket_frame_reflect_error(self):
r, _ = self.pathoc(
["ws:/p/", "wf:-mask:knone:f'wf:b@10':i13,'a'"],
@@ -233,7 +224,6 @@ class CommonTests(tutils.DaemonTests):
# FIXME: Race Condition?
assert "Parse error" in self.d.text_log()
- @pytest.mark.skip(reason="race condition")
def test_websocket_frame_disconnect_error(self):
self.pathoc(["ws:/p/", "wf:b@10:d3"], ws_read_limit=0)
assert self.d.last_log()
diff --git a/test/pathod/test_test.py b/test/pathod/test_test.py
index cee286a4..6399894e 100644
--- a/test/pathod/test_test.py
+++ b/test/pathod/test_test.py
@@ -2,6 +2,10 @@ import logging
import requests
from pathod import test
import tutils
+
+import requests.packages.urllib3
+
+requests.packages.urllib3.disable_warnings()
logging.disable(logging.CRITICAL)
diff --git a/test/pathod/tutils.py b/test/pathod/tutils.py
index f7bb22e5..b9f38d86 100644
--- a/test/pathod/tutils.py
+++ b/test/pathod/tutils.py
@@ -3,6 +3,7 @@ import re
import shutil
import requests
from six.moves import cStringIO as StringIO
+import urllib
from netlib import tcp
from netlib import utils
@@ -63,10 +64,11 @@ class DaemonTests(object):
shutil.rmtree(cls.confdir)
def teardown(self):
+ self.d.wait_for_silence()
if not (self.noweb or self.noapi):
self.d.clear_log()
- def getpath(self, path, params=None):
+ def _getpath(self, path, params=None):
scheme = "https" if self.ssl else "http"
resp = requests.get(
"%s://localhost:%s/%s" % (
@@ -79,9 +81,29 @@ class DaemonTests(object):
)
return resp
+ def getpath(self, path, params=None):
+ logfp = StringIO()
+ c = pathoc.Pathoc(
+ ("localhost", self.d.port),
+ ssl=self.ssl,
+ fp=logfp,
+ )
+ with c.connect():
+ if params:
+ path = path + "?" + urllib.urlencode(params)
+ resp = c.request("get:%s" % path)
+ return resp
+
def get(self, spec):
- resp = requests.get(self.d.p(spec), verify=False)
- return resp
+ logfp = StringIO()
+ c = pathoc.Pathoc(
+ ("localhost", self.d.port),
+ ssl=self.ssl,
+ fp=logfp,
+ )
+ with c.connect():
+ resp = c.request("get:/p/%s" % urllib.quote(spec).encode("string_escape"))
+ return resp
def pathoc(
self,
@@ -106,16 +128,16 @@ class DaemonTests(object):
fp=logfp,
use_http2=use_http2,
)
- c.connect(connect_to)
- ret = []
- for i in specs:
- resp = c.request(i)
- if resp:
- ret.append(resp)
- for frm in c.wait():
- ret.append(frm)
- c.stop()
- return ret, logfp.getvalue()
+ with c.connect(connect_to):
+ ret = []
+ for i in specs:
+ resp = c.request(i)
+ if resp:
+ ret.append(resp)
+ for frm in c.wait():
+ ret.append(frm)
+ c.stop()
+ return ret, logfp.getvalue()
tmpdir = tutils.tmpdir
diff --git a/web/.babelrc b/web/.babelrc
index 5dd7708c..e2d67e33 100644
--- a/web/.babelrc
+++ b/web/.babelrc
@@ -1,4 +1,4 @@
{
"presets": ["es2015", "react"],
- "plugins": ["transform-class-properties"]
+ "plugins": ["transform-class-properties", "transform-object-rest-spread"]
} \ No newline at end of file
diff --git a/web/package.json b/web/package.json
index 2eaac445..88e976e1 100644
--- a/web/package.json
+++ b/web/package.json
@@ -30,6 +30,7 @@
"babel-core": "^6.7.7",
"babel-jest": "^12.0.2",
"babel-plugin-transform-class-properties": "^6.6.0",
+ "babel-plugin-transform-object-rest-spread": "^6.8.0",
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.5.0",
"babelify": "^7.3.0",