HttpNetwork implements Network { @Override public NetworkResponse performRequest(Request<?> request) throws JusError { long requestStart = System.nanoTime(); boolean serverAuthRequested = false; boolean proxyAuthRequested = false; while (true) { if (request.isCanceled()) { return null; } if (request.getNoConnectionPolicy() != null && request.getConnectivityManager() != null) { if (request.getConnectivityManager().getActiveNetwork() == null || !request.getConnectivityManager().getActiveNetwork().isConnected()) { JusError error = request.getNoConnectionPolicy().throwOnNoConnection(request); if (error != null) { throw error; } } } NetworkResponse httpResponse = null; try { Headers.Builder headers = new Headers.Builder(); addCacheHeaders(headers, request.getCacheEntry()); addServerAuthHeaders(request.getServerAuthenticator(), headers); addProxyAuthHeaders(request.getProxyAuthenticator(), headers); Headers extraHeaders = headers.build(); request.addMarker(Request.EVENT_NETWORK_STACK_SEND, request.getNetworkRequest(), extraHeaders); httpResponse = httpStack.performRequest(request, extraHeaders, pool); if (httpResponse == null) { throw new NetworkError("No Response"); } if (request.getRedirectPolicy() != null) { Request newR = request.getRedirectPolicy().verifyRedirect(request, httpResponse); Headers rHeaders = new Headers.Builder().build(); while (newR != null) { request.addMarker(Request.EVENT_NETWORK_STACK_REDIRECT_SEND, newR); httpResponse = httpStack.performRequest(newR, rHeaders, pool); request.addMarker(Request.EVENT_NETWORK_STACK_REDIRECT_COMPLETE, httpResponse); newR = request.getRedirectPolicy().verifyRedirect(request, httpResponse); } } request.addMarker(Request.EVENT_NETWORK_STACK_COMPLETE, httpResponse); if (request.getRequestQueue() != null) { httpResponse = request.getRequestQueue().transformResponse(request, httpResponse); request.addMarker(Request.EVENT_NETWORK_TRANSFORM_COMPLETE, httpResponse); } if (httpResponse != null && httpResponse.headers != null) { String contentLen = httpResponse.headers.get(HTTP.CONTENT_LEN); if (contentLen != null) { int cLen = Integer.parseInt(contentLen); if (cLen > httpResponse.data.length && request.getMethod() != Request.Method.HEAD) { throw new NetworkError(httpResponse, "Response Body not completely " + "received"); } } } if (httpResponse.statusCode == HttpURLConnection.HTTP_UNAUTHORIZED) { request.addMarker(Request.EVENT_NETWORK_STACK_AUTH_ERROR, httpResponse); if (request.getServerAuthenticator() != null && !serverAuthRequested) { request.getServerAuthenticator().clearAuthValue(); try { request.getServerAuthenticator().getAuthValue(); } catch (AuthError authError) { throw authError; } request.addMarker(Request.EVENT_NETWORK_STACK_AUTH_ERROR_RESEND, httpResponse); serverAuthRequested = true; continue; } else { throw new AuthError(httpResponse); } } else if (httpResponse.statusCode == HttpURLConnection.HTTP_PROXY_AUTH) { request.addMarker(Request.EVENT_NETWORK_STACK_AUTH_PROXY_ERROR, httpResponse); if (request.getProxyAuthenticator() != null && !proxyAuthRequested) { request.getProxyAuthenticator().clearAuthValue(); try { request.getProxyAuthenticator().getAuthValue(); } catch (AuthError authError) { throw authError; } request.addMarker(Request.EVENT_NETWORK_STACK_AUTH_ERROR_RESEND, httpResponse); proxyAuthRequested = true; continue; } else { throw new AuthError(httpResponse); } } long requestLifetime = System.nanoTime() - requestStart; logSlowRequests(requestLifetime, request, httpResponse.data, httpResponse .statusCode); if (httpResponse.statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) { Entry entry = request.getCacheEntry(); if (entry != null) { final Map<String, List<String>> responseHeaders = httpResponse.headers.toMultimap(); final Map<String, List<String>> cacheHeaders = entry.responseHeaders.toMultimap(); Headers.Builder hBuilder = new Headers.Builder(); hBuilder.addMMap(responseHeaders); if (cacheHeaders != null) { for (Map.Entry<String, List<String>> hentry : cacheHeaders.entrySet()) { if (hentry.getKey() != null && !responseHeaders.containsKey(hentry.getKey())) { hBuilder.add(hentry.getKey(), hentry.getValue()); } } } httpResponse = new NetworkResponse( httpResponse.statusCode, entry.data, hBuilder.build(), System.nanoTime() - requestStart ); } else { httpResponse = new NetworkResponse( httpResponse.statusCode, null, httpResponse.headers, System.nanoTime() - requestStart ); } } else if (httpResponse.statusCode < 200 || httpResponse.statusCode > 299) { throw new IOException(); } return httpResponse; } catch (SocketTimeoutException e) { attemptRetryOnException("socket", request, new TimeoutError("socket Timeout", e)); } catch (MalformedURLException e) { throw new RuntimeException("Bad URL " + request.getUrlString(), e); } catch (IOException e) { NetworkResponse networkResponse; if (httpResponse != null) { networkResponse = httpResponse; } else { throw new NetworkError(e); } if (networkResponse != null) { if (networkResponse.statusCode == HttpURLConnection .HTTP_CLIENT_TIMEOUT) { attemptRetryOnException("http-client", request, new RequestError (networkResponse, "HTTP_CLIENT_TIMEOUT")); } else if (networkResponse.statusCode > 399 && networkResponse.statusCode < 500) { throw new RequestError(networkResponse); } else if (networkResponse.statusCode > 499) { attemptRetryOnException("server", request, new ServerError(networkResponse)); } else { throw new JusError(networkResponse, e); } } else { attemptRetryOnException("network", request, new NetworkError()); } } catch (AuthError authError) { throw authError; } } } HttpNetwork(HttpStack httpStack);  HttpNetwork(HttpStack httpStack, ByteArrayPool pool); @Override NetworkResponse performRequest(Request<?> request); static final int DEFAULT_POOL_SIZE; }
@Test public void headersAndPostParams() throws Exception { MockHttpStack mockHttpStack = new MockHttpStack(); final NetworkResponse fakeResponse = new NetworkResponse(200, "foobar".getBytes(), new Headers .Builder().add("requestheader", "foo").build(), 0); mockHttpStack.setResponseToReturn(fakeResponse); HttpNetwork httpNetwork = new HttpNetwork(mockHttpStack); Request<String> request = new Request<String>(Request.Method.GET, "http: @Override protected void deliverResponse(String response) { } }; request.setNetworkRequest(new FormEncodingBuilder() .add("requestpost", "foo") .builder().setHeader("requestheader", "foo").build()); httpNetwork.performRequest(request); assertEquals("foo", mockHttpStack.getLastHeaders().get("requestheader")); assertEquals("requestpost=foo", new String(mockHttpStack.getLastPostBody())); }
@Test public void cacheHeadersFromCache() throws Exception { MockHttpStack mockHttpStack = new MockHttpStack(); final NetworkResponse fakeResponse = new NetworkResponse(304, new byte[0], new Headers.Builder().add("responseheader", "response-foo").build(), 0); mockHttpStack.setResponseToReturn(fakeResponse); HttpNetwork httpNetwork = new HttpNetwork(mockHttpStack); Request<NetworkResponse> request = new Request<NetworkResponse>(Request.Method.GET, "http: @Override protected void deliverResponse(NetworkResponse response) { } @Override public Cache.Entry getCacheEntry() { Cache.Entry entry = new Cache.Entry(); entry.data = "cached-foo".getBytes(); entry.responseHeaders = new Headers.Builder() .add("Date: Sun, 15 May 2016 11:03:26 GMT") .add("ETag: W/\"123456\"") .add("Cache-Control: public, max-age=60, s-maxage=60") .add("Expires: Mon, 14 Nov 2016 11:03:26 GMT") .add("Vary: Accept") .add("Content-Location: /cache") .build(); return entry; } }; request.setNetworkRequest(new NetworkRequest.Builder() .setHeader("requestheader", "foo").build()); NetworkResponse networkResponse = httpNetwork.performRequest(request); assertEquals("foo", mockHttpStack.getLastHeaders().get("requestheader")); assertEquals("cached-foo", new String(networkResponse.data)); assertEquals("response-foo", networkResponse.headers.get("responseheader")); assertEquals("Sun, 15 May 2016 11:03:26 GMT", networkResponse.headers.get("Date")); assertEquals("W/\"123456\"", networkResponse.headers.get("ETag")); assertEquals("public, max-age=60, s-maxage=60", networkResponse.headers.get("Cache-Control")); assertEquals("Mon, 14 Nov 2016 11:03:26 GMT", networkResponse.headers.get("Expires")); assertEquals("Accept", networkResponse.headers.get("Vary")); assertEquals("/cache", networkResponse.headers.get("Content-Location")); }
@Test public void cacheHeadersFromResponse() throws Exception { MockHttpStack mockHttpStack = new MockHttpStack(); final NetworkResponse fakeResponse = new NetworkResponse(304, new byte[0], new Headers.Builder().add("responseheader", "response-foo") .add("Date: Sun, 15 May 2016 11:03:27 GMT") .add("ETag: W/\"123457\"") .add("Cache-Control: public, max-age=70, s-maxage=70") .add("Expires: Mon, 14 Nov 2016 11:03:27 GMT") .add("Vary: Accept7") .add("Content-Location: /response") .build(), 0); mockHttpStack.setResponseToReturn(fakeResponse); HttpNetwork httpNetwork = new HttpNetwork(mockHttpStack); Request<NetworkResponse> request = new Request<NetworkResponse>(Request.Method.GET, "http: @Override protected void deliverResponse(NetworkResponse response) { } @Override public Cache.Entry getCacheEntry() { Cache.Entry entry = new Cache.Entry(); entry.data = "cached-foo".getBytes(); entry.responseHeaders = new Headers.Builder() .add("Date: Sun, 15 May 2016 11:03:26 GMT") .add("ETag: W/\"123456\"") .add("Cache-Control: public, max-age=60, s-maxage=60") .add("Expires: Mon, 14 Nov 2016 11:03:26 GMT") .add("Vary: Accept") .add("Content-Location: /cache") .build(); return entry; } }; request.setNetworkRequest(new NetworkRequest.Builder() .setHeader("requestheader", "foo").build()); NetworkResponse networkResponse = httpNetwork.performRequest(request); assertEquals("foo", mockHttpStack.getLastHeaders().get("requestheader")); assertEquals("cached-foo", new String(networkResponse.data)); assertEquals("response-foo", networkResponse.headers.get("responseheader")); assertEquals(1,networkResponse.headers.values("Date").size()); assertEquals("Sun, 15 May 2016 11:03:27 GMT", networkResponse.headers.get("Date")); assertEquals(1,networkResponse.headers.values("ETag").size()); assertEquals("W/\"123457\"", networkResponse.headers.get("ETag")); assertEquals(1,networkResponse.headers.values("Cache-Control").size()); assertEquals("public, max-age=70, s-maxage=70", networkResponse.headers.get("Cache-Control")); assertEquals(1,networkResponse.headers.values("Expires").size()); assertEquals("Mon, 14 Nov 2016 11:03:27 GMT", networkResponse.headers.get("Expires")); assertEquals(1,networkResponse.headers.values("Vary").size()); assertEquals("Accept7", networkResponse.headers.get("Vary")); assertEquals(1,networkResponse.headers.values("Content-Location").size()); assertEquals("/response", networkResponse.headers.get("Content-Location")); }