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