Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/trunk' into dynamic-grid
Browse files Browse the repository at this point in the history
  • Loading branch information
VietND96 committed Jan 11, 2025
2 parents e309cde + 4aee006 commit 45a6759
Show file tree
Hide file tree
Showing 41 changed files with 423 additions and 455 deletions.
42 changes: 17 additions & 25 deletions dotnet/src/webdriver/CookieJar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,20 @@ public ReadOnlyCollection<Cookie> AllCookies
{
Response response = driver.InternalExecute(DriverCommand.GetAllCookies, new Dictionary<string, object>());

try
List<Cookie> toReturn = new List<Cookie>();
if (response.Value is object?[] cookies)
{
List<Cookie> toReturn = new List<Cookie>();
if (response.Value is object?[] cookies)
foreach (object? rawCookie in cookies)
{
foreach (object? rawCookie in cookies)
if (rawCookie != null)
{
if (rawCookie != null)
{
Cookie newCookie = Cookie.FromDictionary((Dictionary<string, object?>)rawCookie);
toReturn.Add(newCookie);
}
Cookie newCookie = Cookie.FromDictionary((Dictionary<string, object?>)rawCookie);
toReturn.Add(newCookie);
}
}

return new ReadOnlyCollection<Cookie>(toReturn);
}
catch (Exception e)
{
throw new WebDriverException("Unexpected problem getting cookies", e);
}

return new ReadOnlyCollection<Cookie>(toReturn);
}
}

Expand Down Expand Up @@ -124,22 +117,21 @@ public void DeleteAllCookies()
/// <returns>A Cookie from the name; or <see langword="null"/> if not found.</returns>
public Cookie? GetCookieNamed(string name)
{
if (name is null)
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentNullException(nameof(name));
throw new ArgumentException("Cookie name cannot be empty", nameof(name));
}


foreach (Cookie currentCookie in this.AllCookies)
try
{
if (name.Equals(currentCookie.Name))
{
return currentCookie;
}
var rawCookie = driver.InternalExecute(DriverCommand.GetCookie, new() { { "name", name } }).Value;

return Cookie.FromDictionary((Dictionary<string, object>)rawCookie);
}
catch (NoSuchCookieException)
{
return null;
}

return null;
}
}
}
35 changes: 35 additions & 0 deletions dotnet/src/webdriver/DevTools/Json/DevToolsJsonOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// <copyright file="DevToolsJsonOptions.cs" company="Selenium Committers">
// 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.
// </copyright>

using System.Text.Json;

#nullable enable

namespace OpenQA.Selenium.DevTools.Json;

internal static class DevToolsJsonOptions
{
public static JsonSerializerOptions Default { get; } = new JsonSerializerOptions()
{
Converters =
{
new StringConverter(),
}
};
}
61 changes: 61 additions & 0 deletions dotnet/src/webdriver/DevTools/Json/StringConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// <copyright file="StringConverter.cs" company="Selenium Committers">
// 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.
// </copyright>

using System;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

#nullable enable

namespace OpenQA.Selenium.DevTools.Json;

internal sealed class StringConverter : JsonConverter<string>
{
public override bool HandleNull => true;

public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
try
{
return reader.GetString();
}
catch (InvalidOperationException)
{
// Fallback to read the value as bytes instead of string.
// System.Text.Json library throws exception when CDP remote end sends non-encoded string as binary data.
// Using JavaScriptEncoder.UnsafeRelaxedJsonEscaping doesn't help because the string actually is byte[].
// https://chromedevtools.github.io/devtools-protocol/tot/Network/#type-Request - here "postData" property
// is a string, which we cannot deserialize properly. This property is marked as deprecated, and new "postDataEntries"
// is suggested for using, where most likely it is base64 encoded.

var bytes = reader.ValueSpan;
var sb = new StringBuilder(bytes.Length);
foreach (byte b in bytes)
{
sb.Append(Convert.ToChar(b));
}

return sb.ToString();
}
}

public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) =>
writer.WriteStringValue(value);
}
2 changes: 1 addition & 1 deletion dotnet/src/webdriver/ICookieJar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public interface ICookieJar
/// <param name="name">The name of the cookie to retrieve.</param>
/// <returns>The <see cref="Cookie"/> containing the name. Returns <see langword="null"/>
/// if no cookie with the specified name is found.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="name"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException">If <paramref name="name"/> is <see langword="null"/> or <see cref="string.Empty"/>.</exception>
Cookie? GetCookieNamed(string name);

/// <summary>
Expand Down
33 changes: 24 additions & 9 deletions dotnet/src/webdriver/Internal/Logging/LogContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;

#nullable enable
Expand All @@ -30,7 +31,7 @@ namespace OpenQA.Selenium.Internal.Logging
/// Represents a logging context that provides methods for creating sub-contexts, retrieving loggers, emitting log messages, and configuring minimum log levels.
/// </summary>
/// <inheritdoc cref="ILogContext"/>
internal class LogContext : ILogContext
internal sealed class LogContext : ILogContext
{
private ConcurrentDictionary<Type, ILogger>? _loggers;

Expand All @@ -46,7 +47,7 @@ public LogContext(LogEventLevel level, ILogContext? parentLogContext, Concurrent

_parentLogContext = parentLogContext;

_loggers = loggers;
_loggers = CloneLoggers(loggers, level);

if (handlers is not null)
{
Expand All @@ -65,12 +66,7 @@ public ILogContext CreateContext()

public ILogContext CreateContext(LogEventLevel minimumLevel)
{
ConcurrentDictionary<Type, ILogger>? loggers = null;

if (_loggers != null)
{
loggers = new ConcurrentDictionary<Type, ILogger>(_loggers.Select(l => new KeyValuePair<Type, ILogger>(l.Key, new Logger(l.Value.Issuer, minimumLevel))));
}
ConcurrentDictionary<Type, ILogger>? loggers = CloneLoggers(_loggers, minimumLevel);

var context = new LogContext(minimumLevel, this, loggers, Handlers);

Expand Down Expand Up @@ -98,7 +94,7 @@ public ILogger GetLogger(Type type)

public bool IsEnabled(ILogger logger, LogEventLevel level)
{
return Handlers != null && level >= _level && level >= logger.Level;
return Handlers != null && level >= _level && (_loggers?.TryGetValue(logger.Issuer, out var loggerEntry) != true || level >= loggerEntry?.Level);
}

public void EmitMessage(ILogger logger, LogEventLevel level, string message)
Expand Down Expand Up @@ -155,5 +151,24 @@ public void Dispose()

Log.CurrentContext = _parentLogContext;
}

[return: NotNullIfNotNull(nameof(loggers))]
private static ConcurrentDictionary<Type, ILogger>? CloneLoggers(ConcurrentDictionary<Type, ILogger>? loggers, LogEventLevel minimumLevel)
{
if (loggers is null)
{
return null;
}

var cloned = new Dictionary<Type, ILogger>(loggers.Count);

foreach (KeyValuePair<Type, ILogger> logger in loggers)
{
var clonedLogger = new Logger(logger.Value.Issuer, minimumLevel);
cloned.Add(logger.Key, clonedLogger);
}

return new ConcurrentDictionary<Type, ILogger>(cloned);
}
}
}
63 changes: 63 additions & 0 deletions dotnet/src/webdriver/NoSuchCookieException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// <copyright file="NoSuchCookieException.cs" company="Selenium Committers">
// 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.
// </copyright>

using System;

#nullable enable

namespace OpenQA.Selenium
{
/// <summary>
/// The exception that is thrown when a cookie is not found.
/// </summary>
[Serializable]
public class NoSuchCookieException : NotFoundException
{
/// <summary>
/// Initializes a new instance of the <see cref="NoSuchCookieException"/> class.
/// </summary>
public NoSuchCookieException()
: base()
{
}

/// <summary>
/// Initializes a new instance of the <see cref="NoSuchCookieException"/> class with
/// a specified error message.
/// </summary>
/// <param name="message">The message that describes the error.</param>
public NoSuchCookieException(string? message)
: base(message)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="NoSuchCookieException"/> class with
/// a specified error message and a reference to the inner exception that is the
/// cause of this exception.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
/// <param name="innerException">The exception that is the cause of the current exception,
/// or <see langword="null"/> if no inner exception is specified.</param>
public NoSuchCookieException(string? message, Exception? innerException)
: base(message, innerException)
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ protected override void InitializeCommandDictionary()
this.TryAddCommand(DriverCommand.ExecuteScript, new HttpCommandInfo(HttpCommandInfo.PostCommand, "/session/{sessionId}/execute/sync"));
this.TryAddCommand(DriverCommand.ExecuteAsyncScript, new HttpCommandInfo(HttpCommandInfo.PostCommand, "/session/{sessionId}/execute/async"));
this.TryAddCommand(DriverCommand.GetAllCookies, new HttpCommandInfo(HttpCommandInfo.GetCommand, "/session/{sessionId}/cookie"));
this.TryAddCommand(DriverCommand.GetCookie, new HttpCommandInfo(HttpCommandInfo.PostCommand, "/session/{sessionId}/cookie/{name}"));
this.TryAddCommand(DriverCommand.GetCookie, new HttpCommandInfo(HttpCommandInfo.GetCommand, "/session/{sessionId}/cookie/{name}"));
this.TryAddCommand(DriverCommand.AddCookie, new HttpCommandInfo(HttpCommandInfo.PostCommand, "/session/{sessionId}/cookie"));
this.TryAddCommand(DriverCommand.DeleteCookie, new HttpCommandInfo(HttpCommandInfo.DeleteCommand, "/session/{sessionId}/cookie/{name}"));
this.TryAddCommand(DriverCommand.DeleteAllCookies, new HttpCommandInfo(HttpCommandInfo.DeleteCommand, "/session/{sessionId}/cookie"));
Expand Down
3 changes: 3 additions & 0 deletions dotnet/src/webdriver/WebDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,9 @@ private static void UnpackAndThrowOnError(Response errorResponse, string command
case WebDriverResult.UnsupportedOperation:
throw new UnsupportedOperationException(errorMessage);

case WebDriverResult.NoSuchCookie:
throw new NoSuchCookieException(errorMessage);

default:
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "{0} ({1})", errorMessage, errorResponse.Status));
}
Expand Down
4 changes: 2 additions & 2 deletions dotnet/src/webdriver/cdp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ add an entry for version `<N>` to the `SupportedDevToolsVersions` dictionary ini
6. In [`//dotnet/src/webdriver:WebDriver.csproj.prebuild.cmd`](https://github.com/SeleniumHQ/selenium/blob/trunk/dotnet/src/webdriver/WebDriver.csproj.prebuild.cmd),
add the following block (substituting the proper value for `<N>`):

```
```bash
if not exist "%1..\..\..\bazel-bin\dotnet\src\webdriver\cdp\v<N>\DevToolsSessionDomains.cs" (
echo Generating CDP code for version <N>
pushd "%1..\..\.."
Expand All @@ -29,7 +29,7 @@ if not exist "%1..\..\..\bazel-bin\dotnet\src\webdriver\cdp\v<N>\DevToolsSessio
7. In [`//dotnet/src/webdriver:WebDriver.csproj.prebuild.sh`](https://github.com/SeleniumHQ/selenium/blob/trunk/dotnet/src/webdriver/WebDriver.csproj.prebuild.sh),
add the following block (substituting the proper value for `<N>`):
```
```bash
if [[ ! -f "$1../../../bazel-bin/dotnet/src/webdriver/cdp/v<N>/DevToolsSessionDomains.cs" ]]
then
echo "Generating CDP code for version <N>"
Expand Down
Loading

0 comments on commit 45a6759

Please sign in to comment.