LibWeb/Fetch: Share validation logic in the Headers class

This is an editorial change in the Fetch spec.

See: https://github.com/whatwg/fetch/commit/f435978
This commit is contained in:
Linus Groh 2022-12-07 19:14:45 +00:00
parent 3414a6ba20
commit a06b97dae0
Notes: sideshowbarker 2024-07-17 05:05:51 +09:00
2 changed files with 47 additions and 57 deletions

View file

@ -62,36 +62,24 @@ WebIDL::ExceptionOr<void> Headers::delete_(DeprecatedString const& name_string)
auto& realm = this->realm();
auto name = name_string.bytes();
// 1. If name is not a header name, then throw a TypeError.
if (!Infrastructure::is_header_name(name))
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid header name"sv };
// 2. If thiss guard is "immutable", then throw a TypeError.
if (m_guard == Guard::Immutable)
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Headers object is immutable"sv };
// 3. Otherwise, if this's guard is "request" and (name, ``) is a forbidden request-header, return.
// NOTE: Passing a dummy header value to forbidden request-header ought not to have any negative repercussions.
// 1. If validating (name, ``) for headers returns false, then return.
// NOTE: Passing a dummy header value ought not to have any negative repercussions.
auto header = TRY_OR_RETURN_OOM(realm, Infrastructure::Header::from_string_pair(name, ""sv));
if (m_guard == Guard::Request && TRY_OR_RETURN_OOM(realm, Infrastructure::is_forbidden_request_header(header)))
if (!TRY(validate(header)))
return {};
// 4. Otherwise, if thiss guard is "request-no-cors", name is not a no-CORS-safelisted request-header name, and name is not a privileged no-CORS request-header name, return.
// 2. If thiss guard is "request-no-cors", name is not a no-CORS-safelisted request-header name, and name is not a privileged no-CORS request-header name, then return.
if (m_guard == Guard::RequestNoCORS && !Infrastructure::is_no_cors_safelisted_request_header_name(name) && !Infrastructure::is_privileged_no_cors_request_header_name(name))
return {};
// 5. Otherwise, if thiss guard is "response" and name is a forbidden response-header name, return.
if (m_guard == Guard::Response && Infrastructure::is_forbidden_response_header_name(name))
return {};
// 6. If thiss header list does not contain name, then return.
// 3. If thiss header list does not contain name, then return.
if (!m_header_list->contains(name))
return {};
// 7. Delete name from thiss header list.
// 4. Delete name from thiss header list.
m_header_list->delete_(name);
// 8. If thiss guard is "request-no-cors", then remove privileged no-CORS request-headers from this.
// 5. If thiss guard is "request-no-cors", then remove privileged no-CORS request-headers from this.
if (m_guard == Guard::RequestNoCORS)
remove_privileged_no_cors_request_headers();
@ -144,32 +132,18 @@ WebIDL::ExceptionOr<void> Headers::set(DeprecatedString const& name_string, Depr
.value = move(normalized_value),
};
// 2. If name is not a header name or value is not a header value, then throw a TypeError.
if (!Infrastructure::is_header_name(name))
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid header name"sv };
if (!Infrastructure::is_header_value(value))
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid header value"sv };
// 3. If thiss guard is "immutable", then throw a TypeError.
if (m_guard == Guard::Immutable)
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Headers object is immutable"sv };
// 4. Otherwise, if thiss guard is "request" and (name, value) is a forbidden request-header, return.
if (m_guard == Guard::Request && TRY_OR_RETURN_OOM(realm, Infrastructure::is_forbidden_request_header(header)))
// 2. If validating (name, value) for headers returns false, then return.
if (!TRY(validate(header)))
return {};
// 5. Otherwise, if thiss guard is "request-no-cors" and (name, value) is not a no-CORS-safelisted request-header, return.
// 3. If thiss guard is "request-no-cors" and (name, value) is not a no-CORS-safelisted request-header, then return.
if (m_guard == Guard::RequestNoCORS && !Infrastructure::is_no_cors_safelisted_request_header(header))
return {};
// 6. Otherwise, if thiss guard is "response" and name is a forbidden response-header name, return.
if (m_guard == Guard::Response && Infrastructure::is_forbidden_response_header_name(name))
return {};
// 7. Set (name, value) in thiss header list.
// 4. Set (name, value) in thiss header list.
TRY_OR_RETURN_OOM(realm, m_header_list->set(move(header)));
// 8. If thiss guard is "request-no-cors", then remove privileged no-CORS request-headers from this.
// 5. If thiss guard is "request-no-cors", then remove privileged no-CORS request-headers from this.
if (m_guard == Guard::RequestNoCORS)
remove_privileged_no_cors_request_headers();
@ -213,6 +187,35 @@ JS::ThrowCompletionOr<void> Headers::for_each(ForEachCallback callback)
return {};
}
// https://fetch.spec.whatwg.org/#headers-validate
WebIDL::ExceptionOr<bool> Headers::validate(Infrastructure::Header const& header) const
{
// To validate a header (name, value) for a Headers object headers:
auto& realm = this->realm();
auto const& [name, value] = header;
// 1. If name is not a header name or value is not a header value, then throw a TypeError.
if (!Infrastructure::is_header_name(name))
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid header name"sv };
if (!Infrastructure::is_header_value(value))
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid header value"sv };
// 2. If headerss guard is "immutable", then throw a TypeError.
if (m_guard == Guard::Immutable)
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Headers object is immutable"sv };
// 3. If headerss guard is "request" and (name, value) is a forbidden request-header, then return false.
if (m_guard == Guard::Request && TRY_OR_RETURN_OOM(realm, Infrastructure::is_forbidden_request_header(header)))
return false;
// 4. If headerss guard is "response" and name is a forbidden response-header name, then return false.
if (m_guard == Guard::Response && Infrastructure::is_forbidden_response_header_name(name))
return false;
// 5. Return true.
return true;
}
// https://fetch.spec.whatwg.org/#concept-headers-append
WebIDL::ExceptionOr<void> Headers::append(Infrastructure::Header header)
{
@ -223,21 +226,11 @@ WebIDL::ExceptionOr<void> Headers::append(Infrastructure::Header header)
// 1. Normalize value.
value = TRY_OR_RETURN_OOM(realm, Infrastructure::normalize_header_value(value));
// 2. If name is not a header name or value is not a header value, then throw a TypeError.
if (!Infrastructure::is_header_name(name))
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid header name"sv };
if (!Infrastructure::is_header_value(value))
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid header value"sv };
// 3. If headerss guard is "immutable", then throw a TypeError.
if (m_guard == Guard::Immutable)
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Headers object is immutable"sv };
// 4. Otherwise, if headerss guard is "request" and (name, value) is a forbidden request-header, return.
if (m_guard == Guard::Request && TRY_OR_RETURN_OOM(realm, Infrastructure::is_forbidden_request_header(header)))
// 2. If validating (name, value) for headers returns false, then return.
if (!TRY(validate(header)))
return {};
// 5. Otherwise, if headerss guard is "request-no-cors":
// 3. If headerss guard is "request-no-cors":
if (m_guard == Guard::RequestNoCORS) {
// 1. Let temporaryValue be the result of getting name from headerss header list.
auto temporary_value = TRY_OR_RETURN_OOM(realm, m_header_list->get(name));
@ -263,14 +256,10 @@ WebIDL::ExceptionOr<void> Headers::append(Infrastructure::Header header)
return {};
}
// 6. Otherwise, if headerss guard is "response" and name is a forbidden response-header name, return.
if (m_guard == Guard::Response && Infrastructure::is_forbidden_response_header_name(name))
return {};
// 7. Append (name, value) to headerss header list.
// 4. Append (name, value) to headerss header list.
TRY_OR_RETURN_OOM(realm, m_header_list->append(move(header)));
// 8. If headerss guard is "request-no-cors", then remove privileged no-CORS request-headers from headers.
// 5. If headerss guard is "request-no-cors", then remove privileged no-CORS request-headers from headers.
if (m_guard == Guard::RequestNoCORS)
remove_privileged_no_cors_request_headers();

View file

@ -62,6 +62,7 @@ private:
virtual void visit_edges(JS::Cell::Visitor&) override;
WebIDL::ExceptionOr<bool> validate(Infrastructure::Header const&) const;
void remove_privileged_no_cors_request_headers();
// https://fetch.spec.whatwg.org/#concept-headers-header-list