Skip to content

Commit 18053aa

Browse files
Jake ChampionJakeChampion
authored andcommitted
Add ability to make Headers immutable - this is required for the Response.error and Response.redirect static methods
1 parent 4ea7de7 commit 18053aa

File tree

4 files changed

+40
-16
lines changed

4 files changed

+40
-16
lines changed

runtime/js-compute-runtime/builtins/headers.cpp

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,10 @@ bool ensure_all_header_values_from_handle(JSContext *cx, JS::HandleObject self,
436436

437437
} // namespace
438438

439+
bool Headers::is_immutable(JS::HandleObject self) {
440+
return JS::GetReservedSlot(self, static_cast<uint32_t>(Headers::Slots::Immutable)).toBoolean();
441+
}
442+
439443
bool Headers::append_header_value(JSContext *cx, JS::HandleObject self, JS::HandleValue name,
440444
JS::HandleValue value, const char *fun_name) {
441445
NORMALIZE_NAME(name, fun_name)
@@ -482,8 +486,8 @@ bool Headers::delazify(JSContext *cx, JS::HandleObject headers) {
482486
}
483487

484488
JSObject *Headers::create(JSContext *cx, JS::HandleObject self, Headers::Mode mode,
485-
JS::HandleObject owner, JS::HandleObject init_headers) {
486-
JS::RootedObject headers(cx, create(cx, self, mode, owner));
489+
JS::HandleObject owner, JS::HandleObject init_headers, bool immutable) {
490+
JS::RootedObject headers(cx, create(cx, self, mode, owner, immutable));
487491
if (!headers) {
488492
return nullptr;
489493
}
@@ -536,8 +540,8 @@ JSObject *Headers::create(JSContext *cx, JS::HandleObject self, Headers::Mode mo
536540
}
537541

538542
JSObject *Headers::create(JSContext *cx, JS::HandleObject self, Headers::Mode mode,
539-
JS::HandleObject owner, JS::HandleValue initv) {
540-
JS::RootedObject headers(cx, create(cx, self, mode, owner));
543+
JS::HandleObject owner, JS::HandleValue initv, bool immutable) {
544+
JS::RootedObject headers(cx, create(cx, self, mode, owner, immutable));
541545
if (!headers)
542546
return nullptr;
543547

@@ -569,6 +573,11 @@ bool Headers::set(JSContext *cx, unsigned argc, JS::Value *vp) {
569573
NORMALIZE_NAME(args[0], "Headers.set")
570574
NORMALIZE_VALUE(args[1], "Headers.set")
571575

576+
if (Headers::is_immutable(self)) {
577+
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_HEADERS_IMMUTABLE, "Headers.set");
578+
return false;
579+
}
580+
572581
auto mode = get_mode(self);
573582
if (mode != Mode::Standalone) {
574583
auto handle = get_handle(self);
@@ -608,6 +617,11 @@ bool Headers::has(JSContext *cx, unsigned argc, JS::Value *vp) {
608617
bool Headers::append(JSContext *cx, unsigned argc, JS::Value *vp) {
609618
METHOD_HEADER(2)
610619

620+
if (Headers::is_immutable(self)) {
621+
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_HEADERS_IMMUTABLE, "Headers.append");
622+
return false;
623+
}
624+
611625
if (!Headers::append_header_value(cx, self, args[0], args[1], "Headers.append")) {
612626
return false;
613627
}
@@ -647,6 +661,11 @@ bool Headers::delete_(JSContext *cx, unsigned argc, JS::Value *vp) {
647661

648662
NORMALIZE_NAME(args[0], "Headers.delete")
649663

664+
if (Headers::is_immutable(self)) {
665+
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_HEADERS_IMMUTABLE, "Headers.delete");
666+
return false;
667+
}
668+
650669
bool has;
651670
JS::RootedObject map(cx, get_backing_map(self));
652671
if (!JS::MapDelete(cx, map, normalized_name, &has)) {
@@ -763,7 +782,7 @@ const JSPropertySpec Headers::properties[] = {
763782
bool Headers::constructor(JSContext *cx, unsigned argc, JS::Value *vp) {
764783
CTOR_HEADER("Headers", 0);
765784
JS::RootedObject headersInstance(cx, JS_NewObjectForConstructor(cx, &class_, args));
766-
JS::RootedObject headers(cx, create(cx, headersInstance, Mode::Standalone, nullptr, args.get(0)));
785+
JS::RootedObject headers(cx, create(cx, headersInstance, Mode::Standalone, nullptr, args.get(0), false));
767786
if (!headers) {
768787
return false;
769788
}
@@ -787,7 +806,7 @@ bool Headers::init_class(JSContext *cx, JS::HandleObject global) {
787806
}
788807

789808
JSObject *Headers::create(JSContext *cx, JS::HandleObject self, Headers::Mode mode,
790-
JS::HandleObject owner) {
809+
JS::HandleObject owner, bool immutable) {
791810
JS_SetReservedSlot(self, static_cast<uint32_t>(Slots::Mode),
792811
JS::Int32Value(static_cast<int32_t>(mode)));
793812
uint32_t handle = UINT32_MAX - 1;
@@ -814,6 +833,7 @@ JSObject *Headers::create(JSContext *cx, JS::HandleObject self, Headers::Mode mo
814833
}
815834

816835
JS_SetReservedSlot(self, static_cast<uint32_t>(Slots::HasLazyValues), JS::BooleanValue(lazy));
836+
JS_SetReservedSlot(self, static_cast<uint32_t>(Slots::Immutable), JS::BooleanValue(immutable));
817837

818838
return self;
819839
}

runtime/js-compute-runtime/builtins/headers.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,16 @@ class Headers final : public BuiltinImpl<Headers> {
3030
Handle,
3131
Mode,
3232
HasLazyValues,
33+
Immutable,
3334
Count,
3435
};
3536

37+
static bool is_immutable(JS::HandleObject self);
38+
3639
static bool delazify(JSContext *cx, JS::HandleObject headers);
3740

3841
/**
39-
* Adds the given header name/value to `self`'s list of headers iff `self`
42+
* Adds the given header name/value to `self`'s list of headers if `self`
4043
* doesn't already contain a header with that name.
4144
*
4245
* Assumes that both the name and value are valid and normalized.
@@ -63,11 +66,11 @@ class Headers final : public BuiltinImpl<Headers> {
6366
static bool constructor(JSContext *cx, unsigned argc, JS::Value *vp);
6467

6568
static JSObject *create(JSContext *cx, JS::HandleObject headers, enum Mode mode,
66-
JS::HandleObject owner, JS::HandleObject init_headers);
69+
JS::HandleObject owner, JS::HandleObject init_headers, bool immutable);
6770
static JSObject *create(JSContext *cx, JS::HandleObject headers, enum Mode mode,
68-
JS::HandleObject owner, JS::HandleValue initv);
71+
JS::HandleObject owner, JS::HandleValue initv, bool immutable);
6972
static JSObject *create(JSContext *cx, JS::HandleObject self, enum Mode mode,
70-
JS::HandleObject owner);
73+
JS::HandleObject owner, bool immutable);
7174
};
7275

7376
} // namespace builtins

runtime/js-compute-runtime/builtins/request-response.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ JSObject *RequestOrResponse::headers(JSContext *cx, JS::HandleObject obj) {
366366
return nullptr;
367367
}
368368

369-
headers = builtins::Headers::create(cx, headersInstance, mode, obj);
369+
headers = builtins::Headers::create(cx, headersInstance, mode, obj, false);
370370
if (!headers) {
371371
return nullptr;
372372
}
@@ -1821,7 +1821,7 @@ JSObject *Request::create(JSContext *cx, JS::HandleObject requestInstance, JS::H
18211821
return nullptr;
18221822

18231823
headers = builtins::Headers::create(
1824-
cx, headersInstance, builtins::Headers::Mode::ProxyToRequest, request, headers_val);
1824+
cx, headersInstance, builtins::Headers::Mode::ProxyToRequest, request, headers_val, false);
18251825
} else {
18261826
JS::RootedObject headersInstance(cx, JS_NewObjectWithGivenProto(cx, &builtins::Headers::class_,
18271827
builtins::Headers::proto_obj));
@@ -2416,7 +2416,7 @@ bool Response::redirect(JSContext *cx, unsigned argc, JS::Value *vp) {
24162416
return false;
24172417

24182418
headers = builtins::Headers::create(cx, headersInstance, builtins::Headers::Mode::ProxyToResponse,
2419-
response);
2419+
response, false);
24202420
if (!headers) {
24212421
return false;
24222422
}
@@ -2569,7 +2569,7 @@ bool Response::json(JSContext *cx, unsigned argc, JS::Value *vp) {
25692569
return false;
25702570

25712571
headers = builtins::Headers::create(cx, headersInstance, builtins::Headers::Mode::ProxyToResponse,
2572-
response, headers_val);
2572+
response, headers_val, false);
25732573
if (!headers) {
25742574
return false;
25752575
}
@@ -2764,7 +2764,7 @@ bool Response::constructor(JSContext *cx, unsigned argc, JS::Value *vp) {
27642764
return false;
27652765

27662766
headers = builtins::Headers::create(cx, headersInstance, builtins::Headers::Mode::ProxyToResponse,
2767-
response, headers_val);
2767+
response, headers_val, false);
27682768
if (!headers) {
27692769
return false;
27702770
}

runtime/js-compute-runtime/error-numbers.msg

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ MSG_DEF(JSMSG_RESPONSE_JSON_INVALID_VALUE, 0, JSEXN_TYPEERR,
115115
MSG_DEF(JSMSG_TEXT_DECODER_INVALID_ENCODING, 1, JSEXN_RANGEERR, "TextDecoder constructor: The given encoding '{0}' is not supported.")
116116
MSG_DEF(JSMSG_TEXT_DECODER_DECODING_FAILED, 0, JSEXN_TYPEERR, "TextDecoder.decode: Decoding failed.")
117117
MSG_DEF(JSMSG_TEXT_DECODER_OPTIONS_NOT_DICTIONARY, 0, JSEXN_TYPEERR, "TextDecoder constructor: options argument can't be converted to a dictionary.")
118-
MSG_DEF(JSMSG_TEXT_DECODER_DECODE_OPTIONS_NOT_DICTIONARY, 0, JSEXN_TYPEERR, "TextDecoder.decode: options argument can't be converted to a dictionary.")
118+
MSG_DEF(JSMSG_TEXT_DECODER_DECODE_OPTIONS_NOT_DICTIONARY, 0, JSEXN_TYPEERR, "TextDecoder.decode: options argument can't be converted to a dictionary.")
119119
MSG_DEF(JSMSG_TEXT_ENCODER_ENCODEINTO_INVALID_ARRAY, 0, JSEXN_TYPEERR, "TextEncoder.encodeInto: Argument 2 does not implement interface Uint8Array.")
120120
MSG_DEF(JSMSG_SIMPLE_CACHE_SET_CONTENT_STREAM, 0, JSEXN_TYPEERR, "Content-provided streams are not yet supported for streaming into SimpleCache")
121+
MSG_DEF(JSMSG_HEADERS_IMMUTABLE, 1, JSEXN_TYPEERR, "{0}: Headers are immutable and cannot be modified")
121122
//clang-format on

0 commit comments

Comments
 (0)