Skip to content

Commit

Permalink
Fix issue with HttpCache causes HttpParseException
Browse files Browse the repository at this point in the history
  • Loading branch information
sav007 committed Mar 27, 2020
1 parent 1bf4a92 commit 9841251
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,10 @@ interface HttpCache {
* Do not store the http response
*/
const val CACHE_DO_NOT_STORE = "X-APOLLO-CACHE-DO-NOT-STORE"

/**
* Signals that HTTP response comes from the local cache
*/
const val FROM_CACHE = "X-APOLLO-FROM-CACHE"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public void close() throws IOException {
String contentType = response.header("Content-Type");
String contentLength = response.header("Content-Length");
return response.newBuilder()
.addHeader(FROM_CACHE, "true")
.body(new CacheResponseBody(cacheResponseSource, contentType, contentLength))
.build();
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
final class ResponseBodyProxy extends ResponseBody {
private final String contentType;
private final String contentLength;
private final Source responseBodySource;
private final BufferedSource responseBodySource;

ResponseBodyProxy(@NotNull HttpCacheRecordEditor cacheRecordEditor, @NotNull Response sourceResponse,
@NotNull ApolloLogger logger) {
Expand All @@ -31,7 +31,7 @@ final class ResponseBodyProxy extends ResponseBody {
checkNotNull(logger, "logger == null");
this.contentType = sourceResponse.header("Content-Type");
this.contentLength = sourceResponse.header("Content-Length");
this.responseBodySource = new ProxySource(cacheRecordEditor, sourceResponse.body().source(), logger);
this.responseBodySource = Okio.buffer(new ProxySource(cacheRecordEditor, sourceResponse.body().source(), logger));
}

@Override public MediaType contentType() {
Expand All @@ -46,18 +46,18 @@ final class ResponseBodyProxy extends ResponseBody {
}
}

@Override public BufferedSource source() {
return Okio.buffer(responseBodySource);
@NotNull @Override public BufferedSource source() {
return responseBodySource;
}

private static class ProxySource implements Source {
final HttpCacheRecordEditor cacheRecordEditor;
final ResponseBodyCacheSink responseBodyCacheSink;
final Source responseBodySource;
final ApolloLogger logger;
boolean closed;
private final HttpCacheRecordEditor cacheRecordEditor;
private final ResponseBodyCacheSink responseBodyCacheSink;
private final BufferedSource responseBodySource;
private final ApolloLogger logger;
private boolean closed;

ProxySource(HttpCacheRecordEditor cacheRecordEditor, Source responseBodySource, final ApolloLogger logger) {
ProxySource(HttpCacheRecordEditor cacheRecordEditor, BufferedSource responseBodySource, final ApolloLogger logger) {
this.cacheRecordEditor = cacheRecordEditor;
this.responseBodySource = responseBodySource;
this.logger = logger;
Expand Down Expand Up @@ -95,24 +95,23 @@ private static class ProxySource implements Source {
return bytesRead;
}

@Override public Timeout timeout() {
@NotNull @Override public Timeout timeout() {
return responseBodySource.timeout();
}

@Override public void close() throws IOException {
@Override public void close() {
if (closed) return;
closed = true;

if (discard(this, 100, MILLISECONDS)) {
responseBodySource.close();
commitCache();
} else {
responseBodySource.close();
abortCacheQuietly();
}
}

private void commitCache() {
closeQuietly(responseBodySource);
try {
responseBodyCacheSink.close();
cacheRecordEditor.commit();
Expand All @@ -124,11 +123,12 @@ private void commitCache() {
}

void abortCacheQuietly() {
closeQuietly(responseBodySource);
closeQuietly(responseBodyCacheSink);
try {
cacheRecordEditor.abort();
} catch (Exception ignore) {
logger.w(ignore, "Failed to abort cache edit");
} catch (Exception e) {
logger.w(e, "Failed to abort cache edit");
}
}
}
Expand Down
1 change: 1 addition & 0 deletions gradle/dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ ext.dep = [
okHttp : [
mockWebServer: "com.squareup.okhttp3:mockwebserver:$versions.okHttp",
okHttp : "com.squareup.okhttp3:okhttp:$versions.okHttp",
logging : "com.squareup.okhttp3:logging-interceptor:$versions.okHttp",
],
okio : [
okio : "com.squareup.okio:okio:$versions.okio",
Expand Down
2 changes: 2 additions & 0 deletions samples/kotlin-sample/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ dependencies {
add("implementation", "com.apollographql.apollo:apollo-rx2-support")
add("implementation", "com.apollographql.apollo:apollo-coroutines-support")
add("implementation", "com.apollographql.apollo:apollo-runtime")
add("implementation", "com.apollographql.apollo:apollo-http-cache")
add("implementation", groovy.util.Eval.x(project, "x.dep.okHttp.logging"))
add("implementation", groovy.util.Eval.x(project, "x.dep.android.appcompat"))
add("implementation", groovy.util.Eval.x(project, "x.dep.android.recyclerView"))
add("implementation", groovy.util.Eval.x(project, "x.dep.kotlin.coroutines.android"))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package com.apollographql.apollo.kotlinsample

import android.app.Application
import android.util.Log
import com.apollographql.apollo.ApolloClient
import com.apollographql.apollo.api.Operation
import com.apollographql.apollo.api.ResponseField
import com.apollographql.apollo.api.cache.http.HttpCachePolicy
import com.apollographql.apollo.cache.http.ApolloHttpCache
import com.apollographql.apollo.cache.http.DiskLruHttpCacheStore
import com.apollographql.apollo.cache.normalized.CacheKey
import com.apollographql.apollo.cache.normalized.CacheKeyResolver
import com.apollographql.apollo.cache.normalized.sql.ApolloSqlHelper
Expand All @@ -13,11 +17,21 @@ import com.apollographql.apollo.kotlinsample.data.ApolloCoroutinesService
import com.apollographql.apollo.kotlinsample.data.ApolloRxService
import com.apollographql.apollo.kotlinsample.data.GitHubDataSource
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import java.io.File

@Suppress("unused")
class KotlinSampleApp : Application() {
private val baseUrl = "https://api.github.com/graphql"
private val apolloClient: ApolloClient by lazy {
val logInterceptor = HttpLoggingInterceptor(
object : HttpLoggingInterceptor.Logger {
override fun log(message: String) {
Log.d("OkHttp", message)
}
}
).apply { level = HttpLoggingInterceptor.Level.BODY }

val okHttpClient = OkHttpClient.Builder()
.addNetworkInterceptor { chain ->
val request = chain.request().newBuilder()
Expand All @@ -26,6 +40,7 @@ class KotlinSampleApp : Application() {

chain.proceed(request)
}
.addInterceptor(logInterceptor)
.build()

val apolloSqlHelper = ApolloSqlHelper.create(this, "github_cache")
Expand All @@ -44,9 +59,14 @@ class KotlinSampleApp : Application() {
}
}

// Create the http response cache store
val cacheStore = DiskLruHttpCacheStore(File(cacheDir, "apolloCache"), 1024 * 1024)

ApolloClient.builder()
.serverUrl(baseUrl)
.normalizedCache(sqlNormalizedCacheFactory, cacheKeyResolver)
.httpCache(ApolloHttpCache(cacheStore))
.defaultHttpCachePolicy(HttpCachePolicy.CACHE_FIRST)
.okHttpClient(okHttpClient)
.build()
}
Expand All @@ -71,4 +91,4 @@ class KotlinSampleApp : Application() {
RX_JAVA,
COROUTINES
}
}
}

0 comments on commit 9841251

Please sign in to comment.