bool fetch(JSContext *cx, unsigned argc, Value *vp) {
  CallArgs args = CallArgsFromVp(argc, vp);

  REQUEST_HANDLER_ONLY("fetch")

  if (!args.requireAtLeast(cx, "fetch", 1)) {
    return ReturnPromiseRejectedWithPendingError(cx, args);
  }

  RootedObject requestInstance(
      cx, JS_NewObjectWithGivenProto(cx, &Request::class_, Request::proto_obj));
  if (!requestInstance)
    return false;

  RootedObject request(cx, Request::create(cx, requestInstance, args[0], args.get(1)));
  if (!request) {
    return ReturnPromiseRejectedWithPendingError(cx, args);
  }

  RootedString backend(cx, Request::backend(request));
  if (!backend) {
    backend = builtins::Fastly::defaultBackend;
  }
  if (!backend) {
    size_t bytes_read;
    RequestHandle handle = Request::request_handle(request);
    UniqueChars buf(
        read_from_handle_all<xqd_req_uri_get, RequestHandle>(cx, handle, &bytes_read, false));
    if (buf) {
      JS_ReportErrorUTF8(cx,
                         "No backend specified for request with url %s. "
                         "Must provide a `backend` property on the `init` object "
                         "passed to either `new Request()` or `fetch`",
                         buf.get());
    }
    return ReturnPromiseRejectedWithPendingError(cx, args);
  }

  size_t backend_len;
  UniqueChars backend_chars = encode(cx, backend, &backend_len);
  if (!backend_chars)
    return ReturnPromiseRejectedWithPendingError(cx, args);

  PendingRequestHandle request_handle = {INVALID_HANDLE};
  RootedObject response_promise(cx, JS::NewPromiseObject(cx, nullptr));
  if (!response_promise)
    return ReturnPromiseRejectedWithPendingError(cx, args);

  if (!Request::apply_cache_override(cx, request)) {
    return false;
  }

  bool streaming = false;
  if (!RequestOrResponse::maybe_stream_body(cx, request, &streaming)) {
    return false;
  }

  int result;
  if (streaming) {
    result = xqd_req_send_async_streaming(Request::request_handle(request),
                                          RequestOrResponse::body_handle(request),
                                          backend_chars.get(), backend_len, &request_handle);
  } else {
    result = xqd_req_send_async(Request::request_handle(request),
                                RequestOrResponse::body_handle(request), backend_chars.get(),
                                backend_len, &request_handle);
  }

  if (!HANDLE_RESULT(cx, result))
    return ReturnPromiseRejectedWithPendingError(cx, args);

  // If the request body is streamed, we need to wait for streaming to complete before marking the
  // request as pending.
  if (!streaming) {
    if (!pending_requests->append(request))
      return ReturnPromiseRejectedWithPendingError(cx, args);
  }

  JS::SetReservedSlot(request, Request::Slots::PendingRequest,
                      JS::Int32Value(request_handle.handle));
  JS::SetReservedSlot(request, Request::Slots::ResponsePromise, JS::ObjectValue(*response_promise));

  args.rval().setObject(*response_promise);
  return true;
}
bool fetch(JSContext *cx, unsigned argc, Value *vp) {
  CallArgs args = CallArgsFromVp(argc, vp);

  REQUEST_HANDLER_ONLY("fetch")

  if (!args.requireAtLeast(cx, "fetch", 1)) {
    return ReturnPromiseRejectedWithPendingError(cx, args);
  }

  RootedObject requestInstance(
      cx, JS_NewObjectWithGivenProto(cx, &Request::class_, Request::proto_obj));
  if (!requestInstance)
    return false;

  RootedObject request(cx, Request::create(cx, requestInstance, args[0], args.get(1)));
  if (!request) {
    return ReturnPromiseRejectedWithPendingError(cx, args);
  }

  RootedString backend(cx, Request::backend(request));
  if (!backend) {
    backend = builtins::Fastly::defaultBackend;
  }
  if (!backend) {
    size_t bytes_read;
    RequestHandle handle = Request::request_handle(request);
    UniqueChars buf(
        read_from_handle_all<xqd_req_uri_get, RequestHandle>(cx, handle, &bytes_read, false));
    if (buf) {
      JS_ReportErrorUTF8(cx,
                         "No backend specified for request with url %s. "
                         "Must provide a `backend` property on the `init` object "
                         "passed to either `new Request()` or `fetch`",
                         buf.get());
    }
    return ReturnPromiseRejectedWithPendingError(cx, args);
  }

  size_t backend_len;
  UniqueChars backend_chars = encode(cx, backend, &backend_len);
  if (!backend_chars)
    return ReturnPromiseRejectedWithPendingError(cx, args);

  PendingRequestHandle request_handle = {INVALID_HANDLE};
  RootedObject response_promise(cx, JS::NewPromiseObject(cx, nullptr));
  if (!response_promise)
    return ReturnPromiseRejectedWithPendingError(cx, args);

  if (!Request::apply_cache_override(cx, request)) {
    return false;
  }

  bool streaming = false;
  if (!RequestOrResponse::maybe_stream_body(cx, request, &streaming)) {
    return false;
  }

  int result;
  if (streaming) {
    result = xqd_req_send_async_streaming(Request::request_handle(request),
                                          RequestOrResponse::body_handle(request),
                                          backend_chars.get(), backend_len, &request_handle);
  } else {
    result = xqd_req_send_async(Request::request_handle(request),
                                RequestOrResponse::body_handle(request), backend_chars.get(),
                                backend_len, &request_handle);
  }

  if (!HANDLE_RESULT(cx, result))
    return ReturnPromiseRejectedWithPendingError(cx, args);

   
   
  if (!streaming) {
    if (!pending_requests->append(request))
      return ReturnPromiseRejectedWithPendingError(cx, args);
  }

  JS::SetReservedSlot(request, Request::Slots::PendingRequest,
                      JS::Int32Value(request_handle.handle));
  JS::SetReservedSlot(request, Request::Slots::ResponsePromise, JS::ObjectValue(*response_promise));

  args.rval().setObject(*response_promise);
  return true;
}