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
This commit is contained in:
@@ -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) {
|
||||
@@ -145,6 +228,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)
|
||||
*/
|
||||
@@ -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() ?
|
||||
|
||||
Reference in New Issue
Block a user