Uri: check authority and scheme as part of determining URI path

The interpretation of the path depends on whether the scheme or
authority are specified and should be observed when unparcelling
URIs.

Bug: 171966843
Test: atest FrameworksCoreTests:android.net.UriTest
Test: atest com.android.devicehealthchecks.SystemAppCheck
Change-Id: I06981d1c6e387b16df792494523994518848db37
(cherry picked from commit f37a94ae92)
This commit is contained in:
Orion Hodson
2022-04-07 21:42:04 +01:00
committed by Varun Shah
parent 9f101a5077
commit d83281c730
2 changed files with 69 additions and 7 deletions

View File

@@ -1205,13 +1205,16 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
}
static Uri readFrom(Parcel parcel) {
return new HierarchicalUri(
parcel.readString8(),
Part.readFrom(parcel),
PathPart.readFrom(parcel),
Part.readFrom(parcel),
Part.readFrom(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 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() {
@@ -2270,6 +2273,11 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
}
}
static PathPart readFrom(boolean hasSchemeOrAuthority, Parcel parcel) {
final PathPart path = readFrom(parcel);
return hasSchemeOrAuthority ? makeAbsolute(path) : path;
}
/**
* Creates a path from the encoded string.
*

View File

@@ -48,6 +48,7 @@ public class UriTest extends TestCase {
public void testParcelling() {
parcelAndUnparcel(Uri.parse("foo:bob%20lee"));
parcelAndUnparcel(Uri.fromParts("foo", "bob lee", "fragment"));
parcelAndUnparcel(Uri.fromParts("https", "www.google.com", null));
parcelAndUnparcel(new Uri.Builder()
.scheme("http")
.authority("crazybob.org")
@@ -890,9 +891,62 @@ public class UriTest extends TestCase {
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) {
// 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();
}
}
public void testUnparcelMalformedPath() {
// Regression tests for b/171966843.
// Test cases with arguments encoded (covering testing `scheme` * `authority` options).
Uri uri0 = buildUriFromRawParcel(true, "https", "google.com", "@evil.com", null, null);
assertEquals("https://google.com/@evil.com", uri0.toString());
Uri uri1 = buildUriFromRawParcel(true, null, "google.com", "@evil.com", "name=spark", "x");
assertEquals("//google.com/@evil.com?name=spark#x", uri1.toString());
Uri uri2 = buildUriFromRawParcel(true, "http:", null, "@evil.com", null, null);
assertEquals("http::/@evil.com", uri2.toString());
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 = buildUriFromRawParcel(false, "https", "google.com", "@evil.com", null, null);
assertEquals("https://google.com/%40evil.com", uriA.toString());
Uri uriB = buildUriFromRawParcel(false, null, "google.com", "@evil.com", null, null);
assertEquals("//google.com/%40evil.com", uriB.toString());
Uri uriC = buildUriFromRawParcel(false, "http:", null, "@evil.com", null, null);
assertEquals("http::/%40evil.com", uriC.toString());
Uri uriD = buildUriFromRawParcel(false, null, null, "@evil.com", "name=spark", "y");
assertEquals("%40evil.com?name%3Dspark#y", uriD.toString());
}
public void testToSafeString() {
checkToSafeString("tel:xxxxxx", "tel:Google");
checkToSafeString("tel:xxxxxxxxxx", "tel:1234567890");