2022-07-12 18:04:24 +01:00
/*
2023-03-02 23:26:35 +00:00
* Copyright ( c ) 2022 - 2023 , Linus Groh < linusg @ serenityos . org >
2022-07-12 18:04:24 +01:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2022-10-02 10:59:22 +01:00
# include <LibJS/Runtime/PromiseCapability.h>
2022-09-25 19:25:53 +01:00
# include <LibWeb/Bindings/MainThreadVM.h>
2022-10-30 14:39:32 +00:00
# include <LibWeb/Fetch/BodyInit.h>
2022-07-12 18:04:24 +01:00
# include <LibWeb/Fetch/Infrastructure/HTTP/Bodies.h>
2023-02-28 18:12:44 +00:00
# include <LibWeb/Fetch/Infrastructure/Task.h>
2024-01-27 09:16:09 -05:00
# include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
# include <LibWeb/Streams/AbstractOperations.h>
2022-09-25 19:27:02 +01:00
# include <LibWeb/WebIDL/Promise.h>
2022-07-12 18:04:24 +01:00
2022-07-17 23:52:02 +01:00
namespace Web : : Fetch : : Infrastructure {
2022-07-12 18:04:24 +01:00
2023-11-19 19:47:52 +01:00
JS_DEFINE_ALLOCATOR ( Body ) ;
2023-08-18 19:38:13 +02:00
JS : : NonnullGCPtr < Body > Body : : create ( JS : : VM & vm , JS : : NonnullGCPtr < Streams : : ReadableStream > stream )
{
return vm . heap ( ) . allocate_without_realm < Body > ( stream ) ;
}
JS : : NonnullGCPtr < Body > Body : : create ( JS : : VM & vm , JS : : NonnullGCPtr < Streams : : ReadableStream > stream , SourceType source , Optional < u64 > length )
{
return vm . heap ( ) . allocate_without_realm < Body > ( stream , source , length ) ;
}
Body : : Body ( JS : : NonnullGCPtr < Streams : : ReadableStream > stream )
2022-09-21 23:54:04 +01:00
: m_stream ( move ( stream ) )
2022-07-12 18:04:24 +01:00
{
}
2023-08-18 19:38:13 +02:00
Body : : Body ( JS : : NonnullGCPtr < Streams : : ReadableStream > stream , SourceType source , Optional < u64 > length )
2022-09-21 23:54:04 +01:00
: m_stream ( move ( stream ) )
2022-07-12 18:04:24 +01:00
, m_source ( move ( source ) )
, m_length ( move ( length ) )
{
}
2023-08-18 19:38:13 +02:00
void Body : : visit_edges ( Cell : : Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
visitor . visit ( m_stream ) ;
}
2022-09-25 19:25:53 +01:00
// https://fetch.spec.whatwg.org/#concept-body-clone
2024-01-28 14:21:32 -05:00
JS : : NonnullGCPtr < Body > Body : : clone ( JS : : Realm & realm )
2022-09-25 19:25:53 +01:00
{
2024-01-27 09:16:09 -05:00
HTML : : TemporaryExecutionContext execution_context { Bindings : : host_defined_environment_settings_object ( realm ) , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes } ;
2022-09-25 19:25:53 +01:00
// To clone a body body, run these steps:
2024-01-28 14:21:32 -05:00
// 1. Let « out1, out2 » be the result of teeing body’ s stream.
auto [ out1 , out2 ] = m_stream - > tee ( ) . release_value_but_fixme_should_propagate_errors ( ) ;
2024-01-27 09:16:09 -05:00
2024-01-28 14:21:32 -05:00
// 2. Set body’ s stream to out1.
m_stream = out1 ;
2022-09-25 19:25:53 +01:00
// 3. Return a body whose stream is out2 and other members are copied from body.
2024-01-27 09:16:09 -05:00
return Body : : create ( realm . vm ( ) , * out2 , m_source , m_length ) ;
2022-09-25 19:25:53 +01:00
}
2023-02-28 18:12:44 +00:00
// https://fetch.spec.whatwg.org/#body-fully-read
2024-04-26 14:57:40 -04:00
void Body : : fully_read ( JS : : Realm & realm , Web : : Fetch : : Infrastructure : : Body : : ProcessBodyCallback process_body , Web : : Fetch : : Infrastructure : : Body : : ProcessBodyErrorCallback process_body_error , TaskDestination task_destination ) const
2022-09-25 19:27:02 +01:00
{
2023-02-28 18:12:44 +00:00
// FIXME: 1. If taskDestination is null, then set taskDestination to the result of starting a new parallel queue.
// FIXME: Handle 'parallel queue' task destination
VERIFY ( ! task_destination . has < Empty > ( ) ) ;
auto task_destination_object = task_destination . get < JS : : NonnullGCPtr < JS : : Object > > ( ) ;
// 2. Let successSteps given a byte sequence bytes be to queue a fetch task to run processBody given bytes, with taskDestination.
2024-04-26 14:57:40 -04:00
auto success_steps = [ & realm , process_body , task_destination_object = task_destination_object ] ( ReadonlyBytes bytes ) - > ErrorOr < void > {
2023-02-28 18:12:44 +00:00
// Make a copy of the bytes, as the source of the bytes may disappear between the time the task is queued and executed.
auto bytes_copy = TRY ( ByteBuffer : : copy ( bytes ) ) ;
2024-04-26 14:14:18 -04:00
queue_fetch_task ( * task_destination_object , JS : : create_heap_function ( realm . heap ( ) , [ process_body , bytes_copy = move ( bytes_copy ) ] ( ) mutable {
2024-04-23 10:25:20 +02:00
process_body - > function ( ) ( move ( bytes_copy ) ) ;
2024-04-19 10:23:40 +02:00
} ) ) ;
2023-02-28 18:12:44 +00:00
return { } ;
} ;
2023-05-13 12:44:46 +01:00
// 3. Let errorSteps optionally given an exception exception be to queue a fetch task to run processBodyError given exception, with taskDestination.
2024-04-26 14:57:40 -04:00
auto error_steps = [ & realm , process_body_error , task_destination_object ] ( JS : : GCPtr < WebIDL : : DOMException > exception ) {
queue_fetch_task ( * task_destination_object , JS : : create_heap_function ( realm . heap ( ) , [ process_body_error , exception ] ( ) {
2024-04-30 07:20:41 -04:00
process_body_error - > function ( ) ( exception ) ;
2024-04-19 10:23:40 +02:00
} ) ) ;
2023-02-28 18:12:44 +00:00
} ;
// 4. Let reader be the result of getting a reader for body’ s stream. If that threw an exception, then run errorSteps with that exception and return.
// 5. Read all bytes from reader, given successSteps and errorSteps.
2024-04-26 14:57:40 -04:00
// FIXME: Use streams for these steps.
m_source . visit (
[ & ] ( ByteBuffer const & byte_buffer ) {
if ( auto result = success_steps ( byte_buffer ) ; result . is_error ( ) )
error_steps ( WebIDL : : UnknownError : : create ( realm , " Out-of-memory " _fly_string ) ) ;
} ,
[ & ] ( JS : : Handle < FileAPI : : Blob > const & blob ) {
if ( auto result = success_steps ( blob - > bytes ( ) ) ; result . is_error ( ) )
error_steps ( WebIDL : : UnknownError : : create ( realm , " Out-of-memory " _fly_string ) ) ;
} ,
[ & ] ( Empty ) {
error_steps ( WebIDL : : DOMException : : create ( realm , " DOMException " _fly_string , " Reading from Blob, FormData or null source is not yet implemented " _fly_string ) ) ;
} ) ;
2022-09-25 19:27:02 +01:00
}
2022-10-30 14:39:32 +00:00
// https://fetch.spec.whatwg.org/#byte-sequence-as-a-body
2023-08-18 19:38:13 +02:00
WebIDL : : ExceptionOr < JS : : NonnullGCPtr < Body > > byte_sequence_as_body ( JS : : Realm & realm , ReadonlyBytes bytes )
2022-10-30 14:39:32 +00:00
{
// To get a byte sequence bytes as a body, return the body of the result of safely extracting bytes.
auto [ body , _ ] = TRY ( safely_extract_body ( realm , bytes ) ) ;
return body ;
}
2022-07-12 18:04:24 +01:00
}