* 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 коммит произвёл GitHub
Родитель d46d2ce193
Коммит fdb4184dbf
31 изменённых файлов: 527 добавлений и 173 удалений

Просмотреть файл

@ -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
script:
- ./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

Просмотреть файл

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26814.0
VisualStudioVersion = 15.0.26730.16
MinimumVisualStudioVersion = 15.0.26730.03
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7972A5D6-3385-4127-9277-428506DD44FF}"
ProjectSection(SolutionItems) = preProject
@ -68,8 +68,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeGenerator", "tools\Code
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kestrel.Https", "src\Kestrel.Https\Kestrel.Https.csproj", "{5F64B3C3-0C2E-431A-B820-A81BBFC863DA}"
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}"
EndProject
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
EndProjectSection
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
GlobalSection(SolutionConfigurationPlatforms) = preSolution
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|x86.ActiveCfg = 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.Build.0 = 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|x86.ActiveCfg = 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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -325,7 +346,6 @@ Global
{B35D4D31-E74C-4646-8A11-7A7A40F0021E} = {8A3D00B8-1CCF-4BE6-A060-11104CE2D9CE}
{BD2D4D29-1BD9-40D0-BB31-337D5416B63C} = {327F7880-D9AF-46BD-B45C-3B7E34A01DFD}
{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}
{2822C132-BFFB-4D53-AC5B-E7E47DD81A6E} = {0EF2ACDF-012F-4472-A13A-4272419E2903}
{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}
{6956CF5C-3163-4398-8628-4ECA569245B5} = {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
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2D10D020-6770-47CA-BB8D-2C23FE3AE071}

Просмотреть файл

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Net;
@ -51,7 +52,7 @@ namespace SampleApp
basePort = 5000;
}
var host = new WebHostBuilder()
var hostBuilder = new WebHostBuilder()
.ConfigureLogging((_, factory) =>
{
factory.AddConsole();
@ -80,16 +81,20 @@ namespace SampleApp
// The following section should be used to demo sockets
//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())
.UseStartup<Startup>()
.Build();
.UseStartup<Startup>();
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();
}
}
}

Просмотреть файл

@ -3,7 +3,8 @@
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("Kestrel.Performance, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

Просмотреть файл

@ -3,4 +3,6 @@
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")]

Просмотреть файл

@ -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);
}
}

Просмотреть файл

@ -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);
}
}

Просмотреть файл

@ -5,30 +5,36 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Pipelines;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.IO.Pipelines;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
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
{
internal sealed class SocketConnection : TransportConnection
{
private readonly Socket _socket;
private readonly SocketTransport _transport;
private IList<ArraySegment<byte>> _sendBufferList;
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(transport != null);
Debug.Assert(pipeFactory != null);
Debug.Assert(trace != null);
_socket = socket;
_transport = transport;
PipeFactory = pipeFactory;
_trace = trace;
var localEndPoint = (IPEndPoint)_socket.LocalEndPoint;
var remoteEndPoint = (IPEndPoint)_socket.RemoteEndPoint;
@ -40,6 +46,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
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)
{
try
@ -66,9 +76,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
// Dispose the socket(should noop if already called)
_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)
{
// FIN
_trace.ConnectionReadFin(ConnectionId);
break;
}
@ -100,7 +111,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
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)
{
// 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)
{
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();
_trace.ConnectionError(ConnectionId, error);
}
catch (ObjectDisposedException)
{
error = new ConnectionAbortedException();
_trace.ConnectionError(ConnectionId, error);
}
catch (IOException ex)
{
error = ex;
_trace.ConnectionError(ConnectionId, error);
}
catch (Exception ex)
{
error = new IOException(ex.Message, ex);
_trace.ConnectionError(ConnectionId, error);
}
finally
{
if (_aborted)
{
error = error ?? new ConnectionAbortedException();
}
Input.Complete(error);
}
}
@ -202,8 +235,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
Output.Advance(buffer.End);
}
}
_socket.Shutdown(SocketShutdown.Send);
}
catch (SocketException ex) when (ex.SocketErrorCode == SocketError.OperationAborted)
{
@ -224,6 +255,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
finally
{
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;
}
public override PipeFactory PipeFactory => _transport.TransportFactory.PipeFactory;
public override IScheduler InputWriterScheduler => InlineScheduler.Default;
public override IScheduler OutputReaderScheduler => TaskRunScheduler.Default;
}
}

Просмотреть файл

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

Просмотреть файл

@ -2,18 +2,32 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO.Pipelines;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
{
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)
@ -33,9 +47,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
throw new ArgumentNullException(nameof(handler));
}
return new SocketTransport(this, endPointInformation, handler);
return new SocketTransport(endPointInformation, handler, _trace);
}
internal PipeFactory PipeFactory => _pipeFactory;
}
}

Просмотреть файл

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

Просмотреть файл

@ -16,7 +16,9 @@
<ItemGroup>
<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.Sockets\Kestrel.Transport.Sockets.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

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

Просмотреть файл

@ -163,7 +163,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
private async Task RegisterAddresses_Success(string addressInput, string[] testUrls, int testPort = 0)
{
var hostBuilder = new WebHostBuilder()
var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel()
.ConfigureLogging(_configureLoggingDelegate)
.UseUrls(addressInput)
@ -223,7 +223,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
private async Task RegisterIPEndPoint_Success(IPEndPoint endPoint, string testUrl, int testPort = 0)
{
var hostBuilder = new WebHostBuilder()
var hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate)
.UseKestrel(options =>
{
@ -304,7 +304,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{
var testLogger = new TestApplicationErrorLogger();
var hostBuilder = new WebHostBuilder()
var hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate)
.UseKestrel()
.ConfigureLogging(builder => builder
@ -336,7 +336,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
socket.Bind(new IPEndPoint(IPAddress.Loopback, 0));
var port = ((IPEndPoint)socket.LocalEndPoint).Port;
var hostBuilder = new WebHostBuilder()
var hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate)
.UseKestrel()
.UseUrls($"http://127.0.0.1:{port}")
@ -359,7 +359,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
socket.Bind(new IPEndPoint(IPAddress.IPv6Loopback, 0));
var port = ((IPEndPoint)socket.LocalEndPoint).Port;
var hostBuilder = new WebHostBuilder()
var hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate)
.UseKestrel()
.UseUrls($"http://[::1]:{port}")
@ -378,7 +378,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{
var useUrlsAddress = $"http://127.0.0.1:0";
var testLogger = new TestApplicationErrorLogger();
var hostBuilder = new WebHostBuilder()
var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel(options =>
{
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 testLogger = new TestApplicationErrorLogger();
var hostBuilder = new WebHostBuilder()
var hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate)
.UseKestrel(options =>
{
@ -455,7 +455,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Fact]
public async Task DoesNotOverrideDirectConfigurationWithIServerAddressesFeature_IfAddressesEmpty()
{
var hostBuilder = new WebHostBuilder()
var hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate)
.UseKestrel(options =>
{
@ -499,7 +499,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Fact]
public void ThrowsWhenBindingLocalhostToDynamicPort()
{
var hostBuilder = new WebHostBuilder()
var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel()
.UseUrls("http://localhost:0")
.Configure(ConfigureEchoAddress);
@ -515,7 +515,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[InlineData("ftp://localhost")]
public void ThrowsForUnsupportedAddressFromHosting(string addr)
{
var hostBuilder = new WebHostBuilder()
var hostBuilder = TransportSelector.GetWebHostBuilder()
.UseKestrel()
.UseUrls(addr)
.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)
{
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));
var port = ((IPEndPoint)socket.LocalEndPoint).Port;
var hostBuilder = new WebHostBuilder()
var hostBuilder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(_configureLoggingDelegate)
.UseKestrel()
.UseUrls($"http://localhost:{port}")
@ -807,6 +892,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
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
{
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
@ -819,6 +910,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{
return false;
}
#endif
}
}
}

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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(bufferLength % 256 == 0, $"{nameof(bufferLength)} must be evenly divisible by 256");
var builder = new WebHostBuilder()
var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel(options =>
{
options.Limits.MaxRequestBodySize = contentLength;
@ -155,7 +155,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Fact]
public async Task DoesNotHangOnConnectionCloseRequest()
{
var builder = new WebHostBuilder()
var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel()
.UseUrls("http://127.0.0.1:0")
.Configure(app =>
@ -185,7 +185,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
var requestBodyPersisted = false;
var responseBodyPersisted = false;
var builder = new WebHostBuilder()
var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel()
.UseUrls("http://127.0.0.1:0")
.Configure(app =>
@ -228,7 +228,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
public void CanUpgradeRequestWithConnectionKeepAliveUpgradeHeader()
{
var dataRead = false;
var builder = new WebHostBuilder()
var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel()
.UseUrls("http://127.0.0.1:0")
.Configure(app =>
@ -300,7 +300,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
.Setup(factory => factory.CreateLogger(It.IsAny<string>()))
.Returns(Mock.Of<ILogger>());
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);
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>()))
.Returns(Mock.Of<ILogger>());
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);
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>()))
.Returns(Mock.Of<ILogger>());
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);
using (var server = new TestServer(async context =>
@ -464,7 +470,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
var appDone = new SemaphoreSlim(0);
var expectedExceptionThrown = false;
var builder = new WebHostBuilder()
var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel()
.UseUrls("http://127.0.0.1:0")
.Configure(app => app.Run(async context =>
@ -508,7 +514,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{
var appStarted = new SemaphoreSlim(0);
var requestAborted = new SemaphoreSlim(0);
var builder = new WebHostBuilder()
var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel()
.UseUrls("http://127.0.0.1:0")
.Configure(app => app.Run(async context =>
@ -538,7 +544,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
[Fact]
public void AbortingTheConnectionSendsFIN()
{
var builder = new WebHostBuilder()
var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel()
.UseUrls("http://127.0.0.1:0")
.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)
{
var builder = new WebHostBuilder()
var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel()
.UseUrls($"http://{registerAddress}:0")
.Configure(app =>

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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;
}
}
}
}

Просмотреть файл

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

Просмотреть файл

@ -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();
}
}
}

Просмотреть файл

@ -1,7 +1,10 @@
// 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.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Text;
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.Transport.Libuv.Tests.TestHelpers;
using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit;
using Xunit;
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]
public async Task TransportCanBindAndStop()
{
@ -80,5 +86,49 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
await transport.UnbindAsync();
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();
}
}
}

Просмотреть файл

@ -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>

Просмотреть файл

@ -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();
}
}
}

Просмотреть файл