Process synchronous requests in the same RequestQueue.

Use a dedicated Connection to process a synchronous request using the main
RequestQueue and on the WebCore thread.

HttpConnection, HttpsConnection, Connection:
    No need for ConnectionManager, just pass the proxy host to
    HttpsConnection. In Connection.clearPipe, empty should be set to true if the
    RequestFeeder does _not_ have a request for the host. I don't think that
    broke anything but it is incorrect.
ConnectionThread:
    Refactor the proxy selection into ConnectionManager.getConnection
RequestHandle:
    Add a new constructor that takes a Connection argument. Add processRequest
    to process a single request on that Connection.
RequestQueue:
    Add determine host to select between the request's host and the proxy. Add
    queueSynchronousRequest to make a new request that operates on a private
    connection. Add SyncFeeder to handle RequestFeeder.requeueRequest if the
    request fails.
Network: Use the new RequestQueue api to handle a synchronous request.

Bug: 1315832
This commit is contained in:
Patrick Scott
2009-10-01 15:54:46 -04:00
parent 18d1255ebe
commit 86806ce11a
7 changed files with 118 additions and 54 deletions

View File

@@ -94,7 +94,6 @@ abstract class Connection {
*/
private static final String HTTP_CONNECTION = "http.connection";
RequestQueue.ConnectionManager mConnectionManager;
RequestFeeder mRequestFeeder;
/**
@@ -104,11 +103,9 @@ abstract class Connection {
private byte[] mBuf;
protected Connection(Context context, HttpHost host,
RequestQueue.ConnectionManager connectionManager,
RequestFeeder requestFeeder) {
mContext = context;
mHost = host;
mConnectionManager = connectionManager;
mRequestFeeder = requestFeeder;
mCanPersist = false;
@@ -124,18 +121,15 @@ abstract class Connection {
* necessary
*/
static Connection getConnection(
Context context, HttpHost host,
RequestQueue.ConnectionManager connectionManager,
Context context, HttpHost host, HttpHost proxy,
RequestFeeder requestFeeder) {
if (host.getSchemeName().equals("http")) {
return new HttpConnection(context, host, connectionManager,
requestFeeder);
return new HttpConnection(context, host, requestFeeder);
}
// Otherwise, default to https
return new HttpsConnection(context, host, connectionManager,
requestFeeder);
return new HttpsConnection(context, host, proxy, requestFeeder);
}
/**
@@ -338,7 +332,7 @@ abstract class Connection {
mRequestFeeder.requeueRequest(tReq);
empty = false;
}
if (empty) empty = mRequestFeeder.haveRequest(mHost);
if (empty) empty = !mRequestFeeder.haveRequest(mHost);
}
return empty;
}

View File

@@ -108,24 +108,11 @@ class ConnectionThread extends Thread {
if (HttpLog.LOGV) HttpLog.v("ConnectionThread: new request " +
request.mHost + " " + request );
HttpHost proxy = mConnectionManager.getProxyHost();
HttpHost host;
if (false) {
// Allow https proxy
host = proxy == null ? request.mHost : proxy;
} else {
// Disallow https proxy -- tmob proxy server
// serves a request loop for https reqs
host = (proxy == null ||
request.mHost.getSchemeName().equals("https")) ?
request.mHost : proxy;
}
mConnection = mConnectionManager.getConnection(mContext, host);
mConnection = mConnectionManager.getConnection(mContext,
request.mHost);
mConnection.processRequests(request);
if (mConnection.getCanPersist()) {
if (!mConnectionManager.recycleConnection(host,
mConnection)) {
if (!mConnectionManager.recycleConnection(mConnection)) {
mConnection.closeConnection();
}
} else {

View File

@@ -35,9 +35,8 @@ import org.apache.http.params.HttpConnectionParams;
class HttpConnection extends Connection {
HttpConnection(Context context, HttpHost host,
RequestQueue.ConnectionManager connectionManager,
RequestFeeder requestFeeder) {
super(context, host, connectionManager, requestFeeder);
super(context, host, requestFeeder);
}
/**

View File

@@ -131,13 +131,16 @@ public class HttpsConnection extends Connection {
*/
private boolean mAborted = false;
// Used when connecting through a proxy.
private HttpHost mProxyHost;
/**
* Contructor for a https connection.
*/
HttpsConnection(Context context, HttpHost host,
RequestQueue.ConnectionManager connectionManager,
HttpsConnection(Context context, HttpHost host, HttpHost proxy,
RequestFeeder requestFeeder) {
super(context, host, connectionManager, requestFeeder);
super(context, host, requestFeeder);
mProxyHost = proxy;
}
/**
@@ -159,8 +162,7 @@ public class HttpsConnection extends Connection {
AndroidHttpClientConnection openConnection(Request req) throws IOException {
SSLSocket sslSock = null;
HttpHost proxyHost = mConnectionManager.getProxyHost();
if (proxyHost != null) {
if (mProxyHost != null) {
// If we have a proxy set, we first send a CONNECT request
// to the proxy; if the proxy returns 200 OK, we negotiate
// a secure connection to the target server via the proxy.
@@ -172,7 +174,7 @@ public class HttpsConnection extends Connection {
Socket proxySock = null;
try {
proxySock = new Socket
(proxyHost.getHostName(), proxyHost.getPort());
(mProxyHost.getHostName(), mProxyHost.getPort());
proxySock.setSoTimeout(60 * 1000);

View File

@@ -42,15 +42,13 @@ public class RequestHandle {
private WebAddress mUri;
private String mMethod;
private Map<String, String> mHeaders;
private RequestQueue mRequestQueue;
private Request mRequest;
private InputStream mBodyProvider;
private int mBodyLength;
private int mRedirectCount = 0;
// Used only with synchronous requests.
private Connection mConnection;
private final static String AUTHORIZATION_HEADER = "Authorization";
private final static String PROXY_AUTHORIZATION_HEADER = "Proxy-Authorization";
@@ -80,6 +78,19 @@ public class RequestHandle {
mRequest = request;
}
/**
* Creates a new request session with a given Connection. This connection
* is used during a synchronous load to handle this request.
*/
public RequestHandle(RequestQueue requestQueue, String url, WebAddress uri,
String method, Map<String, String> headers,
InputStream bodyProvider, int bodyLength, Request request,
Connection conn) {
this(requestQueue, url, uri, method, headers, bodyProvider, bodyLength,
request);
mConnection = conn;
}
/**
* Cancels this request
*/
@@ -262,6 +273,12 @@ public class RequestHandle {
mRequest.waitUntilComplete();
}
public void processRequest() {
if (mConnection != null) {
mConnection.processRequests(mRequest);
}
}
/**
* @return Digest-scheme authentication response.
*/

View File

@@ -171,16 +171,17 @@ public class RequestQueue implements RequestFeeder {
}
public Connection getConnection(Context context, HttpHost host) {
host = RequestQueue.this.determineHost(host);
Connection con = mIdleCache.getConnection(host);
if (con == null) {
mTotalConnection++;
con = Connection.getConnection(
mContext, host, this, RequestQueue.this);
con = Connection.getConnection(mContext, host, mProxyHost,
RequestQueue.this);
}
return con;
}
public boolean recycleConnection(HttpHost host, Connection connection) {
return mIdleCache.cacheConnection(host, connection);
public boolean recycleConnection(Connection connection) {
return mIdleCache.cacheConnection(connection.getHost(), connection);
}
}
@@ -342,6 +343,66 @@ public class RequestQueue implements RequestFeeder {
req);
}
private static class SyncFeeder implements RequestFeeder {
// This is used in the case where the request fails and needs to be
// requeued into the RequestFeeder.
private Request mRequest;
SyncFeeder() {
}
public Request getRequest() {
Request r = mRequest;
mRequest = null;
return r;
}
public Request getRequest(HttpHost host) {
return getRequest();
}
public boolean haveRequest(HttpHost host) {
return mRequest != null;
}
public void requeueRequest(Request r) {
mRequest = r;
}
}
public RequestHandle queueSynchronousRequest(String url, WebAddress uri,
String method, Map<String, String> headers,
EventHandler eventHandler, InputStream bodyProvider,
int bodyLength) {
if (HttpLog.LOGV) {
HttpLog.v("RequestQueue.dispatchSynchronousRequest " + uri);
}
HttpHost host = new HttpHost(uri.mHost, uri.mPort, uri.mScheme);
Request req = new Request(method, host, mProxyHost, uri.mPath,
bodyProvider, bodyLength, eventHandler, headers);
// Open a new connection that uses our special RequestFeeder
// implementation.
host = determineHost(host);
Connection conn = Connection.getConnection(mContext, host, mProxyHost,
new SyncFeeder());
// TODO: I would like to process the request here but LoadListener
// needs a RequestHandle to process some messages.
return new RequestHandle(this, url, uri, method, headers, bodyProvider,
bodyLength, req, conn);
}
// Chooses between the proxy and the request's host.
private HttpHost determineHost(HttpHost host) {
// There used to be a comment in ConnectionThread about t-mob's proxy
// being really bad about https. But, HttpsConnection actually looks
// for a proxy and connects through it anyway. I think that this check
// is still valid because if a site is https, we will use
// HttpsConnection rather than HttpConnection if the proxy address is
// not secure.
return (mProxyHost == null || "https".equals(host.getSchemeName()))
? host : mProxyHost;
}
/**
* @return true iff there are any non-active requests pending
*/
@@ -478,6 +539,6 @@ public class RequestQueue implements RequestFeeder {
interface ConnectionManager {
HttpHost getProxyHost();
Connection getConnection(Context context, HttpHost host);
boolean recycleConnection(HttpHost host, Connection connection);
boolean recycleConnection(Connection connection);
}
}

View File

@@ -180,20 +180,24 @@ class Network {
}
RequestQueue q = mRequestQueue;
RequestHandle handle = null;
if (loader.isSynchronous()) {
q = new RequestQueue(loader.getContext(), 1);
}
RequestHandle handle = q.queueRequest(
url, loader.getWebAddress(), method, headers, loader,
bodyProvider, bodyLength);
loader.attachRequestHandle(handle);
if (loader.isSynchronous()) {
handle.waitUntilComplete();
handle = q.queueSynchronousRequest(url, loader.getWebAddress(),
method, headers, loader, bodyProvider, bodyLength);
loader.attachRequestHandle(handle);
handle.processRequest();
loader.loadSynchronousMessages();
q.shutdown();
} else {
handle = q.queueRequest(url, loader.getWebAddress(), method,
headers, loader, bodyProvider, bodyLength);
// FIXME: Although this is probably a rare condition, normal network
// requests are processed in a separate thread. This means that it
// is possible to process part of the request before setting the
// request handle on the loader. We should probably refactor this to
// ensure the handle is attached before processing begins.
loader.attachRequestHandle(handle);
}
return true;
}