Skip to content

Commit a09b398

Browse files
committed
fix: handle failure of optional web resource requests
1 parent 0d6bf53 commit a09b398

File tree

5 files changed

+53
-38
lines changed

5 files changed

+53
-38
lines changed

packages/android/app/src/full/java/io/literal/repository/ErrorRepository.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public static void captureException(Exception exception) {
4848
Log.d("captureException", "", exception);
4949
}
5050

51-
public static void captureException(Exception exception, Map<String, Object> context) {
51+
public static void captureException(Throwable exception, Map<String, Object> context) {
5252
if (!BuildConfig.DEBUG) {
5353
Sentry.pushScope();
5454
Sentry.configureScope((scope) -> context.forEach(scope::setContexts));

packages/android/app/src/main/java/io/literal/model/WebArchive.java

+34-22
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,34 @@
2525
import java.nio.charset.StandardCharsets;
2626
import java.util.ArrayList;
2727
import java.util.HashMap;
28+
import java.util.LinkedList;
2829
import java.util.List;
30+
import java.util.Map;
2931
import java.util.Objects;
3032
import java.util.Optional;
3133
import java.util.concurrent.CompletableFuture;
34+
import java.util.function.Supplier;
3235
import java.util.stream.Collectors;
3336

3437
import io.literal.repository.ErrorRepository;
3538
import io.literal.repository.WebArchiveRepository;
3639

3740
public class WebArchive implements Parcelable {
41+
public static final Creator<WebArchive> CREATOR = new Creator<WebArchive>() {
42+
@Override
43+
public WebArchive createFromParcel(Parcel in) {
44+
return new WebArchive(in);
45+
}
46+
47+
@Override
48+
public WebArchive[] newArray(int size) {
49+
return new WebArchive[size];
50+
}
51+
};
3852
public static String KEY_WEB_REQUESTS = "WEB_REQUESTS";
3953
public static String KEY_SCRIPT_ELEMENTS = "SCRIPT_ELEMENTS";
4054
public static String KEY_STORAGE_OBJECT = "STORAGE_OBJECT";
4155
public static String KEY_ID = "ID";
42-
4356
private final StorageObject storageObject;
4457
private final ArrayList<ParcelableWebResourceRequest> webRequests;
4558
private final ArrayList<HTMLScriptElement> scriptElements;
@@ -93,24 +106,14 @@ public int describeContents() {
93106
return 0;
94107
}
95108

96-
public static final Creator<WebArchive> CREATOR = new Creator<WebArchive>() {
97-
@Override
98-
public WebArchive createFromParcel(Parcel in) {
99-
return new WebArchive(in);
100-
}
101-
102-
@Override
103-
public WebArchive[] newArray(int size) {
104-
return new WebArchive[size];
105-
}
106-
};
107-
108109
public StorageObject getStorageObject() {
109110
return storageObject;
110111
}
112+
111113
public List<ParcelableWebResourceRequest> getWebRequests() {
112114
return webRequests;
113115
}
116+
114117
public List<HTMLScriptElement> getScriptElements() {
115118
return scriptElements;
116119
}
@@ -130,13 +133,13 @@ public CompletableFuture<Void> open(Context context, User user) {
130133
} catch (Exception innerException) {
131134
future.completeExceptionally(innerException);
132135
} finally {
133-
if (fileInputStream != null) {
134-
try {
135-
fileInputStream.close();
136-
} catch (IOException ioException) {
137-
ErrorRepository.captureException(ioException);
138-
}
139-
}
136+
if (fileInputStream != null) {
137+
try {
138+
fileInputStream.close();
139+
} catch (IOException ioException) {
140+
ErrorRepository.captureException(ioException);
141+
}
142+
}
140143
}
141144
return future;
142145
});
@@ -169,6 +172,7 @@ private void buildMimeBodyPartIndex(Context context, User user) {
169172
(BodyPart) bodyParts.get(0)
170173
);
171174
}
175+
172176
public CompletableFuture<WebArchive> compile(Context context, User user) {
173177
if (this.getScriptElements().size() == 0 && this.getWebRequests().size() == 0) {
174178
return CompletableFuture.completedFuture(this);
@@ -178,19 +182,27 @@ public CompletableFuture<WebArchive> compile(Context context, User user) {
178182
.thenCompose(_file -> {
179183
// For each web request not currently within the archive, execute it and build a BodyPart
180184
HashMap<String, BodyPart> bodyPartByContentLocation = getBodyPartByContentLocation();
185+
Supplier<List<CompletableFuture<Optional<BodyPart>>>> supplier = () -> new LinkedList<>();
181186
List<CompletableFuture<Optional<BodyPart>>> webRequestBodyPartFutures = getWebRequests()
182187
.stream()
183188
.filter(webResourceRequest -> !bodyPartByContentLocation.containsKey(webResourceRequest.getUrl().toString()))
184189
.map(webResourceRequest ->
185190
WebArchiveRepository.executeWebResourceRequest(webResourceRequest)
186191
.thenApply((responseBody) -> WebArchiveRepository.createBodyPart(webResourceRequest, responseBody))
192+
.<Optional<BodyPart>>handle((bodyPart, e) -> {
193+
// Tolerate any errors that occurred when replaying the web request - the asset we attempted to fetch may not be required.
194+
if (e != null) {
195+
ErrorRepository.captureException(e, Map.of("headers", WebArchiveRepository.getIdempotentRequestHeaders(webResourceRequest.getRequestHeaders())));
196+
return Optional.empty();
197+
}
198+
return bodyPart;
199+
})
187200
)
188201
.collect(Collectors.toList());
189-
190202
return CompletableFuture.allOf(webRequestBodyPartFutures.toArray(new CompletableFuture[0]))
191203
.thenApply(_void -> webRequestBodyPartFutures.stream()
192204
.map((f) -> f.getNow(Optional.empty()).orElse(null))
193-
.filter(f -> !Objects.isNull(f))
205+
.filter(Objects::nonNull)
194206
.collect(Collectors.toList()));
195207
})
196208
.thenCompose((bodyParts) -> {

packages/android/app/src/main/java/io/literal/repository/NotificationRepository.java

-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,6 @@ public static void annotationsCreatedNotificationStart(
150150
Optional<Bitmap> annotationHostFavicon,
151151
Pair<Integer, Integer> progress
152152
) {
153-
154153
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, context.getString(R.string.annotation_created_notification_channel_id))
155154
.setSmallIcon(R.drawable.ic_stat_name)
156155
.setColor(Color.BLACK)

packages/android/app/src/main/java/io/literal/repository/WebArchiveRepository.java

+17-13
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ public static Optional<BodyPart> createBodyPart(WebResourceRequest webResourceRe
113113
}
114114
}
115115

116-
public static CompletableFuture<ResponseBody> executeWebResourceRequest(WebResourceRequest webResourceRequest) {
117-
Map<String, String> filteredHeaders = webResourceRequest.getRequestHeaders().entrySet().stream()
116+
public static Map<String, String> getIdempotentRequestHeaders(Map<String, String> headers) {
117+
return headers.entrySet().stream()
118118
.collect(
119119
HashMap::new,
120120
(agg, entry) -> {
@@ -124,10 +124,12 @@ public static CompletableFuture<ResponseBody> executeWebResourceRequest(WebResou
124124
},
125125
HashMap::putAll
126126
);
127+
}
127128

129+
public static CompletableFuture<ResponseBody> executeWebResourceRequest(WebResourceRequest webResourceRequest) {
128130
Request request = new Request.Builder()
129131
.url(webResourceRequest.getUrl().toString())
130-
.headers(Headers.of(filteredHeaders))
132+
.headers(Headers.of(getIdempotentRequestHeaders(webResourceRequest.getRequestHeaders())))
131133
.build();
132134
CompletableFuture<ResponseBody> future = new CompletableFuture<>();
133135
client.newCall(request).enqueue(new Callback() {
@@ -138,17 +140,19 @@ public void onFailure(@NotNull Call call, @NotNull IOException e) {
138140

139141
@Override
140142
public void onResponse(@NotNull Call call, @NotNull Response response) {
141-
if (!response.isSuccessful()) {
142-
future.completeExceptionally(new IOException("Unexpected code: " + response));
143-
return;
144-
}
145-
146-
ResponseBody responseBody = response.body();
147-
if (responseBody == null) {
148-
future.completeExceptionally(new Exception("Response Body is null."));
149-
return;
143+
try (ResponseBody responseBody = response.body()) {
144+
if (!response.isSuccessful()) {
145+
future.completeExceptionally(new IOException("Unexpected code: " + response));
146+
return;
147+
}
148+
if (responseBody == null) {
149+
future.completeExceptionally(new Exception("Response Body is null."));
150+
return;
151+
}
152+
future.complete(responseBody);
153+
} catch (Exception e) {
154+
future.completeExceptionally(e);
150155
}
151-
future.complete(responseBody);
152156
}
153157
});
154158

packages/android/app/src/main/java/io/literal/ui/view/MessagingWebView.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public void postWebEvent(WebEvent webEvent) {
6464
),
6565
Uri.parse("*")
6666
);
67-
67+
6868
try {
6969
JSONObject loggedEvent = webEvent.toJSON(!webEvent.getType().startsWith("AUTH"));
7070
JSONObject properties = new JSONObject();

0 commit comments

Comments
 (0)