// static already_AddRefed<IDBLocaleAwareKeyRange> IDBLocaleAwareKeyRange::Bound(const GlobalObject& aGlobal, JS::Handle<JS::Value> aLower, JS::Handle<JS::Value> aUpper, bool aLowerOpen, bool aUpperOpen, ErrorResult& aRv) { RefPtr<IDBLocaleAwareKeyRange> keyRange = new IDBLocaleAwareKeyRange(aGlobal.GetAsSupports(), aLowerOpen, aUpperOpen, false); aRv = GetKeyFromJSVal(aGlobal.Context(), aLower, keyRange->Lower()); if (aRv.Failed()) { return nullptr; } aRv = GetKeyFromJSVal(aGlobal.Context(), aUpper, keyRange->Upper()); if (aRv.Failed()) { return nullptr; } if (keyRange->Lower() == keyRange->Upper() && (aLowerOpen || aUpperOpen)) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); return nullptr; } return keyRange.forget(); }
already_AddRefed<CustomEvent> CustomEvent::Constructor(const GlobalObject& aGlobal, const nsAString& aType, const CustomEventInit& aParam, ErrorResult& aRv) { nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports()); nsRefPtr<CustomEvent> e = new CustomEvent(t, nullptr, nullptr); bool trusted = e->Init(t); JS::Rooted<JS::Value> detail(aGlobal.Context(), aParam.mDetail); e->InitCustomEvent(aGlobal.Context(), aType, aParam.mBubbles, aParam.mCancelable, detail, aRv); e->SetTrusted(trusted); return e.forget(); }
/* static */ already_AddRefed<KeyframeEffectType> KeyframeEffectReadOnly::ConstructKeyframeEffect( const GlobalObject& aGlobal, const Nullable<ElementOrCSSPseudoElement>& aTarget, JS::Handle<JSObject*> aKeyframes, const OptionsType& aOptions, ErrorResult& aRv) { nsIDocument* doc = AnimationUtils::GetCurrentRealmDocument(aGlobal.Context()); if (!doc) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } TimingParams timingParams = TimingParams::FromOptionsUnion(aOptions, doc, aRv); if (aRv.Failed()) { return nullptr; } nsAutoString invalidPacedProperty; KeyframeEffectParams effectOptions = KeyframeEffectParamsFromUnion(aOptions, invalidPacedProperty, aRv); if (aRv.Failed()) { return nullptr; } if (!invalidPacedProperty.IsEmpty()) { const char16_t* params[] = { invalidPacedProperty.get() }; nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Animation"), doc, nsContentUtils::eDOM_PROPERTIES, "UnanimatablePacedProperty", params, ArrayLength(params)); } Maybe<OwningAnimationTarget> target = ConvertTarget(aTarget); RefPtr<KeyframeEffectType> effect = new KeyframeEffectType(doc, target, timingParams, effectOptions); effect->SetKeyframes(aGlobal.Context(), aKeyframes, aRv); if (aRv.Failed()) { return nullptr; } return effect.forget(); }
already_AddRefed<BluetoothLeDeviceEvent> BluetoothLeDeviceEvent::Constructor( const GlobalObject& aGlobal, const nsAString& aType, const BluetoothLeDeviceEventInit& aEventInitDict, ErrorResult& aRv) { nsCOMPtr<mozilla::dom::EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports()); RefPtr<BluetoothLeDeviceEvent> e = new BluetoothLeDeviceEvent(owner); bool trusted = e->Init(owner); e->InitEvent(aType, aEventInitDict.mBubbles, aEventInitDict.mCancelable); e->mDevice = aEventInitDict.mDevice; e->mRssi = aEventInitDict.mRssi; if (!aEventInitDict.mScanRecord.IsNull()) { const auto& scanRecord = aEventInitDict.mScanRecord.Value(); scanRecord.ComputeLengthAndData(); e->mScanRecord = ArrayBuffer::Create(aGlobal.Context(), scanRecord.Length(), scanRecord.Data()); if (!e->mScanRecord) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return nullptr; } } e->SetTrusted(trusted); return e.forget(); }
/* static */ already_AddRefed<Blob> Blob::Constructor(const GlobalObject& aGlobal, const Optional<Sequence<BlobPart>>& aData, const BlobPropertyBag& aBag, ErrorResult& aRv) { RefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl(); if (aData.WasPassed()) { nsAutoString type(aBag.mType); MakeValidBlobType(type); impl->InitializeBlob(aGlobal.Context(), aData.Value(), type, aBag.mEndings == EndingTypes::Native, aRv); } else { impl->InitializeBlob(aRv); } if (NS_WARN_IF(aRv.Failed())) { return nullptr; } MOZ_ASSERT(!impl->IsFile()); RefPtr<Blob> blob = Blob::Create(aGlobal.GetAsSupports(), impl); return blob.forget(); }
// static already_AddRefed<PerformanceObserver> PerformanceObserver::Constructor(const GlobalObject& aGlobal, PerformanceObserverCallback& aCb, ErrorResult& aRv) { if (NS_IsMainThread()) { nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aGlobal.GetAsSupports()); if (!ownerWindow) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } MOZ_ASSERT(ownerWindow->IsInnerWindow()); RefPtr<PerformanceObserver> observer = new PerformanceObserver(ownerWindow, aCb); return observer.forget(); } JSContext* cx = aGlobal.Context(); WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); MOZ_ASSERT(workerPrivate); RefPtr<PerformanceObserver> observer = new PerformanceObserver(workerPrivate, aCb); return observer.forget(); }
/* static */ already_AddRefed<KeyframeEffectType> KeyframeEffectReadOnly::ConstructKeyframeEffect(const GlobalObject& aGlobal, KeyframeEffectReadOnly& aSource, ErrorResult& aRv) { nsIDocument* doc = AnimationUtils::GetCurrentRealmDocument(aGlobal.Context()); if (!doc) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } // Create a new KeyframeEffectReadOnly object with aSource's target, // iteration composite operation, composite operation, and spacing mode. // The constructor creates a new AnimationEffect(ReadOnly) object by // aSource's TimingParams. // Note: we don't need to re-throw exceptions since the value specified on // aSource's timing object can be assumed valid. RefPtr<KeyframeEffectType> effect = new KeyframeEffectType(doc, aSource.mTarget, aSource.SpecifiedTiming(), aSource.mEffectOptions); // Copy cumulative change hint. mCumulativeChangeHint should be the same as // the source one because both of targets are the same. effect->mCumulativeChangeHint = aSource.mCumulativeChangeHint; // Copy aSource's keyframes and animation properties. // Note: We don't call SetKeyframes directly, which might revise the // computed offsets and rebuild the animation properties. // FIXME: Bug 1314537: We have to make sure SharedKeyframeList is handled // properly. effect->mKeyframes = aSource.mKeyframes; effect->mProperties = aSource.mProperties; return effect.forget(); }
// --------------------------------------------------------------------------- // // Animation interface: // // --------------------------------------------------------------------------- /* static */ already_AddRefed<Animation> Animation::Constructor(const GlobalObject& aGlobal, KeyframeEffectReadOnly* aEffect, const Optional<AnimationTimeline*>& aTimeline, ErrorResult& aRv) { nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); RefPtr<Animation> animation = new Animation(global); if (!aEffect) { // Bug 1049975: We do not support null effect yet. aRv.Throw(NS_ERROR_DOM_ANIM_NO_EFFECT_ERR); return nullptr; } AnimationTimeline* timeline; if (aTimeline.WasPassed()) { timeline = aTimeline.Value(); } else { nsIDocument* document = AnimationUtils::GetCurrentRealmDocument(aGlobal.Context()); if (!document) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } timeline = document->Timeline(); } animation->SetTimelineNoUpdate(timeline); animation->SetEffect(aEffect); return animation.forget(); }
already_AddRefed<MediaEncryptedEvent> MediaEncryptedEvent::Constructor(const GlobalObject& aGlobal, const nsAString& aType, const MediaKeyNeededEventInit& aEventInitDict, ErrorResult& aRv) { nsCOMPtr<EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports()); RefPtr<MediaEncryptedEvent> e = new MediaEncryptedEvent(owner); bool trusted = e->Init(owner); e->InitEvent(aType, aEventInitDict.mBubbles, aEventInitDict.mCancelable); e->mInitDataType = aEventInitDict.mInitDataType; if (!aEventInitDict.mInitData.IsNull()) { const auto& a = aEventInitDict.mInitData.Value(); a.ComputeLengthAndData(); e->mInitData = ArrayBuffer::Create(aGlobal.Context(), a.Length(), a.Data()); if (!e->mInitData) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return nullptr; } } e->SetTrusted(trusted); return e.forget(); }
/* static */ already_AddRefed<File> File::Constructor(const GlobalObject& aGlobal, const Sequence<BlobPart>& aData, const nsAString& aName, const FilePropertyBag& aBag, ErrorResult& aRv) { // Normalizing the filename nsString name(aName); name.ReplaceChar('/', ':'); RefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl(name); nsAutoString type(aBag.mType); MakeValidBlobType(type); impl->InitializeBlob(aGlobal.Context(), aData, type, false, aRv); if (aRv.Failed()) { return nullptr; } MOZ_ASSERT(impl->IsFile()); if (aBag.mLastModified.WasPassed()) { impl->SetLastModified(aBag.mLastModified.Value()); } RefPtr<File> file = new File(aGlobal.GetAsSupports(), impl); return file.forget(); }
/* static */ void ThreadSafeChromeUtils::Base64URLDecode(GlobalObject& aGlobal, const nsACString& aString, const Base64URLDecodeOptions& aOptions, JS::MutableHandle<JSObject*> aRetval, ErrorResult& aRv) { Base64URLDecodePaddingPolicy paddingPolicy; switch (aOptions.mPadding) { case Base64URLDecodePadding::Require: paddingPolicy = Base64URLDecodePaddingPolicy::Require; break; case Base64URLDecodePadding::Ignore: paddingPolicy = Base64URLDecodePaddingPolicy::Ignore; break; case Base64URLDecodePadding::Reject: paddingPolicy = Base64URLDecodePaddingPolicy::Reject; break; default: aRv.Throw(NS_ERROR_INVALID_ARG); return; } FallibleTArray<uint8_t> data; nsresult rv = mozilla::Base64URLDecode(aString, paddingPolicy, data); if (NS_WARN_IF(NS_FAILED(rv))) { aRv.Throw(rv); return; } JS::Rooted<JSObject*> buffer(aGlobal.Context(), ArrayBuffer::Create(aGlobal.Context(), data.Length(), data.Elements())); if (NS_WARN_IF(!buffer)) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return; } aRetval.set(buffer); }
already_AddRefed<Promise> Cache::AddAll(const GlobalObject& aGlobal, nsTArray<RefPtr<Request>>&& aRequestList, CallerType aCallerType, ErrorResult& aRv) { MOZ_DIAGNOSTIC_ASSERT(mActor); // If there is no work to do, then resolve immediately if (aRequestList.IsEmpty()) { RefPtr<Promise> promise = Promise::Create(mGlobal, aRv); if (NS_WARN_IF(!promise)) { return nullptr; } promise->MaybeResolveWithUndefined(); return promise.forget(); } AutoTArray<RefPtr<Promise>, 256> fetchList; fetchList.SetCapacity(aRequestList.Length()); // Begin fetching each request in parallel. For now, if an error occurs just // abandon our previous fetch calls. In theory we could cancel them in the // future once fetch supports it. for (uint32_t i = 0; i < aRequestList.Length(); ++i) { RequestOrUSVString requestOrString; requestOrString.SetAsRequest() = aRequestList[i]; RefPtr<Promise> fetch = FetchRequest(mGlobal, requestOrString, RequestInit(), aCallerType, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } fetchList.AppendElement(std::move(fetch)); } RefPtr<Promise> promise = Promise::Create(mGlobal, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } RefPtr<FetchHandler> handler = new FetchHandler(mActor->GetWorkerHolder(), this, std::move(aRequestList), promise); RefPtr<Promise> fetchPromise = Promise::All(aGlobal.Context(), fetchList, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } fetchPromise->AppendNativeHandler(handler); return promise.forget(); }
/* static */ void ThreadSafeChromeUtils::Base64URLDecode(GlobalObject& aGlobal, const nsACString& aString, const Base64URLDecodeOptions& aOptions, JS::MutableHandle<JSObject*> aRetval, ErrorResult& aRv) { FallibleTArray<uint8_t> data; nsresult rv = mozilla::Base64URLDecode(aString, aOptions, data); if (NS_WARN_IF(NS_FAILED(rv))) { aRv.Throw(rv); return; } JS::Rooted<JSObject*> buffer(aGlobal.Context(), ArrayBuffer::Create(aGlobal.Context(), data.Length(), data.Elements())); if (NS_WARN_IF(!buffer)) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return; } aRetval.set(buffer); }
// static already_AddRefed<IDBKeyRange> IDBKeyRange::Only(const GlobalObject& aGlobal, JS::Handle<JS::Value> aValue, ErrorResult& aRv) { RefPtr<IDBKeyRange> keyRange = new IDBKeyRange(aGlobal.GetAsSupports(), false, false, true); aRv = GetKeyFromJSVal(aGlobal.Context(), aValue, keyRange->Lower()); if (aRv.Failed()) { return nullptr; } return keyRange.forget(); }
/* static */ already_AddRefed<FileReader> FileReader::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) { nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); WorkerPrivate* workerPrivate = nullptr; if (!NS_IsMainThread()) { JSContext* cx = aGlobal.Context(); workerPrivate = GetWorkerPrivateFromContext(cx); MOZ_ASSERT(workerPrivate); } RefPtr<FileReader> fileReader = new FileReader(global, workerPrivate); return fileReader.forget(); }
/* static */ void ThreadSafeChromeUtils::NondeterministicGetWeakSetKeys(GlobalObject& aGlobal, JS::Handle<JS::Value> aSet, JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv) { if (!aSet.isObject()) { aRetval.setUndefined(); } else { JSContext* cx = aGlobal.Context(); JS::Rooted<JSObject*> objRet(cx); JS::Rooted<JSObject*> setObj(cx, &aSet.toObject()); if (!JS_NondeterministicGetWeakSetKeys(cx, setObj, &objRet)) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); } else { aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue()); } } }
/* static */ already_AddRefed<Blob> Blob::Constructor( const GlobalObject& aGlobal, const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData, const BlobPropertyBag& aBag, ErrorResult& aRv) { nsRefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl(); impl->InitializeBlob(aGlobal.Context(), aData, aBag.mType, aBag.mEndings == EndingTypes::Native, aRv); if (aRv.Failed()) { return nullptr; } MOZ_ASSERT(!impl->IsFile()); nsRefPtr<Blob> blob = Blob::Create(aGlobal.GetAsSupports(), impl); return blob.forget(); }
// static already_AddRefed<PushManager> PushManager::Constructor(GlobalObject& aGlobal, const nsAString& aScope, ErrorResult& aRv) { if (!NS_IsMainThread()) { RefPtr<PushManager> ret = new PushManager(aScope); return ret.forget(); } RefPtr<PushManagerImpl> impl = PushManagerImpl::Constructor(aGlobal, aGlobal.Context(), aScope, aRv); if (aRv.Failed()) { return nullptr; } nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); RefPtr<PushManager> ret = new PushManager(global, impl); return ret.forget(); }
/* static */ already_AddRefed<ChromeWorker> ChromeWorker::Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL, ErrorResult& aRv) { JSContext* cx = aGlobal.Context(); RefPtr<WorkerPrivate> workerPrivate = WorkerPrivate::Constructor(cx, aScriptURL, true /* aIsChromeWorker */, WorkerTypeDedicated, EmptyString(), VoidCString(), nullptr /*aLoadInfo */, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(aGlobal.GetAsSupports()); RefPtr<ChromeWorker> worker = new ChromeWorker(globalObject, workerPrivate.forget()); return worker.forget(); }
/* static */ already_AddRefed<File> File::Constructor( const GlobalObject& aGlobal, const Sequence<OwningArrayBufferOrArrayBufferViewOrBlobOrString>& aData, const nsAString& aName, const FilePropertyBag& aBag, ErrorResult& aRv) { nsRefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl(aName); impl->InitializeBlob(aGlobal.Context(), aData, aBag.mType, false, aRv); if (aRv.Failed()) { return nullptr; } MOZ_ASSERT(impl->IsFile()); if (aBag.mLastModified.WasPassed()) { impl->SetLastModified(aBag.mLastModified.Value()); } nsRefPtr<File> file = new File(aGlobal.GetAsSupports(), impl); return file.forget(); }
// static already_AddRefed<Promise> Promise::All(const GlobalObject& aGlobal, const nsTArray<RefPtr<Promise>>& aPromiseList, ErrorResult& aRv) { nsCOMPtr<nsIGlobalObject> global; global = do_QueryInterface(aGlobal.GetAsSupports()); if (!global) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } JSContext* cx = aGlobal.Context(); JS::AutoObjectVector promises(cx); if (!promises.reserve(aPromiseList.Length())) { aRv.NoteJSContextException(cx); return nullptr; } for (auto& promise : aPromiseList) { JS::Rooted<JSObject*> promiseObj(cx, promise->PromiseObj()); // Just in case, make sure these are all in the context compartment. if (!JS_WrapObject(cx, &promiseObj)) { aRv.NoteJSContextException(cx); return nullptr; } promises.infallibleAppend(promiseObj); } JS::Rooted<JSObject*> result(cx, JS::GetWaitForAllPromise(cx, promises)); if (!result) { aRv.NoteJSContextException(cx); return nullptr; } return CreateFromExisting(global, result); }
/* static */ already_AddRefed<FileReader> FileReader::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) { // The owner can be null when this object is used by chrome code. nsCOMPtr<nsPIDOMWindow> owner = do_QueryInterface(aGlobal.GetAsSupports()); WorkerPrivate* workerPrivate = nullptr; if (!NS_IsMainThread()) { JSContext* cx = aGlobal.Context(); workerPrivate = GetWorkerPrivateFromContext(cx); MOZ_ASSERT(workerPrivate); } RefPtr<FileReader> fileReader = new FileReader(owner, workerPrivate); if (!owner && nsContentUtils::ThreadsafeIsCallerChrome()) { // Instead of grabbing some random global from the context stack, // let's use the default one (junk scope) for now. // We should move away from this Init... fileReader->BindToOwner(xpc::NativeGlobal(xpc::PrivilegedJunkScope())); } return fileReader.forget(); }
/*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(); }
/* static */ already_AddRefed<BroadcastChannel> BroadcastChannel::Constructor(const GlobalObject& aGlobal, const nsAString& aChannel, ErrorResult& aRv) { nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports()); // Window is null in workers. nsAutoCString origin; PrincipalInfo principalInfo; WorkerPrivate* workerPrivate = nullptr; if (NS_IsMainThread()) { nsCOMPtr<nsIGlobalObject> incumbent = mozilla::dom::GetIncumbentGlobal(); if (!incumbent) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsIPrincipal* principal = incumbent->PrincipalOrNull(); if (!principal) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } aRv = principal->GetOrigin(origin); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } aRv = PrincipalToPrincipalInfo(principal, &principalInfo); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } } else { JSContext* cx = aGlobal.Context(); workerPrivate = GetWorkerPrivateFromContext(cx); MOZ_ASSERT(workerPrivate); RefPtr<InitializeRunnable> runnable = new InitializeRunnable(workerPrivate, origin, principalInfo, aRv); runnable->Dispatch(Closing, aRv); } if (aRv.Failed()) { return nullptr; } RefPtr<BroadcastChannel> bc = new BroadcastChannel(window, principalInfo, origin, aChannel); // Register this component to PBackground. PBackgroundChild* actor = BackgroundChild::GetForCurrentThread(); if (actor) { bc->ActorCreated(actor); } else { BackgroundChild::GetOrCreateForCurrentThread(bc); } if (!workerPrivate) { MOZ_ASSERT(window); MOZ_ASSERT(window->IsInnerWindow()); bc->mInnerID = window->WindowID(); // Register as observer for inner-window-destroyed. nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); if (obs) { obs->AddObserver(bc, "inner-window-destroyed", false); } } else { bc->mWorkerHolder = new BroadcastChannelWorkerHolder(bc); if (NS_WARN_IF(!bc->mWorkerHolder->HoldWorker(workerPrivate, Closing))) { bc->mWorkerHolder = nullptr; aRv.Throw(NS_ERROR_FAILURE); return nullptr; } } return bc.forget(); }
/* static */ already_AddRefed<BroadcastChannel> BroadcastChannel::Constructor(const GlobalObject& aGlobal, const nsAString& aChannel, ErrorResult& aRv) { nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports()); // Window is null in workers. RefPtr<BroadcastChannel> bc = new BroadcastChannel(window, aChannel); nsAutoCString origin; PrincipalInfo principalInfo; if (NS_IsMainThread()) { nsCOMPtr<nsIGlobalObject> incumbent = mozilla::dom::GetIncumbentGlobal(); if (!incumbent) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsIPrincipal* principal = incumbent->PrincipalOrNull(); if (!principal) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } aRv = principal->GetOrigin(origin); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } aRv = PrincipalToPrincipalInfo(principal, &principalInfo); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } } else { JSContext* cx = aGlobal.Context(); WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); MOZ_ASSERT(workerPrivate); RefPtr<StrongWorkerRef> workerRef = StrongWorkerRef::Create(workerPrivate, "BroadcastChannel", [bc] () { bc->Shutdown(); }); // We are already shutting down the worker. Let's return a non-active // object. if (NS_WARN_IF(!workerRef)) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr<ThreadSafeWorkerRef> tsr = new ThreadSafeWorkerRef(workerRef); RefPtr<InitializeRunnable> runnable = new InitializeRunnable(tsr, origin, principalInfo, aRv); runnable->Dispatch(Canceling, aRv); if (aRv.Failed()) { return nullptr; } bc->mWorkerRef = Move(workerRef); } // Register this component to PBackground. PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread(); if (NS_WARN_IF(!actorChild)) { // Firefox is probably shutting down. Let's return a 'generic' error. aRv.Throw(NS_ERROR_FAILURE); return nullptr; } PBroadcastChannelChild* actor = actorChild->SendPBroadcastChannelConstructor(principalInfo, origin, nsString(aChannel)); bc->mActor = static_cast<BroadcastChannelChild*>(actor); MOZ_ASSERT(bc->mActor); bc->mActor->SetParent(bc); return bc.forget(); }
already_AddRefed<WebSocket> WebSocket::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl, const Sequence<nsString>& aProtocols, ErrorResult& aRv) { if (!PrefEnabled()) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return nullptr; } nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal = do_QueryInterface(aGlobal.GetAsSupports()); if (!scriptPrincipal) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsCOMPtr<nsIPrincipal> principal = scriptPrincipal->GetPrincipal(); if (!principal) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aGlobal.GetAsSupports()); if (!sgo) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aGlobal.GetAsSupports()); if (!ownerWindow) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsTArray<nsString> protocolArray; for (uint32_t index = 0, len = aProtocols.Length(); index < len; ++index) { const nsString& protocolElement = aProtocols[index]; if (protocolElement.IsEmpty()) { aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); return nullptr; } if (protocolArray.Contains(protocolElement)) { aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); return nullptr; } if (protocolElement.FindChar(',') != -1) /* interferes w/list */ { aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); return nullptr; } protocolArray.AppendElement(protocolElement); } nsRefPtr<WebSocket> webSocket = new WebSocket(ownerWindow); nsresult rv = webSocket->Init(aGlobal.Context(), principal, aUrl, protocolArray); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return webSocket.forget(); }
/* static */ void PrioEncoder::Encode(GlobalObject& aGlobal, const nsCString& aBatchID, const PrioParams& aPrioParams, RootedDictionary<PrioEncodedData>& aData, ErrorResult& aRv) { nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); if (!global) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } SECStatus prio_rv = SECSuccess; if (!sSingleton) { nsresult rv; nsAutoCStringN<CURVE25519_KEY_LEN_HEX + 1> prioKeyA; rv = Preferences::GetCString("prio.publicKeyA", prioKeyA); if (NS_FAILED(rv)) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } nsAutoCStringN<CURVE25519_KEY_LEN_HEX + 1> prioKeyB; rv = Preferences::GetCString("prio.publicKeyB", prioKeyB); if (NS_FAILED(rv)) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } // Check that both public keys are of the right length // and contain only hex digits 0-9a-fA-f if (!PrioEncoder::IsValidHexPublicKey(prioKeyA) || !PrioEncoder::IsValidHexPublicKey(prioKeyB)) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } prio_rv = Prio_init(); if (prio_rv != SECSuccess) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } prio_rv = PublicKey_import_hex( &sPublicKeyA, reinterpret_cast<const unsigned char*>(prioKeyA.BeginReading()), CURVE25519_KEY_LEN_HEX); if (prio_rv != SECSuccess) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } prio_rv = PublicKey_import_hex( &sPublicKeyB, reinterpret_cast<const unsigned char*>(prioKeyB.BeginReading()), CURVE25519_KEY_LEN_HEX); if (prio_rv != SECSuccess) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } sSingleton = new PrioEncoder(); ClearOnShutdown(&sSingleton); } nsTArray<bool> dataItems = aPrioParams.mBooleans; if (dataItems.Length() > gNumBooleans) { aRv.ThrowRangeError<MSG_VALUE_OUT_OF_RANGE>( NS_LITERAL_STRING("Maximum boolean value exceeded")); return; } PrioConfig prioConfig = PrioConfig_new( dataItems.Length(), sPublicKeyA, sPublicKeyB, reinterpret_cast<const unsigned char*>(aBatchID.BeginReading()), aBatchID.Length()); if (!prioConfig) { aRv.Throw(NS_ERROR_FAILURE); return; } auto configGuard = MakeScopeExit([&] { PrioConfig_clear(prioConfig); }); unsigned char* forServerA = nullptr; unsigned int lenA = 0; unsigned char* forServerB = nullptr; unsigned int lenB = 0; prio_rv = PrioClient_encode(prioConfig, dataItems.Elements(), &forServerA, &lenA, &forServerB, &lenB); nsTArray<uint8_t> arrayForServerA; nsTArray<uint8_t> arrayForServerB; if (!arrayForServerA.AppendElements(reinterpret_cast<uint8_t*>(forServerA), lenA, fallible)) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return; } free(forServerA); if (!arrayForServerB.AppendElements(reinterpret_cast<uint8_t*>(forServerB), lenB, fallible)) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return; } free(forServerB); if (prio_rv != SECSuccess) { aRv.Throw(NS_ERROR_FAILURE); return; } JS::Rooted<JS::Value> valueA(aGlobal.Context()); if (!ToJSValue(aGlobal.Context(), TypedArrayCreator<Uint8Array>(arrayForServerA), &valueA)) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return; } aData.mA.Construct().Init(&valueA.toObject()); JS::Rooted<JS::Value> valueB(aGlobal.Context()); if (!ToJSValue(aGlobal.Context(), TypedArrayCreator<Uint8Array>(arrayForServerB), &valueB)) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return; } aData.mB.Construct().Init(&valueB.toObject()); }
/* static */ already_AddRefed<BroadcastChannel> BroadcastChannel::Constructor(const GlobalObject& aGlobal, const nsAString& aChannel, ErrorResult& aRv) { nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports()); // Window is null in workers. nsAutoString origin; PrincipalInfo principalInfo; bool privateBrowsing = false; WorkerPrivate* workerPrivate = nullptr; if (NS_IsMainThread()) { nsCOMPtr<nsIGlobalObject> incumbent = mozilla::dom::GetIncumbentGlobal(); if (!incumbent) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsIPrincipal* principal = incumbent->PrincipalOrNull(); if (!principal) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } bool isNullPrincipal; aRv = principal->GetIsNullPrincipal(&isNullPrincipal); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } if (NS_WARN_IF(isNullPrincipal)) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } GetOrigin(principal, origin, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } aRv = PrincipalToPrincipalInfo(principal, &principalInfo); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } nsIDocument* doc = window->GetExtantDoc(); if (doc) { privateBrowsing = nsContentUtils::IsInPrivateBrowsing(doc); // No bfcache when BroadcastChannel is used. doc->DisallowBFCaching(); } } else { JSContext* cx = aGlobal.Context(); workerPrivate = GetWorkerPrivateFromContext(cx); MOZ_ASSERT(workerPrivate); nsRefPtr<InitializeRunnable> runnable = new InitializeRunnable(workerPrivate, origin, principalInfo, privateBrowsing, aRv); runnable->Dispatch(cx); } if (aRv.Failed()) { return nullptr; } nsRefPtr<BroadcastChannel> bc = new BroadcastChannel(window, principalInfo, origin, aChannel, privateBrowsing); // Register this component to PBackground. PBackgroundChild* actor = BackgroundChild::GetForCurrentThread(); if (actor) { bc->ActorCreated(actor); } else { BackgroundChild::GetOrCreateForCurrentThread(bc); } if (!workerPrivate) { MOZ_ASSERT(window); MOZ_ASSERT(window->IsInnerWindow()); bc->mInnerID = window->WindowID(); // Register as observer for inner-window-destroyed. nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); if (obs) { obs->AddObserver(bc, "inner-window-destroyed", false); } } else { bc->mWorkerFeature = new BroadcastChannelFeature(bc); JSContext* cx = workerPrivate->GetJSContext(); if (NS_WARN_IF(!workerPrivate->AddFeature(cx, bc->mWorkerFeature))) { NS_WARNING("Failed to register the BroadcastChannel worker feature."); bc->mWorkerFeature = nullptr; aRv.Throw(NS_ERROR_FAILURE); return nullptr; } } return bc.forget(); }