IPCBlobInputStreamChild::IPCBlobInputStreamChild(const nsID& aID,
                                                 uint64_t aSize)
  : mMutex("IPCBlobInputStreamChild::mMutex")
  , mID(aID)
  , mSize(aSize)
  , mState(eActive)
  , mOwningEventTarget(GetCurrentThreadSerialEventTarget())
{
  // If we are running in a worker, we need to send a Close() to the parent side
  // before the thread is released.
  if (!NS_IsMainThread()) {
    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    if (!workerPrivate) {
      return;
    }

    RefPtr<StrongWorkerRef> workerRef =
      StrongWorkerRef::Create(workerPrivate, "IPCBlobInputStreamChild");
    if (!workerRef) {
      return;
    }

    // We must keep the worker alive until the migration is completed.
    mWorkerRef = new ThreadSafeWorkerRef(workerRef);
  }
}
void
BroadcastChannel::Shutdown()
{
  mState = StateClosed;

  // The DTOR of this WorkerRef will release the worker for us.
  mWorkerRef = nullptr;

  if (mActor) {
    mActor->SetParent(nullptr);

    if (NS_IsMainThread()) {
      RefPtr<TeardownRunnableOnMainThread> runnable =
        new TeardownRunnableOnMainThread(mActor);
      NS_DispatchToCurrentThread(runnable);
    } else {
      WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
      MOZ_ASSERT(workerPrivate);

      RefPtr<TeardownRunnableOnWorker> runnable =
        new TeardownRunnableOnWorker(workerPrivate, mActor);
      runnable->Dispatch();
    }

    mActor = nullptr;
  }

  IgnoreKeepAliveIfHasListenersFor(NS_LITERAL_STRING("message"));
}
Exemple #3
0
void
Promise::ReportRejectedPromise(JSContext* aCx, JS::HandleObject aPromise)
{
  MOZ_ASSERT(!js::IsWrapper(aPromise));

  MOZ_ASSERT(JS::GetPromiseState(aPromise) == JS::PromiseState::Rejected);

  JS::Rooted<JS::Value> result(aCx, JS::GetPromiseResult(aPromise));

  js::ErrorReport report(aCx);
  if (!report.init(aCx, result, js::ErrorReport::NoSideEffects)) {
    JS_ClearPendingException(aCx);
    return;
  }

  RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
  bool isMainThread = MOZ_LIKELY(NS_IsMainThread());
  bool isChrome = isMainThread ? nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(aPromise))
                               : GetCurrentThreadWorkerPrivate()->IsChromeWorker();
  nsGlobalWindow* win = isMainThread ? xpc::WindowGlobalOrNull(aPromise) : nullptr;
  xpcReport->Init(report.report(), report.toStringResult().c_str(), isChrome,
                  win ? win->AsInner()->WindowID() : 0);

  // Now post an event to do the real reporting async
  NS_DispatchToMainThread(new AsyncErrorReporter(xpcReport));
}
already_AddRefed<Promise>
PushManager::PermissionState(ErrorResult& aRv)
{
  if (mImpl) {
    MOZ_ASSERT(NS_IsMainThread());
    return mImpl->PermissionState(aRv);
  }

  WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
  MOZ_ASSERT(worker);
  worker->AssertIsOnWorkerThread();

  nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope();
  RefPtr<Promise> p = Promise::Create(global, aRv);
  if (NS_WARN_IF(aRv.Failed())) {
    return nullptr;
  }

  RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, p);
  if (!proxy) {
    p->MaybeReject(worker->GetJSContext(), JS::UndefinedHandleValue);
    return p.forget();
  }

  RefPtr<PermissionStateRunnable> r =
    new PermissionStateRunnable(proxy);
  NS_DispatchToMainThread(r);

  return p.forget();
}
already_AddRefed<Promise>
PushManager::PerformSubscriptionActionFromWorker(
  SubscriptionAction aAction, ErrorResult& aRv)
{
  WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
  MOZ_ASSERT(worker);
  worker->AssertIsOnWorkerThread();

  nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope();
  RefPtr<Promise> p = Promise::Create(global, aRv);
  if (NS_WARN_IF(aRv.Failed())) {
    return nullptr;
  }

  RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, p);
  if (!proxy) {
    p->MaybeReject(NS_ERROR_DOM_PUSH_ABORT_ERR);
    return p.forget();
  }

  RefPtr<GetSubscriptionRunnable> r =
    new GetSubscriptionRunnable(proxy, mScope, aAction);
  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));

  return p.forget();
}
already_AddRefed<Promise>
PushSubscription::UnsubscribeFromWorker(ErrorResult& aRv)
{
  WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
  MOZ_ASSERT(worker);
  worker->AssertIsOnWorkerThread();

  nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope();
  RefPtr<Promise> p = Promise::Create(global, aRv);
  if (NS_WARN_IF(aRv.Failed())) {
    return nullptr;
  }

  RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, p);
  if (!proxy) {
    p->MaybeReject(NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE);
    return p.forget();
  }

  RefPtr<UnsubscribeRunnable> r =
    new UnsubscribeRunnable(proxy, mScope);
  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));

  return p.forget();
}
// static
already_AddRefed<IDBOpenDBRequest>
IDBOpenDBRequest::CreateForJS(IDBFactory* aFactory,
                              JS::Handle<JSObject*> aScriptOwner)
{
  MOZ_ASSERT(aFactory);
  aFactory->AssertIsOnOwningThread();
  MOZ_ASSERT(aScriptOwner);

  nsRefPtr<IDBOpenDBRequest> request = new IDBOpenDBRequest(aFactory, nullptr);
  CaptureCaller(request->mFilename, &request->mLineNo);

  request->SetScriptOwner(aScriptOwner);

  if (!NS_IsMainThread()) {
    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    MOZ_ASSERT(workerPrivate);

    workerPrivate->AssertIsOnWorkerThread();

    JSContext* cx = workerPrivate->GetJSContext();
    MOZ_ASSERT(cx);

    nsAutoPtr<WorkerFeature> feature(new WorkerFeature(workerPrivate));
    if (NS_WARN_IF(!workerPrivate->AddFeature(cx, feature))) {
      return nullptr;
    }

    request->mWorkerFeature = Move(feature);
  }

  return request.forget();
}
Exemple #8
0
// This method sets the request's referrerURL, as specified by the "determine
// request's referrer" steps from Referrer Policy [1].
// The actual referrer policy and stripping is dealt with by HttpBaseChannel,
// this always sets the full API referrer URL of the relevant global if it is
// not already a url or no-referrer.
// [1]: https://w3c.github.io/webappsec/specs/referrer-policy/#determine-requests-referrer
nsresult
UpdateRequestReferrer(nsIGlobalObject* aGlobal, InternalRequest* aRequest)
{
  nsAutoString originalReferrer;
  aRequest->GetReferrer(originalReferrer);
  // If it is no-referrer ("") or a URL, don't modify.
  if (!originalReferrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
    return NS_OK;
  }

  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal);
  if (window) {
    nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
    if (doc) {
      nsAutoString referrer;
      doc->GetReferrer(referrer);
      aRequest->SetReferrer(referrer);
    }
  } else {
    WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
    MOZ_ASSERT(worker);
    worker->AssertIsOnWorkerThread();
    WorkerPrivate::LocationInfo& info = worker->GetLocationInfo();
    aRequest->SetReferrer(NS_ConvertUTF8toUTF16(info.mHref));
  }

  return NS_OK;
}
void
BroadcastChannel::Shutdown()
{
  mState = StateClosed;

  if (mWorkerFeature) {
    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    workerPrivate->RemoveFeature(workerPrivate->GetJSContext(), mWorkerFeature);
    mWorkerFeature = nullptr;
  }

  if (mActor) {
    mActor->SetParent(nullptr);

    nsRefPtr<TeardownRunnable> runnable = new TeardownRunnable(mActor);
    NS_DispatchToCurrentThread(runnable);

    mActor = nullptr;
  }

  // If shutdown() is called we have to release the reference if we still keep
  // it.
  if (mIsKeptAlive) {
    mIsKeptAlive = false;
    Release();
  }
}
// static
already_AddRefed<WorkerPushSubscription>
WorkerPushSubscription::Constructor(GlobalObject& aGlobal, const nsAString& aEndpoint, const nsAString& aScope, ErrorResult& aRv)
{
  WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
  MOZ_ASSERT(worker);
  worker->AssertIsOnWorkerThread();

  nsRefPtr<WorkerPushSubscription> sub = new WorkerPushSubscription(aEndpoint, aScope);
  return sub.forget();
}
Exemple #11
0
Promise*
PromiseWorkerProxy::WorkerPromise() const
{
#ifdef DEBUG
  WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
  MOZ_ASSERT(worker);
  worker->AssertIsOnWorkerThread();
#endif
  MOZ_ASSERT(mWorkerPromise);
  return mWorkerPromise;
}
Exemple #12
0
PushManager::PushManager(const nsAString& aScope)
  : mScope(aScope)
{
#ifdef DEBUG
  // There's only one global on a worker, so we don't need to pass a global
  // object to the constructor.
  WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
  MOZ_ASSERT(worker);
  worker->AssertIsOnWorkerThread();
#endif
}
 InitializeRunnable(WorkerPrivate* aWorkerPrivate, nsACString& aOrigin,
                    PrincipalInfo& aPrincipalInfo, ErrorResult& aRv)
   : WorkerMainThreadRunnable(aWorkerPrivate,
                              NS_LITERAL_CSTRING("BroadcastChannel :: Initialize"))
   , mWorkerPrivate(GetCurrentThreadWorkerPrivate())
   , mOrigin(aOrigin)
   , mPrincipalInfo(aPrincipalInfo)
   , mRv(aRv)
 {
   MOZ_ASSERT(mWorkerPrivate);
 }
Exemple #14
0
void
WorkerNavigator::GetUserAgent(nsString& aUserAgent, ErrorResult& aRv) const
{
  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
  MOZ_ASSERT(workerPrivate);

  RefPtr<GetUserAgentRunnable> runnable =
    new GetUserAgentRunnable(workerPrivate, aUserAgent);

  runnable->Dispatch(aRv);
}
Exemple #15
0
 InitializeRunnable(WorkerPrivate* aWorkerPrivate, nsACString& aOrigin,
                    PrincipalInfo& aPrincipalInfo, bool& aPrivateBrowsing,
                    ErrorResult& aRv)
   : WorkerMainThreadRunnable(aWorkerPrivate)
   , mWorkerPrivate(GetCurrentThreadWorkerPrivate())
   , mOrigin(aOrigin)
   , mPrincipalInfo(aPrincipalInfo)
   , mPrivateBrowsing(aPrivateBrowsing)
   , mRv(aRv)
 {
   MOZ_ASSERT(mWorkerPrivate);
 }
Exemple #16
0
void
WorkerNavigator::GetUserAgent(nsString& aUserAgent) const
{
  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
  MOZ_ASSERT(workerPrivate);

  nsRefPtr<GetUserAgentRunnable> runnable =
    new GetUserAgentRunnable(workerPrivate, aUserAgent);

  if (!runnable->Dispatch(workerPrivate->GetJSContext())) {
    JS_ReportPendingException(workerPrivate->GetJSContext());
  }
}
Exemple #17
0
void
WorkerNavigator::GetPlatform(nsString& aPlatform) const
{
  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
  MOZ_ASSERT(workerPrivate);

  if (!mProperties.mPlatformOverridden.IsEmpty() &&
      !workerPrivate->UsesSystemPrincipal()) {
    aPlatform = mProperties.mPlatformOverridden;
  } else {
    aPlatform = mProperties.mPlatform;
  }
}
Exemple #18
0
void
WorkerNavigator::GetAppVersion(nsString& aAppVersion) const
{
  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
  MOZ_ASSERT(workerPrivate);

  if (!mProperties.mAppVersionOverridden.IsEmpty() &&
      !workerPrivate->UsesSystemPrincipal()) {
    aAppVersion = mProperties.mAppVersionOverridden;
  } else {
    aAppVersion = mProperties.mAppVersion;
  }
}
Exemple #19
0
already_AddRefed<URL> ParseURLFromWorker(const GlobalObject& aGlobal,
                                         const nsAString& aInput,
                                         ErrorResult& aRv) {
  WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
  MOZ_ASSERT(worker);
  worker->AssertIsOnWorkerThread();

  NS_ConvertUTF8toUTF16 baseURL(worker->GetLocationInfo().mHref);
  RefPtr<URL> url = URL::WorkerConstructor(aGlobal, aInput, baseURL, aRv);
  if (NS_WARN_IF(aRv.Failed())) {
    aRv.ThrowTypeError<MSG_INVALID_URL>(aInput);
  }
  return url.forget();
}
Exemple #20
0
void
BlobImplFile::GetType(nsAString& aType)
{
  aType.Truncate();

  if (mContentType.IsVoid()) {
    NS_ASSERTION(mWholeFile,
                 "Should only use lazy ContentType when using the whole file");

    if (!NS_IsMainThread()) {
      WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
      if (!workerPrivate) {
        // I have no idea in which thread this method is called. We cannot
        // return any valid value.
        return;
      }

      RefPtr<GetTypeRunnable> runnable =
        new GetTypeRunnable(workerPrivate, this);

      ErrorResult rv;
      runnable->Dispatch(rv);
      if (NS_WARN_IF(rv.Failed())) {
        rv.SuppressException();
      }
      return;
    }

    nsresult rv;
    nsCOMPtr<nsIMIMEService> mimeService =
      do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return;
    }

    nsAutoCString mimeType;
    rv = mimeService->GetTypeFromFile(mFile, mimeType);
    if (NS_FAILED(rv)) {
      mimeType.Truncate();
    }

    AppendUTF8toUTF16(mimeType, mContentType);
    mContentType.SetIsVoid(false);
  }

  aType = mContentType;
}
Exemple #21
0
void
PromiseWorkerProxy::CleanProperties()
{
#ifdef DEBUG
  WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
  MOZ_ASSERT(worker);
  worker->AssertIsOnWorkerThread();
#endif
  // Ok to do this unprotected from Create().
  // CleanUp() holds the lock before calling this.
  mCleanedUp = true;
  mWorkerPromise = nullptr;
  mWorkerPrivate = nullptr;

  // Clear the StructuredCloneHolderBase class.
  Clear();
}
/* static */ bool
BroadcastChannel::IsEnabled(JSContext* aCx, JSObject* aGlobal)
{
  if (NS_IsMainThread()) {
    return Preferences::GetBool("dom.broadcastChannel.enabled", false);
  }

  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
  MOZ_ASSERT(workerPrivate);
  workerPrivate->AssertIsOnWorkerThread();

  nsRefPtr<PrefEnabledRunnable> runnable =
    new PrefEnabledRunnable(workerPrivate);
  runnable->Dispatch(workerPrivate->GetJSContext());

  return runnable->IsEnabled();
}
Exemple #23
0
bool
CacheStorage::HasStorageAccess() const
{
  NS_ASSERT_OWNINGTHREAD(CacheStorage);

  if (NS_IsMainThread()) {
    nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mGlobal);
    if (NS_WARN_IF(!window)) {
      return true;
    }

    nsContentUtils::StorageAccess access =
      nsContentUtils::StorageAllowedForWindow(window);
    return access > nsContentUtils::StorageAccess::ePrivateBrowsing;
  }

  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
  MOZ_ASSERT(workerPrivate);

  return workerPrivate->IsStorageAllowed();
}
Exemple #24
0
void
BlobImplBase::GetMozFullPath(nsAString& aFileName, ErrorResult& aRv) const
{
  NS_ASSERTION(mIsFile, "Should only be called on files");

  aFileName.Truncate();

  if (NS_IsMainThread()) {
    if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
      GetMozFullPathInternal(aFileName, aRv);
    }

    return;
  }

  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
  MOZ_ASSERT(workerPrivate);

  if (workerPrivate->UsesSystemPrincipal()) {
    GetMozFullPathInternal(aFileName, aRv);
  }
}
// static
nsresult
IndexedDatabaseManager::CommonPostHandleEvent(EventChainPostVisitor& aVisitor,
                                              IDBFactory* aFactory)
{
  MOZ_ASSERT(aVisitor.mDOMEvent);
  MOZ_ASSERT(aFactory);

  if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault) {
    return NS_OK;
  }

  Event* internalEvent = aVisitor.mDOMEvent->InternalDOMEvent();
  MOZ_ASSERT(internalEvent);

  if (!internalEvent->IsTrusted()) {
    return NS_OK;
  }

  nsString type;
  MOZ_ALWAYS_SUCCEEDS(internalEvent->GetType(type));

  MOZ_ASSERT(nsDependentString(kErrorEventType).EqualsLiteral("error"));
  if (!type.EqualsLiteral("error")) {
    return NS_OK;
  }

  nsCOMPtr<EventTarget> eventTarget = internalEvent->GetTarget();
  MOZ_ASSERT(eventTarget);

  // Only mess with events that were originally targeted to an IDBRequest.
  RefPtr<IDBRequest> request;
  if (NS_FAILED(eventTarget->QueryInterface(kIDBRequestIID,
                                            getter_AddRefs(request))) ||
      !request) {
    return NS_OK;
  }

  RefPtr<DOMError> error = request->GetErrorAfterResult();

  nsString errorName;
  if (error) {
    error->GetName(errorName);
  }

  RootedDictionary<ErrorEventInit> init(nsContentUtils::RootingCxForThread());
  request->GetCallerLocation(init.mFilename, &init.mLineno, &init.mColno);

  init.mMessage = errorName;
  init.mCancelable = true;
  init.mBubbles = true;

  nsEventStatus status = nsEventStatus_eIgnore;

  if (NS_IsMainThread()) {
    nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(eventTarget->GetOwnerGlobal());
    if (window) {
      nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(window);
      MOZ_ASSERT(sgo);

      if (NS_WARN_IF(NS_FAILED(sgo->HandleScriptError(init, &status)))) {
        status = nsEventStatus_eIgnore;
      }
    } else {
      // We don't fire error events at any global for non-window JS on the main
      // thread.
    }
  } else {
    // Not on the main thread, must be in a worker.
    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    MOZ_ASSERT(workerPrivate);

    RefPtr<WorkerGlobalScope> globalScope = workerPrivate->GlobalScope();
    MOZ_ASSERT(globalScope);

    RefPtr<ErrorEvent> errorEvent =
      ErrorEvent::Constructor(globalScope,
                              nsDependentString(kErrorEventType),
                              init);
    MOZ_ASSERT(errorEvent);

    errorEvent->SetTrusted(true);

    auto* target = static_cast<EventTarget*>(globalScope.get());

    if (NS_WARN_IF(NS_FAILED(
      EventDispatcher::DispatchDOMEvent(target,
                                        /* aWidgetEvent */ nullptr,
                                        errorEvent,
                                        /* aPresContext */ nullptr,
                                        &status)))) {
      status = nsEventStatus_eIgnore;
    }
  }

  if (status == nsEventStatus_eConsumeNoDefault) {
    return NS_OK;
  }

  // Log the error to the error console.
  ScriptErrorHelper::Dump(errorName,
                          init.mFilename,
                          init.mLineno,
                          init.mColno,
                          nsIScriptError::errorFlag,
                          aFactory->IsChrome(),
                          aFactory->InnerWindowID());

  return NS_OK;
}
Exemple #26
0
/*static*/ already_AddRefed<Response>
Response::Constructor(const GlobalObject& aGlobal,
                      const Optional<Nullable<fetch::ResponseBodyInit>>& aBody,
                      const ResponseInit& aInit, ErrorResult& aRv)
{
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());

  if (aInit.mStatus < 200 || aInit.mStatus > 599) {
    aRv.ThrowRangeError<MSG_INVALID_RESPONSE_STATUSCODE_ERROR>();
    return nullptr;
  }

  // Check if the status text contains illegal characters
  nsACString::const_iterator start, end;
  aInit.mStatusText.BeginReading(start);
  aInit.mStatusText.EndReading(end);
  if (FindCharInReadable('\r', start, end)) {
    aRv.ThrowTypeError<MSG_RESPONSE_INVALID_STATUSTEXT_ERROR>();
    return nullptr;
  }
  // Reset iterator since FindCharInReadable advances it.
  aInit.mStatusText.BeginReading(start);
  if (FindCharInReadable('\n', start, end)) {
    aRv.ThrowTypeError<MSG_RESPONSE_INVALID_STATUSTEXT_ERROR>();
    return nullptr;
  }

  RefPtr<InternalResponse> internalResponse =
    new InternalResponse(aInit.mStatus, aInit.mStatusText);

  // Grab a valid channel info from the global so this response is 'valid' for
  // interception.
  if (NS_IsMainThread()) {
    ChannelInfo info;
    nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global);
    if (window) {
      nsIDocument* doc = window->GetExtantDoc();
      MOZ_ASSERT(doc);
      info.InitFromDocument(doc);
    } else {
      info.InitFromChromeGlobal(global);
    }
    internalResponse->InitChannelInfo(info);
  } else {
    WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
    MOZ_ASSERT(worker);
    internalResponse->InitChannelInfo(worker->GetChannelInfo());
  }

  RefPtr<Response> r = new Response(global, internalResponse, nullptr);

  if (aInit.mHeaders.WasPassed()) {
    internalResponse->Headers()->Clear();

    // Instead of using Fill, create an object to allow the constructor to
    // unwrap the HeadersInit.
    RefPtr<Headers> headers =
      Headers::Create(global, aInit.mHeaders.Value(), aRv);
    if (aRv.Failed()) {
      return nullptr;
    }

    internalResponse->Headers()->Fill(*headers->GetInternalHeaders(), aRv);
    if (NS_WARN_IF(aRv.Failed())) {
      return nullptr;
    }
  }

  if (aBody.WasPassed() && !aBody.Value().IsNull()) {
    if (aInit.mStatus == 204 || aInit.mStatus == 205 || aInit.mStatus == 304) {
      aRv.ThrowTypeError<MSG_RESPONSE_NULL_STATUS_WITH_BODY>();
      return nullptr;
    }

    nsCString contentTypeWithCharset;
    nsCOMPtr<nsIInputStream> bodyStream;
    int64_t bodySize = InternalResponse::UNKNOWN_BODY_SIZE;

    const fetch::ResponseBodyInit& body = aBody.Value().Value();
    if (body.IsReadableStream()) {
      aRv.MightThrowJSException();

      JSContext* cx = aGlobal.Context();
      const ReadableStream& readableStream = body.GetAsReadableStream();

      JS::Rooted<JSObject*> readableStreamObj(cx, readableStream.Obj());

      bool disturbed;
      bool locked;
      if (!JS::ReadableStreamIsDisturbed(cx, readableStreamObj, &disturbed) ||
          !JS::ReadableStreamIsLocked(cx, readableStreamObj, &locked)) {
        aRv.StealExceptionFromJSContext(cx);
        return nullptr;
      }
      if (disturbed || locked) {
        aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
        return nullptr;
      }

      r->SetReadableStreamBody(cx, readableStreamObj);

      JS::ReadableStreamMode streamMode;
      if (!JS::ReadableStreamGetMode(cx, readableStreamObj, &streamMode)) {
        aRv.StealExceptionFromJSContext(cx);
        return nullptr;
      }
      if (streamMode == JS::ReadableStreamMode::ExternalSource) {
        // If this is a DOM generated ReadableStream, we can extract the
        // inputStream directly.
        void* underlyingSource = nullptr;
        if (!JS::ReadableStreamGetExternalUnderlyingSource(cx,
                                                           readableStreamObj,
                                                           &underlyingSource)) {
          aRv.StealExceptionFromJSContext(cx);
          return nullptr;
        }

        MOZ_ASSERT(underlyingSource);

        aRv = FetchStream::RetrieveInputStream(underlyingSource,
                                               getter_AddRefs(bodyStream));

        // The releasing of the external source is needed in order to avoid an
        // extra stream lock.
        if (!JS::ReadableStreamReleaseExternalUnderlyingSource(cx, readableStreamObj)) {
          aRv.StealExceptionFromJSContext(cx);
          return nullptr;
        }
        if (NS_WARN_IF(aRv.Failed())) {
          return nullptr;
        }
      } else {
        // If this is a JS-created ReadableStream, let's create a
        // FetchStreamReader.
        aRv = FetchStreamReader::Create(aGlobal.Context(), global,
                                        getter_AddRefs(r->mFetchStreamReader),
                                        getter_AddRefs(bodyStream));
        if (NS_WARN_IF(aRv.Failed())) {
          return nullptr;
        }
      }
    } else {
      uint64_t size = 0;
      aRv = ExtractByteStreamFromBody(body,
                                      getter_AddRefs(bodyStream),
                                      contentTypeWithCharset,
                                      size);
      if (NS_WARN_IF(aRv.Failed())) {
        return nullptr;
      }

      bodySize = size;
    }

    internalResponse->SetBody(bodyStream, bodySize);

    if (!contentTypeWithCharset.IsVoid() &&
        !internalResponse->Headers()->Has(NS_LITERAL_CSTRING("Content-Type"),
                                          aRv)) {
      // Ignore Append() failing here.
      ErrorResult error;
      internalResponse->Headers()->Append(NS_LITERAL_CSTRING("Content-Type"),
                                          contentTypeWithCharset, error);
      error.SuppressException();
    }

    if (aRv.Failed()) {
      return nullptr;
    }
  }

  r->SetMimeType();
  return r.forget();
}