Skip to content

Commit 554ba02

Browse files
maraflewing
andauthored
[browser] Use StaticWebAssets fingerprinting in Wasm SDK (#103755) (#105294)
* Build and publish integration * Make fingerpring work at runtime for assemblies * Make fingerpring work at runtime for icu * Remove version fingerprint check * Check core assembly extension * Typescript nits * JSModules and SatelliteAssemblies * DEBUG require newer SDK for testing * Fix fingerprint for new publish assets * Lazy loading and FP mapping boot json * WBT file on disk checks * WBT file on disk checks * WBT file on disk checks * WBT testmain no fingerprint * WBT revert debug message * AOT * WBT fix ordering * Fingerprinting without webcil * Fix GenerateWasmBootJson when FP is off * NoFingerprint WBT variant * DEBUG try to run WBT without fingerprinting * WBT make entry comparison order agnostic * WBT smoke tests for no-fingerprinting * Update sendtohelix-browser.targets * Remove debug log * Fix typo * Fix regex matching * Remove test for dotnet.js FP since we don't support that anymore * Fix check for System.Private.CoreLib * FP for dotnet.globalization.js * Fingerprinting pdbs * WBT fix file check * Fingerprint segmentation-rules.json * Fix loading pdb for fingerprinted lazy assembly * Ensure lazy pdb is loaded * Remove non-WasmSDK tests from non-FP category * Revert drop for dotnet.js finterprinting * Compute non-Fingerprinted virtualPath for pdb and resource as well * Make debugger working with fingerprinted assemblies and pdbs * DEBUG latest SDK for WBT * DEBUG fix wbt installation * Add WorkloadBuildTasks to WasmBuild.sln * Fix WBT * Revert escaping URL in debugger * Fix lazy loading test and message emit in release config * Fixes for MT after merge * Skip WBT without workloads and without fingerprinting * Turn off fingerprinting when targeting downlevel versions * Git ignore *.d.ts.sha256 * Fix * Update source-build-reference-packages to latest * Revert "Update source-build-reference-packages to latest" This reverts commit bef50ee. * Fix the references * Update Versions.props * Update Versions.props --------- Co-authored-by: Larry Ewing <lewing@microsoft.com>
1 parent f64e68a commit 554ba02

35 files changed

+466
-218
lines changed

src/libraries/sendtohelix-browser.targets

+1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
<BuildWasmAppsJobsList>$(RepositoryEngineeringDir)testing\scenarios\BuildWasmAppsJobsList.txt</BuildWasmAppsJobsList>
140140
<_XUnitTraitArg Condition="'$(TestUsingWorkloads)' == 'true'">-notrait category=no-workload</_XUnitTraitArg>
141141
<_XUnitTraitArg Condition="'$(TestUsingWorkloads)' != 'true'">-trait category=no-workload</_XUnitTraitArg>
142+
<_XUnitTraitArg Condition="'$(TestUsingFingerprinting)' == 'false'">$(_XUnitTraitArg) -trait category=no-fingerprinting</_XUnitTraitArg>
142143
</PropertyGroup>
143144

144145
<PropertyGroup>

src/libraries/sendtohelix-wasm.targets

+3-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<WorkItemPrefix Condition="'$(TestUsingWorkloads)' == 'true'">Workloads-</WorkItemPrefix>
1414
<WorkItemPrefix Condition="'$(TestUsingWorkloads)' != 'true'">NoWorkload-</WorkItemPrefix>
1515
<WorkItemPrefix Condition="'$(TestUsingWebcil)' == 'false'">$(WorkItemPrefix)NoWebcil-</WorkItemPrefix>
16+
<WorkItemPrefix Condition="'$(TestUsingFingerprinting)' == 'false'">$(WorkItemPrefix)NoFingerprint-</WorkItemPrefix>
1617
<WorkItemPrefix Condition="'$(WasmEnableThreads)' != 'true'">$(WorkItemPrefix)ST-</WorkItemPrefix>
1718
<WorkItemPrefix Condition="'$(WasmEnableThreads)' == 'true'">$(WorkItemPrefix)MT-</WorkItemPrefix>
1819
</PropertyGroup>
@@ -49,15 +50,15 @@
4950

5051
<!-- for testing with workloads, we use separate items -->
5152
<ItemGroup>
52-
<HelixWorkItem Include="@(BuildWasmApps_PerJobList->'$(WorkItemPrefix)%(Identity)')" Condition="'$(TestUsingWorkloads)' == 'true'">
53+
<HelixWorkItem Include="@(BuildWasmApps_PerJobList->'$(WorkItemPrefix)%(Identity)')" Condition="'$(TestUsingWorkloads)' == 'true' and '$(TestUsingFingerprinting)' == 'true'">
5354
<PayloadArchive>$(_BuildWasmAppsPayloadArchive)</PayloadArchive>
5455
<PreCommands Condition="'$(OS)' == 'Windows_NT'">set &quot;HELIX_XUNIT_ARGS=-class %(Identity)&quot;</PreCommands>
5556
<PreCommands Condition="'$(OS)' != 'Windows_NT'">export &quot;HELIX_XUNIT_ARGS=-class %(Identity)&quot;</PreCommands>
5657
<Command>$(HelixCommand)</Command>
5758
<Timeout>$(_workItemTimeout)</Timeout>
5859
</HelixWorkItem>
5960

60-
<HelixWorkItem Include="$(WorkItemPrefix)Wasm.Build.Tests" Condition="'$(TestUsingWorkloads)' != 'true'">
61+
<HelixWorkItem Include="$(WorkItemPrefix)Wasm.Build.Tests" Condition="'$(TestUsingWorkloads)' != 'true' or '$(TestUsingFingerprinting)' != 'true'">
6162
<PayloadArchive>$(_BuildWasmAppsPayloadArchive)</PayloadArchive>
6263
<Command>$(HelixCommand)</Command>
6364
<Timeout>$(_workItemTimeout)</Timeout>

src/libraries/sendtohelix.proj

+9-2
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,24 @@
8787
<ItemGroup Condition="'@(_Scenarios -> AnyHaveMetadataValue('Identity', 'buildwasmapps'))' == 'true'">
8888
<_TestUsingWorkloadsValues Include="true;false" />
8989
<_TestUsingWebcilValues Include="true;false" Condition="'$(TargetOS)' == 'browser'" />
90+
<_TestUsingFingerprintingValues Include="true;false" Condition="'$(TargetOS)' == 'browser'" />
9091

9192
<!-- now make the cartesian product of true and false values for two categories -->
9293
<_TestUsingCrossProductValuesTemp Include="@(_TestUsingWorkloadsValues)">
9394
<Workloads>%(_TestUsingWorkloadsValues.Identity)</Workloads>
9495
</_TestUsingCrossProductValuesTemp>
95-
<_TestUsingCrossProductValues Include="@(_TestUsingCrossProductValuesTemp)">
96+
<_TestUsingCrossProductValuesTemp2 Include="@(_TestUsingCrossProductValuesTemp)">
9697
<Webcil>%(_TestUsingWebcilValues.Identity)</Webcil>
98+
</_TestUsingCrossProductValuesTemp2>
99+
<_TestUsingCrossProductValues Include="@(_TestUsingCrossProductValuesTemp2)">
100+
<Fingerprinting>%(_TestUsingFingerprintingValues.Identity)</Fingerprinting>
97101
</_TestUsingCrossProductValues>
98102

103+
<!-- There no tests without fingerprinting and without workloads -->
104+
<_TestUsingCrossProductValues Remove="@(_TestUsingCrossProductValues)" Condition="'%(_TestUsingCrossProductValues.Workloads)' == 'false' and '%(_TestUsingCrossProductValues.Fingerprinting)' == 'false'" />
105+
99106
<_BuildWasmAppsProjectsToBuild Include="$(PerScenarioProjectFile)">
100-
<AdditionalProperties>$(_PropertiesToPass);Scenario=BuildWasmApps;TestArchiveRuntimeFile=$(TestArchiveRuntimeFile);TestUsingWorkloads=%(_TestUsingCrossProductValues.Workloads);TestUsingWebcil=%(_TestUsingCrossProductValues.Webcil)</AdditionalProperties>
107+
<AdditionalProperties>$(_PropertiesToPass);Scenario=BuildWasmApps;TestArchiveRuntimeFile=$(TestArchiveRuntimeFile);TestUsingWorkloads=%(_TestUsingCrossProductValues.Workloads);TestUsingWebcil=%(_TestUsingCrossProductValues.Webcil);TestUsingFingerprinting=%(_TestUsingCrossProductValues.Fingerprinting)</AdditionalProperties>
101108
<AdditionalProperties Condition="'$(NeedsToBuildWasmAppsOnHelix)' != ''">%(_BuildWasmAppsProjectsToBuild.AdditionalProperties);NeedsToBuildWasmAppsOnHelix=$(NeedsToBuildWasmAppsOnHelix)</AdditionalProperties>
102109
</_BuildWasmAppsProjectsToBuild>
103110
</ItemGroup>

src/libraries/sendtohelixhelp.proj

+2-1
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@
157157
<HelixCommandPrefixEnvVarItem Include="DOTNET_CLI_TELEMETRY_OPTOUT=1" />
158158
<HelixCommandPrefixEnvVarItem Condition="'$(TestUsingWorkloads)' == 'true'" Include="TEST_USING_WORKLOADS=true" />
159159
<HelixCommandPrefixEnvVarItem Condition="'$(TestUsingWebcil)' == 'false'" Include="TEST_USING_WEBCIL=false" />
160+
<HelixCommandPrefixEnvVarItem Condition="'$(TestUsingFingerprinting)' == 'false'" Include="TEST_USING_FINGERPRINTING=false" />
160161
<HelixCommandPrefixEnvVarItem Condition="'$(WorkloadsTestPreviousVersions)' == 'true'" Include="WORKLOADS_TEST_PREVIOUS_VERSIONS=true" />
161162
</ItemGroup>
162163

@@ -346,7 +347,7 @@
346347
<Target Name="PrintHelixQueues">
347348
<Message Importance="High" Text="Using Queues: $(HelixTargetQueues)" />
348349
<Message Condition="'$(Scenario)' == 'BuildWasmApps'" Importance="High"
349-
Text="Scenario: $(Scenario), TestUsingWorkloads: $(TestUsingWorkloads), TestUsingWebcil: $(TestUsingWebcil)" />
350+
Text="Scenario: $(Scenario), TestUsingWorkloads: $(TestUsingWorkloads), TestUsingWebcil: $(TestUsingWebcil), TestUsingFingerprinting: $(TestUsingFingerprinting)" />
350351
</Target>
351352

352353
<Target Name="PrintBuildTargetFramework">

src/mono/browser/.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
.stamp-wasm-install-and-select*
33
emsdk
44

5-
runtime/dotnet.d.ts.sha256
5+
runtime/*.d.ts.sha256

src/mono/browser/debugger/BrowserDebugProxy/DebugStore.cs

+18-4
Original file line numberDiff line numberDiff line change
@@ -1683,6 +1683,9 @@ public async IAsyncEnumerable<SourceFile> Load(SessionId id, string[] loaded_fil
16831683
var asm_files = new List<string>();
16841684
List<DebugItem> steps = new List<DebugItem>();
16851685

1686+
// Use System.Private.CoreLib to determine if we have a fingerprinted assemblies or not.
1687+
bool isFingerprinted = Path.GetFileNameWithoutExtension(loaded_files.FirstOrDefault(f => f.Contains("System.Private.CoreLib"))) != "System.Private.CoreLib";
1688+
16861689
if (!useDebuggerProtocol)
16871690
{
16881691
var pdb_files = new List<string>();
@@ -1698,8 +1701,17 @@ public async IAsyncEnumerable<SourceFile> Load(SessionId id, string[] loaded_fil
16981701
{
16991702
try
17001703
{
1701-
string candidate_pdb = Path.ChangeExtension(url, "pdb");
1702-
string pdb = pdb_files.FirstOrDefault(n => n == candidate_pdb);
1704+
string pdb;
1705+
if (isFingerprinted)
1706+
{
1707+
string noFingerprintPdbFileName = string.Concat(Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(url)), ".pdb");
1708+
pdb = pdb_files.FirstOrDefault(n => string.Concat(Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(n)), Path.GetExtension(n)) == noFingerprintPdbFileName);
1709+
}
1710+
else
1711+
{
1712+
string candidate_pdb = Path.ChangeExtension(url, "pdb");
1713+
pdb = pdb_files.FirstOrDefault(n => n == candidate_pdb);
1714+
}
17031715

17041716
steps.Add(
17051717
new DebugItem
@@ -1722,12 +1734,14 @@ public async IAsyncEnumerable<SourceFile> Load(SessionId id, string[] loaded_fil
17221734
continue;
17231735
try
17241736
{
1725-
string unescapedFileName = Uri.UnescapeDataString(file_name);
1737+
string unescapedFileName = Path.GetFileName(Uri.UnescapeDataString(file_name));
1738+
if (isFingerprinted)
1739+
unescapedFileName = string.Concat(Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(unescapedFileName)), Path.GetExtension(unescapedFileName));
17261740
steps.Add(
17271741
new DebugItem
17281742
{
17291743
Url = file_name,
1730-
DataTask = context.SdbAgent.GetDataFromAssemblyAndPdbAsync(Path.GetFileName(unescapedFileName), false, token)
1744+
DataTask = context.SdbAgent.GetDataFromAssemblyAndPdbAsync(unescapedFileName, false, token)
17311745
});
17321746
}
17331747
catch (Exception e)

src/mono/browser/runtime/diagnostics-mock.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,4 @@ interface MockEnvironment {
7171
expectAdvertise: FilterPredicate;
7272
}
7373

74-
export { MockEnvironment, MockScriptConnection, PromiseAndController };
74+
export type { MockEnvironment, MockScriptConnection, PromiseAndController };

src/mono/browser/runtime/diagnostics-mock.d.ts.sha256

-1
This file was deleted.

src/mono/browser/runtime/dotnet.d.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,9 @@ type ResourceExtensions = {
247247
};
248248
interface ResourceGroups {
249249
hash?: string;
250+
fingerprinting?: {
251+
[name: string]: string;
252+
};
250253
coreAssembly?: ResourceList;
251254
assembly?: ResourceList;
252255
lazyAssembly?: ResourceList;
@@ -692,4 +695,4 @@ declare global {
692695
}
693696
declare const createDotnetRuntime: CreateDotnetRuntimeType;
694697

695-
export { AssetBehaviors, AssetEntry, CreateDotnetRuntimeType, DotnetHostBuilder, DotnetModuleConfig, EmscriptenModule, GlobalizationMode, IMemoryView, ModuleAPI, MonoConfig, RuntimeAPI, createDotnetRuntime as default, dotnet, exit };
698+
export { type AssetBehaviors, type AssetEntry, type CreateDotnetRuntimeType, type DotnetHostBuilder, type DotnetModuleConfig, type EmscriptenModule, GlobalizationMode, type IMemoryView, type ModuleAPI, type MonoConfig, type RuntimeAPI, createDotnetRuntime as default, dotnet, exit };

src/mono/browser/runtime/lazyLoading.ts

+28-2
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,23 @@ import { AssetEntry } from "./types";
77

88
export async function loadLazyAssembly (assemblyNameToLoad: string): Promise<boolean> {
99
const resources = loaderHelpers.config.resources!;
10+
const originalAssemblyName = assemblyNameToLoad;
1011
const lazyAssemblies = resources.lazyAssembly;
1112
if (!lazyAssemblies) {
1213
throw new Error("No assemblies have been marked as lazy-loadable. Use the 'BlazorWebAssemblyLazyLoad' item group in your project file to enable lazy loading an assembly.");
1314
}
1415

16+
if (loaderHelpers.config.resources!.fingerprinting) {
17+
const map = loaderHelpers.config.resources!.fingerprinting;
18+
for (const fingerprintedName in map) {
19+
const nonFingerprintedName = map[fingerprintedName];
20+
if (nonFingerprintedName == assemblyNameToLoad) {
21+
assemblyNameToLoad = fingerprintedName;
22+
break;
23+
}
24+
}
25+
}
26+
1527
if (!lazyAssemblies[assemblyNameToLoad]) {
1628
throw new Error(`${assemblyNameToLoad} must be marked with 'BlazorWebAssemblyLazyLoad' item group in your project file to allow lazy-loading.`);
1729
}
@@ -26,8 +38,22 @@ export async function loadLazyAssembly (assemblyNameToLoad: string): Promise<boo
2638
return false;
2739
}
2840

29-
const pdbNameToLoad = changeExtension(dllAsset.name, ".pdb");
30-
const shouldLoadPdb = loaderHelpers.config.debugLevel != 0 && loaderHelpers.isDebuggingSupported() && Object.prototype.hasOwnProperty.call(lazyAssemblies, pdbNameToLoad);
41+
let pdbNameToLoad = changeExtension(originalAssemblyName, ".pdb");
42+
let shouldLoadPdb = false;
43+
if (loaderHelpers.config.debugLevel != 0 && loaderHelpers.isDebuggingSupported()) {
44+
shouldLoadPdb = Object.prototype.hasOwnProperty.call(lazyAssemblies, pdbNameToLoad);
45+
if (loaderHelpers.config.resources!.fingerprinting) {
46+
const map = loaderHelpers.config.resources!.fingerprinting;
47+
for (const fingerprintedName in map) {
48+
const nonFingerprintedName = map[fingerprintedName];
49+
if (nonFingerprintedName == pdbNameToLoad) {
50+
pdbNameToLoad = fingerprintedName;
51+
shouldLoadPdb = true;
52+
break;
53+
}
54+
}
55+
}
56+
}
3157

3258
const dllBytesPromise = loaderHelpers.retrieve_asset_download(dllAsset);
3359

src/mono/browser/runtime/loader/assets.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ export function prepareAssets () {
318318
}
319319

320320
const addAsset = (asset: AssetEntryInternal, isCore: boolean) => {
321+
if (resources.fingerprinting && (asset.behavior == "assembly" || asset.behavior == "pdb" || asset.behavior == "resource")) {
322+
asset.virtualPath = getNonFingerprintedAssetName(asset.name);
323+
}
321324
if (isCore) {
322325
asset.isCore = true;
323326
coreAssetsToLoad.push(asset);
@@ -418,7 +421,7 @@ export function prepareAssets () {
418421
behavior: "icu",
419422
loadRemote: true
420423
});
421-
} else if (name === "segmentation-rules.json") {
424+
} else if (name.startsWith("segmentation-rules") && name.endsWith(".json")) {
422425
assetsToLoad.push({
423426
name,
424427
hash: resources.icu[name],
@@ -460,6 +463,15 @@ export function prepareAssets () {
460463
config.assets = [...coreAssetsToLoad, ...assetsToLoad, ...modulesAssets];
461464
}
462465

466+
export function getNonFingerprintedAssetName (assetName: string) {
467+
const fingerprinting = loaderHelpers.config.resources?.fingerprinting;
468+
if (fingerprinting && fingerprinting[assetName]) {
469+
return fingerprinting[assetName];
470+
}
471+
472+
return assetName;
473+
}
474+
463475
export function prepareAssetsWorker () {
464476
const config = loaderHelpers.config;
465477
mono_assert(config.assets, "config.assets must be defined");

src/mono/browser/runtime/loader/icu.ts

+14-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { mono_log_error } from "./logging";
55
import { GlobalizationMode, MonoConfig } from "../types";
66
import { ENVIRONMENT_IS_WEB, loaderHelpers } from "./globals";
77
import { mono_log_info, mono_log_debug } from "./logging";
8+
import { getNonFingerprintedAssetName } from "./assets";
89

910
export function init_globalization () {
1011
loaderHelpers.preferredIcuAsset = getIcuResourceName(loaderHelpers.config);
@@ -51,6 +52,17 @@ export function getIcuResourceName (config: MonoConfig): string | null {
5152
const culture = config.applicationCulture || (ENVIRONMENT_IS_WEB ? (globalThis.navigator && globalThis.navigator.languages && globalThis.navigator.languages[0]) : Intl.DateTimeFormat().resolvedOptions().locale);
5253

5354
const icuFiles = Object.keys(config.resources.icu);
55+
const fileMapping: {
56+
[k: string]: string
57+
} = {};
58+
for (let index = 0; index < icuFiles.length; index++) {
59+
const icuFile = icuFiles[index];
60+
if (config.resources.fingerprinting) {
61+
fileMapping[getNonFingerprintedAssetName(icuFile)] = icuFile;
62+
} else {
63+
fileMapping[icuFile] = icuFile;
64+
}
65+
}
5466

5567
let icuFile = null;
5668
if (config.globalizationMode === GlobalizationMode.Custom) {
@@ -65,8 +77,8 @@ export function getIcuResourceName (config: MonoConfig): string | null {
6577
icuFile = getShardedIcuResourceName(culture);
6678
}
6779

68-
if (icuFile && icuFiles.includes(icuFile)) {
69-
return icuFile;
80+
if (icuFile && fileMapping[icuFile]) {
81+
return fileMapping[icuFile];
7082
}
7183
}
7284

src/mono/browser/runtime/types/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ export type ResourceExtensions = { [extensionName: string]: ResourceList };
203203

204204
export interface ResourceGroups {
205205
hash?: string;
206+
fingerprinting?: { [name: string]: string },
206207
coreAssembly?: ResourceList; // nullable only temporarily
207208
assembly?: ResourceList; // nullable only temporarily
208209
lazyAssembly?: ResourceList; // nullable only temporarily

src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.props

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Copyright (c) .NET Foundation. All rights reserved.
3535
<StaticWebAssetsGetPublishAssetsTargets>ComputeFilesToPublish;GetCurrentProjectPublishStaticWebAssetItems</StaticWebAssetsGetPublishAssetsTargets>
3636
<StaticWebAssetsAdditionalPublishProperties>$(StaticWebAssetsAdditionalPublishProperties);BuildProjectReferences=false;ResolveAssemblyReferencesFindRelatedSatellites=true</StaticWebAssetsAdditionalPublishProperties>
3737
<StaticWebAssetsAdditionalPublishPropertiesToRemove>$(StaticWebAssetsAdditionalPublishPropertiesToRemove);NoBuild;RuntimeIdentifier</StaticWebAssetsAdditionalPublishPropertiesToRemove>
38+
<StaticWebAssetStandaloneHosting Condition="'$(StaticWebAssetStandaloneHosting)' == '' and '$(StaticWebAssetProjectMode)' == 'Root'">true</StaticWebAssetStandaloneHosting>
3839
</PropertyGroup>
3940

4041
<ItemGroup>

0 commit comments

Comments
 (0)