// static nsresult IDBKeyRange::FromJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal, IDBKeyRange** aKeyRange) { nsRefPtr<IDBKeyRange> keyRange; if (aVal.isNullOrUndefined()) { // undefined and null returns no IDBKeyRange. keyRange.forget(aKeyRange); return NS_OK; } JS::Rooted<JSObject*> obj(aCx, aVal.isObject() ? &aVal.toObject() : nullptr); if (aVal.isPrimitive() || JS_IsArrayObject(aCx, obj) || JS_ObjectIsDate(aCx, obj)) { // A valid key returns an 'only' IDBKeyRange. keyRange = new IDBKeyRange(nullptr, false, false, true); nsresult rv = GetKeyFromJSVal(aCx, aVal, keyRange->Lower()); if (NS_FAILED(rv)) { return rv; } } else { MOZ_ASSERT(aVal.isObject()); // An object is not permitted unless it's another IDBKeyRange. if (NS_FAILED(UNWRAP_OBJECT(IDBKeyRange, obj, keyRange))) { return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; } } keyRange.forget(aKeyRange); return NS_OK; }
// PromiseNativeHandler void PresentationResponderInfo::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) { MOZ_ASSERT(NS_IsMainThread()); if (NS_WARN_IF(!aValue.isObject())) { ReplyError(NS_ERROR_NOT_AVAILABLE); return; } JS::Rooted<JSObject*> obj(aCx, &aValue.toObject()); if (NS_WARN_IF(!obj)) { ReplyError(NS_ERROR_NOT_AVAILABLE); return; } // Start to listen to document state change event |STATE_TRANSFERRING|. HTMLIFrameElement* frame = nullptr; nsresult rv = UNWRAP_OBJECT(HTMLIFrameElement, obj, frame); if (NS_WARN_IF(!frame)) { ReplyError(NS_ERROR_NOT_AVAILABLE); return; } nsCOMPtr<nsIFrameLoaderOwner> owner = do_QueryInterface((nsIFrameLoaderOwner*) frame); if (NS_WARN_IF(!owner)) { ReplyError(NS_ERROR_NOT_AVAILABLE); return; } nsCOMPtr<nsIFrameLoader> frameLoader; rv = owner->GetFrameLoader(getter_AddRefs(frameLoader)); if (NS_WARN_IF(NS_FAILED(rv))) { ReplyError(rv); return; } nsRefPtr<TabParent> tabParent = TabParent::GetFrom(frameLoader); if (tabParent) { // OOP frame nsCOMPtr<nsIContentParent> cp = tabParent->Manager(); NS_WARN_IF(!static_cast<ContentParent*>(cp.get())->SendNotifyPresentationReceiverLaunched(tabParent, mSessionId)); } else { // In-process frame nsCOMPtr<nsIDocShell> docShell; rv = frameLoader->GetDocShell(getter_AddRefs(docShell)); if (NS_WARN_IF(NS_FAILED(rv))) { ReplyError(rv); return; } mLoadingCallback = new PresentationResponderLoadingCallback(mSessionId); rv = mLoadingCallback->Init(docShell); if (NS_WARN_IF(NS_FAILED(rv))) { ReplyError(rv); return; } } }
NS_IMETHODIMP ArrayBufferInputStream::SetData(JS::Handle<JS::Value> aBuffer, uint32_t aByteOffset, uint32_t aLength, JSContext* aCx) { if (!aBuffer.isObject()) { return NS_ERROR_FAILURE; } JS::RootedObject arrayBuffer(aCx, &aBuffer.toObject()); if (!JS_IsArrayBufferObject(arrayBuffer)) { return NS_ERROR_FAILURE; } mArrayBuffer.construct(aCx, aBuffer); uint32_t buflen = JS_GetArrayBufferByteLength(arrayBuffer); mOffset = std::min(buflen, aByteOffset); mBufferLength = std::min(buflen - mOffset, aLength); mBuffer = JS_GetStableArrayBufferData(aCx, arrayBuffer); if (!mBuffer) { return NS_ERROR_FAILURE; } return NS_OK; }
NS_IMETHODIMP TCPSocketParent::InitJS(JS::Handle<JS::Value> aIntermediary, JSContext* aCx) { MOZ_ASSERT(aIntermediary.isObject()); mIntermediaryObj = &aIntermediary.toObject(); return NS_OK; }
NS_IMETHODIMP nsBinaryInputStream::ReadArrayBuffer(uint32_t aLength, JS::Handle<JS::Value> aBuffer, JSContext* cx) { if (!aBuffer.isObject()) { return NS_ERROR_FAILURE; } JS::RootedObject buffer(cx, &aBuffer.toObject()); if (!JS_IsArrayBufferObject(buffer) || JS_GetArrayBufferByteLength(buffer) < aLength) { return NS_ERROR_FAILURE; } uint8_t* data = JS_GetStableArrayBufferData(cx, buffer); if (!data) { return NS_ERROR_FAILURE; } uint32_t bytesRead; nsresult rv = Read(reinterpret_cast<char*>(data), aLength, &bytesRead); if (NS_WARN_IF(NS_FAILED(rv))) return rv; if (bytesRead != aLength) { return NS_ERROR_FAILURE; } return NS_OK; }
NS_IMETHODIMP nsBinaryInputStream::ReadArrayBuffer(uint32_t aLength, JS::Handle<JS::Value> aBuffer, JSContext* aCx, uint32_t* aReadLength) { if (!aBuffer.isObject()) { return NS_ERROR_FAILURE; } JS::RootedObject buffer(aCx, &aBuffer.toObject()); if (!JS_IsArrayBufferObject(buffer)) { return NS_ERROR_FAILURE; } uint32_t bufferLength = JS_GetArrayBufferByteLength(buffer); if (bufferLength < aLength) { return NS_ERROR_FAILURE; } uint32_t bufSize = std::min<uint32_t>(aLength, 4096); UniquePtr<char[]> buf = MakeUnique<char[]>(bufSize); uint32_t pos = 0; *aReadLength = 0; do { // Read data into temporary buffer. uint32_t bytesRead; uint32_t amount = std::min(aLength - pos, bufSize); nsresult rv = Read(buf.get(), amount, &bytesRead); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } MOZ_ASSERT(bytesRead <= amount); if (bytesRead == 0) { break; } // Copy data into actual buffer. JS::AutoCheckCannotGC nogc; bool isShared; if (bufferLength != JS_GetArrayBufferByteLength(buffer)) { return NS_ERROR_FAILURE; } char* data = reinterpret_cast<char*>(JS_GetArrayBufferData(buffer, &isShared, nogc)); MOZ_ASSERT(!isShared); // Implied by JS_GetArrayBufferData() if (!data) { return NS_ERROR_FAILURE; } *aReadLength += bytesRead; PodCopy(data + pos, buf.get(), bytesRead); pos += bytesRead; } while (pos < aLength); return NS_OK; }
// static nsresult IDBKeyRange::FromJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal, IDBKeyRange** aKeyRange) { MOZ_ASSERT_IF(!aCx, aVal.isUndefined()); RefPtr<IDBKeyRange> keyRange; if (aVal.isNullOrUndefined()) { // undefined and null returns no IDBKeyRange. keyRange.forget(aKeyRange); return NS_OK; } JS::Rooted<JSObject*> obj(aCx, aVal.isObject() ? &aVal.toObject() : nullptr); bool isValidKey = aVal.isPrimitive(); if (!isValidKey) { js::ESClass cls; if (!js::GetBuiltinClass(aCx, obj, &cls)) { return NS_ERROR_UNEXPECTED; } isValidKey = cls == js::ESClass::Array || cls == js::ESClass::Date; } if (isValidKey) { // A valid key returns an 'only' IDBKeyRange. keyRange = new IDBKeyRange(nullptr, false, false, true); nsresult rv = GetKeyFromJSVal(aCx, aVal, keyRange->Lower()); if (NS_FAILED(rv)) { return rv; } } else { MOZ_ASSERT(aVal.isObject()); // An object is not permitted unless it's another IDBKeyRange. if (NS_FAILED(UNWRAP_OBJECT(IDBKeyRange, obj, keyRange))) { return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; } } keyRange.forget(aKeyRange); return NS_OK; }
NS_IMETHODIMP nsSpeechTask::SendAudio(JS::Handle<JS::Value> aData, JS::Handle<JS::Value> aLandmarks, JSContext* aCx) { MOZ_ASSERT(XRE_IsParentProcess()); if(NS_WARN_IF(!(mStream))) { return NS_ERROR_NOT_AVAILABLE; } if(NS_WARN_IF(mStream->IsDestroyed())) { return NS_ERROR_NOT_AVAILABLE; } if(NS_WARN_IF(!(mChannels))) { return NS_ERROR_FAILURE; } if(NS_WARN_IF(!(aData.isObject()))) { return NS_ERROR_INVALID_ARG; } if (mIndirectAudio) { NS_WARNING("Can't call SendAudio from an indirect audio speech service."); return NS_ERROR_FAILURE; } JS::Rooted<JSObject*> darray(aCx, &aData.toObject()); JSAutoCompartment ac(aCx, darray); JS::Rooted<JSObject*> tsrc(aCx, nullptr); // Allow either Int16Array or plain JS Array if (JS_IsInt16Array(darray)) { tsrc = darray; } else { bool isArray; if (!JS_IsArrayObject(aCx, darray, &isArray)) { return NS_ERROR_UNEXPECTED; } if (isArray) { tsrc = JS_NewInt16ArrayFromArray(aCx, darray); } } if (!tsrc) { return NS_ERROR_DOM_TYPE_MISMATCH_ERR; } uint32_t dataLen = JS_GetTypedArrayLength(tsrc); RefPtr<mozilla::SharedBuffer> samples; { JS::AutoCheckCannotGC nogc; samples = makeSamples(JS_GetInt16ArrayData(tsrc, nogc), dataLen); } SendAudioImpl(samples, dataLen); return NS_OK; }
NS_IMETHODIMP LoadInfo::SetScriptableOriginAttributes(JSContext* aCx, JS::Handle<JS::Value> aOriginAttributes) { NeckoOriginAttributes attrs; if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { return NS_ERROR_INVALID_ARG; } mOriginAttributes = attrs; return NS_OK; }
static already_AddRefed<EventListener> ToEventListener(JSContext* aCx, JS::Handle<JS::Value> aValue) { if (NS_WARN_IF(!aValue.isObject())) { return nullptr; } JS::Rooted<JSObject*> obj(aCx, &aValue.toObject()); RefPtr<EventListener> listener = new EventListener(aCx, obj, GetIncumbentGlobal()); return listener.forget(); }
NS_IMETHODIMP WebVTTListener::OnRegion(JS::Handle<JS::Value> aRegion, JSContext* aCx) { if (!aRegion.isObject()) { return NS_ERROR_FAILURE; } TextTrackRegion* region; nsresult rv = UNWRAP_OBJECT(VTTRegion, &aRegion.toObject(), region); NS_ENSURE_SUCCESS(rv, rv); mElement->mTrack->AddRegion(*region); return NS_OK; }
NS_IMETHODIMP WebVTTListener::OnCue(JS::Handle<JS::Value> aCue, JSContext* aCx) { if (!aCue.isObject()) { return NS_ERROR_FAILURE; } TextTrackCue* cue = nullptr; nsresult rv = UNWRAP_OBJECT(VTTCue, &aCue.toObject(), cue); NS_ENSURE_SUCCESS(rv, rv); cue->SetTrackElement(mElement); mElement->mTrack->AddCue(*cue); return NS_OK; }
bool ValueHasISupportsPrivate(JS::Handle<JS::Value> v) { if (!v.isObject()) { return false; } const DOMJSClass* domClass = GetDOMClass(&v.toObject()); if (domClass) { return domClass->mDOMObjectIsISupports; } const JSClass* clasp = ::JS_GetClass(&v.toObject()); const uint32_t HAS_PRIVATE_NSISUPPORTS = JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS; return (clasp->flags & HAS_PRIVATE_NSISUPPORTS) == HAS_PRIVATE_NSISUPPORTS; }
void GetEntryHelper::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) { if(NS_WARN_IF(!aValue.isObject())) { return; } JS::Rooted<JSObject*> obj(aCx, &aValue.toObject()); // This is not the last part of the path. if (!mParts.IsEmpty()) { ContinueRunning(obj); return; } CompleteOperation(obj); }
NS_IMETHODIMP SmsFilter::SetNumbers(JSContext* aCx, JS::Handle<JS::Value> aNumbers) { if (aNumbers.isNull()) { mData.numbers().Clear(); return NS_OK; } if (!aNumbers.isObject()) { return NS_ERROR_INVALID_ARG; } JS::Rooted<JSObject*> obj(aCx, &aNumbers.toObject()); if (!JS_IsArrayObject(aCx, obj)) { return NS_ERROR_INVALID_ARG; } uint32_t size; JS_ALWAYS_TRUE(JS_GetArrayLength(aCx, obj, &size)); nsTArray<nsString> numbers; for (uint32_t i=0; i<size; ++i) { JS::Rooted<JS::Value> jsNumber(aCx); if (!JS_GetElement(aCx, obj, i, &jsNumber)) { return NS_ERROR_INVALID_ARG; } if (!jsNumber.isString()) { return NS_ERROR_INVALID_ARG; } nsDependentJSString number; number.init(aCx, jsNumber.toString()); numbers.AppendElement(number); } mData.numbers().Clear(); mData.numbers().AppendElements(numbers); return NS_OK; }
/* 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()); } } }
void RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) { AutoCancel autoCancel(this); if (!aValue.isObject()) { return; } nsRefPtr<Response> response; nsresult rv = UNWRAP_OBJECT(Response, &aValue.toObject(), response); if (NS_FAILED(rv)) { return; } nsCOMPtr<nsIInputStream> body; response->GetBody(getter_AddRefs(body)); if (NS_WARN_IF(!body) || NS_WARN_IF(response->BodyUsed())) { return; } response->SetBodyUsed(); nsCOMPtr<nsIOutputStream> responseBody; rv = mInterceptedChannel->GetResponseBody(getter_AddRefs(responseBody)); if (NS_WARN_IF(NS_FAILED(rv))) { return; } nsAutoPtr<RespondWithClosure> closure(new RespondWithClosure(mInterceptedChannel)); nsCOMPtr<nsIEventTarget> stsThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); if (NS_WARN_IF(!stsThread)) { return; } rv = NS_AsyncCopy(body, responseBody, stsThread, NS_ASYNCCOPY_VIA_READSEGMENTS, 4096, RespondWithCopyComplete, closure.forget()); if (NS_WARN_IF(NS_FAILED(rv))) { return; } autoCancel.Reset(); }
bool CallbackObject::CallSetup::ShouldRethrowException(JS::Handle<JS::Value> aException) { if (mExceptionHandling == eRethrowExceptions) { if (!mCompartment) { // Caller didn't ask us to filter for only exceptions we subsume. return true; } // On workers, we don't have nsIPrincipals to work with. But we also only // have one compartment, so check whether mCompartment is the same as the // current compartment of mCx. if (mCompartment == js::GetContextCompartment(mCx)) { return true; } MOZ_ASSERT(NS_IsMainThread()); // At this point mCx is in the compartment of our unwrapped callback, so // just check whether the principal of mCompartment subsumes that of the // current compartment/global of mCx. nsIPrincipal* callerPrincipal = nsJSPrincipals::get(JS_GetCompartmentPrincipals(mCompartment)); nsIPrincipal* calleePrincipal = nsContentUtils::SubjectPrincipal(); if (callerPrincipal->SubsumesConsideringDomain(calleePrincipal)) { return true; } } MOZ_ASSERT(mCompartment); // Now we only want to throw an exception to the caller if the object that was // thrown is in the caller compartment (which we stored in mCompartment). if (!aException.isObject()) { return false; } JS::Rooted<JSObject*> obj(mCx, &aException.toObject()); obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false); return js::GetObjectCompartment(obj) == mCompartment; }
nsresult SystemWorkerManager::RegisterNfcWorker(JS::Handle<JS::Value> aWorker, JSContext* aCx) { #ifndef MOZ_NFC return NS_ERROR_NOT_IMPLEMENTED; #else NS_ENSURE_TRUE(aWorker.isObject(), NS_ERROR_UNEXPECTED); JSAutoCompartment ac(aCx, &aWorker.toObject()); WorkerCrossThreadDispatcher* wctd = GetWorkerCrossThreadDispatcher(aCx, aWorker); if (!wctd) { NS_WARNING("Failed to GetWorkerCrossThreadDispatcher for nfc"); return NS_ERROR_FAILURE; } return NfcConsumer::Register(wctd); #endif // MOZ_NFC }
nsresult SystemWorkerManager::RegisterRilWorker(unsigned int aClientId, JS::Handle<JS::Value> aWorker, JSContext *aCx) { #ifndef MOZ_B2G_RIL return NS_ERROR_NOT_IMPLEMENTED; #else NS_ENSURE_TRUE(aWorker.isObject(), NS_ERROR_UNEXPECTED); JSAutoCompartment ac(aCx, &aWorker.toObject()); WorkerCrossThreadDispatcher *wctd = GetWorkerCrossThreadDispatcher(aCx, aWorker); if (!wctd) { NS_WARNING("Failed to GetWorkerCrossThreadDispatcher for ril"); return NS_ERROR_FAILURE; } return RilWorker::Register(aClientId, wctd); #endif // MOZ_B2G_RIL }
NS_IMETHODIMP nsSpeechTask::SendAudio(JS::Handle<JS::Value> aData, JS::Handle<JS::Value> aLandmarks, JSContext* aCx) { MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); NS_ENSURE_TRUE(mStream, NS_ERROR_NOT_AVAILABLE); NS_ENSURE_FALSE(mStream->IsDestroyed(), NS_ERROR_NOT_AVAILABLE); NS_ENSURE_TRUE(mChannels, NS_ERROR_FAILURE); NS_ENSURE_TRUE(aData.isObject(), NS_ERROR_INVALID_ARG); if (mIndirectAudio) { NS_WARNING("Can't call SendAudio from an indirect audio speech service."); return NS_ERROR_FAILURE; } JS::Rooted<JSObject*> darray(aCx, &aData.toObject()); JSAutoCompartment ac(aCx, darray); JS::Rooted<JSObject*> tsrc(aCx, nullptr); // Allow either Int16Array or plain JS Array if (JS_IsInt16Array(darray)) { tsrc = darray; } else if (JS_IsArrayObject(aCx, darray)) { tsrc = JS_NewInt16ArrayFromArray(aCx, darray); } if (!tsrc) { return NS_ERROR_DOM_TYPE_MISMATCH_ERR; } SendAudioImpl(JS_GetInt16ArrayData(tsrc), JS_GetTypedArrayLength(tsrc)); return NS_OK; }
void PaymentRequestUpdateEvent::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) { MOZ_ASSERT(aCx); MOZ_ASSERT(mRequest); if (NS_WARN_IF(!aValue.isObject()) || !mWaitForUpdate) { return; } // Converting value to a PaymentDetailsUpdate dictionary PaymentDetailsUpdate details; if (!details.Init(aCx, aValue)) { mRequest->AbortUpdate(NS_ERROR_TYPE_ERR); JS_ClearPendingException(aCx); return; } // Validate and canonicalize the details // requestShipping must be true here. PaymentRequestUpdateEvent is only // dispatched when shippingAddress/shippingOption is changed, and it also means // Options.RequestShipping must be true while creating the corresponding // PaymentRequest. nsresult rv = mRequest->IsValidDetailsUpdate(details, true/*aRequestShipping*/); if (NS_FAILED(rv)) { mRequest->AbortUpdate(rv); return; } // Update the PaymentRequest with the new details if (NS_FAILED(mRequest->UpdatePayment(aCx, details))) { mRequest->AbortUpdate(NS_ERROR_DOM_ABORT_ERR); return; } mWaitForUpdate = false; mRequest->SetUpdating(false); }
void CompareCache::ManageCacheResult(JSContext* aCx, JS::Handle<JS::Value> aValue) { AssertIsOnMainThread(); if (NS_WARN_IF(!aValue.isObject())) { mManager->CacheFinished(NS_ERROR_FAILURE, false); return; } JS::Rooted<JSObject*> obj(aCx, &aValue.toObject()); if (NS_WARN_IF(!obj)) { mManager->CacheFinished(NS_ERROR_FAILURE, false); return; } Cache* cache = nullptr; nsresult rv = UNWRAP_OBJECT(Cache, obj, cache); if (NS_WARN_IF(NS_FAILED(rv))) { mManager->CacheFinished(rv, false); return; } RequestOrUSVString request; request.SetAsUSVString().Rebind(mURL.Data(), mURL.Length()); ErrorResult error; CacheQueryOptions params; RefPtr<Promise> promise = cache->Match(request, params, error); if (NS_WARN_IF(error.Failed())) { mManager->CacheFinished(error.StealNSResult(), false); return; } promise->AppendNativeHandler(this); mState = WaitingForValue; }
// This class manages 2 promises: 1 is to retrieve Cache object, and 2 is to // Put the value in the cache. For this reason we have mState to know what // callback we are handling. void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override { AssertIsOnMainThread(); MOZ_ASSERT(mCallback); if (mState == WaitingForOpen) { if (NS_WARN_IF(!aValue.isObject())) { Fail(NS_ERROR_FAILURE); return; } JS::Rooted<JSObject*> obj(aCx, &aValue.toObject()); if (NS_WARN_IF(!obj)) { Fail(NS_ERROR_FAILURE); return; } Cache* cache = nullptr; nsresult rv = UNWRAP_OBJECT(Cache, obj, cache); if (NS_WARN_IF(NS_FAILED(rv))) { Fail(rv); return; } // Just to be safe. RefPtr<Cache> kungfuDeathGrip = cache; WriteToCache(cache); return; } MOZ_ASSERT(mState == WaitingForPut); mCallback->ComparisonResult(NS_OK, false /* aIsEqual */, mNewCacheName, mMaxScope); Cleanup(); }
void RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) { AutoCancel autoCancel(this, mRequestURL); if (!aValue.isObject()) { NS_WARNING("FetchEvent::RespondWith was passed a promise resolved to a non-Object value"); nsCString sourceSpec; uint32_t line = 0; uint32_t column = 0; nsString valueString; ExtractErrorValues(aCx, aValue, sourceSpec, &line, &column, valueString); autoCancel.SetCancelMessageAndLocation(sourceSpec, line, column, NS_LITERAL_CSTRING("InterceptedNonResponseWithURL"), mRequestURL, valueString); return; } RefPtr<Response> response; nsresult rv = UNWRAP_OBJECT(Response, &aValue.toObject(), response); if (NS_FAILED(rv)) { nsCString sourceSpec; uint32_t line = 0; uint32_t column = 0; nsString valueString; ExtractErrorValues(aCx, aValue, sourceSpec, &line, &column, valueString); autoCancel.SetCancelMessageAndLocation(sourceSpec, line, column, NS_LITERAL_CSTRING("InterceptedNonResponseWithURL"), mRequestURL, valueString); return; } WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); worker->AssertIsOnWorkerThread(); // Section "HTTP Fetch", step 3.3: // If one of the following conditions is true, return a network error: // * response's type is "error". // * request's mode is not "no-cors" and response's type is "opaque". // * request's redirect mode is not "manual" and response's type is // "opaqueredirect". // * request's redirect mode is not "follow" and response's url list // has more than one item. if (response->Type() == ResponseType::Error) { autoCancel.SetCancelMessage( NS_LITERAL_CSTRING("InterceptedErrorResponseWithURL"), mRequestURL); return; } MOZ_ASSERT_IF(mIsClientRequest, mRequestMode == RequestMode::Same_origin || mRequestMode == RequestMode::Navigate); if (response->Type() == ResponseType::Opaque && mRequestMode != RequestMode::No_cors) { uint32_t mode = static_cast<uint32_t>(mRequestMode); NS_ConvertASCIItoUTF16 modeString(RequestModeValues::strings[mode].value, RequestModeValues::strings[mode].length); autoCancel.SetCancelMessage( NS_LITERAL_CSTRING("BadOpaqueInterceptionRequestModeWithURL"), mRequestURL, modeString); return; } if (mRequestRedirectMode != RequestRedirect::Manual && response->Type() == ResponseType::Opaqueredirect) { autoCancel.SetCancelMessage( NS_LITERAL_CSTRING("BadOpaqueRedirectInterceptionWithURL"), mRequestURL); return; } if (mRequestRedirectMode != RequestRedirect::Follow && response->Redirected()) { autoCancel.SetCancelMessage( NS_LITERAL_CSTRING("BadRedirectModeInterceptionWithURL"), mRequestURL); return; } if (NS_WARN_IF(response->BodyUsed())) { autoCancel.SetCancelMessage( NS_LITERAL_CSTRING("InterceptedUsedResponseWithURL"), mRequestURL); return; } RefPtr<InternalResponse> ir = response->GetInternalResponse(); if (NS_WARN_IF(!ir)) { return; } // When an opaque response is encountered, we need the original channel's principal // to reflect the final URL. Non-opaque responses are either same-origin or CORS-enabled // cross-origin responses, which are treated as same-origin by consumers. nsCString responseURL; if (response->Type() == ResponseType::Opaque) { responseURL = ir->GetUnfilteredURL(); if (NS_WARN_IF(responseURL.IsEmpty())) { return; } } nsAutoPtr<RespondWithClosure> closure(new RespondWithClosure(mInterceptedChannel, mRegistration, ir, worker->GetChannelInfo(), mScriptSpec, responseURL, mRequestURL, mRespondWithScriptSpec, mRespondWithLineNumber, mRespondWithColumnNumber)); nsCOMPtr<nsIInputStream> body; ir->GetUnfilteredBody(getter_AddRefs(body)); // Errors and redirects may not have a body. if (body) { response->SetBodyUsed(); nsCOMPtr<nsIOutputStream> responseBody; rv = mInterceptedChannel->GetResponseBody(getter_AddRefs(responseBody)); if (NS_WARN_IF(NS_FAILED(rv))) { return; } const uint32_t kCopySegmentSize = 4096; // Depending on how the Response passed to .respondWith() was created, we may // get a non-buffered input stream. In addition, in some configurations the // destination channel's output stream can be unbuffered. We wrap the output // stream side here so that NS_AsyncCopy() works. Wrapping the output side // provides the most consistent operation since there are fewer stream types // we are writing to. The input stream can be a wide variety of concrete // objects which may or many not play well with NS_InputStreamIsBuffered(). if (!NS_OutputStreamIsBuffered(responseBody)) { nsCOMPtr<nsIOutputStream> buffered; rv = NS_NewBufferedOutputStream(getter_AddRefs(buffered), responseBody, kCopySegmentSize); if (NS_WARN_IF(NS_FAILED(rv))) { return; } responseBody = buffered; } nsCOMPtr<nsIEventTarget> stsThread = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); if (NS_WARN_IF(!stsThread)) { return; } // XXXnsm, Fix for Bug 1141332 means that if we decide to make this // streaming at some point, we'll need a different solution to that bug. rv = NS_AsyncCopy(body, responseBody, stsThread, NS_ASYNCCOPY_VIA_WRITESEGMENTS, kCopySegmentSize, RespondWithCopyComplete, closure.forget()); if (NS_WARN_IF(NS_FAILED(rv))) { return; } } else { RespondWithCopyComplete(closure.forget(), NS_OK); } MOZ_ASSERT(!closure); autoCancel.Reset(); mRequestWasHandled = true; }
void CompareCache::ManageValueResult(JSContext* aCx, JS::Handle<JS::Value> aValue) { AssertIsOnMainThread(); // The cache returns undefined if the object is not stored. if (aValue.isUndefined()) { mManager->CacheFinished(NS_OK, false); return; } MOZ_ASSERT(aValue.isObject()); JS::Rooted<JSObject*> obj(aCx, &aValue.toObject()); if (NS_WARN_IF(!obj)) { mManager->CacheFinished(NS_ERROR_FAILURE, false); return; } Response* response = nullptr; nsresult rv = UNWRAP_OBJECT(Response, obj, response); if (NS_WARN_IF(NS_FAILED(rv))) { mManager->CacheFinished(rv, false); return; } MOZ_ASSERT(response->Ok()); nsCOMPtr<nsIInputStream> inputStream; response->GetBody(getter_AddRefs(inputStream)); MOZ_ASSERT(inputStream); MOZ_ASSERT(!mPump); rv = NS_NewInputStreamPump(getter_AddRefs(mPump), inputStream); if (NS_WARN_IF(NS_FAILED(rv))) { mManager->CacheFinished(rv, false); return; } nsCOMPtr<nsIStreamLoader> loader; rv = NS_NewStreamLoader(getter_AddRefs(loader), this); if (NS_WARN_IF(NS_FAILED(rv))) { mManager->CacheFinished(rv, false); return; } rv = mPump->AsyncRead(loader, nullptr); if (NS_WARN_IF(NS_FAILED(rv))) { mPump = nullptr; mManager->CacheFinished(rv, false); return; } nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(mPump); if (rr) { nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); rv = rr->RetargetDeliveryTo(sts); if (NS_WARN_IF(NS_FAILED(rv))) { mPump = nullptr; mManager->CacheFinished(rv, false); return; } } }
NS_IMETHODIMP TCPSocketParent::SendEvent(const nsAString& aType, JS::Handle<JS::Value> aDataVal, const nsAString& aReadyState, JSContext* aCx) { if (!mIPCOpen) { NS_WARNING("Dropping callback due to no IPC connection"); return NS_OK; } CallbackData data; if (aDataVal.isString()) { JSString* jsstr = aDataVal.toString(); nsAutoJSString str; if (!str.init(aCx, jsstr)) { FireInteralError(this, __LINE__); return NS_ERROR_OUT_OF_MEMORY; } data = SendableData(str); } else if (aDataVal.isUndefined() || aDataVal.isNull()) { data = mozilla::void_t(); } else if (aDataVal.isObject()) { JS::Rooted<JSObject *> obj(aCx, &aDataVal.toObject()); if (JS_IsArrayBufferObject(obj)) { FallibleTArray<uint8_t> fallibleArr; uint32_t errLine = 0; do { JS::AutoCheckCannotGC nogc; uint32_t nbytes = JS_GetArrayBufferByteLength(obj); uint8_t* buffer = JS_GetArrayBufferData(obj, nogc); if (!buffer) { errLine = __LINE__; break; } if (!fallibleArr.InsertElementsAt(0, buffer, nbytes, fallible)) { errLine = __LINE__; break; } } while (false); if (errLine) { FireInteralError(this, errLine); return NS_ERROR_OUT_OF_MEMORY; } InfallibleTArray<uint8_t> arr; arr.SwapElements(fallibleArr); data = SendableData(arr); } else { nsAutoJSString name; JS::Rooted<JS::Value> val(aCx); if (!JS_GetProperty(aCx, obj, "name", &val)) { NS_ERROR("No name property on supposed error object"); } else if (val.isString()) { if (!name.init(aCx, val.toString())) { NS_WARNING("couldn't initialize string"); } } data = TCPError(name); } } else { NS_ERROR("Unexpected JS value encountered"); FireInteralError(this, __LINE__); return NS_ERROR_FAILURE; } mozilla::unused << PTCPSocketParent::SendCallback(nsString(aType), data, nsString(aReadyState)); return NS_OK; }
void RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) { AutoCancel autoCancel(this); if (!aValue.isObject()) { NS_WARNING("FetchEvent::RespondWith was passed a promise resolved to a non-Object value"); return; } RefPtr<Response> response; nsresult rv = UNWRAP_OBJECT(Response, &aValue.toObject(), response); if (NS_FAILED(rv)) { return; } WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); worker->AssertIsOnWorkerThread(); // Allow opaque response interception to be disabled until we can ensure the // security implications are not a complete disaster. if (response->Type() == ResponseType::Opaque && !worker->OpaqueInterceptionEnabled()) { autoCancel.SetCancelStatus(NS_ERROR_OPAQUE_INTERCEPTION_DISABLED); return; } // Section "HTTP Fetch", step 2.2: // If one of the following conditions is true, return a network error: // * response's type is "error". // * request's mode is not "no-cors" and response's type is "opaque". // * request is not a navigation request and response's type is // "opaqueredirect". if (response->Type() == ResponseType::Error) { autoCancel.SetCancelStatus(NS_ERROR_INTERCEPTED_ERROR_RESPONSE); return; } MOZ_ASSERT_IF(mIsClientRequest, mRequestMode == RequestMode::Same_origin); if (response->Type() == ResponseType::Opaque && mRequestMode != RequestMode::No_cors) { autoCancel.SetCancelStatus(NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE); return; } if (!mIsNavigationRequest && response->Type() == ResponseType::Opaqueredirect) { autoCancel.SetCancelStatus(NS_ERROR_BAD_OPAQUE_REDIRECT_INTERCEPTION); return; } if (NS_WARN_IF(response->BodyUsed())) { autoCancel.SetCancelStatus(NS_ERROR_INTERCEPTED_USED_RESPONSE); return; } RefPtr<InternalResponse> ir = response->GetInternalResponse(); if (NS_WARN_IF(!ir)) { return; } nsAutoPtr<RespondWithClosure> closure(new RespondWithClosure(mInterceptedChannel, ir, worker->GetChannelInfo(), mScriptSpec)); nsCOMPtr<nsIInputStream> body; ir->GetUnfilteredBody(getter_AddRefs(body)); // Errors and redirects may not have a body. if (body) { response->SetBodyUsed(); nsCOMPtr<nsIOutputStream> responseBody; rv = mInterceptedChannel->GetResponseBody(getter_AddRefs(responseBody)); if (NS_WARN_IF(NS_FAILED(rv))) { return; } nsCOMPtr<nsIEventTarget> stsThread = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); if (NS_WARN_IF(!stsThread)) { return; } // XXXnsm, Fix for Bug 1141332 means that if we decide to make this // streaming at some point, we'll need a different solution to that bug. rv = NS_AsyncCopy(body, responseBody, stsThread, NS_ASYNCCOPY_VIA_READSEGMENTS, 4096, RespondWithCopyComplete, closure.forget()); if (NS_WARN_IF(NS_FAILED(rv))) { return; } } else { RespondWithCopyComplete(closure.forget(), NS_OK); } MOZ_ASSERT(!closure); autoCancel.Reset(); mRequestWasHandled = true; }
bool IsWitness(JS::Handle<JS::Value> v) { return v.isObject() && JS_GetClass(&v.toObject()) == &sWitnessClass; }
void RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) { AutoCancel autoCancel(this); if (!aValue.isObject()) { NS_WARNING("FetchEvent::RespondWith was passed a promise resolved to a non-Object value"); return; } nsRefPtr<Response> response; nsresult rv = UNWRAP_OBJECT(Response, &aValue.toObject(), response); if (NS_FAILED(rv)) { return; } WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); worker->AssertIsOnWorkerThread(); // Allow opaque response interception to be disabled until we can ensure the // security implications are not a complete disaster. if (response->Type() == ResponseType::Opaque && !worker->OpaqueInterceptionEnabled()) { return; } // Section 4.2, step 2.2 "If either response's type is "opaque" and request's // mode is not "no-cors" or response's type is error, return a network error." if (((response->Type() == ResponseType::Opaque) && (mRequestMode != RequestMode::No_cors)) || response->Type() == ResponseType::Error) { return; } if (NS_WARN_IF(response->BodyUsed())) { return; } nsRefPtr<InternalResponse> ir = response->GetInternalResponse(); if (NS_WARN_IF(!ir)) { return; } nsAutoPtr<RespondWithClosure> closure( new RespondWithClosure(mInterceptedChannel, ir, worker->GetChannelInfo())); nsCOMPtr<nsIInputStream> body; ir->GetInternalBody(getter_AddRefs(body)); // Errors and redirects may not have a body. if (body) { response->SetBodyUsed(); nsCOMPtr<nsIOutputStream> responseBody; rv = mInterceptedChannel->GetResponseBody(getter_AddRefs(responseBody)); if (NS_WARN_IF(NS_FAILED(rv))) { return; } nsCOMPtr<nsIEventTarget> stsThread = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); if (NS_WARN_IF(!stsThread)) { return; } // XXXnsm, Fix for Bug 1141332 means that if we decide to make this // streaming at some point, we'll need a different solution to that bug. rv = NS_AsyncCopy(body, responseBody, stsThread, NS_ASYNCCOPY_VIA_READSEGMENTS, 4096, RespondWithCopyComplete, closure.forget()); if (NS_WARN_IF(NS_FAILED(rv))) { return; } } else { RespondWithCopyComplete(closure.forget(), NS_OK); } MOZ_ASSERT(!closure); autoCancel.Reset(); }