Merge "Unbundle org.apache.http.legacy."
diff --git a/Android.mk b/Android.mk
index f3eb679..e5da4a1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -22,5 +22,7 @@
     $(call all-java-files-under,src) \
     $(call all-java-files-under,android)
 
+LOCAL_SDK_VERSION := 21
+
 LOCAL_MODULE_TAGS := optional
 include $(BUILD_JAVA_LIBRARY)
diff --git a/android/src/android/net/compatibility/WebAddress.java b/android/src/android/net/compatibility/WebAddress.java
new file mode 100644
index 0000000..ca3081f
--- /dev/null
+++ b/android/src/android/net/compatibility/WebAddress.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2006 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 android.net.compatibility;
+
+import static android.util.Patterns.GOOD_IRI_CHAR;
+
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Web Address Parser
+ *
+ * This is called WebAddress, rather than URL or URI, because it
+ * attempts to parse the stuff that a user will actually type into a
+ * browser address widget.
+ *
+ * Unlike java.net.uri, this parser will not choke on URIs missing
+ * schemes.  It will only throw a IllegalArgumentException if the input is
+ * really hosed.
+ *
+ * If given an https scheme but no port, fills in port
+ *
+ */
+public class WebAddress {
+
+    private String mScheme;
+    private String mHost;
+    private int mPort;
+    private String mPath;
+    private String mAuthInfo;
+
+    static final int MATCH_GROUP_SCHEME = 1;
+    static final int MATCH_GROUP_AUTHORITY = 2;
+    static final int MATCH_GROUP_HOST = 3;
+    static final int MATCH_GROUP_PORT = 4;
+    static final int MATCH_GROUP_PATH = 5;
+
+    static Pattern sAddressPattern = Pattern.compile(
+            /* scheme    */ "(?:(http|https|file)\\:\\/\\/)?" +
+            /* authority */ "(?:([-A-Za-z0-9$_.+!*'(),;?&=]+(?:\\:[-A-Za-z0-9$_.+!*'(),;?&=]+)?)@)?" +
+            /* host      */ "([" + GOOD_IRI_CHAR + "%_-][" + GOOD_IRI_CHAR + "%_\\.-]*|\\[[0-9a-fA-F:\\.]+\\])?" +
+            /* port      */ "(?:\\:([0-9]*))?" +
+            /* path      */ "(\\/?[^#]*)?" +
+            /* anchor    */ ".*", Pattern.CASE_INSENSITIVE);
+
+    /** parses given uriString. */
+    public WebAddress(String address) throws IllegalArgumentException {
+        if (address == null) {
+            throw new NullPointerException();
+        }
+
+        // android.util.Log.d(LOGTAG, "WebAddress: " + address);
+
+        mScheme = "";
+        mHost = "";
+        mPort = -1;
+        mPath = "/";
+        mAuthInfo = "";
+
+        Matcher m = sAddressPattern.matcher(address);
+        String t;
+        if (m.matches()) {
+            t = m.group(MATCH_GROUP_SCHEME);
+            if (t != null) mScheme = t.toLowerCase(Locale.ROOT);
+            t = m.group(MATCH_GROUP_AUTHORITY);
+            if (t != null) mAuthInfo = t;
+            t = m.group(MATCH_GROUP_HOST);
+            if (t != null) mHost = t;
+            t = m.group(MATCH_GROUP_PORT);
+            if (t != null && t.length() > 0) {
+                // The ':' character is not returned by the regex.
+                try {
+                    mPort = Integer.parseInt(t);
+                } catch (NumberFormatException ex) {
+                    throw new IllegalArgumentException("Bad port");
+                }
+            }
+            t = m.group(MATCH_GROUP_PATH);
+            if (t != null && t.length() > 0) {
+                /* handle busted myspace frontpage redirect with
+                   missing initial "/" */
+                if (t.charAt(0) == '/') {
+                    mPath = t;
+                } else {
+                    mPath = "/" + t;
+                }
+            }
+
+        } else {
+            // nothing found... outa here
+            throw new IllegalArgumentException("Bad address");
+        }
+
+        /* Get port from scheme or scheme from port, if necessary and
+           possible */
+        if (mPort == 443 && mScheme.equals("")) {
+            mScheme = "https";
+        } else if (mPort == -1) {
+            if (mScheme.equals("https"))
+                mPort = 443;
+            else
+                mPort = 80; // default
+        }
+        if (mScheme.equals("")) mScheme = "http";
+    }
+
+    @Override
+    public String toString() {
+        String port = "";
+        if ((mPort != 443 && mScheme.equals("https")) ||
+            (mPort != 80 && mScheme.equals("http"))) {
+            port = ":" + Integer.toString(mPort);
+        }
+        String authInfo = "";
+        if (mAuthInfo.length() > 0) {
+            authInfo = mAuthInfo + "@";
+        }
+
+        return mScheme + "://" + authInfo + mHost + port + mPath;
+    }
+
+    public void setScheme(String scheme) {
+      mScheme = scheme;
+    }
+
+    public String getScheme() {
+      return mScheme;
+    }
+
+    public void setHost(String host) {
+      mHost = host;
+    }
+
+    public String getHost() {
+      return mHost;
+    }
+
+    public void setPort(int port) {
+      mPort = port;
+    }
+
+    public int getPort() {
+      return mPort;
+    }
+
+    public void setPath(String path) {
+      mPath = path;
+    }
+
+    public String getPath() {
+      return mPath;
+    }
+
+    public void setAuthInfo(String authInfo) {
+      mAuthInfo = authInfo;
+    }
+
+    public String getAuthInfo() {
+      return mAuthInfo;
+    }
+}
diff --git a/android/src/android/net/http/AndroidHttpClient.java b/android/src/android/net/http/AndroidHttpClient.java
index 04f3974..c2e5999 100644
--- a/android/src/android/net/http/AndroidHttpClient.java
+++ b/android/src/android/net/http/AndroidHttpClient.java
@@ -16,8 +16,6 @@
 
 package android.net.http;
 
-import com.android.internal.http.HttpDateTime;
-
 import org.apache.http.Header;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpEntityEnclosingRequest;
@@ -504,6 +502,6 @@
      *     of an unsupported format.
      */
     public static long parseDate(String dateString) {
-        return HttpDateTime.parse(dateString);
+        return LegacyHttpDateTime.parse(dateString);
     }
 }
diff --git a/android/src/android/net/http/AndroidHttpClientConnection.java b/android/src/android/net/http/AndroidHttpClientConnection.java
index 6d48fce..a90da62 100644
--- a/android/src/android/net/http/AndroidHttpClientConnection.java
+++ b/android/src/android/net/http/AndroidHttpClientConnection.java
@@ -57,8 +57,6 @@
 /**
  * A alternate class for (@link DefaultHttpClientConnection).
  * It has better performance than DefaultHttpClientConnection
- * 
- * {@hide}
  */
 public class AndroidHttpClientConnection
         implements HttpInetConnection, HttpConnection {
diff --git a/android/src/android/net/http/CertificateChainValidator.java b/android/src/android/net/http/CertificateChainValidator.java
index bf3fe02..d45e83f 100644
--- a/android/src/android/net/http/CertificateChainValidator.java
+++ b/android/src/android/net/http/CertificateChainValidator.java
@@ -19,7 +19,7 @@
 import com.android.org.conscrypt.SSLParametersImpl;
 import com.android.org.conscrypt.TrustManagerImpl;
 
-import android.util.Slog;
+import android.util.Log;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -44,8 +44,6 @@
 
 /**
  * Class responsible for all server certificate validation functionality
- *
- * {@hide}
  */
 public class CertificateChainValidator {
     private static final String TAG = "CertificateChainValidator";
@@ -176,10 +174,10 @@
             tmf = TrustManagerFactory.getInstance("X.509");
             tmf.init((KeyStore) null);
         } catch (NoSuchAlgorithmException e) {
-            Slog.w(TAG, "Couldn't find default X.509 TrustManagerFactory");
+            Log.w(TAG, "Couldn't find default X.509 TrustManagerFactory");
             return;
         } catch (KeyStoreException e) {
-            Slog.w(TAG, "Couldn't initialize default X.509 TrustManagerFactory", e);
+            Log.w(TAG, "Couldn't initialize default X.509 TrustManagerFactory", e);
             return;
         }
 
@@ -195,7 +193,7 @@
             }
         }
         if (!sentUpdate) {
-            Slog.w(TAG, "Didn't find a TrustManager to handle CA list update");
+            Log.w(TAG, "Didn't find a TrustManager to handle CA list update");
         }
     }
 
diff --git a/android/src/android/net/http/Connection.java b/android/src/android/net/http/Connection.java
index 831bd0e..4a49d22 100644
--- a/android/src/android/net/http/Connection.java
+++ b/android/src/android/net/http/Connection.java
@@ -36,9 +36,6 @@
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.BasicHttpContext;
 
-/**
- * {@hide}
- */
 abstract class Connection {
 
     /**
diff --git a/android/src/android/net/http/ConnectionThread.java b/android/src/android/net/http/ConnectionThread.java
index d825530..3a8cd05 100644
--- a/android/src/android/net/http/ConnectionThread.java
+++ b/android/src/android/net/http/ConnectionThread.java
@@ -21,9 +21,6 @@
 
 import java.lang.Thread;
 
-/**
- * {@hide}
- */
 class ConnectionThread extends Thread {
 
     static final int WAIT_TIMEOUT = 5000;
diff --git a/android/src/android/net/http/DelegatingSSLSession.java b/android/src/android/net/http/DelegatingSSLSession.java
index 98fbe21..48692d7 100644
--- a/android/src/android/net/http/DelegatingSSLSession.java
+++ b/android/src/android/net/http/DelegatingSSLSession.java
@@ -29,8 +29,6 @@
 /**
  * This is only used when a {@code certificate} is available but usage
  * requires a {@link SSLSession}.
- *
- * @hide
  */
 public class DelegatingSSLSession implements SSLSession {
     protected DelegatingSSLSession() {
diff --git a/android/src/android/net/http/EventHandler.java b/android/src/android/net/http/EventHandler.java
index 3fd471d..df9a5d6 100644
--- a/android/src/android/net/http/EventHandler.java
+++ b/android/src/android/net/http/EventHandler.java
@@ -23,8 +23,6 @@
  * then multiple data() then endData().  handleSslErrorRequest(), if
  * there is an SSL certificate error. error() can occur anywhere
  * in the transaction.
- * 
- * {@hide}
  */
 
 public interface EventHandler {
diff --git a/android/src/android/net/http/Headers.java b/android/src/android/net/http/Headers.java
index 0f8b105..f5b1044 100644
--- a/android/src/android/net/http/Headers.java
+++ b/android/src/android/net/http/Headers.java
@@ -29,8 +29,6 @@
 
 /**
  * Manages received headers
- *
- * {@hide}
  */
 public final class Headers {
     private static final String LOGTAG = "Http";
diff --git a/android/src/android/net/http/HttpAuthHeader.java b/android/src/android/net/http/HttpAuthHeader.java
index 3abac23..2a1ee98 100644
--- a/android/src/android/net/http/HttpAuthHeader.java
+++ b/android/src/android/net/http/HttpAuthHeader.java
@@ -21,8 +21,6 @@
 /**
  * HttpAuthHeader: a class to store HTTP authentication-header parameters.
  * For more information, see: RFC 2617: HTTP Authentication.
- * 
- * {@hide}
  */
 public class HttpAuthHeader {
     /**
diff --git a/android/src/android/net/http/HttpConnection.java b/android/src/android/net/http/HttpConnection.java
index edf8fed..316c1a8 100644
--- a/android/src/android/net/http/HttpConnection.java
+++ b/android/src/android/net/http/HttpConnection.java
@@ -27,8 +27,6 @@
 
 /**
  * A requestConnection connecting to a normal (non secure) http server
- * 
- * {@hide}
  */
 class HttpConnection extends Connection {
 
diff --git a/android/src/android/net/http/HttpLog.java b/android/src/android/net/http/HttpLog.java
index 0934664..60b7673 100644
--- a/android/src/android/net/http/HttpLog.java
+++ b/android/src/android/net/http/HttpLog.java
@@ -24,9 +24,6 @@
 
 import android.util.Log;
 
-/**
- * {@hide}
- */
 class HttpLog {
     private final static String LOGTAG = "http";
 
diff --git a/android/src/android/net/http/HttpsConnection.java b/android/src/android/net/http/HttpsConnection.java
index a8674de..213537b 100644
--- a/android/src/android/net/http/HttpsConnection.java
+++ b/android/src/android/net/http/HttpsConnection.java
@@ -48,8 +48,6 @@
 /**
  * A Connection connecting to a secure http server or tunneling through
  * a http proxy server to a https server.
- *
- * @hide
  */
 public class HttpsConnection extends Connection {
 
@@ -66,8 +64,6 @@
     }
 
     /**
-     * @hide
-     *
      * @param sessionDir directory to cache SSL sessions
      */
     public static void initializeEngine(File sessionDir) {
@@ -423,7 +419,6 @@
 /**
  * Simple exception we throw if the SSL connection is closed by the user.
  *
- * {@hide}
  */
 class SSLConnectionClosedByUserException extends SSLException {
 
diff --git a/android/src/android/net/http/IdleCache.java b/android/src/android/net/http/IdleCache.java
index fda6009..023dff1 100644
--- a/android/src/android/net/http/IdleCache.java
+++ b/android/src/android/net/http/IdleCache.java
@@ -24,9 +24,6 @@
 
 import android.os.SystemClock;
 
-/**
- * {@hide}
- */
 class IdleCache {
 
     class Entry {
diff --git a/android/src/android/net/http/LegacyHttpDateTime.java b/android/src/android/net/http/LegacyHttpDateTime.java
new file mode 100644
index 0000000..f8d0529
--- /dev/null
+++ b/android/src/android/net/http/LegacyHttpDateTime.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2007 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 android.net.http;
+
+import android.text.format.Time;
+
+import java.util.Calendar;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Helper for parsing an HTTP date.
+ */
+final class LegacyHttpDateTime {
+
+    /*
+     * Regular expression for parsing HTTP-date.
+     *
+     * Wdy, DD Mon YYYY HH:MM:SS GMT
+     * RFC 822, updated by RFC 1123
+     *
+     * Weekday, DD-Mon-YY HH:MM:SS GMT
+     * RFC 850, obsoleted by RFC 1036
+     *
+     * Wdy Mon DD HH:MM:SS YYYY
+     * ANSI C's asctime() format
+     *
+     * with following variations
+     *
+     * Wdy, DD-Mon-YYYY HH:MM:SS GMT
+     * Wdy, (SP)D Mon YYYY HH:MM:SS GMT
+     * Wdy,DD Mon YYYY HH:MM:SS GMT
+     * Wdy, DD-Mon-YY HH:MM:SS GMT
+     * Wdy, DD Mon YYYY HH:MM:SS -HHMM
+     * Wdy, DD Mon YYYY HH:MM:SS
+     * Wdy Mon (SP)D HH:MM:SS YYYY
+     * Wdy Mon DD HH:MM:SS YYYY GMT
+     * 
+     * HH can be H if the first digit is zero.
+     * 
+     * Mon can be the full name of the month.
+     */
+    private static final String HTTP_DATE_RFC_REGEXP =
+            "([0-9]{1,2})[- ]([A-Za-z]{3,9})[- ]([0-9]{2,4})[ ]"
+            + "([0-9]{1,2}:[0-9][0-9]:[0-9][0-9])";
+
+    private static final String HTTP_DATE_ANSIC_REGEXP =
+            "[ ]([A-Za-z]{3,9})[ ]+([0-9]{1,2})[ ]"
+            + "([0-9]{1,2}:[0-9][0-9]:[0-9][0-9])[ ]([0-9]{2,4})";
+
+    /**
+     * The compiled version of the HTTP-date regular expressions.
+     */
+    private static final Pattern HTTP_DATE_RFC_PATTERN =
+            Pattern.compile(HTTP_DATE_RFC_REGEXP);
+    private static final Pattern HTTP_DATE_ANSIC_PATTERN =
+            Pattern.compile(HTTP_DATE_ANSIC_REGEXP);
+
+    private static class TimeOfDay {
+        TimeOfDay(int h, int m, int s) {
+            this.hour = h;
+            this.minute = m;
+            this.second = s;
+        }
+        
+        int hour;
+        int minute;
+        int second;
+    }
+
+    public static long parse(String timeString)
+            throws IllegalArgumentException {
+
+        int date = 1;
+        int month = Calendar.JANUARY;
+        int year = 1970;
+        TimeOfDay timeOfDay;
+
+        Matcher rfcMatcher = HTTP_DATE_RFC_PATTERN.matcher(timeString);
+        if (rfcMatcher.find()) {
+            date = getDate(rfcMatcher.group(1));
+            month = getMonth(rfcMatcher.group(2));
+            year = getYear(rfcMatcher.group(3));
+            timeOfDay = getTime(rfcMatcher.group(4));
+        } else {
+            Matcher ansicMatcher = HTTP_DATE_ANSIC_PATTERN.matcher(timeString);
+            if (ansicMatcher.find()) {
+                month = getMonth(ansicMatcher.group(1));
+                date = getDate(ansicMatcher.group(2));
+                timeOfDay = getTime(ansicMatcher.group(3));
+                year = getYear(ansicMatcher.group(4));
+            } else {
+                throw new IllegalArgumentException();
+            }
+        }
+
+        // FIXME: Y2038 BUG!
+        if (year >= 2038) {
+            year = 2038;
+            month = Calendar.JANUARY;
+            date = 1;
+        }
+
+        Time time = new Time(Time.TIMEZONE_UTC);
+        time.set(timeOfDay.second, timeOfDay.minute, timeOfDay.hour, date,
+                month, year);
+        return time.toMillis(false /* use isDst */);
+    }
+
+    private static int getDate(String dateString) {
+        if (dateString.length() == 2) {
+            return (dateString.charAt(0) - '0') * 10
+                    + (dateString.charAt(1) - '0');
+        } else {
+            return (dateString.charAt(0) - '0');
+        }
+    }
+
+    /*
+     * jan = 9 + 0 + 13 = 22
+     * feb = 5 + 4 + 1 = 10
+     * mar = 12 + 0 + 17 = 29
+     * apr = 0 + 15 + 17 = 32
+     * may = 12 + 0 + 24 = 36
+     * jun = 9 + 20 + 13 = 42
+     * jul = 9 + 20 + 11 = 40
+     * aug = 0 + 20 + 6 = 26
+     * sep = 18 + 4 + 15 = 37
+     * oct = 14 + 2 + 19 = 35
+     * nov = 13 + 14 + 21 = 48
+     * dec = 3 + 4 + 2 = 9
+     */
+    private static int getMonth(String monthString) {
+        int hash = Character.toLowerCase(monthString.charAt(0)) +
+                Character.toLowerCase(monthString.charAt(1)) +
+                Character.toLowerCase(monthString.charAt(2)) - 3 * 'a';
+        switch (hash) {
+            case 22:
+                return Calendar.JANUARY;
+            case 10:
+                return Calendar.FEBRUARY;
+            case 29:
+                return Calendar.MARCH;
+            case 32:
+                return Calendar.APRIL;
+            case 36:
+                return Calendar.MAY;
+            case 42:
+                return Calendar.JUNE;
+            case 40:
+                return Calendar.JULY;
+            case 26:
+                return Calendar.AUGUST;
+            case 37:
+                return Calendar.SEPTEMBER;
+            case 35:
+                return Calendar.OCTOBER;
+            case 48:
+                return Calendar.NOVEMBER;
+            case 9:
+                return Calendar.DECEMBER;
+            default:
+                throw new IllegalArgumentException();
+        }
+    }
+
+    private static int getYear(String yearString) {
+        if (yearString.length() == 2) {
+            int year = (yearString.charAt(0) - '0') * 10
+                    + (yearString.charAt(1) - '0');
+            if (year >= 70) {
+                return year + 1900;
+            } else {
+                return year + 2000;
+            }
+        } else if (yearString.length() == 3) {
+            // According to RFC 2822, three digit years should be added to 1900.
+            int year = (yearString.charAt(0) - '0') * 100
+                    + (yearString.charAt(1) - '0') * 10
+                    + (yearString.charAt(2) - '0');
+            return year + 1900;
+        } else if (yearString.length() == 4) {
+             return (yearString.charAt(0) - '0') * 1000
+                    + (yearString.charAt(1) - '0') * 100
+                    + (yearString.charAt(2) - '0') * 10
+                    + (yearString.charAt(3) - '0');
+        } else {
+             return 1970;
+        }
+    }
+
+    private static TimeOfDay getTime(String timeString) {
+        // HH might be H
+        int i = 0;
+        int hour = timeString.charAt(i++) - '0';
+        if (timeString.charAt(i) != ':')
+            hour = hour * 10 + (timeString.charAt(i++) - '0');
+        // Skip ':'
+        i++;
+        
+        int minute = (timeString.charAt(i++) - '0') * 10
+                    + (timeString.charAt(i++) - '0');
+        // Skip ':'
+        i++;
+        
+        int second = (timeString.charAt(i++) - '0') * 10
+                  + (timeString.charAt(i++) - '0');
+
+        return new TimeOfDay(hour, minute, second);        
+    }
+}
diff --git a/android/src/android/net/http/LoggingEventHandler.java b/android/src/android/net/http/LoggingEventHandler.java
index bdafa0b..4af1e8b 100644
--- a/android/src/android/net/http/LoggingEventHandler.java
+++ b/android/src/android/net/http/LoggingEventHandler.java
@@ -22,9 +22,6 @@
 
 import android.net.http.Headers;
 
-/**
- * {@hide}
- */
 public class LoggingEventHandler implements EventHandler {
 
     public void requestSent() {
diff --git a/android/src/android/net/http/Request.java b/android/src/android/net/http/Request.java
index 76d7bb9..d8eba11 100644
--- a/android/src/android/net/http/Request.java
+++ b/android/src/android/net/http/Request.java
@@ -42,8 +42,6 @@
 
 /**
  * Represents an HTTP request for a given host.
- * 
- * {@hide}
  */
 
 class Request {
@@ -516,11 +514,8 @@
      * Helper: calls error() on eventhandler with appropriate message
      * This should not be called before the mConnection is set.
      */
-    void error(int errorId, int resourceId) {
-        mEventHandler.error(
-                errorId,
-                mConnection.mContext.getText(
-                        resourceId).toString());
+    void error(int errorId, String errorMessage) {
+        mEventHandler.error(errorId, errorMessage);
     }
 
 }
diff --git a/android/src/android/net/http/RequestFeeder.java b/android/src/android/net/http/RequestFeeder.java
index 34ca267..a6322ae 100644
--- a/android/src/android/net/http/RequestFeeder.java
+++ b/android/src/android/net/http/RequestFeeder.java
@@ -22,9 +22,6 @@
 
 import org.apache.http.HttpHost;
 
-/**
- * {@hide}
- */
 interface RequestFeeder {
 
     Request getRequest();
diff --git a/android/src/android/net/http/RequestHandle.java b/android/src/android/net/http/RequestHandle.java
index 46c3869..bc40df1 100644
--- a/android/src/android/net/http/RequestHandle.java
+++ b/android/src/android/net/http/RequestHandle.java
@@ -16,8 +16,7 @@
 
 package android.net.http;
 
-import android.net.ParseException;
-import android.net.WebAddress;
+import android.net.compatibility.WebAddress;
 import android.webkit.CookieManager;
 
 import org.apache.commons.codec.binary.Base64;
@@ -33,8 +32,6 @@
 /**
  * RequestHandle: handles a request session that may include multiple
  * redirects, HTTP authentication requests, etc.
- * 
- * {@hide}
  */
 public class RequestHandle {
 
@@ -161,7 +158,7 @@
                     "RequestHandle.setupRedirect(): too many redirects " +
                     mRequest);
             mRequest.error(EventHandler.ERROR_REDIRECT_LOOP,
-                           com.android.internal.R.string.httpErrorRedirectLoop);
+                    "The page contains too many server redirects.");
             return false;
         }
 
@@ -176,13 +173,16 @@
         mUrl = redirectTo;
         try {
             mUri = new WebAddress(mUrl);
-        } catch (ParseException e) {
+        } catch (IllegalArgumentException e) {
             e.printStackTrace();
         }
 
         // update the "Cookie" header based on the redirected url
         mHeaders.remove("Cookie");
-        String cookie = CookieManager.getInstance().getCookie(mUri);
+        String cookie = null;
+        if (mUri != null) {
+            cookie = CookieManager.getInstance().getCookie(mUri.toString());
+        }
         if (cookie != null && cookie.length() > 0) {
             mHeaders.put("Cookie", cookie);
         }
diff --git a/android/src/android/net/http/RequestQueue.java b/android/src/android/net/http/RequestQueue.java
index 7d2da1b..17f34a5 100644
--- a/android/src/android/net/http/RequestQueue.java
+++ b/android/src/android/net/http/RequestQueue.java
@@ -28,7 +28,7 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.Proxy;
-import android.net.WebAddress;
+import android.net.compatibility.WebAddress;
 import android.util.Log;
 
 import java.io.InputStream;
@@ -40,9 +40,6 @@
 
 import org.apache.http.HttpHost;
 
-/**
- * {@hide}
- */
 public class RequestQueue implements RequestFeeder {
 
 
diff --git a/src/org/apache/http/impl/conn/DefaultClientConnectionOperator.java b/src/org/apache/http/impl/conn/DefaultClientConnectionOperator.java
index 9567eb1..62169bc 100644
--- a/src/org/apache/http/impl/conn/DefaultClientConnectionOperator.java
+++ b/src/org/apache/http/impl/conn/DefaultClientConnectionOperator.java
@@ -183,8 +183,13 @@
             //       catch SocketException to cover any kind of connect failure
             } catch (SocketException ex) {
                 if (i == addresses.length - 1) {
-                    ConnectException cause = ex instanceof ConnectException
-                            ? (ConnectException) ex : new ConnectException(ex.getMessage(), ex);
+                    final ConnectException cause;
+                    if (ex instanceof ConnectException) {
+                        cause = (ConnectException) ex;
+                    } else {
+                        cause = new ConnectException(ex.getMessage());
+                        cause.initCause(ex);
+                    }
                     throw new HttpHostConnectException(target, cause);
                 }
             // END android-changed
diff --git a/src/org/apache/http/impl/conn/SingleClientConnManager.java b/src/org/apache/http/impl/conn/SingleClientConnManager.java
index 55e9757..d8fb956 100644
--- a/src/org/apache/http/impl/conn/SingleClientConnManager.java
+++ b/src/org/apache/http/impl/conn/SingleClientConnManager.java
@@ -31,11 +31,11 @@
 
 package org.apache.http.impl.conn;
 
-import dalvik.system.SocketTagger;
 import java.io.IOException;
 import java.net.Socket;
 import java.util.concurrent.TimeUnit;
 
+import android.net.TrafficStats;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.http.conn.ClientConnectionManager;
@@ -261,7 +261,7 @@
         try {
             final Socket socket = uniquePoolEntry.connection.getSocket();
             if (socket != null) {
-                SocketTagger.get().tag(socket);
+                TrafficStats.tagSocket(socket);
             }
         } catch (IOException iox) {
             log.debug("Problem tagging socket.", iox);
@@ -303,7 +303,7 @@
             // statistics from future users.
             final Socket socket = uniquePoolEntry.connection.getSocket();
             if (socket != null) {
-                SocketTagger.get().untag(socket);
+                TrafficStats.untagSocket(socket);
             }
             // END android-changed
 
diff --git a/src/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.java b/src/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.java
index e9c11b0..7d6a560 100644
--- a/src/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.java
+++ b/src/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.java
@@ -30,11 +30,11 @@
 
 package org.apache.http.impl.conn.tsccm;
 
-import dalvik.system.SocketTagger;
 import java.io.IOException;
 import java.net.Socket;
 import java.util.concurrent.TimeUnit;
 
+import android.net.TrafficStats;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.http.conn.routing.HttpRoute;
@@ -185,7 +185,7 @@
                 try {
                     final Socket socket = entry.getConnection().getSocket();
                     if (socket != null) {
-                        SocketTagger.get().tag(socket);
+                        TrafficStats.tagSocket(socket);
                     }
                 } catch (IOException iox) {
                     log.debug("Problem tagging socket.", iox);
@@ -220,7 +220,7 @@
             final BasicPoolEntry entry = (BasicPoolEntry) hca.getPoolEntry();
             final Socket socket = entry.getConnection().getSocket();
             if (socket != null) {
-                SocketTagger.get().untag(socket);
+                TrafficStats.untagSocket(socket);
             }
             // END android-changed
 
diff --git a/src/org/apache/http/impl/io/SocketInputBuffer.java b/src/org/apache/http/impl/io/SocketInputBuffer.java
index f525833..5e1869c 100644
--- a/src/org/apache/http/impl/io/SocketInputBuffer.java
+++ b/src/org/apache/http/impl/io/SocketInputBuffer.java
@@ -101,8 +101,6 @@
      * 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()) {