@@ -2526,6 +2526,101 @@ bool Response::json(JSContext *cx, unsigned argc, JS::Value *vp) {
25262526}
25272527
25282528
2529+ // / https://fetch.spec.whatwg.org/#dom-response-clone
2530+ bool Response::clone (JSContext *cx, unsigned argc, JS::Value *vp) {
2531+ METHOD_HEADER (0 );
2532+
2533+ // Step 1: If this is unusable (i.e. disturbed or locked), throw a TypeError.
2534+ // We check body usability below when the body exists.
2535+
2536+ // Step 2: Let clonedResponse be a copy of this's response, except for its body.
2537+ RootedObject new_response (cx, create (cx));
2538+ if (!new_response) {
2539+ return false ;
2540+ }
2541+
2542+ // Copy headers.
2543+ RootedValue cloned_headers_val (cx, JS::NullValue ());
2544+ RootedObject headers (cx, RequestOrResponse::maybe_headers (self));
2545+ if (headers) {
2546+ RootedValue headers_val (cx, ObjectValue (*headers));
2547+ JSObject *cloned_headers = Headers::create (cx, headers_val, Headers::guard (headers));
2548+ if (!cloned_headers) {
2549+ return false ;
2550+ }
2551+ cloned_headers_val.set (ObjectValue (*cloned_headers));
2552+ } else if (RequestOrResponse::maybe_handle (self)) {
2553+ auto handle = RequestOrResponse::headers_handle_clone (cx, self);
2554+ JSObject *cloned_headers =
2555+ Headers::create (cx, handle.release (),
2556+ RequestOrResponse::is_incoming (self) ? Headers::HeadersGuard::Immutable
2557+ : Headers::HeadersGuard::Response);
2558+ if (!cloned_headers) {
2559+ return false ;
2560+ }
2561+ cloned_headers_val.set (ObjectValue (*cloned_headers));
2562+ }
2563+
2564+ SetReservedSlot (new_response, static_cast <uint32_t >(Slots::Headers), cloned_headers_val);
2565+
2566+ // Copy URL.
2567+ Value url_val = GetReservedSlot (self, static_cast <uint32_t >(Slots::URL));
2568+ SetReservedSlot (new_response, static_cast <uint32_t >(Slots::URL), url_val);
2569+
2570+ // Copy status.
2571+ SetReservedSlot (new_response, static_cast <uint32_t >(Slots::Status),
2572+ GetReservedSlot (self, static_cast <uint32_t >(Slots::Status)));
2573+
2574+ // Copy status message.
2575+ SetReservedSlot (new_response, static_cast <uint32_t >(Slots::StatusMessage),
2576+ GetReservedSlot (self, static_cast <uint32_t >(Slots::StatusMessage)));
2577+
2578+ // Copy type.
2579+ SetReservedSlot (new_response, static_cast <uint32_t >(Slots::Type),
2580+ GetReservedSlot (self, static_cast <uint32_t >(Slots::Type)));
2581+
2582+ // Copy redirected.
2583+ SetReservedSlot (new_response, static_cast <uint32_t >(Slots::Redirected),
2584+ GetReservedSlot (self, static_cast <uint32_t >(Slots::Redirected)));
2585+
2586+ // Copy aborted.
2587+ SetReservedSlot (new_response, static_cast <uint32_t >(Slots::Aborted),
2588+ GetReservedSlot (self, static_cast <uint32_t >(Slots::Aborted)));
2589+
2590+ // Step 3: If this's response's body is non-null, clone the body.
2591+ auto has_body = RequestOrResponse::has_body (self);
2592+ if (!has_body) {
2593+ args.rval ().setObject (*new_response);
2594+ return true ;
2595+ }
2596+
2597+ // Get (or create) the body stream, then tee it.
2598+ JS::RootedObject body_stream (cx, RequestOrResponse::body_stream (self));
2599+ if (!body_stream) {
2600+ body_stream = RequestOrResponse::create_body_stream (cx, self);
2601+ if (!body_stream) {
2602+ return false ;
2603+ }
2604+ }
2605+
2606+ if (RequestOrResponse::body_unusable (cx, body_stream)) {
2607+ return api::throw_error (cx, FetchErrors::BodyStreamUnusable);
2608+ }
2609+
2610+ RootedObject self_body (cx);
2611+ RootedObject new_body (cx);
2612+ if (!ReadableStreamTee (cx, body_stream, &self_body, &new_body)) {
2613+ return false ;
2614+ }
2615+
2616+ SetReservedSlot (self, static_cast <uint32_t >(Slots::BodyStream), ObjectValue (*self_body));
2617+ SetReservedSlot (new_response, static_cast <uint32_t >(Slots::BodyStream), ObjectValue (*new_body));
2618+ SetReservedSlot (new_response, static_cast <uint32_t >(Slots::HasBody), JS::BooleanValue (true ));
2619+
2620+ args.rval ().setObject (*new_response);
2621+ return true ;
2622+ }
2623+
25292624const JSFunctionSpec Response::static_methods[] = {
25302625 JS_FN (" redirect" , redirect, 1 , JSPROP_ENUMERATE),
25312626 JS_FN (" json" , json, 1 , JSPROP_ENUMERATE),
@@ -2543,6 +2638,7 @@ const JSFunctionSpec Response::methods[] = {
25432638 JS_FN (" formData" , bodyAll<RequestOrResponse::BodyReadResult::FormData>, 0 , JSPROP_ENUMERATE),
25442639 JS_FN (" json" , bodyAll<RequestOrResponse::BodyReadResult::JSON>, 0 , JSPROP_ENUMERATE),
25452640 JS_FN (" text" , bodyAll<RequestOrResponse::BodyReadResult::Text>, 0 , JSPROP_ENUMERATE),
2641+ JS_FN (" clone" , Response::clone, 0 , JSPROP_ENUMERATE),
25462642 JS_FS_END,
25472643};
25482644
0 commit comments