Repository navigation
[wasi] Build-switchable wasi:http capability for the CoreCLR-WASI test host (corerun) #130742
Description
Context
The CoreCLR-WASI library-test leg (#130129) relinks corerun per-app via WasiApp.CoreCLR.targets. Test assemblies that reference System.Net.Http/System.Net.Quic pull in [WasmImportLinkage] bindings that emit direct component-model imports for the wasi:http world (wasi:http/types@0.2.x, wasi:http/outgoing-handler@0.2.x). corerun's baked CLI/command world does not declare wasi:http (http lives in the proxy/serve world), so wasm-component-ld fails to encode a bundle that references those imports unless the world is extended.
The baked corerun already declares wasi:io/* and wasi:clocks/monotonic-clock (from WasiPollWorld, used by framework timers/polling), and those encode + run fine — only wasi:http/* is new to the app bundle.
Current state (smoke leg)
The smoke leg ships an http-capable corerun: the relink adds -Wl,--component-type,WasiHttpWorld_component_type.wit (mirroring Mono's WasiApp.targets) so corerun's world declares wasi:http, and it runs under wasmtime -S http (already passed by eng/testing/tests.wasi.targets). This is validated end-to-end (System.Runtime.Tests: 9930 cases discovered + executed).
WASI-preview2 constraint: a component that declares a wasi:http import must have the host provide it at instantiation, or wasmtime refuses to instantiate. So an http-capable corerun requires -S http on every run. That is fine for the current leg (it always passes -S http), but it is a capability the non-networking smoke does not actually use.
Proposal
Add a build-time switch on the relink (e.g. WasmHostWasiHttp) selecting between two corerun variants:
- no-http (default candidate for non-networking legs): do not declare
wasi:http; instead add the two modules to_WasmIgnoredPInvokeModulesso the generated p/invoke table omits them (mirrors the existingIgnoredPInvokeModuleswiring inBrowserWasmApp.CoreCLR.targets). No-S httpneeded. Safe because those imports bind lazily and are never referenced by non-networking tests.<_WasmIgnoredPInvokeModules Include="wasi:http/outgoing-handler@0.2.8" /> <_WasmIgnoredPInvokeModules Include="wasi:http/types@0.2.8" />
- http-capable (for
System.Net.*.Tests): declarewasi:httpvia--component-typeand run withwasmtime --wasi http(the current behavior).
Caveats to resolve in the switch:
- The ignore-list strings are ordinal, version-pinned (
@0.2.8); a prefix-ignore forwasi:http/in the generator would be more robust as versions bump. - Enumerate the current
wasi:http/*module strings from the generatedcallhelpers-pinvoke.cpp/WASM0066warnings to be sure all are covered.
Why now vs. later
Browser never hits this (HttpClientHandler uses BrowserHttpHandler/JS-fetch under #if !TARGET_WASI; WasiHttpHandler + its wasi:http interop is TARGET_WASI-only). So there is no browser prior art for the capability split — it is genuinely new wasi work. The smoke leg is unblocked today by the http-capable variant; this issue tracks making the capability build-switchable so non-networking legs can ship a minimal no-http host and networking legs get a properly-declared http world.
Related: #130129 (CoreCLR-WASI library tests), #130634 (R2R call_indirect path), #130739 (reverse-thunk key robustness).
Note
This issue was drafted with GitHub Copilot.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNo status
Activity
dotnet-policy-service commentedon Jul 14, 2026
Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.
lewing commentedon Jul 15, 2026
Additional framing (thanks @lewing): the over-declaration is fundamentally an untrimmed-test-bundle artifact, not a general
corerun-world problem.ManagedToNativeGenerator/PInvokeCollectoris a pure metadata scan —type.GetMethods(...)over every method looking forDllImportAttribute/WasmImportLinkageAttribute(src/tasks/WasmAppBuilder/coreclr/PInvokeCollector.cs:77). It is not reachability-based: it emits an import for every[WasmImportLinkage]method present in the scanned assemblies, whether or not it is ever called.Consequence: if the bundle were trimmed, the trimmer would remove the unreferenced
WasiHttpHandler(a non-networking bundle likeSystem.Runtime.Testsnever reaches it), the generator would never see those methods, and nowasi:http/*import would be emitted — so neither--component-typenor the ignore-list would be needed, and the host would not need-S http.wasi:httpthey actually reach is declared, and--wasi httpis required only when http is genuinely used.--component-type, or no-http via the ignore-list).So the
WasmHostWasiHttpbuild-switch proposed above is really "how the untrimmed test host handles imports the app metadata declares but never calls." A generator-sidewasi:http/prefix-ignore (or a reachability-aware emit) would also address it without a per-bundle world change.Note
This comment was drafted with GitHub Copilot.
lewing commentedon Jul 15, 2026
Path forward (per @lewing): rather than declaring the world (
--component-type) or dropping the imports (ignore-list/trimming), statify the imports that are there — provide static stub definitions in the host that satisfy the app-declaredwasi:http/*(and any other unused world) imports, trapping if actually invoked. That makes the relinkedcorerunself-contained:wasm-component-ldresolves the imports locally, so no host-provided world is required at instantiation and no-S httpis needed, regardless of whether the (untrimmed) bundle over-declares. The--component-typeapproach in the current smoke leg is a rough patch; the stub-satisfy path is the intended direction.Note
This comment was drafted with GitHub Copilot.
lewing commentedon Jul 15, 2026
Implementation note for the statify path (from the dispatch analysis in the Wasi r2r prototype session):
callhelpers-pinvoke.cppcurrently emits thewasi:http/*externs with theimport_module/import_nameattributes, and dispatch flows throughcallhelpers_pinvoke_override(ResolvePInvokeTarget→PInvokeOverride::GetMethodImpl→ the attributed extern). Two ways to statify:import_moduleextern for a configured stub-list — keeps it in the generated table (one source of truth), and a call resolves to a localabort/trap thunk instead ofnullptr→LoadLibrary-fail.(i) is cleaner. Either makes
corerunself-contained (no--component-typeworld declaration, no-S http) and safe (an actually-invoked stubbed import traps rather than mis-dispatches). Post-smoke; the--component-typevariant ships now.Note
This comment was drafted with GitHub Copilot.
[wasi] Stand up CoreCLR-WASI library-test leg (per-app corerun relink) (