diff options
| author | Steve Block <steveblock@google.com> | 2010-03-12 18:49:48 +0000 |
|---|---|---|
| committer | Steve Block <steveblock@google.com> | 2010-03-19 13:48:49 +0000 |
| commit | c877c6b87a2e72bdffda756fc75f0ec684de6fbd (patch) | |
| tree | bc1b3c6e860608288bdefb7eac65acc319c15893 /core/java/android/webkit/HttpAuthHandler.java | |
| parent | 9b63c8ee37efa728c7be33baf748078329894437 (diff) | |
Fix HttpAuthHandler for synchronous requests
When HttpAuthHandler queries the WebViewClient to obtain a username and
password, we need to make sure that this is done synchronously when the request
is synchronous.
Bug: 2511043
Change-Id: I9ff2156cfb3c81edaf4a50ec7094a00a8f8ff91f
Diffstat (limited to 'core/java/android/webkit/HttpAuthHandler.java')
| -rw-r--r-- | core/java/android/webkit/HttpAuthHandler.java | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/core/java/android/webkit/HttpAuthHandler.java b/core/java/android/webkit/HttpAuthHandler.java index 1c17575033fe..621660390c58 100644 --- a/core/java/android/webkit/HttpAuthHandler.java +++ b/core/java/android/webkit/HttpAuthHandler.java @@ -19,6 +19,7 @@ package android.webkit; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.util.Log; import java.util.ListIterator; import java.util.LinkedList; @@ -52,6 +53,14 @@ public class HttpAuthHandler extends Handler { private static final int AUTH_PROCEED = 100; private static final int AUTH_CANCEL = 200; + // Use to synchronize when making synchronous calls to + // onReceivedHttpAuthRequest(). We can't use a single Boolean object for + // both the lock and the state, because Boolean is immutable. + Object mRequestInFlightLock = new Object(); + boolean mRequestInFlight; + String mUsername; + String mPassword; + /** * Creates a new HTTP authentication handler with an empty * loader queue @@ -70,6 +79,7 @@ public class HttpAuthHandler extends Handler { synchronized (mLoaderQueue) { loader = mLoaderQueue.poll(); } + assert(loader.isSynchronous() == false); switch (msg.what) { case AUTH_PROCEED: @@ -87,25 +97,70 @@ public class HttpAuthHandler extends Handler { processNextLoader(); } + /** + * Helper method used to unblock handleAuthRequest(), which in the case of a + * synchronous request will wait for proxy.onReceivedHttpAuthRequest() to + * call back to either proceed() or cancel(). + * + * @param username The username to use for authentication + * @param password The password to use for authentication + * @return True if the request is synchronous and handleAuthRequest() has + * been unblocked + */ + private boolean handleResponseForSynchronousRequest(String username, String password) { + LoadListener loader = null; + synchronized (mLoaderQueue) { + loader = mLoaderQueue.peek(); + } + if (loader.isSynchronous()) { + mUsername = username; + mPassword = password; + return true; + } + return false; + } + + private void signalRequestComplete() { + synchronized (mRequestInFlightLock) { + assert(mRequestInFlight); + mRequestInFlight = false; + mRequestInFlightLock.notify(); + } + } /** * Proceed with the authorization with the given credentials * + * May be called on the UI thread, rather than the WebCore thread. + * * @param username The username to use for authentication * @param password The password to use for authentication */ public void proceed(String username, String password) { + if (handleResponseForSynchronousRequest(username, password)) { + signalRequestComplete(); + return; + } Message msg = obtainMessage(AUTH_PROCEED); msg.getData().putString("username", username); msg.getData().putString("password", password); sendMessage(msg); + signalRequestComplete(); } /** * Cancel the authorization request + * + * May be called on the UI thread, rather than the WebCore thread. + * */ public void cancel() { + if (handleResponseForSynchronousRequest(null, null)) { + signalRequestComplete(); + return; + } sendMessage(obtainMessage(AUTH_CANCEL)); + signalRequestComplete(); } /** @@ -132,6 +187,34 @@ public class HttpAuthHandler extends Handler { * authentication request */ /* package */ void handleAuthRequest(LoadListener loader) { + // The call to proxy.onReceivedHttpAuthRequest() may be asynchronous. If + // the request is synchronous, we must block here until we have a + // response. + if (loader.isSynchronous()) { + // If there's a request in flight, wait for it to complete. The + // response will queue a message on this thread. + waitForRequestToComplete(); + // Make a request to the proxy for this request, jumping the queue. + // We use the queue so that the loader is present in + // useHttpAuthUsernamePassword(). + synchronized (mLoaderQueue) { + mLoaderQueue.addFirst(loader); + } + processNextLoader(); + // Wait for this request to complete. + waitForRequestToComplete(); + // Pop the loader from the queue. + synchronized (mLoaderQueue) { + assert(mLoaderQueue.peek() == loader); + mLoaderQueue.poll(); + } + // Call back. + loader.handleAuthResponse(mUsername, mPassword); + // The message queued by the response from the last asynchronous + // request, if present, will start the next request. + return; + } + boolean processNext = false; synchronized (mLoaderQueue) { @@ -146,6 +229,21 @@ public class HttpAuthHandler extends Handler { } /** + * Wait for the request in flight, if any, to complete + */ + private void waitForRequestToComplete() { + synchronized (mRequestInFlightLock) { + while (mRequestInFlight) { + try { + mRequestInFlightLock.wait(); + } catch(InterruptedException e) { + Log.e(LOGTAG, "Interrupted while waiting for request to complete"); + } + } + } + } + + /** * Process the next loader in the queue (helper method) */ private void processNextLoader() { @@ -154,6 +252,11 @@ public class HttpAuthHandler extends Handler { loader = mLoaderQueue.peek(); } if (loader != null) { + synchronized (mRequestInFlightLock) { + assert(mRequestInFlight == false); + mRequestInFlight = true; + } + CallbackProxy proxy = loader.getFrame().getCallbackProxy(); String hostname = loader.proxyAuthenticate() ? |
