chromium/ios/chrome/browser/webui/ui_bundled/interstitials/interstitial_ui.mm

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/webui/ui_bundled/interstitials/interstitial_ui.h"

#import <Foundation/Foundation.h>

#import <memory>
#import <utility>

#import "base/memory/raw_ptr.h"
#import "base/memory/ref_counted_memory.h"
#import "base/time/time.h"
#import "components/grit/dev_ui_components_resources.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
#import "ios/chrome/browser/shared/model/url/chrome_url_constants.h"
#import "ios/chrome/browser/webui/ui_bundled/interstitials/interstitial_ui_constants.h"
#import "ios/chrome/browser/webui/ui_bundled/interstitials/interstitial_ui_util.h"
#import "ios/components/security_interstitials/ios_security_interstitial_page.h"
#import "ios/web/public/web_state.h"
#import "ios/web/public/webui/url_data_source_ios.h"
#import "ios/web/public/webui/web_ui_ios.h"
#import "ios/web/public/webui/web_ui_ios_data_source.h"
#import "net/base/url_util.h"
#import "ui/base/resource/resource_bundle.h"

namespace {

// Implementation of chrome://interstitials demonstration pages.
class InterstitialHTMLSource : public web::URLDataSourceIOS {
 public:
  explicit InterstitialHTMLSource(ChromeBrowserState* browser_state);
  ~InterstitialHTMLSource() override;
  InterstitialHTMLSource(InterstitialHTMLSource&& other) = default;
  InterstitialHTMLSource& operator=(InterstitialHTMLSource&& other) = default;

 private:
  // web::URLDataSourceIOS:
  std::string GetSource() const override;
  void StartDataRequest(
      const std::string& path,
      web::URLDataSourceIOS::GotDataCallback callback) override;
  std::string GetMimeType(const std::string& path) const override;

  // The ChromeBrowserState passed on initialization.  Used to construct
  // WebStates that are passed to IOSSecurityInterstitialPages.
  raw_ptr<ChromeBrowserState> browser_state_ = nullptr;
};

}  //  namespace

#pragma mark - InterstitialHTMLSource

InterstitialHTMLSource::InterstitialHTMLSource(
    ChromeBrowserState* browser_state)
    : browser_state_(browser_state) {
  DCHECK(browser_state_);
}

InterstitialHTMLSource::~InterstitialHTMLSource() = default;

std::string InterstitialHTMLSource::GetMimeType(
    const std::string& mime_type) const {
  return "text/html";
}

std::string InterstitialHTMLSource::GetSource() const {
  return kChromeUIIntersitialsHost;
}

void InterstitialHTMLSource::StartDataRequest(
    const std::string& path,
    web::URLDataSourceIOS::GotDataCallback callback) {
  std::unique_ptr<web::WebState> web_state =
      web::WebState::Create(web::WebState::CreateParams(browser_state_));
  std::unique_ptr<security_interstitials::IOSSecurityInterstitialPage>
      interstitial_page;
  std::string html;
  // Using this form of the path so we can do exact matching, while ignoring the
  // query (everything after the ? character).
  GURL url = GURL(kChromeUIIntersitialsURL).GetWithEmptyPath().Resolve(path);
  std::string path_without_query = url.path();
  if (path_without_query == kChromeInterstitialSslPath) {
    interstitial_page = CreateSslBlockingPage(web_state.get(), url);
  } else if (path_without_query == kChromeInterstitialCaptivePortalPath) {
    interstitial_page = CreateCaptivePortalBlockingPage(web_state.get());
  } else if (path_without_query == kChromeInterstitialSafeBrowsingPath) {
    interstitial_page = CreateSafeBrowsingBlockingPage(web_state.get(), url);
  }
  // TODO(crbug.com/40681491): Update the page HTML when a link for an
  // unsupported interstitial type is tapped.

  // Use the HTML generated from the interstitial page if created
  // successfully.  Otherwise, return the default chrome://interstitials HTML.
  if (interstitial_page) {
    html = interstitial_page->GetHtmlContents();
  } else {
    html = ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
        IDR_SECURITY_INTERSTITIAL_UI_HTML);
  }

  std::move(callback).Run(
      base::MakeRefCounted<base::RefCountedString>(std::move(html)));
}

#pragma mark - InterstitialUI

InterstitialUI::InterstitialUI(web::WebUIIOS* web_ui, const std::string& host)
    : WebUIIOSController(web_ui, host) {
  ChromeBrowserState* browser_state = ChromeBrowserState::FromWebUIIOS(web_ui);
  web::URLDataSourceIOS::Add(browser_state,
                             new InterstitialHTMLSource(browser_state));
}

InterstitialUI::~InterstitialUI() = default;