cdk-common 2.1.33 → 2.1.35
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/.jsii +3 -3
- package/lib/main.js +1 -1
- package/node_modules/fast-uri/.github/workflows/ci.yml +12 -7
- package/node_modules/fast-uri/.github/workflows/lock-threads.yml +19 -0
- package/node_modules/fast-uri/.github/workflows/package-manager-ci.yml +1 -1
- package/node_modules/fast-uri/LICENSE +1 -3
- package/node_modules/fast-uri/README.md +13 -4
- package/node_modules/fast-uri/index.js +90 -24
- package/node_modules/fast-uri/lib/utils.js +129 -22
- package/node_modules/fast-uri/package.json +3 -4
- package/node_modules/fast-uri/test/equal.test.js +9 -0
- package/node_modules/fast-uri/test/parse.test.js +5 -0
- package/node_modules/fast-uri/test/resolve.test.js +9 -0
- package/node_modules/fast-uri/test/security-normalization.test.js +39 -0
- package/node_modules/fast-uri/test/security.test.js +133 -0
- package/package.json +1 -1
- package/node_modules/fast-uri/.github/.stale.yml +0 -21
- package/node_modules/fast-uri/.github/tests_checker.yml +0 -8
package/.jsii
CHANGED
|
@@ -3943,7 +3943,7 @@
|
|
|
3943
3943
|
"stability": "experimental"
|
|
3944
3944
|
},
|
|
3945
3945
|
"homepage": "https://github.com/neilkuan/cdk-common.git",
|
|
3946
|
-
"jsiiVersion": "5.9.
|
|
3946
|
+
"jsiiVersion": "5.9.39 (build cdf85b4)",
|
|
3947
3947
|
"keywords": [
|
|
3948
3948
|
"aws",
|
|
3949
3949
|
"aws-cdk",
|
|
@@ -12984,6 +12984,6 @@
|
|
|
12984
12984
|
"symbolId": "src/main:LambdaArmFunctionProps"
|
|
12985
12985
|
}
|
|
12986
12986
|
},
|
|
12987
|
-
"version": "2.1.
|
|
12988
|
-
"fingerprint": "
|
|
12987
|
+
"version": "2.1.35",
|
|
12988
|
+
"fingerprint": "NFDErK/8HKOBmjwZW7YyqvfsSvofOt2FOB5Or/og6Os="
|
|
12989
12989
|
}
|
package/lib/main.js
CHANGED
|
@@ -38,5 +38,5 @@ class LambdaArmFunction extends constructs_1.Construct {
|
|
|
38
38
|
}
|
|
39
39
|
exports.LambdaArmFunction = LambdaArmFunction;
|
|
40
40
|
_a = JSII_RTTI_SYMBOL_1;
|
|
41
|
-
LambdaArmFunction[_a] = { fqn: "cdk-common.LambdaArmFunction", version: "2.1.
|
|
41
|
+
LambdaArmFunction[_a] = { fqn: "cdk-common.LambdaArmFunction", version: "2.1.35" };
|
|
42
42
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9tYWluLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsbUNBQW1DO0FBQ25DLGlEQUFpRDtBQUNqRCwyQ0FBdUM7QUFLdkMsTUFBYSxpQkFBa0IsU0FBUSxzQkFBUztJQUU5QyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQTRCO1FBQ3BFLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFakIsTUFBTSxlQUFlLEdBQUcsSUFBSSxHQUFHLENBQXlCO1lBQ3RELENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsbUNBQW1DLENBQUM7WUFDakUsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxtQ0FBbUMsQ0FBQztZQUNqRSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLG1DQUFtQyxDQUFDO1lBQ2pFLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsa0NBQWtDLENBQUM7WUFDaEUsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxrQ0FBa0MsQ0FBQztZQUNoRSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLGtDQUFrQyxDQUFDO1lBQ2hFLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsa0NBQWtDLENBQUM7WUFDaEUsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSw4QkFBOEIsQ0FBQztZQUN4RCxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLDhCQUE4QixDQUFDO1lBQ3hELENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsNkJBQTZCLENBQUM7WUFDeEQsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSwrQkFBK0IsQ0FBQztZQUMxRCxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLCtCQUErQixDQUFDO1NBQzNELENBQUMsQ0FBQztRQUVILE1BQU0sT0FBTyxHQUFHLGVBQWUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ25ELElBQUksT0FBTyxFQUFFLENBQUM7WUFDWixHQUFHLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDL0MsQ0FBQzthQUFNLENBQUM7WUFDTixNQUFNLElBQUksS0FBSyxDQUFDLG1CQUFtQixLQUFLLENBQUMsT0FBTyx1R0FBdUcsQ0FBQyxDQUFDO1FBQzNKLENBQUM7UUFFRCxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsZ0JBQWdCLEVBQUU7WUFDaEUsWUFBWSxFQUFFLEtBQUssQ0FBQyxZQUFZLElBQUksTUFBTSxDQUFDLFlBQVksQ0FBQyxNQUFNO1lBQzlELEdBQUcsS0FBSztTQUNULENBQUMsQ0FBQztJQUNMLENBQUM7O0FBL0JILDhDQWdDQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGNkayBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgKiBhcyBsYW1iZGEgZnJvbSAnYXdzLWNkay1saWIvYXdzLWxhbWJkYSc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmV4cG9ydCBpbnRlcmZhY2UgTGFtYmRhQXJtRnVuY3Rpb25Qcm9wcyBleHRlbmRzIGxhbWJkYS5GdW5jdGlvblByb3BzIHtcblxufVxuXG5leHBvcnQgY2xhc3MgTGFtYmRhQXJtRnVuY3Rpb24gZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBwdWJsaWMgcmVhZG9ubHkgbGFtYmRhRnVuY3Rpb246IGxhbWJkYS5GdW5jdGlvbjtcbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6TGFtYmRhQXJtRnVuY3Rpb25Qcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICBjb25zdCBydW50aW1lV2FybmluZ3MgPSBuZXcgTWFwPGxhbWJkYS5SdW50aW1lLCBzdHJpbmc+KFtcbiAgICAgIFtsYW1iZGEuUnVudGltZS5OT0RFSlNfMjJfWCwgJ1lvdSBhcmUgdXNpbmcgTm9kZS5qcyAyMi54IGF0IEFSTSddLFxuICAgICAgW2xhbWJkYS5SdW50aW1lLk5PREVKU18yMF9YLCAnWW91IGFyZSB1c2luZyBOb2RlLmpzIDIwLnggYXQgQVJNJ10sXG4gICAgICBbbGFtYmRhLlJ1bnRpbWUuTk9ERUpTXzE4X1gsICdZb3UgYXJlIHVzaW5nIE5vZGUuanMgMTgueCBhdCBBUk0nXSxcbiAgICAgIFtsYW1iZGEuUnVudGltZS5QWVRIT05fM18xMywgJ1lvdSBhcmUgdXNpbmcgUHl0aG9uIDMuMTMgYXQgQVJNJ10sXG4gICAgICBbbGFtYmRhLlJ1bnRpbWUuUFlUSE9OXzNfMTIsICdZb3UgYXJlIHVzaW5nIFB5dGhvbiAzLjEyIGF0IEFSTSddLFxuICAgICAgW2xhbWJkYS5SdW50aW1lLlBZVEhPTl8zXzExLCAnWW91IGFyZSB1c2luZyBQeXRob24gMy4xMSBhdCBBUk0nXSxcbiAgICAgIFtsYW1iZGEuUnVudGltZS5QWVRIT05fM18xMCwgJ1lvdSBhcmUgdXNpbmcgUHl0aG9uIDMuMTAgYXQgQVJNJ10sXG4gICAgICBbbGFtYmRhLlJ1bnRpbWUuSkFWQV8yMSwgJ1lvdSBhcmUgdXNpbmcgSmF2YSAyMSBhdCBBUk0nXSxcbiAgICAgIFtsYW1iZGEuUnVudGltZS5KQVZBXzE3LCAnWW91IGFyZSB1c2luZyBKYXZhIDE3IGF0IEFSTSddLFxuICAgICAgW2xhbWJkYS5SdW50aW1lLkRPVE5FVF84LCAnWW91IGFyZSB1c2luZyAuTkVUIDggYXQgQVJNJ10sXG4gICAgICBbbGFtYmRhLlJ1bnRpbWUuUlVCWV8zXzQsICdZb3UgYXJlIHVzaW5nIFJ1YnkgMy40IGF0IEFSTSddLFxuICAgICAgW2xhbWJkYS5SdW50aW1lLlJVQllfM18zLCAnWW91IGFyZSB1c2luZyBSdWJ5IDMuMyBhdCBBUk0nXSxcbiAgICBdKTtcblxuICAgIGNvbnN0IHdhcm5pbmcgPSBydW50aW1lV2FybmluZ3MuZ2V0KHByb3BzLnJ1bnRpbWUpO1xuICAgIGlmICh3YXJuaW5nKSB7XG4gICAgICBjZGsuQW5ub3RhdGlvbnMub2YodGhpcykuYWRkV2FybmluZyh3YXJuaW5nKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIFJ1bnRpbWUgJHtwcm9wcy5ydW50aW1lfSBhdCBBUk0sIFNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vbGFtYmRhL2xhdGVzdC9kZy9mb3VuZGF0aW9uLWFyY2guaHRtbD9pY21waWQ9ZG9jc19sYW1iZGFfcnNzYCk7XG4gICAgfVxuXG4gICAgdGhpcy5sYW1iZGFGdW5jdGlvbiA9IG5ldyBsYW1iZGEuRnVuY3Rpb24odGhpcywgJ0xhbWJkYUZ1bmN0aW9uJywge1xuICAgICAgYXJjaGl0ZWN0dXJlOiBwcm9wcy5hcmNoaXRlY3R1cmUgPz8gbGFtYmRhLkFyY2hpdGVjdHVyZS5BUk1fNjQsXG4gICAgICAuLi5wcm9wcyxcbiAgICB9KTtcbiAgfVxufVxuIl19
|
|
@@ -14,6 +14,11 @@ on:
|
|
|
14
14
|
- 'docs/**'
|
|
15
15
|
- '*.md'
|
|
16
16
|
|
|
17
|
+
# This allows a subsequently queued workflow run to interrupt previous runs
|
|
18
|
+
concurrency:
|
|
19
|
+
group: "${{ github.workflow }}-${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
|
|
20
|
+
cancel-in-progress: true
|
|
21
|
+
|
|
17
22
|
permissions:
|
|
18
23
|
contents: read
|
|
19
24
|
|
|
@@ -24,11 +29,11 @@ jobs:
|
|
|
24
29
|
permissions:
|
|
25
30
|
contents: read
|
|
26
31
|
steps:
|
|
27
|
-
- uses: actions/checkout@
|
|
32
|
+
- uses: actions/checkout@v6
|
|
28
33
|
with:
|
|
29
34
|
persist-credentials: false
|
|
30
35
|
|
|
31
|
-
- uses: actions/setup-node@
|
|
36
|
+
- uses: actions/setup-node@v6
|
|
32
37
|
with:
|
|
33
38
|
node-version: '10'
|
|
34
39
|
cache: 'npm'
|
|
@@ -66,11 +71,11 @@ jobs:
|
|
|
66
71
|
permissions:
|
|
67
72
|
contents: read
|
|
68
73
|
steps:
|
|
69
|
-
- uses: actions/checkout@
|
|
74
|
+
- uses: actions/checkout@v6
|
|
70
75
|
with:
|
|
71
76
|
persist-credentials: false
|
|
72
77
|
|
|
73
|
-
- uses: actions/setup-node@
|
|
78
|
+
- uses: actions/setup-node@v6
|
|
74
79
|
with:
|
|
75
80
|
node-version: '24'
|
|
76
81
|
cache: 'npm'
|
|
@@ -80,21 +85,21 @@ jobs:
|
|
|
80
85
|
- name: Install dependencies
|
|
81
86
|
run: |
|
|
82
87
|
npm install --ignore-scripts
|
|
83
|
-
|
|
88
|
+
|
|
84
89
|
- if: ${{ matrix.os == 'windows-latest' }}
|
|
85
90
|
run: npx playwright install winldd
|
|
86
91
|
|
|
87
92
|
- name: Run browser tests
|
|
88
93
|
run: |
|
|
89
94
|
npm run test:browser:${{ matrix.browser }}
|
|
90
|
-
|
|
95
|
+
|
|
91
96
|
test:
|
|
92
97
|
needs:
|
|
93
98
|
- test-regression-check-node10
|
|
94
99
|
permissions:
|
|
95
100
|
contents: write
|
|
96
101
|
pull-requests: write
|
|
97
|
-
uses: fastify/workflows/.github/workflows/plugins-ci.yml@
|
|
102
|
+
uses: fastify/workflows/.github/workflows/plugins-ci.yml@v6
|
|
98
103
|
with:
|
|
99
104
|
license-check: true
|
|
100
105
|
lint: true
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: Lock Threads
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: '0 0 1 * *'
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: lock
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
lock-threads:
|
|
16
|
+
permissions:
|
|
17
|
+
issues: write
|
|
18
|
+
pull-requests: write
|
|
19
|
+
uses: fastify/workflows/.github/workflows/lock-threads.yml@v6
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
Copyright (c) 2011-2021, Gary Court until https://github.com/garycourt/uri-js/commit/a1acf730b4bba3f1097c9f52e7d9d3aba8cdcaae
|
|
2
|
-
Copyright (c) 2021-present The Fastify team
|
|
2
|
+
Copyright (c) 2021-present The Fastify team <https://github.com/fastify/fastify#team>
|
|
3
3
|
All rights reserved.
|
|
4
4
|
|
|
5
|
-
The Fastify team members are listed at https://github.com/fastify/fastify#team.
|
|
6
|
-
|
|
7
5
|
Redistribution and use in source and binary forms, with or without
|
|
8
6
|
modification, are permitted provided that the following conditions are met:
|
|
9
7
|
* Redistributions of source code must retain the above copyright
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# fast-uri
|
|
2
2
|
|
|
3
|
-
<div align="center">
|
|
4
|
-
|
|
5
3
|
[](https://www.npmjs.com/package/fast-uri)
|
|
6
4
|
[](https://github.com/fastify/fast-uri/actions/workflows/ci.yml)
|
|
7
5
|
[](https://github.com/neostandard/neostandard)
|
|
8
6
|
|
|
9
|
-
</div>
|
|
10
|
-
|
|
11
7
|
Dependency-free RFC 3986 URI toolbox.
|
|
12
8
|
|
|
13
9
|
## Usage
|
|
@@ -16,6 +12,8 @@ Dependency-free RFC 3986 URI toolbox.
|
|
|
16
12
|
|
|
17
13
|
All of the above functions can accept an additional options argument that is an object that can contain one or more of the following properties:
|
|
18
14
|
|
|
15
|
+
Malformed authorities and out-of-range ports are reported through the parsed component's `error` field. `normalize()` leaves malformed string inputs unchanged, and `equal()` returns `false` when either string input is malformed.
|
|
16
|
+
|
|
19
17
|
* `scheme` (string)
|
|
20
18
|
Indicates the scheme that the URI should be treated as, overriding the URI's normal scheme parsing behavior.
|
|
21
19
|
|
|
@@ -70,6 +68,17 @@ uri.resolve("uri://a/b/c/d?q", "../../g")
|
|
|
70
68
|
"uri://a/g"
|
|
71
69
|
```
|
|
72
70
|
|
|
71
|
+
### Normalize
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
const uri = require('fast-uri')
|
|
75
|
+
uri.normalize('http://example.com/a%2Fb')
|
|
76
|
+
// Output
|
|
77
|
+
"http://example.com/a%2Fb"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Reserved path escapes such as `%2F` and `%2E` are preserved as path data during normalization and comparison.
|
|
81
|
+
|
|
73
82
|
### Equal
|
|
74
83
|
|
|
75
84
|
```js
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { normalizeIPv6, removeDotSegments, recomposeAuthority,
|
|
3
|
+
const { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require('./lib/utils')
|
|
4
4
|
const { SCHEMES, getSchemeHandler } = require('./lib/schemes')
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -11,7 +11,7 @@ const { SCHEMES, getSchemeHandler } = require('./lib/schemes')
|
|
|
11
11
|
*/
|
|
12
12
|
function normalize (uri, options) {
|
|
13
13
|
if (typeof uri === 'string') {
|
|
14
|
-
uri = /** @type {T} */ (
|
|
14
|
+
uri = /** @type {T} */ (normalizeString(uri, options))
|
|
15
15
|
} else if (typeof uri === 'object') {
|
|
16
16
|
uri = /** @type {T} */ (parse(serialize(uri, options), options))
|
|
17
17
|
}
|
|
@@ -106,21 +106,10 @@ function resolveComponent (base, relative, options, skipNormalization) {
|
|
|
106
106
|
* @returns {boolean}
|
|
107
107
|
*/
|
|
108
108
|
function equal (uriA, uriB, options) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
uriA = serialize(normalizeComponentEncoding(parse(uriA, options), true), { ...options, skipEscape: true })
|
|
112
|
-
} else if (typeof uriA === 'object') {
|
|
113
|
-
uriA = serialize(normalizeComponentEncoding(uriA, true), { ...options, skipEscape: true })
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (typeof uriB === 'string') {
|
|
117
|
-
uriB = unescape(uriB)
|
|
118
|
-
uriB = serialize(normalizeComponentEncoding(parse(uriB, options), true), { ...options, skipEscape: true })
|
|
119
|
-
} else if (typeof uriB === 'object') {
|
|
120
|
-
uriB = serialize(normalizeComponentEncoding(uriB, true), { ...options, skipEscape: true })
|
|
121
|
-
}
|
|
109
|
+
const normalizedA = normalizeComparableURI(uriA, options)
|
|
110
|
+
const normalizedB = normalizeComparableURI(uriB, options)
|
|
122
111
|
|
|
123
|
-
return
|
|
112
|
+
return normalizedA !== undefined && normalizedB !== undefined && normalizedA.toLowerCase() === normalizedB.toLowerCase()
|
|
124
113
|
}
|
|
125
114
|
|
|
126
115
|
/**
|
|
@@ -156,13 +145,13 @@ function serialize (cmpts, opts) {
|
|
|
156
145
|
|
|
157
146
|
if (component.path !== undefined) {
|
|
158
147
|
if (!options.skipEscape) {
|
|
159
|
-
component.path =
|
|
148
|
+
component.path = escapePreservingEscapes(component.path)
|
|
160
149
|
|
|
161
150
|
if (component.scheme !== undefined) {
|
|
162
151
|
component.path = component.path.split('%3A').join(':')
|
|
163
152
|
}
|
|
164
153
|
} else {
|
|
165
|
-
component.path =
|
|
154
|
+
component.path = normalizePercentEncoding(component.path)
|
|
166
155
|
}
|
|
167
156
|
}
|
|
168
157
|
|
|
@@ -213,12 +202,29 @@ function serialize (cmpts, opts) {
|
|
|
213
202
|
|
|
214
203
|
const URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u
|
|
215
204
|
|
|
205
|
+
/**
|
|
206
|
+
* @param {import('./types/index').URIComponent} parsed
|
|
207
|
+
* @param {RegExpMatchArray} matches
|
|
208
|
+
* @returns {string|undefined}
|
|
209
|
+
*/
|
|
210
|
+
function getParseError (parsed, matches) {
|
|
211
|
+
if (matches[2] !== undefined && parsed.path && parsed.path[0] !== '/') {
|
|
212
|
+
return 'URI path must start with "/" when authority is present.'
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (typeof parsed.port === 'number' && (parsed.port < 0 || parsed.port > 65535)) {
|
|
216
|
+
return 'URI port is malformed.'
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return undefined
|
|
220
|
+
}
|
|
221
|
+
|
|
216
222
|
/**
|
|
217
223
|
* @param {string} uri
|
|
218
224
|
* @param {import('./types/index').Options} [opts]
|
|
219
|
-
* @returns
|
|
225
|
+
* @returns {{ parsed: import('./types/index').URIComponent, malformedAuthorityOrPort: boolean }}
|
|
220
226
|
*/
|
|
221
|
-
function
|
|
227
|
+
function parseWithStatus (uri, opts) {
|
|
222
228
|
const options = Object.assign({}, opts)
|
|
223
229
|
/** @type {import('./types/index').URIComponent} */
|
|
224
230
|
const parsed = {
|
|
@@ -231,6 +237,8 @@ function parse (uri, opts) {
|
|
|
231
237
|
fragment: undefined
|
|
232
238
|
}
|
|
233
239
|
|
|
240
|
+
let malformedAuthorityOrPort = false
|
|
241
|
+
|
|
234
242
|
let isIP = false
|
|
235
243
|
if (options.reference === 'suffix') {
|
|
236
244
|
if (options.scheme) {
|
|
@@ -256,6 +264,13 @@ function parse (uri, opts) {
|
|
|
256
264
|
if (isNaN(parsed.port)) {
|
|
257
265
|
parsed.port = matches[5]
|
|
258
266
|
}
|
|
267
|
+
|
|
268
|
+
const parseError = getParseError(parsed, matches)
|
|
269
|
+
if (parseError !== undefined) {
|
|
270
|
+
parsed.error = parsed.error || parseError
|
|
271
|
+
malformedAuthorityOrPort = true
|
|
272
|
+
}
|
|
273
|
+
|
|
259
274
|
if (parsed.host) {
|
|
260
275
|
const ipv4result = isIPv4(parsed.host)
|
|
261
276
|
if (ipv4result === false) {
|
|
@@ -304,14 +319,18 @@ function parse (uri, opts) {
|
|
|
304
319
|
parsed.scheme = unescape(parsed.scheme)
|
|
305
320
|
}
|
|
306
321
|
if (parsed.host !== undefined) {
|
|
307
|
-
parsed.host = unescape(parsed.host)
|
|
322
|
+
parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP)
|
|
308
323
|
}
|
|
309
324
|
}
|
|
310
325
|
if (parsed.path) {
|
|
311
|
-
parsed.path =
|
|
326
|
+
parsed.path = normalizePathEncoding(parsed.path)
|
|
312
327
|
}
|
|
313
328
|
if (parsed.fragment) {
|
|
314
|
-
|
|
329
|
+
try {
|
|
330
|
+
parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment))
|
|
331
|
+
} catch {
|
|
332
|
+
parsed.error = parsed.error || 'URI malformed'
|
|
333
|
+
}
|
|
315
334
|
}
|
|
316
335
|
}
|
|
317
336
|
|
|
@@ -322,7 +341,54 @@ function parse (uri, opts) {
|
|
|
322
341
|
} else {
|
|
323
342
|
parsed.error = parsed.error || 'URI can not be parsed.'
|
|
324
343
|
}
|
|
325
|
-
return parsed
|
|
344
|
+
return { parsed, malformedAuthorityOrPort }
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* @param {string} uri
|
|
349
|
+
* @param {import('./types/index').Options} [opts]
|
|
350
|
+
* @returns
|
|
351
|
+
*/
|
|
352
|
+
function parse (uri, opts) {
|
|
353
|
+
return parseWithStatus(uri, opts).parsed
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* @param {string} uri
|
|
358
|
+
* @param {import('./types/index').Options} [opts]
|
|
359
|
+
* @returns {string}
|
|
360
|
+
*/
|
|
361
|
+
function normalizeString (uri, opts) {
|
|
362
|
+
return normalizeStringWithStatus(uri, opts).normalized
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* @param {string} uri
|
|
367
|
+
* @param {import('./types/index').Options} [opts]
|
|
368
|
+
* @returns {{ normalized: string, malformedAuthorityOrPort: boolean }}
|
|
369
|
+
*/
|
|
370
|
+
function normalizeStringWithStatus (uri, opts) {
|
|
371
|
+
const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts)
|
|
372
|
+
return {
|
|
373
|
+
normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
|
|
374
|
+
malformedAuthorityOrPort
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* @param {import ('./types/index').URIComponent|string} uri
|
|
380
|
+
* @param {import('./types/index').Options} [opts]
|
|
381
|
+
* @returns {string|undefined}
|
|
382
|
+
*/
|
|
383
|
+
function normalizeComparableURI (uri, opts) {
|
|
384
|
+
if (typeof uri === 'string') {
|
|
385
|
+
const { normalized, malformedAuthorityOrPort } = normalizeStringWithStatus(uri, opts)
|
|
386
|
+
return malformedAuthorityOrPort ? undefined : normalized
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (typeof uri === 'object') {
|
|
390
|
+
return serialize(uri, opts)
|
|
391
|
+
}
|
|
326
392
|
}
|
|
327
393
|
|
|
328
394
|
const fastUri = {
|
|
@@ -6,6 +6,15 @@ const isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\d
|
|
|
6
6
|
/** @type {(value: string) => boolean} */
|
|
7
7
|
const isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u)
|
|
8
8
|
|
|
9
|
+
/** @type {(value: string) => boolean} */
|
|
10
|
+
const isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu)
|
|
11
|
+
|
|
12
|
+
/** @type {(value: string) => boolean} */
|
|
13
|
+
const isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu)
|
|
14
|
+
|
|
15
|
+
/** @type {(value: string) => boolean} */
|
|
16
|
+
const isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu)
|
|
17
|
+
|
|
9
18
|
/**
|
|
10
19
|
* @param {Array<string>} input
|
|
11
20
|
* @returns {string}
|
|
@@ -264,31 +273,126 @@ function removeDotSegments (path) {
|
|
|
264
273
|
}
|
|
265
274
|
|
|
266
275
|
/**
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
276
|
+
* Re-escape RFC 3986 gen-delims that must not appear literally in the host.
|
|
277
|
+
* After the URI regex parses, these characters cannot be literal in the host
|
|
278
|
+
* field, so any that appear after decoding came from percent-encoding and
|
|
279
|
+
* must be restored to prevent authority structure changes.
|
|
280
|
+
*
|
|
281
|
+
* @param {string} host
|
|
282
|
+
* @param {boolean} isIP - true for IPv4/IPv6 hosts (skip colon re-escaping)
|
|
283
|
+
* @returns {string}
|
|
270
284
|
*/
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
285
|
+
const HOST_DELIMS = { '@': '%40', '/': '%2F', '?': '%3F', '#': '%23', ':': '%3A' }
|
|
286
|
+
const HOST_DELIM_RE = /[@/?#:]/g
|
|
287
|
+
const HOST_DELIM_NO_COLON_RE = /[@/?#]/g
|
|
288
|
+
|
|
289
|
+
function reescapeHostDelimiters (host, isIP) {
|
|
290
|
+
const re = isIP ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_RE
|
|
291
|
+
re.lastIndex = 0
|
|
292
|
+
return host.replace(re, (ch) => HOST_DELIMS[ch])
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Normalizes percent escapes and optionally decodes only unreserved ASCII bytes.
|
|
297
|
+
* Reserved delimiters such as `%2F` and `%2E` stay escaped.
|
|
298
|
+
*
|
|
299
|
+
* @param {string} input
|
|
300
|
+
* @param {boolean} [decodeUnreserved=false]
|
|
301
|
+
* @returns {string}
|
|
302
|
+
*/
|
|
303
|
+
function normalizePercentEncoding (input, decodeUnreserved = false) {
|
|
304
|
+
if (input.indexOf('%') === -1) {
|
|
305
|
+
return input
|
|
281
306
|
}
|
|
282
|
-
|
|
283
|
-
|
|
307
|
+
|
|
308
|
+
let output = ''
|
|
309
|
+
|
|
310
|
+
for (let i = 0; i < input.length; i++) {
|
|
311
|
+
if (input[i] === '%' && i + 2 < input.length) {
|
|
312
|
+
const hex = input.slice(i + 1, i + 3)
|
|
313
|
+
if (isHexPair(hex)) {
|
|
314
|
+
const normalizedHex = hex.toUpperCase()
|
|
315
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16))
|
|
316
|
+
|
|
317
|
+
if (decodeUnreserved && isUnreserved(decoded)) {
|
|
318
|
+
output += decoded
|
|
319
|
+
} else {
|
|
320
|
+
output += '%' + normalizedHex
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
i += 2
|
|
324
|
+
continue
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
output += input[i]
|
|
284
329
|
}
|
|
285
|
-
|
|
286
|
-
|
|
330
|
+
|
|
331
|
+
return output
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Normalizes path data without turning reserved escapes into live path syntax.
|
|
336
|
+
* Valid escapes are uppercased, raw unsafe characters are escaped, and only
|
|
337
|
+
* unreserved bytes that are not `.` are decoded.
|
|
338
|
+
*
|
|
339
|
+
* @param {string} input
|
|
340
|
+
* @returns {string}
|
|
341
|
+
*/
|
|
342
|
+
function normalizePathEncoding (input) {
|
|
343
|
+
let output = ''
|
|
344
|
+
|
|
345
|
+
for (let i = 0; i < input.length; i++) {
|
|
346
|
+
if (input[i] === '%' && i + 2 < input.length) {
|
|
347
|
+
const hex = input.slice(i + 1, i + 3)
|
|
348
|
+
if (isHexPair(hex)) {
|
|
349
|
+
const normalizedHex = hex.toUpperCase()
|
|
350
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16))
|
|
351
|
+
|
|
352
|
+
if (decoded !== '.' && isUnreserved(decoded)) {
|
|
353
|
+
output += decoded
|
|
354
|
+
} else {
|
|
355
|
+
output += '%' + normalizedHex
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
i += 2
|
|
359
|
+
continue
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (isPathCharacter(input[i])) {
|
|
364
|
+
output += input[i]
|
|
365
|
+
} else {
|
|
366
|
+
output += escape(input[i])
|
|
367
|
+
}
|
|
287
368
|
}
|
|
288
|
-
|
|
289
|
-
|
|
369
|
+
|
|
370
|
+
return output
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Escapes a component while preserving existing valid percent escapes.
|
|
375
|
+
*
|
|
376
|
+
* @param {string} input
|
|
377
|
+
* @returns {string}
|
|
378
|
+
*/
|
|
379
|
+
function escapePreservingEscapes (input) {
|
|
380
|
+
let output = ''
|
|
381
|
+
|
|
382
|
+
for (let i = 0; i < input.length; i++) {
|
|
383
|
+
if (input[i] === '%' && i + 2 < input.length) {
|
|
384
|
+
const hex = input.slice(i + 1, i + 3)
|
|
385
|
+
if (isHexPair(hex)) {
|
|
386
|
+
output += '%' + hex.toUpperCase()
|
|
387
|
+
i += 2
|
|
388
|
+
continue
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
output += escape(input[i])
|
|
290
393
|
}
|
|
291
|
-
|
|
394
|
+
|
|
395
|
+
return output
|
|
292
396
|
}
|
|
293
397
|
|
|
294
398
|
/**
|
|
@@ -310,7 +414,7 @@ function recomposeAuthority (component) {
|
|
|
310
414
|
if (ipV6res.isIPV6 === true) {
|
|
311
415
|
host = `[${ipV6res.escapedHost}]`
|
|
312
416
|
} else {
|
|
313
|
-
host =
|
|
417
|
+
host = reescapeHostDelimiters(host, false)
|
|
314
418
|
}
|
|
315
419
|
}
|
|
316
420
|
uriTokens.push(host)
|
|
@@ -327,7 +431,10 @@ function recomposeAuthority (component) {
|
|
|
327
431
|
module.exports = {
|
|
328
432
|
nonSimpleDomain,
|
|
329
433
|
recomposeAuthority,
|
|
330
|
-
|
|
434
|
+
reescapeHostDelimiters,
|
|
435
|
+
normalizePercentEncoding,
|
|
436
|
+
normalizePathEncoding,
|
|
437
|
+
escapePreservingEscapes,
|
|
331
438
|
removeDotSegments,
|
|
332
439
|
isIPv4,
|
|
333
440
|
isUUID,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-uri",
|
|
3
3
|
"description": "Dependency-free RFC 3986 URI toolbox",
|
|
4
|
-
"version": "3.1.
|
|
4
|
+
"version": "3.1.2",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"types": "types/index.d.ts",
|
|
@@ -58,12 +58,11 @@
|
|
|
58
58
|
"test:typescript": "tsd"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@fastify/pre-commit": "^2.1.0",
|
|
62
61
|
"ajv": "^8.16.0",
|
|
63
62
|
"eslint": "^9.17.0",
|
|
64
|
-
"neostandard": "^0.
|
|
63
|
+
"neostandard": "^0.13.0",
|
|
65
64
|
"playwright-test": "^14.1.12",
|
|
66
65
|
"tape": "^5.8.1",
|
|
67
|
-
"tsd": "^0.
|
|
66
|
+
"tsd": "^0.33.0"
|
|
68
67
|
}
|
|
69
68
|
}
|
|
@@ -106,3 +106,12 @@ test('WSS Equal', (t) => {
|
|
|
106
106
|
runTest(t, suite)
|
|
107
107
|
t.end()
|
|
108
108
|
})
|
|
109
|
+
|
|
110
|
+
test('URI Equals tolerates malformed fragments', (t) => {
|
|
111
|
+
t.equal(
|
|
112
|
+
fastURI.equal('http://example.com/#%E0%A4A', 'http://example.com/#%E0%A4A'),
|
|
113
|
+
true,
|
|
114
|
+
'malformed fragment does not throw during equality checks'
|
|
115
|
+
)
|
|
116
|
+
t.end()
|
|
117
|
+
})
|
|
@@ -150,6 +150,11 @@ test('URI parse', (t) => {
|
|
|
150
150
|
t.equal(components.query, undefined, 'query')
|
|
151
151
|
t.equal(components.fragment, '%0D', 'fragment')
|
|
152
152
|
|
|
153
|
+
// malformed percent-encoded fragment must not throw
|
|
154
|
+
components = fastURI.parse('http://example.com/#%E0%A4A')
|
|
155
|
+
t.equal(components.error, 'URI malformed', 'malformed fragment errors')
|
|
156
|
+
t.equal(components.fragment, '%E0%A4A', 'malformed fragment is preserved')
|
|
157
|
+
|
|
153
158
|
// all
|
|
154
159
|
components = fastURI.parse('uri://user:pass@example.com:123/one/two.three?q1=a1&q2=a2#body')
|
|
155
160
|
t.equal(components.error, undefined, 'all errors')
|
|
@@ -76,3 +76,12 @@ test('URN Resolving', (t) => {
|
|
|
76
76
|
t.equal(fastURI.resolve('urn:some:other:prop', 'urn:some:ip:prop'), 'urn:some:ip:prop', 'urn:some:ip:prop')
|
|
77
77
|
t.end()
|
|
78
78
|
})
|
|
79
|
+
|
|
80
|
+
test('URI Resolving tolerates malformed fragments', (t) => {
|
|
81
|
+
t.equal(
|
|
82
|
+
fastURI.resolve('http://base.com/', 'http://example.com/#%E0%A4A'),
|
|
83
|
+
'http://example.com/#%E0%A4A',
|
|
84
|
+
'malformed fragment does not throw during resolve'
|
|
85
|
+
)
|
|
86
|
+
t.end()
|
|
87
|
+
})
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const test = require('tape')
|
|
4
|
+
const fastURI = require('..')
|
|
5
|
+
|
|
6
|
+
test('parse preserves reserved path escapes as data', (t) => {
|
|
7
|
+
const components = fastURI.parse('http://example.com/a%2Fb/public/%2e%2e/admin')
|
|
8
|
+
|
|
9
|
+
t.equal(components.path, '/a%2Fb/public/%2E%2E/admin')
|
|
10
|
+
t.end()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
test('normalize preserves percent-encoded path separators and dot segments', (t) => {
|
|
14
|
+
t.equal(
|
|
15
|
+
fastURI.normalize('http://example.com/public/%2e%2e/admin'),
|
|
16
|
+
'http://example.com/public/%2E%2E/admin'
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
t.equal(
|
|
20
|
+
fastURI.normalize('http://example.com/a%2Fb'),
|
|
21
|
+
'http://example.com/a%2Fb'
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
t.end()
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('equal does not treat reserved path escapes as live path syntax', (t) => {
|
|
28
|
+
t.equal(
|
|
29
|
+
fastURI.equal('http://example.com/public/%2e%2e/admin', 'http://example.com/admin', {}),
|
|
30
|
+
false
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
t.equal(
|
|
34
|
+
fastURI.equal('http://example.com/a%2Fb', 'http://example.com/a/b', {}),
|
|
35
|
+
false
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
t.end()
|
|
39
|
+
})
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const test = require('tape')
|
|
4
|
+
const fastURI = require('..')
|
|
5
|
+
|
|
6
|
+
test('parse marks malformed authority and port inputs as errors', (t) => {
|
|
7
|
+
const malformedCases = [
|
|
8
|
+
{
|
|
9
|
+
input: 'http://[::1]foo',
|
|
10
|
+
expectedError: 'URI path must start with "/" when authority is present.'
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
input: 'http://[::1]:80abc/path',
|
|
14
|
+
expectedError: 'URI path must start with "/" when authority is present.'
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
input: 'http://example.com:80abc/path',
|
|
18
|
+
expectedError: 'URI path must start with "/" when authority is present.'
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
input: 'http://[::1]:65536',
|
|
22
|
+
expectedError: 'URI port is malformed.'
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
t.plan(malformedCases.length)
|
|
27
|
+
|
|
28
|
+
malformedCases.forEach(({ input, expectedError }) => {
|
|
29
|
+
t.equal(fastURI.parse(input).error, expectedError, input)
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('normalize does not canonicalize malformed URLs into different valid URLs', (t) => {
|
|
34
|
+
const malformedCases = [
|
|
35
|
+
'http://[::1]foo',
|
|
36
|
+
'http://[::1]:80abc/path',
|
|
37
|
+
'http://example.com:80abc/path',
|
|
38
|
+
'http://[::1]:65536'
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
t.plan(malformedCases.length)
|
|
42
|
+
|
|
43
|
+
malformedCases.forEach((input) => {
|
|
44
|
+
t.equal(fastURI.normalize(input), input, input)
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('equal returns false when either side is malformed', (t) => {
|
|
49
|
+
const malformedPairs = [
|
|
50
|
+
['http://[::1]foo', 'http://[::1]/foo'],
|
|
51
|
+
['http://[::1]:80abc/path', 'http://[::1]/abc/path'],
|
|
52
|
+
['http://example.com:80abc/path', 'http://example.com/abc/path'],
|
|
53
|
+
['http://[::1]:65536', 'http://[::1]:65536/']
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
t.plan(malformedPairs.length)
|
|
57
|
+
|
|
58
|
+
malformedPairs.forEach(([left, right]) => {
|
|
59
|
+
t.equal(fastURI.equal(left, right), false, `${left} != ${right}`)
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
test('normalize preserves encoded authority delimiters in host', (t) => {
|
|
64
|
+
const cases = [
|
|
65
|
+
['http://trusted.com%40evil.com/', 'http://trusted.com%40evil.com/'],
|
|
66
|
+
['http://example.com%3A8080/', 'http://example.com%3A8080/'],
|
|
67
|
+
['http://example.com%2Fevil.com/path', 'http://example.com%2Fevil.com/path'],
|
|
68
|
+
['http://example.com%23fragment/path', 'http://example.com%23fragment/path'],
|
|
69
|
+
['http://example.com%3Fq=evil/path', 'http://example.com%3Fq=evil/path'],
|
|
70
|
+
['http://user%3Apass%40evil.com/', 'http://user%3Apass%40evil.com/'],
|
|
71
|
+
['http://user@trusted.com%40evil.com/', 'http://user@trusted.com%40evil.com/'],
|
|
72
|
+
['https://trusted.com%40evil.com/', 'https://trusted.com%40evil.com/'],
|
|
73
|
+
['ws://trusted.com%40evil.com/chat', 'ws://trusted.com%40evil.com/chat'],
|
|
74
|
+
['wss://trusted.com%40evil.com/chat', 'wss://trusted.com%40evil.com/chat']
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
t.plan(cases.length)
|
|
78
|
+
|
|
79
|
+
cases.forEach(([input, expected]) => {
|
|
80
|
+
t.equal(fastURI.normalize(input), expected, input)
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
test('parse preserves encoded authority delimiters in host', (t) => {
|
|
85
|
+
const cases = [
|
|
86
|
+
['http://trusted.com%40evil.com/', 'trusted.com%40evil.com'],
|
|
87
|
+
['http://example.com%3A8080/', 'example.com%3A8080'],
|
|
88
|
+
['http://user%3Apass%40evil.com/', 'user%3Apass%40evil.com']
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
t.plan(cases.length)
|
|
92
|
+
|
|
93
|
+
cases.forEach(([input, expectedHost]) => {
|
|
94
|
+
t.equal(fastURI.parse(input).host, expectedHost, input)
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test('equal returns false when encoded delimiters differ from live delimiters', (t) => {
|
|
99
|
+
const pairs = [
|
|
100
|
+
['http://trusted.com%40evil.com/', 'http://trusted.com@evil.com/'],
|
|
101
|
+
['http://example.com%3A8080/', 'http://example.com:8080/']
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
t.plan(pairs.length)
|
|
105
|
+
|
|
106
|
+
pairs.forEach(([left, right]) => {
|
|
107
|
+
t.equal(fastURI.equal(left, right, {}), false, `${left} != ${right}`)
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
test('resolve preserves encoded authority delimiters', (t) => {
|
|
112
|
+
const result = fastURI.resolve('http://base.com/', '//trusted.com%40evil.com/path')
|
|
113
|
+
const parsed = fastURI.parse(result)
|
|
114
|
+
|
|
115
|
+
t.plan(1)
|
|
116
|
+
t.notEqual(parsed.host, 'evil.com', '//trusted.com%40evil.com/path')
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
test('serialize escapes authority delimiters in host field', (t) => {
|
|
120
|
+
const result = fastURI.serialize({ scheme: 'http', host: 'trusted.com@evil.com', path: '/' })
|
|
121
|
+
const parsed = fastURI.parse(result)
|
|
122
|
+
|
|
123
|
+
t.plan(1)
|
|
124
|
+
t.notEqual(parsed.host, 'evil.com', 'host: trusted.com@evil.com')
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
test('normalize does not double-decode %2540 into a live @', (t) => {
|
|
128
|
+
const result = fastURI.normalize('http://trusted.com%2540evil.com/')
|
|
129
|
+
const parsed = fastURI.parse(result)
|
|
130
|
+
|
|
131
|
+
t.plan(1)
|
|
132
|
+
t.notEqual(parsed.host, 'trusted.com@evil.com', 'http://trusted.com%2540evil.com/')
|
|
133
|
+
})
|
package/package.json
CHANGED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# Number of days of inactivity before an issue becomes stale
|
|
2
|
-
daysUntilStale: 15
|
|
3
|
-
# Number of days of inactivity before a stale issue is closed
|
|
4
|
-
daysUntilClose: 7
|
|
5
|
-
# Issues with these labels will never be considered stale
|
|
6
|
-
exemptLabels:
|
|
7
|
-
- "discussion"
|
|
8
|
-
- "feature request"
|
|
9
|
-
- "bug"
|
|
10
|
-
- "help wanted"
|
|
11
|
-
- "plugin suggestion"
|
|
12
|
-
- "good first issue"
|
|
13
|
-
# Label to use when marking an issue as stale
|
|
14
|
-
staleLabel: stale
|
|
15
|
-
# Comment to post when marking an issue as stale. Set to `false` to disable
|
|
16
|
-
markComment: >
|
|
17
|
-
This issue has been automatically marked as stale because it has not had
|
|
18
|
-
recent activity. It will be closed if no further activity occurs. Thank you
|
|
19
|
-
for your contributions.
|
|
20
|
-
# Comment to post when closing a stale issue. Set to `false` to disable
|
|
21
|
-
closeComment: false
|