1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
|
#include "Common.h"
#include "HashStore.h"
#include "Classifier.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsTArray.h"
#include "nsIThread.h"
#include "nsThreadUtils.h"
#include "nsUrlClassifierUtils.h"
using namespace mozilla;
using namespace mozilla::safebrowsing;
#define GTEST_SAFEBROWSING_DIR NS_LITERAL_CSTRING("safebrowsing")
#define GTEST_TABLE NS_LITERAL_CSTRING("gtest-malware-proto")
template <typename Function>
void RunTestInNewThread(Function&& aFunction) {
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
"RunTestInNewThread", mozilla::Forward<Function>(aFunction));
nsCOMPtr<nsIThread> testingThread;
nsresult rv =
NS_NewNamedThread("Testing Thread", getter_AddRefs(testingThread), r);
ASSERT_EQ(rv, NS_OK);
testingThread->Shutdown();
}
nsresult SyncApplyUpdates(Classifier* aClassifier,
nsTArray<TableUpdate*>* aUpdates) {
// We need to spin a new thread specifically because the callback
// will be on the caller thread. If we call Classifier::AsyncApplyUpdates
// and wait on the same thread, this function will never return.
nsresult ret = NS_ERROR_FAILURE;
bool done = false;
auto onUpdateComplete = [&done, &ret](nsresult rv) {
// We are on the "ApplyUpdate" thread. Post an event to main thread
// so that we can avoid busy waiting on the main thread.
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction("SyncApplyUpdates", [&done, &ret, rv] {
ret = rv;
done = true;
});
NS_DispatchToMainThread(r);
};
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction("SyncApplyUpdates", [&]() {
nsresult rv = aClassifier->AsyncApplyUpdates(aUpdates, onUpdateComplete);
if (NS_FAILED(rv)) {
onUpdateComplete(rv);
}
});
nsCOMPtr<nsIThread> testingThread;
NS_NewNamedThread("ApplyUpdates", getter_AddRefs(testingThread));
if (!testingThread) {
return NS_ERROR_FAILURE;
}
testingThread->Dispatch(r, NS_DISPATCH_NORMAL);
// NS_NewCheckSummedOutputStream in HashStore::WriteFile
// will synchronously init NS_CRYPTO_HASH_CONTRACTID on
// the main thread. As a result we have to keep processing
// pending event until |done| becomes true. If there's no
// more pending event, what we only can do is wait.
MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return done; }));
return ret;
}
already_AddRefed<nsIFile> GetFile(const nsTArray<nsString>& path) {
nsCOMPtr<nsIFile> file;
nsresult rv =
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(file));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
for (uint32_t i = 0; i < path.Length(); i++) {
file->Append(path[i]);
}
return file.forget();
}
void ApplyUpdate(nsTArray<TableUpdate*>& updates) {
nsCOMPtr<nsIFile> file;
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(file));
UniquePtr<Classifier> classifier(new Classifier());
classifier->Open(*file);
{
// Force nsIUrlClassifierUtils loading on main thread
// because nsIUrlClassifierDBService will not run in advance
// in gtest.
nsresult rv;
nsCOMPtr<nsIUrlClassifierUtils> dummy =
do_GetService(NS_URLCLASSIFIERUTILS_CONTRACTID, &rv);
ASSERT_TRUE(NS_SUCCEEDED(rv));
}
SyncApplyUpdates(classifier.get(), &updates);
}
void ApplyUpdate(TableUpdate* update) {
nsTArray<TableUpdate*> updates = {update};
ApplyUpdate(updates);
}
void PrefixArrayToPrefixStringMap(const nsTArray<nsCString>& prefixArray,
PrefixStringMap& out) {
out.Clear();
for (uint32_t i = 0; i < prefixArray.Length(); i++) {
const nsCString& prefix = prefixArray[i];
nsCString* prefixString = out.LookupOrAdd(prefix.Length());
prefixString->Append(prefix.BeginReading(), prefix.Length());
}
}
nsresult PrefixArrayToAddPrefixArrayV2(const nsTArray<nsCString>& prefixArray,
AddPrefixArray& out) {
out.Clear();
for (size_t i = 0; i < prefixArray.Length(); i++) {
// Create prefix hash from string
Prefix hash;
static_assert(sizeof(hash.buf) == PREFIX_SIZE,
"Prefix must be 4 bytes length");
memcpy(hash.buf, prefixArray[i].BeginReading(), PREFIX_SIZE);
AddPrefix* add = out.AppendElement(fallible);
if (!add) {
return NS_ERROR_OUT_OF_MEMORY;
}
add->addChunk = i;
add->prefix = hash;
}
return NS_OK;
}
nsCString GeneratePrefix(const nsCString& aFragment, uint8_t aLength) {
Completion complete;
complete.FromPlaintext(aFragment);
nsCString hash;
hash.Assign((const char*)complete.buf, aLength);
return hash;
}
static nsresult BuildCache(LookupCacheV2* cache,
const _PrefixArray& prefixArray) {
AddPrefixArray prefixes;
AddCompleteArray completions;
nsresult rv = PrefixArrayToAddPrefixArrayV2(prefixArray, prefixes);
if (NS_FAILED(rv)) {
return rv;
}
EntrySort(prefixes);
return cache->Build(prefixes, completions);
}
static nsresult BuildCache(LookupCacheV4* cache,
const _PrefixArray& prefixArray) {
PrefixStringMap map;
PrefixArrayToPrefixStringMap(prefixArray, map);
return cache->Build(map);
}
template <typename T>
UniquePtr<T> SetupLookupCache(const _PrefixArray& prefixArray) {
nsCOMPtr<nsIFile> file;
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(file));
file->AppendNative(GTEST_SAFEBROWSING_DIR);
UniquePtr<T> cache = MakeUnique<T>(GTEST_TABLE, EmptyCString(), file);
nsresult rv = cache->Init();
EXPECT_EQ(rv, NS_OK);
rv = BuildCache(cache.get(), prefixArray);
EXPECT_EQ(rv, NS_OK);
return Move(cache);
}
|