| // Copyright (c) 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/offline_pages/recent_tab_helper.h" |
| |
| #include <queue> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/location.h" |
| #include "base/macros.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/system/sys_info.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "chrome/browser/offline_pages/offline_page_mhtml_archiver.h" |
| #include "chrome/browser/offline_pages/offline_page_model_factory.h" |
| #include "chrome/browser/offline_pages/offline_page_utils.h" |
| #include "chrome/browser/offline_pages/request_coordinator_factory.h" |
| #include "components/offline_pages/core/background/request_coordinator.h" |
| #include "components/offline_pages/core/client_namespace_constants.h" |
| #include "components/offline_pages/core/offline_page_feature.h" |
| #include "components/offline_pages/core/offline_page_item.h" |
| #include "components/offline_pages/core/offline_page_model.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/navigation_entry.h" |
| #include "content/public/browser/navigation_handle.h" |
| |
| namespace { |
| class DefaultRecentTabHelperDelegate |
| : public offline_pages::RecentTabHelper::Delegate { |
| public: |
| DefaultRecentTabHelperDelegate() |
| : is_low_end_device_(base::SysInfo::IsLowEndDevice()) {} |
| |
| // offline_pages::RecentTabHelper::Delegate |
| std::unique_ptr<offline_pages::OfflinePageArchiver> CreatePageArchiver( |
| content::WebContents* web_contents) override { |
| return std::make_unique<offline_pages::OfflinePageMHTMLArchiver>(); |
| } |
| bool GetTabId(content::WebContents* web_contents, int* tab_id) override { |
| return offline_pages::OfflinePageUtils::GetTabId(web_contents, tab_id); |
| } |
| bool IsLowEndDevice() override { return is_low_end_device_; } |
| |
| bool IsCustomTab(content::WebContents* web_contents) override { |
| return offline_pages::OfflinePageUtils::CurrentlyShownInCustomTab( |
| web_contents); |
| } |
| |
| private: |
| // Cached value of whether low end device. |
| bool is_low_end_device_; |
| }; |
| } // namespace |
| |
| namespace offline_pages { |
| |
| using PageQuality = SnapshotController::PageQuality; |
| |
| // Keeps client_id/request_id that will be used for the offline snapshot. |
| struct RecentTabHelper::SnapshotProgressInfo { |
| public: |
| // For a downloads snapshot request, where the |request_id| is defined. |
| SnapshotProgressInfo(const ClientId& client_id, |
| int64_t request_id, |
| const std::string& origin) |
| : client_id(client_id), request_id(request_id), origin(origin) {} |
| |
| // For a last_n snapshot request. |
| explicit SnapshotProgressInfo(const ClientId& client_id) |
| : client_id(client_id) {} |
| |
| bool IsForLastN() { return client_id.name_space == kLastNNamespace; } |
| |
| // The ClientID to go with the offline page. |
| ClientId client_id; |
| |
| // Id of the suspended request in Background Offliner. Used to un-suspend |
| // the request if the capture of the current page was not possible (e.g. |
| // the user navigated to another page before current one was loaded). |
| // 0 if this is a "last_n" info. |
| int64_t request_id = OfflinePageModel::kInvalidOfflineId; |
| |
| // Expected snapshot quality should the saving succeed. This value is only |
| // valid for successfully saved snapshots. |
| SnapshotController::PageQuality expected_page_quality = |
| SnapshotController::PageQuality::POOR; |
| |
| // The app that created the tab - either a package name of the CCT origin |
| // or empty, meaning chrome. |
| std::string origin = ""; |
| }; |
| |
| RecentTabHelper::RecentTabHelper(content::WebContents* web_contents) |
| : content::WebContentsObserver(web_contents), |
| delegate_(new DefaultRecentTabHelperDelegate()), |
| weak_ptr_factory_(this) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| } |
| |
| RecentTabHelper::~RecentTabHelper() { |
| } |
| |
| void RecentTabHelper::SetDelegate( |
| std::unique_ptr<RecentTabHelper::Delegate> delegate) { |
| DCHECK(delegate); |
| delegate_ = std::move(delegate); |
| } |
| |
| void RecentTabHelper::ObserveAndDownloadCurrentPage(const ClientId& client_id, |
| int64_t request_id, |
| const std::string& origin) { |
| // Note: as this implementation only supports one client namespace, enforce |
| // that the call is from Downloads. |
| DCHECK_EQ(kDownloadNamespace, client_id.name_space); |
| auto new_downloads_snapshot_info = |
| std::make_unique<SnapshotProgressInfo>(client_id, request_id, origin); |
| |
| // If this tab helper is not enabled, immediately give the job back to |
| // RequestCoordinator. |
| if (!EnsureInitialized()) { |
| DVLOG(1) << "Snapshots disabled; ignored download request for: " |
| << web_contents()->GetLastCommittedURL().spec(); |
| ReportDownloadStatusToRequestCoordinator(new_downloads_snapshot_info.get(), |
| false); |
| return; |
| } |
| |
| // If there is an ongoing snapshot request, completely ignore this one and |
| // cancel the Background Offliner request. |
| // TODO(carlosk): it might be better to make the decision to schedule or not |
| // the background request here. See https://crbug.com/686165. |
| if (downloads_ongoing_snapshot_info_) { |
| DVLOG(1) << "Ongoing request exist; ignored download request for: " |
| << web_contents()->GetLastCommittedURL().spec(); |
| ReportDownloadStatusToRequestCoordinator(new_downloads_snapshot_info.get(), |
| true); |
| return; |
| } |
| |
| // Stores the new snapshot info. |
| downloads_ongoing_snapshot_info_ = std::move(new_downloads_snapshot_info); |
| |
| // If the page is not yet ready for a snapshot return now as it will be |
| // started later, once page loading advances. |
| if (PageQuality::POOR == snapshot_controller_->current_page_quality()) { |
| DVLOG(1) << "Waiting for the page to load before fulfilling download " |
| << "request for: " << web_contents()->GetLastCommittedURL().spec(); |
| downloads_snapshot_on_hold_ = true; |
| return; |
| } |
| |
| // Otherwise start saving the snapshot now. |
| DVLOG(1) << "Starting download request for: " |
| << web_contents()->GetLastCommittedURL().spec(); |
| SaveSnapshotForDownloads(false); |
| } |
| |
| // Initialize lazily. It needs TabAndroid for initialization, which is also a |
| // TabHelper - so can't initialize in constructor because of uncertain order |
| // of creation of TabHelpers. |
| bool RecentTabHelper::EnsureInitialized() { |
| if (snapshot_controller_) // Initialized already. |
| return snapshots_enabled_; |
| |
| snapshot_controller_ = std::make_unique<SnapshotController>( |
| base::ThreadTaskRunnerHandle::Get(), this); |
| snapshot_controller_->Stop(); // It is reset when navigation commits. |
| |
| int tab_id_number = 0; |
| tab_id_.clear(); |
| |
| if (delegate_->GetTabId(web_contents(), &tab_id_number)) |
| tab_id_ = base::IntToString(tab_id_number); |
| |
| // TODO(dimich): When we have BackgroundOffliner, avoid capturing prerenderer |
| // WebContents with its origin as well. |
| snapshots_enabled_ = !tab_id_.empty() && |
| !web_contents()->GetBrowserContext()->IsOffTheRecord(); |
| |
| if (snapshots_enabled_) { |
| page_model_ = OfflinePageModelFactory::GetForBrowserContext( |
| web_contents()->GetBrowserContext()); |
| } |
| |
| return snapshots_enabled_; |
| } |
| |
| void RecentTabHelper::DidFinishNavigation( |
| content::NavigationHandle* navigation_handle) { |
| if (!navigation_handle->IsInMainFrame() || |
| !navigation_handle->HasCommitted() || |
| navigation_handle->IsSameDocument()) { |
| DVLOG_IF(1, navigation_handle->IsInMainFrame()) |
| << "Main frame navigation ignored (reasons: " |
| << !navigation_handle->HasCommitted() << ", " |
| << navigation_handle->IsSameDocument() |
| << ") to: " << web_contents()->GetLastCommittedURL().spec(); |
| return; |
| } |
| |
| if (!EnsureInitialized()) |
| return; |
| DVLOG(1) << "Navigation acknowledged to: " |
| << web_contents()->GetLastCommittedURL().spec(); |
| |
| // If there is an ongoing downloads request, lets make Background Offliner |
| // take over downloading that page. |
| if (downloads_ongoing_snapshot_info_) { |
| DVLOG(1) << " - Passing ongoing downloads request to Background Offliner"; |
| ReportDownloadStatusToRequestCoordinator( |
| downloads_ongoing_snapshot_info_.get(), false); |
| } |
| |
| // If currently loading an offline page get a pointer to it. It will be null |
| // otherwise. |
| const OfflinePageItem* current_offline_page = |
| OfflinePageUtils::GetOfflinePageFromWebContents(web_contents()); |
| |
| // If the previous page was saved, delete it now unless we are currently |
| // loading that very snapshot. |
| if (last_n_latest_saved_snapshot_info_ && |
| (!current_offline_page || |
| current_offline_page->offline_id != |
| last_n_latest_saved_snapshot_info_->request_id)) { |
| DVLOG(1) << " - Deleting previous last_n snapshot with offline_id " |
| << last_n_latest_saved_snapshot_info_->request_id; |
| std::vector<int64_t> id{last_n_latest_saved_snapshot_info_->request_id}; |
| page_model_->DeletePagesByOfflineId(id, DeletePageCallback()); |
| last_n_latest_saved_snapshot_info_.reset(); |
| } |
| |
| // Cancel any and all in flight snapshot tasks from the previous page. |
| CancelInFlightSnapshots(); |
| downloads_snapshot_on_hold_ = false; |
| |
| // Always reset so that posted tasks get canceled. |
| snapshot_controller_->Reset(); |
| |
| // Check for conditions that should stop us from creating snapshots of |
| // this page: |
| // - It is an error page. |
| // - The navigated URL is not supported. |
| // - The page being loaded is already an offline page. |
| bool can_save = |
| !navigation_handle->IsErrorPage() && |
| OfflinePageModel::CanSaveURL(web_contents()->GetLastCommittedURL()) && |
| current_offline_page == nullptr; |
| DVLOG_IF(1, !can_save) |
| << " - Page can not be saved for offline usage (reasons: " |
| << !navigation_handle->IsErrorPage() << ", " |
| << OfflinePageModel::CanSaveURL(web_contents()->GetLastCommittedURL()) |
| << ", " << (current_offline_page == nullptr) << ")"; |
| |
| UMA_HISTOGRAM_BOOLEAN("OfflinePages.CanSaveRecentPage", can_save); |
| |
| if (!can_save) |
| snapshot_controller_->Stop(); |
| // Last N should be disabled when: |
| // - Running on low end devices. |
| // - Viewing POST content for privacy considerations. |
| // - Disabled by flag. |
| last_n_listen_to_tab_hidden_ = can_save && !delegate_->IsLowEndDevice() && |
| !navigation_handle->IsPost() && |
| IsOffliningRecentPagesEnabled(); |
| DVLOG_IF(1, can_save && !last_n_listen_to_tab_hidden_) |
| << " - Page can not be saved by last_n"; |
| } |
| |
| void RecentTabHelper::DocumentAvailableInMainFrame() { |
| EnsureInitialized(); |
| snapshot_controller_->DocumentAvailableInMainFrame(); |
| } |
| |
| void RecentTabHelper::DocumentOnLoadCompletedInMainFrame() { |
| EnsureInitialized(); |
| snapshot_controller_->DocumentOnLoadCompletedInMainFrame(); |
| } |
| |
| void RecentTabHelper::WebContentsDestroyed() { |
| // If there is an ongoing downloads request, lets allow Background Offliner to |
| // continue downloading this page. |
| if (downloads_ongoing_snapshot_info_) { |
| DVLOG(1) << "WebContents destroyed; passing ongoing downloads request to " |
| "Background Offliner"; |
| ReportDownloadStatusToRequestCoordinator( |
| downloads_ongoing_snapshot_info_.get(), false); |
| } |
| // And cancel any ongoing snapshots. |
| CancelInFlightSnapshots(); |
| } |
| |
| void RecentTabHelper::OnVisibilityChanged(content::Visibility visibility) { |
| if (visibility == content::Visibility::HIDDEN) |
| WebContentsWasHidden(); |
| else |
| WebContentsWasShown(); |
| } |
| |
| void RecentTabHelper::WebContentsWasHidden() { |
| if (!IsOffliningRecentPagesEnabled()) |
| return; |
| |
| // Do not save a snapshots if any of these are true: |
| // - Last_n is not listening to tab hidden events. |
| // - A last_n snapshot is currently being saved. |
| // - The tab is in the process of being closed. |
| // - The tab is currently presented as a custom tab. |
| if (!last_n_listen_to_tab_hidden_ || last_n_ongoing_snapshot_info_ || |
| tab_is_closing_ || delegate_->IsCustomTab(web_contents())) { |
| DVLOG(1) << "Will not snapshot for last_n (reasons: " |
| << !last_n_listen_to_tab_hidden_ << ", " |
| << !!last_n_ongoing_snapshot_info_ << ", " << tab_is_closing_ |
| << ", " << delegate_->IsCustomTab(web_contents()) |
| << ") for: " << web_contents()->GetLastCommittedURL().spec(); |
| return; |
| } |
| |
| // Do not save if page quality is too low. |
| // Note: we assume page quality for a page can only increase. |
| if (snapshot_controller_->current_page_quality() == PageQuality::POOR) { |
| DVLOG(1) << "Will not snapshot for last_n (page quality too low) for: " |
| << web_contents()->GetLastCommittedURL().spec(); |
| return; |
| } |
| |
| DVLOG(1) << "Starting last_n snapshot for: " |
| << web_contents()->GetLastCommittedURL().spec(); |
| last_n_ongoing_snapshot_info_ = |
| std::make_unique<SnapshotProgressInfo>(GetRecentPagesClientId()); |
| DCHECK(last_n_ongoing_snapshot_info_->IsForLastN()); |
| DCHECK(snapshots_enabled_); |
| // Remove previously captured pages for this tab. |
| page_model_->GetOfflineIdsForClientId( |
| GetRecentPagesClientId(), |
| base::Bind(&RecentTabHelper::ContinueSnapshotWithIdsToPurge, |
| weak_ptr_factory_.GetWeakPtr(), |
| last_n_ongoing_snapshot_info_.get())); |
| |
| IsSavingSamePageEnum saving_same_page_value = IsSavingSamePageEnum::kNewPage; |
| if (last_n_latest_saved_snapshot_info_) { |
| // If there was a previously saved snapshot for the current page we are |
| // saving a new one for the same page. |
| // Note: there might be a difference in page quality between here and when |
| // it's assessed again in ContinueSnapshotAfterPurge but this is not |
| // expected to happen often. |
| if (last_n_latest_saved_snapshot_info_->expected_page_quality == |
| snapshot_controller_->current_page_quality()) { |
| saving_same_page_value = IsSavingSamePageEnum::kSamePageSameQuality; |
| } else { |
| saving_same_page_value = IsSavingSamePageEnum::kSamePageBetterQuality; |
| } |
| } |
| UMA_HISTOGRAM_ENUMERATION("OfflinePages.LastN.IsSavingSamePage", |
| saving_same_page_value); |
| |
| last_n_latest_saved_snapshot_info_.reset(); |
| } |
| |
| void RecentTabHelper::WebContentsWasShown() { |
| // If the tab was closing and is now being shown, the closure was reverted. |
| DVLOG_IF(0, tab_is_closing_) << "Tab is not closing anymore: " |
| << web_contents()->GetLastCommittedURL().spec(); |
| tab_is_closing_ = false; |
| } |
| |
| void RecentTabHelper::WillCloseTab() { |
| DVLOG(1) << "Tab is now closing: " |
| << web_contents()->GetLastCommittedURL().spec(); |
| tab_is_closing_ = true; |
| } |
| |
| // TODO(carlosk): rename this to RequestSnapshot and make it return a bool |
| // representing the acceptance of the snapshot request. |
| void RecentTabHelper::StartSnapshot() { |
| DCHECK_NE(PageQuality::POOR, snapshot_controller_->current_page_quality()); |
| |
| // As long as snapshots are enabled for this tab, there are two situations |
| // that allow for a navigation event to start a snapshot: |
| // 1) There is a request on hold waiting for the page to be minimally loaded. |
| if (snapshots_enabled_ && downloads_snapshot_on_hold_) { |
| DVLOG(1) << "Resuming downloads snapshot request for: " |
| << web_contents()->GetLastCommittedURL().spec(); |
| downloads_snapshot_on_hold_ = false; |
| SaveSnapshotForDownloads(false); |
| return; |
| } |
| |
| // 2) There's no ongoing snapshot and a previous one was saved with lower |
| // expected quality than what would be possible now. |
| if (snapshots_enabled_ && |
| (!downloads_ongoing_snapshot_info_ && |
| downloads_latest_saved_snapshot_info_ && |
| downloads_latest_saved_snapshot_info_->expected_page_quality < |
| snapshot_controller_->current_page_quality())) { |
| DVLOG(1) << "Upgrading last downloads snapshot for: " |
| << web_contents()->GetLastCommittedURL().spec(); |
| SaveSnapshotForDownloads(true); |
| return; |
| } |
| |
| // Notify the controller that a snapshot was not started. |
| snapshot_controller_->PendingSnapshotCompleted(); |
| } |
| |
| void RecentTabHelper::SaveSnapshotForDownloads(bool replace_latest) { |
| DCHECK_NE(PageQuality::POOR, snapshot_controller_->current_page_quality()); |
| |
| if (replace_latest) { |
| // Start by requesting the deletion of the existing previous snapshot of |
| // this page. |
| DCHECK(downloads_latest_saved_snapshot_info_); |
| DCHECK(!downloads_ongoing_snapshot_info_); |
| downloads_ongoing_snapshot_info_ = std::make_unique<SnapshotProgressInfo>( |
| downloads_latest_saved_snapshot_info_->client_id, |
| downloads_latest_saved_snapshot_info_->request_id, |
| downloads_latest_saved_snapshot_info_->origin); |
| std::vector<int64_t> ids{downloads_latest_saved_snapshot_info_->request_id}; |
| ContinueSnapshotWithIdsToPurge(downloads_ongoing_snapshot_info_.get(), ids); |
| } else { |
| // Otherwise go straight to saving the page. |
| DCHECK(downloads_ongoing_snapshot_info_); |
| ContinueSnapshotAfterPurge(downloads_ongoing_snapshot_info_.get(), |
| OfflinePageModel::DeletePageResult::SUCCESS); |
| } |
| } |
| |
| // This is the 1st step of a sequence of async operations chained through |
| // callbacks, mostly shared between last_n and downloads: |
| // 1) Compute the set of old 'last_n' pages that have to be purged. |
| // 2) Delete the pages found in the previous step. |
| // 3) Snapshot the current web contents. |
| // 4) Notify requesters about the final result of the operation. |
| // |
| // For last_n requests the sequence is always started in 1). For downloads it |
| // starts in either 2) or 3). Step 4) might be called anytime during the chain |
| // for early termination in case of errors. |
| void RecentTabHelper::ContinueSnapshotWithIdsToPurge( |
| SnapshotProgressInfo* snapshot_info, |
| const std::vector<int64_t>& page_ids) { |
| DCHECK(snapshot_info); |
| |
| DVLOG_IF(1, !page_ids.empty()) << "Deleting " << page_ids.size() |
| << " offline pages..."; |
| page_model_->DeletePagesByOfflineId( |
| page_ids, base::Bind(&RecentTabHelper::ContinueSnapshotAfterPurge, |
| weak_ptr_factory_.GetWeakPtr(), snapshot_info)); |
| } |
| |
| void RecentTabHelper::ContinueSnapshotAfterPurge( |
| SnapshotProgressInfo* snapshot_info, |
| OfflinePageModel::DeletePageResult result) { |
| if (result != OfflinePageModel::DeletePageResult::SUCCESS) { |
| ReportSnapshotCompleted(snapshot_info, false); |
| return; |
| } |
| |
| DCHECK(OfflinePageModel::CanSaveURL(web_contents()->GetLastCommittedURL())); |
| snapshot_info->expected_page_quality = |
| snapshot_controller_->current_page_quality(); |
| OfflinePageModel::SavePageParams save_page_params; |
| save_page_params.url = web_contents()->GetLastCommittedURL(); |
| save_page_params.client_id = snapshot_info->client_id; |
| save_page_params.proposed_offline_id = snapshot_info->request_id; |
| save_page_params.is_background = false; |
| save_page_params.original_url = |
| OfflinePageUtils::GetOriginalURLFromWebContents(web_contents()); |
| save_page_params.request_origin = snapshot_info->origin; |
| page_model_->SavePage( |
| save_page_params, delegate_->CreatePageArchiver(web_contents()), |
| web_contents(), |
| base::Bind(&RecentTabHelper::SavePageCallback, |
| weak_ptr_factory_.GetWeakPtr(), snapshot_info)); |
| } |
| |
| void RecentTabHelper::SavePageCallback(SnapshotProgressInfo* snapshot_info, |
| OfflinePageModel::SavePageResult result, |
| int64_t offline_id) { |
| DCHECK((snapshot_info->IsForLastN() && |
| snapshot_info->request_id == OfflinePageModel::kInvalidOfflineId) || |
| snapshot_info->request_id == offline_id) |
| << "SnapshotProgressInfo(client_id=" << snapshot_info->client_id |
| << ", request_id=" << snapshot_info->request_id |
| << ", origin=" << snapshot_info->origin << "), offline_id=" << offline_id; |
| // Store the assigned offline_id (for downloads case it will already contain |
| // the same value). |
| snapshot_info->request_id = offline_id; |
| ReportSnapshotCompleted(snapshot_info, result == SavePageResult::SUCCESS); |
| } |
| |
| // Note: this is the final step in the chain of callbacks and it's where the |
| // behavior is different depending on this being a last_n or downloads snapshot. |
| void RecentTabHelper::ReportSnapshotCompleted( |
| SnapshotProgressInfo* snapshot_info, |
| bool success) { |
| DVLOG(1) << (snapshot_info->IsForLastN() ? "Last_n" : "Downloads") |
| << " snapshot " << (success ? "succeeded" : "failed") |
| << " for: " << web_contents()->GetLastCommittedURL().spec(); |
| if (snapshot_info->IsForLastN()) { |
| DCHECK_EQ(snapshot_info, last_n_ongoing_snapshot_info_.get()); |
| if (success) { |
| last_n_latest_saved_snapshot_info_ = |
| std::move(last_n_ongoing_snapshot_info_); |
| } else { |
| last_n_ongoing_snapshot_info_.reset(); |
| } |
| return; |
| } |
| |
| DCHECK_EQ(snapshot_info, downloads_ongoing_snapshot_info_.get()); |
| snapshot_controller_->PendingSnapshotCompleted(); |
| // Tell RequestCoordinator how the request should be processed further. |
| ReportDownloadStatusToRequestCoordinator(snapshot_info, success); |
| if (success) { |
| downloads_latest_saved_snapshot_info_ = |
| std::move(downloads_ongoing_snapshot_info_); |
| } else { |
| downloads_ongoing_snapshot_info_.reset(); |
| } |
| } |
| |
| // Note: we cannot assume that snapshot_info == downloads_latest_snapshot_info_ |
| // because further calls made to ObserveAndDownloadCurrentPage will replace |
| // downloads_latest_snapshot_info_ with a new instance. |
| void RecentTabHelper::ReportDownloadStatusToRequestCoordinator( |
| SnapshotProgressInfo* snapshot_info, |
| bool cancel_background_request) { |
| DCHECK(snapshot_info); |
| DCHECK(!snapshot_info->IsForLastN()); |
| |
| RequestCoordinator* request_coordinator = |
| RequestCoordinatorFactory::GetForBrowserContext( |
| web_contents()->GetBrowserContext()); |
| if (!request_coordinator) |
| return; |
| |
| // It is OK to call these methods more then once, depending on |
| // number of snapshots attempted in this tab helper. If the request_id is not |
| // in the list of RequestCoordinator, these calls have no effect. |
| if (cancel_background_request) { |
| request_coordinator->MarkRequestCompleted(snapshot_info->request_id); |
| } else { |
| request_coordinator->EnableForOffliner(snapshot_info->request_id, |
| snapshot_info->client_id); |
| } |
| } |
| |
| ClientId RecentTabHelper::GetRecentPagesClientId() const { |
| return ClientId(kLastNNamespace, tab_id_); |
| } |
| |
| void RecentTabHelper::CancelInFlightSnapshots() { |
| DVLOG_IF(1, last_n_ongoing_snapshot_info_) |
| << " - Canceling ongoing last_n snapshot"; |
| DVLOG_IF(1, downloads_ongoing_snapshot_info_) |
| << " - Canceling ongoing downloads snapshot"; |
| weak_ptr_factory_.InvalidateWeakPtrs(); |
| downloads_ongoing_snapshot_info_.reset(); |
| downloads_latest_saved_snapshot_info_.reset(); |
| last_n_ongoing_snapshot_info_.reset(); |
| } |
| |
| } // namespace offline_pages |