Skip to content

Commit 3b7cdc1

Browse files
authored
Generalize Http2Cat #14894 (#17438)
1 parent 40c9989 commit 3b7cdc1

File tree

58 files changed

+890
-221
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+890
-221
lines changed

src/Servers/HttpSys/HttpSysServer.sln

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
2424
version.xml = version.xml
2525
EndProjectSection
2626
EndProject
27-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}"
27+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestClient", "samples\TestClient\TestClient.csproj", "{8B828433-B333-4C19-96AE-00BFFF9D8841}"
2828
EndProject
2929
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SelfHostServer", "samples\SelfHostServer\SelfHostServer.csproj", "{1236F93A-AC5C-4A77-9477-C88F040151CA}"
3030
EndProject
@@ -72,6 +72,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Connec
7272
EndProject
7373
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QueueSharing", "samples\QueueSharing\QueueSharing.csproj", "{9B58DF76-DC6D-4728-86B7-40087BDDC897}"
7474
EndProject
75+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets", "..\Kestrel\Transport.Sockets\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.csproj", "{33CF53ED-A4BC-4EAA-9EA7-EF5E748A03BB}"
76+
EndProject
7577
Global
7678
GlobalSection(SolutionConfigurationPlatforms) = preSolution
7779
Debug|Any CPU = Debug|Any CPU
@@ -318,6 +320,18 @@ Global
318320
{9B58DF76-DC6D-4728-86B7-40087BDDC897}.Release|Mixed Platforms.Build.0 = Release|Any CPU
319321
{9B58DF76-DC6D-4728-86B7-40087BDDC897}.Release|x86.ActiveCfg = Release|Any CPU
320322
{9B58DF76-DC6D-4728-86B7-40087BDDC897}.Release|x86.Build.0 = Release|Any CPU
323+
{33CF53ED-A4BC-4EAA-9EA7-EF5E748A03BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
324+
{33CF53ED-A4BC-4EAA-9EA7-EF5E748A03BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
325+
{33CF53ED-A4BC-4EAA-9EA7-EF5E748A03BB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
326+
{33CF53ED-A4BC-4EAA-9EA7-EF5E748A03BB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
327+
{33CF53ED-A4BC-4EAA-9EA7-EF5E748A03BB}.Debug|x86.ActiveCfg = Debug|Any CPU
328+
{33CF53ED-A4BC-4EAA-9EA7-EF5E748A03BB}.Debug|x86.Build.0 = Debug|Any CPU
329+
{33CF53ED-A4BC-4EAA-9EA7-EF5E748A03BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
330+
{33CF53ED-A4BC-4EAA-9EA7-EF5E748A03BB}.Release|Any CPU.Build.0 = Release|Any CPU
331+
{33CF53ED-A4BC-4EAA-9EA7-EF5E748A03BB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
332+
{33CF53ED-A4BC-4EAA-9EA7-EF5E748A03BB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
333+
{33CF53ED-A4BC-4EAA-9EA7-EF5E748A03BB}.Release|x86.ActiveCfg = Release|Any CPU
334+
{33CF53ED-A4BC-4EAA-9EA7-EF5E748A03BB}.Release|x86.Build.0 = Release|Any CPU
321335
EndGlobalSection
322336
GlobalSection(SolutionProperties) = preSolution
323337
HideSolutionNode = FALSE
@@ -344,6 +358,7 @@ Global
344358
{D93575B3-BFA3-4523-B060-D268D6A0A66B} = {4DA3C456-5050-4AC0-A554-795F6DEC8660}
345359
{00A88B8D-D539-45DD-B071-1E955AF89A4A} = {4DA3C456-5050-4AC0-A554-795F6DEC8660}
346360
{9B58DF76-DC6D-4728-86B7-40087BDDC897} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514}
361+
{33CF53ED-A4BC-4EAA-9EA7-EF5E748A03BB} = {4DA3C456-5050-4AC0-A554-795F6DEC8660}
347362
EndGlobalSection
348363
GlobalSection(ExtensibilityGlobals) = postSolution
349364
SolutionGuid = {34B42B42-FA09-41AB-9216-14073990C504}
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Threading.Tasks;
5+
using Microsoft.AspNetCore.Http2Cat;
6+
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
7+
using Microsoft.AspNetCore.Testing;
8+
using Microsoft.Extensions.Hosting;
9+
using Microsoft.Extensions.Logging;
10+
using Microsoft.Net.Http.Headers;
11+
using Xunit;
12+
13+
namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests
14+
{
15+
public class Http2Tests
16+
{
17+
[ConditionalFact(Skip = "https://github.com/aspnet/AspNetCore/issues/17420")]
18+
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10, SkipReason = "Http2 requires Win10")]
19+
[MaximumOSVersion(OperatingSystems.Windows, "10.0.18362.9999", SkipReason = "This is last version without GoAway support")]
20+
public async Task ConnectionClose_NoOSSupport_NoGoAway()
21+
{
22+
using var server = Utilities.CreateDynamicHttpsServer(out var address, httpContext =>
23+
{
24+
httpContext.Response.Headers[HeaderNames.Connection] = "close";
25+
return Task.FromResult(0);
26+
});
27+
28+
await new HostBuilder()
29+
.UseHttp2Cat(address, async h2Connection =>
30+
{
31+
await h2Connection.InitializeConnectionAsync();
32+
33+
h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
34+
35+
await h2Connection.StartStreamAsync(1, Http2Utilities.BrowserRequestHeaders, endStream: true);
36+
37+
var headersFrame = await h2Connection.ReceiveFrameAsync();
38+
39+
Assert.Equal(Http2FrameType.HEADERS, headersFrame.Type);
40+
Assert.True((headersFrame.Flags & (byte)Http2HeadersFrameFlags.END_HEADERS) != 0);
41+
Assert.True((headersFrame.Flags & (byte)Http2HeadersFrameFlags.END_STREAM) != 0);
42+
43+
h2Connection.Logger.LogInformation("Received headers in a single frame.");
44+
45+
var decodedHeaders = h2Connection.DecodeHeaders(headersFrame);
46+
47+
// HTTP/2 filters out the connection header
48+
Assert.False(decodedHeaders.ContainsKey(HeaderNames.Connection));
49+
Assert.Equal("200", decodedHeaders[HeaderNames.Status]);
50+
51+
// Send and receive a second request to ensure there is no GoAway frame on the wire yet.
52+
53+
await h2Connection.StartStreamAsync(3, Http2Utilities.BrowserRequestHeaders, endStream: true);
54+
55+
headersFrame = await h2Connection.ReceiveFrameAsync();
56+
57+
Assert.Equal(Http2FrameType.HEADERS, headersFrame.Type);
58+
Assert.True((headersFrame.Flags & (byte)Http2HeadersFrameFlags.END_HEADERS) != 0);
59+
Assert.True((headersFrame.Flags & (byte)Http2HeadersFrameFlags.END_STREAM) != 0);
60+
61+
h2Connection.Logger.LogInformation("Received headers in a single frame.");
62+
63+
h2Connection.ResetHeaders();
64+
decodedHeaders = h2Connection.DecodeHeaders(headersFrame);
65+
66+
// HTTP/2 filters out the connection header
67+
Assert.False(decodedHeaders.ContainsKey(HeaderNames.Connection));
68+
Assert.Equal("200", decodedHeaders[HeaderNames.Status]);
69+
70+
await h2Connection.StopConnectionAsync(expectedLastStreamId: 1, ignoreNonGoAwayFrames: false);
71+
72+
h2Connection.Logger.LogInformation("Connection stopped.");
73+
})
74+
.Build().RunAsync();
75+
}
76+
77+
[ConditionalFact]
78+
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10_19H2, SkipReason = "GoAway support was added in Win10_19H2.")]
79+
public async Task ConnectionClose_OSSupport_SendsGoAway()
80+
{
81+
using var server = Utilities.CreateDynamicHttpsServer(out var address, httpContext =>
82+
{
83+
httpContext.Response.Headers[HeaderNames.Connection] = "close";
84+
return Task.FromResult(0);
85+
});
86+
87+
await new HostBuilder()
88+
.UseHttp2Cat(address, async h2Connection =>
89+
{
90+
await h2Connection.InitializeConnectionAsync();
91+
92+
h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
93+
94+
await h2Connection.StartStreamAsync(1, Http2Utilities.BrowserRequestHeaders, endStream: true);
95+
96+
var goAwayFrame = await h2Connection.ReceiveFrameAsync();
97+
h2Connection.VerifyGoAway(goAwayFrame, int.MaxValue, Http2ErrorCode.NO_ERROR);
98+
99+
var headersFrame = await h2Connection.ReceiveFrameAsync();
100+
101+
Assert.Equal(Http2FrameType.HEADERS, headersFrame.Type);
102+
Assert.Equal(Http2HeadersFrameFlags.END_HEADERS, headersFrame.HeadersFlags);
103+
104+
h2Connection.Logger.LogInformation("Received headers in a single frame.");
105+
106+
var decodedHeaders = h2Connection.DecodeHeaders(headersFrame);
107+
108+
// HTTP/2 filters out the connection header
109+
Assert.False(decodedHeaders.ContainsKey(HeaderNames.Connection));
110+
Assert.Equal("200", decodedHeaders[HeaderNames.Status]);
111+
112+
var dataFrame = await h2Connection.ReceiveFrameAsync();
113+
Assert.Equal(Http2FrameType.DATA, dataFrame.Type);
114+
Assert.Equal(Http2DataFrameFlags.END_STREAM, dataFrame.DataFlags);
115+
Assert.Equal(0, dataFrame.PayloadLength);
116+
117+
// Http.Sys doesn't send a final GoAway unless we ignore the first one and send 200 additional streams.
118+
119+
h2Connection.Logger.LogInformation("Connection stopped.");
120+
})
121+
.Build().RunAsync();
122+
}
123+
124+
[ConditionalFact]
125+
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10_19H2, SkipReason = "GoAway support was added in Win10_19H2.")]
126+
public async Task ConnectionClose_AdditionalRequests_ReceivesSecondGoAway()
127+
{
128+
using var server = Utilities.CreateDynamicHttpsServer(out var address, httpContext =>
129+
{
130+
httpContext.Response.Headers[HeaderNames.Connection] = "close";
131+
return Task.FromResult(0);
132+
});
133+
134+
await new HostBuilder()
135+
.UseHttp2Cat(address, async h2Connection =>
136+
{
137+
await h2Connection.InitializeConnectionAsync();
138+
139+
h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
140+
141+
var streamId = 1;
142+
await h2Connection.StartStreamAsync(streamId, Http2Utilities.BrowserRequestHeaders, endStream: true);
143+
144+
var goAwayFrame = await h2Connection.ReceiveFrameAsync();
145+
h2Connection.VerifyGoAway(goAwayFrame, int.MaxValue, Http2ErrorCode.NO_ERROR);
146+
147+
var headersFrame = await h2Connection.ReceiveFrameAsync();
148+
149+
Assert.Equal(Http2FrameType.HEADERS, headersFrame.Type);
150+
Assert.Equal(Http2HeadersFrameFlags.END_HEADERS, headersFrame.HeadersFlags);
151+
Assert.Equal(streamId, headersFrame.StreamId);
152+
153+
h2Connection.Logger.LogInformation("Received headers in a single frame.");
154+
155+
var decodedHeaders = h2Connection.DecodeHeaders(headersFrame);
156+
157+
// HTTP/2 filters out the connection header
158+
Assert.False(decodedHeaders.ContainsKey(HeaderNames.Connection));
159+
Assert.Equal("200", decodedHeaders[HeaderNames.Status]);
160+
h2Connection.ResetHeaders();
161+
162+
var dataFrame = await h2Connection.ReceiveFrameAsync();
163+
Assert.Equal(Http2FrameType.DATA, dataFrame.Type);
164+
Assert.Equal(Http2DataFrameFlags.END_STREAM, dataFrame.DataFlags);
165+
Assert.Equal(0, dataFrame.PayloadLength);
166+
Assert.Equal(streamId, dataFrame.StreamId);
167+
168+
// Http.Sys doesn't send a final GoAway unless we ignore the first one and send 200 additional streams.
169+
170+
for (var i = 1; i < 200; i++)
171+
{
172+
streamId = 1 + (i * 2); // Odds.
173+
await h2Connection.StartStreamAsync(streamId, Http2Utilities.BrowserRequestHeaders, endStream: true);
174+
175+
headersFrame = await h2Connection.ReceiveFrameAsync();
176+
177+
Assert.Equal(Http2FrameType.HEADERS, headersFrame.Type);
178+
Assert.Equal(Http2HeadersFrameFlags.END_HEADERS, headersFrame.HeadersFlags);
179+
Assert.Equal(streamId, headersFrame.StreamId);
180+
181+
h2Connection.Logger.LogInformation("Received headers in a single frame.");
182+
183+
decodedHeaders = h2Connection.DecodeHeaders(headersFrame);
184+
185+
// HTTP/2 filters out the connection header
186+
Assert.False(decodedHeaders.ContainsKey(HeaderNames.Connection));
187+
Assert.Equal("200", decodedHeaders[HeaderNames.Status]);
188+
h2Connection.ResetHeaders();
189+
190+
dataFrame = await h2Connection.ReceiveFrameAsync();
191+
Assert.Equal(Http2FrameType.DATA, dataFrame.Type);
192+
Assert.Equal(Http2DataFrameFlags.END_STREAM, dataFrame.DataFlags);
193+
Assert.Equal(0, dataFrame.PayloadLength);
194+
Assert.Equal(streamId, dataFrame.StreamId);
195+
}
196+
197+
streamId = 1 + (200 * 2); // Odds.
198+
await h2Connection.StartStreamAsync(streamId, Http2Utilities.BrowserRequestHeaders, endStream: true);
199+
200+
// Final GoAway
201+
goAwayFrame = await h2Connection.ReceiveFrameAsync();
202+
h2Connection.VerifyGoAway(goAwayFrame, streamId, Http2ErrorCode.NO_ERROR);
203+
204+
// Normal response
205+
headersFrame = await h2Connection.ReceiveFrameAsync();
206+
207+
Assert.Equal(Http2FrameType.HEADERS, headersFrame.Type);
208+
Assert.Equal(Http2HeadersFrameFlags.END_HEADERS, headersFrame.HeadersFlags);
209+
Assert.Equal(streamId, headersFrame.StreamId);
210+
211+
h2Connection.Logger.LogInformation("Received headers in a single frame.");
212+
213+
decodedHeaders = h2Connection.DecodeHeaders(headersFrame);
214+
215+
// HTTP/2 filters out the connection header
216+
Assert.False(decodedHeaders.ContainsKey(HeaderNames.Connection));
217+
Assert.Equal("200", decodedHeaders[HeaderNames.Status]);
218+
h2Connection.ResetHeaders();
219+
220+
dataFrame = await h2Connection.ReceiveFrameAsync();
221+
Assert.Equal(Http2FrameType.DATA, dataFrame.Type);
222+
Assert.Equal(Http2DataFrameFlags.END_STREAM, dataFrame.DataFlags);
223+
Assert.Equal(0, dataFrame.PayloadLength);
224+
Assert.Equal(streamId, dataFrame.StreamId);
225+
226+
h2Connection.Logger.LogInformation("Connection stopped.");
227+
})
228+
.Build().RunAsync();
229+
}
230+
}
231+
}

src/Servers/HttpSys/test/FunctionalTests/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
55
<TestGroupName>HttpSys.FunctionalTests</TestGroupName>
66
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
77
</PropertyGroup>
88

9+
<ItemGroup>
10+
<Compile Include="$(SharedSourceRoot)Http2\**\*.cs" LinkBase="Shared\Http2\" />
11+
<Compile Include="$(SharedSourceRoot)Http2cat\**\*.cs" LinkBase="Shared\Http2cat" />
12+
<Compile Include="$(SharedSourceRoot)ServerInfrastructure\**\*.cs" LinkBase="Shared\" />
13+
<Compile Include="$(SharedSourceRoot)TaskToApm.cs" Link="Shared\TaskToApm.cs" />
14+
</ItemGroup>
15+
916
<ItemGroup>
1017
<Reference Include="Microsoft.AspNetCore.Server.HttpSys" />
18+
<Reference Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets" />
19+
<Reference Include="Microsoft.Extensions.Hosting" />
1120
<Reference Include="System.Net.Http.WinHttpHandler" />
1221
</ItemGroup>
1322

@@ -22,4 +31,15 @@
2231
<HelixPreCommand Include="call RunPowershell.cmd UpdateIISExpressCertificate.ps1 || exit /b 1" />
2332
</ItemGroup>
2433

34+
<ItemGroup>
35+
<EmbeddedResource Include="$(SharedSourceRoot)ServerInfrastructure\SharedStrings.resx" Link="Shared\SharedStrings.resx">
36+
<ManifestResourceName>Microsoft.AspNetCore.Server.SharedStrings</ManifestResourceName>
37+
<Generator></Generator>
38+
</EmbeddedResource>
39+
<EmbeddedResource Include="$(SharedSourceRoot)Http2\SR.resx" Link="Shared\Http2\SR.resx">
40+
<ManifestResourceName>System.Net.Http.SR</ManifestResourceName>
41+
<Generator></Generator>
42+
</EmbeddedResource>
43+
</ItemGroup>
44+
2545
</Project>

src/Servers/Kestrel/Core/src/Microsoft.AspNetCore.Server.Kestrel.Core.csproj

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
<Compile Include="$(SharedSourceRoot)CertificateGeneration\**\*.cs" />
1616
<Compile Include="$(SharedSourceRoot)ValueTaskExtensions\**\*.cs" />
1717
<Compile Include="$(SharedSourceRoot)UrlDecoder\**\*.cs" />
18-
<Compile Include="$(SharedSourceRoot)Http2\**\*.cs" Link="Shared\Http2\%(Filename)%(Extension)" />
18+
<Compile Include="$(SharedSourceRoot)Http2\**\*.cs" LinkBase="Shared\Http2\" />
19+
<Compile Include="$(SharedSourceRoot)ServerInfrastructure\**\*.cs" LinkBase="Shared\" />
1920
<Compile Include="$(RepoRoot)src\Shared\TaskToApm.cs" Link="Internal\TaskToApm.cs" />
2021
</ItemGroup>
2122

@@ -35,6 +36,10 @@
3536
<EmbeddedResource Update="CoreStrings.resx">
3637
<Generator></Generator>
3738
</EmbeddedResource>
39+
<EmbeddedResource Include="$(SharedSourceRoot)ServerInfrastructure\SharedStrings.resx" Link="Shared\SharedStrings.resx">
40+
<ManifestResourceName>Microsoft.AspNetCore.Server.SharedStrings</ManifestResourceName>
41+
<Generator></Generator>
42+
</EmbeddedResource>
3843
<EmbeddedResource Include="$(SharedSourceRoot)Http2\SR.resx" Link="Shared\Http2\SR.resx">
3944
<ManifestResourceName>System.Net.Http.SR</ManifestResourceName>
4045
<Generator></Generator>

src/Servers/Kestrel/Core/src/Middleware/HttpsConnectionMiddleware.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -291,19 +291,5 @@ private static X509Certificate2 ConvertToX509Certificate2(X509Certificate certif
291291

292292
return new X509Certificate2(certificate);
293293
}
294-
295-
private class SslDuplexPipe : DuplexPipeStreamAdapter<SslStream>
296-
{
297-
public SslDuplexPipe(IDuplexPipe transport, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions)
298-
: this(transport, readerOptions, writerOptions, s => new SslStream(s))
299-
{
300-
301-
}
302-
303-
public SslDuplexPipe(IDuplexPipe transport, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions, Func<Stream, SslStream> factory) :
304-
base(transport, readerOptions, writerOptions, factory)
305-
{
306-
}
307-
}
308294
}
309295
}

src/Servers/Kestrel/Core/src/Properties/AssemblyInfo.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,3 @@
1414
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.Performance, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
1515
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
1616
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
17-
[assembly: InternalsVisibleTo("http2cat, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

0 commit comments

Comments
 (0)