1 /* 2 * Copyright (C) 2014 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 com.android.contacts.quickcontact; 18 19 import java.util.Locale; 20 import java.util.regex.Matcher; 21 import java.util.regex.Pattern; 22 23 import static android.util.Patterns.GOOD_IRI_CHAR; 24 25 /** 26 * Below is a partial copy of {@link android.net.WebAddress}. The original author doesn't 27 * believe this API is suitable for making public. He recommends we copy it. 28 * 29 * Web Address Parser 30 * 31 * This is called WebAddress, rather than URL or URI, because it 32 * attempts to parse the stuff that a user will actually type into a 33 * browser address widget. 34 * 35 * Unlike java.net.uri, this parser will not choke on URIs missing 36 * schemes. It will only throw a ParseException if the input is 37 * really hosed. 38 * 39 * If given an https scheme but no port, fills in port 40 * 41 */ 42 public class WebAddress { 43 44 private String mScheme; 45 private String mHost; 46 private int mPort; 47 private String mPath; 48 private String mAuthInfo; 49 50 static final int MATCH_GROUP_SCHEME = 1; 51 static final int MATCH_GROUP_AUTHORITY = 2; 52 static final int MATCH_GROUP_HOST = 3; 53 static final int MATCH_GROUP_PORT = 4; 54 static final int MATCH_GROUP_PATH = 5; 55 56 static Pattern sAddressPattern = Pattern.compile( 57 /* scheme */ "(?:(http|https|file)\\:\\/\\/)?" + 58 /* authority */ "(?:([-A-Za-z0-9$_.+!*'(),;?&=]+(?:\\:[-A-Za-z0-9$_.+!*'(),;?&=]+)?)@)?" + 59 /* host */ "([" + GOOD_IRI_CHAR + "%_-][" + GOOD_IRI_CHAR + "%_\\.-]*|\\[[0-9a-fA-F:\\.]+\\])?" + 60 /* port */ "(?:\\:([0-9]*))?" + 61 /* path */ "(\\/?[^#]*)?" + 62 /* anchor */ ".*", Pattern.CASE_INSENSITIVE); 63 64 /** parses given uriString. */ 65 public WebAddress(String address) throws ParseException { 66 if (address == null) { 67 throw new NullPointerException(); 68 } 69 70 // android.util.Log.d(LOGTAG, "WebAddress: " + address); 71 72 mScheme = ""; 73 mHost = ""; 74 mPort = -1; 75 mPath = "/"; 76 mAuthInfo = ""; 77 78 Matcher m = sAddressPattern.matcher(address); 79 String t; 80 if (m.matches()) { 81 t = m.group(MATCH_GROUP_SCHEME); 82 if (t != null) mScheme = t.toLowerCase(Locale.ROOT); 83 t = m.group(MATCH_GROUP_AUTHORITY); 84 if (t != null) mAuthInfo = t; 85 t = m.group(MATCH_GROUP_HOST); 86 if (t != null) mHost = t; 87 t = m.group(MATCH_GROUP_PORT); 88 if (t != null && t.length() > 0) { 89 // The ':' character is not returned by the regex. 90 try { 91 mPort = Integer.parseInt(t); 92 } catch (NumberFormatException ex) { 93 throw new ParseException("Bad port"); 94 } 95 } 96 t = m.group(MATCH_GROUP_PATH); 97 if (t != null && t.length() > 0) { 98 /* handle busted myspace frontpage redirect with 99 missing initial "/" */ 100 if (t.charAt(0) == '/') { 101 mPath = t; 102 } else { 103 mPath = "/" + t; 104 } 105 } 106 107 } else { 108 // nothing found... outa here 109 throw new ParseException("Bad address"); 110 } 111 112 /* Get port from scheme or scheme from port, if necessary and 113 possible */ 114 if (mPort == 443 && mScheme.equals("")) { 115 mScheme = "https"; 116 } else if (mPort == -1) { 117 if (mScheme.equals("https")) 118 mPort = 443; 119 else 120 mPort = 80; // default 121 } 122 if (mScheme.equals("")) mScheme = "http"; 123 } 124 125 @Override 126 public String toString() { 127 String port = ""; 128 if ((mPort != 443 && mScheme.equals("https")) || 129 (mPort != 80 && mScheme.equals("http"))) { 130 port = ":" + Integer.toString(mPort); 131 } 132 String authInfo = ""; 133 if (mAuthInfo.length() > 0) { 134 authInfo = mAuthInfo + "@"; 135 } 136 137 return mScheme + "://" + authInfo + mHost + port + mPath; 138 } 139 140 public class ParseException extends Exception { 141 public String response; 142 143 ParseException(String response) { 144 this.response = response; 145 } 146 } 147 } 148