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