Sockets transport (#2100)

* Make Sockets the default transport
* Create separate Libuv and Sockets functional test projects
* Fix functional tests that fail with Sockets
* Moved OneToTenThreads test to Kestrel.Transport.Libuv.Tests
* Fix systemd activation tests to use libuv transport
* Dispose Sockets PipeFactory
* Improve Socket's server-side abort handling
* Add explicit rebinding test
This commit is contained in:
Stephen Halter 2017-10-11 15:14:35 -07:00 committed by GitHub
parent d46d2ce193
commit fdb4184dbf
31 changed files with 527 additions and 173 deletions

View File

@ -28,4 +28,4 @@ before_install:
- if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi
script: script:
- ./build.sh - ./build.sh
- if test "$TRAVIS_OS_NAME" != "osx"; then bash test/Kestrel.FunctionalTests/SystemdActivation/docker.sh; fi - if test "$TRAVIS_OS_NAME" != "osx"; then bash test/SystemdActivation/docker.sh; fi

View File

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 15
VisualStudioVersion = 15.0.26814.0 VisualStudioVersion = 15.0.26730.16
MinimumVisualStudioVersion = 15.0.26730.03 MinimumVisualStudioVersion = 15.0.26730.03
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7972A5D6-3385-4127-9277-428506DD44FF}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7972A5D6-3385-4127-9277-428506DD44FF}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
@ -68,8 +68,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeGenerator", "tools\Code
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kestrel.Https", "src\Kestrel.Https\Kestrel.Https.csproj", "{5F64B3C3-0C2E-431A-B820-A81BBFC863DA}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kestrel.Https", "src\Kestrel.Https\Kestrel.Https.csproj", "{5F64B3C3-0C2E-431A-B820-A81BBFC863DA}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kestrel.FunctionalTests", "test\Kestrel.FunctionalTests\Kestrel.FunctionalTests.csproj", "{9559A5F1-080C-4909-B6CF-7E4B3DC55748}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kestrel.Performance", "benchmarks\Kestrel.Performance\Kestrel.Performance.csproj", "{EBFE9719-A44B-4978-A71F-D5C254E7F35A}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kestrel.Performance", "benchmarks\Kestrel.Performance\Kestrel.Performance.csproj", "{EBFE9719-A44B-4978-A71F-D5C254E7F35A}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestCertificates", "TestCertificates", "{2822C132-BFFB-4D53-AC5B-E7E47DD81A6E}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestCertificates", "TestCertificates", "{2822C132-BFFB-4D53-AC5B-E7E47DD81A6E}"
@ -112,6 +110,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{C2910A13
build\repo.targets = build\repo.targets build\repo.targets = build\repo.targets
EndProjectSection EndProjectSection
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SystemdActivation", "SystemdActivation", "{B7B0EA74-528F-46B8-9BC4-909D9A67C194}"
ProjectSection(SolutionItems) = preProject
test\SystemdActivation\docker-entrypoint.sh = test\SystemdActivation\docker-entrypoint.sh
test\SystemdActivation\docker.sh = test\SystemdActivation\docker.sh
test\SystemdActivation\Dockerfile = test\SystemdActivation\Dockerfile
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kestrel.Transport.Libuv.FunctionalTests", "test\Kestrel.Transport.Libuv.FunctionalTests\Kestrel.Trasnport.Libuv.FunctionalTests.csproj", "{74032D79-8EA7-4483-BD82-C38370420FFF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kestrel.Transport.Sockets.FunctionalTests", "test\Kestrel.Transport.Sockets.FunctionalTests\Kestrel.Trasnport.Sockets.FunctionalTests.csproj", "{9C7B6B5F-088A-436E-834B-6373EA36DEEE}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -194,18 +203,6 @@ Global
{5F64B3C3-0C2E-431A-B820-A81BBFC863DA}.Release|x64.Build.0 = Release|Any CPU {5F64B3C3-0C2E-431A-B820-A81BBFC863DA}.Release|x64.Build.0 = Release|Any CPU
{5F64B3C3-0C2E-431A-B820-A81BBFC863DA}.Release|x86.ActiveCfg = Release|Any CPU {5F64B3C3-0C2E-431A-B820-A81BBFC863DA}.Release|x86.ActiveCfg = Release|Any CPU
{5F64B3C3-0C2E-431A-B820-A81BBFC863DA}.Release|x86.Build.0 = Release|Any CPU {5F64B3C3-0C2E-431A-B820-A81BBFC863DA}.Release|x86.Build.0 = Release|Any CPU
{9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Debug|x64.ActiveCfg = Debug|Any CPU
{9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Debug|x64.Build.0 = Debug|Any CPU
{9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Debug|x86.ActiveCfg = Debug|Any CPU
{9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Debug|x86.Build.0 = Debug|Any CPU
{9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Release|Any CPU.Build.0 = Release|Any CPU
{9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Release|x64.ActiveCfg = Release|Any CPU
{9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Release|x64.Build.0 = Release|Any CPU
{9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Release|x86.ActiveCfg = Release|Any CPU
{9559A5F1-080C-4909-B6CF-7E4B3DC55748}.Release|x86.Build.0 = Release|Any CPU
{EBFE9719-A44B-4978-A71F-D5C254E7F35A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EBFE9719-A44B-4978-A71F-D5C254E7F35A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EBFE9719-A44B-4978-A71F-D5C254E7F35A}.Debug|Any CPU.Build.0 = Debug|Any CPU {EBFE9719-A44B-4978-A71F-D5C254E7F35A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBFE9719-A44B-4978-A71F-D5C254E7F35A}.Debug|x64.ActiveCfg = Debug|Any CPU {EBFE9719-A44B-4978-A71F-D5C254E7F35A}.Debug|x64.ActiveCfg = Debug|Any CPU
@ -314,6 +311,30 @@ Global
{924AE57C-1EBA-4A1D-A039-8C100B7507A5}.Release|x64.Build.0 = Release|Any CPU {924AE57C-1EBA-4A1D-A039-8C100B7507A5}.Release|x64.Build.0 = Release|Any CPU
{924AE57C-1EBA-4A1D-A039-8C100B7507A5}.Release|x86.ActiveCfg = Release|Any CPU {924AE57C-1EBA-4A1D-A039-8C100B7507A5}.Release|x86.ActiveCfg = Release|Any CPU
{924AE57C-1EBA-4A1D-A039-8C100B7507A5}.Release|x86.Build.0 = Release|Any CPU {924AE57C-1EBA-4A1D-A039-8C100B7507A5}.Release|x86.Build.0 = Release|Any CPU
{74032D79-8EA7-4483-BD82-C38370420FFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{74032D79-8EA7-4483-BD82-C38370420FFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{74032D79-8EA7-4483-BD82-C38370420FFF}.Debug|x64.ActiveCfg = Debug|Any CPU
{74032D79-8EA7-4483-BD82-C38370420FFF}.Debug|x64.Build.0 = Debug|Any CPU
{74032D79-8EA7-4483-BD82-C38370420FFF}.Debug|x86.ActiveCfg = Debug|Any CPU
{74032D79-8EA7-4483-BD82-C38370420FFF}.Debug|x86.Build.0 = Debug|Any CPU
{74032D79-8EA7-4483-BD82-C38370420FFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{74032D79-8EA7-4483-BD82-C38370420FFF}.Release|Any CPU.Build.0 = Release|Any CPU
{74032D79-8EA7-4483-BD82-C38370420FFF}.Release|x64.ActiveCfg = Release|Any CPU
{74032D79-8EA7-4483-BD82-C38370420FFF}.Release|x64.Build.0 = Release|Any CPU
{74032D79-8EA7-4483-BD82-C38370420FFF}.Release|x86.ActiveCfg = Release|Any CPU
{74032D79-8EA7-4483-BD82-C38370420FFF}.Release|x86.Build.0 = Release|Any CPU
{9C7B6B5F-088A-436E-834B-6373EA36DEEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9C7B6B5F-088A-436E-834B-6373EA36DEEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9C7B6B5F-088A-436E-834B-6373EA36DEEE}.Debug|x64.ActiveCfg = Debug|Any CPU
{9C7B6B5F-088A-436E-834B-6373EA36DEEE}.Debug|x64.Build.0 = Debug|Any CPU
{9C7B6B5F-088A-436E-834B-6373EA36DEEE}.Debug|x86.ActiveCfg = Debug|Any CPU
{9C7B6B5F-088A-436E-834B-6373EA36DEEE}.Debug|x86.Build.0 = Debug|Any CPU
{9C7B6B5F-088A-436E-834B-6373EA36DEEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9C7B6B5F-088A-436E-834B-6373EA36DEEE}.Release|Any CPU.Build.0 = Release|Any CPU
{9C7B6B5F-088A-436E-834B-6373EA36DEEE}.Release|x64.ActiveCfg = Release|Any CPU
{9C7B6B5F-088A-436E-834B-6373EA36DEEE}.Release|x64.Build.0 = Release|Any CPU
{9C7B6B5F-088A-436E-834B-6373EA36DEEE}.Release|x86.ActiveCfg = Release|Any CPU
{9C7B6B5F-088A-436E-834B-6373EA36DEEE}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -325,7 +346,6 @@ Global
{B35D4D31-E74C-4646-8A11-7A7A40F0021E} = {8A3D00B8-1CCF-4BE6-A060-11104CE2D9CE} {B35D4D31-E74C-4646-8A11-7A7A40F0021E} = {8A3D00B8-1CCF-4BE6-A060-11104CE2D9CE}
{BD2D4D29-1BD9-40D0-BB31-337D5416B63C} = {327F7880-D9AF-46BD-B45C-3B7E34A01DFD} {BD2D4D29-1BD9-40D0-BB31-337D5416B63C} = {327F7880-D9AF-46BD-B45C-3B7E34A01DFD}
{5F64B3C3-0C2E-431A-B820-A81BBFC863DA} = {2D5D5227-4DBD-499A-96B1-76A36B03B750} {5F64B3C3-0C2E-431A-B820-A81BBFC863DA} = {2D5D5227-4DBD-499A-96B1-76A36B03B750}
{9559A5F1-080C-4909-B6CF-7E4B3DC55748} = {D3273454-EA07-41D2-BF0B-FCC3675C2483}
{EBFE9719-A44B-4978-A71F-D5C254E7F35A} = {A95C3BE1-B850-4265-97A0-777ADCCD437F} {EBFE9719-A44B-4978-A71F-D5C254E7F35A} = {A95C3BE1-B850-4265-97A0-777ADCCD437F}
{2822C132-BFFB-4D53-AC5B-E7E47DD81A6E} = {0EF2ACDF-012F-4472-A13A-4272419E2903} {2822C132-BFFB-4D53-AC5B-E7E47DD81A6E} = {0EF2ACDF-012F-4472-A13A-4272419E2903}
{A76B8C8C-0DC5-4DD3-9B1F-02E51A0915F4} = {2D5D5227-4DBD-499A-96B1-76A36B03B750} {A76B8C8C-0DC5-4DD3-9B1F-02E51A0915F4} = {2D5D5227-4DBD-499A-96B1-76A36B03B750}
@ -336,6 +356,9 @@ Global
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC} = {D3273454-EA07-41D2-BF0B-FCC3675C2483} {4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC} = {D3273454-EA07-41D2-BF0B-FCC3675C2483}
{6956CF5C-3163-4398-8628-4ECA569245B5} = {2D5D5227-4DBD-499A-96B1-76A36B03B750} {6956CF5C-3163-4398-8628-4ECA569245B5} = {2D5D5227-4DBD-499A-96B1-76A36B03B750}
{924AE57C-1EBA-4A1D-A039-8C100B7507A5} = {2D5D5227-4DBD-499A-96B1-76A36B03B750} {924AE57C-1EBA-4A1D-A039-8C100B7507A5} = {2D5D5227-4DBD-499A-96B1-76A36B03B750}
{B7B0EA74-528F-46B8-9BC4-909D9A67C194} = {D3273454-EA07-41D2-BF0B-FCC3675C2483}
{74032D79-8EA7-4483-BD82-C38370420FFF} = {D3273454-EA07-41D2-BF0B-FCC3675C2483}
{9C7B6B5F-088A-436E-834B-6373EA36DEEE} = {D3273454-EA07-41D2-BF0B-FCC3675C2483}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2D10D020-6770-47CA-BB8D-2C23FE3AE071} SolutionGuid = {2D10D020-6770-47CA-BB8D-2C23FE3AE071}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Net; using System.Net;
@ -51,7 +52,7 @@ namespace SampleApp
basePort = 5000; basePort = 5000;
} }
var host = new WebHostBuilder() var hostBuilder = new WebHostBuilder()
.ConfigureLogging((_, factory) => .ConfigureLogging((_, factory) =>
{ {
factory.AddConsole(); factory.AddConsole();
@ -80,16 +81,20 @@ namespace SampleApp
// The following section should be used to demo sockets // The following section should be used to demo sockets
//options.ListenUnixSocket("/tmp/kestrel-test.sock"); //options.ListenUnixSocket("/tmp/kestrel-test.sock");
}) })
.UseLibuv(options =>
{
// Uncomment the following line to change the default number of libuv threads for all endpoints.
// options.ThreadCount = 4;
})
.UseContentRoot(Directory.GetCurrentDirectory()) .UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>() .UseStartup<Startup>();
.Build();
return host.RunAsync(); if (string.Equals(Process.GetCurrentProcess().Id.ToString(), Environment.GetEnvironmentVariable("LISTEN_PID")))
{
// Use libuv if activated by systemd, since that's currently the only transport that supports being passed a socket handle.
hostBuilder.UseLibuv(options =>
{
// Uncomment the following line to change the default number of libuv threads for all endpoints.
// options.ThreadCount = 4;
});
}
return hostBuilder.Build().RunAsync();
} }
} }
} }

View File

@ -3,7 +3,8 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.Core.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.Core.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Kestrel.Performance, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Kestrel.Performance, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

View File

@ -3,4 +3,6 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

View File

@ -0,0 +1,23 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
{
public interface ISocketsTrace : ILogger
{
void ConnectionReadFin(string connectionId);
void ConnectionWriteFin(string connectionId);
void ConnectionError(string connectionId, Exception ex);
void ConnectionReset(string connectionId);
void ConnectionPause(string connectionId);
void ConnectionResume(string connectionId);
}
}

View File

@ -0,0 +1,93 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
{
public class SocketsTrace : ISocketsTrace
{
// ConnectionRead: Reserved: 3
private static readonly Action<ILogger, string, Exception> _connectionPause =
LoggerMessage.Define<string>(LogLevel.Debug, 4, @"Connection id ""{ConnectionId}"" paused.");
private static readonly Action<ILogger, string, Exception> _connectionResume =
LoggerMessage.Define<string>(LogLevel.Debug, 5, @"Connection id ""{ConnectionId}"" resumed.");
private static readonly Action<ILogger, string, Exception> _connectionReadFin =
LoggerMessage.Define<string>(LogLevel.Debug, 6, @"Connection id ""{ConnectionId}"" received FIN.");
private static readonly Action<ILogger, string, Exception> _connectionWriteFin =
LoggerMessage.Define<string>(LogLevel.Debug, 7, @"Connection id ""{ConnectionId}"" sending FIN.");
private static readonly Action<ILogger, string, Exception> _connectionError =
LoggerMessage.Define<string>(LogLevel.Information, 14, @"Connection id ""{ConnectionId}"" communication error.");
private static readonly Action<ILogger, string, Exception> _connectionReset =
LoggerMessage.Define<string>(LogLevel.Debug, 19, @"Connection id ""{ConnectionId}"" reset.");
private readonly ILogger _logger;
public SocketsTrace(ILogger logger)
{
_logger = logger;
}
public void ConnectionRead(string connectionId, int count)
{
// Don't log for now since this could be *too* verbose.
// Reserved: Event ID 3
}
public void ConnectionReadFin(string connectionId)
{
_connectionReadFin(_logger, connectionId, null);
}
public void ConnectionWriteFin(string connectionId)
{
_connectionWriteFin(_logger, connectionId, null);
}
public void ConnectionWrite(string connectionId, int count)
{
// Don't log for now since this could be *too* verbose.
// Reserved: Event ID 11
}
public void ConnectionWriteCallback(string connectionId, int status)
{
// Don't log for now since this could be *too* verbose.
// Reserved: Event ID 12
}
public void ConnectionError(string connectionId, Exception ex)
{
_connectionError(_logger, connectionId, ex);
}
public void ConnectionReset(string connectionId)
{
_connectionReset(_logger, connectionId, null);
}
public void ConnectionPause(string connectionId)
{
_connectionPause(_logger, connectionId, null);
}
public void ConnectionResume(string connectionId)
{
_connectionResume(_logger, connectionId, null);
}
public IDisposable BeginScope<TState>(TState state) => _logger.BeginScope(state);
public bool IsEnabled(LogLevel logLevel) => _logger.IsEnabled(logLevel);
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
=> _logger.Log(logLevel, eventId, state, exception, formatter);
}
}

View File

@ -5,30 +5,36 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.IO.Pipelines;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.IO.Pipelines;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Protocols; using Microsoft.AspNetCore.Protocols;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
{ {
internal sealed class SocketConnection : TransportConnection internal sealed class SocketConnection : TransportConnection
{ {
private readonly Socket _socket;
private readonly SocketTransport _transport;
private IList<ArraySegment<byte>> _sendBufferList;
private const int MinAllocBufferSize = 2048; private const int MinAllocBufferSize = 2048;
internal SocketConnection(Socket socket, SocketTransport transport) private readonly Socket _socket;
private readonly ISocketsTrace _trace;
private IList<ArraySegment<byte>> _sendBufferList;
private volatile bool _aborted;
internal SocketConnection(Socket socket, PipeFactory pipeFactory, ISocketsTrace trace)
{ {
Debug.Assert(socket != null); Debug.Assert(socket != null);
Debug.Assert(transport != null); Debug.Assert(pipeFactory != null);
Debug.Assert(trace != null);
_socket = socket; _socket = socket;
_transport = transport; PipeFactory = pipeFactory;
_trace = trace;
var localEndPoint = (IPEndPoint)_socket.LocalEndPoint; var localEndPoint = (IPEndPoint)_socket.LocalEndPoint;
var remoteEndPoint = (IPEndPoint)_socket.RemoteEndPoint; var remoteEndPoint = (IPEndPoint)_socket.RemoteEndPoint;
@ -40,6 +46,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
RemotePort = remoteEndPoint.Port; RemotePort = remoteEndPoint.Port;
} }
public override PipeFactory PipeFactory { get; }
public override IScheduler InputWriterScheduler => InlineScheduler.Default;
public override IScheduler OutputReaderScheduler => TaskRunScheduler.Default;
public async Task StartAsync(IConnectionHandler connectionHandler) public async Task StartAsync(IConnectionHandler connectionHandler)
{ {
try try
@ -66,9 +76,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
// Dispose the socket(should noop if already called) // Dispose the socket(should noop if already called)
_socket.Dispose(); _socket.Dispose();
} }
catch (Exception) catch (Exception ex)
{ {
// TODO: Log _trace.LogError(0, ex, $"Unexpected exception in {nameof(SocketConnection)}.{nameof(StartAsync)}.");
} }
} }
@ -90,6 +100,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
if (bytesReceived == 0) if (bytesReceived == 0)
{ {
// FIN // FIN
_trace.ConnectionReadFin(ConnectionId);
break; break;
} }
@ -100,7 +111,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
buffer.Commit(); buffer.Commit();
} }
var result = await buffer.FlushAsync(); var flushTask = buffer.FlushAsync();
if (!flushTask.IsCompleted)
{
_trace.ConnectionPause(ConnectionId);
await flushTask;
_trace.ConnectionResume(ConnectionId);
}
var result = flushTask.GetAwaiter().GetResult();
if (result.IsCompleted) if (result.IsCompleted)
{ {
// Pipe consumer is shut down, do we stop writing // Pipe consumer is shut down, do we stop writing
@ -111,25 +133,36 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
catch (SocketException ex) when (ex.SocketErrorCode == SocketError.ConnectionReset) catch (SocketException ex) when (ex.SocketErrorCode == SocketError.ConnectionReset)
{ {
error = new ConnectionResetException(ex.Message, ex); error = new ConnectionResetException(ex.Message, ex);
_trace.ConnectionReset(ConnectionId);
} }
catch (SocketException ex) when (ex.SocketErrorCode == SocketError.OperationAborted) catch (SocketException ex) when (ex.SocketErrorCode == SocketError.OperationAborted ||
ex.SocketErrorCode == SocketError.Interrupted)
{ {
error = new ConnectionAbortedException(); error = new ConnectionAbortedException();
_trace.ConnectionError(ConnectionId, error);
} }
catch (ObjectDisposedException) catch (ObjectDisposedException)
{ {
error = new ConnectionAbortedException(); error = new ConnectionAbortedException();
_trace.ConnectionError(ConnectionId, error);
} }
catch (IOException ex) catch (IOException ex)
{ {
error = ex; error = ex;
_trace.ConnectionError(ConnectionId, error);
} }
catch (Exception ex) catch (Exception ex)
{ {
error = new IOException(ex.Message, ex); error = new IOException(ex.Message, ex);
_trace.ConnectionError(ConnectionId, error);
} }
finally finally
{ {
if (_aborted)
{
error = error ?? new ConnectionAbortedException();
}
Input.Complete(error); Input.Complete(error);
} }
} }
@ -202,8 +235,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
Output.Advance(buffer.End); Output.Advance(buffer.End);
} }
} }
_socket.Shutdown(SocketShutdown.Send);
} }
catch (SocketException ex) when (ex.SocketErrorCode == SocketError.OperationAborted) catch (SocketException ex) when (ex.SocketErrorCode == SocketError.OperationAborted)
{ {
@ -224,6 +255,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
finally finally
{ {
Output.Complete(error); Output.Complete(error);
// Make sure to close the connection only after the _aborted flag is set.
// Without this, the RequestsCanBeAbortedMidRead test will sometimes fail when
// a BadHttpRequestException is thrown instead of a TaskCanceledException.
_aborted = true;
_trace.ConnectionWriteFin(ConnectionId);
_socket.Shutdown(SocketShutdown.Both);
} }
} }
@ -237,8 +275,5 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
return segment; return segment;
} }
public override PipeFactory PipeFactory => _transport.TransportFactory.PipeFactory;
public override IScheduler InputWriterScheduler => InlineScheduler.Default;
public override IScheduler OutputReaderScheduler => TaskRunScheduler.Default;
} }
} }

View File

@ -3,32 +3,38 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO.Pipelines;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Protocols; using Microsoft.AspNetCore.Protocols;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal; using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
{ {
internal sealed class SocketTransport : ITransport internal sealed class SocketTransport : ITransport
{ {
private readonly SocketTransportFactory _transportFactory; private readonly PipeFactory _pipeFactory = new PipeFactory();
private readonly IEndPointInformation _endPointInformation; private readonly IEndPointInformation _endPointInformation;
private readonly IConnectionHandler _handler; private readonly IConnectionHandler _handler;
private readonly ISocketsTrace _trace;
private Socket _listenSocket; private Socket _listenSocket;
private Task _listenTask; private Task _listenTask;
internal SocketTransport(SocketTransportFactory transportFactory, IEndPointInformation endPointInformation, IConnectionHandler handler) internal SocketTransport(
IEndPointInformation endPointInformation,
IConnectionHandler handler,
ISocketsTrace trace)
{ {
Debug.Assert(transportFactory != null);
Debug.Assert(endPointInformation != null); Debug.Assert(endPointInformation != null);
Debug.Assert(endPointInformation.Type == ListenType.IPEndPoint); Debug.Assert(endPointInformation.Type == ListenType.IPEndPoint);
Debug.Assert(handler != null); Debug.Assert(handler != null);
Debug.Assert(trace != null);
_transportFactory = transportFactory;
_endPointInformation = endPointInformation; _endPointInformation = endPointInformation;
_handler = handler; _handler = handler;
_trace = trace;
_listenSocket = null; _listenSocket = null;
_listenTask = null; _listenTask = null;
@ -92,6 +98,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
public Task StopAsync() public Task StopAsync()
{ {
_pipeFactory.Dispose();
return Task.CompletedTask; return Task.CompletedTask;
} }
@ -105,7 +112,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
acceptSocket.NoDelay = _endPointInformation.NoDelay; acceptSocket.NoDelay = _endPointInformation.NoDelay;
var connection = new SocketConnection(acceptSocket, this); var connection = new SocketConnection(acceptSocket, _pipeFactory, _trace);
_ = connection.StartAsync(_handler); _ = connection.StartAsync(_handler);
} }
} }
@ -121,7 +128,5 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
} }
} }
} }
internal SocketTransportFactory TransportFactory => _transportFactory;
} }
} }

View File

@ -2,18 +2,32 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.IO.Pipelines;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal; using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
{ {
public sealed class SocketTransportFactory : ITransportFactory public sealed class SocketTransportFactory : ITransportFactory
{ {
private readonly PipeFactory _pipeFactory = new PipeFactory(); private readonly SocketsTrace _trace;
public SocketTransportFactory(IOptions<SocketTransportOptions> options) public SocketTransportFactory(
IOptions<SocketTransportOptions> options,
ILoggerFactory loggerFactory)
{ {
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets");
_trace = new SocketsTrace(logger);
} }
public ITransport Create(IEndPointInformation endPointInformation, IConnectionHandler handler) public ITransport Create(IEndPointInformation endPointInformation, IConnectionHandler handler)
@ -33,9 +47,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
throw new ArgumentNullException(nameof(handler)); throw new ArgumentNullException(nameof(handler));
} }
return new SocketTransport(this, endPointInformation, handler); return new SocketTransport(endPointInformation, handler, _trace);
} }
internal PipeFactory PipeFactory => _pipeFactory;
} }
} }

View File

@ -83,6 +83,10 @@
{ {
"Name": "options", "Name": "options",
"Type": "Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportOptions>" "Type": "Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportOptions>"
},
{
"Name": "loggerFactory",
"Type": "Microsoft.Extensions.Logging.ILoggerFactory"
} }
], ],
"Visibility": "Public", "Visibility": "Public",

View File

@ -16,7 +16,9 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Kestrel.Core\Kestrel.Core.csproj" /> <ProjectReference Include="..\Kestrel.Core\Kestrel.Core.csproj" />
<!-- Even though the Libuv transport is no longer used by default, it remains for back-compat -->
<ProjectReference Include="..\Kestrel.Transport.Libuv\Kestrel.Transport.Libuv.csproj" /> <ProjectReference Include="..\Kestrel.Transport.Libuv\Kestrel.Transport.Libuv.csproj" />
<ProjectReference Include="..\Kestrel.Transport.Sockets\Kestrel.Transport.Sockets.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -5,7 +5,10 @@ using System;
using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Hosting namespace Microsoft.AspNetCore.Hosting
@ -23,10 +26,11 @@ namespace Microsoft.AspNetCore.Hosting
/// </returns> /// </returns>
public static IWebHostBuilder UseKestrel(this IWebHostBuilder hostBuilder) public static IWebHostBuilder UseKestrel(this IWebHostBuilder hostBuilder)
{ {
hostBuilder.UseLibuv();
return hostBuilder.ConfigureServices(services => return hostBuilder.ConfigureServices(services =>
{ {
// Don't override an already-configured transport
services.TryAddSingleton<ITransportFactory, SocketTransportFactory>();
services.AddTransient<IConfigureOptions<KestrelServerOptions>, KestrelServerOptionsSetup>(); services.AddTransient<IConfigureOptions<KestrelServerOptions>, KestrelServerOptionsSetup>();
services.AddSingleton<IServer, KestrelServer>(); services.AddSingleton<IServer, KestrelServer>();
}); });

View File

@ -163,7 +163,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
private async Task RegisterAddresses_Success(string addressInput, string[] testUrls, int testPort = 0) private async Task RegisterAddresses_Success(string addressInput, string[] testUrls, int testPort = 0)
{ {
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel() .UseKestrel()
.ConfigureLogging(_configureLoggingDelegate) .ConfigureLogging(_configureLoggingDelegate)
.UseUrls(addressInput) .UseUrls(addressInput)
@ -223,7 +223,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
private async Task RegisterIPEndPoint_Success(IPEndPoint endPoint, string testUrl, int testPort = 0) private async Task RegisterIPEndPoint_Success(IPEndPoint endPoint, string testUrl, int testPort = 0)
{ {
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate) .ConfigureLogging(_configureLoggingDelegate)
.UseKestrel(options => .UseKestrel(options =>
{ {
@ -304,7 +304,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
var testLogger = new TestApplicationErrorLogger(); var testLogger = new TestApplicationErrorLogger();
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate) .ConfigureLogging(_configureLoggingDelegate)
.UseKestrel() .UseKestrel()
.ConfigureLogging(builder => builder .ConfigureLogging(builder => builder
@ -336,7 +336,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
socket.Bind(new IPEndPoint(IPAddress.Loopback, 0)); socket.Bind(new IPEndPoint(IPAddress.Loopback, 0));
var port = ((IPEndPoint)socket.LocalEndPoint).Port; var port = ((IPEndPoint)socket.LocalEndPoint).Port;
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate) .ConfigureLogging(_configureLoggingDelegate)
.UseKestrel() .UseKestrel()
.UseUrls($"http://127.0.0.1:{port}") .UseUrls($"http://127.0.0.1:{port}")
@ -359,7 +359,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
socket.Bind(new IPEndPoint(IPAddress.IPv6Loopback, 0)); socket.Bind(new IPEndPoint(IPAddress.IPv6Loopback, 0));
var port = ((IPEndPoint)socket.LocalEndPoint).Port; var port = ((IPEndPoint)socket.LocalEndPoint).Port;
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate) .ConfigureLogging(_configureLoggingDelegate)
.UseKestrel() .UseKestrel()
.UseUrls($"http://[::1]:{port}") .UseUrls($"http://[::1]:{port}")
@ -378,7 +378,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
var useUrlsAddress = $"http://127.0.0.1:0"; var useUrlsAddress = $"http://127.0.0.1:0";
var testLogger = new TestApplicationErrorLogger(); var testLogger = new TestApplicationErrorLogger();
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel(options => .UseKestrel(options =>
{ {
options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions => options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions =>
@ -417,7 +417,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
var useUrlsAddress = $"http://127.0.0.1:0"; var useUrlsAddress = $"http://127.0.0.1:0";
var testLogger = new TestApplicationErrorLogger(); var testLogger = new TestApplicationErrorLogger();
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate) .ConfigureLogging(_configureLoggingDelegate)
.UseKestrel(options => .UseKestrel(options =>
{ {
@ -455,7 +455,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Fact] [Fact]
public async Task DoesNotOverrideDirectConfigurationWithIServerAddressesFeature_IfAddressesEmpty() public async Task DoesNotOverrideDirectConfigurationWithIServerAddressesFeature_IfAddressesEmpty()
{ {
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate) .ConfigureLogging(_configureLoggingDelegate)
.UseKestrel(options => .UseKestrel(options =>
{ {
@ -499,7 +499,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Fact] [Fact]
public void ThrowsWhenBindingLocalhostToDynamicPort() public void ThrowsWhenBindingLocalhostToDynamicPort()
{ {
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls("http://localhost:0") .UseUrls("http://localhost:0")
.Configure(ConfigureEchoAddress); .Configure(ConfigureEchoAddress);
@ -515,7 +515,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[InlineData("ftp://localhost")] [InlineData("ftp://localhost")]
public void ThrowsForUnsupportedAddressFromHosting(string addr) public void ThrowsForUnsupportedAddressFromHosting(string addr)
{ {
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls(addr) .UseUrls(addr)
.Configure(ConfigureEchoAddress); .Configure(ConfigureEchoAddress);
@ -526,6 +526,91 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
} }
} }
// https://github.com/dotnet/corefx/issues/24562
[ConditionalFact]
[OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Sockets transport fails to rebind on macOS.")]
[OSSkipCondition(OperatingSystems.Linux, SkipReason = "Sockets transport fails to rebind on Linux.")]
public async Task CanRebindToEndPoint()
{
var port = GetNextPort();
var endPointAddress = $"http://127.0.0.1:{port}/";
var hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate)
.UseKestrel(options =>
{
options.Listen(IPAddress.Loopback, port);
})
.Configure(ConfigureEchoAddress);
using (var host = hostBuilder.Build())
{
host.Start();
Assert.Equal(endPointAddress, await HttpClientSlim.GetStringAsync(endPointAddress));
}
hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate)
.UseKestrel(options =>
{
options.Listen(IPAddress.Loopback, port);
})
.Configure(ConfigureEchoAddress);
using (var host = hostBuilder.Build())
{
host.Start();
Assert.Equal(endPointAddress, await HttpClientSlim.GetStringAsync(endPointAddress));
}
}
// https://github.com/dotnet/corefx/issues/24562
[ConditionalFact]
[OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Sockets transport fails to rebind on macOS.")]
[OSSkipCondition(OperatingSystems.Linux, SkipReason = "Sockets transport fails to rebind on Linux.")]
public async Task CanRebindToMultipleEndPoints()
{
var port = GetNextPort();
var ipv4endPointAddress = $"http://127.0.0.1:{port}/";
var ipv6endPointAddress = $"http://[::1]:{port}/";
var hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate)
.UseKestrel(options =>
{
options.Listen(IPAddress.Loopback, port);
options.Listen(IPAddress.IPv6Loopback, port);
})
.Configure(ConfigureEchoAddress);
using (var host = hostBuilder.Build())
{
host.Start();
Assert.Equal(ipv4endPointAddress, await HttpClientSlim.GetStringAsync(ipv4endPointAddress));
Assert.Equal(ipv6endPointAddress, await HttpClientSlim.GetStringAsync(ipv6endPointAddress));
}
hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate)
.UseKestrel(options =>
{
options.Listen(IPAddress.Loopback, port);
options.Listen(IPAddress.IPv6Loopback, port);
})
.Configure(ConfigureEchoAddress);
using (var host = hostBuilder.Build())
{
host.Start();
Assert.Equal(ipv4endPointAddress, await HttpClientSlim.GetStringAsync(ipv4endPointAddress));
Assert.Equal(ipv6endPointAddress, await HttpClientSlim.GetStringAsync(ipv6endPointAddress));
}
}
private void ThrowsWhenBindingLocalhostToAddressInUse(AddressFamily addressFamily, IPAddress address) private void ThrowsWhenBindingLocalhostToAddressInUse(AddressFamily addressFamily, IPAddress address)
{ {
using (var socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp)) using (var socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp))
@ -533,7 +618,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
socket.Bind(new IPEndPoint(address, 0)); socket.Bind(new IPEndPoint(address, 0));
var port = ((IPEndPoint)socket.LocalEndPoint).Port; var port = ((IPEndPoint)socket.LocalEndPoint).Port;
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate) .ConfigureLogging(_configureLoggingDelegate)
.UseKestrel() .UseKestrel()
.UseUrls($"http://localhost:{port}") .UseUrls($"http://localhost:{port}")
@ -807,6 +892,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
private bool CanBindToPort() private bool CanBindToPort()
{ {
#if MACOS && SOCKETS
// Binding to a port with a Socket, disposing the Socket, and rebinding often fails with
// SocketError.AddressAlreadyInUse on macOS. This isn't an issue if binding with libuv second.
// https://github.com/dotnet/corefx/issues/24562
return false;
#else
try try
{ {
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
@ -819,6 +910,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
return false; return false;
} }
#endif
} }
} }
} }

View File

@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
private async Task TestSuccess(HttpProtocols serverProtocols, string request, string expectedResponse) private async Task TestSuccess(HttpProtocols serverProtocols, string request, string expectedResponse)
{ {
var builder = new WebHostBuilder() var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel(options => .UseKestrel(options =>
{ {
options.Listen(IPAddress.Loopback, 0, listenOptions => listenOptions.Protocols = serverProtocols); options.Listen(IPAddress.Loopback, 0, listenOptions => listenOptions.Protocols = serverProtocols);
@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
.Setup(provider => provider.CreateLogger(It.IsAny<string>())) .Setup(provider => provider.CreateLogger(It.IsAny<string>()))
.Returns(logger); .Returns(logger);
var builder = new WebHostBuilder() var builder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(loggingBuilder => loggingBuilder.AddProvider(loggerProvider.Object)) .ConfigureLogging(loggingBuilder => loggingBuilder.AddProvider(loggerProvider.Object))
.UseKestrel(options => options.Listen(IPAddress.Loopback, 0, listenOptions => listenOptions.Protocols = serverProtocols)) .UseKestrel(options => options.Listen(IPAddress.Loopback, 0, listenOptions => listenOptions.Protocols = serverProtocols))
.Configure(app => app.Run(context => Task.CompletedTask)); .Configure(app => app.Run(context => Task.CompletedTask));

View File

@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
var loggerProvider = new HandshakeErrorLoggerProvider(); var loggerProvider = new HandshakeErrorLoggerProvider();
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel(options => .UseKestrel(options =>
{ {
options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions => options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions =>
@ -65,7 +65,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
var loggerProvider = new HandshakeErrorLoggerProvider(); var loggerProvider = new HandshakeErrorLoggerProvider();
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel(options => .UseKestrel(options =>
{ {
options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions => options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions =>
@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
public async Task DoesNotThrowObjectDisposedExceptionOnConnectionAbort() public async Task DoesNotThrowObjectDisposedExceptionOnConnectionAbort()
{ {
var loggerProvider = new HandshakeErrorLoggerProvider(); var loggerProvider = new HandshakeErrorLoggerProvider();
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel(options => .UseKestrel(options =>
{ {
options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions => options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions =>
@ -153,7 +153,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
var tcs = new TaskCompletionSource<object>(); var tcs = new TaskCompletionSource<object>();
var loggerProvider = new HandshakeErrorLoggerProvider(); var loggerProvider = new HandshakeErrorLoggerProvider();
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel(options => .UseKestrel(options =>
{ {
options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions => options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions =>
@ -202,7 +202,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
public async Task DoesNotThrowObjectDisposedExceptionOnEmptyConnection() public async Task DoesNotThrowObjectDisposedExceptionOnEmptyConnection()
{ {
var loggerProvider = new HandshakeErrorLoggerProvider(); var loggerProvider = new HandshakeErrorLoggerProvider();
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel(options => .UseKestrel(options =>
{ {
options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions => options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions =>
@ -236,7 +236,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
var loggerProvider = new HandshakeErrorLoggerProvider(); var loggerProvider = new HandshakeErrorLoggerProvider();
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel(options => .UseKestrel(options =>
{ {
options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions => options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions =>
@ -265,7 +265,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
public async Task HandshakeTimesOutAndIsLoggedAsInformation() public async Task HandshakeTimesOutAndIsLoggedAsInformation()
{ {
var loggerProvider = new HandshakeErrorLoggerProvider(); var loggerProvider = new HandshakeErrorLoggerProvider();
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel(options => .UseKestrel(options =>
{ {
options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions => options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions =>

View File

@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Fact] [Fact]
public async Task LoggingConnectionAdapterCanBeAddedBeforeAndAfterHttpsAdapter() public async Task LoggingConnectionAdapterCanBeAddedBeforeAndAfterHttpsAdapter()
{ {
var host = new WebHostBuilder() var host = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(builder => .ConfigureLogging(builder =>
{ {
builder.SetMinimumLevel(LogLevel.Trace); builder.SetMinimumLevel(LogLevel.Trace);

View File

@ -258,7 +258,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
TaskCompletionSource<object> startReadingRequestBody, TaskCompletionSource<object> startReadingRequestBody,
TaskCompletionSource<object> clientFinishedSendingRequestBody) TaskCompletionSource<object> clientFinishedSendingRequestBody)
{ {
var host = new WebHostBuilder() var host = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate) .ConfigureLogging(_configureLoggingDelegate)
.UseKestrel(options => .UseKestrel(options =>
{ {

View File

@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
Assert.True(contentLength % bufferLength == 0, $"{nameof(contentLength)} sent must be evenly divisible by {bufferLength}."); Assert.True(contentLength % bufferLength == 0, $"{nameof(contentLength)} sent must be evenly divisible by {bufferLength}.");
Assert.True(bufferLength % 256 == 0, $"{nameof(bufferLength)} must be evenly divisible by 256"); Assert.True(bufferLength % 256 == 0, $"{nameof(bufferLength)} must be evenly divisible by 256");
var builder = new WebHostBuilder() var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel(options => .UseKestrel(options =>
{ {
options.Limits.MaxRequestBodySize = contentLength; options.Limits.MaxRequestBodySize = contentLength;
@ -155,7 +155,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Fact] [Fact]
public async Task DoesNotHangOnConnectionCloseRequest() public async Task DoesNotHangOnConnectionCloseRequest()
{ {
var builder = new WebHostBuilder() var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls("http://127.0.0.1:0") .UseUrls("http://127.0.0.1:0")
.Configure(app => .Configure(app =>
@ -185,7 +185,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
var requestBodyPersisted = false; var requestBodyPersisted = false;
var responseBodyPersisted = false; var responseBodyPersisted = false;
var builder = new WebHostBuilder() var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls("http://127.0.0.1:0") .UseUrls("http://127.0.0.1:0")
.Configure(app => .Configure(app =>
@ -228,7 +228,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
public void CanUpgradeRequestWithConnectionKeepAliveUpgradeHeader() public void CanUpgradeRequestWithConnectionKeepAliveUpgradeHeader()
{ {
var dataRead = false; var dataRead = false;
var builder = new WebHostBuilder() var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls("http://127.0.0.1:0") .UseUrls("http://127.0.0.1:0")
.Configure(app => .Configure(app =>
@ -300,7 +300,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
.Setup(factory => factory.CreateLogger(It.IsAny<string>())) .Setup(factory => factory.CreateLogger(It.IsAny<string>()))
.Returns(Mock.Of<ILogger>()); .Returns(Mock.Of<ILogger>());
mockLoggerFactory mockLoggerFactory
.Setup(factory => factory.CreateLogger(It.IsIn("Microsoft.AspNetCore.Server.Kestrel", "Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv"))) .Setup(factory => factory.CreateLogger(It.IsIn("Microsoft.AspNetCore.Server.Kestrel",
"Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv",
"Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets")))
.Returns(mockLogger.Object); .Returns(mockLogger.Object);
using (var server = new TestServer(context => Task.CompletedTask, new TestServiceContext(mockLoggerFactory.Object))) using (var server = new TestServer(context => Task.CompletedTask, new TestServiceContext(mockLoggerFactory.Object)))
@ -354,7 +356,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
.Setup(factory => factory.CreateLogger(It.IsAny<string>())) .Setup(factory => factory.CreateLogger(It.IsAny<string>()))
.Returns(Mock.Of<ILogger>()); .Returns(Mock.Of<ILogger>());
mockLoggerFactory mockLoggerFactory
.Setup(factory => factory.CreateLogger(It.IsIn("Microsoft.AspNetCore.Server.Kestrel", "Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv"))) .Setup(factory => factory.CreateLogger(It.IsIn("Microsoft.AspNetCore.Server.Kestrel",
"Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv",
"Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets")))
.Returns(mockLogger.Object); .Returns(mockLogger.Object);
using (var server = new TestServer(context => Task.CompletedTask, new TestServiceContext(mockLoggerFactory.Object))) using (var server = new TestServer(context => Task.CompletedTask, new TestServiceContext(mockLoggerFactory.Object)))
@ -424,7 +428,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
.Setup(factory => factory.CreateLogger(It.IsAny<string>())) .Setup(factory => factory.CreateLogger(It.IsAny<string>()))
.Returns(Mock.Of<ILogger>()); .Returns(Mock.Of<ILogger>());
mockLoggerFactory mockLoggerFactory
.Setup(factory => factory.CreateLogger(It.IsIn("Microsoft.AspNetCore.Server.Kestrel", "Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv"))) .Setup(factory => factory.CreateLogger(It.IsIn("Microsoft.AspNetCore.Server.Kestrel",
"Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv",
"Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets")))
.Returns(mockLogger.Object); .Returns(mockLogger.Object);
using (var server = new TestServer(async context => using (var server = new TestServer(async context =>
@ -464,7 +470,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
var appDone = new SemaphoreSlim(0); var appDone = new SemaphoreSlim(0);
var expectedExceptionThrown = false; var expectedExceptionThrown = false;
var builder = new WebHostBuilder() var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls("http://127.0.0.1:0") .UseUrls("http://127.0.0.1:0")
.Configure(app => app.Run(async context => .Configure(app => app.Run(async context =>
@ -508,7 +514,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
var appStarted = new SemaphoreSlim(0); var appStarted = new SemaphoreSlim(0);
var requestAborted = new SemaphoreSlim(0); var requestAborted = new SemaphoreSlim(0);
var builder = new WebHostBuilder() var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls("http://127.0.0.1:0") .UseUrls("http://127.0.0.1:0")
.Configure(app => app.Run(async context => .Configure(app => app.Run(async context =>
@ -538,7 +544,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Fact] [Fact]
public void AbortingTheConnectionSendsFIN() public void AbortingTheConnectionSendsFIN()
{ {
var builder = new WebHostBuilder() var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls("http://127.0.0.1:0") .UseUrls("http://127.0.0.1:0")
.Configure(app => app.Run(context => .Configure(app => app.Run(context =>
@ -1617,7 +1623,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
private async Task TestRemoteIPAddress(string registerAddress, string requestAddress, string expectAddress) private async Task TestRemoteIPAddress(string registerAddress, string requestAddress, string expectAddress)
{ {
var builder = new WebHostBuilder() var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls($"http://{registerAddress}:0") .UseUrls($"http://{registerAddress}:0")
.Configure(app => .Configure(app =>

View File

@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Fact] [Fact]
public async Task LargeDownload() public async Task LargeDownload()
{ {
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls("http://127.0.0.1:0/") .UseUrls("http://127.0.0.1:0/")
.Configure(app => .Configure(app =>
@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Theory, MemberData(nameof(NullHeaderData))] [Theory, MemberData(nameof(NullHeaderData))]
public async Task IgnoreNullHeaderValues(string headerName, StringValues headerValue, string expectedValue) public async Task IgnoreNullHeaderValues(string headerName, StringValues headerValue, string expectedValue)
{ {
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls("http://127.0.0.1:0/") .UseUrls("http://127.0.0.1:0/")
.Configure(app => .Configure(app =>
@ -144,7 +144,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
var onStartingCalled = false; var onStartingCalled = false;
var onCompletedCalled = false; var onCompletedCalled = false;
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls("http://127.0.0.1:0/") .UseUrls("http://127.0.0.1:0/")
.Configure(app => .Configure(app =>
@ -179,7 +179,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
InvalidOperationException ex = null; InvalidOperationException ex = null;
var hostBuilder = new WebHostBuilder() var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel() .UseKestrel()
.UseUrls("http://127.0.0.1:0/") .UseUrls("http://127.0.0.1:0/")
.Configure(app => .Configure(app =>
@ -2506,6 +2506,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
totalReceived += received; totalReceived += received;
} while (received > 0 && totalReceived < responseSize); } while (received > 0 && totalReceived < responseSize);
} }
catch (SocketException) { }
catch (IOException) catch (IOException)
{ {
// Socket.Receive could throw, and that is fine // Socket.Receive could throw, and that is fine

View File

@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
_listenOptions = listenOptions; _listenOptions = listenOptions;
Context = context; Context = context;
_host = new WebHostBuilder() _host = TransportSelector.GetWebHostBuilder()
.UseKestrel(o => .UseKestrel(o =>
{ {
o.ListenOptions.Add(_listenOptions); o.ListenOptions.Add(_listenOptions);

View File

@ -1,72 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Testing.xunit;
using Xunit;
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{
public class ThreadCountTests
{
[ConditionalTheory]
[MemberData(nameof(OneToTen))]
[OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Tests fail on OS X due to low file descriptor limit.")]
public async Task OneToTenThreads(int threadCount)
{
var hostBuilder = new WebHostBuilder()
.UseKestrel()
.UseLibuv(options =>
{
options.ThreadCount = threadCount;
})
.UseUrls("http://127.0.0.1:0/")
.Configure(app =>
{
app.Run(context =>
{
return context.Response.WriteAsync("Hello World");
});
});
using (var host = hostBuilder.Build())
{
host.Start();
using (var client = new HttpClient())
{
// Send 20 requests just to make sure we don't get any failures
var requestTasks = new List<Task<string>>();
for (int i = 0; i < 20; i++)
{
var requestTask = client.GetStringAsync($"http://127.0.0.1:{host.GetPort()}/");
requestTasks.Add(requestTask);
}
foreach (var result in await Task.WhenAll(requestTasks))
{
Assert.Equal("Hello World", result);
}
}
}
}
public static TheoryData<int> OneToTen
{
get
{
var dataset = new TheoryData<int>();
for (int i = 1; i <= 10; i++)
{
dataset.Add(i);
}
return dataset;
}
}
}
}

View File

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<AssemblyName>Microsoft.AspNetCore.Server.Kestrel.FunctionalTests</AssemblyName> <AssemblyName>Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.FunctionalTests</AssemblyName>
<RootNamespace>Microsoft.AspNetCore.Server.Kestrel.FunctionalTests</RootNamespace> <RootNamespace>Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.FunctionalTests</RootNamespace>
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks> <TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netcoreapp2.0</TargetFrameworks> <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netcoreapp2.0</TargetFrameworks>
<DefineConstants Condition="$([MSBuild]::IsOSPlatform('OSX'))">$(DefineConstants);MACOS</DefineConstants> <DefineConstants Condition="$([MSBuild]::IsOSPlatform('OSX'))">$(DefineConstants);MACOS</DefineConstants>
@ -11,6 +11,7 @@
<ItemGroup> <ItemGroup>
<Compile Include="..\shared\**\*.cs" /> <Compile Include="..\shared\**\*.cs" />
<Compile Include="..\Kestrel.FunctionalTests\**\*.cs" />
<Content Include="..\shared\TestCertificates\*.pfx" CopyToOutputDirectory="PreserveNewest" /> <Content Include="..\shared\TestCertificates\*.pfx" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup> </ItemGroup>
@ -20,6 +21,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Kestrel\Kestrel.csproj" /> <ProjectReference Include="..\..\src\Kestrel\Kestrel.csproj" />
<ProjectReference Include="..\..\src\Kestrel.Transport.Libuv\Kestrel.Transport.Libuv.csproj" />
<ProjectReference Include="..\..\src\Kestrel.Https\Kestrel.Https.csproj" /> <ProjectReference Include="..\..\src\Kestrel.Https\Kestrel.Https.csproj" />
</ItemGroup> </ItemGroup>

View File

@ -0,0 +1,15 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Hosting;
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{
public static class TransportSelector
{
public static IWebHostBuilder GetWebHostBuilder()
{
return new WebHostBuilder().UseLibuv();
}
}
}

View File

@ -1,7 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using System.Net; using System.Net;
using System.Net.Http;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -10,6 +13,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers; using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
@ -25,6 +29,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
} }
}; };
public static IEnumerable<object[]> OneToTen => Enumerable.Range(1, 10).Select(i => new object[] { i });
[Fact] [Fact]
public async Task TransportCanBindAndStop() public async Task TransportCanBindAndStop()
{ {
@ -80,5 +86,49 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
await transport.UnbindAsync(); await transport.UnbindAsync();
await transport.StopAsync(); await transport.StopAsync();
} }
[ConditionalTheory]
[MemberData(nameof(OneToTen))]
[OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Tests fail on OS X due to low file descriptor limit.")]
public async Task OneToTenThreads(int threadCount)
{
var listenOptions = new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0));
var serviceContext = new TestServiceContext();
var testApplication = new DummyApplication(context =>
{
return context.Response.WriteAsync("Hello World");
});
listenOptions.UseHttpServer(listenOptions.ConnectionAdapters, serviceContext, testApplication, HttpProtocols.Http1);
var transportContext = new TestLibuvTransportContext()
{
ConnectionHandler = new ConnectionHandler(serviceContext, listenOptions.Build()),
Options = new LibuvTransportOptions { ThreadCount = threadCount }
};
var transport = new LibuvTransport(transportContext, listenOptions);
await transport.BindAsync();
using (var client = new HttpClient())
{
// Send 20 requests just to make sure we don't get any failures
var requestTasks = new List<Task<string>>();
for (int i = 0; i < 20; i++)
{
var requestTask = client.GetStringAsync($"http://127.0.0.1:{listenOptions.IPEndPoint.Port}/");
requestTasks.Add(requestTask);
}
foreach (var result in await Task.WhenAll(requestTasks))
{
Assert.Equal("Hello World", result);
}
}
await transport.UnbindAsync();
await transport.StopAsync();
}
} }
} }

View File

@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.FunctionalTests</AssemblyName>
<RootNamespace>Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.FunctionalTests</RootNamespace>
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netcoreapp2.0</TargetFrameworks>
<DefineConstants Condition="$([MSBuild]::IsOSPlatform('OSX'))">$(DefineConstants);MACOS</DefineConstants>
<DefineConstants>$(DefineConstants);SOCKETS</DefineConstants>
<ServerGarbageCollection>true</ServerGarbageCollection>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\shared\**\*.cs" />
<Compile Include="..\Kestrel.FunctionalTests\**\*.cs" />
<Content Include="..\shared\TestCertificates\*.pfx" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp2.0'">
<ProjectReference Include="..\..\tools\CodeGenerator\CodeGenerator.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Kestrel\Kestrel.csproj" />
<ProjectReference Include="..\..\src\Kestrel.Transport.Sockets\Kestrel.Transport.Sockets.csproj" />
<ProjectReference Include="..\..\src\Kestrel.Https\Kestrel.Https.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" />
<PackageReference Include="Microsoft.AspNetCore.Testing" />
<PackageReference Include="Microsoft.Extensions.Logging.Testing" />
<PackageReference Include="Newtonsoft.Json" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,15 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Hosting;
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{
public static class TransportSelector
{
public static IWebHostBuilder GetWebHostBuilder()
{
return new WebHostBuilder().UseSockets();
}
}
}