25
25
import java .nio .charset .StandardCharsets ;
26
26
import java .util .ArrayList ;
27
27
import java .util .HashMap ;
28
+ import java .util .LinkedList ;
28
29
import java .util .List ;
30
+ import java .util .Map ;
29
31
import java .util .Objects ;
30
32
import java .util .Optional ;
31
33
import java .util .concurrent .CompletableFuture ;
34
+ import java .util .function .Supplier ;
32
35
import java .util .stream .Collectors ;
33
36
34
37
import io .literal .repository .ErrorRepository ;
35
38
import io .literal .repository .WebArchiveRepository ;
36
39
37
40
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
+ };
38
52
public static String KEY_WEB_REQUESTS = "WEB_REQUESTS" ;
39
53
public static String KEY_SCRIPT_ELEMENTS = "SCRIPT_ELEMENTS" ;
40
54
public static String KEY_STORAGE_OBJECT = "STORAGE_OBJECT" ;
41
55
public static String KEY_ID = "ID" ;
42
-
43
56
private final StorageObject storageObject ;
44
57
private final ArrayList <ParcelableWebResourceRequest > webRequests ;
45
58
private final ArrayList <HTMLScriptElement > scriptElements ;
@@ -93,24 +106,14 @@ public int describeContents() {
93
106
return 0 ;
94
107
}
95
108
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
-
108
109
public StorageObject getStorageObject () {
109
110
return storageObject ;
110
111
}
112
+
111
113
public List <ParcelableWebResourceRequest > getWebRequests () {
112
114
return webRequests ;
113
115
}
116
+
114
117
public List <HTMLScriptElement > getScriptElements () {
115
118
return scriptElements ;
116
119
}
@@ -130,13 +133,13 @@ public CompletableFuture<Void> open(Context context, User user) {
130
133
} catch (Exception innerException ) {
131
134
future .completeExceptionally (innerException );
132
135
} 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
+ }
140
143
}
141
144
return future ;
142
145
});
@@ -169,6 +172,7 @@ private void buildMimeBodyPartIndex(Context context, User user) {
169
172
(BodyPart ) bodyParts .get (0 )
170
173
);
171
174
}
175
+
172
176
public CompletableFuture <WebArchive > compile (Context context , User user ) {
173
177
if (this .getScriptElements ().size () == 0 && this .getWebRequests ().size () == 0 ) {
174
178
return CompletableFuture .completedFuture (this );
@@ -178,19 +182,27 @@ public CompletableFuture<WebArchive> compile(Context context, User user) {
178
182
.thenCompose (_file -> {
179
183
// For each web request not currently within the archive, execute it and build a BodyPart
180
184
HashMap <String , BodyPart > bodyPartByContentLocation = getBodyPartByContentLocation ();
185
+ Supplier <List <CompletableFuture <Optional <BodyPart >>>> supplier = () -> new LinkedList <>();
181
186
List <CompletableFuture <Optional <BodyPart >>> webRequestBodyPartFutures = getWebRequests ()
182
187
.stream ()
183
188
.filter (webResourceRequest -> !bodyPartByContentLocation .containsKey (webResourceRequest .getUrl ().toString ()))
184
189
.map (webResourceRequest ->
185
190
WebArchiveRepository .executeWebResourceRequest (webResourceRequest )
186
191
.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
+ })
187
200
)
188
201
.collect (Collectors .toList ());
189
-
190
202
return CompletableFuture .allOf (webRequestBodyPartFutures .toArray (new CompletableFuture [0 ]))
191
203
.thenApply (_void -> webRequestBodyPartFutures .stream ()
192
204
.map ((f ) -> f .getNow (Optional .empty ()).orElse (null ))
193
- .filter (f -> ! Objects . isNull ( f ) )
205
+ .filter (Objects :: nonNull )
194
206
.collect (Collectors .toList ()));
195
207
})
196
208
.thenCompose ((bodyParts ) -> {
0 commit comments