Files
sdk/tests/corelib/uri_ipvfuture_test.dart
Lasse R.H. Nielsen b2f0b8d083 Accept IPvFuture syntax in Uri.
The RFC 3986 grammar for `[...]` addresses accepts
IPv6 addresses  and IPvFuture addresses, where the latter
have the form `'v' <hexDigit>+ '.' (<unreserved>|<sub-delim>|':')+`.

This allows the IPvFuture syntax, with no interpretation,
as the `host` of a `Uri`.

For now, the `Uri(host: ...)` constructor argument only allows
IPvFuture addresses that are already wrapped in `[...]` brackets,
and the `Uri.host` gette returns IPvFuture addresses including
brackets.
The `Uri(host:...)` still allows unbracketed IPv6 addresses
(distinguished from plain host-names by containing a `:`),
and `Uri.host` returns IPv6 addresses without brackets.
`Uri.parse` only accept IPv6 and IPvFuture in brackets.
(Only IPv6 can have a zone.)

Fixes #60483.

CoreLibraryReviewExempt: Local implementation only, no API.
Bug: https://dartbug.com/60483
Change-Id: Id369ba1316b34f443edfe5b0f56864c32beddccc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/421081
Reviewed-by: Nate Bosch <nbosch@google.com>
Commit-Queue: Lasse Nielsen <lrn@google.com>
2025-04-09 03:56:37 -07:00

106 lines
3.4 KiB
Dart

// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:expect/expect.dart';
void testValidIPvFutureUri() {
void test(String address) {
var bracketedAddress = '[$address]';
var path = 'https://me:you@$bracketedAddress:1234/path?query=5#now';
var uri = Uri.parse(path);
var uriString = uri.toString();
Expect.equals(path, uriString);
Expect.isTrue(uri.hasAuthority);
Expect.equals('https', uri.scheme, ".scheme of $uriString");
Expect.equals('me:you', uri.userInfo, ".userInfo of $uriString");
Expect.equals(bracketedAddress, uri.host, ".host of $uriString");
Expect.equals(1234, uri.port, ".port of $uriString");
Expect.equals('/path', uri.path, ".path of $uriString");
Expect.equals('query=5', uri.query, ".query of $uriString");
Expect.equals('now', uri.fragment, ".fragment of $uriString");
uri = Uri(scheme: 'https', host: bracketedAddress, path: '/path');
Expect.isTrue(uri.hasAuthority);
Expect.equals('https://$bracketedAddress/path', uri.toString());
Expect.equals(bracketedAddress, uri.host);
uri = Uri.https(bracketedAddress, '/path');
Expect.isTrue(uri.hasAuthority);
Expect.equals('https://$bracketedAddress/path', uri.toString());
Expect.equals(bracketedAddress, uri.host);
uri = Uri.parse('https://example.com/path');
uri = uri.replace(host: bracketedAddress);
Expect.isTrue(uri.hasAuthority);
Expect.equals('https://$bracketedAddress/path', uri.toString());
Expect.equals(bracketedAddress, uri.host);
}
test('v0.0'); // Minimal valid
test('vDEADBEEF.CAKE:EAT'); // More characters.
// All allowed characters in each position
// (skipping the middle ones of 0-9, a-z and A-Z).
test(r"v0123456789abcdefABCDEF.!$&'()*+,-.09:;=AZ_az~");
}
void testInvalidIPvFutureUri() {
void fail(String host) {
Expect.throwsFormatException(() => Uri.parse('http://[$host]/'), '[$host]');
Expect.throwsFormatException(
() => Uri(scheme: 'http', host: '[$host]'),
'[$host]',
);
}
// No leading whitespace.
fail(' v0.0'); // Also not valid IPv6.
// Must start with lower-case 'v'.
fail('V0.0'); // Also not valid IPv6.
// Does not allow escapes, %56 is 'v'.
fail('%560.0'); // Also not valid IPv6.
// Hex digit must follow `v`.
fail('v');
fail('v:');
fail('v:0');
fail('v 0.0');
fail('v.:');
fail('vv0.:');
fail('v%41.:'); // No escape.
// Correct ranges for hex digits.
fail('v/.:'); // / is before 0
fail('v:.:'); // : is after 9
fail('v@.:'); // @ is before A
fail('vG.:'); // G is after F
fail('v`.:'); // ` is before a
fail('vg.:'); // g is after f
// Dot must follow hex-digits.
fail('v0');
fail('v0:');
fail('v0%2E:'); // No escape.
// Correct ranges for second hex digit.
fail('v0/.:'); // / is before 0
fail('v0:.:'); // : is after 9
fail('v0@.:'); // @ is before A
fail('v0G.:'); // G is after F
fail('v0`.:'); // ` is before a
fail('v0g.:'); // g is after f
// Valid character must follow dot.
// Unreserved, sub-delimiters and colon are valid.
fail('vA.');
fail('vA.%41'); // No escapes, no zones
// No trailing garbage.
fail('v0.0 ');
fail('v0.0/');
// No zones.
fail('v0.0%41');
fail('v0.0%25x');
}
void main() {
testValidIPvFutureUri();
testInvalidIPvFutureUri();
}