| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/android/offline_pages/offline_page_request_job.h" | 5 #include "chrome/browser/android/offline_pages/offline_page_request_job.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/files/file_path.h" | 10 #include "base/files/file_path.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/metrics/histogram_macros.h" | 12 #include "base/metrics/histogram_macros.h" |
| 13 #include "base/strings/string_number_conversions.h" |
| 13 #include "base/strings/string_tokenizer.h" | 14 #include "base/strings/string_tokenizer.h" |
| 14 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
| 15 #include "base/threading/thread_task_runner_handle.h" | 16 #include "base/threading/thread_task_runner_handle.h" |
| 16 #include "chrome/browser/android/offline_pages/offline_page_model_factory.h" | 17 #include "chrome/browser/android/offline_pages/offline_page_model_factory.h" |
| 17 #include "chrome/browser/android/offline_pages/offline_page_tab_helper.h" | 18 #include "chrome/browser/android/offline_pages/offline_page_tab_helper.h" |
| 18 #include "chrome/browser/android/offline_pages/offline_page_utils.h" | 19 #include "chrome/browser/android/offline_pages/offline_page_utils.h" |
| 19 #include "chrome/browser/browser_process.h" | 20 #include "chrome/browser/browser_process.h" |
| 20 #include "chrome/browser/profiles/profile.h" | |
| 21 #include "chrome/browser/profiles/profile_manager.h" | 21 #include "chrome/browser/profiles/profile_manager.h" |
| 22 #include "components/offline_pages/offline_page_model.h" | 22 #include "components/offline_pages/offline_page_model.h" |
| 23 #include "components/previews/previews_experiments.h" | 23 #include "components/previews/previews_experiments.h" |
| 24 #include "content/public/browser/browser_thread.h" | 24 #include "content/public/browser/browser_thread.h" |
| 25 #include "content/public/browser/resource_request_info.h" | 25 #include "content/public/browser/resource_request_info.h" |
| 26 #include "content/public/browser/web_contents.h" | 26 #include "content/public/browser/web_contents.h" |
| 27 #include "content/public/common/resource_type.h" | 27 #include "content/public/common/resource_type.h" |
| 28 #include "net/base/network_change_notifier.h" | 28 #include "net/base/network_change_notifier.h" |
| 29 #include "net/http/http_request_headers.h" | 29 #include "net/http/http_request_headers.h" |
| 30 #include "net/nqe/network_quality_estimator.h" | 30 #include "net/nqe/network_quality_estimator.h" |
| 31 #include "net/url_request/url_request.h" | 31 #include "net/url_request/url_request.h" |
| 32 #include "net/url_request/url_request_context.h" | 32 #include "net/url_request/url_request_context.h" |
| 33 | 33 |
| 34 namespace offline_pages { | 34 namespace offline_pages { |
| 35 | 35 |
| 36 const char kLoadingOfflinePageHeader[] = "X-Chrome-offline"; | 36 const char kOfflinePageHeader[] = "X-Chrome-offline"; |
| 37 const char kLoadingOfflinePageReason[] = "reason="; | 37 const char kOfflinePageHeaderReasonKey[] = "reason"; |
| 38 const char kLoadingOfflinePageDueToNetError[] = "error"; | 38 const char kOfflinePageHeaderReasonValueDueToNetError[] = "error"; |
| 39 const char kOfflinePageHeaderReasonValueFromDownload[] = "download"; |
| 40 const char kOfflinePageHeaderPersistKey[] = "persist"; |
| 41 const char kOfflinePageHeaderIDKey[] = "id"; |
| 39 | 42 |
| 40 namespace { | 43 namespace { |
| 41 | 44 |
| 42 enum class NetworkState { | 45 enum class NetworkState { |
| 43 // No network connection. | 46 // No network connection. |
| 44 DISCONNECTED_NETWORK, | 47 DISCONNECTED_NETWORK, |
| 45 // Prohibitively slow means that the NetworkQualityEstimator reported a | 48 // Prohibitively slow means that the NetworkQualityEstimator reported a |
| 46 // connection slow enough to warrant showing an offline page if available. | 49 // connection slow enough to warrant showing an offline page if available. |
| 47 PROHIBITIVELY_SLOW_NETWORK, | 50 PROHIBITIVELY_SLOW_NETWORK, |
| 48 // Network error received due to bad network, i.e. connected to a hotspot or | 51 // Network error received due to bad network, i.e. connected to a hotspot or |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 } | 109 } |
| 107 | 110 |
| 108 private: | 111 private: |
| 109 static bool GetTabId(content::WebContents* web_contents, int* tab_id) { | 112 static bool GetTabId(content::WebContents* web_contents, int* tab_id) { |
| 110 return OfflinePageUtils::GetTabId(web_contents, tab_id); | 113 return OfflinePageUtils::GetTabId(web_contents, tab_id); |
| 111 } | 114 } |
| 112 | 115 |
| 113 DISALLOW_COPY_AND_ASSIGN(DefaultDelegate); | 116 DISALLOW_COPY_AND_ASSIGN(DefaultDelegate); |
| 114 }; | 117 }; |
| 115 | 118 |
| 116 // Returns true if custom offline header is present. | 119 // Used to parse the extra request header string that defines offline page |
| 117 // |reason| may be set with the reason to trigger the offline page loading. | 120 // loading behaviors. |
| 118 bool ParseOfflineHeader(net::URLRequest* request, std::string* reason) { | 121 class OfflinePageHeader { |
| 119 std::string value; | 122 public: |
| 120 if (!request->extra_request_headers().GetHeader(kLoadingOfflinePageHeader, | 123 enum class Reason { |
| 121 &value)) { | 124 NET_ERROR, |
| 122 return false; | 125 DOWNLOAD, |
| 126 UNKNOWN |
| 127 }; |
| 128 |
| 129 explicit OfflinePageHeader(const std::string& header_string); |
| 130 ~OfflinePageHeader() {} |
| 131 |
| 132 bool successfully_parsed() const { return successfully_parsed_; } |
| 133 bool need_to_persist() const { return need_to_persist_; } |
| 134 Reason reason() const { return reason_; } |
| 135 const std::string& id() const { return id_; } |
| 136 |
| 137 private: |
| 138 // True if the header is present and parsed successfully. |
| 139 bool successfully_parsed_; |
| 140 // Flag to indicate if the header should be persisted across session restore. |
| 141 bool need_to_persist_; |
| 142 // Describes the reason to load offline page. |
| 143 Reason reason_; |
| 144 // The offline ID of the page to load. |
| 145 std::string id_; |
| 146 |
| 147 DISALLOW_COPY_AND_ASSIGN(OfflinePageHeader); |
| 148 }; |
| 149 |
| 150 OfflinePageHeader::OfflinePageHeader(const std::string& header_string) |
| 151 : successfully_parsed_(false), |
| 152 need_to_persist_(false), |
| 153 reason_(Reason::UNKNOWN) { |
| 154 // If the offline header is not present, treat it as not parsed successfully. |
| 155 if (header_string.empty()) |
| 156 return; |
| 157 |
| 158 base::StringTokenizer tokenizer(header_string, ", "); |
| 159 while (tokenizer.GetNext()) { |
| 160 std::string pair = tokenizer.token(); |
| 161 std::size_t pos = pair.find('='); |
| 162 if (pos == std::string::npos) |
| 163 return; |
| 164 std::string key = base::ToLowerASCII(pair.substr(0, pos)); |
| 165 std::string value = base::ToLowerASCII(pair.substr(pos + 1)); |
| 166 if (key == kOfflinePageHeaderPersistKey) { |
| 167 need_to_persist_ = (value == "1"); |
| 168 } else if (key == kOfflinePageHeaderReasonKey) { |
| 169 if (value == kOfflinePageHeaderReasonValueDueToNetError) |
| 170 reason_ = Reason::NET_ERROR; |
| 171 else if (value == kOfflinePageHeaderReasonValueFromDownload) |
| 172 reason_ = Reason::DOWNLOAD; |
| 173 else |
| 174 reason_ = Reason::UNKNOWN; |
| 175 } else if (key == kOfflinePageHeaderIDKey) { |
| 176 id_ = value; |
| 177 } |
| 123 } | 178 } |
| 124 | 179 |
| 125 // Currently we only support reason field. | 180 successfully_parsed_ = true; |
| 126 base::StringTokenizer tokenizer(value, ", "); | |
| 127 while (tokenizer.GetNext()) { | |
| 128 if (base::StartsWith(tokenizer.token(), | |
| 129 kLoadingOfflinePageReason, | |
| 130 base::CompareCase::INSENSITIVE_ASCII)) { | |
| 131 *reason = tokenizer.token().substr( | |
| 132 arraysize(kLoadingOfflinePageReason) - 1); | |
| 133 break; | |
| 134 } | |
| 135 } | |
| 136 return true; | |
| 137 } | 181 } |
| 138 | 182 |
| 139 bool IsNetworkProhibitivelySlow(net::URLRequest* request) { | 183 bool IsNetworkProhibitivelySlow(net::URLRequest* request) { |
| 140 // NetworkQualityEstimator only works when it is enabled. | 184 // NetworkQualityEstimator only works when it is enabled. |
| 141 if (!previews::IsOfflinePreviewsEnabled()) | 185 if (!previews::IsOfflinePreviewsEnabled()) |
| 142 return false; | 186 return false; |
| 143 | 187 |
| 144 if (!request->context()) | 188 if (!request->context()) |
| 145 return false; | 189 return false; |
| 146 | 190 |
| 147 net::NetworkQualityEstimator* network_quality_estimator = | 191 net::NetworkQualityEstimator* network_quality_estimator = |
| 148 request->context()->network_quality_estimator(); | 192 request->context()->network_quality_estimator(); |
| 149 if (!network_quality_estimator) | 193 if (!network_quality_estimator) |
| 150 return false; | 194 return false; |
| 151 | 195 |
| 152 net::EffectiveConnectionType effective_connection_type = | 196 net::EffectiveConnectionType effective_connection_type = |
| 153 network_quality_estimator->GetEffectiveConnectionType(); | 197 network_quality_estimator->GetEffectiveConnectionType(); |
| 154 return effective_connection_type >= net::EFFECTIVE_CONNECTION_TYPE_OFFLINE && | 198 return effective_connection_type >= net::EFFECTIVE_CONNECTION_TYPE_OFFLINE && |
| 155 effective_connection_type <= net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G; | 199 effective_connection_type <= net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G; |
| 156 } | 200 } |
| 157 | 201 |
| 158 NetworkState GetNetworkState(net::URLRequest* request) { | 202 NetworkState GetNetworkState(net::URLRequest* request) { |
| 159 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 203 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 160 | 204 |
| 161 std::string reason; | 205 std::string offline_header_string; |
| 162 bool has_offline_header = ParseOfflineHeader(request, &reason); | 206 request->extra_request_headers().GetHeader( |
| 163 if (has_offline_header && | 207 kOfflinePageHeader, &offline_header_string); |
| 164 base::EqualsCaseInsensitiveASCII(reason, | 208 OfflinePageHeader offline_header(offline_header_string); |
| 165 kLoadingOfflinePageDueToNetError)) { | 209 if (offline_header.reason() == OfflinePageHeader::Reason::NET_ERROR) |
| 166 return NetworkState::FLAKY_NETWORK; | 210 return NetworkState::FLAKY_NETWORK; |
| 167 } | |
| 168 | 211 |
| 169 if (net::NetworkChangeNotifier::IsOffline()) | 212 if (net::NetworkChangeNotifier::IsOffline()) |
| 170 return NetworkState::DISCONNECTED_NETWORK; | 213 return NetworkState::DISCONNECTED_NETWORK; |
| 171 | 214 |
| 172 if (IsNetworkProhibitivelySlow(request)) | 215 if (IsNetworkProhibitivelySlow(request)) |
| 173 return NetworkState::PROHIBITIVELY_SLOW_NETWORK; | 216 return NetworkState::PROHIBITIVELY_SLOW_NETWORK; |
| 174 | 217 |
| 175 // The presence of custom offline header will force to load an offline page | 218 // If custom offline header is present, the offline page should be forced to |
| 176 // even when network is connected. | 219 // load even when the network is connected. |
| 177 return has_offline_header ? NetworkState::FORCE_OFFLINE_ON_CONNECTED_NETWORK | 220 return offline_header.successfully_parsed() |
| 178 : NetworkState::CONNECTED_NETWORK; | 221 ? NetworkState::FORCE_OFFLINE_ON_CONNECTED_NETWORK |
| 222 : NetworkState::CONNECTED_NETWORK; |
| 179 } | 223 } |
| 180 | 224 |
| 181 OfflinePageRequestJob::AggregatedRequestResult | 225 OfflinePageRequestJob::AggregatedRequestResult |
| 182 RequestResultToAggregatedRequestResult( | 226 RequestResultToAggregatedRequestResult( |
| 183 RequestResult request_result, NetworkState network_state) { | 227 RequestResult request_result, NetworkState network_state) { |
| 184 if (request_result == RequestResult::NO_TAB_ID) | 228 if (request_result == RequestResult::NO_TAB_ID) |
| 185 return OfflinePageRequestJob::AggregatedRequestResult::NO_TAB_ID; | 229 return OfflinePageRequestJob::AggregatedRequestResult::NO_TAB_ID; |
| 186 | 230 |
| 187 if (request_result == RequestResult::NO_WEB_CONTENTS) | 231 if (request_result == RequestResult::NO_WEB_CONTENTS) |
| 188 return OfflinePageRequestJob::AggregatedRequestResult::NO_WEB_CONTENTS; | 232 return OfflinePageRequestJob::AggregatedRequestResult::NO_WEB_CONTENTS; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 234 return OfflinePageRequestJob::AggregatedRequestResult:: | 278 return OfflinePageRequestJob::AggregatedRequestResult:: |
| 235 AGGREGATED_REQUEST_RESULT_MAX; | 279 AGGREGATED_REQUEST_RESULT_MAX; |
| 236 } | 280 } |
| 237 | 281 |
| 238 void ReportRequestResult( | 282 void ReportRequestResult( |
| 239 RequestResult request_result, NetworkState network_state) { | 283 RequestResult request_result, NetworkState network_state) { |
| 240 OfflinePageRequestJob::ReportAggregatedRequestResult( | 284 OfflinePageRequestJob::ReportAggregatedRequestResult( |
| 241 RequestResultToAggregatedRequestResult(request_result, network_state)); | 285 RequestResultToAggregatedRequestResult(request_result, network_state)); |
| 242 } | 286 } |
| 243 | 287 |
| 288 OfflinePageModel* GetOfflinePageModel( |
| 289 content::ResourceRequestInfo::WebContentsGetter web_contents_getter) { |
| 290 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 291 |
| 292 content::WebContents* web_contents = web_contents_getter.Run(); |
| 293 return web_contents ? |
| 294 OfflinePageModelFactory::GetForBrowserContext( |
| 295 web_contents->GetBrowserContext()) : |
| 296 nullptr; |
| 297 } |
| 298 |
| 244 void NotifyOfflineFilePathOnIO(base::WeakPtr<OfflinePageRequestJob> job, | 299 void NotifyOfflineFilePathOnIO(base::WeakPtr<OfflinePageRequestJob> job, |
| 245 const base::FilePath& offline_file_path) { | 300 const base::FilePath& offline_file_path) { |
| 246 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 301 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 247 | 302 |
| 248 if (!job) | 303 if (!job) |
| 249 return; | 304 return; |
| 250 job->OnOfflineFilePathAvailable(offline_file_path); | 305 job->OnOfflineFilePathAvailable(offline_file_path); |
| 251 } | 306 } |
| 252 | 307 |
| 253 // Notifies OfflinePageRequestJob about the offline file path. Note that the | 308 // Notifies OfflinePageRequestJob about the offline file path. Note that the |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 OfflinePageTabHelper::FromWebContents(web_contents); | 362 OfflinePageTabHelper::FromWebContents(web_contents); |
| 308 DCHECK(tab_helper); | 363 DCHECK(tab_helper); |
| 309 tab_helper->SetOfflinePage( | 364 tab_helper->SetOfflinePage( |
| 310 *offline_page, network_state == NetworkState::PROHIBITIVELY_SLOW_NETWORK); | 365 *offline_page, network_state == NetworkState::PROHIBITIVELY_SLOW_NETWORK); |
| 311 | 366 |
| 312 *offline_file_path = offline_page->file_path; | 367 *offline_file_path = offline_page->file_path; |
| 313 return RequestResult::OFFLINE_PAGE_SERVED; | 368 return RequestResult::OFFLINE_PAGE_SERVED; |
| 314 } | 369 } |
| 315 | 370 |
| 316 // Handles the result of finding an offline page. | 371 // Handles the result of finding an offline page. |
| 317 void SelectPageForOnlineURLDone( | 372 void SucceededToFindOfflinePage( |
| 318 NetworkState network_state, | 373 NetworkState network_state, |
| 319 base::WeakPtr<OfflinePageRequestJob> job, | 374 base::WeakPtr<OfflinePageRequestJob> job, |
| 320 content::ResourceRequestInfo::WebContentsGetter web_contents_getter, | 375 content::ResourceRequestInfo::WebContentsGetter web_contents_getter, |
| 321 const OfflinePageItem* offline_page) { | 376 const OfflinePageItem* offline_page) { |
| 322 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 377 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 323 | 378 |
| 324 base::FilePath offline_file_path; | 379 base::FilePath offline_file_path; |
| 325 RequestResult request_result = AccessOfflineFile( | 380 RequestResult request_result = AccessOfflineFile( |
| 326 network_state, job, web_contents_getter, offline_page, | 381 network_state, job, web_contents_getter, offline_page, |
| 327 &offline_file_path); | 382 &offline_file_path); |
| 328 | 383 |
| 329 ReportRequestResult(request_result, network_state); | 384 ReportRequestResult(request_result, network_state); |
| 330 | 385 |
| 331 // NotifyOfflineFilePathOnUI should always be called regardless the failure | 386 // NotifyOfflineFilePathOnUI should always be called regardless the failure |
| 332 // result and empty file path such that OfflinePageRequestJob will be notified | 387 // result and empty file path such that OfflinePageRequestJob will be notified |
| 333 // on failure. | 388 // on failure. |
| 334 NotifyOfflineFilePathOnUI(job, offline_file_path); | 389 NotifyOfflineFilePathOnUI(job, offline_file_path); |
| 335 } | 390 } |
| 336 | 391 |
| 337 void FailedToSelectOfflinePage(base::WeakPtr<OfflinePageRequestJob> job) { | 392 void FailedToFindOfflinePage(base::WeakPtr<OfflinePageRequestJob> job) { |
| 338 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 393 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 339 | 394 |
| 340 // Proceed with empty file path in order to notify the OfflinePageRequestJob | 395 // Proceed with empty file path in order to notify the OfflinePageRequestJob |
| 341 // about the failure. | 396 // about the failure. |
| 342 base::FilePath empty_file_path; | 397 base::FilePath empty_file_path; |
| 343 NotifyOfflineFilePathOnUI(job, empty_file_path); | 398 NotifyOfflineFilePathOnUI(job, empty_file_path); |
| 344 } | 399 } |
| 345 | 400 |
| 346 // Tries to find the offline page to serve for |online_url|. | 401 // Tries to find the offline page to serve for |online_url|. |
| 347 void SelectOfflinePage( | 402 void SelectPageForOnlineURL( |
| 348 const GURL& online_url, | 403 const GURL& online_url, |
| 349 NetworkState network_state, | 404 NetworkState network_state, |
| 350 void* profile_id, | |
| 351 content::ResourceRequestInfo::WebContentsGetter web_contents_getter, | 405 content::ResourceRequestInfo::WebContentsGetter web_contents_getter, |
| 352 OfflinePageRequestJob::Delegate::TabIdGetter tab_id_getter, | 406 OfflinePageRequestJob::Delegate::TabIdGetter tab_id_getter, |
| 353 base::WeakPtr<OfflinePageRequestJob> job) { | 407 base::WeakPtr<OfflinePageRequestJob> job) { |
| 354 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 408 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 355 | 409 |
| 356 // |profile_id| needs to be checked with ProfileManager::IsValidProfile | |
| 357 // before using it. | |
| 358 if (!g_browser_process->profile_manager()->IsValidProfile(profile_id)) { | |
| 359 FailedToSelectOfflinePage(job); | |
| 360 return; | |
| 361 } | |
| 362 Profile* profile = reinterpret_cast<Profile*>(profile_id); | |
| 363 | |
| 364 content::WebContents* web_contents = web_contents_getter.Run(); | 410 content::WebContents* web_contents = web_contents_getter.Run(); |
| 365 if (!web_contents){ | 411 if (!web_contents){ |
| 366 ReportRequestResult(RequestResult::NO_WEB_CONTENTS, network_state); | 412 ReportRequestResult(RequestResult::NO_WEB_CONTENTS, network_state); |
| 367 FailedToSelectOfflinePage(job); | 413 FailedToFindOfflinePage(job); |
| 368 return; | 414 return; |
| 369 } | 415 } |
| 370 int tab_id; | 416 int tab_id; |
| 371 if (!tab_id_getter.Run(web_contents, &tab_id)) { | 417 if (!tab_id_getter.Run(web_contents, &tab_id)) { |
| 372 ReportRequestResult(RequestResult::NO_TAB_ID, network_state); | 418 ReportRequestResult(RequestResult::NO_TAB_ID, network_state); |
| 373 FailedToSelectOfflinePage(job); | 419 FailedToFindOfflinePage(job); |
| 374 return; | 420 return; |
| 375 } | 421 } |
| 376 | 422 |
| 377 OfflinePageUtils::SelectPageForOnlineURL( | 423 OfflinePageUtils::SelectPageForOnlineURL( |
| 378 profile, | 424 web_contents->GetBrowserContext(), |
| 379 online_url, | 425 online_url, |
| 380 tab_id, | 426 tab_id, |
| 381 base::Bind(&SelectPageForOnlineURLDone, | 427 base::Bind(&SucceededToFindOfflinePage, |
| 382 network_state, | 428 network_state, |
| 383 job, | 429 job, |
| 384 web_contents_getter)); | 430 web_contents_getter)); |
| 385 } | 431 } |
| 386 | 432 |
| 433 void FindPageWithOfflineIDDone( |
| 434 const GURL& online_url, |
| 435 NetworkState network_state, |
| 436 content::ResourceRequestInfo::WebContentsGetter web_contents_getter, |
| 437 OfflinePageRequestJob::Delegate::TabIdGetter tab_id_getter, |
| 438 base::WeakPtr<OfflinePageRequestJob> job, |
| 439 const OfflinePageItem* offline_page) { |
| 440 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 441 |
| 442 // If the found offline page does not has same URL as the request URL, fall |
| 443 // back to find the offline page based on the URL. |
| 444 if (!offline_page || offline_page->url != online_url) { |
| 445 SelectPageForOnlineURL( |
| 446 online_url, network_state, web_contents_getter, tab_id_getter, job); |
| 447 return; |
| 448 } |
| 449 |
| 450 SucceededToFindOfflinePage( |
| 451 network_state, job, web_contents_getter, offline_page); |
| 452 } |
| 453 |
| 454 // Tries to find an offline page associated with |offline_id|. |
| 455 void FindPageWithOfflineID( |
| 456 const GURL& online_url, |
| 457 int64_t offline_id, |
| 458 NetworkState network_state, |
| 459 content::ResourceRequestInfo::WebContentsGetter web_contents_getter, |
| 460 OfflinePageRequestJob::Delegate::TabIdGetter tab_id_getter, |
| 461 base::WeakPtr<OfflinePageRequestJob> job) { |
| 462 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 463 |
| 464 OfflinePageModel* offline_page_model = |
| 465 GetOfflinePageModel(web_contents_getter); |
| 466 if (!offline_page_model) { |
| 467 FailedToFindOfflinePage(job); |
| 468 return; |
| 469 } |
| 470 |
| 471 offline_page_model->GetPageByOfflineId( |
| 472 offline_id, |
| 473 base::Bind(&FindPageWithOfflineIDDone, |
| 474 online_url, |
| 475 network_state, |
| 476 web_contents_getter, |
| 477 tab_id_getter, |
| 478 job)); |
| 479 } |
| 480 |
| 481 // Tries to find the offline page to serve for |online_url|. |
| 482 void SelectPage( |
| 483 const GURL& online_url, |
| 484 const std::string& offline_header_string, |
| 485 NetworkState network_state, |
| 486 content::ResourceRequestInfo::WebContentsGetter web_contents_getter, |
| 487 OfflinePageRequestJob::Delegate::TabIdGetter tab_id_getter, |
| 488 base::WeakPtr<OfflinePageRequestJob> job) { |
| 489 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 490 |
| 491 OfflinePageHeader offline_header(offline_header_string); |
| 492 |
| 493 // If an offline ID is present in the offline header, try to load that |
| 494 // particular version. |
| 495 if (!offline_header.id().empty()) { |
| 496 // if the id string cannot be converted to int64 id, fall through to |
| 497 // select page via online URL. |
| 498 int64_t offline_id; |
| 499 if (base::StringToInt64(offline_header.id(), &offline_id)) { |
| 500 FindPageWithOfflineID(online_url, offline_id, network_state, |
| 501 web_contents_getter, tab_id_getter, job); |
| 502 return; |
| 503 } |
| 504 } |
| 505 |
| 506 SelectPageForOnlineURL(online_url, network_state, web_contents_getter, |
| 507 tab_id_getter, job); |
| 508 } |
| 509 |
| 387 } // namespace | 510 } // namespace |
| 388 | 511 |
| 389 // static | 512 // static |
| 390 void OfflinePageRequestJob::ReportAggregatedRequestResult( | 513 void OfflinePageRequestJob::ReportAggregatedRequestResult( |
| 391 AggregatedRequestResult result) { | 514 AggregatedRequestResult result) { |
| 392 UMA_HISTOGRAM_ENUMERATION("OfflinePages.AggregatedRequestResult", | 515 UMA_HISTOGRAM_ENUMERATION("OfflinePages.AggregatedRequestResult", |
| 393 static_cast<int>(result), | 516 static_cast<int>(result), |
| 394 static_cast<int>(AggregatedRequestResult::AGGREGATED_REQUEST_RESULT_MAX)); | 517 static_cast<int>(AggregatedRequestResult::AGGREGATED_REQUEST_RESULT_MAX)); |
| 395 } | 518 } |
| 396 | 519 |
| 397 // static | 520 // static |
| 398 OfflinePageRequestJob* OfflinePageRequestJob::Create( | 521 OfflinePageRequestJob* OfflinePageRequestJob::Create( |
| 399 void* profile_id, | |
| 400 net::URLRequest* request, | 522 net::URLRequest* request, |
| 401 net::NetworkDelegate* network_delegate) { | 523 net::NetworkDelegate* network_delegate) { |
| 402 const content::ResourceRequestInfo* resource_request_info = | 524 const content::ResourceRequestInfo* resource_request_info = |
| 403 content::ResourceRequestInfo::ForRequest(request); | 525 content::ResourceRequestInfo::ForRequest(request); |
| 404 if (!resource_request_info) | 526 if (!resource_request_info) |
| 405 return nullptr; | 527 return nullptr; |
| 406 | 528 |
| 407 // Ignore the requests not for the main resource. | 529 // Ignore the requests not for the main resource. |
| 408 if (resource_request_info->GetResourceType() != | 530 if (resource_request_info->GetResourceType() != |
| 409 content::RESOURCE_TYPE_MAIN_FRAME) { | 531 content::RESOURCE_TYPE_MAIN_FRAME) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 422 OfflinePageRequestInfo::GetFromRequest(request); | 544 OfflinePageRequestInfo::GetFromRequest(request); |
| 423 if (info) { | 545 if (info) { |
| 424 // Fall back to default which is set when an offline page cannot be served, | 546 // Fall back to default which is set when an offline page cannot be served, |
| 425 // either page not found or online version desired. | 547 // either page not found or online version desired. |
| 426 if (info->use_default()) | 548 if (info->use_default()) |
| 427 return nullptr; | 549 return nullptr; |
| 428 } else { | 550 } else { |
| 429 request->SetUserData(&kUserDataKey, new OfflinePageRequestInfo()); | 551 request->SetUserData(&kUserDataKey, new OfflinePageRequestInfo()); |
| 430 } | 552 } |
| 431 | 553 |
| 432 return new OfflinePageRequestJob(profile_id, request, network_delegate); | 554 return new OfflinePageRequestJob(request, network_delegate); |
| 433 } | 555 } |
| 434 | 556 |
| 435 OfflinePageRequestJob::OfflinePageRequestJob( | 557 OfflinePageRequestJob::OfflinePageRequestJob( |
| 436 void* profile_id, | |
| 437 net::URLRequest* request, | 558 net::URLRequest* request, |
| 438 net::NetworkDelegate* network_delegate) | 559 net::NetworkDelegate* network_delegate) |
| 439 : net::URLRequestFileJob( | 560 : net::URLRequestFileJob( |
| 440 request, | 561 request, |
| 441 network_delegate, | 562 network_delegate, |
| 442 base::FilePath(), | 563 base::FilePath(), |
| 443 content::BrowserThread::GetBlockingPool()-> | 564 content::BrowserThread::GetBlockingPool()-> |
| 444 GetTaskRunnerWithShutdownBehavior( | 565 GetTaskRunnerWithShutdownBehavior( |
| 445 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)), | 566 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)), |
| 446 profile_id_(profile_id), | |
| 447 delegate_(new DefaultDelegate()), | 567 delegate_(new DefaultDelegate()), |
| 448 weak_ptr_factory_(this) { | 568 weak_ptr_factory_(this) { |
| 449 } | 569 } |
| 450 | 570 |
| 451 OfflinePageRequestJob::~OfflinePageRequestJob() { | 571 OfflinePageRequestJob::~OfflinePageRequestJob() { |
| 452 } | 572 } |
| 453 | 573 |
| 454 void OfflinePageRequestJob::Start() { | 574 void OfflinePageRequestJob::Start() { |
| 455 base::ThreadTaskRunnerHandle::Get()->PostTask( | 575 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 456 FROM_HERE, base::Bind(&OfflinePageRequestJob::StartAsync, | 576 FROM_HERE, base::Bind(&OfflinePageRequestJob::StartAsync, |
| 457 weak_ptr_factory_.GetWeakPtr())); | 577 weak_ptr_factory_.GetWeakPtr())); |
| 458 } | 578 } |
| 459 | 579 |
| 460 void OfflinePageRequestJob::StartAsync() { | 580 void OfflinePageRequestJob::StartAsync() { |
| 461 NetworkState network_state = GetNetworkState(request()); | 581 NetworkState network_state = GetNetworkState(request()); |
| 462 if (network_state == NetworkState::CONNECTED_NETWORK) { | 582 if (network_state == NetworkState::CONNECTED_NETWORK) { |
| 463 FallbackToDefault(); | 583 FallbackToDefault(); |
| 464 return; | 584 return; |
| 465 } | 585 } |
| 466 | 586 |
| 587 std::string offline_header_string; |
| 588 request()->extra_request_headers().GetHeader(kOfflinePageHeader, |
| 589 &offline_header_string); |
| 467 content::BrowserThread::PostTask( | 590 content::BrowserThread::PostTask( |
| 468 content::BrowserThread::UI, | 591 content::BrowserThread::UI, |
| 469 FROM_HERE, | 592 FROM_HERE, |
| 470 base::Bind(&SelectOfflinePage, | 593 base::Bind(&SelectPage, |
| 471 request()->url(), | 594 request()->url(), |
| 595 offline_header_string, |
| 472 network_state, | 596 network_state, |
| 473 profile_id_, | |
| 474 delegate_->GetWebContentsGetter(request()), | 597 delegate_->GetWebContentsGetter(request()), |
| 475 delegate_->GetTabIdGetter(), | 598 delegate_->GetTabIdGetter(), |
| 476 weak_ptr_factory_.GetWeakPtr())); | 599 weak_ptr_factory_.GetWeakPtr())); |
| 477 } | 600 } |
| 478 | 601 |
| 479 void OfflinePageRequestJob::Kill() { | 602 void OfflinePageRequestJob::Kill() { |
| 480 net::URLRequestJob::Kill(); | 603 net::URLRequestJob::Kill(); |
| 481 weak_ptr_factory_.InvalidateWeakPtrs(); | 604 weak_ptr_factory_.InvalidateWeakPtrs(); |
| 482 } | 605 } |
| 483 | 606 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 503 file_path_ = offline_file_path; | 626 file_path_ = offline_file_path; |
| 504 URLRequestFileJob::Start(); | 627 URLRequestFileJob::Start(); |
| 505 } | 628 } |
| 506 | 629 |
| 507 void OfflinePageRequestJob::SetDelegateForTesting( | 630 void OfflinePageRequestJob::SetDelegateForTesting( |
| 508 std::unique_ptr<Delegate> delegate) { | 631 std::unique_ptr<Delegate> delegate) { |
| 509 delegate_ = std::move(delegate); | 632 delegate_ = std::move(delegate); |
| 510 } | 633 } |
| 511 | 634 |
| 512 } // namespace offline_pages | 635 } // namespace offline_pages |
| OLD | NEW |