/* -*- 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/. */
// Only compare the attributes, not the spec part of the principal. // The scope comparison above already covers the origin and codebase // principals include the full path in their spec which is not what // we want here. return aLeft.scope() == aRight.scope() &&
leftPrincipal.attrs() == rightPrincipal.attrs();
}
nsCOMPtr<nsIEventTarget> target =
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
MOZ_ASSERT(target, "Must have stream transport service");
nsCOMPtr<nsIRunnable> runnable =
NewRunnableMethod("dom::ServiceWorkerRegistrar::LoadData", this,
&ServiceWorkerRegistrar::LoadData);
nsresult rv = target->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL); if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch the LoadDataRunnable."); returnfalse;
}
mMonitor.AssertCurrentThreadOwns(); while (!mDataLoaded) {
mMonitor.Wait();
}
return mDataLoaded;
}
nsresult ServiceWorkerRegistrar::ReadData() { // We cannot assert about the correct thread because normally this method // runs on a IO thread, but in gTests we call it from the main-thread.
entry->navigationPreloadState() = gDefaultNavigationPreloadState;
} else {
MOZ_ASSERT_UNREACHABLE("Should never get here!");
}
#undef GET_LINE
rv = lineInputStream->ReadLine(line, &hasMoreLines); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
if (!line.EqualsLiteral(SERVICEWORKERREGISTRAR_TERMINATOR)) { return NS_ERROR_FAILURE;
}
}
stream->Close();
// We currently only call this at startup where we block the main thread // preventing further operation until it completes, however take the lock // in case that changes
{
MonitorAutoLock lock(mMonitor); // Copy data over to mData. for (uint32_t i = 0; i < tmpData.Length(); ++i) { // Older versions could sometimes write out empty, useless entries. // Prune those here. if (!ServiceWorkerRegistrationDataIsValid(tmpData[i])) { continue;
}
bool match = false; if (dedupe) {
MOZ_ASSERT(overwrite); // If this is an old profile, then we might need to deduplicate. In // theory this can be removed in the future (Bug 1248449) for (uint32_t j = 0; j < mData.Length(); ++j) { // Use same comparison as RegisterServiceWorker. Scope contains // basic origin information. Combine with any principal attributes. if (Equivalent(tmpData[i], mData[j])) { // Last match wins, just like legacy loading used to do in // the ServiceWorkerManager.
mData[j] = tmpData[i]; // Dupe found, so overwrite file with reduced list.
match = true; break;
}
}
} else { #ifdef DEBUG // Otherwise assert no duplications in debug builds. for (uint32_t j = 0; j < mData.Length(); ++j) {
MOZ_ASSERT(!Equivalent(tmpData[i], mData[j]));
} #endif
} if (!match) {
mData.AppendElement(tmpData[i]);
}
}
} // Overwrite previous version. // Cannot call SaveData directly because gtest uses main-thread.
// XXX NOTE: if we could be accessed multi-threaded here, we would need to // find a way to lock around access to mData. Since we can't, suppress the // thread-safety warnings.
MOZ_PUSH_IGNORE_THREAD_SAFETY if (overwrite && NS_FAILED(WriteData(mData))) {
NS_WARNING("Failed to write data for the ServiceWorker Registations.");
DeleteData();
}
MOZ_POP_THREAD_SAFETY
return NS_OK;
}
void ServiceWorkerRegistrar::DeleteData() { // We cannot assert about the correct thread because normally this method // runs on a IO thread, but in gTests we call it from the main-thread.
nsCOMPtr<nsIFile> file;
{
MonitorAutoLock lock(mMonitor);
mData.Clear();
if (!mProfileDir) { return;
}
nsresult rv = mProfileDir->Clone(getter_AddRefs(file)); if (NS_WARN_IF(NS_FAILED(rv))) { return;
}
}
nsresult rv = file->Append(nsLiteralString(SERVICEWORKERREGISTRAR_FILE)); if (NS_WARN_IF(NS_FAILED(rv))) { return;
}
rv = file->Remove(false); if (rv == NS_ERROR_FILE_NOT_FOUND) { return;
}
if (NS_WARN_IF(NS_FAILED(rv))) { return;
}
}
void ServiceWorkerRegistrar::RegisterServiceWorkerInternal( const ServiceWorkerRegistrationData& aData) { bool found = false; for (uint32_t i = 0, len = mData.Length(); i < len; ++i) { if (Equivalent(aData, mData[i])) {
found = true;
mData[i] = aData; break;
}
}
if (!found) {
MOZ_ASSERT(ServiceWorkerRegistrationDataIsValid(aData));
mData.AppendElement(aData);
}
mDataGeneration = GetNextGeneration();
}
class ServiceWorkerRegistrarSaveDataRunnable final : public Runnable {
nsCOMPtr<nsIEventTarget> mEventTarget; const nsTArray<ServiceWorkerRegistrationData> mData; const uint32_t mGeneration;
nsresult rv = WriteData(aData); if (NS_FAILED(rv)) {
NS_WARNING("Failed to write data for the ServiceWorker Registations."); // Don't touch the file or in-memory state. Writing files can // sometimes fail due to virus scanning, etc. We should just leave // things as is so the next save operation can pick up any changes // without losing data.
} return rv;
}
// Check for shutdown before possibly triggering any more saves // runnables.
MaybeScheduleShutdownCompleted(); if (mShuttingDown) { return;
}
// If we got a valid generation, then the save was successful. if (aFileGeneration != kInvalidGeneration) { // Update the file generation. We also check to see if we // can reset the generation back to zero if the file and data // are now in sync. This allows us to avoid dealing with wrap // around of the generation count.
mFileGeneration = aFileGeneration;
MaybeResetGeneration();
// Successful write resets the retry count.
mRetryCount = 0;
// Possibly schedule another save operation if more data // has come in while processing this one.
MaybeScheduleSaveData();
return;
}
// Otherwise, the save failed since the generation is invalid. We // want to retry the save, but only a limited number of times. staticconst uint32_t kMaxRetryCount = 2; if (mRetryCount >= kMaxRetryCount) { return;
}
bool ServiceWorkerRegistrar::IsSupportedVersion( const nsACString& aVersion) const {
uint32_t numVersions = std::size(gSupportedRegistrarVersions); for (uint32_t i = 0; i < numVersions; i++) { if (aVersion.EqualsASCII(gSupportedRegistrarVersions[i])) { returntrue;
}
} returnfalse;
}
nsresult ServiceWorkerRegistrar::WriteData( const nsTArray<ServiceWorkerRegistrationData>& aData) { // We cannot assert about the correct thread because normally this method // runs on a IO thread, but in gTests we call it from the main-thread.
if (count != buffer.Length()) { return NS_ERROR_UNEXPECTED;
}
for (uint32_t i = 0, len = aData.Length(); i < len; ++i) { // We have an assertion further up the stack, but as a last // resort avoid writing out broken entries here. if (!ServiceWorkerRegistrationDataIsValid(aData[i])) { continue;
}
const mozilla::ipc::PrincipalInfo& info = aData[i].principal();
if (!mProfileDir) {
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(mProfileDir)); if (NS_WARN_IF(NS_FAILED(rv))) { // If we do not have a profile directory, we are somehow screwed.
MOZ_DIAGNOSTIC_ASSERT( false, "NS_GetSpecialDirectory for NS_APP_USER_PROFILE_50_DIR failed!");
}
}
// Mutations to the ServiceWorkerRegistrar happen on the PBackground thread, // issued by the ServiceWorkerManagerService, so the appropriate place to // trigger shutdown is on that thread. // // However, it's quite possible that the PBackground thread was not brought // into existence for xpcshell tests. We don't cause it to be created // ourselves for any reason, for example. // // In this scenario, we know that: // - We will receive exactly one call to ourself from BlockShutdown() and // BlockShutdown() will be called (at most) once. // - The only way our Shutdown() method gets called is via // BackgroundParentImpl::RecvShutdownServiceWorkerRegistrar() being // invoked, which only happens if we get to that send below here that we // can't get to. // - All Shutdown() does is set mShuttingDown=true (essential for // invariants) and invoke MaybeScheduleShutdownCompleted(). // - Since there is no PBackground thread, mSaveDataRunnableDispatched must // be false because only MaybeScheduleSaveData() set it and it only runs // on the background thread, so it cannot have run. And so we would // expect MaybeScheduleShutdownCompleted() to schedule an invocation of // ShutdownCompleted on the main thread.
PBackgroundChild* child = BackgroundChild::GetForCurrentThread(); if (mProfileDir && child) { if (child->SendShutdownServiceWorkerRegistrar()) { // Normal shutdown sequence has been initiated, go home. return;
} // If we get here, the PBackground thread has probably gone nuts and we // want to know it.
MOZ_DIAGNOSTIC_ASSERT( false, "Unable to send the ShutdownServiceWorkerRegistrar message.");
}
// On any error it's appropriate to set mShuttingDown=true (as Shutdown // would do) and directly invoke ShutdownCompleted() (as Shutdown would // indirectly do via MaybeScheduleShutdownCompleted) in order to unblock // shutdown.
mShuttingDown = true;
ShutdownCompleted();
}
#define RELEASE_ASSERT_SUCCEEDED(rv, name) \ do { \ if (NS_FAILED(rv)) { \ if ((rv) == NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS) { \ if (auto* context = CycleCollectedJSContext::Get()) { \ if (RefPtr<Exception> exn = context->GetPendingException()) { \
MOZ_CRASH_UNSAFE_PRINTF("Failed to get " name ": %s", \
exn->GetMessageMoz().get()); \
} \
} \
} \
\
nsAutoCString errorName; \
GetErrorName(rv, errorName); \
MOZ_CRASH_UNSAFE_PRINTF("Failed to get " name ": %s", errorName.get()); \
} \
} while (0)
nsCOMPtr<nsIAsyncShutdownClient> ServiceWorkerRegistrar::GetShutdownPhase() const {
nsresult rv;
nsCOMPtr<nsIAsyncShutdownService> svc =
do_GetService("@mozilla.org/async-shutdown-service;1", &rv); // If this fails, something is very wrong on the JS side (or we're out of // memory), and there's no point in continuing startup. Include as much // information as possible in the crash report.
RELEASE_ASSERT_SUCCEEDED(rv, "async shutdown service");
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.