1 /* 2 * Copyright (C) 2010 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 android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.compat.annotation.UnsupportedAppUsage; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 import android.text.TextUtils; 25 26 import java.net.InetSocketAddress; 27 import java.net.URLConnection; 28 import java.util.List; 29 import java.util.Locale; 30 31 /** 32 * Describes a proxy configuration. 33 * 34 * Proxy configurations are already integrated within the {@code java.net} and 35 * Apache HTTP stack. So {@link URLConnection} and Apache's {@code HttpClient} will use 36 * them automatically. 37 * 38 * Other HTTP stacks will need to obtain the proxy info from 39 * {@link Proxy#PROXY_CHANGE_ACTION} broadcast as the extra {@link Proxy#EXTRA_PROXY_INFO}. 40 */ 41 public class ProxyInfo implements Parcelable { 42 43 private final String mHost; 44 private final int mPort; 45 private final String mExclusionList; 46 private final String[] mParsedExclusionList; 47 private final Uri mPacFileUrl; 48 49 /** 50 *@hide 51 */ 52 public static final String LOCAL_EXCL_LIST = ""; 53 /** 54 *@hide 55 */ 56 public static final int LOCAL_PORT = -1; 57 /** 58 *@hide 59 */ 60 public static final String LOCAL_HOST = "localhost"; 61 62 /** 63 * Constructs a {@link ProxyInfo} object that points at a Direct proxy 64 * on the specified host and port. 65 */ buildDirectProxy(String host, int port)66 public static ProxyInfo buildDirectProxy(String host, int port) { 67 return new ProxyInfo(host, port, null); 68 } 69 70 /** 71 * Constructs a {@link ProxyInfo} object that points at a Direct proxy 72 * on the specified host and port. 73 * 74 * The proxy will not be used to access any host in exclusion list, exclList. 75 * 76 * @param exclList Hosts to exclude using the proxy on connections for. These 77 * hosts can use wildcards such as *.example.com. 78 */ buildDirectProxy(String host, int port, List<String> exclList)79 public static ProxyInfo buildDirectProxy(String host, int port, List<String> exclList) { 80 String[] array = exclList.toArray(new String[exclList.size()]); 81 return new ProxyInfo(host, port, TextUtils.join(",", array), array); 82 } 83 84 /** 85 * Construct a {@link ProxyInfo} that will download and run the PAC script 86 * at the specified URL. 87 */ buildPacProxy(Uri pacUri)88 public static ProxyInfo buildPacProxy(Uri pacUri) { 89 return new ProxyInfo(pacUri); 90 } 91 92 /** 93 * Construct a {@link ProxyInfo} object that will download and run the PAC script at the 94 * specified URL and port. 95 */ 96 @NonNull buildPacProxy(@onNull Uri pacUrl, int port)97 public static ProxyInfo buildPacProxy(@NonNull Uri pacUrl, int port) { 98 return new ProxyInfo(pacUrl, port); 99 } 100 101 /** 102 * Create a ProxyProperties that points at a HTTP Proxy. 103 * @hide 104 */ 105 @UnsupportedAppUsage ProxyInfo(String host, int port, String exclList)106 public ProxyInfo(String host, int port, String exclList) { 107 mHost = host; 108 mPort = port; 109 mExclusionList = exclList; 110 mParsedExclusionList = parseExclusionList(mExclusionList); 111 mPacFileUrl = Uri.EMPTY; 112 } 113 114 /** 115 * Create a ProxyProperties that points at a PAC URL. 116 * @hide 117 */ ProxyInfo(@onNull Uri pacFileUrl)118 public ProxyInfo(@NonNull Uri pacFileUrl) { 119 mHost = LOCAL_HOST; 120 mPort = LOCAL_PORT; 121 mExclusionList = LOCAL_EXCL_LIST; 122 mParsedExclusionList = parseExclusionList(mExclusionList); 123 if (pacFileUrl == null) { 124 throw new NullPointerException(); 125 } 126 mPacFileUrl = pacFileUrl; 127 } 128 129 /** 130 * Only used in PacManager after Local Proxy is bound. 131 * @hide 132 */ ProxyInfo(@onNull Uri pacFileUrl, int localProxyPort)133 public ProxyInfo(@NonNull Uri pacFileUrl, int localProxyPort) { 134 mHost = LOCAL_HOST; 135 mPort = localProxyPort; 136 mExclusionList = LOCAL_EXCL_LIST; 137 mParsedExclusionList = parseExclusionList(mExclusionList); 138 if (pacFileUrl == null) { 139 throw new NullPointerException(); 140 } 141 mPacFileUrl = pacFileUrl; 142 } 143 parseExclusionList(String exclusionList)144 private static String[] parseExclusionList(String exclusionList) { 145 if (exclusionList == null) { 146 return new String[0]; 147 } else { 148 return exclusionList.toLowerCase(Locale.ROOT).split(","); 149 } 150 } 151 ProxyInfo(String host, int port, String exclList, String[] parsedExclList)152 private ProxyInfo(String host, int port, String exclList, String[] parsedExclList) { 153 mHost = host; 154 mPort = port; 155 mExclusionList = exclList; 156 mParsedExclusionList = parsedExclList; 157 mPacFileUrl = Uri.EMPTY; 158 } 159 160 /** 161 * A copy constructor to hold proxy properties. 162 */ ProxyInfo(@ullable ProxyInfo source)163 public ProxyInfo(@Nullable ProxyInfo source) { 164 if (source != null) { 165 mHost = source.getHost(); 166 mPort = source.getPort(); 167 mPacFileUrl = source.mPacFileUrl; 168 mExclusionList = source.getExclusionListAsString(); 169 mParsedExclusionList = source.mParsedExclusionList; 170 } else { 171 mHost = null; 172 mPort = 0; 173 mExclusionList = null; 174 mParsedExclusionList = null; 175 mPacFileUrl = Uri.EMPTY; 176 } 177 } 178 179 /** 180 * @hide 181 */ getSocketAddress()182 public InetSocketAddress getSocketAddress() { 183 InetSocketAddress inetSocketAddress = null; 184 try { 185 inetSocketAddress = new InetSocketAddress(mHost, mPort); 186 } catch (IllegalArgumentException e) { } 187 return inetSocketAddress; 188 } 189 190 /** 191 * Returns the URL of the current PAC script or null if there is 192 * no PAC script. 193 */ getPacFileUrl()194 public Uri getPacFileUrl() { 195 return mPacFileUrl; 196 } 197 198 /** 199 * When configured to use a Direct Proxy this returns the host 200 * of the proxy. 201 */ getHost()202 public String getHost() { 203 return mHost; 204 } 205 206 /** 207 * When configured to use a Direct Proxy this returns the port 208 * of the proxy 209 */ getPort()210 public int getPort() { 211 return mPort; 212 } 213 214 /** 215 * When configured to use a Direct Proxy this returns the list 216 * of hosts for which the proxy is ignored. 217 */ getExclusionList()218 public String[] getExclusionList() { 219 return mParsedExclusionList; 220 } 221 222 /** 223 * comma separated 224 * @hide 225 */ 226 @Nullable getExclusionListAsString()227 public String getExclusionListAsString() { 228 return mExclusionList; 229 } 230 231 /** 232 * Return true if the pattern of proxy is valid, otherwise return false. 233 */ isValid()234 public boolean isValid() { 235 if (!Uri.EMPTY.equals(mPacFileUrl)) return true; 236 return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost, 237 mPort == 0 ? "" : Integer.toString(mPort), 238 mExclusionList == null ? "" : mExclusionList); 239 } 240 241 /** 242 * @hide 243 */ makeProxy()244 public java.net.Proxy makeProxy() { 245 java.net.Proxy proxy = java.net.Proxy.NO_PROXY; 246 if (mHost != null) { 247 try { 248 InetSocketAddress inetSocketAddress = new InetSocketAddress(mHost, mPort); 249 proxy = new java.net.Proxy(java.net.Proxy.Type.HTTP, inetSocketAddress); 250 } catch (IllegalArgumentException e) { 251 } 252 } 253 return proxy; 254 } 255 256 @Override toString()257 public String toString() { 258 StringBuilder sb = new StringBuilder(); 259 if (!Uri.EMPTY.equals(mPacFileUrl)) { 260 sb.append("PAC Script: "); 261 sb.append(mPacFileUrl); 262 } 263 if (mHost != null) { 264 sb.append("["); 265 sb.append(mHost); 266 sb.append("] "); 267 sb.append(Integer.toString(mPort)); 268 if (mExclusionList != null) { 269 sb.append(" xl=").append(mExclusionList); 270 } 271 } else { 272 sb.append("[ProxyProperties.mHost == null]"); 273 } 274 return sb.toString(); 275 } 276 277 @Override equals(Object o)278 public boolean equals(Object o) { 279 if (!(o instanceof ProxyInfo)) return false; 280 ProxyInfo p = (ProxyInfo)o; 281 // If PAC URL is present in either then they must be equal. 282 // Other parameters will only be for fall back. 283 if (!Uri.EMPTY.equals(mPacFileUrl)) { 284 return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort; 285 } 286 if (!Uri.EMPTY.equals(p.mPacFileUrl)) { 287 return false; 288 } 289 if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) { 290 return false; 291 } 292 if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) { 293 return false; 294 } 295 if (mHost != null && p.mHost == null) return false; 296 if (mHost == null && p.mHost != null) return false; 297 if (mPort != p.mPort) return false; 298 return true; 299 } 300 301 /** 302 * Implement the Parcelable interface 303 * @hide 304 */ describeContents()305 public int describeContents() { 306 return 0; 307 } 308 309 @Override 310 /* 311 * generate hashcode based on significant fields 312 */ hashCode()313 public int hashCode() { 314 return ((null == mHost) ? 0 : mHost.hashCode()) 315 + ((null == mExclusionList) ? 0 : mExclusionList.hashCode()) 316 + mPort; 317 } 318 319 /** 320 * Implement the Parcelable interface. 321 * @hide 322 */ writeToParcel(Parcel dest, int flags)323 public void writeToParcel(Parcel dest, int flags) { 324 if (!Uri.EMPTY.equals(mPacFileUrl)) { 325 dest.writeByte((byte)1); 326 mPacFileUrl.writeToParcel(dest, 0); 327 dest.writeInt(mPort); 328 return; 329 } else { 330 dest.writeByte((byte)0); 331 } 332 if (mHost != null) { 333 dest.writeByte((byte)1); 334 dest.writeString(mHost); 335 dest.writeInt(mPort); 336 } else { 337 dest.writeByte((byte)0); 338 } 339 dest.writeString(mExclusionList); 340 dest.writeStringArray(mParsedExclusionList); 341 } 342 343 public static final @android.annotation.NonNull Creator<ProxyInfo> CREATOR = 344 new Creator<ProxyInfo>() { 345 public ProxyInfo createFromParcel(Parcel in) { 346 String host = null; 347 int port = 0; 348 if (in.readByte() != 0) { 349 Uri url = Uri.CREATOR.createFromParcel(in); 350 int localPort = in.readInt(); 351 return new ProxyInfo(url, localPort); 352 } 353 if (in.readByte() != 0) { 354 host = in.readString(); 355 port = in.readInt(); 356 } 357 String exclList = in.readString(); 358 String[] parsedExclList = in.readStringArray(); 359 ProxyInfo proxyProperties = new ProxyInfo(host, port, exclList, parsedExclList); 360 return proxyProperties; 361 } 362 363 public ProxyInfo[] newArray(int size) { 364 return new ProxyInfo[size]; 365 } 366 }; 367 } 368