Remove Google-specific (or only-used-by-Google-code) classes.
Fix a small typo in Context javadoc.
This commit is contained in:
@ -1314,7 +1314,7 @@ public abstract class Context {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Use with {@link #getSystemService} to retrieve a
|
* Use with {@link #getSystemService} to retrieve a
|
||||||
* {@blink android.appwidget.AppWidgetManager} for accessing AppWidgets.
|
* {@link android.appwidget.AppWidgetManager} for accessing AppWidgets.
|
||||||
*
|
*
|
||||||
* @hide
|
* @hide
|
||||||
* @see #getSystemService
|
* @see #getSystemService
|
||||||
@ -1323,7 +1323,7 @@ public abstract class Context {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Use with {@link #getSystemService} to retrieve an
|
* Use with {@link #getSystemService} to retrieve an
|
||||||
* {@blink android.backup.IBackupManager IBackupManager} for communicating
|
* {@link android.backup.IBackupManager IBackupManager} for communicating
|
||||||
* with the backup mechanism.
|
* with the backup mechanism.
|
||||||
* @hide
|
* @hide
|
||||||
*
|
*
|
||||||
@ -1333,7 +1333,7 @@ public abstract class Context {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Use with {@link #getSystemService} to retrieve a
|
* Use with {@link #getSystemService} to retrieve a
|
||||||
* {@blink android.os.DropBox DropBox} instance for recording
|
* {@link android.os.DropBox DropBox} instance for recording
|
||||||
* diagnostic logs.
|
* diagnostic logs.
|
||||||
* @see #getSystemService
|
* @see #getSystemService
|
||||||
*/
|
*/
|
||||||
|
@ -1,289 +0,0 @@
|
|||||||
// Copyright 2009 The Android Open Source Project
|
|
||||||
|
|
||||||
package com.android.internal.net;
|
|
||||||
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.SQLException;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import org.apache.commons.codec.binary.Base64;
|
|
||||||
import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLSession;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook into harmony SSL cache to persist the SSL sessions.
|
|
||||||
*
|
|
||||||
* Current implementation is suitable for saving a small number of hosts -
|
|
||||||
* like google services. It can be extended with expiration and more features
|
|
||||||
* to support more hosts.
|
|
||||||
*
|
|
||||||
* {@hide}
|
|
||||||
*/
|
|
||||||
public class DbSSLSessionCache implements SSLClientSessionCache {
|
|
||||||
private static final String TAG = "DbSSLSessionCache";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Table where sessions are stored.
|
|
||||||
*/
|
|
||||||
public static final String SSL_CACHE_TABLE = "ssl_sessions";
|
|
||||||
|
|
||||||
private static final String SSL_CACHE_ID = "_id";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Key is host:port - port is not optional.
|
|
||||||
*/
|
|
||||||
private static final String SSL_CACHE_HOSTPORT = "hostport";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base64-encoded DER value of the session.
|
|
||||||
*/
|
|
||||||
private static final String SSL_CACHE_SESSION = "session";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Time when the record was added - should be close to the time
|
|
||||||
* of the initial session negotiation.
|
|
||||||
*/
|
|
||||||
private static final String SSL_CACHE_TIME_SEC = "time_sec";
|
|
||||||
|
|
||||||
public static final String DATABASE_NAME = "ssl_sessions.db";
|
|
||||||
|
|
||||||
public static final int DATABASE_VERSION = 2;
|
|
||||||
|
|
||||||
/** public for testing
|
|
||||||
*/
|
|
||||||
public static final int SSL_CACHE_ID_COL = 0;
|
|
||||||
public static final int SSL_CACHE_HOSTPORT_COL = 1;
|
|
||||||
public static final int SSL_CACHE_SESSION_COL = 2;
|
|
||||||
public static final int SSL_CACHE_TIME_SEC_COL = 3;
|
|
||||||
|
|
||||||
public static final int MAX_CACHE_SIZE = 256;
|
|
||||||
|
|
||||||
private final Map<String, byte[]> mExternalCache =
|
|
||||||
new HashMap<String, byte[]>();
|
|
||||||
|
|
||||||
|
|
||||||
private DatabaseHelper mDatabaseHelper;
|
|
||||||
|
|
||||||
private boolean mNeedsCacheLoad = true;
|
|
||||||
|
|
||||||
public static final String[] PROJECTION = new String[] {
|
|
||||||
SSL_CACHE_ID,
|
|
||||||
SSL_CACHE_HOSTPORT,
|
|
||||||
SSL_CACHE_SESSION,
|
|
||||||
SSL_CACHE_TIME_SEC
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final Map<String,DbSSLSessionCache> sInstances =
|
|
||||||
new HashMap<String,DbSSLSessionCache>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a singleton instance of the DbSSLSessionCache that should be used for this
|
|
||||||
* context's package.
|
|
||||||
*
|
|
||||||
* @param context The context that should be used for getting/creating the singleton instance.
|
|
||||||
* @return The singleton instance for the context's package.
|
|
||||||
*/
|
|
||||||
public static synchronized DbSSLSessionCache getInstanceForPackage(Context context) {
|
|
||||||
String packageName = context.getPackageName();
|
|
||||||
if (sInstances.containsKey(packageName)) {
|
|
||||||
return sInstances.get(packageName);
|
|
||||||
}
|
|
||||||
DbSSLSessionCache cache = new DbSSLSessionCache(context);
|
|
||||||
sInstances.put(packageName, cache);
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a SslSessionCache instance, using the specified context to
|
|
||||||
* initialize the database.
|
|
||||||
*
|
|
||||||
* This constructor will use the default database - created for the application
|
|
||||||
* context.
|
|
||||||
*
|
|
||||||
* @param activityContext
|
|
||||||
*/
|
|
||||||
private DbSSLSessionCache(Context activityContext) {
|
|
||||||
Context appContext = activityContext.getApplicationContext();
|
|
||||||
mDatabaseHelper = new DatabaseHelper(appContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a SslSessionCache that uses a specific database.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param database
|
|
||||||
*/
|
|
||||||
public DbSSLSessionCache(DatabaseHelper database) {
|
|
||||||
this.mDatabaseHelper = database;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putSessionData(SSLSession session, byte[] der) {
|
|
||||||
if (mDatabaseHelper == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
synchronized (this.getClass()) {
|
|
||||||
SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
|
|
||||||
if (mExternalCache.size() == MAX_CACHE_SIZE) {
|
|
||||||
// remove oldest.
|
|
||||||
// TODO: check if the new one is in cached already ( i.e. update ).
|
|
||||||
Cursor byTime = mDatabaseHelper.getReadableDatabase().query(SSL_CACHE_TABLE,
|
|
||||||
PROJECTION, null, null, null, null, SSL_CACHE_TIME_SEC);
|
|
||||||
if (byTime.moveToFirst()) {
|
|
||||||
// TODO: can I do byTime.deleteRow() ?
|
|
||||||
String hostPort = byTime.getString(SSL_CACHE_HOSTPORT_COL);
|
|
||||||
db.delete(SSL_CACHE_TABLE,
|
|
||||||
SSL_CACHE_HOSTPORT + "= ?" , new String[] { hostPort });
|
|
||||||
mExternalCache.remove(hostPort);
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "No rows found");
|
|
||||||
// something is wrong, clear it
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Serialize native session to standard DER encoding
|
|
||||||
long t0 = System.currentTimeMillis();
|
|
||||||
|
|
||||||
String b64 = new String(Base64.encodeBase64(der));
|
|
||||||
String key = session.getPeerHost() + ":" + session.getPeerPort();
|
|
||||||
|
|
||||||
ContentValues values = new ContentValues();
|
|
||||||
values.put(SSL_CACHE_HOSTPORT, key);
|
|
||||||
values.put(SSL_CACHE_SESSION, b64);
|
|
||||||
values.put(SSL_CACHE_TIME_SEC, System.currentTimeMillis() / 1000);
|
|
||||||
|
|
||||||
mExternalCache.put(key, der);
|
|
||||||
|
|
||||||
try {
|
|
||||||
db.insert(SSL_CACHE_TABLE, null /*nullColumnHack */ , values);
|
|
||||||
} catch(SQLException ex) {
|
|
||||||
// Ignore - nothing we can do to recover, and caller shouldn't
|
|
||||||
// be affected.
|
|
||||||
Log.w(TAG, "Ignoring SQL exception when caching session", ex);
|
|
||||||
}
|
|
||||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
|
||||||
long t1 = System.currentTimeMillis();
|
|
||||||
Log.d(TAG, "New SSL session " + session.getPeerHost() +
|
|
||||||
" DER len: " + der.length + " " + (t1 - t0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getSessionData(String host, int port) {
|
|
||||||
// Current (simple) implementation does a single lookup to DB, then saves
|
|
||||||
// all entries to the cache.
|
|
||||||
|
|
||||||
// This works for google services - i.e. small number of certs.
|
|
||||||
// If we extend this to all processes - we should hold a separate cache
|
|
||||||
// or do lookups to DB each time.
|
|
||||||
if (mDatabaseHelper == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
synchronized(this.getClass()) {
|
|
||||||
if (mNeedsCacheLoad) {
|
|
||||||
// Don't try to load again, if something is wrong on the first
|
|
||||||
// request it'll likely be wrong each time.
|
|
||||||
mNeedsCacheLoad = false;
|
|
||||||
long t0 = System.currentTimeMillis();
|
|
||||||
|
|
||||||
Cursor cur = null;
|
|
||||||
try {
|
|
||||||
cur = mDatabaseHelper.getReadableDatabase().query(SSL_CACHE_TABLE,
|
|
||||||
PROJECTION, null, null, null, null, null);
|
|
||||||
if (cur.moveToFirst()) {
|
|
||||||
do {
|
|
||||||
String hostPort = cur.getString(SSL_CACHE_HOSTPORT_COL);
|
|
||||||
String value = cur.getString(SSL_CACHE_SESSION_COL);
|
|
||||||
|
|
||||||
if (hostPort == null || value == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// TODO: blob support ?
|
|
||||||
byte[] der = Base64.decodeBase64(value.getBytes());
|
|
||||||
mExternalCache.put(hostPort, der);
|
|
||||||
} while (cur.moveToNext());
|
|
||||||
|
|
||||||
}
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
Log.d(TAG, "Error loading SSL cached entries ", ex);
|
|
||||||
} finally {
|
|
||||||
if (cur != null) {
|
|
||||||
cur.close();
|
|
||||||
}
|
|
||||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
|
||||||
long t1 = System.currentTimeMillis();
|
|
||||||
Log.d(TAG, "LOADED CACHED SSL " + (t1 - t0) + " ms");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String key = host + ":" + port;
|
|
||||||
|
|
||||||
return mExternalCache.get(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the database and internal state.
|
|
||||||
* Used for testing or to free space.
|
|
||||||
*/
|
|
||||||
public void clear() {
|
|
||||||
synchronized(this) {
|
|
||||||
try {
|
|
||||||
mExternalCache.clear();
|
|
||||||
mNeedsCacheLoad = true;
|
|
||||||
mDatabaseHelper.getWritableDatabase().delete(SSL_CACHE_TABLE,
|
|
||||||
null, null);
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
Log.d(TAG, "Error removing SSL cached entries ", ex);
|
|
||||||
// ignore - nothing we can do about it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getSessionData(byte[] id) {
|
|
||||||
// We support client side only - the cache will do nothing for
|
|
||||||
// server-side sessions.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Visible for testing.
|
|
||||||
*/
|
|
||||||
public static class DatabaseHelper extends SQLiteOpenHelper {
|
|
||||||
|
|
||||||
public DatabaseHelper(Context context) {
|
|
||||||
super(context, DATABASE_NAME, null /* factory */, DATABASE_VERSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(SQLiteDatabase db) {
|
|
||||||
db.execSQL("CREATE TABLE " + SSL_CACHE_TABLE + " (" +
|
|
||||||
SSL_CACHE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
|
|
||||||
SSL_CACHE_HOSTPORT + " TEXT UNIQUE ON CONFLICT REPLACE," +
|
|
||||||
SSL_CACHE_SESSION + " TEXT," +
|
|
||||||
SSL_CACHE_TIME_SEC + " INTEGER" +
|
|
||||||
");");
|
|
||||||
|
|
||||||
// No index - we load on startup, index would slow down inserts.
|
|
||||||
// If we want to scale this to lots of rows - we could use
|
|
||||||
// index, but then we'll hit DB a bit too often ( including
|
|
||||||
// negative hits )
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
|
||||||
db.execSQL("DROP TABLE IF EXISTS " + SSL_CACHE_TABLE );
|
|
||||||
onCreate(db);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 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 com.google.android.net;
|
|
||||||
|
|
||||||
import android.net.TrafficStats;
|
|
||||||
import android.os.SystemClock;
|
|
||||||
import android.os.SystemProperties;
|
|
||||||
import android.util.EventLog;
|
|
||||||
import org.apache.http.HttpEntity;
|
|
||||||
import org.apache.http.entity.HttpEntityWrapper;
|
|
||||||
|
|
||||||
import java.io.FilterInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
|
|
||||||
public class NetworkStatsEntity extends HttpEntityWrapper {
|
|
||||||
|
|
||||||
private static final int HTTP_STATS_EVENT = 52001;
|
|
||||||
|
|
||||||
private class NetworkStatsInputStream extends FilterInputStream {
|
|
||||||
|
|
||||||
public NetworkStatsInputStream(InputStream wrapped) {
|
|
||||||
super(wrapped);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
try {
|
|
||||||
super.close();
|
|
||||||
} finally {
|
|
||||||
long processingTime = SystemClock.elapsedRealtime() - mProcessingStartTime;
|
|
||||||
long tx = TrafficStats.getUidTxBytes(mUid);
|
|
||||||
long rx = TrafficStats.getUidRxBytes(mUid);
|
|
||||||
|
|
||||||
EventLog.writeEvent(HTTP_STATS_EVENT, mUa, mResponseLatency, processingTime,
|
|
||||||
tx - mStartTx, rx - mStartRx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final String mUa;
|
|
||||||
private final int mUid;
|
|
||||||
private final long mStartTx;
|
|
||||||
private final long mStartRx;
|
|
||||||
private final long mResponseLatency;
|
|
||||||
private final long mProcessingStartTime;
|
|
||||||
|
|
||||||
public NetworkStatsEntity(HttpEntity orig, String ua,
|
|
||||||
int uid, long startTx, long startRx, long responseLatency,
|
|
||||||
long processingStartTime) {
|
|
||||||
super(orig);
|
|
||||||
this.mUa = ua;
|
|
||||||
this.mUid = uid;
|
|
||||||
this.mStartTx = startTx;
|
|
||||||
this.mStartRx = startRx;
|
|
||||||
this.mResponseLatency = responseLatency;
|
|
||||||
this.mProcessingStartTime = processingStartTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean shouldLogNetworkStats() {
|
|
||||||
return "1".equals(SystemProperties.get("googlehttpclient.logstats"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream getContent() throws IOException {
|
|
||||||
InputStream orig = super.getContent();
|
|
||||||
return new NetworkStatsInputStream(orig);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
package com.google.android.net;
|
|
||||||
|
|
||||||
import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
|
|
||||||
import org.apache.harmony.xnet.provider.jsse.FileClientSessionCache;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.provider.Settings;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import com.android.internal.net.DbSSLSessionCache;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory that returns the appropriate implementation of a {@link SSLClientSessionCache} based
|
|
||||||
* on gservices.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
// TODO: return a proxied implementation that is updated as the gservices value changes.
|
|
||||||
public final class SSLClientSessionCacheFactory {
|
|
||||||
|
|
||||||
private static final String TAG = "SSLClientSessionCacheFactory";
|
|
||||||
|
|
||||||
public static final String DB = "db";
|
|
||||||
public static final String FILE = "file";
|
|
||||||
|
|
||||||
// utility class
|
|
||||||
private SSLClientSessionCacheFactory() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new {@link SSLClientSessionCache} based on the persistent cache that's specified,
|
|
||||||
* if any, in gservices. If no cache is specified, returns null.
|
|
||||||
* @param context The application context used for the per-process persistent cache.
|
|
||||||
* @return A new {@link SSLClientSessionCache}, or null if no persistent cache is configured.
|
|
||||||
*/
|
|
||||||
public static SSLClientSessionCache getCache(Context context) {
|
|
||||||
String type = Settings.Gservices.getString(context.getContentResolver(),
|
|
||||||
Settings.Gservices.SSL_SESSION_CACHE);
|
|
||||||
|
|
||||||
if (type != null) {
|
|
||||||
if (DB.equals(type)) {
|
|
||||||
return DbSSLSessionCache.getInstanceForPackage(context);
|
|
||||||
} else if (FILE.equals(type)) {
|
|
||||||
File dir = context.getFilesDir();
|
|
||||||
File cacheDir = new File(dir, "sslcache");
|
|
||||||
if (!cacheDir.exists()) {
|
|
||||||
cacheDir.mkdir();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return FileClientSessionCache.usingDirectory(cacheDir);
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
Log.w(TAG, "Unable to create FileClientSessionCache in " + cacheDir.getName(), ioe);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "Ignoring unrecognized type: '" + type + "'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,236 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 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 com.google.android.net;
|
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.provider.Checkin;
|
|
||||||
import android.provider.Settings;
|
|
||||||
import android.util.Config;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A set of rules rewriting and blocking URLs. Used to offer a point of
|
|
||||||
* control for redirecting HTTP requests, often to the Android proxy server.
|
|
||||||
*
|
|
||||||
* <p>Each rule has the following format:
|
|
||||||
*
|
|
||||||
* <pre><em>url-prefix</em> [REWRITE <em>new-prefix</em>] [BLOCK]</pre>
|
|
||||||
*
|
|
||||||
* <p>Any URL which starts with <em>url-prefix</em> will trigger the rule.
|
|
||||||
* If BLOCK is specified, requests to that URL will be blocked and fail.
|
|
||||||
* If REWRITE is specified, the matching prefix will be removed and replaced
|
|
||||||
* with <em>new-prefix</em>. (If both are specified, BLOCK wins.) Case is
|
|
||||||
* insensitive for the REWRITE and BLOCK keywords, but sensitive for URLs.
|
|
||||||
*
|
|
||||||
* <p>In Gservices, the value of any key that starts with "url:" will be
|
|
||||||
* interpreted as a rule. The full name of the key is unimportant (but can
|
|
||||||
* be used to document the intent of the rule, and must be unique).
|
|
||||||
* Example gservices keys:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* url:use_proxy_for_calendar = "http://www.google.com/calendar/ REWRITE http://android.clients.google.com/proxy/calendar/"
|
|
||||||
* url:stop_crash_reports = "http://android.clients.google.com/crash/ BLOCK"
|
|
||||||
* url:use_ssl_for_contacts = "http://www.google.com/m8/ REWRITE https://www.google.com/m8/"
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
public class UrlRules {
|
|
||||||
public static final String TAG = "UrlRules";
|
|
||||||
public static final boolean LOCAL_LOGV = Config.LOGV || false;
|
|
||||||
|
|
||||||
/** Thrown when the rewrite rules can't be parsed. */
|
|
||||||
public static class RuleFormatException extends Exception {
|
|
||||||
public RuleFormatException(String msg) { super(msg); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A single rule specifying actions for URLs matching a certain prefix. */
|
|
||||||
public static class Rule implements Comparable {
|
|
||||||
/** Name assigned to the rule (for logging and debugging). */
|
|
||||||
public final String mName;
|
|
||||||
|
|
||||||
/** Prefix required to match this rule. */
|
|
||||||
public final String mPrefix;
|
|
||||||
|
|
||||||
/** Text to replace mPrefix with (null to leave alone). */
|
|
||||||
public final String mRewrite;
|
|
||||||
|
|
||||||
/** True if matching URLs should be blocked. */
|
|
||||||
public final boolean mBlock;
|
|
||||||
|
|
||||||
/** Default rule that does nothing. */
|
|
||||||
public static final Rule DEFAULT = new Rule();
|
|
||||||
|
|
||||||
/** Parse a rewrite rule as given in a Gservices value. */
|
|
||||||
public Rule(String name, String rule) throws RuleFormatException {
|
|
||||||
mName = name;
|
|
||||||
String[] words = PATTERN_SPACE_PLUS.split(rule);
|
|
||||||
if (words.length == 0) throw new RuleFormatException("Empty rule");
|
|
||||||
|
|
||||||
mPrefix = words[0];
|
|
||||||
String rewrite = null;
|
|
||||||
boolean block = false;
|
|
||||||
for (int pos = 1; pos < words.length; ) {
|
|
||||||
String word = words[pos].toLowerCase();
|
|
||||||
if (word.equals("rewrite") && pos + 1 < words.length) {
|
|
||||||
rewrite = words[pos + 1];
|
|
||||||
pos += 2;
|
|
||||||
} else if (word.equals("block")) {
|
|
||||||
block = true;
|
|
||||||
pos += 1;
|
|
||||||
} else {
|
|
||||||
throw new RuleFormatException("Illegal rule: " + rule);
|
|
||||||
}
|
|
||||||
// TODO: Parse timeout specifications, etc.
|
|
||||||
}
|
|
||||||
|
|
||||||
mRewrite = rewrite;
|
|
||||||
mBlock = block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create the default Rule. */
|
|
||||||
private Rule() {
|
|
||||||
mName = "DEFAULT";
|
|
||||||
mPrefix = "";
|
|
||||||
mRewrite = null;
|
|
||||||
mBlock = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply the rule to a particular URL (assumed to match the rule).
|
|
||||||
* @param url to rewrite or modify.
|
|
||||||
* @return modified URL, or null if the URL is blocked.
|
|
||||||
*/
|
|
||||||
public String apply(String url) {
|
|
||||||
if (mBlock) {
|
|
||||||
return null;
|
|
||||||
} else if (mRewrite != null) {
|
|
||||||
return mRewrite + url.substring(mPrefix.length());
|
|
||||||
} else {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** More generic rules are greater than more specific rules. */
|
|
||||||
public int compareTo(Object o) {
|
|
||||||
return ((Rule) o).mPrefix.compareTo(mPrefix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Cached rule set from Gservices. */
|
|
||||||
private static UrlRules sCachedRules = new UrlRules(new Rule[] {});
|
|
||||||
|
|
||||||
private static final Pattern PATTERN_SPACE_PLUS = Pattern.compile(" +");
|
|
||||||
private static final Pattern RULE_PATTERN = Pattern.compile("\\W");
|
|
||||||
|
|
||||||
/** Gservices digest when sCachedRules was cached. */
|
|
||||||
private static String sCachedDigest = null;
|
|
||||||
|
|
||||||
/** Currently active set of Rules. */
|
|
||||||
private final Rule[] mRules;
|
|
||||||
|
|
||||||
/** Regular expression with one capturing group for each Rule. */
|
|
||||||
private final Pattern mPattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a rewriter from an array of Rules. Normally used only for
|
|
||||||
* testing. Instead, use {@link #getRules} to get rules from Gservices.
|
|
||||||
* @param rules to use.
|
|
||||||
*/
|
|
||||||
public UrlRules(Rule[] rules) {
|
|
||||||
// Sort the rules to put the most specific rules first.
|
|
||||||
Arrays.sort(rules);
|
|
||||||
|
|
||||||
// Construct a regular expression, escaping all the prefix strings.
|
|
||||||
StringBuilder pattern = new StringBuilder("(");
|
|
||||||
for (int i = 0; i < rules.length; ++i) {
|
|
||||||
if (i > 0) pattern.append(")|(");
|
|
||||||
pattern.append(RULE_PATTERN.matcher(rules[i].mPrefix).replaceAll("\\\\$0"));
|
|
||||||
}
|
|
||||||
mPattern = Pattern.compile(pattern.append(")").toString());
|
|
||||||
mRules = rules;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Match a string against every Rule and find one that matches.
|
|
||||||
* @param uri to match against the Rules in the rewriter.
|
|
||||||
* @return the most specific matching Rule, or Rule.DEFAULT if none match.
|
|
||||||
*/
|
|
||||||
public Rule matchRule(String url) {
|
|
||||||
Matcher matcher = mPattern.matcher(url);
|
|
||||||
if (matcher.lookingAt()) {
|
|
||||||
for (int i = 0; i < mRules.length; ++i) {
|
|
||||||
if (matcher.group(i + 1) != null) {
|
|
||||||
return mRules[i]; // Rules are sorted most specific first.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Rule.DEFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the (possibly cached) UrlRules based on the rules in Gservices.
|
|
||||||
* @param resolver to use for accessing the Gservices database.
|
|
||||||
* @return an updated UrlRules instance
|
|
||||||
*/
|
|
||||||
public static synchronized UrlRules getRules(ContentResolver resolver) {
|
|
||||||
String digest = Settings.Gservices.getString(resolver,
|
|
||||||
Settings.Gservices.PROVISIONING_DIGEST);
|
|
||||||
if (sCachedDigest != null && sCachedDigest.equals(digest)) {
|
|
||||||
// The digest is the same, so the rules are the same.
|
|
||||||
if (LOCAL_LOGV) Log.v(TAG, "Using cached rules for digest: " + digest);
|
|
||||||
return sCachedRules;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LOCAL_LOGV) Log.v(TAG, "Scanning for Gservices \"url:*\" rules");
|
|
||||||
Cursor cursor = resolver.query(Settings.Gservices.CONTENT_URI,
|
|
||||||
new String[] {
|
|
||||||
Settings.Gservices.NAME,
|
|
||||||
Settings.Gservices.VALUE
|
|
||||||
},
|
|
||||||
Settings.Gservices.NAME + " like \"url:%\"", null,
|
|
||||||
Settings.Gservices.NAME);
|
|
||||||
try {
|
|
||||||
ArrayList<Rule> rules = new ArrayList<Rule>();
|
|
||||||
while (cursor.moveToNext()) {
|
|
||||||
try {
|
|
||||||
String name = cursor.getString(0).substring(4); // "url:X"
|
|
||||||
String value = cursor.getString(1);
|
|
||||||
if (value == null || value.length() == 0) continue;
|
|
||||||
if (LOCAL_LOGV) Log.v(TAG, " Rule " + name + ": " + value);
|
|
||||||
rules.add(new Rule(name, value));
|
|
||||||
} catch (RuleFormatException e) {
|
|
||||||
// Oops, Gservices has an invalid rule! Skip it.
|
|
||||||
Log.e(TAG, "Invalid rule from Gservices", e);
|
|
||||||
Checkin.logEvent(resolver,
|
|
||||||
Checkin.Events.Tag.GSERVICES_ERROR, e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sCachedRules = new UrlRules(rules.toArray(new Rule[rules.size()]));
|
|
||||||
sCachedDigest = digest;
|
|
||||||
if (LOCAL_LOGV) Log.v(TAG, "New rules stored for digest: " + digest);
|
|
||||||
} finally {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return sCachedRules;
|
|
||||||
}
|
|
||||||
}
|
|
@ -691,8 +691,6 @@ com.google.android.mms.ContentType
|
|||||||
com.google.android.mms.pdu.CharacterSets
|
com.google.android.mms.pdu.CharacterSets
|
||||||
com.google.android.mms.pdu.PduPart
|
com.google.android.mms.pdu.PduPart
|
||||||
com.google.android.mms.pdu.PduPersister
|
com.google.android.mms.pdu.PduPersister
|
||||||
com.google.android.net.UrlRules
|
|
||||||
com.google.android.net.UrlRules$Rule
|
|
||||||
com.ibm.icu4jni.charset.CharsetDecoderICU
|
com.ibm.icu4jni.charset.CharsetDecoderICU
|
||||||
com.ibm.icu4jni.charset.CharsetEncoderICU
|
com.ibm.icu4jni.charset.CharsetEncoderICU
|
||||||
com.ibm.icu4jni.charset.CharsetICU
|
com.ibm.icu4jni.charset.CharsetICU
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
package com.android.unit_tests;
|
|
||||||
|
|
||||||
import junit.framework.TestSuite;
|
|
||||||
|
|
||||||
public class ApacheHttpTests {
|
|
||||||
public static TestSuite suite() {
|
|
||||||
TestSuite suite = new TestSuite(ApacheHttpTests.class.getName());
|
|
||||||
|
|
||||||
suite.addTestSuite(TestHttpService.class);
|
|
||||||
|
|
||||||
return suite;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
package com.android.unit_tests;
|
|
||||||
|
|
||||||
import com.google.android.net.SSLClientSessionCacheFactory;
|
|
||||||
import com.android.internal.net.DbSSLSessionCache;
|
|
||||||
import android.test.AndroidTestCase;
|
|
||||||
import android.test.suitebuilder.annotation.MediumTest;
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.provider.Settings;
|
|
||||||
import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unit test for {@link SSLClientSessionCacheFactory}.
|
|
||||||
*/
|
|
||||||
@MediumTest
|
|
||||||
public final class SSLClientSessionCacheFactoryTest extends AndroidTestCase {
|
|
||||||
|
|
||||||
protected void tearDown() throws Exception {
|
|
||||||
setSslSessionCacheValue(getContext(), "");
|
|
||||||
super.tearDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void setSslSessionCacheValue(Context context, String value) {
|
|
||||||
ContentResolver resolver = context.getContentResolver();
|
|
||||||
Settings.Gservices.putString(resolver, Settings.Gservices.SSL_SESSION_CACHE, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static SSLClientSessionCache getCache(Context context, String type) {
|
|
||||||
setSslSessionCacheValue(context, type);
|
|
||||||
return SSLClientSessionCacheFactory.getCache(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testGetDbCache() throws Exception {
|
|
||||||
Context context = getContext();
|
|
||||||
SSLClientSessionCache cache = getCache(context, "db");
|
|
||||||
assertNotNull(cache);
|
|
||||||
assertTrue(cache instanceof DbSSLSessionCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testGetFileCache() throws Exception {
|
|
||||||
Context context = getContext();
|
|
||||||
SSLClientSessionCache cache = getCache(context, "file");
|
|
||||||
assertNotNull(cache);
|
|
||||||
// yuck =)
|
|
||||||
assertEquals("org.apache.harmony.xnet.provider.jsse.FileClientSessionCache$Impl",
|
|
||||||
cache.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testGetNoCache() throws Exception {
|
|
||||||
Context context = getContext();
|
|
||||||
SSLClientSessionCache cache = getCache(context, "none");
|
|
||||||
assertNull(cache);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,207 +0,0 @@
|
|||||||
/*
|
|
||||||
* $HeadURL: http://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha6/module-main/src/test/java/org/apache/http/mockup/TestHttpServer.java $
|
|
||||||
* $Revision: 576077 $
|
|
||||||
* $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $
|
|
||||||
*
|
|
||||||
* ====================================================================
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you 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.
|
|
||||||
* ====================================================================
|
|
||||||
*
|
|
||||||
* This software consists of voluntary contributions made by many
|
|
||||||
* individuals on behalf of the Apache Software Foundation. For more
|
|
||||||
* information on the Apache Software Foundation, please see
|
|
||||||
* <http://www.apache.org/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.unit_tests;
|
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
|
|
||||||
import org.apache.http.ConnectionClosedException;
|
|
||||||
import org.apache.http.ConnectionReuseStrategy;
|
|
||||||
import org.apache.http.HttpException;
|
|
||||||
import org.apache.http.HttpResponseFactory;
|
|
||||||
import org.apache.http.HttpServerConnection;
|
|
||||||
import org.apache.http.impl.DefaultConnectionReuseStrategy;
|
|
||||||
import org.apache.http.impl.DefaultHttpResponseFactory;
|
|
||||||
import org.apache.http.impl.DefaultHttpServerConnection;
|
|
||||||
import org.apache.http.params.BasicHttpParams;
|
|
||||||
import org.apache.http.params.CoreConnectionPNames;
|
|
||||||
import org.apache.http.params.HttpParams;
|
|
||||||
import org.apache.http.params.CoreProtocolPNames;
|
|
||||||
import org.apache.http.protocol.BasicHttpProcessor;
|
|
||||||
import org.apache.http.protocol.HttpContext;
|
|
||||||
import org.apache.http.protocol.BasicHttpContext;
|
|
||||||
import org.apache.http.protocol.HttpExpectationVerifier;
|
|
||||||
import org.apache.http.protocol.HttpRequestHandler;
|
|
||||||
import org.apache.http.protocol.HttpRequestHandlerRegistry;
|
|
||||||
import org.apache.http.protocol.HttpService;
|
|
||||||
import org.apache.http.protocol.ResponseConnControl;
|
|
||||||
import org.apache.http.protocol.ResponseContent;
|
|
||||||
import org.apache.http.protocol.ResponseDate;
|
|
||||||
import org.apache.http.protocol.ResponseServer;
|
|
||||||
|
|
||||||
public class TestHttpServer {
|
|
||||||
|
|
||||||
private final HttpParams params;
|
|
||||||
private final BasicHttpProcessor httpproc;
|
|
||||||
private final ConnectionReuseStrategy connStrategy;
|
|
||||||
private final HttpResponseFactory responseFactory;
|
|
||||||
private final HttpRequestHandlerRegistry reqistry;
|
|
||||||
private final ServerSocket serversocket;
|
|
||||||
|
|
||||||
private HttpExpectationVerifier expectationVerifier;
|
|
||||||
|
|
||||||
private Thread listener;
|
|
||||||
private volatile boolean shutdown;
|
|
||||||
|
|
||||||
public TestHttpServer() throws IOException {
|
|
||||||
super();
|
|
||||||
this.params = new BasicHttpParams();
|
|
||||||
this.params
|
|
||||||
.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 20000)
|
|
||||||
.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
|
|
||||||
.setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
|
|
||||||
.setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
|
|
||||||
.setParameter(CoreProtocolPNames.ORIGIN_SERVER, "TEST-SERVER/1.1");
|
|
||||||
this.httpproc = new BasicHttpProcessor();
|
|
||||||
this.httpproc.addInterceptor(new ResponseDate());
|
|
||||||
this.httpproc.addInterceptor(new ResponseServer());
|
|
||||||
this.httpproc.addInterceptor(new ResponseContent());
|
|
||||||
this.httpproc.addInterceptor(new ResponseConnControl());
|
|
||||||
this.connStrategy = new DefaultConnectionReuseStrategy();
|
|
||||||
this.responseFactory = new DefaultHttpResponseFactory();
|
|
||||||
this.reqistry = new HttpRequestHandlerRegistry();
|
|
||||||
this.serversocket = new ServerSocket(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerHandler(
|
|
||||||
final String pattern,
|
|
||||||
final HttpRequestHandler handler) {
|
|
||||||
this.reqistry.register(pattern, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExpectationVerifier(final HttpExpectationVerifier expectationVerifier) {
|
|
||||||
this.expectationVerifier = expectationVerifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
private HttpServerConnection acceptConnection() throws IOException {
|
|
||||||
Socket socket = this.serversocket.accept();
|
|
||||||
DefaultHttpServerConnection conn = new DefaultHttpServerConnection();
|
|
||||||
conn.bind(socket, this.params);
|
|
||||||
return conn;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPort() {
|
|
||||||
return this.serversocket.getLocalPort();
|
|
||||||
}
|
|
||||||
|
|
||||||
public InetAddress getInetAddress() {
|
|
||||||
return this.serversocket.getInetAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start() {
|
|
||||||
if (this.listener != null) {
|
|
||||||
throw new IllegalStateException("Listener already running");
|
|
||||||
}
|
|
||||||
this.listener = new Thread(new Runnable() {
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
while (!shutdown && !Thread.interrupted()) {
|
|
||||||
try {
|
|
||||||
// Set up HTTP connection
|
|
||||||
HttpServerConnection conn = acceptConnection();
|
|
||||||
// Set up the HTTP service
|
|
||||||
HttpService httpService = new HttpService(
|
|
||||||
httpproc,
|
|
||||||
connStrategy,
|
|
||||||
responseFactory);
|
|
||||||
httpService.setParams(params);
|
|
||||||
httpService.setExpectationVerifier(expectationVerifier);
|
|
||||||
httpService.setHandlerResolver(reqistry);
|
|
||||||
|
|
||||||
// Start worker thread
|
|
||||||
Thread t = new WorkerThread(httpService, conn);
|
|
||||||
t.setDaemon(true);
|
|
||||||
t.start();
|
|
||||||
} catch (InterruptedIOException ex) {
|
|
||||||
break;
|
|
||||||
} catch (IOException e) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
this.listener.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void shutdown() {
|
|
||||||
if (this.shutdown) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.shutdown = true;
|
|
||||||
try {
|
|
||||||
this.serversocket.close();
|
|
||||||
} catch (IOException ignore) {}
|
|
||||||
this.listener.interrupt();
|
|
||||||
try {
|
|
||||||
this.listener.join(1000);
|
|
||||||
} catch (InterruptedException ignore) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class WorkerThread extends Thread {
|
|
||||||
|
|
||||||
private final HttpService httpservice;
|
|
||||||
private final HttpServerConnection conn;
|
|
||||||
|
|
||||||
public WorkerThread(
|
|
||||||
final HttpService httpservice,
|
|
||||||
final HttpServerConnection conn) {
|
|
||||||
super();
|
|
||||||
this.httpservice = httpservice;
|
|
||||||
this.conn = conn;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
HttpContext context = new BasicHttpContext(null);
|
|
||||||
try {
|
|
||||||
while (!Thread.interrupted() && this.conn.isOpen()) {
|
|
||||||
this.httpservice.handleRequest(this.conn, context);
|
|
||||||
}
|
|
||||||
} catch (ConnectionClosedException ex) {
|
|
||||||
} catch (IOException ex) {
|
|
||||||
System.err.println("I/O error: " + ex.getMessage());
|
|
||||||
} catch (HttpException ex) {
|
|
||||||
System.err.println("Unrecoverable HTTP protocol violation: " + ex.getMessage());
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
this.conn.shutdown();
|
|
||||||
} catch (IOException ignore) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,608 +0,0 @@
|
|||||||
/*
|
|
||||||
* $HeadURL: http://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha6/module-main/src/test/java/org/apache/http/protocol/TestHttpServiceAndExecutor.java $
|
|
||||||
* $Revision: 576073 $
|
|
||||||
* $Date: 2007-09-16 03:53:13 -0700 (Sun, 16 Sep 2007) $
|
|
||||||
* ====================================================================
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you 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.
|
|
||||||
* ====================================================================
|
|
||||||
*
|
|
||||||
* This software consists of voluntary contributions made by many
|
|
||||||
* individuals on behalf of the Apache Software Foundation. For more
|
|
||||||
* information on the Apache Software Foundation, please see
|
|
||||||
* <http://www.apache.org/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.unit_tests;
|
|
||||||
|
|
||||||
import org.apache.http.protocol.HttpExpectationVerifier;
|
|
||||||
import org.apache.http.protocol.HttpRequestHandler;
|
|
||||||
import android.test.PerformanceTestCase;
|
|
||||||
import android.test.suitebuilder.annotation.LargeTest;
|
|
||||||
import android.test.suitebuilder.annotation.MediumTest;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
import org.apache.http.Header;
|
|
||||||
import org.apache.http.HttpConnectionMetrics;
|
|
||||||
import org.apache.http.HttpEntity;
|
|
||||||
import org.apache.http.HttpEntityEnclosingRequest;
|
|
||||||
import org.apache.http.HttpException;
|
|
||||||
import org.apache.http.HttpHost;
|
|
||||||
import org.apache.http.HttpRequest;
|
|
||||||
import org.apache.http.HttpResponse;
|
|
||||||
import org.apache.http.HttpStatus;
|
|
||||||
import org.apache.http.HttpVersion;
|
|
||||||
import org.apache.http.entity.ByteArrayEntity;
|
|
||||||
import org.apache.http.entity.StringEntity;
|
|
||||||
import org.apache.http.impl.DefaultHttpClientConnection;
|
|
||||||
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
|
|
||||||
import org.apache.http.message.BasicHttpRequest;
|
|
||||||
import org.apache.http.params.CoreProtocolPNames;
|
|
||||||
import org.apache.http.protocol.HttpContext;
|
|
||||||
import org.apache.http.util.EncodingUtils;
|
|
||||||
import org.apache.http.util.EntityUtils;
|
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
public class TestHttpService extends TestCase implements PerformanceTestCase {
|
|
||||||
|
|
||||||
public boolean isPerformanceOnly() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int startPerformance(Intermediates intermediates) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TestHttpServer server;
|
|
||||||
private TestHttpClient client;
|
|
||||||
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
this.server = new TestHttpServer();
|
|
||||||
this.client = new TestHttpClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void tearDown() throws Exception {
|
|
||||||
if (server != null) {
|
|
||||||
this.server.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This test case executes a series of simple GET requests
|
|
||||||
*/
|
|
||||||
@LargeTest
|
|
||||||
public void testSimpleBasicHttpRequests() throws Exception {
|
|
||||||
|
|
||||||
int reqNo = 20;
|
|
||||||
|
|
||||||
Random rnd = new Random();
|
|
||||||
|
|
||||||
// Prepare some random data
|
|
||||||
final List testData = new ArrayList(reqNo);
|
|
||||||
for (int i = 0; i < reqNo; i++) {
|
|
||||||
int size = rnd.nextInt(5000);
|
|
||||||
byte[] data = new byte[size];
|
|
||||||
rnd.nextBytes(data);
|
|
||||||
testData.add(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the server-side request handler
|
|
||||||
this.server.registerHandler("*", new HttpRequestHandler() {
|
|
||||||
|
|
||||||
public void handle(
|
|
||||||
final HttpRequest request,
|
|
||||||
final HttpResponse response,
|
|
||||||
final HttpContext context) throws HttpException, IOException {
|
|
||||||
|
|
||||||
String s = request.getRequestLine().getUri();
|
|
||||||
if (s.startsWith("/?")) {
|
|
||||||
s = s.substring(2);
|
|
||||||
}
|
|
||||||
int index = Integer.parseInt(s);
|
|
||||||
byte[] data = (byte []) testData.get(index);
|
|
||||||
ByteArrayEntity entity = new ByteArrayEntity(data);
|
|
||||||
response.setEntity(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
this.server.start();
|
|
||||||
|
|
||||||
DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
|
|
||||||
HttpHost host = new HttpHost("localhost", this.server.getPort());
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (int r = 0; r < reqNo; r++) {
|
|
||||||
if (!conn.isOpen()) {
|
|
||||||
Socket socket = new Socket(host.getHostName(), host.getPort());
|
|
||||||
conn.bind(socket, this.client.getParams());
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicHttpRequest get = new BasicHttpRequest("GET", "/?" + r);
|
|
||||||
HttpResponse response = this.client.execute(get, host, conn);
|
|
||||||
byte[] received = EntityUtils.toByteArray(response.getEntity());
|
|
||||||
byte[] expected = (byte[]) testData.get(r);
|
|
||||||
|
|
||||||
assertEquals(expected.length, received.length);
|
|
||||||
for (int i = 0; i < expected.length; i++) {
|
|
||||||
assertEquals(expected[i], received[i]);
|
|
||||||
}
|
|
||||||
if (!this.client.keepAlive(response)) {
|
|
||||||
conn.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Verify the connection metrics
|
|
||||||
HttpConnectionMetrics cm = conn.getMetrics();
|
|
||||||
assertEquals(reqNo, cm.getRequestCount());
|
|
||||||
assertEquals(reqNo, cm.getResponseCount());
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
conn.close();
|
|
||||||
this.server.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This test case executes a series of simple POST requests with content length
|
|
||||||
* delimited content.
|
|
||||||
*/
|
|
||||||
@LargeTest
|
|
||||||
public void testSimpleHttpPostsWithContentLength() throws Exception {
|
|
||||||
|
|
||||||
int reqNo = 20;
|
|
||||||
|
|
||||||
Random rnd = new Random();
|
|
||||||
|
|
||||||
// Prepare some random data
|
|
||||||
List testData = new ArrayList(reqNo);
|
|
||||||
for (int i = 0; i < reqNo; i++) {
|
|
||||||
int size = rnd.nextInt(5000);
|
|
||||||
byte[] data = new byte[size];
|
|
||||||
rnd.nextBytes(data);
|
|
||||||
testData.add(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the server-side request handler
|
|
||||||
this.server.registerHandler("*", new HttpRequestHandler() {
|
|
||||||
|
|
||||||
public void handle(
|
|
||||||
final HttpRequest request,
|
|
||||||
final HttpResponse response,
|
|
||||||
final HttpContext context) throws HttpException, IOException {
|
|
||||||
|
|
||||||
if (request instanceof HttpEntityEnclosingRequest) {
|
|
||||||
HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity();
|
|
||||||
byte[] data = EntityUtils.toByteArray(incoming);
|
|
||||||
|
|
||||||
ByteArrayEntity outgoing = new ByteArrayEntity(data);
|
|
||||||
outgoing.setChunked(false);
|
|
||||||
response.setEntity(outgoing);
|
|
||||||
} else {
|
|
||||||
StringEntity outgoing = new StringEntity("No content");
|
|
||||||
response.setEntity(outgoing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
this.server.start();
|
|
||||||
|
|
||||||
DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
|
|
||||||
HttpHost host = new HttpHost("localhost", this.server.getPort());
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (int r = 0; r < reqNo; r++) {
|
|
||||||
if (!conn.isOpen()) {
|
|
||||||
Socket socket = new Socket(host.getHostName(), host.getPort());
|
|
||||||
conn.bind(socket, this.client.getParams());
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/");
|
|
||||||
byte[] data = (byte[]) testData.get(r);
|
|
||||||
ByteArrayEntity outgoing = new ByteArrayEntity(data);
|
|
||||||
post.setEntity(outgoing);
|
|
||||||
|
|
||||||
HttpResponse response = this.client.execute(post, host, conn);
|
|
||||||
byte[] received = EntityUtils.toByteArray(response.getEntity());
|
|
||||||
byte[] expected = (byte[]) testData.get(r);
|
|
||||||
|
|
||||||
assertEquals(expected.length, received.length);
|
|
||||||
for (int i = 0; i < expected.length; i++) {
|
|
||||||
assertEquals(expected[i], received[i]);
|
|
||||||
}
|
|
||||||
if (!this.client.keepAlive(response)) {
|
|
||||||
conn.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Verify the connection metrics
|
|
||||||
HttpConnectionMetrics cm = conn.getMetrics();
|
|
||||||
assertEquals(reqNo, cm.getRequestCount());
|
|
||||||
assertEquals(reqNo, cm.getResponseCount());
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
conn.close();
|
|
||||||
this.server.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This test case executes a series of simple POST requests with chunk
|
|
||||||
* coded content content.
|
|
||||||
*/
|
|
||||||
@LargeTest
|
|
||||||
public void testSimpleHttpPostsChunked() throws Exception {
|
|
||||||
|
|
||||||
int reqNo = 20;
|
|
||||||
|
|
||||||
Random rnd = new Random();
|
|
||||||
|
|
||||||
// Prepare some random data
|
|
||||||
List testData = new ArrayList(reqNo);
|
|
||||||
for (int i = 0; i < reqNo; i++) {
|
|
||||||
int size = rnd.nextInt(20000);
|
|
||||||
byte[] data = new byte[size];
|
|
||||||
rnd.nextBytes(data);
|
|
||||||
testData.add(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the server-side request handler
|
|
||||||
this.server.registerHandler("*", new HttpRequestHandler() {
|
|
||||||
|
|
||||||
public void handle(
|
|
||||||
final HttpRequest request,
|
|
||||||
final HttpResponse response,
|
|
||||||
final HttpContext context) throws HttpException, IOException {
|
|
||||||
|
|
||||||
if (request instanceof HttpEntityEnclosingRequest) {
|
|
||||||
HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity();
|
|
||||||
byte[] data = EntityUtils.toByteArray(incoming);
|
|
||||||
|
|
||||||
ByteArrayEntity outgoing = new ByteArrayEntity(data);
|
|
||||||
outgoing.setChunked(true);
|
|
||||||
response.setEntity(outgoing);
|
|
||||||
} else {
|
|
||||||
StringEntity outgoing = new StringEntity("No content");
|
|
||||||
response.setEntity(outgoing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
this.server.start();
|
|
||||||
|
|
||||||
DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
|
|
||||||
HttpHost host = new HttpHost("localhost", this.server.getPort());
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (int r = 0; r < reqNo; r++) {
|
|
||||||
if (!conn.isOpen()) {
|
|
||||||
Socket socket = new Socket(host.getHostName(), host.getPort());
|
|
||||||
conn.bind(socket, this.client.getParams());
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/");
|
|
||||||
byte[] data = (byte[]) testData.get(r);
|
|
||||||
ByteArrayEntity outgoing = new ByteArrayEntity(data);
|
|
||||||
outgoing.setChunked(true);
|
|
||||||
post.setEntity(outgoing);
|
|
||||||
|
|
||||||
HttpResponse response = this.client.execute(post, host, conn);
|
|
||||||
byte[] received = EntityUtils.toByteArray(response.getEntity());
|
|
||||||
byte[] expected = (byte[]) testData.get(r);
|
|
||||||
|
|
||||||
assertEquals(expected.length, received.length);
|
|
||||||
for (int i = 0; i < expected.length; i++) {
|
|
||||||
assertEquals(expected[i], received[i]);
|
|
||||||
}
|
|
||||||
if (!this.client.keepAlive(response)) {
|
|
||||||
conn.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Verify the connection metrics
|
|
||||||
HttpConnectionMetrics cm = conn.getMetrics();
|
|
||||||
assertEquals(reqNo, cm.getRequestCount());
|
|
||||||
assertEquals(reqNo, cm.getResponseCount());
|
|
||||||
} finally {
|
|
||||||
conn.close();
|
|
||||||
this.server.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This test case executes a series of simple HTTP/1.0 POST requests.
|
|
||||||
*/
|
|
||||||
@LargeTest
|
|
||||||
public void testSimpleHttpPostsHTTP10() throws Exception {
|
|
||||||
|
|
||||||
int reqNo = 20;
|
|
||||||
|
|
||||||
Random rnd = new Random();
|
|
||||||
|
|
||||||
// Prepare some random data
|
|
||||||
List testData = new ArrayList(reqNo);
|
|
||||||
for (int i = 0; i < reqNo; i++) {
|
|
||||||
int size = rnd.nextInt(5000);
|
|
||||||
byte[] data = new byte[size];
|
|
||||||
rnd.nextBytes(data);
|
|
||||||
testData.add(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the server-side request handler
|
|
||||||
this.server.registerHandler("*", new HttpRequestHandler() {
|
|
||||||
|
|
||||||
public void handle(
|
|
||||||
final HttpRequest request,
|
|
||||||
final HttpResponse response,
|
|
||||||
final HttpContext context) throws HttpException, IOException {
|
|
||||||
|
|
||||||
if (request instanceof HttpEntityEnclosingRequest) {
|
|
||||||
HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity();
|
|
||||||
byte[] data = EntityUtils.toByteArray(incoming);
|
|
||||||
|
|
||||||
ByteArrayEntity outgoing = new ByteArrayEntity(data);
|
|
||||||
outgoing.setChunked(false);
|
|
||||||
response.setEntity(outgoing);
|
|
||||||
} else {
|
|
||||||
StringEntity outgoing = new StringEntity("No content");
|
|
||||||
response.setEntity(outgoing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
this.server.start();
|
|
||||||
|
|
||||||
// Set protocol level to HTTP/1.0
|
|
||||||
this.client.getParams().setParameter(
|
|
||||||
CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_0);
|
|
||||||
|
|
||||||
DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
|
|
||||||
HttpHost host = new HttpHost("localhost", this.server.getPort());
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (int r = 0; r < reqNo; r++) {
|
|
||||||
if (!conn.isOpen()) {
|
|
||||||
Socket socket = new Socket(host.getHostName(), host.getPort());
|
|
||||||
conn.bind(socket, this.client.getParams());
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/");
|
|
||||||
byte[] data = (byte[]) testData.get(r);
|
|
||||||
ByteArrayEntity outgoing = new ByteArrayEntity(data);
|
|
||||||
post.setEntity(outgoing);
|
|
||||||
|
|
||||||
HttpResponse response = this.client.execute(post, host, conn);
|
|
||||||
assertEquals(HttpVersion.HTTP_1_0, response.getStatusLine().getProtocolVersion());
|
|
||||||
byte[] received = EntityUtils.toByteArray(response.getEntity());
|
|
||||||
byte[] expected = (byte[]) testData.get(r);
|
|
||||||
|
|
||||||
assertEquals(expected.length, received.length);
|
|
||||||
for (int i = 0; i < expected.length; i++) {
|
|
||||||
assertEquals(expected[i], received[i]);
|
|
||||||
}
|
|
||||||
if (!this.client.keepAlive(response)) {
|
|
||||||
conn.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Verify the connection metrics
|
|
||||||
HttpConnectionMetrics cm = conn.getMetrics();
|
|
||||||
assertEquals(reqNo, cm.getRequestCount());
|
|
||||||
assertEquals(reqNo, cm.getResponseCount());
|
|
||||||
} finally {
|
|
||||||
conn.close();
|
|
||||||
this.server.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This test case executes a series of simple POST requests using
|
|
||||||
* the 'expect: continue' handshake.
|
|
||||||
*/
|
|
||||||
@LargeTest
|
|
||||||
public void testHttpPostsWithExpectContinue() throws Exception {
|
|
||||||
|
|
||||||
int reqNo = 20;
|
|
||||||
|
|
||||||
Random rnd = new Random();
|
|
||||||
|
|
||||||
// Prepare some random data
|
|
||||||
List testData = new ArrayList(reqNo);
|
|
||||||
for (int i = 0; i < reqNo; i++) {
|
|
||||||
int size = rnd.nextInt(5000);
|
|
||||||
byte[] data = new byte[size];
|
|
||||||
rnd.nextBytes(data);
|
|
||||||
testData.add(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the server-side request handler
|
|
||||||
this.server.registerHandler("*", new HttpRequestHandler() {
|
|
||||||
|
|
||||||
public void handle(
|
|
||||||
final HttpRequest request,
|
|
||||||
final HttpResponse response,
|
|
||||||
final HttpContext context) throws HttpException, IOException {
|
|
||||||
|
|
||||||
if (request instanceof HttpEntityEnclosingRequest) {
|
|
||||||
HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity();
|
|
||||||
byte[] data = EntityUtils.toByteArray(incoming);
|
|
||||||
|
|
||||||
ByteArrayEntity outgoing = new ByteArrayEntity(data);
|
|
||||||
outgoing.setChunked(true);
|
|
||||||
response.setEntity(outgoing);
|
|
||||||
} else {
|
|
||||||
StringEntity outgoing = new StringEntity("No content");
|
|
||||||
response.setEntity(outgoing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
this.server.start();
|
|
||||||
|
|
||||||
// Activate 'expect: continue' handshake
|
|
||||||
this.client.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, true);
|
|
||||||
|
|
||||||
DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
|
|
||||||
HttpHost host = new HttpHost("localhost", this.server.getPort());
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (int r = 0; r < reqNo; r++) {
|
|
||||||
if (!conn.isOpen()) {
|
|
||||||
Socket socket = new Socket(host.getHostName(), host.getPort());
|
|
||||||
conn.bind(socket, this.client.getParams());
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/");
|
|
||||||
byte[] data = (byte[]) testData.get(r);
|
|
||||||
ByteArrayEntity outgoing = new ByteArrayEntity(data);
|
|
||||||
outgoing.setChunked(true);
|
|
||||||
post.setEntity(outgoing);
|
|
||||||
|
|
||||||
HttpResponse response = this.client.execute(post, host, conn);
|
|
||||||
byte[] received = EntityUtils.toByteArray(response.getEntity());
|
|
||||||
byte[] expected = (byte[]) testData.get(r);
|
|
||||||
|
|
||||||
assertEquals(expected.length, received.length);
|
|
||||||
for (int i = 0; i < expected.length; i++) {
|
|
||||||
assertEquals(expected[i], received[i]);
|
|
||||||
}
|
|
||||||
if (!this.client.keepAlive(response)) {
|
|
||||||
conn.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Verify the connection metrics
|
|
||||||
HttpConnectionMetrics cm = conn.getMetrics();
|
|
||||||
assertEquals(reqNo, cm.getRequestCount());
|
|
||||||
assertEquals(reqNo, cm.getResponseCount());
|
|
||||||
} finally {
|
|
||||||
conn.close();
|
|
||||||
this.server.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This test case executes a series of simple POST requests that do not
|
|
||||||
* meet the target server expectations.
|
|
||||||
*/
|
|
||||||
@LargeTest
|
|
||||||
public void testHttpPostsWithExpectationVerification() throws Exception {
|
|
||||||
|
|
||||||
int reqNo = 3;
|
|
||||||
|
|
||||||
// Initialize the server-side request handler
|
|
||||||
this.server.registerHandler("*", new HttpRequestHandler() {
|
|
||||||
|
|
||||||
public void handle(
|
|
||||||
final HttpRequest request,
|
|
||||||
final HttpResponse response,
|
|
||||||
final HttpContext context) throws HttpException, IOException {
|
|
||||||
|
|
||||||
StringEntity outgoing = new StringEntity("No content");
|
|
||||||
response.setEntity(outgoing);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
this.server.setExpectationVerifier(new HttpExpectationVerifier() {
|
|
||||||
|
|
||||||
public void verify(
|
|
||||||
final HttpRequest request,
|
|
||||||
final HttpResponse response,
|
|
||||||
final HttpContext context) throws HttpException {
|
|
||||||
Header someheader = request.getFirstHeader("Secret");
|
|
||||||
if (someheader != null) {
|
|
||||||
int secretNumber;
|
|
||||||
try {
|
|
||||||
secretNumber = Integer.parseInt(someheader.getValue());
|
|
||||||
} catch (NumberFormatException ex) {
|
|
||||||
response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (secretNumber < 2) {
|
|
||||||
response.setStatusCode(HttpStatus.SC_EXPECTATION_FAILED);
|
|
||||||
ByteArrayEntity outgoing = new ByteArrayEntity(
|
|
||||||
EncodingUtils.getAsciiBytes("Wrong secret number"));
|
|
||||||
response.setEntity(outgoing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
this.server.start();
|
|
||||||
|
|
||||||
// Activate 'expect: continue' handshake
|
|
||||||
this.client.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, true);
|
|
||||||
|
|
||||||
DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
|
|
||||||
HttpHost host = new HttpHost("localhost", this.server.getPort());
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (int r = 0; r < reqNo; r++) {
|
|
||||||
if (!conn.isOpen()) {
|
|
||||||
Socket socket = new Socket(host.getHostName(), host.getPort());
|
|
||||||
conn.bind(socket, this.client.getParams());
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/");
|
|
||||||
post.addHeader("Secret", Integer.toString(r));
|
|
||||||
ByteArrayEntity outgoing = new ByteArrayEntity(
|
|
||||||
EncodingUtils.getAsciiBytes("No content"));
|
|
||||||
post.setEntity(outgoing);
|
|
||||||
|
|
||||||
HttpResponse response = this.client.execute(post, host, conn);
|
|
||||||
|
|
||||||
HttpEntity entity = response.getEntity();
|
|
||||||
assertNotNull(entity);
|
|
||||||
entity.consumeContent();
|
|
||||||
|
|
||||||
if (r < 2) {
|
|
||||||
assertEquals(HttpStatus.SC_EXPECTATION_FAILED, response.getStatusLine().getStatusCode());
|
|
||||||
} else {
|
|
||||||
assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.client.keepAlive(response)) {
|
|
||||||
conn.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Verify the connection metrics
|
|
||||||
HttpConnectionMetrics cm = conn.getMetrics();
|
|
||||||
assertEquals(reqNo, cm.getRequestCount());
|
|
||||||
assertEquals(reqNo, cm.getResponseCount());
|
|
||||||
} finally {
|
|
||||||
conn.close();
|
|
||||||
this.server.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,120 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 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 com.android.unit_tests;
|
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.provider.Settings;
|
|
||||||
import android.test.AndroidTestCase;
|
|
||||||
import android.test.suitebuilder.annotation.MediumTest;
|
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
|
||||||
|
|
||||||
import com.google.android.net.UrlRules;
|
|
||||||
import static com.google.android.net.UrlRules.Rule;
|
|
||||||
|
|
||||||
/** Test loading and matching URL rewrite rules for UrlRules. */
|
|
||||||
public class UrlRulesTest extends AndroidTestCase {
|
|
||||||
@SmallTest
|
|
||||||
public void testEmptyRules() {
|
|
||||||
UrlRules rules = new UrlRules(new Rule[] { });
|
|
||||||
assertTrue(rules.matchRule("http://foo.bar/") == Rule.DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SmallTest
|
|
||||||
public void testInvalidRule() throws Exception {
|
|
||||||
try {
|
|
||||||
new Rule("rule", "foo bar");
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Re-throw any exception except the one we're looking for.
|
|
||||||
if (!e.toString().contains("Illegal rule: foo bar")) throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SmallTest
|
|
||||||
public void testRewriteRule() throws UrlRules.RuleFormatException {
|
|
||||||
Rule rule = new Rule("test_rule",
|
|
||||||
"http://foo.bar/ rewrite http://bar.foo/");
|
|
||||||
assertEquals("test_rule", rule.mName);
|
|
||||||
assertEquals("http://foo.bar/", rule.mPrefix);
|
|
||||||
assertEquals("http://bar.foo/", rule.mRewrite);
|
|
||||||
assertFalse(rule.mBlock);
|
|
||||||
assertEquals("http://bar.foo/bat", rule.apply("http://foo.bar/bat"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SmallTest
|
|
||||||
public void testBlockRule() throws UrlRules.RuleFormatException {
|
|
||||||
Rule rule = new Rule("test_rule",
|
|
||||||
"http://foo.bar/ block");
|
|
||||||
assertEquals("test_rule", rule.mName);
|
|
||||||
assertEquals("http://foo.bar/", rule.mPrefix);
|
|
||||||
assertTrue(rule.mRewrite == null);
|
|
||||||
assertTrue(rule.mBlock);
|
|
||||||
assertTrue(rule.apply("http://foo.bar/bat") == null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SmallTest
|
|
||||||
public void testMatchRule() throws UrlRules.RuleFormatException {
|
|
||||||
UrlRules rules = new UrlRules(new Rule[] {
|
|
||||||
new Rule("12", "http://one.two/ rewrite http://buckle.my.shoe/"),
|
|
||||||
new Rule("34", "http://three.four/ rewrite http://close.the.door/"),
|
|
||||||
new Rule("56", "http://five.six/ rewrite http://pick.up.sticks/"),
|
|
||||||
});
|
|
||||||
|
|
||||||
assertTrue(rules.matchRule("https://one.two/") == Rule.DEFAULT);
|
|
||||||
assertTrue(rules.matchRule("http://one.two") == Rule.DEFAULT);
|
|
||||||
assertEquals("12", rules.matchRule("http://one.two/foo").mName);
|
|
||||||
|
|
||||||
String u = "http://five.six/bar";
|
|
||||||
assertEquals("http://pick.up.sticks/bar", rules.matchRule(u).apply(u));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SmallTest
|
|
||||||
public void testAmbiguousMatch() throws UrlRules.RuleFormatException {
|
|
||||||
// Rule is the longest match wins.
|
|
||||||
UrlRules rules = new UrlRules(new Rule[] {
|
|
||||||
new Rule("1", "http://xyz/one rewrite http://rewrite/"),
|
|
||||||
new Rule("123", "http://xyz/onetwothree rewrite http://rewrite/"),
|
|
||||||
new Rule("12", "http://xyz/onetwo rewrite http://rewrite/"),
|
|
||||||
});
|
|
||||||
|
|
||||||
assertEquals("1", rules.matchRule("http://xyz/one").mName);
|
|
||||||
assertEquals("1", rules.matchRule("http://xyz/one...").mName);
|
|
||||||
assertEquals("12", rules.matchRule("http://xyz/onetwo...").mName);
|
|
||||||
assertEquals("123", rules.matchRule("http://xyz/onetwothree...").mName);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
public void testGservicesRules() {
|
|
||||||
// TODO: use a MockContentProvider/MockContentResolver instead.
|
|
||||||
ContentResolver r = getContext().getContentResolver();
|
|
||||||
|
|
||||||
// Update the digest, so the UrlRules cache is reloaded.
|
|
||||||
Settings.Gservices.putString(r, "digest", "testGservicesRules");
|
|
||||||
Settings.Gservices.putString(r, "url:blank_test", "");
|
|
||||||
Settings.Gservices.putString(r, "url:test",
|
|
||||||
"http://foo.bar/ rewrite http://bar.foo/");
|
|
||||||
|
|
||||||
UrlRules rules = UrlRules.getRules(r); // Don't crash, please. :)
|
|
||||||
assertTrue(rules.matchRule("http://bar.foo/") == Rule.DEFAULT);
|
|
||||||
|
|
||||||
Rule rule = rules.matchRule("http://foo.bar/bat");
|
|
||||||
assertEquals("test", rule.mName);
|
|
||||||
assertEquals("http://foo.bar/", rule.mPrefix);
|
|
||||||
assertEquals("http://bar.foo/", rule.mRewrite);
|
|
||||||
assertFalse(rule.mBlock);
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user