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