| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/browser/media/webrtc/webrtc_identity_store_backend.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 #include <stdint.h> | |
| 9 | |
| 10 #include <tuple> | |
| 11 | |
| 12 #include "base/files/file_path.h" | |
| 13 #include "base/files/file_util.h" | |
| 14 #include "base/macros.h" | |
| 15 #include "base/memory/scoped_vector.h" | |
| 16 #include "base/strings/string_util.h" | |
| 17 #include "content/public/browser/browser_thread.h" | |
| 18 #include "net/base/net_errors.h" | |
| 19 #include "sql/statement.h" | |
| 20 #include "sql/transaction.h" | |
| 21 #include "storage/browser/quota/special_storage_policy.h" | |
| 22 #include "url/gurl.h" | |
| 23 | |
| 24 namespace content { | |
| 25 | |
| 26 static const char kWebRTCIdentityStoreDBName[] = "webrtc_identity_store"; | |
| 27 | |
| 28 static const base::FilePath::CharType kWebRTCIdentityStoreDirectory[] = | |
| 29 FILE_PATH_LITERAL("WebRTCIdentityStore"); | |
| 30 | |
| 31 // Initializes the identity table, returning true on success. | |
| 32 static bool InitDB(sql::Connection* db) { | |
| 33 if (db->DoesTableExist(kWebRTCIdentityStoreDBName)) { | |
| 34 if (db->DoesColumnExist(kWebRTCIdentityStoreDBName, "origin") && | |
| 35 db->DoesColumnExist(kWebRTCIdentityStoreDBName, "identity_name") && | |
| 36 db->DoesColumnExist(kWebRTCIdentityStoreDBName, "common_name") && | |
| 37 db->DoesColumnExist(kWebRTCIdentityStoreDBName, "certificate") && | |
| 38 db->DoesColumnExist(kWebRTCIdentityStoreDBName, "private_key") && | |
| 39 db->DoesColumnExist(kWebRTCIdentityStoreDBName, "creation_time")) | |
| 40 return true; | |
| 41 | |
| 42 if (!db->Execute("DROP TABLE webrtc_identity_store")) | |
| 43 return false; | |
| 44 } | |
| 45 | |
| 46 return db->Execute( | |
| 47 "CREATE TABLE webrtc_identity_store" | |
| 48 " (" | |
| 49 "origin TEXT NOT NULL," | |
| 50 "identity_name TEXT NOT NULL," | |
| 51 "common_name TEXT NOT NULL," | |
| 52 "certificate BLOB NOT NULL," | |
| 53 "private_key BLOB NOT NULL," | |
| 54 "creation_time INTEGER)"); | |
| 55 } | |
| 56 | |
| 57 struct WebRTCIdentityStoreBackend::IdentityKey { | |
| 58 IdentityKey(const GURL& origin, const std::string& identity_name) | |
| 59 : origin(origin), identity_name(identity_name) {} | |
| 60 | |
| 61 bool operator<(const IdentityKey& other) const { | |
| 62 return std::tie(origin, identity_name) < | |
| 63 std::tie(other.origin, other.identity_name); | |
| 64 } | |
| 65 | |
| 66 GURL origin; | |
| 67 std::string identity_name; | |
| 68 }; | |
| 69 | |
| 70 struct WebRTCIdentityStoreBackend::Identity { | |
| 71 Identity(const std::string& common_name, | |
| 72 const std::string& certificate, | |
| 73 const std::string& private_key) | |
| 74 : common_name(common_name), | |
| 75 certificate(certificate), | |
| 76 private_key(private_key), | |
| 77 creation_time(base::Time::Now().ToInternalValue()) {} | |
| 78 | |
| 79 Identity(const std::string& common_name, | |
| 80 const std::string& certificate, | |
| 81 const std::string& private_key, | |
| 82 int64_t creation_time) | |
| 83 : common_name(common_name), | |
| 84 certificate(certificate), | |
| 85 private_key(private_key), | |
| 86 creation_time(creation_time) {} | |
| 87 | |
| 88 std::string common_name; | |
| 89 std::string certificate; | |
| 90 std::string private_key; | |
| 91 int64_t creation_time; | |
| 92 }; | |
| 93 | |
| 94 struct WebRTCIdentityStoreBackend::PendingFindRequest { | |
| 95 PendingFindRequest(const GURL& origin, | |
| 96 const std::string& identity_name, | |
| 97 const std::string& common_name, | |
| 98 const FindIdentityCallback& callback) | |
| 99 : origin(origin), | |
| 100 identity_name(identity_name), | |
| 101 common_name(common_name), | |
| 102 callback(callback) {} | |
| 103 | |
| 104 ~PendingFindRequest() {} | |
| 105 | |
| 106 GURL origin; | |
| 107 std::string identity_name; | |
| 108 std::string common_name; | |
| 109 FindIdentityCallback callback; | |
| 110 }; | |
| 111 | |
| 112 // The class encapsulates the database operations. All members except ctor and | |
| 113 // dtor should be accessed on the DB thread. | |
| 114 // It can be created/destroyed on any thread. | |
| 115 class WebRTCIdentityStoreBackend::SqlLiteStorage | |
| 116 : public base::RefCountedThreadSafe<SqlLiteStorage> { | |
| 117 public: | |
| 118 SqlLiteStorage(base::TimeDelta validity_period, | |
| 119 const base::FilePath& path, | |
| 120 storage::SpecialStoragePolicy* policy) | |
| 121 : validity_period_(validity_period), special_storage_policy_(policy) { | |
| 122 if (!path.empty()) | |
| 123 path_ = path.Append(kWebRTCIdentityStoreDirectory); | |
| 124 } | |
| 125 | |
| 126 void Load(IdentityMap* out_map); | |
| 127 void Close(); | |
| 128 void AddIdentity(const GURL& origin, | |
| 129 const std::string& identity_name, | |
| 130 const Identity& identity); | |
| 131 void DeleteIdentity(const GURL& origin, | |
| 132 const std::string& identity_name, | |
| 133 const Identity& identity); | |
| 134 void DeleteBetween(base::Time delete_begin, base::Time delete_end); | |
| 135 | |
| 136 void SetValidityPeriodForTesting(base::TimeDelta validity_period) { | |
| 137 DCHECK_CURRENTLY_ON(BrowserThread::DB); | |
| 138 DCHECK(!db_.get()); | |
| 139 validity_period_ = validity_period; | |
| 140 } | |
| 141 | |
| 142 private: | |
| 143 friend class base::RefCountedThreadSafe<SqlLiteStorage>; | |
| 144 | |
| 145 enum OperationType { | |
| 146 ADD_IDENTITY, | |
| 147 DELETE_IDENTITY | |
| 148 }; | |
| 149 struct PendingOperation { | |
| 150 PendingOperation(OperationType type, | |
| 151 const GURL& origin, | |
| 152 const std::string& identity_name, | |
| 153 const Identity& identity) | |
| 154 : type(type), | |
| 155 origin(origin), | |
| 156 identity_name(identity_name), | |
| 157 identity(identity) {} | |
| 158 | |
| 159 OperationType type; | |
| 160 GURL origin; | |
| 161 std::string identity_name; | |
| 162 Identity identity; | |
| 163 }; | |
| 164 typedef ScopedVector<PendingOperation> PendingOperationList; | |
| 165 | |
| 166 virtual ~SqlLiteStorage() {} | |
| 167 void OnDatabaseError(int error, sql::Statement* stmt); | |
| 168 void BatchOperation(OperationType type, | |
| 169 const GURL& origin, | |
| 170 const std::string& identity_name, | |
| 171 const Identity& identity); | |
| 172 void Commit(); | |
| 173 | |
| 174 base::TimeDelta validity_period_; | |
| 175 // The file path of the DB. Empty if temporary. | |
| 176 base::FilePath path_; | |
| 177 scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_; | |
| 178 std::unique_ptr<sql::Connection> db_; | |
| 179 // Batched DB operations pending to commit. | |
| 180 PendingOperationList pending_operations_; | |
| 181 | |
| 182 DISALLOW_COPY_AND_ASSIGN(SqlLiteStorage); | |
| 183 }; | |
| 184 | |
| 185 WebRTCIdentityStoreBackend::WebRTCIdentityStoreBackend( | |
| 186 const base::FilePath& path, | |
| 187 storage::SpecialStoragePolicy* policy, | |
| 188 base::TimeDelta validity_period) | |
| 189 : validity_period_(validity_period), | |
| 190 state_(NOT_STARTED), | |
| 191 sql_lite_storage_(new SqlLiteStorage(validity_period, path, policy)) { | |
| 192 } | |
| 193 | |
| 194 bool WebRTCIdentityStoreBackend::FindIdentity( | |
| 195 const GURL& origin, | |
| 196 const std::string& identity_name, | |
| 197 const std::string& common_name, | |
| 198 const FindIdentityCallback& callback) { | |
| 199 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 200 if (state_ == CLOSED) | |
| 201 return false; | |
| 202 | |
| 203 if (state_ != LOADED) { | |
| 204 // Queues the request to wait for the DB to load. | |
| 205 pending_find_requests_.push_back( | |
| 206 new PendingFindRequest(origin, identity_name, common_name, callback)); | |
| 207 if (state_ == LOADING) | |
| 208 return true; | |
| 209 | |
| 210 DCHECK_EQ(state_, NOT_STARTED); | |
| 211 | |
| 212 // Kick off loading the DB. | |
| 213 std::unique_ptr<IdentityMap> out_map(new IdentityMap()); | |
| 214 base::Closure task( | |
| 215 base::Bind(&SqlLiteStorage::Load, sql_lite_storage_, out_map.get())); | |
| 216 // |out_map| will be NULL after this call. | |
| 217 if (BrowserThread::PostTaskAndReply( | |
| 218 BrowserThread::DB, | |
| 219 FROM_HERE, | |
| 220 task, | |
| 221 base::Bind(&WebRTCIdentityStoreBackend::OnLoaded, | |
| 222 this, | |
| 223 base::Passed(&out_map)))) { | |
| 224 state_ = LOADING; | |
| 225 return true; | |
| 226 } | |
| 227 // If it fails to post task, falls back to ERR_FILE_NOT_FOUND. | |
| 228 } | |
| 229 | |
| 230 IdentityKey key(origin, identity_name); | |
| 231 IdentityMap::iterator iter = identities_.find(key); | |
| 232 if (iter != identities_.end() && iter->second.common_name == common_name) { | |
| 233 base::TimeDelta age = base::Time::Now() - base::Time::FromInternalValue( | |
| 234 iter->second.creation_time); | |
| 235 if (age < validity_period_) { | |
| 236 // Identity found. | |
| 237 return BrowserThread::PostTask(BrowserThread::IO, | |
| 238 FROM_HERE, | |
| 239 base::Bind(callback, | |
| 240 net::OK, | |
| 241 iter->second.certificate, | |
| 242 iter->second.private_key)); | |
| 243 } | |
| 244 // Removes the expired identity from the in-memory cache. The copy in the | |
| 245 // database will be removed on the next load. | |
| 246 identities_.erase(iter); | |
| 247 } | |
| 248 | |
| 249 return BrowserThread::PostTask( | |
| 250 BrowserThread::IO, | |
| 251 FROM_HERE, | |
| 252 base::Bind(callback, net::ERR_FILE_NOT_FOUND, "", "")); | |
| 253 } | |
| 254 | |
| 255 void WebRTCIdentityStoreBackend::AddIdentity(const GURL& origin, | |
| 256 const std::string& identity_name, | |
| 257 const std::string& common_name, | |
| 258 const std::string& certificate, | |
| 259 const std::string& private_key) { | |
| 260 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 261 if (state_ == CLOSED) | |
| 262 return; | |
| 263 | |
| 264 // If there is an existing identity for the same origin and identity_name, | |
| 265 // delete it. | |
| 266 IdentityKey key(origin, identity_name); | |
| 267 Identity identity(common_name, certificate, private_key); | |
| 268 | |
| 269 if (identities_.find(key) != identities_.end()) { | |
| 270 if (!BrowserThread::PostTask(BrowserThread::DB, | |
| 271 FROM_HERE, | |
| 272 base::Bind(&SqlLiteStorage::DeleteIdentity, | |
| 273 sql_lite_storage_, | |
| 274 origin, | |
| 275 identity_name, | |
| 276 identities_.find(key)->second))) | |
| 277 return; | |
| 278 } | |
| 279 identities_.insert(std::pair<IdentityKey, Identity>(key, identity)); | |
| 280 | |
| 281 BrowserThread::PostTask(BrowserThread::DB, | |
| 282 FROM_HERE, | |
| 283 base::Bind(&SqlLiteStorage::AddIdentity, | |
| 284 sql_lite_storage_, | |
| 285 origin, | |
| 286 identity_name, | |
| 287 identity)); | |
| 288 } | |
| 289 | |
| 290 void WebRTCIdentityStoreBackend::Close() { | |
| 291 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
| 292 BrowserThread::PostTask( | |
| 293 BrowserThread::IO, | |
| 294 FROM_HERE, | |
| 295 base::Bind(&WebRTCIdentityStoreBackend::Close, this)); | |
| 296 return; | |
| 297 } | |
| 298 | |
| 299 if (state_ == CLOSED) | |
| 300 return; | |
| 301 | |
| 302 state_ = CLOSED; | |
| 303 BrowserThread::PostTask( | |
| 304 BrowserThread::DB, | |
| 305 FROM_HERE, | |
| 306 base::Bind(&SqlLiteStorage::Close, sql_lite_storage_)); | |
| 307 } | |
| 308 | |
| 309 void WebRTCIdentityStoreBackend::DeleteBetween(base::Time delete_begin, | |
| 310 base::Time delete_end, | |
| 311 const base::Closure& callback) { | |
| 312 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 313 if (state_ == CLOSED) | |
| 314 return; | |
| 315 | |
| 316 // Delete the in-memory cache. | |
| 317 IdentityMap::iterator it = identities_.begin(); | |
| 318 while (it != identities_.end()) { | |
| 319 if (it->second.creation_time >= delete_begin.ToInternalValue() && | |
| 320 it->second.creation_time <= delete_end.ToInternalValue()) { | |
| 321 identities_.erase(it++); | |
| 322 } else { | |
| 323 ++it; | |
| 324 } | |
| 325 } | |
| 326 BrowserThread::PostTaskAndReply(BrowserThread::DB, | |
| 327 FROM_HERE, | |
| 328 base::Bind(&SqlLiteStorage::DeleteBetween, | |
| 329 sql_lite_storage_, | |
| 330 delete_begin, | |
| 331 delete_end), | |
| 332 callback); | |
| 333 } | |
| 334 | |
| 335 void WebRTCIdentityStoreBackend::SetValidityPeriodForTesting( | |
| 336 base::TimeDelta validity_period) { | |
| 337 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 338 validity_period_ = validity_period; | |
| 339 BrowserThread::PostTask( | |
| 340 BrowserThread::DB, | |
| 341 FROM_HERE, | |
| 342 base::Bind(&SqlLiteStorage::SetValidityPeriodForTesting, | |
| 343 sql_lite_storage_, | |
| 344 validity_period)); | |
| 345 } | |
| 346 | |
| 347 WebRTCIdentityStoreBackend::~WebRTCIdentityStoreBackend() {} | |
| 348 | |
| 349 void WebRTCIdentityStoreBackend::OnLoaded( | |
| 350 std::unique_ptr<IdentityMap> out_map) { | |
| 351 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 352 | |
| 353 if (state_ != LOADING) | |
| 354 return; | |
| 355 | |
| 356 DVLOG(3) << "WebRTC identity store has loaded."; | |
| 357 | |
| 358 state_ = LOADED; | |
| 359 identities_.swap(*out_map); | |
| 360 | |
| 361 for (size_t i = 0; i < pending_find_requests_.size(); ++i) { | |
| 362 FindIdentity(pending_find_requests_[i]->origin, | |
| 363 pending_find_requests_[i]->identity_name, | |
| 364 pending_find_requests_[i]->common_name, | |
| 365 pending_find_requests_[i]->callback); | |
| 366 delete pending_find_requests_[i]; | |
| 367 } | |
| 368 pending_find_requests_.clear(); | |
| 369 } | |
| 370 | |
| 371 // | |
| 372 // Implementation of SqlLiteStorage. | |
| 373 // | |
| 374 | |
| 375 void WebRTCIdentityStoreBackend::SqlLiteStorage::Load(IdentityMap* out_map) { | |
| 376 DCHECK_CURRENTLY_ON(BrowserThread::DB); | |
| 377 DCHECK(!db_.get()); | |
| 378 | |
| 379 // Ensure the parent directory for storing certs is created before reading | |
| 380 // from it. | |
| 381 const base::FilePath dir = path_.DirName(); | |
| 382 if (!base::PathExists(dir) && !base::CreateDirectory(dir)) { | |
| 383 DVLOG(2) << "Unable to open DB file path."; | |
| 384 return; | |
| 385 } | |
| 386 | |
| 387 db_.reset(new sql::Connection()); | |
| 388 | |
| 389 db_->set_error_callback(base::Bind(&SqlLiteStorage::OnDatabaseError, this)); | |
| 390 | |
| 391 if (!db_->Open(path_)) { | |
| 392 DVLOG(2) << "Unable to open DB."; | |
| 393 db_.reset(); | |
| 394 return; | |
| 395 } | |
| 396 | |
| 397 if (!InitDB(db_.get())) { | |
| 398 DVLOG(2) << "Unable to init DB."; | |
| 399 db_.reset(); | |
| 400 return; | |
| 401 } | |
| 402 | |
| 403 db_->Preload(); | |
| 404 | |
| 405 // Delete expired identities. | |
| 406 DeleteBetween(base::Time(), base::Time::Now() - validity_period_); | |
| 407 | |
| 408 // Slurp all the identities into the out_map. | |
| 409 sql::Statement stmt(db_->GetUniqueStatement( | |
| 410 "SELECT origin, identity_name, common_name, " | |
| 411 "certificate, private_key, creation_time " | |
| 412 "FROM webrtc_identity_store")); | |
| 413 CHECK(stmt.is_valid()); | |
| 414 | |
| 415 while (stmt.Step()) { | |
| 416 IdentityKey key(GURL(stmt.ColumnString(0)), stmt.ColumnString(1)); | |
| 417 std::string common_name(stmt.ColumnString(2)); | |
| 418 std::string cert, private_key; | |
| 419 stmt.ColumnBlobAsString(3, &cert); | |
| 420 stmt.ColumnBlobAsString(4, &private_key); | |
| 421 int64_t creation_time = stmt.ColumnInt64(5); | |
| 422 std::pair<IdentityMap::iterator, bool> result = | |
| 423 out_map->insert(std::pair<IdentityKey, Identity>( | |
| 424 key, Identity(common_name, cert, private_key, creation_time))); | |
| 425 DCHECK(result.second); | |
| 426 } | |
| 427 } | |
| 428 | |
| 429 void WebRTCIdentityStoreBackend::SqlLiteStorage::Close() { | |
| 430 DCHECK_CURRENTLY_ON(BrowserThread::DB); | |
| 431 Commit(); | |
| 432 db_.reset(); | |
| 433 } | |
| 434 | |
| 435 void WebRTCIdentityStoreBackend::SqlLiteStorage::AddIdentity( | |
| 436 const GURL& origin, | |
| 437 const std::string& identity_name, | |
| 438 const Identity& identity) { | |
| 439 DCHECK_CURRENTLY_ON(BrowserThread::DB); | |
| 440 if (!db_.get()) | |
| 441 return; | |
| 442 | |
| 443 // Do not add for session only origins. | |
| 444 if (special_storage_policy_.get() && | |
| 445 !special_storage_policy_->IsStorageProtected(origin) && | |
| 446 special_storage_policy_->IsStorageSessionOnly(origin)) { | |
| 447 return; | |
| 448 } | |
| 449 BatchOperation(ADD_IDENTITY, origin, identity_name, identity); | |
| 450 } | |
| 451 | |
| 452 void WebRTCIdentityStoreBackend::SqlLiteStorage::DeleteIdentity( | |
| 453 const GURL& origin, | |
| 454 const std::string& identity_name, | |
| 455 const Identity& identity) { | |
| 456 DCHECK_CURRENTLY_ON(BrowserThread::DB); | |
| 457 if (!db_.get()) | |
| 458 return; | |
| 459 BatchOperation(DELETE_IDENTITY, origin, identity_name, identity); | |
| 460 } | |
| 461 | |
| 462 void WebRTCIdentityStoreBackend::SqlLiteStorage::DeleteBetween( | |
| 463 base::Time delete_begin, | |
| 464 base::Time delete_end) { | |
| 465 DCHECK_CURRENTLY_ON(BrowserThread::DB); | |
| 466 if (!db_.get()) | |
| 467 return; | |
| 468 | |
| 469 // Commit pending operations first. | |
| 470 Commit(); | |
| 471 | |
| 472 sql::Statement del_stmt(db_->GetCachedStatement( | |
| 473 SQL_FROM_HERE, | |
| 474 "DELETE FROM webrtc_identity_store" | |
| 475 " WHERE creation_time >= ? AND creation_time <= ?")); | |
| 476 CHECK(del_stmt.is_valid()); | |
| 477 | |
| 478 del_stmt.BindInt64(0, delete_begin.ToInternalValue()); | |
| 479 del_stmt.BindInt64(1, delete_end.ToInternalValue()); | |
| 480 | |
| 481 sql::Transaction transaction(db_.get()); | |
| 482 if (!transaction.Begin()) { | |
| 483 DVLOG(2) << "Failed to begin the transaction."; | |
| 484 return; | |
| 485 } | |
| 486 | |
| 487 if (!del_stmt.Run()) { | |
| 488 DVLOG(2) << "Failed to run the delete statement."; | |
| 489 return; | |
| 490 } | |
| 491 | |
| 492 if (!transaction.Commit()) | |
| 493 DVLOG(2) << "Failed to commit the transaction."; | |
| 494 } | |
| 495 | |
| 496 void WebRTCIdentityStoreBackend::SqlLiteStorage::OnDatabaseError( | |
| 497 int error, | |
| 498 sql::Statement* stmt) { | |
| 499 DCHECK_CURRENTLY_ON(BrowserThread::DB); | |
| 500 | |
| 501 db_->RazeAndClose(); | |
| 502 // It's not safe to reset |db_| here. | |
| 503 } | |
| 504 | |
| 505 void WebRTCIdentityStoreBackend::SqlLiteStorage::BatchOperation( | |
| 506 OperationType type, | |
| 507 const GURL& origin, | |
| 508 const std::string& identity_name, | |
| 509 const Identity& identity) { | |
| 510 DCHECK_CURRENTLY_ON(BrowserThread::DB); | |
| 511 // Commit every 30 seconds. | |
| 512 static const base::TimeDelta kCommitInterval( | |
| 513 base::TimeDelta::FromSeconds(30)); | |
| 514 // Commit right away if we have more than 512 outstanding operations. | |
| 515 static const size_t kCommitAfterBatchSize = 512; | |
| 516 | |
| 517 // We do a full copy of the cert here, and hopefully just here. | |
| 518 std::unique_ptr<PendingOperation> operation( | |
| 519 new PendingOperation(type, origin, identity_name, identity)); | |
| 520 | |
| 521 pending_operations_.push_back(operation.release()); | |
| 522 | |
| 523 if (pending_operations_.size() == 1) { | |
| 524 // We've gotten our first entry for this batch, fire off the timer. | |
| 525 BrowserThread::PostDelayedTask(BrowserThread::DB, | |
| 526 FROM_HERE, | |
| 527 base::Bind(&SqlLiteStorage::Commit, this), | |
| 528 kCommitInterval); | |
| 529 } else if (pending_operations_.size() >= kCommitAfterBatchSize) { | |
| 530 // We've reached a big enough batch, fire off a commit now. | |
| 531 BrowserThread::PostTask(BrowserThread::DB, | |
| 532 FROM_HERE, | |
| 533 base::Bind(&SqlLiteStorage::Commit, this)); | |
| 534 } | |
| 535 } | |
| 536 | |
| 537 void WebRTCIdentityStoreBackend::SqlLiteStorage::Commit() { | |
| 538 DCHECK_CURRENTLY_ON(BrowserThread::DB); | |
| 539 // Maybe an old timer fired or we are already Close()'ed. | |
| 540 if (!db_.get() || pending_operations_.empty()) | |
| 541 return; | |
| 542 | |
| 543 sql::Statement add_stmt(db_->GetCachedStatement( | |
| 544 SQL_FROM_HERE, | |
| 545 "INSERT INTO webrtc_identity_store " | |
| 546 "(origin, identity_name, common_name, certificate," | |
| 547 " private_key, creation_time) VALUES" | |
| 548 " (?,?,?,?,?,?)")); | |
| 549 | |
| 550 CHECK(add_stmt.is_valid()); | |
| 551 | |
| 552 sql::Statement del_stmt(db_->GetCachedStatement( | |
| 553 SQL_FROM_HERE, | |
| 554 "DELETE FROM webrtc_identity_store WHERE origin=? AND identity_name=?")); | |
| 555 | |
| 556 CHECK(del_stmt.is_valid()); | |
| 557 | |
| 558 sql::Transaction transaction(db_.get()); | |
| 559 if (!transaction.Begin()) { | |
| 560 DVLOG(2) << "Failed to begin the transaction."; | |
| 561 return; | |
| 562 } | |
| 563 | |
| 564 // Swaps |pending_operations_| into a temporary list to make sure | |
| 565 // |pending_operations_| is always cleared in case of DB errors. | |
| 566 PendingOperationList pending_operations_copy; | |
| 567 pending_operations_.swap(pending_operations_copy); | |
| 568 | |
| 569 for (PendingOperationList::const_iterator it = | |
| 570 pending_operations_copy.begin(); | |
| 571 it != pending_operations_copy.end(); | |
| 572 ++it) { | |
| 573 switch ((*it)->type) { | |
| 574 case ADD_IDENTITY: { | |
| 575 add_stmt.Reset(true); | |
| 576 add_stmt.BindString(0, (*it)->origin.spec()); | |
| 577 add_stmt.BindString(1, (*it)->identity_name); | |
| 578 add_stmt.BindString(2, (*it)->identity.common_name); | |
| 579 const std::string& cert = (*it)->identity.certificate; | |
| 580 add_stmt.BindBlob(3, cert.data(), cert.size()); | |
| 581 const std::string& private_key = (*it)->identity.private_key; | |
| 582 add_stmt.BindBlob(4, private_key.data(), private_key.size()); | |
| 583 add_stmt.BindInt64(5, (*it)->identity.creation_time); | |
| 584 if (!add_stmt.Run()) { | |
| 585 DVLOG(2) << "Failed to add the identity to DB."; | |
| 586 return; | |
| 587 } | |
| 588 break; | |
| 589 } | |
| 590 case DELETE_IDENTITY: | |
| 591 del_stmt.Reset(true); | |
| 592 del_stmt.BindString(0, (*it)->origin.spec()); | |
| 593 del_stmt.BindString(1, (*it)->identity_name); | |
| 594 if (!del_stmt.Run()) { | |
| 595 DVLOG(2) << "Failed to delete the identity from DB."; | |
| 596 return; | |
| 597 } | |
| 598 break; | |
| 599 | |
| 600 default: | |
| 601 NOTREACHED(); | |
| 602 break; | |
| 603 } | |
| 604 } | |
| 605 | |
| 606 if (!transaction.Commit()) | |
| 607 DVLOG(2) << "Failed to commit the transaction."; | |
| 608 } | |
| 609 | |
| 610 } // namespace content | |
| OLD | NEW |