diff --git a/src/browser/Page.zig b/src/browser/Page.zig
index 836c831b..d4721315 100644
--- a/src/browser/Page.zig
+++ b/src/browser/Page.zig
@@ -3613,7 +3613,7 @@ pub fn submitForm(self: *Page, submitter_: ?*Element, form_: ?*Element.Html.Form
// The submitter can be an input box (if enter was entered on the box)
// I don't think this is technically correct, but FormData handles it ok
- const form_data = try FormData.init(form, submitter_, self);
+ const form_data = try FormData.init(form, submitter_, &self.js.execution);
const arena = try self._session.getArena(.medium, "submitForm");
errdefer self._session.releaseArena(arena);
diff --git a/src/browser/js/Env.zig b/src/browser/js/Env.zig
index 6e9c574b..5958e341 100644
--- a/src/browser/js/Env.zig
+++ b/src/browser/js/Env.zig
@@ -302,6 +302,7 @@ fn _createContext(self: *Env, global: anytype, params: ContextParams) !*Context
context.execution = .{
.url = &global.url,
.buf = &global.buf,
+ .charset = &global.charset,
.context = context,
.arena = global.arena,
.call_arena = params.call_arena,
diff --git a/src/browser/js/Execution.zig b/src/browser/js/Execution.zig
index 877cd9e3..96af6504 100644
--- a/src/browser/js/Execution.zig
+++ b/src/browser/js/Execution.zig
@@ -45,3 +45,11 @@ _scheduler: *Scheduler,
// Pointer to the url field (Page or WorkerGlobalScope) - allows access to current url even after navigation
url: *[:0]const u8,
+
+// Pointer to the charset field of the global (Page or WorkerGlobalScope).
+charset: *[]const u8,
+
+// Returns the current base URL of the global scope.
+pub fn base(self: *const Execution) [:0]const u8 {
+ return self.context.global.base();
+}
diff --git a/src/browser/js/bridge.zig b/src/browser/js/bridge.zig
index 3e5ab70c..0d0d5873 100644
--- a/src/browser/js/bridge.zig
+++ b/src/browser/js/bridge.zig
@@ -919,15 +919,21 @@ pub const WorkerJsApis = flattenTypes(&.{
@import("../webapi/File.zig"),
@import("../webapi/Console.zig"),
@import("../webapi/Crypto.zig"),
+ @import("../webapi/net/FormData.zig"),
+ @import("../webapi/net/Headers.zig"),
+ @import("../webapi/net/Request.zig"),
+ @import("../webapi/net/Response.zig"),
// @import("../webapi/URL.zig"),
// @import("../webapi/Blob.zig"),
- // @import("../webapi/net/FormData.zig"),
// @import("../webapi/Performance.zig"),
- // @import("../webapi/net/Response.zig"),
- // @import("../webapi/net/Request.zig"),
- // @import("../webapi/net/Headers.zig"),
// @import("../webapi/AbortSignal.zig"),
// @import("../webapi/AbortController.zig"),
+ // @import("../webapi/streams/ReadableStream.zig"),
+ // @import("../webapi/streams/ReadableStreamDefaultReader.zig"),
+ // @import("../webapi/streams/ReadableStreamDefaultController.zig"),
+ // @import("../webapi/streams/WritableStream.zig"),
+ // @import("../webapi/streams/WritableStreamDefaultWriter.zig"),
+ // @import("../webapi/streams/WritableStreamDefaultController.zig"),
});
// Master list of ALL JS APIs across all contexts.
diff --git a/src/browser/tests/worker/api-worker.js b/src/browser/tests/worker/api-worker.js
new file mode 100644
index 00000000..2c01d8fd
--- /dev/null
+++ b/src/browser/tests/worker/api-worker.js
@@ -0,0 +1,55 @@
+// Exercises WebAPI classes available in WorkerGlobalScope.
+// Replies with either { ok: true, results: {...} } or { ok: false, err }.
+(async function() {
+ try {
+ // Headers
+ const headers = new Headers();
+ headers.set('X-Test', 'hello');
+ headers.append('X-Test', 'world');
+
+ // FormData (no form - pure data container)
+ const fd = new FormData();
+ fd.set('name', 'first');
+ fd.append('name', 'second');
+
+ // Request
+ const request = new Request('https://example.com/path', {
+ method: 'POST',
+ headers: { 'x-custom': 'header' },
+ body: 'request body',
+ });
+ const request_body_text = await request.text();
+
+ // Response
+ const response = new Response('response body', {
+ status: 201,
+ statusText: 'Created',
+ headers: { 'content-type': 'text/plain' },
+ });
+ const response_body_text = await response.text();
+ const response_clone_text = await response.clone().text();
+
+ postMessage({
+ ok: true,
+ results: {
+ headers_get: headers.get('x-test'),
+ headers_has: headers.has('x-test'),
+ headers_has_missing: headers.has('x-missing'),
+ formdata_get: fd.get('name'),
+ formdata_getall: fd.getAll('name'),
+ request_url: request.url,
+ request_method: request.method,
+ request_headers_custom: request.headers.get('x-custom'),
+ request_body_text,
+ response_status: response.status,
+ response_status_text: response.statusText,
+ response_ok: response.ok,
+ response_headers_content_type: response.headers.get('content-type'),
+ response_body_text,
+ response_clone_text,
+ },
+ });
+ } catch (e) {
+ postMessage({ ok: false, err: String(e), stack: e.stack });
+ }
+})();
diff --git a/src/browser/tests/worker/worker.html b/src/browser/tests/worker/worker.html
index 5dbda1f7..c0960231 100644
--- a/src/browser/tests/worker/worker.html
+++ b/src/browser/tests/worker/worker.html
@@ -172,6 +172,47 @@
}
+
+