Skip to content

Commit 4ea7de7

Browse files
Jake ChampionJakeChampion
authored andcommitted
fix: return correct error type (TypeError or RangeError instead of Error) in Request and Response methods
1 parent b08ae8d commit 4ea7de7

File tree

3 files changed

+37
-13
lines changed

3 files changed

+37
-13
lines changed

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

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ bool RequestOrResponse::mark_body_used(JSContext *cx, JS::HandleObject obj) {
167167
// it's a disturbed ReadableStream. To improve error reporting, we clear
168168
// the current exception and throw a better one.
169169
JS_ClearPendingException(cx);
170-
JS_ReportErrorLatin1(cx, "The ReadableStream body is already locked and can't be consumed");
170+
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_READABLE_STREAM_LOCKED_OR_DISTRUBED);
171171
return false;
172172
}
173173
}
@@ -258,8 +258,7 @@ bool RequestOrResponse::extract_body(JSContext *cx, JS::HandleObject self,
258258

259259
if (body_obj && JS::IsReadableStream(body_obj)) {
260260
if (RequestOrResponse::body_unusable(cx, body_obj)) {
261-
JS_ReportErrorLatin1(cx, "Can't use a ReadableStream that's locked or has ever been "
262-
"read from or canceled as a Request or Response body.");
261+
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_READABLE_STREAM_LOCKED_OR_DISTRUBED);
263262
return false;
264263
}
265264

@@ -1368,8 +1367,7 @@ bool Request::clone(JSContext *cx, unsigned argc, JS::Value *vp) {
13681367
}
13691368
body_stream.set(&body1_val.toObject());
13701369
if (RequestOrResponse::body_unusable(cx, body_stream)) {
1371-
JS_ReportErrorLatin1(cx, "Can't use a ReadableStream that's locked or has ever been "
1372-
"read from or canceled as a Request body.");
1370+
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_READABLE_STREAM_LOCKED_OR_DISTRUBED);
13731371
return false;
13741372
}
13751373

@@ -2651,9 +2649,34 @@ bool Response::constructor(JSContext *cx, unsigned argc, JS::Value *vp) {
26512649
if (!status_val.isUndefined() && !JS::ToUint16(cx, status_val, &status)) {
26522650
return false;
26532651
}
2652+
if (!statusText_val.isUndefined()) {
2653+
auto status_text_result = GlobalProperties::convertJSValueToByteString(cx, statusText_val);
2654+
if (status_text_result.isErr()) {
2655+
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_RESPONSE_CONSTRUCTOR_INVALID_STATUS_TEXT);
2656+
return false;
2657+
}
2658+
auto status_text = status_text_result.unwrap();
2659+
auto it = std::find_if(status_text.begin(), status_text.end(), [](unsigned char c) {
2660+
if (c < 9) {
2661+
return true;
2662+
}
2663+
if (c > 9 && c < 32) {
2664+
return true;
2665+
}
2666+
if (c == 127) {
2667+
return true;
2668+
}
2669+
if (c > 255) {
2670+
return true;
2671+
}
2672+
return false;
2673+
});
26542674

2655-
if (!statusText_val.isUndefined() && !(statusText = JS::ToString(cx, statusText_val))) {
2656-
return false;
2675+
if (it != status_text.end()) {
2676+
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_RESPONSE_CONSTRUCTOR_INVALID_STATUS_TEXT);
2677+
return false;
2678+
}
2679+
statusText = JS_NewStringCopyZ(cx, status_text.c_str());
26572680
}
26582681

26592682
} else if (!init_val.isNullOrUndefined()) {
@@ -2665,13 +2688,12 @@ bool Response::constructor(JSContext *cx, unsigned argc, JS::Value *vp) {
26652688
// 1. If `init`["status"] is not in the range 200 to 599, inclusive, then
26662689
// `throw` a ``RangeError``.
26672690
if (status < 200 || status > 599) {
2668-
JS_ReportErrorLatin1(cx, "Response constructor: invalid status %u", status);
2691+
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_RESPONSE_CONSTRUCTOR_INVALID_STATUS, status);
26692692
return false;
26702693
}
26712694

26722695
// 2. If `init`["statusText"] does not match the `reason-phrase` token
2673-
// production, then `throw` a ``TypeError``. Skipped: the statusText can only
2674-
// be consumed by the content creating it, so we're lenient about its format.
2696+
// production, then `throw` a ``TypeError``.
26752697

26762698
// 3. Set `this`’s `response` to a new `response`.
26772699
// TODO(performance): consider not creating a host-side representation for responses
@@ -2752,8 +2774,7 @@ bool Response::constructor(JSContext *cx, unsigned argc, JS::Value *vp) {
27522774
// 1. If `init`["status"] is a `null body status`, then `throw` a
27532775
// ``TypeError``.
27542776
if (status == 204 || status == 205 || status == 304) {
2755-
JS_ReportErrorLatin1(cx, "Response constructor: Response body is given "
2756-
"with a null body status.");
2777+
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_RESPONSE_CONSTRUCTOR_BODY_WITH_NULL_BODY_STATUS);
27572778
return false;
27582779
}
27592780

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ MSG_DEF(JSMSG_BACKEND_PORT_INVALID, 0, JSEXN_RANGEERR
101101
MSG_DEF(JSMSG_CACHE_OVERRIDE_MODE_INVALID, 1, JSEXN_TYPEERR, "CacheOverride constructor: 'mode' has to be \"none\", \"pass\", or \"override\", but got \"{0}\"")
102102
MSG_DEF(JSMSG_RESPONSE_VALUE_NOT_UINT8ARRAY, 0, JSEXN_TYPEERR, "Can't convert value to Uint8Array while consuming Body")
103103
MSG_DEF(JSMSG_RESPONSE_BODY_DISTURBED_OR_LOCKED, 0, JSEXN_TYPEERR, "Response body object should not be disturbed or locked")
104+
MSG_DEF(JSMSG_RESPONSE_CONSTRUCTOR_INVALID_STATUS, 1, JSEXN_RANGEERR, "Response constructor: Invalid response status code. The status provided ({0}) is outside the range [200, 599].")
105+
MSG_DEF(JSMSG_RESPONSE_CONSTRUCTOR_INVALID_STATUS_TEXT, 0, JSEXN_TYPEERR, "Response constructor: Invalid response status text. The statusText provided contains invalid characters.")
106+
MSG_DEF(JSMSG_RESPONSE_CONSTRUCTOR_BODY_WITH_NULL_BODY_STATUS, 0, JSEXN_TYPEERR, "Response constructor: Response body is given with a null body status.")
104107
MSG_DEF(JSMSG_REQUEST_BACKEND_DOES_NOT_EXIST, 1, JSEXN_TYPEERR, "Requested backend named '{0}' does not exist")
105108
MSG_DEF(JSMSG_SUBTLE_CRYPTO_ERROR, 1, JSEXN_ERR, "{0}")
106109
MSG_DEF(JSMSG_SUBTLE_CRYPTO_INVALID_JWK_KTY_VALUE, 1, JSEXN_ERR, "The JWK 'kty' member was not '{0}'")

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ extern const char base64URLEncodeTable[65];
102102

103103
std::string forgivingBase64Encode(std::string_view data, const char *encodeTable);
104104
JS::Result<std::string> forgivingBase64Decode(std::string_view data, const uint8_t *decodeTable);
105-
105+
JS::Result<std::string> convertJSValueToByteString(JSContext *cx, JS::Handle<JS::Value> v);
106106
JS::Result<std::string> convertJSValueToByteString(JSContext *cx, std::string v);
107107
} // namespace GlobalProperties
108108

0 commit comments

Comments
 (0)