| Index: ios/chrome/browser/reading_list/reading_list_distiller_page.mm
|
| diff --git a/ios/chrome/browser/reading_list/reading_list_distiller_page.mm b/ios/chrome/browser/reading_list/reading_list_distiller_page.mm
|
| index cf67cc6176f52557454e5fa91d48b0aab9c607a4..9bf23db09388e4c8415320c1df6b097b776e4a77 100644
|
| --- a/ios/chrome/browser/reading_list/reading_list_distiller_page.mm
|
| +++ b/ios/chrome/browser/reading_list/reading_list_distiller_page.mm
|
| @@ -5,18 +5,26 @@
|
| #include "ios/chrome/browser/reading_list/reading_list_distiller_page.h"
|
|
|
| #include "base/bind.h"
|
| +#include "base/mac/foundation_util.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| #include "base/threading/thread_task_runner_handle.h"
|
| #include "components/favicon/ios/web_favicon_driver.h"
|
| +#include "components/google/core/browser/google_util.h"
|
| #include "ios/chrome/browser/reading_list/favicon_web_state_dispatcher_impl.h"
|
| #import "ios/web/public/navigation_item.h"
|
| #import "ios/web/public/navigation_manager.h"
|
| #include "ios/web/public/ssl_status.h"
|
| +#import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
|
| #import "ios/web/public/web_state/web_state.h"
|
| +#import "net/base/mac/url_conversions.h"
|
| #include "net/cert/cert_status_flags.h"
|
| +#include "url/url_constants.h"
|
|
|
| namespace {
|
| // The delay between the page load and the distillation in seconds.
|
| const int64_t kDistillationDelayInSeconds = 2;
|
| +const char* kGetIframeURLJavaScript =
|
| + "document.getElementsByTagName('iframe')[0].src;";
|
| } // namespace
|
|
|
| namespace reading_list {
|
| @@ -59,7 +67,7 @@ void ReadingListDistillerPage::OnDistillationDone(const GURL& page_url,
|
|
|
| bool ReadingListDistillerPage::IsLoadingSuccess(
|
| web::PageLoadCompletionStatus load_completion_status) {
|
| - if (load_completion_status == web::PageLoadCompletionStatus::FAILURE) {
|
| + if (load_completion_status != web::PageLoadCompletionStatus::SUCCESS) {
|
| return false;
|
| }
|
| if (!CurrentWebState() || !CurrentWebState()->GetNavigationManager() ||
|
| @@ -91,16 +99,97 @@ void ReadingListDistillerPage::OnLoadURLDone(
|
| DistillerPageIOS::OnLoadURLDone(load_completion_status);
|
| return;
|
| }
|
| + if (IsGoogleCachedAMPPage()) {
|
| + // Workaround for Google AMP pages.
|
| + HandleGoogleCachedAMPPage();
|
| + } else {
|
| + WaitForPageLoadCompletion();
|
| + }
|
| +}
|
| +
|
| +void ReadingListDistillerPage::WaitForPageLoadCompletion() {
|
| base::WeakPtr<ReadingListDistillerPage> weak_this =
|
| weak_ptr_factory_.GetWeakPtr();
|
| base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
|
| - FROM_HERE, base::Bind(&ReadingListDistillerPage::DelayedOnLoadURLDone,
|
| - weak_this, load_completion_status),
|
| + FROM_HERE,
|
| + base::Bind(&ReadingListDistillerPage::DelayedOnLoadURLDone, weak_this),
|
| base::TimeDelta::FromSeconds(kDistillationDelayInSeconds));
|
| }
|
|
|
| -void ReadingListDistillerPage::DelayedOnLoadURLDone(
|
| - web::PageLoadCompletionStatus load_completion_status) {
|
| - DistillerPageIOS::OnLoadURLDone(load_completion_status);
|
| +void ReadingListDistillerPage::DelayedOnLoadURLDone() {
|
| + DistillerPageIOS::OnLoadURLDone(web::PageLoadCompletionStatus::SUCCESS);
|
| +}
|
| +
|
| +bool ReadingListDistillerPage::IsGoogleCachedAMPPage() {
|
| + // All google AMP pages have URL in the form "https://google_domain/amp/..."
|
| + // and a valid certificate.
|
| + // This method checks that this is strictly the case.
|
| + const GURL& url = CurrentWebState()->GetLastCommittedURL();
|
| + if (!url.is_valid() || !url.SchemeIs(url::kHttpsScheme)) {
|
| + return false;
|
| + }
|
| + if (!google_util::IsGoogleDomainUrl(
|
| + url, google_util::DISALLOW_SUBDOMAIN,
|
| + google_util::DISALLOW_NON_STANDARD_PORTS) ||
|
| + !url.path().compare(0, 4, "amp/")) {
|
| + return false;
|
| + }
|
| + const web::SSLStatus& ssl_status = CurrentWebState()
|
| + ->GetNavigationManager()
|
| + ->GetLastCommittedItem()
|
| + ->GetSSL();
|
| + if (!ssl_status.certificate ||
|
| + (net::IsCertStatusError(ssl_status.cert_status) &&
|
| + !net::IsCertStatusMinorError(ssl_status.cert_status))) {
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| }
|
| +
|
| +void ReadingListDistillerPage::HandleGoogleCachedAMPPage() {
|
| + base::WeakPtr<ReadingListDistillerPage> weak_this =
|
| + weak_ptr_factory_.GetWeakPtr();
|
| + [CurrentWebState()->GetJSInjectionReceiver()
|
| + executeJavaScript:@(kGetIframeURLJavaScript)
|
| + completionHandler:^(id result, NSError* error) {
|
| + if (weak_this &&
|
| + !weak_this->HandleGoogleCachedAMPPageJavaScriptResult(result,
|
| + error)) {
|
| + // If there is an error on navigation, continue normal distillation.
|
| + weak_this->WaitForPageLoadCompletion();
|
| + }
|
| + // If there is no error, the navigation completion will trigger a new
|
| + // |OnLoadURLDone| call that will resume the distillation.
|
| + }];
|
| +}
|
| +
|
| +bool ReadingListDistillerPage::HandleGoogleCachedAMPPageJavaScriptResult(
|
| + id result,
|
| + NSError* error) {
|
| + if (error) {
|
| + return false;
|
| + }
|
| + NSString* result_string = base::mac::ObjCCast<NSString>(result);
|
| + NSURL* new_url = [NSURL URLWithString:result_string];
|
| + if (!new_url) {
|
| + return false;
|
| + }
|
| + bool is_cdn_ampproject =
|
| + [[new_url host] isEqualToString:@"cdn.ampproject.org"];
|
| + bool is_cdn_ampproject_subdomain =
|
| + [[new_url host] hasSuffix:@".cdn.ampproject.org"];
|
| +
|
| + if (!is_cdn_ampproject && !is_cdn_ampproject_subdomain) {
|
| + return false;
|
| + }
|
| + GURL new_gurl = net::GURLWithNSURL(new_url);
|
| + if (!new_gurl.is_valid()) {
|
| + return false;
|
| + }
|
| + web::NavigationManager::WebLoadParams params(new_gurl);
|
| + CurrentWebState()->GetNavigationManager()->LoadURLWithParams(params);
|
| + return true;
|
| +}
|
| +
|
| } // namespace reading_list
|
|
|