Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion dotnet/src/webdriver/Command.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,29 @@ public string ParametersAsJsonString
}
}

/// <summary>
/// Serializes the parameters of the comand to JSON as UTF-8 bytes.
/// </summary>
/// <returns></returns>
public byte[] GetParametersAsUtf8Bytes()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Command is an abstraction. Command to bytes... we should mention json in method name. Like GetParametersAsJsoonUtf8Bytes()

{
if (this.Parameters != null && this.Parameters.Count > 0)
{
return JsonSerializer.SerializeToUtf8Bytes(this.Parameters, s_jsonSerializerOptions);
}
else
{
return "{}"u8.ToArray();
}
}

/// <summary>
/// Returns a string of the Command object
/// </summary>
/// <returns>A string representation of the Command Object</returns>
public override string ToString()
{
return string.Concat("[", this.SessionId, "]: ", this.Name, " ", this.ParametersAsJsonString);
return $"[{this.SessionId}]: {this.Name} {this.ParametersAsJsonString}";
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sidenote: ParametersAsJsonString does JSON serialization, here inside the ToString() method. I missed this as part of #14741. Do we want to change this? (Follow-up PR either way)

}

/// <summary>
Expand Down
6 changes: 3 additions & 3 deletions dotnet/src/webdriver/Remote/HttpCommandExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ private async Task<HttpResponseInfo> MakeHttpRequest(HttpRequestInfo requestInfo
acceptHeader.CharSet = Utf8CharsetType;
requestMessage.Headers.Accept.Add(acceptHeader);

byte[] bytes = Encoding.UTF8.GetBytes(requestInfo.RequestBody);
byte[] bytes = requestInfo.RequestBody;
requestMessage.Content = new ByteArrayContent(bytes, 0, bytes.Length);

MediaTypeHeaderValue contentTypeHeader = new MediaTypeHeaderValue(JsonMimeType);
Expand Down Expand Up @@ -370,12 +370,12 @@ public HttpRequestInfo(Uri serverUri, Command commandToExecute, HttpCommandInfo

this.FullUri = commandInfo.CreateCommandUri(serverUri, commandToExecute);
this.HttpMethod = commandInfo.Method;
this.RequestBody = commandToExecute.ParametersAsJsonString;
this.RequestBody = commandToExecute.GetParametersAsUtf8Bytes();
}

public Uri FullUri { get; set; }
public string HttpMethod { get; set; }
public string RequestBody { get; set; }
public byte[] RequestBody { get; set; }
}

private class HttpResponseInfo
Expand Down
32 changes: 30 additions & 2 deletions dotnet/src/webdriver/Remote/SendingRemoteHttpRequestEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

using System;
using System.Collections.Generic;
using System.Text;

#nullable enable

Expand All @@ -29,6 +30,8 @@ namespace OpenQA.Selenium.Remote
/// </summary>
public class SendingRemoteHttpRequestEventArgs : EventArgs
{
private string? _requestBody;
private readonly byte[]? _utf8RequestBody;
private readonly Dictionary<string, string> headers = new Dictionary<string, string>();

/// <summary>
Expand All @@ -42,7 +45,21 @@ public SendingRemoteHttpRequestEventArgs(string method, string fullUrl, string?
{
this.Method = method ?? throw new ArgumentNullException(nameof(method));
this.FullUrl = fullUrl ?? throw new ArgumentNullException(nameof(fullUrl));
this.RequestBody = requestBody;
_utf8RequestBody = requestBody is null ? null : Encoding.UTF8.GetBytes(requestBody);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Old constructor kept around for backwards compatibility, but unused by our code.

}

/// <summary>
/// Initializes a new instance of the <see cref="SendingRemoteHttpRequestEventArgs"/> class.
/// </summary>
/// <param name="method">The HTTP method of the request being sent.</param>
/// <param name="fullUrl">The full URL of the request being sent.</param>
/// <param name="requestBody">The body of the request.</param>
/// <exception cref="ArgumentNullException">If <paramref name="method"/>, <paramref name="fullUrl"/> are null.</exception>
public SendingRemoteHttpRequestEventArgs(string method, string fullUrl, byte[]? requestBody)
{
this.Method = method ?? throw new ArgumentNullException(nameof(method));
this.FullUrl = fullUrl ?? throw new ArgumentNullException(nameof(fullUrl));
_utf8RequestBody = requestBody;
}

/// <summary>
Expand All @@ -58,7 +75,18 @@ public SendingRemoteHttpRequestEventArgs(string method, string fullUrl, string?
/// <summary>
/// Gets the body of the HTTP request as a string.
/// </summary>
public string? RequestBody { get; }
public string? RequestBody
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This event args seems to be an obscure mechanism to add headers to requests. I don't know how many people are accessing the SendingRemoteHttpRequestEventArgs.RequestBody property in the world.

For this reason, I feel that the added complexity is warranted: We will not decode our data into a string unless the user requests it (and we cache it here so users do not have to worry about it).

{
get
{
if (_requestBody is not null)
{
return _requestBody;
}

return _requestBody = _utf8RequestBody is null ? null : Encoding.UTF8.GetString(_utf8RequestBody);
}
}

/// <summary>
/// Gets a read-only dictionary of the headers of the HTTP request.
Expand Down
18 changes: 17 additions & 1 deletion dotnet/test/common/CommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@ namespace OpenQA.Selenium
[TestFixture]
public class CommandTests
{
[Test]
public void CommandSerializesNullParameters()
{
var command = new Command(new SessionId("session"), "test command", parameters: null);

Assert.That(command.GetParametersAsUtf8Bytes(), Is.EqualTo("{}"u8.ToArray()));
}

[Test]
public void CommandSerializesEmptyParameters()
{
var command = new Command(new SessionId("session"), "test command", parameters: new Dictionary<string, object>());

Assert.That(command.GetParametersAsUtf8Bytes(), Is.EqualTo("{}"u8.ToArray()));
}

[Test]
public void CommandSerializesAnonymousType()
{
Expand All @@ -35,7 +51,7 @@ public void CommandSerializesAnonymousType()

var command = new Command(new SessionId("session"), "test command", parameters);

Assert.That(command.ParametersAsJsonString, Is.EqualTo("""{"arg":{"param1":true,"param2":false}}"""));
Assert.That(command.GetParametersAsUtf8Bytes(), Is.EqualTo("""{"arg":{"param1":true,"param2":false}}"""u8.ToArray()));
}
}
}
Loading