void spewInternal() { if (pending.remaining() > 0) { com.koushikdutta.async.Util.emitAllData(BodySpewer.this, pending); if (pending.remaining() > 0) return; } // fill pending try { while (pending.remaining() == 0) { ByteBuffer buffer = ByteBuffer.allocate(8192); int read = cacheResponse.getBody().read(buffer.array()); if (read == -1) { allowEnd = true; report(null); return; } buffer.limit(read); pending.add(buffer); com.koushikdutta.async.Util.emitAllData(BodySpewer.this, pending); } } catch (IOException e) { allowEnd = true; report(e); } }
/** * Initialize the source for this response. It may be corrected later if the request headers * forbids network use. */ private void initResponseSource() throws IOException { responseSource = ResponseSource.NETWORK; if (!policy.getUseCaches()) return; OkResponseCache responseCache = client.getOkResponseCache(); if (responseCache == null) return; CacheResponse candidate = responseCache.get(uri, method, requestHeaders.getHeaders().toMultimap(false)); if (candidate == null) return; Map<String, List<String>> responseHeadersMap = candidate.getHeaders(); cachedResponseBody = candidate.getBody(); if (!acceptCacheResponseType(candidate) || responseHeadersMap == null || cachedResponseBody == null) { Util.closeQuietly(cachedResponseBody); return; } RawHeaders rawResponseHeaders = RawHeaders.fromMultimap(responseHeadersMap, true); cachedResponseHeaders = new ResponseHeaders(uri, rawResponseHeaders); long now = System.currentTimeMillis(); this.responseSource = cachedResponseHeaders.chooseResponseSource(now, requestHeaders); if (responseSource == ResponseSource.CACHE) { this.cacheResponse = candidate; setResponse(cachedResponseHeaders, cachedResponseBody); } else if (responseSource == ResponseSource.CONDITIONAL_CACHE) { this.cacheResponse = candidate; } else if (responseSource == ResponseSource.NETWORK) { Util.closeQuietly(cachedResponseBody); } else { throw new AssertionError(); } }
/** * Figures out what the response source will be, and opens a socket to that source if necessary. * Prepares the request headers and gets ready to start writing the request body if it exists. */ public final void sendRequest() throws IOException { if (responseSource != null) { return; } prepareRawRequestHeaders(); initResponseSource(); OkResponseCache responseCache = client.getOkResponseCache(); if (responseCache != null) { responseCache.trackResponse(responseSource); } // The raw response source may require the network, but the request // headers may forbid network use. In that case, dispose of the network // response and use a GATEWAY_TIMEOUT response instead, as specified // by http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4. if (requestHeaders.isOnlyIfCached() && responseSource.requiresConnection()) { if (responseSource == ResponseSource.CONDITIONAL_CACHE) { Util.closeQuietly(cachedResponseBody); } this.responseSource = ResponseSource.CACHE; this.cacheResponse = GATEWAY_TIMEOUT_RESPONSE; RawHeaders rawResponseHeaders = RawHeaders.fromMultimap(cacheResponse.getHeaders(), true); setResponse(new ResponseHeaders(uri, rawResponseHeaders), cacheResponse.getBody()); } if (responseSource.requiresConnection()) { sendSocketRequest(); } else if (connection != null) { client.getConnectionPool().recycle(connection); connection = null; } }
// Tries to get head and body from cache, return true if has got this time // or // already got before private boolean getFromCache() throws IOException { if (useCaches && null != responseCache && !hasTriedCache) { hasTriedCache = true; if (null == resHeader) { resHeader = new Header(); } cacheResponse = responseCache.get(uri, method, resHeader.getFieldMap()); if (null != cacheResponse) { Map<String, List<String>> headMap = cacheResponse.getHeaders(); if (null != headMap) { resHeader = new Header(headMap); } is = cacheResponse.getBody(); if (null != is) { return true; } } } if (hasTriedCache && null != is) { return true; } return false; }
// step 1) see if we can serve request from the cache directly. // also see if this can be turned into a conditional cache request. @Override public Cancellable getSocket(final GetSocketData data) { if (cache == null) return null; if (!caching) return null; if (data.request.getHeaders().isNoCache()) return null; // Log.i(LOGTAG, "getting cache socket: " + request.getUri().toString()); String key = uriToKey(data.request.getUri()); DiskLruCache.Snapshot snapshot; Entry entry; try { snapshot = cache.get(key); if (snapshot == null) { // Log.i(LOGTAG, "snapshot fail"); return null; } entry = new Entry(snapshot.getInputStream(ENTRY_METADATA)); } catch (IOException e) { // Give up because the cache cannot be read. return null; } if (!entry.matches( data.request.getUri(), data.request.getMethod(), data.request.getHeaders().getHeaders().toMultimap())) { snapshot.close(); return null; } ResponseSource responseSource = ResponseSource.NETWORK; CacheResponse candidate = entry.isHttps() ? new EntrySecureCacheResponse(entry, snapshot) : new EntryCacheResponse(entry, snapshot); Map<String, List<String>> responseHeadersMap; InputStream cachedResponseBody; try { responseHeadersMap = candidate.getHeaders(); cachedResponseBody = candidate.getBody(); } catch (Exception e) { return null; } if (responseHeadersMap == null || cachedResponseBody == null) { try { cachedResponseBody.close(); } catch (Exception e) { } return null; } RawHeaders rawResponseHeaders = RawHeaders.fromMultimap(responseHeadersMap); ResponseHeaders cachedResponseHeaders = new ResponseHeaders(data.request.getUri(), rawResponseHeaders); long now = System.currentTimeMillis(); responseSource = cachedResponseHeaders.chooseResponseSource(now, data.request.getHeaders()); if (responseSource == ResponseSource.CACHE) { cacheStoreCount++; final CachedSocket socket = entry.isHttps() ? new CachedSSLSocket((EntrySecureCacheResponse) candidate) : new CachedSocket((EntryCacheResponse) candidate); client .getServer() .post( new Runnable() { @Override public void run() { data.connectCallback.onConnectCompleted(null, socket); socket.spewInternal(); } }); } else if (responseSource == ResponseSource.CONDITIONAL_CACHE) { CacheData cacheData = new CacheData(); cacheData.cachedResponseHeaders = cachedResponseHeaders; cacheData.candidate = candidate; data.state.putParcelable("cache-data", cacheData); return null; } else { // NETWORK or other try { cachedResponseBody.close(); } catch (Exception e) { } return null; } return new SimpleCancelable(); }