Line data Source code
1 : /* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "Helpers.h"
7 : #include "mozIStorageError.h"
8 : #include "prio.h"
9 : #include "nsString.h"
10 : #include "nsNavHistory.h"
11 : #include "mozilla/Base64.h"
12 : #include "mozilla/Services.h"
13 :
14 : // The length of guids that are used by history and bookmarks.
15 : #define GUID_LENGTH 12
16 :
17 : namespace mozilla {
18 : namespace places {
19 :
20 : ////////////////////////////////////////////////////////////////////////////////
21 : //// AsyncStatementCallback
22 :
23 10 : NS_IMPL_ISUPPORTS(
24 : AsyncStatementCallback
25 : , mozIStorageStatementCallback
26 : )
27 :
28 : NS_IMETHODIMP
29 0 : WeakAsyncStatementCallback::HandleResult(mozIStorageResultSet *aResultSet)
30 : {
31 0 : MOZ_ASSERT(false, "Was not expecting a resultset, but got it.");
32 : return NS_OK;
33 : }
34 :
35 : NS_IMETHODIMP
36 1 : WeakAsyncStatementCallback::HandleCompletion(uint16_t aReason)
37 : {
38 1 : return NS_OK;
39 : }
40 :
41 : NS_IMETHODIMP
42 0 : WeakAsyncStatementCallback::HandleError(mozIStorageError *aError)
43 : {
44 : #ifdef DEBUG
45 : int32_t result;
46 0 : nsresult rv = aError->GetResult(&result);
47 0 : NS_ENSURE_SUCCESS(rv, rv);
48 0 : nsAutoCString message;
49 0 : rv = aError->GetMessage(message);
50 0 : NS_ENSURE_SUCCESS(rv, rv);
51 :
52 0 : nsAutoCString warnMsg;
53 0 : warnMsg.AppendLiteral("An error occurred while executing an async statement: ");
54 0 : warnMsg.AppendInt(result);
55 0 : warnMsg.Append(' ');
56 0 : warnMsg.Append(message);
57 0 : NS_WARNING(warnMsg.get());
58 : #endif
59 :
60 0 : return NS_OK;
61 : }
62 :
63 : #define URI_TO_URLCSTRING(uri, spec) \
64 : nsAutoCString spec; \
65 : if (NS_FAILED(aURI->GetSpec(spec))) { \
66 : return NS_ERROR_UNEXPECTED; \
67 : }
68 :
69 : // Bind URI to statement by index.
70 : nsresult // static
71 0 : URIBinder::Bind(mozIStorageStatement* aStatement,
72 : int32_t aIndex,
73 : nsIURI* aURI)
74 : {
75 0 : NS_ASSERTION(aStatement, "Must have non-null statement");
76 0 : NS_ASSERTION(aURI, "Must have non-null uri");
77 :
78 0 : URI_TO_URLCSTRING(aURI, spec);
79 0 : return URIBinder::Bind(aStatement, aIndex, spec);
80 : }
81 :
82 : // Statement URLCString to statement by index.
83 : nsresult // static
84 0 : URIBinder::Bind(mozIStorageStatement* aStatement,
85 : int32_t index,
86 : const nsACString& aURLString)
87 : {
88 0 : NS_ASSERTION(aStatement, "Must have non-null statement");
89 0 : return aStatement->BindUTF8StringByIndex(
90 0 : index, StringHead(aURLString, URI_LENGTH_MAX)
91 0 : );
92 : }
93 :
94 : // Bind URI to statement by name.
95 : nsresult // static
96 0 : URIBinder::Bind(mozIStorageStatement* aStatement,
97 : const nsACString& aName,
98 : nsIURI* aURI)
99 : {
100 0 : NS_ASSERTION(aStatement, "Must have non-null statement");
101 0 : NS_ASSERTION(aURI, "Must have non-null uri");
102 :
103 0 : URI_TO_URLCSTRING(aURI, spec);
104 0 : return URIBinder::Bind(aStatement, aName, spec);
105 : }
106 :
107 : // Bind URLCString to statement by name.
108 : nsresult // static
109 4 : URIBinder::Bind(mozIStorageStatement* aStatement,
110 : const nsACString& aName,
111 : const nsACString& aURLString)
112 : {
113 4 : NS_ASSERTION(aStatement, "Must have non-null statement");
114 8 : return aStatement->BindUTF8StringByName(
115 8 : aName, StringHead(aURLString, URI_LENGTH_MAX)
116 12 : );
117 : }
118 :
119 : // Bind URI to params by index.
120 : nsresult // static
121 0 : URIBinder::Bind(mozIStorageBindingParams* aParams,
122 : int32_t aIndex,
123 : nsIURI* aURI)
124 : {
125 0 : NS_ASSERTION(aParams, "Must have non-null statement");
126 0 : NS_ASSERTION(aURI, "Must have non-null uri");
127 :
128 0 : URI_TO_URLCSTRING(aURI, spec);
129 0 : return URIBinder::Bind(aParams, aIndex, spec);
130 : }
131 :
132 : // Bind URLCString to params by index.
133 : nsresult // static
134 0 : URIBinder::Bind(mozIStorageBindingParams* aParams,
135 : int32_t index,
136 : const nsACString& aURLString)
137 : {
138 0 : NS_ASSERTION(aParams, "Must have non-null statement");
139 0 : return aParams->BindUTF8StringByIndex(
140 0 : index, StringHead(aURLString, URI_LENGTH_MAX)
141 0 : );
142 : }
143 :
144 : // Bind URI to params by name.
145 : nsresult // static
146 0 : URIBinder::Bind(mozIStorageBindingParams* aParams,
147 : const nsACString& aName,
148 : nsIURI* aURI)
149 : {
150 0 : NS_ASSERTION(aParams, "Must have non-null params array");
151 0 : NS_ASSERTION(aURI, "Must have non-null uri");
152 :
153 0 : URI_TO_URLCSTRING(aURI, spec);
154 0 : return URIBinder::Bind(aParams, aName, spec);
155 : }
156 :
157 : // Bind URLCString to params by name.
158 : nsresult // static
159 1 : URIBinder::Bind(mozIStorageBindingParams* aParams,
160 : const nsACString& aName,
161 : const nsACString& aURLString)
162 : {
163 1 : NS_ASSERTION(aParams, "Must have non-null params array");
164 :
165 : nsresult rv = aParams->BindUTF8StringByName(
166 2 : aName, StringHead(aURLString, URI_LENGTH_MAX)
167 2 : );
168 1 : NS_ENSURE_SUCCESS(rv, rv);
169 1 : return NS_OK;
170 : }
171 :
172 : #undef URI_TO_URLCSTRING
173 :
174 : nsresult
175 1 : GetReversedHostname(nsIURI* aURI, nsString& aRevHost)
176 : {
177 2 : nsAutoCString forward8;
178 1 : nsresult rv = aURI->GetHost(forward8);
179 : // Not all URIs have a host.
180 1 : if (NS_FAILED(rv))
181 0 : return rv;
182 :
183 : // can't do reversing in UTF8, better use 16-bit chars
184 1 : GetReversedHostname(NS_ConvertUTF8toUTF16(forward8), aRevHost);
185 1 : return NS_OK;
186 : }
187 :
188 : void
189 1 : GetReversedHostname(const nsString& aForward, nsString& aRevHost)
190 : {
191 1 : ReverseString(aForward, aRevHost);
192 1 : aRevHost.Append(char16_t('.'));
193 1 : }
194 :
195 : void
196 17 : ReverseString(const nsString& aInput, nsString& aReversed)
197 : {
198 17 : aReversed.Truncate(0);
199 170 : for (int32_t i = aInput.Length() - 1; i >= 0; i--) {
200 153 : aReversed.Append(aInput[i]);
201 : }
202 17 : }
203 :
204 : #ifdef XP_WIN
205 : } // namespace places
206 : } // namespace mozilla
207 :
208 : // Included here because windows.h conflicts with the use of mozIStorageError
209 : // above, but make sure that these are not included inside mozilla::places.
210 : #include <windows.h>
211 : #include <wincrypt.h>
212 :
213 : namespace mozilla {
214 : namespace places {
215 : #endif
216 :
217 : static
218 : nsresult
219 1 : GenerateRandomBytes(uint32_t aSize,
220 : uint8_t* _buffer)
221 : {
222 : // On Windows, we'll use its built-in cryptographic API.
223 : #if defined(XP_WIN)
224 : HCRYPTPROV cryptoProvider;
225 : BOOL rc = CryptAcquireContext(&cryptoProvider, 0, 0, PROV_RSA_FULL,
226 : CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
227 : if (rc) {
228 : rc = CryptGenRandom(cryptoProvider, aSize, _buffer);
229 : (void)CryptReleaseContext(cryptoProvider, 0);
230 : }
231 : return rc ? NS_OK : NS_ERROR_FAILURE;
232 :
233 : // On Unix, we'll just read in from /dev/urandom.
234 : #elif defined(XP_UNIX)
235 1 : NS_ENSURE_ARG_MAX(aSize, INT32_MAX);
236 1 : PRFileDesc* urandom = PR_Open("/dev/urandom", PR_RDONLY, 0);
237 1 : nsresult rv = NS_ERROR_FAILURE;
238 1 : if (urandom) {
239 1 : int32_t bytesRead = PR_Read(urandom, _buffer, aSize);
240 1 : if (bytesRead == static_cast<int32_t>(aSize)) {
241 1 : rv = NS_OK;
242 : }
243 1 : (void)PR_Close(urandom);
244 : }
245 1 : return rv;
246 : #endif
247 : }
248 :
249 : nsresult
250 1 : GenerateGUID(nsACString& _guid)
251 : {
252 1 : _guid.Truncate();
253 :
254 : // Request raw random bytes and base64url encode them. For each set of three
255 : // bytes, we get one character.
256 : const uint32_t kRequiredBytesLength =
257 1 : static_cast<uint32_t>(GUID_LENGTH / 4 * 3);
258 :
259 : uint8_t buffer[kRequiredBytesLength];
260 1 : nsresult rv = GenerateRandomBytes(kRequiredBytesLength, buffer);
261 1 : NS_ENSURE_SUCCESS(rv, rv);
262 :
263 : rv = Base64URLEncode(kRequiredBytesLength, buffer,
264 1 : Base64URLEncodePaddingPolicy::Omit, _guid);
265 1 : NS_ENSURE_SUCCESS(rv, rv);
266 :
267 1 : NS_ASSERTION(_guid.Length() == GUID_LENGTH, "GUID is not the right size!");
268 1 : return NS_OK;
269 : }
270 :
271 : bool
272 0 : IsValidGUID(const nsACString& aGUID)
273 : {
274 0 : nsCString::size_type len = aGUID.Length();
275 0 : if (len != GUID_LENGTH) {
276 0 : return false;
277 : }
278 :
279 0 : for (nsCString::size_type i = 0; i < len; i++ ) {
280 0 : char c = aGUID[i];
281 0 : if ((c >= 'a' && c <= 'z') || // a-z
282 0 : (c >= 'A' && c <= 'Z') || // A-Z
283 0 : (c >= '0' && c <= '9') || // 0-9
284 0 : c == '-' || c == '_') { // - or _
285 0 : continue;
286 : }
287 0 : return false;
288 : }
289 0 : return true;
290 : }
291 :
292 : void
293 0 : TruncateTitle(const nsACString& aTitle, nsACString& aTrimmed)
294 : {
295 0 : if (aTitle.IsVoid()) {
296 0 : return;
297 : }
298 0 : aTrimmed = aTitle;
299 0 : if (aTitle.Length() > TITLE_LENGTH_MAX) {
300 0 : aTrimmed = StringHead(aTitle, TITLE_LENGTH_MAX);
301 : }
302 : }
303 :
304 : PRTime
305 0 : RoundToMilliseconds(PRTime aTime) {
306 0 : return aTime - (aTime % PR_USEC_PER_MSEC);
307 : }
308 :
309 : PRTime
310 0 : RoundedPRNow() {
311 0 : return RoundToMilliseconds(PR_Now());
312 : }
313 :
314 : bool
315 1 : GetHiddenState(bool aIsRedirect,
316 : uint32_t aTransitionType)
317 : {
318 1 : return aTransitionType == nsINavHistoryService::TRANSITION_FRAMED_LINK ||
319 2 : aTransitionType == nsINavHistoryService::TRANSITION_EMBED ||
320 1 : aIsRedirect;
321 : }
322 :
323 : ////////////////////////////////////////////////////////////////////////////////
324 : //// AsyncStatementCallbackNotifier
325 :
326 : NS_IMETHODIMP
327 0 : AsyncStatementCallbackNotifier::HandleCompletion(uint16_t aReason)
328 : {
329 0 : if (aReason != mozIStorageStatementCallback::REASON_FINISHED)
330 0 : return NS_ERROR_UNEXPECTED;
331 :
332 0 : nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
333 0 : if (obs) {
334 0 : (void)obs->NotifyObservers(nullptr, mTopic, nullptr);
335 : }
336 :
337 0 : return NS_OK;
338 : }
339 :
340 : ////////////////////////////////////////////////////////////////////////////////
341 : //// AsyncStatementCallbackNotifier
342 :
343 : NS_IMETHODIMP
344 0 : AsyncStatementTelemetryTimer::HandleCompletion(uint16_t aReason)
345 : {
346 0 : if (aReason == mozIStorageStatementCallback::REASON_FINISHED) {
347 0 : Telemetry::AccumulateTimeDelta(mHistogramId, mStart);
348 : }
349 0 : return NS_OK;
350 : }
351 :
352 : } // namespace places
353 : } // namespace mozilla
|