| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/indexed_db/indexed_db_internals_ui.h" | 5 #include "content/browser/indexed_db/indexed_db_internals_ui.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/files/scoped_temp_dir.h" | 11 #include "base/files/scoped_temp_dir.h" |
| 12 #include "base/macros.h" | 12 #include "base/macros.h" |
| 13 #include "base/threading/platform_thread.h" | 13 #include "base/threading/platform_thread.h" |
| 14 #include "base/values.h" | 14 #include "base/values.h" |
| 15 #include "content/browser/indexed_db/indexed_db_context_impl.h" | 15 #include "content/browser/indexed_db/indexed_db_context_impl.h" |
| 16 #include "content/grit/content_resources.h" | 16 #include "content/grit/content_resources.h" |
| 17 #include "content/public/browser/browser_context.h" | 17 #include "content/public/browser/browser_context.h" |
| 18 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
| 19 #include "content/public/browser/download_manager.h" | 19 #include "content/public/browser/download_manager.h" |
| 20 #include "content/public/browser/download_url_parameters.h" | 20 #include "content/public/browser/download_url_parameters.h" |
| 21 #include "content/public/browser/storage_partition.h" | 21 #include "content/public/browser/storage_partition.h" |
| 22 #include "content/public/browser/web_contents.h" | 22 #include "content/public/browser/web_contents.h" |
| 23 #include "content/public/browser/web_ui.h" | 23 #include "content/public/browser/web_ui.h" |
| 24 #include "content/public/browser/web_ui_data_source.h" | 24 #include "content/public/browser/web_ui_data_source.h" |
| 25 #include "content/public/common/url_constants.h" | 25 #include "content/public/common/url_constants.h" |
| 26 #include "storage/common/database/database_identifier.h" | 26 #include "storage/common/database/database_identifier.h" |
| 27 #include "third_party/zlib/google/zip.h" | 27 #include "third_party/zlib/google/zip.h" |
| 28 #include "ui/base/text/bytes_formatting.h" | 28 #include "ui/base/text/bytes_formatting.h" |
| 29 #include "url/origin.h" |
| 30 |
| 31 using url::Origin; |
| 29 | 32 |
| 30 namespace content { | 33 namespace content { |
| 31 | 34 |
| 32 namespace { | 35 namespace { |
| 33 | 36 |
| 34 bool AllowWhitelistedPaths(const std::vector<base::FilePath>& allowed_paths, | 37 bool AllowWhitelistedPaths(const std::vector<base::FilePath>& allowed_paths, |
| 35 const base::FilePath& candidate_path) { | 38 const base::FilePath& candidate_path) { |
| 36 for (const base::FilePath& allowed_path : allowed_paths) { | 39 for (const base::FilePath& allowed_path : allowed_paths) { |
| 37 if (allowed_path.IsParent(candidate_path)) | 40 if (allowed_path.IsParent(candidate_path)) |
| 38 return true; | 41 return true; |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 if (storage_partition->GetPath() == partition_path) { | 135 if (storage_partition->GetPath() == partition_path) { |
| 133 *result_partition = storage_partition; | 136 *result_partition = storage_partition; |
| 134 *result_context = static_cast<IndexedDBContextImpl*>( | 137 *result_context = static_cast<IndexedDBContextImpl*>( |
| 135 storage_partition->GetIndexedDBContext()); | 138 storage_partition->GetIndexedDBContext()); |
| 136 } | 139 } |
| 137 } | 140 } |
| 138 | 141 |
| 139 bool IndexedDBInternalsUI::GetOriginData( | 142 bool IndexedDBInternalsUI::GetOriginData( |
| 140 const base::ListValue* args, | 143 const base::ListValue* args, |
| 141 base::FilePath* partition_path, | 144 base::FilePath* partition_path, |
| 142 GURL* origin_url, | 145 Origin* origin, |
| 143 scoped_refptr<IndexedDBContextImpl>* context) { | 146 scoped_refptr<IndexedDBContextImpl>* context) { |
| 144 base::FilePath::StringType path_string; | 147 base::FilePath::StringType path_string; |
| 145 if (!args->GetString(0, &path_string)) | 148 if (!args->GetString(0, &path_string)) |
| 146 return false; | 149 return false; |
| 147 *partition_path = base::FilePath(path_string); | 150 *partition_path = base::FilePath(path_string); |
| 148 | 151 |
| 149 std::string url_string; | 152 std::string url_string; |
| 150 if (!args->GetString(1, &url_string)) | 153 if (!args->GetString(1, &url_string)) |
| 151 return false; | 154 return false; |
| 152 | 155 |
| 153 *origin_url = GURL(url_string); | 156 *origin = Origin(GURL(url_string)); |
| 154 | 157 |
| 155 return GetOriginContext(*partition_path, *origin_url, context); | 158 return GetOriginContext(*partition_path, *origin, context); |
| 156 } | 159 } |
| 157 | 160 |
| 158 bool IndexedDBInternalsUI::GetOriginContext( | 161 bool IndexedDBInternalsUI::GetOriginContext( |
| 159 const base::FilePath& path, | 162 const base::FilePath& path, |
| 160 const GURL& origin_url, | 163 const Origin& origin, |
| 161 scoped_refptr<IndexedDBContextImpl>* context) { | 164 scoped_refptr<IndexedDBContextImpl>* context) { |
| 162 // search the origins to find the right context | 165 // search the origins to find the right context |
| 163 BrowserContext* browser_context = | 166 BrowserContext* browser_context = |
| 164 web_ui()->GetWebContents()->GetBrowserContext(); | 167 web_ui()->GetWebContents()->GetBrowserContext(); |
| 165 | 168 |
| 166 StoragePartition* result_partition; | 169 StoragePartition* result_partition; |
| 167 BrowserContext::StoragePartitionCallback cb = | 170 BrowserContext::StoragePartitionCallback cb = |
| 168 base::Bind(&FindContext, path, &result_partition, context); | 171 base::Bind(&FindContext, path, &result_partition, context); |
| 169 BrowserContext::ForEachStoragePartition(browser_context, cb); | 172 BrowserContext::ForEachStoragePartition(browser_context, cb); |
| 170 | 173 |
| 171 if (!result_partition || !(context->get())) | 174 if (!result_partition || !(context->get())) |
| 172 return false; | 175 return false; |
| 173 | 176 |
| 174 return true; | 177 return true; |
| 175 } | 178 } |
| 176 | 179 |
| 177 void IndexedDBInternalsUI::DownloadOriginData(const base::ListValue* args) { | 180 void IndexedDBInternalsUI::DownloadOriginData(const base::ListValue* args) { |
| 178 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 181 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 179 | 182 |
| 180 base::FilePath partition_path; | 183 base::FilePath partition_path; |
| 181 GURL origin_url; | 184 Origin origin; |
| 182 scoped_refptr<IndexedDBContextImpl> context; | 185 scoped_refptr<IndexedDBContextImpl> context; |
| 183 if (!GetOriginData(args, &partition_path, &origin_url, &context)) | 186 if (!GetOriginData(args, &partition_path, &origin, &context)) |
| 184 return; | 187 return; |
| 185 | 188 |
| 186 DCHECK(context.get()); | 189 DCHECK(context.get()); |
| 187 context->TaskRunner()->PostTask( | 190 context->TaskRunner()->PostTask( |
| 188 FROM_HERE, | 191 FROM_HERE, |
| 189 base::Bind(&IndexedDBInternalsUI::DownloadOriginDataOnIndexedDBThread, | 192 base::Bind(&IndexedDBInternalsUI::DownloadOriginDataOnIndexedDBThread, |
| 190 base::Unretained(this), | 193 base::Unretained(this), partition_path, context, origin)); |
| 191 partition_path, | |
| 192 context, | |
| 193 origin_url)); | |
| 194 } | 194 } |
| 195 | 195 |
| 196 void IndexedDBInternalsUI::ForceCloseOrigin(const base::ListValue* args) { | 196 void IndexedDBInternalsUI::ForceCloseOrigin(const base::ListValue* args) { |
| 197 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 197 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 198 | 198 |
| 199 base::FilePath partition_path; | 199 base::FilePath partition_path; |
| 200 GURL origin_url; | 200 Origin origin; |
| 201 scoped_refptr<IndexedDBContextImpl> context; | 201 scoped_refptr<IndexedDBContextImpl> context; |
| 202 if (!GetOriginData(args, &partition_path, &origin_url, &context)) | 202 if (!GetOriginData(args, &partition_path, &origin, &context)) |
| 203 return; | 203 return; |
| 204 | 204 |
| 205 context->TaskRunner()->PostTask( | 205 context->TaskRunner()->PostTask( |
| 206 FROM_HERE, | 206 FROM_HERE, |
| 207 base::Bind(&IndexedDBInternalsUI::ForceCloseOriginOnIndexedDBThread, | 207 base::Bind(&IndexedDBInternalsUI::ForceCloseOriginOnIndexedDBThread, |
| 208 base::Unretained(this), | 208 base::Unretained(this), partition_path, context, origin)); |
| 209 partition_path, | |
| 210 context, | |
| 211 origin_url)); | |
| 212 } | 209 } |
| 213 | 210 |
| 214 void IndexedDBInternalsUI::DownloadOriginDataOnIndexedDBThread( | 211 void IndexedDBInternalsUI::DownloadOriginDataOnIndexedDBThread( |
| 215 const base::FilePath& partition_path, | 212 const base::FilePath& partition_path, |
| 216 const scoped_refptr<IndexedDBContextImpl> context, | 213 const scoped_refptr<IndexedDBContextImpl> context, |
| 217 const GURL& origin_url) { | 214 const Origin& origin) { |
| 218 DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread()); | 215 DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread()); |
| 219 // This runs on the IndexedDB task runner to prevent script from reopening | 216 // This runs on the IndexedDB task runner to prevent script from reopening |
| 220 // the origin while we are zipping. | 217 // the origin while we are zipping. |
| 221 | 218 |
| 222 // Make sure the database hasn't been deleted since the page was loaded. | 219 // Make sure the database hasn't been deleted since the page was loaded. |
| 223 if (!context->HasOrigin(origin_url)) | 220 if (!context->HasOrigin(origin)) |
| 224 return; | 221 return; |
| 225 | 222 |
| 226 context->ForceClose(origin_url, | 223 context->ForceClose(origin, IndexedDBContextImpl::FORCE_CLOSE_INTERNALS_PAGE); |
| 227 IndexedDBContextImpl::FORCE_CLOSE_INTERNALS_PAGE); | 224 size_t connection_count = context->GetConnectionCount(origin); |
| 228 size_t connection_count = context->GetConnectionCount(origin_url); | |
| 229 | 225 |
| 230 base::ScopedTempDir temp_dir; | 226 base::ScopedTempDir temp_dir; |
| 231 if (!temp_dir.CreateUniqueTempDir()) | 227 if (!temp_dir.CreateUniqueTempDir()) |
| 232 return; | 228 return; |
| 233 | 229 |
| 234 // This will get cleaned up on the File thread after the download | 230 // This will get cleaned up on the File thread after the download |
| 235 // has completed. | 231 // has completed. |
| 236 base::FilePath temp_path = temp_dir.Take(); | 232 base::FilePath temp_path = temp_dir.Take(); |
| 237 | 233 |
| 238 std::string origin_id = storage::GetIdentifierFromOrigin(origin_url); | 234 std::string origin_id = |
| 235 storage::GetIdentifierFromOrigin(GURL(origin.Serialize())); |
| 239 base::FilePath zip_path = | 236 base::FilePath zip_path = |
| 240 temp_path.AppendASCII(origin_id).AddExtension(FILE_PATH_LITERAL("zip")); | 237 temp_path.AppendASCII(origin_id).AddExtension(FILE_PATH_LITERAL("zip")); |
| 241 | 238 |
| 242 std::vector<base::FilePath> paths = context->GetStoragePaths(origin_url); | 239 std::vector<base::FilePath> paths = context->GetStoragePaths(origin); |
| 243 zip::ZipWithFilterCallback(context->data_path(), zip_path, | 240 zip::ZipWithFilterCallback(context->data_path(), zip_path, |
| 244 base::Bind(AllowWhitelistedPaths, paths)); | 241 base::Bind(AllowWhitelistedPaths, paths)); |
| 245 | 242 |
| 246 BrowserThread::PostTask(BrowserThread::UI, | 243 BrowserThread::PostTask( |
| 247 FROM_HERE, | 244 BrowserThread::UI, FROM_HERE, |
| 248 base::Bind(&IndexedDBInternalsUI::OnDownloadDataReady, | 245 base::Bind(&IndexedDBInternalsUI::OnDownloadDataReady, |
| 249 base::Unretained(this), | 246 base::Unretained(this), partition_path, origin, temp_path, |
| 250 partition_path, | 247 zip_path, connection_count)); |
| 251 origin_url, | |
| 252 temp_path, | |
| 253 zip_path, | |
| 254 connection_count)); | |
| 255 } | 248 } |
| 256 | 249 |
| 257 void IndexedDBInternalsUI::ForceCloseOriginOnIndexedDBThread( | 250 void IndexedDBInternalsUI::ForceCloseOriginOnIndexedDBThread( |
| 258 const base::FilePath& partition_path, | 251 const base::FilePath& partition_path, |
| 259 const scoped_refptr<IndexedDBContextImpl> context, | 252 const scoped_refptr<IndexedDBContextImpl> context, |
| 260 const GURL& origin_url) { | 253 const Origin& origin) { |
| 261 DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread()); | 254 DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread()); |
| 262 | 255 |
| 263 // Make sure the database hasn't been deleted since the page was loaded. | 256 // Make sure the database hasn't been deleted since the page was loaded. |
| 264 if (!context->HasOrigin(origin_url)) | 257 if (!context->HasOrigin(origin)) |
| 265 return; | 258 return; |
| 266 | 259 |
| 267 context->ForceClose(origin_url, | 260 context->ForceClose(origin, IndexedDBContextImpl::FORCE_CLOSE_INTERNALS_PAGE); |
| 268 IndexedDBContextImpl::FORCE_CLOSE_INTERNALS_PAGE); | 261 size_t connection_count = context->GetConnectionCount(origin); |
| 269 size_t connection_count = context->GetConnectionCount(origin_url); | |
| 270 | 262 |
| 271 BrowserThread::PostTask(BrowserThread::UI, | 263 BrowserThread::PostTask( |
| 272 FROM_HERE, | 264 BrowserThread::UI, FROM_HERE, |
| 273 base::Bind(&IndexedDBInternalsUI::OnForcedClose, | 265 base::Bind(&IndexedDBInternalsUI::OnForcedClose, base::Unretained(this), |
| 274 base::Unretained(this), | 266 partition_path, origin, connection_count)); |
| 275 partition_path, | |
| 276 origin_url, | |
| 277 connection_count)); | |
| 278 } | 267 } |
| 279 | 268 |
| 280 void IndexedDBInternalsUI::OnForcedClose(const base::FilePath& partition_path, | 269 void IndexedDBInternalsUI::OnForcedClose(const base::FilePath& partition_path, |
| 281 const GURL& origin_url, | 270 const Origin& origin, |
| 282 size_t connection_count) { | 271 size_t connection_count) { |
| 283 web_ui()->CallJavascriptFunction( | 272 web_ui()->CallJavascriptFunction( |
| 284 "indexeddb.onForcedClose", | 273 "indexeddb.onForcedClose", base::StringValue(partition_path.value()), |
| 285 base::StringValue(partition_path.value()), | 274 base::StringValue(origin.Serialize()), |
| 286 base::StringValue(origin_url.spec()), | |
| 287 base::FundamentalValue(static_cast<double>(connection_count))); | 275 base::FundamentalValue(static_cast<double>(connection_count))); |
| 288 } | 276 } |
| 289 | 277 |
| 290 void IndexedDBInternalsUI::OnDownloadDataReady( | 278 void IndexedDBInternalsUI::OnDownloadDataReady( |
| 291 const base::FilePath& partition_path, | 279 const base::FilePath& partition_path, |
| 292 const GURL& origin_url, | 280 const Origin& origin, |
| 293 const base::FilePath temp_path, | 281 const base::FilePath temp_path, |
| 294 const base::FilePath zip_path, | 282 const base::FilePath zip_path, |
| 295 size_t connection_count) { | 283 size_t connection_count) { |
| 296 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 284 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 297 const GURL url = GURL(FILE_PATH_LITERAL("file://") + zip_path.value()); | 285 const GURL url = GURL(FILE_PATH_LITERAL("file://") + zip_path.value()); |
| 298 BrowserContext* browser_context = | 286 BrowserContext* browser_context = |
| 299 web_ui()->GetWebContents()->GetBrowserContext(); | 287 web_ui()->GetWebContents()->GetBrowserContext(); |
| 300 std::unique_ptr<DownloadUrlParameters> dl_params( | 288 std::unique_ptr<DownloadUrlParameters> dl_params( |
| 301 DownloadUrlParameters::FromWebContents(web_ui()->GetWebContents(), url)); | 289 DownloadUrlParameters::FromWebContents(web_ui()->GetWebContents(), url)); |
| 302 DownloadManager* dlm = BrowserContext::GetDownloadManager(browser_context); | 290 DownloadManager* dlm = BrowserContext::GetDownloadManager(browser_context); |
| 303 | 291 |
| 304 const GURL referrer(web_ui()->GetWebContents()->GetLastCommittedURL()); | 292 const GURL referrer(web_ui()->GetWebContents()->GetLastCommittedURL()); |
| 305 dl_params->set_referrer(content::Referrer::SanitizeForRequest( | 293 dl_params->set_referrer(content::Referrer::SanitizeForRequest( |
| 306 url, content::Referrer(referrer, blink::WebReferrerPolicyDefault))); | 294 url, content::Referrer(referrer, blink::WebReferrerPolicyDefault))); |
| 307 | 295 |
| 308 // This is how to watch for the download to finish: first wait for it | 296 // This is how to watch for the download to finish: first wait for it |
| 309 // to start, then attach a DownloadItem::Observer to observe the | 297 // to start, then attach a DownloadItem::Observer to observe the |
| 310 // state change to the finished state. | 298 // state change to the finished state. |
| 311 dl_params->set_callback(base::Bind(&IndexedDBInternalsUI::OnDownloadStarted, | 299 dl_params->set_callback(base::Bind(&IndexedDBInternalsUI::OnDownloadStarted, |
| 312 base::Unretained(this), | 300 base::Unretained(this), partition_path, |
| 313 partition_path, | 301 origin, temp_path, connection_count)); |
| 314 origin_url, | |
| 315 temp_path, | |
| 316 connection_count)); | |
| 317 dlm->DownloadUrl(std::move(dl_params)); | 302 dlm->DownloadUrl(std::move(dl_params)); |
| 318 } | 303 } |
| 319 | 304 |
| 320 // The entire purpose of this class is to delete the temp file after | 305 // The entire purpose of this class is to delete the temp file after |
| 321 // the download is complete. | 306 // the download is complete. |
| 322 class FileDeleter : public DownloadItem::Observer { | 307 class FileDeleter : public DownloadItem::Observer { |
| 323 public: | 308 public: |
| 324 explicit FileDeleter(const base::FilePath& temp_dir) : temp_dir_(temp_dir) {} | 309 explicit FileDeleter(const base::FilePath& temp_dir) : temp_dir_(temp_dir) {} |
| 325 ~FileDeleter() override; | 310 ~FileDeleter() override; |
| 326 | 311 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 352 } | 337 } |
| 353 | 338 |
| 354 FileDeleter::~FileDeleter() { | 339 FileDeleter::~FileDeleter() { |
| 355 base::ScopedTempDir path; | 340 base::ScopedTempDir path; |
| 356 bool will_delete = path.Set(temp_dir_); | 341 bool will_delete = path.Set(temp_dir_); |
| 357 DCHECK(will_delete); | 342 DCHECK(will_delete); |
| 358 } | 343 } |
| 359 | 344 |
| 360 void IndexedDBInternalsUI::OnDownloadStarted( | 345 void IndexedDBInternalsUI::OnDownloadStarted( |
| 361 const base::FilePath& partition_path, | 346 const base::FilePath& partition_path, |
| 362 const GURL& origin_url, | 347 const Origin& origin, |
| 363 const base::FilePath& temp_path, | 348 const base::FilePath& temp_path, |
| 364 size_t connection_count, | 349 size_t connection_count, |
| 365 DownloadItem* item, | 350 DownloadItem* item, |
| 366 DownloadInterruptReason interrupt_reason) { | 351 DownloadInterruptReason interrupt_reason) { |
| 367 | |
| 368 if (interrupt_reason != DOWNLOAD_INTERRUPT_REASON_NONE) { | 352 if (interrupt_reason != DOWNLOAD_INTERRUPT_REASON_NONE) { |
| 369 LOG(ERROR) << "Error downloading database dump: " | 353 LOG(ERROR) << "Error downloading database dump: " |
| 370 << DownloadInterruptReasonToString(interrupt_reason); | 354 << DownloadInterruptReasonToString(interrupt_reason); |
| 371 return; | 355 return; |
| 372 } | 356 } |
| 373 | 357 |
| 374 item->AddObserver(new FileDeleter(temp_path)); | 358 item->AddObserver(new FileDeleter(temp_path)); |
| 375 web_ui()->CallJavascriptFunction( | 359 web_ui()->CallJavascriptFunction( |
| 376 "indexeddb.onOriginDownloadReady", | 360 "indexeddb.onOriginDownloadReady", |
| 377 base::StringValue(partition_path.value()), | 361 base::StringValue(partition_path.value()), |
| 378 base::StringValue(origin_url.spec()), | 362 base::StringValue(origin.Serialize()), |
| 379 base::FundamentalValue(static_cast<double>(connection_count))); | 363 base::FundamentalValue(static_cast<double>(connection_count))); |
| 380 } | 364 } |
| 381 | 365 |
| 382 } // namespace content | 366 } // namespace content |
| OLD | NEW |