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

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

Issue 2002433002: Handle online and offline redirects via interceptor and offline scheme (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 4 years, 6 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_handler.cc
diff --git a/chrome/browser/android/offline_pages/offline_page_request_handler.cc b/chrome/browser/android/offline_pages/offline_page_request_handler.cc
new file mode 100644
index 0000000000000000000000000000000000000000..dc7d992a27aa0cd1529e4c494c1b0a6402f1d68d
--- /dev/null
+++ b/chrome/browser/android/offline_pages/offline_page_request_handler.cc
@@ -0,0 +1,195 @@
+// Copyright 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/android/offline_pages/offline_page_request_handler.h"
+
+#include "base/macros.h"
+#include "chrome/browser/android/offline_pages/offline_page_utils.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/url_constants.h"
+#include "components/offline_pages/offline_page_feature.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/network_change_notifier.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_redirect_job.h"
+
+namespace offline_pages {
+
+namespace {
+
+int kUserDataKey; // Only address is used.
+
+// An interceptor to hijack requests and potentially service them based on
+// their offline information.
+class OfflinePageRequestInterceptor : public net::URLRequestInterceptor {
+ public:
+ explicit OfflinePageRequestInterceptor(void* profile_id)
+ : profile_id_(profile_id) { }
+ ~OfflinePageRequestInterceptor() override {}
+
+ private:
+ // Overrides from net::URLRequestInterceptor:
+ net::URLRequestJob* MaybeInterceptRequest(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ OfflinePageRequestHandler* handler = OfflinePageRequestHandler::GetHandler(
+ request);
+ if (!handler)
+ return nullptr;
+ return handler->MaybeCreateJob(request, network_delegate, profile_id_);
+ }
+
+ // The profile for processing Drive accesses. Should not be NULL.
+ void* profile_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(OfflinePageRequestInterceptor);
+};
+
+// Called on IO thread after a redirect URL is obtained.
+void DidGetRedirectURL(const GURL& redirect_url,
+ base::WeakPtr<OfflinePageRequestRedirectJob> job) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ if (!job)
+ return;
+
+ if (redirect_url.is_valid())
+ job->SetRedirectURL(redirect_url);
+ else
+ job->FallbackToDefault();
+}
+
+// Called on UI thread after an offline URL is obtained.
+void DidGetOfflineURL(base::WeakPtr<OfflinePageRequestRedirectJob> job,
+ const GURL& online_url,
+ const GURL& offline_file_url) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ // DidGetRedirectURL should always be called even when no offline URL is
+ // found.
+ GURL redirect_url;
+ if (offline_file_url.is_valid()) {
+ redirect_url =
+ GURL(chrome::kOfflinePageScheme + std::string(":") + online_url.spec());
+ }
+
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&DidGetRedirectURL, redirect_url, job));
+}
+
+} // namespace
+
+// static
+void OfflinePageRequestHandler::InitializeHandler(
+ net::URLRequest* request,
+ content::ResourceType resource_type) {
+ if (!IsOfflinePagesEnabled())
+ return;
+
+ // Ignore the request not for the main resource file.
+ if (resource_type != content::RESOURCE_TYPE_MAIN_FRAME)
+ return;
+
+ // TODO(jianli): Ignore other requests that will not involve offline
+ // redirects.
+
+ // Any more precise checks to see if the request should be intercepted are
+ // asynchronous, so just create our handler in all cases.
+ std::unique_ptr<OfflinePageRequestHandler> handler(
+ new OfflinePageRequestHandler());
+ request->SetUserData(&kUserDataKey, handler.release());
+}
+
+// static
+OfflinePageRequestHandler* OfflinePageRequestHandler::GetHandler(
+ net::URLRequest* request) {
+ return static_cast<OfflinePageRequestHandler*>(
+ request->GetUserData(&kUserDataKey));
+}
+
+// static
+std::unique_ptr<net::URLRequestInterceptor>
+OfflinePageRequestHandler::CreateInterceptor(void* profile_id) {
+ if (!IsOfflinePagesEnabled())
+ return nullptr;
+
+ return std::unique_ptr<net::URLRequestInterceptor>(
+ new OfflinePageRequestInterceptor(profile_id));
+}
+
+OfflinePageRequestHandler::OfflinePageRequestHandler()
+ : weak_ptr_factory_(this) {
+}
+
+OfflinePageRequestHandler::~OfflinePageRequestHandler() {
+}
+
+void OfflinePageRequestHandler::OnPrepareToRestart() {
+ use_default_ = true;
+ redirect_job_.reset();
+}
+
+net::URLRequestJob* OfflinePageRequestHandler::MaybeCreateJob(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ void* profile_id) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ if (use_default_)
+ return nullptr;
+
+ OfflinePageRequestRedirectJob* redirect_job =
+ new OfflinePageRequestRedirectJob(request, network_delegate, this);
+ redirect_job_ = redirect_job->GetWeakPtr();
+
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&OfflinePageRequestHandler::GetRedirectUrl,
+ weak_ptr_factory_.GetWeakPtr(),
+ request->url(),
+ profile_id));
+
+ return redirect_job_.get();
+}
+
+void OfflinePageRequestHandler::GetRedirectUrl(const GURL& url,
+ void* profile_id){
+ 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))
+ return;
+ Profile* profile = reinterpret_cast<Profile*>(profile_id);
+
+ if (net::NetworkChangeNotifier::IsOffline()) {
+ // TODO(jianli): Currently offline_url returned by GetOfflineURLForOnlineURL
+ // is the underlying file URL. We should change it to offline scheme URL and
+ // expose file path in another method.
+ OfflinePageUtils::GetOfflineURLForOnlineURL(
+ profile,
+ url,
+ base::Bind(&DidGetOfflineURL, redirect_job_, url));
+ return;
+ }
+
+ GURL redirect_url;
+ if (url.SchemeIs(chrome::kOfflinePageScheme)) {
+ GURL online_url = GURL(url.GetContent());
+ if (online_url.is_valid() && online_url.SchemeIsHTTPOrHTTPS())
+ redirect_url = online_url;
+ }
+
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&DidGetRedirectURL, redirect_url, redirect_job_));
+}
+
+} // namespace offline_pages

Powered by Google App Engine
This is Rietveld 408576698