1 /* 2 * Copyright 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.core.net; 18 19 import android.net.Uri; 20 21 import org.jspecify.annotations.NonNull; 22 23 /** 24 * Helper for accessing function in {@link Uri} in a backwards compatible fashion. 25 */ 26 public final class UriCompat { 27 UriCompat()28 private UriCompat() {} 29 30 /** 31 * Return a string representation of this URI that has common forms of PII redacted, 32 * making it safer to use for logging purposes. For example, {@code tel:800-466-4411} is 33 * returned as {@code tel:xxx-xxx-xxxx} and {@code http://example.com/path/to/item/} is 34 * returned as {@code http://example.com/...}. 35 * 36 * @param uri The uri for converted to string. 37 * @return Return a string representation of this URI that has common forms of PII redacted. 38 */ toSafeString(@onNull Uri uri)39 public static @NonNull String toSafeString(@NonNull Uri uri) { 40 String scheme = uri.getScheme(); 41 String ssp = uri.getSchemeSpecificPart(); 42 if (scheme != null) { 43 if (scheme.equalsIgnoreCase("tel") || scheme.equalsIgnoreCase("sip") 44 || scheme.equalsIgnoreCase("sms") || scheme.equalsIgnoreCase("smsto") 45 || scheme.equalsIgnoreCase("mailto") || scheme.equalsIgnoreCase("nfc")) { 46 StringBuilder builder = new StringBuilder(64); 47 builder.append(scheme); 48 builder.append(':'); 49 if (ssp != null) { 50 for (int i = 0; i < ssp.length(); i++) { 51 char c = ssp.charAt(i); 52 if (c == '-' || c == '@' || c == '.') { 53 builder.append(c); 54 } else { 55 builder.append('x'); 56 } 57 } 58 } 59 return builder.toString(); 60 } else if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https") 61 || scheme.equalsIgnoreCase("ftp") || scheme.equalsIgnoreCase("rtsp")) { 62 ssp = "//" + ((uri.getHost() != null) ? uri.getHost() : "") 63 + ((uri.getPort() != -1) ? (":" + uri.getPort()) : "") 64 + "/..."; 65 } 66 } 67 // Not a sensitive scheme, but let's still be conservative about 68 // the data we include -- only the ssp, not the query params or 69 // fragment, because those can often have sensitive info. 70 StringBuilder builder = new StringBuilder(64); 71 if (scheme != null) { 72 builder.append(scheme); 73 builder.append(':'); 74 } 75 if (ssp != null) { 76 builder.append(ssp); 77 } 78 return builder.toString(); 79 } 80 } 81