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

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

Issue 2322833002: Support serving offline page by offline ID (Closed)
Patch Set: Created 4 years, 3 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/offline_page_request_job.cc
diff --git a/chrome/browser/android/offline_pages/offline_page_request_job.cc b/chrome/browser/android/offline_pages/offline_page_request_job.cc
index 886ab76848337dbf2d8b5570c8de32ab997b43eb..30b4bbca19bf2d32649e0f916097db1d2b0f83c4 100644
--- a/chrome/browser/android/offline_pages/offline_page_request_job.cc
+++ b/chrome/browser/android/offline_pages/offline_page_request_job.cc
@@ -10,6 +10,7 @@
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -33,9 +34,12 @@
namespace offline_pages {
-const char kLoadingOfflinePageHeader[] = "X-Chrome-offline";
-const char kLoadingOfflinePageReason[] = "reason=";
-const char kLoadingOfflinePageDueToNetError[] = "error";
+const char kOfflinePageHeader[] = "X-Chrome-offline";
+const char kOfflinePageHeaderReasonKey[] = "reason";
+const char kOfflinePageHeaderReasonValueDueToNetError[] = "error";
+const char kOfflinePageHeaderPersistKey[] = "persist";
+const char kOfflinePageHeaderNamespaceKey[] = "namespace";
+const char kOfflinePageHeaderIDKey[] = "id";
namespace {
@@ -113,27 +117,54 @@ class DefaultDelegate : public OfflinePageRequestJob::Delegate {
DISALLOW_COPY_AND_ASSIGN(DefaultDelegate);
};
-// Returns true if custom offline header is present.
-// |reason| may be set with the reason to trigger the offline page loading.
-bool ParseOfflineHeader(net::URLRequest* request, std::string* reason) {
- std::string value;
- if (!request->extra_request_headers().GetHeader(kLoadingOfflinePageHeader,
- &value)) {
- return false;
+class OfflinePageHeader {
Dmitry Titov 2016/09/09 04:33:06 Nice to add a class for that. Please add a class
jianli 2016/09/10 00:56:03 Done.
+ public:
+ explicit OfflinePageHeader(const std::string& header_string);
+ ~OfflinePageHeader() {}
+
+ bool succeeded_to_parse() const { return succeeded_to_parse_; }
Dmitry Titov 2016/09/09 04:33:06 Naming suggestion: successfully_parsed_
jianli 2016/09/10 00:56:03 Done.
+ bool need_to_persist() const { return need_to_persist_; }
Dmitry Titov 2016/09/09 04:33:06 Shouldn't this always be 'true' ? Again, if persis
jianli 2016/09/10 00:56:04 I think it should always be false because we shoul
+ const std::string& reason() const { return reason_; }
Dmitry Titov 2016/09/09 04:33:06 this looks like enum that this class should expose
jianli 2016/09/10 00:56:03 Done.
+ const std::string& name_space() const { return name_space_; }
+ const std::string& id() const { return id_; }
+
+ private:
+ bool succeeded_to_parse_;
+
Dmitry Titov 2016/09/09 04:33:06 extra empty line
jianli 2016/09/10 00:56:03 Done.
+ bool need_to_persist_;
+ std::string reason_;
+ std::string name_space_;
+ std::string id_;
+
+ DISALLOW_COPY_AND_ASSIGN(OfflinePageHeader);
+};
+
+OfflinePageHeader::OfflinePageHeader(const std::string& header_string)
+ : succeeded_to_parse_(false), need_to_persist_(false) {
+ if (header_string.empty()) {
+ succeeded_to_parse_ = true;
+ return;
}
- // Currently we only support reason field.
- base::StringTokenizer tokenizer(value, ", ");
+ base::StringTokenizer tokenizer(header_string, ", ");
while (tokenizer.GetNext()) {
- if (base::StartsWith(tokenizer.token(),
- kLoadingOfflinePageReason,
- base::CompareCase::INSENSITIVE_ASCII)) {
- *reason = tokenizer.token().substr(
- arraysize(kLoadingOfflinePageReason) - 1);
- break;
- }
+ std::string pair = tokenizer.token();
+ std::size_t pos = pair.find('=');
+ if (pos == std::string::npos)
+ return;
+ std::string key = pair.substr(0, pos);
+ std::string value = pair.substr(pos + 1);
+ if (key == kOfflinePageHeaderPersistKey)
fgorski 2016/09/08 02:25:02 is there a place where you call toLower? Or should
jianli 2016/09/10 00:56:03 Done.
+ need_to_persist_ = (value == "1");
+ else if (key == kOfflinePageHeaderReasonKey)
+ reason_ = value;
+ else if (key == kOfflinePageHeaderNamespaceKey)
+ name_space_ = value;
+ else if (key == kOfflinePageHeaderIDKey)
+ id_ = value;
}
- return true;
+
+ succeeded_to_parse_ = true;
Dmitry Titov 2016/09/09 04:33:06 Are there valid combinations and invalid combinati
jianli 2016/09/10 00:56:03 After I remove namespace field, all remaining 3 fi
}
bool IsNetworkProhibitivelySlow(net::URLRequest* request) {
@@ -158,11 +189,12 @@ bool IsNetworkProhibitivelySlow(net::URLRequest* request) {
NetworkState GetNetworkState(net::URLRequest* request) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- std::string reason;
- bool has_offline_header = ParseOfflineHeader(request, &reason);
- if (has_offline_header &&
- base::EqualsCaseInsensitiveASCII(reason,
- kLoadingOfflinePageDueToNetError)) {
+ std::string offline_header_string;
+ request->extra_request_headers().GetHeader(
+ kOfflinePageHeader, &offline_header_string);
+ OfflinePageHeader offline_header(offline_header_string);
+ if (base::EqualsCaseInsensitiveASCII(
+ offline_header.reason(), kOfflinePageHeaderReasonValueDueToNetError)) {
return NetworkState::FLAKY_NETWORK;
}
@@ -172,10 +204,11 @@ NetworkState GetNetworkState(net::URLRequest* request) {
if (IsNetworkProhibitivelySlow(request))
return NetworkState::PROHIBITIVELY_SLOW_NETWORK;
- // The presence of custom offline header will force to load an offline page
- // even when network is connected.
- return has_offline_header ? NetworkState::FORCE_OFFLINE_ON_CONNECTED_NETWORK
- : NetworkState::CONNECTED_NETWORK;
+ // If custom offline header is present and contains the reason field, the
+ // offline page should be forced to load even when the network is connected.
+ return offline_header.succeeded_to_parse() && !offline_header.reason().empty()
+ ? NetworkState::FORCE_OFFLINE_ON_CONNECTED_NETWORK
+ : NetworkState::CONNECTED_NETWORK;
}
OfflinePageRequestJob::AggregatedRequestResult
@@ -241,6 +274,17 @@ void ReportRequestResult(
RequestResultToAggregatedRequestResult(request_result, network_state));
}
+OfflinePageModel* GetOfflinePageModel(
+ content::ResourceRequestInfo::WebContentsGetter web_contents_getter) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ content::WebContents* web_contents = web_contents_getter.Run();
+ return web_contents ?
+ OfflinePageModelFactory::GetForBrowserContext(
+ web_contents->GetBrowserContext()) :
+ nullptr;
+}
+
void NotifyOfflineFilePathOnIO(base::WeakPtr<OfflinePageRequestJob> job,
const base::FilePath& offline_file_path) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
@@ -314,7 +358,7 @@ RequestResult AccessOfflineFile(
}
// Handles the result of finding an offline page.
-void SelectPageForOnlineURLDone(
+void SucceededToFindOfflinePage(
NetworkState network_state,
base::WeakPtr<OfflinePageRequestJob> job,
content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
@@ -334,7 +378,7 @@ void SelectPageForOnlineURLDone(
NotifyOfflineFilePathOnUI(job, offline_file_path);
}
-void FailedToSelectOfflinePage(base::WeakPtr<OfflinePageRequestJob> job) {
+void FailedToFindOfflinePage(base::WeakPtr<OfflinePageRequestJob> job) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Proceed with empty file path in order to notify the OfflinePageRequestJob
@@ -344,46 +388,174 @@ void FailedToSelectOfflinePage(base::WeakPtr<OfflinePageRequestJob> job) {
}
// Tries to find the offline page to serve for |online_url|.
-void SelectOfflinePage(
+void SelectPageForOnlineURL(
const GURL& online_url,
NetworkState network_state,
- void* profile_id,
content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
OfflinePageRequestJob::Delegate::TabIdGetter tab_id_getter,
base::WeakPtr<OfflinePageRequestJob> job) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- // |profile_id| needs to be checked with ProfileManager::IsValidProfile
- // before using it.
- if (!g_browser_process->profile_manager()->IsValidProfile(profile_id)) {
- FailedToSelectOfflinePage(job);
- return;
- }
- Profile* profile = reinterpret_cast<Profile*>(profile_id);
-
content::WebContents* web_contents = web_contents_getter.Run();
if (!web_contents){
ReportRequestResult(RequestResult::NO_WEB_CONTENTS, network_state);
- FailedToSelectOfflinePage(job);
+ FailedToFindOfflinePage(job);
return;
}
int tab_id;
if (!tab_id_getter.Run(web_contents, &tab_id)) {
ReportRequestResult(RequestResult::NO_TAB_ID, network_state);
- FailedToSelectOfflinePage(job);
+ FailedToFindOfflinePage(job);
return;
}
OfflinePageUtils::SelectPageForOnlineURL(
- profile,
+ web_contents->GetBrowserContext(),
online_url,
tab_id,
- base::Bind(&SelectPageForOnlineURLDone,
+ base::Bind(&SucceededToFindOfflinePage,
network_state,
job,
web_contents_getter));
}
+void FindPageWithOfflineIDDone(
+ const GURL& online_url,
fgorski 2016/09/08 02:25:02 nit: since we no longer have the concept of offlin
jianli 2016/09/10 00:56:04 Agreed. But I rather make another patch after land
+ NetworkState network_state,
+ content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+ OfflinePageRequestJob::Delegate::TabIdGetter tab_id_getter,
+ base::WeakPtr<OfflinePageRequestJob> job,
+ const OfflinePageItem* offline_page) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ // If the found offline page does not has same online URL as the request URL,
fgorski 2016/09/08 02:25:02 nit: does not have the same URL as the online URL
jianli 2016/09/10 00:56:03 Done.
+ // fall back to find the offline page based on the online URL.
+ if (offline_page->url != online_url) {
+ SelectPageForOnlineURL(
+ online_url, network_state, web_contents_getter, tab_id_getter, job);
+ return;
+ }
+
+ SucceededToFindOfflinePage(
+ network_state, job, web_contents_getter, offline_page);
+}
+
+// Tries to find an offline page associated with |offline_id|.
+void FindPageWithOfflineID(
+ const GURL& online_url,
+ int64_t offline_id,
+ NetworkState network_state,
+ content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+ OfflinePageRequestJob::Delegate::TabIdGetter tab_id_getter,
+ base::WeakPtr<OfflinePageRequestJob> job) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ OfflinePageModel* offline_page_model =
+ GetOfflinePageModel(web_contents_getter);
+ if (!offline_page_model) {
+ FailedToFindOfflinePage(job);
+ return;
+ }
+
+ offline_page_model->GetPageByOfflineId(
+ offline_id,
+ base::Bind(&FindPageWithOfflineIDDone,
+ online_url,
+ network_state,
+ web_contents_getter,
+ tab_id_getter,
+ job));
+}
+
+void GetOfflineIdsForClientIdDone(
+ const GURL& online_url,
+ NetworkState network_state,
+ content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+ OfflinePageRequestJob::Delegate::TabIdGetter tab_id_getter,
+ base::WeakPtr<OfflinePageRequestJob> job,
+ const MultipleOfflineIdResult& offline_ids) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ if (offline_ids.empty()) {
+ FailedToFindOfflinePage(job);
+ return;
+ }
+
+ DCHECK_EQ(1u, offline_ids.size());
+ FindPageWithOfflineID(online_url,
+ offline_ids[0],
+ network_state,
+ web_contents_getter,
+ tab_id_getter,
+ job);
+}
+
+// Tries to find an offline page associated with |client_id|.
+void FindPageWithClientID(
+ const GURL& online_url,
+ const ClientId& client_id,
+ NetworkState network_state,
+ content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+ OfflinePageRequestJob::Delegate::TabIdGetter tab_id_getter,
+ base::WeakPtr<OfflinePageRequestJob> job) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ OfflinePageModel* offline_page_model =
+ GetOfflinePageModel(web_contents_getter);
+ if (!offline_page_model) {
+ FailedToFindOfflinePage(job);
+ return;
+ }
+
+ offline_page_model->GetOfflineIdsForClientId(
+ client_id,
+ base::Bind(&GetOfflineIdsForClientIdDone,
+ online_url,
+ network_state,
+ web_contents_getter,
+ tab_id_getter,
+ job));
+}
+
+// Tries to find the offline page to serve for |online_url|.
+void SelectPage(
+ const GURL& online_url,
+ const std::string& offline_header_string,
+ NetworkState network_state,
+ content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+ OfflinePageRequestJob::Delegate::TabIdGetter tab_id_getter,
+ base::WeakPtr<OfflinePageRequestJob> job) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ OfflinePageHeader offline_header(offline_header_string);
+
+ // If an id, either offline ID or client ID, is present in the offline header,
Dmitry Titov 2016/09/09 04:33:06 This logic is too complicated. It's hard to recall
jianli 2016/09/10 00:56:04 Per discussion, we only support passing offline id
+ // try to load that particular version.
+ if (!offline_header.id().empty()) {
+ // If namespace is not set in offline header, the id given in the offline
+ // header should be used as offline ID.
+ if (offline_header.name_space().empty()) {
+ // if the id string cannot be converted to int64 id, fall through to
+ // select page via online URL.
+ int64_t offline_id;
+ if (base::StringToInt64(offline_header.id(), &offline_id)) {
+ FindPageWithOfflineID(online_url, offline_id, network_state,
+ web_contents_getter, tab_id_getter, job);
+ return;
+ }
+ } else {
+ // Otherwise, try to find the offline page based on the client ID.
+ ClientId client_id(offline_header.name_space(), offline_header.id());
+ FindPageWithClientID(online_url, client_id, network_state,
+ web_contents_getter, tab_id_getter, job);
+ return;
+ }
+ }
+
+ SelectPageForOnlineURL(online_url, network_state, web_contents_getter,
+ tab_id_getter, job);
+}
+
} // namespace
// static
@@ -464,13 +636,16 @@ void OfflinePageRequestJob::StartAsync() {
return;
}
+ std::string offline_header_string;
+ request()->extra_request_headers().GetHeader(kOfflinePageHeader,
+ &offline_header_string);
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
- base::Bind(&SelectOfflinePage,
+ base::Bind(&SelectPage,
request()->url(),
+ offline_header_string,
network_state,
- profile_id_,
delegate_->GetWebContentsGetter(request()),
delegate_->GetTabIdGetter(),
weak_ptr_factory_.GetWeakPtr()));

Powered by Google App Engine
This is Rietveld 408576698