/* * Copyright (c) 2022-2023, Linus Groh * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include namespace Web::Fetch::Infrastructure { // https://fetch.spec.whatwg.org/#concept-body class WEB_API Body final : public JS::Cell { GC_CELL(Body, JS::Cell); GC_DECLARE_ALLOCATOR(Body); public: using SourceType = Variant>; using SourceTypeInternal = Variant>; // processBody must be an algorithm accepting a byte sequence. using ProcessBodyCallback = GC::Ref>; // processBodyError must be an algorithm optionally accepting an exception. using ProcessBodyErrorCallback = GC::Ref>; // processBodyChunk must be an algorithm accepting a byte sequence. using ProcessBodyChunkCallback = GC::Ref>; // processEndOfBody must be an algorithm accepting no arguments using ProcessEndOfBodyCallback = GC::Ref>; [[nodiscard]] static GC::Ref create(JS::VM&, GC::Ref); [[nodiscard]] static GC::Ref create(JS::VM&, GC::Ref, SourceType, Optional); [[nodiscard]] static GC::Ref create(JS::VM&, GC::Ref, SourceTypeInternal, Optional); [[nodiscard]] GC::Ref stream() const { return *m_stream; } void set_stream(GC::Ref value) { m_stream = value; } [[nodiscard]] SourceTypeInternal const& source() const { return m_source; } [[nodiscard]] Optional const& length() const { return m_length; } // https://mimesniff.spec.whatwg.org/#reading-the-resource-header // Non-standard infrastructure to obtain the "resource header" for MIME type sniffing. // The spec defines resource header as the byte sequence to sniff, obtained by reading // "until [...] 1445 or more bytes have been read" or end of resource is reached. // For non-streaming bodies (ByteBuffer/Blob source), bytes are available immediately. // For streaming bodies, bytes are captured during fetch and delivered via callback. using SniffBytesCallback = GC::Ref>; Optional sniff_bytes_if_available() const; void wait_for_sniff_bytes(SniffBytesCallback on_ready); // Called by FetchedDataReceiver to provide sniff bytes during streaming fetch. void append_sniff_bytes(ReadonlyBytes bytes); void set_sniff_bytes_complete(); [[nodiscard]] GC::Ref clone(JS::Realm&); void fully_read(JS::Realm&, ProcessBodyCallback process_body, ProcessBodyErrorCallback process_body_error, TaskDestination) const; void incrementally_read(ProcessBodyChunkCallback process_body_chunk, ProcessEndOfBodyCallback process_end_of_body, ProcessBodyErrorCallback process_body_error, TaskDestination); void incrementally_read_loop(Streams::ReadableStreamDefaultReader& reader, TaskDestination, ProcessBodyChunkCallback process_body_chunk, ProcessEndOfBodyCallback process_end_of_body, ProcessBodyErrorCallback process_body_error); virtual void visit_edges(JS::Cell::Visitor&) override; private: explicit Body(GC::Ref); Body(GC::Ref, SourceTypeInternal, Optional); // https://fetch.spec.whatwg.org/#concept-body-stream // A stream (a ReadableStream object). GC::Ref m_stream; // https://fetch.spec.whatwg.org/#concept-body-source // A source (null, a byte sequence, a Blob object, or a FormData object), initially null. SourceTypeInternal m_source; // https://fetch.spec.whatwg.org/#concept-body-total-bytes // A length (null or an integer), initially null. Optional m_length; // https://mimesniff.spec.whatwg.org/#reading-the-resource-header // Non-standard: Captured "resource header" bytes for MIME type sniffing. ByteBuffer m_sniff_bytes; bool m_sniff_bytes_complete { false }; GC::Ptr> m_sniff_bytes_callback; }; // https://fetch.spec.whatwg.org/#body-with-type // A body with type is a tuple that consists of a body (a body) and a type (a header value or null). struct BodyWithType { GC::Ref body; Optional type; }; WEB_API GC::Ref byte_sequence_as_body(JS::Realm&, ReadonlyBytes); }