1d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru/* 2d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Copyright (C) 2011 The Android Open Source Project 3d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 4d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Licensed under the Apache License, Version 2.0 (the "License"); 5d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * you may not use this file except in compliance with the License. 6d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * You may obtain a copy of the License at 7d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 8d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * http://www.apache.org/licenses/LICENSE-2.0 9d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 10d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Unless required by applicable law or agreed to in writing, software 11d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * distributed under the License is distributed on an "AS IS" BASIS, 12d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * See the License for the specific language governing permissions and 14d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * limitations under the License. 15d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 16d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 17d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Querupackage com.android.volley.toolbox; 18d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 19d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport android.os.SystemClock; 20d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 21d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport com.android.volley.AuthFailureError; 22d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport com.android.volley.Cache; 2319a40379b22eeb21991fb1c55cf45788e62188b2Ralph Bergmannimport com.android.volley.Cache.Entry; 24d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport com.android.volley.Network; 25d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport com.android.volley.NetworkError; 26d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport com.android.volley.NetworkResponse; 27d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport com.android.volley.NoConnectionError; 28d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport com.android.volley.Request; 29d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport com.android.volley.RetryPolicy; 30d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport com.android.volley.ServerError; 31d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport com.android.volley.TimeoutError; 32d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport com.android.volley.VolleyError; 33d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport com.android.volley.VolleyLog; 34d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 35d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.Header; 36d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.HttpEntity; 37d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.HttpResponse; 38d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.HttpStatus; 39d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.StatusLine; 40d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.conn.ConnectTimeoutException; 41d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport org.apache.http.impl.cookie.DateUtils; 42d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 43d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.io.IOException; 44d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.io.InputStream; 45d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.net.MalformedURLException; 46d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.net.SocketTimeoutException; 47ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmannimport java.util.Collections; 48d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.Date; 49d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.HashMap; 50d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.Map; 51ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmannimport java.util.TreeMap; 52d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 53d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru/** 54d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * A network performing Volley requests over an {@link HttpStack}. 55d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 56d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Querupublic class BasicNetwork implements Network { 57d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru protected static final boolean DEBUG = VolleyLog.DEBUG; 58d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 59d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private static int SLOW_REQUEST_THRESHOLD_MS = 3000; 60d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 61d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private static int DEFAULT_POOL_SIZE = 4096; 62d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 63d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru protected final HttpStack mHttpStack; 64d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 65d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru protected final ByteArrayPool mPool; 66d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 67d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 68d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param httpStack HTTP stack to be used 69d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 70d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public BasicNetwork(HttpStack httpStack) { 71d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // If a pool isn't passed in, then build a small default pool that will give us a lot of 72d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // benefit and not use too much memory. 73d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE)); 74d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 75d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 76d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 77d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param httpStack HTTP stack to be used 78d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param pool a buffer pool that improves GC performance in copy operations 79d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 80d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) { 81d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mHttpStack = httpStack; 82d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mPool = pool; 83d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 84d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 85d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru @Override 86d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public NetworkResponse performRequest(Request<?> request) throws VolleyError { 87d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru long requestStart = SystemClock.elapsedRealtime(); 88d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru while (true) { 89d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru HttpResponse httpResponse = null; 90d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru byte[] responseContents = null; 91ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann Map<String, String> responseHeaders = Collections.emptyMap(); 92d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru try { 93d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // Gather headers. 94d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru Map<String, String> headers = new HashMap<String, String>(); 95d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru addCacheHeaders(headers, request.getCacheEntry()); 96d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru httpResponse = mHttpStack.performRequest(request, headers); 97d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru StatusLine statusLine = httpResponse.getStatusLine(); 98cd8ce543d0a51dac9f6308cd8730816f690ead2fJon Boekenoogen int statusCode = statusLine.getStatusCode(); 99d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 100d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru responseHeaders = convertHeaders(httpResponse.getAllHeaders()); 101d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // Handle cache validation. 102cd8ce543d0a51dac9f6308cd8730816f690ead2fJon Boekenoogen if (statusCode == HttpStatus.SC_NOT_MODIFIED) { 10319a40379b22eeb21991fb1c55cf45788e62188b2Ralph Bergmann 10419a40379b22eeb21991fb1c55cf45788e62188b2Ralph Bergmann Entry entry = request.getCacheEntry(); 10519a40379b22eeb21991fb1c55cf45788e62188b2Ralph Bergmann if (entry == null) { 10619a40379b22eeb21991fb1c55cf45788e62188b2Ralph Bergmann return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null, 107750c5b995f4f326c7b30ab88eda20b25285dd2f7Ivan Stalev responseHeaders, true, 108750c5b995f4f326c7b30ab88eda20b25285dd2f7Ivan Stalev SystemClock.elapsedRealtime() - requestStart); 10919a40379b22eeb21991fb1c55cf45788e62188b2Ralph Bergmann } 11019a40379b22eeb21991fb1c55cf45788e62188b2Ralph Bergmann 11119a40379b22eeb21991fb1c55cf45788e62188b2Ralph Bergmann // A HTTP 304 response does not have all header fields. We 11219a40379b22eeb21991fb1c55cf45788e62188b2Ralph Bergmann // have to use the header fields from the cache entry plus 11319a40379b22eeb21991fb1c55cf45788e62188b2Ralph Bergmann // the new ones from the response. 11419a40379b22eeb21991fb1c55cf45788e62188b2Ralph Bergmann // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5 11519a40379b22eeb21991fb1c55cf45788e62188b2Ralph Bergmann entry.responseHeaders.putAll(responseHeaders); 11619a40379b22eeb21991fb1c55cf45788e62188b2Ralph Bergmann return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data, 117750c5b995f4f326c7b30ab88eda20b25285dd2f7Ivan Stalev entry.responseHeaders, true, 118750c5b995f4f326c7b30ab88eda20b25285dd2f7Ivan Stalev SystemClock.elapsedRealtime() - requestStart); 119d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 120d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 121e8f5353b17aea6659dc3aa13223317b484d01483Ray Colline // Some responses such as 204s do not have content. We must check. 122e8f5353b17aea6659dc3aa13223317b484d01483Ray Colline if (httpResponse.getEntity() != null) { 123e8f5353b17aea6659dc3aa13223317b484d01483Ray Colline responseContents = entityToBytes(httpResponse.getEntity()); 124e8f5353b17aea6659dc3aa13223317b484d01483Ray Colline } else { 125e8f5353b17aea6659dc3aa13223317b484d01483Ray Colline // Add 0 byte response as a way of honestly representing a 126e8f5353b17aea6659dc3aa13223317b484d01483Ray Colline // no-content request. 127e8f5353b17aea6659dc3aa13223317b484d01483Ray Colline responseContents = new byte[0]; 128e8f5353b17aea6659dc3aa13223317b484d01483Ray Colline } 129e8f5353b17aea6659dc3aa13223317b484d01483Ray Colline 130d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // if the request is slow, log it. 131d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru long requestLifetime = SystemClock.elapsedRealtime() - requestStart; 132d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru logSlowRequests(requestLifetime, request, responseContents, statusLine); 133d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 134f2cd36f7fa3932c2d7973eabb87fdb22a37e1bbcReed Ellsworth if (statusCode < 200 || statusCode > 299) { 135d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru throw new IOException(); 136d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 137750c5b995f4f326c7b30ab88eda20b25285dd2f7Ivan Stalev return new NetworkResponse(statusCode, responseContents, responseHeaders, false, 138750c5b995f4f326c7b30ab88eda20b25285dd2f7Ivan Stalev SystemClock.elapsedRealtime() - requestStart); 139d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } catch (SocketTimeoutException e) { 140d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru attemptRetryOnException("socket", request, new TimeoutError()); 141d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } catch (ConnectTimeoutException e) { 142d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru attemptRetryOnException("connection", request, new TimeoutError()); 143d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } catch (MalformedURLException e) { 144d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru throw new RuntimeException("Bad URL " + request.getUrl(), e); 145d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } catch (IOException e) { 146d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru int statusCode = 0; 147d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru NetworkResponse networkResponse = null; 148d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (httpResponse != null) { 149d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru statusCode = httpResponse.getStatusLine().getStatusCode(); 150d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } else { 151d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru throw new NoConnectionError(e); 152d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 153d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl()); 154d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (responseContents != null) { 155d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru networkResponse = new NetworkResponse(statusCode, responseContents, 156750c5b995f4f326c7b30ab88eda20b25285dd2f7Ivan Stalev responseHeaders, false, SystemClock.elapsedRealtime() - requestStart); 157d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (statusCode == HttpStatus.SC_UNAUTHORIZED || 158d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru statusCode == HttpStatus.SC_FORBIDDEN) { 159d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru attemptRetryOnException("auth", 160d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru request, new AuthFailureError(networkResponse)); 161d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } else { 162d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // TODO: Only throw ServerError for 5xx status codes. 163d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru throw new ServerError(networkResponse); 164d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 165d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } else { 166d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru throw new NetworkError(networkResponse); 167d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 168d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 169d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 170d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 171d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 172d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 173d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Logs requests that took over SLOW_REQUEST_THRESHOLD_MS to complete. 174d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 175d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private void logSlowRequests(long requestLifetime, Request<?> request, 176d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru byte[] responseContents, StatusLine statusLine) { 177d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (DEBUG || requestLifetime > SLOW_REQUEST_THRESHOLD_MS) { 178d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru VolleyLog.d("HTTP response for request=<%s> [lifetime=%d], [size=%s], " + 179d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru "[rc=%d], [retryCount=%s]", request, requestLifetime, 180d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru responseContents != null ? responseContents.length : "null", 181d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru statusLine.getStatusCode(), request.getRetryPolicy().getCurrentRetryCount()); 182d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 183d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 184d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 185d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 186d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Attempts to prepare the request for a retry. If there are no more attempts remaining in the 187d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * request's retry policy, a timeout exception is thrown. 188d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param request The request to use. 189d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 190d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private static void attemptRetryOnException(String logPrefix, Request<?> request, 191d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru VolleyError exception) throws VolleyError { 192d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru RetryPolicy retryPolicy = request.getRetryPolicy(); 193d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru int oldTimeout = request.getTimeoutMs(); 194d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 195d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru try { 196d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru retryPolicy.retry(exception); 197d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } catch (VolleyError e) { 198d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru request.addMarker( 199d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout)); 200d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru throw e; 201d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 202d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout)); 203d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 204d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 205d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private void addCacheHeaders(Map<String, String> headers, Cache.Entry entry) { 206d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // If there's no cache entry, we're done. 207d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (entry == null) { 208d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru return; 209d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 210d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 211d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (entry.etag != null) { 212d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("If-None-Match", entry.etag); 213d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 214d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 2159324df1b8046548587ffec89ec755264f6fbb097Ralph Bergmann if (entry.lastModified > 0) { 2169324df1b8046548587ffec89ec755264f6fbb097Ralph Bergmann Date refTime = new Date(entry.lastModified); 217d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("If-Modified-Since", DateUtils.formatDate(refTime)); 218d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 219d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 220d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 221d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru protected void logError(String what, String url, long start) { 222d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru long now = SystemClock.elapsedRealtime(); 223d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru VolleyLog.v("HTTP ERROR(%s) %d ms to fetch %s", what, (now - start), url); 224d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 225d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 226d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** Reads the contents of HttpEntity into a byte[]. */ 227d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError { 228d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru PoolingByteArrayOutputStream bytes = 229d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength()); 230d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru byte[] buffer = null; 231d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru try { 232d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru InputStream in = entity.getContent(); 233d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (in == null) { 234d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru throw new ServerError(); 235d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 236d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru buffer = mPool.getBuf(1024); 237d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru int count; 238d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru while ((count = in.read(buffer)) != -1) { 239d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru bytes.write(buffer, 0, count); 240d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 241d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru return bytes.toByteArray(); 242d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } finally { 243d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru try { 244d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // Close the InputStream and release the resources by "consuming the content". 245d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru entity.consumeContent(); 246d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } catch (IOException e) { 247d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // This can happen if there was an exception above that left the entity in 248d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // an invalid state. 249d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru VolleyLog.v("Error occured when calling consumingContent"); 250d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 251d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mPool.returnBuf(buffer); 252d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru bytes.close(); 253d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 254d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 255d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 256d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 257d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Converts Headers[] to Map<String, String>. 258d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 259ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann protected static Map<String, String> convertHeaders(Header[] headers) { 260ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann Map<String, String> result = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER); 261d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru for (int i = 0; i < headers.length; i++) { 262d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru result.put(headers[i].getName(), headers[i].getValue()); 263d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 264d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru return result; 265d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 266d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru} 267