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