diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java index 7fbaf1027af60e4cda7cbbdc7fa83fc3fc680214..3da696ad0bc795bd33476676cb7fa83722e0a8c6 100644 --- a/core/java/android/net/Uri.java +++ b/core/java/android/net/Uri.java @@ -882,11 +882,10 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { } static Uri readFrom(Parcel parcel) { - final StringUri stringUri = new StringUri(parcel.readString8()); return new OpaqueUri( - stringUri.parseScheme(), - stringUri.getSsp(), - stringUri.getFragmentPart() + parcel.readString8(), + Part.readFrom(parcel), + Part.readFrom(parcel) ); } @@ -896,7 +895,9 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(TYPE_ID); - parcel.writeString8(toString()); + parcel.writeString8(scheme); + ssp.writeTo(parcel); + fragment.writeTo(parcel); } public boolean isHierarchical() { @@ -1195,25 +1196,22 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { Part query, Part fragment) { this.scheme = scheme; this.authority = Part.nonNull(authority); - this.path = generatePath(path); + this.path = path == null ? PathPart.NULL : path; this.query = Part.nonNull(query); this.fragment = Part.nonNull(fragment); } - private PathPart generatePath(PathPart originalPath) { + static Uri readFrom(Parcel parcel) { + final String scheme = parcel.readString8(); + final Part authority = Part.readFrom(parcel); // In RFC3986 the path should be determined based on whether there is a scheme or // authority present (https://www.rfc-editor.org/rfc/rfc3986.html#section-3.3). final boolean hasSchemeOrAuthority = (scheme != null && scheme.length() > 0) || !authority.isEmpty(); - final PathPart newPath = hasSchemeOrAuthority ? PathPart.makeAbsolute(originalPath) - : originalPath; - return newPath == null ? PathPart.NULL : newPath; - } - - static Uri readFrom(Parcel parcel) { - final StringUri stringUri = new StringUri(parcel.readString8()); - return new HierarchicalUri(stringUri.getScheme(), stringUri.getAuthorityPart(), - stringUri.getPathPart(), stringUri.getQueryPart(), stringUri.getFragmentPart()); + final PathPart path = PathPart.readFrom(hasSchemeOrAuthority, parcel); + final Part query = Part.readFrom(parcel); + final Part fragment = Part.readFrom(parcel); + return new HierarchicalUri(scheme, authority, path, query, fragment); } public int describeContents() { @@ -1222,7 +1220,11 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(TYPE_ID); - parcel.writeString8(toString()); + parcel.writeString8(scheme); + authority.writeTo(parcel); + path.writeTo(parcel); + query.writeTo(parcel); + fragment.writeTo(parcel); } public boolean isHierarchical() { diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java index 2a4ca79d997e835b2922e7f6c9551e42efdad9c9..89632a46267e6306f2e53dcce825e749242b0683 100644 --- a/core/tests/coretests/src/android/net/UriTest.java +++ b/core/tests/coretests/src/android/net/UriTest.java @@ -25,6 +25,8 @@ import junit.framework.TestCase; import java.io.File; import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Arrays; import java.util.Iterator; import java.util.List; @@ -867,90 +869,84 @@ public class UriTest extends TestCase { return (Uri) hierarchicalUriConstructor.newInstance("https", authority, path, null, null); } - private Uri buildUriFromParts(boolean argumentsEncoded, + /** Attempting to unparcel a legacy parcel format of Uri.{,Path}Part should fail. */ + public void testUnparcelLegacyPart_fails() throws Exception { + assertUnparcelLegacyPart_fails(Class.forName("android.net.Uri$Part")); + assertUnparcelLegacyPart_fails(Class.forName("android.net.Uri$PathPart")); + } + + private static void assertUnparcelLegacyPart_fails(Class partClass) throws Exception { + Parcel parcel = Parcel.obtain(); + parcel.writeInt(0 /* BOTH */); + parcel.writeString("encoded"); + parcel.writeString("decoded"); + parcel.setDataPosition(0); + + Method readFromMethod = partClass.getDeclaredMethod("readFrom", Parcel.class); + readFromMethod.setAccessible(true); + try { + readFromMethod.invoke(null, parcel); + fail(); + } catch (InvocationTargetException expected) { + Throwable targetException = expected.getTargetException(); + // Check that the exception was thrown for the correct reason. + assertEquals("Unknown representation: 0", targetException.getMessage()); + } finally { + parcel.recycle(); + } + } + + private Uri buildUriFromRawParcel(boolean argumentsEncoded, String scheme, String authority, String path, String query, String fragment) { - final Uri.Builder builder = new Uri.Builder(); - builder.scheme(scheme); - if (argumentsEncoded) { - builder.encodedAuthority(authority); - builder.encodedPath(path); - builder.encodedQuery(query); - builder.encodedFragment(fragment); - } else { - builder.authority(authority); - builder.path(path); - builder.query(query); - builder.fragment(fragment); + // Representation value (from AbstractPart.REPRESENTATION_{ENCODED,DECODED}). + final int representation = argumentsEncoded ? 1 : 2; + Parcel parcel = Parcel.obtain(); + try { + parcel.writeInt(3); // hierarchical + parcel.writeString8(scheme); + parcel.writeInt(representation); + parcel.writeString8(authority); + parcel.writeInt(representation); + parcel.writeString8(path); + parcel.writeInt(representation); + parcel.writeString8(query); + parcel.writeInt(representation); + parcel.writeString8(fragment); + parcel.setDataPosition(0); + return Uri.CREATOR.createFromParcel(parcel); + } finally { + parcel.recycle(); } - return builder.build(); } public void testUnparcelMalformedPath() { // Regression tests for b/171966843. // Test cases with arguments encoded (covering testing `scheme` * `authority` options). - Uri uri0 = buildUriFromParts(true, "https", "google.com", "@evil.com", null, null); + Uri uri0 = buildUriFromRawParcel(true, "https", "google.com", "@evil.com", null, null); assertEquals("https://google.com/@evil.com", uri0.toString()); - Uri uri1 = buildUriFromParts(true, null, "google.com", "@evil.com", "name=spark", "x"); + Uri uri1 = buildUriFromRawParcel(true, null, "google.com", "@evil.com", "name=spark", "x"); assertEquals("//google.com/@evil.com?name=spark#x", uri1.toString()); - Uri uri2 = buildUriFromParts(true, "http:", null, "@evil.com", null, null); + Uri uri2 = buildUriFromRawParcel(true, "http:", null, "@evil.com", null, null); assertEquals("http::/@evil.com", uri2.toString()); - Uri uri3 = buildUriFromParts(true, null, null, "@evil.com", null, null); + Uri uri3 = buildUriFromRawParcel(true, null, null, "@evil.com", null, null); assertEquals("@evil.com", uri3.toString()); // Test cases with arguments not encoded (covering testing `scheme` * `authority` options). - Uri uriA = buildUriFromParts(false, "https", "google.com", "@evil.com", null, null); + Uri uriA = buildUriFromRawParcel(false, "https", "google.com", "@evil.com", null, null); assertEquals("https://google.com/%40evil.com", uriA.toString()); - Uri uriB = buildUriFromParts(false, null, "google.com", "@evil.com", null, null); + Uri uriB = buildUriFromRawParcel(false, null, "google.com", "@evil.com", null, null); assertEquals("//google.com/%40evil.com", uriB.toString()); - Uri uriC = buildUriFromParts(false, "http:", null, "@evil.com", null, null); + Uri uriC = buildUriFromRawParcel(false, "http:", null, "@evil.com", null, null); assertEquals("http::/%40evil.com", uriC.toString()); - Uri uriD = buildUriFromParts(false, null, null, "@evil.com", "name=spark", "y"); + Uri uriD = buildUriFromRawParcel(false, null, null, "@evil.com", "name=spark", "y"); assertEquals("%40evil.com?name%3Dspark#y", uriD.toString()); } - public void testParsedUriFromStringEquality() { - Uri uri = buildUriFromParts( - true, "https", "google.com", "@evil.com", null, null); - assertEquals(uri, Uri.parse(uri.toString())); - Uri uri2 = buildUriFromParts( - true, "content://evil.authority?foo=", "safe.authority", "@evil.com", null, null); - assertEquals(uri2, Uri.parse(uri2.toString())); - Uri uri3 = buildUriFromParts( - false, "content://evil.authority?foo=", "safe.authority", "@evil.com", null, null); - assertEquals(uri3, Uri.parse(uri3.toString())); - } - - public void testParceledUrisAreEqual() { - Uri opaqueUri = Uri.fromParts("fake://uri#", "ssp", "fragment"); - Parcel parcel = Parcel.obtain(); - try { - opaqueUri.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - Uri postParcelUri = Uri.CREATOR.createFromParcel(parcel); - Uri parsedUri = Uri.parse(postParcelUri.toString()); - assertEquals(parsedUri.getScheme(), postParcelUri.getScheme()); - } finally { - parcel.recycle(); - } - - Uri hierarchicalUri = new Uri.Builder().scheme("fake://uri#").authority("auth").build(); - parcel = Parcel.obtain(); - try { - hierarchicalUri.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - Uri postParcelUri = Uri.CREATOR.createFromParcel(parcel); - Uri parsedUri = Uri.parse(postParcelUri.toString()); - assertEquals(parsedUri.getScheme(), postParcelUri.getScheme()); - } finally { - parcel.recycle(); - } - } - public void testToSafeString() { checkToSafeString("tel:xxxxxx", "tel:Google"); checkToSafeString("tel:xxxxxxxxxx", "tel:1234567890");