From edf25b7817d6b19557c1158e5f87cea4d0acbce2 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Wed, 19 Aug 2020 07:41:48 +1200 Subject: [PATCH 01/81] HTTP method matching: Jump table optimized for a single method (#24953) --- .../HttpMethodPolicyJumpTableBenchmark.cs | 54 ++++++++++++ .../HttpMethodDictionaryPolicyJumpTable.cs | 48 +++++++++++ .../src/Matching/HttpMethodMatcherPolicy.cs | 86 +++++++++---------- .../HttpMethodSingleEntryPolicyJumpTable.cs | 45 ++++++++++ ...pMethodMatcherPolicyIntegrationTestBase.cs | 20 +++-- 5 files changed, 198 insertions(+), 55 deletions(-) create mode 100644 src/Http/Routing/perf/Matching/HttpMethodPolicyJumpTableBenchmark.cs create mode 100644 src/Http/Routing/src/Matching/HttpMethodDictionaryPolicyJumpTable.cs create mode 100644 src/Http/Routing/src/Matching/HttpMethodSingleEntryPolicyJumpTable.cs diff --git a/src/Http/Routing/perf/Matching/HttpMethodPolicyJumpTableBenchmark.cs b/src/Http/Routing/perf/Matching/HttpMethodPolicyJumpTableBenchmark.cs new file mode 100644 index 0000000000..012d138e9a --- /dev/null +++ b/src/Http/Routing/perf/Matching/HttpMethodPolicyJumpTableBenchmark.cs @@ -0,0 +1,54 @@ +// 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 BenchmarkDotNet.Attributes; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Routing.Matching +{ + public class HttpMethodPolicyJumpTableBenchmark + { + private PolicyJumpTable _dictionaryJumptable; + private PolicyJumpTable _singleEntryJumptable; + private DefaultHttpContext _httpContext; + + [GlobalSetup] + public void Setup() + { + _dictionaryJumptable = new HttpMethodDictionaryPolicyJumpTable( + 0, + new Dictionary + { + [HttpMethods.Get] = 1 + }, + -1, + new Dictionary + { + [HttpMethods.Get] = 2 + }); + _singleEntryJumptable = new HttpMethodSingleEntryPolicyJumpTable( + 0, + HttpMethods.Get, + -1, + supportsCorsPreflight: true, + -1, + 2); + + _httpContext = new DefaultHttpContext(); + _httpContext.Request.Method = HttpMethods.Get; + } + + [Benchmark] + public int DictionaryPolicyJumpTable() + { + return _dictionaryJumptable.GetDestination(_httpContext); + } + + [Benchmark] + public int SingleEntryPolicyJumpTable() + { + return _singleEntryJumptable.GetDestination(_httpContext); + } + } +} diff --git a/src/Http/Routing/src/Matching/HttpMethodDictionaryPolicyJumpTable.cs b/src/Http/Routing/src/Matching/HttpMethodDictionaryPolicyJumpTable.cs new file mode 100644 index 0000000000..f77e65f37e --- /dev/null +++ b/src/Http/Routing/src/Matching/HttpMethodDictionaryPolicyJumpTable.cs @@ -0,0 +1,48 @@ +// 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 Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Routing.Matching +{ + internal sealed class HttpMethodDictionaryPolicyJumpTable : PolicyJumpTable + { + private readonly int _exitDestination; + private readonly Dictionary? _destinations; + private readonly int _corsPreflightExitDestination; + private readonly Dictionary? _corsPreflightDestinations; + + private readonly bool _supportsCorsPreflight; + + public HttpMethodDictionaryPolicyJumpTable( + int exitDestination, + Dictionary? destinations, + int corsPreflightExitDestination, + Dictionary? corsPreflightDestinations) + { + _exitDestination = exitDestination; + _destinations = destinations; + _corsPreflightExitDestination = corsPreflightExitDestination; + _corsPreflightDestinations = corsPreflightDestinations; + + _supportsCorsPreflight = _corsPreflightDestinations != null && _corsPreflightDestinations.Count > 0; + } + + public override int GetDestination(HttpContext httpContext) + { + int destination; + + var httpMethod = httpContext.Request.Method; + if (_supportsCorsPreflight && HttpMethodMatcherPolicy.IsCorsPreflightRequest(httpContext, httpMethod, out var accessControlRequestMethod)) + { + return _corsPreflightDestinations!.TryGetValue(accessControlRequestMethod, out destination) + ? destination + : _corsPreflightExitDestination; + } + + return _destinations != null && + _destinations.TryGetValue(httpMethod, out destination) ? destination : _exitDestination; + } + } +} diff --git a/src/Http/Routing/src/Matching/HttpMethodMatcherPolicy.cs b/src/Http/Routing/src/Matching/HttpMethodMatcherPolicy.cs index 039d889fed..9ffa13fa91 100644 --- a/src/Http/Routing/src/Matching/HttpMethodMatcherPolicy.cs +++ b/src/Http/Routing/src/Matching/HttpMethodMatcherPolicy.cs @@ -370,11 +370,38 @@ namespace Microsoft.AspNetCore.Routing.Matching destinations.Remove(AnyMethod); } - return new HttpMethodPolicyJumpTable( - exitDestination, - destinations, - corsPreflightExitDestination, - corsPreflightDestinations); + if (destinations?.Count == 1) + { + // If there is only a single valid HTTP method then use an optimized jump table. + // It avoids unnecessary dictionary lookups with the method name. + var httpMethodDestination = destinations.Single(); + var method = httpMethodDestination.Key; + var destination = httpMethodDestination.Value; + var supportsCorsPreflight = false; + var corsPreflightDestination = 0; + + if (corsPreflightDestinations?.Count > 0) + { + supportsCorsPreflight = true; + corsPreflightDestination = corsPreflightDestinations.Single().Value; + } + + return new HttpMethodSingleEntryPolicyJumpTable( + exitDestination, + method, + destination, + supportsCorsPreflight, + corsPreflightExitDestination, + corsPreflightDestination); + } + else + { + return new HttpMethodDictionaryPolicyJumpTable( + exitDestination, + destinations, + corsPreflightExitDestination, + corsPreflightDestinations); + } } private Endpoint CreateRejectionEndpoint(IEnumerable httpMethods) @@ -418,50 +445,15 @@ namespace Microsoft.AspNetCore.Routing.Matching return false; } - private class HttpMethodPolicyJumpTable : PolicyJumpTable + internal static bool IsCorsPreflightRequest(HttpContext httpContext, string httpMethod, out StringValues accessControlRequestMethod) { - private readonly int _exitDestination; - private readonly Dictionary? _destinations; - private readonly int _corsPreflightExitDestination; - private readonly Dictionary? _corsPreflightDestinations; + accessControlRequestMethod = default; + var headers = httpContext.Request.Headers; - private readonly bool _supportsCorsPreflight; - - public HttpMethodPolicyJumpTable( - int exitDestination, - Dictionary? destinations, - int corsPreflightExitDestination, - Dictionary? corsPreflightDestinations) - { - _exitDestination = exitDestination; - _destinations = destinations; - _corsPreflightExitDestination = corsPreflightExitDestination; - _corsPreflightDestinations = corsPreflightDestinations; - - _supportsCorsPreflight = _corsPreflightDestinations != null && _corsPreflightDestinations.Count > 0; - } - - public override int GetDestination(HttpContext httpContext) - { - int destination; - - var httpMethod = httpContext.Request.Method; - var headers = httpContext.Request.Headers; - if (_supportsCorsPreflight && - HttpMethods.Equals(httpMethod, PreflightHttpMethod) && - headers.ContainsKey(HeaderNames.Origin) && - headers.TryGetValue(HeaderNames.AccessControlRequestMethod, out var accessControlRequestMethod) && - !StringValues.IsNullOrEmpty(accessControlRequestMethod)) - { - return _corsPreflightDestinations != null && - _corsPreflightDestinations.TryGetValue(accessControlRequestMethod, out destination) - ? destination - : _corsPreflightExitDestination; - } - - return _destinations != null && - _destinations.TryGetValue(httpMethod, out destination) ? destination : _exitDestination; - } + return HttpMethods.Equals(httpMethod, PreflightHttpMethod) && + headers.ContainsKey(HeaderNames.Origin) && + headers.TryGetValue(HeaderNames.AccessControlRequestMethod, out accessControlRequestMethod) && + !StringValues.IsNullOrEmpty(accessControlRequestMethod); } private class HttpMethodMetadataEndpointComparer : EndpointMetadataComparer diff --git a/src/Http/Routing/src/Matching/HttpMethodSingleEntryPolicyJumpTable.cs b/src/Http/Routing/src/Matching/HttpMethodSingleEntryPolicyJumpTable.cs new file mode 100644 index 0000000000..a114b373da --- /dev/null +++ b/src/Http/Routing/src/Matching/HttpMethodSingleEntryPolicyJumpTable.cs @@ -0,0 +1,45 @@ +// 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.Http; + +namespace Microsoft.AspNetCore.Routing.Matching +{ + internal sealed class HttpMethodSingleEntryPolicyJumpTable : PolicyJumpTable + { + private readonly int _exitDestination; + private readonly string _method; + private readonly int _destination; + private readonly int _corsPreflightExitDestination; + private readonly int _corsPreflightDestination; + + private readonly bool _supportsCorsPreflight; + + public HttpMethodSingleEntryPolicyJumpTable( + int exitDestination, + string method, + int destination, + bool supportsCorsPreflight, + int corsPreflightExitDestination, + int corsPreflightDestination) + { + _exitDestination = exitDestination; + _method = method; + _destination = destination; + _supportsCorsPreflight = supportsCorsPreflight; + _corsPreflightExitDestination = corsPreflightExitDestination; + _corsPreflightDestination = corsPreflightDestination; + } + + public override int GetDestination(HttpContext httpContext) + { + var httpMethod = httpContext.Request.Method; + if (_supportsCorsPreflight && HttpMethodMatcherPolicy.IsCorsPreflightRequest(httpContext, httpMethod, out var accessControlRequestMethod)) + { + return HttpMethods.Equals(accessControlRequestMethod, _method) ? _corsPreflightDestination : _corsPreflightExitDestination; + } + + return HttpMethods.Equals(httpMethod, _method) ? _destination : _exitDestination; + } + } +} diff --git a/src/Http/Routing/test/UnitTests/Matching/HttpMethodMatcherPolicyIntegrationTestBase.cs b/src/Http/Routing/test/UnitTests/Matching/HttpMethodMatcherPolicyIntegrationTestBase.cs index 5f219e329a..fbb8cecc69 100644 --- a/src/Http/Routing/test/UnitTests/Matching/HttpMethodMatcherPolicyIntegrationTestBase.cs +++ b/src/Http/Routing/test/UnitTests/Matching/HttpMethodMatcherPolicyIntegrationTestBase.cs @@ -84,14 +84,16 @@ namespace Microsoft.AspNetCore.Routing.Matching Assert.Same(HttpMethodMatcherPolicy.Http405EndpointDisplayName, httpContext.GetEndpoint().DisplayName); } - [Fact] - public async Task Match_HttpMethod_CaseInsensitive() + [Theory] + [InlineData("GeT", "GET")] + [InlineData("unKNOWN", "UNKNOWN")] + public async Task Match_HttpMethod_CaseInsensitive(string endpointMethod, string requestMethod) { // Arrange - var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { "GeT", }); + var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { endpointMethod, }); var matcher = CreateMatcher(endpoint); - var httpContext = CreateContext("/hello", "GET"); + var httpContext = CreateContext("/hello", requestMethod); // Act await matcher.MatchAsync(httpContext); @@ -100,14 +102,16 @@ namespace Microsoft.AspNetCore.Routing.Matching MatcherAssert.AssertMatch(httpContext, endpoint); } - [Fact] - public async Task Match_HttpMethod_CaseInsensitive_CORS_Preflight() + [Theory] + [InlineData("GeT", "GET")] + [InlineData("unKNOWN", "UNKNOWN")] + public async Task Match_HttpMethod_CaseInsensitive_CORS_Preflight(string endpointMethod, string requestMethod) { // Arrange - var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { "GeT", }, acceptCorsPreflight: true); + var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { endpointMethod, }, acceptCorsPreflight: true); var matcher = CreateMatcher(endpoint); - var httpContext = CreateContext("/hello", "GET", corsPreflight: true); + var httpContext = CreateContext("/hello", requestMethod, corsPreflight: true); // Act await matcher.MatchAsync(httpContext); From bc40f40382668b84571e62ab97ba175869ac239b Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Tue, 18 Aug 2020 12:55:42 -0700 Subject: [PATCH 02/81] Log for SameSite=None without Secure (#24970) * Log for SameSite=None without Secure * Update src/Http/Http/src/Internal/EventIds.cs Co-authored-by: campersau Co-authored-by: campersau --- .../src/Features/ResponseCookiesFeature.cs | 21 ++---- src/Http/Http/src/Internal/EventIds.cs | 12 ++++ src/Http/Http/src/Internal/ResponseCookies.cs | 45 +++++++++--- src/Http/Http/test/ResponseCookiesTest.cs | 69 +++++++++++++++++-- 4 files changed, 115 insertions(+), 32 deletions(-) create mode 100644 src/Http/Http/src/Internal/EventIds.cs diff --git a/src/Http/Http/src/Features/ResponseCookiesFeature.cs b/src/Http/Http/src/Features/ResponseCookiesFeature.cs index 7e3cabb28e..b51b99831f 100644 --- a/src/Http/Http/src/Features/ResponseCookiesFeature.cs +++ b/src/Http/Http/src/Features/ResponseCookiesFeature.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Http.Features // Lambda hoisted to static readonly field to improve inlining https://github.com/dotnet/roslyn/issues/13624 private readonly static Func _nullResponseFeature = f => null; - private FeatureReferences _features; + private readonly IFeatureCollection _features; private IResponseCookies? _cookiesCollection; /// @@ -27,12 +27,7 @@ namespace Microsoft.AspNetCore.Http.Features /// public ResponseCookiesFeature(IFeatureCollection features) { - if (features == null) - { - throw new ArgumentNullException(nameof(features)); - } - - _features.Initalize(features); + _features = features ?? throw new ArgumentNullException(nameof(features)); } /// @@ -46,16 +41,9 @@ namespace Microsoft.AspNetCore.Http.Features [Obsolete("This constructor is obsolete and will be removed in a future version.")] public ResponseCookiesFeature(IFeatureCollection features, ObjectPool? builderPool) { - if (features == null) - { - throw new ArgumentNullException(nameof(features)); - } - - _features.Initalize(features); + _features = features ?? throw new ArgumentNullException(nameof(features)); } - private IHttpResponseFeature HttpResponseFeature => _features.Fetch(ref _features.Cache, _nullResponseFeature)!; - /// public IResponseCookies Cookies { @@ -63,8 +51,7 @@ namespace Microsoft.AspNetCore.Http.Features { if (_cookiesCollection == null) { - var headers = HttpResponseFeature.Headers; - _cookiesCollection = new ResponseCookies(headers); + _cookiesCollection = new ResponseCookies(_features); } return _cookiesCollection; diff --git a/src/Http/Http/src/Internal/EventIds.cs b/src/Http/Http/src/Internal/EventIds.cs new file mode 100644 index 0000000000..ddefeceecf --- /dev/null +++ b/src/Http/Http/src/Internal/EventIds.cs @@ -0,0 +1,12 @@ +// 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.Extensions.Logging; + +namespace Microsoft.AspNetCore.Http +{ + internal static class EventIds + { + public static readonly EventId SameSiteNotSecure = new EventId(1, "SameSiteNotSecure"); + } +} diff --git a/src/Http/Http/src/Internal/ResponseCookies.cs b/src/Http/Http/src/Internal/ResponseCookies.cs index d9adfb69f1..e6e582bfda 100644 --- a/src/Http/Http/src/Internal/ResponseCookies.cs +++ b/src/Http/Http/src/Internal/ResponseCookies.cs @@ -3,6 +3,9 @@ using System; using System.Collections.Generic; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; @@ -16,18 +19,16 @@ namespace Microsoft.AspNetCore.Http internal const string EnableCookieNameEncoding = "Microsoft.AspNetCore.Http.EnableCookieNameEncoding"; internal bool _enableCookieNameEncoding = AppContext.TryGetSwitch(EnableCookieNameEncoding, out var enabled) && enabled; + private readonly IFeatureCollection _features; + private ILogger? _logger; + /// /// Create a new wrapper. /// - /// The for the response. - public ResponseCookies(IHeaderDictionary headers) + internal ResponseCookies(IFeatureCollection features) { - if (headers == null) - { - throw new ArgumentNullException(nameof(headers)); - } - - Headers = headers; + _features = features; + Headers = _features.Get().Headers; } private IHeaderDictionary Headers { get; set; } @@ -54,6 +55,21 @@ namespace Microsoft.AspNetCore.Http throw new ArgumentNullException(nameof(options)); } + // SameSite=None cookies must be marked as Secure. + if (!options.Secure && options.SameSite == SameSiteMode.None) + { + if (_logger == null) + { + var services = _features.Get()?.RequestServices; + _logger = services?.GetService>(); + } + + if (_logger != null) + { + Log.SameSiteCookieNotSecure(_logger, key); + } + } + var setCookieHeaderValue = new SetCookieHeaderValue( _enableCookieNameEncoding ? Uri.EscapeDataString(key) : key, Uri.EscapeDataString(value)) @@ -135,5 +151,18 @@ namespace Microsoft.AspNetCore.Http SameSite = options.SameSite }); } + + private static class Log + { + private static readonly Action _samesiteNotSecure = LoggerMessage.Define( + LogLevel.Warning, + EventIds.SameSiteNotSecure, + "The cookie '{name}' has set 'SameSite=None' and must also set 'Secure'."); + + public static void SameSiteCookieNotSecure(ILogger logger, string name) + { + _samesiteNotSecure(logger, name, null); + } + } } } diff --git a/src/Http/Http/test/ResponseCookiesTest.cs b/src/Http/Http/test/ResponseCookiesTest.cs index 8e4e60aaa9..2c73a75ec1 100644 --- a/src/Http/Http/test/ResponseCookiesTest.cs +++ b/src/Http/Http/test/ResponseCookiesTest.cs @@ -2,6 +2,10 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Testing; using Microsoft.Net.Http.Headers; using Xunit; @@ -9,11 +13,56 @@ namespace Microsoft.AspNetCore.Http.Tests { public class ResponseCookiesTest { + private IFeatureCollection MakeFeatures(IHeaderDictionary headers) + { + var responseFeature = new HttpResponseFeature() + { + Headers = headers + }; + var features = new FeatureCollection(); + features.Set(responseFeature); + return features; + } + + [Fact] + public void AppendSameSiteNoneWithoutSecureLogsWarning() + { + var headers = new HeaderDictionary(); + var features = MakeFeatures(headers); + var services = new ServiceCollection(); + + var sink = new TestSink(TestSink.EnableWithTypeName); + var loggerFactory = new TestLoggerFactory(sink, enabled: true); + services.AddLogging(); + services.AddSingleton(loggerFactory); + + features.Set(new ServiceProvidersFeature() { RequestServices = services.BuildServiceProvider() }); + + var cookies = new ResponseCookies(features); + var testCookie = "TestCookie"; + + cookies.Append(testCookie, "value", new CookieOptions() + { + SameSite = SameSiteMode.None, + }); + + var cookieHeaderValues = headers[HeaderNames.SetCookie]; + Assert.Single(cookieHeaderValues); + Assert.StartsWith(testCookie, cookieHeaderValues[0]); + Assert.Contains("path=/", cookieHeaderValues[0]); + Assert.Contains("samesite=none", cookieHeaderValues[0]); + Assert.DoesNotContain("secure", cookieHeaderValues[0]); + + var writeContext = Assert.Single(sink.Writes); + Assert.Equal("The cookie 'TestCookie' has set 'SameSite=None' and must also set 'Secure'.", writeContext.Message); + } + [Fact] public void DeleteCookieShouldSetDefaultPath() { var headers = new HeaderDictionary(); - var cookies = new ResponseCookies(headers); + var features = MakeFeatures(headers); + var cookies = new ResponseCookies(features); var testCookie = "TestCookie"; cookies.Delete(testCookie); @@ -29,7 +78,8 @@ namespace Microsoft.AspNetCore.Http.Tests public void DeleteCookieWithCookieOptionsShouldKeepPropertiesOfCookieOptions() { var headers = new HeaderDictionary(); - var cookies = new ResponseCookies(headers); + var features = MakeFeatures(headers); + var cookies = new ResponseCookies(features); var testCookie = "TestCookie"; var time = new DateTimeOffset(2000, 1, 1, 1, 1, 1, 1, TimeSpan.Zero); var options = new CookieOptions @@ -58,7 +108,8 @@ namespace Microsoft.AspNetCore.Http.Tests public void NoParamsDeleteRemovesCookieCreatedByAdd() { var headers = new HeaderDictionary(); - var cookies = new ResponseCookies(headers); + var features = MakeFeatures(headers); + var cookies = new ResponseCookies(features); var testCookie = "TestCookie"; cookies.Append(testCookie, testCookie); @@ -75,7 +126,8 @@ namespace Microsoft.AspNetCore.Http.Tests public void ProvidesMaxAgeWithCookieOptionsArgumentExpectMaxAgeToBeSet() { var headers = new HeaderDictionary(); - var cookies = new ResponseCookies(headers); + var features = MakeFeatures(headers); + var cookies = new ResponseCookies(features); var cookieOptions = new CookieOptions(); var maxAgeTime = TimeSpan.FromHours(1); cookieOptions.MaxAge = TimeSpan.FromHours(1); @@ -96,7 +148,8 @@ namespace Microsoft.AspNetCore.Http.Tests public void EscapesValuesBeforeSettingCookie(string value, string expected) { var headers = new HeaderDictionary(); - var cookies = new ResponseCookies(headers); + var features = MakeFeatures(headers); + var cookies = new ResponseCookies(features); cookies.Append("key", value); @@ -111,7 +164,8 @@ namespace Microsoft.AspNetCore.Http.Tests public void InvalidKeysThrow(string key) { var headers = new HeaderDictionary(); - var cookies = new ResponseCookies(headers); + var features = MakeFeatures(headers); + var cookies = new ResponseCookies(features); Assert.Throws(() => cookies.Append(key, "1")); } @@ -124,7 +178,8 @@ namespace Microsoft.AspNetCore.Http.Tests public void AppContextSwitchEscapesKeysAndValuesBeforeSettingCookie(string key, string value, string expected) { var headers = new HeaderDictionary(); - var cookies = new ResponseCookies(headers); + var features = MakeFeatures(headers); + var cookies = new ResponseCookies(features); cookies._enableCookieNameEncoding = true; cookies.Append(key, value); From ae1981f931cb1a873145191645f4ab966a0a8f4b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 18 Aug 2020 23:23:51 +0000 Subject: [PATCH 03/81] Sync shared code from runtime (#25009) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/Shared/runtime/Quic/Implementations/Mock/MockConnection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Shared/runtime/Quic/Implementations/Mock/MockConnection.cs b/src/Shared/runtime/Quic/Implementations/Mock/MockConnection.cs index cba2f936ef..b97f4876bf 100644 --- a/src/Shared/runtime/Quic/Implementations/Mock/MockConnection.cs +++ b/src/Shared/runtime/Quic/Implementations/Mock/MockConnection.cs @@ -74,7 +74,7 @@ namespace System.Net.Quic.Implementations.Mock } Socket socket = new Socket(_remoteEndPoint!.AddressFamily, SocketType.Stream, ProtocolType.Tcp); - await socket.ConnectAsync(_remoteEndPoint).ConfigureAwait(false); + await socket.ConnectAsync(_remoteEndPoint, cancellationToken).ConfigureAwait(false); socket.NoDelay = true; _localEndPoint = (IPEndPoint?)socket.LocalEndPoint; From 94e314d4d2b87e1d67eb594a4925804779e7f77c Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Mon, 17 Aug 2020 15:24:16 -0700 Subject: [PATCH 04/81] Helix pass in -nopath for dotnet-install (#24968) --- eng/helix/content/InstallDotNet.ps1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/eng/helix/content/InstallDotNet.ps1 b/eng/helix/content/InstallDotNet.ps1 index 7e87866433..778e24dbd2 100644 --- a/eng/helix/content/InstallDotNet.ps1 +++ b/eng/helix/content/InstallDotNet.ps1 @@ -28,8 +28,8 @@ param( & $PSScriptRoot\Download.ps1 "https://dot.net/v1/dotnet-install.ps1" $PSScriptRoot\dotnet-install.ps1 Write-Host "Download of dotnet-install.ps1 complete..." -Write-Host "Installing SDK...& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Version $sdkVersion -InstallDir $installDir" -Invoke-Expression "& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Version $sdkVersion -InstallDir $installDir" -Write-Host "Installing Runtime...& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Runtime dotnet -Version $runtimeVersion -InstallDir $installDir" -Invoke-Expression "& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Runtime dotnet -Version $runtimeVersion -InstallDir $installDir" -Write-Host "InstallDotNet.ps1 complete..." \ No newline at end of file +Write-Host "Installing SDK...& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Version $sdkVersion -InstallDir $installDir -NoPath" +Invoke-Expression "& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Version $sdkVersion -InstallDir $installDir -NoPath" +Write-Host "Installing Runtime...& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Runtime dotnet -Version $runtimeVersion -InstallDir $installDir -NoPath" +Invoke-Expression "& $PSScriptRoot\dotnet-install.ps1 -Architecture $arch -Runtime dotnet -Version $runtimeVersion -InstallDir $installDir -NoPath" +Write-Host "InstallDotNet.ps1 complete..." From 2d6fd453e26b4c07296a0c99638f84293f135199 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 17 Aug 2020 16:55:03 -0700 Subject: [PATCH 05/81] Allow ProblemDetails \ ValidationProblemDetails to be more testable Fixes https://github.com/dotnet/aspnetcore/issues/15166 --- src/Mvc/Mvc.Core/src/ControllerBase.cs | 62 ++++++++++++++----- .../test/ControllerUnitTestabilityTests.cs | 38 +++++++++++- 2 files changed, 84 insertions(+), 16 deletions(-) diff --git a/src/Mvc/Mvc.Core/src/ControllerBase.cs b/src/Mvc/Mvc.Core/src/ControllerBase.cs index b24e67a7c6..5903c4126b 100644 --- a/src/Mvc/Mvc.Core/src/ControllerBase.cs +++ b/src/Mvc/Mvc.Core/src/ControllerBase.cs @@ -1886,13 +1886,29 @@ namespace Microsoft.AspNetCore.Mvc string title = null, string type = null) { - var problemDetails = ProblemDetailsFactory.CreateProblemDetails( - HttpContext, - statusCode: statusCode ?? 500, - title: title, - type: type, - detail: detail, - instance: instance); + ProblemDetails problemDetails; + if (ProblemDetailsFactory == null) + { + // ProblemDetailsFactory may be null in unit testing scenarios. Improvise to make this more testable. + problemDetails = new ProblemDetails + { + Detail = detail, + Instance = instance, + Status = statusCode ?? 500, + Title = title, + Type = type, + }; + } + else + { + problemDetails = ProblemDetailsFactory.CreateProblemDetails( + HttpContext, + statusCode: statusCode ?? 500, + title: title, + type: type, + detail: detail, + instance: instance); + } return new ObjectResult(problemDetails) { @@ -1958,14 +1974,30 @@ namespace Microsoft.AspNetCore.Mvc { modelStateDictionary ??= ModelState; - var validationProblem = ProblemDetailsFactory.CreateValidationProblemDetails( - HttpContext, - modelStateDictionary, - statusCode: statusCode, - title: title, - type: type, - detail: detail, - instance: instance); + ValidationProblemDetails validationProblem; + if (ProblemDetailsFactory == null) + { + // ProblemDetailsFactory may be null in unit testing scenarios. Improvise to make this more testable. + validationProblem = new ValidationProblemDetails(modelStateDictionary) + { + Detail = detail, + Instance = instance, + Status = statusCode, + Title = title, + Type = type, + }; + } + else + { + validationProblem = ProblemDetailsFactory?.CreateValidationProblemDetails( + HttpContext, + modelStateDictionary, + statusCode: statusCode, + title: title, + type: type, + detail: detail, + instance: instance); + } if (validationProblem.Status == 400) { diff --git a/src/Mvc/Mvc.ViewFeatures/test/ControllerUnitTestabilityTests.cs b/src/Mvc/Mvc.ViewFeatures/test/ControllerUnitTestabilityTests.cs index 63615039b1..00a4485b8c 100644 --- a/src/Mvc/Mvc.ViewFeatures/test/ControllerUnitTestabilityTests.cs +++ b/src/Mvc/Mvc.ViewFeatures/test/ControllerUnitTestabilityTests.cs @@ -373,7 +373,7 @@ namespace Microsoft.AspNetCore.Mvc Assert.Equal(routeName, acceptedAtRouteResult.RouteName); Assert.Single(acceptedAtRouteResult.RouteValues); Assert.Equal("sample", acceptedAtRouteResult.RouteValues["route"]); - Assert.Same(value,acceptedAtRouteResult.Value); + Assert.Same(value, acceptedAtRouteResult.Value); // Arrange controller = new TestabilityController(); @@ -682,6 +682,42 @@ namespace Microsoft.AspNetCore.Mvc Assert.Equal(new { Arg1 = "Hi", Arg2 = "There" }, result.Arguments); } + [Fact] + public void Problem_Works() + { + // Arrange + var detail = "Some random error"; + var controller = new TestabilityController(); + + // Act + var result = controller.Problem(detail); + + // Assert + var badRequest = Assert.IsType(result); + var problemDetails = Assert.IsType(badRequest.Value); + Assert.Equal(detail, problemDetails.Detail); + } + + [Fact] + public void ValidationProblem_Works() + { + // Arrange + var detail = "Some random error"; + var controller = new TestabilityController(); + + // Act + controller.ModelState.AddModelError("some-key", "some-error"); + var result = controller.ValidationProblem(detail); + + // Assert + var badRequest = Assert.IsType(result); + var validationProblemDetails = Assert.IsType(badRequest.Value); + Assert.Equal(detail, validationProblemDetails.Detail); + var error = Assert.Single(validationProblemDetails.Errors); + Assert.Equal("some-key", error.Key); + Assert.Equal(new[] { "some-error" }, error.Value); + } + public static IEnumerable TestabilityViewTestData { get From 2f0cf8d3e9283b3f481e5f29d7553a9fa5540e6d Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 14 Aug 2020 14:59:59 -0700 Subject: [PATCH 06/81] Add support for views + SingleFileExe --- .../RelatedAssemblyAttribute.cs | 34 +++++++++++++++---- .../Sdk.Razor.CurrentVersion.targets | 2 ++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/Mvc/Mvc.Core/src/ApplicationParts/RelatedAssemblyAttribute.cs b/src/Mvc/Mvc.Core/src/ApplicationParts/RelatedAssemblyAttribute.cs index 0c89c0e49d..5bdfb076c0 100644 --- a/src/Mvc/Mvc.Core/src/ApplicationParts/RelatedAssemblyAttribute.cs +++ b/src/Mvc/Mvc.Core/src/ApplicationParts/RelatedAssemblyAttribute.cs @@ -1,4 +1,4 @@ -// 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. using System; @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.Loader; using Microsoft.AspNetCore.Mvc.Core; namespace Microsoft.AspNetCore.Mvc.ApplicationParts @@ -16,7 +17,8 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public sealed class RelatedAssemblyAttribute : Attribute { - private static readonly Func AssemblyLoadFileDelegate = Assembly.LoadFile; + private static readonly Func LoadFromAssemblyPathDelegate = + AssemblyLoadContext.GetLoadContext(typeof(RelatedAssemblyAttribute).Assembly).LoadFromAssemblyPath; /// /// Initializes a new instance of . @@ -50,7 +52,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts throw new ArgumentNullException(nameof(assembly)); } - return GetRelatedAssemblies(assembly, throwOnError, File.Exists, AssemblyLoadFileDelegate); + return GetRelatedAssemblies(assembly, throwOnError, File.Exists, LoadFromAssemblyPathDelegate); } internal static IReadOnlyList GetRelatedAssemblies( @@ -66,7 +68,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts // MVC will specifically look for related parts in the same physical directory as the assembly. // No-op if the assembly does not have a location. - if (assembly.IsDynamic || string.IsNullOrEmpty(assembly.Location)) + if (assembly.IsDynamic) { return Array.Empty(); } @@ -78,8 +80,10 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts } var assemblyName = assembly.GetName().Name; - var assemblyLocation = assembly.Location; - var assemblyDirectory = Path.GetDirectoryName(assemblyLocation); + // Assembly.Location may be null for a single-file exe. In this case, attempt to look for related parts in the app's base directory + var assemblyDirectory = string.IsNullOrEmpty(assembly.Location) ? + AppContext.BaseDirectory : + Path.GetDirectoryName(assembly.Location); var relatedAssemblies = new List(); for (var i = 0; i < attributes.Length; i++) @@ -91,6 +95,22 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts Resources.FormatRelatedAssemblyAttribute_AssemblyCannotReferenceSelf(nameof(RelatedAssemblyAttribute), assemblyName)); } + var relatedAssemblyName = new AssemblyName(attribute.AssemblyFileName); + Assembly relatedAssembly; + try + { + // Perform a cursory check to determine if the Assembly has already been loaded + // before going to disk. In the ordinary case, related parts that are part of + // application's reference closure should already be loaded. + relatedAssembly = Assembly.Load(relatedAssemblyName); + relatedAssemblies.Add(relatedAssembly); + continue; + } + catch (IOException) + { + // The assembly isn't already loaded. Patience, we'll attempt to load it from disk next. + } + var relatedAssemblyLocation = Path.Combine(assemblyDirectory, attribute.AssemblyFileName + ".dll"); if (!fileExists(relatedAssemblyLocation)) { @@ -106,7 +126,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts } } - var relatedAssembly = loadFile(relatedAssemblyLocation); + relatedAssembly = loadFile(relatedAssemblyLocation); relatedAssemblies.Add(relatedAssembly); } diff --git a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Sdk.Razor.CurrentVersion.targets b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Sdk.Razor.CurrentVersion.targets index 277c0f0021..24865730c8 100644 --- a/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Sdk.Razor.CurrentVersion.targets +++ b/src/Razor/Microsoft.NET.Sdk.Razor/src/build/netstandard2.0/Sdk.Razor.CurrentVersion.targets @@ -720,10 +720,12 @@ Copyright (c) .NET Foundation. All rights reserved. %(Filename)%(Extension) PreserveNewest + true %(Filename)%(Extension) PreserveNewest + true From ad8a927e8526b4720bc069d54feb4ef46c0fedcd Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 18 Aug 2020 17:52:17 -0700 Subject: [PATCH 07/81] Changes per discussion. Add a test --- .../RelatedAssemblyAttribute.cs | 56 ++++++++------- .../RelatedAssemblyPartTest.cs | 50 +++++++++---- .../Infrastructure/GenerateTestProps.targets | 2 +- src/ProjectTemplates/Shared/AspNetProcess.cs | 19 ++++- src/ProjectTemplates/Shared/Project.cs | 8 ++- .../Infrastructure/GenerateTestProps.targets | 2 +- src/ProjectTemplates/test/MvcTemplateTest.cs | 71 +++++++++++++++++++ 7 files changed, 159 insertions(+), 49 deletions(-) diff --git a/src/Mvc/Mvc.Core/src/ApplicationParts/RelatedAssemblyAttribute.cs b/src/Mvc/Mvc.Core/src/ApplicationParts/RelatedAssemblyAttribute.cs index 5bdfb076c0..bda87a8b3e 100644 --- a/src/Mvc/Mvc.Core/src/ApplicationParts/RelatedAssemblyAttribute.cs +++ b/src/Mvc/Mvc.Core/src/ApplicationParts/RelatedAssemblyAttribute.cs @@ -17,9 +17,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public sealed class RelatedAssemblyAttribute : Attribute { - private static readonly Func LoadFromAssemblyPathDelegate = - AssemblyLoadContext.GetLoadContext(typeof(RelatedAssemblyAttribute).Assembly).LoadFromAssemblyPath; - /// /// Initializes a new instance of . /// @@ -52,14 +49,15 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts throw new ArgumentNullException(nameof(assembly)); } - return GetRelatedAssemblies(assembly, throwOnError, File.Exists, LoadFromAssemblyPathDelegate); + var loadContext = AssemblyLoadContext.GetLoadContext(assembly) ?? AssemblyLoadContext.Default; + return GetRelatedAssemblies(assembly, throwOnError, File.Exists, new AssemblyLoadContextWrapper(loadContext)); } internal static IReadOnlyList GetRelatedAssemblies( Assembly assembly, bool throwOnError, Func fileExists, - Func loadFile) + AssemblyLoadContextWrapper assemblyLoadContext) { if (assembly == null) { @@ -95,42 +93,46 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts Resources.FormatRelatedAssemblyAttribute_AssemblyCannotReferenceSelf(nameof(RelatedAssemblyAttribute), assemblyName)); } - var relatedAssemblyName = new AssemblyName(attribute.AssemblyFileName); Assembly relatedAssembly; - try - { - // Perform a cursory check to determine if the Assembly has already been loaded - // before going to disk. In the ordinary case, related parts that are part of - // application's reference closure should already be loaded. - relatedAssembly = Assembly.Load(relatedAssemblyName); - relatedAssemblies.Add(relatedAssembly); - continue; - } - catch (IOException) - { - // The assembly isn't already loaded. Patience, we'll attempt to load it from disk next. - } - var relatedAssemblyLocation = Path.Combine(assemblyDirectory, attribute.AssemblyFileName + ".dll"); - if (!fileExists(relatedAssemblyLocation)) + if (fileExists(relatedAssemblyLocation)) { - if (throwOnError) + relatedAssembly = assemblyLoadContext.LoadFromAssemblyPath(relatedAssemblyLocation); + } + else + { + try { - throw new FileNotFoundException( - Resources.FormatRelatedAssemblyAttribute_CouldNotBeFound(attribute.AssemblyFileName, assemblyName, assemblyDirectory), - relatedAssemblyLocation); + var relatedAssemblyName = new AssemblyName(attribute.AssemblyFileName); + relatedAssembly = assemblyLoadContext.LoadFromAssemblyName(relatedAssemblyName); } - else + catch when (!throwOnError) { + // Ignore assembly load failures when throwOnError = false. continue; } } - relatedAssembly = loadFile(relatedAssemblyLocation); relatedAssemblies.Add(relatedAssembly); } return relatedAssemblies; } + + internal class AssemblyLoadContextWrapper + { + private readonly AssemblyLoadContext _loadContext; + + public AssemblyLoadContextWrapper(AssemblyLoadContext loadContext) + { + _loadContext = loadContext; + } + + public virtual Assembly LoadFromAssemblyName(AssemblyName assemblyName) + => _loadContext.LoadFromAssemblyName(assemblyName); + + public virtual Assembly LoadFromAssemblyPath(string assemblyPath) + => _loadContext.LoadFromAssemblyPath(assemblyPath); + } } } diff --git a/src/Mvc/Mvc.Core/test/ApplicationParts/RelatedAssemblyPartTest.cs b/src/Mvc/Mvc.Core/test/ApplicationParts/RelatedAssemblyPartTest.cs index 33d5e9d0e5..5e80484c66 100644 --- a/src/Mvc/Mvc.Core/test/ApplicationParts/RelatedAssemblyPartTest.cs +++ b/src/Mvc/Mvc.Core/test/ApplicationParts/RelatedAssemblyPartTest.cs @@ -1,10 +1,12 @@ -// 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. using System; +using System.Collections.Generic; using System.IO; using System.Reflection; using System.Reflection.Emit; +using System.Runtime.Loader; using Xunit; namespace Microsoft.AspNetCore.Mvc.ApplicationParts @@ -43,7 +45,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts public void GetRelatedAssemblies_ThrowsIfAssemblyCannotBeFound() { // Arrange - var expected = $"Related assembly 'DoesNotExist' specified by assembly 'MyAssembly' could not be found in the directory {AssemblyDirectory}. Related assemblies must be co-located with the specifying assemblies."; var assemblyPath = Path.Combine(AssemblyDirectory, "MyAssembly.dll"); var assembly = new TestAssembly { @@ -51,27 +52,32 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts }; // Act & Assert - var ex = Assert.Throws(() => RelatedAssemblyAttribute.GetRelatedAssemblies(assembly, throwOnError: true)); - Assert.Equal(expected, ex.Message); - Assert.Equal(Path.Combine(AssemblyDirectory, "DoesNotExist.dll"), ex.FileName); + Assert.Throws(() => RelatedAssemblyAttribute.GetRelatedAssemblies(assembly, throwOnError: true)); } [Fact] - public void GetRelatedAssemblies_LoadsRelatedAssembly() + public void GetRelatedAssemblies_ReadsAssemblyFromLoadContext_IfItAlreadyExists() { // Arrange - var destination = Path.Combine(AssemblyDirectory, "RelatedAssembly.dll"); + var expected = $"Related assembly 'DoesNotExist' specified by assembly 'MyAssembly' could not be found in the directory {AssemblyDirectory}. Related assemblies must be co-located with the specifying assemblies."; + var assemblyPath = Path.Combine(AssemblyDirectory, "MyAssembly.dll"); + var relatedAssembly = typeof(RelatedAssemblyPartTest).Assembly; var assembly = new TestAssembly { - AttributeAssembly = "RelatedAssembly", + AttributeAssembly = "RelatedAssembly" }; - var relatedAssembly = typeof(RelatedAssemblyPartTest).Assembly; - - var result = RelatedAssemblyAttribute.GetRelatedAssemblies(assembly, throwOnError: true, file => true, file => + var loadContext = new TestableAssemblyLoadContextWrapper { - Assert.Equal(file, destination); - return relatedAssembly; - }); + Assemblies = + { + ["RelatedAssembly"] = relatedAssembly, + } + }; + + // Act + var result = RelatedAssemblyAttribute.GetRelatedAssemblies(assembly, throwOnError: true, file => false, loadContext); + + // Assert Assert.Equal(new[] { relatedAssembly }, result); } @@ -94,5 +100,21 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts return new[] { attribute }; } } + + private class TestableAssemblyLoadContextWrapper : RelatedAssemblyAttribute.AssemblyLoadContextWrapper + { + public TestableAssemblyLoadContextWrapper() : base(AssemblyLoadContext.Default) + { + } + + public Dictionary Assemblies { get; } = new Dictionary(); + + public override Assembly LoadFromAssemblyPath(string assemblyPath) => throw new NotSupportedException(); + + public override Assembly LoadFromAssemblyName(AssemblyName assemblyName) + { + return Assemblies[assemblyName.Name]; + } + } } } diff --git a/src/ProjectTemplates/BlazorTemplates.Tests/Infrastructure/GenerateTestProps.targets b/src/ProjectTemplates/BlazorTemplates.Tests/Infrastructure/GenerateTestProps.targets index a97cf0dbd2..10ce80aec3 100644 --- a/src/ProjectTemplates/BlazorTemplates.Tests/Infrastructure/GenerateTestProps.targets +++ b/src/ProjectTemplates/BlazorTemplates.Tests/Infrastructure/GenerateTestProps.targets @@ -35,7 +35,7 @@ MicrosoftNETSdkRazorPackageVersion=$(MicrosoftNETSdkRazorPackageVersion); MicrosoftAspNetCoreAppRefPackageVersion=$(MicrosoftAspNetCoreAppRefPackageVersion); MicrosoftAspNetCoreAppRuntimePackageVersion=@(_RuntimePackageVersionInfo->'%(PackageVersion)'); - SupportedRuntimeIdentifiers=$(SupportedRuntimeIdentifiers); + SupportedRuntimeIdentifiers=$(SupportedRuntimeIdentifiers.Trim()); DefaultNetCoreTargetFramework=$(DefaultNetCoreTargetFramework); RepoRoot=$(RepoRoot); Configuration=$(Configuration); diff --git a/src/ProjectTemplates/Shared/AspNetProcess.cs b/src/ProjectTemplates/Shared/AspNetProcess.cs index 7412e3b369..afc34a3f30 100644 --- a/src/ProjectTemplates/Shared/AspNetProcess.cs +++ b/src/ProjectTemplates/Shared/AspNetProcess.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; using System.Net; using System.Net.Http; @@ -59,9 +60,21 @@ namespace Templates.Test.Helpers output.WriteLine("Running ASP.NET Core application..."); - var arguments = published ? $"exec {dllPath}" : "run --no-build"; + string process; + string arguments; + if (published) + { + // When publishingu used the app host to run the app. This makes it easy to consistently run for regular and single-file publish + process = OperatingSystem.IsWindows() ? dllPath + ".exe" : dllPath; + arguments = null; + } + else + { + process = DotNetMuxer.MuxerPathOrDefault(); + arguments = "run --no-build"; + } - logger?.LogInformation($"AspNetProcess - process: {DotNetMuxer.MuxerPathOrDefault()} arguments: {arguments}"); + logger?.LogInformation($"AspNetProcess - process: {process} arguments: {arguments}"); var finalEnvironmentVariables = new Dictionary(environmentVariables) { @@ -69,7 +82,7 @@ namespace Templates.Test.Helpers ["ASPNETCORE_Kestrel__Certificates__Default__Password"] = _developmentCertificate.CertificatePassword, }; - Process = ProcessEx.Run(output, workingDirectory, DotNetMuxer.MuxerPathOrDefault(), arguments, envVars: finalEnvironmentVariables); + Process = ProcessEx.Run(output, workingDirectory, process, arguments, envVars: finalEnvironmentVariables); logger?.LogInformation("AspNetProcess - process started"); diff --git a/src/ProjectTemplates/Shared/Project.cs b/src/ProjectTemplates/Shared/Project.cs index cb28d482f4..fbfeee80c4 100644 --- a/src/ProjectTemplates/Shared/Project.cs +++ b/src/ProjectTemplates/Shared/Project.cs @@ -110,14 +110,16 @@ namespace Templates.Test.Helpers } } - internal async Task RunDotNetPublishAsync(IDictionary packageOptions = null, string additionalArgs = null) + internal async Task RunDotNetPublishAsync(IDictionary packageOptions = null, string additionalArgs = null, bool noRestore = true) { Output.WriteLine("Publishing ASP.NET Core application..."); // Avoid restoring as part of build or publish. These projects should have already restored as part of running dotnet new. Explicitly disabling restore // should avoid any global contention and we can execute a build or publish in a lock-free way - using var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), $"publish --no-restore -c Release /bl {additionalArgs}", packageOptions); + var restoreArgs = noRestore ? "--no-restore" : null; + + using var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), $"publish {restoreArgs} -c Release /bl {additionalArgs}", packageOptions); await result.Exited; CaptureBinLogOnFailure(result); return new ProcessResult(result); @@ -188,7 +190,7 @@ namespace Templates.Test.Helpers ["ASPNETCORE_Logging__Console__FormatterOptions__IncludeScopes"] = "true", }; - var projectDll = $"{ProjectName}.dll"; + var projectDll = Path.Combine(TemplatePublishDir, ProjectName); return new AspNetProcess(Output, TemplatePublishDir, projectDll, environment, published: true, hasListeningUri: hasListeningUri); } diff --git a/src/ProjectTemplates/test/Infrastructure/GenerateTestProps.targets b/src/ProjectTemplates/test/Infrastructure/GenerateTestProps.targets index a97cf0dbd2..10ce80aec3 100644 --- a/src/ProjectTemplates/test/Infrastructure/GenerateTestProps.targets +++ b/src/ProjectTemplates/test/Infrastructure/GenerateTestProps.targets @@ -35,7 +35,7 @@ MicrosoftNETSdkRazorPackageVersion=$(MicrosoftNETSdkRazorPackageVersion); MicrosoftAspNetCoreAppRefPackageVersion=$(MicrosoftAspNetCoreAppRefPackageVersion); MicrosoftAspNetCoreAppRuntimePackageVersion=@(_RuntimePackageVersionInfo->'%(PackageVersion)'); - SupportedRuntimeIdentifiers=$(SupportedRuntimeIdentifiers); + SupportedRuntimeIdentifiers=$(SupportedRuntimeIdentifiers.Trim()); DefaultNetCoreTargetFramework=$(DefaultNetCoreTargetFramework); RepoRoot=$(RepoRoot); Configuration=$(Configuration); diff --git a/src/ProjectTemplates/test/MvcTemplateTest.cs b/src/ProjectTemplates/test/MvcTemplateTest.cs index 15a1c87300..9136d26717 100644 --- a/src/ProjectTemplates/test/MvcTemplateTest.cs +++ b/src/ProjectTemplates/test/MvcTemplateTest.cs @@ -223,6 +223,77 @@ namespace Templates.Test } } + [ConditionalFact] + [SkipOnHelix("cert failure", Queues = "OSX.1014.Amd64;OSX.1014.Amd64.Open")] + public async Task MvcTemplate_SingleFileExe() + { + // This test verifies publishing an MVC app as a single file exe works. We'll limit testing + // this to a few operating systems to make our lives easier. + string runtimeIdentifer; + if (OperatingSystem.IsWindows()) + { + runtimeIdentifer = "win-x64"; + } + else if (OperatingSystem.IsLinux()) + { + runtimeIdentifer = "linux-x64"; + } + else + { + return; + } + + Project = await ProjectFactory.GetOrCreateProject("mvcindividualuld", Output); + Project.RuntimeIdentifier = runtimeIdentifer; + + var createResult = await Project.RunDotNetNewAsync("mvc", auth: "Individual", useLocalDB: true); + Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult)); + + var publishResult = await Project.RunDotNetPublishAsync(additionalArgs: $"/p:PublishSingleFile=true -r {runtimeIdentifer}", noRestore: false); + Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult)); + + var pages = new[] + { + new Page + { + // Verify a view from the app works + Url = PageUrls.HomeUrl, + Links = new [] + { + PageUrls.HomeUrl, + PageUrls.RegisterUrl, + PageUrls.LoginUrl, + PageUrls.HomeUrl, + PageUrls.PrivacyUrl, + PageUrls.DocsUrl, + PageUrls.PrivacyUrl + } + }, + new Page + { + // Verify a view from a RCL (in this case IdentityUI) works + Url = PageUrls.RegisterUrl, + Links = new [] + { + PageUrls.HomeUrl, + PageUrls.RegisterUrl, + PageUrls.LoginUrl, + PageUrls.HomeUrl, + PageUrls.PrivacyUrl, + PageUrls.ExternalArticle, + PageUrls.PrivacyUrl + } + }, + }; + + using var aspNetProcess = Project.StartPublishedProjectAsync(); + Assert.False( + aspNetProcess.Process.HasExited, + ErrorMessages.GetFailedProcessMessageOrEmpty("Run published project", Project, aspNetProcess.Process)); + + await aspNetProcess.AssertPagesOk(pages); + } + [Fact] [QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/23993")] public async Task MvcTemplate_RazorRuntimeCompilation_BuildsAndPublishes() From 24f26e7b6abfed1b4c0059093a35e1b304a00740 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Tue, 18 Aug 2020 18:25:51 -0700 Subject: [PATCH 08/81] React to runtime release branch rename (#25026) --- .github/workflows/runtime-sync.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/runtime-sync.yml b/.github/workflows/runtime-sync.yml index 41044d30ee..03e7e8f9d6 100644 --- a/.github/workflows/runtime-sync.yml +++ b/.github/workflows/runtime-sync.yml @@ -28,7 +28,7 @@ jobs: # Test this script using changes in a fork repository: 'dotnet/runtime' path: runtime - ref: release/5.0-rc1 + ref: release/5.0 - name: Copy shell: cmd working-directory: .\runtime\src\libraries\Common\src\System\Net\Http\aspnetcore\ From 6a3887aba864a30473f0252e0d3c24850580c8bd Mon Sep 17 00:00:00 2001 From: Mackinnon Buck Date: Tue, 18 Aug 2020 20:15:50 -0700 Subject: [PATCH 09/81] Make Virtualize behave correctly with when ItemSize is unspecified or wrong. (#24920) --- .../Web.JS/dist/Release/blazor.server.js | 2 +- .../Web.JS/dist/Release/blazor.webassembly.js | 2 +- src/Components/Web.JS/src/Virtualize.ts | 5 +- .../Virtualization/IVirtualizeJsCallbacks.cs | 4 +- .../src/Virtualization/PlaceholderContext.cs | 13 +++- .../Web/src/Virtualization/Virtualize.cs | 64 ++++++++++++++----- .../src/Virtualization/VirtualizeJsInterop.cs | 8 +-- .../Web/test/Virtualization/VirtualizeTest.cs | 2 +- .../VirtualizationComponent.razor | 2 +- 9 files changed, 74 insertions(+), 28 deletions(-) diff --git a/src/Components/Web.JS/dist/Release/blazor.server.js b/src/Components/Web.JS/dist/Release/blazor.server.js index 2b195f22b8..d665ed7c5f 100644 --- a/src/Components/Web.JS/dist/Release/blazor.server.js +++ b/src/Components/Web.JS/dist/Release/blazor.server.js @@ -5,7 +5,7 @@ * @author Feross Aboukhadijeh * @license MIT */ -var r=n(51),o=n(52),i=n(53);function a(){return c.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function s(e,t){if(a()=a())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+a().toString(16)+" bytes");return 0|e}function d(e,t){if(c.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var n=e.length;if(0===n)return 0;for(var r=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":case void 0:return F(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return H(e).length;default:if(r)return F(e).length;t=(""+t).toLowerCase(),r=!0}}function g(e,t,n){var r=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if((n>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return x(this,t,n);case"utf8":case"utf-8":return k(this,t,n);case"ascii":return T(this,t,n);case"latin1":case"binary":return P(this,t,n);case"base64":return _(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return O(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}function y(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function v(e,t,n,r,o){if(0===e.length)return-1;if("string"==typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,isNaN(n)&&(n=o?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(o)return-1;n=e.length-1}else if(n<0){if(!o)return-1;n=0}if("string"==typeof t&&(t=c.from(t,r)),c.isBuffer(t))return 0===t.length?-1:b(e,t,n,r,o);if("number"==typeof t)return t&=255,c.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?o?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):b(e,[t],n,r,o);throw new TypeError("val must be string, number or Buffer")}function b(e,t,n,r,o){var i,a=1,s=e.length,c=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;a=2,s/=2,c/=2,n/=2}function u(e,t){return 1===a?e[t]:e.readUInt16BE(t*a)}if(o){var l=-1;for(i=n;is&&(n=s-c),i=n;i>=0;i--){for(var f=!0,h=0;ho&&(r=o):r=o;var i=t.length;if(i%2!=0)throw new TypeError("Invalid hex string");r>i/2&&(r=i/2);for(var a=0;a>8,o=n%256,i.push(o),i.push(r);return i}(t,e.length-n),e,n,r)}function _(e,t,n){return 0===t&&n===e.length?r.fromByteArray(e):r.fromByteArray(e.slice(t,n))}function k(e,t,n){n=Math.min(e.length,n);for(var r=[],o=t;o239?4:u>223?3:u>191?2:1;if(o+f<=n)switch(f){case 1:u<128&&(l=u);break;case 2:128==(192&(i=e[o+1]))&&(c=(31&u)<<6|63&i)>127&&(l=c);break;case 3:i=e[o+1],a=e[o+2],128==(192&i)&&128==(192&a)&&(c=(15&u)<<12|(63&i)<<6|63&a)>2047&&(c<55296||c>57343)&&(l=c);break;case 4:i=e[o+1],a=e[o+2],s=e[o+3],128==(192&i)&&128==(192&a)&&128==(192&s)&&(c=(15&u)<<18|(63&i)<<12|(63&a)<<6|63&s)>65535&&c<1114112&&(l=c)}null===l?(l=65533,f=1):l>65535&&(l-=65536,r.push(l>>>10&1023|55296),l=56320|1023&l),r.push(l),o+=f}return function(e){var t=e.length;if(t<=4096)return String.fromCharCode.apply(String,e);var n="",r=0;for(;r0&&(e=this.toString("hex",0,n).match(/.{2}/g).join(" "),this.length>n&&(e+=" ... ")),""},c.prototype.compare=function(e,t,n,r,o){if(!c.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===o&&(o=this.length),t<0||n>e.length||r<0||o>this.length)throw new RangeError("out of range index");if(r>=o&&t>=n)return 0;if(r>=o)return-1;if(t>=n)return 1;if(this===e)return 0;for(var i=(o>>>=0)-(r>>>=0),a=(n>>>=0)-(t>>>=0),s=Math.min(i,a),u=this.slice(r,o),l=e.slice(t,n),f=0;fo)&&(n=o),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var i=!1;;)switch(r){case"hex":return m(this,e,t,n);case"utf8":case"utf-8":return w(this,e,t,n);case"ascii":return E(this,e,t,n);case"latin1":case"binary":return S(this,e,t,n);case"base64":return C(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return I(this,e,t,n);default:if(i)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),i=!0}},c.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};function T(e,t,n){var r="";n=Math.min(e.length,n);for(var o=t;or)&&(n=r);for(var o="",i=t;in)throw new RangeError("Trying to access beyond buffer length")}function L(e,t,n,r,o,i){if(!c.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>o||te.length)throw new RangeError("Index out of range")}function D(e,t,n,r){t<0&&(t=65535+t+1);for(var o=0,i=Math.min(e.length-n,2);o>>8*(r?o:1-o)}function M(e,t,n,r){t<0&&(t=4294967295+t+1);for(var o=0,i=Math.min(e.length-n,4);o>>8*(r?o:3-o)&255}function j(e,t,n,r,o,i){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function A(e,t,n,r,i){return i||j(e,0,n,4),o.write(e,t,n,r,23,4),n+4}function B(e,t,n,r,i){return i||j(e,0,n,8),o.write(e,t,n,r,52,8),n+8}c.prototype.slice=function(e,t){var n,r=this.length;if((e=~~e)<0?(e+=r)<0&&(e=0):e>r&&(e=r),(t=void 0===t?r:~~t)<0?(t+=r)<0&&(t=0):t>r&&(t=r),t0&&(o*=256);)r+=this[e+--t]*o;return r},c.prototype.readUInt8=function(e,t){return t||R(e,1,this.length),this[e]},c.prototype.readUInt16LE=function(e,t){return t||R(e,2,this.length),this[e]|this[e+1]<<8},c.prototype.readUInt16BE=function(e,t){return t||R(e,2,this.length),this[e]<<8|this[e+1]},c.prototype.readUInt32LE=function(e,t){return t||R(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},c.prototype.readUInt32BE=function(e,t){return t||R(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},c.prototype.readIntLE=function(e,t,n){e|=0,t|=0,n||R(e,t,this.length);for(var r=this[e],o=1,i=0;++i=(o*=128)&&(r-=Math.pow(2,8*t)),r},c.prototype.readIntBE=function(e,t,n){e|=0,t|=0,n||R(e,t,this.length);for(var r=t,o=1,i=this[e+--r];r>0&&(o*=256);)i+=this[e+--r]*o;return i>=(o*=128)&&(i-=Math.pow(2,8*t)),i},c.prototype.readInt8=function(e,t){return t||R(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},c.prototype.readInt16LE=function(e,t){t||R(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},c.prototype.readInt16BE=function(e,t){t||R(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},c.prototype.readInt32LE=function(e,t){return t||R(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},c.prototype.readInt32BE=function(e,t){return t||R(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},c.prototype.readFloatLE=function(e,t){return t||R(e,4,this.length),o.read(this,e,!0,23,4)},c.prototype.readFloatBE=function(e,t){return t||R(e,4,this.length),o.read(this,e,!1,23,4)},c.prototype.readDoubleLE=function(e,t){return t||R(e,8,this.length),o.read(this,e,!0,52,8)},c.prototype.readDoubleBE=function(e,t){return t||R(e,8,this.length),o.read(this,e,!1,52,8)},c.prototype.writeUIntLE=function(e,t,n,r){(e=+e,t|=0,n|=0,r)||L(this,e,t,n,Math.pow(2,8*n)-1,0);var o=1,i=0;for(this[t]=255&e;++i=0&&(i*=256);)this[t+o]=e/i&255;return t+n},c.prototype.writeUInt8=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,1,255,0),c.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},c.prototype.writeUInt16LE=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,2,65535,0),c.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):D(this,e,t,!0),t+2},c.prototype.writeUInt16BE=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,2,65535,0),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):D(this,e,t,!1),t+2},c.prototype.writeUInt32LE=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,4,4294967295,0),c.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):M(this,e,t,!0),t+4},c.prototype.writeUInt32BE=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,4,4294967295,0),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):M(this,e,t,!1),t+4},c.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);L(this,e,t,n,o-1,-o)}var i=0,a=1,s=0;for(this[t]=255&e;++i>0)-s&255;return t+n},c.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);L(this,e,t,n,o-1,-o)}var i=n-1,a=1,s=0;for(this[t+i]=255&e;--i>=0&&(a*=256);)e<0&&0===s&&0!==this[t+i+1]&&(s=1),this[t+i]=(e/a>>0)-s&255;return t+n},c.prototype.writeInt8=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,1,127,-128),c.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},c.prototype.writeInt16LE=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,2,32767,-32768),c.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):D(this,e,t,!0),t+2},c.prototype.writeInt16BE=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,2,32767,-32768),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):D(this,e,t,!1),t+2},c.prototype.writeInt32LE=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,4,2147483647,-2147483648),c.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):M(this,e,t,!0),t+4},c.prototype.writeInt32BE=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):M(this,e,t,!1),t+4},c.prototype.writeFloatLE=function(e,t,n){return A(this,e,t,!0,n)},c.prototype.writeFloatBE=function(e,t,n){return A(this,e,t,!1,n)},c.prototype.writeDoubleLE=function(e,t,n){return B(this,e,t,!0,n)},c.prototype.writeDoubleBE=function(e,t,n){return B(this,e,t,!1,n)},c.prototype.copy=function(e,t,n,r){if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw new RangeError("sourceStart out of bounds");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t=0;--o)e[o+t]=this[o+n];else if(i<1e3||!c.TYPED_ARRAY_SUPPORT)for(o=0;o>>=0,n=void 0===n?this.length:n>>>0,e||(e=0),"number"==typeof e)for(i=t;i55295&&n<57344){if(!o){if(n>56319){(t-=3)>-1&&i.push(239,191,189);continue}if(a+1===r){(t-=3)>-1&&i.push(239,191,189);continue}o=n;continue}if(n<56320){(t-=3)>-1&&i.push(239,191,189),o=n;continue}n=65536+(o-55296<<10|n-56320)}else o&&(t-=3)>-1&&i.push(239,191,189);if(o=null,n<128){if((t-=1)<0)break;i.push(n)}else if(n<2048){if((t-=2)<0)break;i.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;i.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;i.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return i}function H(e){return r.toByteArray(function(e){if((e=function(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}(e).replace(N,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function q(e,t,n,r){for(var o=0;o=t.length||o>=e.length);++o)t[o+n]=e[o];return o}}).call(this,n(8))},function(e,t,n){"use strict";var r=n(14).Buffer,o=n(54),i=n(20),a=n(67),s=n(70),c=n(71);e.exports=function(e){var t=[],n=[];return{encode:c(t,(e=e||{forceFloat64:!1,compatibilityMode:!1,disableTimestampEncoding:!1}).forceFloat64,e.compatibilityMode,e.disableTimestampEncoding),decode:s(n),register:function(e,t,n,a){return o(t,"must have a constructor"),o(n,"must have an encode function"),o(e>=0,"must have a non-negative type"),o(a,"must have a decode function"),this.registerEncoder((function(e){return e instanceof t}),(function(t){var o=i(),a=r.allocUnsafe(1);return a.writeInt8(e,0),o.append(a),o.append(n(t)),o})),this.registerDecoder(e,a),this},registerEncoder:function(e,n){return o(e,"must have an encode function"),o(n,"must have an encode function"),t.push({check:e,encode:n}),this},registerDecoder:function(e,t){return o(e>=0,"must have a non-negative type"),o(t,"must have a decode function"),n.push({type:e,decode:t}),this},encoder:a.encoder,decoder:a.decoder,buffer:!0,type:"msgpack5",IncompleteBufferError:s.IncompleteBufferError}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=p("_blazorLogicalChildren"),o=p("_blazorLogicalParent"),i=p("_blazorLogicalEnd");function a(e,t){if(e.childNodes.length>0&&!t)throw new Error("New logical elements must start empty, or allowExistingContents must be true");return r in e||(e[r]=[]),e}function s(e,t,n){var i=e;if(e instanceof Comment&&(u(i)&&u(i).length>0))throw new Error("Not implemented: inserting non-empty logical container");if(c(i))throw new Error("Not implemented: moving existing logical children");var a=u(t);if(n0;)e(r,0)}var i=r;i.parentNode.removeChild(i)},t.getLogicalParent=c,t.getLogicalSiblingEnd=function(e){return e[i]||null},t.getLogicalChild=function(e,t){return u(e)[t]},t.isSvgElement=function(e){return"http://www.w3.org/2000/svg"===l(e).namespaceURI},t.getLogicalChildrenArray=u,t.permuteLogicalChildren=function(e,t){var n=u(e);t.forEach((function(e){e.moveRangeStart=n[e.fromSiblingIndex],e.moveRangeEnd=function e(t){if(t instanceof Element)return t;var n=f(t);if(n)return n.previousSibling;var r=c(t);return r instanceof Element?r.lastChild:e(r)}(e.moveRangeStart)})),t.forEach((function(t){var r=t.moveToBeforeMarker=document.createComment("marker"),o=n[t.toSiblingIndex+1];o?o.parentNode.insertBefore(r,o):h(r,e)})),t.forEach((function(e){for(var t=e.moveToBeforeMarker,n=t.parentNode,r=e.moveRangeStart,o=e.moveRangeEnd,i=r;i;){var a=i.nextSibling;if(n.insertBefore(i,t),i===o)break;i=a}n.removeChild(t)})),t.forEach((function(e){n[e.toSiblingIndex]=e.moveRangeStart}))},t.getClosestDomElement=l},function(e,t){var n,r,o=e.exports={};function i(){throw new Error("setTimeout has not been defined")}function a(){throw new Error("clearTimeout has not been defined")}function s(e){if(n===setTimeout)return setTimeout(e,0);if((n===i||!n)&&setTimeout)return n=setTimeout,setTimeout(e,0);try{return n(e,0)}catch(t){try{return n.call(null,e,0)}catch(t){return n.call(this,e,0)}}}!function(){try{n="function"==typeof setTimeout?setTimeout:i}catch(e){n=i}try{r="function"==typeof clearTimeout?clearTimeout:a}catch(e){r=a}}();var c,u=[],l=!1,f=-1;function h(){l&&c&&(l=!1,c.length?u=c.concat(u):f=-1,u.length&&p())}function p(){if(!l){var e=s(h);l=!0;for(var t=u.length;t;){for(c=u,u=[];++f1)for(var n=1;nthis.length)&&(r=this.length),n>=this.length)return e||i.alloc(0);if(r<=0)return e||i.alloc(0);var o,a,s=!!e,c=this._offset(n),u=r-n,l=u,f=s&&t||0,h=c[1];if(0===n&&r==this.length){if(!s)return 1===this._bufs.length?this._bufs[0]:i.concat(this._bufs,this.length);for(a=0;a(o=this._bufs[a].length-h))){this._bufs[a].copy(e,f,h,h+l);break}this._bufs[a].copy(e,f,h),f+=o,l-=o,h&&(h=0)}return e},a.prototype.shallowSlice=function(e,t){e=e||0,t=t||this.length,e<0&&(e+=this.length),t<0&&(t+=this.length);var n=this._offset(e),r=this._offset(t),o=this._bufs.slice(n[0],r[0]+1);return 0==r[1]?o.pop():o[o.length-1]=o[o.length-1].slice(0,r[1]),0!=n[1]&&(o[0]=o[0].slice(n[1])),new a(o)},a.prototype.toString=function(e,t,n){return this.slice(t,n).toString(e)},a.prototype.consume=function(e){for(;this._bufs.length;){if(!(e>=this._bufs[0].length)){this._bufs[0]=this._bufs[0].slice(e),this.length-=e;break}e-=this._bufs[0].length,this.length-=this._bufs[0].length,this._bufs.shift()}return this},a.prototype.duplicate=function(){for(var e=0,t=new a;e0&&e.invokeMethodAsync("OnSpacerAfterVisible",r.boundingClientRect.bottom-r.intersectionRect.bottom,i)}}))}),{root:o(t),rootMargin:i+"px"});a.observe(t),a.observe(n);var s=u(t),c=u(n);function u(e){var t=new MutationObserver((function(){a.unobserve(e),a.observe(e)}));return t.observe(e,{attributes:!0}),t}r[e._id]={intersectionObserver:a,mutationObserverBefore:s,mutationObserverAfter:c}},dispose:function(e){var t=r[e._id];t&&(t.intersectionObserver.disconnect(),t.mutationObserverBefore.disconnect(),t.mutationObserverAfter.disconnect(),e.dispose(),delete r[e._id])}};var r={};function o(e){return e?"visible"!==getComputedStyle(e).overflowY?e:o(e.parentElement):null}},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,i){function a(e){try{c(r.next(e))}catch(e){i(e)}}function s(e){try{c(r.throw(e))}catch(e){i(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}c((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,i,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function s(i){return function(s){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return a.label++,{value:i[1],done:!1};case 5:a.label++,r=i[1],i=[0];continue;case 7:i=a.ops.pop(),a.trys.pop();continue;default:if(!(o=a.trys,(o=o.length>0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]=i)return e;switch(e){case"%s":return String(r[n++]);case"%d":return Number(r[n++]);case"%j":try{return JSON.stringify(r[n++])}catch(e){return"[Circular]"}default:return e}})),c=r[n];n=3&&(r.depth=arguments[2]),arguments.length>=4&&(r.colors=arguments[3]),d(n)?r.showHidden=n:n&&t._extend(r,n),b(r.showHidden)&&(r.showHidden=!1),b(r.depth)&&(r.depth=2),b(r.colors)&&(r.colors=!1),b(r.customInspect)&&(r.customInspect=!0),r.colors&&(r.stylize=c),l(r,e,r.depth)}function c(e,t){var n=s.styles[t];return n?"["+s.colors[n][0]+"m"+e+"["+s.colors[n][1]+"m":e}function u(e,t){return e}function l(e,n,r){if(e.customInspect&&n&&C(n.inspect)&&n.inspect!==t.inspect&&(!n.constructor||n.constructor.prototype!==n)){var o=n.inspect(r,e);return v(o)||(o=l(e,o,r)),o}var i=function(e,t){if(b(t))return e.stylize("undefined","undefined");if(v(t)){var n="'"+JSON.stringify(t).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return e.stylize(n,"string")}if(y(t))return e.stylize(""+t,"number");if(d(t))return e.stylize(""+t,"boolean");if(g(t))return e.stylize("null","null")}(e,n);if(i)return i;var a=Object.keys(n),s=function(e){var t={};return e.forEach((function(e,n){t[e]=!0})),t}(a);if(e.showHidden&&(a=Object.getOwnPropertyNames(n)),S(n)&&(a.indexOf("message")>=0||a.indexOf("description")>=0))return f(n);if(0===a.length){if(C(n)){var c=n.name?": "+n.name:"";return e.stylize("[Function"+c+"]","special")}if(m(n))return e.stylize(RegExp.prototype.toString.call(n),"regexp");if(E(n))return e.stylize(Date.prototype.toString.call(n),"date");if(S(n))return f(n)}var u,w="",I=!1,_=["{","}"];(p(n)&&(I=!0,_=["[","]"]),C(n))&&(w=" [Function"+(n.name?": "+n.name:"")+"]");return m(n)&&(w=" "+RegExp.prototype.toString.call(n)),E(n)&&(w=" "+Date.prototype.toUTCString.call(n)),S(n)&&(w=" "+f(n)),0!==a.length||I&&0!=n.length?r<0?m(n)?e.stylize(RegExp.prototype.toString.call(n),"regexp"):e.stylize("[Object]","special"):(e.seen.push(n),u=I?function(e,t,n,r,o){for(var i=[],a=0,s=t.length;a=0&&0,e+t.replace(/\u001b\[\d\d?m/g,"").length+1}),0)>60)return n[0]+(""===t?"":t+"\n ")+" "+e.join(",\n ")+" "+n[1];return n[0]+t+" "+e.join(", ")+" "+n[1]}(u,w,_)):_[0]+w+_[1]}function f(e){return"["+Error.prototype.toString.call(e)+"]"}function h(e,t,n,r,o,i){var a,s,c;if((c=Object.getOwnPropertyDescriptor(t,o)||{value:t[o]}).get?s=c.set?e.stylize("[Getter/Setter]","special"):e.stylize("[Getter]","special"):c.set&&(s=e.stylize("[Setter]","special")),P(r,o)||(a="["+o+"]"),s||(e.seen.indexOf(c.value)<0?(s=g(n)?l(e,c.value,null):l(e,c.value,n-1)).indexOf("\n")>-1&&(s=i?s.split("\n").map((function(e){return" "+e})).join("\n").substr(2):"\n"+s.split("\n").map((function(e){return" "+e})).join("\n")):s=e.stylize("[Circular]","special")),b(a)){if(i&&o.match(/^\d+$/))return s;(a=JSON.stringify(""+o)).match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(a=a.substr(1,a.length-2),a=e.stylize(a,"name")):(a=a.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),a=e.stylize(a,"string"))}return a+": "+s}function p(e){return Array.isArray(e)}function d(e){return"boolean"==typeof e}function g(e){return null===e}function y(e){return"number"==typeof e}function v(e){return"string"==typeof e}function b(e){return void 0===e}function m(e){return w(e)&&"[object RegExp]"===I(e)}function w(e){return"object"==typeof e&&null!==e}function E(e){return w(e)&&"[object Date]"===I(e)}function S(e){return w(e)&&("[object Error]"===I(e)||e instanceof Error)}function C(e){return"function"==typeof e}function I(e){return Object.prototype.toString.call(e)}function _(e){return e<10?"0"+e.toString(10):e.toString(10)}t.debuglog=function(n){if(b(i)&&(i=e.env.NODE_DEBUG||""),n=n.toUpperCase(),!a[n])if(new RegExp("\\b"+n+"\\b","i").test(i)){var r=e.pid;a[n]=function(){var e=t.format.apply(t,arguments);console.error("%s %d: %s",n,r,e)}}else a[n]=function(){};return a[n]},t.inspect=s,s.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]},s.styles={special:"cyan",number:"yellow",boolean:"yellow",undefined:"grey",null:"bold",string:"green",date:"magenta",regexp:"red"},t.isArray=p,t.isBoolean=d,t.isNull=g,t.isNullOrUndefined=function(e){return null==e},t.isNumber=y,t.isString=v,t.isSymbol=function(e){return"symbol"==typeof e},t.isUndefined=b,t.isRegExp=m,t.isObject=w,t.isDate=E,t.isError=S,t.isFunction=C,t.isPrimitive=function(e){return null===e||"boolean"==typeof e||"number"==typeof e||"string"==typeof e||"symbol"==typeof e||void 0===e},t.isBuffer=n(56);var k=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function T(){var e=new Date,t=[_(e.getHours()),_(e.getMinutes()),_(e.getSeconds())].join(":");return[e.getDate(),k[e.getMonth()],t].join(" ")}function P(e,t){return Object.prototype.hasOwnProperty.call(e,t)}t.log=function(){console.log("%s - %s",T(),t.format.apply(t,arguments))},t.inherits=n(57),t._extend=function(e,t){if(!t||!w(t))return e;for(var n=Object.keys(t),r=n.length;r--;)e[n[r]]=t[n[r]];return e};var x="undefined"!=typeof Symbol?Symbol("util.promisify.custom"):void 0;function O(e,t){if(!e){var n=new Error("Promise was rejected with a falsy value");n.reason=e,e=n}return t(e)}t.promisify=function(e){if("function"!=typeof e)throw new TypeError('The "original" argument must be of type Function');if(x&&e[x]){var t;if("function"!=typeof(t=e[x]))throw new TypeError('The "util.promisify.custom" argument must be of type Function');return Object.defineProperty(t,x,{value:t,enumerable:!1,writable:!1,configurable:!0}),t}function t(){for(var t,n,r=new Promise((function(e,r){t=e,n=r})),o=[],i=0;i0?("string"==typeof t||a.objectMode||Object.getPrototypeOf(t)===u.prototype||(t=function(e){return u.from(e)}(t)),r?a.endEmitted?e.emit("error",new Error("stream.unshift() after end event")):E(e,a,t,!0):a.ended?e.emit("error",new Error("stream.push() after EOF")):(a.reading=!1,a.decoder&&!n?(t=a.decoder.write(t),a.objectMode||0!==t.length?E(e,a,t,!1):_(e,a)):E(e,a,t,!1))):r||(a.reading=!1));return function(e){return!e.ended&&(e.needReadable||e.lengtht.highWaterMark&&(t.highWaterMark=function(e){return e>=8388608?e=8388608:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}function C(e){var t=e._readableState;t.needReadable=!1,t.emittedReadable||(p("emitReadable",t.flowing),t.emittedReadable=!0,t.sync?o.nextTick(I,e):I(e))}function I(e){p("emit readable"),e.emit("readable"),x(e)}function _(e,t){t.readingMore||(t.readingMore=!0,o.nextTick(k,e,t))}function k(e,t){for(var n=t.length;!t.reading&&!t.flowing&&!t.ended&&t.length=t.length?(n=t.decoder?t.buffer.join(""):1===t.buffer.length?t.buffer.head.data:t.buffer.concat(t.length),t.buffer.clear()):n=function(e,t,n){var r;ei.length?i.length:e;if(a===i.length?o+=i:o+=i.slice(0,e),0===(e-=a)){a===i.length?(++r,n.next?t.head=n.next:t.head=t.tail=null):(t.head=n,n.data=i.slice(a));break}++r}return t.length-=r,o}(e,t):function(e,t){var n=u.allocUnsafe(e),r=t.head,o=1;r.data.copy(n),e-=r.data.length;for(;r=r.next;){var i=r.data,a=e>i.length?i.length:e;if(i.copy(n,n.length-e,0,a),0===(e-=a)){a===i.length?(++o,r.next?t.head=r.next:t.head=t.tail=null):(t.head=r,r.data=i.slice(a));break}++o}return t.length-=o,n}(e,t);return r}(e,t.buffer,t.decoder),n);var n}function R(e){var t=e._readableState;if(t.length>0)throw new Error('"endReadable()" called on non-empty stream');t.endEmitted||(t.ended=!0,o.nextTick(L,t,e))}function L(e,t){e.endEmitted||0!==e.length||(e.endEmitted=!0,t.readable=!1,t.emit("end"))}function D(e,t){for(var n=0,r=e.length;n=t.highWaterMark||t.ended))return p("read: emitReadable",t.length,t.ended),0===t.length&&t.ended?R(this):C(this),null;if(0===(e=S(e,t))&&t.ended)return 0===t.length&&R(this),null;var r,o=t.needReadable;return p("need readable",o),(0===t.length||t.length-e0?O(e,t):null)?(t.needReadable=!0,e=0):t.length-=e,0===t.length&&(t.ended||(t.needReadable=!0),n!==e&&t.ended&&R(this)),null!==r&&this.emit("data",r),r},m.prototype._read=function(e){this.emit("error",new Error("_read() is not implemented"))},m.prototype.pipe=function(e,t){var n=this,i=this._readableState;switch(i.pipesCount){case 0:i.pipes=e;break;case 1:i.pipes=[i.pipes,e];break;default:i.pipes.push(e)}i.pipesCount+=1,p("pipe count=%d opts=%j",i.pipesCount,t);var c=(!t||!1!==t.end)&&e!==r.stdout&&e!==r.stderr?l:m;function u(t,r){p("onunpipe"),t===n&&r&&!1===r.hasUnpiped&&(r.hasUnpiped=!0,p("cleanup"),e.removeListener("close",v),e.removeListener("finish",b),e.removeListener("drain",f),e.removeListener("error",y),e.removeListener("unpipe",u),n.removeListener("end",l),n.removeListener("end",m),n.removeListener("data",g),h=!0,!i.awaitDrain||e._writableState&&!e._writableState.needDrain||f())}function l(){p("onend"),e.end()}i.endEmitted?o.nextTick(c):n.once("end",c),e.on("unpipe",u);var f=function(e){return function(){var t=e._readableState;p("pipeOnDrain",t.awaitDrain),t.awaitDrain&&t.awaitDrain--,0===t.awaitDrain&&s(e,"data")&&(t.flowing=!0,x(e))}}(n);e.on("drain",f);var h=!1;var d=!1;function g(t){p("ondata"),d=!1,!1!==e.write(t)||d||((1===i.pipesCount&&i.pipes===e||i.pipesCount>1&&-1!==D(i.pipes,e))&&!h&&(p("false write response, pause",n._readableState.awaitDrain),n._readableState.awaitDrain++,d=!0),n.pause())}function y(t){p("onerror",t),m(),e.removeListener("error",y),0===s(e,"error")&&e.emit("error",t)}function v(){e.removeListener("finish",b),m()}function b(){p("onfinish"),e.removeListener("close",v),m()}function m(){p("unpipe"),n.unpipe(e)}return n.on("data",g),function(e,t,n){if("function"==typeof e.prependListener)return e.prependListener(t,n);e._events&&e._events[t]?a(e._events[t])?e._events[t].unshift(n):e._events[t]=[n,e._events[t]]:e.on(t,n)}(e,"error",y),e.once("close",v),e.once("finish",b),e.emit("pipe",n),i.flowing||(p("pipe resume"),n.resume()),e},m.prototype.unpipe=function(e){var t=this._readableState,n={hasUnpiped:!1};if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes||(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,n)),this;if(!e){var r=t.pipes,o=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var i=0;i0&&a.length>o&&!a.warned){a.warned=!0;var c=new Error("Possible EventEmitter memory leak detected. "+a.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");c.name="MaxListenersExceededWarning",c.emitter=e,c.type=t,c.count=a.length,s=c,console&&console.warn&&console.warn(s)}return e}function h(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function p(e,t,n){var r={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},o=h.bind(r);return o.listener=n,r.wrapFn=o,o}function d(e,t,n){var r=e._events;if(void 0===r)return[];var o=r[t];return void 0===o?[]:"function"==typeof o?n?[o.listener||o]:[o]:n?function(e){for(var t=new Array(e.length),n=0;n0&&(a=t[0]),a instanceof Error)throw a;var s=new Error("Unhandled error."+(a?" ("+a.message+")":""));throw s.context=a,s}var c=o[e];if(void 0===c)return!1;if("function"==typeof c)i(c,this,t);else{var u=c.length,l=y(c,u);for(n=0;n=0;i--)if(n[i]===t||n[i].listener===t){a=n[i].listener,o=i;break}if(o<0)return this;0===o?n.shift():function(e,t){for(;t+1=0;r--)this.removeListener(e,t[r]);return this},s.prototype.listeners=function(e){return d(this,e,!0)},s.prototype.rawListeners=function(e){return d(this,e,!1)},s.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):g.call(e,t)},s.prototype.listenerCount=g,s.prototype.eventNames=function(){return this._eventsCount>0?r(this._events):[]}},function(e,t,n){e.exports=n(36).EventEmitter},function(e,t,n){"use strict";var r=n(21);function o(e,t){e.emit("error",t)}e.exports={destroy:function(e,t){var n=this,i=this._readableState&&this._readableState.destroyed,a=this._writableState&&this._writableState.destroyed;return i||a?(t?t(e):!e||this._writableState&&this._writableState.errorEmitted||r.nextTick(o,this,e),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(e||null,(function(e){!t&&e?(r.nextTick(o,n,e),n._writableState&&(n._writableState.errorEmitted=!0)):t&&t(e)})),this)},undestroy:function(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}}},function(e,t,n){"use strict";var r=n(63).Buffer,o=r.isEncoding||function(e){switch((e=""+e)&&e.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};function i(e){var t;switch(this.encoding=function(e){var t=function(e){if(!e)return"utf8";for(var t;;)switch(e){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return e;default:if(t)return;e=(""+e).toLowerCase(),t=!0}}(e);if("string"!=typeof t&&(r.isEncoding===o||!o(e)))throw new Error("Unknown encoding: "+e);return t||e}(e),this.encoding){case"utf16le":this.text=c,this.end=u,t=4;break;case"utf8":this.fillLast=s,t=4;break;case"base64":this.text=l,this.end=f,t=3;break;default:return this.write=h,void(this.end=p)}this.lastNeed=0,this.lastTotal=0,this.lastChar=r.allocUnsafe(t)}function a(e){return e<=127?0:e>>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function s(e){var t=this.lastTotal-this.lastNeed,n=function(e,t,n){if(128!=(192&t[0]))return e.lastNeed=0,"�";if(e.lastNeed>1&&t.length>1){if(128!=(192&t[1]))return e.lastNeed=1,"�";if(e.lastNeed>2&&t.length>2&&128!=(192&t[2]))return e.lastNeed=2,"�"}}(this,e);return void 0!==n?n:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):(e.copy(this.lastChar,t,0,e.length),void(this.lastNeed-=e.length))}function c(e,t){if((e.length-t)%2==0){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function u(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function l(e,t){var n=(e.length-t)%3;return 0===n?e.toString("base64",t):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-n))}function f(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function h(e){return e.toString(this.encoding)}function p(e){return e&&e.length?this.write(e):""}t.StringDecoder=i,i.prototype.write=function(e){if(0===e.length)return"";var t,n;if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";n=this.lastNeed,this.lastNeed=0}else n=0;return n=0)return o>0&&(e.lastNeed=o-1),o;if(--r=0)return o>0&&(e.lastNeed=o-2),o;if(--r=0)return o>0&&(2===o?o=0:e.lastNeed=o-3),o;return 0}(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)},i.prototype.fillLast=function(e){if(this.lastNeed<=e.length)return e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,e.length),this.lastNeed-=e.length}},function(e,t,n){"use strict";(function(t,r,o){var i=n(21);function a(e){var t=this;this.next=null,this.entry=null,this.finish=function(){!function(e,t,n){var r=e.entry;e.entry=null;for(;r;){var o=r.callback;t.pendingcb--,o(n),r=r.next}t.corkedRequestsFree?t.corkedRequestsFree.next=e:t.corkedRequestsFree=e}(t,e)}}e.exports=b;var s,c=!t.browser&&["v0.10","v0.9."].indexOf(t.version.slice(0,5))>-1?r:i.nextTick;b.WritableState=v;var u=n(19);u.inherits=n(15);var l={deprecate:n(66)},f=n(37),h=n(14).Buffer,p=o.Uint8Array||function(){};var d,g=n(38);function y(){}function v(e,t){s=s||n(9),e=e||{};var r=t instanceof s;this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.writableObjectMode);var o=e.highWaterMark,u=e.writableHighWaterMark,l=this.objectMode?16:16384;this.highWaterMark=o||0===o?o:r&&(u||0===u)?u:l,this.highWaterMark=Math.floor(this.highWaterMark),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var f=!1===e.decodeStrings;this.decodeStrings=!f,this.defaultEncoding=e.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(e){!function(e,t){var n=e._writableState,r=n.sync,o=n.writecb;if(function(e){e.writing=!1,e.writecb=null,e.length-=e.writelen,e.writelen=0}(n),t)!function(e,t,n,r,o){--t.pendingcb,n?(i.nextTick(o,r),i.nextTick(I,e,t),e._writableState.errorEmitted=!0,e.emit("error",r)):(o(r),e._writableState.errorEmitted=!0,e.emit("error",r),I(e,t))}(e,n,r,t,o);else{var a=S(n);a||n.corked||n.bufferProcessing||!n.bufferedRequest||E(e,n),r?c(w,e,n,a,o):w(e,n,a,o)}}(t,e)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.bufferedRequestCount=0,this.corkedRequestsFree=new a(this)}function b(e){if(s=s||n(9),!(d.call(b,this)||this instanceof s))return new b(e);this._writableState=new v(e,this),this.writable=!0,e&&("function"==typeof e.write&&(this._write=e.write),"function"==typeof e.writev&&(this._writev=e.writev),"function"==typeof e.destroy&&(this._destroy=e.destroy),"function"==typeof e.final&&(this._final=e.final)),f.call(this)}function m(e,t,n,r,o,i,a){t.writelen=r,t.writecb=a,t.writing=!0,t.sync=!0,n?e._writev(o,t.onwrite):e._write(o,i,t.onwrite),t.sync=!1}function w(e,t,n,r){n||function(e,t){0===t.length&&t.needDrain&&(t.needDrain=!1,e.emit("drain"))}(e,t),t.pendingcb--,r(),I(e,t)}function E(e,t){t.bufferProcessing=!0;var n=t.bufferedRequest;if(e._writev&&n&&n.next){var r=t.bufferedRequestCount,o=new Array(r),i=t.corkedRequestsFree;i.entry=n;for(var s=0,c=!0;n;)o[s]=n,n.isBuf||(c=!1),n=n.next,s+=1;o.allBuffers=c,m(e,t,!0,t.length,o,"",i.finish),t.pendingcb++,t.lastBufferedRequest=null,i.next?(t.corkedRequestsFree=i.next,i.next=null):t.corkedRequestsFree=new a(t),t.bufferedRequestCount=0}else{for(;n;){var u=n.chunk,l=n.encoding,f=n.callback;if(m(e,t,!1,t.objectMode?1:u.length,u,l,f),n=n.next,t.bufferedRequestCount--,t.writing)break}null===n&&(t.lastBufferedRequest=null)}t.bufferedRequest=n,t.bufferProcessing=!1}function S(e){return e.ending&&0===e.length&&null===e.bufferedRequest&&!e.finished&&!e.writing}function C(e,t){e._final((function(n){t.pendingcb--,n&&e.emit("error",n),t.prefinished=!0,e.emit("prefinish"),I(e,t)}))}function I(e,t){var n=S(t);return n&&(!function(e,t){t.prefinished||t.finalCalled||("function"==typeof e._final?(t.pendingcb++,t.finalCalled=!0,i.nextTick(C,e,t)):(t.prefinished=!0,e.emit("prefinish")))}(e,t),0===t.pendingcb&&(t.finished=!0,e.emit("finish"))),n}u.inherits(b,f),v.prototype.getBuffer=function(){for(var e=this.bufferedRequest,t=[];e;)t.push(e),e=e.next;return t},function(){try{Object.defineProperty(v.prototype,"buffer",{get:l.deprecate((function(){return this.getBuffer()}),"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch(e){}}(),"function"==typeof Symbol&&Symbol.hasInstance&&"function"==typeof Function.prototype[Symbol.hasInstance]?(d=Function.prototype[Symbol.hasInstance],Object.defineProperty(b,Symbol.hasInstance,{value:function(e){return!!d.call(this,e)||this===b&&(e&&e._writableState instanceof v)}})):d=function(e){return e instanceof this},b.prototype.pipe=function(){this.emit("error",new Error("Cannot pipe, not readable"))},b.prototype.write=function(e,t,n){var r,o=this._writableState,a=!1,s=!o.objectMode&&(r=e,h.isBuffer(r)||r instanceof p);return s&&!h.isBuffer(e)&&(e=function(e){return h.from(e)}(e)),"function"==typeof t&&(n=t,t=null),s?t="buffer":t||(t=o.defaultEncoding),"function"!=typeof n&&(n=y),o.ended?function(e,t){var n=new Error("write after end");e.emit("error",n),i.nextTick(t,n)}(this,n):(s||function(e,t,n,r){var o=!0,a=!1;return null===n?a=new TypeError("May not write null values to stream"):"string"==typeof n||void 0===n||t.objectMode||(a=new TypeError("Invalid non-string/buffer chunk")),a&&(e.emit("error",a),i.nextTick(r,a),o=!1),o}(this,o,e,n))&&(o.pendingcb++,a=function(e,t,n,r,o,i){if(!n){var a=function(e,t,n){e.objectMode||!1===e.decodeStrings||"string"!=typeof t||(t=h.from(t,n));return t}(t,r,o);r!==a&&(n=!0,o="buffer",r=a)}var s=t.objectMode?1:r.length;t.length+=s;var c=t.length-1))throw new TypeError("Unknown encoding: "+e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(b.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),b.prototype._write=function(e,t,n){n(new Error("_write() is not implemented"))},b.prototype._writev=null,b.prototype.end=function(e,t,n){var r=this._writableState;"function"==typeof e?(n=e,e=null,t=null):"function"==typeof t&&(n=t,t=null),null!=e&&this.write(e,t),r.corked&&(r.corked=1,this.uncork()),r.ending||r.finished||function(e,t,n){t.ending=!0,I(e,t),n&&(t.finished?i.nextTick(n):e.once("finish",n));t.ended=!0,e.writable=!1}(this,r,n)},Object.defineProperty(b.prototype,"destroyed",{get:function(){return void 0!==this._writableState&&this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}}),b.prototype.destroy=g.destroy,b.prototype._undestroy=g.undestroy,b.prototype._destroy=function(e,t){this.end(),t(e)}}).call(this,n(13),n(64).setImmediate,n(8))},function(e,t,n){"use strict";e.exports=a;var r=n(9),o=n(19);function i(e,t){var n=this._transformState;n.transforming=!1;var r=n.writecb;if(!r)return this.emit("error",new Error("write callback called multiple times"));n.writechunk=null,n.writecb=null,null!=t&&this.push(t),r(e);var o=this._readableState;o.reading=!1,(o.needReadable||o.lengths?a.slice(s).buffer:null}else{var c,u=t;if(-1===(c=u.indexOf(r.a.RecordSeparator)))throw new Error("Message is incomplete.");s=c+1;n=u.substring(0,s),i=u.length>s?u.substring(s):null}var l=r.a.parse(n),f=JSON.parse(l[0]);if(f.type)throw new Error("Expected a handshake response from the server.");return[i,f]},t}()}).call(this,n(10).Buffer)},,,,,,,,function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,i){function a(e){try{c(r.next(e))}catch(e){i(e)}}function s(e){try{c(r.throw(e))}catch(e){i(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}c((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,i,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function s(i){return function(s){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return a.label++,{value:i[1],done:!1};case 5:a.label++,r=i[1],i=[0];continue;case 7:i=a.ops.pop(),a.trys.pop();continue;default:if(!(o=a.trys,(o=o.length>0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0)&&!(r=i.next()).done;)a.push(r.value)}catch(e){o={error:e}}finally{try{r&&!r.done&&(n=i.return)&&n.call(i)}finally{if(o)throw o.error}}return a},a=this&&this.__spread||function(){for(var e=[],t=0;t0?a-4:a;for(n=0;n>16&255,c[l++]=t>>8&255,c[l++]=255&t;2===s&&(t=o[e.charCodeAt(n)]<<2|o[e.charCodeAt(n+1)]>>4,c[l++]=255&t);1===s&&(t=o[e.charCodeAt(n)]<<10|o[e.charCodeAt(n+1)]<<4|o[e.charCodeAt(n+2)]>>2,c[l++]=t>>8&255,c[l++]=255&t);return c},t.fromByteArray=function(e){for(var t,n=e.length,o=n%3,i=[],a=0,s=n-o;as?s:a+16383));1===o?(t=e[n-1],i.push(r[t>>2]+r[t<<4&63]+"==")):2===o&&(t=(e[n-2]<<8)+e[n-1],i.push(r[t>>10]+r[t>>4&63]+r[t<<2&63]+"="));return i.join("")};for(var r=[],o=[],i="undefined"!=typeof Uint8Array?Uint8Array:Array,a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",s=0,c=a.length;s0)throw new Error("Invalid string. Length must be a multiple of 4");var n=e.indexOf("=");return-1===n&&(n=t),[n,n===t?0:4-n%4]}function l(e,t,n){for(var o,i,a=[],s=t;s>18&63]+r[i>>12&63]+r[i>>6&63]+r[63&i]);return a.join("")}o["-".charCodeAt(0)]=62,o["_".charCodeAt(0)]=63},function(e,t){t.read=function(e,t,n,r,o){var i,a,s=8*o-r-1,c=(1<>1,l=-7,f=n?o-1:0,h=n?-1:1,p=e[t+f];for(f+=h,i=p&(1<<-l)-1,p>>=-l,l+=s;l>0;i=256*i+e[t+f],f+=h,l-=8);for(a=i&(1<<-l)-1,i>>=-l,l+=r;l>0;a=256*a+e[t+f],f+=h,l-=8);if(0===i)i=1-u;else{if(i===c)return a?NaN:1/0*(p?-1:1);a+=Math.pow(2,r),i-=u}return(p?-1:1)*a*Math.pow(2,i-r)},t.write=function(e,t,n,r,o,i){var a,s,c,u=8*i-o-1,l=(1<>1,h=23===o?Math.pow(2,-24)-Math.pow(2,-77):0,p=r?0:i-1,d=r?1:-1,g=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(s=isNaN(t)?1:0,a=l):(a=Math.floor(Math.log(t)/Math.LN2),t*(c=Math.pow(2,-a))<1&&(a--,c*=2),(t+=a+f>=1?h/c:h*Math.pow(2,1-f))*c>=2&&(a++,c/=2),a+f>=l?(s=0,a=l):a+f>=1?(s=(t*c-1)*Math.pow(2,o),a+=f):(s=t*Math.pow(2,f-1)*Math.pow(2,o),a=0));o>=8;e[n+p]=255&s,p+=d,s/=256,o-=8);for(a=a<0;e[n+p]=255&a,p+=d,a/=256,u-=8);e[n+p-d]|=128*g}},function(e,t){var n={}.toString;e.exports=Array.isArray||function(e){return"[object Array]"==n.call(e)}},function(e,t,n){"use strict";(function(t){var r=n(55); +var r=n(51),o=n(52),i=n(53);function a(){return c.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function s(e,t){if(a()=a())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+a().toString(16)+" bytes");return 0|e}function d(e,t){if(c.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var n=e.length;if(0===n)return 0;for(var r=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":case void 0:return F(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return H(e).length;default:if(r)return F(e).length;t=(""+t).toLowerCase(),r=!0}}function g(e,t,n){var r=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if((n>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return x(this,t,n);case"utf8":case"utf-8":return k(this,t,n);case"ascii":return T(this,t,n);case"latin1":case"binary":return P(this,t,n);case"base64":return _(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return O(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}function y(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function v(e,t,n,r,o){if(0===e.length)return-1;if("string"==typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,isNaN(n)&&(n=o?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(o)return-1;n=e.length-1}else if(n<0){if(!o)return-1;n=0}if("string"==typeof t&&(t=c.from(t,r)),c.isBuffer(t))return 0===t.length?-1:b(e,t,n,r,o);if("number"==typeof t)return t&=255,c.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?o?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):b(e,[t],n,r,o);throw new TypeError("val must be string, number or Buffer")}function b(e,t,n,r,o){var i,a=1,s=e.length,c=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;a=2,s/=2,c/=2,n/=2}function u(e,t){return 1===a?e[t]:e.readUInt16BE(t*a)}if(o){var l=-1;for(i=n;is&&(n=s-c),i=n;i>=0;i--){for(var f=!0,h=0;ho&&(r=o):r=o;var i=t.length;if(i%2!=0)throw new TypeError("Invalid hex string");r>i/2&&(r=i/2);for(var a=0;a>8,o=n%256,i.push(o),i.push(r);return i}(t,e.length-n),e,n,r)}function _(e,t,n){return 0===t&&n===e.length?r.fromByteArray(e):r.fromByteArray(e.slice(t,n))}function k(e,t,n){n=Math.min(e.length,n);for(var r=[],o=t;o239?4:u>223?3:u>191?2:1;if(o+f<=n)switch(f){case 1:u<128&&(l=u);break;case 2:128==(192&(i=e[o+1]))&&(c=(31&u)<<6|63&i)>127&&(l=c);break;case 3:i=e[o+1],a=e[o+2],128==(192&i)&&128==(192&a)&&(c=(15&u)<<12|(63&i)<<6|63&a)>2047&&(c<55296||c>57343)&&(l=c);break;case 4:i=e[o+1],a=e[o+2],s=e[o+3],128==(192&i)&&128==(192&a)&&128==(192&s)&&(c=(15&u)<<18|(63&i)<<12|(63&a)<<6|63&s)>65535&&c<1114112&&(l=c)}null===l?(l=65533,f=1):l>65535&&(l-=65536,r.push(l>>>10&1023|55296),l=56320|1023&l),r.push(l),o+=f}return function(e){var t=e.length;if(t<=4096)return String.fromCharCode.apply(String,e);var n="",r=0;for(;r0&&(e=this.toString("hex",0,n).match(/.{2}/g).join(" "),this.length>n&&(e+=" ... ")),""},c.prototype.compare=function(e,t,n,r,o){if(!c.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===o&&(o=this.length),t<0||n>e.length||r<0||o>this.length)throw new RangeError("out of range index");if(r>=o&&t>=n)return 0;if(r>=o)return-1;if(t>=n)return 1;if(this===e)return 0;for(var i=(o>>>=0)-(r>>>=0),a=(n>>>=0)-(t>>>=0),s=Math.min(i,a),u=this.slice(r,o),l=e.slice(t,n),f=0;fo)&&(n=o),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var i=!1;;)switch(r){case"hex":return m(this,e,t,n);case"utf8":case"utf-8":return w(this,e,t,n);case"ascii":return E(this,e,t,n);case"latin1":case"binary":return S(this,e,t,n);case"base64":return C(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return I(this,e,t,n);default:if(i)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),i=!0}},c.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};function T(e,t,n){var r="";n=Math.min(e.length,n);for(var o=t;or)&&(n=r);for(var o="",i=t;in)throw new RangeError("Trying to access beyond buffer length")}function L(e,t,n,r,o,i){if(!c.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>o||te.length)throw new RangeError("Index out of range")}function D(e,t,n,r){t<0&&(t=65535+t+1);for(var o=0,i=Math.min(e.length-n,2);o>>8*(r?o:1-o)}function M(e,t,n,r){t<0&&(t=4294967295+t+1);for(var o=0,i=Math.min(e.length-n,4);o>>8*(r?o:3-o)&255}function j(e,t,n,r,o,i){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function A(e,t,n,r,i){return i||j(e,0,n,4),o.write(e,t,n,r,23,4),n+4}function B(e,t,n,r,i){return i||j(e,0,n,8),o.write(e,t,n,r,52,8),n+8}c.prototype.slice=function(e,t){var n,r=this.length;if((e=~~e)<0?(e+=r)<0&&(e=0):e>r&&(e=r),(t=void 0===t?r:~~t)<0?(t+=r)<0&&(t=0):t>r&&(t=r),t0&&(o*=256);)r+=this[e+--t]*o;return r},c.prototype.readUInt8=function(e,t){return t||R(e,1,this.length),this[e]},c.prototype.readUInt16LE=function(e,t){return t||R(e,2,this.length),this[e]|this[e+1]<<8},c.prototype.readUInt16BE=function(e,t){return t||R(e,2,this.length),this[e]<<8|this[e+1]},c.prototype.readUInt32LE=function(e,t){return t||R(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},c.prototype.readUInt32BE=function(e,t){return t||R(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},c.prototype.readIntLE=function(e,t,n){e|=0,t|=0,n||R(e,t,this.length);for(var r=this[e],o=1,i=0;++i=(o*=128)&&(r-=Math.pow(2,8*t)),r},c.prototype.readIntBE=function(e,t,n){e|=0,t|=0,n||R(e,t,this.length);for(var r=t,o=1,i=this[e+--r];r>0&&(o*=256);)i+=this[e+--r]*o;return i>=(o*=128)&&(i-=Math.pow(2,8*t)),i},c.prototype.readInt8=function(e,t){return t||R(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},c.prototype.readInt16LE=function(e,t){t||R(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},c.prototype.readInt16BE=function(e,t){t||R(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},c.prototype.readInt32LE=function(e,t){return t||R(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},c.prototype.readInt32BE=function(e,t){return t||R(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},c.prototype.readFloatLE=function(e,t){return t||R(e,4,this.length),o.read(this,e,!0,23,4)},c.prototype.readFloatBE=function(e,t){return t||R(e,4,this.length),o.read(this,e,!1,23,4)},c.prototype.readDoubleLE=function(e,t){return t||R(e,8,this.length),o.read(this,e,!0,52,8)},c.prototype.readDoubleBE=function(e,t){return t||R(e,8,this.length),o.read(this,e,!1,52,8)},c.prototype.writeUIntLE=function(e,t,n,r){(e=+e,t|=0,n|=0,r)||L(this,e,t,n,Math.pow(2,8*n)-1,0);var o=1,i=0;for(this[t]=255&e;++i=0&&(i*=256);)this[t+o]=e/i&255;return t+n},c.prototype.writeUInt8=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,1,255,0),c.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},c.prototype.writeUInt16LE=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,2,65535,0),c.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):D(this,e,t,!0),t+2},c.prototype.writeUInt16BE=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,2,65535,0),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):D(this,e,t,!1),t+2},c.prototype.writeUInt32LE=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,4,4294967295,0),c.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):M(this,e,t,!0),t+4},c.prototype.writeUInt32BE=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,4,4294967295,0),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):M(this,e,t,!1),t+4},c.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);L(this,e,t,n,o-1,-o)}var i=0,a=1,s=0;for(this[t]=255&e;++i>0)-s&255;return t+n},c.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);L(this,e,t,n,o-1,-o)}var i=n-1,a=1,s=0;for(this[t+i]=255&e;--i>=0&&(a*=256);)e<0&&0===s&&0!==this[t+i+1]&&(s=1),this[t+i]=(e/a>>0)-s&255;return t+n},c.prototype.writeInt8=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,1,127,-128),c.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},c.prototype.writeInt16LE=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,2,32767,-32768),c.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):D(this,e,t,!0),t+2},c.prototype.writeInt16BE=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,2,32767,-32768),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):D(this,e,t,!1),t+2},c.prototype.writeInt32LE=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,4,2147483647,-2147483648),c.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):M(this,e,t,!0),t+4},c.prototype.writeInt32BE=function(e,t,n){return e=+e,t|=0,n||L(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):M(this,e,t,!1),t+4},c.prototype.writeFloatLE=function(e,t,n){return A(this,e,t,!0,n)},c.prototype.writeFloatBE=function(e,t,n){return A(this,e,t,!1,n)},c.prototype.writeDoubleLE=function(e,t,n){return B(this,e,t,!0,n)},c.prototype.writeDoubleBE=function(e,t,n){return B(this,e,t,!1,n)},c.prototype.copy=function(e,t,n,r){if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw new RangeError("sourceStart out of bounds");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t=0;--o)e[o+t]=this[o+n];else if(i<1e3||!c.TYPED_ARRAY_SUPPORT)for(o=0;o>>=0,n=void 0===n?this.length:n>>>0,e||(e=0),"number"==typeof e)for(i=t;i55295&&n<57344){if(!o){if(n>56319){(t-=3)>-1&&i.push(239,191,189);continue}if(a+1===r){(t-=3)>-1&&i.push(239,191,189);continue}o=n;continue}if(n<56320){(t-=3)>-1&&i.push(239,191,189),o=n;continue}n=65536+(o-55296<<10|n-56320)}else o&&(t-=3)>-1&&i.push(239,191,189);if(o=null,n<128){if((t-=1)<0)break;i.push(n)}else if(n<2048){if((t-=2)<0)break;i.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;i.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;i.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return i}function H(e){return r.toByteArray(function(e){if((e=function(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}(e).replace(N,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function q(e,t,n,r){for(var o=0;o=t.length||o>=e.length);++o)t[o+n]=e[o];return o}}).call(this,n(8))},function(e,t,n){"use strict";var r=n(14).Buffer,o=n(54),i=n(20),a=n(67),s=n(70),c=n(71);e.exports=function(e){var t=[],n=[];return{encode:c(t,(e=e||{forceFloat64:!1,compatibilityMode:!1,disableTimestampEncoding:!1}).forceFloat64,e.compatibilityMode,e.disableTimestampEncoding),decode:s(n),register:function(e,t,n,a){return o(t,"must have a constructor"),o(n,"must have an encode function"),o(e>=0,"must have a non-negative type"),o(a,"must have a decode function"),this.registerEncoder((function(e){return e instanceof t}),(function(t){var o=i(),a=r.allocUnsafe(1);return a.writeInt8(e,0),o.append(a),o.append(n(t)),o})),this.registerDecoder(e,a),this},registerEncoder:function(e,n){return o(e,"must have an encode function"),o(n,"must have an encode function"),t.push({check:e,encode:n}),this},registerDecoder:function(e,t){return o(e>=0,"must have a non-negative type"),o(t,"must have a decode function"),n.push({type:e,decode:t}),this},encoder:a.encoder,decoder:a.decoder,buffer:!0,type:"msgpack5",IncompleteBufferError:s.IncompleteBufferError}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=p("_blazorLogicalChildren"),o=p("_blazorLogicalParent"),i=p("_blazorLogicalEnd");function a(e,t){if(e.childNodes.length>0&&!t)throw new Error("New logical elements must start empty, or allowExistingContents must be true");return r in e||(e[r]=[]),e}function s(e,t,n){var i=e;if(e instanceof Comment&&(u(i)&&u(i).length>0))throw new Error("Not implemented: inserting non-empty logical container");if(c(i))throw new Error("Not implemented: moving existing logical children");var a=u(t);if(n0;)e(r,0)}var i=r;i.parentNode.removeChild(i)},t.getLogicalParent=c,t.getLogicalSiblingEnd=function(e){return e[i]||null},t.getLogicalChild=function(e,t){return u(e)[t]},t.isSvgElement=function(e){return"http://www.w3.org/2000/svg"===l(e).namespaceURI},t.getLogicalChildrenArray=u,t.permuteLogicalChildren=function(e,t){var n=u(e);t.forEach((function(e){e.moveRangeStart=n[e.fromSiblingIndex],e.moveRangeEnd=function e(t){if(t instanceof Element)return t;var n=f(t);if(n)return n.previousSibling;var r=c(t);return r instanceof Element?r.lastChild:e(r)}(e.moveRangeStart)})),t.forEach((function(t){var r=t.moveToBeforeMarker=document.createComment("marker"),o=n[t.toSiblingIndex+1];o?o.parentNode.insertBefore(r,o):h(r,e)})),t.forEach((function(e){for(var t=e.moveToBeforeMarker,n=t.parentNode,r=e.moveRangeStart,o=e.moveRangeEnd,i=r;i;){var a=i.nextSibling;if(n.insertBefore(i,t),i===o)break;i=a}n.removeChild(t)})),t.forEach((function(e){n[e.toSiblingIndex]=e.moveRangeStart}))},t.getClosestDomElement=l},function(e,t){var n,r,o=e.exports={};function i(){throw new Error("setTimeout has not been defined")}function a(){throw new Error("clearTimeout has not been defined")}function s(e){if(n===setTimeout)return setTimeout(e,0);if((n===i||!n)&&setTimeout)return n=setTimeout,setTimeout(e,0);try{return n(e,0)}catch(t){try{return n.call(null,e,0)}catch(t){return n.call(this,e,0)}}}!function(){try{n="function"==typeof setTimeout?setTimeout:i}catch(e){n=i}try{r="function"==typeof clearTimeout?clearTimeout:a}catch(e){r=a}}();var c,u=[],l=!1,f=-1;function h(){l&&c&&(l=!1,c.length?u=c.concat(u):f=-1,u.length&&p())}function p(){if(!l){var e=s(h);l=!0;for(var t=u.length;t;){for(c=u,u=[];++f1)for(var n=1;nthis.length)&&(r=this.length),n>=this.length)return e||i.alloc(0);if(r<=0)return e||i.alloc(0);var o,a,s=!!e,c=this._offset(n),u=r-n,l=u,f=s&&t||0,h=c[1];if(0===n&&r==this.length){if(!s)return 1===this._bufs.length?this._bufs[0]:i.concat(this._bufs,this.length);for(a=0;a(o=this._bufs[a].length-h))){this._bufs[a].copy(e,f,h,h+l);break}this._bufs[a].copy(e,f,h),f+=o,l-=o,h&&(h=0)}return e},a.prototype.shallowSlice=function(e,t){e=e||0,t=t||this.length,e<0&&(e+=this.length),t<0&&(t+=this.length);var n=this._offset(e),r=this._offset(t),o=this._bufs.slice(n[0],r[0]+1);return 0==r[1]?o.pop():o[o.length-1]=o[o.length-1].slice(0,r[1]),0!=n[1]&&(o[0]=o[0].slice(n[1])),new a(o)},a.prototype.toString=function(e,t,n){return this.slice(t,n).toString(e)},a.prototype.consume=function(e){for(;this._bufs.length;){if(!(e>=this._bufs[0].length)){this._bufs[0]=this._bufs[0].slice(e),this.length-=e;break}e-=this._bufs[0].length,this.length-=this._bufs[0].length,this._bufs.shift()}return this},a.prototype.duplicate=function(){for(var e=0,t=new a;e0&&e.invokeMethodAsync("OnSpacerAfterVisible",r.boundingClientRect.bottom-r.intersectionRect.bottom,i,a)}}))}),{root:o(t),rootMargin:i+"px"});a.observe(t),a.observe(n);var s=u(t),c=u(n);function u(e){var t=new MutationObserver((function(){a.unobserve(e),a.observe(e)}));return t.observe(e,{attributes:!0}),t}r[e._id]={intersectionObserver:a,mutationObserverBefore:s,mutationObserverAfter:c}},dispose:function(e){var t=r[e._id];t&&(t.intersectionObserver.disconnect(),t.mutationObserverBefore.disconnect(),t.mutationObserverAfter.disconnect(),e.dispose(),delete r[e._id])}};var r={};function o(e){return e?"visible"!==getComputedStyle(e).overflowY?e:o(e.parentElement):null}},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,i){function a(e){try{c(r.next(e))}catch(e){i(e)}}function s(e){try{c(r.throw(e))}catch(e){i(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}c((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,i,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function s(i){return function(s){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return a.label++,{value:i[1],done:!1};case 5:a.label++,r=i[1],i=[0];continue;case 7:i=a.ops.pop(),a.trys.pop();continue;default:if(!(o=a.trys,(o=o.length>0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]=i)return e;switch(e){case"%s":return String(r[n++]);case"%d":return Number(r[n++]);case"%j":try{return JSON.stringify(r[n++])}catch(e){return"[Circular]"}default:return e}})),c=r[n];n=3&&(r.depth=arguments[2]),arguments.length>=4&&(r.colors=arguments[3]),d(n)?r.showHidden=n:n&&t._extend(r,n),b(r.showHidden)&&(r.showHidden=!1),b(r.depth)&&(r.depth=2),b(r.colors)&&(r.colors=!1),b(r.customInspect)&&(r.customInspect=!0),r.colors&&(r.stylize=c),l(r,e,r.depth)}function c(e,t){var n=s.styles[t];return n?"["+s.colors[n][0]+"m"+e+"["+s.colors[n][1]+"m":e}function u(e,t){return e}function l(e,n,r){if(e.customInspect&&n&&C(n.inspect)&&n.inspect!==t.inspect&&(!n.constructor||n.constructor.prototype!==n)){var o=n.inspect(r,e);return v(o)||(o=l(e,o,r)),o}var i=function(e,t){if(b(t))return e.stylize("undefined","undefined");if(v(t)){var n="'"+JSON.stringify(t).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return e.stylize(n,"string")}if(y(t))return e.stylize(""+t,"number");if(d(t))return e.stylize(""+t,"boolean");if(g(t))return e.stylize("null","null")}(e,n);if(i)return i;var a=Object.keys(n),s=function(e){var t={};return e.forEach((function(e,n){t[e]=!0})),t}(a);if(e.showHidden&&(a=Object.getOwnPropertyNames(n)),S(n)&&(a.indexOf("message")>=0||a.indexOf("description")>=0))return f(n);if(0===a.length){if(C(n)){var c=n.name?": "+n.name:"";return e.stylize("[Function"+c+"]","special")}if(m(n))return e.stylize(RegExp.prototype.toString.call(n),"regexp");if(E(n))return e.stylize(Date.prototype.toString.call(n),"date");if(S(n))return f(n)}var u,w="",I=!1,_=["{","}"];(p(n)&&(I=!0,_=["[","]"]),C(n))&&(w=" [Function"+(n.name?": "+n.name:"")+"]");return m(n)&&(w=" "+RegExp.prototype.toString.call(n)),E(n)&&(w=" "+Date.prototype.toUTCString.call(n)),S(n)&&(w=" "+f(n)),0!==a.length||I&&0!=n.length?r<0?m(n)?e.stylize(RegExp.prototype.toString.call(n),"regexp"):e.stylize("[Object]","special"):(e.seen.push(n),u=I?function(e,t,n,r,o){for(var i=[],a=0,s=t.length;a=0&&0,e+t.replace(/\u001b\[\d\d?m/g,"").length+1}),0)>60)return n[0]+(""===t?"":t+"\n ")+" "+e.join(",\n ")+" "+n[1];return n[0]+t+" "+e.join(", ")+" "+n[1]}(u,w,_)):_[0]+w+_[1]}function f(e){return"["+Error.prototype.toString.call(e)+"]"}function h(e,t,n,r,o,i){var a,s,c;if((c=Object.getOwnPropertyDescriptor(t,o)||{value:t[o]}).get?s=c.set?e.stylize("[Getter/Setter]","special"):e.stylize("[Getter]","special"):c.set&&(s=e.stylize("[Setter]","special")),P(r,o)||(a="["+o+"]"),s||(e.seen.indexOf(c.value)<0?(s=g(n)?l(e,c.value,null):l(e,c.value,n-1)).indexOf("\n")>-1&&(s=i?s.split("\n").map((function(e){return" "+e})).join("\n").substr(2):"\n"+s.split("\n").map((function(e){return" "+e})).join("\n")):s=e.stylize("[Circular]","special")),b(a)){if(i&&o.match(/^\d+$/))return s;(a=JSON.stringify(""+o)).match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(a=a.substr(1,a.length-2),a=e.stylize(a,"name")):(a=a.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),a=e.stylize(a,"string"))}return a+": "+s}function p(e){return Array.isArray(e)}function d(e){return"boolean"==typeof e}function g(e){return null===e}function y(e){return"number"==typeof e}function v(e){return"string"==typeof e}function b(e){return void 0===e}function m(e){return w(e)&&"[object RegExp]"===I(e)}function w(e){return"object"==typeof e&&null!==e}function E(e){return w(e)&&"[object Date]"===I(e)}function S(e){return w(e)&&("[object Error]"===I(e)||e instanceof Error)}function C(e){return"function"==typeof e}function I(e){return Object.prototype.toString.call(e)}function _(e){return e<10?"0"+e.toString(10):e.toString(10)}t.debuglog=function(n){if(b(i)&&(i=e.env.NODE_DEBUG||""),n=n.toUpperCase(),!a[n])if(new RegExp("\\b"+n+"\\b","i").test(i)){var r=e.pid;a[n]=function(){var e=t.format.apply(t,arguments);console.error("%s %d: %s",n,r,e)}}else a[n]=function(){};return a[n]},t.inspect=s,s.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]},s.styles={special:"cyan",number:"yellow",boolean:"yellow",undefined:"grey",null:"bold",string:"green",date:"magenta",regexp:"red"},t.isArray=p,t.isBoolean=d,t.isNull=g,t.isNullOrUndefined=function(e){return null==e},t.isNumber=y,t.isString=v,t.isSymbol=function(e){return"symbol"==typeof e},t.isUndefined=b,t.isRegExp=m,t.isObject=w,t.isDate=E,t.isError=S,t.isFunction=C,t.isPrimitive=function(e){return null===e||"boolean"==typeof e||"number"==typeof e||"string"==typeof e||"symbol"==typeof e||void 0===e},t.isBuffer=n(56);var k=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function T(){var e=new Date,t=[_(e.getHours()),_(e.getMinutes()),_(e.getSeconds())].join(":");return[e.getDate(),k[e.getMonth()],t].join(" ")}function P(e,t){return Object.prototype.hasOwnProperty.call(e,t)}t.log=function(){console.log("%s - %s",T(),t.format.apply(t,arguments))},t.inherits=n(57),t._extend=function(e,t){if(!t||!w(t))return e;for(var n=Object.keys(t),r=n.length;r--;)e[n[r]]=t[n[r]];return e};var x="undefined"!=typeof Symbol?Symbol("util.promisify.custom"):void 0;function O(e,t){if(!e){var n=new Error("Promise was rejected with a falsy value");n.reason=e,e=n}return t(e)}t.promisify=function(e){if("function"!=typeof e)throw new TypeError('The "original" argument must be of type Function');if(x&&e[x]){var t;if("function"!=typeof(t=e[x]))throw new TypeError('The "util.promisify.custom" argument must be of type Function');return Object.defineProperty(t,x,{value:t,enumerable:!1,writable:!1,configurable:!0}),t}function t(){for(var t,n,r=new Promise((function(e,r){t=e,n=r})),o=[],i=0;i0?("string"==typeof t||a.objectMode||Object.getPrototypeOf(t)===u.prototype||(t=function(e){return u.from(e)}(t)),r?a.endEmitted?e.emit("error",new Error("stream.unshift() after end event")):E(e,a,t,!0):a.ended?e.emit("error",new Error("stream.push() after EOF")):(a.reading=!1,a.decoder&&!n?(t=a.decoder.write(t),a.objectMode||0!==t.length?E(e,a,t,!1):_(e,a)):E(e,a,t,!1))):r||(a.reading=!1));return function(e){return!e.ended&&(e.needReadable||e.lengtht.highWaterMark&&(t.highWaterMark=function(e){return e>=8388608?e=8388608:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}function C(e){var t=e._readableState;t.needReadable=!1,t.emittedReadable||(p("emitReadable",t.flowing),t.emittedReadable=!0,t.sync?o.nextTick(I,e):I(e))}function I(e){p("emit readable"),e.emit("readable"),x(e)}function _(e,t){t.readingMore||(t.readingMore=!0,o.nextTick(k,e,t))}function k(e,t){for(var n=t.length;!t.reading&&!t.flowing&&!t.ended&&t.length=t.length?(n=t.decoder?t.buffer.join(""):1===t.buffer.length?t.buffer.head.data:t.buffer.concat(t.length),t.buffer.clear()):n=function(e,t,n){var r;ei.length?i.length:e;if(a===i.length?o+=i:o+=i.slice(0,e),0===(e-=a)){a===i.length?(++r,n.next?t.head=n.next:t.head=t.tail=null):(t.head=n,n.data=i.slice(a));break}++r}return t.length-=r,o}(e,t):function(e,t){var n=u.allocUnsafe(e),r=t.head,o=1;r.data.copy(n),e-=r.data.length;for(;r=r.next;){var i=r.data,a=e>i.length?i.length:e;if(i.copy(n,n.length-e,0,a),0===(e-=a)){a===i.length?(++o,r.next?t.head=r.next:t.head=t.tail=null):(t.head=r,r.data=i.slice(a));break}++o}return t.length-=o,n}(e,t);return r}(e,t.buffer,t.decoder),n);var n}function R(e){var t=e._readableState;if(t.length>0)throw new Error('"endReadable()" called on non-empty stream');t.endEmitted||(t.ended=!0,o.nextTick(L,t,e))}function L(e,t){e.endEmitted||0!==e.length||(e.endEmitted=!0,t.readable=!1,t.emit("end"))}function D(e,t){for(var n=0,r=e.length;n=t.highWaterMark||t.ended))return p("read: emitReadable",t.length,t.ended),0===t.length&&t.ended?R(this):C(this),null;if(0===(e=S(e,t))&&t.ended)return 0===t.length&&R(this),null;var r,o=t.needReadable;return p("need readable",o),(0===t.length||t.length-e0?O(e,t):null)?(t.needReadable=!0,e=0):t.length-=e,0===t.length&&(t.ended||(t.needReadable=!0),n!==e&&t.ended&&R(this)),null!==r&&this.emit("data",r),r},m.prototype._read=function(e){this.emit("error",new Error("_read() is not implemented"))},m.prototype.pipe=function(e,t){var n=this,i=this._readableState;switch(i.pipesCount){case 0:i.pipes=e;break;case 1:i.pipes=[i.pipes,e];break;default:i.pipes.push(e)}i.pipesCount+=1,p("pipe count=%d opts=%j",i.pipesCount,t);var c=(!t||!1!==t.end)&&e!==r.stdout&&e!==r.stderr?l:m;function u(t,r){p("onunpipe"),t===n&&r&&!1===r.hasUnpiped&&(r.hasUnpiped=!0,p("cleanup"),e.removeListener("close",v),e.removeListener("finish",b),e.removeListener("drain",f),e.removeListener("error",y),e.removeListener("unpipe",u),n.removeListener("end",l),n.removeListener("end",m),n.removeListener("data",g),h=!0,!i.awaitDrain||e._writableState&&!e._writableState.needDrain||f())}function l(){p("onend"),e.end()}i.endEmitted?o.nextTick(c):n.once("end",c),e.on("unpipe",u);var f=function(e){return function(){var t=e._readableState;p("pipeOnDrain",t.awaitDrain),t.awaitDrain&&t.awaitDrain--,0===t.awaitDrain&&s(e,"data")&&(t.flowing=!0,x(e))}}(n);e.on("drain",f);var h=!1;var d=!1;function g(t){p("ondata"),d=!1,!1!==e.write(t)||d||((1===i.pipesCount&&i.pipes===e||i.pipesCount>1&&-1!==D(i.pipes,e))&&!h&&(p("false write response, pause",n._readableState.awaitDrain),n._readableState.awaitDrain++,d=!0),n.pause())}function y(t){p("onerror",t),m(),e.removeListener("error",y),0===s(e,"error")&&e.emit("error",t)}function v(){e.removeListener("finish",b),m()}function b(){p("onfinish"),e.removeListener("close",v),m()}function m(){p("unpipe"),n.unpipe(e)}return n.on("data",g),function(e,t,n){if("function"==typeof e.prependListener)return e.prependListener(t,n);e._events&&e._events[t]?a(e._events[t])?e._events[t].unshift(n):e._events[t]=[n,e._events[t]]:e.on(t,n)}(e,"error",y),e.once("close",v),e.once("finish",b),e.emit("pipe",n),i.flowing||(p("pipe resume"),n.resume()),e},m.prototype.unpipe=function(e){var t=this._readableState,n={hasUnpiped:!1};if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes||(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,n)),this;if(!e){var r=t.pipes,o=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var i=0;i0&&a.length>o&&!a.warned){a.warned=!0;var c=new Error("Possible EventEmitter memory leak detected. "+a.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");c.name="MaxListenersExceededWarning",c.emitter=e,c.type=t,c.count=a.length,s=c,console&&console.warn&&console.warn(s)}return e}function h(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function p(e,t,n){var r={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},o=h.bind(r);return o.listener=n,r.wrapFn=o,o}function d(e,t,n){var r=e._events;if(void 0===r)return[];var o=r[t];return void 0===o?[]:"function"==typeof o?n?[o.listener||o]:[o]:n?function(e){for(var t=new Array(e.length),n=0;n0&&(a=t[0]),a instanceof Error)throw a;var s=new Error("Unhandled error."+(a?" ("+a.message+")":""));throw s.context=a,s}var c=o[e];if(void 0===c)return!1;if("function"==typeof c)i(c,this,t);else{var u=c.length,l=y(c,u);for(n=0;n=0;i--)if(n[i]===t||n[i].listener===t){a=n[i].listener,o=i;break}if(o<0)return this;0===o?n.shift():function(e,t){for(;t+1=0;r--)this.removeListener(e,t[r]);return this},s.prototype.listeners=function(e){return d(this,e,!0)},s.prototype.rawListeners=function(e){return d(this,e,!1)},s.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):g.call(e,t)},s.prototype.listenerCount=g,s.prototype.eventNames=function(){return this._eventsCount>0?r(this._events):[]}},function(e,t,n){e.exports=n(36).EventEmitter},function(e,t,n){"use strict";var r=n(21);function o(e,t){e.emit("error",t)}e.exports={destroy:function(e,t){var n=this,i=this._readableState&&this._readableState.destroyed,a=this._writableState&&this._writableState.destroyed;return i||a?(t?t(e):!e||this._writableState&&this._writableState.errorEmitted||r.nextTick(o,this,e),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(e||null,(function(e){!t&&e?(r.nextTick(o,n,e),n._writableState&&(n._writableState.errorEmitted=!0)):t&&t(e)})),this)},undestroy:function(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}}},function(e,t,n){"use strict";var r=n(63).Buffer,o=r.isEncoding||function(e){switch((e=""+e)&&e.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};function i(e){var t;switch(this.encoding=function(e){var t=function(e){if(!e)return"utf8";for(var t;;)switch(e){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return e;default:if(t)return;e=(""+e).toLowerCase(),t=!0}}(e);if("string"!=typeof t&&(r.isEncoding===o||!o(e)))throw new Error("Unknown encoding: "+e);return t||e}(e),this.encoding){case"utf16le":this.text=c,this.end=u,t=4;break;case"utf8":this.fillLast=s,t=4;break;case"base64":this.text=l,this.end=f,t=3;break;default:return this.write=h,void(this.end=p)}this.lastNeed=0,this.lastTotal=0,this.lastChar=r.allocUnsafe(t)}function a(e){return e<=127?0:e>>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function s(e){var t=this.lastTotal-this.lastNeed,n=function(e,t,n){if(128!=(192&t[0]))return e.lastNeed=0,"�";if(e.lastNeed>1&&t.length>1){if(128!=(192&t[1]))return e.lastNeed=1,"�";if(e.lastNeed>2&&t.length>2&&128!=(192&t[2]))return e.lastNeed=2,"�"}}(this,e);return void 0!==n?n:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):(e.copy(this.lastChar,t,0,e.length),void(this.lastNeed-=e.length))}function c(e,t){if((e.length-t)%2==0){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function u(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function l(e,t){var n=(e.length-t)%3;return 0===n?e.toString("base64",t):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-n))}function f(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function h(e){return e.toString(this.encoding)}function p(e){return e&&e.length?this.write(e):""}t.StringDecoder=i,i.prototype.write=function(e){if(0===e.length)return"";var t,n;if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";n=this.lastNeed,this.lastNeed=0}else n=0;return n=0)return o>0&&(e.lastNeed=o-1),o;if(--r=0)return o>0&&(e.lastNeed=o-2),o;if(--r=0)return o>0&&(2===o?o=0:e.lastNeed=o-3),o;return 0}(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)},i.prototype.fillLast=function(e){if(this.lastNeed<=e.length)return e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,e.length),this.lastNeed-=e.length}},function(e,t,n){"use strict";(function(t,r,o){var i=n(21);function a(e){var t=this;this.next=null,this.entry=null,this.finish=function(){!function(e,t,n){var r=e.entry;e.entry=null;for(;r;){var o=r.callback;t.pendingcb--,o(n),r=r.next}t.corkedRequestsFree?t.corkedRequestsFree.next=e:t.corkedRequestsFree=e}(t,e)}}e.exports=b;var s,c=!t.browser&&["v0.10","v0.9."].indexOf(t.version.slice(0,5))>-1?r:i.nextTick;b.WritableState=v;var u=n(19);u.inherits=n(15);var l={deprecate:n(66)},f=n(37),h=n(14).Buffer,p=o.Uint8Array||function(){};var d,g=n(38);function y(){}function v(e,t){s=s||n(9),e=e||{};var r=t instanceof s;this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.writableObjectMode);var o=e.highWaterMark,u=e.writableHighWaterMark,l=this.objectMode?16:16384;this.highWaterMark=o||0===o?o:r&&(u||0===u)?u:l,this.highWaterMark=Math.floor(this.highWaterMark),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var f=!1===e.decodeStrings;this.decodeStrings=!f,this.defaultEncoding=e.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(e){!function(e,t){var n=e._writableState,r=n.sync,o=n.writecb;if(function(e){e.writing=!1,e.writecb=null,e.length-=e.writelen,e.writelen=0}(n),t)!function(e,t,n,r,o){--t.pendingcb,n?(i.nextTick(o,r),i.nextTick(I,e,t),e._writableState.errorEmitted=!0,e.emit("error",r)):(o(r),e._writableState.errorEmitted=!0,e.emit("error",r),I(e,t))}(e,n,r,t,o);else{var a=S(n);a||n.corked||n.bufferProcessing||!n.bufferedRequest||E(e,n),r?c(w,e,n,a,o):w(e,n,a,o)}}(t,e)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.bufferedRequestCount=0,this.corkedRequestsFree=new a(this)}function b(e){if(s=s||n(9),!(d.call(b,this)||this instanceof s))return new b(e);this._writableState=new v(e,this),this.writable=!0,e&&("function"==typeof e.write&&(this._write=e.write),"function"==typeof e.writev&&(this._writev=e.writev),"function"==typeof e.destroy&&(this._destroy=e.destroy),"function"==typeof e.final&&(this._final=e.final)),f.call(this)}function m(e,t,n,r,o,i,a){t.writelen=r,t.writecb=a,t.writing=!0,t.sync=!0,n?e._writev(o,t.onwrite):e._write(o,i,t.onwrite),t.sync=!1}function w(e,t,n,r){n||function(e,t){0===t.length&&t.needDrain&&(t.needDrain=!1,e.emit("drain"))}(e,t),t.pendingcb--,r(),I(e,t)}function E(e,t){t.bufferProcessing=!0;var n=t.bufferedRequest;if(e._writev&&n&&n.next){var r=t.bufferedRequestCount,o=new Array(r),i=t.corkedRequestsFree;i.entry=n;for(var s=0,c=!0;n;)o[s]=n,n.isBuf||(c=!1),n=n.next,s+=1;o.allBuffers=c,m(e,t,!0,t.length,o,"",i.finish),t.pendingcb++,t.lastBufferedRequest=null,i.next?(t.corkedRequestsFree=i.next,i.next=null):t.corkedRequestsFree=new a(t),t.bufferedRequestCount=0}else{for(;n;){var u=n.chunk,l=n.encoding,f=n.callback;if(m(e,t,!1,t.objectMode?1:u.length,u,l,f),n=n.next,t.bufferedRequestCount--,t.writing)break}null===n&&(t.lastBufferedRequest=null)}t.bufferedRequest=n,t.bufferProcessing=!1}function S(e){return e.ending&&0===e.length&&null===e.bufferedRequest&&!e.finished&&!e.writing}function C(e,t){e._final((function(n){t.pendingcb--,n&&e.emit("error",n),t.prefinished=!0,e.emit("prefinish"),I(e,t)}))}function I(e,t){var n=S(t);return n&&(!function(e,t){t.prefinished||t.finalCalled||("function"==typeof e._final?(t.pendingcb++,t.finalCalled=!0,i.nextTick(C,e,t)):(t.prefinished=!0,e.emit("prefinish")))}(e,t),0===t.pendingcb&&(t.finished=!0,e.emit("finish"))),n}u.inherits(b,f),v.prototype.getBuffer=function(){for(var e=this.bufferedRequest,t=[];e;)t.push(e),e=e.next;return t},function(){try{Object.defineProperty(v.prototype,"buffer",{get:l.deprecate((function(){return this.getBuffer()}),"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch(e){}}(),"function"==typeof Symbol&&Symbol.hasInstance&&"function"==typeof Function.prototype[Symbol.hasInstance]?(d=Function.prototype[Symbol.hasInstance],Object.defineProperty(b,Symbol.hasInstance,{value:function(e){return!!d.call(this,e)||this===b&&(e&&e._writableState instanceof v)}})):d=function(e){return e instanceof this},b.prototype.pipe=function(){this.emit("error",new Error("Cannot pipe, not readable"))},b.prototype.write=function(e,t,n){var r,o=this._writableState,a=!1,s=!o.objectMode&&(r=e,h.isBuffer(r)||r instanceof p);return s&&!h.isBuffer(e)&&(e=function(e){return h.from(e)}(e)),"function"==typeof t&&(n=t,t=null),s?t="buffer":t||(t=o.defaultEncoding),"function"!=typeof n&&(n=y),o.ended?function(e,t){var n=new Error("write after end");e.emit("error",n),i.nextTick(t,n)}(this,n):(s||function(e,t,n,r){var o=!0,a=!1;return null===n?a=new TypeError("May not write null values to stream"):"string"==typeof n||void 0===n||t.objectMode||(a=new TypeError("Invalid non-string/buffer chunk")),a&&(e.emit("error",a),i.nextTick(r,a),o=!1),o}(this,o,e,n))&&(o.pendingcb++,a=function(e,t,n,r,o,i){if(!n){var a=function(e,t,n){e.objectMode||!1===e.decodeStrings||"string"!=typeof t||(t=h.from(t,n));return t}(t,r,o);r!==a&&(n=!0,o="buffer",r=a)}var s=t.objectMode?1:r.length;t.length+=s;var c=t.length-1))throw new TypeError("Unknown encoding: "+e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(b.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),b.prototype._write=function(e,t,n){n(new Error("_write() is not implemented"))},b.prototype._writev=null,b.prototype.end=function(e,t,n){var r=this._writableState;"function"==typeof e?(n=e,e=null,t=null):"function"==typeof t&&(n=t,t=null),null!=e&&this.write(e,t),r.corked&&(r.corked=1,this.uncork()),r.ending||r.finished||function(e,t,n){t.ending=!0,I(e,t),n&&(t.finished?i.nextTick(n):e.once("finish",n));t.ended=!0,e.writable=!1}(this,r,n)},Object.defineProperty(b.prototype,"destroyed",{get:function(){return void 0!==this._writableState&&this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}}),b.prototype.destroy=g.destroy,b.prototype._undestroy=g.undestroy,b.prototype._destroy=function(e,t){this.end(),t(e)}}).call(this,n(13),n(64).setImmediate,n(8))},function(e,t,n){"use strict";e.exports=a;var r=n(9),o=n(19);function i(e,t){var n=this._transformState;n.transforming=!1;var r=n.writecb;if(!r)return this.emit("error",new Error("write callback called multiple times"));n.writechunk=null,n.writecb=null,null!=t&&this.push(t),r(e);var o=this._readableState;o.reading=!1,(o.needReadable||o.lengths?a.slice(s).buffer:null}else{var c,u=t;if(-1===(c=u.indexOf(r.a.RecordSeparator)))throw new Error("Message is incomplete.");s=c+1;n=u.substring(0,s),i=u.length>s?u.substring(s):null}var l=r.a.parse(n),f=JSON.parse(l[0]);if(f.type)throw new Error("Expected a handshake response from the server.");return[i,f]},t}()}).call(this,n(10).Buffer)},,,,,,,,function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,i){function a(e){try{c(r.next(e))}catch(e){i(e)}}function s(e){try{c(r.throw(e))}catch(e){i(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}c((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,i,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function s(i){return function(s){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return a.label++,{value:i[1],done:!1};case 5:a.label++,r=i[1],i=[0];continue;case 7:i=a.ops.pop(),a.trys.pop();continue;default:if(!(o=a.trys,(o=o.length>0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0)&&!(r=i.next()).done;)a.push(r.value)}catch(e){o={error:e}}finally{try{r&&!r.done&&(n=i.return)&&n.call(i)}finally{if(o)throw o.error}}return a},a=this&&this.__spread||function(){for(var e=[],t=0;t0?a-4:a;for(n=0;n>16&255,c[l++]=t>>8&255,c[l++]=255&t;2===s&&(t=o[e.charCodeAt(n)]<<2|o[e.charCodeAt(n+1)]>>4,c[l++]=255&t);1===s&&(t=o[e.charCodeAt(n)]<<10|o[e.charCodeAt(n+1)]<<4|o[e.charCodeAt(n+2)]>>2,c[l++]=t>>8&255,c[l++]=255&t);return c},t.fromByteArray=function(e){for(var t,n=e.length,o=n%3,i=[],a=0,s=n-o;as?s:a+16383));1===o?(t=e[n-1],i.push(r[t>>2]+r[t<<4&63]+"==")):2===o&&(t=(e[n-2]<<8)+e[n-1],i.push(r[t>>10]+r[t>>4&63]+r[t<<2&63]+"="));return i.join("")};for(var r=[],o=[],i="undefined"!=typeof Uint8Array?Uint8Array:Array,a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",s=0,c=a.length;s0)throw new Error("Invalid string. Length must be a multiple of 4");var n=e.indexOf("=");return-1===n&&(n=t),[n,n===t?0:4-n%4]}function l(e,t,n){for(var o,i,a=[],s=t;s>18&63]+r[i>>12&63]+r[i>>6&63]+r[63&i]);return a.join("")}o["-".charCodeAt(0)]=62,o["_".charCodeAt(0)]=63},function(e,t){t.read=function(e,t,n,r,o){var i,a,s=8*o-r-1,c=(1<>1,l=-7,f=n?o-1:0,h=n?-1:1,p=e[t+f];for(f+=h,i=p&(1<<-l)-1,p>>=-l,l+=s;l>0;i=256*i+e[t+f],f+=h,l-=8);for(a=i&(1<<-l)-1,i>>=-l,l+=r;l>0;a=256*a+e[t+f],f+=h,l-=8);if(0===i)i=1-u;else{if(i===c)return a?NaN:1/0*(p?-1:1);a+=Math.pow(2,r),i-=u}return(p?-1:1)*a*Math.pow(2,i-r)},t.write=function(e,t,n,r,o,i){var a,s,c,u=8*i-o-1,l=(1<>1,h=23===o?Math.pow(2,-24)-Math.pow(2,-77):0,p=r?0:i-1,d=r?1:-1,g=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(s=isNaN(t)?1:0,a=l):(a=Math.floor(Math.log(t)/Math.LN2),t*(c=Math.pow(2,-a))<1&&(a--,c*=2),(t+=a+f>=1?h/c:h*Math.pow(2,1-f))*c>=2&&(a++,c/=2),a+f>=l?(s=0,a=l):a+f>=1?(s=(t*c-1)*Math.pow(2,o),a+=f):(s=t*Math.pow(2,f-1)*Math.pow(2,o),a=0));o>=8;e[n+p]=255&s,p+=d,s/=256,o-=8);for(a=a<0;e[n+p]=255&a,p+=d,a/=256,u-=8);e[n+p-d]|=128*g}},function(e,t){var n={}.toString;e.exports=Array.isArray||function(e){return"[object Array]"==n.call(e)}},function(e,t,n){"use strict";(function(t){var r=n(55); /*! * The buffer module from node.js, for the browser. * diff --git a/src/Components/Web.JS/dist/Release/blazor.webassembly.js b/src/Components/Web.JS/dist/Release/blazor.webassembly.js index 73ed84cac9..3c87e2a0cc 100644 --- a/src/Components/Web.JS/dist/Release/blazor.webassembly.js +++ b/src/Components/Web.JS/dist/Release/blazor.webassembly.js @@ -1 +1 @@ -!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=43)}([,,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e){window.DotNet=e;var t=[],n={},r={},o=1,i=null;function a(e){t.push(e)}function s(e,t,n,r){var o=c();if(o.invokeDotNetFromJS){var i=JSON.stringify(r,m),a=o.invokeDotNetFromJS(e,t,n,i);return a?f(a):null}throw new Error("The current dispatcher does not support synchronous calls from JS to .NET. Use invokeMethodAsync instead.")}function u(e,t,r,i){if(e&&r)throw new Error("For instance method calls, assemblyName should be null. Received '"+e+"'.");var a=o++,s=new Promise((function(e,t){n[a]={resolve:e,reject:t}}));try{var u=JSON.stringify(i,m);c().beginInvokeDotNetFromJS(a,e,t,r,u)}catch(e){l(a,!1,e)}return s}function c(){if(null!==i)return i;throw new Error("No .NET call dispatcher has been set.")}function l(e,t,r){if(!n.hasOwnProperty(e))throw new Error("There is no pending async call with ID "+e+".");var o=n[e];delete n[e],t?o.resolve(r):o.reject(r)}function f(e){return e?JSON.parse(e,(function(e,n){return t.reduce((function(t,n){return n(e,t)}),n)})):null}function d(e){return e instanceof Error?e.message+"\n"+e.stack:e?e.toString():"null"}function p(e){if(Object.prototype.hasOwnProperty.call(r,e))return r[e];var t,n=window,o="window";if(e.split(".").forEach((function(e){if(!(e in n))throw new Error("Could not find '"+e+"' in '"+o+"'.");t=n,n=n[e],o+="."+e})),n instanceof Function)return n=n.bind(t),r[e]=n,n;throw new Error("The value '"+o+"' is not a function.")}e.attachDispatcher=function(e){i=e},e.attachReviver=a,e.invokeMethod=function(e,t){for(var n=[],r=2;r0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&!t)throw new Error("New logical elements must start empty, or allowExistingContents must be true");return r in e||(e[r]=[]),e}function s(e,t,n){var i=e;if(e instanceof Comment&&(c(i)&&c(i).length>0))throw new Error("Not implemented: inserting non-empty logical container");if(u(i))throw new Error("Not implemented: moving existing logical children");var a=c(t);if(n0;)e(r,0)}var i=r;i.parentNode.removeChild(i)},t.getLogicalParent=u,t.getLogicalSiblingEnd=function(e){return e[i]||null},t.getLogicalChild=function(e,t){return c(e)[t]},t.isSvgElement=function(e){return"http://www.w3.org/2000/svg"===l(e).namespaceURI},t.getLogicalChildrenArray=c,t.permuteLogicalChildren=function(e,t){var n=c(e);t.forEach((function(e){e.moveRangeStart=n[e.fromSiblingIndex],e.moveRangeEnd=function e(t){if(t instanceof Element)return t;var n=f(t);if(n)return n.previousSibling;var r=u(t);return r instanceof Element?r.lastChild:e(r)}(e.moveRangeStart)})),t.forEach((function(t){var r=t.moveToBeforeMarker=document.createComment("marker"),o=n[t.toSiblingIndex+1];o?o.parentNode.insertBefore(r,o):d(r,e)})),t.forEach((function(e){for(var t=e.moveToBeforeMarker,n=t.parentNode,r=e.moveRangeStart,o=e.moveRangeEnd,i=r;i;){var a=i.nextSibling;if(n.insertBefore(i,t),i===o)break;i=a}n.removeChild(t)})),t.forEach((function(e){n[e.toSiblingIndex]=e.moveRangeStart}))},t.getClosestDomElement=l},,,,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.setPlatform=function(e){return t.platform=e,t.platform}},function(e,t,n){"use strict";var r;Object.defineProperty(t,"__esModule",{value:!0}),t.dispatchEvent=function(e,t){if(!r)throw new Error("eventDispatcher not initialized. Call 'setEventDispatcher' to configure it.");r(e,t)},t.setEventDispatcher=function(e){r=e}},,,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(7),o=n(4),i=n(30),a=n(31);window.Blazor={navigateTo:r.navigateTo,_internal:{attachRootComponentToElement:o.attachRootComponentToElement,navigationManager:r.internalFunctions,domWrapper:i.domFunctions,Virtualize:a.Virtualize}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0})},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(25),o=n(26),i=n(12),a=n(29),s=n(18),u=n(7),c=document.createElement("template"),l=document.createElementNS("http://www.w3.org/2000/svg","g"),f={submit:!0},d={},p=function(){function e(e){var t=this;this.childComponentLocations={},this.browserRendererId=e,this.eventDelegator=new o.EventDelegator((function(e,n,r,o){!function(e,t,n,r,o){f[e.type]&&e.preventDefault();var i={browserRendererId:t,eventHandlerId:n,eventArgsType:r.type,eventFieldInfo:o};s.dispatchEvent(i,r.data)}(e,t.browserRendererId,n,r,o)})),u.attachToEventDelegator(this.eventDelegator)}return e.prototype.attachRootComponentToLogicalElement=function(e,t){this.attachComponentToElement(e,t),d[e]=t},e.prototype.updateComponent=function(e,t,n,r){var o,a=this.childComponentLocations[t];if(!a)throw new Error("No element is currently associated with component "+t);var s=d[t];if(s){var u=i.getLogicalSiblingEnd(s);delete d[t],u?function(e,t){var n=i.getLogicalParent(e);if(!n)throw new Error("Can't clear between nodes. The start node does not have a logical parent.");for(var r=i.getLogicalChildrenArray(n),o=r.indexOf(e)+1,a=r.indexOf(t),s=o;s<=a;s++)i.removeLogicalChild(n,o);e.textContent="!"}(s,u):function(e){var t;for(;t=e.firstChild;)e.removeChild(t)}(s)}var c=null===(o=i.getClosestDomElement(a))||void 0===o?void 0:o.ownerDocument,l=c&&c.activeElement;this.applyEdits(e,t,a,0,n,r),l instanceof HTMLElement&&c&&c.activeElement!==l&&l.focus()},e.prototype.disposeComponent=function(e){delete this.childComponentLocations[e]},e.prototype.disposeEventHandler=function(e){this.eventDelegator.removeListener(e)},e.prototype.attachComponentToElement=function(e,t){this.childComponentLocations[e]=t},e.prototype.applyEdits=function(e,t,n,o,a,s){for(var u,c=0,l=o,f=e.arrayBuilderSegmentReader,d=e.editReader,p=e.frameReader,h=f.values(a),m=f.offset(a),v=m+f.count(a),y=m;y0&&e.invokeMethodAsync("OnSpacerAfterVisible",r.boundingClientRect.bottom-r.intersectionRect.bottom,i)}}))}),{root:o(t),rootMargin:i+"px"});a.observe(t),a.observe(n);var s=c(t),u=c(n);function c(e){var t=new MutationObserver((function(){a.unobserve(e),a.observe(e)}));return t.observe(e,{attributes:!0}),t}r[e._id]={intersectionObserver:a,mutationObserverBefore:s,mutationObserverAfter:u}},dispose:function(e){var t=r[e._id];t&&(t.intersectionObserver.disconnect(),t.mutationObserverBefore.disconnect(),t.mutationObserverAfter.disconnect(),e.dispose(),delete r[e._id])}};var r={};function o(e){return e?"visible"!==getComputedStyle(e).overflowY?e:o(e.parentElement):null}},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,i){function a(e){try{u(r.next(e))}catch(e){i(e)}}function s(e){try{u(r.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}u((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,i,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function s(i){return function(s){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return a.label++,{value:i[1],done:!1};case 5:a.label++,r=i[1],i=[0];continue;case 7:i=a.ops.pop(),a.trys.pop();continue;default:if(!(o=a.trys,(o=o.length>0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0)&&!(r=i.next()).done;)a.push(r.value)}catch(e){o={error:e}}finally{try{r&&!r.done&&(n=i.return)&&n.call(i)}finally{if(o)throw o.error}}return a};Object.defineProperty(t,"__esModule",{value:!0});var a=n(3);n(22);var s=n(17),u=n(44),c=n(4),l=n(46),f=n(33),d=n(18),p=n(47),h=n(48),m=n(49),v=!1;function y(e){return r(this,void 0,void 0,(function(){var t,n,f,y,b,g,w,E,_=this;return o(this,(function(I){switch(I.label){case 0:if(v)throw new Error("Blazor has already started.");return v=!0,d.setEventDispatcher((function(e,t){c.getRendererer(e.browserRendererId).eventDelegator.getHandler(e.eventHandlerId)&&u.monoPlatform.invokeWhenHeapUnlocked((function(){return a.DotNet.invokeMethodAsync("Microsoft.AspNetCore.Components.WebAssembly","DispatchEvent",e,JSON.stringify(t))}))})),t=s.setPlatform(u.monoPlatform),window.Blazor.platform=t,window.Blazor._internal.renderBatch=function(e,t){var n=u.monoPlatform.beginHeapLock();try{c.renderBatch(e,new l.SharedMemoryRenderBatch(t))}finally{n.release()}},n=window.Blazor._internal.navigationManager.getBaseURI,f=window.Blazor._internal.navigationManager.getLocationHref,window.Blazor._internal.navigationManager.getUnmarshalledBaseURI=function(){return BINDING.js_string_to_mono_string(n())},window.Blazor._internal.navigationManager.getUnmarshalledLocationHref=function(){return BINDING.js_string_to_mono_string(f())},window.Blazor._internal.navigationManager.listenForNavigationEvents((function(e,t){return r(_,void 0,void 0,(function(){return o(this,(function(n){switch(n.label){case 0:return[4,a.DotNet.invokeMethodAsync("Microsoft.AspNetCore.Components.WebAssembly","NotifyLocationChanged",e,t)];case 1:return n.sent(),[2]}}))}))})),y=null==e?void 0:e.environment,[4,m.BootConfigResult.initAsync(y)];case 1:return b=I.sent(),[4,Promise.all([p.WebAssemblyResourceLoader.initAsync(b.bootConfig,e||{}),h.WebAssemblyConfigLoader.initAsync(b)])];case 2:g=i.apply(void 0,[I.sent(),1]),w=g[0],I.label=3;case 3:return I.trys.push([3,5,,6]),[4,t.start(w)];case 4:return I.sent(),[3,6];case 5:throw E=I.sent(),new Error("Failed to start platform. Reason: "+E);case 6:return t.callEntryPoint(w.bootConfig.entryAssembly),[2]}}))}))}window.Blazor.start=y,f.shouldAutoStart()&&y().catch((function(e){"undefined"!=typeof Module&&Module.printErr?Module.printErr(e):console.error(e)}))},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,i){function a(e){try{u(r.next(e))}catch(e){i(e)}}function s(e){try{u(r.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}u((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,i,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function s(i){return function(s){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return a.label++,{value:i[1],done:!1};case 5:a.label++,r=i[1],i=[0];continue;case 7:i=a.ops.pop(),a.trys.pop();continue;default:if(!(o=a.trys,(o=o.length>0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]>2]}t.monoPlatform={start:function(e){return new Promise((function(t,n){var c,l;s.attachDebuggerHotkey(e),window.Browser={init:function(){}},c=function(){window.Module=function(e,t,n){var c=this,l=e.bootConfig.resources,f=window.Module||{},d=["DEBUGGING ENABLED"];f.print=function(e){return d.indexOf(e)<0&&console.log(e)},f.printErr=function(e){console.error(e),u.showErrorNotification()},f.preRun=f.preRun||[],f.postRun=f.postRun||[],f.preloadPlugins=[];var h,b,g=e.loadResources(l.assembly,(function(e){return"_framework/"+e}),"assembly"),w=e.loadResources(l.pdb||{},(function(e){return"_framework/"+e}),"pdb"),E=e.loadResource("dotnet.wasm","_framework/dotnet.wasm",e.bootConfig.resources.runtime["dotnet.wasm"],"dotnetwasm");return e.bootConfig.resources.runtime.hasOwnProperty("dotnet.timezones.blat")&&(h=e.loadResource("dotnet.timezones.blat","_framework/dotnet.timezones.blat",e.bootConfig.resources.runtime["dotnet.timezones.blat"],"globalization")),e.bootConfig.resources.runtime.hasOwnProperty("icudt.dat")&&(b=e.loadResource("icudt.dat","_framework/icudt.dat",e.bootConfig.resources.runtime["icudt.dat"],"globalization")),f.instantiateWasm=function(e,t){return r(c,void 0,void 0,(function(){var n,r;return o(this,(function(o){switch(o.label){case 0:return o.trys.push([0,3,,4]),[4,E];case 1:return[4,v(o.sent(),e)];case 2:return n=o.sent(),[3,4];case 3:throw r=o.sent(),f.printErr(r),r;case 4:return t(n),[2]}}))})),[]},f.preRun.push((function(){i=cwrap("mono_wasm_add_assembly",null,["string","number","number"]),MONO.loaded_files=[],h&&function(e){r(this,void 0,void 0,(function(){var t,n;return o(this,(function(r){switch(r.label){case 0:return t="blazor:timezonedata",addRunDependency(t),[4,e.response];case 1:return[4,r.sent().arrayBuffer()];case 2:return n=r.sent(),Module.FS_createPath("/","usr",!0,!0),Module.FS_createPath("/usr/","share",!0,!0),Module.FS_createPath("/usr/share/","zoneinfo",!0,!0),MONO.mono_wasm_load_data_archive(new Uint8Array(n),"/usr/share/zoneinfo/"),removeRunDependency(t),[2]}}))}))}(h),b?function(e){r(this,void 0,void 0,(function(){var t,n,r,i,a;return o(this,(function(o){switch(o.label){case 0:return t="blazor:icudata",addRunDependency(t),[4,e.response];case 1:return n=o.sent(),i=Uint8Array.bind,[4,n.arrayBuffer()];case 2:if(r=new(i.apply(Uint8Array,[void 0,o.sent()])),a=MONO.mono_wasm_load_bytes_into_heap(r),!MONO.mono_wasm_load_icu_data(a))throw new Error("Error loading ICU asset.");return removeRunDependency(t),[2]}}))}))}(b):MONO.mono_wasm_setenv("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT","1"),g.forEach((function(e){return _(e,function(e,t){var n=e.lastIndexOf(".");if(n<0)throw new Error("No extension to replace in '"+e+"'");return e.substr(0,n)+t}(e.name,".dll"))})),w.forEach((function(e){return _(e,e.name)})),window.Blazor._internal.dotNetCriticalError=function(e){f.printErr(BINDING.conv_string(e)||"(null)")},window.Blazor._internal.getSatelliteAssemblies=function(t){var n=BINDING.mono_array_to_js_array(t),i=e.bootConfig.resources.satelliteResources;if(i){var a=Promise.all(n.filter((function(e){return i.hasOwnProperty(e)})).map((function(t){return e.loadResources(i[t],(function(e){return"_framework/"+e}),"assembly")})).reduce((function(e,t){return e.concat(t)}),new Array).map((function(e){return r(c,void 0,void 0,(function(){return o(this,(function(t){switch(t.label){case 0:return[4,e.response];case 1:return[2,t.sent().arrayBuffer()]}}))}))})));return BINDING.js_to_mono_obj(a.then((function(e){return e.length&&(window.Blazor._internal.readSatelliteAssemblies=function(){for(var t=BINDING.mono_obj_array_new(e.length),n=0;n>1];var n},readInt32Field:function(e,t){return d(e+(t||0))},readUint64Field:function(e,t){return function(e){var t=e>>2,n=Module.HEAPU32[t+1];if(n>l)throw new Error("Cannot read uint64 with high order part "+n+", because the result would exceed Number.MAX_SAFE_INTEGER.");return n*c+Module.HEAPU32[t]}(e+(t||0))},readFloatField:function(e,t){return n=e+(t||0),Module.HEAPF32[n>>2];var n},readObjectField:function(e,t){return d(e+(t||0))},readStringField:function(e,t,n){var r,o=d(e+(t||0));if(0===o)return null;if(n){var i=BINDING.unbox_mono_obj(o);return"boolean"==typeof i?i?"":null:i}return f?void 0===(r=f.stringCache.get(o))&&(r=BINDING.conv_string(o),f.stringCache.set(o,r)):r=BINDING.conv_string(o),r},readStructField:function(e,t){return e+(t||0)},beginHeapLock:function(){return y(),f=new b},invokeWhenHeapUnlocked:function(e){f?f.enqueuePostReleaseAction(e):e()}};var p=document.createElement("a");function h(e){return e+12}function m(e,t,n){var r="["+e+"] "+t+":"+n;return BINDING.bind_static_method(r)}function v(e,t){return r(this,void 0,void 0,(function(){var n,r;return o(this,(function(o){switch(o.label){case 0:if("function"!=typeof WebAssembly.instantiateStreaming)return[3,4];o.label=1;case 1:return o.trys.push([1,3,,4]),[4,WebAssembly.instantiateStreaming(e.response,t)];case 2:return[2,o.sent().instance];case 3:return n=o.sent(),console.info("Streaming compilation failed. Falling back to ArrayBuffer instantiation. ",n),[3,4];case 4:return[4,e.response.then((function(e){return e.arrayBuffer()}))];case 5:return r=o.sent(),[4,WebAssembly.instantiate(r,t)];case 6:return[2,o.sent().instance]}}))}))}function y(){if(f)throw new Error("Assertion failed - heap is currently locked")}var b=function(){function e(){this.stringCache=new Map}return e.prototype.enqueuePostReleaseAction=function(e){this.postReleaseActions||(this.postReleaseActions=[]),this.postReleaseActions.push(e)},e.prototype.release=function(){var e;if(f!==this)throw new Error("Trying to release a lock which isn't current");for(f=null;null===(e=this.postReleaseActions)||void 0===e?void 0:e.length;){this.postReleaseActions.shift()(),y()}},e}()},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=window.chrome&&navigator.userAgent.indexOf("Edge")<0,o=!0;window.addEventListener("load",(function(){var e=new URLSearchParams(window.location.search);o="true"===e.get("_blazor_debug")}));var i=!1;function a(){return o&&i&&r}t.hasDebuggingEnabled=a,t.attachDebuggerHotkey=function(e){i=!!e.bootConfig.resources.pdb;var t=navigator.platform.match(/^Mac/i)?"Cmd":"Alt";a()&&console.info("Debugging hotkey: Shift+"+t+"+D (when application has focus)"),document.addEventListener("keydown",(function(e){var t;e.shiftKey&&(e.metaKey||e.altKey)&&"KeyD"===e.code&&(i?r?o?((t=document.createElement("a")).href="_framework/debug?url="+encodeURIComponent(location.href),t.target="_blank",t.rel="noopener noreferrer",t.click()):console.error("_blazor_debug query parameter must be set to enable debugging. To enable debugging, go to "+location.href+"?_blazor_debug=true."):console.error("Currently, only Microsoft Edge (80+), or Google Chrome, are supported for debugging."):console.error("Cannot start debugging, because the application was not compiled with debugging enabled."))}))}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(17),o=function(){function e(e){this.batchAddress=e,this.arrayRangeReader=i,this.arrayBuilderSegmentReader=a,this.diffReader=s,this.editReader=u,this.frameReader=c}return e.prototype.updatedComponents=function(){return r.platform.readStructField(this.batchAddress,0)},e.prototype.referenceFrames=function(){return r.platform.readStructField(this.batchAddress,i.structLength)},e.prototype.disposedComponentIds=function(){return r.platform.readStructField(this.batchAddress,2*i.structLength)},e.prototype.disposedEventHandlerIds=function(){return r.platform.readStructField(this.batchAddress,3*i.structLength)},e.prototype.updatedComponentsEntry=function(e,t){return l(e,t,s.structLength)},e.prototype.referenceFramesEntry=function(e,t){return l(e,t,c.structLength)},e.prototype.disposedComponentIdsEntry=function(e,t){var n=l(e,t,4);return r.platform.readInt32Field(n)},e.prototype.disposedEventHandlerIdsEntry=function(e,t){var n=l(e,t,8);return r.platform.readUint64Field(n)},e}();t.SharedMemoryRenderBatch=o;var i={structLength:8,values:function(e){return r.platform.readObjectField(e,0)},count:function(e){return r.platform.readInt32Field(e,4)}},a={structLength:12,values:function(e){var t=r.platform.readObjectField(e,0),n=r.platform.getObjectFieldsBaseAddress(t);return r.platform.readObjectField(n,0)},offset:function(e){return r.platform.readInt32Field(e,4)},count:function(e){return r.platform.readInt32Field(e,8)}},s={structLength:4+a.structLength,componentId:function(e){return r.platform.readInt32Field(e,0)},edits:function(e){return r.platform.readStructField(e,4)},editsEntry:function(e,t){return l(e,t,u.structLength)}},u={structLength:20,editType:function(e){return r.platform.readInt32Field(e,0)},siblingIndex:function(e){return r.platform.readInt32Field(e,4)},newTreeIndex:function(e){return r.platform.readInt32Field(e,8)},moveToSiblingIndex:function(e){return r.platform.readInt32Field(e,8)},removedAttributeName:function(e){return r.platform.readStringField(e,16)}},c={structLength:36,frameType:function(e){return r.platform.readInt16Field(e,4)},subtreeLength:function(e){return r.platform.readInt32Field(e,8)},elementReferenceCaptureId:function(e){return r.platform.readStringField(e,16)},componentId:function(e){return r.platform.readInt32Field(e,12)},elementName:function(e){return r.platform.readStringField(e,16)},textContent:function(e){return r.platform.readStringField(e,16)},markupContent:function(e){return r.platform.readStringField(e,16)},attributeName:function(e){return r.platform.readStringField(e,16)},attributeValue:function(e){return r.platform.readStringField(e,24,!0)},attributeEventHandlerId:function(e){return r.platform.readUint64Field(e,8)}};function l(e,t,n){return r.platform.getArrayEntryPtr(e,t,n)}},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,i){function a(e){try{u(r.next(e))}catch(e){i(e)}}function s(e){try{u(r.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}u((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,i,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function s(i){return function(s){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return a.label++,{value:i[1],done:!1};case 5:a.label++,r=i[1],i=[0];continue;case 7:i=a.ops.pop(),a.trys.pop();continue;default:if(!(o=a.trys,(o=o.length>0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&!t)throw new Error("New logical elements must start empty, or allowExistingContents must be true");return r in e||(e[r]=[]),e}function s(e,t,n){var i=e;if(e instanceof Comment&&(c(i)&&c(i).length>0))throw new Error("Not implemented: inserting non-empty logical container");if(u(i))throw new Error("Not implemented: moving existing logical children");var a=c(t);if(n0;)e(r,0)}var i=r;i.parentNode.removeChild(i)},t.getLogicalParent=u,t.getLogicalSiblingEnd=function(e){return e[i]||null},t.getLogicalChild=function(e,t){return c(e)[t]},t.isSvgElement=function(e){return"http://www.w3.org/2000/svg"===l(e).namespaceURI},t.getLogicalChildrenArray=c,t.permuteLogicalChildren=function(e,t){var n=c(e);t.forEach((function(e){e.moveRangeStart=n[e.fromSiblingIndex],e.moveRangeEnd=function e(t){if(t instanceof Element)return t;var n=f(t);if(n)return n.previousSibling;var r=u(t);return r instanceof Element?r.lastChild:e(r)}(e.moveRangeStart)})),t.forEach((function(t){var r=t.moveToBeforeMarker=document.createComment("marker"),o=n[t.toSiblingIndex+1];o?o.parentNode.insertBefore(r,o):d(r,e)})),t.forEach((function(e){for(var t=e.moveToBeforeMarker,n=t.parentNode,r=e.moveRangeStart,o=e.moveRangeEnd,i=r;i;){var a=i.nextSibling;if(n.insertBefore(i,t),i===o)break;i=a}n.removeChild(t)})),t.forEach((function(e){n[e.toSiblingIndex]=e.moveRangeStart}))},t.getClosestDomElement=l},,,,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.setPlatform=function(e){return t.platform=e,t.platform}},function(e,t,n){"use strict";var r;Object.defineProperty(t,"__esModule",{value:!0}),t.dispatchEvent=function(e,t){if(!r)throw new Error("eventDispatcher not initialized. Call 'setEventDispatcher' to configure it.");r(e,t)},t.setEventDispatcher=function(e){r=e}},,,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(7),o=n(4),i=n(30),a=n(31);window.Blazor={navigateTo:r.navigateTo,_internal:{attachRootComponentToElement:o.attachRootComponentToElement,navigationManager:r.internalFunctions,domWrapper:i.domFunctions,Virtualize:a.Virtualize}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0})},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(25),o=n(26),i=n(12),a=n(29),s=n(18),u=n(7),c=document.createElement("template"),l=document.createElementNS("http://www.w3.org/2000/svg","g"),f={submit:!0},d={},p=function(){function e(e){var t=this;this.childComponentLocations={},this.browserRendererId=e,this.eventDelegator=new o.EventDelegator((function(e,n,r,o){!function(e,t,n,r,o){f[e.type]&&e.preventDefault();var i={browserRendererId:t,eventHandlerId:n,eventArgsType:r.type,eventFieldInfo:o};s.dispatchEvent(i,r.data)}(e,t.browserRendererId,n,r,o)})),u.attachToEventDelegator(this.eventDelegator)}return e.prototype.attachRootComponentToLogicalElement=function(e,t){this.attachComponentToElement(e,t),d[e]=t},e.prototype.updateComponent=function(e,t,n,r){var o,a=this.childComponentLocations[t];if(!a)throw new Error("No element is currently associated with component "+t);var s=d[t];if(s){var u=i.getLogicalSiblingEnd(s);delete d[t],u?function(e,t){var n=i.getLogicalParent(e);if(!n)throw new Error("Can't clear between nodes. The start node does not have a logical parent.");for(var r=i.getLogicalChildrenArray(n),o=r.indexOf(e)+1,a=r.indexOf(t),s=o;s<=a;s++)i.removeLogicalChild(n,o);e.textContent="!"}(s,u):function(e){var t;for(;t=e.firstChild;)e.removeChild(t)}(s)}var c=null===(o=i.getClosestDomElement(a))||void 0===o?void 0:o.ownerDocument,l=c&&c.activeElement;this.applyEdits(e,t,a,0,n,r),l instanceof HTMLElement&&c&&c.activeElement!==l&&l.focus()},e.prototype.disposeComponent=function(e){delete this.childComponentLocations[e]},e.prototype.disposeEventHandler=function(e){this.eventDelegator.removeListener(e)},e.prototype.attachComponentToElement=function(e,t){this.childComponentLocations[e]=t},e.prototype.applyEdits=function(e,t,n,o,a,s){for(var u,c=0,l=o,f=e.arrayBuilderSegmentReader,d=e.editReader,p=e.frameReader,h=f.values(a),m=f.offset(a),v=m+f.count(a),y=m;y0&&e.invokeMethodAsync("OnSpacerAfterVisible",r.boundingClientRect.bottom-r.intersectionRect.bottom,i,a)}}))}),{root:o(t),rootMargin:i+"px"});a.observe(t),a.observe(n);var s=c(t),u=c(n);function c(e){var t=new MutationObserver((function(){a.unobserve(e),a.observe(e)}));return t.observe(e,{attributes:!0}),t}r[e._id]={intersectionObserver:a,mutationObserverBefore:s,mutationObserverAfter:u}},dispose:function(e){var t=r[e._id];t&&(t.intersectionObserver.disconnect(),t.mutationObserverBefore.disconnect(),t.mutationObserverAfter.disconnect(),e.dispose(),delete r[e._id])}};var r={};function o(e){return e?"visible"!==getComputedStyle(e).overflowY?e:o(e.parentElement):null}},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,i){function a(e){try{u(r.next(e))}catch(e){i(e)}}function s(e){try{u(r.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}u((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,i,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function s(i){return function(s){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return a.label++,{value:i[1],done:!1};case 5:a.label++,r=i[1],i=[0];continue;case 7:i=a.ops.pop(),a.trys.pop();continue;default:if(!(o=a.trys,(o=o.length>0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0)&&!(r=i.next()).done;)a.push(r.value)}catch(e){o={error:e}}finally{try{r&&!r.done&&(n=i.return)&&n.call(i)}finally{if(o)throw o.error}}return a};Object.defineProperty(t,"__esModule",{value:!0});var a=n(3);n(22);var s=n(17),u=n(44),c=n(4),l=n(46),f=n(33),d=n(18),p=n(47),h=n(48),m=n(49),v=!1;function y(e){return r(this,void 0,void 0,(function(){var t,n,f,y,b,g,w,E,_=this;return o(this,(function(I){switch(I.label){case 0:if(v)throw new Error("Blazor has already started.");return v=!0,d.setEventDispatcher((function(e,t){c.getRendererer(e.browserRendererId).eventDelegator.getHandler(e.eventHandlerId)&&u.monoPlatform.invokeWhenHeapUnlocked((function(){return a.DotNet.invokeMethodAsync("Microsoft.AspNetCore.Components.WebAssembly","DispatchEvent",e,JSON.stringify(t))}))})),t=s.setPlatform(u.monoPlatform),window.Blazor.platform=t,window.Blazor._internal.renderBatch=function(e,t){var n=u.monoPlatform.beginHeapLock();try{c.renderBatch(e,new l.SharedMemoryRenderBatch(t))}finally{n.release()}},n=window.Blazor._internal.navigationManager.getBaseURI,f=window.Blazor._internal.navigationManager.getLocationHref,window.Blazor._internal.navigationManager.getUnmarshalledBaseURI=function(){return BINDING.js_string_to_mono_string(n())},window.Blazor._internal.navigationManager.getUnmarshalledLocationHref=function(){return BINDING.js_string_to_mono_string(f())},window.Blazor._internal.navigationManager.listenForNavigationEvents((function(e,t){return r(_,void 0,void 0,(function(){return o(this,(function(n){switch(n.label){case 0:return[4,a.DotNet.invokeMethodAsync("Microsoft.AspNetCore.Components.WebAssembly","NotifyLocationChanged",e,t)];case 1:return n.sent(),[2]}}))}))})),y=null==e?void 0:e.environment,[4,m.BootConfigResult.initAsync(y)];case 1:return b=I.sent(),[4,Promise.all([p.WebAssemblyResourceLoader.initAsync(b.bootConfig,e||{}),h.WebAssemblyConfigLoader.initAsync(b)])];case 2:g=i.apply(void 0,[I.sent(),1]),w=g[0],I.label=3;case 3:return I.trys.push([3,5,,6]),[4,t.start(w)];case 4:return I.sent(),[3,6];case 5:throw E=I.sent(),new Error("Failed to start platform. Reason: "+E);case 6:return t.callEntryPoint(w.bootConfig.entryAssembly),[2]}}))}))}window.Blazor.start=y,f.shouldAutoStart()&&y().catch((function(e){"undefined"!=typeof Module&&Module.printErr?Module.printErr(e):console.error(e)}))},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,i){function a(e){try{u(r.next(e))}catch(e){i(e)}}function s(e){try{u(r.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}u((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,i,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function s(i){return function(s){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return a.label++,{value:i[1],done:!1};case 5:a.label++,r=i[1],i=[0];continue;case 7:i=a.ops.pop(),a.trys.pop();continue;default:if(!(o=a.trys,(o=o.length>0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]>2]}t.monoPlatform={start:function(e){return new Promise((function(t,n){var c,l;s.attachDebuggerHotkey(e),window.Browser={init:function(){}},c=function(){window.Module=function(e,t,n){var c=this,l=e.bootConfig.resources,f=window.Module||{},d=["DEBUGGING ENABLED"];f.print=function(e){return d.indexOf(e)<0&&console.log(e)},f.printErr=function(e){console.error(e),u.showErrorNotification()},f.preRun=f.preRun||[],f.postRun=f.postRun||[],f.preloadPlugins=[];var h,b,g=e.loadResources(l.assembly,(function(e){return"_framework/"+e}),"assembly"),w=e.loadResources(l.pdb||{},(function(e){return"_framework/"+e}),"pdb"),E=e.loadResource("dotnet.wasm","_framework/dotnet.wasm",e.bootConfig.resources.runtime["dotnet.wasm"],"dotnetwasm");return e.bootConfig.resources.runtime.hasOwnProperty("dotnet.timezones.blat")&&(h=e.loadResource("dotnet.timezones.blat","_framework/dotnet.timezones.blat",e.bootConfig.resources.runtime["dotnet.timezones.blat"],"globalization")),e.bootConfig.resources.runtime.hasOwnProperty("icudt.dat")&&(b=e.loadResource("icudt.dat","_framework/icudt.dat",e.bootConfig.resources.runtime["icudt.dat"],"globalization")),f.instantiateWasm=function(e,t){return r(c,void 0,void 0,(function(){var n,r;return o(this,(function(o){switch(o.label){case 0:return o.trys.push([0,3,,4]),[4,E];case 1:return[4,v(o.sent(),e)];case 2:return n=o.sent(),[3,4];case 3:throw r=o.sent(),f.printErr(r),r;case 4:return t(n),[2]}}))})),[]},f.preRun.push((function(){i=cwrap("mono_wasm_add_assembly",null,["string","number","number"]),MONO.loaded_files=[],h&&function(e){r(this,void 0,void 0,(function(){var t,n;return o(this,(function(r){switch(r.label){case 0:return t="blazor:timezonedata",addRunDependency(t),[4,e.response];case 1:return[4,r.sent().arrayBuffer()];case 2:return n=r.sent(),Module.FS_createPath("/","usr",!0,!0),Module.FS_createPath("/usr/","share",!0,!0),Module.FS_createPath("/usr/share/","zoneinfo",!0,!0),MONO.mono_wasm_load_data_archive(new Uint8Array(n),"/usr/share/zoneinfo/"),removeRunDependency(t),[2]}}))}))}(h),b?function(e){r(this,void 0,void 0,(function(){var t,n,r,i,a;return o(this,(function(o){switch(o.label){case 0:return t="blazor:icudata",addRunDependency(t),[4,e.response];case 1:return n=o.sent(),i=Uint8Array.bind,[4,n.arrayBuffer()];case 2:if(r=new(i.apply(Uint8Array,[void 0,o.sent()])),a=MONO.mono_wasm_load_bytes_into_heap(r),!MONO.mono_wasm_load_icu_data(a))throw new Error("Error loading ICU asset.");return removeRunDependency(t),[2]}}))}))}(b):MONO.mono_wasm_setenv("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT","1"),g.forEach((function(e){return _(e,function(e,t){var n=e.lastIndexOf(".");if(n<0)throw new Error("No extension to replace in '"+e+"'");return e.substr(0,n)+t}(e.name,".dll"))})),w.forEach((function(e){return _(e,e.name)})),window.Blazor._internal.dotNetCriticalError=function(e){f.printErr(BINDING.conv_string(e)||"(null)")},window.Blazor._internal.getSatelliteAssemblies=function(t){var n=BINDING.mono_array_to_js_array(t),i=e.bootConfig.resources.satelliteResources;if(i){var a=Promise.all(n.filter((function(e){return i.hasOwnProperty(e)})).map((function(t){return e.loadResources(i[t],(function(e){return"_framework/"+e}),"assembly")})).reduce((function(e,t){return e.concat(t)}),new Array).map((function(e){return r(c,void 0,void 0,(function(){return o(this,(function(t){switch(t.label){case 0:return[4,e.response];case 1:return[2,t.sent().arrayBuffer()]}}))}))})));return BINDING.js_to_mono_obj(a.then((function(e){return e.length&&(window.Blazor._internal.readSatelliteAssemblies=function(){for(var t=BINDING.mono_obj_array_new(e.length),n=0;n>1];var n},readInt32Field:function(e,t){return d(e+(t||0))},readUint64Field:function(e,t){return function(e){var t=e>>2,n=Module.HEAPU32[t+1];if(n>l)throw new Error("Cannot read uint64 with high order part "+n+", because the result would exceed Number.MAX_SAFE_INTEGER.");return n*c+Module.HEAPU32[t]}(e+(t||0))},readFloatField:function(e,t){return n=e+(t||0),Module.HEAPF32[n>>2];var n},readObjectField:function(e,t){return d(e+(t||0))},readStringField:function(e,t,n){var r,o=d(e+(t||0));if(0===o)return null;if(n){var i=BINDING.unbox_mono_obj(o);return"boolean"==typeof i?i?"":null:i}return f?void 0===(r=f.stringCache.get(o))&&(r=BINDING.conv_string(o),f.stringCache.set(o,r)):r=BINDING.conv_string(o),r},readStructField:function(e,t){return e+(t||0)},beginHeapLock:function(){return y(),f=new b},invokeWhenHeapUnlocked:function(e){f?f.enqueuePostReleaseAction(e):e()}};var p=document.createElement("a");function h(e){return e+12}function m(e,t,n){var r="["+e+"] "+t+":"+n;return BINDING.bind_static_method(r)}function v(e,t){return r(this,void 0,void 0,(function(){var n,r;return o(this,(function(o){switch(o.label){case 0:if("function"!=typeof WebAssembly.instantiateStreaming)return[3,4];o.label=1;case 1:return o.trys.push([1,3,,4]),[4,WebAssembly.instantiateStreaming(e.response,t)];case 2:return[2,o.sent().instance];case 3:return n=o.sent(),console.info("Streaming compilation failed. Falling back to ArrayBuffer instantiation. ",n),[3,4];case 4:return[4,e.response.then((function(e){return e.arrayBuffer()}))];case 5:return r=o.sent(),[4,WebAssembly.instantiate(r,t)];case 6:return[2,o.sent().instance]}}))}))}function y(){if(f)throw new Error("Assertion failed - heap is currently locked")}var b=function(){function e(){this.stringCache=new Map}return e.prototype.enqueuePostReleaseAction=function(e){this.postReleaseActions||(this.postReleaseActions=[]),this.postReleaseActions.push(e)},e.prototype.release=function(){var e;if(f!==this)throw new Error("Trying to release a lock which isn't current");for(f=null;null===(e=this.postReleaseActions)||void 0===e?void 0:e.length;){this.postReleaseActions.shift()(),y()}},e}()},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=window.chrome&&navigator.userAgent.indexOf("Edge")<0,o=!0;window.addEventListener("load",(function(){var e=new URLSearchParams(window.location.search);o="true"===e.get("_blazor_debug")}));var i=!1;function a(){return o&&i&&r}t.hasDebuggingEnabled=a,t.attachDebuggerHotkey=function(e){i=!!e.bootConfig.resources.pdb;var t=navigator.platform.match(/^Mac/i)?"Cmd":"Alt";a()&&console.info("Debugging hotkey: Shift+"+t+"+D (when application has focus)"),document.addEventListener("keydown",(function(e){var t;e.shiftKey&&(e.metaKey||e.altKey)&&"KeyD"===e.code&&(i?r?o?((t=document.createElement("a")).href="_framework/debug?url="+encodeURIComponent(location.href),t.target="_blank",t.rel="noopener noreferrer",t.click()):console.error("_blazor_debug query parameter must be set to enable debugging. To enable debugging, go to "+location.href+"?_blazor_debug=true."):console.error("Currently, only Microsoft Edge (80+), or Google Chrome, are supported for debugging."):console.error("Cannot start debugging, because the application was not compiled with debugging enabled."))}))}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(17),o=function(){function e(e){this.batchAddress=e,this.arrayRangeReader=i,this.arrayBuilderSegmentReader=a,this.diffReader=s,this.editReader=u,this.frameReader=c}return e.prototype.updatedComponents=function(){return r.platform.readStructField(this.batchAddress,0)},e.prototype.referenceFrames=function(){return r.platform.readStructField(this.batchAddress,i.structLength)},e.prototype.disposedComponentIds=function(){return r.platform.readStructField(this.batchAddress,2*i.structLength)},e.prototype.disposedEventHandlerIds=function(){return r.platform.readStructField(this.batchAddress,3*i.structLength)},e.prototype.updatedComponentsEntry=function(e,t){return l(e,t,s.structLength)},e.prototype.referenceFramesEntry=function(e,t){return l(e,t,c.structLength)},e.prototype.disposedComponentIdsEntry=function(e,t){var n=l(e,t,4);return r.platform.readInt32Field(n)},e.prototype.disposedEventHandlerIdsEntry=function(e,t){var n=l(e,t,8);return r.platform.readUint64Field(n)},e}();t.SharedMemoryRenderBatch=o;var i={structLength:8,values:function(e){return r.platform.readObjectField(e,0)},count:function(e){return r.platform.readInt32Field(e,4)}},a={structLength:12,values:function(e){var t=r.platform.readObjectField(e,0),n=r.platform.getObjectFieldsBaseAddress(t);return r.platform.readObjectField(n,0)},offset:function(e){return r.platform.readInt32Field(e,4)},count:function(e){return r.platform.readInt32Field(e,8)}},s={structLength:4+a.structLength,componentId:function(e){return r.platform.readInt32Field(e,0)},edits:function(e){return r.platform.readStructField(e,4)},editsEntry:function(e,t){return l(e,t,u.structLength)}},u={structLength:20,editType:function(e){return r.platform.readInt32Field(e,0)},siblingIndex:function(e){return r.platform.readInt32Field(e,4)},newTreeIndex:function(e){return r.platform.readInt32Field(e,8)},moveToSiblingIndex:function(e){return r.platform.readInt32Field(e,8)},removedAttributeName:function(e){return r.platform.readStringField(e,16)}},c={structLength:36,frameType:function(e){return r.platform.readInt16Field(e,4)},subtreeLength:function(e){return r.platform.readInt32Field(e,8)},elementReferenceCaptureId:function(e){return r.platform.readStringField(e,16)},componentId:function(e){return r.platform.readInt32Field(e,12)},elementName:function(e){return r.platform.readStringField(e,16)},textContent:function(e){return r.platform.readStringField(e,16)},markupContent:function(e){return r.platform.readStringField(e,16)},attributeName:function(e){return r.platform.readStringField(e,16)},attributeValue:function(e){return r.platform.readStringField(e,24,!0)},attributeEventHandlerId:function(e){return r.platform.readUint64Field(e,8)}};function l(e,t,n){return r.platform.getArrayEntryPtr(e,t,n)}},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))((function(o,i){function a(e){try{u(r.next(e))}catch(e){i(e)}}function s(e){try{u(r.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}u((r=r.apply(e,t||[])).next())}))},o=this&&this.__generator||function(e,t){var n,r,o,i,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function s(i){return function(s){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return a.label++,{value:i[1],done:!1};case 5:a.label++,r=i[1],i=[0];continue;case 7:i=a.ops.pop(),a.trys.pop();continue;default:if(!(o=a.trys,(o=o.length>0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1] 0) { // When we first start up, both the "before" and "after" spacers will be visible, but it's only relevant to raise a // single event to load the initial data. To avoid raising two events, skip the one for the "after" spacer if we know // it's meaningless to talk about any overlap into it. - dotNetHelper.invokeMethodAsync('OnSpacerAfterVisible', entry.boundingClientRect.bottom - entry.intersectionRect.bottom, containerSize); + dotNetHelper.invokeMethodAsync('OnSpacerAfterVisible', entry.boundingClientRect.bottom - entry.intersectionRect.bottom, spacerSeparation, containerSize); } }); } diff --git a/src/Components/Web/src/Virtualization/IVirtualizeJsCallbacks.cs b/src/Components/Web/src/Virtualization/IVirtualizeJsCallbacks.cs index f7447b9b46..b8948d057e 100644 --- a/src/Components/Web/src/Virtualization/IVirtualizeJsCallbacks.cs +++ b/src/Components/Web/src/Virtualization/IVirtualizeJsCallbacks.cs @@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization { internal interface IVirtualizeJsCallbacks { - void OnBeforeSpacerVisible(float spacerSize, float containerSize); - void OnAfterSpacerVisible(float spacerSize, float containerSize); + void OnBeforeSpacerVisible(float spacerSize, float spacerSeparation, float containerSize); + void OnAfterSpacerVisible(float spacerSize, float spacerSeparation, float containerSize); } } diff --git a/src/Components/Web/src/Virtualization/PlaceholderContext.cs b/src/Components/Web/src/Virtualization/PlaceholderContext.cs index d8b73d46ab..6cdd39d110 100644 --- a/src/Components/Web/src/Virtualization/PlaceholderContext.cs +++ b/src/Components/Web/src/Virtualization/PlaceholderContext.cs @@ -13,13 +13,24 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization /// public int Index { get; } + /// + /// The size of the placeholder in pixels. + /// + /// For virtualized components with vertical scrolling, this would be the height of the placeholder in pixels. + /// For virtualized components with horizontal scrolling, this would be the width of the placeholder in pixels. + /// + /// + public float Size { get; } + /// /// Constructs a new instance. /// /// The item index of the placeholder. - public PlaceholderContext(int index) + /// The size of the placeholder in pixels. + public PlaceholderContext(int index, float size = 0f) { Index = index; + Size = size; } } } diff --git a/src/Components/Web/src/Virtualization/Virtualize.cs b/src/Components/Web/src/Virtualization/Virtualize.cs index 97e6e04aa5..ac80974d5f 100644 --- a/src/Components/Web/src/Virtualization/Virtualize.cs +++ b/src/Components/Web/src/Virtualization/Virtualize.cs @@ -31,6 +31,12 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization private int _loadedItemsStartIndex; + private int _lastRenderedItemCount; + + private int _lastRenderedPlaceholderCount; + + private float _itemSize; + private IEnumerable? _loadedItems; private CancellationTokenSource? _refreshCts; @@ -65,10 +71,10 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization public RenderFragment? Placeholder { get; set; } /// - /// Gets the size of each item in pixels. + /// Gets the size of each item in pixels. Defaults to 50px. /// [Parameter] - public float ItemSize { get; set; } + public float ItemSize { get; set; } = 50f; /// /// Gets or sets the function providing items to the list. @@ -88,7 +94,12 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization if (ItemSize <= 0) { throw new InvalidOperationException( - $"{GetType()} requires a positive value for parameter '{nameof(ItemSize)}' to perform virtualization."); + $"{GetType()} requires a positive value for parameter '{nameof(ItemSize)}'."); + } + + if (_itemSize <= 0) + { + _itemSize = ItemSize; } if (ItemsProvider != null) @@ -154,11 +165,13 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization { // This is a rare case where it's valid for the sequence number to be programmatically incremented. // This is only true because we know for certain that no other content will be alongside it. - builder.AddContent(renderIndex, _placeholder, new PlaceholderContext(renderIndex)); + builder.AddContent(renderIndex, _placeholder, new PlaceholderContext(renderIndex, _itemSize)); } builder.CloseRegion(); + _lastRenderedItemCount = 0; + // Render the loaded items. if (_loadedItems != null && _itemTemplate != null) { @@ -171,18 +184,22 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization foreach (var item in itemsToShow) { _itemTemplate(item)(builder); - renderIndex++; + _lastRenderedItemCount++; } + renderIndex += _lastRenderedItemCount; + builder.CloseRegion(); } + _lastRenderedPlaceholderCount = Math.Max(0, lastItemIndex - _itemsBefore - _lastRenderedItemCount); + builder.OpenRegion(5); // Render the placeholders after the loaded items. for (; renderIndex < lastItemIndex; renderIndex++) { - builder.AddContent(renderIndex, _placeholder, new PlaceholderContext(renderIndex)); + builder.AddContent(renderIndex, _placeholder, new PlaceholderContext(renderIndex, _itemSize)); } builder.CloseRegion(); @@ -197,28 +214,45 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization } private string GetSpacerStyle(int itemsInSpacer) - => $"height: {itemsInSpacer * ItemSize}px;"; + => $"height: {itemsInSpacer * _itemSize}px;"; - void IVirtualizeJsCallbacks.OnBeforeSpacerVisible(float spacerSize, float containerSize) + void IVirtualizeJsCallbacks.OnBeforeSpacerVisible(float spacerSize, float spacerSeparation, float containerSize) { - CalcualteItemDistribution(spacerSize, containerSize, out var itemsBefore, out var visibleItemCapacity); + CalcualteItemDistribution(spacerSize, spacerSeparation, containerSize, out var itemsBefore, out var visibleItemCapacity); UpdateItemDistribution(itemsBefore, visibleItemCapacity); } - void IVirtualizeJsCallbacks.OnAfterSpacerVisible(float spacerSize, float containerSize) + void IVirtualizeJsCallbacks.OnAfterSpacerVisible(float spacerSize, float spacerSeparation, float containerSize) { - CalcualteItemDistribution(spacerSize, containerSize, out var itemsAfter, out var visibleItemCapacity); + CalcualteItemDistribution(spacerSize, spacerSeparation, containerSize, out var itemsAfter, out var visibleItemCapacity); var itemsBefore = Math.Max(0, _itemCount - itemsAfter - visibleItemCapacity); UpdateItemDistribution(itemsBefore, visibleItemCapacity); } - private void CalcualteItemDistribution(float spacerSize, float containerSize, out int itemsInSpacer, out int visibleItemCapacity) + private void CalcualteItemDistribution( + float spacerSize, + float spacerSeparation, + float containerSize, + out int itemsInSpacer, + out int visibleItemCapacity) { - itemsInSpacer = Math.Max(0, (int)Math.Floor(spacerSize / ItemSize) - 1); - visibleItemCapacity = (int)Math.Ceiling(containerSize / ItemSize) + 2; + if (_lastRenderedItemCount > 0) + { + _itemSize = (spacerSeparation - (_lastRenderedPlaceholderCount * _itemSize)) / _lastRenderedItemCount; + } + + if (_itemSize <= 0) + { + // At this point, something unusual has occurred, likely due to misuse of this component. + // Reset the calculated item size to the user-provided item size. + _itemSize = ItemSize; + } + + itemsInSpacer = Math.Max(0, (int)Math.Floor(spacerSize / _itemSize) - 1); + visibleItemCapacity = (int)Math.Ceiling(containerSize / _itemSize) + 2; } private void UpdateItemDistribution(int itemsBefore, int visibleItemCapacity) @@ -285,7 +319,7 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization private RenderFragment DefaultPlaceholder(PlaceholderContext context) => (builder) => { builder.OpenElement(0, "div"); - builder.AddAttribute(1, "style", $"height: {ItemSize}px;"); + builder.AddAttribute(1, "style", $"height: {_itemSize}px;"); builder.CloseElement(); }; diff --git a/src/Components/Web/src/Virtualization/VirtualizeJsInterop.cs b/src/Components/Web/src/Virtualization/VirtualizeJsInterop.cs index 2b655d1f7e..9792f0d396 100644 --- a/src/Components/Web/src/Virtualization/VirtualizeJsInterop.cs +++ b/src/Components/Web/src/Virtualization/VirtualizeJsInterop.cs @@ -30,15 +30,15 @@ namespace Microsoft.AspNetCore.Components.Web.Virtualization } [JSInvokable] - public void OnSpacerBeforeVisible(float spacerSize, float containerSize) + public void OnSpacerBeforeVisible(float spacerSize, float spacerSeparation, float containerSize) { - _owner.OnBeforeSpacerVisible(spacerSize, containerSize); + _owner.OnBeforeSpacerVisible(spacerSize, spacerSeparation, containerSize); } [JSInvokable] - public void OnSpacerAfterVisible(float spacerSize, float containerSize) + public void OnSpacerAfterVisible(float spacerSize, float spacerSeparation, float containerSize) { - _owner.OnAfterSpacerVisible(spacerSize, containerSize); + _owner.OnAfterSpacerVisible(spacerSize, spacerSeparation, containerSize); } public async ValueTask DisposeAsync() diff --git a/src/Components/Web/test/Virtualization/VirtualizeTest.cs b/src/Components/Web/test/Virtualization/VirtualizeTest.cs index cf2cd2a281..931a46545c 100644 --- a/src/Components/Web/test/Virtualization/VirtualizeTest.cs +++ b/src/Components/Web/test/Virtualization/VirtualizeTest.cs @@ -97,7 +97,7 @@ namespace Microsoft.AspNetCore.Components.Virtualization Assert.NotNull(renderedVirtualize); // Simulate a JS spacer callback. - ((IVirtualizeJsCallbacks)renderedVirtualize).OnAfterSpacerVisible(10f, 100f); + ((IVirtualizeJsCallbacks)renderedVirtualize).OnAfterSpacerVisible(10f, 50f, 100f); // Validate that the exception is dispatched through the renderer. var ex = await Assert.ThrowsAsync(async () => await testRenderer.RenderRootComponentAsync(componentId)); diff --git a/src/Components/test/testassets/BasicTestApp/VirtualizationComponent.razor b/src/Components/test/testassets/BasicTestApp/VirtualizationComponent.razor index 29aba9ea3e..69e776ccfd 100644 --- a/src/Components/test/testassets/BasicTestApp/VirtualizationComponent.razor +++ b/src/Components/test/testassets/BasicTestApp/VirtualizationComponent.razor @@ -22,7 +22,7 @@
Item @context
-
Loading item @context.Index...
+
Loading item @context.Index...
From 38563dd8d1c80f7313664dc9457f00274f4d60d6 Mon Sep 17 00:00:00 2001 From: Javier Calvarro Nelson Date: Wed, 19 Aug 2020 11:12:35 +0200 Subject: [PATCH 10/81] [Blazor][Identity] Update to the latest identity server version (#25002) * Updates to IdentityServer 4.0.4 * Updates templates with the new migrations. * Fixes a small configuration bug that required the configuration for the key to be specified. * Updates the error url in IdentityServer config to match our template defaults. --- AspNetCore.sln | 155 +++++-- eng/Dependencies.props | 1 + eng/Version.Details.xml | 4 + eng/Versions.props | 11 +- src/Components/ComponentsNoDeps.slnf | 11 +- ...20200818132003_IdentityServer4.Designer.cs | 405 ++++++++++++++++++ .../20200818132003_IdentityServer4.cs | 77 ++++ .../ApplicationDbContextModelSnapshot.cs | 114 +++-- .../Wasm.Authentication.Server.csproj | 1 + .../Tests/WebAssemblyAuthenticationTests.cs | 2 +- .../AspNetConventionsConfigureOptions.cs | 5 +- .../src/Configuration/ConfigureApiScopes.cs | 30 ++ .../Configuration/ConfigureClientScopes.cs | 4 +- .../ConfigureSigningCredentials.cs | 19 +- .../AutoRedirectEndSessionEndpoint.cs | 1 + ...ityServerBuilderConfigurationExtensions.cs | 22 +- .../src/Options/ApiAuthorizationOptions.cs | 8 +- .../src/Options/ApiResourceBuilder.cs | 9 +- .../src/Options/ApiScopeCollection.cs | 82 ++++ .../ConfigureApiResourcesTests.cs | 10 +- .../ConfigureSigningCredentialsTests.cs | 38 +- ...000000000_CreateIdentitySchema.Designer.cs | 109 +++-- .../00000000000000_CreateIdentitySchema.cs | 112 ++--- .../ApplicationDbContextModelSnapshot.cs | 111 +++-- ...000000000_CreateIdentitySchema.Designer.cs | 115 +++-- .../00000000000000_CreateIdentitySchema.cs | 112 ++--- .../ApplicationDbContextModelSnapshot.cs | 117 ++--- .../Server/app.db | Bin 135168 -> 139264 bytes ...000000000_CreateIdentitySchema.Designer.cs | 115 +++-- .../00000000000000_CreateIdentitySchema.cs | 112 ++--- .../ApplicationDbContextModelSnapshot.cs | 117 ++--- ...000000000_CreateIdentitySchema.Designer.cs | 109 +++-- .../00000000000000_CreateIdentitySchema.cs | 112 ++--- .../ApplicationDbContextModelSnapshot.cs | 111 +++-- .../content/Angular-CSharp/app.db | Bin 135168 -> 139264 bytes ...000000000_CreateIdentitySchema.Designer.cs | 115 +++-- .../00000000000000_CreateIdentitySchema.cs | 112 ++--- .../ApplicationDbContextModelSnapshot.cs | 117 ++--- ...000000000_CreateIdentitySchema.Designer.cs | 109 +++-- .../00000000000000_CreateIdentitySchema.cs | 112 ++--- .../ApplicationDbContextModelSnapshot.cs | 111 +++-- .../content/React-CSharp/app.db | Bin 135168 -> 139264 bytes 42 files changed, 2073 insertions(+), 964 deletions(-) create mode 100644 src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Data/Migrations/20200818132003_IdentityServer4.Designer.cs create mode 100644 src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Data/Migrations/20200818132003_IdentityServer4.cs create mode 100644 src/Identity/ApiAuthorization.IdentityServer/src/Configuration/ConfigureApiScopes.cs create mode 100644 src/Identity/ApiAuthorization.IdentityServer/src/Options/ApiScopeCollection.cs diff --git a/AspNetCore.sln b/AspNetCore.sln index f0f0fe4031..16238f73a3 100644 --- a/AspNetCore.sln +++ b/AspNetCore.sln @@ -1423,13 +1423,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Compon EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sdk", "Sdk", "{FED4267E-E5E4-49C5-98DB-8B3F203596EE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.NET.Sdk.BlazorWebAssembly", "src\Components\WebAssembly\Sdk\src\Microsoft.NET.Sdk.BlazorWebAssembly.csproj", "{6B2734BF-C61D-4889-ABBF-456A4075D59B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.BlazorWebAssembly", "src\Components\WebAssembly\Sdk\src\Microsoft.NET.Sdk.BlazorWebAssembly.csproj", "{6B2734BF-C61D-4889-ABBF-456A4075D59B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.NET.Sdk.BlazorWebAssembly.Tests", "src\Components\WebAssembly\Sdk\test\Microsoft.NET.Sdk.BlazorWebAssembly.Tests.csproj", "{83371889-9A3E-4D16-AE77-EB4F83BC6374}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.BlazorWebAssembly.Tests", "src\Components\WebAssembly\Sdk\test\Microsoft.NET.Sdk.BlazorWebAssembly.Tests.csproj", "{83371889-9A3E-4D16-AE77-EB4F83BC6374}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.NET.Sdk.BlazorWebAssembly.IntegrationTests", "src\Components\WebAssembly\Sdk\integrationtests\Microsoft.NET.Sdk.BlazorWebAssembly.IntegrationTests.csproj", "{525EBCB4-A870-470B-BC90-845306C337D1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.BlazorWebAssembly.IntegrationTests", "src\Components\WebAssembly\Sdk\integrationtests\Microsoft.NET.Sdk.BlazorWebAssembly.IntegrationTests.csproj", "{525EBCB4-A870-470B-BC90-845306C337D1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.NET.Sdk.BlazorWebAssembly.Tools", "src\Components\WebAssembly\Sdk\tools\Microsoft.NET.Sdk.BlazorWebAssembly.Tools.csproj", "{175E5CD8-92D4-46BB-882E-3A930D3302D4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.BlazorWebAssembly.Tools", "src\Components\WebAssembly\Sdk\tools\Microsoft.NET.Sdk.BlazorWebAssembly.Tools.csproj", "{175E5CD8-92D4-46BB-882E-3A930D3302D4}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{6126DCE4-9692-4EE2-B240-C65743572995}" EndProject @@ -1455,7 +1455,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InteropClient", "src\Grpc\t EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InteropWebsite", "src\Grpc\test\testassets\InteropWebsite\InteropWebsite.csproj", "{19189670-E206-471D-94F8-7D3D545E5020}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wasm.Performance.ConsoleHost", "src\Components\benchmarkapps\Wasm.Performance\ConsoleHost\Wasm.Performance.ConsoleHost.csproj", "{E9408723-E6A9-4715-B906-3B25B0238ABA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wasm.Performance.ConsoleHost", "src\Components\benchmarkapps\Wasm.Performance\ConsoleHost\Wasm.Performance.ConsoleHost.csproj", "{E9408723-E6A9-4715-B906-3B25B0238ABA}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InProcessWebSite", "src\Servers\IIS\IIS\test\testassets\InProcessWebSite\InProcessWebSite.csproj", "{8DA61885-B95E-4BA1-A752-C79B6597FC44}" EndProject @@ -1483,6 +1483,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Watch. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Watch.BrowserRefresh.Tests", "src\Tools\dotnet-watch\BrowserRefresh\test\Microsoft.AspNetCore.Watch.BrowserRefresh.Tests.csproj", "{E6A23627-8D63-4DF1-A4F2-8881172C1FE6}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{7D2B0799-A634-42AC-AE77-5D167BA51389}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostedInAspNet.Client", "src\Components\WebAssembly\testassets\HostedInAspNet.Client\HostedInAspNet.Client.csproj", "{9788C76F-658B-4441-88F8-22C6B86FAD27}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostedInAspNet.Server", "src\Components\WebAssembly\testassets\HostedInAspNet.Server\HostedInAspNet.Server.csproj", "{1970D5CD-D9A4-4673-A297-179BB04199F4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StandaloneApp", "src\Components\WebAssembly\testassets\StandaloneApp\StandaloneApp.csproj", "{A40350FE-4334-4007-B1C3-6BEB1B070309}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wasm.Authentication.Client", "src\Components\WebAssembly\testassets\Wasm.Authentication.Client\Wasm.Authentication.Client.csproj", "{C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wasm.Authentication.Server", "src\Components\WebAssembly\testassets\Wasm.Authentication.Server\Wasm.Authentication.Server.csproj", "{FE5290C7-45DA-46F8-BD74-698E7A161DD6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wasm.Authentication.Shared", "src\Components\WebAssembly\testassets\Wasm.Authentication.Shared\Wasm.Authentication.Shared.csproj", "{ED66DC0E-FD6A-477A-BA8A-5273AA64F580}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -6809,30 +6823,6 @@ Global {175E5CD8-92D4-46BB-882E-3A930D3302D4}.Release|x64.Build.0 = Release|Any CPU {175E5CD8-92D4-46BB-882E-3A930D3302D4}.Release|x86.ActiveCfg = Release|Any CPU {175E5CD8-92D4-46BB-882E-3A930D3302D4}.Release|x86.Build.0 = Release|Any CPU - {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|x64.ActiveCfg = Debug|Any CPU - {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|x64.Build.0 = Debug|Any CPU - {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|x86.ActiveCfg = Debug|Any CPU - {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|x86.Build.0 = Debug|Any CPU - {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|Any CPU.Build.0 = Release|Any CPU - {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|x64.ActiveCfg = Release|Any CPU - {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|x64.Build.0 = Release|Any CPU - {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|x86.ActiveCfg = Release|Any CPU - {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|x86.Build.0 = Release|Any CPU - {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|x64.ActiveCfg = Debug|Any CPU - {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|x64.Build.0 = Debug|Any CPU - {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|x86.ActiveCfg = Debug|Any CPU - {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|x86.Build.0 = Debug|Any CPU - {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|Any CPU.Build.0 = Release|Any CPU - {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|x64.ActiveCfg = Release|Any CPU - {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|x64.Build.0 = Release|Any CPU - {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|x86.ActiveCfg = Release|Any CPU - {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|x86.Build.0 = Release|Any CPU {46FB7E93-1294-4068-B80A-D4864F78277A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {46FB7E93-1294-4068-B80A-D4864F78277A}.Debug|Any CPU.Build.0 = Debug|Any CPU {46FB7E93-1294-4068-B80A-D4864F78277A}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -7071,6 +7061,102 @@ Global {7E268085-1046-4362-80CB-2977FF826DCA}.Release|x64.Build.0 = Release|Any CPU {7E268085-1046-4362-80CB-2977FF826DCA}.Release|x86.ActiveCfg = Release|Any CPU {7E268085-1046-4362-80CB-2977FF826DCA}.Release|x86.Build.0 = Release|Any CPU + {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|x64.ActiveCfg = Debug|Any CPU + {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|x64.Build.0 = Debug|Any CPU + {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|x86.ActiveCfg = Debug|Any CPU + {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Debug|x86.Build.0 = Debug|Any CPU + {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|Any CPU.Build.0 = Release|Any CPU + {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|x64.ActiveCfg = Release|Any CPU + {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|x64.Build.0 = Release|Any CPU + {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|x86.ActiveCfg = Release|Any CPU + {A5CE25E9-89E1-4F2C-9B89-0C161707E700}.Release|x86.Build.0 = Release|Any CPU + {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|x64.ActiveCfg = Debug|Any CPU + {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|x64.Build.0 = Debug|Any CPU + {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|x86.ActiveCfg = Debug|Any CPU + {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Debug|x86.Build.0 = Debug|Any CPU + {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|Any CPU.Build.0 = Release|Any CPU + {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|x64.ActiveCfg = Release|Any CPU + {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|x64.Build.0 = Release|Any CPU + {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|x86.ActiveCfg = Release|Any CPU + {E6A23627-8D63-4DF1-A4F2-8881172C1FE6}.Release|x86.Build.0 = Release|Any CPU + {9788C76F-658B-4441-88F8-22C6B86FAD27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9788C76F-658B-4441-88F8-22C6B86FAD27}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9788C76F-658B-4441-88F8-22C6B86FAD27}.Debug|x64.ActiveCfg = Debug|Any CPU + {9788C76F-658B-4441-88F8-22C6B86FAD27}.Debug|x64.Build.0 = Debug|Any CPU + {9788C76F-658B-4441-88F8-22C6B86FAD27}.Debug|x86.ActiveCfg = Debug|Any CPU + {9788C76F-658B-4441-88F8-22C6B86FAD27}.Debug|x86.Build.0 = Debug|Any CPU + {9788C76F-658B-4441-88F8-22C6B86FAD27}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9788C76F-658B-4441-88F8-22C6B86FAD27}.Release|Any CPU.Build.0 = Release|Any CPU + {9788C76F-658B-4441-88F8-22C6B86FAD27}.Release|x64.ActiveCfg = Release|Any CPU + {9788C76F-658B-4441-88F8-22C6B86FAD27}.Release|x64.Build.0 = Release|Any CPU + {9788C76F-658B-4441-88F8-22C6B86FAD27}.Release|x86.ActiveCfg = Release|Any CPU + {9788C76F-658B-4441-88F8-22C6B86FAD27}.Release|x86.Build.0 = Release|Any CPU + {1970D5CD-D9A4-4673-A297-179BB04199F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1970D5CD-D9A4-4673-A297-179BB04199F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1970D5CD-D9A4-4673-A297-179BB04199F4}.Debug|x64.ActiveCfg = Debug|Any CPU + {1970D5CD-D9A4-4673-A297-179BB04199F4}.Debug|x64.Build.0 = Debug|Any CPU + {1970D5CD-D9A4-4673-A297-179BB04199F4}.Debug|x86.ActiveCfg = Debug|Any CPU + {1970D5CD-D9A4-4673-A297-179BB04199F4}.Debug|x86.Build.0 = Debug|Any CPU + {1970D5CD-D9A4-4673-A297-179BB04199F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1970D5CD-D9A4-4673-A297-179BB04199F4}.Release|Any CPU.Build.0 = Release|Any CPU + {1970D5CD-D9A4-4673-A297-179BB04199F4}.Release|x64.ActiveCfg = Release|Any CPU + {1970D5CD-D9A4-4673-A297-179BB04199F4}.Release|x64.Build.0 = Release|Any CPU + {1970D5CD-D9A4-4673-A297-179BB04199F4}.Release|x86.ActiveCfg = Release|Any CPU + {1970D5CD-D9A4-4673-A297-179BB04199F4}.Release|x86.Build.0 = Release|Any CPU + {A40350FE-4334-4007-B1C3-6BEB1B070309}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A40350FE-4334-4007-B1C3-6BEB1B070309}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A40350FE-4334-4007-B1C3-6BEB1B070309}.Debug|x64.ActiveCfg = Debug|Any CPU + {A40350FE-4334-4007-B1C3-6BEB1B070309}.Debug|x64.Build.0 = Debug|Any CPU + {A40350FE-4334-4007-B1C3-6BEB1B070309}.Debug|x86.ActiveCfg = Debug|Any CPU + {A40350FE-4334-4007-B1C3-6BEB1B070309}.Debug|x86.Build.0 = Debug|Any CPU + {A40350FE-4334-4007-B1C3-6BEB1B070309}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A40350FE-4334-4007-B1C3-6BEB1B070309}.Release|Any CPU.Build.0 = Release|Any CPU + {A40350FE-4334-4007-B1C3-6BEB1B070309}.Release|x64.ActiveCfg = Release|Any CPU + {A40350FE-4334-4007-B1C3-6BEB1B070309}.Release|x64.Build.0 = Release|Any CPU + {A40350FE-4334-4007-B1C3-6BEB1B070309}.Release|x86.ActiveCfg = Release|Any CPU + {A40350FE-4334-4007-B1C3-6BEB1B070309}.Release|x86.Build.0 = Release|Any CPU + {C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Debug|x64.ActiveCfg = Debug|Any CPU + {C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Debug|x64.Build.0 = Debug|Any CPU + {C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Debug|x86.ActiveCfg = Debug|Any CPU + {C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Debug|x86.Build.0 = Debug|Any CPU + {C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Release|Any CPU.Build.0 = Release|Any CPU + {C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Release|x64.ActiveCfg = Release|Any CPU + {C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Release|x64.Build.0 = Release|Any CPU + {C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Release|x86.ActiveCfg = Release|Any CPU + {C26965A9-EAC6-4E5A-B8C1-D161260EFE4F}.Release|x86.Build.0 = Release|Any CPU + {FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Debug|x64.ActiveCfg = Debug|Any CPU + {FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Debug|x64.Build.0 = Debug|Any CPU + {FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Debug|x86.ActiveCfg = Debug|Any CPU + {FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Debug|x86.Build.0 = Debug|Any CPU + {FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Release|Any CPU.Build.0 = Release|Any CPU + {FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Release|x64.ActiveCfg = Release|Any CPU + {FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Release|x64.Build.0 = Release|Any CPU + {FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Release|x86.ActiveCfg = Release|Any CPU + {FE5290C7-45DA-46F8-BD74-698E7A161DD6}.Release|x86.Build.0 = Release|Any CPU + {ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Debug|x64.ActiveCfg = Debug|Any CPU + {ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Debug|x64.Build.0 = Debug|Any CPU + {ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Debug|x86.ActiveCfg = Debug|Any CPU + {ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Debug|x86.Build.0 = Debug|Any CPU + {ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Release|Any CPU.Build.0 = Release|Any CPU + {ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Release|x64.ActiveCfg = Release|Any CPU + {ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Release|x64.Build.0 = Release|Any CPU + {ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Release|x86.ActiveCfg = Release|Any CPU + {ED66DC0E-FD6A-477A-BA8A-5273AA64F580}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -7788,8 +7874,6 @@ Global {83371889-9A3E-4D16-AE77-EB4F83BC6374} = {FED4267E-E5E4-49C5-98DB-8B3F203596EE} {525EBCB4-A870-470B-BC90-845306C337D1} = {FED4267E-E5E4-49C5-98DB-8B3F203596EE} {175E5CD8-92D4-46BB-882E-3A930D3302D4} = {FED4267E-E5E4-49C5-98DB-8B3F203596EE} - {A5CE25E9-89E1-4F2C-9B89-0C161707E700} = {B6118E15-C37A-4B05-B4DF-97FE99790417} - {E6A23627-8D63-4DF1-A4F2-8881172C1FE6} = {B6118E15-C37A-4B05-B4DF-97FE99790417} {6126DCE4-9692-4EE2-B240-C65743572995} = {0508E463-0269-40C9-B5C2-3B600FB2A28B} {46FB7E93-1294-4068-B80A-D4864F78277A} = {6126DCE4-9692-4EE2-B240-C65743572995} {25FA84DB-EEA7-4068-8E2D-F3D48B281C16} = {6126DCE4-9692-4EE2-B240-C65743572995} @@ -7814,6 +7898,15 @@ Global {7F87406C-A3C8-4139-A68D-E4C344294A67} = {D62AF49B-F9FE-4794-AC39-A473FF13CA81} {1533E271-F61B-441B-8B74-59FB61DF0552} = {D62AF49B-F9FE-4794-AC39-A473FF13CA81} {7E268085-1046-4362-80CB-2977FF826DCA} = {D62AF49B-F9FE-4794-AC39-A473FF13CA81} + {A5CE25E9-89E1-4F2C-9B89-0C161707E700} = {B6118E15-C37A-4B05-B4DF-97FE99790417} + {E6A23627-8D63-4DF1-A4F2-8881172C1FE6} = {B6118E15-C37A-4B05-B4DF-97FE99790417} + {7D2B0799-A634-42AC-AE77-5D167BA51389} = {562D5067-8CD8-4F19-BCBB-873204932C61} + {9788C76F-658B-4441-88F8-22C6B86FAD27} = {7D2B0799-A634-42AC-AE77-5D167BA51389} + {1970D5CD-D9A4-4673-A297-179BB04199F4} = {7D2B0799-A634-42AC-AE77-5D167BA51389} + {A40350FE-4334-4007-B1C3-6BEB1B070309} = {7D2B0799-A634-42AC-AE77-5D167BA51389} + {C26965A9-EAC6-4E5A-B8C1-D161260EFE4F} = {7D2B0799-A634-42AC-AE77-5D167BA51389} + {FE5290C7-45DA-46F8-BD74-698E7A161DD6} = {7D2B0799-A634-42AC-AE77-5D167BA51389} + {ED66DC0E-FD6A-477A-BA8A-5273AA64F580} = {7D2B0799-A634-42AC-AE77-5D167BA51389} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F} diff --git a/eng/Dependencies.props b/eng/Dependencies.props index 35853a5024..8da95c6314 100644 --- a/eng/Dependencies.props +++ b/eng/Dependencies.props @@ -107,6 +107,7 @@ and are generated based on the last package release. + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index e98ae62047..87f35b2979 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -41,6 +41,10 @@ https://github.com/dotnet/efcore 5099d918192f5df031e1ff5e3beea9cb361c605a + + https://github.com/dotnet/efcore + 5099d918192f5df031e1ff5e3beea9cb361c605a + https://github.com/dotnet/runtime 0862d48a9c9fbda879206b194a16d8e607deac42 diff --git a/eng/Versions.props b/eng/Versions.props index d5dfb4a496..fabfae40a7 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -140,6 +140,7 @@ 5.0.0-rc.1.20417.2 5.0.0-rc.1.20417.2 5.0.0-rc.1.20417.2 + 5.0.0-rc.1.20417.2 + + + + From b140c09c02c3e197b8aed3e4780483523f654eb5 Mon Sep 17 00:00:00 2001 From: Sourabh Shirhatti Date: Wed, 19 Aug 2020 10:27:18 -0700 Subject: [PATCH 15/81] Add support delegating requests in HttpSysServer (#24857) * Add new ctors for RequestQueue and UrlGroup * Add DelegateRequest pinvokes * Add Request Transfer Feature * Fix accessibility of feature * Test cleanup * Update ref assembly * hack: Make HttpSysServer packable * Cleanup based on PR feedback * Avoid sending headers after transfer * Fix ref assembly * Fix rebase conflict * Switch to DelegateRequestEx * Add feature detection * Delete ref folder * Add server feature * s/RequestQueueWrapper/DelegationRule * Fix UrlGroup was null issue * Add light-up for ServerDelegationPropertyFeature * Revert changes to sample * Revert changes to sample take 2 * PR feedback * s/Transfered/Transferred * DelegateAfterRequestBodyReadShouldThrow * Make DelegationRule disposable * More license headers * Incomplete XML doc * PR feedback * Fix broken test * PR feedback * Fixup test * s/Transfer/Delegate * s/transfer/delegate * PR feedback --- src/Servers/HttpSys/src/AsyncAcceptContext.cs | 4 +- src/Servers/HttpSys/src/DelegationRule.cs | 40 ++++ src/Servers/HttpSys/src/FeatureContext.cs | 11 +- .../src/IHttpSysRequestDelegationFeature.cs | 20 ++ .../HttpSys/src/IServerDelegationFeature.cs | 16 ++ src/Servers/HttpSys/src/MessagePump.cs | 6 + .../HttpSys/src/NativeInterop/HttpApi.cs | 21 ++ .../HttpSys/src/NativeInterop/RequestQueue.cs | 34 +++- .../HttpSys/src/NativeInterop/UrlGroup.cs | 26 +++ .../HttpSys/src/RequestProcessing/Request.cs | 49 +++-- .../src/RequestProcessing/RequestContext.cs | 43 ++++- .../HttpSys/src/RequestProcessing/Response.cs | 6 + .../src/RequestProcessing/ResponseBody.cs | 5 + .../src/ServerDelegationPropertyFeature.cs | 29 +++ .../HttpSys/src/StandardFeatureCollection.cs | 6 + .../DelegateSupportedConditionAttribute.cs | 27 +++ .../test/FunctionalTests/DelegateTests.cs | 179 ++++++++++++++++++ .../HttpSys/NativeInterop/HttpApiTypes.cs | 24 +++ 18 files changed, 513 insertions(+), 33 deletions(-) create mode 100644 src/Servers/HttpSys/src/DelegationRule.cs create mode 100644 src/Servers/HttpSys/src/IHttpSysRequestDelegationFeature.cs create mode 100644 src/Servers/HttpSys/src/IServerDelegationFeature.cs create mode 100644 src/Servers/HttpSys/src/ServerDelegationPropertyFeature.cs create mode 100644 src/Servers/HttpSys/test/FunctionalTests/DelegateSupportedConditionAttribute.cs create mode 100644 src/Servers/HttpSys/test/FunctionalTests/DelegateTests.cs diff --git a/src/Servers/HttpSys/src/AsyncAcceptContext.cs b/src/Servers/HttpSys/src/AsyncAcceptContext.cs index f3f5bc14cd..c313f9124e 100644 --- a/src/Servers/HttpSys/src/AsyncAcceptContext.cs +++ b/src/Servers/HttpSys/src/AsyncAcceptContext.cs @@ -127,7 +127,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys statusCode = HttpApi.HttpReceiveHttpRequest( Server.RequestQueue.Handle, _nativeRequestContext.RequestId, - (uint)HttpApiTypes.HTTP_FLAGS.HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY, + // Small perf impact by not using HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY + // if the request sends header+body in a single TCP packet + (uint)HttpApiTypes.HTTP_FLAGS.NONE, _nativeRequestContext.NativeRequest, _nativeRequestContext.Size, &bytesTransferred, diff --git a/src/Servers/HttpSys/src/DelegationRule.cs b/src/Servers/HttpSys/src/DelegationRule.cs new file mode 100644 index 0000000000..593b88456a --- /dev/null +++ b/src/Servers/HttpSys/src/DelegationRule.cs @@ -0,0 +1,40 @@ +// 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.HttpSys +{ + /// + /// Rule that maintains a handle to the Request Queue and UrlPrefix to + /// delegate to. + /// + public class DelegationRule : IDisposable + { + private readonly ILogger _logger; + /// + /// The name of the Http.Sys request queue + /// + public string QueueName { get; } + /// + /// The URL of the Http.Sys Url Prefix + /// + public string UrlPrefix { get; } + internal RequestQueue Queue { get; } + + internal DelegationRule(string queueName, string urlPrefix, ILogger logger) + { + _logger = logger; + QueueName = queueName; + UrlPrefix = urlPrefix; + Queue = new RequestQueue(queueName, UrlPrefix, _logger, receiver: true); + } + + public void Dispose() + { + Queue.UrlGroup?.Dispose(); + Queue?.Dispose(); + } + } +} diff --git a/src/Servers/HttpSys/src/FeatureContext.cs b/src/Servers/HttpSys/src/FeatureContext.cs index 4845013a6b..3d505c1578 100644 --- a/src/Servers/HttpSys/src/FeatureContext.cs +++ b/src/Servers/HttpSys/src/FeatureContext.cs @@ -37,7 +37,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys IHttpBodyControlFeature, IHttpSysRequestInfoFeature, IHttpResponseTrailersFeature, - IHttpResetFeature + IHttpResetFeature, + IHttpSysRequestDelegationFeature { private RequestContext _requestContext; private IFeatureCollection _features; @@ -591,6 +592,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys set => _responseTrailers = value; } + public bool CanDelegate => Request.CanDelegate; + internal async Task OnResponseStart() { if (_responseStarted) @@ -711,5 +714,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys await actionPair.Item1(actionPair.Item2); } } + + public void DelegateRequest(DelegationRule destination) + { + _requestContext.Delegate(destination); + _responseStarted = true; + } } } diff --git a/src/Servers/HttpSys/src/IHttpSysRequestDelegationFeature.cs b/src/Servers/HttpSys/src/IHttpSysRequestDelegationFeature.cs new file mode 100644 index 0000000000..a581cc8683 --- /dev/null +++ b/src/Servers/HttpSys/src/IHttpSysRequestDelegationFeature.cs @@ -0,0 +1,20 @@ +// 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. + +namespace Microsoft.AspNetCore.Server.HttpSys +{ + public interface IHttpSysRequestDelegationFeature + { + /// + /// Indicates if the server can delegate this request to another HttpSys request queue. + /// + bool CanDelegate { get; } + + /// + /// Attempt to delegate the request to another Http.Sys request queue. The request body + /// must not be read nor the response started before this is invoked. Check + /// before invoking. + /// + void DelegateRequest(DelegationRule destination); + } +} diff --git a/src/Servers/HttpSys/src/IServerDelegationFeature.cs b/src/Servers/HttpSys/src/IServerDelegationFeature.cs new file mode 100644 index 0000000000..7353f9f053 --- /dev/null +++ b/src/Servers/HttpSys/src/IServerDelegationFeature.cs @@ -0,0 +1,16 @@ +// 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. + +namespace Microsoft.AspNetCore.Server.HttpSys +{ + public interface IServerDelegationFeature + { + /// + /// Create a delegation rule on request queue owned by the server. + /// + /// + /// Creates a that can used to delegate individual requests. + /// + DelegationRule CreateDelegationRule(string queueName, string urlPrefix); + } +} diff --git a/src/Servers/HttpSys/src/MessagePump.cs b/src/Servers/HttpSys/src/MessagePump.cs index 8de84fbb05..c3ccdda86f 100644 --- a/src/Servers/HttpSys/src/MessagePump.cs +++ b/src/Servers/HttpSys/src/MessagePump.cs @@ -55,6 +55,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys _serverAddresses = new ServerAddressesFeature(); Features.Set(_serverAddresses); + if (HttpApi.IsFeatureSupported(HttpApiTypes.HTTP_FEATURE_ID.HttpFeatureDelegateEx)) + { + var delegationProperty = new ServerDelegationPropertyFeature(Listener.RequestQueue, _logger); + Features.Set(delegationProperty); + } + _maxAccepts = _options.MaxAccepts; } diff --git a/src/Servers/HttpSys/src/NativeInterop/HttpApi.cs b/src/Servers/HttpSys/src/NativeInterop/HttpApi.cs index 6781465bc2..afa2c7c2ff 100644 --- a/src/Servers/HttpSys/src/NativeInterop/HttpApi.cs +++ b/src/Servers/HttpSys/src/NativeInterop/HttpApi.cs @@ -45,6 +45,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern uint HttpCreateUrlGroup(ulong serverSessionId, ulong* urlGroupId, uint reserved); + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern uint HttpFindUrlGroupId(string pFullyQualifiedUrl, SafeHandle requestQueueHandle, ulong* urlGroupId); + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] internal static extern uint HttpAddUrlToUrlGroup(ulong urlGroupId, string pFullyQualifiedUrl, ulong context, uint pReserved); @@ -70,6 +73,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern unsafe uint HttpCloseRequestQueue(IntPtr pReqQueueHandle); + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)] + internal static extern bool HttpIsFeatureSupported(HTTP_FEATURE_ID feature); + + [DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern unsafe uint HttpDelegateRequestEx(SafeHandle pReqQueueHandle, SafeHandle pDelegateQueueHandle, ulong requestId, + ulong delegateUrlGroupId, ulong propertyInfoSetSize, HTTP_DELEGATE_REQUEST_PROPERTY_INFO* pRequestPropertyBuffer); + internal delegate uint HttpSetRequestPropertyInvoker(SafeHandle requestQueueHandle, ulong requestId, HTTP_REQUEST_PROPERTY propertyId, void* input, uint inputSize, IntPtr overlapped); private static HTTPAPI_VERSION version; @@ -145,5 +155,16 @@ namespace Microsoft.AspNetCore.Server.HttpSys return supported; } } + + internal static bool IsFeatureSupported(HTTP_FEATURE_ID feature) + { + try + { + return HttpIsFeatureSupported(feature); + } + catch (EntryPointNotFoundException) { } + + return false; + } } } diff --git a/src/Servers/HttpSys/src/NativeInterop/RequestQueue.cs b/src/Servers/HttpSys/src/NativeInterop/RequestQueue.cs index 4fb2d60280..ca3d2e7940 100644 --- a/src/Servers/HttpSys/src/NativeInterop/RequestQueue.cs +++ b/src/Servers/HttpSys/src/NativeInterop/RequestQueue.cs @@ -16,22 +16,44 @@ namespace Microsoft.AspNetCore.Server.HttpSys Marshal.SizeOf(); private readonly RequestQueueMode _mode; - private readonly UrlGroup _urlGroup; private readonly ILogger _logger; private bool _disposed; + internal RequestQueue(string requestQueueName, string urlPrefix, ILogger logger, bool receiver) + : this(urlGroup: null, requestQueueName, RequestQueueMode.Attach, logger, receiver) + { + try + { + UrlGroup = new UrlGroup(this, UrlPrefix.Create(urlPrefix)); + } + catch + { + Dispose(); + throw; + } + } + internal RequestQueue(UrlGroup urlGroup, string requestQueueName, RequestQueueMode mode, ILogger logger) + : this(urlGroup, requestQueueName, mode, logger, false) + { } + + private RequestQueue(UrlGroup urlGroup, string requestQueueName, RequestQueueMode mode, ILogger logger, bool receiver) { _mode = mode; - _urlGroup = urlGroup; + UrlGroup = urlGroup; _logger = logger; var flags = HttpApiTypes.HTTP_CREATE_REQUEST_QUEUE_FLAG.None; Created = true; + if (_mode == RequestQueueMode.Attach) { flags = HttpApiTypes.HTTP_CREATE_REQUEST_QUEUE_FLAG.OpenExisting; Created = false; + if (receiver) + { + flags |= HttpApiTypes.HTTP_CREATE_REQUEST_QUEUE_FLAG.Delegation; + } } var statusCode = HttpApi.HttpCreateRequestQueue( @@ -54,7 +76,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys out requestQueueHandle); } - if (flags == HttpApiTypes.HTTP_CREATE_REQUEST_QUEUE_FLAG.OpenExisting && statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_FILE_NOT_FOUND) + if (flags.HasFlag(HttpApiTypes.HTTP_CREATE_REQUEST_QUEUE_FLAG.OpenExisting) && statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_FILE_NOT_FOUND) { throw new HttpSysException((int)statusCode, $"Failed to attach to the given request queue '{requestQueueName}', the queue could not be found."); } @@ -95,6 +117,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal SafeHandle Handle { get; } internal ThreadPoolBoundHandle BoundHandle { get; } + internal UrlGroup UrlGroup { get; } + internal unsafe void AttachToUrlGroup() { Debug.Assert(Created); @@ -108,7 +132,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys var infoptr = new IntPtr(&info); - _urlGroup.SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, + UrlGroup.SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, infoptr, (uint)BindingInfoSize); } @@ -128,7 +152,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys var infoptr = new IntPtr(&info); - _urlGroup.SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, + UrlGroup.SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerBindingProperty, infoptr, (uint)BindingInfoSize, throwOnError: false); } diff --git a/src/Servers/HttpSys/src/NativeInterop/UrlGroup.cs b/src/Servers/HttpSys/src/NativeInterop/UrlGroup.cs index 081c2d7e15..de348d3786 100644 --- a/src/Servers/HttpSys/src/NativeInterop/UrlGroup.cs +++ b/src/Servers/HttpSys/src/NativeInterop/UrlGroup.cs @@ -13,6 +13,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys { private static readonly int QosInfoSize = Marshal.SizeOf(); + private static readonly int RequestPropertyInfoSize = + Marshal.SizeOf(); private ServerSession _serverSession; private ILogger _logger; @@ -36,6 +38,21 @@ namespace Microsoft.AspNetCore.Server.HttpSys Id = urlGroupId; } + internal unsafe UrlGroup(RequestQueue requestQueue, UrlPrefix url) + { + ulong urlGroupId = 0; + var statusCode = HttpApi.HttpFindUrlGroupId( + url.FullPrefix, requestQueue.Handle, &urlGroupId); + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + throw new HttpSysException((int)statusCode); + } + + Debug.Assert(urlGroupId != 0, "Invalid id returned by HttpCreateUrlGroup"); + Id = urlGroupId; + } + internal ulong Id { get; private set; } internal unsafe void SetMaxConnections(long maxConnections) @@ -51,6 +68,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerQosProperty, new IntPtr(&qosSettings), (uint)QosInfoSize); } + internal unsafe void SetDelegationProperty(RequestQueue destination) + { + var propertyInfo = new HttpApiTypes.HTTP_BINDING_INFO(); + propertyInfo.Flags = HttpApiTypes.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT; + propertyInfo.RequestQueueHandle = destination.Handle.DangerousGetHandle(); + + SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerDelegationProperty, new IntPtr(&propertyInfo), (uint)RequestPropertyInfoSize); + } + internal void SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY property, IntPtr info, uint infosize, bool throwOnError = true) { Debug.Assert(info != IntPtr.Zero, "SetUrlGroupProperty called with invalid pointer"); diff --git a/src/Servers/HttpSys/src/RequestProcessing/Request.cs b/src/Servers/HttpSys/src/RequestProcessing/Request.cs index 84fb017393..494f3e5d6d 100644 --- a/src/Servers/HttpSys/src/RequestProcessing/Request.cs +++ b/src/Servers/HttpSys/src/RequestProcessing/Request.cs @@ -61,43 +61,40 @@ namespace Microsoft.AspNetCore.Server.HttpSys var rawUrlInBytes = _nativeRequestContext.GetRawUrlInBytes(); var originalPath = RequestUriBuilder.DecodeAndUnescapePath(rawUrlInBytes); + PathBase = string.Empty; + Path = originalPath; + // 'OPTIONS * HTTP/1.1' if (KnownMethod == HttpApiTypes.HTTP_VERB.HttpVerbOPTIONS && string.Equals(RawUrl, "*", StringComparison.Ordinal)) { PathBase = string.Empty; Path = string.Empty; } - else if (requestContext.Server.RequestQueue.Created) - { - var prefix = requestContext.Server.Options.UrlPrefixes.GetPrefix((int)nativeRequestContext.UrlContext); - - if (originalPath.Length == prefix.PathWithoutTrailingSlash.Length) - { - // They matched exactly except for the trailing slash. - PathBase = originalPath; - Path = string.Empty; - } - else - { - // url: /base/path, prefix: /base/, base: /base, path: /path - // url: /, prefix: /, base: , path: / - PathBase = originalPath.Substring(0, prefix.PathWithoutTrailingSlash.Length); // Preserve the user input casing - Path = originalPath.Substring(prefix.PathWithoutTrailingSlash.Length); - } - } else { - // When attaching to an existing queue, the UrlContext hint may not match our configuration. Search manualy. - if (requestContext.Server.Options.UrlPrefixes.TryMatchLongestPrefix(IsHttps, cookedUrl.GetHost(), originalPath, out var pathBase, out var path)) + var prefix = requestContext.Server.Options.UrlPrefixes.GetPrefix((int)nativeRequestContext.UrlContext); + // Prefix may be null if the requested has been transfered to our queue + if (!(prefix is null)) + { + if (originalPath.Length == prefix.PathWithoutTrailingSlash.Length) + { + // They matched exactly except for the trailing slash. + PathBase = originalPath; + Path = string.Empty; + } + else + { + // url: /base/path, prefix: /base/, base: /base, path: /path + // url: /, prefix: /, base: , path: / + PathBase = originalPath.Substring(0, prefix.PathWithoutTrailingSlash.Length); // Preserve the user input casing + Path = originalPath.Substring(prefix.PathWithoutTrailingSlash.Length); + } + } + else if (requestContext.Server.Options.UrlPrefixes.TryMatchLongestPrefix(IsHttps, cookedUrl.GetHost(), originalPath, out var pathBase, out var path)) { PathBase = pathBase; Path = path; } - else - { - PathBase = string.Empty; - Path = originalPath; - } } ProtocolVersion = _nativeRequestContext.GetVersion(); @@ -350,6 +347,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } + public bool CanDelegate => !(HasRequestBodyStarted || RequestContext.Response.HasStarted); + // Populates the client certificate. The result may be null if there is no client cert. // TODO: Does it make sense for this to be invoked multiple times (e.g. renegotiate)? Client and server code appear to // enable this, but it's unclear what Http.Sys would do. diff --git a/src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs b/src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs index 997339ac14..cc7cee0df3 100644 --- a/src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs +++ b/src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs @@ -2,8 +2,10 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Concurrent; using System.Diagnostics; using System.IO; +using System.Runtime.InteropServices; using System.Security.Authentication.ExtendedProtection; using System.Security.Principal; using System.Threading; @@ -17,7 +19,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys internal sealed class RequestContext : IDisposable, IThreadPoolWorkItem { private static readonly Action AbortDelegate = Abort; - private NativeRequestContext _memoryBlob; private CancellationTokenSource _requestAbortSource; private CancellationToken? _disconnectToken; @@ -322,5 +323,45 @@ namespace Microsoft.AspNetCore.Server.HttpSys Response.ContentLength = 0; Dispose(); } + + internal unsafe void Delegate(DelegationRule destination) + { + if (Request.HasRequestBodyStarted) + { + throw new InvalidOperationException("This request cannot be delegated, the request body has already started."); + } + if (Response.HasStarted) + { + throw new InvalidOperationException("This request cannot be delegated, the response has already started."); + } + + var source = Server.RequestQueue; + + uint statusCode; + + fixed (char* uriPointer = destination.UrlPrefix) + { + var property = new HttpApiTypes.HTTP_DELEGATE_REQUEST_PROPERTY_INFO() + { + ProperyId = HttpApiTypes.HTTP_DELEGATE_REQUEST_PROPERTY_ID.DelegateRequestDelegateUrlProperty, + PropertyInfo = (IntPtr)uriPointer, + PropertyInfoLength = (uint)System.Text.Encoding.Unicode.GetByteCount(destination.UrlPrefix) + }; + + statusCode = HttpApi.HttpDelegateRequestEx(source.Handle, + destination.Queue.Handle, + Request.RequestId, + destination.Queue.UrlGroup.Id, + propertyInfoSetSize: 1, + &property); + } + + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) + { + throw new HttpSysException((int)statusCode); + } + + Response.MarkDelegated(); + } } } diff --git a/src/Servers/HttpSys/src/RequestProcessing/Response.cs b/src/Servers/HttpSys/src/RequestProcessing/Response.cs index 3f8dd86f7e..a6fc52bd92 100644 --- a/src/Servers/HttpSys/src/RequestProcessing/Response.cs +++ b/src/Servers/HttpSys/src/RequestProcessing/Response.cs @@ -730,6 +730,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } + internal void MarkDelegated() + { + Abort(); + _nativeStream?.MarkDelegated(); + } + internal void CancelLastWrite() { _nativeStream?.CancelLastWrite(); diff --git a/src/Servers/HttpSys/src/RequestProcessing/ResponseBody.cs b/src/Servers/HttpSys/src/RequestProcessing/ResponseBody.cs index 6b181cc312..2e59530a9c 100644 --- a/src/Servers/HttpSys/src/RequestProcessing/ResponseBody.cs +++ b/src/Servers/HttpSys/src/RequestProcessing/ResponseBody.cs @@ -106,6 +106,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys FlushInternal(endOfRequest: false); } + public void MarkDelegated() + { + _skipWrites = true; + } + // We never expect endOfRequest and data at the same time private unsafe void FlushInternal(bool endOfRequest, ArraySegment data = new ArraySegment()) { diff --git a/src/Servers/HttpSys/src/ServerDelegationPropertyFeature.cs b/src/Servers/HttpSys/src/ServerDelegationPropertyFeature.cs new file mode 100644 index 0000000000..d9066a3dd5 --- /dev/null +++ b/src/Servers/HttpSys/src/ServerDelegationPropertyFeature.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.Extensions.Logging; + +namespace Microsoft.AspNetCore.Server.HttpSys +{ + internal class ServerDelegationPropertyFeature : IServerDelegationFeature + { + private readonly ILogger _logger; + private readonly RequestQueue _queue; + + public ServerDelegationPropertyFeature(RequestQueue queue, ILogger logger) + { + _queue = queue; + _logger = logger; + } + + public DelegationRule CreateDelegationRule(string queueName, string uri) + { + var rule = new DelegationRule(queueName, uri, _logger); + _queue.UrlGroup.SetDelegationProperty(rule.Queue); + return rule; + } + } +} diff --git a/src/Servers/HttpSys/src/StandardFeatureCollection.cs b/src/Servers/HttpSys/src/StandardFeatureCollection.cs index 304b39b070..c8705b2ee6 100644 --- a/src/Servers/HttpSys/src/StandardFeatureCollection.cs +++ b/src/Servers/HttpSys/src/StandardFeatureCollection.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Connections.Features; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features.Authentication; +using Microsoft.AspNetCore.HttpSys.Internal; namespace Microsoft.AspNetCore.Server.HttpSys { @@ -44,6 +45,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys // Win8+ _featureFuncLookup[typeof(ITlsHandshakeFeature)] = ctx => ctx.GetTlsHandshakeFeature(); } + + if (HttpApi.IsFeatureSupported(HttpApiTypes.HTTP_FEATURE_ID.HttpFeatureDelegateEx)) + { + _featureFuncLookup[typeof(IHttpSysRequestDelegationFeature)] = _identityFunc; + } } public StandardFeatureCollection(FeatureContext featureContext) diff --git a/src/Servers/HttpSys/test/FunctionalTests/DelegateSupportedConditionAttribute.cs b/src/Servers/HttpSys/test/FunctionalTests/DelegateSupportedConditionAttribute.cs new file mode 100644 index 0000000000..b6267657e4 --- /dev/null +++ b/src/Servers/HttpSys/test/FunctionalTests/DelegateSupportedConditionAttribute.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing; +using static Microsoft.AspNetCore.HttpSys.Internal.HttpApiTypes; + +namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class DelegateSupportedConditionAttribute : Attribute, ITestCondition + { + private readonly bool _isSupported; + public DelegateSupportedConditionAttribute(bool isSupported) => _isSupported = isSupported; + + private readonly Lazy _isDelegateSupported = new Lazy(CanDelegate); + public bool IsMet => (_isDelegateSupported.Value == _isSupported); + + public string SkipReason => $"Http.Sys does {(_isSupported ? "not" : "")} support delegating requests"; + + private static bool CanDelegate() + { + return HttpApi.IsFeatureSupported(HTTP_FEATURE_ID.HttpFeatureDelegateEx); + } + } +} diff --git a/src/Servers/HttpSys/test/FunctionalTests/DelegateTests.cs b/src/Servers/HttpSys/test/FunctionalTests/DelegateTests.cs new file mode 100644 index 0000000000..f94f0bf0be --- /dev/null +++ b/src/Servers/HttpSys/test/FunctionalTests/DelegateTests.cs @@ -0,0 +1,179 @@ +// 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 System.IO; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Testing; +using Xunit; + +namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests +{ + public class DelegateTests + { + private static readonly string _expectedResponseString = "Hello from delegatee"; + + [ConditionalFact] + [DelegateSupportedCondition(true)] + public async Task DelegateRequestTest() + { + var queueName = Guid.NewGuid().ToString(); + using var receiver = Utilities.CreateHttpServer(out var receiverAddress, async httpContext => + { + await httpContext.Response.WriteAsync(_expectedResponseString); + }, + options => + { + options.RequestQueueName = queueName; + }); + + DelegationRule destination = default; + + using var delegator = Utilities.CreateHttpServer(out var delegatorAddress, httpContext => + { + var delegateFeature = httpContext.Features.Get(); + delegateFeature.DelegateRequest(destination); + return Task.CompletedTask; + }); + + var delegationProperty = delegator.Features.Get(); + destination = delegationProperty.CreateDelegationRule(queueName, receiverAddress); + + var responseString = await SendRequestAsync(delegatorAddress); + Assert.Equal(_expectedResponseString, responseString); + destination?.Dispose(); + } + + [ConditionalFact] + [DelegateSupportedCondition(true)] + public async Task DelegateAfterWriteToResponseBodyShouldThrowTest() + { + var queueName = Guid.NewGuid().ToString(); + using var receiver = Utilities.CreateHttpServer(out var receiverAddress, httpContext => + { + httpContext.Response.StatusCode = StatusCodes.Status418ImATeapot; + return Task.CompletedTask; + }, + options => + { + options.RequestQueueName = queueName; + }); + + DelegationRule destination = default; + + using var delegator = Utilities.CreateHttpServer(out var delegatorAddress, async httpContext => + { + await httpContext.Response.WriteAsync(_expectedResponseString); + var delegateFeature = httpContext.Features.Get(); + Assert.False(delegateFeature.CanDelegate); + Assert.Throws(() => delegateFeature.DelegateRequest(destination)); + }); + + var delegationProperty = delegator.Features.Get(); + destination = delegationProperty.CreateDelegationRule(queueName, receiverAddress); + + var responseString = await SendRequestAsync(delegatorAddress); + Assert.Equal(_expectedResponseString, responseString); + destination?.Dispose(); + } + + [ConditionalFact] + [DelegateSupportedCondition(true)] + public async Task WriteToBodyAfterDelegateShouldNoOp() + { + var queueName = Guid.NewGuid().ToString(); + using var receiver = Utilities.CreateHttpServer(out var receiverAddress, async httpContext => + { + await httpContext.Response.WriteAsync(_expectedResponseString); + }, + options => + { + options.RequestQueueName = queueName; + }); + + DelegationRule destination = default; + + using var delegator = Utilities.CreateHttpServer(out var delegatorAddress, httpContext => + { + var delegateFeature = httpContext.Features.Get(); + delegateFeature.DelegateRequest(destination); + Assert.False(delegateFeature.CanDelegate); + httpContext.Response.WriteAsync(_expectedResponseString); + return Task.CompletedTask; + }); + + var delegationProperty = delegator.Features.Get(); + destination = delegationProperty.CreateDelegationRule(queueName, receiverAddress); + + var responseString = await SendRequestAsync(delegatorAddress); + Assert.Equal(_expectedResponseString, responseString); + destination?.Dispose(); + } + + [ConditionalFact] + [DelegateSupportedCondition(true)] + public async Task DelegateAfterRequestBodyReadShouldThrow() + { + var queueName = Guid.NewGuid().ToString(); + using var receiver = Utilities.CreateHttpServer(out var receiverAddress, httpContext => + { + httpContext.Response.StatusCode = StatusCodes.Status418ImATeapot; + return Task.CompletedTask; + }, + options => + { + options.RequestQueueName = queueName; + }); + + DelegationRule destination = default; + + using var delegator = Utilities.CreateHttpServer(out var delegatorAddress, async httpContext => + { + var memoryStream = new MemoryStream(); + await httpContext.Request.Body.CopyToAsync(memoryStream); + var delegateFeature = httpContext.Features.Get(); + Assert.Throws(() => delegateFeature.DelegateRequest(destination)); + }); + + var delegationProperty = delegator.Features.Get(); + destination = delegationProperty.CreateDelegationRule(queueName, receiverAddress); + + _ = await SendRequestWithBodyAsync(delegatorAddress); + destination?.Dispose(); + } + + [ConditionalFact] + [DelegateSupportedCondition(false)] + public async Task DelegationFeaturesAreNull() + { + using var delegator = Utilities.CreateHttpServer(out var delegatorAddress, httpContext => + { + var delegateFeature = httpContext.Features.Get(); + Assert.Null(delegateFeature); + return Task.CompletedTask; + }); + + var delegationProperty = delegator.Features.Get(); + Assert.Null(delegationProperty); + + _ = await SendRequestAsync(delegatorAddress); + } + + private async Task SendRequestAsync(string uri) + { + using var client = new HttpClient(); + return await client.GetStringAsync(uri); + } + + private async Task SendRequestWithBodyAsync(string uri) + { + using var client = new HttpClient(); + var content = new StringContent("Sample request body"); + var response = await client.PostAsync(uri, content); + response.EnsureSuccessStatusCode(); + return await response.Content.ReadAsStringAsync(); + } + } +} diff --git a/src/Shared/HttpSys/NativeInterop/HttpApiTypes.cs b/src/Shared/HttpSys/NativeInterop/HttpApiTypes.cs index 2e69d7bc40..706fbd3d32 100644 --- a/src/Shared/HttpSys/NativeInterop/HttpApiTypes.cs +++ b/src/Shared/HttpSys/NativeInterop/HttpApiTypes.cs @@ -32,6 +32,7 @@ namespace Microsoft.AspNetCore.HttpSys.Internal HttpServerListenEndpointProperty, HttpServerChannelBindProperty, HttpServerProtectionLevelProperty, + HttpServerDelegationProperty = 16 } // Currently only one request info type is supported but the enum is for future extensibility. @@ -71,6 +72,28 @@ namespace Microsoft.AspNetCore.HttpSys.Internal MinSendRate, } + internal enum HTTP_DELEGATE_REQUEST_PROPERTY_ID : uint + { + DelegateRequestReservedProperty, + DelegateRequestDelegateUrlProperty + } + + internal enum HTTP_FEATURE_ID + { + HttpFeatureUnknown = 0, + HttpFeatureResponseTrailers = 1, + HttpFeatureApiTimings = 2, + HttpFeatureDelegateEx = 3, + } + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal struct HTTP_DELEGATE_REQUEST_PROPERTY_INFO + { + internal HTTP_DELEGATE_REQUEST_PROPERTY_ID ProperyId; + internal uint PropertyInfoLength; + internal IntPtr PropertyInfo; + } + internal struct HTTP_REQUEST_PROPERTY_STREAM_ERROR { internal uint ErrorCode; @@ -651,6 +674,7 @@ namespace Microsoft.AspNetCore.HttpSys.Internal OpenExisting = 1, // The handle to the request queue created using this flag cannot be used to perform I/O operations. This flag can be set only when the request queue handle is created. Controller = 2, + Delegation = 8 } internal static class HTTP_RESPONSE_HEADER_ID From 57db5937f8cb6ae1f7dd00b3a79d191021df0b89 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 19 Aug 2020 11:23:02 -0700 Subject: [PATCH 16/81] Fixup test --- src/ProjectTemplates/Shared/AspNetProcess.cs | 15 ++++++++++++--- src/ProjectTemplates/Shared/Project.cs | 6 +++--- src/ProjectTemplates/test/MvcTemplateTest.cs | 4 ++-- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/ProjectTemplates/Shared/AspNetProcess.cs b/src/ProjectTemplates/Shared/AspNetProcess.cs index afc34a3f30..13a9281c56 100644 --- a/src/ProjectTemplates/Shared/AspNetProcess.cs +++ b/src/ProjectTemplates/Shared/AspNetProcess.cs @@ -42,6 +42,7 @@ namespace Templates.Test.Helpers IDictionary environmentVariables, bool published, bool hasListeningUri = true, + bool usePublishedAppHost = false, ILogger logger = null) { _developmentCertificate = DevelopmentCertificate.Create(workingDirectory); @@ -64,9 +65,17 @@ namespace Templates.Test.Helpers string arguments; if (published) { - // When publishingu used the app host to run the app. This makes it easy to consistently run for regular and single-file publish - process = OperatingSystem.IsWindows() ? dllPath + ".exe" : dllPath; - arguments = null; + if (usePublishedAppHost) + { + // When publishingu used the app host to run the app. This makes it easy to consistently run for regular and single-file publish + process = Path.ChangeExtension(dllPath, OperatingSystem.IsWindows() ? ".exe" : null); + arguments = null; + } + else + { + process = DotNetMuxer.MuxerPathOrDefault(); + arguments = $"exec {dllPath}"; + } } else { diff --git a/src/ProjectTemplates/Shared/Project.cs b/src/ProjectTemplates/Shared/Project.cs index fbfeee80c4..e1ce4b2a41 100644 --- a/src/ProjectTemplates/Shared/Project.cs +++ b/src/ProjectTemplates/Shared/Project.cs @@ -179,7 +179,7 @@ namespace Templates.Test.Helpers return new AspNetProcess(Output, TemplateOutputDir, projectDll, environment, published: false, hasListeningUri: hasListeningUri, logger: logger); } - internal AspNetProcess StartPublishedProjectAsync(bool hasListeningUri = true) + internal AspNetProcess StartPublishedProjectAsync(bool hasListeningUri = true, bool usePublishedAppHost = false) { var environment = new Dictionary { @@ -190,8 +190,8 @@ namespace Templates.Test.Helpers ["ASPNETCORE_Logging__Console__FormatterOptions__IncludeScopes"] = "true", }; - var projectDll = Path.Combine(TemplatePublishDir, ProjectName); - return new AspNetProcess(Output, TemplatePublishDir, projectDll, environment, published: true, hasListeningUri: hasListeningUri); + var projectDll = Path.Combine(TemplatePublishDir, $"{ProjectName}.dll"); + return new AspNetProcess(Output, TemplatePublishDir, projectDll, environment, published: true, hasListeningUri: hasListeningUri, usePublishedAppHost: usePublishedAppHost); } internal async Task RunDotNetEfCreateMigrationAsync(string migrationName) diff --git a/src/ProjectTemplates/test/MvcTemplateTest.cs b/src/ProjectTemplates/test/MvcTemplateTest.cs index 9136d26717..ee33c7034e 100644 --- a/src/ProjectTemplates/test/MvcTemplateTest.cs +++ b/src/ProjectTemplates/test/MvcTemplateTest.cs @@ -243,7 +243,7 @@ namespace Templates.Test return; } - Project = await ProjectFactory.GetOrCreateProject("mvcindividualuld", Output); + Project = await ProjectFactory.GetOrCreateProject("mvcsinglefileexe", Output); Project.RuntimeIdentifier = runtimeIdentifer; var createResult = await Project.RunDotNetNewAsync("mvc", auth: "Individual", useLocalDB: true); @@ -286,7 +286,7 @@ namespace Templates.Test }, }; - using var aspNetProcess = Project.StartPublishedProjectAsync(); + using var aspNetProcess = Project.StartPublishedProjectAsync(usePublishedAppHost: true); Assert.False( aspNetProcess.Process.HasExited, ErrorMessages.GetFailedProcessMessageOrEmpty("Run published project", Project, aspNetProcess.Process)); From dd43757bfe015692112aa43725483c399ffe054b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 19 Aug 2020 18:38:38 +0000 Subject: [PATCH 17/81] Update dependencies from https://github.com/dotnet/efcore build 20200819.5 (#25040) [release/5.0] Update dependencies from dotnet/efcore - Updates: - Microsoft.EntityFrameworkCore.Tools: from 5.0.0-rc.1.20417.2 to 5.0.0-rc.1.20419.5 - Microsoft.EntityFrameworkCore.SqlServer: from 5.0.0-rc.1.20417.2 to 5.0.0-rc.1.20419.5 - dotnet-ef: from 5.0.0-rc.1.20417.2 to 5.0.0-rc.1.20419.5 - Microsoft.EntityFrameworkCore: from 5.0.0-rc.1.20417.2 to 5.0.0-rc.1.20419.5 - Microsoft.EntityFrameworkCore.Design: from 5.0.0-rc.1.20417.2 to 5.0.0-rc.1.20419.5 - Microsoft.EntityFrameworkCore.Relational: from 5.0.0-rc.1.20417.2 to 5.0.0-rc.1.20419.5 - Microsoft.EntityFrameworkCore.Sqlite: from 5.0.0-rc.1.20417.2 to 5.0.0-rc.1.20419.5 - Microsoft.EntityFrameworkCore.InMemory: from 5.0.0-rc.1.20417.2 to 5.0.0-rc.1.20419.5 --- eng/Version.Details.xml | 32 ++++++++++++++++---------------- eng/Versions.props | 16 ++++++++-------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 87f35b2979..3113cbd68c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -13,37 +13,37 @@ https://github.com/dotnet/blazor cc449601d638ffaab58ae9487f0fd010bb178a12 - + https://github.com/dotnet/efcore - 5099d918192f5df031e1ff5e3beea9cb361c605a + 897dc03d976fa2c115c81c867c074c6cf5ece282 - + https://github.com/dotnet/efcore - 5099d918192f5df031e1ff5e3beea9cb361c605a + 897dc03d976fa2c115c81c867c074c6cf5ece282 - + https://github.com/dotnet/efcore - 5099d918192f5df031e1ff5e3beea9cb361c605a + 897dc03d976fa2c115c81c867c074c6cf5ece282 - + https://github.com/dotnet/efcore - 5099d918192f5df031e1ff5e3beea9cb361c605a + 897dc03d976fa2c115c81c867c074c6cf5ece282 - + https://github.com/dotnet/efcore - 5099d918192f5df031e1ff5e3beea9cb361c605a + 897dc03d976fa2c115c81c867c074c6cf5ece282 - + https://github.com/dotnet/efcore - 5099d918192f5df031e1ff5e3beea9cb361c605a + 897dc03d976fa2c115c81c867c074c6cf5ece282 - + https://github.com/dotnet/efcore - 5099d918192f5df031e1ff5e3beea9cb361c605a + 897dc03d976fa2c115c81c867c074c6cf5ece282 - + https://github.com/dotnet/efcore - 5099d918192f5df031e1ff5e3beea9cb361c605a + 897dc03d976fa2c115c81c867c074c6cf5ece282 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index fabfae40a7..ac700a9889 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -133,14 +133,14 @@ 3.2.0 - 5.0.0-rc.1.20417.2 - 5.0.0-rc.1.20417.2 - 5.0.0-rc.1.20417.2 - 5.0.0-rc.1.20417.2 - 5.0.0-rc.1.20417.2 - 5.0.0-rc.1.20417.2 - 5.0.0-rc.1.20417.2 - 5.0.0-rc.1.20417.2 + 5.0.0-rc.1.20419.5 + 5.0.0-rc.1.20419.5 + 5.0.0-rc.1.20419.5 + 5.0.0-rc.1.20419.5 + 5.0.0-rc.1.20419.5 + 5.0.0-rc.1.20419.5 + 5.0.0-rc.1.20419.5 + 5.0.0-rc.1.20419.5 3.2.0 - 5.0.0-rc.1.20419.5 - 5.0.0-rc.1.20419.5 - 5.0.0-rc.1.20419.5 - 5.0.0-rc.1.20419.5 - 5.0.0-rc.1.20419.5 - 5.0.0-rc.1.20419.5 - 5.0.0-rc.1.20419.5 - 5.0.0-rc.1.20419.5 + 5.0.0-rc.1.20419.12 + 5.0.0-rc.1.20419.12 + 5.0.0-rc.1.20419.12 + 5.0.0-rc.1.20419.12 + 5.0.0-rc.1.20419.12 + 5.0.0-rc.1.20419.12 + 5.0.0-rc.1.20419.12 + 5.0.0-rc.1.20419.12 3.2.0 - 5.0.0-rc.1.20419.12 - 5.0.0-rc.1.20419.12 - 5.0.0-rc.1.20419.12 - 5.0.0-rc.1.20419.12 - 5.0.0-rc.1.20419.12 - 5.0.0-rc.1.20419.12 - 5.0.0-rc.1.20419.12 - 5.0.0-rc.1.20419.12 + 5.0.0-rc.1.20419.15 + 5.0.0-rc.1.20419.15 + 5.0.0-rc.1.20419.15 + 5.0.0-rc.1.20419.15 + 5.0.0-rc.1.20419.15 + 5.0.0-rc.1.20419.15 + 5.0.0-rc.1.20419.15 + 5.0.0-rc.1.20419.15 3.2.0 - 5.0.0-rc.1.20419.15 - 5.0.0-rc.1.20419.15 - 5.0.0-rc.1.20419.15 - 5.0.0-rc.1.20419.15 - 5.0.0-rc.1.20419.15 - 5.0.0-rc.1.20419.15 - 5.0.0-rc.1.20419.15 - 5.0.0-rc.1.20419.15 + 5.0.0-rc.1.20420.2 + 5.0.0-rc.1.20420.2 + 5.0.0-rc.1.20420.2 + 5.0.0-rc.1.20420.2 + 5.0.0-rc.1.20420.2 + 5.0.0-rc.1.20420.2 + 5.0.0-rc.1.20420.2 + 5.0.0-rc.1.20420.2 diff --git a/src/Components/test/testassets/TestServer/Pages/_ServerHost.cshtml b/src/Components/test/testassets/TestServer/Pages/_ServerHost.cshtml index 54a00f8697..ebd2beeaf9 100644 --- a/src/Components/test/testassets/TestServer/Pages/_ServerHost.cshtml +++ b/src/Components/test/testassets/TestServer/Pages/_ServerHost.cshtml @@ -41,6 +41,8 @@ + + + + + + + + + diff --git a/src/Mvc/Mvc.TagHelpers/src/ComponentTagHelper.cs b/src/Mvc/Mvc.TagHelpers/src/ComponentTagHelper.cs index 4bac5c8fc7..0f7a565c25 100644 --- a/src/Mvc/Mvc.TagHelpers/src/ComponentTagHelper.cs +++ b/src/Mvc/Mvc.TagHelpers/src/ComponentTagHelper.cs @@ -1,4 +1,4 @@ -// 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. using System; @@ -66,6 +66,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers case RenderMode.Server: case RenderMode.ServerPrerendered: case RenderMode.Static: + case RenderMode.WebAssembly: + case RenderMode.WebAssemblyPrerendered: _renderMode = value; break; diff --git a/src/Mvc/Mvc.ViewFeatures/src/ClientComponentSerializer.cs b/src/Mvc/Mvc.ViewFeatures/src/ClientComponentSerializer.cs new file mode 100644 index 0000000000..5f8bf44062 --- /dev/null +++ b/src/Mvc/Mvc.ViewFeatures/src/ClientComponentSerializer.cs @@ -0,0 +1,75 @@ +// 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 System.Collections.Generic; +using System.Text.Json; +using Microsoft.AspNetCore.Components; + +namespace Microsoft.AspNetCore.Mvc.ViewFeatures +{ + // See the details of the component serialization protocol in WebAssemblyComponentDeserializer.cs on the Components solution. + internal class WebAssemblyComponentSerializer + { + public WebAssemblyComponentMarker SerializeInvocation(Type type, ParameterView parameters, bool prerendered) + { + var assembly = type.Assembly.GetName().Name; + var typeFullName = type.FullName; + var (definitions, values) = ComponentParameter.FromParameterView(parameters); + + // We need to serialize and Base64 encode parameters separately since they can contain arbitrary data that might + // cause the HTML comment to be invalid (like if you serialize a string that contains two consecutive dashes "--"). + var serializedDefinitions = Convert.ToBase64String(JsonSerializer.SerializeToUtf8Bytes(definitions, WebAssemblyComponentSerializationSettings.JsonSerializationOptions)); + var serializedValues = Convert.ToBase64String(JsonSerializer.SerializeToUtf8Bytes(values, WebAssemblyComponentSerializationSettings.JsonSerializationOptions)); + + return prerendered ? WebAssemblyComponentMarker.Prerendered(assembly, typeFullName, serializedDefinitions, serializedValues) : + WebAssemblyComponentMarker.NonPrerendered(assembly, typeFullName, serializedDefinitions, serializedValues); + } + + internal IEnumerable GetPreamble(WebAssemblyComponentMarker record) + { + var serializedStartRecord = JsonSerializer.Serialize( + record, + WebAssemblyComponentSerializationSettings.JsonSerializationOptions); + + if (record.PrerenderId != null) + { + return PrerenderedStart(serializedStartRecord); + } + else + { + return NonPrerenderedSequence(serializedStartRecord); + } + + static IEnumerable PrerenderedStart(string startRecord) + { + yield return ""; + } + + static IEnumerable NonPrerenderedSequence(string record) + { + yield return ""; + } + } + + internal IEnumerable GetEpilogue(WebAssemblyComponentMarker record) + { + var serializedStartRecord = JsonSerializer.Serialize( + record.GetEndRecord(), + WebAssemblyComponentSerializationSettings.JsonSerializationOptions); + + return PrerenderEnd(serializedStartRecord); + + static IEnumerable PrerenderEnd(string endRecord) + { + yield return ""; + } + } + } +} diff --git a/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs b/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs index 84ffe50ce1..933145e614 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs @@ -177,6 +177,9 @@ namespace Microsoft.Extensions.DependencyInjection // Component services for Blazor server-side interop services.TryAddSingleton(); + // Component services for Blazor webassembly interop + services.TryAddSingleton(); + // // View Components // diff --git a/src/Mvc/Mvc.ViewFeatures/src/Microsoft.AspNetCore.Mvc.ViewFeatures.csproj b/src/Mvc/Mvc.ViewFeatures/src/Microsoft.AspNetCore.Mvc.ViewFeatures.csproj index 56f7a39218..0a93600bcf 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/Microsoft.AspNetCore.Mvc.ViewFeatures.csproj +++ b/src/Mvc/Mvc.ViewFeatures/src/Microsoft.AspNetCore.Mvc.ViewFeatures.csproj @@ -1,4 +1,4 @@ - + @@ -31,7 +31,9 @@ + + diff --git a/src/Mvc/Mvc.ViewFeatures/src/PublicAPI.Unshipped.txt b/src/Mvc/Mvc.ViewFeatures/src/PublicAPI.Unshipped.txt index 4b6567f9ce..e371b29c8d 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/PublicAPI.Unshipped.txt +++ b/src/Mvc/Mvc.ViewFeatures/src/PublicAPI.Unshipped.txt @@ -77,6 +77,8 @@ Microsoft.AspNetCore.Mvc.Rendering.RenderMode Microsoft.AspNetCore.Mvc.Rendering.RenderMode.Server = 2 -> Microsoft.AspNetCore.Mvc.Rendering.RenderMode Microsoft.AspNetCore.Mvc.Rendering.RenderMode.ServerPrerendered = 3 -> Microsoft.AspNetCore.Mvc.Rendering.RenderMode Microsoft.AspNetCore.Mvc.Rendering.RenderMode.Static = 1 -> Microsoft.AspNetCore.Mvc.Rendering.RenderMode +Microsoft.AspNetCore.Mvc.Rendering.RenderMode.WebAssembly = 4 -> Microsoft.AspNetCore.Mvc.Rendering.RenderMode +Microsoft.AspNetCore.Mvc.Rendering.RenderMode.WebAssemblyPrerendered = 5 -> Microsoft.AspNetCore.Mvc.Rendering.RenderMode Microsoft.AspNetCore.Mvc.Rendering.SelectList Microsoft.AspNetCore.Mvc.Rendering.SelectListGroup Microsoft.AspNetCore.Mvc.Rendering.SelectListGroup.Disabled.get -> bool diff --git a/src/Mvc/Mvc.ViewFeatures/src/RazorComponents/ComponentRenderer.cs b/src/Mvc/Mvc.ViewFeatures/src/RazorComponents/ComponentRenderer.cs index 44a618fb04..0ba79b5927 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/RazorComponents/ComponentRenderer.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/RazorComponents/ComponentRenderer.cs @@ -1,4 +1,4 @@ -// 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. using System; @@ -15,13 +15,16 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures private static readonly object ComponentSequenceKey = new object(); private readonly StaticComponentRenderer _staticComponentRenderer; private readonly ServerComponentSerializer _serverComponentSerializer; + private readonly WebAssemblyComponentSerializer _WebAssemblyComponentSerializer; public ComponentRenderer( StaticComponentRenderer staticComponentRenderer, - ServerComponentSerializer serverComponentSerializer) + ServerComponentSerializer serverComponentSerializer, + WebAssemblyComponentSerializer WebAssemblyComponentSerializer) { _staticComponentRenderer = staticComponentRenderer; _serverComponentSerializer = serverComponentSerializer; + _WebAssemblyComponentSerializer = WebAssemblyComponentSerializer; } public async Task RenderComponentAsync( @@ -55,6 +58,8 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures RenderMode.Server => NonPrerenderedServerComponent(context, GetOrCreateInvocationId(viewContext), componentType, parameterView), RenderMode.ServerPrerendered => await PrerenderedServerComponentAsync(context, GetOrCreateInvocationId(viewContext), componentType, parameterView), RenderMode.Static => await StaticComponentAsync(context, componentType, parameterView), + RenderMode.WebAssembly => NonPrerenderedWebAssemblyComponent(context, componentType, parameterView), + RenderMode.WebAssemblyPrerendered => await PrerenderedWebAssemblyComponentAsync(context, componentType, parameterView), _ => throw new ArgumentException(Resources.FormatUnsupportedRenderMode(renderMode), nameof(renderMode)), }; } @@ -99,12 +104,36 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures _serverComponentSerializer.GetEpilogue(currentInvocation)); } + private async Task PrerenderedWebAssemblyComponentAsync(HttpContext context, Type type, ParameterView parametersCollection) + { + var currentInvocation = _WebAssemblyComponentSerializer.SerializeInvocation( + type, + parametersCollection, + prerendered: true); + + var result = await _staticComponentRenderer.PrerenderComponentAsync( + parametersCollection, + context, + type); + + return new ComponentHtmlContent( + _WebAssemblyComponentSerializer.GetPreamble(currentInvocation), + result, + _WebAssemblyComponentSerializer.GetEpilogue(currentInvocation)); + } + private IHtmlContent NonPrerenderedServerComponent(HttpContext context, ServerComponentInvocationSequence invocationId, Type type, ParameterView parametersCollection) { - var serviceProvider = context.RequestServices; var currentInvocation = _serverComponentSerializer.SerializeInvocation(invocationId, type, parametersCollection, prerendered: false); return new ComponentHtmlContent(_serverComponentSerializer.GetPreamble(currentInvocation)); } + + private IHtmlContent NonPrerenderedWebAssemblyComponent(HttpContext context, Type type, ParameterView parametersCollection) + { + var currentInvocation = _WebAssemblyComponentSerializer.SerializeInvocation(type, parametersCollection, prerendered: false); + + return new ComponentHtmlContent(_WebAssemblyComponentSerializer.GetPreamble(currentInvocation)); + } } } diff --git a/src/Mvc/Mvc.ViewFeatures/src/RazorComponents/StaticComponentRenderer.cs b/src/Mvc/Mvc.ViewFeatures/src/RazorComponents/StaticComponentRenderer.cs index 411e6014a8..7a8a8dd62d 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/RazorComponents/StaticComponentRenderer.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/RazorComponents/StaticComponentRenderer.cs @@ -1,4 +1,4 @@ -// 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. using System; @@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures Type componentType) { InitializeStandardComponentServices(httpContext); - var loggerFactory = (ILoggerFactory)httpContext.RequestServices.GetService(typeof (ILoggerFactory)); + var loggerFactory = (ILoggerFactory)httpContext.RequestServices.GetService(typeof(ILoggerFactory)); using (var htmlRenderer = new HtmlRenderer(httpContext.RequestServices, loggerFactory, _encoder.Encode)) { ComponentRenderedText result = default; @@ -71,15 +71,15 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures { _initialized = true; + var navigationManager = (IHostEnvironmentNavigationManager)httpContext.RequestServices.GetRequiredService(); + navigationManager?.Initialize(GetContextBaseUri(httpContext.Request), GetFullUri(httpContext.Request)); + var authenticationStateProvider = httpContext.RequestServices.GetService() as IHostEnvironmentAuthenticationStateProvider; if (authenticationStateProvider != null) { var authenticationState = new AuthenticationState(httpContext.User); authenticationStateProvider.SetAuthenticationState(Task.FromResult(authenticationState)); } - - var navigationManager = (IHostEnvironmentNavigationManager)httpContext.RequestServices.GetRequiredService(); - navigationManager?.Initialize(GetContextBaseUri(httpContext.Request), GetFullUri(httpContext.Request)); } } diff --git a/src/Mvc/Mvc.ViewFeatures/src/RenderMode.cs b/src/Mvc/Mvc.ViewFeatures/src/RenderMode.cs index f6816e68ff..d0422753cb 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/RenderMode.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/RenderMode.cs @@ -1,4 +1,4 @@ -// 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. namespace Microsoft.AspNetCore.Mvc.Rendering @@ -30,5 +30,16 @@ namespace Microsoft.AspNetCore.Mvc.Rendering /// ServerPrerendered = 3, + /// + /// Renders a marker for a Blazor webassembly application. This doesn't include any output from the component. + /// When the user-agent starts, it uses this marker to bootstrap a blazor client-side application. + /// + WebAssembly = 4, + + /// + /// Renders the component into static HTML and includes a marker for a Blazor webassembly application. + /// When the user-agent starts, it uses this marker to bootstrap a blazor client-side application. + /// + WebAssemblyPrerendered = 5, } } diff --git a/src/Mvc/Mvc.ViewFeatures/test/RazorComponents/ComponentRendererTest.cs b/src/Mvc/Mvc.ViewFeatures/test/RazorComponents/ComponentRendererTest.cs index f9e403ca2f..e20a4203b9 100644 --- a/src/Mvc/Mvc.ViewFeatures/test/RazorComponents/ComponentRendererTest.cs +++ b/src/Mvc/Mvc.ViewFeatures/test/RazorComponents/ComponentRendererTest.cs @@ -3,6 +3,7 @@ using System; using System.IO; +using System.Text; using System.Text.Encodings.Web; using System.Text.Json; using System.Text.RegularExpressions; @@ -26,13 +27,239 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures { public class ComponentRendererTest { - private const string PrerenderedServerComponentPattern = "^(?.+?)$"; - private const string ServerComponentPattern = "^$"; + private const string PrerenderedComponentPattern = "^(?.+?)$"; + private const string ComponentPattern = "^$"; private static readonly IDataProtectionProvider _dataprotectorProvider = new EphemeralDataProtectionProvider(); private readonly ComponentRenderer renderer = GetComponentRenderer(); + [Fact] + public async Task CanRender_ParameterlessComponent_ClientMode() + { + // Arrange + var viewContext = GetViewContext(); + var writer = new StringWriter(); + + // Act + var result = await renderer.RenderComponentAsync(viewContext, typeof(TestComponent), RenderMode.WebAssembly, null); + result.WriteTo(writer, HtmlEncoder.Default); + var content = writer.ToString(); + var match = Regex.Match(content, ComponentPattern); + + // Assert + Assert.True(match.Success); + var marker = JsonSerializer.Deserialize(match.Groups[1].Value, ServerComponentSerializationSettings.JsonSerializationOptions); + Assert.Null(marker.PrerenderId); + Assert.Equal("webassembly", marker.Type); + Assert.Equal(typeof(TestComponent).Assembly.GetName().Name, marker.Assembly); + Assert.Equal(typeof(TestComponent).FullName, marker.TypeName); + } + + [Fact] + public async Task CanPrerender_ParameterlessComponent_ClientMode() + { + // Arrange + var viewContext = GetViewContext(); + var writer = new StringWriter(); + + // Act + var result = await renderer.RenderComponentAsync(viewContext, typeof(TestComponent), RenderMode.WebAssemblyPrerendered, null); + result.WriteTo(writer, HtmlEncoder.Default); + var content = writer.ToString(); + var match = Regex.Match(content, PrerenderedComponentPattern, RegexOptions.Multiline); + + // Assert + Assert.True(match.Success); + var preamble = match.Groups["preamble"].Value; + var preambleMarker = JsonSerializer.Deserialize(preamble, ServerComponentSerializationSettings.JsonSerializationOptions); + Assert.NotNull(preambleMarker.PrerenderId); + Assert.Equal("webassembly", preambleMarker.Type); + Assert.Equal(typeof(TestComponent).Assembly.GetName().Name, preambleMarker.Assembly); + Assert.Equal(typeof(TestComponent).FullName, preambleMarker.TypeName); + + var prerenderedContent = match.Groups["content"].Value; + Assert.Equal("

Hello world!

", prerenderedContent); + + var epilogue = match.Groups["epilogue"].Value; + var epilogueMarker = JsonSerializer.Deserialize(epilogue, ServerComponentSerializationSettings.JsonSerializationOptions); + Assert.Equal(preambleMarker.PrerenderId, epilogueMarker.PrerenderId); + Assert.Null(epilogueMarker.Assembly); + Assert.Null(epilogueMarker.TypeName); + Assert.Null(epilogueMarker.Type); + Assert.Null(epilogueMarker.ParameterDefinitions); + Assert.Null(epilogueMarker.ParameterValues); + } + + [Fact] + public async Task CanRender_ComponentWithParameters_ClientMode() + { + // Arrange + var viewContext = GetViewContext(); + var writer = new StringWriter(); + + // Act + var result = await renderer.RenderComponentAsync(viewContext, typeof(GreetingComponent), + RenderMode.WebAssembly, + new + { + Name = "Daniel" + }); + result.WriteTo(writer, HtmlEncoder.Default); + var content = writer.ToString(); + var match = Regex.Match(content, ComponentPattern); + + // Assert + Assert.True(match.Success); + var marker = JsonSerializer.Deserialize(match.Groups[1].Value, ServerComponentSerializationSettings.JsonSerializationOptions); + Assert.Null(marker.PrerenderId); + Assert.Equal("webassembly", marker.Type); + Assert.Equal(typeof(GreetingComponent).Assembly.GetName().Name, marker.Assembly); + Assert.Equal(typeof(GreetingComponent).FullName, marker.TypeName); + + var parameterDefinition = Assert.Single( + JsonSerializer.Deserialize(Convert.FromBase64String(marker.ParameterDefinitions), WebAssemblyComponentSerializationSettings.JsonSerializationOptions)); + Assert.Equal("Name", parameterDefinition.Name); + Assert.Equal("System.String", parameterDefinition.TypeName); + Assert.Equal("System.Private.CoreLib", parameterDefinition.Assembly); + + var value = Assert.Single(JsonSerializer.Deserialize(Convert.FromBase64String(marker.ParameterValues), WebAssemblyComponentSerializationSettings.JsonSerializationOptions)); + var rawValue = Assert.IsType(value); + Assert.Equal("Daniel", rawValue.GetString()); + } + + [Fact] + public async Task CanRender_ComponentWithNullParameters_ClientMode() + { + // Arrange + var viewContext = GetViewContext(); + var writer = new StringWriter(); + + // Act + var result = await renderer.RenderComponentAsync(viewContext, typeof(GreetingComponent), + RenderMode.WebAssembly, + new + { + Name = (string)null + }); + result.WriteTo(writer, HtmlEncoder.Default); + var content = writer.ToString(); + var match = Regex.Match(content, ComponentPattern); + + // Assert + Assert.True(match.Success); + var marker = JsonSerializer.Deserialize(match.Groups[1].Value, ServerComponentSerializationSettings.JsonSerializationOptions); + Assert.Null(marker.PrerenderId); + Assert.Equal("webassembly", marker.Type); + Assert.Equal(typeof(GreetingComponent).Assembly.GetName().Name, marker.Assembly); + Assert.Equal(typeof(GreetingComponent).FullName, marker.TypeName); + + var parameterDefinition = Assert.Single(JsonSerializer.Deserialize(Convert.FromBase64String(marker.ParameterDefinitions), WebAssemblyComponentSerializationSettings.JsonSerializationOptions)); + Assert.Equal("Name", parameterDefinition.Name); + Assert.Null(parameterDefinition.TypeName); + Assert.Null(parameterDefinition.Assembly); + + var value = Assert.Single(JsonSerializer.Deserialize(Convert.FromBase64String(marker.ParameterValues), WebAssemblyComponentSerializationSettings.JsonSerializationOptions)); + Assert.Null(value); + } + + [Fact] + public async Task CanPrerender_ComponentWithParameters_ClientMode() + { + // Arrange + var viewContext = GetViewContext(); + var writer = new StringWriter(); + + // Act + var result = await renderer.RenderComponentAsync(viewContext, typeof(GreetingComponent), + RenderMode.WebAssemblyPrerendered, + new + { + Name = "Daniel" + }); + result.WriteTo(writer, HtmlEncoder.Default); + var content = writer.ToString(); + var match = Regex.Match(content, PrerenderedComponentPattern, RegexOptions.Multiline); + + // Assert + Assert.True(match.Success); + var preamble = match.Groups["preamble"].Value; + var preambleMarker = JsonSerializer.Deserialize(preamble, ServerComponentSerializationSettings.JsonSerializationOptions); + Assert.NotNull(preambleMarker.PrerenderId); + Assert.Equal("webassembly", preambleMarker.Type); + Assert.Equal(typeof(GreetingComponent).Assembly.GetName().Name, preambleMarker.Assembly); + Assert.Equal(typeof(GreetingComponent).FullName, preambleMarker.TypeName); + + var parameterDefinition = Assert.Single(JsonSerializer.Deserialize(Convert.FromBase64String(preambleMarker.ParameterDefinitions), WebAssemblyComponentSerializationSettings.JsonSerializationOptions)); + Assert.Equal("Name", parameterDefinition.Name); + Assert.Equal("System.String", parameterDefinition.TypeName); + Assert.Equal("System.Private.CoreLib", parameterDefinition.Assembly); + + var value = Assert.Single(JsonSerializer.Deserialize(Convert.FromBase64String(preambleMarker.ParameterValues), WebAssemblyComponentSerializationSettings.JsonSerializationOptions)); + var rawValue = Assert.IsType(value); + Assert.Equal("Daniel", rawValue.GetString()); + + var prerenderedContent = match.Groups["content"].Value; + Assert.Equal("

Hello Daniel!

", prerenderedContent); + + var epilogue = match.Groups["epilogue"].Value; + var epilogueMarker = JsonSerializer.Deserialize(epilogue, ServerComponentSerializationSettings.JsonSerializationOptions); + Assert.Equal(preambleMarker.PrerenderId, epilogueMarker.PrerenderId); + Assert.Null(epilogueMarker.Assembly); + Assert.Null(epilogueMarker.TypeName); + Assert.Null(epilogueMarker.Type); + Assert.Null(epilogueMarker.ParameterDefinitions); + Assert.Null(epilogueMarker.ParameterValues); + } + + [Fact] + public async Task CanPrerender_ComponentWithNullParameters_ClientMode() + { + // Arrange + var viewContext = GetViewContext(); + var writer = new StringWriter(); + + // Act + var result = await renderer.RenderComponentAsync(viewContext, typeof(GreetingComponent), + RenderMode.WebAssemblyPrerendered, + new + { + Name = (string)null + }); + result.WriteTo(writer, HtmlEncoder.Default); + var content = writer.ToString(); + var match = Regex.Match(content, PrerenderedComponentPattern, RegexOptions.Multiline); + + // Assert + Assert.True(match.Success); + var preamble = match.Groups["preamble"].Value; + var preambleMarker = JsonSerializer.Deserialize(preamble, ServerComponentSerializationSettings.JsonSerializationOptions); + Assert.NotNull(preambleMarker.PrerenderId); + Assert.Equal("webassembly", preambleMarker.Type); + Assert.Equal(typeof(GreetingComponent).Assembly.GetName().Name, preambleMarker.Assembly); + Assert.Equal(typeof(GreetingComponent).FullName, preambleMarker.TypeName); + + var parameterDefinition = Assert.Single(JsonSerializer.Deserialize(Convert.FromBase64String(preambleMarker.ParameterDefinitions), WebAssemblyComponentSerializationSettings.JsonSerializationOptions)); + Assert.Equal("Name", parameterDefinition.Name); + Assert.Null(parameterDefinition.TypeName); + Assert.Null(parameterDefinition.Assembly); + + var value = Assert.Single(JsonSerializer.Deserialize(Convert.FromBase64String(preambleMarker.ParameterValues), WebAssemblyComponentSerializationSettings.JsonSerializationOptions)); + Assert.Null(value); + + var prerenderedContent = match.Groups["content"].Value; + Assert.Equal("

Hello (null)!

", prerenderedContent); + + var epilogue = match.Groups["epilogue"].Value; + var epilogueMarker = JsonSerializer.Deserialize(epilogue, ServerComponentSerializationSettings.JsonSerializationOptions); + Assert.Equal(preambleMarker.PrerenderId, epilogueMarker.PrerenderId); + Assert.Null(epilogueMarker.Assembly); + Assert.Null(epilogueMarker.TypeName); + Assert.Null(epilogueMarker.Type); + Assert.Null(epilogueMarker.ParameterDefinitions); + Assert.Null(epilogueMarker.ParameterValues); + } + [Fact] public async Task CanRender_ParameterlessComponent() { @@ -60,7 +287,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures // Act var result = await renderer.RenderComponentAsync(viewContext, typeof(TestComponent), RenderMode.Server, null); var content = HtmlContentUtilities.HtmlContentToString(result); - var match = Regex.Match(content, ServerComponentPattern); + var match = Regex.Match(content, ComponentPattern); // Assert Assert.True(match.Success); @@ -89,7 +316,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures // Act var result = await renderer.RenderComponentAsync(viewContext, typeof(TestComponent), RenderMode.ServerPrerendered, null); var content = HtmlContentUtilities.HtmlContentToString(result); - var match = Regex.Match(content, PrerenderedServerComponentPattern, RegexOptions.Multiline); + var match = Regex.Match(content, PrerenderedComponentPattern, RegexOptions.Multiline); // Assert Assert.True(match.Success); @@ -130,11 +357,11 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures // Act var firstResult = await renderer.RenderComponentAsync(viewContext, typeof(TestComponent), RenderMode.ServerPrerendered, null); var firstComponent = HtmlContentUtilities.HtmlContentToString(firstResult); - var firstMatch = Regex.Match(firstComponent, PrerenderedServerComponentPattern, RegexOptions.Multiline); + var firstMatch = Regex.Match(firstComponent, PrerenderedComponentPattern, RegexOptions.Multiline); var secondResult = await renderer.RenderComponentAsync(viewContext, typeof(TestComponent), RenderMode.Server, null); var secondComponent = HtmlContentUtilities.HtmlContentToString(secondResult); - var secondMatch = Regex.Match(secondComponent, ServerComponentPattern); + var secondMatch = Regex.Match(secondComponent, ComponentPattern); // Assert Assert.True(firstMatch.Success); @@ -186,7 +413,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures // Act var result = await renderer.RenderComponentAsync(viewContext, typeof(GreetingComponent), RenderMode.Server, new { Name = "Daniel" }); var content = HtmlContentUtilities.HtmlContentToString(result); - var match = Regex.Match(content, ServerComponentPattern); + var match = Regex.Match(content, ComponentPattern); // Assert Assert.True(match.Success); @@ -225,7 +452,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures var result = await renderer.RenderComponentAsync(viewContext, typeof(GreetingComponent), RenderMode.Server, new { Name = (string)null }); var content = HtmlContentUtilities.HtmlContentToString(result); - var match = Regex.Match(content, ServerComponentPattern); + var match = Regex.Match(content, ComponentPattern); // Assert Assert.True(match.Success); @@ -264,7 +491,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures // Act var result = await renderer.RenderComponentAsync(viewContext, typeof(GreetingComponent), RenderMode.ServerPrerendered, new { Name = "Daniel" }); var content = HtmlContentUtilities.HtmlContentToString(result); - var match = Regex.Match(content, PrerenderedServerComponentPattern, RegexOptions.Multiline); + var match = Regex.Match(content, PrerenderedComponentPattern, RegexOptions.Multiline); // Assert Assert.True(match.Success); @@ -315,7 +542,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures // Act var result = await renderer.RenderComponentAsync(viewContext, typeof(GreetingComponent), RenderMode.ServerPrerendered, new { Name = (string)null }); var content = HtmlContentUtilities.HtmlContentToString(result); - var match = Regex.Match(content, PrerenderedServerComponentPattern, RegexOptions.Multiline); + var match = Regex.Match(content, PrerenderedComponentPattern, RegexOptions.Multiline); // Assert Assert.True(match.Success); @@ -554,7 +781,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures "; // Act - var result = await renderer.RenderComponentAsync(viewContext,typeof(AsyncComponent), RenderMode.Static, null); + var result = await renderer.RenderComponentAsync(viewContext, typeof(AsyncComponent), RenderMode.Static, null); var content = HtmlContentUtilities.HtmlContentToString(result); // Assert @@ -564,7 +791,8 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures private static ComponentRenderer GetComponentRenderer() => new ComponentRenderer( new StaticComponentRenderer(HtmlEncoder.Default), - new ServerComponentSerializer(_dataprotectorProvider)); + new ServerComponentSerializer(_dataprotectorProvider), + new WebAssemblyComponentSerializer()); private static ViewContext GetViewContext(HttpContext context = null, Action configureServices = null) { diff --git a/src/Shared/Components/WebAssemblyComponentMarker.cs b/src/Shared/Components/WebAssemblyComponentMarker.cs new file mode 100644 index 0000000000..bd8fab295a --- /dev/null +++ b/src/Shared/Components/WebAssemblyComponentMarker.cs @@ -0,0 +1,43 @@ +// 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; + +namespace Microsoft.AspNetCore.Components +{ + internal struct WebAssemblyComponentMarker + { + public const string ClientMarkerType = "webassembly"; + + public WebAssemblyComponentMarker(string type, string assembly, string typeName, string parameterDefinitions, string parameterValues, string prereenderId) => + (Type, Assembly, TypeName, ParameterDefinitions, ParameterValues, PrerenderId) = (type, assembly, typeName, parameterDefinitions, parameterValues, prereenderId); + + public string Type { get; set; } + + public string Assembly { get; set; } + + public string TypeName { get; set; } + + public string ParameterDefinitions { get; set; } + + public string ParameterValues { get; set; } + + public string PrerenderId { get; set; } + + internal static WebAssemblyComponentMarker NonPrerendered(string assembly, string typeName, string parameterDefinitions, string parameterValues) => + new WebAssemblyComponentMarker(ClientMarkerType, assembly, typeName, parameterDefinitions, parameterValues, null); + + internal static WebAssemblyComponentMarker Prerendered(string assembly, string typeName, string parameterDefinitions, string parameterValues) => + new WebAssemblyComponentMarker(ClientMarkerType, assembly, typeName, parameterDefinitions, parameterValues, Guid.NewGuid().ToString("N")); + + public WebAssemblyComponentMarker GetEndRecord() + { + if (PrerenderId == null) + { + throw new InvalidOperationException("Can't get an end record for non-prerendered components."); + } + + return new WebAssemblyComponentMarker(null, null, null, null, null, PrerenderId); + } + } +} diff --git a/src/Shared/Components/WebAssemblyComponentSerializationSettings.cs b/src/Shared/Components/WebAssemblyComponentSerializationSettings.cs new file mode 100644 index 0000000000..741ab989d5 --- /dev/null +++ b/src/Shared/Components/WebAssemblyComponentSerializationSettings.cs @@ -0,0 +1,19 @@ +// 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 System.Text.Json; + +namespace Microsoft.AspNetCore.Components +{ + internal static class WebAssemblyComponentSerializationSettings + { + public static readonly JsonSerializerOptions JsonSerializationOptions = + new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + PropertyNameCaseInsensitive = true, + IgnoreNullValues = true + }; + } +} diff --git a/src/Tools/dotnet-watch/test/TestProjects/KitchenSink/.net/objDebug/net5.0/.NETCoreApp,Version=v5.0.AssemblyAttributes.cs b/src/Tools/dotnet-watch/test/TestProjects/KitchenSink/.net/objDebug/net5.0/.NETCoreApp,Version=v5.0.AssemblyAttributes.cs new file mode 100644 index 0000000000..2f7e5ec5af --- /dev/null +++ b/src/Tools/dotnet-watch/test/TestProjects/KitchenSink/.net/objDebug/net5.0/.NETCoreApp,Version=v5.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v5.0", FrameworkDisplayName = "")] diff --git a/src/Tools/dotnet-watch/test/TestProjects/KitchenSink/.net/objDebug/net5.0/KitchenSink.AssemblyInfo.cs b/src/Tools/dotnet-watch/test/TestProjects/KitchenSink/.net/objDebug/net5.0/KitchenSink.AssemblyInfo.cs new file mode 100644 index 0000000000..1172632a87 --- /dev/null +++ b/src/Tools/dotnet-watch/test/TestProjects/KitchenSink/.net/objDebug/net5.0/KitchenSink.AssemblyInfo.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyMetadataAttribute("SourceCommitUrl", "https://github.com/dotnet/aspnetcore/tree/")] +[assembly: System.Reflection.AssemblyMetadataAttribute("Serviceable", "True")] +[assembly: System.Reflection.AssemblyCompanyAttribute("Microsoft Corporation")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyCopyrightAttribute("© Microsoft Corporation. All rights reserved.")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("42.42.42.42424")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("5.0.0-dev")] +[assembly: System.Reflection.AssemblyProductAttribute("Microsoft ASP.NET Core")] +[assembly: System.Reflection.AssemblyTitleAttribute("KitchenSink")] +[assembly: System.Reflection.AssemblyVersionAttribute("5.0.0.0")] +[assembly: System.Reflection.AssemblyMetadataAttribute("RepositoryUrl", "https://github.com/dotnet/aspnetcore")] +[assembly: System.Resources.NeutralResourcesLanguageAttribute("en-US")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/src/Tools/dotnet-watch/test/TestProjects/KitchenSink/.net/objDebug/net5.0/KitchenSink.AssemblyInfoInputs.cache b/src/Tools/dotnet-watch/test/TestProjects/KitchenSink/.net/objDebug/net5.0/KitchenSink.AssemblyInfoInputs.cache new file mode 100644 index 0000000000..9042200dfc --- /dev/null +++ b/src/Tools/dotnet-watch/test/TestProjects/KitchenSink/.net/objDebug/net5.0/KitchenSink.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +5426b0432f23f134c800ff0d43b24a23681aac3d From 70ea49fd8a020e8652d90a8313bd17e6915f160c Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 25 Aug 2020 17:00:07 +0000 Subject: [PATCH 75/81] Update dependencies from https://github.com/dotnet/efcore build 20200825.4 (#25243) [release/5.0] Update dependencies from dotnet/efcore - Updates: - Microsoft.EntityFrameworkCore.Tools: from 5.0.0-rc.1.20425.3 to 5.0.0-rc.1.20425.4 - Microsoft.EntityFrameworkCore.SqlServer: from 5.0.0-rc.1.20425.3 to 5.0.0-rc.1.20425.4 - dotnet-ef: from 5.0.0-rc.1.20425.3 to 5.0.0-rc.1.20425.4 - Microsoft.EntityFrameworkCore: from 5.0.0-rc.1.20425.3 to 5.0.0-rc.1.20425.4 - Microsoft.EntityFrameworkCore.Design: from 5.0.0-rc.1.20425.3 to 5.0.0-rc.1.20425.4 - Microsoft.EntityFrameworkCore.Relational: from 5.0.0-rc.1.20425.3 to 5.0.0-rc.1.20425.4 - Microsoft.EntityFrameworkCore.Sqlite: from 5.0.0-rc.1.20425.3 to 5.0.0-rc.1.20425.4 - Microsoft.EntityFrameworkCore.InMemory: from 5.0.0-rc.1.20425.3 to 5.0.0-rc.1.20425.4 --- eng/Version.Details.xml | 32 ++++++++++++++++---------------- eng/Versions.props | 16 ++++++++-------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ab3ec5f74e..c89e801957 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -13,37 +13,37 @@ https://github.com/dotnet/blazor cc449601d638ffaab58ae9487f0fd010bb178a12
- + https://github.com/dotnet/efcore - fa4bb966c1fbc30b6334e658f20bba46cb0555c8 + 9638c0cda4bfb2eb8b70a047baefc982ffa7dade - + https://github.com/dotnet/efcore - fa4bb966c1fbc30b6334e658f20bba46cb0555c8 + 9638c0cda4bfb2eb8b70a047baefc982ffa7dade - + https://github.com/dotnet/efcore - fa4bb966c1fbc30b6334e658f20bba46cb0555c8 + 9638c0cda4bfb2eb8b70a047baefc982ffa7dade - + https://github.com/dotnet/efcore - fa4bb966c1fbc30b6334e658f20bba46cb0555c8 + 9638c0cda4bfb2eb8b70a047baefc982ffa7dade - + https://github.com/dotnet/efcore - fa4bb966c1fbc30b6334e658f20bba46cb0555c8 + 9638c0cda4bfb2eb8b70a047baefc982ffa7dade - + https://github.com/dotnet/efcore - fa4bb966c1fbc30b6334e658f20bba46cb0555c8 + 9638c0cda4bfb2eb8b70a047baefc982ffa7dade - + https://github.com/dotnet/efcore - fa4bb966c1fbc30b6334e658f20bba46cb0555c8 + 9638c0cda4bfb2eb8b70a047baefc982ffa7dade - + https://github.com/dotnet/efcore - fa4bb966c1fbc30b6334e658f20bba46cb0555c8 + 9638c0cda4bfb2eb8b70a047baefc982ffa7dade https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 95429244e7..965ed5bdd1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -133,14 +133,14 @@ 3.2.0 - 5.0.0-rc.1.20425.3 - 5.0.0-rc.1.20425.3 - 5.0.0-rc.1.20425.3 - 5.0.0-rc.1.20425.3 - 5.0.0-rc.1.20425.3 - 5.0.0-rc.1.20425.3 - 5.0.0-rc.1.20425.3 - 5.0.0-rc.1.20425.3 + 5.0.0-rc.1.20425.4 + 5.0.0-rc.1.20425.4 + 5.0.0-rc.1.20425.4 + 5.0.0-rc.1.20425.4 + 5.0.0-rc.1.20425.4 + 5.0.0-rc.1.20425.4 + 5.0.0-rc.1.20425.4 + 5.0.0-rc.1.20425.4 false + + + true + true - - - - - + + + + - @@ -36,19 +45,5 @@ - - - <_RuntimeFramework Include="@(RuntimeFramework)" /> - - - - - - - - - - - diff --git a/src/Components/benchmarkapps/Wasm.Performance/Driver/Wasm.Performance.Driver.csproj b/src/Components/benchmarkapps/Wasm.Performance/Driver/Wasm.Performance.Driver.csproj index 66aea279ee..346ddc48f1 100644 --- a/src/Components/benchmarkapps/Wasm.Performance/Driver/Wasm.Performance.Driver.csproj +++ b/src/Components/benchmarkapps/Wasm.Performance/Driver/Wasm.Performance.Driver.csproj @@ -12,13 +12,18 @@ + + - + + + + - diff --git a/src/Components/test/testassets/TestServer/Components.TestServer.csproj b/src/Components/test/testassets/TestServer/Components.TestServer.csproj index 651b301bec..59b8fe5685 100644 --- a/src/Components/test/testassets/TestServer/Components.TestServer.csproj +++ b/src/Components/test/testassets/TestServer/Components.TestServer.csproj @@ -22,10 +22,13 @@ - + + + + <_Parameter1>Microsoft.AspNetCore.Testing.BasicTestApp.ContentRoot diff --git a/src/Tools/dotnet-watch/src/DotnetToolSettings.xml b/src/Tools/dotnet-watch/src/DotnetToolSettings.xml new file mode 100644 index 0000000000..f077af6da4 --- /dev/null +++ b/src/Tools/dotnet-watch/src/DotnetToolSettings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/Tools/dotnet-watch/src/dotnet-watch.csproj b/src/Tools/dotnet-watch/src/dotnet-watch.csproj index cbe5cf13c9..2975059825 100644 --- a/src/Tools/dotnet-watch/src/dotnet-watch.csproj +++ b/src/Tools/dotnet-watch/src/dotnet-watch.csproj @@ -10,6 +10,13 @@ false false + + + true + true @@ -20,8 +27,13 @@ - - + + + - - - <_RuntimeFramework Include="@(RuntimeFramework)" /> - - - - - - - - - - - - diff --git a/src/Tools/dotnet-watch/test/dotnet-watch.Tests.csproj b/src/Tools/dotnet-watch/test/dotnet-watch.Tests.csproj index d171daa39d..b9c9d9fe3c 100644 --- a/src/Tools/dotnet-watch/test/dotnet-watch.Tests.csproj +++ b/src/Tools/dotnet-watch/test/dotnet-watch.Tests.csproj @@ -5,6 +5,13 @@ Microsoft.DotNet.Watcher.Tools.Tests $(DefaultItemExcludes);TestProjects\**\* DotNetWatcherToolsTests + + + true + true @@ -14,6 +21,7 @@ + From c2f03318052aa81ce67c6abb120aae892ae519e7 Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Tue, 25 Aug 2020 10:47:37 -0700 Subject: [PATCH 77/81] Include project file in F# Worker Service template (#25180) - add test of this project template --- .../Microsoft.DotNet.Web.ProjectTemplates.csproj | 1 + src/ProjectTemplates/test/WorkerTemplateTest.cs | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj b/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj index 9aa8755e9f..e2021461e6 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj +++ b/src/ProjectTemplates/Web.ProjectTemplates/Microsoft.DotNet.Web.ProjectTemplates.csproj @@ -59,6 +59,7 @@ + diff --git a/src/ProjectTemplates/test/WorkerTemplateTest.cs b/src/ProjectTemplates/test/WorkerTemplateTest.cs index d7e4714585..1656ebb089 100644 --- a/src/ProjectTemplates/test/WorkerTemplateTest.cs +++ b/src/ProjectTemplates/test/WorkerTemplateTest.cs @@ -21,13 +21,17 @@ namespace Templates.Test public ProjectFactoryFixture ProjectFactory { get; } public ITestOutputHelper Output { get; } - [ConditionalFact] + [ConditionalTheory] [OSSkipCondition(OperatingSystems.Linux, SkipReason = "https://github.com/dotnet/sdk/issues/12831")] - public async Task WorkerTemplateAsync() + [InlineData("C#")] + [InlineData("F#")] + public async Task WorkerTemplateAsync(string language) { - Project = await ProjectFactory.GetOrCreateProject("worker", Output); + Project = await ProjectFactory.GetOrCreateProject( + $"worker-{ language.ToLowerInvariant()[0] }sharp", + Output); - var createResult = await Project.RunDotNetNewAsync("worker"); + var createResult = await Project.RunDotNetNewAsync("worker", language: language); Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult)); var publishResult = await Project.RunDotNetPublishAsync(); From 098be5f5ee2039ff7a184a4098802537390f2b35 Mon Sep 17 00:00:00 2001 From: John Luo Date: Tue, 25 Aug 2020 13:21:46 -0700 Subject: [PATCH 78/81] Use LDAP support from DirectoryServices.Protocols for RBAC claim resolution on Linux for Negotiate (#25075) --- eng/Dependencies.props | 1 + eng/Version.Details.xml | 4 + eng/Versions.props | 1 + .../samples/NegotiateAuthSample/Startup.cs | 18 ++++ .../Negotiate/src/Events/LdapContext.cs | 35 +++++++ .../Negotiate/src/Events/NegotiateEvents.cs | 11 +++ .../Negotiate/src/Internal/LdapAdapter.cs | 97 +++++++++++++++++++ ...NegotiateOptionsValidationStartupFilter.cs | 31 ++++++ .../Negotiate/src/LdapSettings.cs | 75 ++++++++++++++ ...AspNetCore.Authentication.Negotiate.csproj | 2 + .../Negotiate/src/NegotiateExtensions.cs | 3 + .../Negotiate/src/NegotiateHandler.cs | 34 ++++++- .../Negotiate/src/NegotiateOptions.cs | 38 ++++++++ .../src/PostConfigureNegotiateOptions.cs | 32 ++++++ .../test/Negotiate.Test/EventTests.cs | 23 ++++- .../LdapSettingsValidationTests.cs | 34 +++++++ .../Negotiate.Test/ServerDeferralTests.cs | 3 +- 17 files changed, 435 insertions(+), 7 deletions(-) create mode 100644 src/Security/Authentication/Negotiate/src/Events/LdapContext.cs create mode 100644 src/Security/Authentication/Negotiate/src/Internal/LdapAdapter.cs create mode 100644 src/Security/Authentication/Negotiate/src/Internal/NegotiateOptionsValidationStartupFilter.cs create mode 100644 src/Security/Authentication/Negotiate/src/LdapSettings.cs create mode 100644 src/Security/Authentication/Negotiate/test/Negotiate.Test/LdapSettingsValidationTests.cs diff --git a/eng/Dependencies.props b/eng/Dependencies.props index 8da95c6314..68e1f6149c 100644 --- a/eng/Dependencies.props +++ b/eng/Dependencies.props @@ -64,6 +64,7 @@ and are generated based on the last package release. + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c89e801957..db9cc55f62 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -205,6 +205,10 @@ https://github.com/dotnet/runtime f4e99f4afa445b519abcd7c5c87cbf54771614db + + https://github.com/dotnet/runtime + f4e99f4afa445b519abcd7c5c87cbf54771614db + https://github.com/dotnet/runtime f4e99f4afa445b519abcd7c5c87cbf54771614db diff --git a/eng/Versions.props b/eng/Versions.props index 965ed5bdd1..9c2fd0000e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -108,6 +108,7 @@ 5.0.0-rc.1.20425.1 5.0.0-rc.1.20425.1 5.0.0-rc.1.20425.1 + 5.0.0-rc.1.20425.1 5.0.0-rc.1.20425.1 5.0.0-rc.1.20425.1 5.0.0-rc.1.20425.1 diff --git a/src/Security/Authentication/Negotiate/samples/NegotiateAuthSample/Startup.cs b/src/Security/Authentication/Negotiate/samples/NegotiateAuthSample/Startup.cs index 2e62846f8f..c2b0b0ba7f 100644 --- a/src/Security/Authentication/Negotiate/samples/NegotiateAuthSample/Startup.cs +++ b/src/Security/Authentication/Negotiate/samples/NegotiateAuthSample/Startup.cs @@ -1,6 +1,7 @@ // 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.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication.Negotiate; using Microsoft.AspNetCore.Builder; @@ -22,6 +23,23 @@ namespace NegotiateAuthSample services.AddAuthentication(NegotiateDefaults.AuthenticationScheme) .AddNegotiate(options => { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + /* + options.EnableLdap("DOMAIN.net"); + + options.EnableLdap(settings => + { + // Mandatory settings + settings.Domain = "DOMAIN.com"; + // Optional settings + settings.MachineAccountName = "machineName"; + settings.MachineAccountPassword = "PassW0rd"; + settings.IgnoreNestedGroups = true; + }); + */ + } + options.Events = new NegotiateEvents() { OnAuthenticationFailed = context => diff --git a/src/Security/Authentication/Negotiate/src/Events/LdapContext.cs b/src/Security/Authentication/Negotiate/src/Events/LdapContext.cs new file mode 100644 index 0000000000..9e6d7a40ac --- /dev/null +++ b/src/Security/Authentication/Negotiate/src/Events/LdapContext.cs @@ -0,0 +1,35 @@ +// 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.Http; + +namespace Microsoft.AspNetCore.Authentication.Negotiate +{ + /// + /// State for the RetrieveLdapClaims event. + /// + public class LdapContext : ResultContext + { + /// + /// Creates a new . + /// + /// + /// + /// + /// + public LdapContext( + HttpContext context, + AuthenticationScheme scheme, + NegotiateOptions options, + LdapSettings settings) + : base(context, scheme, options) + { + LdapSettings = settings; + } + + /// + /// The LDAP settings to use for the RetrieveLdapClaims event. + /// + public LdapSettings LdapSettings { get; } + } +} diff --git a/src/Security/Authentication/Negotiate/src/Events/NegotiateEvents.cs b/src/Security/Authentication/Negotiate/src/Events/NegotiateEvents.cs index 0d57be28eb..88dfdf2b74 100644 --- a/src/Security/Authentication/Negotiate/src/Events/NegotiateEvents.cs +++ b/src/Security/Authentication/Negotiate/src/Events/NegotiateEvents.cs @@ -16,6 +16,12 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate /// public Func OnAuthenticationFailed { get; set; } = context => Task.CompletedTask; + /// + /// Invoked after the authentication before ClaimsIdentity is populated with claims retrieved through the LDAP connection. + /// This event is invoked when is set to true on . + /// + public Func OnRetrieveLdapClaims { get; set; } = context => Task.CompletedTask; + /// /// Invoked after the authentication is complete and a ClaimsIdentity has been generated. /// @@ -31,6 +37,11 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate /// public virtual Task AuthenticationFailed(AuthenticationFailedContext context) => OnAuthenticationFailed(context); + /// + /// Invoked after the authentication before ClaimsIdentity is populated with claims retrieved through the LDAP connection. + /// + public virtual Task RetrieveLdapClaims(LdapContext context) => OnRetrieveLdapClaims(context); + /// /// Invoked after the authentication is complete and a ClaimsIdentity has been generated. /// diff --git a/src/Security/Authentication/Negotiate/src/Internal/LdapAdapter.cs b/src/Security/Authentication/Negotiate/src/Internal/LdapAdapter.cs new file mode 100644 index 0000000000..4ddad3c5e3 --- /dev/null +++ b/src/Security/Authentication/Negotiate/src/Internal/LdapAdapter.cs @@ -0,0 +1,97 @@ +// 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.DirectoryServices.Protocols; +using System.Linq; +using System.Security.Claims; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; + +namespace Microsoft.AspNetCore.Authentication.Negotiate +{ + internal static class LdapAdapter + { + public static async Task RetrieveClaimsAsync(LdapSettings settings, ClaimsIdentity identity, ILogger logger) + { + var user = identity.Name; + var userAccountName = user.Substring(0, user.IndexOf('@')); + var distinguishedName = settings.Domain.Split('.').Select(name => $"dc={name}").Aggregate((a, b) => $"{a},{b}"); + + var filter = $"(&(objectClass=user)(sAMAccountName={userAccountName}))"; // This is using ldap search query language, it is looking on the server for someUser + var searchRequest = new SearchRequest(distinguishedName, filter, SearchScope.Subtree, null); + var searchResponse = (SearchResponse) await Task.Factory.FromAsync( + settings.LdapConnection.BeginSendRequest, + settings.LdapConnection.EndSendRequest, + searchRequest, + PartialResultProcessing.NoPartialResultSupport, + null); + + if (searchResponse.Entries.Count > 0) + { + if (searchResponse.Entries.Count > 1) + { + logger.LogWarning($"More than one response received for query: {filter} with distinguished name: {distinguishedName}"); + } + + var userFound = searchResponse.Entries[0]; //Get the object that was found on ldap + var memberof = userFound.Attributes["memberof"]; // You can access ldap Attributes with Attributes property + + foreach (var group in memberof) + { + // Example distinguished name: CN=TestGroup,DC=KERB,DC=local + var groupDN = $"{Encoding.UTF8.GetString((byte[])group)}"; + var groupCN = groupDN.Split(',')[0].Substring("CN=".Length); + + if (!settings.IgnoreNestedGroups) + { + GetNestedGroups(settings.LdapConnection, identity, distinguishedName, groupCN, logger); + } + else + { + AddRole(identity, groupCN); + } + } + } + else + { + logger.LogWarning($"No response received for query: {filter} with distinguished name: {distinguishedName}"); + } + } + + private static void GetNestedGroups(LdapConnection connection, ClaimsIdentity principal, string distinguishedName, string groupCN, ILogger logger) + { + var filter = $"(&(objectClass=group)(sAMAccountName={groupCN}))"; // This is using ldap search query language, it is looking on the server for someUser + var searchRequest = new SearchRequest(distinguishedName, filter, System.DirectoryServices.Protocols.SearchScope.Subtree, null); + var searchResponse = (SearchResponse)connection.SendRequest(searchRequest); + + if (searchResponse.Entries.Count > 0) + { + if (searchResponse.Entries.Count > 1) + { + logger.LogWarning($"More than one response received for query: {filter} with distinguished name: {distinguishedName}"); + } + + var group = searchResponse.Entries[0]; //Get the object that was found on ldap + string name = group.DistinguishedName; + AddRole(principal, name); + + var memberof = group.Attributes["memberof"]; // You can access ldap Attributes with Attributes property + if (memberof != null) + { + foreach (var member in memberof) + { + var groupDN = $"{Encoding.UTF8.GetString((byte[])member)}"; + var nestedGroupCN = groupDN.Split(',')[0].Substring("CN=".Length); + GetNestedGroups(connection, principal, distinguishedName, nestedGroupCN, logger); + } + } + } + } + + private static void AddRole(ClaimsIdentity identity, string role) + { + identity.AddClaim(new Claim(identity.RoleClaimType, role)); + } + } +} diff --git a/src/Security/Authentication/Negotiate/src/Internal/NegotiateOptionsValidationStartupFilter.cs b/src/Security/Authentication/Negotiate/src/Internal/NegotiateOptionsValidationStartupFilter.cs new file mode 100644 index 0000000000..429a57d81e --- /dev/null +++ b/src/Security/Authentication/Negotiate/src/Internal/NegotiateOptionsValidationStartupFilter.cs @@ -0,0 +1,31 @@ +// 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.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Authentication.Negotiate.Internal +{ + internal class NegotiateOptionsValidationStartupFilter : IStartupFilter + { + private readonly string _authenticationScheme; + + public NegotiateOptionsValidationStartupFilter(string authenticationScheme) + { + _authenticationScheme = authenticationScheme; + } + + public Action Configure(Action next) + { + return builder => + { + // Resolve NegotiateOptions on startup to trigger post configuration and bind LdapConnection if needed + var options = builder.ApplicationServices.GetRequiredService>().Get(_authenticationScheme); + next(builder); + }; + } + } +} diff --git a/src/Security/Authentication/Negotiate/src/LdapSettings.cs b/src/Security/Authentication/Negotiate/src/LdapSettings.cs new file mode 100644 index 0000000000..1e26c26c14 --- /dev/null +++ b/src/Security/Authentication/Negotiate/src/LdapSettings.cs @@ -0,0 +1,75 @@ +// 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 System.DirectoryServices.Protocols; + +namespace Microsoft.AspNetCore.Authentication.Negotiate +{ + /// + /// Options class for configuring LDAP connections on Linux + /// + public class LdapSettings + { + /// + /// Configure whether LDAP connection should be used to resolve claims. + /// This is mainly used on Linux. + /// + public bool EnableLdapClaimResolution { get; set; } + + /// + /// The domain to use for the LDAP connection. This is a mandatory setting. + /// + /// + /// DOMAIN.com + /// + public string Domain { get; set; } + + /// + /// The machine account name to use when opening the LDAP connection. + /// If this is not provided, the machine wide credentials of the + /// domain joined machine will be used. + /// + public string MachineAccountName { get; set; } + + /// + /// The machine account password to use when opening the LDAP connection. + /// This must be provided if a is provided. + /// + public string MachineAccountPassword { get; set; } + + /// + /// This option indicates whether nested groups should be ignored when + /// resolving Roles. The default is false. + /// + public bool IgnoreNestedGroups { get; set; } + + /// + /// The to be used to retrieve role claims. + /// If no explicit connection is provided, an LDAP connection will be + /// automatically created based on the , + /// and + /// options. If provided, this connection will be used and the + /// , and + /// options will not be used to create + /// the . + /// + public LdapConnection LdapConnection { get; set; } + + public void Validate() + { + if (EnableLdapClaimResolution) + { + if (string.IsNullOrEmpty(Domain)) + { + throw new ArgumentException($"{nameof(EnableLdapClaimResolution)} is set to true but {nameof(Domain)} is not set."); + } + + if (string.IsNullOrEmpty(MachineAccountName) && !string.IsNullOrEmpty(MachineAccountPassword)) + { + throw new ArgumentException($"{nameof(MachineAccountPassword)} should only be specified when {nameof(MachineAccountName)} is configured."); + } + } + } + } +} diff --git a/src/Security/Authentication/Negotiate/src/Microsoft.AspNetCore.Authentication.Negotiate.csproj b/src/Security/Authentication/Negotiate/src/Microsoft.AspNetCore.Authentication.Negotiate.csproj index 265ffb533a..c0aac839f5 100644 --- a/src/Security/Authentication/Negotiate/src/Microsoft.AspNetCore.Authentication.Negotiate.csproj +++ b/src/Security/Authentication/Negotiate/src/Microsoft.AspNetCore.Authentication.Negotiate.csproj @@ -10,7 +10,9 @@ + + diff --git a/src/Security/Authentication/Negotiate/src/NegotiateExtensions.cs b/src/Security/Authentication/Negotiate/src/NegotiateExtensions.cs index f5bbf8cbc8..e47417e170 100644 --- a/src/Security/Authentication/Negotiate/src/NegotiateExtensions.cs +++ b/src/Security/Authentication/Negotiate/src/NegotiateExtensions.cs @@ -4,6 +4,8 @@ using System; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Negotiate; +using Microsoft.AspNetCore.Authentication.Negotiate.Internal; +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; @@ -52,6 +54,7 @@ namespace Microsoft.Extensions.DependencyInjection public static AuthenticationBuilder AddNegotiate(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action configureOptions) { builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton, PostConfigureNegotiateOptions>()); + builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton(new NegotiateOptionsValidationStartupFilter(authenticationScheme))); return builder.AddScheme(authenticationScheme, displayName, configureOptions); } } diff --git a/src/Security/Authentication/Negotiate/src/NegotiateHandler.cs b/src/Security/Authentication/Negotiate/src/NegotiateHandler.cs index 835542a42d..0ef6697857 100644 --- a/src/Security/Authentication/Negotiate/src/NegotiateHandler.cs +++ b/src/Security/Authentication/Negotiate/src/NegotiateHandler.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Runtime.InteropServices; using System.Security.Claims; using System.Security.Principal; using System.Text.Encodings.Web; @@ -324,10 +325,37 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate user = new ClaimsPrincipal(new ClaimsIdentity(identity)); } - var authenticatedContext = new AuthenticatedContext(Context, Scheme, Options) + AuthenticatedContext authenticatedContext; + + if (Options.LdapSettings.EnableLdapClaimResolution) { - Principal = user - }; + var ldapContext = new LdapContext(Context, Scheme, Options, Options.LdapSettings) + { + Principal = user + }; + + await Events.RetrieveLdapClaims(ldapContext); + + if (ldapContext.Result != null) + { + return ldapContext.Result; + } + + await LdapAdapter.RetrieveClaimsAsync(ldapContext.LdapSettings, ldapContext.Principal.Identity as ClaimsIdentity, Logger); + + authenticatedContext = new AuthenticatedContext(Context, Scheme, Options) + { + Principal = ldapContext.Principal + }; + } + else + { + authenticatedContext = new AuthenticatedContext(Context, Scheme, Options) + { + Principal = user + }; + } + await Events.Authenticated(authenticatedContext); if (authenticatedContext.Result != null) diff --git a/src/Security/Authentication/Negotiate/src/NegotiateOptions.cs b/src/Security/Authentication/Negotiate/src/NegotiateOptions.cs index 3f5d36b39f..40d090265c 100644 --- a/src/Security/Authentication/Negotiate/src/NegotiateOptions.cs +++ b/src/Security/Authentication/Negotiate/src/NegotiateOptions.cs @@ -1,6 +1,8 @@ // 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; + namespace Microsoft.AspNetCore.Authentication.Negotiate { /// @@ -33,6 +35,42 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate /// public bool PersistNtlmCredentials { get; set; } = true; + /// + /// Configuration settings for LDAP connections used to retrieve claims. + /// This should only be used on Linux systems. + /// + internal LdapSettings LdapSettings { get; } = new LdapSettings(); + + /// + /// Use LDAP connections used to retrieve claims for the given domain. + /// This should only be used on Linux systems. + /// + public void EnableLdap(string domain) + { + if (string.IsNullOrEmpty(domain)) + { + throw new ArgumentNullException(nameof(domain)); + } + + LdapSettings.EnableLdapClaimResolution = true; + LdapSettings.Domain = domain; + } + + /// + /// Use LDAP connections used to retrieve claims using the configured settings. + /// This should only be used on Linux systems. + /// + public void EnableLdap(Action configureSettings) + { + if (configureSettings == null) + { + throw new ArgumentNullException(nameof(configureSettings)); + } + + LdapSettings.EnableLdapClaimResolution = true; + configureSettings(LdapSettings); + } + /// /// Indicates if integrated server Windows Auth is being used instead of this handler. /// See . diff --git a/src/Security/Authentication/Negotiate/src/PostConfigureNegotiateOptions.cs b/src/Security/Authentication/Negotiate/src/PostConfigureNegotiateOptions.cs index 91384c3293..4fb8a29be4 100644 --- a/src/Security/Authentication/Negotiate/src/PostConfigureNegotiateOptions.cs +++ b/src/Security/Authentication/Negotiate/src/PostConfigureNegotiateOptions.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.DirectoryServices.Protocols; using System.Linq; +using System.Net; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -59,6 +61,36 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate + " Enable Windows Authentication for the server and the Negotiate Authentication handler will defer to it."); } } + + var ldapSettings = options.LdapSettings; + + if (ldapSettings.EnableLdapClaimResolution) + { + ldapSettings.Validate(); + + if (ldapSettings.LdapConnection == null) + { + var di = new LdapDirectoryIdentifier(server: ldapSettings.Domain, fullyQualifiedDnsHostName: true, connectionless: false); + + if (string.IsNullOrEmpty(ldapSettings.MachineAccountName)) + { + // Use default credentials + ldapSettings.LdapConnection = new LdapConnection(di); + } + else + { + // Use specific specific machine account + var machineAccount = ldapSettings.MachineAccountName + "@" + ldapSettings.Domain; + var credentials = new NetworkCredential(machineAccount, ldapSettings.MachineAccountPassword); + ldapSettings.LdapConnection = new LdapConnection(di, credentials); + } + + ldapSettings.LdapConnection.SessionOptions.ProtocolVersion = 3; //Setting LDAP Protocol to latest version + ldapSettings.LdapConnection.Timeout = TimeSpan.FromMinutes(1); + } + + ldapSettings.LdapConnection.Bind(); // This line actually makes the connection. + } } } } diff --git a/src/Security/Authentication/Negotiate/test/Negotiate.Test/EventTests.cs b/src/Security/Authentication/Negotiate/test/Negotiate.Test/EventTests.cs index 0979640207..af471a5450 100644 --- a/src/Security/Authentication/Negotiate/test/Negotiate.Test/EventTests.cs +++ b/src/Security/Authentication/Negotiate/test/Negotiate.Test/EventTests.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Reflection.Metadata; using System.Security.Principal; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; @@ -13,7 +12,6 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.TestHost; -using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Net.Http.Headers; @@ -371,6 +369,27 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate Assert.Equal(1, callCount); } + [Fact] + public async Task OnRetrieveLdapClaims_DoesNotFireWhenLdapDisabled() + { + var callCount = 0; + using var host = await CreateHostAsync(options => + { + options.Events = new NegotiateEvents() + { + OnRetrieveLdapClaims = context => + { + callCount++; + return Task.CompletedTask; + } + }; + }); + var server = host.GetTestServer(); + + await KerberosStage1And2Auth(server, new TestConnection()); + Assert.Equal(0, callCount); + } + private static async Task KerberosStage1And2Auth(TestServer server, TestConnection testConnection) { await KerberosStage1Auth(server, testConnection); diff --git a/src/Security/Authentication/Negotiate/test/Negotiate.Test/LdapSettingsValidationTests.cs b/src/Security/Authentication/Negotiate/test/Negotiate.Test/LdapSettingsValidationTests.cs new file mode 100644 index 0000000000..6a706d820b --- /dev/null +++ b/src/Security/Authentication/Negotiate/test/Negotiate.Test/LdapSettingsValidationTests.cs @@ -0,0 +1,34 @@ +// 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 Xunit; + +namespace Microsoft.AspNetCore.Authentication.Negotiate.Test +{ + public class LdapSettingsValidationTests + { + [Fact] + public void EnabledWithoutDomainThrows() + { + var settings = new LdapSettings + { + EnableLdapClaimResolution = true + }; + + Assert.Throws(() => settings.Validate()); + } + + [Fact] + public void AccountPasswordWithoutAccountNameThrows() + { + var settings = new LdapSettings + { + EnableLdapClaimResolution = true, + MachineAccountPassword = "Passw0rd" + }; + + Assert.Throws(() => settings.Validate()); + } + } +} diff --git a/src/Security/Authentication/Negotiate/test/Negotiate.Test/ServerDeferralTests.cs b/src/Security/Authentication/Negotiate/test/Negotiate.Test/ServerDeferralTests.cs index efd513b829..f038c7ca80 100644 --- a/src/Security/Authentication/Negotiate/test/Negotiate.Test/ServerDeferralTests.cs +++ b/src/Security/Authentication/Negotiate/test/Negotiate.Test/ServerDeferralTests.cs @@ -29,8 +29,7 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate [Fact] public async Task ServerSupportsAuthButDisabled_Error() { - using var host = await CreateHostAsync(supportsAuth: true, isEnabled: false); - var ex = Assert.Throws(() => host.Services.GetRequiredService>().Value); + var ex = await Assert.ThrowsAsync(async () => await CreateHostAsync(supportsAuth: true, isEnabled: false)); Assert.Equal("The Negotiate Authentication handler cannot be used on a server that directly supports Windows Authentication." + " Enable Windows Authentication for the server and the Negotiate Authentication handler will defer to it.", ex.Message); } From e2dd2969b58a0b84a4cec5f5a737cf78d757b072 Mon Sep 17 00:00:00 2001 From: Safia Abdalla Date: Wed, 26 Aug 2020 19:22:34 +0000 Subject: [PATCH 79/81] Set SameSiteMode for cookies in authentication tests (#25281) --- .../testassets/Wasm.Authentication.Server/Startup.cs | 6 ++++++ .../Wasm.Authentication.Server.csproj | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Startup.cs b/src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Startup.cs index 1224ee978f..038e01f0c7 100644 --- a/src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Startup.cs +++ b/src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Startup.cs @@ -3,6 +3,7 @@ using System.Linq; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; @@ -57,6 +58,11 @@ namespace Wasm.Authentication.Server app.UseWebAssemblyDebugging(); } + app.UseCookiePolicy(new CookiePolicyOptions + { + MinimumSameSitePolicy = SameSiteMode.Lax + }); + app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); diff --git a/src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Wasm.Authentication.Server.csproj b/src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Wasm.Authentication.Server.csproj index 142bfe2145..8daf509266 100644 --- a/src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Wasm.Authentication.Server.csproj +++ b/src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Wasm.Authentication.Server.csproj @@ -10,10 +10,12 @@ + + From 2916f4b09b0cf9e2075bee3fb934949dbae956ab Mon Sep 17 00:00:00 2001 From: Mackinnon Buck Date: Wed, 26 Aug 2020 12:56:56 -0700 Subject: [PATCH 80/81] Fixed server interop reliability tests (#25244) --- src/Components/Ignitor/src/BlazorClient.cs | 6 +++--- src/Components/Ignitor/src/CapturedJSInteropCall.cs | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Components/Ignitor/src/BlazorClient.cs b/src/Components/Ignitor/src/BlazorClient.cs index 5353659f36..b19ab8b3dd 100644 --- a/src/Components/Ignitor/src/BlazorClient.cs +++ b/src/Components/Ignitor/src/BlazorClient.cs @@ -353,7 +353,7 @@ namespace Ignitor _hubConnection = builder.Build(); HubConnection.On("JS.AttachComponent", OnAttachComponent); - HubConnection.On("JS.BeginInvokeJS", OnBeginInvokeJS); + HubConnection.On("JS.BeginInvokeJS", OnBeginInvokeJS); HubConnection.On("JS.EndInvokeDotNet", OnEndInvokeDotNet); HubConnection.On("JS.RenderBatch", OnRenderBatch); HubConnection.On("JS.Error", OnError); @@ -401,9 +401,9 @@ namespace Ignitor NextAttachComponentReceived?.Completion?.TrySetResult(call); } - private void OnBeginInvokeJS(int asyncHandle, string identifier, string argsJson) + private void OnBeginInvokeJS(int asyncHandle, string identifier, string argsJson, int resultType, long targetInstanceId) { - var call = new CapturedJSInteropCall(asyncHandle, identifier, argsJson); + var call = new CapturedJSInteropCall(asyncHandle, identifier, argsJson, resultType, targetInstanceId); Operations?.JSInteropCalls.Enqueue(call); JSInterop?.Invoke(call); diff --git a/src/Components/Ignitor/src/CapturedJSInteropCall.cs b/src/Components/Ignitor/src/CapturedJSInteropCall.cs index 4af491a58a..0dc8b0fa11 100644 --- a/src/Components/Ignitor/src/CapturedJSInteropCall.cs +++ b/src/Components/Ignitor/src/CapturedJSInteropCall.cs @@ -5,15 +5,19 @@ namespace Ignitor { public class CapturedJSInteropCall { - public CapturedJSInteropCall(int asyncHandle, string identifier, string argsJson) + public CapturedJSInteropCall(int asyncHandle, string identifier, string argsJson, int resultType, long targetInstanceId) { AsyncHandle = asyncHandle; Identifier = identifier; ArgsJson = argsJson; + ResultType = resultType; + TargetInstanceId = targetInstanceId; } public int AsyncHandle { get; } public string Identifier { get; } public string ArgsJson { get; } + public int ResultType { get; } + public long TargetInstanceId { get; } } } From f2b72b051166329d4c1f7a3aa5a6295883e2c334 Mon Sep 17 00:00:00 2001 From: Brennan Date: Wed, 26 Aug 2020 14:23:01 -0700 Subject: [PATCH 81/81] Fix SignalR typescript tests with Chrome SameSite reaction (#25283) * Fix Typescript tests * fixup --- .../clients/ts/FunctionalTests/Startup.cs | 18 +++++++++++++++--- .../clients/ts/FunctionalTests/ts/Common.ts | 12 ++++++++++++ .../ts/FunctionalTests/ts/ConnectionTests.ts | 14 ++++++++------ .../FunctionalTests/ts/HubConnectionTests.ts | 18 ++++-------------- 4 files changed, 39 insertions(+), 23 deletions(-) diff --git a/src/SignalR/clients/ts/FunctionalTests/Startup.cs b/src/SignalR/clients/ts/FunctionalTests/Startup.cs index 8a3ccfa767..a53eec75d2 100644 --- a/src/SignalR/clients/ts/FunctionalTests/Startup.cs +++ b/src/SignalR/clients/ts/FunctionalTests/Startup.cs @@ -163,9 +163,21 @@ namespace FunctionalTests { if (context.Request.Path.Value.Contains("/negotiate")) { - context.Response.Cookies.Append("testCookie", "testValue"); - context.Response.Cookies.Append("testCookie2", "testValue2"); - context.Response.Cookies.Append("expiredCookie", "doesntmatter", new CookieOptions() { Expires = DateTimeOffset.Now.AddHours(-1) }); + var cookieOptions = new CookieOptions(); + var expiredCookieOptions = new CookieOptions() { Expires = DateTimeOffset.Now.AddHours(-1) }; + if (context.Request.IsHttps) + { + cookieOptions.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None; + cookieOptions.Secure = true; + + expiredCookieOptions.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None; + expiredCookieOptions.Secure = true; + } + context.Response.Cookies.Append("testCookie", "testValue", cookieOptions); + context.Response.Cookies.Append("testCookie2", "testValue2", cookieOptions); + + cookieOptions.Expires = DateTimeOffset.Now.AddHours(-1); + context.Response.Cookies.Append("expiredCookie", "doesntmatter", expiredCookieOptions); } await next.Invoke(); diff --git a/src/SignalR/clients/ts/FunctionalTests/ts/Common.ts b/src/SignalR/clients/ts/FunctionalTests/ts/Common.ts index 668a738536..4eb412145a 100644 --- a/src/SignalR/clients/ts/FunctionalTests/ts/Common.ts +++ b/src/SignalR/clients/ts/FunctionalTests/ts/Common.ts @@ -60,6 +60,7 @@ console.log(`Using SignalR HTTPS Server: '${ENDPOINT_BASE_HTTPS_URL}'`); console.log(`Jasmine DEFAULT_TIMEOUT_INTERVAL: ${jasmine.DEFAULT_TIMEOUT_INTERVAL}`); export const ECHOENDPOINT_URL = ENDPOINT_BASE_URL + "/echo"; +export const HTTPS_ECHOENDPOINT_URL = ENDPOINT_BASE_HTTPS_URL + "/echo"; export function getHttpTransportTypes(): HttpTransportType[] { const transportTypes = []; @@ -131,3 +132,14 @@ export function eachHttpClient(action: (transport: HttpClient) => void) { return action(t); }); } + +// Run test in Node or Chrome, but not on macOS +export const shouldRunHttpsTests = + // Need to have an HTTPS URL + !!ENDPOINT_BASE_HTTPS_URL && + + // Run on Node, unless macOS + (process && process.platform !== "darwin") && + + // Only run under Chrome browser + (typeof navigator === "undefined" || navigator.userAgent.search("Chrome") !== -1); diff --git a/src/SignalR/clients/ts/FunctionalTests/ts/ConnectionTests.ts b/src/SignalR/clients/ts/FunctionalTests/ts/ConnectionTests.ts index b3445891b3..b377c98112 100644 --- a/src/SignalR/clients/ts/FunctionalTests/ts/ConnectionTests.ts +++ b/src/SignalR/clients/ts/FunctionalTests/ts/ConnectionTests.ts @@ -5,7 +5,7 @@ // tslint:disable:no-floating-promises import { HttpTransportType, IHttpConnectionOptions, TransferFormat } from "@microsoft/signalr"; -import { DEFAULT_TIMEOUT_INTERVAL, eachHttpClient, eachTransport, ECHOENDPOINT_URL } from "./Common"; +import { DEFAULT_TIMEOUT_INTERVAL, eachHttpClient, eachTransport, ECHOENDPOINT_URL, HTTPS_ECHOENDPOINT_URL, shouldRunHttpsTests } from "./Common"; import { TestLogger } from "./TestLogger"; // We want to continue testing HttpConnection, but we don't export it anymore. So just pull it in directly from the source file. @@ -15,6 +15,8 @@ import "./LogBannerReporter"; jasmine.DEFAULT_TIMEOUT_INTERVAL = DEFAULT_TIMEOUT_INTERVAL; +const USED_ECHOENDPOINT_URL = shouldRunHttpsTests ? HTTPS_ECHOENDPOINT_URL : ECHOENDPOINT_URL; + const commonOptions: IHttpConnectionOptions = { logMessageContent: true, logger: TestLogger.instance, @@ -23,7 +25,7 @@ const commonOptions: IHttpConnectionOptions = { describe("connection", () => { it("can connect to the server without specifying transport explicitly", (done) => { const message = "Hello World!"; - const connection = new HttpConnection(ECHOENDPOINT_URL, { + const connection = new HttpConnection(USED_ECHOENDPOINT_URL, { ...commonOptions, }); @@ -53,7 +55,7 @@ describe("connection", () => { const message = "Hello World!"; // the url should be resolved relative to the document.location.host // and the leading '/' should be automatically added to the url - const connection = new HttpConnection(ECHOENDPOINT_URL, { + const connection = new HttpConnection(USED_ECHOENDPOINT_URL, { ...commonOptions, httpClient, transport: transportType, @@ -83,7 +85,7 @@ describe("connection", () => { const message = "Hello World!"; // DON'T use commonOptions because we want to specifically test the scenario where logMessageContent is not set. - const connection = new HttpConnection(ECHOENDPOINT_URL, { + const connection = new HttpConnection(USED_ECHOENDPOINT_URL, { httpClient, logger: TestLogger.instance, transport: transportType, @@ -119,7 +121,7 @@ describe("connection", () => { const message = "Hello World!"; // DON'T use commonOptions because we want to specifically test the scenario where logMessageContent is set to true (even if commonOptions changes). - const connection = new HttpConnection(ECHOENDPOINT_URL, { + const connection = new HttpConnection(USED_ECHOENDPOINT_URL, { httpClient, logMessageContent: true, logger: TestLogger.instance, @@ -167,7 +169,7 @@ describe("connection", () => { const message = "Hello World!"; // The server will set some response headers for the '/negotiate' endpoint - const connection = new HttpConnection(ECHOENDPOINT_URL, { + const connection = new HttpConnection(USED_ECHOENDPOINT_URL, { ...commonOptions, httpClient, transport: transportType, diff --git a/src/SignalR/clients/ts/FunctionalTests/ts/HubConnectionTests.ts b/src/SignalR/clients/ts/FunctionalTests/ts/HubConnectionTests.ts index a802d79424..600617d5f3 100644 --- a/src/SignalR/clients/ts/FunctionalTests/ts/HubConnectionTests.ts +++ b/src/SignalR/clients/ts/FunctionalTests/ts/HubConnectionTests.ts @@ -8,7 +8,7 @@ import { AbortError, DefaultHttpClient, HttpClient, HttpRequest, HttpResponse, H import { MessagePackHubProtocol } from "@microsoft/signalr-protocol-msgpack"; import { getUserAgentHeader, Platform } from "@microsoft/signalr/dist/esm/Utils"; -import { DEFAULT_TIMEOUT_INTERVAL, eachTransport, eachTransportAndProtocolAndHttpClient, ENDPOINT_BASE_HTTPS_URL, ENDPOINT_BASE_URL } from "./Common"; +import { DEFAULT_TIMEOUT_INTERVAL, eachTransport, eachTransportAndProtocolAndHttpClient, ENDPOINT_BASE_HTTPS_URL, ENDPOINT_BASE_URL, shouldRunHttpsTests } from "./Common"; import "./LogBannerReporter"; import { TestLogger } from "./TestLogger"; @@ -18,6 +18,7 @@ import * as RX from "rxjs"; const TESTHUBENDPOINT_URL = ENDPOINT_BASE_URL + "/testhub"; const TESTHUBENDPOINT_HTTPS_URL = ENDPOINT_BASE_HTTPS_URL ? (ENDPOINT_BASE_HTTPS_URL + "/testhub") : undefined; +const HTTPORHTTPS_TESTHUBENDPOINT_URL = shouldRunHttpsTests ? TESTHUBENDPOINT_HTTPS_URL : TESTHUBENDPOINT_URL; const TESTHUB_NOWEBSOCKETS_ENDPOINT_URL = ENDPOINT_BASE_URL + "/testhub-nowebsockets"; const TESTHUB_REDIRECT_ENDPOINT_URL = ENDPOINT_BASE_URL + "/redirect?numRedirects=0&baseUrl=" + ENDPOINT_BASE_URL; @@ -28,17 +29,6 @@ const commonOptions: IHttpConnectionOptions = { logMessageContent: true, }; -// Run test in Node or Chrome, but not on macOS -const shouldRunHttpsTests = - // Need to have an HTTPS URL - !!TESTHUBENDPOINT_HTTPS_URL && - - // Run on Node, unless macOS - (process && process.platform !== "darwin") && - - // Only run under Chrome browser - (typeof navigator === "undefined" || navigator.userAgent.search("Chrome") !== -1); - function getConnectionBuilder(transportType?: HttpTransportType, url?: string, options?: IHttpConnectionOptions): HubConnectionBuilder { let actualOptions: IHttpConnectionOptions = options || {}; if (transportType) { @@ -599,7 +589,7 @@ describe("hubConnection", () => { } it("preserves cookies between requests", async (done) => { - const hubConnection = getConnectionBuilder(transportType).build(); + const hubConnection = getConnectionBuilder(transportType, HTTPORHTTPS_TESTHUBENDPOINT_URL).build(); await hubConnection.start(); const cookieValue = await hubConnection.invoke("GetCookie", "testCookie"); const cookieValue2 = await hubConnection.invoke("GetCookie", "testCookie2"); @@ -610,7 +600,7 @@ describe("hubConnection", () => { }); it("expired cookies are not preserved", async (done) => { - const hubConnection = getConnectionBuilder(transportType).build(); + const hubConnection = getConnectionBuilder(transportType, HTTPORHTTPS_TESTHUBENDPOINT_URL).build(); await hubConnection.start(); const cookieValue = await hubConnection.invoke("GetCookie", "expiredCookie"); expect(cookieValue).toBeNull();