1 // Copyright 2016 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_TAB_HELPER_H_ 6 #define CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_TAB_HELPER_H_ 7 8 #include <memory> 9 #include <string> 10 #include <vector> 11 12 #include "base/macros.h" 13 #include "base/memory/weak_ptr.h" 14 #include "base/time/time.h" 15 #include "chrome/browser/offline_pages/offline_page_utils.h" 16 #include "chrome/common/mhtml_page_notifier.mojom.h" 17 #include "components/offline_pages/core/request_header/offline_page_header.h" 18 #include "content/public/browser/web_contents_observer.h" 19 #include "content/public/browser/web_contents_receiver_set.h" 20 #include "content/public/browser/web_contents_user_data.h" 21 #include "services/service_manager/public/cpp/binder_registry.h" 22 #include "third_party/blink/public/mojom/loader/mhtml_load_result.mojom-forward.h" 23 #include "url/gurl.h" 24 25 namespace content { 26 class WebContents; 27 } 28 29 namespace offline_pages { 30 31 struct OfflinePageItem; 32 class PrefetchService; 33 34 // This enum is used for UMA reporting. It contains all possible trusted states 35 // of the offline page. 36 // NOTE: because this is used for UMA reporting, these values should not be 37 // changed or reused; new values should be ended immediately before the MAX 38 // value. Make sure to update the histogram enum (OfflinePageTrustedState in 39 // enums.xml) accordingly. 40 enum class OfflinePageTrustedState { 41 // Trusted because the archive file is in internal directory. 42 TRUSTED_AS_IN_INTERNAL_DIR, 43 // Trusted because the archive file is in public directory without 44 // modification. 45 TRUSTED_AS_UNMODIFIED_AND_IN_PUBLIC_DIR, 46 // No trusted because the archive file is in public directory and it is 47 // modified. 48 UNTRUSTED, 49 TRUSTED_STATE_MAX 50 }; 51 52 // Per-tab class that monitors the navigations and stores the necessary info 53 // to facilitate the synchronous access to offline information. 54 class OfflinePageTabHelper 55 : public content::WebContentsObserver, 56 public content::WebContentsUserData<OfflinePageTabHelper>, 57 public offline_pages::mojom::MhtmlPageNotifier { 58 public: 59 ~OfflinePageTabHelper() override; 60 61 // MhtmlPageNotifier overrides. 62 void NotifyMhtmlPageLoadAttempted(blink::mojom::MHTMLLoadResult result, 63 const GURL& main_frame_url, 64 base::Time date) override; 65 66 void SetOfflinePage(const OfflinePageItem& offline_page, 67 const OfflinePageHeader& offline_header, 68 OfflinePageTrustedState trusted_state, 69 bool is_offline_preview); 70 71 void ClearOfflinePage(); 72 offline_page()73 OfflinePageItem* offline_page() { return offline_info_.offline_page.get(); } 74 offline_header()75 const OfflinePageHeader& offline_header() const { 76 return offline_info_.offline_header; 77 } 78 trusted_state()79 OfflinePageTrustedState trusted_state() const { 80 return offline_info_.trusted_state; 81 } 82 83 // Returns whether a trusted offline page is being displayed. 84 bool IsShowingTrustedOfflinePage() const; 85 86 // Returns nullptr if the page is not an offline preview. Returns the 87 // OfflinePageItem related to the page if the page is an offline preview. 88 const OfflinePageItem* GetOfflinePreviewItem() const; 89 90 // Returns provisional offline page since actual navigation does not happen 91 // during unit tests. 92 const OfflinePageItem* GetOfflinePageForTest() const; 93 94 // True if an offline page is loading, but has not committed. 95 bool IsLoadingOfflinePage() const; 96 97 // Returns trusted state of provisional offline page. 98 OfflinePageTrustedState GetTrustedStateForTest() const; 99 100 // Sets the target frame, useful for unit testing the MhtmlPageNotifier 101 // interface. 102 void SetCurrentTargetFrameForTest( 103 content::RenderFrameHost* render_frame_host); 104 105 // Helper function which normally should only be called by 106 // OfflinePageUtils::ScheduleDownload to do the work. This is because we need 107 // to ensure |web_contents| is still valid after returning from the 108 // asynchronous call of duplicate checking function. The lifetime of 109 // OfflinePageTabHelper instance is tied with the associated |web_contents| 110 // and thus the callback will be automatically invalidated if |web_contents| 111 // is gone. 112 void ScheduleDownloadHelper(content::WebContents* web_contents, 113 const std::string& name_space, 114 const GURL& url, 115 OfflinePageUtils::DownloadUIActionFlags ui_action, 116 const std::string& request_origin); 117 118 private: 119 friend class content::WebContentsUserData<OfflinePageTabHelper>; 120 121 // Contains the info about the offline page being loaded. 122 struct LoadedOfflinePageInfo { 123 LoadedOfflinePageInfo(); 124 ~LoadedOfflinePageInfo(); 125 126 // Constructs a valid but untrusted LoadedOfflinePageInfo with |url| as the 127 // online URL. 128 static LoadedOfflinePageInfo MakeUntrusted(); 129 130 LoadedOfflinePageInfo& operator=(LoadedOfflinePageInfo&& other); 131 LoadedOfflinePageInfo(LoadedOfflinePageInfo&& other); 132 133 // The cached copy of OfflinePageItem. Note that if |is_trusted| is false, 134 // offline_page may contain information derived from the MHTML itself and 135 // should be exposed to the user as untrusted. 136 std::unique_ptr<OfflinePageItem> offline_page; 137 138 // The offline header that is provided when offline page is loaded. 139 OfflinePageHeader offline_header; 140 141 // The trusted state of the page. 142 OfflinePageTrustedState trusted_state; 143 144 // Whether the page is an offline preview. Offline page previews are shown 145 // when a user's effective connection type is prohibitively slow. 146 bool is_showing_offline_preview = false; 147 148 // Returns true if this contains an offline page. When constructed, 149 // LoadedOfflinePageInfo objects are invalid until filled with an offline 150 // page. 151 bool IsValid() const; 152 153 void Clear(); 154 }; 155 156 explicit OfflinePageTabHelper(content::WebContents* web_contents); 157 158 // Overridden from content::WebContentsObserver: 159 void DidStartNavigation( 160 content::NavigationHandle* navigation_handle) override; 161 void DidFinishNavigation( 162 content::NavigationHandle* navigation_handle) override; 163 164 // Finalize the offline info when the navigation is done. 165 void FinalizeOfflineInfo(content::NavigationHandle* navigation_handle); 166 167 void ReportOfflinePageMetrics(); 168 169 // Report the metrics essential to PrefetchService. 170 void ReportPrefetchMetrics(content::NavigationHandle* navigation_handle); 171 172 // Reload the URL in order to fetch the offline page on certain net errors. 173 void TryLoadingOfflinePageOnNetError( 174 content::NavigationHandle* navigation_handle); 175 176 // Creates an offline info with an invalid offline ID and the given URL. 177 LoadedOfflinePageInfo MakeUntrustedOfflineInfo(const GURL& url); 178 179 void SelectPagesForURLDone(const std::vector<OfflinePageItem>& offline_pages); 180 181 void DuplicateCheckDoneForScheduleDownload( 182 content::WebContents* web_contents, 183 const std::string& name_space, 184 const GURL& url, 185 OfflinePageUtils::DownloadUIActionFlags ui_action, 186 const std::string& request_origin, 187 OfflinePageUtils::DuplicateCheckResult result); 188 void DoDownloadPageLater(content::WebContents* web_contents, 189 const std::string& name_space, 190 const GURL& url, 191 OfflinePageUtils::DownloadUIActionFlags ui_action, 192 const std::string& request_origin); 193 194 // The provisional info about the offline page being loaded. This is set when 195 // the offline interceptor decides to serve the offline page and it will be 196 // moved to |offline_info_| once the navigation is committed without error. 197 LoadedOfflinePageInfo provisional_offline_info_; 198 199 // The info about offline page being loaded. This is set from 200 // |provisional_offline_info_| when the navigation is committed without error. 201 // This can be used to by the Tab to synchronously ask about the offline 202 // info. 203 LoadedOfflinePageInfo offline_info_; 204 205 bool reloading_url_on_net_error_ = false; 206 207 // Service, outlives this object. 208 PrefetchService* prefetch_service_ = nullptr; 209 210 // TODO(crbug.com/827215): We only really want interface messages for the main 211 // frame but this is not easily done with the current helper classes. 212 content::WebContentsFrameReceiverSet<mojom::MhtmlPageNotifier> 213 mhtml_page_notifier_receivers_; 214 215 base::WeakPtrFactory<OfflinePageTabHelper> weak_ptr_factory_{this}; 216 217 WEB_CONTENTS_USER_DATA_KEY_DECL(); 218 219 DISALLOW_COPY_AND_ASSIGN(OfflinePageTabHelper); 220 }; 221 222 } // namespace offline_pages 223 224 #endif // CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_TAB_HELPER_H_ 225