1// Copyright 2020 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#import "ios/chrome/browser/ui/webui/interstitials/interstitial_ui.h"
6
7#import <Foundation/Foundation.h>
8#include <memory>
9#include <utility>
10
11#include "base/memory/ref_counted_memory.h"
12#include "base/time/time.h"
13#include "components/grit/dev_ui_components_resources.h"
14#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
15#include "ios/chrome/browser/chrome_url_constants.h"
16#import "ios/chrome/browser/ui/webui/interstitials/interstitial_ui_constants.h"
17#import "ios/chrome/browser/ui/webui/interstitials/interstitial_ui_util.h"
18#import "ios/web/public/security/web_interstitial_delegate.h"
19#import "ios/web/public/web_state.h"
20#include "ios/web/public/webui/url_data_source_ios.h"
21#include "ios/web/public/webui/web_ui_ios.h"
22#include "ios/web/public/webui/web_ui_ios_data_source.h"
23#include "net/base/url_util.h"
24#include "ui/base/resource/resource_bundle.h"
25
26#if !defined(__has_feature) || !__has_feature(objc_arc)
27#error "This file requires ARC support."
28#endif
29
30namespace {
31
32// Implementation of chrome://interstitials demonstration pages.
33class InterstitialHTMLSource : public web::URLDataSourceIOS {
34 public:
35  explicit InterstitialHTMLSource(ChromeBrowserState* browser_state);
36  ~InterstitialHTMLSource() override;
37  InterstitialHTMLSource(InterstitialHTMLSource&& other) = default;
38  InterstitialHTMLSource& operator=(InterstitialHTMLSource&& other) = default;
39
40 private:
41  // web::URLDataSourceIOS:
42  std::string GetSource() const override;
43  void StartDataRequest(
44      const std::string& path,
45      web::URLDataSourceIOS::GotDataCallback callback) override;
46  std::string GetMimeType(const std::string& path) const override;
47
48  // The ChromeBrowserState passed on initialization.  Used to construct
49  // WebStates that are passed to WebInterstitialDelegates.
50  ChromeBrowserState* browser_state_ = nullptr;
51};
52
53}  //  namespace
54
55#pragma mark - InterstitialHTMLSource
56
57InterstitialHTMLSource::InterstitialHTMLSource(
58    ChromeBrowserState* browser_state)
59    : browser_state_(browser_state) {
60  DCHECK(browser_state_);
61}
62
63InterstitialHTMLSource::~InterstitialHTMLSource() = default;
64
65std::string InterstitialHTMLSource::GetMimeType(
66    const std::string& mime_type) const {
67  return "text/html";
68}
69
70std::string InterstitialHTMLSource::GetSource() const {
71  return kChromeUIIntersitialsHost;
72}
73
74void InterstitialHTMLSource::StartDataRequest(
75    const std::string& path,
76    web::URLDataSourceIOS::GotDataCallback callback) {
77  std::unique_ptr<web::WebState> web_state =
78      web::WebState::Create(web::WebState::CreateParams(browser_state_));
79  std::unique_ptr<web::WebInterstitialDelegate> interstitial_delegate;
80  std::string html;
81  // Using this form of the path so we can do exact matching, while ignoring the
82  // query (everything after the ? character).
83  GURL url = GURL(kChromeUIIntersitialsURL).GetWithEmptyPath().Resolve(path);
84  std::string path_without_query = url.path();
85  if (path_without_query == kChromeInterstitialSslPath) {
86    interstitial_delegate = CreateSslBlockingPageDelegate(web_state.get(), url);
87  } else if (path_without_query == kChromeInterstitialCaptivePortalPath) {
88    interstitial_delegate =
89        CreateCaptivePortalBlockingPageDelegate(web_state.get());
90  } else if (path_without_query == kChromeInterstitialSafeBrowsingPath) {
91    interstitial_delegate =
92        CreateSafeBrowsingBlockingPageDelegate(web_state.get(), url);
93  }
94  // TODO(crbug.com/1064805): Update the page HTML when a link for an
95  // unsupported interstitial type is tapped.
96
97  // Use the HTML generated from the interstitial delegate if created
98  // successfully.  Otherwise, return the default chrome://interstitials HTML.
99  if (interstitial_delegate) {
100    html = interstitial_delegate->GetHtmlContents();
101  } else {
102    html = ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
103        IDR_SECURITY_INTERSTITIAL_UI_HTML);
104  }
105
106  std::move(callback).Run(base::RefCountedString::TakeString(&html));
107}
108
109#pragma mark - InterstitialUI
110
111InterstitialUI::InterstitialUI(web::WebUIIOS* web_ui, const std::string& host)
112    : WebUIIOSController(web_ui, host) {
113  ChromeBrowserState* browser_state = ChromeBrowserState::FromWebUIIOS(web_ui);
114  web::URLDataSourceIOS::Add(browser_state,
115                             new InterstitialHTMLSource(browser_state));
116}
117
118InterstitialUI::~InterstitialUI() = default;
119