13e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath/* 23e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * Copyright (C) 2006 The Android Open Source Project 33e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * 43e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * Licensed under the Apache License, Version 2.0 (the "License"); 53e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * you may not use this file except in compliance with the License. 63e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * You may obtain a copy of the License at 73e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * 83e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * http://www.apache.org/licenses/LICENSE-2.0 93e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * 103e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * Unless required by applicable law or agreed to in writing, software 113e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * distributed under the License is distributed on an "AS IS" BASIS, 123e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * See the License for the specific language governing permissions and 143e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * limitations under the License. 153e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath */ 163e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 173e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamathpackage android.net.compatibility; 183e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 193e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamathimport static android.util.Patterns.GOOD_IRI_CHAR; 203e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 213e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamathimport java.util.Locale; 223e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamathimport java.util.regex.Matcher; 233e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamathimport java.util.regex.Pattern; 243e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 253e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath/** 263e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * Web Address Parser 273e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * 283e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * This is called WebAddress, rather than URL or URI, because it 293e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * attempts to parse the stuff that a user will actually type into a 303e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * browser address widget. 313e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * 323e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * Unlike java.net.uri, this parser will not choke on URIs missing 333e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * schemes. It will only throw a IllegalArgumentException if the input is 343e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * really hosed. 353e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * 363e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * If given an https scheme but no port, fills in port 373e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath * 383e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath */ 393e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamathpublic class WebAddress { 403e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 413e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath private String mScheme; 423e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath private String mHost; 433e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath private int mPort; 443e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath private String mPath; 453e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath private String mAuthInfo; 463e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 473e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath static final int MATCH_GROUP_SCHEME = 1; 483e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath static final int MATCH_GROUP_AUTHORITY = 2; 493e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath static final int MATCH_GROUP_HOST = 3; 503e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath static final int MATCH_GROUP_PORT = 4; 513e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath static final int MATCH_GROUP_PATH = 5; 523e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 533e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath static Pattern sAddressPattern = Pattern.compile( 543e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath /* scheme */ "(?:(http|https|file)\\:\\/\\/)?" + 553e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath /* authority */ "(?:([-A-Za-z0-9$_.+!*'(),;?&=]+(?:\\:[-A-Za-z0-9$_.+!*'(),;?&=]+)?)@)?" + 563e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath /* host */ "([" + GOOD_IRI_CHAR + "%_-][" + GOOD_IRI_CHAR + "%_\\.-]*|\\[[0-9a-fA-F:\\.]+\\])?" + 573e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath /* port */ "(?:\\:([0-9]*))?" + 583e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath /* path */ "(\\/?[^#]*)?" + 593e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath /* anchor */ ".*", Pattern.CASE_INSENSITIVE); 603e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 613e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath /** parses given uriString. */ 623e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath public WebAddress(String address) throws IllegalArgumentException { 633e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath if (address == null) { 643e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath throw new NullPointerException(); 653e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 663e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 673e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath // android.util.Log.d(LOGTAG, "WebAddress: " + address); 683e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 693e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath mScheme = ""; 703e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath mHost = ""; 713e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath mPort = -1; 723e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath mPath = "/"; 733e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath mAuthInfo = ""; 743e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 753e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath Matcher m = sAddressPattern.matcher(address); 763e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath String t; 773e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath if (m.matches()) { 783e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath t = m.group(MATCH_GROUP_SCHEME); 793e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath if (t != null) mScheme = t.toLowerCase(Locale.ROOT); 803e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath t = m.group(MATCH_GROUP_AUTHORITY); 813e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath if (t != null) mAuthInfo = t; 823e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath t = m.group(MATCH_GROUP_HOST); 833e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath if (t != null) mHost = t; 843e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath t = m.group(MATCH_GROUP_PORT); 853e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath if (t != null && t.length() > 0) { 863e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath // The ':' character is not returned by the regex. 873e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath try { 883e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath mPort = Integer.parseInt(t); 893e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } catch (NumberFormatException ex) { 903e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath throw new IllegalArgumentException("Bad port"); 913e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 923e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 933e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath t = m.group(MATCH_GROUP_PATH); 943e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath if (t != null && t.length() > 0) { 953e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath /* handle busted myspace frontpage redirect with 963e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath missing initial "/" */ 973e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath if (t.charAt(0) == '/') { 983e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath mPath = t; 993e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } else { 1003e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath mPath = "/" + t; 1013e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1023e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1033e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 1043e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } else { 1053e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath // nothing found... outa here 1063e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath throw new IllegalArgumentException("Bad address"); 1073e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1083e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 1093e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath /* Get port from scheme or scheme from port, if necessary and 1103e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath possible */ 1113e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath if (mPort == 443 && mScheme.equals("")) { 1123e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath mScheme = "https"; 1133e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } else if (mPort == -1) { 1143e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath if (mScheme.equals("https")) 1153e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath mPort = 443; 1163e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath else 1173e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath mPort = 80; // default 1183e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1193e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath if (mScheme.equals("")) mScheme = "http"; 1203e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1213e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 1223e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath @Override 1233e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath public String toString() { 1243e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath String port = ""; 1253e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath if ((mPort != 443 && mScheme.equals("https")) || 1263e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath (mPort != 80 && mScheme.equals("http"))) { 1273e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath port = ":" + Integer.toString(mPort); 1283e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1293e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath String authInfo = ""; 1303e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath if (mAuthInfo.length() > 0) { 1313e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath authInfo = mAuthInfo + "@"; 1323e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1333e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 1343e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath return mScheme + "://" + authInfo + mHost + port + mPath; 1353e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1363e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 1373e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath public void setScheme(String scheme) { 1383e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath mScheme = scheme; 1393e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1403e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 1413e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath public String getScheme() { 1423e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath return mScheme; 1433e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1443e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 1453e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath public void setHost(String host) { 1463e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath mHost = host; 1473e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1483e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 1493e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath public String getHost() { 1503e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath return mHost; 1513e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1523e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 1533e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath public void setPort(int port) { 1543e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath mPort = port; 1553e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1563e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 1573e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath public int getPort() { 1583e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath return mPort; 1593e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1603e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 1613e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath public void setPath(String path) { 1623e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath mPath = path; 1633e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1643e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 1653e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath public String getPath() { 1663e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath return mPath; 1673e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1683e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 1693e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath public void setAuthInfo(String authInfo) { 1703e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath mAuthInfo = authInfo; 1713e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1723e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath 1733e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath public String getAuthInfo() { 1743e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath return mAuthInfo; 1753e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath } 1763e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamath} 177