Skip to content

Commit

Permalink
[cdp][java] Allow filters to recover from failed requests in NetworkI…
Browse files Browse the repository at this point in the history
…nterceptor

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
  • Loading branch information
joebandenburg committed Apr 29, 2024
1 parent ffb03bd commit 12eba88
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 3 deletions.
13 changes: 13 additions & 0 deletions java/src/org/openqa/selenium/devtools/RequestFailedException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.openqa.selenium.devtools;

import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.remote.http.Filter;
import org.openqa.selenium.remote.http.HttpHandler;

/**
* This exception is thrown by the final {@link HttpHandler} in a {@link Filter} chain when the
* browser fails to send a HTTP request. It can be caught in a {@link Filter} to handle the error
* by, for example, returning a custom HTTP response.
*/
public class RequestFailedException extends WebDriverException {
}
18 changes: 16 additions & 2 deletions java/src/org/openqa/selenium/devtools/idealized/Network.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.openqa.selenium.devtools.DevToolsException;
import org.openqa.selenium.devtools.Event;
import org.openqa.selenium.devtools.NetworkInterceptor;
import org.openqa.selenium.devtools.RequestFailedException;
import org.openqa.selenium.internal.Either;
import org.openqa.selenium.internal.Require;
import org.openqa.selenium.remote.http.Contents;
Expand Down Expand Up @@ -202,8 +203,12 @@ public void prepareToInterceptTraffic() {
String id = getRequestId(pausedRequest);

if (hasErrorResponse(pausedRequest)) {
pendingResponses.remove(id);
devTools.send(continueWithoutModification(pausedRequest));
CompletableFuture<HttpResponse> future = pendingResponses.remove(id);
if (future == null) {
devTools.send(continueWithoutModification(pausedRequest));
} else {
future.completeExceptionally(new RequestFailedException());
}
return;
}

Expand Down Expand Up @@ -244,6 +249,11 @@ public void prepareToInterceptTraffic() {
pendingResponses.remove(id);
return STOP_PROCESSING;
} catch (ExecutionException e) {
if (e.getCause() instanceof RequestFailedException) {
// Throwing here will give the user's filter a chance to intercept
// the failure and handle it.
throw (RequestFailedException) e.getCause();
}
if (fetchEnabled.get()) {
LOG.log(WARNING, e, () -> "Unable to process request");
}
Expand All @@ -261,6 +271,10 @@ public void prepareToInterceptTraffic() {
}

devTools.send(fulfillRequest(pausedRequest, forBrowser));
} catch (RequestFailedException e) {
// If the exception reaches here, we know the user's filter has not handled it and the
// browser should continue its normal error handling.
devTools.send(continueWithoutModification(pausedRequest));
} catch (TimeoutException e) {
if (fetchEnabled.get()) {
throw e;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,28 @@ void shouldHandleRedirects() {

@Test
@NoDriverBeforeTest
void shouldProceedAsNormalIfRequestResultInAnKnownError() {
void shouldProceedAsNormalIfRequestResultInAnKnownErrorAndExceptionNotCaughtByFilter() {
Filter filter = next -> next;
try (NetworkInterceptor ignored = new NetworkInterceptor(driver, filter)) {
assertThatExceptionOfType(WebDriverException.class)
.isThrownBy(() -> driver.get("http://localhost:" + PortProber.findFreePort()));
}
}

@Test
@NoDriverBeforeTest
void shouldPassResponseBackToBrowserIfRequestResultsInAnKnownErrorAndExceptionCaughtByFilter() {
Filter filter = next -> req -> {
try {
return next.execute(req);
} catch (RequestFailedException e) {
return new HttpResponse().setStatus(200).setContent(Contents.utf8String("Hello, World!"));
}
};
try (NetworkInterceptor ignored = new NetworkInterceptor(driver, filter)) {
driver.get("http://localhost:" + PortProber.findFreePort());
String body = driver.findElement(By.tagName("body")).getText();
assertThat(body).contains("Hello, World!");
}
}
}

0 comments on commit 12eba88

Please sign in to comment.