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
WebIDL : : ExceptionOr < 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
auto & vm = realm . vm ( ) ;
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.
auto success_steps = [ process_body = move ( process_body ) , task_destination_object = JS : : make_handle ( task_destination_object ) ] ( ByteBuffer const & bytes ) mutable - > ErrorOr < void > {
// 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 ) ) ;
queue_fetch_task ( * task_destination_object , [ process_body = move ( process_body ) , bytes_copy = move ( bytes_copy ) ] ( ) {
process_body ( move ( bytes_copy ) ) ;
} ) ;
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.
auto error_steps = [ process_body_error = move ( process_body_error ) , task_destination_object = JS : : make_handle ( task_destination_object ) ] ( JS : : GCPtr < WebIDL : : DOMException > exception ) mutable {
queue_fetch_task ( * task_destination_object , [ process_body_error = move ( process_body_error ) , exception = JS : : make_handle ( exception ) ] ( ) {
process_body_error ( * exception ) ;
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.
2022-09-25 19:27:02 +01:00
// FIXME: Implement the streams spec - this is completely made up for now :^)
if ( auto const * byte_buffer = m_source . get_pointer < ByteBuffer > ( ) ) {
2023-02-28 18:12:44 +00:00
TRY_OR_THROW_OOM ( vm , success_steps ( * byte_buffer ) ) ;
2023-08-01 18:53:39 -04:00
} else if ( auto const * blob_handle = m_source . get_pointer < JS : : Handle < FileAPI : : Blob > > ( ) ) {
auto byte_buffer = TRY_OR_THROW_OOM ( vm , ByteBuffer : : copy ( ( * blob_handle ) - > bytes ( ) ) ) ;
TRY_OR_THROW_OOM ( vm , success_steps ( move ( byte_buffer ) ) ) ;
2023-02-28 18:12:44 +00:00
} else {
// Empty, Blob, FormData
2023-09-06 16:03:01 +12:00
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
}
2023-02-28 18:12:44 +00:00
return { } ;
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
}