bool body_source_pull_algorithm(JSContext *cx, CallArgs args, HandleObject source,
                                HandleObject body_owner, HandleObject controller) {
  // If the stream has been piped to a TransformStream whose readable end was
  // then passed to a Request or Response as the body, we can just append the
  // entire source body to the destination using a single native hostcall, and
  // then close the source stream, instead of reading and writing it in
  // individual chunks. Note that even in situations where multiple streams are
  // piped to the same destination this is guaranteed to happen in the right
  // order: ReadableStream#pipeTo locks the destination WritableStream until the
  // source ReadableStream is closed/canceled, so only one stream can ever be
  // piped in at the same time.
  RootedObject pipe_dest(cx, builtins::NativeStreamSource::piped_to_transform_stream(source));
  if (pipe_dest) {
    if (builtins::TransformStream::readable_used_as_body(pipe_dest)) {
      RootedObject dest_owner(cx, builtins::TransformStream::owner(pipe_dest));
      if (!RequestOrResponse::append_body(cx, dest_owner, body_owner)) {
        return false;
      }

      RootedObject stream(cx, builtins::NativeStreamSource::stream(source));
      bool success = JS::ReadableStreamClose(cx, stream);
      MOZ_RELEASE_ASSERT(success);

      args.rval().setUndefined();
      return true;
    }
  }

  // The actual read from the body needs to be delayed, because it'd otherwise
  // be a blocking operation in case the backend didn't yet send any data.
  // That would lead to situations where we block on I/O before processing
  // all pending Promises, which in turn can result in operations happening in
  // observably different behavior, up to and including causing deadlocks
  // because a body read response is blocked on content making another request.
  //
  // (This deadlock happens in automated tests, but admittedly might not happen
  // in real usage.)

  if (!pending_body_reads->append(source))
    return false;

  args.rval().setUndefined();
  return true;
}
bool body_source_pull_algorithm(JSContext *cx, CallArgs args, HandleObject source,
                                HandleObject body_owner, HandleObject controller) {
   
   
   
   
   
   
   
   
   
  RootedObject pipe_dest(cx, builtins::NativeStreamSource::piped_to_transform_stream(source));
  if (pipe_dest) {
    if (builtins::TransformStream::readable_used_as_body(pipe_dest)) {
      RootedObject dest_owner(cx, builtins::TransformStream::owner(pipe_dest));
      if (!RequestOrResponse::append_body(cx, dest_owner, body_owner)) {
        return false;
      }

      RootedObject stream(cx, builtins::NativeStreamSource::stream(source));
      bool success = JS::ReadableStreamClose(cx, stream);
      MOZ_RELEASE_ASSERT(success);

      args.rval().setUndefined();
      return true;
    }
  }

   
   
   
   
   
   
   
   
   

  if (!pending_body_reads->append(source))
    return false;

  args.rval().setUndefined();
  return true;
}