cdk-common 2.1.34 → 2.1.36

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 CHANGED
@@ -12984,6 +12984,6 @@
12984
12984
  "symbolId": "src/main:LambdaArmFunctionProps"
12985
12985
  }
12986
12986
  },
12987
- "version": "2.1.34",
12988
- "fingerprint": "bxGvPWwwiFW3GKNhsAtpY0JPXV7h0YO7m5vqBPxFhvQ="
12987
+ "version": "2.1.36",
12988
+ "fingerprint": "7QQoukt6kPvbWzn+NN9V7ZN0alsNkAaxkcGp/4lkVhY="
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.34" };
41
+ LambdaArmFunction[_a] = { fqn: "cdk-common.LambdaArmFunction", version: "2.1.36" };
42
42
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9tYWluLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsbUNBQW1DO0FBQ25DLGlEQUFpRDtBQUNqRCwyQ0FBdUM7QUFLdkMsTUFBYSxpQkFBa0IsU0FBUSxzQkFBUztJQUU5QyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQTRCO1FBQ3BFLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFakIsTUFBTSxlQUFlLEdBQUcsSUFBSSxHQUFHLENBQXlCO1lBQ3RELENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsbUNBQW1DLENBQUM7WUFDakUsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxtQ0FBbUMsQ0FBQztZQUNqRSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLG1DQUFtQyxDQUFDO1lBQ2pFLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsa0NBQWtDLENBQUM7WUFDaEUsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxrQ0FBa0MsQ0FBQztZQUNoRSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLGtDQUFrQyxDQUFDO1lBQ2hFLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsa0NBQWtDLENBQUM7WUFDaEUsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSw4QkFBOEIsQ0FBQztZQUN4RCxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLDhCQUE4QixDQUFDO1lBQ3hELENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsNkJBQTZCLENBQUM7WUFDeEQsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSwrQkFBK0IsQ0FBQztZQUMxRCxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLCtCQUErQixDQUFDO1NBQzNELENBQUMsQ0FBQztRQUVILE1BQU0sT0FBTyxHQUFHLGVBQWUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ25ELElBQUksT0FBTyxFQUFFLENBQUM7WUFDWixHQUFHLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDL0MsQ0FBQzthQUFNLENBQUM7WUFDTixNQUFNLElBQUksS0FBSyxDQUFDLG1CQUFtQixLQUFLLENBQUMsT0FBTyx1R0FBdUcsQ0FBQyxDQUFDO1FBQzNKLENBQUM7UUFFRCxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsZ0JBQWdCLEVBQUU7WUFDaEUsWUFBWSxFQUFFLEtBQUssQ0FBQyxZQUFZLElBQUksTUFBTSxDQUFDLFlBQVksQ0FBQyxNQUFNO1lBQzlELEdBQUcsS0FBSztTQUNULENBQUMsQ0FBQztJQUNMLENBQUM7O0FBL0JILDhDQWdDQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGNkayBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgKiBhcyBsYW1iZGEgZnJvbSAnYXdzLWNkay1saWIvYXdzLWxhbWJkYSc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmV4cG9ydCBpbnRlcmZhY2UgTGFtYmRhQXJtRnVuY3Rpb25Qcm9wcyBleHRlbmRzIGxhbWJkYS5GdW5jdGlvblByb3BzIHtcblxufVxuXG5leHBvcnQgY2xhc3MgTGFtYmRhQXJtRnVuY3Rpb24gZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBwdWJsaWMgcmVhZG9ubHkgbGFtYmRhRnVuY3Rpb246IGxhbWJkYS5GdW5jdGlvbjtcbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6TGFtYmRhQXJtRnVuY3Rpb25Qcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICBjb25zdCBydW50aW1lV2FybmluZ3MgPSBuZXcgTWFwPGxhbWJkYS5SdW50aW1lLCBzdHJpbmc+KFtcbiAgICAgIFtsYW1iZGEuUnVudGltZS5OT0RFSlNfMjJfWCwgJ1lvdSBhcmUgdXNpbmcgTm9kZS5qcyAyMi54IGF0IEFSTSddLFxuICAgICAgW2xhbWJkYS5SdW50aW1lLk5PREVKU18yMF9YLCAnWW91IGFyZSB1c2luZyBOb2RlLmpzIDIwLnggYXQgQVJNJ10sXG4gICAgICBbbGFtYmRhLlJ1bnRpbWUuTk9ERUpTXzE4X1gsICdZb3UgYXJlIHVzaW5nIE5vZGUuanMgMTgueCBhdCBBUk0nXSxcbiAgICAgIFtsYW1iZGEuUnVudGltZS5QWVRIT05fM18xMywgJ1lvdSBhcmUgdXNpbmcgUHl0aG9uIDMuMTMgYXQgQVJNJ10sXG4gICAgICBbbGFtYmRhLlJ1bnRpbWUuUFlUSE9OXzNfMTIsICdZb3UgYXJlIHVzaW5nIFB5dGhvbiAzLjEyIGF0IEFSTSddLFxuICAgICAgW2xhbWJkYS5SdW50aW1lLlBZVEhPTl8zXzExLCAnWW91IGFyZSB1c2luZyBQeXRob24gMy4xMSBhdCBBUk0nXSxcbiAgICAgIFtsYW1iZGEuUnVudGltZS5QWVRIT05fM18xMCwgJ1lvdSBhcmUgdXNpbmcgUHl0aG9uIDMuMTAgYXQgQVJNJ10sXG4gICAgICBbbGFtYmRhLlJ1bnRpbWUuSkFWQV8yMSwgJ1lvdSBhcmUgdXNpbmcgSmF2YSAyMSBhdCBBUk0nXSxcbiAgICAgIFtsYW1iZGEuUnVudGltZS5KQVZBXzE3LCAnWW91IGFyZSB1c2luZyBKYXZhIDE3IGF0IEFSTSddLFxuICAgICAgW2xhbWJkYS5SdW50aW1lLkRPVE5FVF84LCAnWW91IGFyZSB1c2luZyAuTkVUIDggYXQgQVJNJ10sXG4gICAgICBbbGFtYmRhLlJ1bnRpbWUuUlVCWV8zXzQsICdZb3UgYXJlIHVzaW5nIFJ1YnkgMy40IGF0IEFSTSddLFxuICAgICAgW2xhbWJkYS5SdW50aW1lLlJVQllfM18zLCAnWW91IGFyZSB1c2luZyBSdWJ5IDMuMyBhdCBBUk0nXSxcbiAgICBdKTtcblxuICAgIGNvbnN0IHdhcm5pbmcgPSBydW50aW1lV2FybmluZ3MuZ2V0KHByb3BzLnJ1bnRpbWUpO1xuICAgIGlmICh3YXJuaW5nKSB7XG4gICAgICBjZGsuQW5ub3RhdGlvbnMub2YodGhpcykuYWRkV2FybmluZyh3YXJuaW5nKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIFJ1bnRpbWUgJHtwcm9wcy5ydW50aW1lfSBhdCBBUk0sIFNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vbGFtYmRhL2xhdGVzdC9kZy9mb3VuZGF0aW9uLWFyY2guaHRtbD9pY21waWQ9ZG9jc19sYW1iZGFfcnNzYCk7XG4gICAgfVxuXG4gICAgdGhpcy5sYW1iZGFGdW5jdGlvbiA9IG5ldyBsYW1iZGEuRnVuY3Rpb24odGhpcywgJ0xhbWJkYUZ1bmN0aW9uJywge1xuICAgICAgYXJjaGl0ZWN0dXJlOiBwcm9wcy5hcmNoaXRlY3R1cmUgPz8gbGFtYmRhLkFyY2hpdGVjdHVyZS5BUk1fNjQsXG4gICAgICAuLi5wcm9wcyxcbiAgICB9KTtcbiAgfVxufVxuIl19
@@ -8,7 +8,7 @@ This package contains type definitions for qs (https://github.com/ljharb/qs).
8
8
  Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/qs.
9
9
 
10
10
  ### Additional Details
11
- * Last updated: Fri, 06 Mar 2026 02:55:52 GMT
11
+ * Last updated: Wed, 06 May 2026 23:46:00 GMT
12
12
  * Dependencies: none
13
13
 
14
14
  # Credits
@@ -2,8 +2,8 @@ export = QueryString;
2
2
  export as namespace qs;
3
3
 
4
4
  declare namespace QueryString {
5
- type defaultEncoder = (str: any, defaultEncoder?: any, charset?: string) => string;
6
- type defaultDecoder = (str: string, decoder?: any, charset?: string) => string;
5
+ type defaultEncoder = (str: unknown, defaultEncoder?: unknown, charset?: string) => string;
6
+ type defaultDecoder = (str: string, decoder?: unknown, charset?: string) => string;
7
7
 
8
8
  type BooleanOptional = boolean | undefined;
9
9
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@types/qs",
3
- "version": "6.15.0",
3
+ "version": "6.15.1",
4
4
  "description": "TypeScript definitions for qs",
5
5
  "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/qs",
6
6
  "license": "MIT",
@@ -61,6 +61,6 @@
61
61
  "scripts": {},
62
62
  "dependencies": {},
63
63
  "peerDependencies": {},
64
- "typesPublisherContentHash": "d601f14ce76d169006396b52d944a1f506b4654a99186b3c26393c6bb6374f8f",
65
- "typeScriptVersion": "5.2"
64
+ "typesPublisherContentHash": "05a407916d8a33f07ac30ace141b782ae9df30ee4857eb8430a1cf88ce3ad457",
65
+ "typeScriptVersion": "5.3"
66
66
  }
@@ -12,6 +12,8 @@ Dependency-free RFC 3986 URI toolbox.
12
12
 
13
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:
14
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
+
15
17
  * `scheme` (string)
16
18
  Indicates the scheme that the URI should be treated as, overriding the URI's normal scheme parsing behavior.
17
19
 
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, isIPv4, nonSimpleDomain } = require('./lib/utils')
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} */ (serialize(parse(uri, options), options))
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,19 +106,10 @@ function resolveComponent (base, relative, options, skipNormalization) {
106
106
  * @returns {boolean}
107
107
  */
108
108
  function equal (uriA, uriB, options) {
109
- if (typeof uriA === 'string') {
110
- uriA = serialize(parse(uriA, options), options)
111
- } else if (typeof uriA === 'object') {
112
- uriA = serialize(uriA, options)
113
- }
114
-
115
- if (typeof uriB === 'string') {
116
- uriB = serialize(parse(uriB, options), options)
117
- } else if (typeof uriB === 'object') {
118
- uriB = serialize(uriB, options)
119
- }
109
+ const normalizedA = normalizeComparableURI(uriA, options)
110
+ const normalizedB = normalizeComparableURI(uriB, options)
120
111
 
121
- return uriA.toLowerCase() === uriB.toLowerCase()
112
+ return normalizedA !== undefined && normalizedB !== undefined && normalizedA.toLowerCase() === normalizedB.toLowerCase()
122
113
  }
123
114
 
124
115
  /**
@@ -211,12 +202,29 @@ function serialize (cmpts, opts) {
211
202
 
212
203
  const URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u
213
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
+
214
222
  /**
215
223
  * @param {string} uri
216
224
  * @param {import('./types/index').Options} [opts]
217
- * @returns
225
+ * @returns {{ parsed: import('./types/index').URIComponent, malformedAuthorityOrPort: boolean }}
218
226
  */
219
- function parse (uri, opts) {
227
+ function parseWithStatus (uri, opts) {
220
228
  const options = Object.assign({}, opts)
221
229
  /** @type {import('./types/index').URIComponent} */
222
230
  const parsed = {
@@ -229,6 +237,8 @@ function parse (uri, opts) {
229
237
  fragment: undefined
230
238
  }
231
239
 
240
+ let malformedAuthorityOrPort = false
241
+
232
242
  let isIP = false
233
243
  if (options.reference === 'suffix') {
234
244
  if (options.scheme) {
@@ -254,6 +264,13 @@ function parse (uri, opts) {
254
264
  if (isNaN(parsed.port)) {
255
265
  parsed.port = matches[5]
256
266
  }
267
+
268
+ const parseError = getParseError(parsed, matches)
269
+ if (parseError !== undefined) {
270
+ parsed.error = parsed.error || parseError
271
+ malformedAuthorityOrPort = true
272
+ }
273
+
257
274
  if (parsed.host) {
258
275
  const ipv4result = isIPv4(parsed.host)
259
276
  if (ipv4result === false) {
@@ -302,14 +319,18 @@ function parse (uri, opts) {
302
319
  parsed.scheme = unescape(parsed.scheme)
303
320
  }
304
321
  if (parsed.host !== undefined) {
305
- parsed.host = unescape(parsed.host)
322
+ parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP)
306
323
  }
307
324
  }
308
325
  if (parsed.path) {
309
326
  parsed.path = normalizePathEncoding(parsed.path)
310
327
  }
311
328
  if (parsed.fragment) {
312
- parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment))
329
+ try {
330
+ parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment))
331
+ } catch {
332
+ parsed.error = parsed.error || 'URI malformed'
333
+ }
313
334
  }
314
335
  }
315
336
 
@@ -320,7 +341,54 @@ function parse (uri, opts) {
320
341
  } else {
321
342
  parsed.error = parsed.error || 'URI can not be parsed.'
322
343
  }
323
- 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
+ }
324
392
  }
325
393
 
326
394
  const fastUri = {
@@ -272,6 +272,26 @@ function removeDotSegments (path) {
272
272
  return output.join('')
273
273
  }
274
274
 
275
+ /**
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}
284
+ */
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
+
275
295
  /**
276
296
  * Normalizes percent escapes and optionally decodes only unreserved ASCII bytes.
277
297
  * Reserved delimiters such as `%2F` and `%2E` stay escaped.
@@ -394,7 +414,7 @@ function recomposeAuthority (component) {
394
414
  if (ipV6res.isIPV6 === true) {
395
415
  host = `[${ipV6res.escapedHost}]`
396
416
  } else {
397
- host = component.host
417
+ host = reescapeHostDelimiters(host, false)
398
418
  }
399
419
  }
400
420
  uriTokens.push(host)
@@ -411,6 +431,7 @@ function recomposeAuthority (component) {
411
431
  module.exports = {
412
432
  nonSimpleDomain,
413
433
  recomposeAuthority,
434
+ reescapeHostDelimiters,
414
435
  normalizePercentEncoding,
415
436
  normalizePathEncoding,
416
437
  escapePreservingEscapes,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fast-uri",
3
3
  "description": "Dependency-free RFC 3986 URI toolbox",
4
- "version": "3.1.1",
4
+ "version": "3.1.2",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
7
7
  "types": "types/index.d.ts",
@@ -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,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
@@ -54,7 +54,7 @@
54
54
  "jsii-docgen": "^10.5.0",
55
55
  "jsii-pacmak": "^1.129.0",
56
56
  "jsii-rosetta": "5.9.x",
57
- "projen": "0.99.52",
57
+ "projen": "0.99.53",
58
58
  "ts-jest": "^27",
59
59
  "typescript": "^5"
60
60
  },
@@ -88,7 +88,7 @@
88
88
  "access": "public",
89
89
  "provenance": true
90
90
  },
91
- "version": "2.1.34",
91
+ "version": "2.1.36",
92
92
  "jest": {
93
93
  "coverageProvider": "v8",
94
94
  "testMatch": [