Add InternetAddress.tryParse

Closes #40692

Allows a better pattern for parsing user input than catching an
`ArgumentError`.

- Add a new static method to InternetAddress and implement it in all
  patch files.
- Add tests which match the tests for the constructor.

Change-Id: Idc76fc4875578f7a381219c0e7e12d1931d98fd8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/136406
Commit-Queue: Nate Bosch <nbosch@google.com>
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
Auto-Submit: Nate Bosch <nbosch@google.com>
This commit is contained in:
Nate Bosch 2020-04-30 17:19:02 +00:00 committed by commit-bot@chromium.org
parent cea45271b3
commit 9b34bee90b
12 changed files with 168 additions and 1 deletions

View file

@ -15,6 +15,7 @@
* Class `OSError` now implements `Exception`. This change means `OSError` will
now be caught in catch clauses catching `Exception`s.
* Added `InternetAddress.tryParse`.
### Tools

View file

@ -427,6 +427,11 @@ class InternetAddress {
InternetAddress address, String host) {
throw UnsupportedError("InternetAddress._cloneWithNewHost");
}
@patch
static InternetAddress tryParse(String address) {
throw UnsupportedError("InternetAddress.tryParse");
}
}
@patch

View file

@ -427,6 +427,11 @@ class InternetAddress {
InternetAddress address, String host) {
throw new UnsupportedError("InternetAddress._cloneWithNewHost");
}
@patch
static InternetAddress tryParse(String address) {
throw new UnsupportedError("InternetAddress.tryParse");
}
}
@patch

View file

@ -92,6 +92,11 @@ class InternetAddress {
InternetAddress address, String host) {
return (address as _InternetAddress)._cloneWithNewHost(host);
}
@patch
static InternetAddress tryParse(String address) {
return _InternetAddress.tryParse(address);
}
}
@patch
@ -253,6 +258,18 @@ class _InternetAddress implements InternetAddress {
}
}
static _InternetAddress tryParse(String address) {
if (address == null) {
throw ArgumentError("Invalid internet address $address");
}
var addressBytes = _parse(address);
if (addressBytes == null) return null;
var type = addressBytes.length == _IPv4AddrLength
? InternetAddressType.IPv4
: InternetAddressType.IPv6;
return _InternetAddress(type, address, null, addressBytes);
}
factory _InternetAddress.fixed(int id) {
switch (id) {
case _addressLoopbackIPv4:

View file

@ -215,6 +215,12 @@ abstract class InternetAddress {
*/
external static InternetAddress _cloneWithNewHost(
InternetAddress address, String host);
/// Attempts to parse [address] as a numeric address.
///
/// Returns `null` if [address] is not a numeric IPv4 (dotted-decimal
/// notation) or IPv6 (hexadecimal representation) address.
external static InternetAddress tryParse(String address);
}
/**

View file

@ -425,6 +425,11 @@ class InternetAddress {
InternetAddress address, String host) {
throw UnsupportedError("InternetAddress._cloneWithNewHost");
}
@patch
static InternetAddress? tryParse(String address) {
throw UnsupportedError("InternetAddress.tryParse");
}
}
@patch

View file

@ -425,6 +425,11 @@ class InternetAddress {
InternetAddress address, String host) {
throw new UnsupportedError("InternetAddress._cloneWithNewHost");
}
@patch
static InternetAddress? tryParse(String address) {
throw UnsupportedError("InternetAddress.tryParse");
}
}
@patch

View file

@ -7,7 +7,7 @@
/// patches of that library. We plan to change this when we have a shared front
/// end and simply use parts.
import "dart:_internal" show VMLibraryHooks, patch;
import "dart:_internal" show VMLibraryHooks, patch, checkNotNullable;
import "dart:async"
show

View file

@ -89,6 +89,11 @@ class InternetAddress {
InternetAddress address, String host) {
return (address as _InternetAddress)._cloneWithNewHost(host);
}
@patch
static InternetAddress? tryParse(String address) {
return _InternetAddress.tryParse(address);
}
}
@patch
@ -255,6 +260,16 @@ class _InternetAddress implements InternetAddress {
}
}
static _InternetAddress? tryParse(String address) {
checkNotNullable(address, "address");
var addressBytes = _parse(address);
if (addressBytes == null) return null;
var type = addressBytes.length == _IPv4AddrLength
? InternetAddressType.IPv4
: InternetAddressType.IPv6;
return _InternetAddress(type, address, null, addressBytes);
}
factory _InternetAddress.fixed(int id) {
switch (id) {
case _addressLoopbackIPv4:

View file

@ -213,6 +213,12 @@ abstract class InternetAddress {
*/
external static InternetAddress _cloneWithNewHost(
InternetAddress address, String host);
/// Attempts to parse [address] as a numeric address.
///
/// Returns `null` If [address] is not a numeric IPv4 (dotted-decimal
/// notation) or IPv6 (hexadecimal representation) address.
external static InternetAddress? tryParse(String address);
}
/**

View file

@ -74,6 +74,56 @@ void testConstructor() {
Expect.throwsArgumentError(() => new InternetAddress("::FFFF::1"));
}
void testTryParse() {
var loopback4 = InternetAddress.tryParse("127.0.0.1")!;
Expect.equals(InternetAddressType.IPv4, loopback4.type);
Expect.equals("127.0.0.1", loopback4.host);
Expect.equals("127.0.0.1", loopback4.address);
Expect.isFalse(loopback4.isMulticast);
var loopback6 = InternetAddress.tryParse("::1")!;
Expect.equals(InternetAddressType.IPv6, loopback6.type);
Expect.equals("::1", loopback6.host);
Expect.equals("::1", loopback6.address);
Expect.isFalse(loopback6.isMulticast);
var ip4 = InternetAddress.tryParse("10.20.30.40")!;
Expect.equals(InternetAddressType.IPv4, ip4.type);
Expect.equals("10.20.30.40", ip4.host);
Expect.equals("10.20.30.40", ip4.address);
Expect.isFalse(ip4.isMulticast);
var ip6 = InternetAddress.tryParse("10:20::30:40")!;
Expect.equals(InternetAddressType.IPv6, ip6.type);
Expect.equals("10:20::30:40", ip6.host);
Expect.equals("10:20::30:40", ip6.address);
Expect.isFalse(ip6.isMulticast);
var multicast4 = InternetAddress.tryParse("224.1.2.3")!;
Expect.equals(InternetAddressType.IPv4, multicast4.type);
Expect.isTrue(multicast4.isMulticast);
var multicast6 = InternetAddress.tryParse("FF00::1:2:3")!;
Expect.equals(InternetAddressType.IPv6, multicast6.type);
Expect.isTrue(multicast6.isMulticast);
var lowercase = InternetAddress.tryParse("ff00::1:2:3")!;
Expect.equals(InternetAddressType.IPv6, lowercase.type);
Expect.equals("ff00::1:2:3", lowercase.host);
Expect.equals("ff00::1:2:3", lowercase.address);
Expect.isNull(InternetAddress.tryParse("1.2.3"));
Expect.isNull(InternetAddress.tryParse("1.2.3.4.5"));
Expect.isNull(InternetAddress.tryParse("192.168.256.0"));
Expect.isNull(InternetAddress.tryParse("192.168.999.0"));
Expect.isNull(InternetAddress.tryParse("1.-2.3.4"));
Expect.isNull(InternetAddress.tryParse("01.02.03.04"));
Expect.isNull(InternetAddress.tryParse(""));
Expect.isNull(InternetAddress.tryParse("FFFG::0"));
Expect.isNull(InternetAddress.tryParse("FFF@::0"));
Expect.isNull(InternetAddress.tryParse("::FFFF::1"));
}
void testEquality() {
Expect.equals(
new InternetAddress("127.0.0.1"), new InternetAddress("127.0.0.1"));
@ -163,6 +213,7 @@ void testRawPath() {
void main() {
testDefaultAddresses();
testConstructor();
testTryParse();
testEquality();
testLookup();
testReverseLookup();

View file

@ -74,6 +74,56 @@ void testConstructor() {
Expect.throwsArgumentError(() => new InternetAddress("::FFFF::1"));
}
void testTryParse() {
var loopback4 = InternetAddress.tryParse("127.0.0.1");
Expect.equals(InternetAddressType.IPv4, loopback4.type);
Expect.equals("127.0.0.1", loopback4.host);
Expect.equals("127.0.0.1", loopback4.address);
Expect.isFalse(loopback4.isMulticast);
var loopback6 = InternetAddress.tryParse("::1");
Expect.equals(InternetAddressType.IPv6, loopback6.type);
Expect.equals("::1", loopback6.host);
Expect.equals("::1", loopback6.address);
Expect.isFalse(loopback6.isMulticast);
var ip4 = InternetAddress.tryParse("10.20.30.40");
Expect.equals(InternetAddressType.IPv4, ip4.type);
Expect.equals("10.20.30.40", ip4.host);
Expect.equals("10.20.30.40", ip4.address);
Expect.isFalse(ip4.isMulticast);
var ip6 = InternetAddress.tryParse("10:20::30:40");
Expect.equals(InternetAddressType.IPv6, ip6.type);
Expect.equals("10:20::30:40", ip6.host);
Expect.equals("10:20::30:40", ip6.address);
Expect.isFalse(ip6.isMulticast);
var multicast4 = InternetAddress.tryParse("224.1.2.3");
Expect.equals(InternetAddressType.IPv4, multicast4.type);
Expect.isTrue(multicast4.isMulticast);
var multicast6 = InternetAddress.tryParse("FF00::1:2:3");
Expect.equals(InternetAddressType.IPv6, multicast6.type);
Expect.isTrue(multicast6.isMulticast);
var lowercase = InternetAddress.tryParse("ff00::1:2:3");
Expect.equals(InternetAddressType.IPv6, lowercase.type);
Expect.equals("ff00::1:2:3", lowercase.host);
Expect.equals("ff00::1:2:3", lowercase.address);
Expect.isNull(InternetAddress.tryParse("1.2.3"));
Expect.isNull(InternetAddress.tryParse("1.2.3.4.5"));
Expect.isNull(InternetAddress.tryParse("192.168.256.0"));
Expect.isNull(InternetAddress.tryParse("192.168.999.0"));
Expect.isNull(InternetAddress.tryParse("1.-2.3.4"));
Expect.isNull(InternetAddress.tryParse("01.02.03.04"));
Expect.isNull(InternetAddress.tryParse(""));
Expect.isNull(InternetAddress.tryParse("FFFG::0"));
Expect.isNull(InternetAddress.tryParse("FFF@::0"));
Expect.isNull(InternetAddress.tryParse("::FFFF::1"));
}
void testEquality() {
Expect.equals(
new InternetAddress("127.0.0.1"), new InternetAddress("127.0.0.1"));
@ -162,6 +212,7 @@ void testRawPath() {
void main() {
testDefaultAddresses();
testConstructor();
testTryParse();
testEquality();
testLookup();
testReverseLookup();