postman-url-encoder
Advanced tools
Comparing version 1.0.3 to 2.0.0
408
index.js
@@ -1,242 +0,248 @@ | ||
var url = require('url'), | ||
/** | ||
* Implementation of the WHATWG URL Standard. | ||
* | ||
* @example | ||
* const urlEncoder = require('postman-url-encoder') | ||
* | ||
* // Encoding URL string to Node.js compatible Url object | ||
* urlEncoder.toNodeUrl('郵便屋さん.com/foo&bar/{baz}?q=("foo")#`hash`') | ||
* | ||
* // Encoding URI component | ||
* urlEncoder.encode('qüêry štrìng') | ||
* | ||
* // Encoding query string object | ||
* urlEncoder.encodeQueryString({ q1: 'foo', q2: ['bãr', 'baž'] }) | ||
* | ||
* @module postman-url-encoder | ||
* @see {@link https://url.spec.whatwg.org} | ||
*/ | ||
/** | ||
* @private | ||
* @const | ||
* @type {String} | ||
*/ | ||
const sdk = require('postman-collection'), | ||
querystring = require('querystring'), | ||
legacy = require('./legacy'), | ||
encoder = require('./encoder'), | ||
QUERY_ENCODE_SET = require('./encoder/encode-set').QUERY_ENCODE_SET, | ||
E = '', | ||
COLON = ':', | ||
STRING = 'string', | ||
OBJECT = 'object', | ||
FUNCTION = 'function', | ||
DOUBLE_SLASH = '//', | ||
DEFAULT_PROTOCOL = 'http', | ||
/** | ||
* @private | ||
* @const | ||
* @type {String} | ||
*/ | ||
QUERY_SEPARATOR = '?', | ||
SEARCH_SEPARATOR = '#', | ||
PROTOCOL_SEPARATOR = '://', | ||
AUTH_CREDENTIALS_SEPARATOR = '@', | ||
/** | ||
* Protocols that always contain a // bit. | ||
* | ||
* @private | ||
* @const | ||
* @type {String} | ||
* @see {@link https://github.com/nodejs/node/blob/v10.17.0/lib/url.js#L91} | ||
*/ | ||
AMPERSAND = '&', | ||
SLASHED_PROTOCOLS = { | ||
'file:': true, | ||
'ftp:': true, | ||
'gopher:': true, | ||
'http:': true, | ||
'https:': true, | ||
'ws:': true, | ||
'wss:': true | ||
}; | ||
/** | ||
* @private | ||
* @const | ||
* @type {String} | ||
*/ | ||
EQUALS = '=', | ||
/** | ||
* Percent-encode the given string using QUERY_ENCODE_SET. | ||
* | ||
* @deprecated since version 2.0, use {@link encodeQueryParam} instead. | ||
* | ||
* @example | ||
* // returns 'foo%20%22%23%26%27%3C%3D%3E%20bar' | ||
* encode('foo "#&\'<=> bar') | ||
* | ||
* // returns '' | ||
* encode(['foobar']) | ||
* | ||
* @param {String} value String to percent-encode | ||
* @returns {String} Percent-encoded string | ||
*/ | ||
function encode (value) { | ||
return encoder.percentEncode(value, QUERY_ENCODE_SET); | ||
} | ||
/** | ||
* @private | ||
* @const | ||
* @type {String} | ||
*/ | ||
PERCENT = '%', | ||
/** | ||
* Percent-encode the URL query string or x-www-form-urlencoded body object | ||
* according to RFC3986. | ||
* | ||
* @example | ||
* // returns 'q1=foo&q2=bar&q2=baz' | ||
* encodeQueryString({ q1: 'foo', q2: ['bar', 'baz'] }) | ||
* | ||
* @param {Object} query Object representing query or urlencoded body | ||
* @returns {String} Percent-encoded string | ||
*/ | ||
function encodeQueryString (query) { | ||
if (!(query && typeof query === OBJECT)) { | ||
return E; | ||
} | ||
/** | ||
* @private | ||
* @const | ||
* @type {string} | ||
*/ | ||
ZERO = '0', | ||
// rely upon faster querystring module | ||
query = querystring.stringify(query); | ||
/** | ||
* @private | ||
* @const | ||
* @type {string} | ||
*/ | ||
STRING = 'string', | ||
// encode characters not encoded by querystring.stringify() according to RFC3986. | ||
return query.replace(/[!'()*]/g, function (c) { | ||
return encoder.percentEncodeCharCode(c.charCodeAt(0)); | ||
}); | ||
} | ||
parseQueryString, | ||
stringifyQueryParams, | ||
encoder; | ||
/** | ||
* Parses a query string into an array, preserving parameter values | ||
* Note: This function is temporary. It will be removed once we implement our own encoding | ||
* instead of url.parse(). | ||
* Converts PostmanUrl / URL string into Node.js compatible Url object. | ||
* | ||
* @param string | ||
* @returns {*} | ||
* @example <caption>Using URL string</caption> | ||
* toNodeUrl('郵便屋さん.com/foo&bar/{baz}?q=("foo")#`hash`') | ||
* // returns | ||
* // { | ||
* // protocol: 'http:', | ||
* // slashes: true, | ||
* // auth: null, | ||
* // host: 'xn--48jwgn17gdel797d.com', | ||
* // port: null, | ||
* // hostname: 'xn--48jwgn17gdel797d.com', | ||
* // hash: '#%60hash%60', | ||
* // search: '?q=(%22foo%22)', | ||
* // query: 'q=(%22foo%22)', | ||
* // pathname: '/foo&bar/%7Bbaz%7D', | ||
* // path: '/foo&bar/%7Bbaz%7D?q=(%22foo%22)', | ||
* // href: 'http://xn--48jwgn17gdel797d.com/foo&bar/%7Bbaz%7D?q=(%22foo%22)#%60hash%60' | ||
* // } | ||
* | ||
* @example <caption>Using PostmanUrl instance</caption> | ||
* toNodeUrl(new sdk.Url({ | ||
* host: 'example.com', | ||
* query: [{ key: 'foo', value: 'bar & baz' }] | ||
* })) | ||
* | ||
* @param {PostmanUrl|String} url | ||
* @returns {Url} | ||
*/ | ||
parseQueryString = function (string) { | ||
var parts; | ||
function toNodeUrl (url) { | ||
var nodeUrl = { | ||
protocol: null, | ||
slashes: null, | ||
auth: null, | ||
host: null, | ||
port: null, | ||
hostname: null, | ||
hash: null, | ||
search: null, | ||
query: null, | ||
pathname: null, | ||
path: null, | ||
href: E | ||
}; | ||
if (typeof string === STRING) { | ||
parts = string.split(AMPERSAND); | ||
// convert URL string to PostmanUrl | ||
if (typeof url === STRING) { | ||
url = new sdk.Url(url); | ||
} | ||
return parts.map(function (param, idx) { | ||
if (param === E && idx !== (parts.length - 1)) { | ||
return { key: null, value: null }; | ||
} | ||
var index = (typeof param === STRING) ? param.indexOf(EQUALS) : -1, | ||
paramObj = {}; | ||
// this means that there was no value for this key (not even blank, so we store this info) and the value is set | ||
// to null | ||
if (index < 0) { | ||
paramObj.key = param.substr(0, param.length); | ||
paramObj.value = null; | ||
} else { | ||
paramObj.key = param.substr(0, index); | ||
paramObj.value = param.substr(index + 1); | ||
} | ||
return paramObj; | ||
}); | ||
// bail out if given url is not a PostmanUrl instance | ||
if (!sdk.Url.isUrl(url)) { | ||
return nodeUrl; | ||
} | ||
return []; | ||
}; | ||
// #protocol | ||
nodeUrl.protocol = (typeof url.protocol === STRING) ? | ||
url.protocol.replace(PROTOCOL_SEPARATOR, E).toLowerCase() : | ||
DEFAULT_PROTOCOL; | ||
nodeUrl.protocol += COLON; | ||
/** | ||
* Stringifies a query string, from an array of parameters | ||
* Note: This function is temporary. It will be removed once we implement our own encoding | ||
* instead of url.parse(). | ||
* | ||
* @param parameters | ||
* @returns {string} | ||
*/ | ||
stringifyQueryParams = function (parameters) { | ||
return parameters ? parameters.map(function (param) { | ||
var key = param.key; | ||
var value = param.value; | ||
// #slashes | ||
nodeUrl.slashes = SLASHED_PROTOCOLS[nodeUrl.protocol] || false; | ||
if (value === undefined) { | ||
return E; | ||
} | ||
// #href = protocol:// | ||
nodeUrl.href = nodeUrl.protocol + DOUBLE_SLASH; | ||
if (key === null) { | ||
key = E; | ||
} | ||
// #auth | ||
if (url.auth) { | ||
if (typeof url.auth.user === STRING) { | ||
nodeUrl.auth = encoder.encodeUserInfo(url.auth.user); | ||
} | ||
if (typeof url.auth.password === STRING) { | ||
!nodeUrl.auth && (nodeUrl.auth = E); | ||
nodeUrl.auth += COLON + encoder.encodeUserInfo(url.auth.password); | ||
} | ||
if (value === null) { | ||
return encoder.encode(key); | ||
} | ||
// #href = protocol://user:password@ | ||
nodeUrl.auth && (nodeUrl.href += nodeUrl.auth + AUTH_CREDENTIALS_SEPARATOR); | ||
} | ||
return encoder.encode(key) + EQUALS + encoder.encode(value); | ||
}).join(AMPERSAND) : E; | ||
}; | ||
// #host, #hostname | ||
nodeUrl.host = nodeUrl.hostname = encoder.encodeHost(url.getHost()).toLowerCase(); | ||
encoder = { | ||
// #href = protocol://user:password@host.name | ||
nodeUrl.href += nodeUrl.hostname; | ||
/** | ||
* Percent encode a character with given code. | ||
* | ||
* @param {Number} c - character code of the character to encode | ||
* @returns {String} - percent encoding of given character | ||
*/ | ||
percentEncode: function(c) { | ||
var hex = c.toString(16).toUpperCase(); | ||
(hex.length === 1) && (hex = ZERO + hex); | ||
return PERCENT + hex; | ||
}, | ||
// @todo Add helper in SDK to normalize port | ||
if (typeof (url.port && url.port.toString) === FUNCTION) { | ||
// #port | ||
nodeUrl.port = url.port.toString(); | ||
/** | ||
* Checks if character at given index in the buffer is already percent encoded or not. | ||
* | ||
* @param {Buffer} buffer | ||
* @param {Number} i | ||
* @returns {Boolean} | ||
*/ | ||
isPreEncoded: function(buffer, i) { | ||
// If it is % check next two bytes for percent encode characters | ||
// looking for pattern %00 - %FF | ||
return (buffer[i] === 0x25 && | ||
(encoder.isPreEncodedCharacter(buffer[i + 1]) && | ||
encoder.isPreEncodedCharacter(buffer[i + 2])) | ||
); | ||
}, | ||
// #host = (#hostname):(#port) | ||
nodeUrl.host = nodeUrl.hostname + COLON + nodeUrl.port; | ||
/** | ||
* Checks if character with given code is valid hexadecimal digit or not. | ||
* | ||
* @param {Number} byte | ||
* @returns {Boolean} | ||
*/ | ||
isPreEncodedCharacter: function(byte) { | ||
return (byte >= 0x30 && byte <= 0x39) || // 0-9 | ||
(byte >= 0x41 && byte <= 0x46) || // A-F | ||
(byte >= 0x61 && byte <= 0x66); // a-f | ||
}, | ||
// #href = protocol://user:password@host.name:port | ||
nodeUrl.href += COLON + nodeUrl.port; | ||
} | ||
/** | ||
* Checks whether given character should be percent encoded or not for fixture. | ||
* | ||
* @param {Number} byte | ||
* @returns {Boolean} | ||
*/ | ||
charactersToPercentEncode: function(byte) { | ||
return (byte < 0x23 || byte > 0x7E || // Below # and after ~ | ||
byte === 0x3C || byte === 0x3E || // > and < | ||
byte === 0x28 || byte === 0x29 || // ( and ) | ||
byte === 0x25 || // % | ||
byte === 0x27 || // ' | ||
byte === 0x2A // * | ||
); | ||
}, | ||
// #path, #pathname | ||
nodeUrl.path = nodeUrl.pathname = encoder.encodePath(url.getPath()); | ||
/** | ||
* Percent encode a query string according to RFC 3986. | ||
* Note: This function is supposed to be used on top of node's inbuilt url encoding | ||
* to solve issue https://github.com/nodejs/node/issues/8321 | ||
* | ||
* @param {String} value | ||
* @returns {String} | ||
*/ | ||
encode: function (value) { | ||
if (!value) { return E; } | ||
// #href = protocol://user:password@host.name:port/p/a/t/h | ||
nodeUrl.href += nodeUrl.pathname; | ||
var buffer = Buffer.from(value), | ||
ret = E, | ||
i, | ||
ii; | ||
if (url.query.count()) { | ||
// #query | ||
nodeUrl.query = encoder.encodeQueryParams(url.query.all()); | ||
for (i = 0, ii = buffer.length; i < ii; ++i) { | ||
// #search | ||
nodeUrl.search = QUERY_SEPARATOR + nodeUrl.query; | ||
if (encoder.charactersToPercentEncode(buffer[i]) && !encoder.isPreEncoded(buffer, i)) { | ||
ret += encoder.percentEncode(buffer[i]); | ||
} | ||
else { | ||
ret += String.fromCodePoint(buffer[i]); // Only works in ES6 (available in Node v4+) | ||
} | ||
} | ||
// #path = (#pathname)?(#search) | ||
nodeUrl.path = nodeUrl.pathname + nodeUrl.search; | ||
return ret; | ||
}, | ||
// #href = protocol://user:password@host.name:port/p/a/t/h?q=query | ||
nodeUrl.href += nodeUrl.search; | ||
} | ||
/** | ||
* Converts URL string into Node's Url object with encoded values | ||
* | ||
* @param {String} url | ||
* @returns {Url} | ||
*/ | ||
toNodeUrl: function (urlString) { | ||
var parsed = url.parse(urlString), | ||
rawQs = parsed.query, | ||
qs, | ||
search, | ||
path, | ||
str; | ||
if (url.hash) { | ||
// #hash | ||
nodeUrl.hash = SEARCH_SEPARATOR + encoder.encodeFragment(url.hash); | ||
if (!(rawQs && rawQs.length)) { return parsed; } | ||
// #href = protocol://user:password@host.name:port/p/a/t/h?q=query#hash | ||
nodeUrl.href += nodeUrl.hash; | ||
} | ||
qs = stringifyQueryParams(parseQueryString(rawQs)); | ||
search = QUERY_SEPARATOR + qs; | ||
path = parsed.pathname + search; | ||
return nodeUrl; | ||
} | ||
parsed.query = qs; | ||
parsed.search = search; | ||
parsed.path = path; | ||
/** | ||
* Converts URL string into Node.js compatible Url object using the v1 encoder. | ||
* | ||
* @deprecated since version 2.0 | ||
* | ||
* @param {String} url URL string | ||
* @returns {Url} Node.js compatible Url object | ||
*/ | ||
function toLegacyNodeUrl (url) { | ||
return legacy.toNodeUrl(url); | ||
} | ||
str = url.format(parsed); | ||
// Parse again, because Node does not guarantee consistency of properties | ||
return url.parse(str); | ||
} | ||
module.exports = { | ||
encode, | ||
toNodeUrl, | ||
toLegacyNodeUrl, | ||
encodeQueryString | ||
}; | ||
module.exports = encoder; |
{ | ||
"name": "postman-url-encoder", | ||
"version": "1.0.3", | ||
"description": " It encodes the given url string as per RFC 3986.", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "mocha unit-test.spec.js" | ||
}, | ||
"description": "Implementation of the WHATWG URL Standard", | ||
"author": "Postman Labs <help@getpostman.com>", | ||
"version": "2.0.0", | ||
"license": "Apache-2.0", | ||
"keywords": [ | ||
"postman", | ||
"url-encoder", | ||
"whatwg-url" | ||
], | ||
"repository": { | ||
@@ -13,8 +16,2 @@ "type": "git", | ||
}, | ||
"keywords": [ | ||
"postman", | ||
"url-encoder" | ||
], | ||
"author": "Postman Labs <help@getpostman.com> (=)", | ||
"license": "MIT", | ||
"bugs": { | ||
@@ -24,7 +21,32 @@ "url": "https://github.com/postmanlabs/postman-url-encoder/issues" | ||
"homepage": "https://github.com/postmanlabs/postman-url-encoder#readme", | ||
"main": "index.js", | ||
"scripts": { | ||
"build-docs": "node npm/build-docs.js", | ||
"publish-docs": "node npm/publish-docs.js", | ||
"test": "npm run test-lint && npm run test-unit", | ||
"test-lint": "node npm/test-lint.js", | ||
"test-unit": "node npm/test-unit.js", | ||
"test-benchmark": "node npm/test-benchmark.js" | ||
}, | ||
"dependencies": { | ||
"postman-collection": "^3.5.5", | ||
"punycode": "^2.1.1" | ||
}, | ||
"devDependencies": { | ||
"expect.js": "^0.3.1", | ||
"mocha": "^3.0.0", | ||
"postman-collection": "^3.5.4" | ||
"@postman/csv-parse": "^4.0.2", | ||
"async": "^3.1.0", | ||
"bipbip": "^0.4.1", | ||
"chai": "^4.2.0", | ||
"chalk": "^2.4.2", | ||
"colors": "^1.4.0", | ||
"eslint": "^5.16.0", | ||
"eslint-plugin-jsdoc": "^18.4.4", | ||
"eslint-plugin-security": "^1.4.0", | ||
"jsdoc": "^3.6.3", | ||
"mocha": "^6.2.2", | ||
"nyc": "^14.1.1", | ||
"postman-jsdoc-theme": "0.0.3", | ||
"recursive-readdir": "^2.2.2", | ||
"shelljs": "^0.8.3" | ||
} | ||
} |
@@ -1,12 +0,49 @@ | ||
# Postman URL encoding | ||
# Postman URL Encoder [![codecov](https://codecov.io/gh/postmanlabs/postman-url-encoder/branch/develop/graph/badge.svg)](https://codecov.io/gh/postmanlabs/postman-url-encoder) | ||
## Simple url string encoder based on RFC 3986 | ||
Postman URL Encoder is a NodeJS module that provides various URL encoding related APIs. This module is created to | ||
implement the [WHATWG URL specification](https://url.spec.whatwg.org/) to remove dependency on Node's URL APIs across | ||
Postman systems. These APIs are useful to encode different parts (like hostname, path, query) of URL and convert | ||
[PostmanUrl](http://www.postmanlabs.com/postman-collection/Url.html) object into | ||
[Node's Url](https://nodejs.org/dist/latest-v10.x/docs/api/url.html#url_legacy_urlobject) like object. | ||
## Installing the Postman URL Encoder | ||
Postman URL Encoder can be installed using NPM or directly from the git repository within your NodeJS projects. If | ||
installing from NPM, the following command installs the module and saves in your `package.json` | ||
```terminal | ||
> npm install postman-url-encoder --save | ||
``` | ||
npm install postman-url-encoder --save | ||
## Getting Started | ||
Following example snippet shows how to convert [PostmanUrl](http://www.postmanlabs.com/postman-collection/Url.html) | ||
object into [Node's Url](https://nodejs.org/dist/latest-v10.x/docs/api/url.html#url_legacy_urlobject) like object. | ||
```javascript | ||
var PostmanUrl = require('postman-collection').Url, | ||
pmEncoder = require('postman-url-encoder'), | ||
myUrl; | ||
// Create PostmanUrl object | ||
myUrl = new PostmanUrl('http://example.com/p/a/t/h?q1=v1'); | ||
// convert PostmanUrl object to Node's Url like object | ||
myUrl = pmEncoder.toNodeUrl(myUrl)); | ||
// { | ||
// protocol: 'http:', | ||
// slashes: true, | ||
// auth: null, | ||
// host: 'example.com', | ||
// port: null, | ||
// hostname: 'example.com', | ||
// hash: null, | ||
// search: '?q1=v1', | ||
// query: 'q1=v1', | ||
// pathname: '/p/a/t/h', | ||
// path: '/p/a/t/h?q1=v1', | ||
// href: 'http://example.com/p/a/t/h?q1=v1' | ||
// } | ||
``` | ||
```js | ||
var urlEncoder = require('postman-url-encoder'); | ||
console.log(urlEncoder.encode('http://foo.bar.com?a=b')) | ||
``` | ||
To know more about provided APIs, head over to [Postman URL Encoder Docs](http://www.postmanlabs.com/postman-url-encoder). |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
149377
34
3263
50
2
15
3
1
+ Addedpostman-collection@^3.5.5
+ Addedpunycode@^2.1.1
+ Addedansi-styles@3.2.1(transitive)
+ Addedarray-uniq@1.0.3(transitive)
+ Addedchalk@2.4.2(transitive)
+ Addedcharset@1.0.1(transitive)
+ Addedcolor-convert@1.9.3(transitive)
+ Addedcolor-name@1.1.3(transitive)
+ Addeddom-serializer@0.2.2(transitive)
+ Addeddomelementtype@1.3.12.3.0(transitive)
+ Addeddomhandler@2.4.2(transitive)
+ Addeddomutils@1.7.0(transitive)
+ Addedentities@1.1.22.2.0(transitive)
+ Addedescape-html@1.0.3(transitive)
+ Addedescape-string-regexp@1.0.5(transitive)
+ Addedfaker@5.5.3(transitive)
+ Addedfile-type@3.9.0(transitive)
+ Addedhas-flag@3.0.0(transitive)
+ Addedhtmlparser2@3.10.1(transitive)
+ Addedhttp-reasons@0.1.0(transitive)
+ Addediconv-lite@0.6.2(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedliquid-json@0.3.1(transitive)
+ Addedlodash@4.17.21(transitive)
+ Addedlodash.clonedeep@4.5.0(transitive)
+ Addedlodash.escaperegexp@4.1.2(transitive)
+ Addedlodash.isplainobject@4.0.6(transitive)
+ Addedlodash.isstring@4.0.1(transitive)
+ Addedlodash.mergewith@4.6.2(transitive)
+ Addedlru-cache@6.0.0(transitive)
+ Addedmarked@2.0.1(transitive)
+ Addedmime-db@1.47.0(transitive)
+ Addedmime-format@2.0.1(transitive)
+ Addedmime-types@2.1.30(transitive)
+ Addednumber-is-nan@1.0.1(transitive)
+ Addedpicocolors@0.2.1(transitive)
+ Addedpostcss@7.0.39(transitive)
+ Addedpostman-collection@3.6.11(transitive)
+ Addedpostman-url-encoder@3.0.1(transitive)
+ Addedpunycode@2.3.1(transitive)
+ Addedreadable-stream@3.6.2(transitive)
+ Addedsafe-buffer@5.2.1(transitive)
+ Addedsafer-buffer@2.1.2(transitive)
+ Addedsanitize-html@1.20.1(transitive)
+ Addedsemver@7.3.5(transitive)
+ Addedsource-map@0.6.1(transitive)
+ Addedsrcset@1.0.0(transitive)
+ Addedstring_decoder@1.3.0(transitive)
+ Addedsupports-color@5.5.0(transitive)
+ Addedutil-deprecate@1.0.2(transitive)
+ Addeduuid@3.4.0(transitive)
+ Addedxtend@4.0.2(transitive)
+ Addedyallist@4.0.0(transitive)