Skip to content

Commit

Permalink
LibWeb: Add statusText validation for Response constructor
Browse files Browse the repository at this point in the history
Implemented validation to ensure `statusText` matches the
`reason-phrase` token production.

This change fixes a WPT subtest which I have imported.
  • Loading branch information
F3n67u committed Dec 10, 2024
1 parent d835a00 commit 35a120e
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 1 deletion.
18 changes: 17 additions & 1 deletion Libraries/LibWeb/Fetch/Response.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,30 @@ GC::Ref<Response> Response::create(JS::Realm& realm, GC::Ref<Infrastructure::Res
return response_object;
}

// A status text is valid if it matches the [reason-phrase](https://httpwg.org/specs/rfc9112.html#status.line) token production.
// reason-phrase = 1*( HTAB / SP / VCHAR / obs-text )
// VCHAR = %x21-7E
// obs-text = %x80-FF
static bool is_valid_status_text(StringView status_text)
{
if (status_text.is_empty())
return false; // reason-phrase must have at least one character

return all_of(status_text, [](auto c) {
return c == '\t' || c == ' ' || (c >= 0x21 && c <= 0x7E) || (c >= 0x80 && c <= 0xFF);
});
}

// https://fetch.spec.whatwg.org/#initialize-a-response
WebIDL::ExceptionOr<void> Response::initialize_response(ResponseInit const& init, Optional<Infrastructure::BodyWithType> const& body)
{
// 1. If init["status"] is not in the range 200 to 599, inclusive, then throw a RangeError.
if (init.status < 200 || init.status > 599)
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::RangeError, "Status must be in range 200-599"sv };

// FIXME: 2. If init["statusText"] does not match the reason-phrase token production, then throw a TypeError.
// 2. If init["statusText"] does not match the reason-phrase token production, then throw a TypeError.
if (!is_valid_status_text(init.status_text))
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid statusText: does not match the reason-phrase token production"sv };

// 3. Set response’s response’s status to init["status"].
m_response->set_status(init.status);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Harness status: OK

Found 10 tests

10 Pass
Pass Throws RangeError when responseInit's status is 0
Pass Throws RangeError when responseInit's status is 100
Pass Throws RangeError when responseInit's status is 199
Pass Throws RangeError when responseInit's status is 600
Pass Throws RangeError when responseInit's status is 1000
Pass Throws TypeError when responseInit's statusText is

Pass Throws TypeError when responseInit's statusText is Ā
Pass Throws TypeError when building a response with body and a body status of 204
Pass Throws TypeError when building a response with body and a body status of 205
Pass Throws TypeError when building a response with body and a body status of 304
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!doctype html>
<meta charset=utf-8>
<title>Response error</title>
<script>
self.GLOBAL = {
isWindow: function() { return true; },
isWorker: function() { return false; },
isShadowRealm: function() { return false; },
};
</script>
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>

<div id=log></div>
<script src="../../../fetch/api/response/response-error.any.js"></script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// META: global=window,worker
// META: title=Response error

var invalidStatus = [0, 100, 199, 600, 1000];
invalidStatus.forEach(function(status) {
test(function() {
assert_throws_js(RangeError, function() { new Response("", { "status" : status }); },
"Expect RangeError exception when status is " + status);
},"Throws RangeError when responseInit's status is " + status);
});

var invalidStatusText = ["\n", "Ā"];
invalidStatusText.forEach(function(statusText) {
test(function() {
assert_throws_js(TypeError, function() { new Response("", { "statusText" : statusText }); },
"Expect TypeError exception " + statusText);
},"Throws TypeError when responseInit's statusText is " + statusText);
});

var nullBodyStatus = [204, 205, 304];
nullBodyStatus.forEach(function(status) {
test(function() {
assert_throws_js(TypeError,
function() { new Response("body", {"status" : status }); },
"Expect TypeError exception ");
},"Throws TypeError when building a response with body and a body status of " + status);
});

0 comments on commit 35a120e

Please sign in to comment.