tldts-icann 7.2.0 → 7.2.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/dist/cjs/index.js CHANGED
@@ -291,29 +291,50 @@ function extractHostname(url, urlIsValidHostname) {
291
291
  if (!allDigits) {
292
292
  const special = getSpecialScheme(url, start, indexOfColon);
293
293
  if (special === 0) {
294
- // No "://" anywhere on the cold path, so a non-special scheme has
295
- // no authority: opaque path, no host ("mailto:x", "foo:bar").
296
- return null;
297
- }
298
- isSpecial = true;
299
- start = indexOfColon + 1;
300
- if (special === 2) {
301
- // file (e.g. "file:\\host"): host only between "//" and next slash.
302
- let slashes = 0;
303
- while ((url.charCodeAt(start) === 47 ||
304
- url.charCodeAt(start) === 92) &&
305
- slashes < 2) {
306
- start += 1;
307
- slashes += 1;
294
+ // No "://" anywhere on the cold path and not a special scheme.
295
+ // A second ':' before the host's end marks a bare, unbracketed
296
+ // IPv6 literal ("2a01:e35::1"): fall through and let the host
297
+ // loop + isIp classify it. Without one this is an opaque path
298
+ // with no host ("mailto:x", "foo:bar").
299
+ let isBareIpv6 = false;
300
+ for (let j = indexOfColon + 1; j < end; j += 1) {
301
+ const code = url.charCodeAt(j);
302
+ if (code === 47 ||
303
+ code === 92 ||
304
+ code === 63 ||
305
+ code === 35) {
306
+ break;
307
+ }
308
+ if (code === 58 /* ':' */) {
309
+ isBareIpv6 = true;
310
+ break;
311
+ }
308
312
  }
309
- if (slashes < 2) {
313
+ if (!isBareIpv6) {
310
314
  return null;
311
315
  }
312
316
  }
313
317
  else {
314
- while (url.charCodeAt(start) === 47 ||
315
- url.charCodeAt(start) === 92) {
316
- start += 1;
318
+ isSpecial = true;
319
+ start = indexOfColon + 1;
320
+ if (special === 2) {
321
+ // file (e.g. "file:\\host"): host only between "//" and next slash.
322
+ let slashes = 0;
323
+ while ((url.charCodeAt(start) === 47 ||
324
+ url.charCodeAt(start) === 92) &&
325
+ slashes < 2) {
326
+ start += 1;
327
+ slashes += 1;
328
+ }
329
+ if (slashes < 2) {
330
+ return null;
331
+ }
332
+ }
333
+ else {
334
+ while (url.charCodeAt(start) === 47 ||
335
+ url.charCodeAt(start) === 92) {
336
+ start += 1;
337
+ }
317
338
  }
318
339
  }
319
340
  }
@@ -323,11 +344,14 @@ function extractHostname(url, urlIsValidHostname) {
323
344
  }
324
345
  // Find the host's end: first '/', '?' or '#' (and '\' for special URLs,
325
346
  // which WHATWG treats like '/'). Track the last '@', ']' and ':' for
326
- // userinfo, ipv6 and port; flag uppercase and a stray tab/newline. The loop
327
- // is split on `code < 64` so common host characters take fewer comparisons.
347
+ // userinfo, ipv6 and port, plus the first ':' of the host (reset at each
348
+ // '@') to tell a bare IPv6 (>= 2 colons) from a host:port (exactly one);
349
+ // flag uppercase and a stray tab/newline. The loop is split on `code < 64`
350
+ // so common host characters take fewer comparisons.
328
351
  let indexOfIdentifier = -1;
329
352
  let indexOfClosingBracket = -1;
330
353
  let indexOfPort = -1;
354
+ let indexOfFirstColon = -1;
331
355
  let hasControl = false;
332
356
  for (let i = start; i < end; i += 1) {
333
357
  const code = url.charCodeAt(i);
@@ -337,6 +361,9 @@ function extractHostname(url, urlIsValidHostname) {
337
361
  break;
338
362
  }
339
363
  else if (code === 58 /* ':' */) {
364
+ if (indexOfFirstColon === -1) {
365
+ indexOfFirstColon = i;
366
+ }
340
367
  indexOfPort = i;
341
368
  }
342
369
  else if (code === 9 || code === 10 || code === 13) {
@@ -349,6 +376,7 @@ function extractHostname(url, urlIsValidHostname) {
349
376
  }
350
377
  else if (code === 64 /* '@' */) {
351
378
  indexOfIdentifier = i;
379
+ indexOfFirstColon = -1; // colons before '@' are userinfo, not the host
352
380
  }
353
381
  else if (code === 93 /* ']' */) {
354
382
  indexOfClosingBracket = i;
@@ -374,7 +402,13 @@ function extractHostname(url, urlIsValidHostname) {
374
402
  }
375
403
  return null;
376
404
  }
377
- else if (indexOfPort !== -1 && indexOfPort > start && indexOfPort < end) {
405
+ else if (indexOfPort !== -1 &&
406
+ indexOfPort > start &&
407
+ indexOfPort < end &&
408
+ // A host:port has exactly one ':' in the host (so its first ':' is its
409
+ // last); a bare, unbracketed IPv6 literal ("2a01:e35::1") has >= 2, so
410
+ // its first ':' precedes the last. Only the former has a ':port' to trim.
411
+ indexOfFirstColon === indexOfPort) {
378
412
  end = indexOfPort; // trim ':port'
379
413
  }
380
414
  // Empty authority ("http://", "file:///path", "//"); only reachable here via