blob: 0deda371f6b9e4d795abb378852e19290f4e7b54 [file] [log] [blame]
Remi NGUYEN VANfbbccbc2021-01-15 18:08:24 +09001/*
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
17package android.net;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.compat.annotation.UnsupportedAppUsage;
22import android.os.Parcel;
23import android.os.Parcelable;
24import android.text.TextUtils;
25
Chiachang Wangf1512902021-02-05 17:33:53 +080026import com.android.net.module.util.ProxyUtils;
27
Remi NGUYEN VANfbbccbc2021-01-15 18:08:24 +090028import java.net.InetSocketAddress;
29import java.net.URLConnection;
30import java.util.List;
31import 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 *
Lorenzo Colitti9c0095c2021-03-18 13:07:37 +090040 * 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}.
Remi NGUYEN VANfbbccbc2021-01-15 18:08:24 +090043 */
44public 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 */
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 */
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 */
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
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
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 */
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 /**
Aaron Huanged0fe3e2021-01-18 15:28:01 +0800133 * Only used in PacProxyService after Local Proxy is bound.
Remi NGUYEN VANfbbccbc2021-01-15 18:08:24 +0900134 * @hide
135 */
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
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
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 */
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 */
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 */
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 */
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 */
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 */
221 public String[] getExclusionList() {
222 return mParsedExclusionList;
223 }
224
225 /**
226 * comma separated
227 * @hide
228 */
229 @Nullable
230 public String getExclusionListAsString() {
231 return mExclusionList;
232 }
233
234 /**
235 * Return true if the pattern of proxy is valid, otherwise return false.
236 */
237 public boolean isValid() {
238 if (!Uri.EMPTY.equals(mPacFileUrl)) return true;
Chiachang Wangf1512902021-02-05 17:33:53 +0800239 return ProxyUtils.PROXY_VALID == ProxyUtils.validate(mHost == null ? "" : mHost,
Remi NGUYEN VANfbbccbc2021-01-15 18:08:24 +0900240 mPort == 0 ? "" : Integer.toString(mPort),
241 mExclusionList == null ? "" : mExclusionList);
242 }
243
244 /**
245 * @hide
246 */
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
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
Roman Kalukiewicz0b6f2902020-10-14 15:59:06 -0700281 public boolean equals(@Nullable Object o) {
Remi NGUYEN VANfbbccbc2021-01-15 18:08:24 +0900282 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 */
308 public int describeContents() {
309 return 0;
310 }
311
312 @Override
313 /*
314 * generate hashcode based on significant fields
315 */
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 */
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}