already_AddRefed<DOMRequest> nsBrowserElement::Download(const nsAString& aUrl, const BrowserElementDownloadOptions& aOptions, ErrorResult& aRv) { NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr); RefPtr<DOMRequest> req; nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(mBrowserElementAPI); MOZ_ASSERT(wrappedObj, "Failed to get wrapped JS from XPCOM component."); MOZ_RELEASE_ASSERT(!js::IsWrapper(wrappedObj->GetJSObject())); AutoJSAPI jsapi; if (!jsapi.Init(wrappedObj->GetJSObject())) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } JSContext* cx = jsapi.cx(); JS::Rooted<JS::Value> options(cx); aRv.MightThrowJSException(); if (!ToJSValue(cx, aOptions, &options)) { aRv.StealExceptionFromJSContext(cx); return nullptr; } nsresult rv = mBrowserElementAPI->Download(aUrl, options, getter_AddRefs(req)); if (NS_WARN_IF(NS_FAILED(rv))) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } return req.forget(); }
already_AddRefed<DOMRequest> nsBrowserElement::ExecuteScript(const nsAString& aScript, const BrowserElementExecuteScriptOptions& aOptions, ErrorResult& aRv) { NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr); NS_ENSURE_TRUE(IsNotWidgetOrThrow(aRv), nullptr); nsCOMPtr<nsIDOMDOMRequest> req; nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(mBrowserElementAPI); MOZ_ASSERT(wrappedObj, "Failed to get wrapped JS from XPCOM component."); AutoJSAPI jsapi; jsapi.Init(wrappedObj->GetJSObject()); JSContext* cx = jsapi.cx(); JS::Rooted<JS::Value> options(cx); aRv.MightThrowJSException(); if (!ToJSValue(cx, aOptions, &options)) { aRv.StealExceptionFromJSContext(cx); return nullptr; } nsresult rv = mBrowserElementAPI->ExecuteScript(aScript, options, getter_AddRefs(req)); if (NS_FAILED(rv)) { if (rv == NS_ERROR_INVALID_ARG) { aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); } else { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); } return nullptr; } return req.forget().downcast<DOMRequest>(); }
void FetchStreamReader::StartConsuming(JSContext* aCx, JS::HandleObject aStream, JS::MutableHandle<JSObject*> aReader, ErrorResult& aRv) { MOZ_DIAGNOSTIC_ASSERT(!mReader); MOZ_DIAGNOSTIC_ASSERT(aStream); aRv.MightThrowJSException(); // Here, by spec, we can pick any global we want. Just to avoid extra // cross-compartment steps, we want to create the reader in the same // compartment of the owning Fetch Body object. // The same global will be used to retrieve data from this reader. JSAutoRealm ar(aCx, mGlobal->GetGlobalJSObject()); JS::Rooted<JSObject*> reader( aCx, JS::ReadableStreamGetReader(aCx, aStream, JS::ReadableStreamReaderMode::Default)); if (!reader) { aRv.StealExceptionFromJSContext(aCx); CloseAndRelease(aCx, NS_ERROR_DOM_INVALID_STATE_ERR); return; } mReader = reader; aReader.set(reader); aRv = mPipeOut->AsyncWait(this, 0, 0, mOwningEventTarget); if (NS_WARN_IF(aRv.Failed())) { return; } }
void BrowsingContext::Location(JSContext* aCx, JS::MutableHandle<JSObject*> aLocation, ErrorResult& aError) { aError.MightThrowJSException(); sSingleton.GetProxyObject(aCx, &mLocation, aLocation); if (!aLocation) { aError.StealExceptionFromJSContext(aCx); } }
already_AddRefed<DOMRequest> MobileMessageManager::SendMMS(const MmsParameters& aParams, const MmsSendParameters& aSendParams, ErrorResult& aRv) { nsCOMPtr<nsIMmsService> mmsService = do_GetService(MMS_SERVICE_CONTRACTID); if (!mmsService) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } // Use the default one unless |aSendParams.serviceId| is available. uint32_t serviceId; nsresult rv; if (aSendParams.mServiceId.WasPassed()) { serviceId = aSendParams.mServiceId.Value(); } else { rv = mmsService->GetMmsDefaultServiceId(&serviceId); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } } nsCOMPtr<nsPIDOMWindowInner> window = GetOwner(); if (!window) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.Init(window))) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } JSContext *cx = jsapi.cx(); JS::Rooted<JS::Value> val(cx); aRv.MightThrowJSException(); if (!ToJSValue(cx, aParams, &val)) { aRv.StealExceptionFromJSContext(cx); return nullptr; } RefPtr<DOMRequest> request = new DOMRequest(window); nsCOMPtr<nsIMobileMessageCallback> msgCallback = new MobileMessageCallback(request); rv = mmsService->Send(serviceId, val, msgCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); }
already_AddRefed<IDBTransaction> IDBDatabase::Transaction(const StringOrStringSequence& aStoreNames, IDBTransactionMode aMode, ErrorResult& aRv) { AssertIsOnOwningThread(); aRv.MightThrowJSException(); if (aMode == IDBTransactionMode::Readwriteflush && !IndexedDatabaseManager::ExperimentalFeaturesEnabled()) { // Pretend that this mode doesn't exist. We don't have a way to annotate // certain enum values as depending on preferences so we just duplicate the // normal exception generation here. ThreadsafeAutoJSContext cx; // Disable any automatic error reporting that might be set up so that we // can grab the exception object. AutoForceSetExceptionOnContext forceExn(cx); MOZ_ALWAYS_FALSE( ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, "Argument 2 of IDBDatabase.transaction", "readwriteflush", "IDBTransactionMode")); MOZ_ASSERT(JS_IsExceptionPending(cx)); JS::Rooted<JS::Value> exception(cx); MOZ_ALWAYS_TRUE(JS_GetPendingException(cx, &exception)); aRv.ThrowJSException(cx, exception); return nullptr; } RefPtr<IDBTransaction> transaction; aRv = Transaction(aStoreNames, aMode, getter_AddRefs(transaction)); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } return transaction.forget(); }
already_AddRefed<LabeledBlob> LabeledBlob::Constructor(const GlobalObject& global, JSContext* cx, const nsAString& blob, Label& privacy, Label& trust, ErrorResult& aRv) { aRv.MightThrowJSException(); JSCompartment *compartment = js::GetContextCompartment(cx); MOZ_ASSERT(compartment); if (MOZ_UNLIKELY(!xpc::cowl::IsCompartmentConfined(compartment))) xpc::cowl::EnableCompartmentConfinement(compartment); nsRefPtr<Label> privs = xpc::cowl::GetCompartmentPrivileges(compartment); // current compartment label must flow to label of blob if (!xpc::cowl::GuardWrite(compartment, privacy, trust, privs)) { COWL::JSErrorResult(cx, aRv, "Label of blob is not above current label or below current clearance."); return nullptr; } // Create blob nsRefPtr<Label> privacyCopy = privacy.Clone(aRv); if (aRv.Failed()) { return nullptr; } nsRefPtr<Label> trustCopy = trust.Clone(aRv); if (aRv.Failed()) { return nullptr; } nsRefPtr<LabeledBlob> labeledBlob = new LabeledBlob(blob, privacy, trust); if (aRv.Failed()) { return nullptr; } return labeledBlob.forget(); }
void LabeledBlob::GetBlob(JSContext* cx, nsString& aRetVal, ErrorResult& aRv) const { aRv.MightThrowJSException(); JSCompartment *compartment = js::GetContextCompartment(cx); MOZ_ASSERT(compartment); if (MOZ_UNLIKELY(!xpc::cowl::IsCompartmentConfined(compartment))) xpc::cowl::EnableCompartmentConfinement(compartment); nsRefPtr<Label> privs = xpc::cowl::GetCompartmentPrivileges(compartment); // current compartment label must flow to label of target // raise it if need be // TODO: raise label if the following check does not hold if (!xpc::cowl::GuardRead(compartment, *mPrivacy,*mTrust, privs, cx)) { COWL::JSErrorResult(cx, aRv, "Cannot inspect blob."); return; } aRetVal = mBlob; }
already_AddRefed<Response> Response::Clone(JSContext* aCx, ErrorResult& aRv) { bool bodyUsed = GetBodyUsed(aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } if (!bodyUsed && mReadableStreamBody) { aRv.MightThrowJSException(); AutoJSAPI jsapi; if (!jsapi.Init(mOwner)) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } JSContext* cx = jsapi.cx(); JS::Rooted<JSObject*> body(cx, mReadableStreamBody); bool locked; // We just need to check the 'locked' state because GetBodyUsed() already // checked the 'disturbed' state. if (!JS::ReadableStreamIsLocked(cx, body, &locked)) { aRv.StealExceptionFromJSContext(cx); return nullptr; } bodyUsed = locked; } if (bodyUsed) { aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>(); return nullptr; } RefPtr<FetchStreamReader> streamReader; nsCOMPtr<nsIInputStream> inputStream; JS::Rooted<JSObject*> body(aCx); MaybeTeeReadableStreamBody(aCx, &body, getter_AddRefs(streamReader), getter_AddRefs(inputStream), aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } MOZ_ASSERT_IF(body, streamReader); MOZ_ASSERT_IF(body, inputStream); RefPtr<InternalResponse> ir = mInternalResponse->Clone(body ? InternalResponse::eDontCloneInputStream : InternalResponse::eCloneInputStream); RefPtr<Response> response = new Response(mOwner, ir, GetSignalImpl()); if (body) { // Maybe we have a body, but we receive null from MaybeTeeReadableStreamBody // if this body is a native stream. In this case the InternalResponse will // have a clone of the native body and the ReadableStream will be created // lazily if needed. response->SetReadableStreamBody(aCx, body); response->mFetchStreamReader = streamReader; ir->SetBody(inputStream, InternalResponse::UNKNOWN_BODY_SIZE); } return response.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(); }