• 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, res, file system or data stream are handled in the other code
167         // path. This only handles network request.
168         if (URLUtil.isAssetUrl(url) || URLUtil.isResourceUrl(url)
169                 || URLUtil.isFileUrl(url) || 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         RequestHandle handle = null;
184         if (loader.isSynchronous()) {
185             handle = q.queueSynchronousRequest(url, loader.getWebAddress(),
186                     method, headers, loader, bodyProvider, bodyLength);
187             loader.attachRequestHandle(handle);
188             handle.processRequest();
189             loader.loadSynchronousMessages();
190         } else {
191             handle = q.queueRequest(url, loader.getWebAddress(), method,
192                     headers, loader, bodyProvider, bodyLength);
193             // FIXME: Although this is probably a rare condition, normal network
194             // requests are processed in a separate thread. This means that it
195             // is possible to process part of the request before setting the
196             // request handle on the loader. We should probably refactor this to
197             // ensure the handle is attached before processing begins.
198             loader.attachRequestHandle(handle);
199         }
200 
201         return true;
202     }
203 
204     /**
205      * @return True iff there is a valid proxy set.
206      */
isValidProxySet()207     public boolean isValidProxySet() {
208         // The proxy host and port can be set within a different thread during
209         // an Intent broadcast.
210         synchronized (mRequestQueue) {
211             return mRequestQueue.getProxyHost() != null;
212         }
213     }
214 
215     /**
216      * Get the proxy hostname.
217      * @return The proxy hostname obtained from the network queue and proxy
218      *         settings.
219      */
getProxyHostname()220     public String getProxyHostname() {
221         return mRequestQueue.getProxyHost().getHostName();
222     }
223 
224     /**
225      * @return The proxy username or null if none.
226      */
getProxyUsername()227     public synchronized String getProxyUsername() {
228         return mProxyUsername;
229     }
230 
231     /**
232      * Sets the proxy username.
233      * @param proxyUsername Username to use when
234      * connecting through the proxy.
235      */
setProxyUsername(String proxyUsername)236     public synchronized void setProxyUsername(String proxyUsername) {
237         if (DebugFlags.NETWORK) {
238             Assert.assertTrue(isValidProxySet());
239         }
240 
241         mProxyUsername = proxyUsername;
242     }
243 
244     /**
245      * @return The proxy password or null if none.
246      */
getProxyPassword()247     public synchronized String getProxyPassword() {
248         return mProxyPassword;
249     }
250 
251     /**
252      * Sets the proxy password.
253      * @param proxyPassword Password to use when
254      * connecting through the proxy.
255      */
setProxyPassword(String proxyPassword)256     public synchronized void setProxyPassword(String proxyPassword) {
257         if (DebugFlags.NETWORK) {
258             Assert.assertTrue(isValidProxySet());
259         }
260 
261         mProxyPassword = proxyPassword;
262     }
263 
264     /**
265      * Saves the state of network handlers (user SSL and HTTP-authentication
266      * preferences).
267      * @param outState The out-state to save (write) to.
268      * @return True iff succeeds.
269      */
saveState(Bundle outState)270     public boolean saveState(Bundle outState) {
271         if (DebugFlags.NETWORK) {
272             Log.v(LOGTAG, "Network.saveState()");
273         }
274 
275         return mSslErrorHandler.saveState(outState);
276     }
277 
278     /**
279      * Restores the state of network handlers (user SSL and HTTP-authentication
280      * preferences).
281      * @param inState The in-state to load (read) from.
282      * @return True iff succeeds.
283      */
restoreState(Bundle inState)284     public boolean restoreState(Bundle inState) {
285         if (DebugFlags.NETWORK) {
286             Log.v(LOGTAG, "Network.restoreState()");
287         }
288 
289         return mSslErrorHandler.restoreState(inState);
290     }
291 
292     /**
293      * Clears user SSL-error preference table.
294      */
clearUserSslPrefTable()295     public void clearUserSslPrefTable() {
296         mSslErrorHandler.clear();
297     }
298 
299     /**
300      * Handles SSL error(s) on the way up to the user: the user must decide
301      * whether errors should be ignored or not.
302      * @param loader The loader that resulted in SSL errors.
303      */
handleSslErrorRequest(LoadListener loader)304     public void handleSslErrorRequest(LoadListener loader) {
305         if (DebugFlags.NETWORK) Assert.assertNotNull(loader);
306         if (loader != null) {
307             mSslErrorHandler.handleSslErrorRequest(loader);
308         }
309     }
310 
checkSslPrefTable(LoadListener loader, SslError error)311     /* package */ boolean checkSslPrefTable(LoadListener loader,
312             SslError error) {
313         if (loader != null && error != null) {
314             return mSslErrorHandler.checkSslPrefTable(loader, error);
315         }
316         return false;
317     }
318 
319      /**
320      * Handles authentication requests on their way up to the user (the user
321      * must provide credentials).
322      * @param loader The loader that resulted in an HTTP
323      * authentication request.
324      */
handleAuthRequest(LoadListener loader)325     public void handleAuthRequest(LoadListener loader) {
326         if (DebugFlags.NETWORK) Assert.assertNotNull(loader);
327         if (loader != null) {
328             mHttpAuthHandler.handleAuthRequest(loader);
329         }
330     }
331 
332     // Performance probe
startTiming()333     public void startTiming() {
334         mRequestQueue.startTiming();
335     }
336 
stopTiming()337     public void stopTiming() {
338         mRequestQueue.stopTiming();
339     }
340 }
341