am e59c288f: am b91c5e93: DefaultRequestDirector should ignore IOExceptions from stale connections

* commit 'e59c288fca5a99d07f09494e8d03a228a347c3f8':
  DefaultRequestDirector should ignore IOExceptions from stale connections
diff --git a/src/org/apache/http/impl/AbstractHttpClientConnection.java b/src/org/apache/http/impl/AbstractHttpClientConnection.java
index ebfaabb..ac3f4d1 100644
--- a/src/org/apache/http/impl/AbstractHttpClientConnection.java
+++ b/src/org/apache/http/impl/AbstractHttpClientConnection.java
@@ -47,6 +47,7 @@
 import org.apache.http.impl.entity.StrictContentLengthStrategy;
 import org.apache.http.impl.io.HttpRequestWriter;
 import org.apache.http.impl.io.HttpResponseParser;
+import org.apache.http.impl.io.SocketInputBuffer;
 import org.apache.http.io.HttpMessageParser;
 import org.apache.http.io.HttpMessageWriter;
 import org.apache.http.io.SessionInputBuffer;
@@ -198,6 +199,12 @@
             return true;
         }
         try {
+            // BEGIN android-added
+            //     don't reuse connections when the socket input stream is exhausted
+            if (inbuffer instanceof SocketInputBuffer) {
+                return ((SocketInputBuffer) inbuffer).isStale();
+            }
+            // END android-added
             this.inbuffer.isDataAvailable(1);
             return false;
         } catch (IOException ex) {
diff --git a/src/org/apache/http/impl/client/DefaultHttpClient.java b/src/org/apache/http/impl/client/DefaultHttpClient.java
index 7dcb2a2..7b3a3fa 100644
--- a/src/org/apache/http/impl/client/DefaultHttpClient.java
+++ b/src/org/apache/http/impl/client/DefaultHttpClient.java
@@ -61,7 +61,7 @@
 import org.apache.http.impl.DefaultConnectionReuseStrategy;
 import org.apache.http.impl.auth.BasicSchemeFactory;
 import org.apache.http.impl.auth.DigestSchemeFactory;
-import org.apache.http.impl.conn.DefaultHttpRoutePlanner;
+import org.apache.http.impl.conn.ProxySelectorRoutePlanner;
 import org.apache.http.impl.conn.SingleClientConnManager;
 import org.apache.http.impl.cookie.BestMatchSpecFactory;
 import org.apache.http.impl.cookie.BrowserCompatSpecFactory;
@@ -326,8 +326,10 @@
 
     @Override
     protected HttpRoutePlanner createHttpRoutePlanner() {
-        return new DefaultHttpRoutePlanner
-            (getConnectionManager().getSchemeRegistry());
+        // BEGIN android-changed
+        //     Use the proxy specified by system properties
+        return new ProxySelectorRoutePlanner(getConnectionManager().getSchemeRegistry(), null);
+        // END android-changed
     }
 
 
diff --git a/src/org/apache/http/impl/client/DefaultRequestDirector.java b/src/org/apache/http/impl/client/DefaultRequestDirector.java
index a95c522..b8f380b 100644
--- a/src/org/apache/http/impl/client/DefaultRequestDirector.java
+++ b/src/org/apache/http/impl/client/DefaultRequestDirector.java
@@ -357,7 +357,13 @@
                 // Reopen connection if needed
                 if (!managedConn.isOpen()) {
                     managedConn.open(route, context, params);
-                } 
+                }
+                // BEGIN android-added
+                else {
+                    // b/3241899 set the per request timeout parameter on reused connections
+                    managedConn.setSocketTimeout(HttpConnectionParams.getSoTimeout(params));
+                }
+                // END android-added
                 
                 try {
                     establishRoute(route, context);
diff --git a/src/org/apache/http/impl/conn/ProxySelectorRoutePlanner.java b/src/org/apache/http/impl/conn/ProxySelectorRoutePlanner.java
index 136caf4..daa7227 100644
--- a/src/org/apache/http/impl/conn/ProxySelectorRoutePlanner.java
+++ b/src/org/apache/http/impl/conn/ProxySelectorRoutePlanner.java
@@ -51,6 +51,7 @@
 import org.apache.http.conn.scheme.SchemeRegistry;
 
 import org.apache.http.conn.params.ConnRouteParams;
+import org.apache.http.conn.params.ConnRoutePNames;
 
 
 /**
@@ -140,7 +141,18 @@
 
         final InetAddress local =
             ConnRouteParams.getLocalAddress(request.getParams());
-        final HttpHost proxy = determineProxy(target, request, context);
+
+        // BEGIN android-changed
+        //     If the client or request explicitly specifies a proxy (or no
+        //     proxy), prefer that over the ProxySelector's VM-wide default.
+        HttpHost proxy = (HttpHost) request.getParams().getParameter(ConnRoutePNames.DEFAULT_PROXY);
+        if (proxy == null) {
+            proxy = determineProxy(target, request, context);
+        } else if (ConnRouteParams.NO_HOST.equals(proxy)) {
+            // value is explicitly unset
+            proxy = null;
+        }
+        // END android-changed
 
         final Scheme schm =
             this.schemeRegistry.getScheme(target.getSchemeName());
diff --git a/src/org/apache/http/impl/io/SocketInputBuffer.java b/src/org/apache/http/impl/io/SocketInputBuffer.java
index 925e80a..9e09436 100644
--- a/src/org/apache/http/impl/io/SocketInputBuffer.java
+++ b/src/org/apache/http/impl/io/SocketInputBuffer.java
@@ -35,6 +35,7 @@
 import java.io.InterruptedIOException;
 import java.net.Socket;
 
+import java.net.SocketTimeoutException;
 import org.apache.http.params.HttpParams;
 
 
@@ -112,4 +113,30 @@
         return result;
     }    
         
+    // BEGIN android-added
+    /**
+     * Returns true if the connection is probably functional. It's insufficient
+     * to rely on isDataAvailable() returning normally; that approach cannot
+     * distinguish between an exhausted stream and a stream with zero bytes
+     * buffered.
+     *
+     * @hide
+     */
+    public boolean isStale() throws IOException {
+        if (hasBufferedData()) {
+            return false;
+        }
+        int oldTimeout = this.socket.getSoTimeout();
+        try {
+            this.socket.setSoTimeout(1);
+            return fillBuffer() == -1;
+        } catch (SocketTimeoutException e) {
+            return false; // the connection is not stale; hooray
+        } catch (IOException e) {
+            return true; // the connection is stale, the read or soTimeout failed.
+        } finally {
+            this.socket.setSoTimeout(oldTimeout);
+        }
+    }
+    // END android-added
 }