254 lines
8.9 KiB
Java
Executable File
254 lines
8.9 KiB
Java
Executable File
// Copyright 2012 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
package org.chromium.android_webview;
|
|
|
|
import android.content.ContentValues;
|
|
import android.content.Context;
|
|
import android.database.Cursor;
|
|
import android.database.sqlite.SQLiteDatabase;
|
|
import android.database.sqlite.SQLiteException;
|
|
import android.util.Log;
|
|
|
|
/**
|
|
* This database is used to support WebView's setHttpAuthUsernamePassword and
|
|
* getHttpAuthUsernamePassword methods, and WebViewDatabase's clearHttpAuthUsernamePassword and
|
|
* hasHttpAuthUsernamePassword methods.
|
|
*
|
|
* While this class is intended to be used as a singleton, this property is not enforced in this
|
|
* layer, primarily for ease of testing. To line up with the classic implementation and behavior,
|
|
* there is no specific handling and reporting when SQL errors occur.
|
|
*
|
|
* Note on thread-safety: As per the classic implementation, most API functions have thread safety
|
|
* provided by the underlying SQLiteDatabase instance. The exception is database opening: this
|
|
* is handled in the dedicated background thread, which also provides a performance gain
|
|
* if triggered early on (e.g. as a side effect of CookieSyncManager.createInstance() call),
|
|
* sufficiently in advance of the first blocking usage of the API.
|
|
*/
|
|
public class HttpAuthDatabase {
|
|
|
|
private static final String LOGTAG = "HttpAuthDatabase";
|
|
|
|
private static final int DATABASE_VERSION = 1;
|
|
|
|
private SQLiteDatabase mDatabase = null;
|
|
|
|
private static final String ID_COL = "_id";
|
|
|
|
private static final String[] ID_PROJECTION = new String[] {
|
|
ID_COL
|
|
};
|
|
|
|
// column id strings for "httpauth" table
|
|
private static final String HTTPAUTH_TABLE_NAME = "httpauth";
|
|
private static final String HTTPAUTH_HOST_COL = "host";
|
|
private static final String HTTPAUTH_REALM_COL = "realm";
|
|
private static final String HTTPAUTH_USERNAME_COL = "username";
|
|
private static final String HTTPAUTH_PASSWORD_COL = "password";
|
|
|
|
/**
|
|
* Initially false until the background thread completes.
|
|
*/
|
|
private boolean mInitialized = false;
|
|
|
|
private final Object mInitializedLock = new Object();
|
|
|
|
/**
|
|
* Create an instance of HttpAuthDatabase for the named file, and kick-off background
|
|
* initialization of that database.
|
|
*
|
|
* @param context the Context to use for opening the database
|
|
* @param databaseFile Name of the file to be initialized.
|
|
*/
|
|
public HttpAuthDatabase(final Context context, final String databaseFile) {
|
|
new Thread() {
|
|
@Override
|
|
public void run() {
|
|
initOnBackgroundThread(context, databaseFile);
|
|
}
|
|
}.start();
|
|
}
|
|
|
|
/**
|
|
* Initializes the databases and notifies any callers waiting on waitForInit.
|
|
*
|
|
* @param context the Context to use for opening the database
|
|
* @param databaseFile Name of the file to be initialized.
|
|
*/
|
|
private void initOnBackgroundThread(Context context, String databaseFile) {
|
|
synchronized (mInitializedLock) {
|
|
if (mInitialized) {
|
|
return;
|
|
}
|
|
|
|
initDatabase(context, databaseFile);
|
|
|
|
// Thread done, notify.
|
|
mInitialized = true;
|
|
mInitializedLock.notifyAll();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Opens the database, and upgrades it if necessary.
|
|
*
|
|
* @param context the Context to use for opening the database
|
|
* @param databaseFile Name of the file to be initialized.
|
|
*/
|
|
private void initDatabase(Context context, String databaseFile) {
|
|
try {
|
|
mDatabase = context.openOrCreateDatabase(databaseFile, 0, null);
|
|
} catch (SQLiteException e) {
|
|
// try again by deleting the old db and create a new one
|
|
if (context.deleteDatabase(databaseFile)) {
|
|
mDatabase = context.openOrCreateDatabase(databaseFile, 0, null);
|
|
}
|
|
}
|
|
|
|
if (mDatabase == null) {
|
|
// Not much we can do to recover at this point
|
|
Log.e(LOGTAG, "Unable to open or create " + databaseFile);
|
|
return;
|
|
}
|
|
|
|
if (mDatabase.getVersion() != DATABASE_VERSION) {
|
|
mDatabase.beginTransactionNonExclusive();
|
|
try {
|
|
createTable();
|
|
mDatabase.setTransactionSuccessful();
|
|
} finally {
|
|
mDatabase.endTransaction();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void createTable() {
|
|
mDatabase.execSQL("CREATE TABLE " + HTTPAUTH_TABLE_NAME
|
|
+ " (" + ID_COL + " INTEGER PRIMARY KEY, "
|
|
+ HTTPAUTH_HOST_COL + " TEXT, " + HTTPAUTH_REALM_COL
|
|
+ " TEXT, " + HTTPAUTH_USERNAME_COL + " TEXT, "
|
|
+ HTTPAUTH_PASSWORD_COL + " TEXT," + " UNIQUE ("
|
|
+ HTTPAUTH_HOST_COL + ", " + HTTPAUTH_REALM_COL
|
|
+ ") ON CONFLICT REPLACE);");
|
|
|
|
mDatabase.setVersion(DATABASE_VERSION);
|
|
}
|
|
|
|
/**
|
|
* Waits for the background initialization thread to complete and check the database creation
|
|
* status.
|
|
*
|
|
* @return true if the database was initialized, false otherwise
|
|
*/
|
|
private boolean waitForInit() {
|
|
synchronized (mInitializedLock) {
|
|
while (!mInitialized) {
|
|
try {
|
|
mInitializedLock.wait();
|
|
} catch (InterruptedException e) {
|
|
Log.e(LOGTAG, "Caught exception while checking initialization", e);
|
|
}
|
|
}
|
|
}
|
|
return mDatabase != null;
|
|
}
|
|
|
|
/**
|
|
* Sets the HTTP authentication password. Tuple (HTTPAUTH_HOST_COL, HTTPAUTH_REALM_COL,
|
|
* HTTPAUTH_USERNAME_COL) is unique.
|
|
*
|
|
* @param host the host for the password
|
|
* @param realm the realm for the password
|
|
* @param username the username for the password.
|
|
* @param password the password
|
|
*/
|
|
public void setHttpAuthUsernamePassword(String host, String realm, String username,
|
|
String password) {
|
|
if (host == null || realm == null || !waitForInit()) {
|
|
return;
|
|
}
|
|
|
|
final ContentValues c = new ContentValues();
|
|
c.put(HTTPAUTH_HOST_COL, host);
|
|
c.put(HTTPAUTH_REALM_COL, realm);
|
|
c.put(HTTPAUTH_USERNAME_COL, username);
|
|
c.put(HTTPAUTH_PASSWORD_COL, password);
|
|
mDatabase.insert(HTTPAUTH_TABLE_NAME, HTTPAUTH_HOST_COL, c);
|
|
}
|
|
|
|
/**
|
|
* Retrieves the HTTP authentication username and password for a given host and realm pair. If
|
|
* there are multiple username/password combinations for a host/realm, only the first one will
|
|
* be returned.
|
|
*
|
|
* @param host the host the password applies to
|
|
* @param realm the realm the password applies to
|
|
* @return a String[] if found where String[0] is username (which can be null) and
|
|
* String[1] is password. Null is returned if it can't find anything.
|
|
*/
|
|
public String[] getHttpAuthUsernamePassword(String host, String realm) {
|
|
if (host == null || realm == null || !waitForInit()) {
|
|
return null;
|
|
}
|
|
|
|
final String[] columns = new String[] {
|
|
HTTPAUTH_USERNAME_COL, HTTPAUTH_PASSWORD_COL
|
|
};
|
|
final String selection = "(" + HTTPAUTH_HOST_COL + " == ?) AND " +
|
|
"(" + HTTPAUTH_REALM_COL + " == ?)";
|
|
|
|
String[] ret = null;
|
|
Cursor cursor = null;
|
|
try {
|
|
cursor = mDatabase.query(HTTPAUTH_TABLE_NAME, columns, selection,
|
|
new String[] { host, realm }, null, null, null);
|
|
if (cursor.moveToFirst()) {
|
|
ret = new String[] {
|
|
cursor.getString(cursor.getColumnIndex(HTTPAUTH_USERNAME_COL)),
|
|
cursor.getString(cursor.getColumnIndex(HTTPAUTH_PASSWORD_COL)),
|
|
};
|
|
}
|
|
} catch (IllegalStateException e) {
|
|
Log.e(LOGTAG, "getHttpAuthUsernamePassword", e);
|
|
} finally {
|
|
if (cursor != null) cursor.close();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Determines if there are any HTTP authentication passwords saved.
|
|
*
|
|
* @return true if there are passwords saved
|
|
*/
|
|
public boolean hasHttpAuthUsernamePassword() {
|
|
if (!waitForInit()) {
|
|
return false;
|
|
}
|
|
|
|
Cursor cursor = null;
|
|
boolean ret = false;
|
|
try {
|
|
cursor = mDatabase.query(HTTPAUTH_TABLE_NAME, ID_PROJECTION, null, null, null, null,
|
|
null);
|
|
ret = cursor.moveToFirst();
|
|
} catch (IllegalStateException e) {
|
|
Log.e(LOGTAG, "hasEntries", e);
|
|
} finally {
|
|
if (cursor != null) cursor.close();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Clears the HTTP authentication password database.
|
|
*/
|
|
public void clearHttpAuthUsernamePassword() {
|
|
if (!waitForInit()) {
|
|
return;
|
|
}
|
|
mDatabase.delete(HTTPAUTH_TABLE_NAME, null, null);
|
|
}
|
|
}
|