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