Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4928)

Unified Diff: chrome/browser/android/offline_pages/prerendering_offliner.cc

Issue 2007783002: Adds PrerenderingOffliner implementation for handling Loader callbacks and then performing SavePage… (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@ploader
Patch Set: Update for petewil comment Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/android/offline_pages/prerendering_offliner.cc
diff --git a/chrome/browser/android/offline_pages/prerendering_offliner.cc b/chrome/browser/android/offline_pages/prerendering_offliner.cc
index b654c75a6b5620ebe6bf03e7d525daa88a111cb0..d873b02238b9a17c4a0767c5a36af87a1fa09a74 100644
--- a/chrome/browser/android/offline_pages/prerendering_offliner.cc
+++ b/chrome/browser/android/offline_pages/prerendering_offliner.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/android/offline_pages/prerendering_offliner.h"
#include "base/bind.h"
+#include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h"
#include "components/offline_pages/background/save_page_request.h"
#include "content/public/browser/browser_context.h"
@@ -16,28 +17,115 @@ PrerenderingOffliner::PrerenderingOffliner(
OfflinePageModel* offline_page_model)
: browser_context_(browser_context),
offline_page_model_(offline_page_model),
+ pending_request_(nullptr),
weak_ptr_factory_(this) {}
PrerenderingOffliner::~PrerenderingOffliner() {}
-void PrerenderingOffliner::OnLoadPageDone(Offliner::RequestStatus load_status,
- content::WebContents* contents) {
- // TODO(dougarnett): Implement save attempt and running CompletionCallback.
+void PrerenderingOffliner::OnLoadPageDone(
+ const SavePageRequest& request,
+ const CompletionCallback& completion_callback,
+ Offliner::RequestStatus load_status,
+ content::WebContents* web_contents) {
+ // Check if request is still pending receiving a callback.
+ // Note: it is possible to get a loaded page, start the save operation,
+ // and then get another callback from the Loader (eg, if its loaded
+ // WebContents is being destroyed for some resource reclamation).
+ if (!pending_request_)
+ return;
+
+ // Since we are able to stop/cancel a previous load request, we should
+ // never see a callback for an older request when we have a newer one
+ // pending. Crash for debug build and ignore for production build.
+ DCHECK_EQ(request.request_id(), pending_request_->request_id());
+ if (request.request_id() != pending_request_->request_id()) {
+ DVLOG(1) << "Ignoring load callback for old request";
+ return;
+ }
+
+ if (load_status == Offliner::RequestStatus::LOADED) {
+ // The page has successfully loaded so now try to save the page.
+ // After issuing the save request we will wait for either: the save
+ // callback or a CANCELED load callback (triggered because the loaded
+ // WebContents are being destroyed) - whichever callback occurs first.
+ DCHECK(web_contents);
+ std::unique_ptr<OfflinePageArchiver> archiver(
+ new OfflinePageMHTMLArchiver(web_contents));
+ SavePage(request.url(), request.client_id(), std::move(archiver),
+ base::Bind(&PrerenderingOffliner::OnSavePageDone,
+ weak_ptr_factory_.GetWeakPtr(), request,
+ completion_callback));
+ } else {
+ // Clear pending request and then run the completion callback.
+ pending_request_ = nullptr;
+ completion_callback.Run(request, load_status);
+ }
+}
+
+void PrerenderingOffliner::OnSavePageDone(
+ const SavePageRequest& request,
+ const CompletionCallback& completion_callback,
+ SavePageResult save_result,
+ int64_t offline_id) {
+ // Check if request is still pending receiving a callback.
+ if (!pending_request_)
+ return;
+
+ // Also check that save callback is for same request as pending request
+ // (since SavePage request is not cancel-able currently and could be old).
+ if (request.request_id() != pending_request_->request_id()) {
+ DVLOG(1) << "Ignoring save callback for old request";
+ return;
+ }
+
+ // Clear pending request here and inform loader we are done with WebContents.
+ pending_request_ = nullptr;
+ GetOrCreateLoader()->StopLoading();
+
+ // Determine status and run the completion callback.
+ Offliner::RequestStatus save_status;
+ if (save_result == SavePageResult::SUCCESS) {
+ save_status = RequestStatus::SAVED;
+ } else {
+ // TODO(dougarnett): Consider reflecting some recommendation to retry the
+ // request based on specific save error cases.
+ save_status = RequestStatus::FAILED_SAVE;
+ }
+ completion_callback.Run(request, save_status);
}
bool PrerenderingOffliner::LoadAndSave(const SavePageRequest& request,
const CompletionCallback& callback) {
- if (!offline_page_model_->CanSavePage(request.url()))
+ if (pending_request_) {
+ DVLOG(1) << "Already have pending request";
return false;
+ }
+
+ if (!CanSavePage(request.url())) {
+ DVLOG(1) << "Not able to save page";
+ return false;
+ }
+
+ // Track pending request for callback handling.
+ pending_request_ = &request;
// Kick off load page attempt.
- return GetOrCreateLoader()->LoadPage(
- request.url(), base::Bind(&PrerenderingOffliner::OnLoadPageDone,
- weak_ptr_factory_.GetWeakPtr()));
+ bool accepted = GetOrCreateLoader()->LoadPage(
+ request.url(),
+ base::Bind(&PrerenderingOffliner::OnLoadPageDone,
+ weak_ptr_factory_.GetWeakPtr(), request, callback));
+ if (!accepted)
+ pending_request_ = nullptr;
+
+ return accepted;
}
void PrerenderingOffliner::Cancel() {
- GetOrCreateLoader()->StopLoading();
+ if (pending_request_) {
+ pending_request_ = nullptr;
+ GetOrCreateLoader()->StopLoading();
+ // TODO(dougarnett): Consider ability to cancel SavePage request.
+ }
}
void PrerenderingOffliner::SetLoaderForTesting(
@@ -46,6 +134,24 @@ void PrerenderingOffliner::SetLoaderForTesting(
loader_ = std::move(loader);
}
+bool PrerenderingOffliner::CanSavePage(const GURL& url) {
+ if (!offline_page_model_) {
+ // Assume we can save if no OfflinePageModel (for unit tests).
+ // TODO(dougarnett): Make OfflinePageModel::CanSavePage() mockable for test.
+ return true;
+ }
+ return offline_page_model_->CanSavePage(url);
+}
+
+void PrerenderingOffliner::SavePage(
+ const GURL& url,
+ const ClientId& client_id,
+ std::unique_ptr<OfflinePageArchiver> archiver,
+ const SavePageCallback& callback) {
+ DCHECK(offline_page_model_);
+ offline_page_model_->SavePage(url, client_id, std::move(archiver), callback);
+}
+
PrerenderingLoader* PrerenderingOffliner::GetOrCreateLoader() {
if (!loader_) {
loader_.reset(new PrerenderingLoader(browser_context_));

Powered by Google App Engine
This is Rietveld 408576698