2022-07-16 17:55:29 +01:00
/*
* Copyright ( c ) 2022 , Linus Groh < linusg @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2022-09-25 19:23:35 +01:00
# include <LibWeb/Fetch/Infrastructure/HTTP/Bodies.h>
2022-07-16 17:55:29 +01:00
# include <LibWeb/Fetch/Infrastructure/HTTP/Responses.h>
2022-07-17 23:52:02 +01:00
namespace Web : : Fetch : : Infrastructure {
2022-07-16 17:55:29 +01:00
2022-09-25 20:52:51 +01:00
Response : : Response ( )
: m_header_list ( make_ref_counted < HeaderList > ( ) )
{
}
2022-10-04 23:45:47 +01:00
NonnullRefPtr < Response > Response : : create ( )
{
return adopt_ref ( * new Response ( ) ) ;
}
2022-07-16 17:55:29 +01:00
// https://fetch.spec.whatwg.org/#ref-for-concept-network-error%E2%91%A3
// A network error is a response whose status is always 0, status message is always
// the empty byte sequence, header list is always empty, and body is always null.
2022-10-04 23:45:47 +01:00
NonnullRefPtr < Response > Response : : aborted_network_error ( )
2022-07-16 17:55:29 +01:00
{
auto response = network_error ( ) ;
2022-09-24 00:28:11 +01:00
response - > set_aborted ( true ) ;
2022-07-16 17:55:29 +01:00
return response ;
}
2022-10-04 23:45:47 +01:00
NonnullRefPtr < Response > Response : : network_error ( )
2022-07-16 17:55:29 +01:00
{
2022-10-04 23:45:47 +01:00
auto response = Response : : create ( ) ;
2022-09-24 00:28:11 +01:00
response - > set_status ( 0 ) ;
response - > set_type ( Type : : Error ) ;
VERIFY ( ! response - > body ( ) . has_value ( ) ) ;
2022-07-16 17:55:29 +01:00
return response ;
}
// https://fetch.spec.whatwg.org/#concept-aborted-network-error
bool Response : : is_aborted_network_error ( ) const
{
// A response whose type is "error" and aborted flag is set is known as an aborted network error.
return m_type = = Type : : Error & & m_aborted ;
}
// https://fetch.spec.whatwg.org/#concept-network-error
bool Response : : is_network_error ( ) const
{
// A response whose type is "error" is known as a network error.
return m_type = = Type : : Error ;
}
// https://fetch.spec.whatwg.org/#concept-response-url
Optional < AK : : URL const & > Response : : url ( ) const
{
// A response has an associated URL. It is a pointer to the last URL in response’ s URL list and null if response’ s URL list is empty.
if ( m_url_list . is_empty ( ) )
return { } ;
return m_url_list . last ( ) ;
}
// https://fetch.spec.whatwg.org/#concept-response-location-url
ErrorOr < Optional < AK : : URL > > Response : : location_url ( Optional < String > const & request_fragment ) const
{
// The location URL of a response response, given null or an ASCII string requestFragment, is the value returned by the following steps. They return null, failure, or a URL.
// 1. If response’ s status is not a redirect status, then return null.
if ( ! is_redirect_status ( m_status ) )
return Optional < AK : : URL > { } ;
// FIXME: 2. Let location be the result of extracting header list values given `Location` and response’ s header list.
auto location_value = ByteBuffer { } ;
// 3. If location is a header value, then set location to the result of parsing location with response’ s URL.
auto location = AK : : URL { StringView { location_value } } ;
if ( ! location . is_valid ( ) )
return Error : : from_string_view ( " Invalid 'Location' header URL " sv ) ;
// 4. If location is a URL whose fragment is null, then set location’ s fragment to requestFragment.
if ( location . fragment ( ) . is_null ( ) )
location . set_fragment ( request_fragment . value_or ( { } ) ) ;
// 5. Return location.
return location ;
}
2022-09-25 19:23:35 +01:00
// https://fetch.spec.whatwg.org/#concept-response-clone
2022-10-04 23:45:47 +01:00
WebIDL : : ExceptionOr < NonnullRefPtr < Response > > Response : : clone ( ) const
2022-09-25 19:23:35 +01:00
{
// To clone a response response, run these steps:
// FIXME: 1. If response is a filtered response, then return a new identical filtered response whose internal response is a clone of response’ s internal response.
// 2. Let newResponse be a copy of response, except for its body.
2022-10-04 23:45:47 +01:00
auto new_response = Infrastructure : : Response : : create ( ) ;
new_response - > set_type ( m_type ) ;
new_response - > set_aborted ( m_aborted ) ;
new_response - > set_url_list ( m_url_list ) ;
new_response - > set_status ( m_status ) ;
new_response - > set_status_message ( m_status_message ) ;
for ( auto const & header : * m_header_list )
MUST ( new_response - > header_list ( ) - > append ( header ) ) ;
new_response - > set_cache_state ( m_cache_state ) ;
new_response - > set_cors_exposed_header_name_list ( m_cors_exposed_header_name_list ) ;
new_response - > set_range_requested ( m_range_requested ) ;
new_response - > set_request_includes_credentials ( m_request_includes_credentials ) ;
new_response - > set_timing_allow_passed ( m_timing_allow_passed ) ;
new_response - > set_body_info ( m_body_info ) ;
// FIXME: service worker timing info
2022-09-25 19:25:53 +01:00
// 3. If response’ s body is non-null, then set newResponse’ s body to the result of cloning response’ s body.
if ( m_body . has_value ( ) )
new_response - > set_body ( TRY ( m_body - > clone ( ) ) ) ;
2022-09-25 19:23:35 +01:00
// 4. Return newResponse.
return new_response ;
}
2022-10-04 23:45:47 +01:00
FilteredResponse : : FilteredResponse ( NonnullRefPtr < Response > internal_response )
: m_internal_response ( move ( internal_response ) )
2022-07-16 17:55:29 +01:00
{
}
FilteredResponse : : ~ FilteredResponse ( )
{
}
2022-10-04 23:45:47 +01:00
ErrorOr < NonnullRefPtr < BasicFilteredResponse > > BasicFilteredResponse : : create ( NonnullRefPtr < Response > internal_response )
2022-07-16 17:55:29 +01:00
{
// A basic filtered response is a filtered response whose type is "basic" and header list excludes
// any headers in internal response’ s header list whose name is a forbidden response-header name.
2022-09-25 20:52:51 +01:00
auto header_list = make_ref_counted < HeaderList > ( ) ;
2022-10-04 23:45:47 +01:00
for ( auto const & header : * internal_response - > header_list ( ) ) {
2022-07-16 17:55:29 +01:00
if ( ! is_forbidden_response_header_name ( header . name ) )
2022-09-25 20:52:51 +01:00
TRY ( header_list - > append ( header ) ) ;
2022-07-16 17:55:29 +01:00
}
2022-10-04 23:45:47 +01:00
return adopt_ref ( * new BasicFilteredResponse ( internal_response , move ( header_list ) ) ) ;
2022-07-16 17:55:29 +01:00
}
2022-10-04 23:45:47 +01:00
BasicFilteredResponse : : BasicFilteredResponse ( NonnullRefPtr < Response > internal_response , NonnullRefPtr < HeaderList > header_list )
: FilteredResponse ( move ( internal_response ) )
2022-07-16 17:55:29 +01:00
, m_header_list ( move ( header_list ) )
{
}
2022-10-04 23:45:47 +01:00
ErrorOr < NonnullRefPtr < CORSFilteredResponse > > CORSFilteredResponse : : create ( NonnullRefPtr < Response > internal_response )
2022-07-16 17:55:29 +01:00
{
// A CORS filtered response is a filtered response whose type is "cors" and header list excludes
// any headers in internal response’ s header list whose name is not a CORS-safelisted response-header
// name, given internal response’ s CORS-exposed header-name list.
Vector < ReadonlyBytes > cors_exposed_header_name_list ;
2022-10-04 23:45:47 +01:00
for ( auto const & header_name : internal_response - > cors_exposed_header_name_list ( ) )
2022-07-16 17:55:29 +01:00
cors_exposed_header_name_list . append ( header_name . span ( ) ) ;
2022-09-25 20:52:51 +01:00
auto header_list = make_ref_counted < HeaderList > ( ) ;
2022-10-04 23:45:47 +01:00
for ( auto const & header : * internal_response - > header_list ( ) ) {
2022-07-16 17:55:29 +01:00
if ( is_cors_safelisted_response_header_name ( header . name , cors_exposed_header_name_list ) )
2022-09-25 20:52:51 +01:00
TRY ( header_list - > append ( header ) ) ;
2022-07-16 17:55:29 +01:00
}
2022-10-04 23:45:47 +01:00
return adopt_ref ( * new CORSFilteredResponse ( internal_response , move ( header_list ) ) ) ;
2022-07-16 17:55:29 +01:00
}
2022-10-04 23:45:47 +01:00
CORSFilteredResponse : : CORSFilteredResponse ( NonnullRefPtr < Response > internal_response , NonnullRefPtr < HeaderList > header_list )
: FilteredResponse ( move ( internal_response ) )
2022-07-16 17:55:29 +01:00
, m_header_list ( move ( header_list ) )
{
}
2022-10-04 23:45:47 +01:00
NonnullRefPtr < OpaqueFilteredResponse > OpaqueFilteredResponse : : create ( NonnullRefPtr < Response > internal_response )
2022-07-16 17:55:29 +01:00
{
// An opaque-redirect filtered response is a filtered response whose type is "opaqueredirect",
// status is 0, status message is the empty byte sequence, header list is empty, and body is null.
2022-10-04 23:45:47 +01:00
return adopt_ref ( * new OpaqueFilteredResponse ( move ( internal_response ) ) ) ;
2022-07-16 17:55:29 +01:00
}
2022-10-04 23:45:47 +01:00
OpaqueFilteredResponse : : OpaqueFilteredResponse ( NonnullRefPtr < Response > internal_response )
: FilteredResponse ( move ( internal_response ) )
2022-09-25 20:52:51 +01:00
, m_header_list ( make_ref_counted < HeaderList > ( ) )
2022-07-16 17:55:29 +01:00
{
}
2022-10-04 23:45:47 +01:00
NonnullRefPtr < OpaqueRedirectFilteredResponse > OpaqueRedirectFilteredResponse : : create ( NonnullRefPtr < Response > internal_response )
2022-07-16 17:55:29 +01:00
{
2022-10-04 23:45:47 +01:00
return adopt_ref ( * new OpaqueRedirectFilteredResponse ( move ( internal_response ) ) ) ;
2022-07-16 17:55:29 +01:00
}
2022-10-04 23:45:47 +01:00
OpaqueRedirectFilteredResponse : : OpaqueRedirectFilteredResponse ( NonnullRefPtr < Response > internal_response )
: FilteredResponse ( move ( internal_response ) )
2022-09-25 20:52:51 +01:00
, m_header_list ( make_ref_counted < HeaderList > ( ) )
2022-07-16 17:55:29 +01:00
{
}
}