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