Skip to content

Commit 0e8059d

Browse files
authored
[bidi][java] Add network request handler APIs (#14424)
1 parent 25551ad commit 0e8059d

File tree

7 files changed

+422
-10
lines changed

7 files changed

+422
-10
lines changed

java/src/org/openqa/selenium/bidi/network/Header.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public class Header {
2525
private final String name;
2626
private final BytesValue value;
2727

28-
private Header(String name, BytesValue value) {
28+
public Header(String name, BytesValue value) {
2929
this.name = name;
3030
this.value = value;
3131
}

java/src/org/openqa/selenium/bidi/network/ResponseData.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public class ResponseData {
2828
private final String url;
2929

3030
private final String protocol;
31-
private final long status;
31+
private final int status;
3232
private final String statusText;
3333
private final boolean fromCache;
3434
private final List<Header> headers;
@@ -42,7 +42,7 @@ public class ResponseData {
4242
private ResponseData(
4343
String url,
4444
String protocol,
45-
long status,
45+
int status,
4646
String statusText,
4747
boolean fromCache,
4848
List<Header> headers,
@@ -69,7 +69,7 @@ private ResponseData(
6969
public static ResponseData fromJson(JsonInput input) {
7070
String url = null;
7171
String protocol = null;
72-
long status = 0;
72+
int status = 0;
7373
String statusText = null;
7474
boolean fromCache = false;
7575
List<Header> headers = new ArrayList<>();
@@ -89,7 +89,7 @@ public static ResponseData fromJson(JsonInput input) {
8989
protocol = input.read(String.class);
9090
break;
9191
case "status":
92-
status = input.read(Long.class);
92+
status = input.read(Integer.class);
9393
break;
9494
case "statusText":
9595
statusText = input.read(String.class);
@@ -150,7 +150,7 @@ public String getProtocol() {
150150
return protocol;
151151
}
152152

153-
public long getStatus() {
153+
public int getStatus() {
154154
return status;
155155
}
156156

java/src/org/openqa/selenium/remote/Network.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919

2020
import java.net.URI;
2121
import java.util.function.Predicate;
22+
import java.util.function.UnaryOperator;
2223
import org.openqa.selenium.Beta;
2324
import org.openqa.selenium.UsernameAndPassword;
25+
import org.openqa.selenium.remote.http.HttpRequest;
2426

2527
@Beta
2628
public interface Network {
@@ -32,4 +34,10 @@ public interface Network {
3234
void removeAuthenticationHandler(long id);
3335

3436
void clearAuthenticationHandlers();
37+
38+
long addRequestHandler(Predicate<URI> filter, UnaryOperator<HttpRequest> handler);
39+
40+
void removeRequestHandler(long id);
41+
42+
void clearRequestHandlers();
3543
}

java/src/org/openqa/selenium/remote/RemoteNetwork.java

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,28 @@
1818
package org.openqa.selenium.remote;
1919

2020
import java.net.URI;
21+
import java.util.ArrayList;
22+
import java.util.List;
2123
import java.util.Map;
2224
import java.util.Optional;
2325
import java.util.concurrent.ConcurrentHashMap;
2426
import java.util.concurrent.atomic.AtomicLong;
2527
import java.util.function.Predicate;
28+
import java.util.function.UnaryOperator;
2629
import org.openqa.selenium.Beta;
2730
import org.openqa.selenium.UsernameAndPassword;
2831
import org.openqa.selenium.WebDriver;
2932
import org.openqa.selenium.bidi.BiDi;
3033
import org.openqa.selenium.bidi.HasBiDi;
3134
import org.openqa.selenium.bidi.network.AddInterceptParameters;
35+
import org.openqa.selenium.bidi.network.BytesValue;
36+
import org.openqa.selenium.bidi.network.ContinueRequestParameters;
37+
import org.openqa.selenium.bidi.network.Header;
3238
import org.openqa.selenium.bidi.network.InterceptPhase;
39+
import org.openqa.selenium.bidi.network.RequestData;
40+
import org.openqa.selenium.remote.http.Contents;
41+
import org.openqa.selenium.remote.http.HttpMethod;
42+
import org.openqa.selenium.remote.http.HttpRequest;
3343

3444
@Beta
3545
class RemoteNetwork implements Network {
@@ -39,13 +49,16 @@ class RemoteNetwork implements Network {
3949

4050
private final Map<Long, AuthDetails> authHandlers = new ConcurrentHashMap<>();
4151

52+
private final Map<Long, RequestDetails> requestHandlers = new ConcurrentHashMap<>();
53+
4254
private final AtomicLong callBackId = new AtomicLong(1);
4355

4456
public RemoteNetwork(WebDriver driver) {
4557
this.biDi = ((HasBiDi) driver).getBiDi();
4658
this.network = new org.openqa.selenium.bidi.module.Network(driver);
4759

4860
interceptAuthTraffic();
61+
interceptRequest();
4962
}
5063

5164
private void interceptAuthTraffic() {
@@ -73,6 +86,71 @@ private Optional<UsernameAndPassword> getAuthCredentials(URI uri) {
7386
.findFirst();
7487
}
7588

89+
private void interceptRequest() {
90+
this.network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
91+
92+
this.network.onBeforeRequestSent(
93+
beforeRequestSent -> {
94+
String requestId = beforeRequestSent.getRequest().getRequestId();
95+
URI uri = URI.create(beforeRequestSent.getRequest().getUrl());
96+
97+
ContinueRequestParameters continueRequestParameters =
98+
new ContinueRequestParameters(requestId);
99+
100+
Optional<UnaryOperator<HttpRequest>> requestHandler = getRequestHandler(uri);
101+
102+
if (requestHandler.isPresent()) {
103+
RequestData interceptedRequest = beforeRequestSent.getRequest();
104+
105+
// Build the originalRequest object from the intercepted request details.
106+
HttpRequest originalRequest =
107+
new HttpRequest(
108+
HttpMethod.getHttpMethod(interceptedRequest.getMethod()),
109+
interceptedRequest.getUrl());
110+
111+
// Populate the headers of the original request.
112+
interceptedRequest
113+
.getHeaders()
114+
.forEach(
115+
header ->
116+
originalRequest.addHeader(header.getName(), header.getValue().getValue()));
117+
118+
HttpRequest modifiedRequest = requestHandler.get().apply(originalRequest);
119+
120+
continueRequestParameters.method(modifiedRequest.getMethod());
121+
122+
if (!uri.toString().equals(modifiedRequest.getUri())) {
123+
continueRequestParameters.url(modifiedRequest.getUri());
124+
}
125+
126+
List<Header> headerList = new ArrayList<>();
127+
modifiedRequest.forEachHeader(
128+
(name, value) ->
129+
headerList.add(
130+
new Header(name, new BytesValue(BytesValue.Type.STRING, value))));
131+
132+
if (!headerList.isEmpty()) {
133+
continueRequestParameters.headers(headerList);
134+
}
135+
136+
Contents.Supplier content = modifiedRequest.getContent();
137+
138+
if (content.length() > 0) {
139+
continueRequestParameters.body(
140+
new BytesValue(BytesValue.Type.STRING, Contents.utf8String(content)));
141+
}
142+
}
143+
network.continueRequest(continueRequestParameters);
144+
});
145+
}
146+
147+
private Optional<UnaryOperator<HttpRequest>> getRequestHandler(URI uri) {
148+
return requestHandlers.values().stream()
149+
.filter(requestDetails -> requestDetails.getFilter().test(uri))
150+
.map(RequestDetails::getHandler)
151+
.findFirst();
152+
}
153+
76154
@Override
77155
public long addAuthenticationHandler(UsernameAndPassword usernameAndPassword) {
78156
return addAuthenticationHandler(url -> true, usernameAndPassword);
@@ -97,6 +175,24 @@ public void clearAuthenticationHandlers() {
97175
authHandlers.clear();
98176
}
99177

178+
@Override
179+
public long addRequestHandler(Predicate<URI> filter, UnaryOperator<HttpRequest> handler) {
180+
long id = this.callBackId.incrementAndGet();
181+
182+
requestHandlers.put(id, new RequestDetails(filter, handler));
183+
return id;
184+
}
185+
186+
@Override
187+
public void removeRequestHandler(long id) {
188+
requestHandlers.remove(id);
189+
}
190+
191+
@Override
192+
public void clearRequestHandlers() {
193+
requestHandlers.clear();
194+
}
195+
100196
private class AuthDetails {
101197
private final Predicate<URI> filter;
102198
private final UsernameAndPassword usernameAndPassword;
@@ -114,4 +210,22 @@ public UsernameAndPassword getUsernameAndPassword() {
114210
return usernameAndPassword;
115211
}
116212
}
213+
214+
private class RequestDetails {
215+
private final Predicate<URI> filter;
216+
private final UnaryOperator<HttpRequest> handler;
217+
218+
public RequestDetails(Predicate<URI> filter, UnaryOperator<HttpRequest> handler) {
219+
this.filter = filter;
220+
this.handler = handler;
221+
}
222+
223+
public Predicate<URI> getFilter() {
224+
return this.filter;
225+
}
226+
227+
public UnaryOperator<HttpRequest> getHandler() {
228+
return this.handler;
229+
}
230+
}
117231
}

java/src/org/openqa/selenium/remote/http/HttpMethod.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,17 @@ public enum HttpMethod {
2626
PATCH,
2727
HEAD,
2828
CONNECT,
29-
TRACE,
29+
TRACE;
30+
31+
public static HttpMethod getHttpMethod(String method) {
32+
if (method == null) {
33+
throw new IllegalArgumentException("Method cannot be null");
34+
}
35+
36+
try {
37+
return HttpMethod.valueOf(method.toUpperCase());
38+
} catch (IllegalArgumentException e) {
39+
throw new IllegalArgumentException("No enum constant for method: " + method);
40+
}
41+
}
3042
}

0 commit comments

Comments
 (0)