Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions eng/Version.Details.props
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,15 @@ This file should be imported by eng/Versions.props
<MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>4.13.0-3.24613.7</MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>
<MicrosoftCodeAnalysisExternalAccessAspNetCorePackageVersion>4.13.0-3.24613.7</MicrosoftCodeAnalysisExternalAccessAspNetCorePackageVersion>
<!-- dotnet/extensions dependencies -->
<MicrosoftExtensionsCachingHybridPackageVersion>9.10.0-preview.1.25462.1</MicrosoftExtensionsCachingHybridPackageVersion>
<MicrosoftExtensionsDiagnosticsTestingPackageVersion>9.10.0-preview.1.25462.1</MicrosoftExtensionsDiagnosticsTestingPackageVersion>
<MicrosoftExtensionsTimeProviderTestingPackageVersion>9.10.0-preview.1.25462.1</MicrosoftExtensionsTimeProviderTestingPackageVersion>
<MicrosoftExtensionsCachingHybridPackageVersion>9.10.0-preview.1.25468.3</MicrosoftExtensionsCachingHybridPackageVersion>
<MicrosoftExtensionsDiagnosticsTestingPackageVersion>9.10.0-preview.1.25468.3</MicrosoftExtensionsDiagnosticsTestingPackageVersion>
<MicrosoftExtensionsTimeProviderTestingPackageVersion>9.10.0-preview.1.25468.3</MicrosoftExtensionsTimeProviderTestingPackageVersion>
<!-- _git/dotnet-optimization dependencies -->
<optimizationlinuxarm64MIBCRuntimePackageVersion>1.0.0-prerelease.25458.1</optimizationlinuxarm64MIBCRuntimePackageVersion>
<optimizationlinuxx64MIBCRuntimePackageVersion>1.0.0-prerelease.25458.1</optimizationlinuxx64MIBCRuntimePackageVersion>
<optimizationwindows_ntarm64MIBCRuntimePackageVersion>1.0.0-prerelease.25458.1</optimizationwindows_ntarm64MIBCRuntimePackageVersion>
<optimizationwindows_ntx64MIBCRuntimePackageVersion>1.0.0-prerelease.25458.1</optimizationwindows_ntx64MIBCRuntimePackageVersion>
<optimizationwindows_ntx86MIBCRuntimePackageVersion>1.0.0-prerelease.25458.1</optimizationwindows_ntx86MIBCRuntimePackageVersion>
<optimizationlinuxarm64MIBCRuntimePackageVersion>1.0.0-prerelease.25467.1</optimizationlinuxarm64MIBCRuntimePackageVersion>
<optimizationlinuxx64MIBCRuntimePackageVersion>1.0.0-prerelease.25467.1</optimizationlinuxx64MIBCRuntimePackageVersion>
<optimizationwindows_ntarm64MIBCRuntimePackageVersion>1.0.0-prerelease.25467.1</optimizationwindows_ntarm64MIBCRuntimePackageVersion>
<optimizationwindows_ntx64MIBCRuntimePackageVersion>1.0.0-prerelease.25467.1</optimizationwindows_ntx64MIBCRuntimePackageVersion>
<optimizationwindows_ntx86MIBCRuntimePackageVersion>1.0.0-prerelease.25467.1</optimizationwindows_ntx86MIBCRuntimePackageVersion>
<!-- dotnet/msbuild dependencies -->
<MicrosoftBuildPackageVersion>17.12.36</MicrosoftBuildPackageVersion>
<MicrosoftBuildFrameworkPackageVersion>17.12.36</MicrosoftBuildFrameworkPackageVersion>
Expand Down
32 changes: 16 additions & 16 deletions eng/Version.Details.xml
Original file line number Diff line number Diff line change
Expand Up @@ -390,37 +390,37 @@
<Uri>https://github.com/dotnet/dotnet</Uri>
<Sha>2dea164f01d307c409cfe0d0ee5cb8a0691e3c94</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Caching.Hybrid" Version="9.10.0-preview.1.25462.1">
<Dependency Name="Microsoft.Extensions.Caching.Hybrid" Version="9.10.0-preview.1.25468.3">
<Uri>https://github.com/dotnet/extensions</Uri>
<Sha>d299e16f15234f9808b18fef50bf7770113fb4b2</Sha>
<Sha>53ef1158f9f42632e111d6873a8cd72b803b4ae6</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.Diagnostics.Testing" Version="9.10.0-preview.1.25462.1">
<Dependency Name="Microsoft.Extensions.Diagnostics.Testing" Version="9.10.0-preview.1.25468.3">
<Uri>https://github.com/dotnet/extensions</Uri>
<Sha>d299e16f15234f9808b18fef50bf7770113fb4b2</Sha>
<Sha>53ef1158f9f42632e111d6873a8cd72b803b4ae6</Sha>
</Dependency>
<Dependency Name="Microsoft.Extensions.TimeProvider.Testing" Version="9.10.0-preview.1.25462.1">
<Dependency Name="Microsoft.Extensions.TimeProvider.Testing" Version="9.10.0-preview.1.25468.3">
<Uri>https://github.com/dotnet/extensions</Uri>
<Sha>d299e16f15234f9808b18fef50bf7770113fb4b2</Sha>
<Sha>53ef1158f9f42632e111d6873a8cd72b803b4ae6</Sha>
</Dependency>
<Dependency Name="optimization.windows_nt-x64.MIBC.Runtime" Version="1.0.0-prerelease.25458.1">
<Dependency Name="optimization.windows_nt-x64.MIBC.Runtime" Version="1.0.0-prerelease.25467.1">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-optimization</Uri>
<Sha>373ed5bf1a64c212e655063e58967eb62f9187ef</Sha>
<Sha>59dc6a9bf1b3e3ab71c73d94160c2049fb104cd1</Sha>
</Dependency>
<Dependency Name="optimization.windows_nt-x86.MIBC.Runtime" Version="1.0.0-prerelease.25458.1">
<Dependency Name="optimization.windows_nt-x86.MIBC.Runtime" Version="1.0.0-prerelease.25467.1">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-optimization</Uri>
<Sha>373ed5bf1a64c212e655063e58967eb62f9187ef</Sha>
<Sha>59dc6a9bf1b3e3ab71c73d94160c2049fb104cd1</Sha>
</Dependency>
<Dependency Name="optimization.linux-x64.MIBC.Runtime" Version="1.0.0-prerelease.25458.1">
<Dependency Name="optimization.linux-x64.MIBC.Runtime" Version="1.0.0-prerelease.25467.1">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-optimization</Uri>
<Sha>373ed5bf1a64c212e655063e58967eb62f9187ef</Sha>
<Sha>59dc6a9bf1b3e3ab71c73d94160c2049fb104cd1</Sha>
</Dependency>
<Dependency Name="optimization.windows_nt-arm64.MIBC.Runtime" Version="1.0.0-prerelease.25458.1">
<Dependency Name="optimization.windows_nt-arm64.MIBC.Runtime" Version="1.0.0-prerelease.25467.1">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-optimization</Uri>
<Sha>373ed5bf1a64c212e655063e58967eb62f9187ef</Sha>
<Sha>59dc6a9bf1b3e3ab71c73d94160c2049fb104cd1</Sha>
</Dependency>
<Dependency Name="optimization.linux-arm64.MIBC.Runtime" Version="1.0.0-prerelease.25458.1">
<Dependency Name="optimization.linux-arm64.MIBC.Runtime" Version="1.0.0-prerelease.25467.1">
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-optimization</Uri>
<Sha>373ed5bf1a64c212e655063e58967eb62f9187ef</Sha>
<Sha>59dc6a9bf1b3e3ab71c73d94160c2049fb104cd1</Sha>
</Dependency>
<!-- Dependencies required for source build to lift to the previously-source-built version. -->
<!-- These versions are manually updated -->
Expand Down
4 changes: 4 additions & 0 deletions src/Components/Web/src/Virtualization/Virtualize.cs
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,10 @@ private void CalcualteItemDistribution(
_ => MaxItemCount
};

// Count the OverscanCount as used capacity, so we don't end up in a situation where
// the user has set a very low MaxItemCount and we end up in an infinite loading loop.
maxItemCount += OverscanCount * 2;

itemsInSpacer = Math.Max(0, (int)Math.Floor(spacerSize / _itemSize) - OverscanCount);
visibleItemCapacity = (int)Math.Ceiling(containerSize / _itemSize) + 2 * OverscanCount;
unusedItemCapacity = Math.Max(0, visibleItemCapacity - maxItemCount);
Expand Down
99 changes: 97 additions & 2 deletions src/Components/test/E2ETest/Tests/VirtualizationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -291,14 +291,14 @@ public void CanLimitMaxItemsRendered(bool useAppContext)
// we only render 10 items due to the MaxItemCount setting
var scrollArea = Browser.Exists(By.Id("virtualize-scroll-area"));
var getItems = () => scrollArea.FindElements(By.ClassName("my-item"));
Browser.Equal(10, () => getItems().Count);
Browser.Equal(16, () => getItems().Count);
Browser.Equal("Id: 0; Name: Thing 0", () => getItems().First().Text);

// Scrolling still works and loads new data, though there's no guarantee about
// exactly how many items will show up at any one time
Browser.ExecuteJavaScript("document.getElementById('virtualize-scroll-area').scrollTop = 300;");
Browser.NotEqual("Id: 0; Name: Thing 0", () => getItems().First().Text);
Browser.True(() => getItems().Count > 3 && getItems().Count <= 10);
Browser.True(() => getItems().Count > 3 && getItems().Count <= 16);
}

[Fact]
Expand Down Expand Up @@ -573,6 +573,101 @@ public void EmptyContentRendered_Async()
int GetPlaceholderCount() => Browser.FindElements(By.Id("async-placeholder")).Count;
}

[Fact]
public void CanElevateEffectiveMaxItemCount_WhenOverscanExceedsMax()
{
Browser.MountTestComponent<VirtualizationLargeOverscan>();
var container = Browser.Exists(By.Id("virtualize-large-overscan"));
// Ensure we have an initial contiguous batch and the elevated effective max has kicked in (>= OverscanCount)
var indices = GetVisibleItemIndices();
Browser.True(() => indices.Count >= 200);

// Give focus so PageDown works
container.Click();

var js = (IJavaScriptExecutor)Browser;
var lastMaxIndex = -1;
var lastScrollTop = -1L;

// Check if we've reached (or effectively reached) the bottom
var scrollHeight = (long)js.ExecuteScript("return arguments[0].scrollHeight", container);
var clientHeight = (long)js.ExecuteScript("return arguments[0].clientHeight", container);
var scrollTop = (long)js.ExecuteScript("return arguments[0].scrollTop", container);
while (scrollTop + clientHeight < scrollHeight)
{
// Validate contiguity on the current page
Browser.True(() => IsCurrentViewContiguous(indices));

// Track progress in indices
var currentMax = indices.Max();
Assert.True(currentMax >= lastMaxIndex, $"Unexpected backward movement: previous max {lastMaxIndex}, current max {currentMax}.");
lastMaxIndex = currentMax;

// Send PageDown
container.SendKeys(Keys.PageDown);

// Wait for scrollTop to change (progress) to avoid infinite loop
var prevScrollTop = scrollTop;
Browser.True(() =>
{
var st = (long)js.ExecuteScript("return arguments[0].scrollTop", container);
if (st > prevScrollTop)
{
lastScrollTop = st;
return true;
}
return false;
});
scrollHeight = (long)js.ExecuteScript("return arguments[0].scrollHeight", container);
clientHeight = (long)js.ExecuteScript("return arguments[0].clientHeight", container);
scrollTop = (long)js.ExecuteScript("return arguments[0].scrollTop", container);
}

// Final contiguous assertion at bottom
Browser.True(() => IsCurrentViewContiguous());

// Helper: check visible items contiguous with no holes
bool IsCurrentViewContiguous(List<int> existingIndices = null)
{
var indices = existingIndices ?? GetVisibleItemIndices();
if (indices.Count == 0)
{
return false;
}

if (indices[^1] - indices[0] != indices.Count - 1)
{
return false;
}
for (var i = 1; i < indices.Count; i++)
{
if (indices[i] - indices[i - 1] != 1)
{
return false;
}
}
return true;
}

List<int> GetVisibleItemIndices()
{
var elements = container.FindElements(By.CssSelector(".large-overscan-item"));
var list = new List<int>(elements.Count);
foreach (var el in elements)
{
var text = el.Text;
if (text.StartsWith("Item ", StringComparison.Ordinal))
{
if (int.TryParse(text.AsSpan(5), NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
{
list.Add(value);
}
}
}
return list;
}
}

private string[] GetPeopleNames(IWebElement container)
{
var peopleElements = container.FindElements(By.CssSelector(".person span"));
Expand Down
1 change: 1 addition & 0 deletions src/Components/test/testassets/BasicTestApp/Index.razor
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
<option value="BasicTestApp.VirtualizationMaxItemCount">Virtualization MaxItemCount</option>
<option value="BasicTestApp.VirtualizationMaxItemCount_AppContext">Virtualization MaxItemCount (via AppContext)</option>
<option value="BasicTestApp.VirtualizationTable">Virtualization HTML table</option>
<option value="BasicTestApp.VirtualizationLargeOverscan">Virtualization large overscan</option>
<option value="BasicTestApp.HotReload.RenderOnHotReload">Render on hot reload</option>
<option value="BasicTestApp.SectionsTest.ParentComponentWithTwoChildren">Sections test</option>
<option value="BasicTestApp.SectionsTest.SectionsWithCascadingParameters">Sections with Cascading parameters test</option>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@* Test component to validate behavior when OverscanCount greatly exceeds MaxItemCount. *@
@using Microsoft.AspNetCore.Components.Web.Virtualization

<div id="virtualize-large-overscan" style="height: 600px; overflow-y: auto; outline: 1px solid #999; background:#f8f8f8;">
<Virtualize Items="_items" ItemSize="30" MaxItemCount="100" OverscanCount="200">
<div class="large-overscan-item" @key="context" style="height:30px; line-height:30px; border-bottom:1px solid #ddd;">Item @context</div>
</Virtualize>
</div>

@code {
private IList<int> _items = Enumerable.Range(0, 5000).ToList();
}
11 changes: 10 additions & 1 deletion src/Servers/HttpSys/samples/TlsFeaturesObserve/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
Expand All @@ -30,6 +31,7 @@
{
var connectionFeature = context.Features.GetRequiredFeature<IHttpConnectionFeature>();
var httpSysPropFeature = context.Features.GetRequiredFeature<IHttpSysRequestPropertyFeature>();
var tlsHandshakeFeature = context.Features.GetRequiredFeature<ITlsHandshakeFeature>();

// first time invocation to find out required size
var success = httpSysPropFeature.TryGetTlsClientHello(Array.Empty<byte>(), out var bytesReturned);
Expand All @@ -41,7 +43,14 @@
success = httpSysPropFeature.TryGetTlsClientHello(bytes, out _);
Debug.Assert(success);

await context.Response.WriteAsync($"[Response] connectionId={connectionFeature.ConnectionId}; tlsClientHello.length={bytesReturned}; tlsclienthello start={string.Join(' ', bytes.AsSpan(0, 30).ToArray())}");
await context.Response.WriteAsync(
$"""
connectionId = {connectionFeature.ConnectionId};
negotiated cipher suite = {tlsHandshakeFeature.NegotiatedCipherSuite};
tlsClientHello.length = {bytesReturned};
tlsclienthello start = {string.Join(' ', bytes.AsSpan(0, 30).ToArray())}
""");

await next(context);
});

Expand Down
1 change: 1 addition & 0 deletions src/Servers/HttpSys/src/LoggerEventIds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,5 @@ internal static class LoggerEventIds
public const int AcceptObserveExpectationMismatch = 53;
public const int RequestParsingError = 54;
public const int TlsListenerError = 55;
public const int QueryTlsCipherSuiteError = 56;
}
2 changes: 2 additions & 0 deletions src/Servers/HttpSys/src/NativeInterop/HttpApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ internal static unsafe uint HttpSetRequestProperty(SafeHandle requestQueueHandle
internal static bool SupportsReset { get; }
internal static bool SupportsDelegation { get; }
internal static bool SupportsClientHello { get; }
internal static bool SupportsQueryTlsCipherInfo { get; }
internal static bool Supported { get; }

static unsafe HttpApi()
Expand All @@ -86,6 +87,7 @@ static unsafe HttpApi()
SupportsTrailers = IsFeatureSupported(HTTP_FEATURE_ID.HttpFeatureResponseTrailers);
SupportsDelegation = IsFeatureSupported(HTTP_FEATURE_ID.HttpFeatureDelegateEx);
SupportsClientHello = IsFeatureSupported((HTTP_FEATURE_ID)11 /* HTTP_FEATURE_ID.HttpFeatureCacheTlsClientHello */) && HttpGetRequestPropertySupported;
SupportsQueryTlsCipherInfo = IsFeatureSupported((HTTP_FEATURE_ID)15 /* HTTP_FEATURE_ID.HttpFeatureQueryCipherInfo */) && HttpGetRequestPropertySupported;
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/Servers/HttpSys/src/RequestProcessing/Request.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Globalization;
using System.Net;
using System.Net.Security;
using System.Security;
using System.Security.Authentication;
using System.Security.Cryptography;
Expand Down Expand Up @@ -334,6 +335,8 @@ private AspNetCore.HttpSys.Internal.SocketAddress LocalEndPoint

public SslProtocols Protocol { get; private set; }

public TlsCipherSuite? NegotiatedCipherSuite { get; private set; }

[Obsolete(Obsoletions.RuntimeTlsCipherAlgorithmEnumsMessage, DiagnosticId = Obsoletions.RuntimeTlsCipherAlgorithmEnumsDiagId, UrlFormat = Obsoletions.RuntimeSharedUrlFormat)]
public CipherAlgorithmType CipherAlgorithm { get; private set; }

Expand All @@ -356,6 +359,8 @@ private void GetTlsHandshakeResults()
{
var handshake = RequestContext.GetTlsHandshake();
Protocol = (SslProtocols)handshake.Protocol;

NegotiatedCipherSuite = RequestContext.GetTlsCipherSuite();
#pragma warning disable SYSLIB0058 // Type or member is obsolete
CipherAlgorithm = (CipherAlgorithmType)handshake.CipherType;
CipherStrength = (int)handshake.CipherStrength;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Globalization;
using System.IO.Pipelines;
using System.Net;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Claims;
using System.Security.Cryptography.X509Certificates;
Expand Down Expand Up @@ -593,6 +594,8 @@ bool IHttpBodyControlFeature.AllowSynchronousIO

SslProtocols ITlsHandshakeFeature.Protocol => Request.Protocol;

TlsCipherSuite? ITlsHandshakeFeature.NegotiatedCipherSuite => Request.NegotiatedCipherSuite;

#pragma warning disable SYSLIB0058 // Type or member is obsolete
CipherAlgorithmType ITlsHandshakeFeature.CipherAlgorithm => Request.CipherAlgorithm;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,8 @@ private static partial class Log

[LoggerMessage(LoggerEventIds.RequestParsingError, LogLevel.Debug, "Failed to invoke QueryTlsClientHello; RequestId: {RequestId}; Win32 Error code: {Win32Error}", EventName = "TlsClientHelloRetrieveError")]
public static partial void TlsClientHelloRetrieveError(ILogger logger, ulong requestId, uint win32Error);

[LoggerMessage(LoggerEventIds.QueryTlsCipherSuiteError, LogLevel.Debug, "Failed to invoke QueryTlsCipherSuite; RequestId: {RequestId}; Win32 Error code: {Win32Error}", EventName = "QueryTlsCipherSuiteError")]
public static partial void QueryTlsCipherSuiteError(ILogger logger, ulong requestId, uint win32Error);
}
}
Loading
Loading