Bug 1310142 - Preserve backup databases and raw table updates for diagnostic. r=francois
MozReview-Commit-ID: GeJoBrhuTgA
--- a/toolkit/components/url-classifier/Classifier.cpp
+++ b/toolkit/components/url-classifier/Classifier.cpp
@@ -584,16 +584,19 @@ Classifier::ApplyUpdates(nsTArray<TableU
if (TableUpdate::Cast<TableUpdateV2>((*aUpdates)[i])) {
rv = UpdateHashStore(aUpdates, updateTable);
} else {
rv = UpdateTableV4(aUpdates, updateTable);
}
if (NS_FAILED(rv)) {
if (rv != NS_ERROR_OUT_OF_MEMORY) {
+#ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
+ DumpFailedUpdate();
+#endif
AbortUpdateAndReset(updateTable);
}
return rv;
}
}
}
} // End of scopedUpdatesClearer scope.
@@ -753,16 +756,94 @@ Classifier::CleanToDelete()
if (exists) {
rv = mToDeleteDirectory->Remove(true);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
+#ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
+
+already_AddRefed<nsIFile>
+Classifier::GetFailedUpdateDirectroy()
+{
+ nsCString failedUpdatekDirName = STORE_DIRECTORY + nsCString("-failedupdate");
+
+ nsCOMPtr<nsIFile> failedUpdatekDirectory;
+ if (NS_FAILED(mCacheDirectory->Clone(getter_AddRefs(failedUpdatekDirectory))) ||
+ NS_FAILED(failedUpdatekDirectory->AppendNative(failedUpdatekDirName))) {
+ LOG(("Failed to init failedUpdatekDirectory."));
+ return nullptr;
+ }
+
+ return failedUpdatekDirectory.forget();
+}
+
+nsresult
+Classifier::DumpRawTableUpdates(const nsACString& aRawUpdates)
+{
+ // DumpFailedUpdate() MUST be called first to create the
+ // "failed update" directory
+
+ LOG(("Dumping raw table updates..."));
+
+ nsCOMPtr<nsIFile> failedUpdatekDirectory = GetFailedUpdateDirectroy();
+
+ // Create tableupdate.bin and dump raw table update data.
+ nsCOMPtr<nsIFile> rawTableUpdatesFile;
+ nsCOMPtr<nsIOutputStream> outputStream;
+ if (NS_FAILED(failedUpdatekDirectory->Clone(getter_AddRefs(rawTableUpdatesFile))) ||
+ NS_FAILED(rawTableUpdatesFile->AppendNative(nsCString("tableupdates.bin"))) ||
+ NS_FAILED(NS_NewLocalFileOutputStream(getter_AddRefs(outputStream),
+ rawTableUpdatesFile,
+ PR_WRONLY | PR_TRUNCATE | PR_CREATE_FILE))) {
+ LOG(("Failed to create file to dump raw table updates."));
+ return NS_ERROR_FAILURE;
+ }
+
+ // Write out the data.
+ uint32_t written;
+ nsresult rv = outputStream->Write(aRawUpdates.BeginReading(),
+ aRawUpdates.Length(), &written);
+ NS_ENSURE_SUCCESS(rv, rv);
+ NS_ENSURE_TRUE(written == aRawUpdates.Length(), NS_ERROR_FAILURE);
+
+ return rv;
+}
+
+nsresult
+Classifier::DumpFailedUpdate()
+{
+ LOG(("Dumping failed update..."));
+
+ nsCOMPtr<nsIFile> failedUpdatekDirectory = GetFailedUpdateDirectroy();
+
+ // Remove the "failed update" directory no matter it exists or not.
+ // Failure is fine because the directory may not exist.
+ failedUpdatekDirectory->Remove(true);
+
+ nsCString failedUpdatekDirName;
+ nsresult rv = failedUpdatekDirectory->GetNativeLeafName(failedUpdatekDirName);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Move backup to a clean "failed update" directory.
+ nsCOMPtr<nsIFile> backupDirectory;
+ if (NS_FAILED(mBackupDirectory->Clone(getter_AddRefs(backupDirectory))) ||
+ NS_FAILED(backupDirectory->MoveToNative(nullptr, failedUpdatekDirName))) {
+ LOG(("Failed to move backup to the \"failed update\" directory %s",
+ failedUpdatekDirName.get()));
+ return NS_ERROR_FAILURE;
+ }
+
+ return rv;
+}
+
+#endif // MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
+
nsresult
Classifier::BackupTables()
{
// We have to work in reverse here: first move the normal directory
// away to be the backup directory, then copy the files over
// to the normal directory. This ensures that if we crash the backup
// dir always has a valid, complete copy, instead of a partial one,
// because that's the one we will copy over the normal store dir.
--- a/toolkit/components/url-classifier/Classifier.h
+++ b/toolkit/components/url-classifier/Classifier.h
@@ -79,16 +79,21 @@ public:
/*
* Get a bunch of extra prefixes to query for completion
* and mask the real entry being requested
*/
nsresult ReadNoiseEntries(const Prefix& aPrefix,
const nsACString& aTableName,
uint32_t aCount,
PrefixArray* aNoiseEntries);
+
+#ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
+ nsresult DumpRawTableUpdates(const nsACString& aRawUpdates);
+#endif
+
static void SplitTables(const nsACString& str, nsTArray<nsCString>& tables);
// Given a root store directory, return a private store directory
// based on the table name. To avoid migration issue, the private
// store directory is only different from root directory for V4 tables.
//
// For V4 tables (suffixed by '-proto'), the private directory would
// be [root directory path]/[provider]. The provider of V4 tables is
@@ -107,16 +112,22 @@ private:
nsresult CreateStoreDirectory();
nsresult SetupPathNames();
nsresult RecoverBackups();
nsresult CleanToDelete();
nsresult BackupTables();
nsresult RemoveBackupTables();
nsresult RegenActiveTables();
+
+#ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
+ already_AddRefed<nsIFile> GetFailedUpdateDirectroy();
+ nsresult DumpFailedUpdate();
+#endif
+
nsresult ScanStoreDir(nsTArray<nsCString>& aTables);
nsresult UpdateHashStore(nsTArray<TableUpdate*>* aUpdates,
const nsACString& aTable);
nsresult UpdateTableV4(nsTArray<TableUpdate*>* aUpdates,
const nsACString& aTable);
--- a/toolkit/components/url-classifier/ProtocolParser.h
+++ b/toolkit/components/url-classifier/ProtocolParser.h
@@ -25,16 +25,20 @@ public:
ProtocolParser();
virtual ~ProtocolParser();
nsresult Status() const { return mUpdateStatus; }
nsresult Init(nsICryptoHash* aHasher);
+#ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
+ nsCString GetRawTableUpdates() const { return mPending; }
+#endif
+
virtual void SetCurrentTable(const nsACString& aTable) = 0;
void SetRequestedTables(const nsTArray<nsCString>& aRequestTables)
{
mRequestedTables = aRequestTables;
}
nsresult Begin();
--- a/toolkit/components/url-classifier/moz.build
+++ b/toolkit/components/url-classifier/moz.build
@@ -76,8 +76,11 @@ LOCAL_INCLUDES += [
'../build',
'/ipc/chromium/src',
]
CXXFLAGS += CONFIG['SQLITE_CFLAGS']
if CONFIG['GNU_CXX']:
CXXFLAGS += ['-Wno-error=shadow']
+
+if CONFIG['NIGHTLY_BUILD'] or CONFIG['MOZ_DEBUG']:
+ DEFINES['MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES'] = True
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
@@ -552,16 +552,21 @@ nsUrlClassifierDBServiceWorker::FinishSt
for (uint32_t i = 0; i < forwards.Length(); i++) {
const ProtocolParser::ForwardedUpdate &forward = forwards[i];
mUpdateObserver->UpdateUrlRequested(forward.url, forward.table);
}
// Hold on to any TableUpdate objects that were created by the
// parser.
mTableUpdates.AppendElements(mProtocolParser->GetTableUpdates());
mProtocolParser->ForgetTableUpdates();
+
+#ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
+ // The assignment involves no string copy since the source string is sharable.
+ mRawTableUpdates = mProtocolParser->GetRawTableUpdates();
+#endif
} else {
LOG(("nsUrlClassifierDBService::FinishStream Failed to parse the stream "
"using mProtocolParser."));
mUpdateStatus = mProtocolParser->Status();
}
mUpdateObserver->StreamFinished(mProtocolParser->Status(), 0);
if (NS_SUCCEEDED(mUpdateStatus)) {
@@ -617,17 +622,27 @@ nsUrlClassifierDBServiceWorker::FinishUp
return NS_OK;
}
nsresult
nsUrlClassifierDBServiceWorker::ApplyUpdate()
{
LOG(("nsUrlClassifierDBServiceWorker::ApplyUpdate()"));
- return mClassifier->ApplyUpdates(&mTableUpdates);
+ nsresult rv = mClassifier->ApplyUpdates(&mTableUpdates);
+
+#ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
+ if (NS_FAILED(rv) && NS_ERROR_OUT_OF_MEMORY != rv) {
+ mClassifier->DumpRawTableUpdates(mRawTableUpdates);
+ }
+ // Invalidate the raw table updates.
+ mRawTableUpdates = EmptyCString();
+#endif
+
+ return rv;
}
NS_IMETHODIMP
nsUrlClassifierDBServiceWorker::ResetDatabase()
{
nsresult rv = OpenDb();
if (NS_SUCCEEDED(rv)) {
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.h
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.h
@@ -244,13 +244,18 @@ private:
mozilla::TimeStamp mStartTime;
nsCString mKey;
nsCString mTables;
nsCOMPtr<nsIUrlClassifierLookupCallback> mCallback;
};
// list of pending lookups
nsTArray<PendingLookup> mPendingLookups;
+
+#ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
+ // The raw update response for debugging.
+ nsCString mRawTableUpdates;
+#endif
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsUrlClassifierDBService, NS_URLCLASSIFIERDBSERVICE_CID)
#endif // nsUrlClassifierDBService_h_