Skip to content

Commit 1a6c55c

Browse files
committed
[cdp][java] Allow filters to recover from failed requests in NetworkInterceptor
This change introduces a new exception, which is thrown through the user's filter chain when the browser fails to get a response for a request and a NetworkInterceptor is in use. This gives the filter an opportunity to catch the exception and return a custom HTTP response. Related to #13774
1 parent ffb03bd commit 1a6c55c

File tree

3 files changed

+64
-3
lines changed

3 files changed

+64
-3
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.devtools;
19+
20+
import org.openqa.selenium.WebDriverException;
21+
import org.openqa.selenium.remote.http.Filter;
22+
import org.openqa.selenium.remote.http.HttpHandler;
23+
24+
/**
25+
* This exception is thrown by the final {@link HttpHandler} in a {@link Filter} chain when the
26+
* browser fails to send a HTTP request. It can be caught in a {@link Filter} to handle the error
27+
* by, for example, returning a custom HTTP response.
28+
*/
29+
public class RequestFailedException extends WebDriverException {
30+
}

java/src/org/openqa/selenium/devtools/idealized/Network.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.openqa.selenium.devtools.DevToolsException;
4646
import org.openqa.selenium.devtools.Event;
4747
import org.openqa.selenium.devtools.NetworkInterceptor;
48+
import org.openqa.selenium.devtools.RequestFailedException;
4849
import org.openqa.selenium.internal.Either;
4950
import org.openqa.selenium.internal.Require;
5051
import org.openqa.selenium.remote.http.Contents;
@@ -202,8 +203,12 @@ public void prepareToInterceptTraffic() {
202203
String id = getRequestId(pausedRequest);
203204

204205
if (hasErrorResponse(pausedRequest)) {
205-
pendingResponses.remove(id);
206-
devTools.send(continueWithoutModification(pausedRequest));
206+
CompletableFuture<HttpResponse> future = pendingResponses.remove(id);
207+
if (future == null) {
208+
devTools.send(continueWithoutModification(pausedRequest));
209+
} else {
210+
future.completeExceptionally(new RequestFailedException());
211+
}
207212
return;
208213
}
209214

@@ -244,6 +249,11 @@ public void prepareToInterceptTraffic() {
244249
pendingResponses.remove(id);
245250
return STOP_PROCESSING;
246251
} catch (ExecutionException e) {
252+
if (e.getCause() instanceof RequestFailedException) {
253+
// Throwing here will give the user's filter a chance to intercept
254+
// the failure and handle it.
255+
throw (RequestFailedException) e.getCause();
256+
}
247257
if (fetchEnabled.get()) {
248258
LOG.log(WARNING, e, () -> "Unable to process request");
249259
}
@@ -261,6 +271,10 @@ public void prepareToInterceptTraffic() {
261271
}
262272

263273
devTools.send(fulfillRequest(pausedRequest, forBrowser));
274+
} catch (RequestFailedException e) {
275+
// If the exception reaches here, we know the user's filter has not handled it and the
276+
// browser should continue its normal error handling.
277+
devTools.send(continueWithoutModification(pausedRequest));
264278
} catch (TimeoutException e) {
265279
if (fetchEnabled.get()) {
266280
throw e;

java/test/org/openqa/selenium/devtools/NetworkInterceptorTest.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,11 +254,28 @@ void shouldHandleRedirects() {
254254

255255
@Test
256256
@NoDriverBeforeTest
257-
void shouldProceedAsNormalIfRequestResultInAnKnownError() {
257+
void shouldProceedAsNormalIfRequestResultInAnKnownErrorAndExceptionNotCaughtByFilter() {
258258
Filter filter = next -> next;
259259
try (NetworkInterceptor ignored = new NetworkInterceptor(driver, filter)) {
260260
assertThatExceptionOfType(WebDriverException.class)
261261
.isThrownBy(() -> driver.get("http://localhost:" + PortProber.findFreePort()));
262262
}
263263
}
264+
265+
@Test
266+
@NoDriverBeforeTest
267+
void shouldPassResponseBackToBrowserIfRequestResultsInAnKnownErrorAndExceptionCaughtByFilter() {
268+
Filter filter = next -> req -> {
269+
try {
270+
return next.execute(req);
271+
} catch (RequestFailedException e) {
272+
return new HttpResponse().setStatus(200).setContent(Contents.utf8String("Hello, World!"));
273+
}
274+
};
275+
try (NetworkInterceptor ignored = new NetworkInterceptor(driver, filter)) {
276+
driver.get("http://localhost:" + PortProber.findFreePort());
277+
String body = driver.findElement(By.tagName("body")).getText();
278+
assertThat(body).contains("Hello, World!");
279+
}
280+
}
264281
}

0 commit comments

Comments
 (0)