diff --git a/Userland/Libraries/LibWeb/DOM/DocumentLoading.cpp b/Userland/Libraries/LibWeb/DOM/DocumentLoading.cpp index bc90501ec3a..e54e8d226e7 100644 --- a/Userland/Libraries/LibWeb/DOM/DocumentLoading.cpp +++ b/Userland/Libraries/LibWeb/DOM/DocumentLoading.cpp @@ -233,7 +233,7 @@ JS::GCPtr load_document(Optional navigati auto& realm = document->realm(); - if (navigation_params->response->body().has_value()) { + if (navigation_params->response->body()) { auto process_body = [navigation_params, document](ByteBuffer bytes) { if (!parse_document(*document, bytes)) { // FIXME: Load html page with an error if parsing failed. diff --git a/Userland/Libraries/LibWeb/Fetch/Body.cpp b/Userland/Libraries/LibWeb/Fetch/Body.cpp index 601f3293554..5dece554d8b 100644 --- a/Userland/Libraries/LibWeb/Fetch/Body.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Body.cpp @@ -31,7 +31,7 @@ bool BodyMixin::is_unusable() const { // An object including the Body interface mixin is said to be unusable if its body is non-null and its body’s stream is disturbed or locked. auto const& body = body_impl(); - return body.has_value() && (body->stream()->is_disturbed() || body->stream()->is_locked()); + return body && (body->stream()->is_disturbed() || body->stream()->is_locked()); } // https://fetch.spec.whatwg.org/#dom-body-body @@ -39,7 +39,7 @@ JS::GCPtr BodyMixin::body() const { // The body getter steps are to return null if this’s body is null; otherwise this’s body’s stream. auto const& body = body_impl(); - return body.has_value() ? body->stream().ptr() : nullptr; + return body ? body->stream().ptr() : nullptr; } // https://fetch.spec.whatwg.org/#dom-body-bodyused @@ -47,7 +47,7 @@ bool BodyMixin::body_used() const { // The bodyUsed getter steps are to return true if this’s body is non-null and this’s body’s stream is disturbed; otherwise false. auto const& body = body_impl(); - return body.has_value() && body->stream()->is_disturbed(); + return body && body->stream()->is_disturbed(); } // https://fetch.spec.whatwg.org/#dom-body-arraybuffer @@ -197,7 +197,7 @@ WebIDL::ExceptionOr> consume_body(JS::Realm& realm // 5. If object’s body is null, then run successSteps with an empty byte sequence. auto const& body = object.body_impl(); - if (!body.has_value()) { + if (!body) { success_steps(ByteBuffer {}); } // 6. Otherwise, fully read object’s body given successSteps, errorSteps, and object’s relevant global object. diff --git a/Userland/Libraries/LibWeb/Fetch/Body.h b/Userland/Libraries/LibWeb/Fetch/Body.h index 0004fcd09d8..4ad3445cc3f 100644 --- a/Userland/Libraries/LibWeb/Fetch/Body.h +++ b/Userland/Libraries/LibWeb/Fetch/Body.h @@ -27,8 +27,8 @@ public: virtual ~BodyMixin(); virtual ErrorOr> mime_type_impl() const = 0; - virtual Optional body_impl() = 0; - virtual Optional body_impl() const = 0; + virtual JS::GCPtr body_impl() = 0; + virtual JS::GCPtr body_impl() const = 0; virtual Bindings::PlatformObject& as_platform_object() = 0; virtual Bindings::PlatformObject const& as_platform_object() const = 0; diff --git a/Userland/Libraries/LibWeb/Fetch/BodyInit.cpp b/Userland/Libraries/LibWeb/Fetch/BodyInit.cpp index d136d1a50d6..815b0bd6520 100644 --- a/Userland/Libraries/LibWeb/Fetch/BodyInit.cpp +++ b/Userland/Libraries/LibWeb/Fetch/BodyInit.cpp @@ -136,7 +136,7 @@ WebIDL::ExceptionOr extract_body(JS::Realm& realm, // FIXME: 12. If action is non-null, then run these steps in parallel: // 13. Let body be a body whose stream is stream, source is source, and length is length. - auto body = Infrastructure::Body { JS::make_handle(*stream), move(source), move(length) }; + auto body = Infrastructure::Body::create(vm, *stream, move(source), move(length)); // 14. Return (body, type). return Infrastructure::BodyWithType { .body = move(body), .type = move(type) }; diff --git a/Userland/Libraries/LibWeb/Fetch/FetchMethod.cpp b/Userland/Libraries/LibWeb/Fetch/FetchMethod.cpp index e9657cf1c0d..fdabd3149be 100644 --- a/Userland/Libraries/LibWeb/Fetch/FetchMethod.cpp +++ b/Userland/Libraries/LibWeb/Fetch/FetchMethod.cpp @@ -165,7 +165,7 @@ void abort_fetch(JS::Realm& realm, WebIDL::Promise const& promise, JS::NonnullGC WebIDL::reject_promise(realm, promise, error); // 2. If request’s body is non-null and is readable, then cancel request’s body with error. - if (auto* body = request->body().get_pointer(); body != nullptr && body->stream()->is_readable()) { + if (auto* body = request->body().get_pointer>(); body != nullptr && (*body)->stream()->is_readable()) { // TODO: Implement cancelling streams (void)error; } @@ -178,7 +178,7 @@ void abort_fetch(JS::Realm& realm, WebIDL::Promise const& promise, JS::NonnullGC auto response = response_object->response(); // 5. If response’s body is non-null and is readable, then error response’s body with error. - if (response->body().has_value()) { + if (response->body()) { auto stream = response->body()->stream(); if (stream->is_readable()) { // TODO: Implement erroring streams diff --git a/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp b/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp index 33386e3ae19..4fc352126f9 100644 --- a/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp @@ -498,7 +498,7 @@ WebIDL::ExceptionOr>> main_fetch(JS:: }; // 2. If response’s body is null, then run processBodyError and abort these steps. - if (!response->body().has_value()) { + if (!response->body()) { process_body_error({}); return; } @@ -644,7 +644,7 @@ WebIDL::ExceptionOr fetch_response_handover(JS::Realm& realm, Infrastructu auto internal_response = response.is_network_error() ? JS::NonnullGCPtr { response } : response.unsafe_response(); // 6. If internalResponse’s body is null, then run processResponseEndOfBody. - if (!internal_response->body().has_value()) { + if (!internal_response->body()) { process_response_end_of_body(); } // 7. Otherwise: @@ -672,7 +672,7 @@ WebIDL::ExceptionOr fetch_response_handover(JS::Realm& realm, Infrastructu // 3. If internalResponse's body is null, then queue a fetch task to run processBody given null, with // fetchParams’s task destination. - if (!internal_response->body().has_value()) { + if (!internal_response->body()) { Infrastructure::queue_fetch_task(task_destination, [process_body = move(process_body)]() { process_body({}); }); @@ -1118,7 +1118,7 @@ WebIDL::ExceptionOr>> http_redirect_f // return a network error. if (actual_response->status() != 303 && !request->body().has() - && request->body().get().source().has()) { + && request->body().get>()->source().has()) { return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request has body but no body source"sv)); } @@ -1160,7 +1160,7 @@ WebIDL::ExceptionOr>> http_redirect_f // request’s body’s source. // NOTE: request’s body’s source’s nullity has already been checked. if (!request->body().has()) { - auto const& source = request->body().get().source(); + auto const& source = request->body().get>()->source(); // NOTE: BodyInitOrReadableBytes is a superset of Body::SourceType auto converted_source = source.has() ? BodyInitOrReadableBytes { source.get() } @@ -1292,8 +1292,8 @@ WebIDL::ExceptionOr> http_network_or_cache_fet include_credentials = IncludeCredentials::No; // 5. Let contentLength be httpRequest’s body’s length, if httpRequest’s body is non-null; otherwise null. - auto content_length = http_request->body().has() - ? http_request->body().get().length() + auto content_length = http_request->body().has>() + ? http_request->body().get>()->length() : Optional {}; // 6. Let contentLengthHeaderValue be null. @@ -1580,13 +1580,13 @@ WebIDL::ExceptionOr> http_network_or_cache_fet // 2. If request’s body is non-null, then: if (!request->body().has()) { // 1. If request’s body’s source is null, then return a network error. - if (request->body().get().source().has()) { + if (request->body().get>()->source().has()) { returned_pending_response->resolve(Infrastructure::Response::network_error(vm, "Request has body but no body source"_string)); return; } // 2. Set request’s body to the body of the result of safely extracting request’s body’s source. - auto const& source = request->body().get().source(); + auto const& source = request->body().get>()->source(); // NOTE: BodyInitOrReadableBytes is a superset of Body::SourceType auto converted_source = source.has() ? BodyInitOrReadableBytes { source.get() } @@ -1657,7 +1657,7 @@ WebIDL::ExceptionOr> http_network_or_cache_fet // - isNewConnectionFetch is false && is_new_connection_fetch == IsNewConnectionFetch::No // - request’s body is null, or request’s body is non-null and request’s body’s source is non-null - && (request->body().has() || !request->body().get().source().has()) + && (request->body().has() || !request->body().get>()->source().has()) // then: ) { // 1. If fetchParams is canceled, then return the appropriate network error for fetchParams. @@ -1738,8 +1738,8 @@ WebIDL::ExceptionOr> nonstandard_resource_load load_request.set_method(DeprecatedString::copy(request->method())); for (auto const& header : *request->header_list()) load_request.set_header(DeprecatedString::copy(header.name), DeprecatedString::copy(header.value)); - if (auto const* body = request->body().get_pointer()) { - TRY(body->source().visit( + if (auto const* body = request->body().get_pointer>()) { + TRY((*body)->source().visit( [&](ByteBuffer const& byte_buffer) -> WebIDL::ExceptionOr { load_request.set_body(TRY_OR_THROW_OOM(vm, ByteBuffer::copy(byte_buffer))); return {}; diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.cpp b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.cpp index bb6aedee651..ec462231aa6 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.cpp @@ -13,20 +13,36 @@ namespace Web::Fetch::Infrastructure { -Body::Body(JS::Handle stream) +JS::NonnullGCPtr Body::create(JS::VM& vm, JS::NonnullGCPtr stream) +{ + return vm.heap().allocate_without_realm(stream); +} + +JS::NonnullGCPtr Body::create(JS::VM& vm, JS::NonnullGCPtr stream, SourceType source, Optional length) +{ + return vm.heap().allocate_without_realm(stream, source, length); +} + +Body::Body(JS::NonnullGCPtr stream) : m_stream(move(stream)) { } -Body::Body(JS::Handle stream, SourceType source, Optional length) +Body::Body(JS::NonnullGCPtr stream, SourceType source, Optional length) : m_stream(move(stream)) , m_source(move(source)) , m_length(move(length)) { } +void Body::visit_edges(Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_stream); +} + // https://fetch.spec.whatwg.org/#concept-body-clone -Body Body::clone(JS::Realm& realm) const +JS::NonnullGCPtr Body::clone(JS::Realm& realm) const { // To clone a body body, run these steps: // FIXME: 1. Let « out1, out2 » be the result of teeing body’s stream. @@ -34,7 +50,7 @@ Body Body::clone(JS::Realm& realm) const auto out2 = realm.heap().allocate(realm, realm); // 3. Return a body whose stream is out2 and other members are copied from body. - return Body { JS::make_handle(out2), m_source, m_length }; + return Body::create(realm.vm(), out2, m_source, m_length); } // https://fetch.spec.whatwg.org/#body-fully-read @@ -80,7 +96,7 @@ WebIDL::ExceptionOr Body::fully_read(JS::Realm& realm, Web::Fetch::Infrast } // https://fetch.spec.whatwg.org/#byte-sequence-as-a-body -WebIDL::ExceptionOr byte_sequence_as_body(JS::Realm& realm, ReadonlyBytes bytes) +WebIDL::ExceptionOr> byte_sequence_as_body(JS::Realm& realm, ReadonlyBytes bytes) { // 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)); diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.h b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.h index ddf93a08dfd..7923094d853 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.h +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Bodies.h @@ -21,7 +21,9 @@ namespace Web::Fetch::Infrastructure { // https://fetch.spec.whatwg.org/#concept-body -class Body final { +class Body final : public JS::Cell { + JS_CELL(Body, JS::Cell); + public: using SourceType = Variant>; // processBody must be an algorithm accepting a byte sequence. @@ -29,21 +31,26 @@ public: // processBodyError must be an algorithm optionally accepting an exception. using ProcessBodyErrorCallback = JS::SafeFunction)>; - explicit Body(JS::Handle); - Body(JS::Handle, SourceType, Optional); + [[nodiscard]] static JS::NonnullGCPtr create(JS::VM&, JS::NonnullGCPtr); + [[nodiscard]] static JS::NonnullGCPtr create(JS::VM&, JS::NonnullGCPtr, SourceType, Optional); [[nodiscard]] JS::NonnullGCPtr stream() const { return *m_stream; } [[nodiscard]] SourceType const& source() const { return m_source; } [[nodiscard]] Optional const& length() const { return m_length; } - [[nodiscard]] Body clone(JS::Realm&) const; + [[nodiscard]] JS::NonnullGCPtr clone(JS::Realm&) const; WebIDL::ExceptionOr fully_read(JS::Realm&, ProcessBodyCallback process_body, ProcessBodyErrorCallback process_body_error, TaskDestination task_destination) const; + virtual void visit_edges(JS::Cell::Visitor&) override; + private: + explicit Body(JS::NonnullGCPtr); + Body(JS::NonnullGCPtr, SourceType, Optional); + // https://fetch.spec.whatwg.org/#concept-body-stream // A stream (a ReadableStream object). - JS::Handle m_stream; + JS::NonnullGCPtr 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. @@ -57,10 +64,10 @@ private: // 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 { - Body body; + JS::NonnullGCPtr body; Optional type; }; -WebIDL::ExceptionOr byte_sequence_as_body(JS::Realm&, ReadonlyBytes); +WebIDL::ExceptionOr> byte_sequence_as_body(JS::Realm&, ReadonlyBytes); } diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.cpp b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.cpp index 3a6a3a2d660..5c5c6207679 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.cpp @@ -23,6 +23,9 @@ void Request::visit_edges(JS::Cell::Visitor& visitor) Base::visit_edges(visitor); visitor.visit(m_header_list); visitor.visit(m_client); + m_body.visit( + [&](JS::GCPtr& body) { visitor.visit(body); }, + [](auto&) {}); m_reserved_client.visit( [&](JS::GCPtr const& value) { visitor.visit(value); }, [](auto const&) {}); @@ -249,8 +252,8 @@ JS::NonnullGCPtr Request::clone(JS::Realm& realm) const new_request->set_timing_allow_failed(m_timing_allow_failed); // 2. If request’s body is non-null, set newRequest’s body to the result of cloning request’s body. - if (auto const* body = m_body.get_pointer()) - new_request->set_body(body->clone(realm)); + if (auto const* body = m_body.get_pointer>()) + new_request->set_body((*body)->clone(realm)); // 3. Return newRequest. return new_request; diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.h b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.h index 30ce01bb81e..65f36c22659 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.h +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.h @@ -153,7 +153,7 @@ public: // Members are implementation-defined struct Priority { }; - using BodyType = Variant; + using BodyType = Variant>; using OriginType = Variant; using PolicyContainerType = Variant; using ReferrerType = Variant; diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.cpp b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.cpp index fa08e85c3fc..92f594e083b 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.cpp @@ -26,6 +26,7 @@ void Response::visit_edges(JS::Cell::Visitor& visitor) { Base::visit_edges(visitor); visitor.visit(m_header_list); + visitor.visit(m_body); } JS::NonnullGCPtr Response::create(JS::VM& vm) @@ -50,7 +51,7 @@ JS::NonnullGCPtr Response::network_error(JS::VM& vm, Variantset_status(0); response->set_type(Type::Error); - VERIFY(!response->body().has_value()); + VERIFY(!response->body()); response->m_network_error_message = move(message); return response; } @@ -163,7 +164,7 @@ WebIDL::ExceptionOr> Response::clone(JS::Realm& realm // FIXME: service worker timing info // 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()) + if (m_body) new_response->set_body(m_body->clone(realm)); // 4. Return newResponse. @@ -283,6 +284,7 @@ void OpaqueFilteredResponse::visit_edges(JS::Cell::Visitor& visitor) { Base::visit_edges(visitor); visitor.visit(m_header_list); + visitor.visit(m_body); } JS::NonnullGCPtr OpaqueRedirectFilteredResponse::create(JS::VM& vm, JS::NonnullGCPtr internal_response) @@ -302,6 +304,7 @@ void OpaqueRedirectFilteredResponse::visit_edges(JS::Cell::Visitor& visitor) { Base::visit_edges(visitor); visitor.visit(m_header_list); + visitor.visit(m_body); } } diff --git a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.h b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.h index 58b5f0f638b..fc7a5b2e236 100644 --- a/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.h +++ b/Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.h @@ -75,9 +75,9 @@ public: [[nodiscard]] virtual JS::NonnullGCPtr header_list() const { return m_header_list; } void set_header_list(JS::NonnullGCPtr header_list) { m_header_list = header_list; } - [[nodiscard]] virtual Optional const& body() const { return m_body; } - [[nodiscard]] virtual Optional& body() { return m_body; } - void set_body(Optional body) { m_body = move(body); } + [[nodiscard]] virtual JS::GCPtr const& body() const { return m_body; } + [[nodiscard]] virtual JS::GCPtr& body() { return m_body; } + void set_body(JS::GCPtr body) { m_body = move(body); } [[nodiscard]] virtual Optional const& cache_state() const { return m_cache_state; } void set_cache_state(Optional cache_state) { m_cache_state = move(cache_state); } @@ -147,7 +147,7 @@ private: // https://fetch.spec.whatwg.org/#concept-response-body // A response has an associated body (null or a body). Unless stated otherwise it is null. - Optional m_body; + JS::GCPtr m_body; // https://fetch.spec.whatwg.org/#concept-response-cache-state // A response has an associated cache state (the empty string, "local", or "validated"). Unless stated otherwise, it is the empty string. @@ -199,8 +199,8 @@ public: [[nodiscard]] virtual Status status() const override { return m_internal_response->status(); } [[nodiscard]] virtual ReadonlyBytes status_message() const override { return m_internal_response->status_message(); } [[nodiscard]] virtual JS::NonnullGCPtr header_list() const override { return m_internal_response->header_list(); } - [[nodiscard]] virtual Optional const& body() const override { return m_internal_response->body(); } - [[nodiscard]] virtual Optional& body() override { return m_internal_response->body(); } + [[nodiscard]] virtual JS::GCPtr const& body() const override { return m_internal_response->body(); } + [[nodiscard]] virtual JS::GCPtr& body() override { return m_internal_response->body(); } [[nodiscard]] virtual Optional const& cache_state() const override { return m_internal_response->cache_state(); } [[nodiscard]] virtual Vector const& cors_exposed_header_name_list() const override { return m_internal_response->cors_exposed_header_name_list(); } [[nodiscard]] virtual bool range_requested() const override { return m_internal_response->range_requested(); } @@ -267,8 +267,8 @@ public: [[nodiscard]] virtual Status status() const override { return 0; } [[nodiscard]] virtual ReadonlyBytes status_message() const override { return {}; } [[nodiscard]] virtual JS::NonnullGCPtr header_list() const override { return m_header_list; } - [[nodiscard]] virtual Optional const& body() const override { return m_body; } - [[nodiscard]] virtual Optional& body() override { return m_body; } + [[nodiscard]] virtual JS::GCPtr const& body() const override { return m_body; } + [[nodiscard]] virtual JS::GCPtr& body() override { return m_body; } private: OpaqueFilteredResponse(JS::NonnullGCPtr, JS::NonnullGCPtr); @@ -277,7 +277,7 @@ private: Vector m_url_list; JS::NonnullGCPtr m_header_list; - Optional m_body; + JS::GCPtr m_body; }; // https://fetch.spec.whatwg.org/#concept-filtered-response-opaque-redirect @@ -291,8 +291,8 @@ public: [[nodiscard]] virtual Status status() const override { return 0; } [[nodiscard]] virtual ReadonlyBytes status_message() const override { return {}; } [[nodiscard]] virtual JS::NonnullGCPtr header_list() const override { return m_header_list; } - [[nodiscard]] virtual Optional const& body() const override { return m_body; } - [[nodiscard]] virtual Optional& body() override { return m_body; } + [[nodiscard]] virtual JS::GCPtr const& body() const override { return m_body; } + [[nodiscard]] virtual JS::GCPtr& body() override { return m_body; } private: OpaqueRedirectFilteredResponse(JS::NonnullGCPtr, JS::NonnullGCPtr); @@ -300,6 +300,6 @@ private: virtual void visit_edges(JS::Cell::Visitor&) override; JS::NonnullGCPtr m_header_list; - Optional m_body; + JS::GCPtr m_body; }; } diff --git a/Userland/Libraries/LibWeb/Fetch/Request.cpp b/Userland/Libraries/LibWeb/Fetch/Request.cpp index e6fec92a4fb..61a410f345a 100644 --- a/Userland/Libraries/LibWeb/Fetch/Request.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Request.cpp @@ -54,28 +54,28 @@ ErrorOr> Request::mime_type_impl() const // https://fetch.spec.whatwg.org/#concept-body-body // https://fetch.spec.whatwg.org/#ref-for-concept-body-body%E2%91%A7 -Optional Request::body_impl() const +JS::GCPtr Request::body_impl() const { // Objects including the Body interface mixin have an associated body (null or a body). // A Request object’s body is its request’s body. return m_request->body().visit( - [](Infrastructure::Body const& b) -> Optional { return b; }, - [](Empty) -> Optional { return {}; }, + [](JS::NonnullGCPtr const& b) -> JS::GCPtr { return b; }, + [](Empty) -> JS::GCPtr { return nullptr; }, // A byte sequence will be safely extracted into a body early on in fetch. - [](ByteBuffer const&) -> Optional { VERIFY_NOT_REACHED(); }); + [](ByteBuffer const&) -> JS::GCPtr { VERIFY_NOT_REACHED(); }); } // https://fetch.spec.whatwg.org/#concept-body-body // https://fetch.spec.whatwg.org/#ref-for-concept-body-body%E2%91%A7 -Optional Request::body_impl() +JS::GCPtr Request::body_impl() { // Objects including the Body interface mixin have an associated body (null or a body). // A Request object’s body is its request’s body. return m_request->body().visit( - [](Infrastructure::Body& b) -> Optional { return b; }, - [](Empty) -> Optional { return {}; }, + [](JS::NonnullGCPtr& b) -> JS::GCPtr { return b; }, + [](Empty) -> JS::GCPtr { return {}; }, // A byte sequence will be safely extracted into a body early on in fetch. - [](ByteBuffer&) -> Optional { VERIFY_NOT_REACHED(); }); + [](ByteBuffer&) -> JS::GCPtr { VERIFY_NOT_REACHED(); }); } // https://fetch.spec.whatwg.org/#request-create @@ -440,7 +440,7 @@ WebIDL::ExceptionOr> Request::construct_impl(JS::Realm return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Method must not be GET or HEAD when body is provided"sv }; // 35. Let initBody be null. - Optional init_body; + JS::GCPtr init_body; // 36. If init["body"] exists and is non-null, then: if (init.body.has_value() && (*init.body).has_value()) { @@ -448,7 +448,7 @@ WebIDL::ExceptionOr> Request::construct_impl(JS::Realm auto body_with_type = TRY(extract_body(realm, (*init.body).value(), request->keepalive())); // 2. Set initBody to bodyWithType’s body. - init_body = move(body_with_type.body); + init_body = body_with_type.body; // 3. Let type be bodyWithType’s type. auto const& type = body_with_type.type; @@ -459,15 +459,15 @@ WebIDL::ExceptionOr> Request::construct_impl(JS::Realm } // 37. Let inputOrInitBody be initBody if it is non-null; otherwise inputBody. - Optional input_or_init_body = init_body.has_value() - ? Infrastructure::Request::BodyType { init_body.value() } + Optional input_or_init_body = init_body + ? Infrastructure::Request::BodyType { *init_body } : input_body; // 38. If inputOrInitBody is non-null and inputOrInitBody’s source is null, then: // FIXME: The spec doesn't check if inputOrInitBody is a body before accessing source. - if (input_or_init_body.has_value() && input_or_init_body->has() && input_or_init_body->get().source().has()) { + if (input_or_init_body.has_value() && input_or_init_body->has>() && input_or_init_body->get>()->source().has()) { // 1. If initBody is non-null and init["duplex"] does not exist, then throw a TypeError. - if (init_body.has_value() && !init.duplex.has_value()) + if (init_body && !init.duplex.has_value()) return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Body without source requires 'duplex' value to be set"sv }; // 2. If this’s request’s mode is neither "same-origin" nor "cors", then throw a TypeError. @@ -482,7 +482,7 @@ WebIDL::ExceptionOr> Request::construct_impl(JS::Realm auto const& final_body = input_or_init_body; // 40. If initBody is null and inputBody is non-null, then: - if (!init_body.has_value() && input_body.has_value()) { + if (!init_body && input_body.has_value()) { // 2. If input is unusable, then throw a TypeError. if (input.has>() && input.get>()->is_unusable()) return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Request is unusable"sv }; diff --git a/Userland/Libraries/LibWeb/Fetch/Request.h b/Userland/Libraries/LibWeb/Fetch/Request.h index 7b74776bbb3..eccfe24e20a 100644 --- a/Userland/Libraries/LibWeb/Fetch/Request.h +++ b/Userland/Libraries/LibWeb/Fetch/Request.h @@ -73,8 +73,8 @@ public: // ^BodyMixin virtual ErrorOr> mime_type_impl() const override; - virtual Optional body_impl() override; - virtual Optional body_impl() const override; + virtual JS::GCPtr body_impl() override; + virtual JS::GCPtr body_impl() const override; virtual Bindings::PlatformObject& as_platform_object() override { return *this; } virtual Bindings::PlatformObject const& as_platform_object() const override { return *this; } diff --git a/Userland/Libraries/LibWeb/Fetch/Response.cpp b/Userland/Libraries/LibWeb/Fetch/Response.cpp index e9b528cac94..db0f0a031d0 100644 --- a/Userland/Libraries/LibWeb/Fetch/Response.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Response.cpp @@ -50,24 +50,20 @@ ErrorOr> Response::mime_type_impl() const // https://fetch.spec.whatwg.org/#concept-body-body // https://fetch.spec.whatwg.org/#ref-for-concept-body-body%E2%91%A8 -Optional Response::body_impl() const +JS::GCPtr Response::body_impl() const { // Objects including the Body interface mixin have an associated body (null or a body). // A Response object’s body is its response’s body. - return m_response->body().has_value() - ? m_response->body().value() - : Optional {}; + return m_response->body() ? m_response->body() : nullptr; } // https://fetch.spec.whatwg.org/#concept-body-body // https://fetch.spec.whatwg.org/#ref-for-concept-body-body%E2%91%A8 -Optional Response::body_impl() +JS::GCPtr Response::body_impl() { // Objects including the Body interface mixin have an associated body (null or a body). // A Response object’s body is its response’s body. - return m_response->body().has_value() - ? m_response->body().value() - : Optional {}; + return m_response->body() ? m_response->body() : nullptr; } // https://fetch.spec.whatwg.org/#response-create diff --git a/Userland/Libraries/LibWeb/Fetch/Response.h b/Userland/Libraries/LibWeb/Fetch/Response.h index dc346630056..d06d4fb70e4 100644 --- a/Userland/Libraries/LibWeb/Fetch/Response.h +++ b/Userland/Libraries/LibWeb/Fetch/Response.h @@ -40,8 +40,8 @@ public: // ^BodyMixin virtual ErrorOr> mime_type_impl() const override; - virtual Optional body_impl() override; - virtual Optional body_impl() const override; + virtual JS::GCPtr body_impl() override; + virtual JS::GCPtr body_impl() const override; virtual Bindings::PlatformObject& as_platform_object() override { return *this; } virtual Bindings::PlatformObject const& as_platform_object() const override { return *this; } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp index 544ce46fce9..643630e0860 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp @@ -1003,7 +1003,7 @@ WebIDL::ExceptionOr HTMLMediaElement::fetch_resource(AK::URL const& url_re // 5. Otherwise, incrementally read response's body given updateMedia, processEndOfMedia, an empty algorithm, and global. - VERIFY(response->body().has_value()); + VERIFY(response->body()); auto empty_algorithm = [](auto) {}; // FIXME: We are "fully" reading the response here, rather than "incrementally". Memory concerns aside, this should be okay for now as we are diff --git a/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.cpp index 5279d7b0a94..6d30e1ac2b1 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.cpp @@ -189,7 +189,7 @@ WebIDL::ExceptionOr HTMLVideoElement::determine_element_poster_frame(Optio m_poster_frame = move(image.release_value().frames[0].bitmap); }; - VERIFY(response->body().has_value()); + VERIFY(response->body()); auto empty_algorithm = [](auto) {}; response->body()->fully_read(realm, move(on_image_data_read), move(empty_algorithm), JS::NonnullGCPtr { global }).release_value_but_fixme_should_propagate_errors(); diff --git a/Userland/Libraries/LibWeb/HTML/SharedImageRequest.cpp b/Userland/Libraries/LibWeb/HTML/SharedImageRequest.cpp index d24c3055153..46b4e1d3d72 100644 --- a/Userland/Libraries/LibWeb/HTML/SharedImageRequest.cpp +++ b/Userland/Libraries/LibWeb/HTML/SharedImageRequest.cpp @@ -82,8 +82,8 @@ void SharedImageRequest::fetch_image(JS::Realm& realm, JS::NonnullGCPtrbody().has_value()) - response->body().value().fully_read(realm, move(process_body), move(process_body_error), JS::NonnullGCPtr { realm.global_object() }).release_value_but_fixme_should_propagate_errors(); + if (response->body()) + response->body()->fully_read(realm, move(process_body), move(process_body_error), JS::NonnullGCPtr { realm.global_object() }).release_value_but_fixme_should_propagate_errors(); }; m_state = State::Fetching; diff --git a/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp b/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp index 2f163541900..bf6f3fba34c 100644 --- a/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp +++ b/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp @@ -82,6 +82,7 @@ void XMLHttpRequest::visit_edges(Cell::Visitor& visitor) Base::visit_edges(visitor); visitor.visit(m_upload_object); visitor.visit(m_author_request_headers); + visitor.visit(m_request_body); visitor.visit(m_response); visitor.visit(m_fetch_controller); @@ -194,7 +195,7 @@ WebIDL::ExceptionOr XMLHttpRequest::response() // Note: Automatically done by the layers above us. // 2. If this’s response’s body is null, then return null. - if (!m_response->body().has_value()) + if (!m_response->body()) return JS::js_null(); // 3. Let jsonObject be the result of running parse JSON from bytes on this’s received bytes. If that threw an exception, then return null. @@ -214,7 +215,7 @@ WebIDL::ExceptionOr XMLHttpRequest::response() String XMLHttpRequest::get_text_response() const { // 1. If xhr’s response’s body is null, then return the empty string. - if (!m_response->body().has_value()) + if (!m_response->body()) return String {}; // 2. Let charset be the result of get a final encoding for xhr. @@ -559,8 +560,8 @@ WebIDL::ExceptionOr XMLHttpRequest::send(Optionalset_body(m_request_body.value()); + if (m_request_body) + request->set_body(JS::NonnullGCPtr { *m_request_body }); // client // This’s relevant settings object. @@ -594,7 +595,7 @@ WebIDL::ExceptionOr XMLHttpRequest::send(Optional XMLHttpRequest::send(Optionallength().has_value()); // NOTE: This is const to allow the callback functions to take a copy of it and know it won't change. - auto const request_body_length = m_request_body.has_value() ? m_request_body->length().value() : 0; + auto const request_body_length = m_request_body ? m_request_body->length().value() : 0; // 5. If this’s upload complete flag is unset and this’s upload listener flag is set, then fire a progress event named loadstart at this’s upload object with requestBodyTransmitted and requestBodyLength. if (!m_upload_complete && m_upload_listener) @@ -691,7 +692,7 @@ WebIDL::ExceptionOr XMLHttpRequest::send(Optionalbody().has_value()) { + if (!m_response->body()) { // NOTE: This cannot throw, as `handle_response_end_of_body` only throws in a synchronous context. // FIXME: However, we can receive allocation failures, but we can't propagate them anywhere currently. handle_response_end_of_body().release_value_but_fixme_should_propagate_errors(); diff --git a/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.h b/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.h index 563bf195a20..acb1a72ff04 100644 --- a/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.h +++ b/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.h @@ -136,7 +136,7 @@ private: // https://xhr.spec.whatwg.org/#request-body // request body // Initially null. - Optional m_request_body; + JS::GCPtr m_request_body; // https://xhr.spec.whatwg.org/#synchronous-flag // synchronous flag