• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 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.webkit;
18 
19 import android.content.Context;
20 import android.net.http.*;
21 import android.os.*;
22 import android.util.Log;
23 
24 import java.io.ByteArrayInputStream;
25 import java.io.InputStream;
26 import java.util.Map;
27 
28 import junit.framework.Assert;
29 
30 class Network {
31 
32     private static final String LOGTAG = "network";
33 
34     /**
35      * Static instance of a Network object.
36      */
37     private static Network sNetwork;
38 
39     /**
40      * Flag to store the state of platform notifications, for the case
41      * when the Network object has not been constructed yet
42      */
43     private static boolean sPlatformNotifications;
44 
45     /**
46      * Reference count for platform notifications as the network class is a
47      * static and can exist over multiple activities, thus over multiple
48      * onPause/onResume pairs.
49      */
50     private static int sPlatformNotificationEnableRefCount;
51 
52     /**
53      * Proxy username if known (used for pre-emptive proxy authentication).
54      */
55     private String mProxyUsername;
56 
57     /**
58      * Proxy password if known (used for pre-emptive proxy authentication).
59      */
60     private String mProxyPassword;
61 
62     /**
63      * Network request queue (requests are added from the browser thread).
64      */
65     private RequestQueue mRequestQueue;
66 
67     /**
68      * SSL error handler: takes care of synchronization of multiple async
69      * loaders with SSL-related problems.
70      */
71     private SslErrorHandler mSslErrorHandler;
72 
73     /**
74      * HTTP authentication handler: takes care of synchronization of HTTP
75      * authentication requests.
76      */
77     private HttpAuthHandler mHttpAuthHandler;
78 
79     /**
80      * @return The singleton instance of the network.
81      */
getInstance(Context context)82     public static synchronized Network getInstance(Context context) {
83         if (sNetwork == null) {
84             // Note Context of the Application is used here, rather than
85             // the what is passed in (usually a Context derived from an
86             // Activity) so the intent receivers belong to the application
87             // rather than an activity - this fixes the issue where
88             // Activities are created and destroyed during the lifetime of
89             // an Application
90             sNetwork = new Network(context.getApplicationContext());
91             if (sPlatformNotifications) {
92                 // Adjust the ref count before calling enable as it is already
93                 // taken into account when the static function was called
94                 // directly
95                 --sPlatformNotificationEnableRefCount;
96                 enablePlatformNotifications();
97             }
98         }
99         return sNetwork;
100     }
101 
102 
103     /**
104      * Enables data state and proxy tracking
105      */
enablePlatformNotifications()106     public static void enablePlatformNotifications() {
107         if (++sPlatformNotificationEnableRefCount == 1) {
108             if (sNetwork != null) {
109                 sNetwork.mRequestQueue.enablePlatformNotifications();
110             } else {
111                 sPlatformNotifications = true;
112             }
113         }
114     }
115 
116     /**
117      * If platform notifications are enabled, this should be called
118      * from onPause() or onStop()
119      */
disablePlatformNotifications()120     public static void disablePlatformNotifications() {
121         if (--sPlatformNotificationEnableRefCount == 0) {
122             if (sNetwork != null) {
123                 sNetwork.mRequestQueue.disablePlatformNotifications();
124             } else {
125                 sPlatformNotifications = false;
126             }
127         }
128     }
129 
130     /**
131      * Creates a new Network object.
132      * XXX: Must be created in the same thread as WebCore!!!!!
133      */
Network(Context context)134     private Network(Context context) {
135         if (DebugFlags.NETWORK) {
136             Assert.assertTrue(Thread.currentThread().
137                     getName().equals(WebViewCore.THREAD_NAME));
138         }
139         mSslErrorHandler = new SslErrorHandler();
140         mHttpAuthHandler = new HttpAuthHandler(this);
141 
142         mRequestQueue = new RequestQueue(context);
143     }
144 
145     /**
146      * Request a url from either the network or the file system.
147      * @param url The url to load.
148      * @param method The http method.
149      * @param headers The http headers.
150      * @param postData The body of the request.
151      * @param loader A LoadListener for receiving the results of the request.
152      * @return True if the request was successfully queued.
153      */
requestURL(String method, Map<String, String> headers, byte [] postData, LoadListener loader)154     public boolean requestURL(String method,
155                               Map<String, String> headers,
156                               byte [] postData,
157                               LoadListener loader) {
158 
159         String url = loader.url();
160 
161         // Not a valid url, return false because we won't service the request!
162         if (!URLUtil.isValidUrl(url)) {
163             return false;
164         }
165 
166         // asset, file system or data stream are handled in the other code path.
167         // This only handles network request.
168         if (URLUtil.isAssetUrl(url) || URLUtil.isFileUrl(url) ||
169                 URLUtil.isDataUrl(url)) {
170             return false;
171         }
172 
173         /* FIXME: this is lame.  Pass an InputStream in, rather than
174            making this lame one here */
175         InputStream bodyProvider = null;
176         int bodyLength = 0;
177         if (postData != null) {
178             bodyLength = postData.length;
179             bodyProvider = new ByteArrayInputStream(postData);
180         }
181 
182         RequestQueue q = mRequestQueue;
183         if (loader.isSynchronous()) {
184             q = new RequestQueue(loader.getContext(), 1);
185         }
186 
187         RequestHandle handle = q.queueRequest(
188                 url, loader.getWebAddress(), method, headers, loader,
189                 bodyProvider, bodyLength);
190         loader.attachRequestHandle(handle);
191 
192         if (loader.isSynchronous()) {
193             handle.waitUntilComplete();
194             loader.loadSynchronousMessages();
195             q.shutdown();
196         }
197         return true;
198     }
199 
200     /**
201      * @return True iff there is a valid proxy set.
202      */
isValidProxySet()203     public boolean isValidProxySet() {
204         // The proxy host and port can be set within a different thread during
205         // an Intent broadcast.
206         synchronized (mRequestQueue) {
207             return mRequestQueue.getProxyHost() != null;
208         }
209     }
210 
211     /**
212      * Get the proxy hostname.
213      * @return The proxy hostname obtained from the network queue and proxy
214      *         settings.
215      */
getProxyHostname()216     public String getProxyHostname() {
217         return mRequestQueue.getProxyHost().getHostName();
218     }
219 
220     /**
221      * @return The proxy username or null if none.
222      */
getProxyUsername()223     public synchronized String getProxyUsername() {
224         return mProxyUsername;
225     }
226 
227     /**
228      * Sets the proxy username.
229      * @param proxyUsername Username to use when
230      * connecting through the proxy.
231      */
setProxyUsername(String proxyUsername)232     public synchronized void setProxyUsername(String proxyUsername) {
233         if (DebugFlags.NETWORK) {
234             Assert.assertTrue(isValidProxySet());
235         }
236 
237         mProxyUsername = proxyUsername;
238     }
239 
240     /**
241      * @return The proxy password or null if none.
242      */
getProxyPassword()243     public synchronized String getProxyPassword() {
244         return mProxyPassword;
245     }
246 
247     /**
248      * Sets the proxy password.
249      * @param proxyPassword Password to use when
250      * connecting through the proxy.
251      */
setProxyPassword(String proxyPassword)252     public synchronized void setProxyPassword(String proxyPassword) {
253         if (DebugFlags.NETWORK) {
254             Assert.assertTrue(isValidProxySet());
255         }
256 
257         mProxyPassword = proxyPassword;
258     }
259 
260     /**
261      * Saves the state of network handlers (user SSL and HTTP-authentication
262      * preferences).
263      * @param outState The out-state to save (write) to.
264      * @return True iff succeeds.
265      */
saveState(Bundle outState)266     public boolean saveState(Bundle outState) {
267         if (DebugFlags.NETWORK) {
268             Log.v(LOGTAG, "Network.saveState()");
269         }
270 
271         return mSslErrorHandler.saveState(outState);
272     }
273 
274     /**
275      * Restores the state of network handlers (user SSL and HTTP-authentication
276      * preferences).
277      * @param inState The in-state to load (read) from.
278      * @return True iff succeeds.
279      */
restoreState(Bundle inState)280     public boolean restoreState(Bundle inState) {
281         if (DebugFlags.NETWORK) {
282             Log.v(LOGTAG, "Network.restoreState()");
283         }
284 
285         return mSslErrorHandler.restoreState(inState);
286     }
287 
288     /**
289      * Clears user SSL-error preference table.
290      */
clearUserSslPrefTable()291     public void clearUserSslPrefTable() {
292         mSslErrorHandler.clear();
293     }
294 
295     /**
296      * Handles SSL error(s) on the way up to the user: the user must decide
297      * whether errors should be ignored or not.
298      * @param loader The loader that resulted in SSL errors.
299      */
handleSslErrorRequest(LoadListener loader)300     public void handleSslErrorRequest(LoadListener loader) {
301         if (DebugFlags.NETWORK) Assert.assertNotNull(loader);
302         if (loader != null) {
303             mSslErrorHandler.handleSslErrorRequest(loader);
304         }
305     }
306 
checkSslPrefTable(LoadListener loader, SslError error)307     /* package */ boolean checkSslPrefTable(LoadListener loader,
308             SslError error) {
309         if (loader != null && error != null) {
310             return mSslErrorHandler.checkSslPrefTable(loader, error);
311         }
312         return false;
313     }
314 
315      /**
316      * Handles authentication requests on their way up to the user (the user
317      * must provide credentials).
318      * @param loader The loader that resulted in an HTTP
319      * authentication request.
320      */
handleAuthRequest(LoadListener loader)321     public void handleAuthRequest(LoadListener loader) {
322         if (DebugFlags.NETWORK) Assert.assertNotNull(loader);
323         if (loader != null) {
324             mHttpAuthHandler.handleAuthRequest(loader);
325         }
326     }
327 
328     // Performance probe
startTiming()329     public void startTiming() {
330         mRequestQueue.startTiming();
331     }
332 
stopTiming()333     public void stopTiming() {
334         mRequestQueue.stopTiming();
335     }
336 }
337