1818package org .openqa .selenium .remote ;
1919
2020import java .net .URI ;
21+ import java .util .ArrayList ;
22+ import java .util .List ;
2123import java .util .Map ;
2224import java .util .Optional ;
2325import java .util .concurrent .ConcurrentHashMap ;
2426import java .util .concurrent .atomic .AtomicLong ;
2527import java .util .function .Predicate ;
28+ import java .util .function .UnaryOperator ;
2629import org .openqa .selenium .Beta ;
2730import org .openqa .selenium .UsernameAndPassword ;
2831import org .openqa .selenium .WebDriver ;
2932import org .openqa .selenium .bidi .BiDi ;
3033import org .openqa .selenium .bidi .HasBiDi ;
3134import 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 ;
3238import 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
3545class 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}
0 commit comments