aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile8
-rw-r--r--integration/bunjs-only-snippets/globals.test.js3
-rw-r--r--integration/bunjs-only-snippets/html-rewriter.test.js4
-rw-r--r--integration/bunjs-only-snippets/mmap.test.js10
-rw-r--r--integration/bunjs-only-snippets/response.file.test.js65
-rw-r--r--src/deps/_libusockets.h15
-rw-r--r--src/javascript/jsc/api/html_rewriter.zig3
-rw-r--r--src/javascript/jsc/api/server.zig30
-rw-r--r--src/javascript/jsc/base.zig2
-rw-r--r--src/javascript/jsc/bindings/ZigGlobalObject.cpp21
-rw-r--r--src/javascript/jsc/bindings/bindings.cpp224
-rw-r--r--src/javascript/jsc/bindings/bindings.zig352
-rw-r--r--src/javascript/jsc/bindings/exports.zig5
-rw-r--r--src/javascript/jsc/bindings/header-gen.zig1
-rw-r--r--src/javascript/jsc/bindings/headers-cpp.h8
-rw-r--r--src/javascript/jsc/bindings/headers-handwritten.h7
-rw-r--r--src/javascript/jsc/bindings/headers-replacements.zig2
-rw-r--r--src/javascript/jsc/bindings/headers.h27
-rw-r--r--src/javascript/jsc/bindings/headers.zig26
-rw-r--r--src/javascript/jsc/bindings/helpers.h30
-rw-r--r--src/javascript/jsc/bindings/webcore/DOMClientIsoSubspaces.h4
-rw-r--r--src/javascript/jsc/bindings/webcore/DOMIsoSubspaces.h4
-rw-r--r--src/javascript/jsc/bindings/webcore/FetchHeaders.cpp245
-rw-r--r--src/javascript/jsc/bindings/webcore/FetchHeaders.h133
-rw-r--r--src/javascript/jsc/bindings/webcore/FetchHeaders.idl44
-rw-r--r--src/javascript/jsc/bindings/webcore/HTTPHeaderField.cpp217
-rw-r--r--src/javascript/jsc/bindings/webcore/HTTPHeaderField.h82
-rw-r--r--src/javascript/jsc/bindings/webcore/HTTPHeaderMap.cpp223
-rw-r--r--src/javascript/jsc/bindings/webcore/HTTPHeaderMap.h282
-rw-r--r--src/javascript/jsc/bindings/webcore/HTTPHeaderNames.cpp718
-rw-r--r--src/javascript/jsc/bindings/webcore/HTTPHeaderNames.gperf295
-rw-r--r--src/javascript/jsc/bindings/webcore/HTTPHeaderNames.h242
-rw-r--r--src/javascript/jsc/bindings/webcore/HTTPHeaderNames.in119
-rw-r--r--src/javascript/jsc/bindings/webcore/HTTPHeaderValues.cpp68
-rw-r--r--src/javascript/jsc/bindings/webcore/HTTPHeaderValues.h40
-rw-r--r--src/javascript/jsc/bindings/webcore/HTTPParsers.cpp1034
-rw-r--r--src/javascript/jsc/bindings/webcore/HTTPParsers.h178
-rw-r--r--src/javascript/jsc/bindings/webcore/JSFetchHeaders.cpp502
-rw-r--r--src/javascript/jsc/bindings/webcore/JSFetchHeaders.dep1
-rw-r--r--src/javascript/jsc/bindings/webcore/JSFetchHeaders.h93
-rw-r--r--src/javascript/jsc/bindings/webcore/ParsedContentType.cpp422
-rw-r--r--src/javascript/jsc/bindings/webcore/ParsedContentType.h76
-rw-r--r--src/javascript/jsc/javascript.zig3
-rw-r--r--src/javascript/jsc/webcore/response.zig893
44 files changed, 5918 insertions, 843 deletions
diff --git a/Makefile b/Makefile
index eb1c55d9f..487d7e4bb 100644
--- a/Makefile
+++ b/Makefile
@@ -200,9 +200,11 @@ MAC_INCLUDE_DIRS := -I$(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders \
LINUX_INCLUDE_DIRS := -I$(JSC_INCLUDE_DIR) \
-Isrc/javascript/jsc/bindings/
-INCLUDE_DIRS := -I$(BUN_DEPS_DIR)/uws
+UWS_INCLUDE_DIR := -I$(BUN_DEPS_DIR)/uws/uSockets/src -I$(BUN_DEPS_DIR)/uws/src -I$(BUN_DEPS_DIR)
+INCLUDE_DIRS := $(UWS_INCLUDE_DIR)
+
ifeq ($(OS_NAME),linux)
INCLUDE_DIRS += $(LINUX_INCLUDE_DIRS)
@@ -456,7 +458,7 @@ build-obj-wasm-small:
build-obj-safe:
$(ZIG) build obj -Drelease-safe
-UWS_CC_FLAGS = -pthread -DUWS_HTTPRESPONSE_NO_WRITEMARK=1 -DLIBUS_USE_OPENSSL=1 -DLIBUS_USE_BORINGSSL=1 -DWITH_BORINGSSL=1 -Wpedantic -Wall -Wextra -Wsign-conversion -Wconversion -Isrc -IuSockets/src -DUWS_WITH_PROXY
+UWS_CC_FLAGS = -pthread -DLIBUS_USE_OPENSSL=1 -DUWS_HTTPRESPONSE_NO_WRITEMARK=1 -DLIBUS_USE_BORINGSSL=1 -DWITH_BORINGSSL=1 -Wpedantic -Wall -Wextra -Wsign-conversion -Wconversion $(UWS_INCLUDE) -DUWS_WITH_PROXY
UWS_CXX_FLAGS = $(UWS_CC_FLAGS) -std=gnu++17
UWS_LDFLAGS = -I$(BUN_DEPS_DIR)/boringssl/include
@@ -1032,7 +1034,7 @@ wasm-return1:
# We do this outside of build.zig for performance reasons
# The C compilation stuff with build.zig is really slow and we don't need to run this as often as the rest
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
- $(CXX) $(CLANG_FLAGS) \
+ $(CXX) $(CLANG_FLAGS) $(UWS_INCLUDE) \
$(MACOS_MIN_FLAG) \
$(OPTIMIZATION_LEVEL) \
-fno-exceptions \
diff --git a/integration/bunjs-only-snippets/globals.test.js b/integration/bunjs-only-snippets/globals.test.js
index 831bbd93f..b498e0e8e 100644
--- a/integration/bunjs-only-snippets/globals.test.js
+++ b/integration/bunjs-only-snippets/globals.test.js
@@ -16,7 +16,8 @@ it("extendable", () => {
var Foo = class extends Class {};
var bar = new Foo();
expect(bar instanceof Class).toBe(true);
- expect(Class.prototype instanceof Class).toBe(true);
+ expect(!!Class.prototype).toBe(true);
+ expect(typeof Class.prototype).toBe("object");
}
expect(true).toBe(true);
});
diff --git a/integration/bunjs-only-snippets/html-rewriter.test.js b/integration/bunjs-only-snippets/html-rewriter.test.js
index a4ca965aa..68e2849d9 100644
--- a/integration/bunjs-only-snippets/html-rewriter.test.js
+++ b/integration/bunjs-only-snippets/html-rewriter.test.js
@@ -26,10 +26,6 @@ describe("HTMLRewriter", () => {
expect(await res.text()).toBe("<div><span>replace</span></div>");
});
- it("exists globally", async () => {
- expect(typeof HTMLRewriter).toBe("function");
- expect(typeof HTMLRewriter.constructor).toBe("function");
- });
it("supports element handlers", async () => {
var rewriter = new HTMLRewriter();
rewriter.on("div", {
diff --git a/integration/bunjs-only-snippets/mmap.test.js b/integration/bunjs-only-snippets/mmap.test.js
index 03ce75e87..3dd3aadb9 100644
--- a/integration/bunjs-only-snippets/mmap.test.js
+++ b/integration/bunjs-only-snippets/mmap.test.js
@@ -10,13 +10,13 @@ it("mmap finalizer", async () => {
map = null;
Bun.gc(true);
- await new Promise(resolve => setTimeout(resolve, 1));
+ await new Promise((resolve) => setTimeout(resolve, 1));
});
-it('mmap passed to other syscalls', async () => {
+it("mmap passed to other syscalls", async () => {
const map = Bun.mmap(path);
- await Bun.write(path + '1', map);
- const text = await (await Bun.file(path + '1')).text();
+ await Bun.write(path + "1", map);
+ const text = await (await Bun.file(path + "1")).text();
expect(text).toBe(new TextDecoder().decode(map));
});
@@ -46,4 +46,4 @@ it("mmap private", () => {
map2[0] = 0;
expect(map2[0]).toBe(0);
expect(map[0]).toBe(old);
-}); \ No newline at end of file
+});
diff --git a/integration/bunjs-only-snippets/response.file.test.js b/integration/bunjs-only-snippets/response.file.test.js
index d094c0a62..6a879c758 100644
--- a/integration/bunjs-only-snippets/response.file.test.js
+++ b/integration/bunjs-only-snippets/response.file.test.js
@@ -2,12 +2,28 @@ import fs from "fs";
import { it, expect } from "bun:test";
import path from "path";
+function gc() {
+ Bun.gc(true);
+}
+
+// we must ensure that finalizers are run
+// so that the reference-counting logic is exercised
+function gcTick() {
+ gc();
+ return new Promise((resolve) => {
+ setTimeout(resolve, 0);
+ });
+}
+
it("Bun.file not found returns ENOENT", async () => {
try {
+ await gcTick();
await Bun.file("/does/not/exist.txt").text();
+ await gcTick();
} catch (exception) {
expect(exception.code).toBe("ENOENT");
}
+ await gcTick();
});
it("Bun.write('out.txt', 'string')", async () => {
@@ -17,11 +33,15 @@ it("Bun.write('out.txt', 'string')", async () => {
fs.unlinkSync(path.join("/tmp", "out.txt"));
} catch (e) {}
}
-
+ await gcTick();
await Bun.write("/tmp/out.txt", "string");
+ await gcTick();
const out = Bun.file("/tmp/out.txt");
+ await gcTick();
expect(await out.text()).toBe("string");
+ await gcTick();
expect(await out.text()).toBe(fs.readFileSync("/tmp/out.txt", "utf8"));
+ await gcTick();
}
});
@@ -30,38 +50,47 @@ it("Bun.write blob", async () => {
Bun.file("/tmp/response-file.test.txt"),
Bun.file(path.join(import.meta.dir, "fetch.js.txt"))
);
+ await gcTick();
await Bun.write(Bun.file("/tmp/response-file.test.txt"), "blah blah blha");
+ await gcTick();
await Bun.write(
Bun.file("/tmp/response-file.test.txt"),
new Uint32Array(1024)
);
+ await gcTick();
await Bun.write("/tmp/response-file.test.txt", new Uint32Array(1024));
+ await gcTick();
expect(
await Bun.write(
new TextEncoder().encode("/tmp/response-file.test.txt"),
new Uint32Array(1024)
)
).toBe(new Uint32Array(1024).byteLength);
+ await gcTick();
});
it("Bun.file -> Bun.file", async () => {
try {
fs.unlinkSync(path.join("/tmp", "fetch.js.in"));
} catch (e) {}
-
+ await gcTick();
try {
fs.unlinkSync(path.join("/tmp", "fetch.js.out"));
} catch (e) {}
-
+ await gcTick();
const file = path.join(import.meta.dir, "fetch.js.txt");
+ await gcTick();
const text = fs.readFileSync(file, "utf8");
fs.writeFileSync("/tmp/fetch.js.in", text, { mode: 0644 });
+ await gcTick();
{
const result = await Bun.write(
Bun.file("/tmp/fetch.js.out"),
Bun.file("/tmp/fetch.js.in")
);
+ await gcTick();
expect(await Bun.file("/tmp/fetch.js.out").text()).toBe(text);
+ await gcTick();
}
{
@@ -75,14 +104,18 @@ it("Bun.file -> Bun.file", async () => {
}
{
+ await gcTick();
await Bun.write("/tmp/fetch.js.in", Bun.file("/tmp/fetch.js.out"));
+ await gcTick();
expect(await Bun.file("/tmp/fetch.js.in").text()).toBe(text);
}
});
it("Bun.file", async () => {
const file = path.join(import.meta.dir, "fetch.js.txt");
+ await gcTick();
expect(await Bun.file(file).text()).toBe(fs.readFileSync(file, "utf8"));
+ await gcTick();
});
it("Bun.file as a Blob", async () => {
@@ -92,27 +125,34 @@ it("Bun.file as a Blob", async () => {
// internally, instead of a byte array, it stores the file path!
// this enables several performance optimizations
var blob = Bun.file(filePath);
+ await gcTick();
// no size because we haven't read it from disk yet
expect(blob.size).toBe(0);
+ await gcTick();
// now it reads "./fetch.js.txt" from the filesystem
// it's lazy, only loads once we ask for it
// if it fails, the promise will reject at this point
expect(await blob.text()).toBe(fixture);
+ await gcTick();
// now that it's loaded, the size updates
expect(blob.size).toBe(fixture.length);
+ await gcTick();
// and it only loads once for _all_ blobs pointing to that file path
// until all references are released
expect((await blob.arrayBuffer()).byteLength).toBe(fixture.length);
+ await gcTick();
const array = new Uint8Array(await blob.arrayBuffer());
+ await gcTick();
const text = fixture;
for (let i = 0; i < text.length; i++) {
expect(array[i]).toBe(text.charCodeAt(i));
}
+ await gcTick();
expect(blob.size).toBe(fixture.length);
blob = null;
- Bun.gc(true);
+ await gcTick();
await new Promise((resolve) => setTimeout(resolve, 1));
// now we're back
var blob = Bun.file(filePath);
@@ -121,9 +161,13 @@ it("Bun.file as a Blob", async () => {
it("Response -> Bun.file", async () => {
const file = path.join(import.meta.dir, "fetch.js.txt");
+ await gcTick();
const text = fs.readFileSync(file, "utf8");
+ await gcTick();
const response = new Response(Bun.file(file));
+ await gcTick();
expect(await response.text()).toBe(text);
+ await gcTick();
});
it("Bun.file -> Response", async () => {
@@ -131,18 +175,29 @@ it("Bun.file -> Response", async () => {
try {
fs.unlinkSync("/tmp/fetch.js.out");
} catch {}
-
+ await gcTick();
const file = path.join(import.meta.dir, "fetch.js.txt");
+ await gcTick();
const text = fs.readFileSync(file, "utf8");
+ await gcTick();
const resp = await fetch("https://example.com");
+ await gcTick();
expect(await Bun.write("/tmp/fetch.js.out", resp)).toBe(text.length);
+ await gcTick();
expect(await Bun.file("/tmp/fetch.js.out").text()).toBe(text);
+ await gcTick();
});
it("Response -> Bun.file -> Response -> text", async () => {
+ await gcTick();
const file = path.join(import.meta.dir, "fetch.js.txt");
+ await gcTick();
const text = fs.readFileSync(file, "utf8");
+ await gcTick();
const response = new Response(Bun.file(file));
+ await gcTick();
const response2 = response.clone();
+ await gcTick();
expect(await response2.text()).toBe(text);
+ await gcTick();
});
diff --git a/src/deps/_libusockets.h b/src/deps/_libusockets.h
index f0825e294..d63fc38ca 100644
--- a/src/deps/_libusockets.h
+++ b/src/deps/_libusockets.h
@@ -1,3 +1,4 @@
+#pragma once
#ifndef LIBUWS_CAPI_HEADER
#define LIBUWS_CAPI_HEADER
@@ -7,6 +8,15 @@
#include <stdint.h>
#include <uws/src/App.h>
#include <uws/src/AsyncSocket.h>
+
+#ifndef STRING_POINTER
+#define STRING_POINTER
+typedef struct StringPointer {
+ uint32_t off;
+ uint32_t len;
+} StringPointer;
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -282,11 +292,6 @@ void uws_loop_addPreHandler(us_loop_t *loop, void *key,
void uws_loop_removePreHandler(us_loop_t *loop, void *ctx_);
void uws_loop_defer(us_loop_t *loop, void *ctx, void (*cb)(void *ctx));
-typedef struct StringPointer {
- uint32_t off;
- uint32_t len;
-} StringPointer;
-
void uws_res_write_headers(int ssl, uws_res_t *res, const StringPointer *names,
const StringPointer *values, size_t count,
const char *buf);
diff --git a/src/javascript/jsc/api/html_rewriter.zig b/src/javascript/jsc/api/html_rewriter.zig
index e3a3c6d75..ac6190f7e 100644
--- a/src/javascript/jsc/api/html_rewriter.zig
+++ b/src/javascript/jsc/api/html_rewriter.zig
@@ -217,7 +217,7 @@ pub const HTMLRewriter = struct {
pub fn returnEmptyResponse(this: *HTMLRewriter, global: *JSGlobalObject, response: *Response) JSValue {
var result = bun.default_allocator.create(Response) catch unreachable;
- response.cloneInto(result, getAllocator(global.ref()));
+ response.cloneInto(result, getAllocator(global.ref()), global);
this.finalizeWithoutDestroy();
return JSValue.fromRef(Response.makeMaybePooled(global.ref(), result));
}
@@ -280,7 +280,6 @@ pub const HTMLRewriter = struct {
.body = .{
.init = .{
.status_code = 200,
- .headers = null,
},
.value = .{
.Locked = .{
diff --git a/src/javascript/jsc/api/server.zig b/src/javascript/jsc/api/server.zig
index 38fad7c0c..aeb13b6bc 100644
--- a/src/javascript/jsc/api/server.zig
+++ b/src/javascript/jsc/api/server.zig
@@ -377,7 +377,7 @@ pub fn NewServer(comptime ssl_enabled: bool, comptime debug_mode: bool) type {
response_ptr: ?*JSC.WebCore.Response = null,
blob: JSC.WebCore.Blob = JSC.WebCore.Blob{},
promise: ?*JSC.JSValue = null,
- response_headers: ?*JSC.WebCore.Headers.RefCountedHeaders = null,
+ response_headers: ?*JSC.FetchHeaders = null,
has_abort_handler: bool = false,
has_sendfile_ctx: bool = false,
has_called_error_handler: bool = false,
@@ -559,25 +559,18 @@ pub fn NewServer(comptime ssl_enabled: bool, comptime debug_mode: bool) type {
fn writeHeaders(
this: *RequestContext,
- headers_: *Headers.RefCountedHeaders,
+ headers: *JSC.FetchHeaders,
) void {
- var headers: *JSC.WebCore.Headers = headers_.get();
- if (headers.getHeaderIndex("content-length")) |index| {
- headers.entries.orderedRemove(index);
- }
-
- if (this.blob.content_type.len > 0 and headers.getHeaderIndex("content-type") == null) {
- this.resp.writeHeader("content-type", this.blob.content_type);
- } else if (MimeType.sniff(this.blob.sharedView())) |content| {
- this.resp.writeHeader("content-type", content.value);
+ headers.remove(&ZigString.init("content-length"));
+ if (!headers.has(&ZigString.init("content-type"))) {
+ if (this.blob.content_type.len > 0) {
+ this.resp.writeHeader("content-type", this.blob.content_type);
+ } else if (MimeType.sniff(this.blob.sharedView())) |content| {
+ this.resp.writeHeader("content-type", content.value);
+ }
}
- defer headers_.deref();
- var entries = headers.entries.slice();
- const names = entries.items(.name);
- const values = entries.items(.value);
-
- this.resp.writeHeaders(names, values, headers.buf.items);
+ headers.toUWSResponse(ssl_enabled, this.resp);
}
pub fn writeStatus(this: *RequestContext, status: u16) void {
@@ -834,8 +827,9 @@ pub fn NewServer(comptime ssl_enabled: bool, comptime debug_mode: bool) type {
this.writeStatus(status);
- if (response.body.init.headers) |headers_| {
+ if (response.body.init.headers.as(JSC.FetchHeaders)) |headers_| {
this.writeHeaders(headers_);
+ headers_.deref();
} else if (this.blob.content_type.len > 0) {
this.resp.writeHeader("content-type", this.blob.content_type);
} else if (MimeType.sniff(this.blob.sharedView())) |content| {
diff --git a/src/javascript/jsc/base.zig b/src/javascript/jsc/base.zig
index 20752e8e6..aa9e9abd2 100644
--- a/src/javascript/jsc/base.zig
+++ b/src/javascript/jsc/base.zig
@@ -21,7 +21,6 @@ const Response = WebCore.Response;
const Request = WebCore.Request;
const Router = @import("./api/router.zig");
const FetchEvent = WebCore.FetchEvent;
-const Headers = WebCore.Headers.RefCountedHeaders;
const IdentityContext = @import("../../identity_context.zig").IdentityContext;
const Body = WebCore.Body;
@@ -2536,7 +2535,6 @@ pub const JSPrivateDataPtr = TaggedPointerUnion(.{
ExpectPrototype,
FetchEvent,
FetchTaskletContext,
- Headers,
HTMLRewriter,
JSNode,
LazyPropertiesObject,
diff --git a/src/javascript/jsc/bindings/ZigGlobalObject.cpp b/src/javascript/jsc/bindings/ZigGlobalObject.cpp
index a99087abf..178fe3d1d 100644
--- a/src/javascript/jsc/bindings/ZigGlobalObject.cpp
+++ b/src/javascript/jsc/bindings/ZigGlobalObject.cpp
@@ -86,10 +86,11 @@
#include "JSCustomEvent.h"
#include "JSAbortController.h"
#include "JSEvent.h"
+#include "JSFetchHeaders.h"
#include "Process.h"
-#include "JavaScriptCore/RemoteInspectorServer.h"
+#include <JavaScriptCore/RemoteInspectorServer.h>
using JSGlobalObject = JSC::JSGlobalObject;
using Exception = JSC::Exception;
@@ -372,6 +373,17 @@ JSC_DEFINE_CUSTOM_GETTER(JSCustomEvent_getter,
WebCore::JSCustomEvent::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject));
}
+JSC_DECLARE_CUSTOM_GETTER(JSFetchHeaders_getter);
+
+JSC_DEFINE_CUSTOM_GETTER(JSFetchHeaders_getter,
+ (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue,
+ JSC::PropertyName))
+{
+ Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
+ return JSC::JSValue::encode(
+ WebCore::JSFetchHeaders::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject));
+}
+
JSC_DECLARE_CUSTOM_GETTER(JSEventTarget_getter);
JSC_DEFINE_CUSTOM_GETTER(JSEventTarget_getter,
@@ -849,11 +861,14 @@ void GlobalObject::installAPIGlobals(JSClassRef* globals, int count, JSC::VM& vm
putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "CustomEvent"), JSC::CustomGetterSetter::create(vm, JSCustomEvent_getter, nullptr),
JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly);
+ putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "Headers"), JSC::CustomGetterSetter::create(vm, JSFetchHeaders_getter, nullptr),
+ JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly);
+
extraStaticGlobals.releaseBuffer();
- // this->setRemoteDebuggingEnabled(true);
+ this->setRemoteDebuggingEnabled(true);
// auto& server = Inspector::RemoteInspectorServer::singleton();
- // if (server.start("127.0.0.1", 9222)) {
+ // if (server.start("localhost", 9222)) {
// }
}
diff --git a/src/javascript/jsc/bindings/bindings.cpp b/src/javascript/jsc/bindings/bindings.cpp
index 3f5486c5f..9bb5b33f3 100644
--- a/src/javascript/jsc/bindings/bindings.cpp
+++ b/src/javascript/jsc/bindings/bindings.cpp
@@ -48,20 +48,234 @@
#include "wtf/text/StringView.h"
#include "wtf/text/WTFString.h"
+#include "JSFetchHeaders.h"
+#include "FetchHeaders.h"
#include "DOMURL.h"
#include "JSDOMURL.h"
+#include "_libusockets.h"
+#include <string_view>
+#include <uws/src/App.h>
+#include <uws/uSockets/src/internal/internal.h>
+#include "IDLTypes.h"
+#include "JSDOMBinding.h"
+#include "JSDOMConstructor.h"
+#include "JSDOMConvertBase.h"
+#include "JSDOMConvertBoolean.h"
+#include "JSDOMConvertInterface.h"
+#include "JSDOMConvertNullable.h"
+#include "JSDOMConvertRecord.h"
+#include "JSDOMConvertSequences.h"
+#include "JSDOMConvertStrings.h"
+#include "JSDOMConvertUnion.h"
+#include "JSDOMExceptionHandling.h"
+#include "JSDOMGlobalObjectInlines.h"
+#include "JSDOMIterator.h"
+#include "JSDOMOperation.h"
+#include "JSDOMWrapperCache.h"
+
+template<typename WebCoreType, typename OutType>
+OutType* WebCoreCast(JSC__JSValue JSValue0, JSC::VM* vm)
+{
+ // we must use jsDynamicCast here so that we check that the type is correct
+ WebCoreType* jsdomURL = JSC::jsDynamicCast<WebCoreType*>(*vm, JSC::JSValue::decode(JSValue0));
+ if (jsdomURL == nullptr) {
+ return nullptr;
+ }
+
+ return reinterpret_cast<OutType*>(&jsdomURL->wrapped());
+}
+
+template<typename UWSResponse>
+static void copyToUWS(WebCore::FetchHeaders* headers, UWSResponse* res)
+{
+ auto iter = headers->createIterator();
+ uint32_t i = 0;
+ unsigned count = 0;
+ for (auto pair = iter.next(); pair; pair = iter.next()) {
+ auto name = pair->key;
+ auto value = pair->value;
+ res->writeHeader(std::string_view(reinterpret_cast<const char*>(name.characters8()), name.length()), std::string_view(reinterpret_cast<const char*>(value.characters8()), value.length()));
+ }
+}
+
extern "C" {
-WebCore__DOMURL* WebCore__DOMURL__cast(JSC__JSValue JSValue0)
+void WebCore__FetchHeaders__toUWSResponse(WebCore__FetchHeaders* arg0, bool is_ssl, void* arg2)
{
- auto* jsdomURL = JSC::jsCast<WebCore::JSDOMURL*>(JSC::JSValue::decode(JSValue0));
- if (jsdomURL == nullptr) {
- return nullptr;
+ if (is_ssl) {
+ copyToUWS<uWS::HttpResponse<true>>(arg0, reinterpret_cast<uWS::HttpResponse<true>*>(arg2));
+ } else {
+ copyToUWS<uWS::HttpResponse<false>>(arg0, reinterpret_cast<uWS::HttpResponse<false>*>(arg2));
}
+}
- return &jsdomURL->wrapped();
+void WebCore__FetchHeaders__append(WebCore__FetchHeaders* headers, const ZigString* arg1, const ZigString* arg2)
+{
+ headers->append(Zig::toString(*arg1), Zig::toString(*arg2));
+}
+WebCore__FetchHeaders* WebCore__FetchHeaders__cast_(JSC__JSValue JSValue0, JSC__VM* vm)
+{
+ return WebCoreCast<WebCore::JSFetchHeaders, WebCore__FetchHeaders>(JSValue0, vm);
}
+
+using namespace WebCore;
+
+WebCore__FetchHeaders* WebCore__FetchHeaders__createFromJS(JSC__JSGlobalObject* lexicalGlobalObject, JSC__JSValue argument0_)
+{
+ Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ EnsureStillAliveScope argument0 = JSC::JSValue::decode(argument0_);
+ auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
+ auto init = argument0.value().isUndefined() ? std::optional<Converter<IDLUnion<IDLSequence<IDLSequence<IDLByteString>>, IDLRecord<IDLByteString, IDLByteString>>>::ReturnType>() : std::optional<Converter<IDLUnion<IDLSequence<IDLSequence<IDLByteString>>, IDLRecord<IDLByteString, IDLByteString>>>::ReturnType>(convert<IDLUnion<IDLSequence<IDLSequence<IDLByteString>>, IDLRecord<IDLByteString, IDLByteString>>>(*lexicalGlobalObject, argument0.value()));
+ RETURN_IF_EXCEPTION(throwScope, nullptr);
+ return WebCoreCast<WebCore::JSFetchHeaders, WebCore__FetchHeaders>(
+ JSC::JSValue::encode(WebCore::toJSNewlyCreated(lexicalGlobalObject, globalObject, WebCore::FetchHeaders::create(WTFMove(init)).releaseReturnValue())),
+ &lexicalGlobalObject->vm());
+}
+
+JSC__JSValue WebCore__FetchHeaders__toJS(WebCore__FetchHeaders* headers, JSC__JSGlobalObject* lexicalGlobalObject)
+{
+ Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+
+ return JSC::JSValue::encode(WebCore::toJS(lexicalGlobalObject, globalObject, headers));
+}
+JSC__JSValue WebCore__FetchHeaders__clone(WebCore__FetchHeaders* headers, JSC__JSGlobalObject* arg1)
+{
+ Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(arg1);
+ auto clone = WebCore::FetchHeaders::create();
+ if (headers->size() > 0) {
+ auto iter = headers->createIterator();
+ uint32_t i = 0;
+ unsigned count = 0;
+ for (auto pair = iter.next(); pair; pair = iter.next()) {
+ auto name = pair->key;
+ auto value = pair->value;
+ clone->append(name.isolatedCopy(), value.isolatedCopy());
+ }
+ }
+ return JSC::JSValue::encode(WebCore::toJSNewlyCreated(arg1, globalObject, WTFMove(clone)));
+}
+
+// WebCore__FetchHeaders* WebCore__FetchHeaders__cloneThis(WebCore__FetchHeaders* headers)
+// {
+
+// return JSC::JSValue::encode(WebCore::toJSNewlyCreated(globalObject, globalObject, WebCore::FetchHeaders::create(*headers)));
+// }
+
+void WebCore__FetchHeaders__copyTo(WebCore__FetchHeaders* headers, StringPointer* names, StringPointer* values, unsigned char* buf)
+{
+ auto iter = headers->createIterator();
+ uint32_t i = 0;
+ unsigned count = 0;
+ for (auto pair = iter.next(); pair; pair = iter.next()) {
+ auto name = pair->key;
+ auto value = pair->value;
+ names[count] = { i, name.length() };
+ memcpy(&buf[i], name.characters8(), name.length());
+ i += name.length();
+ values[count++] = { i, value.length() };
+ memcpy(&buf[i], value.characters8(), value.length());
+ i += value.length();
+ }
+}
+void WebCore__FetchHeaders__count(WebCore__FetchHeaders* headers, uint32_t* count, uint32_t* buf_len)
+{
+ auto iter = headers->createIterator();
+ uint32_t i = 0;
+ for (auto pair = iter.next(); pair; pair = iter.next()) {
+ i += pair->key.length();
+ i += pair->value.length();
+ }
+
+ *count = headers->size();
+ *buf_len = i;
+}
+typedef struct PicoHTTPHeader {
+ unsigned const char* name;
+ size_t name_len;
+ unsigned const char* value;
+ size_t value_len;
+} PicoHTTPHeader;
+
+typedef struct PicoHTTPHeaders {
+ const PicoHTTPHeader* ptr;
+ size_t len;
+} PicoHTTPHeaders;
+JSC__JSValue WebCore__FetchHeaders__createFromPicoHeaders_(JSC__JSGlobalObject* arg0, const void* arg1)
+{
+ PicoHTTPHeaders pico_headers = *reinterpret_cast<const PicoHTTPHeaders*>(arg1);
+ Vector<KeyValuePair<String, String>> pairs;
+ pairs.reserveCapacity(pico_headers.len);
+ for (size_t i = 0; i < pico_headers.len; i++) {
+ WTF::String name = WTF::String(pico_headers.ptr[i].name, pico_headers.ptr[i].name_len);
+ WTF::String value = WTF::String(pico_headers.ptr[i].value, pico_headers.ptr[i].value_len);
+ pairs.uncheckedAppend(KeyValuePair<String, String>(name, value));
+ }
+
+ Ref<WebCore::FetchHeaders> headers = WebCore::FetchHeaders::create();
+ headers->fill(WebCore::FetchHeaders::Init(pairs));
+ pairs.releaseBuffer();
+ return JSC::JSValue::encode(WebCore::toJSNewlyCreated(arg0, reinterpret_cast<Zig::GlobalObject*>(arg0), WTFMove(headers)));
+}
+JSC__JSValue WebCore__FetchHeaders__createFromUWS(JSC__JSGlobalObject* arg0, void* arg1)
+{
+ uWS::HttpRequest req = *reinterpret_cast<uWS::HttpRequest*>(arg1);
+ Vector<KeyValuePair<String, String>> pairs;
+ pairs.reserveCapacity(55);
+ for (const auto& header : req) {
+ auto name = WTF::String(reinterpret_cast<const LChar*>(header.first.data()), header.first.length());
+ auto value = WTF::String(reinterpret_cast<const LChar*>(header.second.data()), header.second.length());
+ pairs.uncheckedAppend(KeyValuePair<String, String>(name, value));
+ }
+
+ Ref<WebCore::FetchHeaders> headers = WebCore::FetchHeaders::create();
+ headers->fill(WebCore::FetchHeaders::Init(pairs));
+ pairs.releaseBuffer();
+ return JSC::JSValue::encode(WebCore::toJS(arg0, reinterpret_cast<Zig::GlobalObject*>(arg0), headers));
+}
+void WebCore__FetchHeaders__deref(WebCore__FetchHeaders* arg0)
+{
+ arg0->deref();
+}
+
+JSC__JSValue WebCore__FetchHeaders__createValue(JSC__JSGlobalObject* arg0, StringPointer* arg1, StringPointer* arg2, const ZigString* arg3, uint32_t count)
+{
+ Vector<KeyValuePair<String, String>> pairs;
+ pairs.reserveCapacity(count);
+ ZigString buf = *arg3;
+ for (uint32_t i = 0; i < count; i++) {
+ WTF::String name = Zig::toStringCopy(buf, arg1[i]);
+ WTF::String value = Zig::toStringCopy(buf, arg2[i]);
+ pairs.uncheckedAppend(KeyValuePair<String, String>(name, value));
+ }
+
+ Ref<WebCore::FetchHeaders> headers = WebCore::FetchHeaders::create();
+ headers->fill(WebCore::FetchHeaders::Init(pairs));
+ pairs.releaseBuffer();
+ return JSC::JSValue::encode(WebCore::toJS(arg0, reinterpret_cast<Zig::GlobalObject*>(arg0), headers));
+}
+void WebCore__FetchHeaders__get_(WebCore__FetchHeaders* headers, const ZigString* arg1, ZigString* arg2)
+{
+ *arg2 = Zig::toZigString(headers->get(Zig::toString(*arg1)).releaseReturnValue());
+}
+bool WebCore__FetchHeaders__has(WebCore__FetchHeaders* headers, const ZigString* arg1)
+{
+ return headers->has(Zig::toString(*arg1)).releaseReturnValue();
+}
+void WebCore__FetchHeaders__put_(WebCore__FetchHeaders* headers, const ZigString* arg1, const ZigString* arg2)
+{
+ headers->set(Zig::toString(*arg1), Zig::toString(*arg2));
+}
+void WebCore__FetchHeaders__remove(WebCore__FetchHeaders* headers, const ZigString* arg1)
+{
+ headers->remove(Zig::toString(*arg1));
+}
+
+WebCore__DOMURL* WebCore__DOMURL__cast_(JSC__JSValue JSValue0, JSC::VM* vm)
+{
+ return WebCoreCast<WebCore::JSDOMURL, WebCore__DOMURL>(JSValue0, vm);
+}
+
void WebCore__DOMURL__href_(WebCore__DOMURL* domURL, ZigString* arg1)
{
const WTF::URL& href = domURL->href();
diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig
index 15f71a470..0f8d5de00 100644
--- a/src/javascript/jsc/bindings/bindings.zig
+++ b/src/javascript/jsc/bindings/bindings.zig
@@ -110,6 +110,24 @@ pub const ZigString = extern struct {
pub const empty = Slice{ .allocator = bun.default_allocator, .ptr = undefined, .len = 0, .allocated = false };
+ pub fn clone(this: Slice, allocator: std.mem.Allocator) !Slice {
+ if (!this.allocated) {
+ return Slice{ .allocator = allocator, .ptr = this.ptr, .len = this.len, .allocated = false };
+ }
+
+ var duped = try allocator.dupe(u8, this.ptr[0..this.len]);
+ return Slice{ .allocator = allocator, .ptr = duped.ptr, .len = this.len, .allocated = true };
+ }
+
+ pub fn cloneZ(this: Slice, allocator: std.mem.Allocator) !Slice {
+ if (this.allocated or this.len == 0) {
+ return this;
+ }
+
+ var duped = try allocator.dupeZ(u8, this.ptr[0..this.len]);
+ return Slice{ .allocator = allocator, .ptr = duped.ptr, .len = this.len, .allocated = true };
+ }
+
pub fn slice(this: Slice) []const u8 {
return this.ptr[0..this.len];
}
@@ -272,6 +290,28 @@ pub const ZigString = extern struct {
};
}
+ pub fn toSliceZ(this: ZigString, allocator: std.mem.Allocator) Slice {
+ if (this.len == 0)
+ return Slice{ .ptr = "", .len = 0, .allocator = allocator, .allocated = false };
+
+ if (is16Bit(&this)) {
+ var buffer = std.fmt.allocPrintZ(allocator, "{}", .{this}) catch unreachable;
+ return Slice{
+ .ptr = buffer.ptr,
+ .len = @truncate(u32, buffer.len),
+ .allocated = true,
+ .allocator = allocator,
+ };
+ }
+
+ return Slice{
+ .ptr = untagged(this.ptr),
+ .len = @truncate(u32, this.len),
+ .allocated = false,
+ .allocator = allocator,
+ };
+ }
+
pub fn sliceZBuf(this: ZigString, buf: *[bun.MAX_PATH_BYTES]u8) ![:0]const u8 {
return try std.fmt.bufPrintZ(buf, "{}", .{this});
}
@@ -355,8 +395,12 @@ pub const DOMURL = opaque {
const cppFn = shim.cppFn;
pub const name = "WebCore::DOMURL";
+ pub fn cast_(value: JSValue, vm: *VM) ?*DOMURL {
+ return shim.cppFn("cast_", .{ value, vm });
+ }
+
pub fn cast(value: JSValue) ?*DOMURL {
- return shim.cppFn("cast", .{value});
+ return cast_(value, JSC.VirtualMachine.vm.global.vm());
}
pub fn href_(this: *DOMURL, out: *ZigString) void {
@@ -380,12 +424,291 @@ pub const DOMURL = opaque {
}
pub const Extern = [_][]const u8{
- "cast",
+ "cast_",
"href_",
"pathname_",
};
};
+const Api = @import("../../../api/schema.zig").Api;
+
+pub const FetchHeaders = opaque {
+ pub const shim = Shimmer("WebCore", "FetchHeaders", @This());
+
+ const cppFn = shim.cppFn;
+ pub const name = "WebCore::FetchHeaders";
+
+ pub fn createValue(
+ global: *JSGlobalObject,
+ names: [*c]Api.StringPointer,
+ values: [*c]Api.StringPointer,
+ buf: *const ZigString,
+ count_: u32,
+ ) JSValue {
+ return shim.cppFn("createValue", .{
+ global,
+ names,
+ values,
+ buf,
+ count_,
+ });
+ }
+
+ pub fn createFromJS(
+ global: *JSGlobalObject,
+ value: JSValue,
+ ) ?*FetchHeaders {
+ return shim.cppFn("createFromJS", .{
+ global,
+ value,
+ });
+ }
+
+ pub fn putDefault(this: *FetchHeaders, name_: []const u8, value: []const u8) void {
+ if (this.has(&ZigString.init(name_))) {
+ return;
+ }
+
+ this.put_(&ZigString.init(name_), &ZigString.init(value));
+ }
+
+ pub fn from(
+ global: *JSGlobalObject,
+ names: [*c]Api.StringPointer,
+ values: [*c]Api.StringPointer,
+ buf: *const ZigString,
+ count_: u32,
+ ) JSValue {
+ return shim.cppFn("createValue", .{
+ global,
+ names,
+ values,
+ buf,
+ count_,
+ });
+ }
+
+ pub fn createFromUWS(
+ global: *JSGlobalObject,
+ uws_request: *anyopaque,
+ ) JSValue {
+ return shim.cppFn("createFromUWS", .{
+ global,
+ uws_request,
+ });
+ }
+
+ pub fn toUWSResponse(
+ headers: *FetchHeaders,
+ is_ssl: bool,
+ uws_response: *anyopaque,
+ ) void {
+ return shim.cppFn("toUWSResponse", .{
+ headers,
+ is_ssl,
+ uws_response,
+ });
+ }
+
+ const PicoHeaders = extern struct {
+ ptr: *const anyopaque,
+ len: usize,
+ };
+
+ pub fn createEmpty(
+ global: *JSGlobalObject,
+ ) JSValue {
+ const pico_ = PicoHeaders{ .ptr = undefined, .len = 0 };
+ return shim.cppFn("createFromPicoHeaders_", .{
+ global,
+ &pico_,
+ });
+ }
+
+ pub fn createFromPicoHeaders(
+ global: *JSGlobalObject,
+ pico_headers: anytype,
+ ) JSValue {
+ const out = PicoHeaders{ .ptr = pico_headers.ptr, .len = pico_headers.len };
+ const result = shim.cppFn("createFromPicoHeaders_", .{
+ global,
+ &out,
+ });
+ return result;
+ }
+
+ pub fn createFromPicoHeaders_(
+ global: *JSGlobalObject,
+ pico_headers: *const anyopaque,
+ ) JSValue {
+ return shim.cppFn("createFromPicoHeaders_", .{
+ global,
+ pico_headers,
+ });
+ }
+
+ pub fn append(
+ this: *FetchHeaders,
+ name_: *const ZigString,
+ value: *const ZigString,
+ ) void {
+ return shim.cppFn("append", .{
+ this,
+ name_,
+ value,
+ });
+ }
+
+ pub fn put_(
+ this: *FetchHeaders,
+ name_: *const ZigString,
+ value: *const ZigString,
+ ) void {
+ return shim.cppFn("put_", .{
+ this,
+ name_,
+ value,
+ });
+ }
+
+ pub fn put(
+ this: *FetchHeaders,
+ name_: []const u8,
+ value: []const u8,
+ ) void {
+ this.put_(&ZigString.init(name_), &ZigString.init(value));
+ }
+
+ pub fn get_(
+ this: *FetchHeaders,
+ name_: *const ZigString,
+ out: *ZigString,
+ ) void {
+ shim.cppFn("get_", .{
+ this,
+ name_,
+ out,
+ });
+ }
+
+ pub fn get(
+ this: *FetchHeaders,
+ name_: []const u8,
+ ) ?[]const u8 {
+ var out = ZigString.Empty;
+ get_(this, &ZigString.init(name_), &out);
+ if (out.len > 0) {
+ return out.slice();
+ }
+
+ return null;
+ }
+
+ pub fn has(
+ this: *FetchHeaders,
+ name_: *const ZigString,
+ ) bool {
+ return shim.cppFn("has", .{
+ this,
+ name_,
+ });
+ }
+
+ pub fn remove(
+ this: *FetchHeaders,
+ name_: *const ZigString,
+ ) void {
+ return shim.cppFn("remove", .{
+ this,
+ name_,
+ });
+ }
+
+ pub fn cast_(value: JSValue, vm: *VM) ?*FetchHeaders {
+ return shim.cppFn("cast_", .{ value, vm });
+ }
+
+ pub fn cast(value: JSValue) ?*FetchHeaders {
+ return cast_(value, JSC.VirtualMachine.vm.global.vm());
+ }
+
+ pub fn toJS(this: *FetchHeaders, globalThis: *JSGlobalObject) JSValue {
+ return shim.cppFn("toJS", .{ this, globalThis });
+ }
+
+ pub fn count(
+ this: *FetchHeaders,
+ names: *u32,
+ buf_len: *u32,
+ ) void {
+ return shim.cppFn("count", .{
+ this,
+ names,
+ buf_len,
+ });
+ }
+
+ pub fn clone(
+ this: *FetchHeaders,
+ global: *JSGlobalObject,
+ ) JSValue {
+ return shim.cppFn("clone", .{
+ this,
+ global,
+ });
+ }
+
+ pub fn cloneThis(
+ this: *FetchHeaders,
+ ) ?*FetchHeaders {
+ return shim.cppFn("cloneThis", .{
+ this,
+ });
+ }
+
+ pub fn deref(
+ this: *FetchHeaders,
+ ) void {
+ return shim.cppFn("deref", .{
+ this,
+ });
+ }
+
+ pub fn copyTo(
+ this: *FetchHeaders,
+ names: [*c]Api.StringPointer,
+ values: [*c]Api.StringPointer,
+ buf: [*]u8,
+ ) void {
+ return shim.cppFn("copyTo", .{
+ this,
+ names,
+ values,
+ buf,
+ });
+ }
+
+ pub const Extern = [_][]const u8{
+ "append",
+ "cast_",
+ "clone",
+ "cloneThis",
+ "copyTo",
+ "count",
+ "createFromJS",
+ "createFromPicoHeaders_",
+ "createFromUWS",
+ "createValue",
+ "deref",
+ "get_",
+ "has",
+ "put_",
+ "remove",
+ "toJS",
+ "toUWSResponse",
+ };
+};
+
pub const SystemError = extern struct {
errno: c_int = 0,
/// label for errno
@@ -1667,6 +1990,10 @@ pub const String = extern struct {
};
};
+pub const BuiltinName = enum(u8) {
+ headers,
+};
+
pub const JSValue = enum(u64) {
_,
@@ -1935,13 +2262,17 @@ pub const JSValue = enum(u64) {
}
pub fn as(value: JSValue, comptime ZigType: type) ?*ZigType {
- if (value.isUndefinedOrNull())
+ if (value.isEmptyOrUndefinedOrNull())
return null;
if (comptime ZigType == DOMURL) {
return DOMURL.cast(value);
}
+ if (comptime ZigType == FetchHeaders) {
+ return FetchHeaders.cast(value);
+ }
+
return JSC.GetJSPrivateData(ZigType, value.asObjectRef());
}
@@ -2083,6 +2414,12 @@ pub const JSValue = enum(u64) {
pub fn isNull(this: JSValue) bool {
return @enumToInt(this) == 0x2;
}
+ pub fn isEmptyOrUndefinedOrNull(this: JSValue) bool {
+ return switch (@enumToInt(this)) {
+ 0, 0xa, 0x2 => true,
+ else => false,
+ };
+ }
pub fn isUndefinedOrNull(this: JSValue) bool {
return switch (@enumToInt(this)) {
0xa, 0x2 => true,
@@ -2249,6 +2586,10 @@ pub const JSValue = enum(u64) {
return cppFn("getIfPropertyExistsImpl", .{ this, global, ptr, len });
}
+ pub fn getHiddenIfPropertyExistsImpl(this: JSValue, global: *JSGlobalObject, ptr: [*]const u8, len: u32) JSValue {
+ return cppFn("getHiddenIfPropertyExistsImpl", .{ this, global, ptr, len });
+ }
+
pub fn getSymbolDescription(this: JSValue, global: *JSGlobalObject, str: *ZigString) void {
cppFn("getSymbolDescription", .{ this, global, str });
}
@@ -2314,6 +2655,11 @@ pub const JSValue = enum(u64) {
return if (@enumToInt(value) != 0) value else return null;
}
+ pub fn getHidden(this: JSValue, global: *JSGlobalObject, property: []const u8) ?JSValue {
+ const value = getIfPropertyExistsImpl(this, global, property.ptr, @intCast(u32, property.len));
+ return if (@enumToInt(value) != 0) value else return null;
+ }
+
pub fn getTruthy(this: JSValue, global: *JSGlobalObject, property: []const u8) ?JSValue {
if (get(this, global, property)) |prop| {
if (@enumToInt(prop) == 0 or prop.isUndefinedOrNull()) return null;
diff --git a/src/javascript/jsc/bindings/exports.zig b/src/javascript/jsc/bindings/exports.zig
index 8c6cb17c9..d58e45157 100644
--- a/src/javascript/jsc/bindings/exports.zig
+++ b/src/javascript/jsc/bindings/exports.zig
@@ -1695,11 +1695,6 @@ pub const ZigConsoleClient = struct {
response.writeFormat(this, writer_, enable_ansi_colors) catch {};
return;
},
- @field(JSPrivateDataPtr.Tag, @typeName(JSC.WebCore.Headers.RefCountedHeaders)) => {
- var obj = priv_data.as(JSC.WebCore.Headers.RefCountedHeaders);
- obj.leak().writeFormat(this, writer_, enable_ansi_colors) catch {};
- return;
- },
.Request => {
this.printAs(.JSON, Writer, writer_, value, .Object, enable_ansi_colors);
return;
diff --git a/src/javascript/jsc/bindings/header-gen.zig b/src/javascript/jsc/bindings/header-gen.zig
index 612f86215..30467f698 100644
--- a/src/javascript/jsc/bindings/header-gen.zig
+++ b/src/javascript/jsc/bindings/header-gen.zig
@@ -41,6 +41,7 @@ pub fn cTypeLabel(comptime Type: type) ?[]const u8 {
f64 => "double",
f32 => "float",
*anyopaque => "void*",
+ *const anyopaque => "const void*",
[*]bool => "bool*",
[*]usize => "size_t*",
[*]isize => "int*",
diff --git a/src/javascript/jsc/bindings/headers-cpp.h b/src/javascript/jsc/bindings/headers-cpp.h
index ab5dead54..9d0ce2113 100644
--- a/src/javascript/jsc/bindings/headers-cpp.h
+++ b/src/javascript/jsc/bindings/headers-cpp.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1648722142
+//-- AUTOGENERATED FILE -- 1648790662
// clang-format off
#pragma once
@@ -256,8 +256,8 @@ extern "C" const size_t Zig__ConsoleClient_object_align_ = alignof(Zig::ConsoleC
extern "C" const size_t Bun__Timer_object_size_ = sizeof(Bun__Timer);
extern "C" const size_t Bun__Timer_object_align_ = alignof(Bun__Timer);
-const size_t sizes[31] = {sizeof(JSC::JSObject), sizeof(WebCore::DOMURL), sizeof(SystemError), sizeof(JSC::JSCell), sizeof(JSC::JSString), sizeof(Inspector::ScriptArguments), sizeof(JSC::JSModuleLoader), sizeof(JSC::JSModuleRecord), sizeof(JSC::JSPromise), sizeof(JSC::JSInternalPromise), sizeof(JSC::SourceOrigin), sizeof(JSC::SourceCode), sizeof(JSC::JSFunction), sizeof(JSC::JSGlobalObject), sizeof(WTF::URL), sizeof(WTF::String), sizeof(JSC::JSValue), sizeof(JSC::PropertyName), sizeof(JSC::Exception), sizeof(JSC::VM), sizeof(JSC::ThrowScope), sizeof(JSC::CatchScope), sizeof(JSC::CallFrame), sizeof(JSC::Identifier), sizeof(WTF::StringImpl), sizeof(WTF::ExternalStringImpl), sizeof(WTF::StringView), sizeof(Zig::GlobalObject), sizeof(Bun__Readable), sizeof(Bun__Writable), sizeof(Bun__Path)};
+const size_t sizes[32] = {sizeof(JSC::JSObject), sizeof(WebCore::DOMURL), sizeof(WebCore::FetchHeaders), sizeof(SystemError), sizeof(JSC::JSCell), sizeof(JSC::JSString), sizeof(Inspector::ScriptArguments), sizeof(JSC::JSModuleLoader), sizeof(JSC::JSModuleRecord), sizeof(JSC::JSPromise), sizeof(JSC::JSInternalPromise), sizeof(JSC::SourceOrigin), sizeof(JSC::SourceCode), sizeof(JSC::JSFunction), sizeof(JSC::JSGlobalObject), sizeof(WTF::URL), sizeof(WTF::String), sizeof(JSC::JSValue), sizeof(JSC::PropertyName), sizeof(JSC::Exception), sizeof(JSC::VM), sizeof(JSC::ThrowScope), sizeof(JSC::CatchScope), sizeof(JSC::CallFrame), sizeof(JSC::Identifier), sizeof(WTF::StringImpl), sizeof(WTF::ExternalStringImpl), sizeof(WTF::StringView), sizeof(Zig::GlobalObject), sizeof(Bun__Readable), sizeof(Bun__Writable), sizeof(Bun__Path)};
-const char* names[31] = {"JSC__JSObject", "WebCore__DOMURL", "SystemError", "JSC__JSCell", "JSC__JSString", "Inspector__ScriptArguments", "JSC__JSModuleLoader", "JSC__JSModuleRecord", "JSC__JSPromise", "JSC__JSInternalPromise", "JSC__SourceOrigin", "JSC__SourceCode", "JSC__JSFunction", "JSC__JSGlobalObject", "WTF__URL", "WTF__String", "JSC__JSValue", "JSC__PropertyName", "JSC__Exception", "JSC__VM", "JSC__ThrowScope", "JSC__CatchScope", "JSC__CallFrame", "JSC__Identifier", "WTF__StringImpl", "WTF__ExternalStringImpl", "WTF__StringView", "Zig__GlobalObject", "Bun__Readable", "Bun__Writable", "Bun__Path"};
+const char* names[32] = {"JSC__JSObject", "WebCore__DOMURL", "WebCore__FetchHeaders", "SystemError", "JSC__JSCell", "JSC__JSString", "Inspector__ScriptArguments", "JSC__JSModuleLoader", "JSC__JSModuleRecord", "JSC__JSPromise", "JSC__JSInternalPromise", "JSC__SourceOrigin", "JSC__SourceCode", "JSC__JSFunction", "JSC__JSGlobalObject", "WTF__URL", "WTF__String", "JSC__JSValue", "JSC__PropertyName", "JSC__Exception", "JSC__VM", "JSC__ThrowScope", "JSC__CatchScope", "JSC__CallFrame", "JSC__Identifier", "WTF__StringImpl", "WTF__ExternalStringImpl", "WTF__StringView", "Zig__GlobalObject", "Bun__Readable", "Bun__Writable", "Bun__Path"};
-const size_t aligns[31] = {alignof(JSC::JSObject), alignof(WebCore::DOMURL), alignof(SystemError), alignof(JSC::JSCell), alignof(JSC::JSString), alignof(Inspector::ScriptArguments), alignof(JSC::JSModuleLoader), alignof(JSC::JSModuleRecord), alignof(JSC::JSPromise), alignof(JSC::JSInternalPromise), alignof(JSC::SourceOrigin), alignof(JSC::SourceCode), alignof(JSC::JSFunction), alignof(JSC::JSGlobalObject), alignof(WTF::URL), alignof(WTF::String), alignof(JSC::JSValue), alignof(JSC::PropertyName), alignof(JSC::Exception), alignof(JSC::VM), alignof(JSC::ThrowScope), alignof(JSC::CatchScope), alignof(JSC::CallFrame), alignof(JSC::Identifier), alignof(WTF::StringImpl), alignof(WTF::ExternalStringImpl), alignof(WTF::StringView), alignof(Zig::GlobalObject), alignof(Bun__Readable), alignof(Bun__Writable), alignof(Bun__Path)};
+const size_t aligns[32] = {alignof(JSC::JSObject), alignof(WebCore::DOMURL), alignof(WebCore::FetchHeaders), alignof(SystemError), alignof(JSC::JSCell), alignof(JSC::JSString), alignof(Inspector::ScriptArguments), alignof(JSC::JSModuleLoader), alignof(JSC::JSModuleRecord), alignof(JSC::JSPromise), alignof(JSC::JSInternalPromise), alignof(JSC::SourceOrigin), alignof(JSC::SourceCode), alignof(JSC::JSFunction), alignof(JSC::JSGlobalObject), alignof(WTF::URL), alignof(WTF::String), alignof(JSC::JSValue), alignof(JSC::PropertyName), alignof(JSC::Exception), alignof(JSC::VM), alignof(JSC::ThrowScope), alignof(JSC::CatchScope), alignof(JSC::CallFrame), alignof(JSC::Identifier), alignof(WTF::StringImpl), alignof(WTF::ExternalStringImpl), alignof(WTF::StringView), alignof(Zig::GlobalObject), alignof(Bun__Readable), alignof(Bun__Writable), alignof(Bun__Path)};
diff --git a/src/javascript/jsc/bindings/headers-handwritten.h b/src/javascript/jsc/bindings/headers-handwritten.h
index 0c4cc2754..8bfc1a09d 100644
--- a/src/javascript/jsc/bindings/headers-handwritten.h
+++ b/src/javascript/jsc/bindings/headers-handwritten.h
@@ -175,12 +175,15 @@ typedef struct {
uint8_t cell_type;
} Bun__ArrayBuffer;
-#ifdef __cplusplus
-
+#ifndef STRING_POINTER
+#define STRING_POINTER
typedef struct StringPointer {
uint32_t off;
uint32_t len;
} StringPointer;
+#endif
+
+#ifdef __cplusplus
extern "C" ZigErrorCode Zig_ErrorCodeParserError;
diff --git a/src/javascript/jsc/bindings/headers-replacements.zig b/src/javascript/jsc/bindings/headers-replacements.zig
index fd1e7b4e9..c503d3288 100644
--- a/src/javascript/jsc/bindings/headers-replacements.zig
+++ b/src/javascript/jsc/bindings/headers-replacements.zig
@@ -60,3 +60,5 @@ pub const Bun__Readable = bindings.NodeReadableStream;
pub const Bun__Writable = bindings.NodeWritableStream;
pub const Bun__ArrayBuffer = bindings.ArrayBuffer;
pub const struct_WebCore__DOMURL = bindings.DOMURL;
+pub const struct_WebCore__FetchHeaders = bindings.FetchHeaders;
+pub const StringPointer = @import("../../../api/schema.zig").Api.StringPointer;
diff --git a/src/javascript/jsc/bindings/headers.h b/src/javascript/jsc/bindings/headers.h
index d99f24e58..9175274cb 100644
--- a/src/javascript/jsc/bindings/headers.h
+++ b/src/javascript/jsc/bindings/headers.h
@@ -1,5 +1,5 @@
// clang-format: off
-//-- AUTOGENERATED FILE -- 1648722142
+//-- AUTOGENERATED FILE -- 1648790662
#pragma once
#include <stddef.h>
@@ -152,9 +152,10 @@ typedef struct JSC__IteratorPrototype JSC__IteratorPrototype; // JSC::IteratorPr
typedef Bun__Readable Bun__Readable;
typedef bJSC__JSInternalPromise JSC__JSInternalPromise; // JSC::JSInternalPromise
typedef Bun__Writable Bun__Writable;
+typedef struct JSC__MapIteratorPrototype JSC__MapIteratorPrototype; // JSC::MapIteratorPrototype
typedef struct JSC__RegExpPrototype JSC__RegExpPrototype; // JSC::RegExpPrototype
typedef bJSC__CallFrame JSC__CallFrame; // JSC::CallFrame
-typedef struct JSC__MapIteratorPrototype JSC__MapIteratorPrototype; // JSC::MapIteratorPrototype
+typedef struct WebCore__FetchHeaders WebCore__FetchHeaders; // WebCore::FetchHeaders
typedef bWTF__StringView WTF__StringView; // WTF::StringView
typedef bJSC__ThrowScope JSC__ThrowScope; // JSC::ThrowScope
typedef bWTF__StringImpl WTF__StringImpl; // WTF::StringImpl
@@ -230,6 +231,7 @@ class JSMicrotaskCallback;
}
namespace WebCore {
class DOMURL;
+class FetchHeaders;
}
namespace Inspector {
class ScriptArguments;
@@ -287,6 +289,7 @@ using WTF__StringView = WTF::StringView;
using WTF__ExternalStringImpl = WTF::ExternalStringImpl;
using Zig__JSMicrotaskCallback = Zig::JSMicrotaskCallback;
using WebCore__DOMURL = WebCore::DOMURL;
+using WebCore__FetchHeaders = WebCore::FetchHeaders;
using Inspector__ScriptArguments = Inspector::ScriptArguments;
#endif
@@ -306,9 +309,27 @@ CPP_DECL JSC__JSValue ZigString__toExternalValue(const ZigString* arg0, JSC__JSG
CPP_DECL JSC__JSValue ZigString__toExternalValueWithCallback(const ZigString* arg0, JSC__JSGlobalObject* arg1, void (*ArgFn2)(void* arg0, void* arg1, size_t arg2));
CPP_DECL JSC__JSValue ZigString__toValue(const ZigString* arg0, JSC__JSGlobalObject* arg1);
CPP_DECL JSC__JSValue ZigString__toValueGC(const ZigString* arg0, JSC__JSGlobalObject* arg1);
-CPP_DECL WebCore__DOMURL* WebCore__DOMURL__cast(JSC__JSValue JSValue0);
+CPP_DECL WebCore__DOMURL* WebCore__DOMURL__cast_(JSC__JSValue JSValue0, JSC__VM* arg1);
CPP_DECL void WebCore__DOMURL__href_(WebCore__DOMURL* arg0, ZigString* arg1);
CPP_DECL void WebCore__DOMURL__pathname_(WebCore__DOMURL* arg0, ZigString* arg1);
+CPP_DECL void WebCore__FetchHeaders__append(WebCore__FetchHeaders* arg0, const ZigString* arg1, const ZigString* arg2);
+CPP_DECL WebCore__FetchHeaders* WebCore__FetchHeaders__cast_(JSC__JSValue JSValue0, JSC__VM* arg1);
+CPP_DECL JSC__JSValue WebCore__FetchHeaders__clone(WebCore__FetchHeaders* arg0, JSC__JSGlobalObject* arg1);
+CPP_DECL WebCore__FetchHeaders* WebCore__FetchHeaders__cloneThis(WebCore__FetchHeaders* arg0);
+CPP_DECL void WebCore__FetchHeaders__copyTo(WebCore__FetchHeaders* arg0, StringPointer* arg1, StringPointer* arg2, unsigned char* arg3);
+CPP_DECL void WebCore__FetchHeaders__count(WebCore__FetchHeaders* arg0, uint32_t* arg1, uint32_t* arg2);
+CPP_DECL WebCore__FetchHeaders* WebCore__FetchHeaders__createFromJS(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1);
+CPP_DECL JSC__JSValue WebCore__FetchHeaders__createFromPicoHeaders_(JSC__JSGlobalObject* arg0, const void* arg1);
+CPP_DECL JSC__JSValue WebCore__FetchHeaders__createFromUWS(JSC__JSGlobalObject* arg0, void* arg1);
+CPP_DECL JSC__JSValue WebCore__FetchHeaders__createValue(JSC__JSGlobalObject* arg0, StringPointer* arg1, StringPointer* arg2, const ZigString* arg3, uint32_t arg4);
+CPP_DECL void WebCore__FetchHeaders__deref(WebCore__FetchHeaders* arg0);
+CPP_DECL void WebCore__FetchHeaders__get_(WebCore__FetchHeaders* arg0, const ZigString* arg1, ZigString* arg2);
+CPP_DECL bool WebCore__FetchHeaders__has(WebCore__FetchHeaders* arg0, const ZigString* arg1);
+CPP_DECL uint32_t WebCore__FetchHeaders__keyCount(WebCore__FetchHeaders* arg0);
+CPP_DECL void WebCore__FetchHeaders__put_(WebCore__FetchHeaders* arg0, const ZigString* arg1, const ZigString* arg2);
+CPP_DECL void WebCore__FetchHeaders__remove(WebCore__FetchHeaders* arg0, const ZigString* arg1);
+CPP_DECL JSC__JSValue WebCore__FetchHeaders__toJS(WebCore__FetchHeaders* arg0, JSC__JSGlobalObject* arg1);
+CPP_DECL void WebCore__FetchHeaders__toUWSResponse(WebCore__FetchHeaders* arg0, bool arg1, void* arg2);
CPP_DECL JSC__JSValue SystemError__toErrorInstance(const SystemError* arg0, JSC__JSGlobalObject* arg1);
#pragma mark - JSC::JSCell
diff --git a/src/javascript/jsc/bindings/headers.zig b/src/javascript/jsc/bindings/headers.zig
index e82ca8e70..2eb6ad46f 100644
--- a/src/javascript/jsc/bindings/headers.zig
+++ b/src/javascript/jsc/bindings/headers.zig
@@ -60,6 +60,8 @@ pub const Bun__Readable = bindings.NodeReadableStream;
pub const Bun__Writable = bindings.NodeWritableStream;
pub const Bun__ArrayBuffer = bindings.ArrayBuffer;
pub const struct_WebCore__DOMURL = bindings.DOMURL;
+pub const struct_WebCore__FetchHeaders = bindings.FetchHeaders;
+pub const StringPointer = @import("../../../api/schema.zig").Api.StringPointer;
// GENERATED CODE - DO NOT MODIFY BY HAND
pub const ptrdiff_t = c_long;
@@ -106,10 +108,12 @@ pub const WTF__URL = bWTF__URL;
pub const JSC__IteratorPrototype = struct_JSC__IteratorPrototype;
pub const JSC__JSInternalPromise = bJSC__JSInternalPromise;
+pub const JSC__MapIteratorPrototype = struct_JSC__MapIteratorPrototype;
+
pub const JSC__RegExpPrototype = struct_JSC__RegExpPrototype;
pub const JSC__CallFrame = bJSC__CallFrame;
-pub const JSC__MapIteratorPrototype = struct_JSC__MapIteratorPrototype;
+pub const WebCore__FetchHeaders = struct_WebCore__FetchHeaders;
pub const WTF__StringView = bWTF__StringView;
pub const JSC__ThrowScope = bJSC__ThrowScope;
pub const WTF__StringImpl = bWTF__StringImpl;
@@ -147,9 +151,27 @@ pub extern fn ZigString__toExternalValue(arg0: [*c]const ZigString, arg1: [*c]JS
pub extern fn ZigString__toExternalValueWithCallback(arg0: [*c]const ZigString, arg1: [*c]JSC__JSGlobalObject, ArgFn2: ?fn (?*anyopaque, ?*anyopaque, usize) callconv(.C) void) JSC__JSValue;
pub extern fn ZigString__toValue(arg0: [*c]const ZigString, arg1: [*c]JSC__JSGlobalObject) JSC__JSValue;
pub extern fn ZigString__toValueGC(arg0: [*c]const ZigString, arg1: [*c]JSC__JSGlobalObject) JSC__JSValue;
-pub extern fn WebCore__DOMURL__cast(JSValue0: JSC__JSValue) ?*WebCore__DOMURL;
+pub extern fn WebCore__DOMURL__cast_(JSValue0: JSC__JSValue, arg1: [*c]JSC__VM) ?*WebCore__DOMURL;
pub extern fn WebCore__DOMURL__href_(arg0: ?*WebCore__DOMURL, arg1: [*c]ZigString) void;
pub extern fn WebCore__DOMURL__pathname_(arg0: ?*WebCore__DOMURL, arg1: [*c]ZigString) void;
+pub extern fn WebCore__FetchHeaders__append(arg0: ?*WebCore__FetchHeaders, arg1: [*c]const ZigString, arg2: [*c]const ZigString) void;
+pub extern fn WebCore__FetchHeaders__cast_(JSValue0: JSC__JSValue, arg1: [*c]JSC__VM) ?*WebCore__FetchHeaders;
+pub extern fn WebCore__FetchHeaders__clone(arg0: ?*WebCore__FetchHeaders, arg1: [*c]JSC__JSGlobalObject) JSC__JSValue;
+pub extern fn WebCore__FetchHeaders__cloneThis(arg0: ?*WebCore__FetchHeaders) ?*WebCore__FetchHeaders;
+pub extern fn WebCore__FetchHeaders__copyTo(arg0: ?*WebCore__FetchHeaders, arg1: [*c]StringPointer, arg2: [*c]StringPointer, arg3: [*c]u8) void;
+pub extern fn WebCore__FetchHeaders__count(arg0: ?*WebCore__FetchHeaders, arg1: [*c]u32, arg2: [*c]u32) void;
+pub extern fn WebCore__FetchHeaders__createFromJS(arg0: [*c]JSC__JSGlobalObject, JSValue1: JSC__JSValue) ?*WebCore__FetchHeaders;
+pub extern fn WebCore__FetchHeaders__createFromPicoHeaders_(arg0: [*c]JSC__JSGlobalObject, arg1: ?*const anyopaque) JSC__JSValue;
+pub extern fn WebCore__FetchHeaders__createFromUWS(arg0: [*c]JSC__JSGlobalObject, arg1: ?*anyopaque) JSC__JSValue;
+pub extern fn WebCore__FetchHeaders__createValue(arg0: [*c]JSC__JSGlobalObject, arg1: [*c]StringPointer, arg2: [*c]StringPointer, arg3: [*c]const ZigString, arg4: u32) JSC__JSValue;
+pub extern fn WebCore__FetchHeaders__deref(arg0: ?*WebCore__FetchHeaders) void;
+pub extern fn WebCore__FetchHeaders__get_(arg0: ?*WebCore__FetchHeaders, arg1: [*c]const ZigString, arg2: [*c]ZigString) void;
+pub extern fn WebCore__FetchHeaders__has(arg0: ?*WebCore__FetchHeaders, arg1: [*c]const ZigString) bool;
+pub extern fn WebCore__FetchHeaders__keyCount(arg0: ?*WebCore__FetchHeaders) u32;
+pub extern fn WebCore__FetchHeaders__put_(arg0: ?*WebCore__FetchHeaders, arg1: [*c]const ZigString, arg2: [*c]const ZigString) void;
+pub extern fn WebCore__FetchHeaders__remove(arg0: ?*WebCore__FetchHeaders, arg1: [*c]const ZigString) void;
+pub extern fn WebCore__FetchHeaders__toJS(arg0: ?*WebCore__FetchHeaders, arg1: [*c]JSC__JSGlobalObject) JSC__JSValue;
+pub extern fn WebCore__FetchHeaders__toUWSResponse(arg0: ?*WebCore__FetchHeaders, arg1: bool, arg2: ?*anyopaque) void;
pub extern fn SystemError__toErrorInstance(arg0: [*c]const SystemError, arg1: [*c]JSC__JSGlobalObject) JSC__JSValue;
pub extern fn JSC__JSCell__getObject(arg0: [*c]JSC__JSCell) [*c]JSC__JSObject;
pub extern fn JSC__JSCell__getString(arg0: [*c]JSC__JSCell, arg1: [*c]JSC__JSGlobalObject) bWTF__String;
diff --git a/src/javascript/jsc/bindings/helpers.h b/src/javascript/jsc/bindings/helpers.h
index 79c9a7ace..e4ceb5696 100644
--- a/src/javascript/jsc/bindings/helpers.h
+++ b/src/javascript/jsc/bindings/helpers.h
@@ -125,6 +125,36 @@ static const WTF::String toString(ZigString str)
reinterpret_cast<const UChar*>(untag(str.ptr)), str.len));
}
+static const WTF::String toString(ZigString str, StringPointer ptr)
+{
+ if (str.len == 0 || str.ptr == nullptr || ptr.len == 0) {
+ return WTF::String();
+ }
+ if (UNLIKELY(isTaggedUTF8Ptr(str.ptr))) {
+ return WTF::String::fromUTF8(&untag(str.ptr)[ptr.off], ptr.len);
+ }
+
+ return !isTaggedUTF16Ptr(str.ptr)
+ ? WTF::String(WTF::StringImpl::createWithoutCopying(&untag(str.ptr)[ptr.off], ptr.len))
+ : WTF::String(WTF::StringImpl::createWithoutCopying(
+ &reinterpret_cast<const UChar*>(untag(str.ptr))[ptr.off], ptr.len));
+}
+
+static const WTF::String toStringCopy(ZigString str, StringPointer ptr)
+{
+ if (str.len == 0 || str.ptr == nullptr || ptr.len == 0) {
+ return WTF::String();
+ }
+ if (UNLIKELY(isTaggedUTF8Ptr(str.ptr))) {
+ return WTF::String::fromUTF8(&untag(str.ptr)[ptr.off], ptr.len);
+ }
+
+ return !isTaggedUTF16Ptr(str.ptr)
+ ? WTF::String(WTF::StringImpl::create(&untag(str.ptr)[ptr.off], ptr.len))
+ : WTF::String(WTF::StringImpl::create(
+ &reinterpret_cast<const UChar*>(untag(str.ptr))[ptr.off], ptr.len));
+}
+
static const WTF::String toStringCopy(ZigString str)
{
if (str.len == 0 || str.ptr == nullptr) {
diff --git a/src/javascript/jsc/bindings/webcore/DOMClientIsoSubspaces.h b/src/javascript/jsc/bindings/webcore/DOMClientIsoSubspaces.h
index 3b496536b..ad1b6a32b 100644
--- a/src/javascript/jsc/bindings/webcore/DOMClientIsoSubspaces.h
+++ b/src/javascript/jsc/bindings/webcore/DOMClientIsoSubspaces.h
@@ -101,8 +101,8 @@ public:
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForFileSystemDirectoryReader;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForFileSystemEntry;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForFileSystemFileEntry;
- // std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForFetchHeaders;
- // std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForFetchHeadersIterator;
+ std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForFetchHeaders;
+ std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForFetchHeadersIterator;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForFetchRequest;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForFetchResponse;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForFileSystemDirectoryHandle;
diff --git a/src/javascript/jsc/bindings/webcore/DOMIsoSubspaces.h b/src/javascript/jsc/bindings/webcore/DOMIsoSubspaces.h
index bb4cc3327..75d91c0a2 100644
--- a/src/javascript/jsc/bindings/webcore/DOMIsoSubspaces.h
+++ b/src/javascript/jsc/bindings/webcore/DOMIsoSubspaces.h
@@ -89,8 +89,8 @@ public:
// std::unique_ptr<IsoSubspace> m_subspaceForFileSystemDirectoryReader;
// std::unique_ptr<IsoSubspace> m_subspaceForFileSystemEntry;
// std::unique_ptr<IsoSubspace> m_subspaceForFileSystemFileEntry;
- // std::unique_ptr<IsoSubspace> m_subspaceForFetchHeaders;
- // std::unique_ptr<IsoSubspace> m_subspaceForFetchHeadersIterator;
+ std::unique_ptr<IsoSubspace> m_subspaceForFetchHeaders;
+ std::unique_ptr<IsoSubspace> m_subspaceForFetchHeadersIterator;
// std::unique_ptr<IsoSubspace> m_subspaceForFetchRequest;
// std::unique_ptr<IsoSubspace> m_subspaceForFetchResponse;
// std::unique_ptr<IsoSubspace> m_subspaceForFileSystemDirectoryHandle;
diff --git a/src/javascript/jsc/bindings/webcore/FetchHeaders.cpp b/src/javascript/jsc/bindings/webcore/FetchHeaders.cpp
new file mode 100644
index 000000000..26af08f1a
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/FetchHeaders.cpp
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2016 Canon Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted, provided that the following conditions
+ * are required to be met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Canon Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FetchHeaders.h"
+
+#include "HTTPParsers.h"
+
+namespace WebCore {
+
+// https://fetch.spec.whatwg.org/#concept-headers-remove-privileged-no-cors-request-headers
+static void removePrivilegedNoCORSRequestHeaders(HTTPHeaderMap& headers)
+{
+ headers.remove(HTTPHeaderName::Range);
+}
+
+static ExceptionOr<bool> canWriteHeader(const String& name, const String& value, const String& combinedValue, FetchHeaders::Guard guard)
+{
+ if (!isValidHTTPToken(name))
+ return Exception { TypeError, makeString("Invalid header name: '", name, "'") };
+ ASSERT(value.isEmpty() || (!isHTTPSpace(value[0]) && !isHTTPSpace(value[value.length() - 1])));
+ if (!isValidHTTPHeaderValue((value)))
+ return Exception { TypeError, makeString("Header '", name, "' has invalid value: '", value, "'") };
+ if (guard == FetchHeaders::Guard::Immutable)
+ return Exception { TypeError, "Headers object's guard is 'immutable'"_s };
+ if (guard == FetchHeaders::Guard::Request && isForbiddenHeaderName(name))
+ return false;
+ if (guard == FetchHeaders::Guard::RequestNoCors && !combinedValue.isEmpty() && !isSimpleHeader(name, combinedValue))
+ return false;
+ if (guard == FetchHeaders::Guard::Response && isForbiddenResponseHeaderName(name))
+ return false;
+ return true;
+}
+
+static ExceptionOr<void> appendToHeaderMap(const String& name, const String& value, HTTPHeaderMap& headers, FetchHeaders::Guard guard)
+{
+ String normalizedValue = stripLeadingAndTrailingHTTPSpaces(value);
+ String combinedValue = normalizedValue;
+ if (headers.contains(name))
+ combinedValue = makeString(headers.get(name), ", ", normalizedValue);
+ auto canWriteResult = canWriteHeader(name, normalizedValue, combinedValue, guard);
+ if (canWriteResult.hasException())
+ return canWriteResult.releaseException();
+ if (!canWriteResult.releaseReturnValue())
+ return { };
+ headers.set(name, combinedValue);
+
+ if (guard == FetchHeaders::Guard::RequestNoCors)
+ removePrivilegedNoCORSRequestHeaders(headers);
+
+ return { };
+}
+
+static ExceptionOr<void> appendToHeaderMap(const HTTPHeaderMap::HTTPHeaderMapConstIterator::KeyValue& header, HTTPHeaderMap& headers, FetchHeaders::Guard guard)
+{
+ String normalizedValue = stripLeadingAndTrailingHTTPSpaces(header.value);
+ auto canWriteResult = canWriteHeader(header.key, normalizedValue, header.value, guard);
+ if (canWriteResult.hasException())
+ return canWriteResult.releaseException();
+ if (!canWriteResult.releaseReturnValue())
+ return { };
+ if (header.keyAsHTTPHeaderName)
+ headers.add(header.keyAsHTTPHeaderName.value(), header.value);
+ else
+ headers.add(header.key, header.value);
+
+ if (guard == FetchHeaders::Guard::RequestNoCors)
+ removePrivilegedNoCORSRequestHeaders(headers);
+
+ return { };
+}
+
+// https://fetch.spec.whatwg.org/#concept-headers-fill
+static ExceptionOr<void> fillHeaderMap(HTTPHeaderMap& headers, const FetchHeaders::Init& headersInit, FetchHeaders::Guard guard)
+{
+ if (std::holds_alternative<Vector<Vector<String>>>(headersInit)) {
+ auto& sequence = std::get<Vector<Vector<String>>>(headersInit);
+ for (auto& header : sequence) {
+ if (header.size() != 2)
+ return Exception { TypeError, "Header sub-sequence must contain exactly two items"_s };
+ auto result = appendToHeaderMap(header[0], header[1], headers, guard);
+ if (result.hasException())
+ return result.releaseException();
+ }
+ } else {
+ auto& record = std::get<Vector<KeyValuePair<String, String>>>(headersInit);
+ for (auto& header : record) {
+ auto result = appendToHeaderMap(header.key, header.value, headers, guard);
+ if (result.hasException())
+ return result.releaseException();
+ }
+ }
+
+ return { };
+}
+
+ExceptionOr<Ref<FetchHeaders>> FetchHeaders::create(std::optional<Init>&& headersInit)
+{
+ HTTPHeaderMap headers;
+
+ if (headersInit) {
+ auto result = fillHeaderMap(headers, *headersInit, Guard::None);
+ if (result.hasException())
+ return result.releaseException();
+ }
+
+ return adoptRef(*new FetchHeaders { Guard::None, WTFMove(headers) });
+}
+
+ExceptionOr<void> FetchHeaders::fill(const Init& headerInit)
+{
+ return fillHeaderMap(m_headers, headerInit, m_guard);
+}
+
+ExceptionOr<void> FetchHeaders::fill(const FetchHeaders& otherHeaders)
+{
+ for (auto& header : otherHeaders.m_headers) {
+ auto result = appendToHeaderMap(header, m_headers, m_guard);
+ if (result.hasException())
+ return result.releaseException();
+ }
+
+ return { };
+}
+
+ExceptionOr<void> FetchHeaders::append(const String& name, const String& value)
+{
+ return appendToHeaderMap(name, value, m_headers, m_guard);
+}
+
+// https://fetch.spec.whatwg.org/#dom-headers-delete
+ExceptionOr<void> FetchHeaders::remove(const String& name)
+{
+ if (!isValidHTTPToken(name))
+ return Exception { TypeError, makeString("Invalid header name: '", name, "'") };
+ if (m_guard == FetchHeaders::Guard::Immutable)
+ return Exception { TypeError, "Headers object's guard is 'immutable'"_s };
+ if (m_guard == FetchHeaders::Guard::Request && isForbiddenHeaderName(name))
+ return { };
+ if (m_guard == FetchHeaders::Guard::RequestNoCors && !isNoCORSSafelistedRequestHeaderName(name) && !isPriviledgedNoCORSRequestHeaderName(name))
+ return { };
+ if (m_guard == FetchHeaders::Guard::Response && isForbiddenResponseHeaderName(name))
+ return { };
+
+ m_headers.remove(name);
+
+ if (m_guard == FetchHeaders::Guard::RequestNoCors)
+ removePrivilegedNoCORSRequestHeaders(m_headers);
+
+ return { };
+}
+
+ExceptionOr<String> FetchHeaders::get(const String& name) const
+{
+ if (!isValidHTTPToken(name))
+ return Exception { TypeError, makeString("Invalid header name: '", name, "'") };
+ return m_headers.get(name);
+}
+
+ExceptionOr<bool> FetchHeaders::has(const String& name) const
+{
+ if (!isValidHTTPToken(name))
+ return Exception { TypeError, makeString("Invalid header name: '", name, "'") };
+ return m_headers.contains(name);
+}
+
+ExceptionOr<void> FetchHeaders::set(const String& name, const String& value)
+{
+ String normalizedValue = stripLeadingAndTrailingHTTPSpaces(value);
+ auto canWriteResult = canWriteHeader(name, normalizedValue, normalizedValue, m_guard);
+ if (canWriteResult.hasException())
+ return canWriteResult.releaseException();
+ if (!canWriteResult.releaseReturnValue())
+ return { };
+
+ m_headers.set(name, normalizedValue);
+
+ if (m_guard == FetchHeaders::Guard::RequestNoCors)
+ removePrivilegedNoCORSRequestHeaders(m_headers);
+
+ return { };
+}
+
+void FetchHeaders::filterAndFill(const HTTPHeaderMap& headers, Guard guard)
+{
+ for (auto& header : headers) {
+ String normalizedValue = stripLeadingAndTrailingHTTPSpaces(header.value);
+ auto canWriteResult = canWriteHeader(header.key, normalizedValue, header.value, guard);
+ if (canWriteResult.hasException())
+ continue;
+ if (!canWriteResult.releaseReturnValue())
+ continue;
+ if (header.keyAsHTTPHeaderName)
+ m_headers.add(header.keyAsHTTPHeaderName.value(), header.value);
+ else
+ m_headers.add(header.key, header.value);
+ }
+}
+
+std::optional<KeyValuePair<String, String>> FetchHeaders::Iterator::next()
+{
+ while (m_currentIndex < m_keys.size()) {
+ auto key = m_keys[m_currentIndex++];
+ auto value = m_headers->m_headers.get(key);
+ if (!value.isNull())
+ return KeyValuePair<String, String> { WTFMove(key), WTFMove(value) };
+ }
+ return std::nullopt;
+}
+
+FetchHeaders::Iterator::Iterator(FetchHeaders& headers)
+ : m_headers(headers)
+{
+ m_keys.reserveInitialCapacity(headers.m_headers.size());
+ for (auto& header : headers.m_headers)
+ m_keys.uncheckedAppend(header.key.convertToASCIILowercase());
+ std::sort(m_keys.begin(), m_keys.end(), WTF::codePointCompareLessThan);
+}
+
+} // namespace WebCore
diff --git a/src/javascript/jsc/bindings/webcore/FetchHeaders.h b/src/javascript/jsc/bindings/webcore/FetchHeaders.h
new file mode 100644
index 000000000..c6a74880f
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/FetchHeaders.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2016 Canon Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted, provided that the following conditions
+ * are required to be met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Canon Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "ExceptionOr.h"
+#include "HTTPHeaderMap.h"
+#include <variant>
+#include <wtf/HashTraits.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class FetchHeaders : public RefCounted<FetchHeaders> {
+public:
+ enum class Guard {
+ None,
+ Immutable,
+ Request,
+ RequestNoCors,
+ Response
+ };
+
+ using Init = std::variant<Vector<Vector<String>>, Vector<KeyValuePair<String, String>>>;
+ static ExceptionOr<Ref<FetchHeaders>> create(std::optional<Init>&&);
+
+ static Ref<FetchHeaders> create(Guard guard = Guard::None, HTTPHeaderMap&& headers = {}) { return adoptRef(*new FetchHeaders { guard, WTFMove(headers) }); }
+ static Ref<FetchHeaders> create(const FetchHeaders& headers) { return adoptRef(*new FetchHeaders { headers }); }
+
+ ExceptionOr<void> append(const String& name, const String& value);
+ ExceptionOr<void> remove(const String&);
+ ExceptionOr<String> get(const String&) const;
+ ExceptionOr<bool> has(const String&) const;
+ ExceptionOr<void> set(const String& name, const String& value);
+
+ ExceptionOr<void> fill(const Init&);
+ ExceptionOr<void> fill(const FetchHeaders&);
+ void filterAndFill(const HTTPHeaderMap&, Guard);
+
+ inline uint32_t size()
+ {
+ return m_headers.size();
+ }
+
+ String fastGet(HTTPHeaderName name) const { return m_headers.get(name); }
+ bool fastHas(HTTPHeaderName name) const { return m_headers.contains(name); }
+ void fastSet(HTTPHeaderName name, const String& value) { m_headers.set(name, value); }
+
+ class Iterator {
+ public:
+ explicit Iterator(FetchHeaders&);
+ std::optional<KeyValuePair<String, String>> next();
+
+ private:
+ Ref<FetchHeaders> m_headers;
+ size_t m_currentIndex { 0 };
+ Vector<String> m_keys;
+ };
+ Iterator createIterator() { return Iterator { *this }; }
+
+ void setInternalHeaders(HTTPHeaderMap&& headers) { m_headers = WTFMove(headers); }
+ const HTTPHeaderMap& internalHeaders() const { return m_headers; }
+
+ void setGuard(Guard);
+ Guard guard() const { return m_guard; }
+
+private:
+ FetchHeaders(Guard, HTTPHeaderMap&&);
+ explicit FetchHeaders(const FetchHeaders&);
+
+ Guard m_guard;
+ HTTPHeaderMap m_headers;
+};
+
+inline FetchHeaders::FetchHeaders(Guard guard, HTTPHeaderMap&& headers)
+ : m_guard(guard)
+ , m_headers(WTFMove(headers))
+{
+}
+
+inline FetchHeaders::FetchHeaders(const FetchHeaders& other)
+ : RefCounted<FetchHeaders>()
+ , m_guard(other.m_guard)
+ , m_headers(other.m_headers)
+{
+}
+
+inline void FetchHeaders::setGuard(Guard guard)
+{
+ ASSERT(!m_headers.size());
+ m_guard = guard;
+}
+
+} // namespace WebCore
+
+namespace WTF {
+
+template<> struct EnumTraits<WebCore::FetchHeaders::Guard> {
+ using values = EnumValues<
+ WebCore::FetchHeaders::Guard,
+ WebCore::FetchHeaders::Guard::None,
+ WebCore::FetchHeaders::Guard::Immutable,
+ WebCore::FetchHeaders::Guard::Request,
+ WebCore::FetchHeaders::Guard::RequestNoCors,
+ WebCore::FetchHeaders::Guard::Response>;
+};
+
+}
diff --git a/src/javascript/jsc/bindings/webcore/FetchHeaders.idl b/src/javascript/jsc/bindings/webcore/FetchHeaders.idl
new file mode 100644
index 000000000..daa0ebb8e
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/FetchHeaders.idl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 Canon Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted, provided that the following conditions
+ * are required to be met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Canon Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+typedef (sequence<sequence<ByteString>> or record<ByteString, ByteString>) HeadersInit;
+
+[
+ Exposed=(Window,Worker),
+ InterfaceName=Headers,
+] interface FetchHeaders {
+ constructor(optional HeadersInit init);
+
+ undefined append(ByteString name, ByteString value);
+ [ImplementedAs=remove] undefined delete(ByteString name);
+ ByteString? get(ByteString name);
+ boolean has(ByteString name);
+ undefined set(ByteString name, ByteString value);
+
+ iterable<ByteString, ByteString>;
+};
diff --git a/src/javascript/jsc/bindings/webcore/HTTPHeaderField.cpp b/src/javascript/jsc/bindings/webcore/HTTPHeaderField.cpp
new file mode 100644
index 000000000..a4d101bdd
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/HTTPHeaderField.cpp
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "HTTPHeaderField.h"
+
+namespace WebCore {
+
+namespace RFC7230 {
+
+bool isTokenCharacter(UChar c)
+{
+ return isASCIIAlpha(c) || isASCIIDigit(c)
+ || c == '!' || c == '#' || c == '$'
+ || c == '%' || c == '&' || c == '\''
+ || c == '*' || c == '+' || c == '-'
+ || c == '.' || c == '^' || c == '_'
+ || c == '`' || c == '|' || c == '~';
+}
+
+bool isDelimiter(UChar c)
+{
+ return c == '(' || c == ')' || c == ','
+ || c == '/' || c == ':' || c == ';'
+ || c == '<' || c == '=' || c == '>'
+ || c == '?' || c == '@' || c == '['
+ || c == '\\' || c == ']' || c == '{'
+ || c == '}' || c == '"';
+}
+
+static bool isVisibleCharacter(UChar c)
+{
+ return isTokenCharacter(c) || isDelimiter(c);
+}
+
+bool isWhitespace(UChar c)
+{
+ return c == ' ' || c == '\t';
+}
+
+template<size_t min, size_t max>
+static bool isInRange(UChar c)
+{
+ return c >= min && c <= max;
+}
+
+static bool isOBSText(UChar c)
+{
+ return isInRange<0x80, 0xFF>(c);
+}
+
+static bool isQuotedTextCharacter(UChar c)
+{
+ return isWhitespace(c)
+ || c == 0x21
+ || isInRange<0x23, 0x5B>(c)
+ || isInRange<0x5D, 0x7E>(c)
+ || isOBSText(c);
+}
+
+bool isQuotedPairSecondOctet(UChar c)
+{
+ return isWhitespace(c)
+ || isVisibleCharacter(c)
+ || isOBSText(c);
+}
+
+bool isCommentText(UChar c)
+{
+ return isWhitespace(c)
+ || isInRange<0x21, 0x27>(c)
+ || isInRange<0x2A, 0x5B>(c)
+ || isInRange<0x5D, 0x7E>(c)
+ || isOBSText(c);
+}
+
+static bool isValidName(StringView name)
+{
+ if (!name.length())
+ return false;
+ for (size_t i = 0; i < name.length(); ++i) {
+ if (!isTokenCharacter(name[i]))
+ return false;
+ }
+ return true;
+}
+
+static bool isValidValue(StringView value)
+{
+ enum class State {
+ OptionalWhitespace,
+ Token,
+ QuotedString,
+ Comment,
+ };
+ State state = State::OptionalWhitespace;
+ size_t commentDepth = 0;
+ bool hadNonWhitespace = false;
+
+ for (size_t i = 0; i < value.length(); ++i) {
+ UChar c = value[i];
+ switch (state) {
+ case State::OptionalWhitespace:
+ if (isWhitespace(c))
+ continue;
+ hadNonWhitespace = true;
+ if (isTokenCharacter(c)) {
+ state = State::Token;
+ continue;
+ }
+ if (c == '"') {
+ state = State::QuotedString;
+ continue;
+ }
+ if (c == '(') {
+ ASSERT(!commentDepth);
+ ++commentDepth;
+ state = State::Comment;
+ continue;
+ }
+ return false;
+
+ case State::Token:
+ if (isTokenCharacter(c))
+ continue;
+ state = State::OptionalWhitespace;
+ continue;
+ case State::QuotedString:
+ if (c == '"') {
+ state = State::OptionalWhitespace;
+ continue;
+ }
+ if (c == '\\') {
+ ++i;
+ if (i == value.length())
+ return false;
+ if (!isQuotedPairSecondOctet(value[i]))
+ return false;
+ continue;
+ }
+ if (!isQuotedTextCharacter(c))
+ return false;
+ continue;
+ case State::Comment:
+ if (c == '(') {
+ ++commentDepth;
+ continue;
+ }
+ if (c == ')') {
+ --commentDepth;
+ if (!commentDepth)
+ state = State::OptionalWhitespace;
+ continue;
+ }
+ if (c == '\\') {
+ ++i;
+ if (i == value.length())
+ return false;
+ if (!isQuotedPairSecondOctet(value[i]))
+ return false;
+ continue;
+ }
+ if (!isCommentText(c))
+ return false;
+ continue;
+ }
+ }
+
+ switch (state) {
+ case State::OptionalWhitespace:
+ case State::Token:
+ return hadNonWhitespace;
+ case State::QuotedString:
+ case State::Comment:
+ // Unclosed comments or quotes are invalid values.
+ break;
+ }
+ return false;
+}
+
+} // namespace RFC7230
+
+std::optional<HTTPHeaderField> HTTPHeaderField::create(String&& unparsedName, String&& unparsedValue)
+{
+ StringView strippedName = StringView(unparsedName).stripLeadingAndTrailingMatchedCharacters(RFC7230::isWhitespace);
+ StringView strippedValue = StringView(unparsedValue).stripLeadingAndTrailingMatchedCharacters(RFC7230::isWhitespace);
+ if (!RFC7230::isValidName(strippedName) || !RFC7230::isValidValue(strippedValue))
+ return std::nullopt;
+
+ String name = strippedName.length() == unparsedName.length() ? WTFMove(unparsedName) : strippedName.toString();
+ String value = strippedValue.length() == unparsedValue.length() ? WTFMove(unparsedValue) : strippedValue.toString();
+ return {{ WTFMove(name), WTFMove(value) }};
+}
+
+}
diff --git a/src/javascript/jsc/bindings/webcore/HTTPHeaderField.h b/src/javascript/jsc/bindings/webcore/HTTPHeaderField.h
new file mode 100644
index 000000000..c5fbc1b43
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/HTTPHeaderField.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class WEBCORE_EXPORT HTTPHeaderField {
+public:
+ static std::optional<HTTPHeaderField> create(String&& name, String&& value);
+
+ const String& name() const { return m_name; }
+ const String& value() const { return m_value; }
+
+ template<class Encoder> void encode(Encoder&) const;
+ template<class Decoder> static std::optional<HTTPHeaderField> decode(Decoder&);
+
+private:
+ HTTPHeaderField(String&& name, String&& value)
+ : m_name(WTFMove(name))
+ , m_value(WTFMove(value))
+ { }
+ String m_name;
+ String m_value;
+};
+
+template<class Encoder>
+void HTTPHeaderField::encode(Encoder& encoder) const
+{
+ encoder << m_name;
+ encoder << m_value;
+}
+
+template<class Decoder>
+std::optional<HTTPHeaderField> HTTPHeaderField::decode(Decoder& decoder)
+{
+ std::optional<String> name;
+ decoder >> name;
+ if (!name)
+ return std::nullopt;
+
+ std::optional<String> value;
+ decoder >> value;
+ if (!value)
+ return std::nullopt;
+
+ return {{ WTFMove(*name), WTFMove(*value) }};
+}
+
+namespace RFC7230 {
+bool isTokenCharacter(UChar);
+bool isWhitespace(UChar);
+bool isCommentText(UChar);
+bool isQuotedPairSecondOctet(UChar);
+bool isDelimiter(UChar);
+} // namespace RFC7230
+
+} // namespace WebCore
diff --git a/src/javascript/jsc/bindings/webcore/HTTPHeaderMap.cpp b/src/javascript/jsc/bindings/webcore/HTTPHeaderMap.cpp
new file mode 100644
index 000000000..bd516cf6c
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/HTTPHeaderMap.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "HTTPHeaderMap.h"
+
+#include <utility>
+#include <wtf/CrossThreadCopier.h>
+#include <wtf/text/StringView.h>
+
+namespace WebCore {
+
+HTTPHeaderMap::HTTPHeaderMap()
+{
+}
+
+HTTPHeaderMap HTTPHeaderMap::isolatedCopy() const &
+{
+ HTTPHeaderMap map;
+ map.m_commonHeaders = crossThreadCopy(m_commonHeaders);
+ map.m_uncommonHeaders = crossThreadCopy(m_uncommonHeaders);
+ return map;
+}
+
+HTTPHeaderMap HTTPHeaderMap::isolatedCopy() &&
+{
+ HTTPHeaderMap map;
+ map.m_commonHeaders = crossThreadCopy(WTFMove(m_commonHeaders));
+ map.m_uncommonHeaders = crossThreadCopy(WTFMove(m_uncommonHeaders));
+ return map;
+}
+
+String HTTPHeaderMap::get(const String& name) const
+{
+ HTTPHeaderName headerName;
+ if (findHTTPHeaderName(name, headerName))
+ return get(headerName);
+
+ return getUncommonHeader(name);
+}
+
+String HTTPHeaderMap::getUncommonHeader(const String& name) const
+{
+ auto index = m_uncommonHeaders.findIf([&](auto& header) {
+ return equalIgnoringASCIICase(header.key, name);
+ });
+ return index != notFound ? m_uncommonHeaders[index].value : String();
+}
+
+#if USE(CF)
+
+void HTTPHeaderMap::set(CFStringRef name, const String& value)
+{
+ // Fast path: avoid constructing a temporary String in the common header case.
+ if (auto* nameCharacters = CFStringGetCStringPtr(name, kCFStringEncodingASCII)) {
+ unsigned length = CFStringGetLength(name);
+ HTTPHeaderName headerName;
+ if (findHTTPHeaderName(StringView(nameCharacters, length), headerName))
+ set(headerName, value);
+ else
+ setUncommonHeader(String(nameCharacters, length), value);
+
+ return;
+ }
+
+ set(String(name), value);
+}
+
+#endif // USE(CF)
+
+void HTTPHeaderMap::set(const String& name, const String& value)
+{
+ HTTPHeaderName headerName;
+ if (findHTTPHeaderName(name, headerName)) {
+ set(headerName, value);
+ return;
+ }
+
+ setUncommonHeader(name, value);
+}
+
+void HTTPHeaderMap::setUncommonHeader(const String& name, const String& value)
+{
+ auto index = m_uncommonHeaders.findIf([&](auto& header) {
+ return equalIgnoringASCIICase(header.key, name);
+ });
+ if (index == notFound)
+ m_uncommonHeaders.append(UncommonHeader { name, value });
+ else
+ m_uncommonHeaders[index].value = value;
+}
+
+void HTTPHeaderMap::add(const String& name, const String& value)
+{
+ HTTPHeaderName headerName;
+ if (findHTTPHeaderName(name, headerName)) {
+ add(headerName, value);
+ return;
+ }
+ auto index = m_uncommonHeaders.findIf([&](auto& header) {
+ return equalIgnoringASCIICase(header.key, name);
+ });
+ if (index == notFound)
+ m_uncommonHeaders.append(UncommonHeader { name, value });
+ else
+ m_uncommonHeaders[index].value = makeString(m_uncommonHeaders[index].value, ", ", value);
+}
+
+void HTTPHeaderMap::append(const String& name, const String& value)
+{
+ ASSERT(!contains(name));
+
+ HTTPHeaderName headerName;
+ if (findHTTPHeaderName(name, headerName))
+ m_commonHeaders.append(CommonHeader { headerName, value });
+ else
+ m_uncommonHeaders.append(UncommonHeader { name, value });
+}
+
+bool HTTPHeaderMap::addIfNotPresent(HTTPHeaderName headerName, const String& value)
+{
+ if (contains(headerName))
+ return false;
+
+ m_commonHeaders.append(CommonHeader { headerName, value });
+ return true;
+}
+
+bool HTTPHeaderMap::contains(const String& name) const
+{
+ HTTPHeaderName headerName;
+ if (findHTTPHeaderName(name, headerName))
+ return contains(headerName);
+
+ return m_uncommonHeaders.findIf([&](auto& header) {
+ return equalIgnoringASCIICase(header.key, name);
+ }) != notFound;
+}
+
+bool HTTPHeaderMap::remove(const String& name)
+{
+ HTTPHeaderName headerName;
+ if (findHTTPHeaderName(name, headerName))
+ return remove(headerName);
+
+ return m_uncommonHeaders.removeFirstMatching([&](auto& header) {
+ return equalIgnoringASCIICase(header.key, name);
+ });
+}
+
+String HTTPHeaderMap::get(HTTPHeaderName name) const
+{
+ auto index = m_commonHeaders.findIf([&](auto& header) {
+ return header.key == name;
+ });
+ return index != notFound ? m_commonHeaders[index].value : String();
+}
+
+void HTTPHeaderMap::set(HTTPHeaderName name, const String& value)
+{
+ auto index = m_commonHeaders.findIf([&](auto& header) {
+ return header.key == name;
+ });
+ if (index == notFound)
+ m_commonHeaders.append(CommonHeader { name, value });
+ else
+ m_commonHeaders[index].value = value;
+}
+
+bool HTTPHeaderMap::contains(HTTPHeaderName name) const
+{
+ return m_commonHeaders.findIf([&](auto& header) {
+ return header.key == name;
+ }) != notFound;
+}
+
+bool HTTPHeaderMap::remove(HTTPHeaderName name)
+{
+ return m_commonHeaders.removeFirstMatching([&](auto& header) {
+ return header.key == name;
+ });
+}
+
+void HTTPHeaderMap::add(HTTPHeaderName name, const String& value)
+{
+ auto index = m_commonHeaders.findIf([&](auto& header) {
+ return header.key == name;
+ });
+ if (index != notFound)
+ m_commonHeaders[index].value = makeString(m_commonHeaders[index].value, ", ", value);
+ else
+ m_commonHeaders.append(CommonHeader { name, value });
+}
+
+} // namespace WebCore
diff --git a/src/javascript/jsc/bindings/webcore/HTTPHeaderMap.h b/src/javascript/jsc/bindings/webcore/HTTPHeaderMap.h
new file mode 100644
index 000000000..1fe19d311
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/HTTPHeaderMap.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2006 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "HTTPHeaderNames.h"
+#include <utility>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+// FIXME: Not every header fits into a map. Notably, multiple Set-Cookie header fields are needed to set multiple cookies.
+
+class HTTPHeaderMap {
+public:
+ struct CommonHeader {
+ HTTPHeaderName key;
+ String value;
+
+ CommonHeader isolatedCopy() const & { return { key , value.isolatedCopy() }; }
+ CommonHeader isolatedCopy() && { return { key , WTFMove(value).isolatedCopy() }; }
+ template <class Encoder> void encode(Encoder&) const;
+ template <class Decoder> static std::optional<CommonHeader> decode(Decoder&);
+
+ bool operator==(const CommonHeader& other) const { return key == other.key && value == other.value; }
+ };
+
+ struct UncommonHeader {
+ String key;
+ String value;
+
+ UncommonHeader isolatedCopy() const & { return { key.isolatedCopy() , value.isolatedCopy() }; }
+ UncommonHeader isolatedCopy() && { return { WTFMove(key).isolatedCopy() , WTFMove(value).isolatedCopy() }; }
+ template <class Encoder> void encode(Encoder&) const;
+ template <class Decoder> static std::optional<UncommonHeader> decode(Decoder&);
+
+ bool operator==(const UncommonHeader& other) const { return key == other.key && value == other.value; }
+ };
+
+ typedef Vector<CommonHeader, 0, CrashOnOverflow, 6> CommonHeadersVector;
+ typedef Vector<UncommonHeader, 0, CrashOnOverflow, 0> UncommonHeadersVector;
+
+ class HTTPHeaderMapConstIterator {
+ public:
+ HTTPHeaderMapConstIterator(const HTTPHeaderMap& table, CommonHeadersVector::const_iterator commonHeadersIt, UncommonHeadersVector::const_iterator uncommonHeadersIt)
+ : m_table(table)
+ , m_commonHeadersIt(commonHeadersIt)
+ , m_uncommonHeadersIt(uncommonHeadersIt)
+ {
+ if (!updateKeyValue(m_commonHeadersIt))
+ updateKeyValue(m_uncommonHeadersIt);
+ }
+
+ struct KeyValue {
+ String key;
+ std::optional<HTTPHeaderName> keyAsHTTPHeaderName;
+ String value;
+ };
+
+ const KeyValue* get() const
+ {
+ ASSERT(*this != m_table.end());
+ return &m_keyValue;
+ }
+ const KeyValue& operator*() const { return *get(); }
+ const KeyValue* operator->() const { return get(); }
+
+ HTTPHeaderMapConstIterator& operator++()
+ {
+ if (m_commonHeadersIt != m_table.m_commonHeaders.end()) {
+ if (updateKeyValue(++m_commonHeadersIt))
+ return *this;
+ } else
+ ++m_uncommonHeadersIt;
+
+ updateKeyValue(m_uncommonHeadersIt);
+ return *this;
+ }
+
+ bool operator!=(const HTTPHeaderMapConstIterator& other) const { return !(*this == other); }
+ bool operator==(const HTTPHeaderMapConstIterator& other) const
+ {
+ return m_commonHeadersIt == other.m_commonHeadersIt && m_uncommonHeadersIt == other.m_uncommonHeadersIt;
+ }
+
+ private:
+ bool updateKeyValue(CommonHeadersVector::const_iterator it)
+ {
+ if (it == m_table.commonHeaders().end())
+ return false;
+ m_keyValue.key = httpHeaderNameString(it->key).toStringWithoutCopying();
+ m_keyValue.keyAsHTTPHeaderName = it->key;
+ m_keyValue.value = it->value;
+ return true;
+ }
+ bool updateKeyValue(UncommonHeadersVector::const_iterator it)
+ {
+ if (it == m_table.uncommonHeaders().end())
+ return false;
+ m_keyValue.key = it->key;
+ m_keyValue.keyAsHTTPHeaderName = std::nullopt;
+ m_keyValue.value = it->value;
+ return true;
+ }
+
+ const HTTPHeaderMap& m_table;
+ CommonHeadersVector::const_iterator m_commonHeadersIt;
+ UncommonHeadersVector::const_iterator m_uncommonHeadersIt;
+ KeyValue m_keyValue;
+ };
+ typedef HTTPHeaderMapConstIterator const_iterator;
+
+ WEBCORE_EXPORT HTTPHeaderMap();
+
+ // Gets a copy of the data suitable for passing to another thread.
+ WEBCORE_EXPORT HTTPHeaderMap isolatedCopy() const &;
+ WEBCORE_EXPORT HTTPHeaderMap isolatedCopy() &&;
+
+ bool isEmpty() const { return m_commonHeaders.isEmpty() && m_uncommonHeaders.isEmpty(); }
+ int size() const { return m_commonHeaders.size() + m_uncommonHeaders.size(); }
+
+ void clear()
+ {
+ m_commonHeaders.clear();
+ m_uncommonHeaders.clear();
+ }
+
+ void shrinkToFit()
+ {
+ m_commonHeaders.shrinkToFit();
+ m_uncommonHeaders.shrinkToFit();
+ }
+
+ WEBCORE_EXPORT String get(const String& name) const;
+ WEBCORE_EXPORT void set(const String& name, const String& value);
+ WEBCORE_EXPORT void add(const String& name, const String& value);
+ WEBCORE_EXPORT void append(const String& name, const String& value);
+ WEBCORE_EXPORT bool contains(const String&) const;
+ WEBCORE_EXPORT bool remove(const String&);
+
+#if USE(CF)
+ void set(CFStringRef name, const String& value);
+#ifdef __OBJC__
+ void set(NSString *name, const String& value) { set((__bridge CFStringRef)name, value); }
+#endif
+#endif
+
+ WEBCORE_EXPORT String get(HTTPHeaderName) const;
+ void set(HTTPHeaderName, const String& value);
+ void add(HTTPHeaderName, const String& value);
+ bool addIfNotPresent(HTTPHeaderName, const String&);
+ WEBCORE_EXPORT bool contains(HTTPHeaderName) const;
+ WEBCORE_EXPORT bool remove(HTTPHeaderName);
+
+ // Instead of passing a string literal to any of these functions, just use a HTTPHeaderName instead.
+ template<size_t length> String get(const char (&)[length]) const = delete;
+ template<size_t length> void set(const char (&)[length], const String&) = delete;
+ template<size_t length> bool contains(const char (&)[length]) = delete;
+ template<size_t length> bool remove(const char (&)[length]) = delete;
+
+ const CommonHeadersVector& commonHeaders() const { return m_commonHeaders; }
+ const UncommonHeadersVector& uncommonHeaders() const { return m_uncommonHeaders; }
+ CommonHeadersVector& commonHeaders() { return m_commonHeaders; }
+ UncommonHeadersVector& uncommonHeaders() { return m_uncommonHeaders; }
+
+ const_iterator begin() const { return const_iterator(*this, m_commonHeaders.begin(), m_uncommonHeaders.begin()); }
+ const_iterator end() const { return const_iterator(*this, m_commonHeaders.end(), m_uncommonHeaders.end()); }
+
+ friend bool operator==(const HTTPHeaderMap& a, const HTTPHeaderMap& b)
+ {
+ if (a.m_commonHeaders.size() != b.m_commonHeaders.size() || a.m_uncommonHeaders.size() != b.m_uncommonHeaders.size())
+ return false;
+ for (auto& commonHeader : a.m_commonHeaders) {
+ if (b.get(commonHeader.key) != commonHeader.value)
+ return false;
+ }
+ for (auto& uncommonHeader : a.m_uncommonHeaders) {
+ if (b.getUncommonHeader(uncommonHeader.key) != uncommonHeader.value)
+ return false;
+ }
+ return true;
+ }
+
+ friend bool operator!=(const HTTPHeaderMap& a, const HTTPHeaderMap& b)
+ {
+ return !(a == b);
+ }
+
+ template <class Encoder> void encode(Encoder&) const;
+ template <class Decoder> static WARN_UNUSED_RETURN bool decode(Decoder&, HTTPHeaderMap&);
+
+private:
+ void setUncommonHeader(const String& name, const String& value);
+ WEBCORE_EXPORT String getUncommonHeader(const String& name) const;
+
+ CommonHeadersVector m_commonHeaders;
+ UncommonHeadersVector m_uncommonHeaders;
+};
+
+template <class Encoder>
+void HTTPHeaderMap::CommonHeader::encode(Encoder& encoder) const
+{
+ encoder << key;
+ encoder << value;
+}
+
+template <class Decoder>
+auto HTTPHeaderMap::CommonHeader::decode(Decoder& decoder) -> std::optional<CommonHeader>
+{
+ HTTPHeaderName name;
+ if (!decoder.decode(name))
+ return std::nullopt;
+ String value;
+ if (!decoder.decode(value))
+ return std::nullopt;
+
+ return CommonHeader { name, WTFMove(value) };
+}
+
+template <class Encoder>
+void HTTPHeaderMap::UncommonHeader::encode(Encoder& encoder) const
+{
+ encoder << key;
+ encoder << value;
+}
+
+template <class Decoder>
+auto HTTPHeaderMap::UncommonHeader::decode(Decoder& decoder) -> std::optional<UncommonHeader>
+{
+ String name;
+ if (!decoder.decode(name))
+ return std::nullopt;
+ String value;
+ if (!decoder.decode(value))
+ return std::nullopt;
+
+ return UncommonHeader { WTFMove(name), WTFMove(value) };
+}
+
+template <class Encoder>
+void HTTPHeaderMap::encode(Encoder& encoder) const
+{
+ encoder << m_commonHeaders;
+ encoder << m_uncommonHeaders;
+}
+
+template <class Decoder>
+bool HTTPHeaderMap::decode(Decoder& decoder, HTTPHeaderMap& headerMap)
+{
+ if (!decoder.decode(headerMap.m_commonHeaders))
+ return false;
+
+ if (!decoder.decode(headerMap.m_uncommonHeaders))
+ return false;
+
+ return true;
+}
+
+} // namespace WebCore
diff --git a/src/javascript/jsc/bindings/webcore/HTTPHeaderNames.cpp b/src/javascript/jsc/bindings/webcore/HTTPHeaderNames.cpp
new file mode 100644
index 000000000..2846f15e5
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/HTTPHeaderNames.cpp
@@ -0,0 +1,718 @@
+/* C++ code produced by gperf version 3.0.3 */
+/* Command-line: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/gperf --key-positions='*' -D -n -s 2 --output-file=HTTPHeaderNames.cpp HTTPHeaderNames.gperf */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+#line 2 "HTTPHeaderNames.gperf"
+
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/// This file is generated by create-http-header-name-table, do not edit.
+
+#include "config.h"
+#include "HTTPHeaderNames.h"
+
+#include <wtf/text/StringView.h>
+
+IGNORE_WARNINGS_BEGIN("implicit-fallthrough")
+
+// Older versions of gperf like to use the `register` keyword.
+#define register
+
+namespace WebCore {
+
+static const struct HeaderNameString {
+ const char* const name;
+ unsigned length;
+} headerNameStrings[] = {
+ { "Accept", 6 },
+ { "Accept-Charset", 14 },
+ { "Accept-Encoding", 15 },
+ { "Accept-Language", 15 },
+ { "Accept-Ranges", 13 },
+ { "Access-Control-Allow-Credentials", 32 },
+ { "Access-Control-Allow-Headers", 28 },
+ { "Access-Control-Allow-Methods", 28 },
+ { "Access-Control-Allow-Origin", 27 },
+ { "Access-Control-Expose-Headers", 29 },
+ { "Access-Control-Max-Age", 22 },
+ { "Access-Control-Request-Headers", 30 },
+ { "Access-Control-Request-Method", 29 },
+ { "Age", 3 },
+ { "Authorization", 13 },
+ { "Cache-Control", 13 },
+ { "Connection", 10 },
+ { "Content-Disposition", 19 },
+ { "Content-Encoding", 16 },
+ { "Content-Language", 16 },
+ { "Content-Length", 14 },
+ { "Content-Location", 16 },
+ { "Content-Range", 13 },
+ { "Content-Security-Policy", 23 },
+ { "Content-Security-Policy-Report-Only", 35 },
+ { "Content-Type", 12 },
+ { "Cookie", 6 },
+ { "Cookie2", 7 },
+ { "Cross-Origin-Embedder-Policy", 28 },
+ { "Cross-Origin-Embedder-Policy-Report-Only", 40 },
+ { "Cross-Origin-Opener-Policy", 26 },
+ { "Cross-Origin-Opener-Policy-Report-Only", 38 },
+ { "Cross-Origin-Resource-Policy", 28 },
+ { "DNT", 3 },
+ { "Date", 4 },
+ { "Default-Style", 13 },
+ { "ETag", 4 },
+ { "Expect", 6 },
+ { "Expires", 7 },
+ { "Host", 4 },
+ { "Icy-MetaInt", 11 },
+ { "Icy-Metadata", 12 },
+ { "If-Match", 8 },
+ { "If-Modified-Since", 17 },
+ { "If-None-Match", 13 },
+ { "If-Range", 8 },
+ { "If-Unmodified-Since", 19 },
+ { "Keep-Alive", 10 },
+ { "Last-Event-ID", 13 },
+ { "Last-Modified", 13 },
+ { "Link", 4 },
+ { "Location", 8 },
+ { "Origin", 6 },
+ { "Ping-From", 9 },
+ { "Ping-To", 7 },
+ { "Pragma", 6 },
+ { "Proxy-Authorization", 19 },
+ { "Purpose", 7 },
+ { "Range", 5 },
+ { "Referer", 7 },
+ { "Referrer-Policy", 15 },
+ { "Refresh", 7 },
+ { "Report-To", 9 },
+ { "Sec-Fetch-Dest", 14 },
+ { "Sec-Fetch-Mode", 14 },
+ { "Sec-WebSocket-Accept", 20 },
+ { "Sec-WebSocket-Extensions", 24 },
+ { "Sec-WebSocket-Key", 17 },
+ { "Sec-WebSocket-Protocol", 22 },
+ { "Sec-WebSocket-Version", 21 },
+ { "Server-Timing", 13 },
+ { "Service-Worker", 14 },
+ { "Service-Worker-Allowed", 22 },
+ { "Service-Worker-Navigation-Preload", 33 },
+ { "Set-Cookie", 10 },
+ { "Set-Cookie2", 11 },
+ { "SourceMap", 9 },
+ { "TE", 2 },
+ { "Timing-Allow-Origin", 19 },
+ { "Trailer", 7 },
+ { "Transfer-Encoding", 17 },
+ { "Upgrade", 7 },
+ { "Upgrade-Insecure-Requests", 25 },
+ { "User-Agent", 10 },
+ { "Vary", 4 },
+ { "Via", 3 },
+ { "X-Content-Type-Options", 22 },
+ { "X-DNS-Prefetch-Control", 22 },
+ { "X-Frame-Options", 15 },
+ { "X-SourceMap", 11 },
+ { "X-Temp-Tablet", 13 },
+ { "X-XSS-Protection", 16 },
+};
+
+
+#line 149 "HTTPHeaderNames.gperf"
+struct HeaderNameHashEntry {
+ const char* name;
+ HTTPHeaderName headerName;
+};
+enum
+ {
+ TOTAL_KEYWORDS = 92,
+ MIN_WORD_LENGTH = 2,
+ MAX_WORD_LENGTH = 40,
+ MIN_HASH_VALUE = 5,
+ MAX_HASH_VALUE = 815
+ };
+
+/* maximum key range = 811, duplicates = 0 */
+
+#ifndef GPERF_DOWNCASE
+#define GPERF_DOWNCASE 1
+static unsigned char gperf_downcase[256] =
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
+ 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
+ 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
+ 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+ 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
+ 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+ 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
+ 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
+ 255
+ };
+#endif
+
+#ifndef GPERF_CASE_STRNCMP
+#define GPERF_CASE_STRNCMP 1
+static int
+gperf_case_strncmp (register const char *s1, register const char *s2, register unsigned int n)
+{
+ for (; n > 0;)
+ {
+ unsigned char c1 = gperf_downcase[(unsigned char)*s1++];
+ unsigned char c2 = gperf_downcase[(unsigned char)*s2++];
+ if (c1 != 0 && c1 == c2)
+ {
+ n--;
+ continue;
+ }
+ return (int)c1 - (int)c2;
+ }
+ return 0;
+}
+#endif
+
+class HTTPHeaderNamesHash
+{
+private:
+ static inline unsigned int header_name_hash_function (const char *str, unsigned int len);
+public:
+ static const struct HeaderNameHashEntry *findHeaderNameImpl (const char *str, unsigned int len);
+};
+
+inline unsigned int
+HTTPHeaderNamesHash::header_name_hash_function (register const char *str, register unsigned int len)
+{
+ static const unsigned short asso_values[] =
+ {
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 0, 816, 816, 816, 816,
+ 5, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 0, 40, 0, 115, 0,
+ 120, 10, 155, 5, 816, 4, 45, 155, 5, 0,
+ 30, 0, 5, 60, 5, 5, 135, 55, 50, 15,
+ 60, 816, 816, 816, 816, 816, 816, 0, 40, 0,
+ 115, 0, 120, 10, 155, 5, 816, 4, 45, 155,
+ 5, 0, 30, 0, 5, 60, 5, 5, 135, 55,
+ 50, 15, 60, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816
+ };
+ register unsigned int hval = 0;
+
+ switch (len)
+ {
+ default:
+ hval += asso_values[(unsigned char)str[39]];
+ /*FALLTHROUGH*/
+ case 39:
+ hval += asso_values[(unsigned char)str[38]];
+ /*FALLTHROUGH*/
+ case 38:
+ hval += asso_values[(unsigned char)str[37]];
+ /*FALLTHROUGH*/
+ case 37:
+ hval += asso_values[(unsigned char)str[36]];
+ /*FALLTHROUGH*/
+ case 36:
+ hval += asso_values[(unsigned char)str[35]];
+ /*FALLTHROUGH*/
+ case 35:
+ hval += asso_values[(unsigned char)str[34]];
+ /*FALLTHROUGH*/
+ case 34:
+ hval += asso_values[(unsigned char)str[33]];
+ /*FALLTHROUGH*/
+ case 33:
+ hval += asso_values[(unsigned char)str[32]];
+ /*FALLTHROUGH*/
+ case 32:
+ hval += asso_values[(unsigned char)str[31]];
+ /*FALLTHROUGH*/
+ case 31:
+ hval += asso_values[(unsigned char)str[30]];
+ /*FALLTHROUGH*/
+ case 30:
+ hval += asso_values[(unsigned char)str[29]];
+ /*FALLTHROUGH*/
+ case 29:
+ hval += asso_values[(unsigned char)str[28]];
+ /*FALLTHROUGH*/
+ case 28:
+ hval += asso_values[(unsigned char)str[27]];
+ /*FALLTHROUGH*/
+ case 27:
+ hval += asso_values[(unsigned char)str[26]];
+ /*FALLTHROUGH*/
+ case 26:
+ hval += asso_values[(unsigned char)str[25]];
+ /*FALLTHROUGH*/
+ case 25:
+ hval += asso_values[(unsigned char)str[24]];
+ /*FALLTHROUGH*/
+ case 24:
+ hval += asso_values[(unsigned char)str[23]];
+ /*FALLTHROUGH*/
+ case 23:
+ hval += asso_values[(unsigned char)str[22]];
+ /*FALLTHROUGH*/
+ case 22:
+ hval += asso_values[(unsigned char)str[21]];
+ /*FALLTHROUGH*/
+ case 21:
+ hval += asso_values[(unsigned char)str[20]];
+ /*FALLTHROUGH*/
+ case 20:
+ hval += asso_values[(unsigned char)str[19]];
+ /*FALLTHROUGH*/
+ case 19:
+ hval += asso_values[(unsigned char)str[18]];
+ /*FALLTHROUGH*/
+ case 18:
+ hval += asso_values[(unsigned char)str[17]];
+ /*FALLTHROUGH*/
+ case 17:
+ hval += asso_values[(unsigned char)str[16]];
+ /*FALLTHROUGH*/
+ case 16:
+ hval += asso_values[(unsigned char)str[15]];
+ /*FALLTHROUGH*/
+ case 15:
+ hval += asso_values[(unsigned char)str[14]];
+ /*FALLTHROUGH*/
+ case 14:
+ hval += asso_values[(unsigned char)str[13]];
+ /*FALLTHROUGH*/
+ case 13:
+ hval += asso_values[(unsigned char)str[12]];
+ /*FALLTHROUGH*/
+ case 12:
+ hval += asso_values[(unsigned char)str[11]];
+ /*FALLTHROUGH*/
+ case 11:
+ hval += asso_values[(unsigned char)str[10]];
+ /*FALLTHROUGH*/
+ case 10:
+ hval += asso_values[(unsigned char)str[9]];
+ /*FALLTHROUGH*/
+ case 9:
+ hval += asso_values[(unsigned char)str[8]];
+ /*FALLTHROUGH*/
+ case 8:
+ hval += asso_values[(unsigned char)str[7]];
+ /*FALLTHROUGH*/
+ case 7:
+ hval += asso_values[(unsigned char)str[6]];
+ /*FALLTHROUGH*/
+ case 6:
+ hval += asso_values[(unsigned char)str[5]];
+ /*FALLTHROUGH*/
+ case 5:
+ hval += asso_values[(unsigned char)str[4]];
+ /*FALLTHROUGH*/
+ case 4:
+ hval += asso_values[(unsigned char)str[3]];
+ /*FALLTHROUGH*/
+ case 3:
+ hval += asso_values[(unsigned char)str[2]];
+ /*FALLTHROUGH*/
+ case 2:
+ hval += asso_values[(unsigned char)str[1]];
+ /*FALLTHROUGH*/
+ case 1:
+ hval += asso_values[(unsigned char)str[0]];
+ break;
+ }
+ return hval;
+}
+
+static const struct HeaderNameHashEntry header_name_wordlist[] =
+ {
+#line 236 "HTTPHeaderNames.gperf"
+ {"TE", HTTPHeaderName::TE},
+#line 185 "HTTPHeaderNames.gperf"
+ {"Cookie", HTTPHeaderName::Cookie},
+#line 172 "HTTPHeaderNames.gperf"
+ {"Age", HTTPHeaderName::Age},
+#line 186 "HTTPHeaderNames.gperf"
+ {"Cookie2", HTTPHeaderName::Cookie2},
+#line 195 "HTTPHeaderNames.gperf"
+ {"ETag", HTTPHeaderName::ETag},
+#line 217 "HTTPHeaderNames.gperf"
+ {"Range", HTTPHeaderName::Range},
+#line 175 "HTTPHeaderNames.gperf"
+ {"Connection", HTTPHeaderName::Connection},
+#line 211 "HTTPHeaderNames.gperf"
+ {"Origin", HTTPHeaderName::Origin},
+#line 159 "HTTPHeaderNames.gperf"
+ {"Accept", HTTPHeaderName::Accept},
+#line 181 "HTTPHeaderNames.gperf"
+ {"Content-Range", HTTPHeaderName::ContentRange},
+#line 221 "HTTPHeaderNames.gperf"
+ {"Report-To", HTTPHeaderName::ReportTo},
+#line 213 "HTTPHeaderNames.gperf"
+ {"Ping-To", HTTPHeaderName::PingTo},
+#line 209 "HTTPHeaderNames.gperf"
+ {"Link", HTTPHeaderName::Link},
+#line 210 "HTTPHeaderNames.gperf"
+ {"Location", HTTPHeaderName::Location},
+#line 238 "HTTPHeaderNames.gperf"
+ {"Trailer", HTTPHeaderName::Trailer},
+#line 184 "HTTPHeaderNames.gperf"
+ {"Content-Type", HTTPHeaderName::ContentType},
+#line 233 "HTTPHeaderNames.gperf"
+ {"Set-Cookie", HTTPHeaderName::SetCookie},
+#line 234 "HTTPHeaderNames.gperf"
+ {"Set-Cookie2", HTTPHeaderName::SetCookie2},
+#line 180 "HTTPHeaderNames.gperf"
+ {"Content-Location", HTTPHeaderName::ContentLocation},
+#line 196 "HTTPHeaderNames.gperf"
+ {"Expect", HTTPHeaderName::Expect},
+#line 242 "HTTPHeaderNames.gperf"
+ {"User-Agent", HTTPHeaderName::UserAgent},
+#line 178 "HTTPHeaderNames.gperf"
+ {"Content-Language", HTTPHeaderName::ContentLanguage},
+#line 162 "HTTPHeaderNames.gperf"
+ {"Accept-Language", HTTPHeaderName::AcceptLanguage},
+#line 163 "HTTPHeaderNames.gperf"
+ {"Accept-Ranges", HTTPHeaderName::AcceptRanges},
+#line 193 "HTTPHeaderNames.gperf"
+ {"Date", HTTPHeaderName::Date},
+#line 192 "HTTPHeaderNames.gperf"
+ {"DNT", HTTPHeaderName::DNT},
+#line 216 "HTTPHeaderNames.gperf"
+ {"Purpose", HTTPHeaderName::Purpose},
+#line 218 "HTTPHeaderNames.gperf"
+ {"Referer", HTTPHeaderName::Referer},
+#line 244 "HTTPHeaderNames.gperf"
+ {"Via", HTTPHeaderName::Via},
+#line 204 "HTTPHeaderNames.gperf"
+ {"If-Range", HTTPHeaderName::IfRange},
+#line 197 "HTTPHeaderNames.gperf"
+ {"Expires", HTTPHeaderName::Expires},
+#line 243 "HTTPHeaderNames.gperf"
+ {"Vary", HTTPHeaderName::Vary},
+#line 177 "HTTPHeaderNames.gperf"
+ {"Content-Encoding", HTTPHeaderName::ContentEncoding},
+#line 240 "HTTPHeaderNames.gperf"
+ {"Upgrade", HTTPHeaderName::Upgrade},
+#line 161 "HTTPHeaderNames.gperf"
+ {"Accept-Encoding", HTTPHeaderName::AcceptEncoding},
+#line 199 "HTTPHeaderNames.gperf"
+ {"Icy-MetaInt", HTTPHeaderName::IcyMetaInt},
+#line 214 "HTTPHeaderNames.gperf"
+ {"Pragma", HTTPHeaderName::Pragma},
+#line 182 "HTTPHeaderNames.gperf"
+ {"Content-Security-Policy", HTTPHeaderName::ContentSecurityPolicy},
+#line 174 "HTTPHeaderNames.gperf"
+ {"Cache-Control", HTTPHeaderName::CacheControl},
+#line 206 "HTTPHeaderNames.gperf"
+ {"Keep-Alive", HTTPHeaderName::KeepAlive},
+#line 198 "HTTPHeaderNames.gperf"
+ {"Host", HTTPHeaderName::Host},
+#line 245 "HTTPHeaderNames.gperf"
+ {"X-Content-Type-Options", HTTPHeaderName::XContentTypeOptions},
+#line 219 "HTTPHeaderNames.gperf"
+ {"Referrer-Policy", HTTPHeaderName::ReferrerPolicy},
+#line 179 "HTTPHeaderNames.gperf"
+ {"Content-Length", HTTPHeaderName::ContentLength},
+#line 226 "HTTPHeaderNames.gperf"
+ {"Sec-WebSocket-Key", HTTPHeaderName::SecWebSocketKey},
+#line 173 "HTTPHeaderNames.gperf"
+ {"Authorization", HTTPHeaderName::Authorization},
+#line 235 "HTTPHeaderNames.gperf"
+ {"SourceMap", HTTPHeaderName::SourceMap},
+#line 224 "HTTPHeaderNames.gperf"
+ {"Sec-WebSocket-Accept", HTTPHeaderName::SecWebSocketAccept},
+#line 160 "HTTPHeaderNames.gperf"
+ {"Accept-Charset", HTTPHeaderName::AcceptCharset},
+#line 230 "HTTPHeaderNames.gperf"
+ {"Service-Worker", HTTPHeaderName::ServiceWorker},
+#line 250 "HTTPHeaderNames.gperf"
+ {"X-XSS-Protection", HTTPHeaderName::XXSSProtection},
+#line 189 "HTTPHeaderNames.gperf"
+ {"Cross-Origin-Opener-Policy", HTTPHeaderName::CrossOriginOpenerPolicy},
+#line 200 "HTTPHeaderNames.gperf"
+ {"Icy-Metadata", HTTPHeaderName::IcyMetadata},
+#line 248 "HTTPHeaderNames.gperf"
+ {"X-SourceMap", HTTPHeaderName::XSourceMap},
+#line 227 "HTTPHeaderNames.gperf"
+ {"Sec-WebSocket-Protocol", HTTPHeaderName::SecWebSocketProtocol},
+#line 176 "HTTPHeaderNames.gperf"
+ {"Content-Disposition", HTTPHeaderName::ContentDisposition},
+#line 183 "HTTPHeaderNames.gperf"
+ {"Content-Security-Policy-Report-Only", HTTPHeaderName::ContentSecurityPolicyReportOnly},
+#line 191 "HTTPHeaderNames.gperf"
+ {"Cross-Origin-Resource-Policy", HTTPHeaderName::CrossOriginResourcePolicy},
+#line 212 "HTTPHeaderNames.gperf"
+ {"Ping-From", HTTPHeaderName::PingFrom},
+#line 249 "HTTPHeaderNames.gperf"
+ {"X-Temp-Tablet", HTTPHeaderName::XTempTablet},
+#line 239 "HTTPHeaderNames.gperf"
+ {"Transfer-Encoding", HTTPHeaderName::TransferEncoding},
+#line 220 "HTTPHeaderNames.gperf"
+ {"Refresh", HTTPHeaderName::Refresh},
+#line 215 "HTTPHeaderNames.gperf"
+ {"Proxy-Authorization", HTTPHeaderName::ProxyAuthorization},
+#line 167 "HTTPHeaderNames.gperf"
+ {"Access-Control-Allow-Origin", HTTPHeaderName::AccessControlAllowOrigin},
+#line 237 "HTTPHeaderNames.gperf"
+ {"Timing-Allow-Origin", HTTPHeaderName::TimingAllowOrigin},
+#line 207 "HTTPHeaderNames.gperf"
+ {"Last-Event-ID", HTTPHeaderName::LastEventID},
+#line 241 "HTTPHeaderNames.gperf"
+ {"Upgrade-Insecure-Requests", HTTPHeaderName::UpgradeInsecureRequests},
+#line 229 "HTTPHeaderNames.gperf"
+ {"Server-Timing", HTTPHeaderName::ServerTiming},
+#line 169 "HTTPHeaderNames.gperf"
+ {"Access-Control-Max-Age", HTTPHeaderName::AccessControlMaxAge},
+#line 190 "HTTPHeaderNames.gperf"
+ {"Cross-Origin-Opener-Policy-Report-Only", HTTPHeaderName::CrossOriginOpenerPolicyReportOnly},
+#line 225 "HTTPHeaderNames.gperf"
+ {"Sec-WebSocket-Extensions", HTTPHeaderName::SecWebSocketExtensions},
+#line 194 "HTTPHeaderNames.gperf"
+ {"Default-Style", HTTPHeaderName::DefaultStyle},
+#line 228 "HTTPHeaderNames.gperf"
+ {"Sec-WebSocket-Version", HTTPHeaderName::SecWebSocketVersion},
+#line 247 "HTTPHeaderNames.gperf"
+ {"X-Frame-Options", HTTPHeaderName::XFrameOptions},
+#line 201 "HTTPHeaderNames.gperf"
+ {"If-Match", HTTPHeaderName::IfMatch},
+#line 203 "HTTPHeaderNames.gperf"
+ {"If-None-Match", HTTPHeaderName::IfNoneMatch},
+#line 222 "HTTPHeaderNames.gperf"
+ {"Sec-Fetch-Dest", HTTPHeaderName::SecFetchDest},
+#line 231 "HTTPHeaderNames.gperf"
+ {"Service-Worker-Allowed", HTTPHeaderName::ServiceWorkerAllowed},
+#line 164 "HTTPHeaderNames.gperf"
+ {"Access-Control-Allow-Credentials", HTTPHeaderName::AccessControlAllowCredentials},
+#line 170 "HTTPHeaderNames.gperf"
+ {"Access-Control-Request-Headers", HTTPHeaderName::AccessControlRequestHeaders},
+#line 246 "HTTPHeaderNames.gperf"
+ {"X-DNS-Prefetch-Control", HTTPHeaderName::XDNSPrefetchControl},
+#line 223 "HTTPHeaderNames.gperf"
+ {"Sec-Fetch-Mode", HTTPHeaderName::SecFetchMode},
+#line 208 "HTTPHeaderNames.gperf"
+ {"Last-Modified", HTTPHeaderName::LastModified},
+#line 232 "HTTPHeaderNames.gperf"
+ {"Service-Worker-Navigation-Preload", HTTPHeaderName::ServiceWorkerNavigationPreload},
+#line 168 "HTTPHeaderNames.gperf"
+ {"Access-Control-Expose-Headers", HTTPHeaderName::AccessControlExposeHeaders},
+#line 165 "HTTPHeaderNames.gperf"
+ {"Access-Control-Allow-Headers", HTTPHeaderName::AccessControlAllowHeaders},
+#line 187 "HTTPHeaderNames.gperf"
+ {"Cross-Origin-Embedder-Policy", HTTPHeaderName::CrossOriginEmbedderPolicy},
+#line 171 "HTTPHeaderNames.gperf"
+ {"Access-Control-Request-Method", HTTPHeaderName::AccessControlRequestMethod},
+#line 202 "HTTPHeaderNames.gperf"
+ {"If-Modified-Since", HTTPHeaderName::IfModifiedSince},
+#line 205 "HTTPHeaderNames.gperf"
+ {"If-Unmodified-Since", HTTPHeaderName::IfUnmodifiedSince},
+#line 188 "HTTPHeaderNames.gperf"
+ {"Cross-Origin-Embedder-Policy-Report-Only", HTTPHeaderName::CrossOriginEmbedderPolicyReportOnly},
+#line 166 "HTTPHeaderNames.gperf"
+ {"Access-Control-Allow-Methods", HTTPHeaderName::AccessControlAllowMethods}
+ };
+
+static const signed char lookup[] =
+ {
+ -1, -1, -1, -1, -1, 0, -1, -1, -1, 1, 2, -1, -1, -1,
+ 3, 4, -1, -1, -1, -1, 5, -1, -1, -1, -1, 6, -1, -1,
+ -1, -1, 7, -1, -1, -1, -1, 8, -1, -1, -1, -1, 9, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, -1, -1, 11,
+ -1, -1, -1, 12, 13, -1, -1, -1, -1, 14, -1, -1, -1, -1,
+ 15, -1, -1, -1, 16, -1, -1, -1, -1, 17, 18, -1, -1, -1,
+ -1, 19, -1, -1, -1, -1, 20, -1, -1, -1, -1, 21, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
+ -1, -1, -1, 23, -1, -1, -1, -1, 24, -1, -1, -1, -1, 25,
+ -1, -1, -1, -1, 26, -1, -1, -1, -1, 27, -1, -1, -1, -1,
+ 28, -1, -1, -1, -1, 29, -1, -1, -1, -1, 30, -1, -1, -1,
+ -1, 31, -1, -1, -1, -1, 32, -1, -1, -1, -1, 33, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 34, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 35,
+ -1, -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 37, -1, -1, -1, -1, 38, -1, -1, -1, 39, 40, -1, -1, -1,
+ -1, 41, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, -1,
+ -1, -1, 43, -1, -1, 44, -1, -1, -1, -1, -1, -1, 45, -1,
+ -1, -1, -1, 46, -1, -1, -1, 47, 48, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 49, 50, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 51, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 52, -1, -1, -1, -1, 53, -1, -1,
+ -1, 54, 55, -1, -1, -1, -1, -1, -1, -1, -1, -1, 56, -1,
+ -1, -1, -1, 57, -1, -1, -1, -1, 58, -1, -1, -1, -1, 59,
+ -1, -1, -1, -1, 60, -1, -1, -1, -1, 61, -1, -1, -1, -1,
+ 62, -1, -1, -1, -1, 63, -1, -1, -1, -1, 64, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, -1, -1,
+ -1, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, 67, -1,
+ -1, -1, -1, 68, -1, -1, -1, -1, 69, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 70, 71, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 72, 73, -1, -1, -1, -1, 74, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 75, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 76, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 77, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 78, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 79, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 80, -1, -1, -1, -1, 81, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 82, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 83, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, -1, -1,
+ -1, -1, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 86, -1, -1, -1, -1, 87,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 88, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 89, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 90, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 91
+ };
+
+const struct HeaderNameHashEntry *
+HTTPHeaderNamesHash::findHeaderNameImpl (register const char *str, register unsigned int len)
+{
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ unsigned int key = header_name_hash_function (str, len);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ register int index = lookup[key];
+
+ if (index >= 0)
+ {
+ register const char *s = header_name_wordlist[index].name;
+
+ if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strncmp (str, s, len) && s[len] == '\0')
+ return &header_name_wordlist[index];
+ }
+ }
+ }
+ return 0;
+}
+#line 251 "HTTPHeaderNames.gperf"
+
+bool findHTTPHeaderName(StringView stringView, HTTPHeaderName& headerName)
+{
+ unsigned length = stringView.length();
+ if (length > maxHTTPHeaderNameLength || length < minHTTPHeaderNameLength)
+ return false;
+
+ if (stringView.is8Bit()) {
+ if (auto nameAndString = HTTPHeaderNamesHash::findHeaderNameImpl(reinterpret_cast<const char*>(stringView.characters8()), length)) {
+ headerName = nameAndString->headerName;
+ return true;
+ }
+ } else {
+ LChar characters[maxHTTPHeaderNameLength];
+ for (unsigned i = 0; i < length; ++i) {
+ UChar character = stringView.characters16()[i];
+ if (!isASCII(character))
+ return false;
+
+ characters[i] = static_cast<LChar>(character);
+ }
+
+ if (auto nameAndString = HTTPHeaderNamesHash::findHeaderNameImpl(reinterpret_cast<const char*>(characters), length)) {
+ headerName = nameAndString->headerName;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+StringView httpHeaderNameString(HTTPHeaderName headerName)
+{
+ ASSERT(static_cast<unsigned>(headerName) < numHTTPHeaderNames);
+
+ const auto& name = headerNameStrings[static_cast<unsigned>(headerName)];
+
+ return StringView { reinterpret_cast<const LChar*>(name.name), static_cast<unsigned>(name.length) };
+}
+
+} // namespace WebCore
+
+#if defined(__clang__)
+IGNORE_WARNINGS_END
+#endif
diff --git a/src/javascript/jsc/bindings/webcore/HTTPHeaderNames.gperf b/src/javascript/jsc/bindings/webcore/HTTPHeaderNames.gperf
new file mode 100644
index 000000000..66a4b24e8
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/HTTPHeaderNames.gperf
@@ -0,0 +1,295 @@
+
+%{
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/// This file is generated by create-http-header-name-table, do not edit.
+
+#include "config.h"
+#include "HTTPHeaderNames.h"
+
+#include <wtf/text/StringView.h>
+
+IGNORE_WARNINGS_BEGIN("implicit-fallthrough")
+
+// Older versions of gperf like to use the `register` keyword.
+#define register
+
+namespace WebCore {
+
+static const struct HeaderNameString {
+ const char* const name;
+ unsigned length;
+} headerNameStrings[] = {
+ { "Accept", 6 },
+ { "Accept-Charset", 14 },
+ { "Accept-Encoding", 15 },
+ { "Accept-Language", 15 },
+ { "Accept-Ranges", 13 },
+ { "Access-Control-Allow-Credentials", 32 },
+ { "Access-Control-Allow-Headers", 28 },
+ { "Access-Control-Allow-Methods", 28 },
+ { "Access-Control-Allow-Origin", 27 },
+ { "Access-Control-Expose-Headers", 29 },
+ { "Access-Control-Max-Age", 22 },
+ { "Access-Control-Request-Headers", 30 },
+ { "Access-Control-Request-Method", 29 },
+ { "Age", 3 },
+ { "Authorization", 13 },
+ { "Cache-Control", 13 },
+ { "Connection", 10 },
+ { "Content-Disposition", 19 },
+ { "Content-Encoding", 16 },
+ { "Content-Language", 16 },
+ { "Content-Length", 14 },
+ { "Content-Location", 16 },
+ { "Content-Range", 13 },
+ { "Content-Security-Policy", 23 },
+ { "Content-Security-Policy-Report-Only", 35 },
+ { "Content-Type", 12 },
+ { "Cookie", 6 },
+ { "Cookie2", 7 },
+ { "Cross-Origin-Embedder-Policy", 28 },
+ { "Cross-Origin-Embedder-Policy-Report-Only", 40 },
+ { "Cross-Origin-Opener-Policy", 26 },
+ { "Cross-Origin-Opener-Policy-Report-Only", 38 },
+ { "Cross-Origin-Resource-Policy", 28 },
+ { "DNT", 3 },
+ { "Date", 4 },
+ { "Default-Style", 13 },
+ { "ETag", 4 },
+ { "Expect", 6 },
+ { "Expires", 7 },
+ { "Host", 4 },
+ { "Icy-MetaInt", 11 },
+ { "Icy-Metadata", 12 },
+ { "If-Match", 8 },
+ { "If-Modified-Since", 17 },
+ { "If-None-Match", 13 },
+ { "If-Range", 8 },
+ { "If-Unmodified-Since", 19 },
+ { "Keep-Alive", 10 },
+ { "Last-Event-ID", 13 },
+ { "Last-Modified", 13 },
+ { "Link", 4 },
+ { "Location", 8 },
+ { "Origin", 6 },
+ { "Ping-From", 9 },
+ { "Ping-To", 7 },
+ { "Pragma", 6 },
+ { "Proxy-Authorization", 19 },
+ { "Purpose", 7 },
+ { "Range", 5 },
+ { "Referer", 7 },
+ { "Referrer-Policy", 15 },
+ { "Refresh", 7 },
+ { "Report-To", 9 },
+ { "Sec-Fetch-Dest", 14 },
+ { "Sec-Fetch-Mode", 14 },
+ { "Sec-WebSocket-Accept", 20 },
+ { "Sec-WebSocket-Extensions", 24 },
+ { "Sec-WebSocket-Key", 17 },
+ { "Sec-WebSocket-Protocol", 22 },
+ { "Sec-WebSocket-Version", 21 },
+ { "Server-Timing", 13 },
+ { "Service-Worker", 14 },
+ { "Service-Worker-Allowed", 22 },
+ { "Service-Worker-Navigation-Preload", 33 },
+ { "Set-Cookie", 10 },
+ { "Set-Cookie2", 11 },
+ { "SourceMap", 9 },
+ { "TE", 2 },
+ { "Timing-Allow-Origin", 19 },
+ { "Trailer", 7 },
+ { "Transfer-Encoding", 17 },
+ { "Upgrade", 7 },
+ { "Upgrade-Insecure-Requests", 25 },
+ { "User-Agent", 10 },
+ { "Vary", 4 },
+ { "Via", 3 },
+ { "X-Content-Type-Options", 22 },
+ { "X-DNS-Prefetch-Control", 22 },
+ { "X-Frame-Options", 15 },
+ { "X-SourceMap", 11 },
+ { "X-Temp-Tablet", 13 },
+ { "X-XSS-Protection", 16 },
+};
+
+
+%}
+
+%language=C++
+%readonly-tables
+%global-table
+%compare-strncmp
+%ignore-case
+%struct-type
+struct HeaderNameHashEntry {
+ const char* name;
+ HTTPHeaderName headerName;
+};
+%define class-name HTTPHeaderNamesHash
+%define lookup-function-name findHeaderNameImpl
+%define hash-function-name header_name_hash_function
+%define word-array-name header_name_wordlist
+%enum
+%%
+Accept, HTTPHeaderName::Accept
+Accept-Charset, HTTPHeaderName::AcceptCharset
+Accept-Encoding, HTTPHeaderName::AcceptEncoding
+Accept-Language, HTTPHeaderName::AcceptLanguage
+Accept-Ranges, HTTPHeaderName::AcceptRanges
+Access-Control-Allow-Credentials, HTTPHeaderName::AccessControlAllowCredentials
+Access-Control-Allow-Headers, HTTPHeaderName::AccessControlAllowHeaders
+Access-Control-Allow-Methods, HTTPHeaderName::AccessControlAllowMethods
+Access-Control-Allow-Origin, HTTPHeaderName::AccessControlAllowOrigin
+Access-Control-Expose-Headers, HTTPHeaderName::AccessControlExposeHeaders
+Access-Control-Max-Age, HTTPHeaderName::AccessControlMaxAge
+Access-Control-Request-Headers, HTTPHeaderName::AccessControlRequestHeaders
+Access-Control-Request-Method, HTTPHeaderName::AccessControlRequestMethod
+Age, HTTPHeaderName::Age
+Authorization, HTTPHeaderName::Authorization
+Cache-Control, HTTPHeaderName::CacheControl
+Connection, HTTPHeaderName::Connection
+Content-Disposition, HTTPHeaderName::ContentDisposition
+Content-Encoding, HTTPHeaderName::ContentEncoding
+Content-Language, HTTPHeaderName::ContentLanguage
+Content-Length, HTTPHeaderName::ContentLength
+Content-Location, HTTPHeaderName::ContentLocation
+Content-Range, HTTPHeaderName::ContentRange
+Content-Security-Policy, HTTPHeaderName::ContentSecurityPolicy
+Content-Security-Policy-Report-Only, HTTPHeaderName::ContentSecurityPolicyReportOnly
+Content-Type, HTTPHeaderName::ContentType
+Cookie, HTTPHeaderName::Cookie
+Cookie2, HTTPHeaderName::Cookie2
+Cross-Origin-Embedder-Policy, HTTPHeaderName::CrossOriginEmbedderPolicy
+Cross-Origin-Embedder-Policy-Report-Only, HTTPHeaderName::CrossOriginEmbedderPolicyReportOnly
+Cross-Origin-Opener-Policy, HTTPHeaderName::CrossOriginOpenerPolicy
+Cross-Origin-Opener-Policy-Report-Only, HTTPHeaderName::CrossOriginOpenerPolicyReportOnly
+Cross-Origin-Resource-Policy, HTTPHeaderName::CrossOriginResourcePolicy
+DNT, HTTPHeaderName::DNT
+Date, HTTPHeaderName::Date
+Default-Style, HTTPHeaderName::DefaultStyle
+ETag, HTTPHeaderName::ETag
+Expect, HTTPHeaderName::Expect
+Expires, HTTPHeaderName::Expires
+Host, HTTPHeaderName::Host
+Icy-MetaInt, HTTPHeaderName::IcyMetaInt
+Icy-Metadata, HTTPHeaderName::IcyMetadata
+If-Match, HTTPHeaderName::IfMatch
+If-Modified-Since, HTTPHeaderName::IfModifiedSince
+If-None-Match, HTTPHeaderName::IfNoneMatch
+If-Range, HTTPHeaderName::IfRange
+If-Unmodified-Since, HTTPHeaderName::IfUnmodifiedSince
+Keep-Alive, HTTPHeaderName::KeepAlive
+Last-Event-ID, HTTPHeaderName::LastEventID
+Last-Modified, HTTPHeaderName::LastModified
+Link, HTTPHeaderName::Link
+Location, HTTPHeaderName::Location
+Origin, HTTPHeaderName::Origin
+Ping-From, HTTPHeaderName::PingFrom
+Ping-To, HTTPHeaderName::PingTo
+Pragma, HTTPHeaderName::Pragma
+Proxy-Authorization, HTTPHeaderName::ProxyAuthorization
+Purpose, HTTPHeaderName::Purpose
+Range, HTTPHeaderName::Range
+Referer, HTTPHeaderName::Referer
+Referrer-Policy, HTTPHeaderName::ReferrerPolicy
+Refresh, HTTPHeaderName::Refresh
+Report-To, HTTPHeaderName::ReportTo
+Sec-Fetch-Dest, HTTPHeaderName::SecFetchDest
+Sec-Fetch-Mode, HTTPHeaderName::SecFetchMode
+Sec-WebSocket-Accept, HTTPHeaderName::SecWebSocketAccept
+Sec-WebSocket-Extensions, HTTPHeaderName::SecWebSocketExtensions
+Sec-WebSocket-Key, HTTPHeaderName::SecWebSocketKey
+Sec-WebSocket-Protocol, HTTPHeaderName::SecWebSocketProtocol
+Sec-WebSocket-Version, HTTPHeaderName::SecWebSocketVersion
+Server-Timing, HTTPHeaderName::ServerTiming
+Service-Worker, HTTPHeaderName::ServiceWorker
+Service-Worker-Allowed, HTTPHeaderName::ServiceWorkerAllowed
+Service-Worker-Navigation-Preload, HTTPHeaderName::ServiceWorkerNavigationPreload
+Set-Cookie, HTTPHeaderName::SetCookie
+Set-Cookie2, HTTPHeaderName::SetCookie2
+SourceMap, HTTPHeaderName::SourceMap
+TE, HTTPHeaderName::TE
+Timing-Allow-Origin, HTTPHeaderName::TimingAllowOrigin
+Trailer, HTTPHeaderName::Trailer
+Transfer-Encoding, HTTPHeaderName::TransferEncoding
+Upgrade, HTTPHeaderName::Upgrade
+Upgrade-Insecure-Requests, HTTPHeaderName::UpgradeInsecureRequests
+User-Agent, HTTPHeaderName::UserAgent
+Vary, HTTPHeaderName::Vary
+Via, HTTPHeaderName::Via
+X-Content-Type-Options, HTTPHeaderName::XContentTypeOptions
+X-DNS-Prefetch-Control, HTTPHeaderName::XDNSPrefetchControl
+X-Frame-Options, HTTPHeaderName::XFrameOptions
+X-SourceMap, HTTPHeaderName::XSourceMap
+X-Temp-Tablet, HTTPHeaderName::XTempTablet
+X-XSS-Protection, HTTPHeaderName::XXSSProtection
+%%
+bool findHTTPHeaderName(StringView stringView, HTTPHeaderName& headerName)
+{
+ unsigned length = stringView.length();
+ if (length > maxHTTPHeaderNameLength || length < minHTTPHeaderNameLength)
+ return false;
+
+ if (stringView.is8Bit()) {
+ if (auto nameAndString = HTTPHeaderNamesHash::findHeaderNameImpl(reinterpret_cast<const char*>(stringView.characters8()), length)) {
+ headerName = nameAndString->headerName;
+ return true;
+ }
+ } else {
+ LChar characters[maxHTTPHeaderNameLength];
+ for (unsigned i = 0; i < length; ++i) {
+ UChar character = stringView.characters16()[i];
+ if (!isASCII(character))
+ return false;
+
+ characters[i] = static_cast<LChar>(character);
+ }
+
+ if (auto nameAndString = HTTPHeaderNamesHash::findHeaderNameImpl(reinterpret_cast<const char*>(characters), length)) {
+ headerName = nameAndString->headerName;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+StringView httpHeaderNameString(HTTPHeaderName headerName)
+{
+ ASSERT(static_cast<unsigned>(headerName) < numHTTPHeaderNames);
+
+ const auto& name = headerNameStrings[static_cast<unsigned>(headerName)];
+
+ return StringView { reinterpret_cast<const LChar*>(name.name), static_cast<unsigned>(name.length) };
+}
+
+} // namespace WebCore
+
+#if defined(__clang__)
+IGNORE_WARNINGS_END
+#endif
diff --git a/src/javascript/jsc/bindings/webcore/HTTPHeaderNames.h b/src/javascript/jsc/bindings/webcore/HTTPHeaderNames.h
new file mode 100644
index 000000000..066d40e90
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/HTTPHeaderNames.h
@@ -0,0 +1,242 @@
+
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/// This file is generated by create-http-header-name-table, do not edit.
+
+#ifndef HTTPHeaderNames_h
+#define HTTPHeaderNames_h
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+enum class HTTPHeaderName {
+ Accept,
+ AcceptCharset,
+ AcceptEncoding,
+ AcceptLanguage,
+ AcceptRanges,
+ AccessControlAllowCredentials,
+ AccessControlAllowHeaders,
+ AccessControlAllowMethods,
+ AccessControlAllowOrigin,
+ AccessControlExposeHeaders,
+ AccessControlMaxAge,
+ AccessControlRequestHeaders,
+ AccessControlRequestMethod,
+ Age,
+ Authorization,
+ CacheControl,
+ Connection,
+ ContentDisposition,
+ ContentEncoding,
+ ContentLanguage,
+ ContentLength,
+ ContentLocation,
+ ContentRange,
+ ContentSecurityPolicy,
+ ContentSecurityPolicyReportOnly,
+ ContentType,
+ Cookie,
+ Cookie2,
+ CrossOriginEmbedderPolicy,
+ CrossOriginEmbedderPolicyReportOnly,
+ CrossOriginOpenerPolicy,
+ CrossOriginOpenerPolicyReportOnly,
+ CrossOriginResourcePolicy,
+ DNT,
+ Date,
+ DefaultStyle,
+ ETag,
+ Expect,
+ Expires,
+ Host,
+ IcyMetaInt,
+ IcyMetadata,
+ IfMatch,
+ IfModifiedSince,
+ IfNoneMatch,
+ IfRange,
+ IfUnmodifiedSince,
+ KeepAlive,
+ LastEventID,
+ LastModified,
+ Link,
+ Location,
+ Origin,
+ PingFrom,
+ PingTo,
+ Pragma,
+ ProxyAuthorization,
+ Purpose,
+ Range,
+ Referer,
+ ReferrerPolicy,
+ Refresh,
+ ReportTo,
+ SecFetchDest,
+ SecFetchMode,
+ SecWebSocketAccept,
+ SecWebSocketExtensions,
+ SecWebSocketKey,
+ SecWebSocketProtocol,
+ SecWebSocketVersion,
+ ServerTiming,
+ ServiceWorker,
+ ServiceWorkerAllowed,
+ ServiceWorkerNavigationPreload,
+ SetCookie,
+ SetCookie2,
+ SourceMap,
+ TE,
+ TimingAllowOrigin,
+ Trailer,
+ TransferEncoding,
+ Upgrade,
+ UpgradeInsecureRequests,
+ UserAgent,
+ Vary,
+ Via,
+ XContentTypeOptions,
+ XDNSPrefetchControl,
+ XFrameOptions,
+ XSourceMap,
+ XTempTablet,
+ XXSSProtection,
+};
+
+const unsigned numHTTPHeaderNames = 92;
+const size_t minHTTPHeaderNameLength = 2;
+const size_t maxHTTPHeaderNameLength = 40;
+
+bool findHTTPHeaderName(StringView, HTTPHeaderName&);
+WEBCORE_EXPORT StringView httpHeaderNameString(HTTPHeaderName);
+
+} // namespace WebCore
+
+namespace WTF {
+
+template<> struct EnumTraits<WebCore::HTTPHeaderName> {
+ using values = EnumValues<
+ WebCore::HTTPHeaderName,
+ WebCore::HTTPHeaderName::Accept,
+ WebCore::HTTPHeaderName::AcceptCharset,
+ WebCore::HTTPHeaderName::AcceptEncoding,
+ WebCore::HTTPHeaderName::AcceptLanguage,
+ WebCore::HTTPHeaderName::AcceptRanges,
+ WebCore::HTTPHeaderName::AccessControlAllowCredentials,
+ WebCore::HTTPHeaderName::AccessControlAllowHeaders,
+ WebCore::HTTPHeaderName::AccessControlAllowMethods,
+ WebCore::HTTPHeaderName::AccessControlAllowOrigin,
+ WebCore::HTTPHeaderName::AccessControlExposeHeaders,
+ WebCore::HTTPHeaderName::AccessControlMaxAge,
+ WebCore::HTTPHeaderName::AccessControlRequestHeaders,
+ WebCore::HTTPHeaderName::AccessControlRequestMethod,
+ WebCore::HTTPHeaderName::Age,
+ WebCore::HTTPHeaderName::Authorization,
+ WebCore::HTTPHeaderName::CacheControl,
+ WebCore::HTTPHeaderName::Connection,
+ WebCore::HTTPHeaderName::ContentDisposition,
+ WebCore::HTTPHeaderName::ContentEncoding,
+ WebCore::HTTPHeaderName::ContentLanguage,
+ WebCore::HTTPHeaderName::ContentLength,
+ WebCore::HTTPHeaderName::ContentLocation,
+ WebCore::HTTPHeaderName::ContentRange,
+ WebCore::HTTPHeaderName::ContentSecurityPolicy,
+ WebCore::HTTPHeaderName::ContentSecurityPolicyReportOnly,
+ WebCore::HTTPHeaderName::ContentType,
+ WebCore::HTTPHeaderName::Cookie,
+ WebCore::HTTPHeaderName::Cookie2,
+ WebCore::HTTPHeaderName::CrossOriginEmbedderPolicy,
+ WebCore::HTTPHeaderName::CrossOriginEmbedderPolicyReportOnly,
+ WebCore::HTTPHeaderName::CrossOriginOpenerPolicy,
+ WebCore::HTTPHeaderName::CrossOriginOpenerPolicyReportOnly,
+ WebCore::HTTPHeaderName::CrossOriginResourcePolicy,
+ WebCore::HTTPHeaderName::DNT,
+ WebCore::HTTPHeaderName::Date,
+ WebCore::HTTPHeaderName::DefaultStyle,
+ WebCore::HTTPHeaderName::ETag,
+ WebCore::HTTPHeaderName::Expect,
+ WebCore::HTTPHeaderName::Expires,
+ WebCore::HTTPHeaderName::Host,
+ WebCore::HTTPHeaderName::IcyMetaInt,
+ WebCore::HTTPHeaderName::IcyMetadata,
+ WebCore::HTTPHeaderName::IfMatch,
+ WebCore::HTTPHeaderName::IfModifiedSince,
+ WebCore::HTTPHeaderName::IfNoneMatch,
+ WebCore::HTTPHeaderName::IfRange,
+ WebCore::HTTPHeaderName::IfUnmodifiedSince,
+ WebCore::HTTPHeaderName::KeepAlive,
+ WebCore::HTTPHeaderName::LastEventID,
+ WebCore::HTTPHeaderName::LastModified,
+ WebCore::HTTPHeaderName::Link,
+ WebCore::HTTPHeaderName::Location,
+ WebCore::HTTPHeaderName::Origin,
+ WebCore::HTTPHeaderName::PingFrom,
+ WebCore::HTTPHeaderName::PingTo,
+ WebCore::HTTPHeaderName::Pragma,
+ WebCore::HTTPHeaderName::ProxyAuthorization,
+ WebCore::HTTPHeaderName::Purpose,
+ WebCore::HTTPHeaderName::Range,
+ WebCore::HTTPHeaderName::Referer,
+ WebCore::HTTPHeaderName::ReferrerPolicy,
+ WebCore::HTTPHeaderName::Refresh,
+ WebCore::HTTPHeaderName::ReportTo,
+ WebCore::HTTPHeaderName::SecFetchDest,
+ WebCore::HTTPHeaderName::SecFetchMode,
+ WebCore::HTTPHeaderName::SecWebSocketAccept,
+ WebCore::HTTPHeaderName::SecWebSocketExtensions,
+ WebCore::HTTPHeaderName::SecWebSocketKey,
+ WebCore::HTTPHeaderName::SecWebSocketProtocol,
+ WebCore::HTTPHeaderName::SecWebSocketVersion,
+ WebCore::HTTPHeaderName::ServerTiming,
+ WebCore::HTTPHeaderName::ServiceWorker,
+ WebCore::HTTPHeaderName::ServiceWorkerAllowed,
+ WebCore::HTTPHeaderName::ServiceWorkerNavigationPreload,
+ WebCore::HTTPHeaderName::SetCookie,
+ WebCore::HTTPHeaderName::SetCookie2,
+ WebCore::HTTPHeaderName::SourceMap,
+ WebCore::HTTPHeaderName::TE,
+ WebCore::HTTPHeaderName::TimingAllowOrigin,
+ WebCore::HTTPHeaderName::Trailer,
+ WebCore::HTTPHeaderName::TransferEncoding,
+ WebCore::HTTPHeaderName::Upgrade,
+ WebCore::HTTPHeaderName::UpgradeInsecureRequests,
+ WebCore::HTTPHeaderName::UserAgent,
+ WebCore::HTTPHeaderName::Vary,
+ WebCore::HTTPHeaderName::Via,
+ WebCore::HTTPHeaderName::XContentTypeOptions,
+ WebCore::HTTPHeaderName::XDNSPrefetchControl,
+ WebCore::HTTPHeaderName::XFrameOptions,
+ WebCore::HTTPHeaderName::XSourceMap,
+ WebCore::HTTPHeaderName::XTempTablet,
+ WebCore::HTTPHeaderName::XXSSProtection
+ >;
+};
+
+} // namespace WTF
+
+#endif // HTTPHeaderNames_h
diff --git a/src/javascript/jsc/bindings/webcore/HTTPHeaderNames.in b/src/javascript/jsc/bindings/webcore/HTTPHeaderNames.in
new file mode 100644
index 000000000..9edb2b2d7
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/HTTPHeaderNames.in
@@ -0,0 +1,119 @@
+//
+// Copyright (C) 2014 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+// BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+Accept
+Accept-Charset
+Accept-Language
+Accept-Encoding
+Accept-Ranges
+Access-Control-Allow-Credentials
+Access-Control-Allow-Headers
+Access-Control-Allow-Methods
+Access-Control-Allow-Origin
+Access-Control-Expose-Headers
+Access-Control-Max-Age
+Access-Control-Request-Headers
+Access-Control-Request-Method
+Age
+Authorization
+Cache-Control
+Connection
+Content-Disposition
+Content-Encoding
+Content-Language
+Content-Length
+Content-Location
+Content-Security-Policy
+Content-Security-Policy-Report-Only
+Content-Type
+Content-Range
+Cookie
+Cookie2
+Cross-Origin-Embedder-Policy
+Cross-Origin-Embedder-Policy-Report-Only
+Cross-Origin-Opener-Policy
+Cross-Origin-Opener-Policy-Report-Only
+Cross-Origin-Resource-Policy
+Date
+DNT
+Default-Style
+ETag
+Expect
+Expires
+Host
+If-Match
+If-Modified-Since
+If-None-Match
+If-Range
+If-Unmodified-Since
+Keep-Alive
+Last-Event-ID
+Last-Modified
+Link
+Location
+Origin
+Ping-From
+Ping-To
+Purpose
+Pragma
+Proxy-Authorization
+Range
+Referer
+Referrer-Policy
+Refresh
+Report-To
+Sec-Fetch-Dest
+Sec-Fetch-Mode
+Sec-WebSocket-Accept
+Sec-WebSocket-Extensions
+Sec-WebSocket-Key
+Sec-WebSocket-Protocol
+Sec-WebSocket-Version
+Server-Timing
+Service-Worker
+Service-Worker-Allowed
+Service-Worker-Navigation-Preload
+Set-Cookie
+Set-Cookie2
+SourceMap
+TE
+Timing-Allow-Origin
+Trailer
+Transfer-Encoding
+Upgrade
+Upgrade-Insecure-Requests
+User-Agent
+Vary
+Via
+X-Content-Type-Options
+X-DNS-Prefetch-Control
+X-Frame-Options
+X-SourceMap
+X-XSS-Protection
+X-Temp-Tablet
+
+// These headers are specific to GStreamer.
+Icy-MetaInt
+Icy-Metadata
diff --git a/src/javascript/jsc/bindings/webcore/HTTPHeaderValues.cpp b/src/javascript/jsc/bindings/webcore/HTTPHeaderValues.cpp
new file mode 100644
index 000000000..b4869e846
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/HTTPHeaderValues.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "HTTPHeaderValues.h"
+
+#include <wtf/NeverDestroyed.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+namespace HTTPHeaderValues {
+
+const String& textPlainContentType()
+{
+ static NeverDestroyed<const String> contentType(MAKE_STATIC_STRING_IMPL("text/plain;charset=UTF-8"));
+ return contentType;
+}
+
+const String& formURLEncodedContentType()
+{
+ static NeverDestroyed<const String> contentType(MAKE_STATIC_STRING_IMPL("application/x-www-form-urlencoded;charset=UTF-8"));
+ return contentType;
+}
+
+const String& applicationJSONContentType()
+{
+ // The default encoding is UTF-8: https://www.ietf.org/rfc/rfc4627.txt.
+ static NeverDestroyed<const String> contentType(MAKE_STATIC_STRING_IMPL("application/json"));
+ return contentType;
+}
+
+const String& noCache()
+{
+ static NeverDestroyed<const String> value(MAKE_STATIC_STRING_IMPL("no-cache"));
+ return value;
+}
+
+const String& maxAge0()
+{
+ static NeverDestroyed<const String> value(MAKE_STATIC_STRING_IMPL("max-age=0"));
+ return value;
+}
+
+}
+
+}
diff --git a/src/javascript/jsc/bindings/webcore/HTTPHeaderValues.h b/src/javascript/jsc/bindings/webcore/HTTPHeaderValues.h
new file mode 100644
index 000000000..6345a9a8f
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/HTTPHeaderValues.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+namespace HTTPHeaderValues {
+
+const String& textPlainContentType();
+const String& formURLEncodedContentType();
+WEBCORE_EXPORT const String& applicationJSONContentType();
+const String& noCache();
+WEBCORE_EXPORT const String& maxAge0();
+}
+
+}
diff --git a/src/javascript/jsc/bindings/webcore/HTTPParsers.cpp b/src/javascript/jsc/bindings/webcore/HTTPParsers.cpp
new file mode 100644
index 000000000..d435cebf4
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/HTTPParsers.cpp
@@ -0,0 +1,1034 @@
+/*
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2011 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "HTTPParsers.h"
+
+#include "HTTPHeaderField.h"
+#include "HTTPHeaderNames.h"
+#include "ParsedContentType.h"
+#include <wtf/DateMath.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/StringToIntegerConversion.h>
+#include <wtf/unicode/CharacterNames.h>
+
+namespace WebCore {
+
+// True if characters which satisfy the predicate are present, incrementing
+// "pos" to the next character which does not satisfy the predicate.
+// Note: might return pos == str.length().
+static inline bool skipWhile(const String& str, unsigned& pos, const Function<bool(const UChar)>& predicate)
+{
+ const unsigned start = pos;
+ const unsigned len = str.length();
+ while (pos < len && predicate(str[pos]))
+ ++pos;
+ return pos != start;
+}
+
+// true if there is more to parse, after incrementing pos past whitespace.
+// Note: Might return pos == str.length()
+static inline bool skipWhiteSpace(const String& str, unsigned& pos)
+{
+ skipWhile(str, pos, RFC7230::isWhitespace);
+ return pos < str.length();
+}
+
+// Returns true if the function can match the whole token (case insensitive)
+// incrementing pos on match, otherwise leaving pos unchanged.
+// Note: Might return pos == str.length()
+static inline bool skipToken(const String& str, unsigned& pos, const char* token)
+{
+ unsigned len = str.length();
+ unsigned current = pos;
+
+ while (current < len && *token) {
+ if (toASCIILower(str[current]) != *token++)
+ return false;
+ ++current;
+ }
+
+ if (*token)
+ return false;
+
+ pos = current;
+ return true;
+}
+
+// True if the expected equals sign is seen and there is more to follow.
+static inline bool skipEquals(const String& str, unsigned &pos)
+{
+ return skipWhiteSpace(str, pos) && str[pos++] == '=' && skipWhiteSpace(str, pos);
+}
+
+// True if a value present, incrementing pos to next space or semicolon, if any.
+// Note: might return pos == str.length().
+static inline bool skipValue(const String& str, unsigned& pos)
+{
+ unsigned start = pos;
+ unsigned len = str.length();
+ while (pos < len) {
+ if (str[pos] == ' ' || str[pos] == '\t' || str[pos] == ';')
+ break;
+ ++pos;
+ }
+ return pos != start;
+}
+
+// See RFC 7230, Section 3.1.2.
+bool isValidReasonPhrase(const String& value)
+{
+ for (unsigned i = 0; i < value.length(); ++i) {
+ UChar c = value[i];
+ if (c == 0x7F || !isLatin1(c) || (c < 0x20 && c != '\t'))
+ return false;
+ }
+ return true;
+}
+
+// See https://fetch.spec.whatwg.org/#concept-header
+bool isValidHTTPHeaderValue(const String& value)
+{
+ UChar c = value[0];
+ if (c == ' ' || c == '\t')
+ return false;
+ c = value[value.length() - 1];
+ if (c == ' ' || c == '\t')
+ return false;
+ for (unsigned i = 0; i < value.length(); ++i) {
+ c = value[i];
+ if (c == 0x00 || c == 0x0A || c == 0x0D)
+ return false;
+ }
+ return true;
+}
+
+// See RFC 7231, Section 5.3.2.
+bool isValidAcceptHeaderValue(const String& value)
+{
+ for (unsigned i = 0; i < value.length(); ++i) {
+ UChar c = value[i];
+
+ // First check for alphanumeric for performance reasons then allowlist four delimiter characters.
+ if (isASCIIAlphanumeric(c) || c == ',' || c == '/' || c == ';' || c == '=')
+ continue;
+
+ ASSERT(isLatin1(c));
+ if (c == 0x7F || (c < 0x20 && c != '\t'))
+ return false;
+
+ if (RFC7230::isDelimiter(c))
+ return false;
+ }
+
+ return true;
+}
+
+static bool containsCORSUnsafeRequestHeaderBytes(const String& value)
+{
+ for (unsigned i = 0; i < value.length(); ++i) {
+ UChar c = value[i];
+ // https://fetch.spec.whatwg.org/#cors-unsafe-request-header-byte
+ if ((c < 0x20 && c != '\t') || (c == '"' || c == '(' || c == ')' || c == ':' || c == '<' || c == '>' || c == '?'
+ || c == '@' || c == '[' || c == '\\' || c == ']' || c == 0x7B || c == '{' || c == '}' || c == 0x7F))
+ return true;
+ }
+
+ return false;
+}
+
+// See RFC 7231, Section 5.3.5 and 3.1.3.2.
+bool isValidLanguageHeaderValue(const String& value)
+{
+ for (unsigned i = 0; i < value.length(); ++i) {
+ UChar c = value[i];
+ if (isASCIIAlphanumeric(c) || c == ' ' || c == '*' || c == ',' || c == '-' || c == '.' || c == ';' || c == '=')
+ continue;
+ return false;
+ }
+
+ // FIXME: Validate further by splitting into language tags and optional quality
+ // values (q=) and then check each language tag.
+ // Language tags https://tools.ietf.org/html/rfc7231#section-3.1.3.1
+ // Language tag syntax https://tools.ietf.org/html/bcp47#section-2.1
+ return true;
+}
+
+// See RFC 7230, Section 3.2.6.
+bool isValidHTTPToken(StringView value)
+{
+ if (value.isEmpty())
+ return false;
+ for (UChar c : value.codeUnits()) {
+ if (!RFC7230::isTokenCharacter(c))
+ return false;
+ }
+ return true;
+}
+
+bool isValidHTTPToken(const String& value)
+{
+ return isValidHTTPToken(StringView(value));
+}
+
+#if USE(GLIB)
+// True if the character at the given position satisifies a predicate, incrementing "pos" by one.
+// Note: Might return pos == str.length()
+static inline bool skipCharacter(const String& value, unsigned& pos, Function<bool(const UChar)>&& predicate)
+{
+ if (pos < value.length() && predicate(value[pos])) {
+ ++pos;
+ return true;
+ }
+ return false;
+}
+
+// True if the "expected" character is at the given position, incrementing "pos" by one.
+// Note: Might return pos == str.length()
+static inline bool skipCharacter(const String& value, unsigned& pos, const UChar expected)
+{
+ return skipCharacter(value, pos, [expected](const UChar c) {
+ return c == expected;
+ });
+}
+
+// True if a quoted pair is present, incrementing "pos" to the position after the quoted pair.
+// Note: Might return pos == str.length()
+// See RFC 7230, Section 3.2.6.
+static constexpr auto QuotedPairStartCharacter = '\\';
+static bool skipQuotedPair(const String& value, unsigned& pos)
+{
+ // quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
+ return skipCharacter(value, pos, QuotedPairStartCharacter)
+ && skipCharacter(value, pos, RFC7230::isQuotedPairSecondOctet);
+}
+
+// True if a comment is present, incrementing "pos" to the position after the comment.
+// Note: Might return pos == str.length()
+// See RFC 7230, Section 3.2.6.
+static constexpr auto CommentStartCharacter = '(';
+static constexpr auto CommentEndCharacter = ')';
+static bool skipComment(const String& value, unsigned& pos)
+{
+ // comment = "(" *( ctext / quoted-pair / comment ) ")"
+ // ctext = HTAB / SP / %x21-27 / %x2A-5B / %x5D-7E / obs-text
+ if (!skipCharacter(value, pos, CommentStartCharacter))
+ return false;
+
+ const unsigned end = value.length();
+ while (pos < end && value[pos] != CommentEndCharacter) {
+ switch (value[pos]) {
+ case CommentStartCharacter:
+ if (!skipComment(value, pos))
+ return false;
+ break;
+ case QuotedPairStartCharacter:
+ if (!skipQuotedPair(value, pos))
+ return false;
+ break;
+ default:
+ if (!skipWhile(value, pos, RFC7230::isCommentText))
+ return false;
+ }
+ }
+ return skipCharacter(value, pos, CommentEndCharacter);
+}
+
+// True if an HTTP header token is present, incrementing "pos" to the position after it.
+// Note: Might return pos == str.length()
+// See RFC 7230, Section 3.2.6.
+static bool skipHTTPToken(const String& value, unsigned& pos)
+{
+ return skipWhile(value, pos, RFC7230::isTokenCharacter);
+}
+
+// True if a product specifier (as in an User-Agent header) is present, incrementing "pos" to the position after it.
+// Note: Might return pos == str.length()
+// See RFC 7231, Section 5.5.3.
+static bool skipUserAgentProduct(const String& value, unsigned& pos)
+{
+ // product = token ["/" product-version]
+ // product-version = token
+ if (!skipHTTPToken(value, pos))
+ return false;
+ if (skipCharacter(value, pos, '/'))
+ return skipHTTPToken(value, pos);
+ return true;
+}
+
+// See RFC 7231, Section 5.5.3
+bool isValidUserAgentHeaderValue(const String& value)
+{
+ // User-Agent = product *( RWS ( product / comment ) )
+ unsigned pos = 0;
+ if (!skipUserAgentProduct(value, pos))
+ return false;
+
+ while (pos < value.length()) {
+ if (!skipWhiteSpace(value, pos))
+ return false;
+ if (value[pos] == CommentStartCharacter) {
+ if (!skipComment(value, pos))
+ return false;
+ } else {
+ if (!skipUserAgentProduct(value, pos))
+ return false;
+ }
+ }
+
+ return pos == value.length();
+}
+#endif
+
+static const size_t maxInputSampleSize = 128;
+template<typename CharType>
+static String trimInputSample(CharType* p, size_t length)
+{
+ String s = String(p, std::min<size_t>(length, maxInputSampleSize));
+ if (length > maxInputSampleSize)
+ s.append(horizontalEllipsis);
+ return s;
+}
+
+std::optional<WallTime> parseHTTPDate(const String& value)
+{
+ double dateInMillisecondsSinceEpoch = parseDateFromNullTerminatedCharacters(value.utf8().data());
+ if (!std::isfinite(dateInMillisecondsSinceEpoch))
+ return std::nullopt;
+ // This assumes system_clock epoch equals Unix epoch which is true for all implementations but unspecified.
+ // FIXME: The parsing function should be switched to WallTime too.
+ return WallTime::fromRawSeconds(dateInMillisecondsSinceEpoch / 1000.0);
+}
+
+// FIXME: This function doesn't comply with RFC 6266.
+// For example, this function doesn't handle the interaction between " and ;
+// that arises from quoted-string, nor does this function properly unquote
+// attribute values. Further this function appears to process parameter names
+// in a case-sensitive manner. (There are likely other bugs as well.)
+String filenameFromHTTPContentDisposition(StringView value)
+{
+ for (auto keyValuePair : value.split(';')) {
+ size_t valueStartPos = keyValuePair.find('=');
+ if (valueStartPos == notFound)
+ continue;
+
+ auto key = keyValuePair.left(valueStartPos).stripWhiteSpace();
+
+ if (key.isEmpty() || key != "filename")
+ continue;
+
+ auto value = keyValuePair.substring(valueStartPos + 1).stripWhiteSpace();
+
+ // Remove quotes if there are any
+ if (value.length() > 1 && value[0] == '\"')
+ value = value.substring(1, value.length() - 2);
+
+ return value.toString();
+ }
+
+ return String();
+}
+
+String extractMIMETypeFromMediaType(const String& mediaType)
+{
+ unsigned position = 0;
+ unsigned length = mediaType.length();
+
+ for (; position < length; ++position) {
+ UChar c = mediaType[position];
+ if (c != '\t' && c != ' ')
+ break;
+ }
+
+ if (position == length)
+ return mediaType;
+
+ unsigned typeStart = position;
+
+ unsigned typeEnd = position;
+ for (; position < length; ++position) {
+ UChar c = mediaType[position];
+
+ // While RFC 2616 does not allow it, other browsers allow multiple values in the HTTP media
+ // type header field, Content-Type. In such cases, the media type string passed here may contain
+ // the multiple values separated by commas. For now, this code ignores text after the first comma,
+ // which prevents it from simply failing to parse such types altogether. Later for better
+ // compatibility we could consider using the first or last valid MIME type instead.
+ // See https://bugs.webkit.org/show_bug.cgi?id=25352 for more discussion.
+ if (c == ',')
+ break;
+
+ if (c == '\t' || c == ' ' || c == ';')
+ break;
+
+ typeEnd = position + 1;
+ }
+
+ return mediaType.substring(typeStart, typeEnd - typeStart);
+}
+
+String extractCharsetFromMediaType(const String& mediaType)
+{
+ unsigned charsetPos = 0, charsetLen = 0;
+ size_t pos = 0;
+ unsigned length = mediaType.length();
+
+ while (pos < length) {
+ pos = mediaType.findIgnoringASCIICase("charset", pos);
+ if (pos == notFound || pos == 0) {
+ charsetLen = 0;
+ break;
+ }
+
+ // is what we found a beginning of a word?
+ if (mediaType[pos-1] > ' ' && mediaType[pos-1] != ';') {
+ pos += 7;
+ continue;
+ }
+
+ pos += 7;
+
+ // skip whitespace
+ while (pos != length && mediaType[pos] <= ' ')
+ ++pos;
+
+ if (mediaType[pos++] != '=') // this "charset" substring wasn't a parameter name, but there may be others
+ continue;
+
+ while (pos != length && (mediaType[pos] <= ' ' || mediaType[pos] == '"' || mediaType[pos] == '\''))
+ ++pos;
+
+ // we don't handle spaces within quoted parameter values, because charset names cannot have any
+ unsigned endpos = pos;
+ while (pos != length && mediaType[endpos] > ' ' && mediaType[endpos] != '"' && mediaType[endpos] != '\'' && mediaType[endpos] != ';')
+ ++endpos;
+
+ charsetPos = pos;
+ charsetLen = endpos - pos;
+ break;
+ }
+ return mediaType.substring(charsetPos, charsetLen);
+}
+
+XSSProtectionDisposition parseXSSProtectionHeader(const String& header, String& failureReason, unsigned& failurePosition, String& reportURL)
+{
+ static NeverDestroyed<String> failureReasonInvalidToggle(MAKE_STATIC_STRING_IMPL("expected 0 or 1"));
+ static NeverDestroyed<String> failureReasonInvalidSeparator(MAKE_STATIC_STRING_IMPL("expected semicolon"));
+ static NeverDestroyed<String> failureReasonInvalidEquals(MAKE_STATIC_STRING_IMPL("expected equals sign"));
+ static NeverDestroyed<String> failureReasonInvalidMode(MAKE_STATIC_STRING_IMPL("invalid mode directive"));
+ static NeverDestroyed<String> failureReasonInvalidReport(MAKE_STATIC_STRING_IMPL("invalid report directive"));
+ static NeverDestroyed<String> failureReasonDuplicateMode(MAKE_STATIC_STRING_IMPL("duplicate mode directive"));
+ static NeverDestroyed<String> failureReasonDuplicateReport(MAKE_STATIC_STRING_IMPL("duplicate report directive"));
+ static NeverDestroyed<String> failureReasonInvalidDirective(MAKE_STATIC_STRING_IMPL("unrecognized directive"));
+
+ unsigned pos = 0;
+
+ if (!skipWhiteSpace(header, pos))
+ return XSSProtectionDisposition::Enabled;
+
+ if (header[pos] == '0')
+ return XSSProtectionDisposition::Disabled;
+
+ if (header[pos++] != '1') {
+ failureReason = failureReasonInvalidToggle;
+ return XSSProtectionDisposition::Invalid;
+ }
+
+ XSSProtectionDisposition result = XSSProtectionDisposition::Enabled;
+ bool modeDirectiveSeen = false;
+ bool reportDirectiveSeen = false;
+
+ while (1) {
+ // At end of previous directive: consume whitespace, semicolon, and whitespace.
+ if (!skipWhiteSpace(header, pos))
+ return result;
+
+ if (header[pos++] != ';') {
+ failureReason = failureReasonInvalidSeparator;
+ failurePosition = pos;
+ return XSSProtectionDisposition::Invalid;
+ }
+
+ if (!skipWhiteSpace(header, pos))
+ return result;
+
+ // At start of next directive.
+ if (skipToken(header, pos, "mode")) {
+ if (modeDirectiveSeen) {
+ failureReason = failureReasonDuplicateMode;
+ failurePosition = pos;
+ return XSSProtectionDisposition::Invalid;
+ }
+ modeDirectiveSeen = true;
+ if (!skipEquals(header, pos)) {
+ failureReason = failureReasonInvalidEquals;
+ failurePosition = pos;
+ return XSSProtectionDisposition::Invalid;
+ }
+ if (!skipToken(header, pos, "block")) {
+ failureReason = failureReasonInvalidMode;
+ failurePosition = pos;
+ return XSSProtectionDisposition::Invalid;
+ }
+ result = XSSProtectionDisposition::BlockEnabled;
+ } else if (skipToken(header, pos, "report")) {
+ if (reportDirectiveSeen) {
+ failureReason = failureReasonDuplicateReport;
+ failurePosition = pos;
+ return XSSProtectionDisposition::Invalid;
+ }
+ reportDirectiveSeen = true;
+ if (!skipEquals(header, pos)) {
+ failureReason = failureReasonInvalidEquals;
+ failurePosition = pos;
+ return XSSProtectionDisposition::Invalid;
+ }
+ size_t startPos = pos;
+ if (!skipValue(header, pos)) {
+ failureReason = failureReasonInvalidReport;
+ failurePosition = pos;
+ return XSSProtectionDisposition::Invalid;
+ }
+ reportURL = header.substring(startPos, pos - startPos);
+ failurePosition = startPos; // If later semantic check deems unacceptable.
+ } else {
+ failureReason = failureReasonInvalidDirective;
+ failurePosition = pos;
+ return XSSProtectionDisposition::Invalid;
+ }
+ }
+}
+
+ContentTypeOptionsDisposition parseContentTypeOptionsHeader(StringView header)
+{
+ StringView leftToken = header.left(header.find(','));
+ if (equalLettersIgnoringASCIICase(stripLeadingAndTrailingHTTPSpaces(leftToken), "nosniff"))
+ return ContentTypeOptionsDisposition::Nosniff;
+ return ContentTypeOptionsDisposition::None;
+}
+
+// For example: "HTTP/1.1 200 OK" => "OK".
+// Note that HTTP/2 does not include a reason phrase, so we return the empty atom.
+AtomString extractReasonPhraseFromHTTPStatusLine(const String& statusLine)
+{
+ StringView view = statusLine;
+ size_t spacePos = view.find(' ');
+
+ // Remove status code from the status line.
+ spacePos = view.find(' ', spacePos + 1);
+ if (spacePos == notFound)
+ return emptyAtom();
+
+ return view.substring(spacePos + 1).toAtomString();
+}
+
+XFrameOptionsDisposition parseXFrameOptionsHeader(StringView header)
+{
+ XFrameOptionsDisposition result = XFrameOptionsDisposition::None;
+
+ if (header.isEmpty())
+ return result;
+
+ for (auto currentHeader : header.split(',')) {
+ currentHeader = currentHeader.stripWhiteSpace();
+ XFrameOptionsDisposition currentValue = XFrameOptionsDisposition::None;
+ if (equalLettersIgnoringASCIICase(currentHeader, "deny"))
+ currentValue = XFrameOptionsDisposition::Deny;
+ else if (equalLettersIgnoringASCIICase(currentHeader, "sameorigin"))
+ currentValue = XFrameOptionsDisposition::SameOrigin;
+ else if (equalLettersIgnoringASCIICase(currentHeader, "allowall"))
+ currentValue = XFrameOptionsDisposition::AllowAll;
+ else
+ currentValue = XFrameOptionsDisposition::Invalid;
+
+ if (result == XFrameOptionsDisposition::None)
+ result = currentValue;
+ else if (result != currentValue)
+ return XFrameOptionsDisposition::Conflict;
+ }
+ return result;
+}
+
+// https://fetch.spec.whatwg.org/#concept-header-list-get-structured-header
+// FIXME: For now, this assumes the type is "item".
+std::optional<std::pair<StringView, HashMap<String, String>>> parseStructuredFieldValue(StringView header)
+{
+ header = stripLeadingAndTrailingHTTPSpaces(header);
+ if (header.isEmpty())
+ return std::nullopt;
+
+ // Parse a token (https://datatracker.ietf.org/doc/html/rfc8941#section-4.2.6).
+ if (!isASCIIAlpha(header[0]) && header[0] != '*')
+ return std::nullopt;
+ size_t index = 1;
+ while (index < header.length()) {
+ UChar c = header[index];
+ if (!RFC7230::isTokenCharacter(c) && c != ':' && c != '/')
+ break;
+ ++index;
+ }
+ StringView bareItem = header.substring(0, index);
+
+ // Parse parameters (https://datatracker.ietf.org/doc/html/rfc8941#section-4.2.3.2).
+ HashMap<String, String> parameters;
+ while (index < header.length()) {
+ if (header[index] != ';')
+ break;
+ ++index; // Consume ';'.
+ while (index < header.length() && header[index] == ' ')
+ ++index;
+ if (index == header.length())
+ return std::nullopt;
+ // Parse a key (https://datatracker.ietf.org/doc/html/rfc8941#section-4.2.3.3)
+ if (!isASCIILower(header[index]))
+ return std::nullopt;
+ size_t keyStart = index++;
+ while (index < header.length()) {
+ UChar c = header[index];
+ if (!isASCIILower(c) && !isASCIIDigit(c) && c != '_' && c != '-' && c != '.' && c != '*')
+ break;
+ ++index;
+ }
+ String key = header.substring(keyStart, index - keyStart).toString();
+ String value = "true";
+ if (index < header.length() && header[index] == '=') {
+ ++index; // Consume '='.
+ if (isASCIIAlpha(header[index]) || header[index] == '*') {
+ // https://datatracker.ietf.org/doc/html/rfc8941#section-4.2.6
+ size_t valueStart = index++;
+ while (index < header.length()) {
+ UChar c = header[index];
+ if (!RFC7230::isTokenCharacter(c) && c != ':' && c != '/')
+ break;
+ ++index;
+ }
+ value = header.substring(valueStart, index - valueStart).toString();
+ } else if (header[index] == '"') {
+ // https://datatracker.ietf.org/doc/html/rfc8941#section-4.2.5
+ StringBuilder valueBuilder;
+ ++index; // Skip DQUOTE.
+ while (index < header.length()) {
+ if (header[index] == '\\') {
+ ++index;
+ if (index == header.length())
+ return std::nullopt;
+ if (header[index] != '\\' && header[index] != '"')
+ return std::nullopt;
+ valueBuilder.append(header[index]);
+ } else if (header[index] == '\"') {
+ value = valueBuilder.toString();
+ break;
+ } else if (header[index] <= 0x1F || (header[index] >= 0x7F && header[index] <= 0xFF)) // Not in VCHAR or SP.
+ return std::nullopt;
+ else
+ valueBuilder.append(header[index]);
+ ++index;
+ }
+ if (index == header.length())
+ return std::nullopt;
+ ++index; // Skip DQUOTE.
+ } else
+ return std::nullopt;
+ }
+ parameters.set(WTFMove(key), WTFMove(value));
+ }
+ if (index != header.length())
+ return std::nullopt;
+ return std::make_pair(bareItem, parameters);
+}
+
+bool parseRange(const String& range, long long& rangeOffset, long long& rangeEnd, long long& rangeSuffixLength)
+{
+ // The format of "Range" header is defined in RFC 2616 Section 14.35.1.
+ // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.1
+ // We don't support multiple range requests.
+
+ rangeOffset = rangeEnd = rangeSuffixLength = -1;
+
+ // The "bytes" unit identifier should be present.
+ static const unsigned bytesLength = 6;
+ if (!startsWithLettersIgnoringASCIICase(range, "bytes="))
+ return false;
+ // FIXME: The rest of this should use StringView.
+ String byteRange = range.substring(bytesLength);
+
+ // The '-' character needs to be present.
+ int index = byteRange.find('-');
+ if (index == -1)
+ return false;
+
+ // If the '-' character is at the beginning, the suffix length, which specifies the last N bytes, is provided.
+ // Example:
+ // -500
+ if (!index) {
+ if (auto value = parseInteger<long long>(StringView { byteRange }.substring(index + 1)))
+ rangeSuffixLength = *value;
+ return true;
+ }
+
+ // Otherwise, the first-byte-position and the last-byte-position are provied.
+ // Examples:
+ // 0-499
+ // 500-
+ auto firstBytePos = parseInteger<long long>(StringView { byteRange }.left(index));
+ if (!firstBytePos)
+ return false;
+
+ auto lastBytePosStr = stripLeadingAndTrailingHTTPSpaces(StringView { byteRange }.substring(index + 1));
+ long long lastBytePos = -1;
+ if (!lastBytePosStr.isEmpty()) {
+ auto value = parseInteger<long long>(lastBytePosStr);
+ if (!value)
+ return false;
+ lastBytePos = *value;
+ }
+
+ if (*firstBytePos < 0 || !(lastBytePos == -1 || lastBytePos >= *firstBytePos))
+ return false;
+
+ rangeOffset = *firstBytePos;
+ rangeEnd = lastBytePos;
+ return true;
+}
+
+template<typename CharacterType>
+static inline bool isValidHeaderNameCharacter(CharacterType character)
+{
+ // https://tools.ietf.org/html/rfc7230#section-3.2
+ // A header name should only contain one or more of
+ // alphanumeric or ! # $ % & ' * + - . ^ _ ` | ~
+ if (isASCIIAlphanumeric(character))
+ return true;
+ switch (character) {
+ case '!':
+ case '#':
+ case '$':
+ case '%':
+ case '&':
+ case '\'':
+ case '*':
+ case '+':
+ case '-':
+ case '.':
+ case '^':
+ case '_':
+ case '`':
+ case '|':
+ case '~':
+ return true;
+ default:
+ return false;
+ }
+}
+
+size_t parseHTTPHeader(const uint8_t* start, size_t length, String& failureReason, StringView& nameStr, String& valueStr, bool strict)
+{
+ auto p = start;
+ auto end = start + length;
+
+ Vector<uint8_t> name;
+ Vector<uint8_t> value;
+
+ bool foundFirstNameChar = false;
+ const uint8_t* namePtr = nullptr;
+ size_t nameSize = 0;
+
+ nameStr = StringView();
+ valueStr = String();
+
+ for (; p < end; p++) {
+ switch (*p) {
+ case '\r':
+ if (name.isEmpty()) {
+ if (p + 1 < end && *(p + 1) == '\n')
+ return (p + 2) - start;
+ failureReason = makeString("CR doesn't follow LF in header name at ", trimInputSample(p, end - p));
+ return 0;
+ }
+ failureReason = makeString("Unexpected CR in header name at ", trimInputSample(name.data(), name.size()));
+ return 0;
+ case '\n':
+ failureReason = makeString("Unexpected LF in header name at ", trimInputSample(name.data(), name.size()));
+ return 0;
+ case ':':
+ break;
+ default:
+ if (!isValidHeaderNameCharacter(*p)) {
+ if (name.size() < 1)
+ failureReason = "Unexpected start character in header name";
+ else
+ failureReason = makeString("Unexpected character in header name at ", trimInputSample(name.data(), name.size()));
+ return 0;
+ }
+ name.append(*p);
+ if (!foundFirstNameChar) {
+ namePtr = p;
+ foundFirstNameChar = true;
+ }
+ continue;
+ }
+ if (*p == ':') {
+ ++p;
+ break;
+ }
+ }
+
+ nameSize = name.size();
+ nameStr = StringView(namePtr, nameSize);
+
+ for (; p < end && *p == 0x20; p++) { }
+
+ for (; p < end; p++) {
+ switch (*p) {
+ case '\r':
+ break;
+ case '\n':
+ if (strict) {
+ failureReason = makeString("Unexpected LF in header value at ", trimInputSample(value.data(), value.size()));
+ return 0;
+ }
+ break;
+ default:
+ value.append(*p);
+ }
+ if (*p == '\r' || (!strict && *p == '\n')) {
+ ++p;
+ break;
+ }
+ }
+ if (p >= end || (strict && *p != '\n')) {
+ failureReason = makeString("CR doesn't follow LF after header value at ", trimInputSample(p, end - p));
+ return 0;
+ }
+ valueStr = String::fromUTF8(value.data(), value.size());
+ if (valueStr.isNull()) {
+ failureReason = "Invalid UTF-8 sequence in header value"_s;
+ return 0;
+ }
+ return p - start;
+}
+
+size_t parseHTTPRequestBody(const uint8_t* data, size_t length, Vector<uint8_t>& body)
+{
+ body.clear();
+ body.append(data, length);
+
+ return length;
+}
+
+// Implements <https://fetch.spec.whatwg.org/#forbidden-header-name>.
+bool isForbiddenHeaderName(const String& name)
+{
+ HTTPHeaderName headerName;
+ if (findHTTPHeaderName(name, headerName)) {
+ switch (headerName) {
+ case HTTPHeaderName::AcceptCharset:
+ case HTTPHeaderName::AcceptEncoding:
+ case HTTPHeaderName::AccessControlRequestHeaders:
+ case HTTPHeaderName::AccessControlRequestMethod:
+ case HTTPHeaderName::Connection:
+ case HTTPHeaderName::ContentLength:
+ case HTTPHeaderName::Cookie:
+ case HTTPHeaderName::Cookie2:
+ case HTTPHeaderName::Date:
+ case HTTPHeaderName::DNT:
+ case HTTPHeaderName::Expect:
+ case HTTPHeaderName::Host:
+ case HTTPHeaderName::KeepAlive:
+ case HTTPHeaderName::Origin:
+ case HTTPHeaderName::Referer:
+ case HTTPHeaderName::TE:
+ case HTTPHeaderName::Trailer:
+ case HTTPHeaderName::TransferEncoding:
+ case HTTPHeaderName::Upgrade:
+ case HTTPHeaderName::Via:
+ return true;
+ default:
+ break;
+ }
+ }
+ return startsWithLettersIgnoringASCIICase(name, "sec-") || startsWithLettersIgnoringASCIICase(name, "proxy-");
+}
+
+// Implements <https://fetch.spec.whatwg.org/#no-cors-safelisted-request-header-name>.
+bool isNoCORSSafelistedRequestHeaderName(const String& name)
+{
+ HTTPHeaderName headerName;
+ if (findHTTPHeaderName(name, headerName)) {
+ switch (headerName) {
+ case HTTPHeaderName::Accept:
+ case HTTPHeaderName::AcceptLanguage:
+ case HTTPHeaderName::ContentLanguage:
+ case HTTPHeaderName::ContentType:
+ return true;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+// Implements <https://fetch.spec.whatwg.org/#privileged-no-cors-request-header-name>.
+bool isPriviledgedNoCORSRequestHeaderName(const String& name)
+{
+ return equalLettersIgnoringASCIICase(name, "range");
+}
+
+// Implements <https://fetch.spec.whatwg.org/#forbidden-response-header-name>.
+bool isForbiddenResponseHeaderName(const String& name)
+{
+ return equalLettersIgnoringASCIICase(name, "set-cookie") || equalLettersIgnoringASCIICase(name, "set-cookie2");
+}
+
+// Implements <https://fetch.spec.whatwg.org/#forbidden-method>.
+bool isForbiddenMethod(const String& name)
+{
+ return equalLettersIgnoringASCIICase(name, "connect") || equalLettersIgnoringASCIICase(name, "trace") || equalLettersIgnoringASCIICase(name, "track");
+}
+
+bool isSimpleHeader(const String& name, const String& value)
+{
+ HTTPHeaderName headerName;
+ if (!findHTTPHeaderName(name, headerName))
+ return false;
+ return isCrossOriginSafeRequestHeader(headerName, value);
+}
+
+bool isCrossOriginSafeHeader(HTTPHeaderName name, const HTTPHeaderSet& accessControlExposeHeaderSet)
+{
+ switch (name) {
+ case HTTPHeaderName::CacheControl:
+ case HTTPHeaderName::ContentLanguage:
+ case HTTPHeaderName::ContentLength:
+ case HTTPHeaderName::ContentType:
+ case HTTPHeaderName::Expires:
+ case HTTPHeaderName::LastModified:
+ case HTTPHeaderName::Pragma:
+ case HTTPHeaderName::Accept:
+ return true;
+ case HTTPHeaderName::SetCookie:
+ case HTTPHeaderName::SetCookie2:
+ return false;
+ default:
+ break;
+ }
+ return accessControlExposeHeaderSet.contains(httpHeaderNameString(name).toStringWithoutCopying());
+}
+
+bool isCrossOriginSafeHeader(const String& name, const HTTPHeaderSet& accessControlExposeHeaderSet)
+{
+#if ASSERT_ENABLED
+ HTTPHeaderName headerName;
+ ASSERT(!findHTTPHeaderName(name, headerName));
+#endif
+ return accessControlExposeHeaderSet.contains(name);
+}
+
+// Implements https://fetch.spec.whatwg.org/#cors-safelisted-request-header
+bool isCrossOriginSafeRequestHeader(HTTPHeaderName name, const String& value)
+{
+ switch (name) {
+ case HTTPHeaderName::Accept:
+ if (!isValidAcceptHeaderValue(value))
+ return false;
+ break;
+ case HTTPHeaderName::AcceptLanguage:
+ case HTTPHeaderName::ContentLanguage:
+ if (!isValidLanguageHeaderValue(value))
+ return false;
+ break;
+ case HTTPHeaderName::ContentType: {
+ // Preflight is required for MIME types that can not be sent via form submission.
+ if (containsCORSUnsafeRequestHeaderBytes(value))
+ return false;
+ auto parsedContentType = ParsedContentType::create(value);
+ if (!parsedContentType)
+ return false;
+ String mimeType = parsedContentType->mimeType();
+ if (!(equalLettersIgnoringASCIICase(mimeType, "application/x-www-form-urlencoded") || equalLettersIgnoringASCIICase(mimeType, "multipart/form-data") || equalLettersIgnoringASCIICase(mimeType, "text/plain")))
+ return false;
+ break;
+ }
+ default:
+ // FIXME: Should we also make safe other headers (DPR, Downlink, Save-Data...)? That would require validating their values.
+ return false;
+ }
+ return value.length() <= 128;
+}
+
+// Implements <https://fetch.spec.whatwg.org/#concept-method-normalize>.
+String normalizeHTTPMethod(const String& method)
+{
+ const ASCIILiteral methods[] = { "DELETE"_s, "GET"_s, "HEAD"_s, "OPTIONS"_s, "POST"_s, "PUT"_s };
+ for (auto value : methods) {
+ if (equalIgnoringASCIICase(method, value.characters())) {
+ // Don't bother allocating a new string if it's already all uppercase.
+ if (method == value)
+ break;
+ return value;
+ }
+ }
+ return method;
+}
+
+// Defined by https://tools.ietf.org/html/rfc7231#section-4.2.1
+bool isSafeMethod(const String& method)
+{
+ const ASCIILiteral safeMethods[] = { "GET"_s, "HEAD"_s, "OPTIONS"_s, "TRACE"_s };
+ for (auto value : safeMethods) {
+ if (equalIgnoringASCIICase(method, value.characters()))
+ return true;
+ }
+ return false;
+}
+
+CrossOriginResourcePolicy parseCrossOriginResourcePolicyHeader(StringView header)
+{
+ auto strippedHeader = stripLeadingAndTrailingHTTPSpaces(header);
+
+ if (strippedHeader.isEmpty())
+ return CrossOriginResourcePolicy::None;
+
+ if (strippedHeader == "same-origin")
+ return CrossOriginResourcePolicy::SameOrigin;
+
+ if (strippedHeader == "same-site")
+ return CrossOriginResourcePolicy::SameSite;
+
+ if (strippedHeader == "cross-origin")
+ return CrossOriginResourcePolicy::CrossOrigin;
+
+ return CrossOriginResourcePolicy::Invalid;
+}
+
+}
diff --git a/src/javascript/jsc/bindings/webcore/HTTPParsers.h b/src/javascript/jsc/bindings/webcore/HTTPParsers.h
new file mode 100644
index 000000000..920a5a5b6
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/HTTPParsers.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2011 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/HashSet.h>
+#include <wtf/WallTime.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+typedef HashSet<String, ASCIICaseInsensitiveHash> HTTPHeaderSet;
+
+enum class HTTPHeaderName;
+
+enum class XSSProtectionDisposition {
+ Invalid,
+ Disabled,
+ Enabled,
+ BlockEnabled,
+};
+
+enum class ContentTypeOptionsDisposition : bool {
+ None,
+ Nosniff
+};
+
+enum class XFrameOptionsDisposition : uint8_t {
+ None,
+ Deny,
+ SameOrigin,
+ AllowAll,
+ Invalid,
+ Conflict
+};
+
+enum class CrossOriginResourcePolicy : uint8_t {
+ None,
+ CrossOrigin,
+ SameOrigin,
+ SameSite,
+ Invalid
+};
+
+bool isValidReasonPhrase(const String&);
+bool isValidHTTPHeaderValue(const String&);
+bool isValidAcceptHeaderValue(const String&);
+bool isValidLanguageHeaderValue(const String&);
+#if USE(GLIB)
+WEBCORE_EXPORT bool isValidUserAgentHeaderValue(const String&);
+#endif
+bool isValidHTTPToken(const String&);
+bool isValidHTTPToken(StringView);
+std::optional<WallTime> parseHTTPDate(const String&);
+String filenameFromHTTPContentDisposition(StringView);
+WEBCORE_EXPORT String extractMIMETypeFromMediaType(const String&);
+String extractCharsetFromMediaType(const String&);
+XSSProtectionDisposition parseXSSProtectionHeader(const String& header, String& failureReason, unsigned& failurePosition, String& reportURL);
+AtomString extractReasonPhraseFromHTTPStatusLine(const String&);
+WEBCORE_EXPORT XFrameOptionsDisposition parseXFrameOptionsHeader(StringView);
+std::optional<std::pair<StringView, HashMap<String, String>>> parseStructuredFieldValue(StringView header);
+
+// -1 could be set to one of the return parameters to indicate the value is not specified.
+WEBCORE_EXPORT bool parseRange(const String&, long long& rangeOffset, long long& rangeEnd, long long& rangeSuffixLength);
+
+ContentTypeOptionsDisposition parseContentTypeOptionsHeader(StringView header);
+
+// Parsing Complete HTTP Messages.
+size_t parseHTTPHeader(const uint8_t* data, size_t length, String& failureReason, StringView& nameStr, String& valueStr, bool strict = true);
+size_t parseHTTPRequestBody(const uint8_t* data, size_t length, Vector<uint8_t>& body);
+
+// HTTP Header routine as per https://fetch.spec.whatwg.org/#terminology-headers
+bool isForbiddenHeaderName(const String&);
+bool isNoCORSSafelistedRequestHeaderName(const String&);
+bool isPriviledgedNoCORSRequestHeaderName(const String&);
+bool isForbiddenResponseHeaderName(const String&);
+bool isForbiddenMethod(const String&);
+bool isSimpleHeader(const String& name, const String& value);
+bool isCrossOriginSafeHeader(HTTPHeaderName, const HTTPHeaderSet&);
+bool isCrossOriginSafeHeader(const String&, const HTTPHeaderSet&);
+bool isCrossOriginSafeRequestHeader(HTTPHeaderName, const String&);
+
+String normalizeHTTPMethod(const String&);
+bool isSafeMethod(const String&);
+
+WEBCORE_EXPORT CrossOriginResourcePolicy parseCrossOriginResourcePolicyHeader(StringView);
+
+inline bool isHTTPSpace(UChar character)
+{
+ return character <= ' ' && (character == ' ' || character == '\n' || character == '\t' || character == '\r');
+}
+
+// Strip leading and trailing whitespace as defined in https://fetch.spec.whatwg.org/#concept-header-value-normalize.
+inline String stripLeadingAndTrailingHTTPSpaces(const String& string)
+{
+ return string.stripLeadingAndTrailingCharacters(isHTTPSpace);
+}
+
+inline StringView stripLeadingAndTrailingHTTPSpaces(StringView string)
+{
+ return string.stripLeadingAndTrailingMatchedCharacters(isHTTPSpace);
+}
+
+template<class HashType>
+bool addToAccessControlAllowList(const String& string, unsigned start, unsigned end, HashSet<String, HashType>& set)
+{
+ StringImpl* stringImpl = string.impl();
+ if (!stringImpl)
+ return true;
+
+ // Skip white space from start.
+ while (start <= end && isHTTPSpace((*stringImpl)[start]))
+ ++start;
+
+ // only white space
+ if (start > end)
+ return true;
+
+ // Skip white space from end.
+ while (end && isHTTPSpace((*stringImpl)[end]))
+ --end;
+
+ auto token = string.substring(start, end - start + 1);
+ if (!isValidHTTPToken(token))
+ return false;
+
+ set.add(WTFMove(token));
+ return true;
+}
+
+template<class HashType = DefaultHash<String>>
+std::optional<HashSet<String, HashType>> parseAccessControlAllowList(const String& string)
+{
+ HashSet<String, HashType> set;
+ unsigned start = 0;
+ size_t end;
+ while ((end = string.find(',', start)) != notFound) {
+ if (start != end) {
+ if (!addToAccessControlAllowList(string, start, end - 1, set))
+ return { };
+ }
+ start = end + 1;
+ }
+ if (start != string.length()) {
+ if (!addToAccessControlAllowList(string, start, string.length() - 1, set))
+ return { };
+ }
+ return set;
+}
+
+}
diff --git a/src/javascript/jsc/bindings/webcore/JSFetchHeaders.cpp b/src/javascript/jsc/bindings/webcore/JSFetchHeaders.cpp
new file mode 100644
index 000000000..91d79388b
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/JSFetchHeaders.cpp
@@ -0,0 +1,502 @@
+/*
+ This file is part of the WebKit open source project.
+ This file has been generated by generate-bindings.pl. DO NOT MODIFY!
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#include "JSFetchHeaders.h"
+
+#include "ActiveDOMObject.h"
+#include "ExtendedDOMClientIsoSubspaces.h"
+#include "ExtendedDOMIsoSubspaces.h"
+#include "IDLTypes.h"
+#include "JSDOMBinding.h"
+#include "JSDOMConstructor.h"
+#include "JSDOMConvertBase.h"
+#include "JSDOMConvertBoolean.h"
+#include "JSDOMConvertInterface.h"
+#include "JSDOMConvertNullable.h"
+#include "JSDOMConvertRecord.h"
+#include "JSDOMConvertSequences.h"
+#include "JSDOMConvertStrings.h"
+#include "JSDOMConvertUnion.h"
+#include "JSDOMExceptionHandling.h"
+#include "JSDOMGlobalObjectInlines.h"
+#include "JSDOMIterator.h"
+#include "JSDOMOperation.h"
+#include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "WebCoreJSClientData.h"
+#include <JavaScriptCore/BuiltinNames.h>
+#include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapAnalyzer.h>
+#include <JavaScriptCore/JSArray.h>
+#include <JavaScriptCore/JSCInlines.h>
+#include <JavaScriptCore/JSDestructibleObjectHeapCellType.h>
+#include <JavaScriptCore/SlotVisitorMacros.h>
+#include <JavaScriptCore/SubspaceInlines.h>
+#include <variant>
+#include <wtf/GetPtr.h>
+#include <wtf/PointerPreparations.h>
+#include <wtf/URL.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+using namespace JSC;
+
+// Functions
+
+static JSC_DECLARE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_append);
+static JSC_DECLARE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_delete);
+static JSC_DECLARE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_get);
+static JSC_DECLARE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_has);
+static JSC_DECLARE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_set);
+static JSC_DECLARE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_entries);
+static JSC_DECLARE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_keys);
+static JSC_DECLARE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_values);
+static JSC_DECLARE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_forEach);
+
+// Attributes
+
+static JSC_DECLARE_CUSTOM_GETTER(jsFetchHeadersConstructor);
+
+class JSFetchHeadersPrototype final : public JSC::JSNonFinalObject {
+public:
+ using Base = JSC::JSNonFinalObject;
+ static JSFetchHeadersPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure)
+ {
+ JSFetchHeadersPrototype* ptr = new (NotNull, JSC::allocateCell<JSFetchHeadersPrototype>(vm)) JSFetchHeadersPrototype(vm, globalObject, structure);
+ ptr->finishCreation(vm);
+ return ptr;
+ }
+
+ DECLARE_INFO;
+ template<typename CellType, JSC::SubspaceAccess>
+ static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSFetchHeadersPrototype, Base);
+ return &vm.plainObjectSpace();
+ }
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+private:
+ JSFetchHeadersPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure)
+ : JSC::JSNonFinalObject(vm, structure)
+ {
+ }
+
+ void finishCreation(JSC::VM&);
+};
+STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSFetchHeadersPrototype, JSFetchHeadersPrototype::Base);
+
+using JSFetchHeadersDOMConstructor = JSDOMConstructor<JSFetchHeaders>;
+
+template<> EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSFetchHeadersDOMConstructor::construct(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame)
+{
+ VM& vm = lexicalGlobalObject->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ auto* castedThis = jsCast<JSFetchHeadersDOMConstructor*>(callFrame->jsCallee());
+ ASSERT(castedThis);
+ EnsureStillAliveScope argument0 = callFrame->argument(0);
+ auto init = argument0.value().isUndefined() ? std::optional<Converter<IDLUnion<IDLSequence<IDLSequence<IDLByteString>>, IDLRecord<IDLByteString, IDLByteString>>>::ReturnType>() : std::optional<Converter<IDLUnion<IDLSequence<IDLSequence<IDLByteString>>, IDLRecord<IDLByteString, IDLByteString>>>::ReturnType>(convert<IDLUnion<IDLSequence<IDLSequence<IDLByteString>>, IDLRecord<IDLByteString, IDLByteString>>>(*lexicalGlobalObject, argument0.value()));
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+ auto object = FetchHeaders::create(WTFMove(init));
+ if constexpr (IsExceptionOr<decltype(object)>)
+ RETURN_IF_EXCEPTION(throwScope, {});
+ static_assert(TypeOrExceptionOrUnderlyingType<decltype(object)>::isRef);
+ auto jsValue = toJSNewlyCreated<IDLInterface<FetchHeaders>>(*lexicalGlobalObject, *castedThis->globalObject(), throwScope, WTFMove(object));
+ if constexpr (IsExceptionOr<decltype(object)>)
+ RETURN_IF_EXCEPTION(throwScope, {});
+ setSubclassStructureIfNeeded<FetchHeaders>(lexicalGlobalObject, callFrame, asObject(jsValue));
+ RETURN_IF_EXCEPTION(throwScope, {});
+ return JSValue::encode(jsValue);
+}
+JSC_ANNOTATE_HOST_FUNCTION(JSFetchHeadersDOMConstructorConstruct, JSFetchHeadersDOMConstructor::construct);
+
+template<> const ClassInfo JSFetchHeadersDOMConstructor::s_info = { "Headers"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSFetchHeadersDOMConstructor) };
+
+template<> JSValue JSFetchHeadersDOMConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject)
+{
+ UNUSED_PARAM(vm);
+ return globalObject.functionPrototype();
+}
+
+template<> void JSFetchHeadersDOMConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject)
+{
+ putDirect(vm, vm.propertyNames->length, jsNumber(0), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
+ JSString* nameString = jsNontrivialString(vm, "Headers"_s);
+ m_originalName.set(vm, this, nameString);
+ putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
+ putDirect(vm, vm.propertyNames->prototype, JSFetchHeaders::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete);
+}
+
+/* Hash table for prototype */
+
+static const HashTableValue JSFetchHeadersPrototypeTableValues[] = {
+ { "constructor", static_cast<unsigned>(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { (intptr_t) static_cast<PropertySlot::GetValueFunc>(jsFetchHeadersConstructor), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(0) } },
+ { "append", static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(jsFetchHeadersPrototypeFunction_append), (intptr_t)(2) } },
+ { "delete", static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(jsFetchHeadersPrototypeFunction_delete), (intptr_t)(1) } },
+ { "get", static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(jsFetchHeadersPrototypeFunction_get), (intptr_t)(1) } },
+ { "has", static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(jsFetchHeadersPrototypeFunction_has), (intptr_t)(1) } },
+ { "set", static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(jsFetchHeadersPrototypeFunction_set), (intptr_t)(2) } },
+ { "entries", static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(jsFetchHeadersPrototypeFunction_entries), (intptr_t)(0) } },
+ { "keys", static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(jsFetchHeadersPrototypeFunction_keys), (intptr_t)(0) } },
+ { "values", static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(jsFetchHeadersPrototypeFunction_values), (intptr_t)(0) } },
+ { "forEach", static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t) static_cast<RawNativeFunction>(jsFetchHeadersPrototypeFunction_forEach), (intptr_t)(1) } },
+};
+
+const ClassInfo JSFetchHeadersPrototype::s_info = { "Headers"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSFetchHeadersPrototype) };
+
+void JSFetchHeadersPrototype::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ reifyStaticProperties(vm, JSFetchHeaders::info(), JSFetchHeadersPrototypeTableValues, *this);
+ putDirect(vm, vm.propertyNames->iteratorSymbol, getDirect(vm, vm.propertyNames->builtinNames().entriesPublicName()), static_cast<unsigned>(JSC::PropertyAttribute::DontEnum));
+ JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
+}
+
+const ClassInfo JSFetchHeaders::s_info = { "Headers"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSFetchHeaders) };
+
+JSFetchHeaders::JSFetchHeaders(Structure* structure, JSDOMGlobalObject& globalObject, Ref<FetchHeaders>&& impl)
+ : JSDOMWrapper<FetchHeaders>(structure, globalObject, WTFMove(impl))
+{
+}
+
+void JSFetchHeaders::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(vm, info()));
+
+ // static_assert(!std::is_base_of<ActiveDOMObject, FetchHeaders>::value, "Interface is not marked as [ActiveDOMObject] even though implementation class subclasses ActiveDOMObject.");
+}
+
+JSObject* JSFetchHeaders::createPrototype(VM& vm, JSDOMGlobalObject& globalObject)
+{
+ return JSFetchHeadersPrototype::create(vm, &globalObject, JSFetchHeadersPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype()));
+}
+
+JSObject* JSFetchHeaders::prototype(VM& vm, JSDOMGlobalObject& globalObject)
+{
+ return getDOMPrototype<JSFetchHeaders>(vm, globalObject);
+}
+
+JSValue JSFetchHeaders::getConstructor(VM& vm, const JSGlobalObject* globalObject)
+{
+ return getDOMConstructor<JSFetchHeadersDOMConstructor, DOMConstructorID::FetchHeaders>(vm, *jsCast<const JSDOMGlobalObject*>(globalObject));
+}
+
+void JSFetchHeaders::destroy(JSC::JSCell* cell)
+{
+ JSFetchHeaders* thisObject = static_cast<JSFetchHeaders*>(cell);
+ thisObject->JSFetchHeaders::~JSFetchHeaders();
+}
+
+JSC_DEFINE_CUSTOM_GETTER(jsFetchHeadersConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName))
+{
+ VM& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ auto* prototype = jsDynamicCast<JSFetchHeadersPrototype*>(vm, JSValue::decode(thisValue));
+ if (UNLIKELY(!prototype))
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ return JSValue::encode(JSFetchHeaders::getConstructor(JSC::getVM(lexicalGlobalObject), prototype->globalObject()));
+}
+
+static inline JSC::EncodedJSValue jsFetchHeadersPrototypeFunction_appendBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSFetchHeaders>::ClassParameter castedThis)
+{
+ auto& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ UNUSED_PARAM(throwScope);
+ UNUSED_PARAM(callFrame);
+ auto& impl = castedThis->wrapped();
+ if (UNLIKELY(callFrame->argumentCount() < 2))
+ return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
+ EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0);
+ auto name = convert<IDLByteString>(*lexicalGlobalObject, argument0.value());
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+ EnsureStillAliveScope argument1 = callFrame->uncheckedArgument(1);
+ auto value = convert<IDLByteString>(*lexicalGlobalObject, argument1.value());
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.append(WTFMove(name), WTFMove(value)); })));
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_append, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ return IDLOperation<JSFetchHeaders>::call<jsFetchHeadersPrototypeFunction_appendBody>(*lexicalGlobalObject, *callFrame, "append");
+}
+
+static inline JSC::EncodedJSValue jsFetchHeadersPrototypeFunction_deleteBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSFetchHeaders>::ClassParameter castedThis)
+{
+ auto& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ UNUSED_PARAM(throwScope);
+ UNUSED_PARAM(callFrame);
+ auto& impl = castedThis->wrapped();
+ if (UNLIKELY(callFrame->argumentCount() < 1))
+ return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
+ EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0);
+ auto name = convert<IDLByteString>(*lexicalGlobalObject, argument0.value());
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.remove(WTFMove(name)); })));
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_delete, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ return IDLOperation<JSFetchHeaders>::call<jsFetchHeadersPrototypeFunction_deleteBody>(*lexicalGlobalObject, *callFrame, "delete");
+}
+
+static inline JSC::EncodedJSValue jsFetchHeadersPrototypeFunction_getBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSFetchHeaders>::ClassParameter castedThis)
+{
+ auto& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ UNUSED_PARAM(throwScope);
+ UNUSED_PARAM(callFrame);
+ auto& impl = castedThis->wrapped();
+ if (UNLIKELY(callFrame->argumentCount() < 1))
+ return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
+ EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0);
+ auto name = convert<IDLByteString>(*lexicalGlobalObject, argument0.value());
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS<IDLNullable<IDLByteString>>(*lexicalGlobalObject, throwScope, impl.get(WTFMove(name)))));
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_get, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ return IDLOperation<JSFetchHeaders>::call<jsFetchHeadersPrototypeFunction_getBody>(*lexicalGlobalObject, *callFrame, "get");
+}
+
+static inline JSC::EncodedJSValue jsFetchHeadersPrototypeFunction_hasBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSFetchHeaders>::ClassParameter castedThis)
+{
+ auto& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ UNUSED_PARAM(throwScope);
+ UNUSED_PARAM(callFrame);
+ auto& impl = castedThis->wrapped();
+ if (UNLIKELY(callFrame->argumentCount() < 1))
+ return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
+ EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0);
+ auto name = convert<IDLByteString>(*lexicalGlobalObject, argument0.value());
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS<IDLBoolean>(*lexicalGlobalObject, throwScope, impl.has(WTFMove(name)))));
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_has, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ return IDLOperation<JSFetchHeaders>::call<jsFetchHeadersPrototypeFunction_hasBody>(*lexicalGlobalObject, *callFrame, "has");
+}
+
+static inline JSC::EncodedJSValue jsFetchHeadersPrototypeFunction_setBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSFetchHeaders>::ClassParameter castedThis)
+{
+ auto& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ UNUSED_PARAM(throwScope);
+ UNUSED_PARAM(callFrame);
+ auto& impl = castedThis->wrapped();
+ if (UNLIKELY(callFrame->argumentCount() < 2))
+ return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
+ EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0);
+ auto name = convert<IDLByteString>(*lexicalGlobalObject, argument0.value());
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+ EnsureStillAliveScope argument1 = callFrame->uncheckedArgument(1);
+ auto value = convert<IDLByteString>(*lexicalGlobalObject, argument1.value());
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.set(WTFMove(name), WTFMove(value)); })));
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_set, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ return IDLOperation<JSFetchHeaders>::call<jsFetchHeadersPrototypeFunction_setBody>(*lexicalGlobalObject, *callFrame, "set");
+}
+
+struct FetchHeadersIteratorTraits {
+ static constexpr JSDOMIteratorType type = JSDOMIteratorType::Map;
+ using KeyType = IDLByteString;
+ using ValueType = IDLByteString;
+};
+
+using FetchHeadersIteratorBase = JSDOMIteratorBase<JSFetchHeaders, FetchHeadersIteratorTraits>;
+class FetchHeadersIterator final : public FetchHeadersIteratorBase {
+public:
+ using Base = FetchHeadersIteratorBase;
+ DECLARE_INFO;
+
+ template<typename, SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ if constexpr (mode == JSC::SubspaceAccess::Concurrently)
+ return nullptr;
+ return WebCore::subspaceForImpl<FetchHeadersIterator, UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForFetchHeadersIterator.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForFetchHeadersIterator = WTFMove(space); },
+ [](auto& spaces) { return spaces.m_subspaceForFetchHeadersIterator.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForFetchHeadersIterator = WTFMove(space); });
+ }
+
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+ static FetchHeadersIterator* create(JSC::VM& vm, JSC::Structure* structure, JSFetchHeaders& iteratedObject, IterationKind kind)
+ {
+ auto* instance = new (NotNull, JSC::allocateCell<FetchHeadersIterator>(vm)) FetchHeadersIterator(structure, iteratedObject, kind);
+ instance->finishCreation(vm);
+ return instance;
+ }
+
+private:
+ FetchHeadersIterator(JSC::Structure* structure, JSFetchHeaders& iteratedObject, IterationKind kind)
+ : Base(structure, iteratedObject, kind)
+ {
+ }
+};
+
+using FetchHeadersIteratorPrototype = JSDOMIteratorPrototype<JSFetchHeaders, FetchHeadersIteratorTraits>;
+JSC_ANNOTATE_HOST_FUNCTION(FetchHeadersIteratorPrototypeNext, FetchHeadersIteratorPrototype::next);
+
+template<>
+const JSC::ClassInfo FetchHeadersIteratorBase::s_info = { "Headers Iterator"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(FetchHeadersIteratorBase) };
+const JSC::ClassInfo FetchHeadersIterator::s_info = { "Headers Iterator"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(FetchHeadersIterator) };
+
+template<>
+const JSC::ClassInfo FetchHeadersIteratorPrototype::s_info = { "Headers Iterator"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(FetchHeadersIteratorPrototype) };
+
+static inline EncodedJSValue jsFetchHeadersPrototypeFunction_entriesCaller(JSGlobalObject*, CallFrame*, JSFetchHeaders* thisObject)
+{
+ return JSValue::encode(iteratorCreate<FetchHeadersIterator>(*thisObject, IterationKind::Entries));
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_entries, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
+{
+ return IDLOperation<JSFetchHeaders>::call<jsFetchHeadersPrototypeFunction_entriesCaller>(*lexicalGlobalObject, *callFrame, "entries");
+}
+
+static inline EncodedJSValue jsFetchHeadersPrototypeFunction_keysCaller(JSGlobalObject*, CallFrame*, JSFetchHeaders* thisObject)
+{
+ return JSValue::encode(iteratorCreate<FetchHeadersIterator>(*thisObject, IterationKind::Keys));
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_keys, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
+{
+ return IDLOperation<JSFetchHeaders>::call<jsFetchHeadersPrototypeFunction_keysCaller>(*lexicalGlobalObject, *callFrame, "keys");
+}
+
+static inline EncodedJSValue jsFetchHeadersPrototypeFunction_valuesCaller(JSGlobalObject*, CallFrame*, JSFetchHeaders* thisObject)
+{
+ return JSValue::encode(iteratorCreate<FetchHeadersIterator>(*thisObject, IterationKind::Values));
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_values, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
+{
+ return IDLOperation<JSFetchHeaders>::call<jsFetchHeadersPrototypeFunction_valuesCaller>(*lexicalGlobalObject, *callFrame, "values");
+}
+
+static inline EncodedJSValue jsFetchHeadersPrototypeFunction_forEachCaller(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame, JSFetchHeaders* thisObject)
+{
+ return JSValue::encode(iteratorForEach<FetchHeadersIterator>(*lexicalGlobalObject, *callFrame, *thisObject));
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_forEach, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
+{
+ return IDLOperation<JSFetchHeaders>::call<jsFetchHeadersPrototypeFunction_forEachCaller>(*lexicalGlobalObject, *callFrame, "forEach");
+}
+
+JSC::GCClient::IsoSubspace* JSFetchHeaders::subspaceForImpl(JSC::VM& vm)
+{
+ return WebCore::subspaceForImpl<JSFetchHeaders, UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForFetchHeaders.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForFetchHeaders = WTFMove(space); },
+ [](auto& spaces) { return spaces.m_subspaceForFetchHeaders.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForFetchHeaders = WTFMove(space); });
+}
+
+void JSFetchHeaders::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer)
+{
+ auto* thisObject = jsCast<JSFetchHeaders*>(cell);
+ analyzer.setWrappedObjectForCell(cell, &thisObject->wrapped());
+ if (thisObject->scriptExecutionContext())
+ analyzer.setLabelForCell(cell, "url " + thisObject->scriptExecutionContext()->url().string());
+ Base::analyzeHeap(cell, analyzer);
+}
+
+bool JSFetchHeadersOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, AbstractSlotVisitor& visitor, const char** reason)
+{
+ UNUSED_PARAM(handle);
+ UNUSED_PARAM(visitor);
+ UNUSED_PARAM(reason);
+ return false;
+}
+
+void JSFetchHeadersOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)
+{
+ auto* jsFetchHeaders = static_cast<JSFetchHeaders*>(handle.slot()->asCell());
+ auto& world = *static_cast<DOMWrapperWorld*>(context);
+ uncacheWrapper(world, &jsFetchHeaders->wrapped(), jsFetchHeaders);
+}
+
+#if ENABLE(BINDING_INTEGRITY)
+#if PLATFORM(WIN)
+#pragma warning(disable : 4483)
+extern "C" {
+extern void (*const __identifier("??_7FetchHeaders@WebCore@@6B@")[])();
+}
+#else
+extern "C" {
+extern void* _ZTVN7WebCore12FetchHeadersE[];
+}
+#endif
+#endif
+
+JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject* globalObject, Ref<FetchHeaders>&& impl)
+{
+
+ if constexpr (std::is_polymorphic_v<FetchHeaders>) {
+#if ENABLE(BINDING_INTEGRITY)
+ const void* actualVTablePointer = getVTablePointer(impl.ptr());
+#if PLATFORM(WIN)
+ void* expectedVTablePointer = __identifier("??_7FetchHeaders@WebCore@@6B@");
+#else
+ void* expectedVTablePointer = &_ZTVN7WebCore12FetchHeadersE[2];
+#endif
+
+ // If you hit this assertion you either have a use after free bug, or
+ // FetchHeaders has subclasses. If FetchHeaders has subclasses that get passed
+ // to toJS() we currently require FetchHeaders you to opt out of binding hardening
+ // by adding the SkipVTableValidation attribute to the interface IDL definition
+ RELEASE_ASSERT(actualVTablePointer == expectedVTablePointer);
+#endif
+ }
+ return createWrapper<FetchHeaders>(globalObject, WTFMove(impl));
+}
+
+JSC::JSValue toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, FetchHeaders& impl)
+{
+ return wrap(lexicalGlobalObject, globalObject, impl);
+}
+
+FetchHeaders* JSFetchHeaders::toWrapped(JSC::VM& vm, JSC::JSValue value)
+{
+ if (auto* wrapper = jsDynamicCast<JSFetchHeaders*>(vm, value))
+ return &wrapper->wrapped();
+ return nullptr;
+}
+
+}
diff --git a/src/javascript/jsc/bindings/webcore/JSFetchHeaders.dep b/src/javascript/jsc/bindings/webcore/JSFetchHeaders.dep
new file mode 100644
index 000000000..e553164bd
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/JSFetchHeaders.dep
@@ -0,0 +1 @@
+JSFetchHeaders.h :
diff --git a/src/javascript/jsc/bindings/webcore/JSFetchHeaders.h b/src/javascript/jsc/bindings/webcore/JSFetchHeaders.h
new file mode 100644
index 000000000..4761e3a66
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/JSFetchHeaders.h
@@ -0,0 +1,93 @@
+/*
+ This file is part of the WebKit open source project.
+ This file has been generated by generate-bindings.pl. DO NOT MODIFY!
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#pragma once
+
+#include "FetchHeaders.h"
+#include "JSDOMWrapper.h"
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+
+class JSFetchHeaders : public JSDOMWrapper<FetchHeaders> {
+public:
+ using Base = JSDOMWrapper<FetchHeaders>;
+ static JSFetchHeaders* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref<FetchHeaders>&& impl)
+ {
+ JSFetchHeaders* ptr = new (NotNull, JSC::allocateCell<JSFetchHeaders>(globalObject->vm())) JSFetchHeaders(structure, *globalObject, WTFMove(impl));
+ ptr->finishCreation(globalObject->vm());
+ return ptr;
+ }
+
+ static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&);
+ static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&);
+ static FetchHeaders* toWrapped(JSC::VM&, JSC::JSValue);
+ static void destroy(JSC::JSCell*);
+
+ DECLARE_INFO;
+
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info(), JSC::NonArray);
+ }
+
+ static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+ template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ if constexpr (mode == JSC::SubspaceAccess::Concurrently)
+ return nullptr;
+ return subspaceForImpl(vm);
+ }
+ static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm);
+ static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
+protected:
+ JSFetchHeaders(JSC::Structure*, JSDOMGlobalObject&, Ref<FetchHeaders>&&);
+
+ void finishCreation(JSC::VM&);
+};
+
+class JSFetchHeadersOwner final : public JSC::WeakHandleOwner {
+public:
+ bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::AbstractSlotVisitor&, const char**) final;
+ void finalize(JSC::Handle<JSC::Unknown>, void* context) final;
+};
+
+inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, FetchHeaders*)
+{
+ static NeverDestroyed<JSFetchHeadersOwner> owner;
+ return &owner.get();
+}
+
+inline void* wrapperKey(FetchHeaders* wrappableObject)
+{
+ return wrappableObject;
+}
+
+JSC::JSValue toJS(JSC::JSGlobalObject*, JSDOMGlobalObject*, FetchHeaders&);
+inline JSC::JSValue toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, FetchHeaders* impl) { return impl ? toJS(lexicalGlobalObject, globalObject, *impl) : JSC::jsNull(); }
+JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject*, Ref<FetchHeaders>&&);
+inline JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* globalObject, RefPtr<FetchHeaders>&& impl) { return impl ? toJSNewlyCreated(lexicalGlobalObject, globalObject, impl.releaseNonNull()) : JSC::jsNull(); }
+
+template<> struct JSDOMWrapperConverterTraits<FetchHeaders> {
+ using WrapperClass = JSFetchHeaders;
+ using ToWrappedReturnType = FetchHeaders*;
+};
+
+} // namespace WebCore
diff --git a/src/javascript/jsc/bindings/webcore/ParsedContentType.cpp b/src/javascript/jsc/bindings/webcore/ParsedContentType.cpp
new file mode 100644
index 000000000..9ef2a1720
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/ParsedContentType.cpp
@@ -0,0 +1,422 @@
+ /*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ParsedContentType.h"
+
+#include "HTTPParsers.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+static void skipSpaces(StringView input, unsigned& startIndex)
+{
+ while (startIndex < input.length() && isHTTPSpace(input[startIndex]))
+ ++startIndex;
+}
+
+static bool isQuotedStringTokenCharacter(UChar c)
+{
+ return (c >= ' ' && c <= '~') || (c >= 0x80 && c <= 0xFF) || c == '\t';
+}
+
+static bool isTokenCharacter(UChar c)
+{
+ return isASCII(c) && c > ' ' && c != '"' && c != '(' && c != ')' && c != ',' && c != '/' && (c < ':' || c > '@') && (c < '[' || c > ']');
+}
+
+using CharacterMeetsCondition = bool (*)(UChar);
+
+static StringView parseToken(StringView input, unsigned& startIndex, CharacterMeetsCondition characterMeetsCondition, Mode mode, bool skipTrailingWhitespace = false)
+{
+ unsigned inputLength = input.length();
+ unsigned tokenStart = startIndex;
+ unsigned& tokenEnd = startIndex;
+
+ if (tokenEnd >= inputLength)
+ return StringView();
+
+ while (tokenEnd < inputLength && characterMeetsCondition(input[tokenEnd])) {
+ if (mode == Mode::Rfc2045 && !isTokenCharacter(input[tokenEnd]))
+ break;
+ ++tokenEnd;
+ }
+
+ if (tokenEnd == tokenStart)
+ return StringView();
+ if (skipTrailingWhitespace) {
+ if (mode == Mode::Rfc2045) {
+ while (input[tokenEnd - 1] == ' ')
+ --tokenEnd;
+ } else {
+ while (isHTTPSpace(input[tokenEnd - 1]))
+ --tokenEnd;
+ }
+ }
+ return input.substring(tokenStart, tokenEnd - tokenStart);
+}
+
+static bool isNotQuoteOrBackslash(UChar ch)
+{
+ return ch != '"' && ch != '\\';
+}
+
+static String collectHTTPQuotedString(StringView input, unsigned& startIndex)
+{
+ ASSERT(input[startIndex] == '"');
+ unsigned inputLength = input.length();
+ unsigned& position = startIndex;
+ position++;
+ StringBuilder builder;
+ while (true) {
+ unsigned positionStart = position;
+ parseToken(input, position, isNotQuoteOrBackslash, Mode::MimeSniff);
+ builder.append(input.substring(positionStart, position - positionStart));
+ if (position >= inputLength)
+ break;
+ UChar quoteOrBackslash = input[position++];
+ if (quoteOrBackslash == '\\') {
+ if (position >= inputLength) {
+ builder.append(quoteOrBackslash);
+ break;
+ }
+ builder.append(input[position++]);
+ } else {
+ ASSERT(quoteOrBackslash == '"');
+ break;
+ }
+
+ }
+ return builder.toString();
+}
+
+static bool containsNonTokenCharacters(StringView input, Mode mode)
+{
+ if (mode == Mode::MimeSniff)
+ return !isValidHTTPToken(input);
+ for (unsigned index = 0; index < input.length(); ++index) {
+ if (!isTokenCharacter(input[index]))
+ return true;
+ }
+ return false;
+}
+
+static StringView parseQuotedString(StringView input, unsigned& startIndex)
+{
+ unsigned inputLength = input.length();
+ unsigned quotedStringStart = startIndex + 1;
+ unsigned& quotedStringEnd = startIndex;
+
+ if (quotedStringEnd >= inputLength)
+ return StringView();
+
+ if (input[quotedStringEnd++] != '"' || quotedStringEnd >= inputLength)
+ return StringView();
+
+ bool lastCharacterWasBackslash = false;
+ char currentCharacter;
+ while ((currentCharacter = input[quotedStringEnd++]) != '"' || lastCharacterWasBackslash) {
+ if (quotedStringEnd >= inputLength)
+ return StringView();
+ if (currentCharacter == '\\' && !lastCharacterWasBackslash) {
+ lastCharacterWasBackslash = true;
+ continue;
+ }
+ if (lastCharacterWasBackslash)
+ lastCharacterWasBackslash = false;
+ }
+ if (input[quotedStringEnd - 1] == '"')
+ quotedStringEnd++;
+ return input.substring(quotedStringStart, quotedStringEnd - quotedStringStart);
+}
+
+// From http://tools.ietf.org/html/rfc2045#section-5.1:
+//
+// content := "Content-Type" ":" type "/" subtype
+// *(";" parameter)
+// ; Matching of media type and subtype
+// ; is ALWAYS case-insensitive.
+//
+// type := discrete-type / composite-type
+//
+// discrete-type := "text" / "image" / "audio" / "video" /
+// "application" / extension-token
+//
+// composite-type := "message" / "multipart" / extension-token
+//
+// extension-token := ietf-token / x-token
+//
+// ietf-token := <An extension token defined by a
+// standards-track RFC and registered
+// with IANA.>
+//
+// x-token := <The two characters "X-" or "x-" followed, with
+// no intervening white space, by any token>
+//
+// subtype := extension-token / iana-token
+//
+// iana-token := <A publicly-defined extension token. Tokens
+// of this form must be registered with IANA
+// as specified in RFC 2048.>
+//
+// parameter := attribute "=" value
+//
+// attribute := token
+// ; Matching of attributes
+// ; is ALWAYS case-insensitive.
+//
+// value := token / quoted-string
+//
+// token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
+// or tspecials>
+//
+// tspecials := "(" / ")" / "<" / ">" / "@" /
+// "," / ";" / ":" / "\" / <">
+// "/" / "[" / "]" / "?" / "="
+// ; Must be in quoted-string,
+// ; to use within parameter values
+
+static bool isNotForwardSlash(UChar ch)
+{
+ return ch != '/';
+}
+
+static bool isNotSemicolon(UChar ch)
+{
+ return ch != ';';
+}
+
+static bool isNotSemicolonOrEqualSign(UChar ch)
+{
+ return ch != ';' && ch != '=';
+}
+
+static bool containsNewline(UChar ch)
+{
+ return ch == '\r' || ch == '\n';
+}
+
+bool ParsedContentType::parseContentType(Mode mode)
+{
+ if (mode == Mode::Rfc2045 && m_contentType.find(containsNewline) != notFound)
+ return false;
+ unsigned index = 0;
+ unsigned contentTypeLength = m_contentType.length();
+ skipSpaces(m_contentType, index);
+ if (index >= contentTypeLength) {
+ LOG_ERROR("Invalid Content-Type string '%s'", m_contentType.ascii().data());
+ return false;
+ }
+
+ unsigned contentTypeStart = index;
+ auto typeRange = parseToken(m_contentType, index, isNotForwardSlash, mode);
+ if (typeRange.isNull() || containsNonTokenCharacters(typeRange, mode)) {
+ LOG_ERROR("Invalid Content-Type, invalid type value.");
+ return false;
+ }
+
+ if (index >= contentTypeLength || m_contentType[index++] != '/') {
+ LOG_ERROR("Invalid Content-Type, missing '/'.");
+ return false;
+ }
+
+ auto subTypeRange = parseToken(m_contentType, index, isNotSemicolon, mode, mode == Mode::MimeSniff);
+ if (subTypeRange.isNull() || containsNonTokenCharacters(subTypeRange, mode)) {
+ LOG_ERROR("Invalid Content-Type, invalid subtype value.");
+ return false;
+ }
+
+ // There should not be any quoted strings until we reach the parameters.
+ size_t semiColonIndex = m_contentType.find(';', contentTypeStart);
+ if (semiColonIndex == notFound) {
+ setContentType(m_contentType.substring(contentTypeStart, contentTypeLength - contentTypeStart), mode);
+ return true;
+ }
+
+ setContentType(m_contentType.substring(contentTypeStart, semiColonIndex - contentTypeStart), mode);
+ index = semiColonIndex + 1;
+ while (true) {
+ skipSpaces(m_contentType, index);
+ auto keyRange = parseToken(m_contentType, index, isNotSemicolonOrEqualSign, mode);
+ if (mode == Mode::Rfc2045 && (keyRange.isNull() || index >= contentTypeLength)) {
+ LOG_ERROR("Invalid Content-Type parameter name.");
+ return false;
+ }
+
+ // Should we tolerate spaces here?
+ if (mode == Mode::Rfc2045) {
+ if (index >= contentTypeLength || m_contentType[index++] != '=') {
+ LOG_ERROR("Invalid Content-Type malformed parameter.");
+ return false;
+ }
+ } else {
+ if (index >= contentTypeLength)
+ break;
+ if (m_contentType[index] != '=' && m_contentType[index] != ';') {
+ LOG_ERROR("Invalid Content-Type malformed parameter.");
+ return false;
+ }
+ if (m_contentType[index++] == ';')
+ continue;
+ }
+
+ // Should we tolerate spaces here?
+ String parameterValue;
+ StringView valueRange;
+ if (index < contentTypeLength && m_contentType[index] == '"') {
+ if (mode == Mode::MimeSniff) {
+ parameterValue = collectHTTPQuotedString(m_contentType, index);
+ parseToken(m_contentType, index, isNotSemicolon, mode);
+ } else
+ valueRange = parseQuotedString(m_contentType, index);
+ } else
+ valueRange = parseToken(m_contentType, index, isNotSemicolon, mode, mode == Mode::MimeSniff);
+
+ if (parameterValue.isNull()) {
+ if (valueRange.isNull()) {
+ if (mode == Mode::MimeSniff)
+ continue;
+ LOG_ERROR("Invalid Content-Type, invalid parameter value.");
+ return false;
+ }
+ parameterValue = valueRange.toString();
+ }
+
+ // Should we tolerate spaces here?
+ if (mode == Mode::Rfc2045 && index < contentTypeLength && m_contentType[index++] != ';') {
+ LOG_ERROR("Invalid Content-Type, invalid character at the end of key/value parameter.");
+ return false;
+ }
+
+ if (!keyRange.isNull())
+ setContentTypeParameter(keyRange.toString(), parameterValue, mode);
+
+ if (index >= contentTypeLength)
+ return true;
+ }
+
+ return true;
+}
+
+std::optional<ParsedContentType> ParsedContentType::create(const String& contentType, Mode mode)
+{
+ ParsedContentType parsedContentType(mode == Mode::Rfc2045 ? contentType : stripLeadingAndTrailingHTTPSpaces(contentType));
+ if (!parsedContentType.parseContentType(mode))
+ return std::nullopt;
+ return { WTFMove(parsedContentType) };
+}
+
+bool isValidContentType(const String& contentType, Mode mode)
+{
+ return ParsedContentType::create(contentType, mode) != std::nullopt;
+}
+
+ParsedContentType::ParsedContentType(const String& contentType)
+ : m_contentType(contentType)
+{
+}
+
+String ParsedContentType::charset() const
+{
+ return parameterValueForName("charset");
+}
+
+void ParsedContentType::setCharset(String&& charset)
+{
+ m_parameterValues.set("charset"_s, WTFMove(charset));
+}
+
+String ParsedContentType::parameterValueForName(const String& name) const
+{
+ return m_parameterValues.get(name);
+}
+
+size_t ParsedContentType::parameterCount() const
+{
+ return m_parameterValues.size();
+}
+
+void ParsedContentType::setContentType(StringView contentRange, Mode mode)
+{
+ m_mimeType = contentRange.toString();
+ if (mode == Mode::MimeSniff)
+ m_mimeType = stripLeadingAndTrailingHTTPSpaces(m_mimeType).convertToASCIILowercase();
+ else
+ m_mimeType = m_mimeType.stripWhiteSpace();
+}
+
+static bool containsNonQuoteStringTokenCharacters(const String& input)
+{
+ for (unsigned index = 0; index < input.length(); ++index) {
+ if (!isQuotedStringTokenCharacter(input[index]))
+ return true;
+ }
+ return false;
+}
+
+void ParsedContentType::setContentTypeParameter(const String& keyName, const String& keyValue, Mode mode)
+{
+ String name = keyName;
+ if (mode == Mode::MimeSniff) {
+ if (m_parameterValues.contains(name) || !isValidHTTPToken(name) || containsNonQuoteStringTokenCharacters(keyValue))
+ return;
+ name = name.convertToASCIILowercase();
+ }
+ m_parameterValues.set(name, keyValue);
+ m_parameterNames.append(name);
+}
+
+String ParsedContentType::serialize() const
+{
+ StringBuilder builder;
+ builder.append(m_mimeType);
+ for (auto& name : m_parameterNames) {
+ builder.append(';');
+ builder.append(name);
+ builder.append('=');
+ String value = m_parameterValues.get(name);
+ if (value.isEmpty() || !isValidHTTPToken(value)) {
+ builder.append('"');
+ for (unsigned index = 0; index < value.length(); ++index) {
+ auto ch = value[index];
+ if (ch == '\\' || ch =='"')
+ builder.append('\\');
+ builder.append(ch);
+ }
+ builder.append('"');
+ } else
+ builder.append(value);
+ }
+ return builder.toString();
+}
+
+}
diff --git a/src/javascript/jsc/bindings/webcore/ParsedContentType.h b/src/javascript/jsc/bindings/webcore/ParsedContentType.h
new file mode 100644
index 000000000..d22b97252
--- /dev/null
+++ b/src/javascript/jsc/bindings/webcore/ParsedContentType.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/HashMap.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+enum class Mode {
+ Rfc2045,
+ MimeSniff
+};
+WEBCORE_EXPORT bool isValidContentType(const String&, Mode = Mode::MimeSniff);
+
+// FIXME: add support for comments.
+class ParsedContentType {
+public:
+ WEBCORE_EXPORT static std::optional<ParsedContentType> create(const String&, Mode = Mode::MimeSniff);
+ ParsedContentType(ParsedContentType&&) = default;
+
+ String mimeType() const { return m_mimeType; }
+ String charset() const;
+ void setCharset(String&&);
+
+ // Note that in the case of multiple values for the same name, the last value is returned.
+ String parameterValueForName(const String&) const;
+ size_t parameterCount() const;
+
+ WEBCORE_EXPORT String serialize() const;
+
+private:
+ ParsedContentType(const String&);
+ ParsedContentType(const ParsedContentType&) = delete;
+ ParsedContentType& operator=(ParsedContentType const&) = delete;
+ bool parseContentType(Mode);
+ void setContentType(StringView, Mode);
+ void setContentTypeParameter(const String&, const String&, Mode);
+
+ typedef HashMap<String, String> KeyValuePairs;
+ String m_contentType;
+ KeyValuePairs m_parameterValues;
+ Vector<String> m_parameterNames;
+ String m_mimeType;
+};
+
+}
diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig
index e17b6e720..66bd0c620 100644
--- a/src/javascript/jsc/javascript.zig
+++ b/src/javascript/jsc/javascript.zig
@@ -91,7 +91,6 @@ pub const GlobalConstructors = [_]type{
WebCore.TextEncoder.Constructor,
Request.Constructor,
Response.Constructor,
- Headers.Constructor,
JSC.Cloudflare.HTMLRewriter.Constructor,
};
@@ -2199,7 +2198,7 @@ pub const EventListenerMixin = struct {
fetch_event.* = FetchEvent{
.request_context = request_context,
- .request = try Request.fromRequestContext(request_context),
+ .request = try Request.fromRequestContext(request_context, vm.global),
.onPromiseRejectionCtx = @as(*anyopaque, ctx),
.onPromiseRejectionHandler = FetchEventRejectionHandler.onRejection,
};
diff --git a/src/javascript/jsc/webcore/response.zig b/src/javascript/jsc/webcore/response.zig
index 46cd37c82..a23ca69ce 100644
--- a/src/javascript/jsc/webcore/response.zig
+++ b/src/javascript/jsc/webcore/response.zig
@@ -11,7 +11,7 @@ const JSC = @import("../../../jsc.zig");
const js = JSC.C;
const Method = @import("../../../http/method.zig").Method;
-
+const FetchHeaders = JSC.FetchHeaders;
const ObjectPool = @import("../../../pool.zig").ObjectPool;
const SystemError = JSC.SystemError;
const Output = @import("../../../global.zig").Output;
@@ -173,9 +173,8 @@ pub const Response = struct {
}
pub fn header(this: *const Response, comptime name: []const u8) ?[]const u8 {
- const headers: *const Headers = (this.body.init.headers orelse return null).value;
- const index = headers.getHeaderIndex(name) orelse return null;
- return headers.asStr(headers.entries.items(.value)[index]);
+ const headers_ = (this.body.init.headers.as(FetchHeaders) orelse return null);
+ return headers_.get(name);
}
pub const Props = struct {};
@@ -282,21 +281,25 @@ pub const Response = struct {
return js.JSValueMakeBoolean(ctx, this.isOK());
}
- fn getOrCreateHeaders(this: *Response) *Headers.RefCountedHeaders {
- if (this.body.init.headers == null) {
- this.body.init.headers = Headers.RefCountedHeaders.init(Headers.empty(this.allocator), this.allocator) catch unreachable;
+ fn getOrCreateHeaders(this: *Response, globalThis: *JSGlobalObject) *FetchHeaders {
+ if (this.body.init.headers.isEmpty()) {
+ this.body.init.headers = FetchHeaders.createEmpty(globalThis).as(FetchHeaders);
}
- return this.body.init.headers.?;
+ return this.body.init.headers;
}
pub fn getHeaders(
this: *Response,
ctx: js.JSContextRef,
- _: js.JSValueRef,
+ obj: js.JSValueRef,
_: js.JSStringRef,
_: js.ExceptionRef,
) js.JSValueRef {
- return Headers.Class.make(ctx, this.getOrCreateHeaders().getRef());
+ var headers_symbol = &ZigString.init("headers_");
+ const thisValue = JSC.JSValue.fromRef(obj);
+ const headers_symbol_ = JSC.JSValue.symbolFor(ctx.ptr(), headers_symbol);
+ this.body.init.headers = JSC.JSValue.get(headers_symbol_) orelse FetchHeaders.createEmpty(ctx.ptr());
+ return this.body.init.headers.asObjectRef();
}
pub fn doClone(
@@ -307,8 +310,16 @@ pub const Response = struct {
_: []const js.JSValueRef,
_: js.ExceptionRef,
) js.JSValueRef {
- var cloned = this.clone(getAllocator(ctx));
- return Response.makeMaybePooled(ctx, cloned);
+ var cloned = this.clone(getAllocator(ctx), ctx.ptr());
+ var val = Response.makeMaybePooled(ctx, cloned);
+ if (!cloned.body.init.headers.isEmpty()) {
+ var headers_symbol = &ZigString.init("headers_");
+ const thisValue = JSC.JSValue.fromRef(val);
+ const headers_symbol_ = JSC.JSValue.symbolFor(ctx.ptr(), headers_symbol);
+ cloned.body.init.headers = thisValue.get(headers_symbol_) orelse FetchHeaders.createEmpty(ctx.ptr());
+ }
+
+ return val;
}
pub fn makeMaybePooled(ctx: js.JSContextRef, ptr: *Response) JSC.C.JSObjectRef {
@@ -324,19 +335,24 @@ pub const Response = struct {
return Response.Class.make(ctx, ptr);
}
- pub fn cloneInto(this: *const Response, new_response: *Response, allocator: std.mem.Allocator) void {
+ pub fn cloneInto(
+ this: *const Response,
+ new_response: *Response,
+ allocator: std.mem.Allocator,
+ globalThis: *JSGlobalObject,
+ ) void {
new_response.* = Response{
.allocator = allocator,
- .body = this.body.clone(allocator),
+ .body = this.body.clone(allocator, globalThis),
.url = allocator.dupe(u8, this.url) catch unreachable,
.status_text = allocator.dupe(u8, this.status_text) catch unreachable,
.redirected = this.redirected,
};
}
- pub fn clone(this: *const Response, allocator: std.mem.Allocator) *Response {
+ pub fn clone(this: *const Response, allocator: std.mem.Allocator, globalThis: *JSGlobalObject) *Response {
var new_response = allocator.create(Response) catch unreachable;
- this.cloneInto(new_response, allocator);
+ this.cloneInto(new_response, allocator, globalThis);
return new_response;
}
@@ -376,14 +392,10 @@ pub const Response = struct {
}
pub fn mimeTypeWithDefault(response: *const Response, default: MimeType, request_ctx_: ?*const RequestContext) string {
- if (response.body.init.headers) |headers_ref| {
- var headers = headers_ref.get();
- defer headers_ref.deref();
+ if (response.header("content-type")) |content_type| {
// Remember, we always lowercase it
// hopefully doesn't matter here tho
- if (headers.getHeaderIndex("content-type")) |content_type| {
- return headers.asStr(headers.entries.items(.value)[content_type]);
- }
+ return content_type;
}
if (request_ctx_) |request_ctx| {
@@ -419,7 +431,6 @@ pub const Response = struct {
var response = Response{
.body = Body{
.init = Body.Init{
- .headers = null,
.status_code = 200,
},
.value = Body.Value.empty,
@@ -461,8 +472,8 @@ pub const Response = struct {
}
}
- var headers_ref = response.getOrCreateHeaders().leak();
- headers_ref.putDefaultHeader("content-type", MimeType.json.value);
+ var headers_ref = response.getOrCreateHeaders(ctx.ptr());
+ headers_ref.putDefault("content-type", MimeType.json.value);
var ptr = response.allocator.create(Response) catch unreachable;
ptr.* = response;
@@ -483,7 +494,6 @@ pub const Response = struct {
var response = Response{
.body = Body{
.init = Body.Init{
- .headers = null,
.status_code = 302,
},
.value = Body.Value.empty,
@@ -511,10 +521,10 @@ pub const Response = struct {
}
}
- response.body.init.headers = response.getOrCreateHeaders();
+ response.body.init.headers = response.getOrCreateHeaders(ctx.ptr());
response.body.init.status_code = 302;
- var headers_ref = response.body.init.headers.?.leak();
- headers_ref.putHeaderNormalized("location", url_string_slice.slice(), false);
+ var headers_ref = response.body.init.headers.?;
+ headers_ref.put("location", url_string_slice.slice());
var ptr = response.allocator.create(Response) catch unreachable;
ptr.* = response;
@@ -532,7 +542,6 @@ pub const Response = struct {
response.* = Response{
.body = Body{
.init = Body.Init{
- .headers = null,
.status_code = 0,
},
.value = Body.Value.empty,
@@ -800,10 +809,7 @@ pub const Fetch = struct {
.redirected = this.http.redirect_count > 0,
.body = .{
.init = .{
- .headers = Headers.RefCountedHeaders.init(
- Headers.fromPicoHeaders(allocator, http_response.headers) catch unreachable,
- allocator,
- ) catch unreachable,
+ .headers = FetchHeaders.createFromPicoHeaders(this.global_this, http_response.headers),
.status_code = @truncate(u16, http_response.status_code),
},
.value = .{
@@ -926,13 +932,12 @@ pub const Fetch = struct {
}
if (options.get(ctx.ptr(), "headers")) |headers_| {
- var headers2: Headers = undefined;
- if (headers_.as(Headers.RefCountedHeaders)) |headers__| {
- headers__.leak().clone(&headers2) catch unreachable;
- headers = headers2;
- } else if (Headers.JS.headersInit(ctx, headers_.asObjectRef()) catch null) |headers__| {
- headers__.clone(&headers2) catch unreachable;
- headers = headers2;
+ if (headers_.as(FetchHeaders)) |headers__| {
+ headers = Headers.from(headers__, bun.default_allocator) catch unreachable;
+ // TODO: make this one pass
+ } else if (FetchHeaders.createFromJS(ctx.ptr(), headers_)) |headers__| {
+ headers = Headers.from(headers__, bun.default_allocator) catch unreachable;
+ headers__.deref();
}
}
@@ -958,10 +963,8 @@ pub const Fetch = struct {
} else if (first_arg.asCheckLoaded(Request)) |request| {
url = ZigURL.parse(request.url.dupe(getAllocator(ctx)) catch unreachable);
method = request.method;
- if (request.headers) |head| {
- var for_clone: Headers = undefined;
- head.leak().clone(&for_clone) catch unreachable;
- headers = for_clone;
+ if (request.headers.as(FetchHeaders)) |head| {
+ headers = Headers.from(head, bun.default_allocator) catch unreachable;
}
var blob = request.body.use();
// TODO: make RequestBody _NOT_ a MutableString
@@ -1033,662 +1036,32 @@ pub const Headers = struct {
entries: Headers.Entries = .{},
buf: std.ArrayListUnmanaged(u8) = .{},
allocator: std.mem.Allocator,
- guard: Guard = Guard.none,
- pub const RefCountedHeaders = bun.RefCount(Headers, true);
-
- pub fn deinit(
- headers: *Headers,
- ) void {
- headers.buf.deinit(headers.allocator);
- headers.entries.deinit(headers.allocator);
- }
-
- pub fn clonefromUWSRequest(headers: *Headers, req: *uws.Request) void {
- req.cloneHeaders(headers);
- }
-
- pub fn preallocate(this: *Headers, buf_size: usize, header_count: usize) callconv(.C) void {
- this.buf.ensureTotalCapacityPrecise(this.allocator, buf_size) catch unreachable;
- this.entries.ensureTotalCapacity(this.allocator, header_count) catch unreachable;
- }
-
- comptime {
- // if (!JSC.is_bindgen) {
- // Initially, these were function pointers
- // However, some Zig Stage1 C ABI bug causes EXC_BAD_ACCESS
- @export(preallocate, .{ .name = "Headers__preallocate" });
- @export(appendHeaderNormalizedC, .{ .name = "Headers__appendHeaderNormalized" });
- // }
+ pub fn asStr(this: *const Headers, ptr: Api.StringPointer) []const u8 {
+ return if (ptr.offset + ptr.length <= this.buf.items.len)
+ this.buf.items[ptr.offset..][0..ptr.length]
+ else
+ "";
}
- pub fn empty(allocator: std.mem.Allocator) Headers {
- return Headers{
+ pub fn from(headers_ref: *FetchHeaders, allocator: std.mem.Allocator) !Headers {
+ var header_count: u32 = 0;
+ var buf_len: u32 = 0;
+ headers_ref.count(&header_count, &buf_len);
+ var headers = Headers{
.entries = .{},
.buf = .{},
.allocator = allocator,
- .guard = Guard.none,
- };
- }
-
- // https://developer.mozilla.org/en-US/docs/Web/API/Headers#methods
- pub const JS = struct {
-
- // https://developer.mozilla.org/en-US/docs/Web/API/Headers/get
- pub fn get(
- ref: *RefCountedHeaders,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- _: js.ExceptionRef,
- ) js.JSValueRef {
- var this = ref.leak();
- if (arguments.len == 0) {
- return js.JSValueMakeNull(ctx);
- }
-
- const key_slice = ZigString.from(arguments[0], ctx).toSlice(bun.default_allocator);
- if (key_slice.len == 0) {
- return js.JSValueMakeNull(ctx);
- }
- defer key_slice.deinit();
-
- if (this.getHeaderIndex(key_slice.slice())) |index| {
- return ZigString.init(this.asStr(this.entries.items(.value)[index]))
- .toValue(ctx.ptr()).asObjectRef();
- } else {
- return js.JSValueMakeNull(ctx);
- }
- }
-
- // https://developer.mozilla.org/en-US/docs/Web/API/Headers/set
- // > The difference between set() and Headers.append is that if the specified header already exists and accepts multiple values
- // > set() overwrites the existing value with the new one, whereas Headers.append appends the new value to the end of the set of values.
- pub fn set(
- ref: *RefCountedHeaders,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- _: js.ExceptionRef,
- ) js.JSValueRef {
- var this = ref.leak();
- if (arguments.len == 0) {
- return js.JSValueMakeNull(ctx);
- }
- const key_slice = ZigString.from(arguments[0], ctx);
- if (key_slice.len == 0) {
- return js.JSValueMakeNull(ctx);
- }
-
- this.putHeaderFromJS(key_slice, ZigString.from(arguments[1], ctx), false);
- return js.JSValueMakeUndefined(ctx);
- }
-
- // https://developer.mozilla.org/en-US/docs/Web/API/Headers/append
- pub fn append(
- ref: *RefCountedHeaders,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- _: js.ExceptionRef,
- ) js.JSValueRef {
- var this = ref.leak();
- if (arguments.len == 0) {
- return js.JSValueMakeNull(ctx);
- }
- const key_slice = ZigString.from(arguments[0], ctx);
- if (key_slice.len == 0) {
- return js.JSValueMakeNull(ctx);
- }
-
- this.putHeaderFromJS(key_slice, ZigString.from(arguments[1], ctx), true);
- return js.JSValueMakeUndefined(ctx);
- }
- pub fn delete(
- ref: *RefCountedHeaders,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- _: js.ExceptionRef,
- ) js.JSValueRef {
- var this: *Headers = ref.leak();
-
- const key = ZigString.from(arguments[0], ctx);
- if (key.len == 0) {
- return js.JSValueMakeNull(ctx);
- }
- var str = key.toSlice(ref.allocator);
- defer str.deinit();
- var entries_ = &this.entries;
-
- if (this.getHeaderIndex(str.slice())) |header_i| {
- entries_.orderedRemove(header_i);
- }
-
- return js.JSValueMakeUndefined(ctx);
- }
- pub fn entries(
- _: *RefCountedHeaders,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- _: []const js.JSValueRef,
- _: js.ExceptionRef,
- ) js.JSValueRef {
- Output.prettyErrorln("<r><b>Headers.entries()<r> is not implemented yet - sorry!!", .{});
- return js.JSValueMakeNull(ctx);
- }
- pub fn keys(
- _: *RefCountedHeaders,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- _: []const js.JSValueRef,
- _: js.ExceptionRef,
- ) js.JSValueRef {
- Output.prettyErrorln("H<r><b>Headers.keys()<r> is not implemented yet- sorry!!", .{});
- return js.JSValueMakeNull(ctx);
- }
- pub fn values(
- _: *RefCountedHeaders,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- _: []const js.JSValueRef,
- _: js.ExceptionRef,
- ) js.JSValueRef {
- Output.prettyErrorln("<r><b>Headers.values()<r> is not implemented yet - sorry!!", .{});
- return js.JSValueMakeNull(ctx);
- }
-
- pub fn headersInit(ctx: js.JSContextRef, header_prop: js.JSObjectRef) !?Headers {
- const header_keys = js.JSObjectCopyPropertyNames(ctx, header_prop);
- defer js.JSPropertyNameArrayRelease(header_keys);
- const total_header_count = js.JSPropertyNameArrayGetCount(header_keys);
- if (total_header_count == 0) return null;
-
- // 2 passes through the headers
-
- // Pass #1: find the "real" count.
- // The number of things which are strings or numbers.
- // Anything else should be ignored.
- // We could throw a TypeError, but ignoring silently is more JavaScript-like imo
- var real_header_count: usize = 0;
- var estimated_buffer_len: usize = 0;
- var j: usize = 0;
- while (j < total_header_count) : (j += 1) {
- var key_ref = js.JSPropertyNameArrayGetNameAtIndex(header_keys, j);
- var value_ref = js.JSObjectGetProperty(ctx, header_prop, key_ref, null);
-
- switch (js.JSValueGetType(ctx, value_ref)) {
- js.JSType.kJSTypeNumber => {
- const key_len = js.JSStringGetLength(key_ref);
- if (key_len > 0) {
- real_header_count += 1;
- estimated_buffer_len += key_len;
- estimated_buffer_len += std.fmt.count("{d}", .{js.JSValueToNumber(ctx, value_ref, null)});
- }
- },
- js.JSType.kJSTypeString => {
- const key_len = js.JSStringGetLength(key_ref);
- const value_len = js.JSStringGetLength(value_ref);
- if (key_len > 0 and value_len > 0) {
- real_header_count += 1;
- estimated_buffer_len += key_len + value_len;
- }
- },
- else => {},
- }
- }
-
- if (real_header_count == 0 or estimated_buffer_len == 0) return null;
-
- j = 0;
- var allocator = getAllocator(ctx);
- var headers = Headers{
- .allocator = allocator,
- .buf = try std.ArrayListUnmanaged(u8).initCapacity(allocator, estimated_buffer_len),
- .entries = Headers.Entries{},
- };
- errdefer headers.deinit();
- try headers.entries.ensureTotalCapacity(allocator, real_header_count);
-
- while (j < total_header_count) : (j += 1) {
- var key_ref = js.JSPropertyNameArrayGetNameAtIndex(header_keys, j);
- var value_ref = js.JSObjectGetProperty(ctx, header_prop, key_ref, null);
-
- switch (js.JSValueGetType(ctx, value_ref)) {
- js.JSType.kJSTypeNumber => {
- if (js.JSStringGetLength(key_ref) == 0) continue;
- try headers.appendInit(ctx, key_ref, .kJSTypeNumber, value_ref);
- },
- js.JSType.kJSTypeString => {
- if (js.JSStringGetLength(value_ref) == 0 or js.JSStringGetLength(key_ref) == 0) continue;
- try headers.appendInit(ctx, key_ref, .kJSTypeString, value_ref);
- },
- else => {},
- }
- }
- return headers;
- }
-
- // https://developer.mozilla.org/en-US/docs/Web/API/Headers/Headers
- pub fn constructor(
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- _: js.ExceptionRef,
- ) js.JSObjectRef {
- var headers = getAllocator(ctx).create(RefCountedHeaders) catch unreachable;
- if (arguments.len > 0 and js.JSValueIsObjectOfClass(ctx, arguments[0], Headers.Class.get().*)) {
- var other = castObj(arguments[0], RefCountedHeaders).leak();
- other.clone(&headers.value) catch unreachable;
- headers.count = 1;
- headers.allocator = getAllocator(ctx);
- } else if (arguments.len == 1 and js.JSValueIsObject(ctx, arguments[0])) {
- headers.* = .{
- .value = (JS.headersInit(ctx, arguments[0]) catch null) orelse Headers{
- .entries = .{},
- .buf = .{},
- .allocator = getAllocator(ctx),
- .guard = Guard.none,
- },
- .allocator = getAllocator(ctx),
- .count = 1,
- };
- } else {
- headers.* = .{
- .value = Headers.empty(getAllocator(ctx)),
- .allocator = getAllocator(ctx),
- .count = 1,
- };
- }
-
- return Headers.Class.make(ctx, headers);
- }
-
- pub fn finalize(
- this: *RefCountedHeaders,
- ) void {
- this.deref();
- }
- };
- pub const Constructor = JSC.NewConstructor(
- Headers,
- .{
- .@"constructor" = .{
- .rfn = JS.constructor,
- .ts = d.ts{},
- },
- },
- .{},
- );
- pub const Class = NewClass(
- RefCountedHeaders,
- .{
- .name = "Headers",
- .read_only = true,
- },
- .{
- .@"get" = .{
- .rfn = JS.get,
- },
- .@"set" = .{
- .rfn = JS.set,
- .ts = d.ts{},
- },
- .@"append" = .{
- .rfn = JS.append,
- .ts = d.ts{},
- },
- .@"delete" = .{
- .rfn = JS.delete,
- .ts = d.ts{},
- },
- .@"entries" = .{
- .rfn = JS.entries,
- .ts = d.ts{},
- },
- .@"keys" = .{
- .rfn = JS.keys,
- .ts = d.ts{},
- },
- .@"values" = .{
- .rfn = JS.values,
- .ts = d.ts{},
- },
-
- .@"finalize" = .{
- .rfn = JS.finalize,
- },
- .toJSON = .{
- .rfn = toJSON,
- .name = "toJSON",
- },
- },
- .{},
- );
-
- // https://developer.mozilla.org/en-US/docs/Glossary/Guard
- pub const Guard = enum {
- immutable,
- request,
- @"request-no-cors",
- response,
- none,
- };
-
- pub fn fromPicoHeaders(allocator: std.mem.Allocator, picohttp_headers: []const picohttp.Header) !Headers {
- var total_len: usize = 0;
- for (picohttp_headers) |header| {
- total_len += header.name.len;
- total_len += header.value.len;
- }
- // for the null bytes
- total_len += picohttp_headers.len * 2;
- var headers = Headers{
- .allocator = allocator,
- .entries = Headers.Entries{},
- .buf = std.ArrayListUnmanaged(u8){},
};
- try headers.entries.ensureTotalCapacity(allocator, picohttp_headers.len);
- try headers.buf.ensureTotalCapacity(allocator, total_len);
- headers.buf.expandToCapacity();
- headers.guard = Guard.request;
-
- for (picohttp_headers) |header| {
- headers.entries.appendAssumeCapacity(.{
- .name = headers.appendString(
- string,
- header.name,
- true,
- true,
- ),
- .value = headers.appendString(
- string,
- header.value,
- true,
- true,
- ),
- });
- }
-
+ headers.entries.ensureTotalCapacity(allocator, header_count) catch unreachable;
+ headers.buf.ensureTotalCapacity(allocator, buf_len) catch unreachable;
+ headers.buf.items.len = buf_len;
+ var sliced = headers.entries.slice();
+ var names = sliced.items(.name);
+ var values = sliced.items(.value);
+ headers_ref.copyTo(names.ptr, values.ptr, headers.buf.items.ptr);
return headers;
}
-
- // TODO: is it worth making this lazy? instead of copying all the request headers, should we just do it on get/put/iterator?
- pub fn fromRequestCtx(allocator: std.mem.Allocator, request: *RequestContext) !Headers {
- return fromPicoHeaders(allocator, request.request.headers);
- }
-
- pub fn asStr(headers: *const Headers, ptr: Api.StringPointer) []u8 {
- return headers.buf.items[ptr.offset..][0..ptr.length];
- }
-
- pub fn putHeader(headers: *Headers, key_: []const u8, value_: []const u8, comptime append: bool) void {
- var header_kv_buf: [4096]u8 = undefined;
-
- const key = strings.copyLowercase(strings.trim(key_, " \n\r"), &header_kv_buf);
- const value = strings.copyLowercase(strings.trim(value_, " \n\r"), header_kv_buf[key.len..]);
-
- return headers.putHeaderNormalized(key, value, append);
- }
-
- pub fn putHeaderFromJS(headers: *Headers, key_: ZigString, value_: ZigString, comptime append: bool) void {
- var key_slice = key_.toSlice(headers.allocator);
- var value_slice = value_.toSlice(headers.allocator);
-
- defer key_slice.deinit();
- defer value_slice.deinit();
-
- headers.putHeader(key_slice.slice(), value_slice.slice(), append);
- }
-
- pub fn putDefaultHeader(
- headers: *Headers,
- key: []const u8,
- value: []const u8,
- ) void {
- return putHeaderNormalizedDefault(headers, key, value, false, true);
- }
-
- pub fn putHeaderNormalizedDefault(
- headers: *Headers,
- key: []const u8,
- value: []const u8,
- comptime append: bool,
- comptime default: bool,
- ) void {
- if (headers.getHeaderIndex(key)) |header_i| {
- if (comptime default) return;
-
- const existing_value = headers.entries.items(.value)[header_i];
- if (append) {
- const end = @truncate(u32, value.len + existing_value.length + 2);
- const offset = headers.buf.items.len;
- headers.buf.ensureUnusedCapacity(headers.allocator, end) catch unreachable;
- headers.buf.appendSliceAssumeCapacity(headers.asStr(existing_value));
- headers.buf.appendSliceAssumeCapacity(", ");
- headers.buf.appendSliceAssumeCapacity(value);
- headers.entries.items(.value)[header_i] = Api.StringPointer{ .offset = @truncate(u32, offset), .length = @truncate(u32, headers.buf.items.len - offset) };
- // Can we get away with just overwriting in-place?
- } else if (existing_value.length >= value.len) {
- std.mem.copy(u8, headers.asStr(existing_value), value);
- headers.entries.items(.value)[header_i].length = @truncate(u32, value.len);
- // Otherwise, append to the buffer, and just don't bother dealing with the existing header value
- // We assume that these header objects are going to be kind of short-lived.
- } else {
- headers.buf.ensureUnusedCapacity(headers.allocator, value.len + 1) catch unreachable;
- headers.entries.items(.value)[header_i] = headers.appendString(string, value, false, false);
- }
- } else {
- headers.appendHeader(key, value, false, false);
- }
- }
-
- pub fn putHeaderNormalized(headers: *Headers, key: []const u8, value: []const u8, comptime append: bool) void {
- return putHeaderNormalizedDefault(headers, key, value, append, false);
- }
-
- pub fn getHeaderIndex(headers: *const Headers, key: string) ?u32 {
- for (headers.entries.items(.name)) |name, i| {
- if (name.length == key.len and strings.eqlInsensitive(key, headers.asStr(name))) {
- return @truncate(u32, i);
- }
- }
-
- return null;
- }
-
- pub fn appendHeaderNormalizedC(
- headers: *Headers,
- key: [*]const u8,
- key_len: usize,
- value: [*]const u8,
- value_len: usize,
- ) callconv(.C) void {
- headers.appendHeader(key[0..key_len], value[0..value_len], false, false);
- }
-
- pub fn appendHeader(
- headers: *Headers,
- key: string,
- value: string,
- comptime needs_lowercase: bool,
- comptime needs_normalize: bool,
- ) void {
- headers.buf.ensureUnusedCapacity(headers.allocator, key.len + value.len + 2) catch unreachable;
-
- headers.entries.append(
- headers.allocator,
- .{
- .name = headers.appendString(
- string,
- key,
- needs_lowercase,
- needs_normalize,
- ),
- .value = headers.appendString(
- string,
- value,
- needs_lowercase,
- needs_normalize,
- ),
- },
- ) catch unreachable;
- }
-
- fn appendString(
- this: *Headers,
- comptime StringType: type,
- str: StringType,
- comptime needs_lowercase: bool,
- comptime needs_normalize: bool,
- ) Api.StringPointer {
- var ptr = Api.StringPointer{ .offset = @truncate(u32, this.buf.items.len), .length = 0 };
- ptr.length = @truncate(
- u32,
- switch (comptime StringType) {
- js.JSStringRef => js.JSStringGetLength(str),
- else => str.len,
- },
- );
- if (Environment.allow_assert) std.debug.assert(ptr.length > 0);
- this.buf.ensureUnusedCapacity(this.allocator, ptr.length) catch unreachable;
- var slice = this.buf.items;
- slice.len += ptr.length;
- slice = slice[ptr.offset..][0..ptr.length];
-
- switch (comptime StringType) {
- js.JSStringRef => {
- ptr.length = @truncate(u32, js.JSStringGetUTF8CString(str, slice.ptr, slice.len) - 1);
- },
- else => {
- std.mem.copy(u8, slice, str);
- },
- }
-
- if (comptime needs_normalize) {
- slice = strings.trim(slice, " \r\n");
- }
-
- if (comptime needs_lowercase) {
- for (slice) |c, i| {
- slice[i] = std.ascii.toLower(c);
- }
- }
-
- ptr.length = @truncate(u32, slice.len);
- this.buf.items.len += slice.len;
- return ptr;
- }
-
- pub fn toJSON(
- ref: *RefCountedHeaders,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- _: []const js.JSValueRef,
- _: js.ExceptionRef,
- ) js.JSValueRef {
- var this = ref.leak();
- const slice = this.entries.slice();
- const keys = slice.items(.name);
- const values = slice.items(.value);
- const StackFallback = std.heap.StackFallbackAllocator(32 * 2 * @sizeOf(ZigString));
- var stack = StackFallback{
- .buffer = undefined,
- .fallback_allocator = default_allocator,
- .fixed_buffer_allocator = undefined,
- };
- var allocator = stack.get();
- var key_strings_ = allocator.alloc(ZigString, keys.len * 2) catch unreachable;
- var key_strings = key_strings_[0..keys.len];
- var value_strings = key_strings_[keys.len..];
-
- for (keys) |key, i| {
- key_strings[i] = ZigString.init(this.asStr(key));
- key_strings[i].detectEncoding();
- value_strings[i] = ZigString.init(this.asStr(values[i]));
- value_strings[i].detectEncoding();
- }
-
- var result = JSValue.fromEntries(ctx.ptr(), key_strings.ptr, value_strings.ptr, keys.len, true).asObjectRef();
- allocator.free(key_strings_);
- return result;
- }
-
- pub fn writeFormat(this: *const Headers, formatter: *JSC.Formatter, writer: anytype, comptime enable_ansi_colors: bool) !void {
- if (this.entries.len == 0) {
- try writer.writeAll("Headers (0 KB) {}");
- return;
- }
-
- try writer.print("Headers ({}) {{\n", .{bun.fmt.size(this.buf.items.len)});
- const Writer = @TypeOf(writer);
- {
- var slice = this.entries.slice();
- const names = slice.items(.name);
- const values = slice.items(.value);
- formatter.indent += 1;
- defer formatter.indent -|= 1;
-
- for (names) |name, i| {
- if (i > 0) {
- formatter.printComma(Writer, writer, enable_ansi_colors) catch unreachable;
- writer.writeAll("\n") catch unreachable;
- }
-
- const value = values[i];
- formatter.writeIndent(Writer, writer) catch unreachable;
- try JSPrinter.writeJSONString(this.asStr(name), Writer, writer, false);
- writer.writeAll(": ") catch unreachable;
- try JSPrinter.writeJSONString(this.asStr(value), Writer, writer, false);
- }
- }
-
- try writer.writeAll("\n");
- try formatter.writeIndent(@TypeOf(writer), writer);
- try writer.writeAll("}");
- }
-
- fn appendNumber(this: *Headers, num: f64) Api.StringPointer {
- var ptr = Api.StringPointer{ .offset = @truncate(u32, this.buf.items.len), .length = @truncate(
- u32,
- std.fmt.count("{d}", .{num}),
- ) };
- this.buf.ensureUnusedCapacity(this.allocator, ptr.length + 1) catch unreachable;
- this.buf.items.len += ptr.length;
- var slice = this.buf.items[ptr.offset..][0..ptr.length];
- var buf = std.fmt.bufPrint(slice, "{d}", .{num}) catch &[_]u8{};
- ptr.length = @truncate(u32, buf.len);
- return ptr;
- }
-
- pub fn appendInit(this: *Headers, ctx: js.JSContextRef, key: js.JSStringRef, comptime value_type: js.JSType, value: js.JSValueRef) !void {
- this.entries.append(this.allocator, .{
- .name = this.appendString(js.JSStringRef, key, true, true),
- .value = switch (comptime value_type) {
- js.JSType.kJSTypeNumber => this.appendNumber(js.JSValueToNumber(ctx, value, null)),
- js.JSType.kJSTypeString => this.appendString(js.JSStringRef, value, true, true),
- else => unreachable,
- },
- }) catch unreachable;
- }
-
- pub fn clone(this: *const Headers, to: *Headers) !void {
- var buf = this.buf;
- to.* = Headers{
- .entries = try this.entries.clone(this.allocator),
- .buf = try buf.clone(this.allocator),
- .allocator = this.allocator,
- .guard = Guard.none,
- };
- }
};
const PathOrBlob = union(enum) {
@@ -2400,13 +1773,13 @@ pub const Blob = struct {
}
var store = this.store.?;
- defer store.deref();
if (this.file_store.pathlike == .path) {
VirtualMachine.vm.removeFileBlob(this.file_store.pathlike);
}
if (this.system_error) |err| {
bun.default_allocator.destroy(this);
+ store.deref();
cb(cb_ctx, ResultType{ .err = err });
return;
}
@@ -2425,7 +1798,9 @@ pub const Blob = struct {
}
bun.default_allocator.destroy(this);
+
cb(cb_ctx, .{ .result = bytes });
+ store.deref();
}
pub fn run(this: *ReadFile, task: *ReadFileTask) void {
this.runAsyncFrame = async this.runAsync(task);
@@ -2929,7 +2304,12 @@ pub const Blob = struct {
var source_buf: [bun.MAX_PATH_BYTES]u8 = undefined;
var dest_buf: [bun.MAX_PATH_BYTES]u8 = undefined;
- switch (JSC.Node.Syscall.clonefile(this.source_file_store.pathlike.path.sliceZ(&source_buf), this.destination_file_store.pathlike.path.sliceZ(&dest_buf))) {
+ switch (JSC.Node.Syscall.clonefile(
+ this.source_file_store.pathlike.path.sliceZ(&source_buf),
+ this.destination_file_store.pathlike.path.sliceZ(
+ &dest_buf,
+ ),
+ )) {
.err => |errno| {
this.system_error = errno.toSystemError();
return AsyncIO.asError(errno.errno);
@@ -3565,7 +2945,6 @@ pub const Blob = struct {
promise.resolve(globalThis, Function(&blob, globalThis, comptime lifetime));
},
.err => |err| {
- blob.detach();
promise.reject(globalThis, err.toErrorInstance(globalThis));
},
}
@@ -4082,9 +3461,9 @@ pub const Body = struct {
return this.value.use();
}
- pub fn clone(this: Body, allocator: std.mem.Allocator) Body {
+ pub fn clone(this: Body, allocator: std.mem.Allocator, globalThis: *JSGlobalObject) Body {
return Body{
- .init = this.init.clone(allocator),
+ .init = this.init.clone(globalThis),
.value = this.value.clone(allocator),
};
}
@@ -4098,12 +3477,12 @@ pub const Body = struct {
try formatter.printComma(Writer, writer, enable_ansi_colors);
try writer.writeAll("\n");
- if (this.init.headers) |headers| {
- try formatter.writeIndent(Writer, writer);
- try writer.writeAll("headers: ");
- try headers.leak().writeFormat(formatter, writer, comptime enable_ansi_colors);
- try writer.writeAll("\n");
- }
+ // if (this.init.headers) |headers| {
+ // try formatter.writeIndent(Writer, writer);
+ // try writer.writeAll("headers: ");
+ // try headers.leak().writeFormat(formatter, writer, comptime enable_ansi_colors);
+ // try writer.writeAll("\n");
+ // }
try formatter.writeIndent(Writer, writer);
try writer.writeAll("status: ");
@@ -4111,36 +3490,25 @@ pub const Body = struct {
}
pub fn deinit(this: *Body, _: std.mem.Allocator) void {
- if (this.init.headers) |headers| {
- headers.deref();
- this.init.headers = null;
- }
-
this.value.deinit();
}
pub const Init = struct {
- headers: ?*Headers.RefCountedHeaders = null,
+ headers: JSValue = JSValue.zero,
status_code: u16,
method: Method = Method.GET,
- pub fn clone(this: Init, allocator: std.mem.Allocator) Init {
+ pub fn clone(this: Init, globalThis: *JSGlobalObject) Init {
var that = this;
- var headers = this.headers;
- if (headers) |head| {
- headers.?.value.allocator = allocator;
- var new_headers = allocator.create(Headers.RefCountedHeaders) catch unreachable;
- new_headers.allocator = allocator;
- new_headers.count = 1;
- head.leak().clone(&new_headers.value) catch unreachable;
- that.headers = new_headers;
+ if (this.headers.as(FetchHeaders)) |head| {
+ that.headers = head.clone(globalThis);
}
return that;
}
- pub fn init(allocator: std.mem.Allocator, ctx: js.JSContextRef, init_ref: js.JSValueRef) !?Init {
- var result = Init{ .headers = null, .status_code = 200 };
+ pub fn init(_: std.mem.Allocator, ctx: js.JSContextRef, init_ref: js.JSValueRef) !?Init {
+ var result = Init{ .status_code = 200 };
var array = js.JSObjectCopyPropertyNames(ctx, init_ref);
defer js.JSPropertyNameArrayRelease(array);
const count = js.JSPropertyNameArrayGetCount(array);
@@ -4153,16 +3521,14 @@ pub const Body = struct {
if (js.JSStringIsEqualToUTF8CString(property_name_ref, "headers")) {
// only support headers as an object for now.
if (js.JSObjectGetProperty(ctx, init_ref, property_name_ref, null)) |header_prop| {
- switch (js.JSValueGetType(ctx, header_prop)) {
- js.JSType.kJSTypeObject => {
- if (JSC.JSValue.fromRef(header_prop).as(Headers.RefCountedHeaders)) |headers| {
- result.headers = try Headers.RefCountedHeaders.init(undefined, allocator);
- try headers.leak().clone(&result.headers.?.value);
- } else if (try Headers.JS.headersInit(ctx, header_prop)) |headers| {
- result.headers = try Headers.RefCountedHeaders.init(headers, allocator);
- }
- },
- else => {},
+ const header_val = JSValue.fromRef(header_prop);
+ if (header_val.as(FetchHeaders)) |orig| {
+ result.headers = orig.clone(ctx.ptr());
+ } else {
+ result.headers = if (FetchHeaders.createFromJS(ctx.ptr(), header_val)) |headers|
+ headers.toJS(ctx.ptr())
+ else
+ result.headers;
}
}
}
@@ -4185,7 +3551,7 @@ pub const Body = struct {
}
}
- if (result.headers == null and result.status_code < 200) return null;
+ if (result.headers.isEmptyOrUndefinedOrNull() and result.status_code < 200) return null;
return result;
}
};
@@ -4375,7 +3741,6 @@ pub const Body = struct {
pub fn @"200"(_: js.JSContextRef) Body {
return Body{
.init = Init{
- .headers = null,
.status_code = 200,
},
.value = Value.empty,
@@ -4411,7 +3776,7 @@ pub const Body = struct {
exception: js.ExceptionRef,
) Body {
var body = Body{
- .init = Init{ .headers = null, .status_code = 200 },
+ .init = Init{ .status_code = 200 },
};
const value = JSC.JSValue.fromRef(body_ref);
var allocator = getAllocator(ctx);
@@ -4443,30 +3808,28 @@ pub const Body = struct {
// https://developer.mozilla.org/en-US/docs/Web/API/Request
pub const Request = struct {
url: ZigString = ZigString.Empty,
- headers: ?*Headers.RefCountedHeaders = null,
+ headers: JSValue = JSValue.zero,
body: Body.Value = Body.Value{ .Empty = .{} },
method: Method = Method.GET,
uws_request: ?*uws.Request = null,
- pub fn fromRequestContext(ctx: *RequestContext) !Request {
+ pub fn fromRequestContext(ctx: *RequestContext, global: *JSGlobalObject) !Request {
var req = Request{
.url = ZigString.init(std.mem.span(ctx.getFullURL())),
.body = Body.Value.empty,
.method = ctx.method,
- .headers = try Headers.RefCountedHeaders.init(Headers.fromRequestCtx(bun.default_allocator, ctx) catch unreachable, bun.default_allocator),
+ .headers = FetchHeaders.createFromPicoHeaders(global, ctx.request.headers),
};
req.url.mark();
return req;
}
pub fn mimeType(this: *const Request) string {
- if (this.headers) |headers_ref| {
- var headers = headers_ref.get();
- defer headers_ref.deref();
+ if (this.headers.as(FetchHeaders)) |headers| {
// Remember, we always lowercase it
// hopefully doesn't matter here tho
- if (headers.getHeaderIndex("content-type")) |content_type| {
- return headers.asStr(headers.entries.items(.value)[content_type]);
+ if (headers.get("content-type")) |content_type| {
+ return content_type;
}
}
@@ -4658,10 +4021,9 @@ pub const Request = struct {
_: js.JSStringRef,
_: js.ExceptionRef,
) js.JSValueRef {
- if (this.headers) |headers_ref| {
- var headers = headers_ref.leak();
- if (headers.getHeaderIndex("referrer")) |i| {
- return ZigString.init(headers.asStr(headers.entries.get(i).value)).toValueGC(ctx.ptr()).asObjectRef();
+ if (this.headers.as(FetchHeaders)) |headers_ref| {
+ if (headers_ref.get("referrer")) |referrer| {
+ return ZigString.init(referrer).toValueGC(ctx.ptr()).asRef();
}
}
@@ -4759,7 +4121,7 @@ pub const Request = struct {
_: []const js.JSValueRef,
_: js.ExceptionRef,
) js.JSValueRef {
- var cloned = this.clone(getAllocator(ctx));
+ var cloned = this.clone(getAllocator(ctx), ctx.ptr());
return Request.Class.make(ctx, cloned);
}
@@ -4770,37 +4132,38 @@ pub const Request = struct {
_: js.JSStringRef,
_: js.ExceptionRef,
) js.JSValueRef {
- if (this.headers == null) {
- this.headers = Headers.RefCountedHeaders.init(Headers.empty(bun.default_allocator), bun.default_allocator) catch unreachable;
-
+ if (this.headers.isEmptyOrUndefinedOrNull()) {
if (this.uws_request) |req| {
- this.headers.?.value.allocator = bun.default_allocator;
- this.headers.?.value.clonefromUWSRequest(req);
+ this.headers = FetchHeaders.createFromUWS(ctx.ptr(), req);
+ } else {
+ this.headers = FetchHeaders.createEmpty(ctx.ptr());
}
}
- return Headers.Class.make(ctx, this.headers.?.getRef());
+ return this.headers.asObjectRef();
}
- pub fn cloneInto(this: *const Request, req: *Request, allocator: std.mem.Allocator) void {
+ pub fn cloneInto(
+ this: *const Request,
+ req: *Request,
+ allocator: std.mem.Allocator,
+ globalThis: *JSGlobalObject,
+ ) void {
req.* = Request{
.body = this.body.clone(allocator),
.url = ZigString.init(allocator.dupe(u8, this.url.slice()) catch unreachable),
.method = this.method,
};
- if (this.headers) |head| {
- var new_headers = Headers.RefCountedHeaders.init(undefined, allocator) catch unreachable;
- head.leak().clone(&new_headers.value) catch unreachable;
- req.headers = new_headers;
+ if (this.headers.as(FetchHeaders)) |head| {
+ req.headers = head.clone(globalThis);
} else if (this.uws_request) |uws_req| {
- req.headers = Headers.RefCountedHeaders.init(Headers.empty(allocator), allocator) catch unreachable;
- req.headers.?.value.clonefromUWSRequest(uws_req);
+ req.headers = FetchHeaders.createFromUWS(globalThis, uws_req);
}
}
- pub fn clone(this: *const Request, allocator: std.mem.Allocator) *Request {
+ pub fn clone(this: *const Request, allocator: std.mem.Allocator, globalThis: *JSGlobalObject) *Request {
var req = allocator.create(Request) catch unreachable;
- this.cloneInto(req, allocator);
+ this.cloneInto(req, allocator, globalThis);
return req;
}
};
@@ -5039,10 +4402,10 @@ pub const FetchEvent = struct {
defer this.pending_promise = null;
var needs_mime_type = true;
var content_length: ?usize = null;
- if (response.body.init.headers) |headers_ref| {
- var headers = headers_ref.get();
- defer headers_ref.deref();
- request_context.clearHeaders() catch {};
+
+ if (response.body.init.headers.as(JSC.FetchHeaders)) |headers_ref| {
+ var headers = Headers.from(headers_ref, request_context.allocator) catch unreachable;
+
var i: usize = 0;
while (i < headers.entries.len) : (i += 1) {
var header = headers.entries.get(i);