| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "components/app_modal/javascript_dialog_manager.h" | 5 #include "components/app_modal/javascript_dialog_manager.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 50 } | 50 } |
| 51 | 51 |
| 52 DISALLOW_COPY_AND_ASSIGN(DefaultExtensionsClient); | 52 DISALLOW_COPY_AND_ASSIGN(DefaultExtensionsClient); |
| 53 }; | 53 }; |
| 54 | 54 |
| 55 bool ShouldDisplaySuppressCheckbox( | 55 bool ShouldDisplaySuppressCheckbox( |
| 56 ChromeJavaScriptDialogExtraData* extra_data) { | 56 ChromeJavaScriptDialogExtraData* extra_data) { |
| 57 return extra_data->has_already_shown_a_dialog_; | 57 return extra_data->has_already_shown_a_dialog_; |
| 58 } | 58 } |
| 59 | 59 |
| 60 enum class DialogType { | 60 void LogUMAMessageLengthStats(const base::string16& message) { |
| 61 JAVASCRIPT, | 61 UMA_HISTOGRAM_COUNTS("JSDialogs.CountOfJSDialogMessageCharacters", |
| 62 ON_BEFORE_UNLOAD, | 62 static_cast<int32_t>(message.length())); |
| 63 }; | |
| 64 | |
| 65 void LogUMAMessageLengthStats(const base::string16& message, DialogType type) { | |
| 66 if (type == DialogType::JAVASCRIPT) { | |
| 67 UMA_HISTOGRAM_COUNTS("JSDialogs.CountOfJSDialogMessageCharacters", | |
| 68 static_cast<int32_t>(message.length())); | |
| 69 } else { | |
| 70 UMA_HISTOGRAM_COUNTS("JSDialogs.CountOfOnBeforeUnloadMessageCharacters", | |
| 71 static_cast<int32_t>(message.length())); | |
| 72 } | |
| 73 | 63 |
| 74 int32_t newline_count = | 64 int32_t newline_count = |
| 75 std::count_if(message.begin(), message.end(), | 65 std::count_if(message.begin(), message.end(), |
| 76 [](const base::char16& c) { return c == '\n'; }); | 66 [](const base::char16& c) { return c == '\n'; }); |
| 77 if (type == DialogType::JAVASCRIPT) { | 67 UMA_HISTOGRAM_COUNTS("JSDialogs.CountOfJSDialogMessageNewlines", |
| 78 UMA_HISTOGRAM_COUNTS("JSDialogs.CountOfJSDialogMessageNewlines", | 68 newline_count); |
| 79 newline_count); | |
| 80 } else { | |
| 81 UMA_HISTOGRAM_COUNTS("JSDialogs.CountOfOnBeforeUnloadMessageNewlines", | |
| 82 newline_count); | |
| 83 } | |
| 84 } | 69 } |
| 85 | 70 |
| 86 } // namespace | 71 } // namespace |
| 87 | 72 |
| 88 //////////////////////////////////////////////////////////////////////////////// | 73 //////////////////////////////////////////////////////////////////////////////// |
| 89 // JavaScriptDialogManager, public: | 74 // JavaScriptDialogManager, public: |
| 90 | 75 |
| 91 // static | 76 // static |
| 92 JavaScriptDialogManager* JavaScriptDialogManager::GetInstance() { | 77 JavaScriptDialogManager* JavaScriptDialogManager::GetInstance() { |
| 93 return base::Singleton<JavaScriptDialogManager>::get(); | 78 return base::Singleton<JavaScriptDialogManager>::get(); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 now - last_close_time_); | 150 now - last_close_time_); |
| 166 last_close_time_ = base::TimeTicks(); | 151 last_close_time_ = base::TimeTicks(); |
| 167 } | 152 } |
| 168 | 153 |
| 169 bool is_alert = message_type == content::JAVASCRIPT_MESSAGE_TYPE_ALERT; | 154 bool is_alert = message_type == content::JAVASCRIPT_MESSAGE_TYPE_ALERT; |
| 170 base::string16 dialog_title = | 155 base::string16 dialog_title = |
| 171 GetTitle(web_contents, origin_url, accept_lang, is_alert); | 156 GetTitle(web_contents, origin_url, accept_lang, is_alert); |
| 172 | 157 |
| 173 extensions_client_->OnDialogOpened(web_contents); | 158 extensions_client_->OnDialogOpened(web_contents); |
| 174 | 159 |
| 175 LogUMAMessageLengthStats(message_text, DialogType::JAVASCRIPT); | 160 LogUMAMessageLengthStats(message_text); |
| 176 AppModalDialogQueue::GetInstance()->AddDialog(new JavaScriptAppModalDialog( | 161 AppModalDialogQueue::GetInstance()->AddDialog(new JavaScriptAppModalDialog( |
| 177 web_contents, | 162 web_contents, |
| 178 &javascript_dialog_extra_data_, | 163 &javascript_dialog_extra_data_, |
| 179 dialog_title, | 164 dialog_title, |
| 180 message_type, | 165 message_type, |
| 181 message_text, | 166 message_text, |
| 182 default_prompt_text, | 167 default_prompt_text, |
| 183 ShouldDisplaySuppressCheckbox(extra_data), | 168 ShouldDisplaySuppressCheckbox(extra_data), |
| 184 false, // is_before_unload_dialog | 169 false, // is_before_unload_dialog |
| 185 false, // is_reload | 170 false, // is_reload |
| 186 base::Bind(&JavaScriptDialogManager::OnDialogClosed, | 171 base::Bind(&JavaScriptDialogManager::OnDialogClosed, |
| 187 base::Unretained(this), web_contents, callback))); | 172 base::Unretained(this), web_contents, callback))); |
| 188 } | 173 } |
| 189 | 174 |
| 190 void JavaScriptDialogManager::RunBeforeUnloadDialog( | 175 void JavaScriptDialogManager::RunBeforeUnloadDialog( |
| 191 content::WebContents* web_contents, | 176 content::WebContents* web_contents, |
| 192 const base::string16& message_text, | |
| 193 bool is_reload, | 177 bool is_reload, |
| 194 const DialogClosedCallback& callback) { | 178 const DialogClosedCallback& callback) { |
| 195 ChromeJavaScriptDialogExtraData* extra_data = | 179 ChromeJavaScriptDialogExtraData* extra_data = |
| 196 &javascript_dialog_extra_data_[web_contents]; | 180 &javascript_dialog_extra_data_[web_contents]; |
| 197 | 181 |
| 198 if (extra_data->suppress_javascript_messages_) { | 182 if (extra_data->suppress_javascript_messages_) { |
| 199 // If a site harassed the user enough for them to put it on mute, then it | 183 // If a site harassed the user enough for them to put it on mute, then it |
| 200 // lost its privilege to deny unloading. | 184 // lost its privilege to deny unloading. |
| 201 callback.Run(true, base::string16()); | 185 callback.Run(true, base::string16()); |
| 202 return; | 186 return; |
| 203 } | 187 } |
| 204 | 188 |
| 189 // Build the dialog message. We explicitly do _not_ allow the webpage to |
| 190 // specify the contents of this dialog, because most of the time nowadays it's |
| 191 // used for scams. |
| 192 // |
| 193 // This does not violate the spec. Per |
| 194 // https://html.spec.whatwg.org/#prompt-to-unload-a-document, step 7: |
| 195 // |
| 196 // "The prompt shown by the user agent may include the string of the |
| 197 // returnValue attribute, or some leading subset thereof." |
| 198 // |
| 199 // The prompt MAY include the string. It doesn't any more. Scam web page |
| 200 // authors have abused this, so we're taking away the toys from everyone. This |
| 201 // is why we can't have nice things. |
| 202 |
| 205 const base::string16 title = l10n_util::GetStringUTF16(is_reload ? | 203 const base::string16 title = l10n_util::GetStringUTF16(is_reload ? |
| 206 IDS_BEFORERELOAD_MESSAGEBOX_TITLE : IDS_BEFOREUNLOAD_MESSAGEBOX_TITLE); | 204 IDS_BEFORERELOAD_MESSAGEBOX_TITLE : IDS_BEFOREUNLOAD_MESSAGEBOX_TITLE); |
| 207 const base::string16 footer = l10n_util::GetStringUTF16(is_reload ? | 205 const base::string16 message = |
| 208 IDS_BEFORERELOAD_MESSAGEBOX_FOOTER : IDS_BEFOREUNLOAD_MESSAGEBOX_FOOTER); | 206 l10n_util::GetStringUTF16(IDS_BEFOREUNLOAD_MESSAGEBOX_MESSAGE); |
| 209 | |
| 210 base::string16 full_message = | |
| 211 message_text + base::ASCIIToUTF16("\n\n") + footer; | |
| 212 | 207 |
| 213 extensions_client_->OnDialogOpened(web_contents); | 208 extensions_client_->OnDialogOpened(web_contents); |
| 214 | 209 |
| 215 LogUMAMessageLengthStats(message_text, DialogType::ON_BEFORE_UNLOAD); | |
| 216 AppModalDialogQueue::GetInstance()->AddDialog(new JavaScriptAppModalDialog( | 210 AppModalDialogQueue::GetInstance()->AddDialog(new JavaScriptAppModalDialog( |
| 217 web_contents, | 211 web_contents, |
| 218 &javascript_dialog_extra_data_, | 212 &javascript_dialog_extra_data_, |
| 219 title, | 213 title, |
| 220 content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM, | 214 content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM, |
| 221 full_message, | 215 message, |
| 222 base::string16(), // default_prompt_text | 216 base::string16(), // default_prompt_text |
| 223 ShouldDisplaySuppressCheckbox(extra_data), | 217 ShouldDisplaySuppressCheckbox(extra_data), |
| 224 true, // is_before_unload_dialog | 218 true, // is_before_unload_dialog |
| 225 is_reload, | 219 is_reload, |
| 226 base::Bind(&JavaScriptDialogManager::OnBeforeUnloadDialogClosed, | 220 base::Bind(&JavaScriptDialogManager::OnBeforeUnloadDialogClosed, |
| 227 base::Unretained(this), web_contents, callback))); | 221 base::Unretained(this), web_contents, callback))); |
| 228 } | 222 } |
| 229 | 223 |
| 230 bool JavaScriptDialogManager::HandleJavaScriptDialog( | 224 bool JavaScriptDialogManager::HandleJavaScriptDialog( |
| 231 content::WebContents* web_contents, | 225 content::WebContents* web_contents, |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 // lazy background page after the dialog closes. (Dialogs are closed before | 329 // lazy background page after the dialog closes. (Dialogs are closed before |
| 336 // their WebContents is destroyed so |web_contents| is still valid here.) | 330 // their WebContents is destroyed so |web_contents| is still valid here.) |
| 337 extensions_client_->OnDialogClosed(web_contents); | 331 extensions_client_->OnDialogClosed(web_contents); |
| 338 | 332 |
| 339 last_close_time_ = base::TimeTicks::Now(); | 333 last_close_time_ = base::TimeTicks::Now(); |
| 340 | 334 |
| 341 callback.Run(success, user_input); | 335 callback.Run(success, user_input); |
| 342 } | 336 } |
| 343 | 337 |
| 344 } // namespace app_modal | 338 } // namespace app_modal |
| OLD | NEW |