1 /* 2 * Copyright (C) 2006 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 android.net; 18 19 import static android.util.Patterns.GOOD_IRI_CHAR; 20 21 import android.annotation.NonNull; 22 import android.annotation.SystemApi; 23 import android.compat.annotation.UnsupportedAppUsage; 24 import android.os.Build; 25 26 import java.util.Locale; 27 import java.util.regex.Matcher; 28 import java.util.regex.Pattern; 29 30 /** 31 * {@hide} 32 * 33 * Web Address Parser 34 * 35 * This is called WebAddress, rather than URL or URI, because it 36 * attempts to parse the stuff that a user will actually type into a 37 * browser address widget. 38 * 39 * Unlike java.net.uri, this parser will not choke on URIs missing 40 * schemes. It will only throw a ParseException if the input is 41 * really hosed. 42 * 43 * If given an https scheme but no port, fills in port 44 * 45 */ 46 // TODO(igsolla): remove WebAddress from the system SDK once the WebView apk does not 47 // longer need to be binary compatible with the API 21 version of the framework. 48 @SystemApi 49 public class WebAddress { 50 51 @UnsupportedAppUsage 52 private String mScheme; 53 @UnsupportedAppUsage 54 private String mHost; 55 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 56 private int mPort; 57 @UnsupportedAppUsage 58 private String mPath; 59 private String mAuthInfo; 60 61 static final int MATCH_GROUP_SCHEME = 1; 62 static final int MATCH_GROUP_AUTHORITY = 2; 63 static final int MATCH_GROUP_HOST = 3; 64 static final int MATCH_GROUP_PORT = 4; 65 static final int MATCH_GROUP_PATH = 5; 66 67 static Pattern sAddressPattern = Pattern.compile( 68 /* scheme */ "(?:(http|https|file)\\:\\/\\/)?" + 69 /* authority */ "(?:([-A-Za-z0-9$_.+!*'(),;?&=]+(?:\\:[-A-Za-z0-9$_.+!*'(),;?&=]+)?)@)?" + 70 /* host */ "([" + GOOD_IRI_CHAR + "%_-][" + GOOD_IRI_CHAR + "%_\\.-]*|\\[[0-9a-fA-F:\\.]+\\])?" + 71 /* port */ "(?:\\:([0-9]*))?" + 72 /* path */ "(\\/?[^#]*)?" + 73 /* anchor */ ".*", Pattern.CASE_INSENSITIVE); 74 75 /** parses given uriString. */ WebAddress(String address)76 public WebAddress(String address) throws ParseException { 77 if (address == null) { 78 throw new NullPointerException(); 79 } 80 81 // android.util.Log.d(LOGTAG, "WebAddress: " + address); 82 83 mScheme = ""; 84 mHost = ""; 85 mPort = -1; 86 mPath = "/"; 87 mAuthInfo = ""; 88 89 Matcher m = sAddressPattern.matcher(address); 90 String t; 91 if (m.matches()) { 92 t = m.group(MATCH_GROUP_SCHEME); 93 if (t != null) mScheme = t.toLowerCase(Locale.ROOT); 94 t = m.group(MATCH_GROUP_AUTHORITY); 95 if (t != null) mAuthInfo = t; 96 t = m.group(MATCH_GROUP_HOST); 97 if (t != null) mHost = t; 98 t = m.group(MATCH_GROUP_PORT); 99 if (t != null && t.length() > 0) { 100 // The ':' character is not returned by the regex. 101 try { 102 mPort = Integer.parseInt(t); 103 } catch (NumberFormatException ex) { 104 throw new ParseException("Bad port"); 105 } 106 } 107 t = m.group(MATCH_GROUP_PATH); 108 if (t != null && t.length() > 0) { 109 /* handle busted myspace frontpage redirect with 110 missing initial "/" */ 111 if (t.charAt(0) == '/') { 112 mPath = t; 113 } else { 114 mPath = "/" + t; 115 } 116 } 117 118 } else { 119 // nothing found... outa here 120 throw new ParseException("Bad address"); 121 } 122 123 /* Get port from scheme or scheme from port, if necessary and 124 possible */ 125 if (mPort == 443 && mScheme.equals("")) { 126 mScheme = "https"; 127 } else if (mPort == -1) { 128 if (mScheme.equals("https")) 129 mPort = 443; 130 else 131 mPort = 80; // default 132 } 133 if (mScheme.equals("")) mScheme = "http"; 134 } 135 136 @NonNull 137 @Override toString()138 public String toString() { 139 String port = ""; 140 if ((mPort != 443 && mScheme.equals("https")) || 141 (mPort != 80 && mScheme.equals("http"))) { 142 port = ":" + Integer.toString(mPort); 143 } 144 String authInfo = ""; 145 if (mAuthInfo.length() > 0) { 146 authInfo = mAuthInfo + "@"; 147 } 148 149 return mScheme + "://" + authInfo + mHost + port + mPath; 150 } 151 152 /** {@hide} */ setScheme(String scheme)153 public void setScheme(String scheme) { 154 mScheme = scheme; 155 } 156 157 /** {@hide} */ 158 @UnsupportedAppUsage getScheme()159 public String getScheme() { 160 return mScheme; 161 } 162 163 /** {@hide} */ 164 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setHost(String host)165 public void setHost(String host) { 166 mHost = host; 167 } 168 169 /** {@hide} */ 170 @UnsupportedAppUsage getHost()171 public String getHost() { 172 return mHost; 173 } 174 175 /** {@hide} */ setPort(int port)176 public void setPort(int port) { 177 mPort = port; 178 } 179 180 /** {@hide} */ 181 @UnsupportedAppUsage getPort()182 public int getPort() { 183 return mPort; 184 } 185 186 /** {@hide} */ 187 @UnsupportedAppUsage setPath(String path)188 public void setPath(String path) { 189 mPath = path; 190 } 191 192 /** {@hide} */ 193 @UnsupportedAppUsage getPath()194 public String getPath() { 195 return mPath; 196 } 197 198 /** {@hide} */ setAuthInfo(String authInfo)199 public void setAuthInfo(String authInfo) { 200 mAuthInfo = authInfo; 201 } 202 203 /** {@hide} */ 204 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getAuthInfo()205 public String getAuthInfo() { 206 return mAuthInfo; 207 } 208 } 209