Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement straightforward ServicePoint(Manager) properties in HttpWebRequest #94664

Merged
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
<Compile Include="System\Net\ServicePoint\SecurityProtocolType.cs" />
<Compile Include="System\Net\ServicePoint\ServicePoint.cs" />
<Compile Include="System\Net\ServicePoint\ServicePointManager.cs" />
<Compile Include="System\Net\ServicePoint\TcpKeepAlive.cs" />
<Compile Include="$(CommonPath)System\Obsoletions.cs"
Link="Common\System\Obsoletions.cs" />
<Compile Include="$(CommonPath)System\Net\Http\HttpHandlerDefaults.cs"
Expand Down
35 changes: 31 additions & 4 deletions src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ public class HttpWebRequest : WebRequest, ISerializable
private readonly Uri _requestUri = null!;
private string _originVerb = HttpMethod.Get.Method;

// We allow getting and setting this (to preserve app-compat). But we don't do anything with it
// as the underlying System.Net.Http API doesn't support it.
private int _continueTimeout = DefaultContinueTimeout;

private bool _allowReadStreamBuffering;
Expand Down Expand Up @@ -115,6 +113,9 @@ private sealed class HttpClientParameters
public readonly RemoteCertificateValidationCallback? ServerCertificateValidationCallback;
public readonly X509CertificateCollection? ClientCertificates;
public readonly CookieContainer? CookieContainer;
public readonly ServicePoint? ServicePoint;
liveans marked this conversation as resolved.
Show resolved Hide resolved
public readonly bool ReusePort;
public readonly TimeSpan ContinueTimeout;

public HttpClientParameters(HttpWebRequest webRequest, bool async)
{
Expand All @@ -135,6 +136,9 @@ public HttpClientParameters(HttpWebRequest webRequest, bool async)
ServerCertificateValidationCallback = webRequest.ServerCertificateValidationCallback ?? ServicePointManager.ServerCertificateValidationCallback;
ClientCertificates = webRequest._clientCertificates;
CookieContainer = webRequest._cookieContainer;
ServicePoint = webRequest._servicePoint;
ReusePort = ServicePointManager.ReusePort;
ContinueTimeout = TimeSpan.FromMilliseconds(webRequest.ContinueTimeout);
}

public bool Matches(HttpClientParameters requestParameters)
Expand All @@ -149,11 +153,14 @@ public bool Matches(HttpClientParameters requestParameters)
&& Timeout == requestParameters.Timeout
&& SslProtocols == requestParameters.SslProtocols
&& CheckCertificateRevocationList == requestParameters.CheckCertificateRevocationList
&& ReusePort == requestParameters.ReusePort
&& ContinueTimeout == requestParameters.ContinueTimeout
&& ReferenceEquals(Credentials, requestParameters.Credentials)
&& ReferenceEquals(Proxy, requestParameters.Proxy)
&& ReferenceEquals(ServerCertificateValidationCallback, requestParameters.ServerCertificateValidationCallback)
&& ReferenceEquals(ClientCertificates, requestParameters.ClientCertificates)
&& ReferenceEquals(CookieContainer, requestParameters.CookieContainer);
&& ReferenceEquals(CookieContainer, requestParameters.CookieContainer)
&& ReferenceEquals(ServicePoint, requestParameters.ServicePoint);
}

public bool AreParametersAcceptableForCaching()
Expand Down Expand Up @@ -1598,6 +1605,7 @@ private static HttpClient CreateHttpClient(HttpClientParameters parameters, Http
handler.MaxAutomaticRedirections = parameters.MaximumAutomaticRedirections;
handler.MaxResponseHeadersLength = parameters.MaximumResponseHeadersLength;
handler.PreAuthenticate = parameters.PreAuthenticate;
handler.Expect100ContinueTimeout = parameters.ContinueTimeout;
client.Timeout = parameters.Timeout;

if (parameters.CookieContainer != null)
Expand Down Expand Up @@ -1660,7 +1668,26 @@ private static HttpClient CreateHttpClient(HttpClientParameters parameters, Http

try
{
socket.NoDelay = true;
if (parameters.ServicePoint is not null)
liveans marked this conversation as resolved.
Show resolved Hide resolved
liveans marked this conversation as resolved.
Show resolved Hide resolved
{
socket.NoDelay = !parameters.ServicePoint.UseNagleAlgorithm;
liveans marked this conversation as resolved.
Show resolved Hide resolved
socket.ReceiveBufferSize = parameters.ServicePoint.ReceiveBufferSize;
liveans marked this conversation as resolved.
Show resolved Hide resolved

if (parameters.ServicePoint.KeepAlive is not null)
{
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, parameters.ServicePoint.KeepAlive.Value.Time);
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, parameters.ServicePoint.KeepAlive.Value.Interval);
}

// TODO (aaksoy): Implement support for ServicePoint.BindIPEndPointDelegate.
liveans marked this conversation as resolved.
Show resolved Hide resolved
}
else
{
socket.NoDelay = true;
}

socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.ReuseUnicastPort, parameters.ReusePort);
liveans marked this conversation as resolved.
Show resolved Hide resolved

if (parameters.Async)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public class ServicePoint
private int _receiveBufferSize = -1;
private int _connectionLimit;

internal TcpKeepAlive? KeepAlive { get; set; }

internal ServicePoint(Uri address)
{
Debug.Assert(address != null);
Expand Down Expand Up @@ -87,11 +89,20 @@ public int ConnectionLimit

public void SetTcpKeepAlive(bool enabled, int keepAliveTime, int keepAliveInterval)
{
if (enabled)
if (!enabled)
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(keepAliveTime);
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(keepAliveInterval);
KeepAlive = null;
return;
}

ArgumentOutOfRangeException.ThrowIfNegativeOrZero(keepAliveTime);
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(keepAliveInterval);

KeepAlive = new TcpKeepAlive
{
Time = keepAliveTime,
Interval = keepAliveInterval
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ private static void ValidateSecurityProtocol(SecurityProtocolType value)
}
}

internal static TcpKeepAlive? KeepAlive { get; private set; }
liveans marked this conversation as resolved.
Show resolved Hide resolved

public static int MaxServicePoints
{
get { return s_maxServicePoints; }
Expand Down Expand Up @@ -153,7 +155,8 @@ public static ServicePoint FindServicePoint(Uri address, IWebProxy? proxy)
ConnectionLimit = DefaultConnectionLimit,
IdleSince = DateTime.Now,
Expect100Continue = Expect100Continue,
UseNagleAlgorithm = UseNagleAlgorithm
UseNagleAlgorithm = UseNagleAlgorithm,
KeepAlive = KeepAlive
};
s_servicePointTable[tableKey] = new WeakReference<ServicePoint>(sp);

Expand Down Expand Up @@ -208,11 +211,20 @@ private static string MakeQueryString(Uri address, bool isProxy)

public static void SetTcpKeepAlive(bool enabled, int keepAliveTime, int keepAliveInterval)
{
if (enabled)
if (!enabled)
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(keepAliveTime);
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(keepAliveInterval);
KeepAlive = null;
return;
}

ArgumentOutOfRangeException.ThrowIfNegativeOrZero(keepAliveTime);
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(keepAliveInterval);

KeepAlive = new TcpKeepAlive
{
Time = keepAliveTime,
Interval = keepAliveInterval
};
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace System.Net
{
internal struct TcpKeepAlive
{
internal int Time { get; set; }
internal int Interval { get; set; }
}
}
Loading