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