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 * Create a ProxyProperties that points at a PAC URL. 131 * @hide 132 */ ProxyInfo(String pacFileUrl)133 public ProxyInfo(String pacFileUrl) { 134 mHost = LOCAL_HOST; 135 mPort = LOCAL_PORT; 136 mExclusionList = LOCAL_EXCL_LIST; 137 mParsedExclusionList = parseExclusionList(mExclusionList); 138 mPacFileUrl = Uri.parse(pacFileUrl); 139 } 140 141 /** 142 * Only used in PacManager after Local Proxy is bound. 143 * @hide 144 */ ProxyInfo(@onNull Uri pacFileUrl, int localProxyPort)145 public ProxyInfo(@NonNull Uri pacFileUrl, int localProxyPort) { 146 mHost = LOCAL_HOST; 147 mPort = localProxyPort; 148 mExclusionList = LOCAL_EXCL_LIST; 149 mParsedExclusionList = parseExclusionList(mExclusionList); 150 if (pacFileUrl == null) { 151 throw new NullPointerException(); 152 } 153 mPacFileUrl = pacFileUrl; 154 } 155 parseExclusionList(String exclusionList)156 private static String[] parseExclusionList(String exclusionList) { 157 if (exclusionList == null) { 158 return new String[0]; 159 } else { 160 return exclusionList.toLowerCase(Locale.ROOT).split(","); 161 } 162 } 163 ProxyInfo(String host, int port, String exclList, String[] parsedExclList)164 private ProxyInfo(String host, int port, String exclList, String[] parsedExclList) { 165 mHost = host; 166 mPort = port; 167 mExclusionList = exclList; 168 mParsedExclusionList = parsedExclList; 169 mPacFileUrl = Uri.EMPTY; 170 } 171 172 /** 173 * A copy constructor to hold proxy properties. 174 */ ProxyInfo(@ullable ProxyInfo source)175 public ProxyInfo(@Nullable ProxyInfo source) { 176 if (source != null) { 177 mHost = source.getHost(); 178 mPort = source.getPort(); 179 mPacFileUrl = source.mPacFileUrl; 180 mExclusionList = source.getExclusionListAsString(); 181 mParsedExclusionList = source.mParsedExclusionList; 182 } else { 183 mHost = null; 184 mPort = 0; 185 mExclusionList = null; 186 mParsedExclusionList = null; 187 mPacFileUrl = Uri.EMPTY; 188 } 189 } 190 191 /** 192 * @hide 193 */ getSocketAddress()194 public InetSocketAddress getSocketAddress() { 195 InetSocketAddress inetSocketAddress = null; 196 try { 197 inetSocketAddress = new InetSocketAddress(mHost, mPort); 198 } catch (IllegalArgumentException e) { } 199 return inetSocketAddress; 200 } 201 202 /** 203 * Returns the URL of the current PAC script or null if there is 204 * no PAC script. 205 */ getPacFileUrl()206 public Uri getPacFileUrl() { 207 return mPacFileUrl; 208 } 209 210 /** 211 * When configured to use a Direct Proxy this returns the host 212 * of the proxy. 213 */ getHost()214 public String getHost() { 215 return mHost; 216 } 217 218 /** 219 * When configured to use a Direct Proxy this returns the port 220 * of the proxy 221 */ getPort()222 public int getPort() { 223 return mPort; 224 } 225 226 /** 227 * When configured to use a Direct Proxy this returns the list 228 * of hosts for which the proxy is ignored. 229 */ getExclusionList()230 public String[] getExclusionList() { 231 return mParsedExclusionList; 232 } 233 234 /** 235 * comma separated 236 * @hide 237 */ 238 @Nullable getExclusionListAsString()239 public String getExclusionListAsString() { 240 return mExclusionList; 241 } 242 243 /** 244 * Return true if the pattern of proxy is valid, otherwise return false. 245 */ isValid()246 public boolean isValid() { 247 if (!Uri.EMPTY.equals(mPacFileUrl)) return true; 248 return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost, 249 mPort == 0 ? "" : Integer.toString(mPort), 250 mExclusionList == null ? "" : mExclusionList); 251 } 252 253 /** 254 * @hide 255 */ makeProxy()256 public java.net.Proxy makeProxy() { 257 java.net.Proxy proxy = java.net.Proxy.NO_PROXY; 258 if (mHost != null) { 259 try { 260 InetSocketAddress inetSocketAddress = new InetSocketAddress(mHost, mPort); 261 proxy = new java.net.Proxy(java.net.Proxy.Type.HTTP, inetSocketAddress); 262 } catch (IllegalArgumentException e) { 263 } 264 } 265 return proxy; 266 } 267 268 @Override toString()269 public String toString() { 270 StringBuilder sb = new StringBuilder(); 271 if (!Uri.EMPTY.equals(mPacFileUrl)) { 272 sb.append("PAC Script: "); 273 sb.append(mPacFileUrl); 274 } 275 if (mHost != null) { 276 sb.append("["); 277 sb.append(mHost); 278 sb.append("] "); 279 sb.append(Integer.toString(mPort)); 280 if (mExclusionList != null) { 281 sb.append(" xl=").append(mExclusionList); 282 } 283 } else { 284 sb.append("[ProxyProperties.mHost == null]"); 285 } 286 return sb.toString(); 287 } 288 289 @Override equals(Object o)290 public boolean equals(Object o) { 291 if (!(o instanceof ProxyInfo)) return false; 292 ProxyInfo p = (ProxyInfo)o; 293 // If PAC URL is present in either then they must be equal. 294 // Other parameters will only be for fall back. 295 if (!Uri.EMPTY.equals(mPacFileUrl)) { 296 return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort; 297 } 298 if (!Uri.EMPTY.equals(p.mPacFileUrl)) { 299 return false; 300 } 301 if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) { 302 return false; 303 } 304 if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) { 305 return false; 306 } 307 if (mHost != null && p.mHost == null) return false; 308 if (mHost == null && p.mHost != null) return false; 309 if (mPort != p.mPort) return false; 310 return true; 311 } 312 313 /** 314 * Implement the Parcelable interface 315 * @hide 316 */ describeContents()317 public int describeContents() { 318 return 0; 319 } 320 321 @Override 322 /* 323 * generate hashcode based on significant fields 324 */ hashCode()325 public int hashCode() { 326 return ((null == mHost) ? 0 : mHost.hashCode()) 327 + ((null == mExclusionList) ? 0 : mExclusionList.hashCode()) 328 + mPort; 329 } 330 331 /** 332 * Implement the Parcelable interface. 333 * @hide 334 */ writeToParcel(Parcel dest, int flags)335 public void writeToParcel(Parcel dest, int flags) { 336 if (!Uri.EMPTY.equals(mPacFileUrl)) { 337 dest.writeByte((byte)1); 338 mPacFileUrl.writeToParcel(dest, 0); 339 dest.writeInt(mPort); 340 return; 341 } else { 342 dest.writeByte((byte)0); 343 } 344 if (mHost != null) { 345 dest.writeByte((byte)1); 346 dest.writeString(mHost); 347 dest.writeInt(mPort); 348 } else { 349 dest.writeByte((byte)0); 350 } 351 dest.writeString(mExclusionList); 352 dest.writeStringArray(mParsedExclusionList); 353 } 354 355 public static final @android.annotation.NonNull Creator<ProxyInfo> CREATOR = 356 new Creator<ProxyInfo>() { 357 public ProxyInfo createFromParcel(Parcel in) { 358 String host = null; 359 int port = 0; 360 if (in.readByte() != 0) { 361 Uri url = Uri.CREATOR.createFromParcel(in); 362 int localPort = in.readInt(); 363 return new ProxyInfo(url, localPort); 364 } 365 if (in.readByte() != 0) { 366 host = in.readString(); 367 port = in.readInt(); 368 } 369 String exclList = in.readString(); 370 String[] parsedExclList = in.readStringArray(); 371 ProxyInfo proxyProperties = new ProxyInfo(host, port, exclList, parsedExclList); 372 return proxyProperties; 373 } 374 375 public ProxyInfo[] newArray(int size) { 376 return new ProxyInfo[size]; 377 } 378 }; 379 } 380