We replace double dash sequences with double dots sequences as double dash sequences are not allowed into HTML.
This commit is contained in:
parent
72f91b8507
commit
8fa4df9bda
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components.Rendering;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
|
@ -15,11 +16,15 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
|||
{
|
||||
private static object CircuitHostKey = new object();
|
||||
private static object CancellationStatusKey = new object();
|
||||
private static readonly JsonSerializerOptions _jsonSerializationOptions =
|
||||
new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
|
||||
|
||||
private readonly CircuitFactory _circuitFactory;
|
||||
private readonly CircuitRegistry _registry;
|
||||
|
||||
public CircuitPrerenderer(CircuitFactory circuitFactory, CircuitRegistry registry)
|
||||
public CircuitPrerenderer(
|
||||
CircuitFactory circuitFactory,
|
||||
CircuitRegistry registry)
|
||||
{
|
||||
_circuitFactory = circuitFactory;
|
||||
_registry = registry;
|
||||
|
|
@ -76,8 +81,16 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
|||
Prerendered = true
|
||||
});
|
||||
|
||||
var record = JsonSerializer.Serialize(new PrerenderedComponentRecord(
|
||||
// We need to do this due to the fact that -- is not allowed within HTML comments and HTML doesn't encode '-'.
|
||||
// We will never have '..' sequences because we Base64UrlEncode the circuit id
|
||||
circuitHost.CircuitId.Replace("--", ".."),
|
||||
circuitHost.Renderer.Id,
|
||||
renderResult.ComponentId),
|
||||
_jsonSerializationOptions);
|
||||
|
||||
var result = (new[] {
|
||||
$"<!-- M.A.C.Component:{{\"circuitId\":\"{circuitHost.CircuitId}\",\"rendererId\":\"{circuitHost.Renderer.Id}\",\"componentId\":\"{renderResult.ComponentId}\"}} -->",
|
||||
$"<!-- M.A.C.Component: {record} -->",
|
||||
}).Concat(renderResult.Tokens).Concat(
|
||||
new[] {
|
||||
$"<!-- M.A.C.Component: {renderResult.ComponentId} -->"
|
||||
|
|
@ -169,6 +182,22 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
|||
return result;
|
||||
}
|
||||
|
||||
private readonly struct PrerenderedComponentRecord
|
||||
{
|
||||
public PrerenderedComponentRecord(string circuitId, int rendererId, int componentId)
|
||||
{
|
||||
CircuitId = circuitId;
|
||||
RendererId = rendererId;
|
||||
ComponentId = componentId;
|
||||
}
|
||||
|
||||
public string CircuitId { get; }
|
||||
|
||||
public int RendererId { get; }
|
||||
|
||||
public int ComponentId { get; }
|
||||
}
|
||||
|
||||
private class PrerenderingCancellationStatus
|
||||
{
|
||||
public bool Canceled { get; set; }
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components.Server.Circuits;
|
||||
|
|
@ -19,7 +20,11 @@ namespace Microsoft.AspNetCore.Components.Server.Tests.Circuits
|
|||
public class CircuitPrerendererTest
|
||||
{
|
||||
private static readonly Regex ContentWrapperRegex = new Regex(
|
||||
$"<!-- M.A.C.Component:{{\"circuitId\":\"[^\"]+\",\"rendererId\":\"0\",\"componentId\":\"0\"}} -->(?<content>.*)<!-- M.A.C.Component: 0 -->",
|
||||
"<!-- M.A.C.Component: {\"circuitId\":\"[^\"]+\",\"rendererId\":0,\"componentId\":0} -->(?<content>.*)<!-- M.A.C.Component: 0 -->",
|
||||
RegexOptions.Compiled | RegexOptions.Singleline, TimeSpan.FromSeconds(1)); // Treat the entire input string as a single line
|
||||
|
||||
private static readonly Regex CircuitInfoRegex = new Regex(
|
||||
"<!-- M.A.C.Component: (?<info>.*?) -->.*",
|
||||
RegexOptions.Compiled | RegexOptions.Singleline, TimeSpan.FromSeconds(1)); // Treat the entire input string as a single line
|
||||
|
||||
// Because CircuitPrerenderer is a point of integration with HttpContext,
|
||||
|
|
@ -74,6 +79,15 @@ namespace Microsoft.AspNetCore.Components.Server.Tests.Circuits
|
|||
.Replace("\r\n","\n");
|
||||
}
|
||||
|
||||
private JsonDocument GetUnwrappedCircuitInfo(ComponentPrerenderResult rawResult)
|
||||
{
|
||||
var writer = new StringWriter();
|
||||
rawResult.WriteTo(writer);
|
||||
var circuitInfo = CircuitInfoRegex.Match(writer.ToString()).Groups["info"].Value;
|
||||
|
||||
return JsonDocument.Parse(circuitInfo);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExtractsUriFromHttpContext_NonemptyPathBase()
|
||||
{
|
||||
|
|
@ -111,6 +125,36 @@ namespace Microsoft.AspNetCore.Components.Server.Tests.Circuits
|
|||
}), GetUnwrappedContent(result));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReplacesDashesWithDots_WhenTheyAppearInPairs()
|
||||
{
|
||||
// Arrange
|
||||
var circuitFactory = new TestCircuitFactory(() => "--1234--");
|
||||
var circuitRegistry = new CircuitRegistry(
|
||||
Options.Create(new CircuitOptions()),
|
||||
Mock.Of<ILogger<CircuitRegistry>>(),
|
||||
TestCircuitIdFactory.CreateTestFactory());
|
||||
var circuitPrerenderer = new CircuitPrerenderer(circuitFactory, circuitRegistry);
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var httpRequest = httpContext.Request;
|
||||
httpRequest.Scheme = "https";
|
||||
httpRequest.Host = new HostString("example.com", 1234);
|
||||
httpRequest.Path = "/some/path";
|
||||
|
||||
var prerenderingContext = new ComponentPrerenderingContext
|
||||
{
|
||||
ComponentType = typeof(UriDisplayComponent),
|
||||
Parameters = ParameterCollection.Empty,
|
||||
Context = httpContext
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await circuitPrerenderer.PrerenderComponentAsync(prerenderingContext);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("..1234..", GetUnwrappedCircuitInfo(result).RootElement.GetProperty("circuitId").GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DisposesCircuitScopeEvenIfPrerenderingThrows()
|
||||
{
|
||||
|
|
@ -139,6 +183,13 @@ namespace Microsoft.AspNetCore.Components.Server.Tests.Circuits
|
|||
|
||||
class TestCircuitFactory : CircuitFactory
|
||||
{
|
||||
private readonly Func<string> _circuitIdFactory;
|
||||
|
||||
public TestCircuitFactory(Func<string> circuitIdFactory = null)
|
||||
{
|
||||
_circuitIdFactory = circuitIdFactory ?? (() => Guid.NewGuid().ToString());
|
||||
}
|
||||
|
||||
public override CircuitHost CreateCircuitHost(HttpContext httpContext, CircuitClientProxy client, string uriAbsolute, string baseUriAbsolute)
|
||||
{
|
||||
var serviceCollection = new ServiceCollection();
|
||||
|
|
@ -149,7 +200,7 @@ namespace Microsoft.AspNetCore.Components.Server.Tests.Circuits
|
|||
return uriHelper;
|
||||
});
|
||||
var serviceScope = serviceCollection.BuildServiceProvider().CreateScope();
|
||||
return TestCircuitHost.Create(Guid.NewGuid().ToString(), serviceScope);
|
||||
return TestCircuitHost.Create(_circuitIdFactory(), serviceScope);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -2,7 +2,7 @@ import '@dotnet/jsinterop';
|
|||
import './GlobalExports';
|
||||
import * as signalR from '@aspnet/signalr';
|
||||
import { MessagePackHubProtocol } from '@aspnet/signalr-protocol-msgpack';
|
||||
import { fetchBootConfigAsync, loadEmbeddedResourcesAsync, shouldAutoStart } from './BootCommon';
|
||||
import { shouldAutoStart } from './BootCommon';
|
||||
import { CircuitHandler } from './Platform/Circuits/CircuitHandler';
|
||||
import { AutoReconnectCircuitHandler } from './Platform/Circuits/AutoReconnectCircuitHandler';
|
||||
import RenderQueue from './Platform/Circuits/RenderQueue';
|
||||
|
|
|
|||
|
|
@ -22,12 +22,15 @@ export function discoverPrerenderedCircuits(document: Document): CircuitDescript
|
|||
const discoveredCircuits = new Map<string, ComponentDescriptor[]>();
|
||||
for (let i = 0; i < commentPairs.length; i++) {
|
||||
const pair = commentPairs[i];
|
||||
let circuit = discoveredCircuits.get(pair.start.circuitId);
|
||||
// We replace '--' on the server with '..' when we prerender due to the fact that this
|
||||
// is not allowed in HTML comments and doesn't get encoded by default.
|
||||
const circuitId = pair.start.circuitId.replace('..', '--');
|
||||
let circuit = discoveredCircuits.get(circuitId);
|
||||
if (!circuit) {
|
||||
circuit = [];
|
||||
discoveredCircuits.set(pair.start.circuitId, circuit);
|
||||
discoveredCircuits.set(circuitId, circuit);
|
||||
}
|
||||
const entry = new ComponentDescriptor(pair.start.componentId, pair.start.circuitId, pair.start.rendererId, pair);
|
||||
const entry = new ComponentDescriptor(pair.start.componentId, circuitId, pair.start.rendererId, pair);
|
||||
circuit.push(entry);
|
||||
}
|
||||
const circuits: CircuitDescriptor[] = [];
|
||||
|
|
@ -82,14 +85,14 @@ function getComponentStartComment(node: Node): StartComponentComment | undefined
|
|||
const json = definition && definition[1];
|
||||
if (json) {
|
||||
try {
|
||||
const { componentId, circuitId, rendererId } = JSON.parse(json);
|
||||
const allComponents = !!componentId && !!circuitId && !!rendererId;
|
||||
const { componentId, rendererId, circuitId } = JSON.parse(json);
|
||||
const allComponents = componentId !== undefined && rendererId !== undefined && !!circuitId;
|
||||
if (allComponents) {
|
||||
return {
|
||||
node: node as Comment,
|
||||
circuitId,
|
||||
rendererId: Number.parseInt(rendererId),
|
||||
componentId: Number.parseInt(componentId),
|
||||
rendererId: rendererId,
|
||||
componentId: componentId,
|
||||
};
|
||||
} else {
|
||||
throw new Error(`Found malformed start component comment at ${node.textContent}`);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
|||
public class HtmlHelperComponentExtensionsTests
|
||||
{
|
||||
private static readonly Regex ContentWrapperRegex = new Regex(
|
||||
$"<!-- M.A.C.Component:{{\"circuitId\":\"[^\"]+\",\"rendererId\":\"0\",\"componentId\":\"0\"}} -->(?<content>.*)<!-- M.A.C.Component: 0 -->",
|
||||
"<!-- M.A.C.Component: {\"circuitId\":\"[^\"]+\",\"rendererId\":0,\"componentId\":0} -->(?<content>.*)<!-- M.A.C.Component: 0 -->",
|
||||
RegexOptions.Compiled | RegexOptions.Singleline, TimeSpan.FromSeconds(1)); // Treat the entire input string as a single line
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
public class ComponentRenderingFunctionalTests : IClassFixture<MvcTestFixture<BasicWebSite.StartupWithoutEndpointRouting>>
|
||||
{
|
||||
private static readonly Regex ContentWrapperRegex = new Regex(
|
||||
$"<!-- M.A.C.Component:{{\"circuitId\":\"[^\"]+\",\"rendererId\":\"\\d+\",\"componentId\":\"\\d+\"}} -->(?<content>.*)<!-- M.A.C.Component: \\d+ -->",
|
||||
"<!-- M.A.C.Component: {\"circuitId\":\"[^\"]+\",\"rendererId\":\\d+,\"componentId\":\\d+} -->(?<content>.*)<!-- M.A.C.Component: \\d+ -->",
|
||||
RegexOptions.Compiled | RegexOptions.Singleline, TimeSpan.FromSeconds(1)); // Treat the entire input string as a single line
|
||||
|
||||
public ComponentRenderingFunctionalTests(MvcTestFixture<BasicWebSite.StartupWithoutEndpointRouting> fixture)
|
||||
|
|
|
|||
Loading…
Reference in New Issue