diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
commit | 9066cfe9886ac131c34d59ed0e2d287b0e3c0087 (patch) | |
tree | d88beb88001f2482911e3d28e43833b50e4b4e97 /core/java/android/webkit/SslErrorHandler.java | |
parent | d83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (diff) | |
download | frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.zip frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.gz frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/android/webkit/SslErrorHandler.java')
-rw-r--r-- | core/java/android/webkit/SslErrorHandler.java | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/core/java/android/webkit/SslErrorHandler.java b/core/java/android/webkit/SslErrorHandler.java new file mode 100644 index 0000000..115434a --- /dev/null +++ b/core/java/android/webkit/SslErrorHandler.java @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.webkit; + +import junit.framework.Assert; + +import android.net.http.SslError; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.util.Config; +import android.util.Log; + +import java.util.LinkedList; +import java.util.ListIterator; + +/** + * SslErrorHandler: class responsible for handling SSL errors. This class is + * passed as a parameter to BrowserCallback.displaySslErrorDialog and is meant + * to receive the user's response. + */ +public class SslErrorHandler extends Handler { + /* One problem here is that there may potentially be multiple SSL errors + * coming from mutiple loaders. Therefore, we keep a queue of loaders + * that have SSL-related problems and process errors one by one in the + * order they were received. + */ + + private static final String LOGTAG = "network"; + + /** + * Network. + */ + private Network mNetwork; + + /** + * Queue of loaders that experience SSL-related problems. + */ + private LinkedList<LoadListener> mLoaderQueue; + + /** + * SSL error preference table. + */ + private Bundle mSslPrefTable; + + // Message id for handling the response + private final int HANDLE_RESPONSE = 100; + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case HANDLE_RESPONSE: + handleSslErrorResponse(msg.arg1 == 1); + fastProcessQueuedSslErrors(); + break; + } + } + + /** + * Creates a new error handler with an empty loader queue. + */ + /* package */ SslErrorHandler(Network network) { + mNetwork = network; + + mLoaderQueue = new LinkedList<LoadListener>(); + mSslPrefTable = new Bundle(); + } + + /** + * Saves this handler's state into a map. + * @return True iff succeeds. + */ + /* package */ boolean saveState(Bundle outState) { + boolean success = (outState != null); + if (success) { + // TODO? + outState.putBundle("ssl-error-handler", mSslPrefTable); + } + + return success; + } + + /** + * Restores this handler's state from a map. + * @return True iff succeeds. + */ + /* package */ boolean restoreState(Bundle inState) { + boolean success = (inState != null); + if (success) { + success = inState.containsKey("ssl-error-handler"); + if (success) { + mSslPrefTable = inState.getBundle("ssl-error-handler"); + } + } + + return success; + } + + /** + * Clears SSL error preference table. + */ + /* package */ synchronized void clear() { + mSslPrefTable.clear(); + } + + /** + * Resets the SSL error handler, removes all loaders that + * share the same BrowserFrame. + */ + /* package */ synchronized void reset(BrowserFrame frame) { + ListIterator<LoadListener> i = mLoaderQueue.listIterator(0); + while (i.hasNext()) { + LoadListener loader = i.next(); + if (frame == loader.getFrame()) { + i.remove(); + } + } + } + + /** + * Handles SSL error(s) on the way up to the user. + */ + /* package */ synchronized void handleSslErrorRequest(LoadListener loader) { + if (Config.LOGV) { + Log.v(LOGTAG, "SslErrorHandler.handleSslErrorRequest(): " + + "url=" + loader.url()); + } + + if (!loader.cancelled()) { + mLoaderQueue.offer(loader); + if (loader == mLoaderQueue.peek()) { + fastProcessQueuedSslErrors(); + } + } + } + + /** + * Processes queued SSL-error confirmation requests in + * a tight loop while there is no need to ask the user. + */ + /* package */void fastProcessQueuedSslErrors() { + while (processNextLoader()); + } + + /** + * Processes the next loader in the queue. + * @return True iff should proceed to processing the + * following loader in the queue + */ + private synchronized boolean processNextLoader() { + LoadListener loader = mLoaderQueue.peek(); + if (loader != null) { + // if this loader has been cancelled + if (loader.cancelled()) { + // go to the following loader in the queue + return true; + } + + SslError error = loader.sslError(); + + if (Config.DEBUG) { + Assert.assertNotNull(error); + } + + int primary = error.getPrimaryError(); + String host = loader.host(); + + if (Config.DEBUG) { + Assert.assertTrue(host != null && primary != 0); + } + + if (mSslPrefTable.containsKey(host)) { + if (primary <= mSslPrefTable.getInt(host)) { + handleSslErrorResponse(true); + return true; + } + } + + // if we do not have information on record, ask + // the user (display a dialog) + CallbackProxy proxy = loader.getFrame().getCallbackProxy(); + proxy.onReceivedSslError(this, error); + } + + // the queue must be empty, stop + return false; + } + + /** + * Proceed with the SSL certificate. + */ + public void proceed() { + sendMessage(obtainMessage(HANDLE_RESPONSE, 1, 0)); + } + + /** + * Cancel this request and all pending requests for the WebView that had + * the error. + */ + public void cancel() { + sendMessage(obtainMessage(HANDLE_RESPONSE, 0, 0)); + } + + /** + * Handles SSL error(s) on the way down from the user. + */ + /* package */ synchronized void handleSslErrorResponse(boolean proceed) { + LoadListener loader = mLoaderQueue.poll(); + if (Config.DEBUG) { + Assert.assertNotNull(loader); + } + + if (Config.LOGV) { + Log.v(LOGTAG, "SslErrorHandler.handleSslErrorResponse():" + + " proceed: " + proceed + + " url:" + loader.url()); + } + + if (!loader.cancelled()) { + if (proceed) { + // update the user's SSL error preference table + int primary = loader.sslError().getPrimaryError(); + String host = loader.host(); + + if (Config.DEBUG) { + Assert.assertTrue(host != null && primary != 0); + } + boolean hasKey = mSslPrefTable.containsKey(host); + if (!hasKey || + primary > mSslPrefTable.getInt(host)) { + mSslPrefTable.putInt(host, new Integer(primary)); + } + + loader.handleSslErrorResponse(proceed); + } else { + loader.handleSslErrorResponse(proceed); + mNetwork.resetHandlersAndStopLoading(loader.getFrame()); + } + } + } +} |