diff --git a/dotnet/src/webdriver/BiDi/Communication/Broker.cs b/dotnet/src/webdriver/BiDi/Communication/Broker.cs index 9dba18f3c2628..ec7cf5b5bd775 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Broker.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Broker.cs @@ -76,7 +76,7 @@ internal Broker(BiDi bidi, Uri url) new BrowserClientWindowConverter(), new NavigationConverter(), new InterceptConverter(_bidi), - new RequestConverter(_bidi), + new RequestConverter(), new ChannelConverter(), new HandleConverter(_bidi), new InternalIdConverter(_bidi), diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/RequestConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/RequestConverter.cs index 308bed6db76db..9c45ccc964d6a 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/RequestConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/RequestConverter.cs @@ -26,18 +26,11 @@ namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; internal class RequestConverter : JsonConverter { - private readonly BiDi _bidi; - - public RequestConverter(BiDi bidi) - { - _bidi = bidi; - } - public override Request? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var id = reader.GetString(); - return new Request(_bidi, id!); + return new Request(id!); } public override void Write(Utf8JsonWriter writer, Request value, JsonSerializerOptions options) diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextNetworkModule.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextNetworkModule.cs index 5c45c841f697e..13c31ba2cea59 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextNetworkModule.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextNetworkModule.cs @@ -25,44 +25,50 @@ namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; public class BrowsingContextNetworkModule(BrowsingContext context, NetworkModule networkModule) { - public async Task InterceptRequestAsync(Func handler, BrowsingContextAddInterceptOptions? interceptOptions = null, SubscriptionOptions? options = null) + public async Task InterceptRequestAsync(Func handler, InterceptRequestOptions? options = null) { - AddInterceptOptions addInterceptOptions = new(interceptOptions) + AddInterceptOptions addInterceptOptions = new(options) { Contexts = [context] }; var intercept = await networkModule.AddInterceptAsync([InterceptPhase.BeforeRequestSent], addInterceptOptions).ConfigureAwait(false); - await intercept.OnBeforeRequestSentAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [context] }).ConfigureAwait(false); + await intercept.OnBeforeRequestSentAsync( + async req => await handler(new(req.BiDi, req.Context, req.IsBlocked, req.Navigation, req.RedirectCount, req.Request, req.Timestamp, req.Initiator)), + new BrowsingContextsSubscriptionOptions(null) { Contexts = [context] }).ConfigureAwait(false); return intercept; } - public async Task InterceptResponseAsync(Func handler, BrowsingContextAddInterceptOptions? interceptOptions = null, SubscriptionOptions? options = null) + public async Task InterceptResponseAsync(Func handler, InterceptResponseOptions? options = null) { - AddInterceptOptions addInterceptOptions = new(interceptOptions) + AddInterceptOptions addInterceptOptions = new(options) { Contexts = [context] }; var intercept = await networkModule.AddInterceptAsync([InterceptPhase.ResponseStarted], addInterceptOptions).ConfigureAwait(false); - await intercept.OnResponseStartedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [context] }).ConfigureAwait(false); + await intercept.OnResponseStartedAsync( + async res => await handler(new(res.BiDi, res.Context, res.IsBlocked, res.Navigation, res.RedirectCount, res.Request, res.Timestamp, res.Response)), + new BrowsingContextsSubscriptionOptions(null) { Contexts = [context] }).ConfigureAwait(false); return intercept; } - public async Task InterceptAuthAsync(Func handler, BrowsingContextAddInterceptOptions? interceptOptions = null, SubscriptionOptions? options = null) + public async Task InterceptAuthAsync(Func handler, InterceptAuthOptions? options = null) { - AddInterceptOptions addInterceptOptions = new(interceptOptions) + AddInterceptOptions addInterceptOptions = new(options) { Contexts = [context] }; var intercept = await networkModule.AddInterceptAsync([InterceptPhase.AuthRequired], addInterceptOptions).ConfigureAwait(false); - await intercept.OnAuthRequiredAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [context] }).ConfigureAwait(false); + await intercept.OnAuthRequiredAsync( + async auth => await handler(new(auth.BiDi, auth.Context, auth.IsBlocked, auth.Navigation, auth.RedirectCount, auth.Request, auth.Timestamp, auth.Response)), + new BrowsingContextsSubscriptionOptions(null) { Contexts = [context] }).ConfigureAwait(false); return intercept; } @@ -127,3 +133,9 @@ public Task OnAuthRequiredAsync(Action hand return networkModule.OnAuthRequiredAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [context] }); } } + +public record InterceptRequestOptions : BrowsingContextAddInterceptOptions; + +public record InterceptResponseOptions : BrowsingContextAddInterceptOptions; + +public record InterceptAuthOptions : BrowsingContextAddInterceptOptions; diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/NetworkModule.HighLevel.cs b/dotnet/src/webdriver/BiDi/Modules/Network/NetworkModule.HighLevel.cs new file mode 100644 index 0000000000000..3ba468219c671 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Modules/Network/NetworkModule.HighLevel.cs @@ -0,0 +1,106 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using System; +using System.Threading.Tasks; + +namespace OpenQA.Selenium.BiDi.Modules.Network; + +public partial class NetworkModule +{ + public async Task InterceptRequestAsync(Func handler, InterceptRequestOptions? options = null) + { + var intercept = await AddInterceptAsync([InterceptPhase.BeforeRequestSent], options).ConfigureAwait(false); + + await intercept.OnBeforeRequestSentAsync(async req => await handler(new(req.BiDi, req.Context, req.IsBlocked, req.Navigation, req.RedirectCount, req.Request, req.Timestamp, req.Initiator))).ConfigureAwait(false); + + return intercept; + } + + public async Task InterceptResponseAsync(Func handler, InterceptResponseOptions? options = null) + { + var intercept = await AddInterceptAsync([InterceptPhase.ResponseStarted], options).ConfigureAwait(false); + + await intercept.OnResponseStartedAsync(async res => await handler(new(res.BiDi, res.Context, res.IsBlocked, res.Navigation, res.RedirectCount, res.Request, res.Timestamp, res.Response))).ConfigureAwait(false); + + return intercept; + } + + public async Task InterceptAuthAsync(Func handler, InterceptAuthOptions? options = null) + { + var intercept = await AddInterceptAsync([InterceptPhase.AuthRequired], options).ConfigureAwait(false); + + await intercept.OnAuthRequiredAsync(async auth => await handler(new(auth.BiDi, auth.Context, auth.IsBlocked, auth.Navigation, auth.RedirectCount, auth.Request, auth.Timestamp, auth.Response))).ConfigureAwait(false); + + return intercept; + } +} + +public record InterceptRequestOptions : AddInterceptOptions; + +public record InterceptResponseOptions : AddInterceptOptions; + +public record InterceptAuthOptions : AddInterceptOptions; + +public record InterceptedRequest(BiDi BiDi, BrowsingContext.BrowsingContext Context, bool IsBlocked, BrowsingContext.Navigation Navigation, long RedirectCount, RequestData Request, DateTimeOffset Timestamp, Initiator Initiator) + : BeforeRequestSentEventArgs(BiDi, Context, IsBlocked, Navigation, RedirectCount, Request, Timestamp, Initiator) +{ + public Task ContinueAsync(ContinueRequestOptions? options = null) + { + return BiDi.Network.ContinueRequestAsync(Request.Request, options); + } + + public Task FailAsync() + { + return BiDi.Network.FailRequestAsync(Request.Request); + } + + public Task ProvideResponseAsync(ProvideResponseOptions? options = null) + { + return BiDi.Network.ProvideResponseAsync(Request.Request, options); + } +} + +public record InterceptedResponse(BiDi BiDi, BrowsingContext.BrowsingContext Context, bool IsBlocked, BrowsingContext.Navigation Navigation, long RedirectCount, RequestData Request, DateTimeOffset Timestamp, ResponseData Response) + : ResponseStartedEventArgs(BiDi, Context, IsBlocked, Navigation, RedirectCount, Request, Timestamp, Response) +{ + public Task ContinueAsync(ContinueResponseOptions? options = null) + { + return BiDi.Network.ContinueResponseAsync(Request.Request, options); + } +} + +public record InterceptedAuth(BiDi BiDi, BrowsingContext.BrowsingContext Context, bool IsBlocked, BrowsingContext.Navigation Navigation, long RedirectCount, RequestData Request, DateTimeOffset Timestamp, ResponseData Response) + : AuthRequiredEventArgs(BiDi, Context, IsBlocked, Navigation, RedirectCount, Request, Timestamp, Response) +{ + public Task ContinueAsync(AuthCredentials credentials, ContinueWithAuthCredentialsOptions? options = null) + { + return BiDi.Network.ContinueWithAuthAsync(Request.Request, credentials, options); + } + + public Task ContinueAsync(ContinueWithAuthDefaultCredentialsOptions? options = null) + { + return BiDi.Network.ContinueWithAuthAsync(Request.Request, options); + } + + public Task ContinueAsync(ContinueWithAuthCancelCredentialsOptions? options = null) + { + return BiDi.Network.ContinueWithAuthAsync(Request.Request, options); + } +} diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/NetworkModule.cs b/dotnet/src/webdriver/BiDi/Modules/Network/NetworkModule.cs index 86940f38722d6..7d31bc344d41b 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/NetworkModule.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/NetworkModule.cs @@ -24,7 +24,7 @@ namespace OpenQA.Selenium.BiDi.Modules.Network; -public sealed class NetworkModule(Broker broker) : Module(broker) +public sealed partial class NetworkModule(Broker broker) : Module(broker) { internal async Task AddInterceptAsync(IEnumerable phases, AddInterceptOptions? options = null) { @@ -42,24 +42,6 @@ internal async Task RemoveInterceptAsync(Intercept intercept, RemoveInterceptOpt await Broker.ExecuteCommandAsync(new RemoveInterceptCommand(@params), options).ConfigureAwait(false); } - public async Task InterceptRequestAsync(Func handler, AddInterceptOptions? interceptOptions = null, SubscriptionOptions? options = null) - { - var intercept = await AddInterceptAsync([InterceptPhase.BeforeRequestSent], interceptOptions).ConfigureAwait(false); - - await intercept.OnBeforeRequestSentAsync(handler, options).ConfigureAwait(false); - - return intercept; - } - - public async Task InterceptResponseAsync(Func handler, AddInterceptOptions? interceptOptions = null, SubscriptionOptions? options = null) - { - var intercept = await AddInterceptAsync([InterceptPhase.ResponseStarted], interceptOptions).ConfigureAwait(false); - - await intercept.OnResponseStartedAsync(handler, options).ConfigureAwait(false); - - return intercept; - } - public async Task SetCacheBehaviorAsync(CacheBehavior behavior, SetCacheBehaviorOptions? options = null) { var @params = new SetCacheBehaviorCommandParameters(behavior, options?.Contexts); @@ -67,15 +49,6 @@ public async Task SetCacheBehaviorAsync(CacheBehavior behavior, SetCacheBehavior await Broker.ExecuteCommandAsync(new SetCacheBehaviorCommand(@params), options).ConfigureAwait(false); } - public async Task InterceptAuthAsync(Func handler, AddInterceptOptions? interceptOptions = null, SubscriptionOptions? options = null) - { - var intercept = await AddInterceptAsync([InterceptPhase.AuthRequired], interceptOptions).ConfigureAwait(false); - - await intercept.OnAuthRequiredAsync(handler, options).ConfigureAwait(false); - - return intercept; - } - internal async Task ContinueRequestAsync(Request request, ContinueRequestOptions? options = null) { var @params = new ContinueRequestCommandParameters(request, options?.Body, options?.Cookies, options?.Headers, options?.Method, options?.Url); diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/Request.cs b/dotnet/src/webdriver/BiDi/Modules/Network/Request.cs index 402a59fb1c3a2..870b6a129db85 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/Request.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/Request.cs @@ -17,54 +17,14 @@ // under the License. // -using System.Threading.Tasks; - namespace OpenQA.Selenium.BiDi.Modules.Network; public class Request { - private readonly BiDi _bidi; - - internal Request(BiDi bidi, string id) + internal Request(string id) { - _bidi = bidi; Id = id; } public string Id { get; private set; } - - public Task ContinueAsync(ContinueRequestOptions? options = null) - { - return _bidi.Network.ContinueRequestAsync(this, options); - } - - public Task FailAsync() - { - return _bidi.Network.FailRequestAsync(this); - } - - public Task ProvideResponseAsync(ProvideResponseOptions? options = null) - { - return _bidi.Network.ProvideResponseAsync(this, options); - } - - public Task ContinueResponseAsync(ContinueResponseOptions? options = null) - { - return _bidi.Network.ContinueResponseAsync(this, options); - } - - public Task ContinueWithAuthAsync(AuthCredentials credentials, ContinueWithAuthCredentialsOptions? options = null) - { - return _bidi.Network.ContinueWithAuthAsync(this, credentials, options); - } - - public Task ContinueWithAuthAsync(ContinueWithAuthDefaultCredentialsOptions? options = null) - { - return _bidi.Network.ContinueWithAuthAsync(this, options); - } - - public Task ContinueWithAuthAsync(ContinueWithAuthCancelCredentialsOptions? options = null) - { - return _bidi.Network.ContinueWithAuthAsync(this, options); - } } diff --git a/dotnet/test/common/BiDi/Network/NetworkTest.cs b/dotnet/test/common/BiDi/Network/NetworkTest.cs index 9fedb7bd8e5c8..4dc4fc3b044da 100644 --- a/dotnet/test/common/BiDi/Network/NetworkTest.cs +++ b/dotnet/test/common/BiDi/Network/NetworkTest.cs @@ -51,7 +51,7 @@ public async Task CanAddInterceptStringUrlPattern() [Test] public async Task CanAddInterceptUrlPattern() { - await using var intercept = await bidi.Network.InterceptRequestAsync(e => Task.CompletedTask, interceptOptions: new() + await using var intercept = await bidi.Network.InterceptRequestAsync(e => Task.CompletedTask, options: new() { UrlPatterns = [new PatternUrlPattern() { @@ -67,11 +67,11 @@ public async Task CanAddInterceptUrlPattern() public async Task CanContinueRequest() { int times = 0; - await using var intercept = await bidi.Network.InterceptRequestAsync(async e => + await using var intercept = await bidi.Network.InterceptRequestAsync(async req => { times++; - await e.Request.Request.ContinueAsync(); + await req.ContinueAsync(); }); await context.NavigateAsync(UrlBuilder.WhereIs("bidi/logEntryAdded.html"), new() { Wait = ReadinessState.Complete }); @@ -85,11 +85,11 @@ public async Task CanContinueResponse() { int times = 0; - await using var intercept = await bidi.Network.InterceptResponseAsync(async e => + await using var intercept = await bidi.Network.InterceptResponseAsync(async res => { times++; - await e.Request.Request.ContinueResponseAsync(); + await res.ContinueAsync(); }); await context.NavigateAsync(UrlBuilder.WhereIs("bidi/logEntryAdded.html"), new() { Wait = ReadinessState.Complete }); @@ -103,11 +103,11 @@ public async Task CanProvideResponse() { int times = 0; - await using var intercept = await bidi.Network.InterceptRequestAsync(async e => + await using var intercept = await bidi.Network.InterceptRequestAsync(async req => { times++; - await e.Request.Request.ProvideResponseAsync(); + await req.ProvideResponseAsync(); }); await context.NavigateAsync(UrlBuilder.WhereIs("bidi/logEntryAdded.html"), new() { Wait = ReadinessState.Complete }); @@ -121,11 +121,11 @@ public async Task CanProvideResponseWithParameters() { int times = 0; - await using var intercept = await bidi.Network.InterceptRequestAsync(async e => + await using var intercept = await bidi.Network.InterceptRequestAsync(async req => { times++; - await e.Request.Request.ProvideResponseAsync(new() { Body = """ + await req.ProvideResponseAsync(new() { Body = """ Hello @@ -160,9 +160,9 @@ public async Task CanRemoveIntercept() [Test] public async Task CanContinueWithAuthCredentials() { - await using var intercept = await bidi.Network.InterceptAuthAsync(async e => + await using var intercept = await bidi.Network.InterceptAuthAsync(async auth => { - await e.Request.Request.ContinueWithAuthAsync(new AuthCredentials("test", "test")); + await auth.ContinueAsync(new AuthCredentials("test", "test")); }); await context.NavigateAsync(UrlBuilder.WhereIs("basicAuth"), new() { Wait = ReadinessState.Complete }); @@ -174,9 +174,9 @@ public async Task CanContinueWithAuthCredentials() [IgnoreBrowser(Selenium.Browser.Firefox)] public async Task CanContinueWithDefaultCredentials() { - await using var intercept = await bidi.Network.InterceptAuthAsync(async e => + await using var intercept = await bidi.Network.InterceptAuthAsync(async auth => { - await e.Request.Request.ContinueWithAuthAsync(new ContinueWithAuthDefaultCredentialsOptions()); + await auth.ContinueAsync(new ContinueWithAuthDefaultCredentialsOptions()); }); var action = async () => await context.NavigateAsync(UrlBuilder.WhereIs("basicAuth"), new() { Wait = ReadinessState.Complete }); @@ -188,9 +188,9 @@ public async Task CanContinueWithDefaultCredentials() [IgnoreBrowser(Selenium.Browser.Firefox)] public async Task CanContinueWithCanceledCredentials() { - await using var intercept = await bidi.Network.InterceptAuthAsync(async e => + await using var intercept = await bidi.Network.InterceptAuthAsync(async auth => { - await e.Request.Request.ContinueWithAuthAsync(new ContinueWithAuthCancelCredentialsOptions()); + await auth.ContinueAsync(new ContinueWithAuthCancelCredentialsOptions()); }); var action = async () => await context.NavigateAsync(UrlBuilder.WhereIs("basicAuth"), new() { Wait = ReadinessState.Complete }); @@ -201,9 +201,9 @@ public async Task CanContinueWithCanceledCredentials() [Test] public async Task CanFailRequest() { - await using var intercept = await bidi.Network.InterceptRequestAsync(async e => + await using var intercept = await bidi.Network.InterceptRequestAsync(async req => { - await e.Request.Request.FailAsync(); + await req.FailAsync(); }); var action = async () => await context.NavigateAsync(UrlBuilder.WhereIs("basicAuth"), new() { Wait = ReadinessState.Complete });