@@ -1507,7 +1507,10 @@ abstract interface class Uri {
1507
1507
}
1508
1508
}
1509
1509
1510
- class _Uri implements Uri {
1510
+ // Superclass of the two implementation types.
1511
+ sealed class _PlatformUri implements Uri {}
1512
+
1513
+ final class _Uri implements _PlatformUri {
1511
1514
// We represent the missing scheme as an empty string.
1512
1515
// A valid scheme cannot be empty.
1513
1516
final String scheme;
@@ -2705,12 +2708,12 @@ class _Uri implements Uri {
2705
2708
return resolveUri (Uri .parse (reference));
2706
2709
}
2707
2710
2708
- // Returns the index of the `/` after the package name of a package URI.
2711
+ // The index of the `/` after the package name of a package URI.
2709
2712
//
2710
- // Returns negative if the URI is not a valid package URI:
2713
+ // Value is negative if the URI is not a valid package URI:
2711
2714
// * Scheme must be "package".
2712
2715
// * No authority.
2713
- // * Path starts with "something"/
2716
+ // * Path starts with "something/".
2714
2717
// * where "something" is not all "." characters,
2715
2718
// * and contains no escapes or colons.
2716
2719
//
@@ -2730,7 +2733,21 @@ class _Uri implements Uri {
2730
2733
int ? targetPort;
2731
2734
String targetPath;
2732
2735
String ? targetQuery;
2736
+ // Position up to which values are known to already be normalized,
2737
+ // because the value is taken from this `_Uri`
2738
+ // If any part of the path is taken from a `reference` which is not
2739
+ // a platform URI, and therefore not known to be canonicalized to the
2740
+ // standard of platform URIs, the combined path counts as potentially
2741
+ // non-normalized.
2742
+ const int atStart = 0 , // Nothing taken from this URI.
2743
+ afterScheme = 1 , // Scheme comes from this URI.
2744
+ afterAuthority = 2 , // Scheme and authority comes from this URI.
2745
+ afterPath = 3 , // The path, and everything before, is from this URI.
2746
+ afterQuery = 4 ; // Everything except fragment is from this URI.
2747
+ int split = atStart;
2748
+
2733
2749
if (reference.scheme.isNotEmpty) {
2750
+ if (reference is _PlatformUri ) return reference;
2734
2751
targetScheme = reference.scheme;
2735
2752
if (reference.hasAuthority) {
2736
2753
targetUserInfo = reference.userInfo;
@@ -2744,26 +2761,33 @@ class _Uri implements Uri {
2744
2761
} else {
2745
2762
targetScheme = this .scheme;
2746
2763
if (reference.hasAuthority) {
2764
+ if (reference is _PlatformUri ) {
2765
+ return reference.replace (scheme: targetScheme);
2766
+ }
2747
2767
targetUserInfo = reference.userInfo;
2748
2768
targetHost = reference.host;
2749
2769
targetPort =
2750
2770
_makePort (reference.hasPort ? reference.port : null , targetScheme);
2751
2771
targetPath = _removeDotSegments (reference.path);
2752
2772
if (reference.hasQuery) targetQuery = reference.query;
2773
+ split = afterScheme;
2753
2774
} else {
2754
2775
targetUserInfo = this ._userInfo;
2755
2776
targetHost = this ._host;
2756
2777
targetPort = this ._port;
2757
- if (reference.path == "" ) {
2778
+ if (reference.hasEmptyPath ) {
2758
2779
targetPath = this .path;
2759
2780
if (reference.hasQuery) {
2781
+ split = afterPath;
2760
2782
targetQuery = reference.query;
2761
2783
} else {
2762
2784
targetQuery = this ._query;
2785
+ split = afterQuery;
2763
2786
}
2764
2787
} else {
2765
2788
String basePath = this .path;
2766
2789
int packageNameEnd = _packageNameEnd (this , basePath);
2790
+ split = afterAuthority;
2767
2791
if (packageNameEnd > 0 ) {
2768
2792
assert (targetScheme == "package" );
2769
2793
assert (! this .hasAuthority);
@@ -2809,11 +2833,41 @@ class _Uri implements Uri {
2809
2833
}
2810
2834
}
2811
2835
}
2812
- if (reference.hasQuery) targetQuery = reference.query;
2836
+ if (reference.hasQuery) {
2837
+ targetQuery = reference.query;
2838
+ }
2813
2839
}
2814
2840
}
2815
2841
}
2816
2842
String ? fragment = reference.hasFragment ? reference.fragment : null ;
2843
+ if (reference is ! _PlatformUri ) {
2844
+ // Don't trust values coming from `reference` to be normalized.
2845
+ if (split == atStart) {
2846
+ targetScheme = _makeScheme (targetScheme, 0 , targetScheme.length);
2847
+ }
2848
+ if (split <= afterScheme) {
2849
+ if (targetUserInfo != null ) {
2850
+ targetUserInfo =
2851
+ _makeUserInfo (targetUserInfo, 0 , targetUserInfo.length);
2852
+ }
2853
+ if (targetPort != null ) {
2854
+ targetPort = _makePort (targetPort, targetScheme);
2855
+ }
2856
+ if (targetHost != null && targetHost.isNotEmpty) {
2857
+ targetHost = _makeHost (targetHost, 0 , targetHost.length, false );
2858
+ }
2859
+ }
2860
+ if (split <= afterPath) {
2861
+ targetPath = _makePath (targetPath, 0 , targetPath.length, null ,
2862
+ targetScheme, targetHost != null );
2863
+ }
2864
+ if (split <= afterPath && targetQuery != null ) {
2865
+ targetQuery = _makeQuery (targetQuery, 0 , targetQuery.length, null );
2866
+ }
2867
+ if (fragment != null ) {
2868
+ fragment = _makeFragment (fragment, 0 , fragment.length);
2869
+ }
2870
+ }
2817
2871
return _Uri ._internal (targetScheme, targetUserInfo, targetHost, targetPort,
2818
2872
targetPath, targetQuery, fragment);
2819
2873
}
@@ -4406,7 +4460,7 @@ int _scan(String uri, int start, int end, int state, List<int> indices) {
4406
4460
return state;
4407
4461
}
4408
4462
4409
- class _SimpleUri implements Uri {
4463
+ final class _SimpleUri implements _PlatformUri {
4410
4464
final String _uri;
4411
4465
final int _schemeEnd;
4412
4466
final int _hostStart;
0 commit comments