1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is Url Classifier code
15 : *
16 : * The Initial Developer of the Original Code is
17 : * the Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2011
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Dave Camp <dcamp@mozilla.com>
23 : * Gian-Carlo Pascutto <gpascutto@mozilla.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
40 : #ifndef SBEntries_h__
41 : #define SBEntries_h__
42 :
43 : #include "nsTArray.h"
44 : #include "nsString.h"
45 : #include "nsICryptoHash.h"
46 : #include "nsNetUtil.h"
47 : #include "prlog.h"
48 :
49 : extern PRLogModuleInfo *gUrlClassifierDbServiceLog;
50 : #if defined(PR_LOGGING)
51 : #define LOG(args) PR_LOG(gUrlClassifierDbServiceLog, PR_LOG_DEBUG, args)
52 : #define LOG_ENABLED() PR_LOG_TEST(gUrlClassifierDbServiceLog, 4)
53 : #else
54 : #define LOG(args)
55 : #define LOG_ENABLED() (PR_FALSE)
56 : #endif
57 :
58 : #if DEBUG
59 : #include "plbase64.h"
60 : #endif
61 :
62 : namespace mozilla {
63 : namespace safebrowsing {
64 :
65 : #define PREFIX_SIZE 4
66 : #define COMPLETE_SIZE 32
67 :
68 : template <uint32 S, class Comparator>
69 : struct SafebrowsingHash
70 202 : {
71 : static const uint32 sHashSize = S;
72 : typedef SafebrowsingHash<S, Comparator> self_type;
73 : uint8 buf[S];
74 :
75 837 : nsresult FromPlaintext(const nsACString& aPlainText, nsICryptoHash* aHash) {
76 : // From the protocol doc:
77 : // Each entry in the chunk is composed
78 : // of the SHA 256 hash of a suffix/prefix expression.
79 :
80 837 : nsresult rv = aHash->Init(nsICryptoHash::SHA256);
81 837 : NS_ENSURE_SUCCESS(rv, rv);
82 :
83 837 : rv = aHash->Update
84 : (reinterpret_cast<const uint8*>(aPlainText.BeginReading()),
85 : aPlainText.Length());
86 837 : NS_ENSURE_SUCCESS(rv, rv);
87 :
88 1674 : nsCAutoString hashed;
89 837 : rv = aHash->Finish(PR_FALSE, hashed);
90 837 : NS_ENSURE_SUCCESS(rv, rv);
91 :
92 837 : NS_ASSERTION(hashed.Length() >= sHashSize,
93 : "not enough characters in the hash");
94 :
95 837 : memcpy(buf, hashed.BeginReading(), sHashSize);
96 :
97 837 : return NS_OK;
98 : }
99 :
100 48 : void Assign(const nsACString& aStr) {
101 48 : NS_ASSERTION(aStr.Length() >= sHashSize,
102 : "string must be at least sHashSize characters long");
103 48 : memcpy(buf, aStr.BeginReading(), sHashSize);
104 48 : }
105 :
106 1543 : int Compare(const self_type& aOther) const {
107 1543 : return Comparator::Compare(buf, aOther.buf);
108 : }
109 :
110 742 : bool operator==(const self_type& aOther) const {
111 742 : return Comparator::Compare(buf, aOther.buf) == 0;
112 : }
113 :
114 : bool operator!=(const self_type& aOther) const {
115 : return Comparator::Compare(buf, aOther.buf) != 0;
116 : }
117 :
118 586 : bool operator<(const self_type& aOther) const {
119 586 : return Comparator::Compare(buf, aOther.buf) < 0;
120 : }
121 :
122 : #ifdef DEBUG
123 0 : void ToString(nsACString& aStr) const {
124 0 : uint32 len = ((sHashSize + 2) / 3) * 4;
125 0 : aStr.SetCapacity(len + 1);
126 0 : PL_Base64Encode((char*)buf, sHashSize, aStr.BeginWriting());
127 0 : aStr.BeginWriting()[len] = '\0';
128 0 : }
129 : #endif
130 747 : PRUint32 ToUint32() const {
131 747 : PRUint32 res = 0;
132 747 : memcpy(&res, buf, NS_MIN<size_t>(4, S));
133 747 : return res;
134 : }
135 448 : void FromUint32(PRUint32 aHash) {
136 448 : memcpy(buf, &aHash, NS_MIN<size_t>(4, S));
137 448 : }
138 : };
139 :
140 : class PrefixComparator {
141 : public:
142 767 : static int Compare(const PRUint8* a, const PRUint8* b) {
143 767 : return *((uint32*)a) - *((uint32*)b);
144 : }
145 : };
146 : typedef SafebrowsingHash<PREFIX_SIZE, PrefixComparator> Prefix;
147 : typedef nsTArray<Prefix> PrefixArray;
148 :
149 : class CompletionComparator {
150 : public:
151 2104 : static int Compare(const PRUint8* a, const PRUint8* b) {
152 2104 : return memcmp(a, b, COMPLETE_SIZE);
153 : }
154 : };
155 : typedef SafebrowsingHash<COMPLETE_SIZE, CompletionComparator> Completion;
156 : typedef nsTArray<Completion> CompletionArray;
157 :
158 199 : struct AddPrefix {
159 : Prefix prefix;
160 : uint32 addChunk;
161 :
162 109 : AddPrefix() : addChunk(0) {}
163 :
164 326 : uint32 Chunk() const { return addChunk; }
165 855 : const Prefix &PrefixHash() const { return prefix; }
166 :
167 : template<class T>
168 750 : int Compare(const T& other) const {
169 750 : int cmp = prefix.Compare(other.PrefixHash());
170 750 : if (cmp != 0) {
171 749 : return cmp;
172 : }
173 1 : return addChunk - other.addChunk;
174 : }
175 : };
176 :
177 473 : struct AddComplete {
178 : union {
179 : Prefix prefix;
180 : Completion complete;
181 : } hash;
182 : uint32 addChunk;
183 :
184 266 : AddComplete() : addChunk(0) {}
185 :
186 174 : uint32 Chunk() const { return addChunk; }
187 1 : const Prefix &PrefixHash() const { return hash.prefix; }
188 892 : const Completion &CompleteHash() const { return hash.complete; }
189 :
190 : template<class T>
191 751 : int Compare(const T& other) const {
192 751 : int cmp = hash.complete.Compare(other.CompleteHash());
193 751 : if (cmp != 0) {
194 708 : return cmp;
195 : }
196 43 : return addChunk - other.addChunk;
197 : }
198 : };
199 :
200 6 : struct SubPrefix {
201 : Prefix prefix;
202 : uint32 addChunk;
203 : uint32 subChunk;
204 :
205 2 : SubPrefix(): addChunk(0), subChunk(0) {}
206 :
207 1 : uint32 Chunk() const { return subChunk; }
208 0 : uint32 AddChunk() const { return addChunk; }
209 5 : const Prefix &PrefixHash() const { return prefix; }
210 :
211 : template<class T>
212 3 : int Compare(const T& aOther) const {
213 3 : int cmp = prefix.Compare(aOther.PrefixHash());
214 3 : if (cmp != 0)
215 3 : return cmp;
216 0 : if (addChunk != aOther.addChunk)
217 0 : return addChunk - aOther.addChunk;
218 0 : return subChunk - aOther.subChunk;
219 : }
220 :
221 : template<class T>
222 1 : int CompareAlt(const T& aOther) const {
223 1 : int cmp = prefix.Compare(aOther.PrefixHash());
224 1 : if (cmp != 0)
225 0 : return cmp;
226 1 : return addChunk - aOther.addChunk;
227 : }
228 : };
229 :
230 89 : struct SubComplete {
231 : union {
232 : Prefix prefix;
233 : Completion complete;
234 : } hash;
235 : uint32 addChunk;
236 : uint32 subChunk;
237 :
238 41 : SubComplete() : addChunk(0), subChunk(0) {}
239 :
240 36 : uint32 Chunk() const { return subChunk; }
241 : uint32 AddChunk() const { return addChunk; }
242 0 : const Prefix &PrefixHash() const { return hash.prefix; }
243 35 : const Completion &CompleteHash() const { return hash.complete; }
244 :
245 38 : int Compare(const SubComplete& aOther) const {
246 38 : int cmp = hash.complete.Compare(aOther.hash.complete);
247 38 : if (cmp != 0)
248 38 : return cmp;
249 0 : if (addChunk != aOther.addChunk)
250 0 : return addChunk - aOther.addChunk;
251 0 : return subChunk - aOther.subChunk;
252 : }
253 : };
254 :
255 : typedef nsTArray<AddPrefix> AddPrefixArray;
256 : typedef nsTArray<AddComplete> AddCompleteArray;
257 : typedef nsTArray<SubPrefix> SubPrefixArray;
258 : typedef nsTArray<SubComplete> SubCompleteArray;
259 :
260 : /**
261 : * Compares chunks by their add chunk, then their prefix.
262 : */
263 : template<class T>
264 : class EntryCompare {
265 : public:
266 : typedef T elem_type;
267 1328 : static int Compare(const void* e1, const void* e2, void* data) {
268 1328 : const elem_type* a = static_cast<const elem_type*>(e1);
269 1328 : const elem_type* b = static_cast<const elem_type*>(e2);
270 1328 : return a->Compare(*b);
271 : }
272 : };
273 :
274 : template<>
275 : class EntryCompare<SubPrefix> {
276 : public:
277 : typedef SubPrefix elem_type;
278 3 : static int Compare(const void* e1, const void* e2, void* data) {
279 3 : const elem_type* a = static_cast<const elem_type*>(e1);
280 3 : const elem_type* b = static_cast<const elem_type*>(e2);
281 3 : return a->Compare(*b);
282 : }
283 : };
284 :
285 : template<>
286 : class EntryCompare<SubComplete> {
287 : public:
288 : typedef SubComplete elem_type;
289 37 : static int Compare(const void* e1, const void* e2, void* data) {
290 37 : const elem_type *a = static_cast<const elem_type*>(e1);
291 37 : const elem_type *b = static_cast<const elem_type*>(e2);
292 37 : return a->Compare(*b);
293 : }
294 : };
295 :
296 : /**
297 : * Sort an array of store entries. nsTArray::Sort uses Equal/LessThan
298 : * to sort, this does a single Compare so it's a bit quicker over the
299 : * large sorts we do.
300 : */
301 : template<class T>
302 : void
303 1364 : EntrySort(nsTArray<T>& aArray)
304 : {
305 1364 : NS_QuickSort(aArray.Elements(), aArray.Length(), sizeof(T),
306 : EntryCompare<T>::Compare, 0);
307 1364 : }
308 :
309 : template<class T>
310 : nsresult
311 1438 : ReadTArray(nsIInputStream* aStream, nsTArray<T>* aArray, PRUint32 aNumElements)
312 : {
313 1438 : if (!aArray->SetLength(aNumElements))
314 0 : return NS_ERROR_OUT_OF_MEMORY;
315 :
316 1438 : void *buffer = aArray->Elements();
317 : nsresult rv = NS_ReadInputStreamToBuffer(aStream, &buffer,
318 1438 : (aNumElements * sizeof(T)));
319 1438 : NS_ENSURE_SUCCESS(rv, rv);
320 1438 : return NS_OK;
321 : }
322 :
323 : template<class T>
324 : nsresult
325 2037 : WriteTArray(nsIOutputStream* aStream, nsTArray<T>& aArray)
326 : {
327 : PRUint32 written;
328 : return aStream->Write(reinterpret_cast<char*>(aArray.Elements()),
329 : aArray.Length() * sizeof(T),
330 2037 : &written);
331 : }
332 :
333 : }
334 : }
335 : #endif
|