Skip to content

Commit 0a41507

Browse files
committed
Merge in 'release/8.0' changes
2 parents 1cdb497 + de3830c commit 0a41507

File tree

12 files changed

+435
-61
lines changed

12 files changed

+435
-61
lines changed

.github/CODEOWNERS

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
/.vscode/ @captainsafia
1111
/.github/ @dotnet/aspnet-build @wtgodbe
1212
/.github/*_TEMPLATE/ @dotnet/aspnet-build @wtgodbe @mkArtakMSFT
13-
/.github/workflows/ @dotnet/aspnet-build @wtgodbe @tratcher
13+
/.github/workflows/ @dotnet/aspnet-build @wtgodbe
1414
/docs/ @captainsafia @mkArtakMSFT
1515
/eng/ @dotnet/aspnet-build @wtgodbe
1616
/eng/common/ @dotnet-maestro-bot
@@ -21,34 +21,31 @@
2121
/src/Caching/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @captainsafia @halter73 @mgravell
2222
/src/Components/ @dotnet/aspnet-blazor-eng
2323
/src/Components/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @dotnet/aspnet-blazor-eng
24-
/src/DefaultBuilder/ @tratcher @halter73
25-
/src/DefaultBuilder/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @tratcher
24+
/src/DefaultBuilder/ @halter73
25+
/src/DefaultBuilder/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review
2626
/src/Grpc/ @JamesNK @captainsafia @mgravell
2727
/src/Grpc/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @JamesNK @captainsafia @mgravell
28-
/src/Hosting/ @tratcher @halter73
29-
/src/Hosting/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @tratcher
30-
/src/Http/ @tratcher @BrennanConroy @halter73 @captainsafia
31-
/src/Http/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @tratcher @BrennanConroy
28+
/src/Hosting/ @halter73
29+
/src/Hosting/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review
30+
/src/Http/ @BrennanConroy @halter73 @captainsafia
31+
/src/Http/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @BrennanConroy
3232
/src/Http/Routing/ @javiercn
3333
/src/Http/Routing/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @javiercn
3434
/src/HttpClientFactory/ @captainsafia @halter73
3535
/src/HttpClientFactory/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @captainsafia @halter73
3636
/src/Installers/ @dotnet/aspnet-build @wtgodbe
3737
/src/JSInterop/ @dotnet/aspnet-blazor-eng
38-
/src/Middleware/ @tratcher @BrennanConroy
39-
/src/Middleware/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @tratcher @BrennanConroy
38+
/src/Middleware/ @BrennanConroy
39+
/src/Middleware/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @BrennanConroy
4040
/src/Mvc/ @dotnet/minimal-apis
4141
/src/Mvc/Mvc.ApiExplorer @captainsafia @halter73 @brunolins16
4242
/src/Mvc/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @dotnet/aspnet-blazor-eng
4343
/src/OpenApi @captainsafia @dotnet/minimal-apis
4444
/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorServerWeb-CSharp/ @dotnet/aspnet-blazor-eng
4545
/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp/ @dotnet/aspnet-blazor-eng
46-
/src/Security/ @tratcher
47-
/src/Security/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @tratcher
48-
/src/Servers/ @tratcher @halter73 @BrennanConroy @JamesNK @mgravell
49-
/src/Servers/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @tratcher @halter73 @BrennanConroy @JamesNK @mgravell
50-
/src/Shared/runtime/ @tratcher
51-
/src/Shared/test/Shared.Tests/runtime/ @tratcher
46+
/src/Security/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review
47+
/src/Servers/ @halter73 @BrennanConroy @JamesNK @mgravell
48+
/src/Servers/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @halter73 @BrennanConroy @JamesNK @mgravell
5249
/src/SignalR/ @BrennanConroy @halter73
5350
/src/SignalR/**/PublicAPI.*Shipped.txt @dotnet/aspnet-api-review @BrennanConroy @halter73
5451
/src/submodules @dotnet/aspnet-build @wtgodbe

.github/workflows/markdownlint-problem-matcher.json

Lines changed: 0 additions & 17 deletions
This file was deleted.

.github/workflows/markdownlint.yml

Lines changed: 0 additions & 26 deletions
This file was deleted.

eng/Publishing.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<Project>
22
<PropertyGroup>
33
<PublishingVersion>3</PublishingVersion>
4+
<ProducesDotNetReleaseShippingAssets>true</ProducesDotNetReleaseShippingAssets>
45
</PropertyGroup>
56

67
<PropertyGroup>

src/Components/Endpoints/src/RazorComponentEndpointInvoker.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Microsoft.AspNetCore.Components.Endpoints.Rendering;
1010
using Microsoft.AspNetCore.Diagnostics;
1111
using Microsoft.AspNetCore.Http;
12+
using Microsoft.AspNetCore.Http.Features;
1213
using Microsoft.AspNetCore.WebUtilities;
1314
using Microsoft.Extensions.DependencyInjection;
1415
using Microsoft.Extensions.Hosting;
@@ -116,6 +117,16 @@ await EndpointHtmlRenderer.InitializeStandardComponentServicesAsync(
116117
}
117118
}
118119

120+
if (!quiesceTask.IsCompleted)
121+
{
122+
// An incomplete QuiescenceTask indicates there may be streaming rendering updates.
123+
// Disable all response buffering and compression on IIS like SignalR's ServerSentEventsServerTransport does.
124+
var bufferingFeature = context.Features.GetRequiredFeature<IHttpResponseBodyFeature>();
125+
bufferingFeature.DisableBuffering();
126+
127+
context.Response.Headers.ContentEncoding = "identity";
128+
}
129+
119130
// Importantly, we must not yield this thread (which holds exclusive access to the renderer sync context)
120131
// in between the first call to htmlContent.WriteTo and the point where we start listening for subsequent
121132
// streaming SSR batches (inside SendStreamingUpdatesAsync). Otherwise some other code might dispatch to the

src/Components/test/E2ETest/ServerRenderingTests/StreamingRenderingTest.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33

44
using System.Globalization;
55
using System.Net.Http;
6-
using System.Net.Http.Headers;
76
using System.Text;
87
using System.Text.RegularExpressions;
98
using Components.TestServer.RazorComponents;
109
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
1110
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
1211
using Microsoft.AspNetCore.E2ETesting;
12+
using Microsoft.Net.Http.Headers;
1313
using OpenQA.Selenium;
1414
using TestServer;
1515
using Xunit.Abstractions;
@@ -30,13 +30,29 @@ public override Task InitializeAsync()
3030
=> InitializeAsync(BrowserFixture.StreamingContext);
3131

3232
[Fact]
33-
public void CanRenderNonstreamingPageWithoutInjectingStreamingMarkers()
33+
public async Task CanRenderNonstreamingPageWithoutInjectingStreamingMarkersOrHeaders()
3434
{
3535
Navigate(ServerPathBase);
3636

3737
Browser.Equal("Hello", () => Browser.Exists(By.TagName("h1")).Text);
3838

3939
Assert.DoesNotContain("<blazor-ssr", Browser.PageSource);
40+
41+
using var httpClient = new HttpClient();
42+
using var response = await httpClient.GetAsync(new Uri(_serverFixture.RootUri, ServerPathBase));
43+
response.EnsureSuccessStatusCode();
44+
45+
Assert.False(response.Content.Headers.Contains(HeaderNames.ContentEncoding));
46+
}
47+
48+
[Fact]
49+
public async Task DoesRenderStreamingPageWithStreamingHeadersToDisableBuffering()
50+
{
51+
using var httpClient = new HttpClient();
52+
using var response = await httpClient.GetAsync(new Uri(_serverFixture.RootUri, $"{ServerPathBase}/streaming"), HttpCompletionOption.ResponseHeadersRead);
53+
response.EnsureSuccessStatusCode();
54+
55+
Assert.Equal("identity", response.Content.Headers.ContentEncoding.Single());
4056
}
4157

4258
[Theory]

src/DataProtection/DataProtection/src/DataProtectionServiceCollectionExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ private static void AddDataProtectionServices(IServiceCollection services)
6767

6868
services.TryAddEnumerable(
6969
ServiceDescriptor.Singleton<IConfigureOptions<KeyManagementOptions>, KeyManagementOptionsSetup>());
70+
services.TryAddEnumerable(
71+
ServiceDescriptor.Singleton<IPostConfigureOptions<KeyManagementOptions>, KeyManagementOptionsPostSetup>());
7072
services.TryAddEnumerable(
7173
ServiceDescriptor.Transient<IConfigureOptions<DataProtectionOptions>, DataProtectionOptionsSetup>());
7274

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.IO;
6+
using System.Xml.Linq;
7+
using Microsoft.AspNetCore.DataProtection.KeyManagement;
8+
using Microsoft.AspNetCore.DataProtection.Repositories;
9+
using Microsoft.AspNetCore.DataProtection.XmlEncryption;
10+
using Microsoft.Extensions.Configuration;
11+
using Microsoft.Extensions.Logging;
12+
using Microsoft.Extensions.Options;
13+
14+
namespace Microsoft.AspNetCore.DataProtection.Internal;
15+
16+
/// <summary>
17+
/// Performs additional <see cref="KeyManagementOptions" /> configuration, after the user's configuration has been applied.
18+
/// </summary>
19+
/// <remarks>
20+
/// In practice, this type is used to set key management to readonly mode if an environment variable is set and the user
21+
/// has not explicitly configured data protection.
22+
/// </remarks>
23+
internal sealed class KeyManagementOptionsPostSetup : IPostConfigureOptions<KeyManagementOptions>
24+
{
25+
/// <remarks>
26+
/// Settable as `ReadOnlyDataProtectionKeyDirectory`, `DOTNET_ReadOnlyDataProtectionKeyDirectory`,
27+
/// or `ASPNETCORE_ReadOnlyDataProtectionKeyDirectory`, in descending order of precedence.
28+
/// </remarks>
29+
internal const string ReadOnlyDataProtectionKeyDirectoryKey = "ReadOnlyDataProtectionKeyDirectory";
30+
31+
private readonly string? _keyDirectoryPath;
32+
private readonly ILoggerFactory? _loggerFactory; // Null iff _keyDirectoryPath is null
33+
private readonly ILogger<KeyManagementOptionsPostSetup>? _logger; // Null iff _keyDirectoryPath is null
34+
35+
public KeyManagementOptionsPostSetup()
36+
{
37+
// If there's no IConfiguration, there's no _keyDirectoryPath and this type will do nothing.
38+
// This is mostly a convenience for tests since ASP.NET Core apps will have an IConfiguration.
39+
}
40+
41+
public KeyManagementOptionsPostSetup(IConfiguration configuration, ILoggerFactory loggerFactory)
42+
{
43+
var dirPath = configuration[ReadOnlyDataProtectionKeyDirectoryKey];
44+
if (string.IsNullOrEmpty(dirPath))
45+
{
46+
return;
47+
}
48+
49+
_keyDirectoryPath = dirPath;
50+
_loggerFactory = loggerFactory;
51+
_logger = loggerFactory.CreateLogger<KeyManagementOptionsPostSetup>();
52+
}
53+
54+
void IPostConfigureOptions<KeyManagementOptions>.PostConfigure(string? name, KeyManagementOptions options)
55+
{
56+
if (_keyDirectoryPath is null)
57+
{
58+
// There's no logger, so we couldn't log if we wanted to
59+
return;
60+
}
61+
62+
var logger = _logger!;
63+
64+
if (name != Options.DefaultName)
65+
{
66+
logger.IgnoringReadOnlyConfigurationForNonDefaultOptions(ReadOnlyDataProtectionKeyDirectoryKey, name);
67+
return;
68+
}
69+
70+
// If Data Protection has not been configured, then set it up according to the environment variable
71+
if (options is { XmlRepository: null, XmlEncryptor: null })
72+
{
73+
var keyDirectory = new DirectoryInfo(_keyDirectoryPath);
74+
75+
logger.UsingReadOnlyKeyConfiguration(keyDirectory.FullName);
76+
77+
options.AutoGenerateKeys = false;
78+
options.XmlEncryptor = InvalidEncryptor.Instance;
79+
options.XmlRepository = new ReadOnlyFileSystemXmlRepository(keyDirectory, _loggerFactory!);
80+
}
81+
else if (options.XmlRepository is not null)
82+
{
83+
logger.NotUsingReadOnlyKeyConfigurationBecauseOfRepository();
84+
}
85+
else
86+
{
87+
logger.NotUsingReadOnlyKeyConfigurationBecauseOfEncryptor();
88+
}
89+
}
90+
91+
private sealed class InvalidEncryptor : IXmlEncryptor
92+
{
93+
public static readonly IXmlEncryptor Instance = new InvalidEncryptor();
94+
95+
private InvalidEncryptor()
96+
{
97+
}
98+
99+
EncryptedXmlInfo IXmlEncryptor.Encrypt(XElement plaintextElement)
100+
{
101+
throw new InvalidOperationException("Keys access is set up as read-only, so nothing should be encrypting");
102+
}
103+
}
104+
105+
private sealed class ReadOnlyFileSystemXmlRepository : FileSystemXmlRepository
106+
{
107+
public ReadOnlyFileSystemXmlRepository(DirectoryInfo directory, ILoggerFactory loggerFactory)
108+
: base(directory, loggerFactory)
109+
{
110+
}
111+
112+
public override void StoreElement(XElement element, string friendlyName)
113+
{
114+
throw new InvalidOperationException("Keys access is set up as read-only, so nothing should be storing keys");
115+
}
116+
}
117+
}

src/DataProtection/DataProtection/src/LoggingExtensions.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,4 +237,16 @@ private static bool IsLogLevelEnabledCore([NotNullWhen(true)] ILogger? logger, L
237237

238238
[LoggerMessage(60, LogLevel.Warning, "Storing keys in a directory '{path}' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. For more information go to https://aka.ms/aspnet/dataprotectionwarning", EventName = "UsingEphemeralFileSystemLocationInContainer")]
239239
public static partial void UsingEphemeralFileSystemLocationInContainer(this ILogger logger, string path);
240+
241+
[LoggerMessage(61, LogLevel.Trace, "Ignoring configuration '{PropertyName}' for options instance '{OptionsName}'", EventName = "IgnoringReadOnlyConfigurationForNonDefaultOptions")]
242+
public static partial void IgnoringReadOnlyConfigurationForNonDefaultOptions(this ILogger logger, string propertyName, string? optionsName);
243+
244+
[LoggerMessage(62, LogLevel.Information, "Enabling read-only key access with repository directory '{Path}'", EventName = "UsingReadOnlyKeyConfiguration")]
245+
public static partial void UsingReadOnlyKeyConfiguration(this ILogger logger, string path);
246+
247+
[LoggerMessage(63, LogLevel.Debug, "Not enabling read-only key access because an XML repository has been specified", EventName = "NotUsingReadOnlyKeyConfigurationBecauseOfRepository")]
248+
public static partial void NotUsingReadOnlyKeyConfigurationBecauseOfRepository(this ILogger logger);
249+
250+
[LoggerMessage(64, LogLevel.Debug, "Not enabling read-only key access because an XML encryptor has been specified", EventName = "NotUsingReadOnlyKeyConfigurationBecauseOfEncryptor")]
251+
public static partial void NotUsingReadOnlyKeyConfigurationBecauseOfEncryptor(this ILogger logger);
240252
}

0 commit comments

Comments
 (0)