| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/browser/external_protocol/external_protocol_handler.h" | 5 #include "chrome/browser/external_protocol/external_protocol_handler.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <set> | 9 #include <set> |
| 10 | 10 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 45 const std::string& protocol, | 45 const std::string& protocol, |
| 46 ExternalProtocolHandler::Delegate* delegate) { | 46 ExternalProtocolHandler::Delegate* delegate) { |
| 47 if (delegate) | 47 if (delegate) |
| 48 return delegate->CreateShellWorker(callback, protocol); | 48 return delegate->CreateShellWorker(callback, protocol); |
| 49 | 49 |
| 50 return new shell_integration::DefaultProtocolClientWorker(callback, protocol); | 50 return new shell_integration::DefaultProtocolClientWorker(callback, protocol); |
| 51 } | 51 } |
| 52 | 52 |
| 53 ExternalProtocolHandler::BlockState GetBlockStateWithDelegate( | 53 ExternalProtocolHandler::BlockState GetBlockStateWithDelegate( |
| 54 const std::string& scheme, | 54 const std::string& scheme, |
| 55 ExternalProtocolHandler::Delegate* delegate) { | 55 ExternalProtocolHandler::Delegate* delegate, |
| 56 Profile* profile) { |
| 56 if (!delegate) | 57 if (!delegate) |
| 57 return ExternalProtocolHandler::GetBlockState(scheme); | 58 return ExternalProtocolHandler::GetBlockState(scheme, profile); |
| 58 | 59 |
| 59 return delegate->GetBlockState(scheme); | 60 return delegate->GetBlockState(scheme, profile); |
| 60 } | 61 } |
| 61 | 62 |
| 62 void RunExternalProtocolDialogWithDelegate( | 63 void RunExternalProtocolDialogWithDelegate( |
| 63 const GURL& url, | 64 const GURL& url, |
| 64 int render_process_host_id, | 65 int render_process_host_id, |
| 65 int routing_id, | 66 int routing_id, |
| 66 ui::PageTransition page_transition, | 67 ui::PageTransition page_transition, |
| 67 bool has_user_gesture, | 68 bool has_user_gesture, |
| 68 ExternalProtocolHandler::Delegate* delegate) { | 69 ExternalProtocolHandler::Delegate* delegate) { |
| 69 if (!delegate) { | 70 if (!delegate) { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 128 } | 129 } |
| 129 | 130 |
| 130 LaunchUrlWithoutSecurityCheckWithDelegate(escaped_url, render_process_host_id, | 131 LaunchUrlWithoutSecurityCheckWithDelegate(escaped_url, render_process_host_id, |
| 131 render_view_routing_id, delegate); | 132 render_view_routing_id, delegate); |
| 132 } | 133 } |
| 133 | 134 |
| 134 } // namespace | 135 } // namespace |
| 135 | 136 |
| 136 // static | 137 // static |
| 137 ExternalProtocolHandler::BlockState ExternalProtocolHandler::GetBlockState( | 138 ExternalProtocolHandler::BlockState ExternalProtocolHandler::GetBlockState( |
| 138 const std::string& scheme) { | 139 const std::string& scheme, Profile* profile) { |
| 139 // If we are being carpet bombed, block the request. | 140 // If we are being carpet bombed, block the request. |
| 140 if (!g_accept_requests) | 141 if (!g_accept_requests) |
| 141 return BLOCK; | 142 return BLOCK; |
| 142 | 143 |
| 143 if (scheme.length() == 1) { | 144 if (scheme.length() == 1) { |
| 144 // We have a URL that looks something like: | 145 // We have a URL that looks something like: |
| 145 // C:/WINDOWS/system32/notepad.exe | 146 // C:/WINDOWS/system32/notepad.exe |
| 146 // ShellExecuting this URL will cause the specified program to be executed. | 147 // ShellExecuting this URL will cause the specified program to be executed. |
| 147 return BLOCK; | 148 return BLOCK; |
| 148 } | 149 } |
| 149 | 150 |
| 150 // Check the stored prefs. | 151 // Check if there are any prefs in the local state. If there are, wipe them, |
| 151 // TODO(pkasting): This kind of thing should go in the preferences on the | 152 // and migrate the prefs to the profile. |
| 152 // profile, not in the local state. http://crbug.com/457254 | 153 // TODO(ramyasharma) remove the migration in M61. |
| 153 PrefService* pref = g_browser_process->local_state(); | 154 PrefService* local_prefs = g_browser_process->local_state(); |
| 154 if (pref) { // May be NULL during testing. | 155 PrefService* profile_prefs = profile->GetPrefs(); |
| 155 DictionaryPrefUpdate update_excluded_schemas(pref, prefs::kExcludedSchemes); | 156 if (local_prefs && profile_prefs) { // May be NULL during testing. |
| 157 DictionaryPrefUpdate local_state_schemas( |
| 158 local_prefs, prefs::kExcludedSchemes); |
| 159 DictionaryPrefUpdate update_excluded_schemas_profile( |
| 160 profile_prefs, prefs::kExcludedSchemes); |
| 161 if (update_excluded_schemas_profile->empty()) { |
| 162 // Copy local state to profile state. |
| 163 for (base::DictionaryValue::Iterator it(*local_state_schemas); |
| 164 !it.IsAtEnd(); it.Advance()) { |
| 165 bool is_blocked; |
| 166 // Discard local state if set to blocked, to reset all users |
| 167 // stuck in 'Do Nothing' + 'Do Not Open' state back to the default |
| 168 // prompt state. |
| 169 if (it.value().GetAsBoolean(&is_blocked) && !is_blocked) |
| 170 update_excluded_schemas_profile->SetBoolean(it.key(), is_blocked); |
| 171 } |
| 172 // TODO(ramyasharma): Clear only if required. |
| 173 local_prefs->ClearPref(prefs::kExcludedSchemes); |
| 174 } |
| 156 | 175 |
| 157 // Warm up the dictionary if needed. | 176 // Prepopulate the default states each time. |
| 158 PrepopulateDictionary(update_excluded_schemas.Get()); | 177 PrepopulateDictionary(update_excluded_schemas_profile.Get()); |
| 159 | 178 |
| 160 bool should_block; | 179 bool should_block; |
| 161 if (update_excluded_schemas->GetBoolean(scheme, &should_block)) | 180 if (update_excluded_schemas_profile->GetBoolean(scheme, &should_block)) |
| 162 return should_block ? BLOCK : DONT_BLOCK; | 181 return should_block ? BLOCK : DONT_BLOCK; |
| 163 } | 182 } |
| 164 | 183 |
| 165 return UNKNOWN; | 184 return UNKNOWN; |
| 166 } | 185 } |
| 167 | 186 |
| 168 // static | 187 // static |
| 169 void ExternalProtocolHandler::SetBlockState(const std::string& scheme, | 188 void ExternalProtocolHandler::SetBlockState(const std::string& scheme, |
| 170 BlockState state) { | 189 BlockState state, |
| 190 Profile* profile) { |
| 171 // Set in the stored prefs. | 191 // Set in the stored prefs. |
| 172 // TODO(pkasting): This kind of thing should go in the preferences on the | 192 PrefService* profile_prefs = profile->GetPrefs(); |
| 173 // profile, not in the local state. http://crbug.com/457254 | 193 if (profile_prefs) { // May be NULL during testing. |
| 174 PrefService* pref = g_browser_process->local_state(); | 194 DictionaryPrefUpdate update_excluded_schemas_profile( |
| 175 if (pref) { // May be NULL during testing. | 195 profile_prefs, prefs::kExcludedSchemes); |
| 176 DictionaryPrefUpdate update_excluded_schemas(pref, prefs::kExcludedSchemes); | 196 if (!update_excluded_schemas_profile->empty()) { |
| 177 | 197 if (state == UNKNOWN) |
| 178 if (state == UNKNOWN) { | 198 update_excluded_schemas_profile->Remove(scheme, nullptr); |
| 179 update_excluded_schemas->Remove(scheme, NULL); | 199 else |
| 180 } else { | 200 update_excluded_schemas_profile->SetBoolean(scheme, (state == BLOCK)); |
| 181 update_excluded_schemas->SetBoolean(scheme, (state == BLOCK)); | |
| 182 } | 201 } |
| 183 } | 202 } |
| 184 } | 203 } |
| 185 | 204 |
| 186 // static | 205 // static |
| 187 void ExternalProtocolHandler::LaunchUrlWithDelegate( | 206 void ExternalProtocolHandler::LaunchUrlWithDelegate( |
| 188 const GURL& url, | 207 const GURL& url, |
| 189 int render_process_host_id, | 208 int render_process_host_id, |
| 190 int render_view_routing_id, | 209 int render_view_routing_id, |
| 191 ui::PageTransition page_transition, | 210 ui::PageTransition page_transition, |
| 192 bool has_user_gesture, | 211 bool has_user_gesture, |
| 193 Delegate* delegate) { | 212 Delegate* delegate) { |
| 194 DCHECK(base::MessageLoopForUI::IsCurrent()); | 213 DCHECK(base::MessageLoopForUI::IsCurrent()); |
| 195 | 214 |
| 196 // Escape the input scheme to be sure that the command does not | 215 // Escape the input scheme to be sure that the command does not |
| 197 // have parameters unexpected by the external program. | 216 // have parameters unexpected by the external program. |
| 198 std::string escaped_url_string = net::EscapeExternalHandlerValue(url.spec()); | 217 std::string escaped_url_string = net::EscapeExternalHandlerValue(url.spec()); |
| 199 GURL escaped_url(escaped_url_string); | 218 GURL escaped_url(escaped_url_string); |
| 219 |
| 220 content::WebContents* web_contents = tab_util::GetWebContentsByID( |
| 221 render_process_host_id, render_view_routing_id); |
| 222 Profile* profile = nullptr; |
| 223 if (web_contents) // Maybe NULL during testing. |
| 224 profile = Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| 200 BlockState block_state = | 225 BlockState block_state = |
| 201 GetBlockStateWithDelegate(escaped_url.scheme(), delegate); | 226 GetBlockStateWithDelegate(escaped_url.scheme(), delegate, profile); |
| 202 if (block_state == BLOCK) { | 227 if (block_state == BLOCK) { |
| 203 if (delegate) | 228 if (delegate) |
| 204 delegate->BlockRequest(); | 229 delegate->BlockRequest(); |
| 205 return; | 230 return; |
| 206 } | 231 } |
| 207 | 232 |
| 208 g_accept_requests = false; | 233 g_accept_requests = false; |
| 209 | 234 |
| 210 // The worker creates tasks with references to itself and puts them into | 235 // The worker creates tasks with references to itself and puts them into |
| 211 // message loops. | 236 // message loops. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 236 | 261 |
| 237 // static | 262 // static |
| 238 void ExternalProtocolHandler::PermitLaunchUrl() { | 263 void ExternalProtocolHandler::PermitLaunchUrl() { |
| 239 DCHECK(base::MessageLoopForUI::IsCurrent()); | 264 DCHECK(base::MessageLoopForUI::IsCurrent()); |
| 240 g_accept_requests = true; | 265 g_accept_requests = true; |
| 241 } | 266 } |
| 242 | 267 |
| 243 // static | 268 // static |
| 244 void ExternalProtocolHandler::PrepopulateDictionary( | 269 void ExternalProtocolHandler::PrepopulateDictionary( |
| 245 base::DictionaryValue* win_pref) { | 270 base::DictionaryValue* win_pref) { |
| 246 static bool is_warm = false; | |
| 247 if (is_warm) | |
| 248 return; | |
| 249 is_warm = true; | |
| 250 | |
| 251 static const char* const denied_schemes[] = { | 271 static const char* const denied_schemes[] = { |
| 252 "afp", | 272 "afp", |
| 253 "data", | 273 "data", |
| 254 "disk", | 274 "disk", |
| 255 "disks", | 275 "disks", |
| 256 // ShellExecuting file:///C:/WINDOWS/system32/notepad.exe will simply | 276 // ShellExecuting file:///C:/WINDOWS/system32/notepad.exe will simply |
| 257 // execute the file specified! Hopefully we won't see any "file" schemes | 277 // execute the file specified! Hopefully we won't see any "file" schemes |
| 258 // because we think of file:// URLs as handled URLs, but better to be safe | 278 // because we think of file:// URLs as handled URLs, but better to be safe |
| 259 // than to let an attacker format the user's hard drive. | 279 // than to let an attacker format the user's hard drive. |
| 260 "file", | 280 "file", |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 292 } | 312 } |
| 293 | 313 |
| 294 // static | 314 // static |
| 295 void ExternalProtocolHandler::RecordMetrics(bool selected) { | 315 void ExternalProtocolHandler::RecordMetrics(bool selected) { |
| 296 UMA_HISTOGRAM_BOOLEAN("BrowserDialogs.ExternalProtocol.RememberCheckbox", | 316 UMA_HISTOGRAM_BOOLEAN("BrowserDialogs.ExternalProtocol.RememberCheckbox", |
| 297 selected); | 317 selected); |
| 298 } | 318 } |
| 299 | 319 |
| 300 // static | 320 // static |
| 301 void ExternalProtocolHandler::RegisterPrefs(PrefRegistrySimple* registry) { | 321 void ExternalProtocolHandler::RegisterPrefs(PrefRegistrySimple* registry) { |
| 302 registry->RegisterDictionaryPref(prefs::kExcludedSchemes); | 322 registry->RegisterDictionaryPref(prefs::kExcludedSchemes); |
| 303 } | 323 } |
| OLD | NEW |