1a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath/* 2a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Copyright (C) 2006 The Android Open Source Project 3a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * 4a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Licensed under the Apache License, Version 2.0 (the "License"); 5a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * you may not use this file except in compliance with the License. 6a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * You may obtain a copy of the License at 7a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * 8a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * http://www.apache.org/licenses/LICENSE-2.0 9a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * 10a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Unless required by applicable law or agreed to in writing, software 11a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * distributed under the License is distributed on an "AS IS" BASIS, 12a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * See the License for the specific language governing permissions and 14a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * limitations under the License. 15a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 16a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 17a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath/** 18a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * High level HTTP Interface 19a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Queues requests as necessary 20a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 21a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 22a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathpackage android.net.http; 23a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 24a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport android.content.BroadcastReceiver; 25a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport android.content.Context; 26a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport android.content.Intent; 27a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport android.content.IntentFilter; 28a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport android.net.ConnectivityManager; 29a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport android.net.NetworkInfo; 30a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport android.net.Proxy; 313e387462b084cf0c62e89c21cfd071df50163e39Narayan Kamathimport android.net.compatibility.WebAddress; 32a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport android.util.Log; 33a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 34a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport java.io.InputStream; 35a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport java.util.Iterator; 36a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport java.util.LinkedHashMap; 37a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport java.util.LinkedList; 38a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport java.util.ListIterator; 39a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport java.util.Map; 40a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 41a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.HttpHost; 42a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 43a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathpublic class RequestQueue implements RequestFeeder { 44a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 45a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 46a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 47a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Requests, indexed by HttpHost (scheme, host, port) 48a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 49a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private final LinkedHashMap<HttpHost, LinkedList<Request>> mPending; 50a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private final Context mContext; 51a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private final ActivePool mActivePool; 52a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private final ConnectivityManager mConnectivityManager; 53a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 54a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private HttpHost mProxyHost = null; 55a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private BroadcastReceiver mProxyChangeReceiver; 56a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 57a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /* default simultaneous connection count */ 58a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private static final int CONNECTION_COUNT = 4; 59a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 60a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 61a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * This class maintains active connection threads 62a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 63a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath class ActivePool implements ConnectionManager { 64a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** Threads used to process requests */ 65a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath ConnectionThread[] mThreads; 66a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 67a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath IdleCache mIdleCache; 68a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 69a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private int mTotalRequest; 70a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private int mTotalConnection; 71a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private int mConnectionCount; 72a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 73a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath ActivePool(int connectionCount) { 74a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mIdleCache = new IdleCache(); 75a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mConnectionCount = connectionCount; 76a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mThreads = new ConnectionThread[mConnectionCount]; 77a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 78a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath for (int i = 0; i < mConnectionCount; i++) { 79a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mThreads[i] = new ConnectionThread( 80a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mContext, i, this, RequestQueue.this); 81a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 82a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 83a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 84a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath void startup() { 85a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath for (int i = 0; i < mConnectionCount; i++) { 86a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mThreads[i].start(); 87a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 88a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 89a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 90a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath void shutdown() { 91a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath for (int i = 0; i < mConnectionCount; i++) { 92a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mThreads[i].requestStop(); 93a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 94a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 95a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 96a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath void startConnectionThread() { 97a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath synchronized (RequestQueue.this) { 98a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath RequestQueue.this.notify(); 99a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 100a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 101a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 102a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public void startTiming() { 103a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath for (int i = 0; i < mConnectionCount; i++) { 104a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath ConnectionThread rt = mThreads[i]; 105a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath rt.mCurrentThreadTime = -1; 106a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath rt.mTotalThreadTime = 0; 107a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 108a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mTotalRequest = 0; 109a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mTotalConnection = 0; 110a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 111a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 112a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public void stopTiming() { 113a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath int totalTime = 0; 114a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath for (int i = 0; i < mConnectionCount; i++) { 115a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath ConnectionThread rt = mThreads[i]; 116a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (rt.mCurrentThreadTime != -1) { 117a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath totalTime += rt.mTotalThreadTime; 118a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 119a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath rt.mCurrentThreadTime = 0; 120a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 121a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Log.d("Http", "Http thread used " + totalTime + " ms " + " for " 122a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath + mTotalRequest + " requests and " + mTotalConnection 123a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath + " new connections"); 124a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 125a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 126a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath void logState() { 127a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath StringBuilder dump = new StringBuilder(); 128a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath for (int i = 0; i < mConnectionCount; i++) { 129a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath dump.append(mThreads[i] + "\n"); 130a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 131a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath HttpLog.v(dump.toString()); 132a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 133a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 134a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 135a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public HttpHost getProxyHost() { 136a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return mProxyHost; 137a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 138a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 139a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 140a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Turns off persistence on all live connections 141a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 142a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath void disablePersistence() { 143a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath for (int i = 0; i < mConnectionCount; i++) { 144a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Connection connection = mThreads[i].mConnection; 145a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (connection != null) connection.setCanPersist(false); 146a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 147a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mIdleCache.clear(); 148a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 149a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 150a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /* Linear lookup -- okay for small thread counts. Might use 151a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private HashMap<HttpHost, LinkedList<ConnectionThread>> mActiveMap; 152a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if this turns out to be a hotspot */ 153a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath ConnectionThread getThread(HttpHost host) { 154a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath synchronized(RequestQueue.this) { 155a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath for (int i = 0; i < mThreads.length; i++) { 156a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath ConnectionThread ct = mThreads[i]; 157a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Connection connection = ct.mConnection; 158a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (connection != null && connection.mHost.equals(host)) { 159a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return ct; 160a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 161a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 162a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 163a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return null; 164a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 165a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 166a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public Connection getConnection(Context context, HttpHost host) { 167a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath host = RequestQueue.this.determineHost(host); 168a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Connection con = mIdleCache.getConnection(host); 169a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (con == null) { 170a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mTotalConnection++; 171a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath con = Connection.getConnection(mContext, host, mProxyHost, 172a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath RequestQueue.this); 173a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 174a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return con; 175a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 176a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public boolean recycleConnection(Connection connection) { 177a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return mIdleCache.cacheConnection(connection.getHost(), connection); 178a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 179a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 180a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 181a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 182a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 183a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * A RequestQueue class instance maintains a set of queued 184a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * requests. It orders them, makes the requests against HTTP 185a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * servers, and makes callbacks to supplied eventHandlers as data 186a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * is read. It supports request prioritization, connection reuse 187a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * and pipelining. 188a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * 189a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param context application context 190a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 191a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public RequestQueue(Context context) { 192a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this(context, CONNECTION_COUNT); 193a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 194a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 195a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 196a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * A RequestQueue class instance maintains a set of queued 197a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * requests. It orders them, makes the requests against HTTP 198a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * servers, and makes callbacks to supplied eventHandlers as data 199a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * is read. It supports request prioritization, connection reuse 200a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * and pipelining. 201a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * 202a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param context application context 203a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param connectionCount The number of simultaneous connections 204a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 205a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public RequestQueue(Context context, int connectionCount) { 206a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mContext = context; 207a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 208a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mPending = new LinkedHashMap<HttpHost, LinkedList<Request>>(32); 209a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 210a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mActivePool = new ActivePool(connectionCount); 211a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mActivePool.startup(); 212a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 213a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mConnectivityManager = (ConnectivityManager) 214a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath context.getSystemService(Context.CONNECTIVITY_SERVICE); 215a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 216a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 217a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 218a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Enables data state and proxy tracking 219a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 220a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public synchronized void enablePlatformNotifications() { 221a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (HttpLog.LOGV) HttpLog.v("RequestQueue.enablePlatformNotifications() network"); 222a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 223a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (mProxyChangeReceiver == null) { 224a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mProxyChangeReceiver = 225a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath new BroadcastReceiver() { 226a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath @Override 227a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public void onReceive(Context ctx, Intent intent) { 228a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath setProxyConfig(); 229a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 230a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath }; 231a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mContext.registerReceiver(mProxyChangeReceiver, 232a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath new IntentFilter(Proxy.PROXY_CHANGE_ACTION)); 233a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 234a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // we need to resample the current proxy setup 235a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath setProxyConfig(); 236a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 237a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 238a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 239a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * If platform notifications have been enabled, call this method 240a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * to disable before destroying RequestQueue 241a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 242a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public synchronized void disablePlatformNotifications() { 243a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (HttpLog.LOGV) HttpLog.v("RequestQueue.disablePlatformNotifications() network"); 244a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 245a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (mProxyChangeReceiver != null) { 246a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mContext.unregisterReceiver(mProxyChangeReceiver); 247a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mProxyChangeReceiver = null; 248a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 249a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 250a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 251a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 252a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Because our IntentReceiver can run within a different thread, 253a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * synchronize setting the proxy 254a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 255a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private synchronized void setProxyConfig() { 256a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); 257a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (info != null && info.getType() == ConnectivityManager.TYPE_WIFI) { 258a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mProxyHost = null; 259a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } else { 260a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath String host = Proxy.getHost(mContext); 261a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (HttpLog.LOGV) HttpLog.v("RequestQueue.setProxyConfig " + host); 262a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (host == null) { 263a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mProxyHost = null; 264a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } else { 265a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mActivePool.disablePersistence(); 266a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mProxyHost = new HttpHost(host, Proxy.getPort(mContext), "http"); 267a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 268a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 269a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 270a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 271a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 272a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * used by webkit 273a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @return proxy host if set, null otherwise 274a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 275a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public HttpHost getProxyHost() { 276a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return mProxyHost; 277a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 278a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 279a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 280a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Queues an HTTP request 281a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param url The url to load. 282a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param method "GET" or "POST." 283a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param headers A hashmap of http headers. 284a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param eventHandler The event handler for handling returned 285a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * data. Callbacks will be made on the supplied instance. 286a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param bodyProvider InputStream providing HTTP body, null if none 287a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param bodyLength length of body, must be 0 if bodyProvider is null 288a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 289a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public RequestHandle queueRequest( 290a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath String url, String method, 291a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Map<String, String> headers, EventHandler eventHandler, 292a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath InputStream bodyProvider, int bodyLength) { 293a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath WebAddress uri = new WebAddress(url); 294a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return queueRequest(url, uri, method, headers, eventHandler, 295a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath bodyProvider, bodyLength); 296a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 297a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 298a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 299a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Queues an HTTP request 300a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param url The url to load. 301a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param uri The uri of the url to load. 302a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param method "GET" or "POST." 303a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param headers A hashmap of http headers. 304a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param eventHandler The event handler for handling returned 305a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * data. Callbacks will be made on the supplied instance. 306a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param bodyProvider InputStream providing HTTP body, null if none 307a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param bodyLength length of body, must be 0 if bodyProvider is null 308a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 309a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public RequestHandle queueRequest( 310a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath String url, WebAddress uri, String method, Map<String, String> headers, 311a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath EventHandler eventHandler, 312a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath InputStream bodyProvider, int bodyLength) { 313a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 314a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (HttpLog.LOGV) HttpLog.v("RequestQueue.queueRequest " + uri); 315a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 316a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // Ensure there is an eventHandler set 317a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (eventHandler == null) { 318a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath eventHandler = new LoggingEventHandler(); 319a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 320a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 321a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /* Create and queue request */ 322a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Request req; 323a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath HttpHost httpHost = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme()); 324a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 325a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // set up request 326a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath req = new Request(method, httpHost, mProxyHost, uri.getPath(), bodyProvider, 327a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath bodyLength, eventHandler, headers); 328a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 329a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath queueRequest(req, false); 330a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 331a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mActivePool.mTotalRequest++; 332a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 333a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // dump(); 334a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mActivePool.startConnectionThread(); 335a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 336a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return new RequestHandle( 337a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this, url, uri, method, headers, bodyProvider, bodyLength, 338a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath req); 339a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 340a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 341a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private static class SyncFeeder implements RequestFeeder { 342a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // This is used in the case where the request fails and needs to be 343a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // requeued into the RequestFeeder. 344a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private Request mRequest; 345a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath SyncFeeder() { 346a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 347a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public Request getRequest() { 348a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Request r = mRequest; 349a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mRequest = null; 350a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return r; 351a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 352a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public Request getRequest(HttpHost host) { 353a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return getRequest(); 354a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 355a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public boolean haveRequest(HttpHost host) { 356a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return mRequest != null; 357a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 358a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public void requeueRequest(Request r) { 359a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mRequest = r; 360a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 361a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 362a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 363a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public RequestHandle queueSynchronousRequest(String url, WebAddress uri, 364a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath String method, Map<String, String> headers, 365a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath EventHandler eventHandler, InputStream bodyProvider, 366a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath int bodyLength) { 367a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (HttpLog.LOGV) { 368a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath HttpLog.v("RequestQueue.dispatchSynchronousRequest " + uri); 369a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 370a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 371a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath HttpHost host = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme()); 372a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 373a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Request req = new Request(method, host, mProxyHost, uri.getPath(), 374a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath bodyProvider, bodyLength, eventHandler, headers); 375a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 376a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // Open a new connection that uses our special RequestFeeder 377a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // implementation. 378a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath host = determineHost(host); 379a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Connection conn = Connection.getConnection(mContext, host, mProxyHost, 380a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath new SyncFeeder()); 381a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 382a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // TODO: I would like to process the request here but LoadListener 383a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // needs a RequestHandle to process some messages. 384a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return new RequestHandle(this, url, uri, method, headers, bodyProvider, 385a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath bodyLength, req, conn); 386a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 387a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 388a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 389a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // Chooses between the proxy and the request's host. 390a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private HttpHost determineHost(HttpHost host) { 391a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // There used to be a comment in ConnectionThread about t-mob's proxy 392a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // being really bad about https. But, HttpsConnection actually looks 393a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // for a proxy and connects through it anyway. I think that this check 394a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // is still valid because if a site is https, we will use 395a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // HttpsConnection rather than HttpConnection if the proxy address is 396a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // not secure. 397a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return (mProxyHost == null || "https".equals(host.getSchemeName())) 398a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath ? host : mProxyHost; 399a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 400a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 401a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 402a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @return true iff there are any non-active requests pending 403a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 404a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath synchronized boolean requestsPending() { 405a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return !mPending.isEmpty(); 406a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 407a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 408a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 409a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 410a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * debug tool: prints request queue to log 411a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 412a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath synchronized void dump() { 413a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath HttpLog.v("dump()"); 414a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath StringBuilder dump = new StringBuilder(); 415a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath int count = 0; 416a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Iterator<Map.Entry<HttpHost, LinkedList<Request>>> iter; 417a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 418a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // mActivePool.log(dump); 419a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 420a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (!mPending.isEmpty()) { 421a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath iter = mPending.entrySet().iterator(); 422a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath while (iter.hasNext()) { 423a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Map.Entry<HttpHost, LinkedList<Request>> entry = iter.next(); 424a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath String hostName = entry.getKey().getHostName(); 425a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath StringBuilder line = new StringBuilder("p" + count++ + " " + hostName + " "); 426a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 427a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath LinkedList<Request> reqList = entry.getValue(); 428a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath ListIterator reqIter = reqList.listIterator(0); 429a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath while (iter.hasNext()) { 430a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Request request = (Request)iter.next(); 431a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath line.append(request + " "); 432a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 433a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath dump.append(line); 434a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath dump.append("\n"); 435a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 436a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 437a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath HttpLog.v(dump.toString()); 438a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 439a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 440a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /* 441a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * RequestFeeder implementation 442a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 443a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public synchronized Request getRequest() { 444a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Request ret = null; 445a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 446a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (!mPending.isEmpty()) { 447a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath ret = removeFirst(mPending); 448a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 449a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (HttpLog.LOGV) HttpLog.v("RequestQueue.getRequest() => " + ret); 450a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return ret; 451a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 452a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 453a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 454a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @return a request for given host if possible 455a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 456a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public synchronized Request getRequest(HttpHost host) { 457a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Request ret = null; 458a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 459a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (mPending.containsKey(host)) { 460a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath LinkedList<Request> reqList = mPending.get(host); 461a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath ret = reqList.removeFirst(); 462a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (reqList.isEmpty()) { 463a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mPending.remove(host); 464a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 465a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 466a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (HttpLog.LOGV) HttpLog.v("RequestQueue.getRequest(" + host + ") => " + ret); 467a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return ret; 468a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 469a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 470a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 471a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @return true if a request for this host is available 472a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 473a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public synchronized boolean haveRequest(HttpHost host) { 474a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return mPending.containsKey(host); 475a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 476a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 477a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 478a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Put request back on head of queue 479a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 480a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public void requeueRequest(Request request) { 481a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath queueRequest(request, true); 482a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 483a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 484a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 485a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * This must be called to cleanly shutdown RequestQueue 486a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 487a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public void shutdown() { 488a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mActivePool.shutdown(); 489a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 490a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 491a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath protected synchronized void queueRequest(Request request, boolean head) { 492a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath HttpHost host = request.mProxyHost == null ? request.mHost : request.mProxyHost; 493a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath LinkedList<Request> reqList; 494a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (mPending.containsKey(host)) { 495a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath reqList = mPending.get(host); 496a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } else { 497a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath reqList = new LinkedList<Request>(); 498a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mPending.put(host, reqList); 499a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 500a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (head) { 501a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath reqList.addFirst(request); 502a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } else { 503a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath reqList.add(request); 504a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 505a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 506a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 507a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 508a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public void startTiming() { 509a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mActivePool.startTiming(); 510a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 511a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 512a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public void stopTiming() { 513a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mActivePool.stopTiming(); 514a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 515a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 516a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /* helper */ 517a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private Request removeFirst(LinkedHashMap<HttpHost, LinkedList<Request>> requestQueue) { 518a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Request ret = null; 519a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Iterator<Map.Entry<HttpHost, LinkedList<Request>>> iter = requestQueue.entrySet().iterator(); 520a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (iter.hasNext()) { 521a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Map.Entry<HttpHost, LinkedList<Request>> entry = iter.next(); 522a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath LinkedList<Request> reqList = entry.getValue(); 523a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath ret = reqList.removeFirst(); 524a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (reqList.isEmpty()) { 525a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath requestQueue.remove(entry.getKey()); 526a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 527a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 528a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return ret; 529a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 530a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 531a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 532a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * This interface is exposed to each connection 533a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 534a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath interface ConnectionManager { 535a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath HttpHost getProxyHost(); 536a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Connection getConnection(Context context, HttpHost host); 537a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath boolean recycleConnection(Connection connection); 538a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 539a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath} 540