toolkit/components/places/Helpers.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial