Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LibWeb: Fix is_valid_status_text to handle UTF-8 correctly #2909

Merged
merged 2 commits into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Libraries/LibWeb/Fetch/Response.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ GC::Ref<Response> Response::create(JS::Realm& realm, GC::Ref<Infrastructure::Res
}

// https://httpwg.org/specs/rfc9112.html#status.line
static bool is_valid_status_text(StringView status_text)
static bool is_valid_status_text(String const& status_text)
{
// A status text is a valid status text if it matches the reason-phrase token production.
// A status text is valid if it is either the empty string or matches the reason-phrase token production.
// reason-phrase = 1*( HTAB / SP / VCHAR / obs-text )
// VCHAR = %x21-7E
// obs-text = %x80-FF
return all_of(status_text, [](auto c) {
F3n67u marked this conversation as resolved.
Show resolved Hide resolved
return all_of(status_text.code_points(), [](auto c) {
F3n67u marked this conversation as resolved.
Show resolved Hide resolved
return c == '\t' || c == ' ' || (c >= 0x21 && c <= 0x7E) || (c >= 0x80 && c <= 0xFF);
});
}
Expand All @@ -103,7 +103,7 @@ WebIDL::ExceptionOr<void> Response::initialize_response(ResponseInit const& init
if (init.status < 200 || init.status > 599)
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::RangeError, "Status must be in range 200-599"sv };

// 2. If init["statusText"] does not match the reason-phrase token production, then throw a TypeError.
// 2. If init["statusText"] is not the empty string and 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 };

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Harness status: OK

Found 9 tests

9 Pass
Pass Check default value for type attribute
Pass Check default value for url attribute
Pass Check default value for ok attribute
Pass Check default value for status attribute
Pass Check default value for statusText attribute
Pass Check default value for body attribute
Pass Check status init values and associated getter
Pass Check statusText init values and associated getter
Pass Test that Response.headers has the [SameObject] extended attribute
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!doctype html>
<meta charset=utf-8>
<title>Response init: simple cases</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-init-001.any.js"></script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// META: global=window,worker
// META: title=Response init: simple cases

var defaultValues = { "type" : "default",
"url" : "",
"ok" : true,
"status" : 200,
"statusText" : "",
"body" : null
};

var statusCodes = { "givenValues" : [200, 300, 400, 500, 599],
"expectedValues" : [200, 300, 400, 500, 599]
};
var statusTexts = { "givenValues" : ["", "OK", "with space", String.fromCharCode(0x80)],
"expectedValues" : ["", "OK", "with space", String.fromCharCode(0x80)]
};
var initValuesDict = { "status" : statusCodes,
"statusText" : statusTexts
};

function isOkStatus(status) {
return 200 <= status && 299 >= status;
}

var response = new Response();
for (var attributeName in defaultValues) {
test(function() {
var expectedValue = defaultValues[attributeName];
assert_equals(response[attributeName], expectedValue,
"Expect default response." + attributeName + " is " + expectedValue);
}, "Check default value for " + attributeName + " attribute");
}

for (var attributeName in initValuesDict) {
test(function() {
var valuesToTest = initValuesDict[attributeName];
for (var valueIdx in valuesToTest["givenValues"]) {
var givenValue = valuesToTest["givenValues"][valueIdx];
var expectedValue = valuesToTest["expectedValues"][valueIdx];
var responseInit = {};
responseInit[attributeName] = givenValue;
var response = new Response("", responseInit);
assert_equals(response[attributeName], expectedValue,
"Expect response." + attributeName + " is " + expectedValue +
" when initialized with " + givenValue);
assert_equals(response.ok, isOkStatus(response.status),
"Expect response.ok is " + isOkStatus(response.status));
}
}, "Check " + attributeName + " init values and associated getter");
}

test(function() {
const response1 = new Response("");
assert_equals(response1.headers, response1.headers);

const response2 = new Response("", {"headers": {"X-Foo": "bar"}});
assert_equals(response2.headers, response2.headers);
const headers = response2.headers;
response2.headers.set("X-Foo", "quux");
assert_equals(headers, response2.headers);
headers.set("X-Other-Header", "baz");
assert_equals(headers, response2.headers);
}, "Test that Response.headers has the [SameObject] extended attribute");
Loading