OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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 #include "components/data_reduction_proxy/content/browser/data_reduction_proxy_b
locking_page.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/lazy_instance.h" |
| 9 #include "base/single_thread_task_runner.h" |
| 10 #include "base/strings/string_piece.h" |
| 11 #include "base/strings/utf_string_conversions.h" |
| 12 #include "base/values.h" |
| 13 #include "content/public/browser/interstitial_page.h" |
| 14 #include "content/public/browser/render_view_host.h" |
| 15 #include "content/public/browser/web_contents.h" |
| 16 #include "grit/components_resources.h" |
| 17 #include "grit/components_strings.h" |
| 18 #include "ui/base/l10n/l10n_util.h" |
| 19 #include "ui/base/resource/resource_bundle.h" |
| 20 #include "ui/base/webui/jstemplate_builder.h" |
| 21 #include "ui/base/webui/web_ui_util.h" |
| 22 |
| 23 namespace data_reduction_proxy { |
| 24 |
| 25 namespace { |
| 26 |
| 27 // The commands returned by the page when the user performs an action. |
| 28 const char kProceedCommand[] = "proceed"; |
| 29 const char kTakeMeBackCommand[] = "takeMeBack"; |
| 30 |
| 31 base::LazyInstance<DataReductionProxyBlockingPage::BypassResourceMap> |
| 32 g_bypass_resource_map = LAZY_INSTANCE_INITIALIZER; |
| 33 |
| 34 } // namespace |
| 35 |
| 36 // static |
| 37 DataReductionProxyBlockingPageFactory* |
| 38 DataReductionProxyBlockingPage::factory_ = NULL; |
| 39 |
| 40 // The default DataReductionProxyBlockingPageFactory. Global, made a singleton |
| 41 // so it isn't leaked. |
| 42 class DataReductionProxyBlockingPageFactoryImpl |
| 43 : public DataReductionProxyBlockingPageFactory { |
| 44 public: |
| 45 virtual DataReductionProxyBlockingPage* CreateDataReductionProxyPage( |
| 46 DataReductionProxyUIManager* ui_manager, |
| 47 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, |
| 48 content::WebContents* web_contents, |
| 49 const DataReductionProxyBlockingPage::BypassResourceList& resource_list) |
| 50 override { |
| 51 return new DataReductionProxyBlockingPage(ui_manager, io_task_runner, |
| 52 web_contents, resource_list); |
| 53 } |
| 54 |
| 55 private: |
| 56 friend struct base::DefaultLazyInstanceTraits< |
| 57 DataReductionProxyBlockingPageFactoryImpl>; |
| 58 |
| 59 DataReductionProxyBlockingPageFactoryImpl() { |
| 60 } |
| 61 |
| 62 DISALLOW_COPY_AND_ASSIGN(DataReductionProxyBlockingPageFactoryImpl); |
| 63 }; |
| 64 |
| 65 static base::LazyInstance<DataReductionProxyBlockingPageFactoryImpl> |
| 66 g_data_reduction_proxy_blocking_page_factory_impl = |
| 67 LAZY_INSTANCE_INITIALIZER; |
| 68 |
| 69 DataReductionProxyBlockingPage::DataReductionProxyBlockingPage( |
| 70 DataReductionProxyUIManager* ui_manager, |
| 71 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, |
| 72 content::WebContents* web_contents, |
| 73 const BypassResourceList& resource_list) |
| 74 : ui_manager_(ui_manager), |
| 75 io_task_runner_(io_task_runner), |
| 76 is_main_frame_load_blocked_(IsMainPageLoadBlocked(resource_list)), |
| 77 resource_list_(resource_list), |
| 78 proceeded_(false), |
| 79 web_contents_(web_contents), |
| 80 url_(resource_list[0].url), |
| 81 interstitial_page_(NULL), |
| 82 create_view_(true) { |
| 83 if (!is_main_frame_load_blocked_) { |
| 84 navigation_entry_index_to_remove_ = |
| 85 web_contents->GetController().GetLastCommittedEntryIndex(); |
| 86 } else { |
| 87 navigation_entry_index_to_remove_ = -1; |
| 88 } |
| 89 // Creating interstitial_page_ without showing it leaks memory, so don't |
| 90 // create it here. |
| 91 } |
| 92 |
| 93 DataReductionProxyBlockingPage::~DataReductionProxyBlockingPage() { |
| 94 } |
| 95 |
| 96 content::InterstitialPage* |
| 97 DataReductionProxyBlockingPage::interstitial_page() const { |
| 98 return interstitial_page_; |
| 99 } |
| 100 |
| 101 void DataReductionProxyBlockingPage::CommandReceived(const std::string& cmd) { |
| 102 // Make a local copy so it can be modified. |
| 103 std::string command(cmd); |
| 104 // The Jasonified response has quotes, remove them. |
| 105 if (command.length() > 1 && command[0] == '"') { |
| 106 command = command.substr(1, command.length() - 2); |
| 107 } |
| 108 |
| 109 if (command == kProceedCommand) { |
| 110 interstitial_page_->Proceed(); |
| 111 // |this| has been deleted after Proceed() returns. |
| 112 return; |
| 113 } |
| 114 |
| 115 if (command == kTakeMeBackCommand) { |
| 116 if (is_main_frame_load_blocked_) { |
| 117 // If the load is blocked, close the interstitial and discard the pending |
| 118 // entry. |
| 119 interstitial_page_->DontProceed(); |
| 120 // |this| has been deleted after DontProceed() returns. |
| 121 return; |
| 122 } |
| 123 |
| 124 // Otherwise the offending entry has committed, so go back or to a new page. |
| 125 // Close the interstitial when that page commits. |
| 126 if (web_contents_->GetController().CanGoBack()) { |
| 127 web_contents_->GetController().GoBack(); |
| 128 } else { |
| 129 web_contents_->GetController().LoadURL( |
| 130 GURL("chrome://newtab/"), |
| 131 content::Referrer(), |
| 132 ui::PAGE_TRANSITION_AUTO_TOPLEVEL, |
| 133 std::string()); |
| 134 } |
| 135 return; |
| 136 } |
| 137 } |
| 138 |
| 139 void DataReductionProxyBlockingPage::OnProceed() { |
| 140 proceeded_ = true; |
| 141 |
| 142 NotifyDataReductionProxyUIManager(ui_manager_, io_task_runner_, |
| 143 resource_list_, true); |
| 144 |
| 145 // The user is proceeding, an interstitial will not be shown again for a |
| 146 // predetermined amount of time. Clear the queued resource notifications |
| 147 // received while the interstitial was showing. |
| 148 BypassResourceMap* resource_map = GetBypassResourcesMap(); |
| 149 BypassResourceMap::iterator iter = resource_map->find(web_contents_); |
| 150 if (iter != resource_map->end() && !iter->second.empty()) { |
| 151 NotifyDataReductionProxyUIManager(ui_manager_, io_task_runner_, |
| 152 iter->second, true); |
| 153 resource_map->erase(iter); |
| 154 } |
| 155 } |
| 156 |
| 157 void DataReductionProxyBlockingPage::Show() { |
| 158 DCHECK(!interstitial_page_); |
| 159 interstitial_page_ = content::InterstitialPage::Create( |
| 160 web_contents_, is_main_frame_load_blocked_, url_, this); |
| 161 if (!create_view_) |
| 162 interstitial_page_->DontCreateViewForTesting(); |
| 163 interstitial_page_->Show(); |
| 164 } |
| 165 |
| 166 void DataReductionProxyBlockingPage::OnDontProceed() { |
| 167 // Proceed() could have already been called, in which case do not notify the |
| 168 // DataReductionProxyUIManager again, as the client has been deleted. |
| 169 if (proceeded_) |
| 170 return; |
| 171 |
| 172 NotifyDataReductionProxyUIManager(ui_manager_, io_task_runner_, |
| 173 resource_list_, false); |
| 174 |
| 175 // The user does not want to proceed, clear the queued resource notifications |
| 176 // received while the interstitial was showing. |
| 177 BypassResourceMap* resource_map = GetBypassResourcesMap(); |
| 178 BypassResourceMap::iterator iter = resource_map->find(web_contents_); |
| 179 if (iter != resource_map->end() && !iter->second.empty()) { |
| 180 NotifyDataReductionProxyUIManager(ui_manager_, io_task_runner_, |
| 181 iter->second, false); |
| 182 resource_map->erase(iter); |
| 183 } |
| 184 |
| 185 // Don't remove the navigation entry if the tab is being destroyed as this |
| 186 // would trigger a navigation that would cause trouble as the render view host |
| 187 // for the tab has by then already been destroyed. Also, don't delete the |
| 188 // current entry if it has been committed again, which is possible on a page |
| 189 // that had a subresource warning. |
| 190 int last_committed_index = |
| 191 web_contents_->GetController().GetLastCommittedEntryIndex(); |
| 192 if (navigation_entry_index_to_remove_ != -1 && |
| 193 navigation_entry_index_to_remove_ != last_committed_index && |
| 194 !web_contents_->IsBeingDestroyed()) { |
| 195 CHECK(web_contents_->GetController().RemoveEntryAtIndex( |
| 196 navigation_entry_index_to_remove_)); |
| 197 navigation_entry_index_to_remove_ = -1; |
| 198 } |
| 199 } |
| 200 |
| 201 // static |
| 202 void DataReductionProxyBlockingPage::NotifyDataReductionProxyUIManager( |
| 203 DataReductionProxyUIManager* ui_manager, |
| 204 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, |
| 205 const BypassResourceList& resource_list, |
| 206 bool proceed) { |
| 207 io_task_runner->PostTask( |
| 208 FROM_HERE, |
| 209 base::Bind(&DataReductionProxyUIManager::OnBlockingPageDone, |
| 210 ui_manager, resource_list, proceed)); |
| 211 } |
| 212 |
| 213 // static |
| 214 DataReductionProxyBlockingPage::BypassResourceMap* |
| 215 DataReductionProxyBlockingPage::GetBypassResourcesMap() { |
| 216 return g_bypass_resource_map.Pointer(); |
| 217 } |
| 218 |
| 219 void DataReductionProxyBlockingPage::DontCreateViewForTesting() { |
| 220 create_view_ = false; |
| 221 } |
| 222 |
| 223 // static |
| 224 DataReductionProxyBlockingPage* |
| 225 DataReductionProxyBlockingPage::CreateBlockingPage( |
| 226 DataReductionProxyUIManager* ui_manager, |
| 227 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, |
| 228 content::WebContents* web_contents, |
| 229 const BypassResource& bypass_resource) { |
| 230 std::vector<BypassResource> resources; |
| 231 resources.push_back(bypass_resource); |
| 232 // Set up the factory if this has not been done already (tests do that |
| 233 // before this method is called). |
| 234 if (!factory_) |
| 235 factory_ = g_data_reduction_proxy_blocking_page_factory_impl.Pointer(); |
| 236 return factory_->CreateDataReductionProxyPage(ui_manager, io_task_runner, |
| 237 web_contents, resources); |
| 238 } |
| 239 |
| 240 // static |
| 241 void DataReductionProxyBlockingPage::ShowBlockingPage( |
| 242 DataReductionProxyUIManager* ui_manager, |
| 243 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, |
| 244 const BypassResource& bypass_resource) { |
| 245 content::RenderViewHost* render_view_host = |
| 246 content:: RenderViewHost::FromID(bypass_resource.render_process_host_id, |
| 247 bypass_resource.render_view_id); |
| 248 content::WebContents* web_contents = nullptr; |
| 249 if (render_view_host) |
| 250 web_contents = content::WebContents::FromRenderViewHost(render_view_host); |
| 251 |
| 252 content::InterstitialPage* interstitial = |
| 253 content::InterstitialPage::GetInterstitialPage(web_contents); |
| 254 if (interstitial && !bypass_resource.is_subresource) { |
| 255 // There is already an interstitial showing and a new one for the main frame |
| 256 // is about to be displayed. Just hide the current one, it is now |
| 257 // irrelevent. |
| 258 interstitial->DontProceed(); |
| 259 interstitial = NULL; |
| 260 } |
| 261 |
| 262 if (!interstitial) { |
| 263 // There is no interstitial currently showing in that tab, go ahead and |
| 264 // show this interstitial. |
| 265 DataReductionProxyBlockingPage* blocking_page = |
| 266 CreateBlockingPage(ui_manager, io_task_runner, web_contents, |
| 267 bypass_resource); |
| 268 blocking_page->Show(); |
| 269 return; |
| 270 } |
| 271 |
| 272 // This is an interstitial for a page's resource, let's queue it. |
| 273 BypassResourceMap* bypassed_resource_map = GetBypassResourcesMap(); |
| 274 (*bypassed_resource_map)[web_contents].push_back(bypass_resource); |
| 275 } |
| 276 |
| 277 // static |
| 278 bool DataReductionProxyBlockingPage::IsMainPageLoadBlocked( |
| 279 const BypassResourceList& resource_list) { |
| 280 return resource_list.size() == 1 && !resource_list[0].is_subresource; |
| 281 } |
| 282 |
| 283 std::string DataReductionProxyBlockingPage::GetHTMLContents() { |
| 284 DCHECK(!resource_list_.empty()); |
| 285 |
| 286 base::DictionaryValue load_time_data; |
| 287 webui::SetFontAndTextDirection(&load_time_data); |
| 288 load_time_data.SetString( |
| 289 "tabTitle", l10n_util::GetStringUTF16(IDS_DATA_REDUCTION_PROXY_TITLE)); |
| 290 load_time_data.SetString( |
| 291 "primaryButtonText", |
| 292 l10n_util::GetStringUTF16(IDS_DATA_REDUCTION_PROXY_BACK_BUTTON)); |
| 293 load_time_data.SetString( |
| 294 "secondaryButtonText", |
| 295 l10n_util::GetStringUTF16(IDS_DATA_REDUCTION_PROXY_CONTINUE_BUTTON)); |
| 296 load_time_data.SetString( |
| 297 "heading", l10n_util::GetStringUTF16(IDS_UNPROXYABLE_HEADING)); |
| 298 load_time_data.SetString( |
| 299 "primaryParagraph", |
| 300 l10n_util::GetStringFUTF16(IDS_UNPROXYABLE_PRIMARY_PARAGRAPH, |
| 301 base::UTF8ToUTF16(url_.host()))); |
| 302 load_time_data.SetString( |
| 303 "secondaryParagraph", |
| 304 l10n_util::GetStringUTF16(IDS_UNPROXYABLE_SECONDARY_PARAGRAPH)); |
| 305 |
| 306 base::StringPiece html( |
| 307 ResourceBundle::GetSharedInstance().GetRawDataResource( |
| 308 IDR_DATA_REDUCTION_PROXY_INTERSTITIAL_HTML)); |
| 309 return webui::GetI18nTemplateHtml(html, &load_time_data); |
| 310 } |
| 311 |
| 312 } // namespace data_reduction_proxy |
OLD | NEW |