2022-09-22 00:04:06 +01:00
/*
2023-03-02 22:26:12 +00:00
* Copyright ( c ) 2022 - 2023 , Linus Groh < linusg @ serenityos . org >
2023-04-02 22:30:56 +02:00
* Copyright ( c ) 2022 - 2023 , Kenneth Myhra < kennethmyhra @ serenityos . org >
2022-09-22 00:04:06 +01:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2023-01-07 12:14:54 -05:00
# include <LibJS/Runtime/Completion.h>
2022-09-22 00:04:06 +01:00
# include <LibWeb/Fetch/BodyInit.h>
# include <LibWeb/Fetch/Infrastructure/HTTP/Bodies.h>
2023-04-02 22:30:56 +02:00
# include <LibWeb/HTML/FormControlInfrastructure.h>
2022-09-22 00:04:06 +01:00
# include <LibWeb/URL/URLSearchParams.h>
2022-09-24 16:14:37 +01:00
# include <LibWeb/WebIDL/AbstractOperations.h>
2022-09-25 17:03:42 +01:00
# include <LibWeb/WebIDL/ExceptionOr.h>
2023-04-02 22:30:56 +02:00
# include <LibWeb/XHR/FormData.h>
2022-09-22 00:04:06 +01:00
namespace Web : : Fetch {
2022-10-13 19:11:42 +02:00
// https://fetch.spec.whatwg.org/#bodyinit-safely-extract
2022-11-09 22:37:07 +00:00
WebIDL : : ExceptionOr < Infrastructure : : BodyWithType > safely_extract_body ( JS : : Realm & realm , BodyInitOrReadableBytes const & object )
2022-10-13 19:11:42 +02:00
{
// 1. If object is a ReadableStream object, then:
if ( auto const * stream = object . get_pointer < JS : : Handle < Streams : : ReadableStream > > ( ) ) {
// 1. Assert: object is neither disturbed nor locked.
VERIFY ( ! ( ( * stream ) - > is_disturbed ( ) | | ( * stream ) - > is_locked ( ) ) ) ;
}
// 2. Return the result of extracting object.
return extract_body ( realm , object ) ;
}
2022-09-22 00:04:06 +01:00
// https://fetch.spec.whatwg.org/#concept-bodyinit-extract
2022-11-09 22:37:07 +00:00
WebIDL : : ExceptionOr < Infrastructure : : BodyWithType > extract_body ( JS : : Realm & realm , BodyInitOrReadableBytes const & object , bool keepalive )
2022-09-22 00:04:06 +01:00
{
2023-01-07 12:14:54 -05:00
auto & vm = realm . vm ( ) ;
2022-10-30 14:37:38 +00:00
// 1. Let stream be null.
JS : : GCPtr < Streams : : ReadableStream > stream ;
// 2. If object is a ReadableStream object, then set stream to object.
if ( auto const * stream_handle = object . get_pointer < JS : : Handle < Streams : : ReadableStream > > ( ) ) {
stream = const_cast < Streams : : ReadableStream * > ( stream_handle - > cell ( ) ) ;
}
// 3. Otherwise, if object is a Blob object, set stream to the result of running object’ s get stream.
else if ( auto const * blob_handle = object . get_pointer < JS : : Handle < FileAPI : : Blob > > ( ) ) {
// FIXME: "set stream to the result of running object’ s get stream"
( void ) blob_handle ;
2023-08-13 13:05:26 +02:00
stream = realm . heap ( ) . allocate < Streams : : ReadableStream > ( realm , realm ) ;
2022-09-22 17:30:54 +01:00
}
2022-10-30 14:37:38 +00:00
// 4. Otherwise, set stream to a new ReadableStream object, and set up stream.
else {
// FIXME: "set up stream"
2023-08-13 13:05:26 +02:00
stream = realm . heap ( ) . allocate < Streams : : ReadableStream > ( realm , realm ) ;
2022-10-30 14:37:38 +00:00
}
// 5. Assert: stream is a ReadableStream object.
VERIFY ( stream ) ;
2022-09-22 17:30:54 +01:00
2022-10-30 14:37:38 +00:00
// FIXME: 6. Let action be null.
// 7. Let source be null.
2022-09-22 00:04:06 +01:00
Infrastructure : : Body : : SourceType source { } ;
2022-10-30 14:37:38 +00:00
// 8. Let length be null.
2022-09-22 00:04:06 +01:00
Optional < u64 > length { } ;
2022-10-30 14:37:38 +00:00
// 9. Let type be null.
2022-09-22 00:04:06 +01:00
Optional < ByteBuffer > type { } ;
2022-10-30 14:37:38 +00:00
// 10. Switch on object.
2023-04-02 22:30:56 +02:00
// FIXME: Still need to support BufferSource
2022-09-22 17:30:54 +01:00
TRY ( object . visit (
2022-09-25 17:03:42 +01:00
[ & ] ( JS : : Handle < FileAPI : : Blob > const & blob ) - > WebIDL : : ExceptionOr < void > {
2022-09-22 00:04:06 +01:00
// Set source to object.
source = blob ;
// Set length to object’ s size.
length = blob - > size ( ) ;
// If object’ s type attribute is not the empty byte sequence, set type to its value.
if ( ! blob - > type ( ) . is_empty ( ) )
2023-02-25 10:27:38 +01:00
type = TRY_OR_THROW_OOM ( vm , ByteBuffer : : copy ( blob - > type ( ) . bytes ( ) ) ) ;
2022-09-22 00:04:06 +01:00
return { } ;
} ,
2022-09-25 19:15:35 +01:00
[ & ] ( ReadonlyBytes bytes ) - > WebIDL : : ExceptionOr < void > {
// Set source to object.
2023-01-07 12:14:54 -05:00
source = TRY_OR_THROW_OOM ( vm , ByteBuffer : : copy ( bytes ) ) ;
2022-09-25 19:15:35 +01:00
return { } ;
} ,
2022-09-25 17:03:42 +01:00
[ & ] ( JS : : Handle < JS : : Object > const & buffer_source ) - > WebIDL : : ExceptionOr < void > {
2022-09-22 00:04:06 +01:00
// Set source to a copy of the bytes held by object.
2023-01-07 12:14:54 -05:00
source = TRY_OR_THROW_OOM ( vm , WebIDL : : get_buffer_source_copy ( * buffer_source . cell ( ) ) ) ;
2022-09-22 00:04:06 +01:00
return { } ;
} ,
2023-04-02 22:30:56 +02:00
[ & ] ( JS : : Handle < XHR : : FormData > const & form_data ) - > WebIDL : : ExceptionOr < void > {
// Set action to this step: run the multipart/form-data encoding algorithm, with object’ s entry list and UTF-8.
auto serialized_form_data = TRY_OR_THROW_OOM ( vm , HTML : : serialize_to_multipart_form_data ( form_data - > entry_list ( ) ) ) ;
// Set source to object.
source = serialized_form_data . serialized_data ;
// FIXME: Set length to unclear, see html/6424 for improving this.
// Set type to `multipart/form-data; boundary=`, followed by the multipart/form-data boundary string generated by the multipart/form-data encoding algorithm.
type = TRY_OR_THROW_OOM ( vm , ByteBuffer : : copy ( TRY_OR_THROW_OOM ( vm , String : : formatted ( " multipart/form-data; boundary={} " sv , serialized_form_data . boundary ) ) . bytes ( ) ) ) ;
return { } ;
} ,
2022-09-25 17:03:42 +01:00
[ & ] ( JS : : Handle < URL : : URLSearchParams > const & url_search_params ) - > WebIDL : : ExceptionOr < void > {
2022-09-22 00:04:06 +01:00
// Set source to the result of running the application/x-www-form-urlencoded serializer with object’ s list.
2023-03-01 20:10:01 +01:00
auto search_params_bytes = TRY ( url_search_params - > to_string ( ) ) . bytes ( ) ;
source = TRY_OR_THROW_OOM ( vm , ByteBuffer : : copy ( search_params_bytes ) ) ;
2022-09-22 00:04:06 +01:00
// Set type to `application/x-www-form-urlencoded;charset=UTF-8`.
2023-01-07 12:14:54 -05:00
type = TRY_OR_THROW_OOM ( vm , ByteBuffer : : copy ( " application/x-www-form-urlencoded;charset=UTF-8 " sv . bytes ( ) ) ) ;
2022-09-22 00:04:06 +01:00
return { } ;
} ,
2023-03-02 22:26:12 +00:00
[ & ] ( String const & scalar_value_string ) - > WebIDL : : ExceptionOr < void > {
// NOTE: AK::String is always UTF-8.
2022-09-22 00:04:06 +01:00
// Set source to the UTF-8 encoding of object.
2023-03-02 22:26:12 +00:00
source = TRY_OR_THROW_OOM ( vm , ByteBuffer : : copy ( scalar_value_string . bytes ( ) ) ) ;
2022-09-22 00:04:06 +01:00
// Set type to `text/plain;charset=UTF-8`.
2023-01-07 12:14:54 -05:00
type = TRY_OR_THROW_OOM ( vm , ByteBuffer : : copy ( " text/plain;charset=UTF-8 " sv . bytes ( ) ) ) ;
2022-09-22 17:30:54 +01:00
return { } ;
} ,
2022-09-25 17:03:42 +01:00
[ & ] ( JS : : Handle < Streams : : ReadableStream > const & stream ) - > WebIDL : : ExceptionOr < void > {
2022-09-22 17:30:54 +01:00
// If keepalive is true, then throw a TypeError.
if ( keepalive )
2022-10-27 23:18:16 +01:00
return WebIDL : : SimpleException { WebIDL : : SimpleExceptionType : : TypeError , " Cannot extract body from stream when keepalive is set " sv } ;
2022-09-22 17:30:54 +01:00
// If object is disturbed or locked, then throw a TypeError.
if ( stream - > is_disturbed ( ) | | stream - > is_locked ( ) )
2022-10-27 23:18:16 +01:00
return WebIDL : : SimpleException { WebIDL : : SimpleExceptionType : : TypeError , " Cannot extract body from disturbed or locked stream " sv } ;
2022-09-22 17:30:54 +01:00
2022-09-22 00:04:06 +01:00
return { } ;
} ) ) ;
2022-10-30 14:37:38 +00:00
// FIXME: 11. If source is a byte sequence, then set action to a step that returns source and length to source’ s length.
2023-02-28 18:50:42 +00:00
// For now, do it synchronously.
if ( source . has < ByteBuffer > ( ) )
length = source . get < ByteBuffer > ( ) . size ( ) ;
2022-11-08 10:02:01 -05:00
// FIXME: 12. If action is non-null, then run these steps in parallel:
2022-10-30 14:37:38 +00:00
// 13. Let body be a body whose stream is stream, source is source, and length is length.
2023-08-18 19:38:13 +02:00
auto body = Infrastructure : : Body : : create ( vm , * stream , move ( source ) , move ( length ) ) ;
2022-09-22 00:04:06 +01:00
2022-10-30 14:37:38 +00:00
// 14. Return (body, type).
2022-09-22 00:04:06 +01:00
return Infrastructure : : BodyWithType { . body = move ( body ) , . type = move ( type ) } ;
}
}