@datanimbus/postman-request 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/tunnel.js ADDED
@@ -0,0 +1,175 @@
1
+ 'use strict'
2
+
3
+ var tunnel = require('@postman/tunnel-agent')
4
+
5
+ var defaultProxyHeaderWhiteList = [
6
+ 'accept',
7
+ 'accept-charset',
8
+ 'accept-encoding',
9
+ 'accept-language',
10
+ 'accept-ranges',
11
+ 'cache-control',
12
+ 'content-encoding',
13
+ 'content-language',
14
+ 'content-location',
15
+ 'content-md5',
16
+ 'content-range',
17
+ 'content-type',
18
+ 'connection',
19
+ 'date',
20
+ 'expect',
21
+ 'max-forwards',
22
+ 'pragma',
23
+ 'referer',
24
+ 'te',
25
+ 'user-agent',
26
+ 'via'
27
+ ]
28
+
29
+ var defaultProxyHeaderExclusiveList = [
30
+ 'proxy-authorization'
31
+ ]
32
+
33
+ function constructProxyHost (uriObject) {
34
+ var port = uriObject.port
35
+ var protocol = uriObject.protocol
36
+ var proxyHost = uriObject.hostname + ':'
37
+
38
+ if (port) {
39
+ proxyHost += port
40
+ } else if (protocol === 'https:') {
41
+ proxyHost += '443'
42
+ } else {
43
+ proxyHost += '80'
44
+ }
45
+
46
+ return proxyHost
47
+ }
48
+
49
+ function constructProxyHeaderWhiteList (headers, proxyHeaderWhiteList) {
50
+ var whiteList = proxyHeaderWhiteList
51
+ .reduce(function (set, header) {
52
+ set[header.toLowerCase()] = true
53
+ return set
54
+ }, {})
55
+
56
+ return Object.keys(headers)
57
+ .filter(function (header) {
58
+ return whiteList[header.toLowerCase()]
59
+ })
60
+ .reduce(function (set, header) {
61
+ set[header] = headers[header]
62
+ return set
63
+ }, {})
64
+ }
65
+
66
+ function constructTunnelOptions (request, proxyHeaders) {
67
+ var proxy = request.proxy
68
+
69
+ var tunnelOptions = {
70
+ proxy: {
71
+ host: proxy.hostname,
72
+ port: +proxy.port,
73
+ proxyAuth: proxy.auth,
74
+ headers: proxyHeaders
75
+ },
76
+ headers: request.headers,
77
+ ca: request.ca,
78
+ cert: request.cert,
79
+ key: request.key,
80
+ passphrase: request.passphrase,
81
+ pfx: request.pfx,
82
+ ciphers: request.ciphers,
83
+ rejectUnauthorized: request.rejectUnauthorized,
84
+ secureOptions: request.secureOptions,
85
+ secureProtocol: request.secureProtocol,
86
+ extraCA: request.extraCA
87
+ }
88
+
89
+ return tunnelOptions
90
+ }
91
+
92
+ function constructTunnelFnName (uri, proxy) {
93
+ var uriProtocol = (uri.protocol === 'https:' ? 'https' : 'http')
94
+ var proxyProtocol = (proxy.protocol === 'https:' ? 'Https' : 'Http')
95
+ return [uriProtocol, proxyProtocol].join('Over')
96
+ }
97
+
98
+ function getTunnelFn (request) {
99
+ var uri = request.uri
100
+ var proxy = request.proxy
101
+ var tunnelFnName = constructTunnelFnName(uri, proxy)
102
+ return tunnel[tunnelFnName]
103
+ }
104
+
105
+ function Tunnel (request) {
106
+ this.request = request
107
+ this.proxyHeaderWhiteList = defaultProxyHeaderWhiteList
108
+ this.proxyHeaderExclusiveList = []
109
+ if (typeof request.tunnel !== 'undefined') {
110
+ this.tunnelOverride = request.tunnel
111
+ }
112
+ }
113
+
114
+ Tunnel.prototype.isEnabled = function () {
115
+ var self = this
116
+ var request = self.request
117
+ // Tunnel HTTPS by default. Allow the user to override this setting.
118
+
119
+ // If self.tunnelOverride is set (the user specified a value), use it.
120
+ if (typeof self.tunnelOverride !== 'undefined') {
121
+ return self.tunnelOverride
122
+ }
123
+
124
+ // If the destination is HTTPS, tunnel.
125
+ if (request.uri.protocol === 'https:') {
126
+ return true
127
+ }
128
+
129
+ // Otherwise, do not use tunnel.
130
+ return false
131
+ }
132
+
133
+ Tunnel.prototype.setup = function (options) {
134
+ var self = this
135
+ var request = self.request
136
+
137
+ options = options || {}
138
+
139
+ if (typeof request.proxy === 'string') {
140
+ request.proxy = request.urlParser.parse(request.proxy)
141
+ }
142
+
143
+ if (!request.proxy || !request.tunnel) {
144
+ return false
145
+ }
146
+
147
+ // Setup Proxy Header Exclusive List and White List
148
+ if (options.proxyHeaderWhiteList) {
149
+ self.proxyHeaderWhiteList = options.proxyHeaderWhiteList
150
+ }
151
+ if (options.proxyHeaderExclusiveList) {
152
+ self.proxyHeaderExclusiveList = options.proxyHeaderExclusiveList
153
+ }
154
+
155
+ var proxyHeaderExclusiveList = self.proxyHeaderExclusiveList.concat(defaultProxyHeaderExclusiveList)
156
+ var proxyHeaderWhiteList = self.proxyHeaderWhiteList.concat(proxyHeaderExclusiveList)
157
+
158
+ // Setup Proxy Headers and Proxy Headers Host
159
+ // Only send the Proxy White Listed Header names
160
+ var proxyHeaders = constructProxyHeaderWhiteList(request.headers, proxyHeaderWhiteList)
161
+ proxyHeaders.host = constructProxyHost(request.uri)
162
+
163
+ proxyHeaderExclusiveList.forEach(request.removeHeader, request)
164
+
165
+ // Set Agent from Tunnel Data
166
+ var tunnelFn = getTunnelFn(request)
167
+ var tunnelOptions = constructTunnelOptions(request, proxyHeaders)
168
+ request.agent = tunnelFn(tunnelOptions)
169
+
170
+ return true
171
+ }
172
+
173
+ Tunnel.defaultProxyHeaderWhiteList = defaultProxyHeaderWhiteList
174
+ Tunnel.defaultProxyHeaderExclusiveList = defaultProxyHeaderExclusiveList
175
+ exports.Tunnel = Tunnel
@@ -0,0 +1,187 @@
1
+ var url = require('url')
2
+ var EMPTY = ''
3
+ var ZERO = '0'
4
+ var PERCENT = '%'
5
+ var STRING = 'string'
6
+ var AMPERSAND = '&'
7
+ var EQUALS = '='
8
+ var QUESTION_MARK = '?'
9
+ var stringify
10
+ var parse
11
+
12
+ /**
13
+ * Percent encode a character with given code.
14
+ *
15
+ * @param {Number} c - character code of the character to encode
16
+ * @returns {String} - percent encoding of given character
17
+ */
18
+ var percentEncode = function (c) {
19
+ var hex = c.toString(16).toUpperCase()
20
+ hex.length === 1 && (hex = ZERO + hex)
21
+ return PERCENT + hex
22
+ }
23
+
24
+ /**
25
+ * Checks if character with given code is valid hexadecimal digit or not.
26
+ *
27
+ * @param {Number} byte
28
+ * @returns {Boolean}
29
+ */
30
+ var isPreEncodedCharacter = function (byte) {
31
+ return (byte >= 0x30 && byte <= 0x39) || // 0-9
32
+ (byte >= 0x41 && byte <= 0x46) || // A-F
33
+ (byte >= 0x61 && byte <= 0x66) // a-f
34
+ }
35
+
36
+ /**
37
+ * Checks if character at given index in the buffer is already percent encoded or not.
38
+ *
39
+ * @param {Buffer} buffer
40
+ * @param {Number} i
41
+ * @returns {Boolean}
42
+ */
43
+ var isPreEncoded = function (buffer, i) {
44
+ // If it is % check next two bytes for percent encode characters
45
+ // looking for pattern %00 - %FF
46
+ return (buffer[i] === 0x25 &&
47
+ (isPreEncodedCharacter(buffer[i + 1]) &&
48
+ isPreEncodedCharacter(buffer[i + 2]))
49
+ )
50
+ }
51
+
52
+ /**
53
+ * Checks whether given character should be percent encoded or not for fixture.
54
+ *
55
+ * @param {Number} byte
56
+ * @returns {Boolean}
57
+ */
58
+ var charactersToPercentEncode = function (byte) {
59
+ return (byte < 0x23 || byte > 0x7E || // Below # and after ~
60
+ byte === 0x3C || byte === 0x3E || // > and <
61
+ byte === 0x28 || byte === 0x29 || // ( and )
62
+ byte === 0x25 || // %
63
+ byte === 0x27 || // '
64
+ byte === 0x2A // *
65
+ )
66
+ }
67
+
68
+ /**
69
+ * Percent encode a query string according to RFC 3986.
70
+ * Note: This function is supposed to be used on top of node's inbuilt url encoding
71
+ * to solve issue https://github.com/nodejs/node/issues/8321
72
+ *
73
+ * @param {String} value
74
+ * @returns {String}
75
+ */
76
+ var encode = function (value) {
77
+ if (!value) { return EMPTY }
78
+
79
+ var buffer = Buffer.from(value)
80
+ var ret = EMPTY
81
+ var i
82
+ var ii
83
+
84
+ for (i = 0, ii = buffer.length; i < ii; ++i) {
85
+ if (charactersToPercentEncode(buffer[i]) && !isPreEncoded(buffer, i)) {
86
+ ret += percentEncode(buffer[i])
87
+ } else {
88
+ ret += String.fromCodePoint(buffer[i]) // Only works in ES6 (available in Node v4+)
89
+ }
90
+ }
91
+
92
+ return ret
93
+ }
94
+
95
+ /**
96
+ * Parses a query string into an array, preserving parameter values
97
+ *
98
+ * @param string
99
+ * @returns {*}
100
+ */
101
+ parse = function (string) {
102
+ var parts
103
+ if (typeof string === STRING) { // eslint-disable-line valid-typeof
104
+ parts = string.split(AMPERSAND)
105
+ return parts.map(function (param, idx) {
106
+ if (param === EMPTY && idx !== (parts.length - 1)) {
107
+ return { key: null, value: null }
108
+ }
109
+
110
+ var index = (typeof param === STRING) ? param.indexOf(EQUALS) : -1 // eslint-disable-line valid-typeof
111
+ var paramObj = {}
112
+
113
+ // this means that there was no value for this key (not even blank, so we store this info) and the value is set
114
+ // to null
115
+ if (index < 0) {
116
+ paramObj.key = param.substr(0, param.length)
117
+ paramObj.value = null
118
+ } else {
119
+ paramObj.key = param.substr(0, index)
120
+ paramObj.value = param.substr(index + 1)
121
+ }
122
+
123
+ return paramObj
124
+ })
125
+ }
126
+ return []
127
+ }
128
+
129
+ /**
130
+ * Stringifies a query string, from an array of parameters
131
+ *
132
+ * @param parameters
133
+ * @returns {string}
134
+ */
135
+ stringify = function (parameters) {
136
+ return parameters ? parameters.map(function (param) {
137
+ var key = param.key
138
+ var value = param.value
139
+
140
+ if (value === undefined) {
141
+ return EMPTY
142
+ }
143
+
144
+ if (key === null) {
145
+ key = EMPTY
146
+ }
147
+
148
+ if (value === null) {
149
+ return encode(key)
150
+ }
151
+
152
+ return encode(key) + EQUALS + encode(value)
153
+ }).join(AMPERSAND) : EMPTY
154
+ }
155
+
156
+ /**
157
+ * Correctly URL encodes query parameters in a URL and returns the final parsed URL.
158
+ *
159
+ * @param str
160
+ */
161
+ module.exports = function (str) {
162
+ var parsed = url.parse(str)
163
+ var rawQs
164
+ var search
165
+ var path
166
+ var qs
167
+
168
+ rawQs = parsed.query
169
+
170
+ if (rawQs && rawQs.length) {
171
+ qs = stringify(parse(parsed.query))
172
+ search = QUESTION_MARK + qs
173
+ path = parsed.pathname + search
174
+
175
+ parsed.query = qs
176
+ parsed.search = search
177
+ parsed.path = path
178
+
179
+ str = url.format(parsed)
180
+ }
181
+
182
+ // Parse again, because Node does not guarantee consistency of properties
183
+ return url.parse(str)
184
+ }
185
+
186
+ module.exports.parse = parse
187
+ module.exports.stringify = stringify
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "@datanimbus/postman-request",
3
+ "description": "Simplified HTTP request client.",
4
+ "keywords": [
5
+ "http",
6
+ "simple",
7
+ "util",
8
+ "utility"
9
+ ],
10
+ "version": "3.0.1",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/postmanlabs/postman-request.git"
14
+ },
15
+ "license": "Apache-2.0",
16
+ "engines": {
17
+ "node": ">= 16"
18
+ },
19
+ "main": "index.js",
20
+ "files": [
21
+ "lib/",
22
+ "index.js",
23
+ "request.js"
24
+ ],
25
+ "dependencies": {
26
+ "@postman/form-data": "~3.1.1",
27
+ "@postman/tough-cookie": "~4.1.3-postman.1",
28
+ "@postman/tunnel-agent": "^0.6.8",
29
+ "aws-sign2": "~0.7.0",
30
+ "aws4": "^1.12.0",
31
+ "caseless": "~0.12.0",
32
+ "combined-stream": "~1.0.6",
33
+ "extend": "~3.0.2",
34
+ "forever-agent": "~0.6.1",
35
+ "http-signature": "~1.4.0",
36
+ "is-typedarray": "~1.0.0",
37
+ "isstream": "~0.1.2",
38
+ "json-stringify-safe": "~5.0.1",
39
+ "mime-types": "^2.1.35",
40
+ "oauth-sign": "~0.9.0",
41
+ "qs": "~6.14.1",
42
+ "safe-buffer": "^5.1.2",
43
+ "socks-proxy-agent": "^8.0.5",
44
+ "stream-length": "^1.0.2",
45
+ "uuid": "^8.3.2"
46
+ },
47
+ "scripts": {
48
+ "test": "npm run lint && npm run test-ci && npm run test-browser",
49
+ "test-ci": "taper tests/test-*.js",
50
+ "test-cov": "istanbul cover tape tests/test-*.js",
51
+ "test-browser": "node tests/browser/start.js",
52
+ "lint": "standard"
53
+ },
54
+ "devDependencies": {
55
+ "bluebird": "^3.2.1",
56
+ "browserify": "^16.5.2",
57
+ "browserify-istanbul": "^3.0.0",
58
+ "buffer-equal": "^1.0.1",
59
+ "codecov": "^3.0.4",
60
+ "coveralls": "^3.0.2",
61
+ "function-bind": "^1.0.2",
62
+ "istanbul": "^0.4.0",
63
+ "karma": "^6.4.4",
64
+ "karma-browserify": "^8.1.0",
65
+ "karma-chrome-launcher": "^3.1.1",
66
+ "karma-cli": "^2.0.0",
67
+ "karma-coverage": "^2.2.1",
68
+ "karma-tap": "^4.2.0",
69
+ "postman-url-encoder": "^3.0.6",
70
+ "puppeteer": "^1.20.0",
71
+ "rimraf": "^2.2.8",
72
+ "server-destroy": "^1.0.1",
73
+ "standard": "^9.0.0",
74
+ "tape": "^4.6.0",
75
+ "taper": "^0.5.0"
76
+ }
77
+ }