aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/android/volley/toolbox/BasicNetwork.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/android/volley/toolbox/BasicNetwork.java')
-rw-r--r--src/main/java/com/android/volley/toolbox/BasicNetwork.java230
1 files changed, 12 insertions, 218 deletions
diff --git a/src/main/java/com/android/volley/toolbox/BasicNetwork.java b/src/main/java/com/android/volley/toolbox/BasicNetwork.java
index b527cb9..06427fe 100644
--- a/src/main/java/com/android/volley/toolbox/BasicNetwork.java
+++ b/src/main/java/com/android/volley/toolbox/BasicNetwork.java
@@ -17,41 +17,21 @@
package com.android.volley.toolbox;
import android.os.SystemClock;
-import com.android.volley.AuthFailureError;
-import com.android.volley.Cache;
-import com.android.volley.Cache.Entry;
-import com.android.volley.ClientError;
import com.android.volley.Header;
import com.android.volley.Network;
-import com.android.volley.NetworkError;
import com.android.volley.NetworkResponse;
-import com.android.volley.NoConnectionError;
import com.android.volley.Request;
-import com.android.volley.RetryPolicy;
-import com.android.volley.ServerError;
-import com.android.volley.TimeoutError;
import com.android.volley.VolleyError;
-import com.android.volley.VolleyLog;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.SocketTimeoutException;
-import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.TreeMap;
-import java.util.TreeSet;
/** A network performing Volley requests over an {@link HttpStack}. */
public class BasicNetwork implements Network {
- protected static final boolean DEBUG = VolleyLog.DEBUG;
-
- private static final int SLOW_REQUEST_THRESHOLD_MS = 3000;
-
private static final int DEFAULT_POOL_SIZE = 4096;
/**
@@ -119,37 +99,24 @@ public class BasicNetwork implements Network {
try {
// Gather headers.
Map<String, String> additionalRequestHeaders =
- getCacheHeaders(request.getCacheEntry());
+ HttpHeaderParser.getCacheHeaders(request.getCacheEntry());
httpResponse = mBaseHttpStack.executeRequest(request, additionalRequestHeaders);
int statusCode = httpResponse.getStatusCode();
responseHeaders = httpResponse.getHeaders();
// Handle cache validation.
if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) {
- Entry entry = request.getCacheEntry();
- if (entry == null) {
- return new NetworkResponse(
- HttpURLConnection.HTTP_NOT_MODIFIED,
- /* data= */ null,
- /* notModified= */ true,
- SystemClock.elapsedRealtime() - requestStart,
- responseHeaders);
- }
- // Combine cached and response headers so the response will be complete.
- List<Header> combinedHeaders = combineHeaders(responseHeaders, entry);
- return new NetworkResponse(
- HttpURLConnection.HTTP_NOT_MODIFIED,
- entry.data,
- /* notModified= */ true,
- SystemClock.elapsedRealtime() - requestStart,
- combinedHeaders);
+ long requestDuration = SystemClock.elapsedRealtime() - requestStart;
+ return NetworkUtility.getNotModifiedNetworkResponse(
+ request, requestDuration, responseHeaders);
}
// Some responses such as 204s do not have content. We must check.
InputStream inputStream = httpResponse.getContent();
if (inputStream != null) {
responseContents =
- inputStreamToBytes(inputStream, httpResponse.getContentLength());
+ NetworkUtility.inputStreamToBytes(
+ inputStream, httpResponse.getContentLength(), mPool);
} else {
// Add 0 byte response as a way of honestly representing a
// no-content request.
@@ -158,7 +125,8 @@ public class BasicNetwork implements Network {
// if the request is slow, log it.
long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
- logSlowRequests(requestLifetime, request, responseContents, statusCode);
+ NetworkUtility.logSlowRequests(
+ requestLifetime, request, responseContents, statusCode);
if (statusCode < 200 || statusCode > 299) {
throw new IOException();
@@ -169,141 +137,12 @@ public class BasicNetwork implements Network {
/* notModified= */ false,
SystemClock.elapsedRealtime() - requestStart,
responseHeaders);
- } catch (SocketTimeoutException e) {
- attemptRetryOnException("socket", request, new TimeoutError());
- } catch (MalformedURLException e) {
- throw new RuntimeException("Bad URL " + request.getUrl(), e);
- } catch (IOException e) {
- int statusCode;
- if (httpResponse != null) {
- statusCode = httpResponse.getStatusCode();
- } else {
- throw new NoConnectionError(e);
- }
- VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
- NetworkResponse networkResponse;
- if (responseContents != null) {
- networkResponse =
- new NetworkResponse(
- statusCode,
- responseContents,
- /* notModified= */ false,
- SystemClock.elapsedRealtime() - requestStart,
- responseHeaders);
- if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED
- || statusCode == HttpURLConnection.HTTP_FORBIDDEN) {
- attemptRetryOnException(
- "auth", request, new AuthFailureError(networkResponse));
- } else if (statusCode >= 400 && statusCode <= 499) {
- // Don't retry other client errors.
- throw new ClientError(networkResponse);
- } else if (statusCode >= 500 && statusCode <= 599) {
- if (request.shouldRetryServerErrors()) {
- attemptRetryOnException(
- "server", request, new ServerError(networkResponse));
- } else {
- throw new ServerError(networkResponse);
- }
- } else {
- // 3xx? No reason to retry.
- throw new ServerError(networkResponse);
- }
- } else {
- attemptRetryOnException("network", request, new NetworkError());
- }
- }
- }
- }
-
- /** Logs requests that took over SLOW_REQUEST_THRESHOLD_MS to complete. */
- private void logSlowRequests(
- long requestLifetime, Request<?> request, byte[] responseContents, int statusCode) {
- if (DEBUG || requestLifetime > SLOW_REQUEST_THRESHOLD_MS) {
- VolleyLog.d(
- "HTTP response for request=<%s> [lifetime=%d], [size=%s], "
- + "[rc=%d], [retryCount=%s]",
- request,
- requestLifetime,
- responseContents != null ? responseContents.length : "null",
- statusCode,
- request.getRetryPolicy().getCurrentRetryCount());
- }
- }
-
- /**
- * Attempts to prepare the request for a retry. If there are no more attempts remaining in the
- * request's retry policy, a timeout exception is thrown.
- *
- * @param request The request to use.
- */
- private static void attemptRetryOnException(
- String logPrefix, Request<?> request, VolleyError exception) throws VolleyError {
- RetryPolicy retryPolicy = request.getRetryPolicy();
- int oldTimeout = request.getTimeoutMs();
-
- try {
- retryPolicy.retry(exception);
- } catch (VolleyError e) {
- request.addMarker(
- String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout));
- throw e;
- }
- request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout));
- }
-
- private Map<String, String> getCacheHeaders(Cache.Entry entry) {
- // If there's no cache entry, we're done.
- if (entry == null) {
- return Collections.emptyMap();
- }
-
- Map<String, String> headers = new HashMap<>();
-
- if (entry.etag != null) {
- headers.put("If-None-Match", entry.etag);
- }
-
- if (entry.lastModified > 0) {
- headers.put(
- "If-Modified-Since", HttpHeaderParser.formatEpochAsRfc1123(entry.lastModified));
- }
-
- return headers;
- }
-
- protected void logError(String what, String url, long start) {
- long now = SystemClock.elapsedRealtime();
- VolleyLog.v("HTTP ERROR(%s) %d ms to fetch %s", what, (now - start), url);
- }
-
- /** Reads the contents of an InputStream into a byte[]. */
- private byte[] inputStreamToBytes(InputStream in, int contentLength)
- throws IOException, ServerError {
- PoolingByteArrayOutputStream bytes = new PoolingByteArrayOutputStream(mPool, contentLength);
- byte[] buffer = null;
- try {
- if (in == null) {
- throw new ServerError();
- }
- buffer = mPool.getBuf(1024);
- int count;
- while ((count = in.read(buffer)) != -1) {
- bytes.write(buffer, 0, count);
- }
- return bytes.toByteArray();
- } finally {
- try {
- // Close the InputStream and release the resources by "consuming the content".
- if (in != null) {
- in.close();
- }
} catch (IOException e) {
- // This can happen if there was an exception above that left the stream in
- // an invalid state.
- VolleyLog.v("Error occurred when closing InputStream");
+ // This will either throw an exception, breaking us from the loop, or will loop
+ // again and retry the request.
+ NetworkUtility.handleException(
+ request, e, requestStart, httpResponse, responseContents);
}
- mPool.returnBuf(buffer);
- bytes.close();
}
}
@@ -321,49 +160,4 @@ public class BasicNetwork implements Network {
}
return result;
}
-
- /**
- * Combine cache headers with network response headers for an HTTP 304 response.
- *
- * <p>An HTTP 304 response does not have all header fields. We have to use the header fields
- * from the cache entry plus the new ones from the response. See also:
- * http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
- *
- * @param responseHeaders Headers from the network response.
- * @param entry The cached response.
- * @return The combined list of headers.
- */
- private static List<Header> combineHeaders(List<Header> responseHeaders, Entry entry) {
- // First, create a case-insensitive set of header names from the network
- // response.
- Set<String> headerNamesFromNetworkResponse = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
- if (!responseHeaders.isEmpty()) {
- for (Header header : responseHeaders) {
- headerNamesFromNetworkResponse.add(header.getName());
- }
- }
-
- // Second, add headers from the cache entry to the network response as long as
- // they didn't appear in the network response, which should take precedence.
- List<Header> combinedHeaders = new ArrayList<>(responseHeaders);
- if (entry.allResponseHeaders != null) {
- if (!entry.allResponseHeaders.isEmpty()) {
- for (Header header : entry.allResponseHeaders) {
- if (!headerNamesFromNetworkResponse.contains(header.getName())) {
- combinedHeaders.add(header);
- }
- }
- }
- } else {
- // Legacy caches only have entry.responseHeaders.
- if (!entry.responseHeaders.isEmpty()) {
- for (Map.Entry<String, String> header : entry.responseHeaders.entrySet()) {
- if (!headerNamesFromNetworkResponse.contains(header.getKey())) {
- combinedHeaders.add(new Header(header.getKey(), header.getValue()));
- }
- }
- }
- }
- return combinedHeaders;
- }
}