Skip to content

Commit

Permalink
[dotnet] Use new implementation of HttpClient in DriverService for co…
Browse files Browse the repository at this point in the history
…mmunication (SeleniumHQ#11143)

* Use new implementation of HttpClient

* Update SafariDriverService.cs
  • Loading branch information
nvborisenko committed Nov 22, 2022
1 parent 38d9776 commit a23df91
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 68 deletions.
68 changes: 39 additions & 29 deletions dotnet/src/webdriver/DriverService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
using System.Globalization;
using System.IO;
using System.Net;
using System.Security.Permissions;
using System.Net.Http;
using System.Threading.Tasks;
using OpenQA.Selenium.Internal;
using OpenQA.Selenium.Remote;

Expand Down Expand Up @@ -235,20 +236,23 @@ protected virtual bool IsInitialized
bool isInitialized = false;
try
{
Uri serviceHealthUri = new Uri(this.ServiceUrl, new Uri(DriverCommand.Status, UriKind.Relative));
HttpWebRequest request = HttpWebRequest.Create(serviceHealthUri) as HttpWebRequest;
request.KeepAlive = false;
request.Timeout = 5000;
HttpWebResponse response = request.GetResponse() as HttpWebResponse;

// Checking the response from the 'status' end point. Note that we are simply checking
// that the HTTP status returned is a 200 status, and that the resposne has the correct
// Content-Type header. A more sophisticated check would parse the JSON response and
// validate its values. At the moment we do not do this more sophisticated check.
isInitialized = response.StatusCode == HttpStatusCode.OK && response.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase);
response.Close();
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.ConnectionClose = true;
httpClient.Timeout = TimeSpan.FromSeconds(5);

Uri serviceHealthUri = new Uri(this.ServiceUrl, new Uri(DriverCommand.Status, UriKind.Relative));
using (var response = Task.Run(async () => await httpClient.GetAsync(serviceHealthUri)).GetAwaiter().GetResult())
{
// Checking the response from the 'status' end point. Note that we are simply checking
// that the HTTP status returned is a 200 status, and that the resposne has the correct
// Content-Type header. A more sophisticated check would parse the JSON response and
// validate its values. At the moment we do not do this more sophisticated check.
isInitialized = response.StatusCode == HttpStatusCode.OK && response.Content.Headers.ContentType.MediaType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase);
}
}
}
catch (WebException ex)
catch (Exception ex) when (ex is HttpRequestException || ex is TaskCanceledException)
{
Console.WriteLine(ex.Message);
}
Expand Down Expand Up @@ -394,23 +398,29 @@ private void Stop()
{
Uri shutdownUrl = new Uri(this.ServiceUrl, "/shutdown");
DateTime timeout = DateTime.Now.Add(this.TerminationTimeout);
while (this.IsRunning && DateTime.Now < timeout)
using (var httpClient = new HttpClient())
{
try
{
// Issue the shutdown HTTP request, then wait a short while for
// the process to have exited. If the process hasn't yet exited,
// we'll retry. We wait for exit here, since catching the exception
// for a failed HTTP request due to a closed socket is particularly
// expensive.
HttpWebRequest request = HttpWebRequest.Create(shutdownUrl) as HttpWebRequest;
request.KeepAlive = false;
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
response.Close();
this.driverServiceProcess.WaitForExit(3000);
}
catch (WebException)
httpClient.DefaultRequestHeaders.ConnectionClose = true;

while (this.IsRunning && DateTime.Now < timeout)
{
try
{
// Issue the shutdown HTTP request, then wait a short while for
// the process to have exited. If the process hasn't yet exited,
// we'll retry. We wait for exit here, since catching the exception
// for a failed HTTP request due to a closed socket is particularly
// expensive.
using (var response = Task.Run(async () => await httpClient.GetAsync(shutdownUrl)).GetAwaiter().GetResult())
{

}

this.driverServiceProcess.WaitForExit(3000);
}
catch (Exception ex) when (ex is HttpRequestException || ex is TimeoutException)
{
}
}
}
}
Expand Down
74 changes: 35 additions & 39 deletions dotnet/src/webdriver/Safari/SafariDriverService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@

using System;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using OpenQA.Selenium.Internal;

namespace OpenQA.Selenium.Safari
Expand Down Expand Up @@ -110,47 +112,41 @@ protected override bool IsInitialized
get
{
bool isInitialized = false;
try
{
// Since Firefox driver won't implement the /session end point (because
// the W3C spec working group stupidly decided that it isn't necessary),
// we'll attempt to poll for a different URL which has no side effects.
// We've chosen to poll on the "quit" URL, passing in a nonexistent
// session id.
Uri serviceHealthUri = new Uri(this.ServiceUrl, new Uri("/session/FakeSessionIdForPollingPurposes", UriKind.Relative));
HttpWebRequest request = HttpWebRequest.Create(serviceHealthUri) as HttpWebRequest;
request.KeepAlive = false;
request.Timeout = 5000;
request.Method = "DELETE";
HttpWebResponse response = request.GetResponse() as HttpWebResponse;

// Checking the response from deleting a nonexistent session. Note that we are simply
// checking that the HTTP status returned is a 200 status, and that the resposne has
// the correct Content-Type header. A more sophisticated check would parse the JSON
// response and validate its values. At the moment we do not do this more sophisticated
// check.
isInitialized = response.StatusCode == HttpStatusCode.OK && response.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase);
response.Close();
}
catch (WebException ex)

Uri serviceHealthUri = new Uri(this.ServiceUrl, new Uri("/session/FakeSessionIdForPollingPurposes", UriKind.Relative));

// Since Firefox driver won't implement the /session end point (because
// the W3C spec working group stupidly decided that it isn't necessary),
// we'll attempt to poll for a different URL which has no side effects.
// We've chosen to poll on the "quit" URL, passing in a nonexistent
// session id.
using (var httpClient = new HttpClient())
{
// Because the Firefox driver (incorrectly) does not allow quit on a
// nonexistent session to succeed, this will throw a WebException,
// which means we're reduced to using exception handling for flow control.
// This situation is highly undesirable, and in fact is a horrible code
// smell, but the implementation leaves us no choice. So we will check for
// the known response code and content type header, just like we would for
// the success case. Either way, a valid HTTP response instead of a socket
// error would tell us that the HTTP server is responding to requests, which
// is really what we want anyway.
HttpWebResponse errorResponse = ex.Response as HttpWebResponse;
if (errorResponse != null)
{
isInitialized = (errorResponse.StatusCode == HttpStatusCode.InternalServerError && errorResponse.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) || (errorResponse.StatusCode == HttpStatusCode.NotFound);
}
else
httpClient.DefaultRequestHeaders.ConnectionClose = true;
httpClient.Timeout = TimeSpan.FromSeconds(5);

using (var httpRequest = new HttpRequestMessage(HttpMethod.Delete, serviceHealthUri))
{
Console.WriteLine(ex.Message);
try
{
using (var httpResponse = Task.Run(async () => await httpClient.SendAsync(httpRequest)).GetAwaiter().GetResult())
{
isInitialized = (httpResponse.StatusCode == HttpStatusCode.OK
|| httpResponse.StatusCode == HttpStatusCode.InternalServerError
|| httpResponse.StatusCode == HttpStatusCode.NotFound)
&& httpResponse.Content.Headers.ContentType.MediaType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase);
}
}

// Checking the response from deleting a nonexistent session. Note that we are simply
// checking that the HTTP status returned is a 200 status, and that the resposne has
// the correct Content-Type header. A more sophisticated check would parse the JSON
// response and validate its values. At the moment we do not do this more sophisticated
// check.
catch (Exception ex) when (ex is HttpRequestException || ex is TaskCanceledException)
{
Console.WriteLine(ex);
}
}
}

Expand Down

0 comments on commit a23df91

Please sign in to comment.