Fix Apache HTTP client to recover from half-closed connections.

android.net.http.DefaultHttpClientTest demonstrates a problem where
half-closed connections get pooled, causing subsequent connections
to timeout.

Change-Id: I7275d99f12eafa28bb2336a3dd67546ffecb4dce
http://b/2612240
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/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
 }