13713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick/*
23713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Copyright (C) 2011 The Android Open Source Project
33713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick *
43713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Licensed under the Apache License, Version 2.0 (the "License");
53713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * you may not use this file except in compliance with the License.
63713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * You may obtain a copy of the License at
73713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick *
83713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick *      http://www.apache.org/licenses/LICENSE-2.0
93713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick *
103713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Unless required by applicable law or agreed to in writing, software
113713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * distributed under the License is distributed on an "AS IS" BASIS,
123713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * See the License for the specific language governing permissions and
143713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * limitations under the License.
153713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick */
163713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
173713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickpackage com.android.volley.toolbox;
183713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
199c19fc62ddd9d1b371cb3ead4e10bb5ff1100a6cJeff Sharkeyimport android.os.SystemClock;
209c19fc62ddd9d1b371cb3ead4e10bb5ff1100a6cJeff Sharkey
213713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport com.android.volley.AuthFailureError;
223713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport com.android.volley.Cache;
233713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport com.android.volley.Network;
243713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport com.android.volley.NetworkError;
253713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport com.android.volley.NetworkResponse;
263713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport com.android.volley.NoConnectionError;
273713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport com.android.volley.Request;
283713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport com.android.volley.RetryPolicy;
293713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport com.android.volley.ServerError;
303713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport com.android.volley.TimeoutError;
313713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport com.android.volley.VolleyError;
323713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport com.android.volley.VolleyLog;
333713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
343713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport org.apache.http.Header;
353713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport org.apache.http.HttpEntity;
363713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport org.apache.http.HttpResponse;
373713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport org.apache.http.HttpStatus;
383713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport org.apache.http.StatusLine;
393713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport org.apache.http.conn.ConnectTimeoutException;
403713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport org.apache.http.impl.cookie.DateUtils;
413713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
423713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.io.IOException;
433713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.io.InputStream;
443713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.net.MalformedURLException;
453713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.net.SocketTimeoutException;
463713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.util.Date;
473713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.util.HashMap;
483713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.util.Map;
493713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
503713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick/**
513713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * A network performing Volley requests over an {@link HttpStack}.
523713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick */
533713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickpublic class BasicNetwork implements Network {
543713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    protected static final boolean DEBUG = VolleyLog.DEBUG;
553713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
563713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private static int SLOW_REQUEST_THRESHOLD_MS = 3000;
573713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
58c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta    private static int DEFAULT_POOL_SIZE = 4096;
59c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta
603713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    protected final HttpStack mHttpStack;
613713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
62c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta    protected final ByteArrayPool mPool;
63c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta
643713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    /**
653713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     * @param httpStack HTTP stack to be used
663713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     */
673713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public BasicNetwork(HttpStack httpStack) {
68c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta        // If a pool isn't passed in, then build a small default pool that will give us a lot of
69c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta        // benefit and not use too much memory.
70c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta        this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));
71c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta    }
72c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta
73c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta    /**
74c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta     * @param httpStack HTTP stack to be used
75c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta     * @param pool a buffer pool that improves GC performance in copy operations
76c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta     */
77c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta    public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) {
783713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        mHttpStack = httpStack;
79c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta        mPool = pool;
803713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
813713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
823713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    @Override
833713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public NetworkResponse performRequest(Request<?> request) throws VolleyError {
849c19fc62ddd9d1b371cb3ead4e10bb5ff1100a6cJeff Sharkey        long requestStart = SystemClock.elapsedRealtime();
853713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        while (true) {
863713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            HttpResponse httpResponse = null;
873713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            byte[] responseContents = null;
883713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            Map<String, String> responseHeaders = new HashMap<String, String>();
893713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            try {
903713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                // Gather headers.
913713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                Map<String, String> headers = new HashMap<String, String>();
923713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                addCacheHeaders(headers, request.getCacheEntry());
933713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                httpResponse = mHttpStack.performRequest(request, headers);
943713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                StatusLine statusLine = httpResponse.getStatusLine();
953713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
963713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                responseHeaders = convertHeaders(httpResponse.getAllHeaders());
973713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                // Handle cache validation.
983713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                if (statusLine.getStatusCode() == HttpStatus.SC_NOT_MODIFIED) {
993713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,
1003713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                            request.getCacheEntry().data, responseHeaders, true);
1013713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                }
1023713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1033713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                responseContents = entityToBytes(httpResponse.getEntity());
1043713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                // if the request is slow, log it.
1059c19fc62ddd9d1b371cb3ead4e10bb5ff1100a6cJeff Sharkey                long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
1063713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                logSlowRequests(requestLifetime, request, responseContents, statusLine);
1073713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1083713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
1093713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    throw new IOException();
1103713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                }
1113713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                return new NetworkResponse(HttpStatus.SC_OK,
1123713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                        responseContents, responseHeaders, false);
1133713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            } catch (SocketTimeoutException e) {
1143713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                attemptRetryOnException("socket", request, new TimeoutError());
1153713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            } catch (ConnectTimeoutException e) {
1163713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                attemptRetryOnException("connection", request, new TimeoutError());
1173713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            } catch (MalformedURLException e) {
1183713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                throw new RuntimeException("Bad URL " + request.getUrl(), e);
1193713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            } catch (IOException e) {
1203713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                int statusCode = 0;
1213713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                NetworkResponse networkResponse = null;
1223713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                if (httpResponse != null) {
1233713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    statusCode = httpResponse.getStatusLine().getStatusCode();
1243713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                } else {
1253713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    throw new NoConnectionError(e);
1263713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                }
1273713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
1283713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                if (responseContents != null) {
1293713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    networkResponse = new NetworkResponse(statusCode, responseContents,
1303713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                            responseHeaders, false);
1313713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
1323713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                            statusCode == HttpStatus.SC_FORBIDDEN) {
1333713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                        attemptRetryOnException("auth",
1343713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                                request, new AuthFailureError(networkResponse));
1353713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    } else {
1363713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                        // TODO: Only throw ServerError for 5xx status codes.
1373713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                        throw new ServerError(networkResponse);
1383713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    }
1393713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                } else {
1403713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    throw new NetworkError(networkResponse);
1413713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                }
1423713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            }
1433713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        }
1443713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
1453713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1463713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    /**
1473713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     * Logs requests that took over SLOW_REQUEST_THRESHOLD_MS to complete.
1483713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     */
1493713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private void logSlowRequests(long requestLifetime, Request<?> request,
1503713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            byte[] responseContents, StatusLine statusLine) {
1513713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        if (DEBUG || requestLifetime > SLOW_REQUEST_THRESHOLD_MS) {
1523713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            VolleyLog.d("HTTP response for request=<%s> [lifetime=%d], [size=%s], " +
1533713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    "[rc=%d], [retryCount=%s]", request, requestLifetime,
1543713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    responseContents != null ? responseContents.length : "null",
1553713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    statusLine.getStatusCode(), request.getRetryPolicy().getCurrentRetryCount());
1563713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        }
1573713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
1583713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1593713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    /**
1603713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     * Attempts to prepare the request for a retry. If there are no more attempts remaining in the
1613713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     * request's retry policy, a timeout exception is thrown.
1623713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     * @param request The request to use.
1633713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     */
1643713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private static void attemptRetryOnException(String logPrefix, Request<?> request,
1653713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            VolleyError exception) throws VolleyError {
1663713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        RetryPolicy retryPolicy = request.getRetryPolicy();
1673713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        int oldTimeout = request.getTimeoutMs();
1683713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1693713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        try {
1703713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            retryPolicy.retry(exception);
1713713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        } catch (VolleyError e) {
1723713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            request.addMarker(
1733713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout));
1743713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            throw e;
1753713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        }
1763713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout));
1773713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
1783713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1793713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private void addCacheHeaders(Map<String, String> headers, Cache.Entry entry) {
1803713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        // If there's no cache entry, we're done.
1813713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        if (entry == null) {
1823713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            return;
1833713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        }
1843713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1853713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        if (entry.etag != null) {
1863713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            headers.put("If-None-Match", entry.etag);
1873713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        }
1883713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1893713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        if (entry.serverDate > 0) {
1903713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            Date refTime = new Date(entry.serverDate);
1913713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            headers.put("If-Modified-Since", DateUtils.formatDate(refTime));
1923713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        }
1933713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
1943713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1953713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    protected void logError(String what, String url, long start) {
1969c19fc62ddd9d1b371cb3ead4e10bb5ff1100a6cJeff Sharkey        long now = SystemClock.elapsedRealtime();
1973713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        VolleyLog.v("HTTP ERROR(%s) %d ms to fetch %s", what, (now - start), url);
1983713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
1993713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
2003713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    /** Reads the contents of HttpEntity into a byte[]. */
201c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta    private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError {
202c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta        PoolingByteArrayOutputStream bytes =
203c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta                new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength());
204c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta        byte[] buffer = null;
2053713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        try {
2063713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            InputStream in = entity.getContent();
2073713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            if (in == null) {
2083713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                throw new ServerError();
2093713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            }
210c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta            buffer = mPool.getBuf(1024);
2113713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            int count;
2123713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            while ((count = in.read(buffer)) != -1) {
2133713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                bytes.write(buffer, 0, count);
2143713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            }
2153713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            return bytes.toByteArray();
2163713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        } finally {
2173713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            try {
2183713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                // Close the InputStream and release the resources by "consuming the content".
2193713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                entity.consumeContent();
2203713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            } catch (IOException e) {
2213713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                // This can happen if there was an exception above that left the entity in
2223713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                // an invalid state.
2233713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                VolleyLog.v("Error occured when calling consumingContent");
2243713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            }
225c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta            mPool.returnBuf(buffer);
226c4cbfcb8d044cea99e2471ce5c401cd959b6cdfeScott Barta            bytes.close();
2273713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        }
2283713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
2293713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
2303713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    /**
2313713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     * Converts Headers[] to Map<String, String>.
2323713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     */
2333713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private static Map<String, String> convertHeaders(Header[] headers) {
2343713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        Map<String, String> result = new HashMap<String, String>();
2353713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        for (int i = 0; i < headers.length; i++) {
2363713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            result.put(headers[i].getName(), headers[i].getValue());
2373713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        }
2383713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        return result;
2393713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
2403713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick}
241