19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 172269d1572e5fcfb725ea55f5764d8c3280d69f6dDianne Hackbornpackage android.net.http; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 197cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilsonimport com.android.internal.http.HttpDateTime; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.Header; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.HttpEntity; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.HttpEntityEnclosingRequest; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.HttpException; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.HttpHost; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.HttpRequest; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.HttpRequestInterceptor; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.HttpResponse; 28992f238d13fff7c21b60ef6958784a4ed2156784Brian Carlstromimport org.apache.http.entity.AbstractHttpEntity; 29992f238d13fff7c21b60ef6958784a4ed2156784Brian Carlstromimport org.apache.http.entity.ByteArrayEntity; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.client.HttpClient; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.client.ResponseHandler; 32992f238d13fff7c21b60ef6958784a4ed2156784Brian Carlstromimport org.apache.http.client.ClientProtocolException; 33992f238d13fff7c21b60ef6958784a4ed2156784Brian Carlstromimport org.apache.http.client.protocol.ClientContext; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.client.methods.HttpUriRequest; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.client.params.HttpClientParams; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.conn.ClientConnectionManager; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.conn.scheme.PlainSocketFactory; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.conn.scheme.Scheme; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.conn.scheme.SchemeRegistry; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.impl.client.DefaultHttpClient; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.impl.client.RequestWrapper; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.params.BasicHttpParams; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.params.HttpConnectionParams; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.params.HttpParams; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.params.HttpProtocolParams; 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.protocol.BasicHttpProcessor; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.protocol.HttpContext; 49992f238d13fff7c21b60ef6958784a4ed2156784Brian Carlstromimport org.apache.http.protocol.BasicHttpContext; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.InputStream; 53992f238d13fff7c21b60ef6958784a4ed2156784Brian Carlstromimport java.io.ByteArrayOutputStream; 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStream; 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.zip.GZIPInputStream; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.zip.GZIPOutputStream; 57992f238d13fff7c21b60ef6958784a4ed2156784Brian Carlstromimport java.net.URI; 58992f238d13fff7c21b60ef6958784a4ed2156784Brian Carlstrom 59992f238d13fff7c21b60ef6958784a4ed2156784Brian Carlstromimport android.content.Context; 60992f238d13fff7c21b60ef6958784a4ed2156784Brian Carlstromimport android.content.ContentResolver; 61992f238d13fff7c21b60ef6958784a4ed2156784Brian Carlstromimport android.net.SSLCertificateSocketFactory; 62992f238d13fff7c21b60ef6958784a4ed2156784Brian Carlstromimport android.net.SSLSessionCache; 63992f238d13fff7c21b60ef6958784a4ed2156784Brian Carlstromimport android.os.Looper; 64992f238d13fff7c21b60ef6958784a4ed2156784Brian Carlstromimport android.util.Base64; 65992f238d13fff7c21b60ef6958784a4ed2156784Brian Carlstromimport android.util.Log; 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 687b91b31e28097b468db4cc2c6ac1a8e4064d8027Elliott Hughes * Implementation of the Apache {@link DefaultHttpClient} that is configured with 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * reasonable default settings and registered schemes for Android, and 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * also lets the user add {@link HttpRequestInterceptor} classes. 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Don't create this directly, use the {@link #newInstance} factory method. 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>This client processes cookies but does not retain them by default. 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * To retain cookies, simply add a cookie store to the HttpContext:</p> 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre>context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);</pre> 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic final class AndroidHttpClient implements HttpClient { 7960586f2ec65d16d185767fce4311d3ed0e9112acDan Egnor 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Gzip of data shorter than this probably won't be worthwhile 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static long DEFAULT_SYNC_MIN_GZIP_BYTES = 256; 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 83d39fd5a97c6f56794a6ed7ac1dfb0bbf585becf1Henrik Baard // Default connection and socket timeout of 60 seconds. Tweak to taste. 84d39fd5a97c6f56794a6ed7ac1dfb0bbf585becf1Henrik Baard private static final int SOCKET_OPERATION_TIMEOUT = 60 * 1000; 85d39fd5a97c6f56794a6ed7ac1dfb0bbf585becf1Henrik Baard 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String TAG = "AndroidHttpClient"; 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 88d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert private static String[] textContentTypes = new String[] { 89d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert "text/", 90d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert "application/xml", 91d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert "application/json" 92d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert }; 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Interceptor throws an exception if the executing thread is blocked */ 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final HttpRequestInterceptor sThreadCheckInterceptor = 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new HttpRequestInterceptor() { 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void process(HttpRequest request, HttpContext context) { 987762d93621f508f4410fd37b5bbdfec0071b0420Paul Westbrook // Prevent the HttpRequest from being sent on the main thread 997762d93621f508f4410fd37b5bbdfec0071b0420Paul Westbrook if (Looper.myLooper() != null && Looper.myLooper() == Looper.getMainLooper() ) { 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new RuntimeException("This thread forbids HTTP requests"); 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Create a new HttpClient with reasonable defaults (which you can update). 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10860586f2ec65d16d185767fce4311d3ed0e9112acDan Egnor * @param userAgent to report in your HTTP requests 10960586f2ec65d16d185767fce4311d3ed0e9112acDan Egnor * @param context to use for caching SSL sessions (may be null for no caching) 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return AndroidHttpClient for you to use for all your requests. 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11260586f2ec65d16d185767fce4311d3ed0e9112acDan Egnor public static AndroidHttpClient newInstance(String userAgent, Context context) { 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HttpParams params = new BasicHttpParams(); 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Turn off stale checking. Our connections break all the time anyway, 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // and it's not worth it to pay the penalty of checking every time. 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HttpConnectionParams.setStaleCheckingEnabled(params, false); 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 119d39fd5a97c6f56794a6ed7ac1dfb0bbf585becf1Henrik Baard HttpConnectionParams.setConnectionTimeout(params, SOCKET_OPERATION_TIMEOUT); 120d39fd5a97c6f56794a6ed7ac1dfb0bbf585becf1Henrik Baard HttpConnectionParams.setSoTimeout(params, SOCKET_OPERATION_TIMEOUT); 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HttpConnectionParams.setSocketBufferSize(params, 8192); 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Don't handle redirects -- return them to the caller. Our code 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // often wants to re-POST after a redirect, which we must do ourselves. 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HttpClientParams.setRedirecting(params, false); 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12760586f2ec65d16d185767fce4311d3ed0e9112acDan Egnor // Use a session cache for SSL sockets 12860586f2ec65d16d185767fce4311d3ed0e9112acDan Egnor SSLSessionCache sessionCache = context == null ? null : new SSLSessionCache(context); 12960586f2ec65d16d185767fce4311d3ed0e9112acDan Egnor 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Set the specified user agent and register standard protocols. 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HttpProtocolParams.setUserAgent(params, userAgent); 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SchemeRegistry schemeRegistry = new SchemeRegistry(); 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project schemeRegistry.register(new Scheme("http", 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PlainSocketFactory.getSocketFactory(), 80)); 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project schemeRegistry.register(new Scheme("https", 136d39fd5a97c6f56794a6ed7ac1dfb0bbf585becf1Henrik Baard SSLCertificateSocketFactory.getHttpSocketFactory( 137992f238d13fff7c21b60ef6958784a4ed2156784Brian Carlstrom SOCKET_OPERATION_TIMEOUT, sessionCache), 443)); 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ClientConnectionManager manager = 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new ThreadSafeClientConnManager(params, schemeRegistry); 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We use a factory method to modify superclass initialization 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // parameters without the funny call-a-static-method dance. 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new AndroidHttpClient(manager, params); 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Create a new HttpClient with reasonable defaults (which you can update). 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param userAgent to report in your HTTP requests. 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return AndroidHttpClient for you to use for all your requests. 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static AndroidHttpClient newInstance(String userAgent) { 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return newInstance(userAgent, null /* session cache */); 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final HttpClient delegate; 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private RuntimeException mLeakedException = new IllegalStateException( 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "AndroidHttpClient created and never closed"); 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private AndroidHttpClient(ClientConnectionManager ccm, HttpParams params) { 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.delegate = new DefaultHttpClient(ccm, params) { 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected BasicHttpProcessor createHttpProcessor() { 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Add interceptor to prevent making requests from main thread. 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BasicHttpProcessor processor = super.createHttpProcessor(); 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project processor.addRequestInterceptor(sThreadCheckInterceptor); 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project processor.addRequestInterceptor(new CurlLogger()); 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return processor; 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected HttpContext createHttpContext() { 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Same as DefaultHttpClient.createHttpContext() minus the 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // cookie store. 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HttpContext context = new BasicHttpContext(); 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project context.setAttribute( 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ClientContext.AUTHSCHEME_REGISTRY, 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getAuthSchemes()); 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project context.setAttribute( 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ClientContext.COOKIESPEC_REGISTRY, 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getCookieSpecs()); 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project context.setAttribute( 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ClientContext.CREDS_PROVIDER, 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getCredentialsProvider()); 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return context; 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void finalize() throws Throwable { 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.finalize(); 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLeakedException != null) { 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Leak found", mLeakedException); 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLeakedException = null; 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Modifies a request to indicate to the server that we would like a 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * gzipped response. (Uses the "Accept-Encoding" HTTP header.) 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param request the request to modify 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #getUngzippedContent 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void modifyRequestToAcceptGzipResponse(HttpRequest request) { 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project request.addHeader("Accept-Encoding", "gzip"); 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the input stream from a response entity. If the entity is gzipped 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * then this will get a stream over the uncompressed data. 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param entity the entity whose content should be read 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the input stream to read from 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws IOException 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static InputStream getUngzippedContent(HttpEntity entity) 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws IOException { 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project InputStream responseStream = entity.getContent(); 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (responseStream == null) return responseStream; 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Header header = entity.getContentEncoding(); 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (header == null) return responseStream; 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String contentEncoding = header.getValue(); 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (contentEncoding == null) return responseStream; 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (contentEncoding.contains("gzip")) responseStream 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project = new GZIPInputStream(responseStream); 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return responseStream; 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Release resources associated with this client. You must call this, 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or significant resources (sockets and memory) may be leaked. 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void close() { 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mLeakedException != null) { 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getConnectionManager().shutdown(); 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLeakedException = null; 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public HttpParams getParams() { 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return delegate.getParams(); 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public ClientConnectionManager getConnectionManager() { 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return delegate.getConnectionManager(); 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public HttpResponse execute(HttpUriRequest request) throws IOException { 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return delegate.execute(request); 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public HttpResponse execute(HttpUriRequest request, HttpContext context) 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws IOException { 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return delegate.execute(request, context); 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public HttpResponse execute(HttpHost target, HttpRequest request) 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws IOException { 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return delegate.execute(target, request); 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public HttpResponse execute(HttpHost target, HttpRequest request, 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HttpContext context) throws IOException { 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return delegate.execute(target, request, context); 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public <T> T execute(HttpUriRequest request, 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ResponseHandler<? extends T> responseHandler) 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws IOException, ClientProtocolException { 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return delegate.execute(request, responseHandler); 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public <T> T execute(HttpUriRequest request, 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ResponseHandler<? extends T> responseHandler, HttpContext context) 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws IOException, ClientProtocolException { 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return delegate.execute(request, responseHandler, context); 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public <T> T execute(HttpHost target, HttpRequest request, 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ResponseHandler<? extends T> responseHandler) throws IOException, 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ClientProtocolException { 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return delegate.execute(target, request, responseHandler); 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public <T> T execute(HttpHost target, HttpRequest request, 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ResponseHandler<? extends T> responseHandler, HttpContext context) 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws IOException, ClientProtocolException { 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return delegate.execute(target, request, responseHandler, context); 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Compress data to send to server. 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Creates a Http Entity holding the gzipped data. 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The data will not be compressed if it is too short. 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param data The bytes to compress 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Entity holding the data 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static AbstractHttpEntity getCompressedEntity(byte data[], ContentResolver resolver) 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws IOException { 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AbstractHttpEntity entity; 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (data.length < getMinGzipSize(resolver)) { 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project entity = new ByteArrayEntity(data); 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ByteArrayOutputStream arr = new ByteArrayOutputStream(); 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project OutputStream zipper = new GZIPOutputStream(arr); 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project zipper.write(data); 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project zipper.close(); 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project entity = new ByteArrayEntity(arr.toByteArray()); 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project entity.setContentEncoding("gzip"); 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return entity; 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Retrieves the minimum size for compressing data. 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Shorter data will not be compressed. 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static long getMinGzipSize(ContentResolver resolver) { 32260586f2ec65d16d185767fce4311d3ed0e9112acDan Egnor return DEFAULT_SYNC_MIN_GZIP_BYTES; // For now, this is just a constant. 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* cURL logging support. */ 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Logging tag and level. 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static class LoggingConfiguration { 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final String tag; 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final int level; 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private LoggingConfiguration(String tag, int level) { 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.tag = tag; 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.level = level; 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns true if logging is turned on for this configuration. 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean isLoggable() { 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Log.isLoggable(tag, level); 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Prints a message using this configuration. 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void println(String message) { 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.println(level, tag, message); 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** cURL logging configuration. */ 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private volatile LoggingConfiguration curlConfiguration; 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enables cURL request logging for this client. 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param name to log messages with 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param level at which to log messages (see {@link android.util.Log}) 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void enableCurlLogging(String name, int level) { 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (name == null) { 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new NullPointerException("name"); 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (level < Log.VERBOSE || level > Log.ASSERT) { 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("Level is out of range [" 370d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert + Log.VERBOSE + ".." + Log.ASSERT + "]"); 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project curlConfiguration = new LoggingConfiguration(name, level); 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Disables cURL logging for this client. 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void disableCurlLogging() { 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project curlConfiguration = null; 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Logs cURL commands equivalent to requests. 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class CurlLogger implements HttpRequestInterceptor { 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void process(HttpRequest request, HttpContext context) 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws HttpException, IOException { 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LoggingConfiguration configuration = curlConfiguration; 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (configuration != null 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && configuration.isLoggable() 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && request instanceof HttpUriRequest) { 39360586f2ec65d16d185767fce4311d3ed0e9112acDan Egnor // Never print auth token -- we used to check ro.secure=0 to 39460586f2ec65d16d185767fce4311d3ed0e9112acDan Egnor // enable that, but can't do that in unbundled code. 39560586f2ec65d16d185767fce4311d3ed0e9112acDan Egnor configuration.println(toCurl((HttpUriRequest) request, false)); 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Generates a cURL command equivalent to the given request. 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String toCurl(HttpUriRequest request, boolean logAuthToken) throws IOException { 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder builder = new StringBuilder(); 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project builder.append("curl "); 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (Header header: request.getAllHeaders()) { 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!logAuthToken 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && (header.getName().equals("Authorization") || 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project header.getName().equals("Cookie"))) { 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project builder.append("--header \""); 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project builder.append(header.toString().trim()); 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project builder.append("\" "); 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project URI uri = request.getURI(); 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If this is a wrapped request, use the URI from the original 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // request instead. getURI() on the wrapper seems to return a 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // relative URI. We want an absolute URI. 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (request instanceof RequestWrapper) { 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HttpRequest original = ((RequestWrapper) request).getOriginal(); 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (original instanceof HttpUriRequest) { 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project uri = ((HttpUriRequest) original).getURI(); 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project builder.append("\""); 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project builder.append(uri); 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project builder.append("\""); 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (request instanceof HttpEntityEnclosingRequest) { 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HttpEntityEnclosingRequest entityRequest = 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (HttpEntityEnclosingRequest) request; 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HttpEntity entity = entityRequest.getEntity(); 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (entity != null && entity.isRepeatable()) { 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (entity.getContentLength() < 1024) { 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ByteArrayOutputStream stream = new ByteArrayOutputStream(); 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project entity.writeTo(stream); 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 444d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert if (isBinaryContent(request)) { 445d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert String base64 = Base64.encodeToString(stream.toByteArray(), Base64.NO_WRAP); 446d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert builder.insert(0, "echo '" + base64 + "' | base64 -d > /tmp/$$.bin; "); 447d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert builder.append(" --data-binary @/tmp/$$.bin"); 448d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert } else { 449d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert String entityString = stream.toString(); 450d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert builder.append(" --data-ascii \"") 451d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert .append(entityString) 452d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert .append("\""); 453d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert } 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project builder.append(" [TOO MUCH DATA TO INCLUDE]"); 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return builder.toString(); 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4627cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson 463d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert private static boolean isBinaryContent(HttpUriRequest request) { 464d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert Header[] headers; 465d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert headers = request.getHeaders(Headers.CONTENT_ENCODING); 466d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert if (headers != null) { 467d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert for (Header header : headers) { 468d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert if ("gzip".equalsIgnoreCase(header.getValue())) { 469d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert return true; 470d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert } 471d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert } 472d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert } 473d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert 474d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert headers = request.getHeaders(Headers.CONTENT_TYPE); 475d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert if (headers != null) { 476d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert for (Header header : headers) { 477d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert for (String contentType : textContentTypes) { 478d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert if (header.getValue().startsWith(contentType)) { 479d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert return false; 480d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert } 481d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert } 482d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert } 483d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert } 484d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert return true; 485d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert } 486d81689aefcf57cfb692b73161b1a00511a90ee1eAlon Albert 4877cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson /** 4887cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson * Returns the date of the given HTTP date string. This method can identify 4897cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson * and parse the date formats emitted by common HTTP servers, such as 4907cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson * <a href="http://www.ietf.org/rfc/rfc0822.txt">RFC 822</a>, 4917cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson * <a href="http://www.ietf.org/rfc/rfc0850.txt">RFC 850</a>, 4927cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson * <a href="http://www.ietf.org/rfc/rfc1036.txt">RFC 1036</a>, 4937cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson * <a href="http://www.ietf.org/rfc/rfc1123.txt">RFC 1123</a> and 4947cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson * <a href="http://www.opengroup.org/onlinepubs/007908799/xsh/asctime.html">ANSI 4957cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson * C's asctime()</a>. 4967cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson * 4977cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson * @return the number of milliseconds since Jan. 1, 1970, midnight GMT. 4987cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson * @throws IllegalArgumentException if {@code dateString} is not a date or 4997cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson * of an unsupported format. 5007cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson */ 5017cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson public static long parseDate(String dateString) { 5027cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson return HttpDateTime.parse(dateString); 5037cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson } 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 505