2525import java .util .concurrent .ConcurrentHashMap ;
2626import java .util .concurrent .atomic .AtomicLong ;
2727import java .util .function .Predicate ;
28+ import java .util .function .Supplier ;
2829import java .util .function .UnaryOperator ;
2930import org .openqa .selenium .Beta ;
3031import org .openqa .selenium .UsernameAndPassword ;
3637import org .openqa .selenium .bidi .network .ContinueRequestParameters ;
3738import org .openqa .selenium .bidi .network .Header ;
3839import org .openqa .selenium .bidi .network .InterceptPhase ;
40+ import org .openqa .selenium .bidi .network .ProvideResponseParameters ;
3941import org .openqa .selenium .bidi .network .RequestData ;
4042import org .openqa .selenium .remote .http .Contents ;
4143import org .openqa .selenium .remote .http .HttpMethod ;
4244import org .openqa .selenium .remote .http .HttpRequest ;
45+ import org .openqa .selenium .remote .http .HttpResponse ;
4346
4447@ Beta
4548class RemoteNetwork implements Network {
@@ -51,6 +54,8 @@ class RemoteNetwork implements Network {
5154
5255 private final Map <Long , RequestDetails > requestHandlers = new ConcurrentHashMap <>();
5356
57+ private final Map <Long , ResponseDetails > responseHandlers = new ConcurrentHashMap <>();
58+
5459 private final AtomicLong callBackId = new AtomicLong (1 );
5560
5661 public RemoteNetwork (WebDriver driver ) {
@@ -97,24 +102,60 @@ private void interceptRequest() {
97102 ContinueRequestParameters continueRequestParameters =
98103 new ContinueRequestParameters (requestId );
99104
100- Optional <UnaryOperator <HttpRequest >> requestHandler = getRequestHandler (uri );
105+ RequestData interceptedRequest = beforeRequestSent .getRequest ();
106+
107+ // Build the originalRequest object from the intercepted request details.
108+ HttpRequest originalRequest =
109+ new HttpRequest (
110+ HttpMethod .getHttpMethod (interceptedRequest .getMethod ()),
111+ interceptedRequest .getUrl ());
112+
113+ // Populate the headers of the original request.
114+ // Body is not available as part of WebDriver Spec, hence we cannot add that or use that.
115+ interceptedRequest
116+ .getHeaders ()
117+ .forEach (
118+ header ->
119+ originalRequest .addHeader (header .getName (), header .getValue ().getValue ()));
120+
121+ Optional <UnaryOperator <HttpRequest >> requestHandler = getRequestHandler (originalRequest );
122+
123+ Optional <Supplier <HttpResponse >> responseHandler = getResponseHandler (originalRequest );
124+
125+ // If request and response handler both are registered for same uri,
126+ // then the response will be mocked instead of modifying the outgoing request.
127+ // This can be altered in the future to let the modified request go through and have a
128+ // response mock for that modified request.
129+ // If in future the Browsers support intercepting at "response started" phase and allow
130+ // using provide response command in that phase.
131+ // Currently, only intercepting in "before request sent" phase is permitted.
132+ if (responseHandler .isPresent ()) {
133+ ProvideResponseParameters provideResponseParameters =
134+ new ProvideResponseParameters (requestId );
101135
102- if (requestHandler .isPresent ()) {
103- RequestData interceptedRequest = beforeRequestSent .getRequest ();
136+ HttpResponse modifiedResponse = responseHandler .get ().get ();
137+
138+ provideResponseParameters .statusCode (modifiedResponse .getStatus ());
139+
140+ List <Header > headerList = new ArrayList <>();
141+ modifiedResponse .forEachHeader (
142+ (name , value ) ->
143+ headerList .add (
144+ new Header (name , new BytesValue (BytesValue .Type .STRING , value ))));
104145
105- // Build the originalRequest object from the intercepted request details.
106- HttpRequest originalRequest =
107- new HttpRequest (
108- HttpMethod .getHttpMethod (interceptedRequest .getMethod ()),
109- interceptedRequest .getUrl ());
146+ if (!headerList .isEmpty ()) {
147+ provideResponseParameters .headers (headerList );
148+ }
110149
111- // Populate the headers of the original request.
112- interceptedRequest
113- .getHeaders ()
114- .forEach (
115- header ->
116- originalRequest .addHeader (header .getName (), header .getValue ().getValue ()));
150+ Contents .Supplier content = modifiedResponse .getContent ();
117151
152+ if (content .length () > 0 ) {
153+ provideResponseParameters .body (
154+ new BytesValue (BytesValue .Type .STRING , Contents .utf8String (content )));
155+ }
156+ network .provideResponse (provideResponseParameters );
157+ return ;
158+ } else if (requestHandler .isPresent ()) {
118159 HttpRequest modifiedRequest = requestHandler .get ().apply (originalRequest );
119160
120161 continueRequestParameters .method (modifiedRequest .getMethod ());
@@ -144,13 +185,20 @@ private void interceptRequest() {
144185 });
145186 }
146187
147- private Optional <UnaryOperator <HttpRequest >> getRequestHandler (URI uri ) {
188+ private Optional <UnaryOperator <HttpRequest >> getRequestHandler (HttpRequest request ) {
148189 return requestHandlers .values ().stream ()
149- .filter (requestDetails -> requestDetails .getFilter ().test (uri ))
190+ .filter (requestDetails -> requestDetails .getFilter ().test (request ))
150191 .map (RequestDetails ::getHandler )
151192 .findFirst ();
152193 }
153194
195+ private Optional <Supplier <HttpResponse >> getResponseHandler (HttpRequest request ) {
196+ return responseHandlers .values ().stream ()
197+ .filter (responseDetails -> responseDetails .getFilter ().test (request ))
198+ .map (ResponseDetails ::getHandler )
199+ .findFirst ();
200+ }
201+
154202 @ Override
155203 public long addAuthenticationHandler (UsernameAndPassword usernameAndPassword ) {
156204 return addAuthenticationHandler (url -> true , usernameAndPassword );
@@ -176,7 +224,7 @@ public void clearAuthenticationHandlers() {
176224 }
177225
178226 @ Override
179- public long addRequestHandler (Predicate <URI > filter , UnaryOperator <HttpRequest > handler ) {
227+ public long addRequestHandler (Predicate <HttpRequest > filter , UnaryOperator <HttpRequest > handler ) {
180228 long id = this .callBackId .incrementAndGet ();
181229
182230 requestHandlers .put (id , new RequestDetails (filter , handler ));
@@ -193,6 +241,25 @@ public void clearRequestHandlers() {
193241 requestHandlers .clear ();
194242 }
195243
244+ // Allows mocking the response body
245+ @ Override
246+ public long addResponseHandler (Predicate <HttpRequest > filter , Supplier <HttpResponse > handler ) {
247+ long id = this .callBackId .incrementAndGet ();
248+
249+ responseHandlers .put (id , new ResponseDetails (filter , handler ));
250+ return id ;
251+ }
252+
253+ @ Override
254+ public void removeResponseHandler (long id ) {
255+ responseHandlers .remove (id );
256+ }
257+
258+ @ Override
259+ public void clearResponseHandlers () {
260+ responseHandlers .clear ();
261+ }
262+
196263 private class AuthDetails {
197264 private final Predicate <URI > filter ;
198265 private final UsernameAndPassword usernameAndPassword ;
@@ -212,20 +279,38 @@ public UsernameAndPassword getUsernameAndPassword() {
212279 }
213280
214281 private class RequestDetails {
215- private final Predicate <URI > filter ;
282+ private final Predicate <HttpRequest > filter ;
216283 private final UnaryOperator <HttpRequest > handler ;
217284
218- public RequestDetails (Predicate <URI > filter , UnaryOperator <HttpRequest > handler ) {
285+ public RequestDetails (Predicate <HttpRequest > filter , UnaryOperator <HttpRequest > handler ) {
219286 this .filter = filter ;
220287 this .handler = handler ;
221288 }
222289
223- public Predicate <URI > getFilter () {
290+ public Predicate <HttpRequest > getFilter () {
224291 return this .filter ;
225292 }
226293
227294 public UnaryOperator <HttpRequest > getHandler () {
228295 return this .handler ;
229296 }
230297 }
298+
299+ private class ResponseDetails {
300+ private final Predicate <HttpRequest > filter ;
301+ private final Supplier <HttpResponse > handler ;
302+
303+ public ResponseDetails (Predicate <HttpRequest > filter , Supplier <HttpResponse > handler ) {
304+ this .filter = filter ;
305+ this .handler = handler ;
306+ }
307+
308+ public Predicate <HttpRequest > getFilter () {
309+ return this .filter ;
310+ }
311+
312+ public Supplier <HttpResponse > getHandler () {
313+ return this .handler ;
314+ }
315+ }
231316}
0 commit comments