Skip to content

Commit bd7451b

Browse files
Jake ChampionJakeChampion
authored andcommitted
Allow Headers to be used as a base class to extend from within application javascript
1 parent cba3860 commit bd7451b

File tree

2 files changed

+154
-95
lines changed

2 files changed

+154
-95
lines changed

c-dependencies/js-compute-runtime/js-compute-builtins.cpp

Lines changed: 153 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,13 +1053,120 @@ enum class BodyReadResult {
10531053

10541054
namespace Headers {
10551055
enum class Mode : int32_t { Standalone, ProxyToRequest, ProxyToResponse };
1056+
namespace Slots {
1057+
enum { BackingMap, Handle, Mode, HasLazyValues, Count };
1058+
};
1059+
1060+
bool is_instance(JSObject *obj);
1061+
bool is_instance(Value val);
1062+
1063+
namespace detail {
1064+
#define HEADERS_ITERATION_METHOD(argc) \
1065+
METHOD_HEADER(argc) \
1066+
RootedObject backing_map(cx, detail::backing_map(self)); \
1067+
if (!detail::ensure_all_header_values_from_handle(cx, self, backing_map)) \
1068+
return false;
1069+
1070+
static const char VALID_NAME_CHARS[128] = {
1071+
0, 0, 0, 0, 0, 0, 0, 0, // 0
1072+
0, 0, 0, 0, 0, 0, 0, 0, // 8
1073+
0, 0, 0, 0, 0, 0, 0, 0, // 16
1074+
0, 0, 0, 0, 0, 0, 0, 0, // 24
1075+
1076+
0, 1, 0, 1, 1, 1, 1, 1, // 32
1077+
0, 0, 1, 1, 0, 1, 1, 0, // 40
1078+
1, 1, 1, 1, 1, 1, 1, 1, // 48
1079+
1, 1, 0, 0, 0, 0, 0, 0, // 56
1080+
1081+
0, 1, 1, 1, 1, 1, 1, 1, // 64
1082+
1, 1, 1, 1, 1, 1, 1, 1, // 72
1083+
1, 1, 1, 1, 1, 1, 1, 1, // 80
1084+
1, 1, 1, 0, 0, 0, 1, 1, // 88
10561085

1057-
JSObject *create(JSContext *cx, Mode mode, HandleObject owner);
1058-
JSObject *create(JSContext *cx, Mode mode, HandleObject owner, HandleObject init_headers);
1059-
JSObject *create(JSContext *cx, Mode mode, HandleObject owner, HandleValue initv);
1086+
1, 1, 1, 1, 1, 1, 1, 1, // 96
1087+
1, 1, 1, 1, 1, 1, 1, 1, // 104
1088+
1, 1, 1, 1, 1, 1, 1, 1, // 112
1089+
1, 1, 1, 0, 1, 0, 1, 0 // 120
1090+
};
1091+
1092+
#define NORMALIZE_NAME(name, fun_name) \
1093+
RootedValue normalized_name(cx, name); \
1094+
size_t name_len; \
1095+
UniqueChars name_chars = \
1096+
detail::normalize_header_name(cx, &normalized_name, &name_len, fun_name); \
1097+
if (!name_chars) \
1098+
return false;
1099+
1100+
#define NORMALIZE_VALUE(value, fun_name) \
1101+
RootedValue normalized_value(cx, value); \
1102+
size_t value_len; \
1103+
UniqueChars value_chars = \
1104+
detail::normalize_header_value(cx, &normalized_value, &value_len, fun_name); \
1105+
if (!value_chars) \
1106+
return false;
1107+
1108+
JSObject *backing_map(JSObject *self);
1109+
Mode mode(JSObject *self);
1110+
bool lazy_values(JSObject *self);
1111+
uint32_t handle(JSObject *self);
1112+
UniqueChars normalize_header_name(JSContext *cx, MutableHandleValue name_val, size_t *name_len,
1113+
const char *fun_name);
1114+
UniqueChars normalize_header_value(JSContext *cx, MutableHandleValue value_val, size_t *value_len,
1115+
const char *fun_name);
1116+
1117+
static PersistentRooted<JSString *> comma;
1118+
bool append_header_value_to_map(JSContext *cx, HandleObject self, HandleValue normalized_name,
1119+
MutableHandleValue normalized_value);
1120+
bool get_header_names_from_handle(JSContext *cx, uint32_t handle, Mode mode,
1121+
HandleObject backing_map);
1122+
static bool retrieve_value_for_header_from_handle(JSContext *cx, HandleObject self,
1123+
HandleValue name, MutableHandleValue value);
1124+
static bool ensure_value_for_header(JSContext *cx, HandleObject self, HandleValue normalized_name,
1125+
MutableHandleValue values);
1126+
bool get_header_value_for_name(JSContext *cx, HandleObject self, HandleValue name,
1127+
MutableHandleValue rval, const char *fun_name);
1128+
static bool ensure_all_header_values_from_handle(JSContext *cx, HandleObject self,
1129+
HandleObject backing_map);
1130+
typedef int AppendHeaderOperation(int handle, const char *name, size_t name_len, const char *value,
1131+
size_t value_len);
1132+
bool append_header_value(JSContext *cx, HandleObject self, HandleValue name, HandleValue value,
1133+
const char *fun_name);
1134+
} // namespace detail
10601135

10611136
bool delazify(JSContext *cx, HandleObject headers);
1062-
bool maybe_add(JSContext *cx, HandleObject headers, const char *name, const char *value);
1137+
JSObject *create(JSContext *cx, HandleObject headers, Mode mode, HandleObject owner,
1138+
HandleValue initv);
1139+
const unsigned ctor_length = 1;
1140+
bool check_receiver(JSContext *cx, HandleValue receiver, const char *method_name);
1141+
bool get(JSContext *cx, unsigned argc, Value *vp);
1142+
typedef int HeaderValuesSetOperation(int handle, const char *name, size_t name_len,
1143+
const char *values, size_t values_len);
1144+
bool set(JSContext *cx, unsigned argc, Value *vp);
1145+
bool has(JSContext *cx, unsigned argc, Value *vp);
1146+
bool append(JSContext *cx, unsigned argc, Value *vp);
1147+
bool maybe_add(JSContext *cx, HandleObject self, const char *name, const char *value);
1148+
typedef int HeaderRemoveOperation(int handle, const char *name, size_t name_len);
1149+
bool delete_(JSContext *cx, unsigned argc, Value *vp);
1150+
bool forEach(JSContext *cx, unsigned argc, Value *vp);
1151+
bool entries(JSContext *cx, unsigned argc, Value *vp);
1152+
bool keys(JSContext *cx, unsigned argc, Value *vp);
1153+
bool values(JSContext *cx, unsigned argc, Value *vp);
1154+
const JSFunctionSpec methods[] = {
1155+
JS_FN("get", get, 1, JSPROP_ENUMERATE), JS_FN("has", has, 1, JSPROP_ENUMERATE),
1156+
JS_FN("set", set, 2, JSPROP_ENUMERATE), JS_FN("append", append, 2, JSPROP_ENUMERATE),
1157+
JS_FN("delete", delete_, 1, JSPROP_ENUMERATE), JS_FN("forEach", forEach, 1, JSPROP_ENUMERATE),
1158+
JS_FN("entries", entries, 0, JSPROP_ENUMERATE), JS_FN("keys", keys, 0, JSPROP_ENUMERATE),
1159+
JS_FN("values", values, 0, JSPROP_ENUMERATE),
1160+
// [Symbol.iterator] added in init_class.
1161+
JS_FS_END};
1162+
const JSPropertySpec properties[] = {JS_PS_END};
1163+
bool constructor(JSContext *cx, unsigned argc, Value *vp);
1164+
CLASS_BOILERPLATE_CUSTOM_INIT(Headers)
1165+
JSObject *create(JSContext *cx, HandleObject headers, Mode mode, HandleObject owner,
1166+
HandleObject init_headers);
1167+
JSObject *create(JSContext *cx, HandleObject headers, Mode mode, HandleObject owner,
1168+
HandleValue initv);
1169+
JSObject *create(JSContext *cx, HandleObject self, Mode mode, HandleObject owner);
10631170
} // namespace Headers
10641171

10651172
namespace Request {
@@ -1340,7 +1447,11 @@ JSObject *maybe_headers(JSObject *obj) {
13401447
template <auto mode> JSObject *headers(JSContext *cx, HandleObject obj) {
13411448
JSObject *headers = maybe_headers(obj);
13421449
if (!headers) {
1343-
headers = Headers::create(cx, mode, obj);
1450+
RootedObject headersInstance(
1451+
cx, JS_NewObjectWithGivenProto(cx, &Headers::class_, Headers::proto_obj));
1452+
if (!headersInstance)
1453+
return nullptr;
1454+
headers = Headers::create(cx, headersInstance, mode, obj);
13441455
if (!headers)
13451456
return nullptr;
13461457
JS_SetReservedSlot(obj, Slots::Headers, ObjectValue(*headers));
@@ -4670,9 +4781,21 @@ JSObject *create(JSContext *cx, HandleObject requestInstance, HandleValue input,
46704781
// empty one.
46714782
RootedObject headers(cx);
46724783
if (!headers_val.isUndefined()) {
4673-
headers = Headers::create(cx, Headers::Mode::ProxyToRequest, request, headers_val);
4784+
RootedObject headersInstance(
4785+
cx, JS_NewObjectWithGivenProto(cx, &Headers::class_, Headers::proto_obj));
4786+
if (!headersInstance)
4787+
return nullptr;
4788+
4789+
headers =
4790+
Headers::create(cx, headersInstance, Headers::Mode::ProxyToRequest, request, headers_val);
46744791
} else {
4675-
headers = Headers::create(cx, Headers::Mode::ProxyToRequest, request, input_headers);
4792+
RootedObject headersInstance(
4793+
cx, JS_NewObjectWithGivenProto(cx, &Headers::class_, Headers::proto_obj));
4794+
if (!headersInstance)
4795+
return nullptr;
4796+
4797+
headers =
4798+
Headers::create(cx, headersInstance, Headers::Mode::ProxyToRequest, request, input_headers);
46764799
}
46774800

46784801
if (!headers) {
@@ -5057,12 +5180,17 @@ bool constructor(JSContext *cx, unsigned argc, Value *vp) {
50575180
// 7. If `init`["headers"] `exists`, then `fill` `this`’s `headers` with
50585181
// `init`["headers"].
50595182
RootedObject headers(cx);
5060-
headers = Headers::create(cx, Headers::Mode::ProxyToResponse, response, headers_val);
5183+
RootedObject headersInstance(
5184+
cx, JS_NewObjectWithGivenProto(cx, &Headers::class_, Headers::proto_obj));
5185+
if (!headersInstance)
5186+
return false;
5187+
5188+
headers =
5189+
Headers::create(cx, headersInstance, Headers::Mode::ProxyToResponse, response, headers_val);
50615190
if (!headers) {
50625191
return false;
50635192
}
50645193
JS::SetReservedSlot(response, Slots::Headers, JS::ObjectValue(*headers));
5065-
50665194
// 8. If `body` is non-null, then:
50675195
if ((!body_val.isNullOrUndefined())) {
50685196
// 1. If `init`["status"] is a `null body status`, then `throw` a
@@ -5429,58 +5557,7 @@ bool maybe_consume_sequence_or_record(JSContext *cx, HandleValue initv, HandleOb
54295557
return true;
54305558
}
54315559
namespace Headers {
5432-
namespace Slots {
5433-
enum { BackingMap, Handle, Mode, HasLazyValues, Count };
5434-
};
5435-
5436-
bool is_instance(JSObject *obj);
5437-
bool is_instance(Value val);
5438-
54395560
namespace detail {
5440-
#define HEADERS_ITERATION_METHOD(argc) \
5441-
METHOD_HEADER(argc) \
5442-
RootedObject backing_map(cx, detail::backing_map(self)); \
5443-
if (!detail::ensure_all_header_values_from_handle(cx, self, backing_map)) \
5444-
return false;
5445-
5446-
static const char VALID_NAME_CHARS[128] = {
5447-
0, 0, 0, 0, 0, 0, 0, 0, // 0
5448-
0, 0, 0, 0, 0, 0, 0, 0, // 8
5449-
0, 0, 0, 0, 0, 0, 0, 0, // 16
5450-
0, 0, 0, 0, 0, 0, 0, 0, // 24
5451-
5452-
0, 1, 0, 1, 1, 1, 1, 1, // 32
5453-
0, 0, 1, 1, 0, 1, 1, 0, // 40
5454-
1, 1, 1, 1, 1, 1, 1, 1, // 48
5455-
1, 1, 0, 0, 0, 0, 0, 0, // 56
5456-
5457-
0, 1, 1, 1, 1, 1, 1, 1, // 64
5458-
1, 1, 1, 1, 1, 1, 1, 1, // 72
5459-
1, 1, 1, 1, 1, 1, 1, 1, // 80
5460-
1, 1, 1, 0, 0, 0, 1, 1, // 88
5461-
5462-
1, 1, 1, 1, 1, 1, 1, 1, // 96
5463-
1, 1, 1, 1, 1, 1, 1, 1, // 104
5464-
1, 1, 1, 1, 1, 1, 1, 1, // 112
5465-
1, 1, 1, 0, 1, 0, 1, 0 // 120
5466-
};
5467-
5468-
#define NORMALIZE_NAME(name, fun_name) \
5469-
RootedValue normalized_name(cx, name); \
5470-
size_t name_len; \
5471-
UniqueChars name_chars = \
5472-
detail::normalize_header_name(cx, &normalized_name, &name_len, fun_name); \
5473-
if (!name_chars) \
5474-
return false;
5475-
5476-
#define NORMALIZE_VALUE(value, fun_name) \
5477-
RootedValue normalized_value(cx, value); \
5478-
size_t value_len; \
5479-
UniqueChars value_chars = \
5480-
detail::normalize_header_value(cx, &normalized_value, &value_len, fun_name); \
5481-
if (!value_chars) \
5482-
return false;
5483-
54845561
JSObject *backing_map(JSObject *self) {
54855562
MOZ_ASSERT(is_instance(self));
54865563
return &JS::GetReservedSlot(self, Slots::BackingMap).toObject();
@@ -5615,8 +5692,6 @@ UniqueChars normalize_header_value(JSContext *cx, MutableHandleValue value_val,
56155692
return value;
56165693
}
56175694

5618-
static PersistentRooted<JSString *> comma;
5619-
56205695
// Append an already normalized value for an already normalized header name
56215696
// to the JS side map, but not the host.
56225697
//
@@ -5868,8 +5943,9 @@ bool delazify(JSContext *cx, HandleObject headers) {
58685943
return detail::ensure_all_header_values_from_handle(cx, headers, backing_map);
58695944
}
58705945

5871-
JSObject *create(JSContext *cx, Mode mode, HandleObject owner, HandleObject init_headers) {
5872-
RootedObject headers(cx, create(cx, mode, owner));
5946+
JSObject *create(JSContext *cx, HandleObject self, Mode mode, HandleObject owner,
5947+
HandleObject init_headers) {
5948+
RootedObject headers(cx, create(cx, self, mode, owner));
58735949
if (!headers) {
58745950
return nullptr;
58755951
}
@@ -5917,8 +5993,9 @@ JSObject *create(JSContext *cx, Mode mode, HandleObject owner, HandleObject init
59175993
return headers;
59185994
}
59195995

5920-
JSObject *create(JSContext *cx, Mode mode, HandleObject owner, HandleValue initv) {
5921-
RootedObject headers(cx, create(cx, mode, owner));
5996+
JSObject *create(JSContext *cx, HandleObject self, Mode mode, HandleObject owner,
5997+
HandleValue initv) {
5998+
RootedObject headers(cx, create(cx, self, mode, owner));
59225999
if (!headers)
59236000
return nullptr;
59246001

@@ -5936,18 +6013,6 @@ JSObject *create(JSContext *cx, Mode mode, HandleObject owner, HandleValue initv
59366013
return headers;
59376014
}
59386015

5939-
bool constructor(JSContext *cx, unsigned argc, Value *vp) {
5940-
CTOR_HEADER("Headers", 0);
5941-
RootedObject headers(cx, create(cx, Mode::Standalone, nullptr, args.get(0)));
5942-
if (!headers)
5943-
return false;
5944-
5945-
args.rval().setObject(*headers);
5946-
return true;
5947-
}
5948-
5949-
const unsigned ctor_length = 1;
5950-
59516016
bool check_receiver(JSContext *cx, HandleValue receiver, const char *method_name);
59526017

59536018
bool get(JSContext *cx, unsigned argc, Value *vp) {
@@ -6135,18 +6200,16 @@ bool values(JSContext *cx, unsigned argc, Value *vp) {
61356200
return JS::MapValues(cx, backing_map, args.rval());
61366201
}
61376202

6138-
const JSFunctionSpec methods[] = {
6139-
JS_FN("get", get, 1, JSPROP_ENUMERATE), JS_FN("has", has, 1, JSPROP_ENUMERATE),
6140-
JS_FN("set", set, 2, JSPROP_ENUMERATE), JS_FN("append", append, 2, JSPROP_ENUMERATE),
6141-
JS_FN("delete", delete_, 1, JSPROP_ENUMERATE), JS_FN("forEach", forEach, 1, JSPROP_ENUMERATE),
6142-
JS_FN("entries", entries, 0, JSPROP_ENUMERATE), JS_FN("keys", keys, 0, JSPROP_ENUMERATE),
6143-
JS_FN("values", values, 0, JSPROP_ENUMERATE),
6144-
// [Symbol.iterator] added in init_class.
6145-
JS_FS_END};
6146-
6147-
const JSPropertySpec properties[] = {JS_PS_END};
6203+
bool constructor(JSContext *cx, unsigned argc, Value *vp) {
6204+
CTOR_HEADER("Headers", 0);
6205+
RootedObject headersInstance(cx, JS_NewObjectForConstructor(cx, &class_, args));
6206+
RootedObject headers(cx, create(cx, headersInstance, Mode::Standalone, nullptr, args.get(0)));
6207+
if (!headers)
6208+
return false;
61486209

6149-
CLASS_BOILERPLATE_CUSTOM_INIT(Headers)
6210+
args.rval().setObject(*headers);
6211+
return true;
6212+
}
61506213

61516214
bool init_class(JSContext *cx, HandleObject global) {
61526215
bool ok = init_class_impl(cx, global);
@@ -6162,11 +6225,7 @@ bool init_class(JSContext *cx, HandleObject global) {
61626225
return JS_DefinePropertyById(cx, proto_obj, iteratorId, entries, 0);
61636226
}
61646227

6165-
JSObject *create(JSContext *cx, Mode mode, HandleObject owner) {
6166-
RootedObject self(cx, JS_NewObjectWithGivenProto(cx, &class_, proto_obj));
6167-
if (!self)
6168-
return nullptr;
6169-
6228+
JSObject *create(JSContext *cx, HandleObject self, Mode mode, HandleObject owner) {
61706229
JS_SetReservedSlot(self, Slots::Mode, JS::Int32Value(static_cast<int32_t>(mode)));
61716230
uint32_t handle = UINT32_MAX - 1;
61726231
if (mode != Mode::Standalone)

integration-tests/js-compute/fixtures/extend-from-builtins/extend-from-builtins.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const builtins = [
66
// Request,
77
Response,
88
Dictionary,
9-
// Headers,
9+
Headers,
1010
CacheOverride,
1111
TextEncoder,
1212
TextDecoder,

0 commit comments

Comments
 (0)