Skip to content

Commit

Permalink
Don't call into unsupported APIs on build targets which don't support…
Browse files Browse the repository at this point in the history
… quic

The code could be extracted to HttpConnectionPool.quick.cs but not sure
it's worth the split as that would move the majority of the code.

Fixes #49201
Fixes #49187
  • Loading branch information
marek-safar committed Mar 6, 2021
1 parent 05f9cc1 commit ba66ddb
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 32 deletions.
15 changes: 10 additions & 5 deletions src/libraries/System.Net.Http/src/System.Net.Http.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
<PropertyGroup Condition="'$(TargetsBrowser)' == 'true'">
<DefineConstants>$(DefineConstants);TARGET_BROWSER</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetsWindows)' == 'true' or '$(TargetsLinux)' == 'true' or '$(TargetsFreeBSD)' == 'true' or '$(TargetsOSX)' == 'true'">
<DefineConstants>$(DefineConstants);HTTP3_SUPPORTED</DefineConstants>
<SupportsQuic>true</SupportsQuic>
</PropertyGroup>
<!-- ILLinker settings -->
<PropertyGroup>
<ILLinkDirectory>$(MSBuildThisFileDirectory)ILLink\</ILLinkDirectory>
</PropertyGroup>
<ItemGroup>
<ILLinkSubstitutionsXmls Include="$(ILLinkDirectory)ILLink.Substitutions.xml" />
</ItemGroup>

<ItemGroup>
<Compile Include="System\Net\Http\ByteArrayContent.cs" />
<Compile Include="System\Net\Http\ByteArrayHelpers.cs" />
Expand Down Expand Up @@ -152,10 +155,6 @@
<Compile Include="System\Net\Http\SocketsHttpHandler\Http2ProtocolException.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\Http2Stream.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\Http2StreamException.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\Http3Connection.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\Http3ConnectionException.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\Http3ProtocolException.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\Http3RequestStream.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\HttpAuthenticatedConnectionHandler.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\HttpAuthority.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\HttpConnection.cs" />
Expand Down Expand Up @@ -215,6 +214,12 @@
<Compile Include="$(CommonPath)Extensions\ValueStopwatch\ValueStopwatch.cs"
Link="Common\Extensions\ValueStopwatch\ValueStopwatch.cs" />
</ItemGroup>
<ItemGroup Condition="'$(SupportsQuic)' == 'true'">
<Compile Include="System\Net\Http\SocketsHttpHandler\Http3Connection.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\Http3ConnectionException.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\Http3ProtocolException.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\Http3RequestStream.cs" />
</ItemGroup>
<!-- Header support -->
<ItemGroup>
<Compile Include="$(CommonPath)System\Net\Http\aspnetcore\IHttpHeadersHandler.cs">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ private static async ValueTask<SslStream> EstablishSslConnectionAsyncCore(bool a
return sslStream;
}

#if HTTP3_SUPPORTED
public static async ValueTask<QuicConnection> ConnectQuicAsync(QuicImplementationProvider quicImplementationProvider, DnsEndPoint endPoint, SslClientAuthenticationOptions? clientAuthenticationOptions, CancellationToken cancellationToken)
{
QuicConnection con = new QuicConnection(quicImplementationProvider, endPoint, clientAuthenticationOptions);
Expand All @@ -114,6 +115,7 @@ public static async ValueTask<QuicConnection> ConnectQuicAsync(QuicImplementatio
throw CreateWrappedException(ex, endPoint.Host, endPoint.Port, cancellationToken);
}
}
#endif

internal static Exception CreateWrappedException(Exception error, string host, int port, CancellationToken cancellationToken)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ internal sealed class HttpConnectionPool : IDisposable
/// </summary>
private volatile HashSet<HttpAuthority>? _altSvcBlocklist;
private CancellationTokenSource? _altSvcBlocklistTimerCancellation;
private volatile bool _altSvcEnabled = true;
private volatile bool _altSvcEnabled;

/// <summary>
/// If <see cref="_altSvcBlocklist"/> exceeds this size, Alt-Svc will be disabled entirely for <see cref="AltSvcBlocklistTimeoutInMilliseconds"/> milliseconds.
Expand All @@ -72,18 +72,22 @@ internal sealed class HttpConnectionPool : IDisposable
private byte[]? _http2AltSvcOriginUri;
internal readonly byte[]? _http2EncodedAuthorityHostHeader;

#if HTTP3_SUPPORTED
private readonly bool _http3Enabled;
private Http3Connection? _http3Connection;
private SemaphoreSlim? _http3ConnectionCreateLock;
internal readonly byte[]? _http3EncodedAuthorityHostHeader;
private readonly SslClientAuthenticationOptions? _sslOptionsHttp3;
#else
private const bool _http3Enabled = false;
#endif

/// <summary>For non-proxy connection pools, this is the host name in bytes; for proxies, null.</summary>
private readonly byte[]? _hostHeaderValueBytes;
/// <summary>Options specialized and cached for this pool and its key.</summary>
private readonly SslClientAuthenticationOptions? _sslOptionsHttp11;
private readonly SslClientAuthenticationOptions? _sslOptionsHttp2;
private readonly SslClientAuthenticationOptions? _sslOptionsHttp2Only;
private readonly SslClientAuthenticationOptions? _sslOptionsHttp3;

/// <summary>Queue of waiters waiting for a connection. Created on demand.</summary>
private Queue<TaskCompletionSourceWithCancellation<HttpConnection?>>? _waiters;
Expand Down Expand Up @@ -119,7 +123,6 @@ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionK
}

_http2Enabled = _poolManager.Settings._maxHttpVersion >= HttpVersion.Version20;
_http3Enabled = _poolManager.Settings._maxHttpVersion >= HttpVersion.Version30 && (_poolManager.Settings._quicImplementationProvider ?? QuicImplementationProviders.Default).IsSupported;

switch (kind)
{
Expand All @@ -129,14 +132,18 @@ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionK
Debug.Assert(sslHostName == null);
Debug.Assert(proxyUri == null);

_http3Enabled = false;
break;

case HttpConnectionKind.Https:
Debug.Assert(host != null);
Debug.Assert(port != 0);
Debug.Assert(sslHostName != null);
Debug.Assert(proxyUri == null);

#if HTTP3_SUPPORTED
_http3Enabled = _poolManager.Settings._maxHttpVersion >= HttpVersion.Version30 && (_poolManager.Settings._quicImplementationProvider ?? QuicImplementationProviders.Default).IsSupported;
_altSvcEnabled = _http3Enabled;
#endif
break;

case HttpConnectionKind.Proxy:
Expand All @@ -146,7 +153,6 @@ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionK
Debug.Assert(proxyUri != null);

_http2Enabled = false;
_http3Enabled = false;
break;

case HttpConnectionKind.ProxyTunnel:
Expand All @@ -156,7 +162,6 @@ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionK
Debug.Assert(proxyUri != null);

_http2Enabled = false;
_http3Enabled = false;
break;

case HttpConnectionKind.SslProxyTunnel:
Expand All @@ -165,7 +170,7 @@ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionK
Debug.Assert(sslHostName != null);
Debug.Assert(proxyUri != null);

_http3Enabled = false; // TODO: how do we tunnel HTTP3?
// TODO: how do we tunnel HTTP3?
break;

case HttpConnectionKind.ProxyConnect:
Expand All @@ -175,20 +180,13 @@ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionK
Debug.Assert(proxyUri != null);

_http2Enabled = false;
_http3Enabled = false;
break;

default:
Debug.Fail("Unkown HttpConnectionKind in HttpConnectionPool.ctor");
break;
}

if (!_http3Enabled)
{
// Avoid parsing Alt-Svc headers if they won't be used.
_altSvcEnabled = false;
}

string? hostHeader = null;
if (_originAuthority != null)
{
Expand All @@ -205,7 +203,9 @@ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionK
if (sslHostName == null)
{
_http2EncodedAuthorityHostHeader = HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexingToAllocatedArray(H2StaticTable.Authority, hostHeader);
#if HTTP3_SUPPORTED
_http3EncodedAuthorityHostHeader = QPackEncoder.EncodeLiteralHeaderFieldWithStaticNameReferenceToArray(H3StaticTable.Authority, hostHeader);
#endif
}
}

Expand Down Expand Up @@ -237,14 +237,18 @@ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionK

Debug.Assert(hostHeader != null);
_http2EncodedAuthorityHostHeader = HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexingToAllocatedArray(H2StaticTable.Authority, hostHeader);
#if HTTP3_SUPPORTED
_http3EncodedAuthorityHostHeader = QPackEncoder.EncodeLiteralHeaderFieldWithStaticNameReferenceToArray(H3StaticTable.Authority, hostHeader);
#endif
}

#if HTTP3_SUPPORTED
if (_http3Enabled)
{
_sslOptionsHttp3 = ConstructSslOptions(poolManager, sslHostName);
_sslOptionsHttp3.ApplicationProtocols = s_http3ApplicationProtocols;
}
#endif
}

// Set up for PreAuthenticate. Access to this cache is guarded by a lock on the cache itself.
Expand All @@ -256,7 +260,9 @@ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionK
if (NetEventSource.Log.IsEnabled()) Trace($"{this}");
}

#if HTTP3_SUPPORTED
private static readonly List<SslApplicationProtocol> s_http3ApplicationProtocols = new List<SslApplicationProtocol>() { Http3Connection.Http3ApplicationProtocol31, Http3Connection.Http3ApplicationProtocol30, Http3Connection.Http3ApplicationProtocol29 };
#endif
private static readonly List<SslApplicationProtocol> s_http2ApplicationProtocols = new List<SslApplicationProtocol>() { SslApplicationProtocol.Http2, SslApplicationProtocol.Http11 };
private static readonly List<SslApplicationProtocol> s_http2OnlyApplicationProtocols = new List<SslApplicationProtocol>() { SslApplicationProtocol.Http2 };

Expand Down Expand Up @@ -352,6 +358,7 @@ public byte[] Http2AltSvcOriginUri
}
}

#if HTTP3_SUPPORTED
// Either H3 explicitly requested or secured upgraded allowed.
if (_http3Enabled && (request.Version.Major >= 3 || (request.VersionPolicy == HttpVersionPolicy.RequestVersionOrHigher && IsSecure)))
{
Expand All @@ -372,7 +379,7 @@ public byte[] Http2AltSvcOriginUri
return GetHttp3ConnectionAsync(request, authority, cancellationToken);
}
}

#endif
// If we got here, we cannot provide HTTP/3 connection. Do not continue if downgrade is not allowed.
if (request.Version.Major >= 3 && request.VersionPolicy != HttpVersionPolicy.RequestVersionOrLower)
{
Expand Down Expand Up @@ -745,6 +752,7 @@ private void AddHttp2Connection(Http2Connection newConnection)
}
}

#if HTTP3_SUPPORTED
private async ValueTask<(HttpConnectionBase? connection, bool isNewConnection, HttpResponseMessage? failureResponse)>
GetHttp3ConnectionAsync(HttpRequestMessage request, HttpAuthority authority, CancellationToken cancellationToken)
{
Expand Down Expand Up @@ -840,6 +848,18 @@ private void AddHttp2Connection(Http2Connection newConnection)
}
}

public void InvalidateHttp3Connection(Http3Connection connection)
{
lock (SyncObj)
{
if (_http3Connection == connection)
{
_http3Connection = null;
}
}
}
#endif

public async ValueTask<HttpResponseMessage> SendWithRetryAsync(HttpRequestMessage request, bool async, bool doRequestAuth, CancellationToken cancellationToken)
{
while (true)
Expand Down Expand Up @@ -917,6 +937,7 @@ public async ValueTask<HttpResponseMessage> SendWithRetryAsync(HttpRequestMessag
continue;
}

#if HTTP3_SUPPORTED
// Check for the Alt-Svc header, to upgrade to HTTP/3.
if (_altSvcEnabled && response.Headers.TryGetValues(KnownHeaders.AltSvc.Descriptor, out IEnumerable<string>? altSvcHeaderValues))
{
Expand All @@ -932,7 +953,7 @@ public async ValueTask<HttpResponseMessage> SendWithRetryAsync(HttpRequestMessag
BlocklistAuthority(h3Connection.Authority);
continue;
}

#endif
return response;
}
}
Expand Down Expand Up @@ -1645,17 +1666,6 @@ public void InvalidateHttp2Connection(Http2Connection connection)
}
}

public void InvalidateHttp3Connection(Http3Connection connection)
{
lock (SyncObj)
{
if (_http3Connection == connection)
{
_http3Connection = null;
}
}
}

/// <summary>
/// Disposes the connection pool. This is only needed when the pool currently contains
/// or has associated connections.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,9 @@ private static bool AllowDraftHttp3

public bool EnableMultipleHttp2Connections => _enableMultipleHttp2Connections;

#if HTTP3_SUPPORTED
private byte[]? _http3SettingsFrame;
internal byte[] Http3SettingsFrame => _http3SettingsFrame ??= Http3Connection.BuildSettingsFrame(this);
#endif
}
}

0 comments on commit ba66ddb

Please sign in to comment.