/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
template <typename... Params> void AsyncLog(nsIInterceptedChannel* aInterceptedChannel, const nsACString& aRespondWithScriptSpec,
uint32_t aRespondWithLineNumber,
uint32_t aRespondWithColumnNumber, // We have to list one explicit string so that calls with an // nsTArray of params won't end up in here. const nsACString& aMessageName, const nsAString& aFirstParam,
Params&&... aParams) {
nsTArray<nsString> paramsList(sizeof...(Params) + 1);
StringArrayAppender::Append(paramsList, sizeof...(Params) + 1, aFirstParam,
std::forward<Params>(aParams)...);
AsyncLog(aInterceptedChannel, aRespondWithScriptSpec, aRespondWithLineNumber,
aRespondWithColumnNumber, aMessageName, paramsList);
}
if (!CSPPermitsResponse(loadInfo)) {
mChannel->CancelInterception(NS_ERROR_CONTENT_BLOCKED); return NS_OK;
}
ChannelInfo channelInfo; if (mInternalResponse->GetChannelInfo().IsInitialized()) {
channelInfo = mInternalResponse->GetChannelInfo();
} else { // We are dealing with a synthesized response here, so fall back to the // channel info for the worker script.
channelInfo = mWorkerChannelInfo;
}
rv = mChannel->SetChannelInfo(&channelInfo); if (NS_WARN_IF(NS_FAILED(rv))) {
mChannel->CancelInterception(NS_ERROR_INTERCEPTION_FAILED); return NS_OK;
}
AutoTArray<InternalHeaders::Entry, 5> entries;
mInternalResponse->UnfilteredHeaders()->GetEntries(entries); for (uint32_t i = 0; i < entries.Length(); ++i) {
mChannel->SynthesizeHeader(entries[i].mName, entries[i].mValue);
}
auto castLoadInfo = static_cast<mozilla::net::LoadInfo*>(loadInfo.get());
castLoadInfo->SynthesizeServiceWorkerTainting(
mInternalResponse->GetTainting());
// Get the preferred alternative data type of outter channel
nsAutoCString preferredAltDataType(""_ns);
nsCOMPtr<nsICacheInfoChannel> outerChannel =
do_QueryInterface(underlyingChannel); if (outerChannel &&
!outerChannel->PreferredAlternativeDataTypes().IsEmpty()) { // TODO: handle multiple types properly.
preferredAltDataType.Assign(
outerChannel->PreferredAlternativeDataTypes()[0].type());
}
// Get the alternative data type saved in the InternalResponse
nsAutoCString altDataType;
nsCOMPtr<nsICacheInfoChannel> cacheInfoChannel =
mInternalResponse->TakeCacheInfoChannel().get(); if (cacheInfoChannel) {
cacheInfoChannel->GetAlternativeDataType(altDataType);
}
nsCOMPtr<nsIInputStream> body; if (preferredAltDataType.Equals(altDataType)) {
body = mInternalResponse->TakeAlternativeBody();
} if (!body) {
mInternalResponse->GetUnfilteredBody(getter_AddRefs(body));
}
RefPtr<BodyCopyHandle> copyHandle;
copyHandle = new BodyCopyHandle(std::move(mClosure));
// This function steals the error message from a ErrorResult. void SetCancelErrorResult(JSContext* aCx, ErrorResult& aRv) {
MOZ_DIAGNOSTIC_ASSERT(aRv.Failed());
MOZ_DIAGNOSTIC_ASSERT(!JS_IsExceptionPending(aCx));
// Storing the error as exception in the JSContext. if (!aRv.MaybeSetPendingException(aCx)) { return;
}
MOZ_ASSERT(!aRv.Failed());
// Let's take the pending exception.
JS::ExceptionStack exnStack(aCx); if (!JS::StealPendingExceptionStack(aCx, &exnStack)) { return;
}
// Converting the exception in a JS::ErrorReportBuilder.
JS::ErrorReportBuilder report(aCx); if (!report.init(aCx, exnStack, JS::ErrorReportBuilder::WithSideEffects)) {
JS_ClearPendingException(aCx); return;
}
// 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("InterceptedErrorResponseWithURL"_ns,
mRequestURL); return;
}
if (NS_WARN_IF(response->BodyUsed())) {
autoCancel.SetCancelMessage("InterceptedUsedResponseWithURL"_ns,
mRequestURL); return;
}
SafeRefPtr<InternalResponse> ir = response->GetInternalResponse(); if (NS_WARN_IF(!ir)) { return;
}
// An extra safety check to make sure our invariant that opaque and cors // responses always have a URL does not break. if (NS_WARN_IF((response->Type() == ResponseType::Opaque ||
response->Type() == ResponseType::Cors) &&
ir->GetUnfilteredURL().IsEmpty())) {
MOZ_DIAGNOSTIC_CRASH("Cors or opaque Response without a URL"); return;
}
if (mRequestMode == RequestMode::Same_origin &&
response->Type() == ResponseType::Cors) { // XXXtt: Will have a pref to enable the quirk response in bug 1419684. // The variadic template provided by StringArrayAppender requires exactly // an nsString.
NS_ConvertUTF8toUTF16 responseURL(ir->GetUnfilteredURL());
autoCancel.SetCancelMessage("CorsResponseForSameOriginRequest"_ns,
mRequestURL, responseURL); return;
}
// Propagate the URL to the content if the request mode is not "navigate". // Note that, we only reflect the final URL if the response.redirected is // false. We propagate all the URLs if the response.redirected is true.
nsCString responseURL; if (mRequestMode != RequestMode::Navigate) {
responseURL = ir->GetUnfilteredURL();
// Similar to how we apply the request fragment to redirects automatically // we also want to apply it automatically when propagating the response // URL from a service worker interception. Currently response.url strips // the fragment, so this will never conflict with an existing fragment // on the response. In the future we will have to check for a response // fragment and avoid overriding in that case. if (!mRequestFragment.IsEmpty() && !responseURL.IsEmpty()) {
MOZ_ASSERT(!responseURL.Contains('#'));
responseURL.Append("#"_ns);
responseURL.Append(mRequestFragment);
}
}
nsCOMPtr<nsIInputStream> body;
ir->GetUnfilteredBody(getter_AddRefs(body)); // Errors and redirects may not have a body. if (body) {
ErrorResult error;
response->SetBodyUsed(aCx, error);
error.WouldReportJSException(); if (NS_WARN_IF(error.Failed())) {
autoCancel.SetCancelErrorResult(aCx, error); return;
}
}
void RespondWithHandler::CancelRequest(nsresult aStatus) {
nsCOMPtr<nsIRunnable> runnable = new CancelChannelRunnable(mInterceptedChannel, mRegistration, aStatus); // Note, this may run off the worker thread during worker termination.
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); if (worker) {
MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(runnable.forget()));
} else {
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable.forget()));
}
mRequestWasHandled = true;
}
// Record where respondWith() was called in the script so we can include the // information in any error reporting. We should be guaranteed not to get // a file:// string here because service workers require http/https. auto location = JSCallingLocation::Get(aCx);
SafeRefPtr<InternalRequest> ir = mRequest->GetInternalRequest();
if (mChannel) {
RefPtr<RespondWithHandler> handler = new RespondWithHandler(
mChannel, mRegistration, mRequest->Mode(), ir->IsClientRequest(),
mRequest->Redirect(), mScriptSpec, NS_ConvertUTF8toUTF16(requestURL),
ir->GetFragment(), location.FileName(), location.mLine,
location.mColumn);
aArg.AppendNativeHandler(handler); // mRespondWithHandler can be nullptr for self-dispatched FetchEvent.
} elseif (mRespondWithHandler) {
mRespondWithHandler->RespondWithCalledAt(location.FileName(),
location.mLine, location.mColumn);
aArg.AppendNativeHandler(mRespondWithHandler);
mRespondWithHandler = nullptr;
}
if (!WaitOnPromise(aArg)) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
}
}
void FetchEvent::PreventDefault(JSContext* aCx, CallerType aCallerType) {
MOZ_ASSERT(aCx);
MOZ_ASSERT(aCallerType != CallerType::System, "Since when do we support system-principal service workers?");
if (!mPreventDefaultLocation) { // Note when the FetchEvent might have been canceled by script, but don't // actually log the location until we are sure it matters. This is // determined in ServiceWorkerPrivate.cpp. We only remember the first // call to preventDefault() as its the most likely to have actually canceled // the event.
mPreventDefaultLocation = JSCallingLocation::Get(aCx);
}
// only use the extracted location if we found one if (!spec.IsEmpty()) {
mLocation.mResource = AsVariant(std::move(spec));
mLocation.mLine = line;
mLocation.mColumn = column;
}
// TODO: Make the error message a localized string. (bug 1222720)
nsString message;
message.AppendLiteral( "Service worker event waitUntil() was passed a " "promise that rejected with '");
message.Append(mRejectValue);
message.AppendLiteral("'.");
// Note, there is a corner case where this won't report to the window // that triggered the error. Consider a navigation fetch event that // rejects waitUntil() without holding respondWith() open. In this case // there is no controlling document yet, the window did call .register() // because there is no documeny yet, and the navigation is no longer // being intercepted.
bool ExtendableEvent::ExtensionsHandler::GetDispatchFlag() const { // mExtendableEvent should set itself as nullptr in its destructor, and we // can't be dispatching an event that doesn't exist, so this should work for // as long as it's not needed to determine whether the event is still alive, // which seems unlikely. if (!mExtendableEvent) { returnfalse;
}
if (!WaitOnPromise(aPromise)) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return;
}
// Append our handler to each waitUntil promise separately so we // can record the location in script where waitUntil was called.
RefPtr<WaitUntilHandler> handler = new WaitUntilHandler(GetCurrentThreadWorkerPrivate(), aCx);
aPromise.AppendNativeHandler(handler);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.