Chromium Code Reviews| 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 the stored prefs. |
| 151 // TODO(pkasting): This kind of thing should go in the preferences on the | 152 // TODO(pkasting): This kind of thing should go in the preferences on the |
|
dominickn
2017/01/19 07:01:22
Nit: you can remove this TODO, because you're doin
ramyasharma
2017/01/20 04:04:45
Done.
| |
| 152 // profile, not in the local state. http://crbug.com/457254 | 153 // profile, not in the local state. http://crbug.com/457254 |
| 153 PrefService* pref = g_browser_process->local_state(); | 154 PrefService* localPref = g_browser_process->local_state(); |
|
dominickn
2017/01/19 07:01:22
Nit: variables use underscore_naming, so call this
ramyasharma
2017/01/20 04:04:45
Done.
| |
| 154 if (pref) { // May be NULL during testing. | 155 PrefService* profilePref = profile->GetPrefs(); |
|
dominickn
2017/01/19 07:01:22
Call this profile_prefs
ramyasharma
2017/01/20 04:04:45
Done.
| |
| 155 DictionaryPrefUpdate update_excluded_schemas(pref, prefs::kExcludedSchemes); | 156 if (localPref && profilePref) { // May be NULL during testing. |
| 156 | 157 DictionaryPrefUpdate update_excluded_schemas( |
|
dominickn
2017/01/19 07:01:22
Call this local_state_schemas, since we're not act
ramyasharma
2017/01/20 04:04:45
Done.
| |
| 157 // Warm up the dictionary if needed. | 158 localPref, prefs::kExcludedSchemes); |
| 158 PrepopulateDictionary(update_excluded_schemas.Get()); | 159 DictionaryPrefUpdate update_excluded_schemas_profile( |
| 160 profilePref, prefs::kExcludedSchemes); | |
| 161 if (update_excluded_schemas_profile->empty()) { | |
| 162 // Copy local state to profile state. | |
| 163 for (base::DictionaryValue::Iterator it(*update_excluded_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) { | |
|
dominickn
2017/01/19 07:01:22
Nit: one-line if statements don't need braces
ramyasharma
2017/01/20 04:04:45
Done. I was wondering about that, why is it not? U
dominickn
2017/01/20 05:07:46
I used to follow that rule too, but this style is
| |
| 170 update_excluded_schemas_profile->SetBoolean(it.key(), is_blocked); | |
| 171 } | |
| 172 } | |
| 173 // TODO(ramyasharma): Clear only if required. | |
| 174 localPref->ClearPref(prefs::kExcludedSchemes); | |
| 175 } | |
| 176 // Prepolutate the default states each time. | |
|
dominickn
2017/01/19 07:01:22
sp. "Prepopulate"
ramyasharma
2017/01/20 04:04:45
Oops, done.
| |
| 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)) { |
|
dominickn
2017/01/19 07:01:22
Nit: don't add the braces here, one line if statem
ramyasharma
2017/01/20 04:04:45
Done.
| |
| 162 return should_block ? BLOCK : DONT_BLOCK; | 181 return should_block ? BLOCK : DONT_BLOCK; |
| 182 } | |
| 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 // TODO(pkasting): This kind of thing should go in the preferences on the |
|
dominickn
2017/01/19 07:01:22
Nit: remove this TODO (you're doing it)
ramyasharma
2017/01/20 04:04:45
Done.
| |
| 173 // profile, not in the local state. http://crbug.com/457254 | 194 // profile, not in the local state. http://crbug.com/457254 |
| 174 PrefService* pref = g_browser_process->local_state(); | 195 PrefService* localPref = g_browser_process->local_state(); |
| 175 if (pref) { // May be NULL during testing. | 196 PrefService* profilePref = profile->GetPrefs(); |
|
dominickn
2017/01/19 07:01:22
local_state_prefs and profile_prefs
ramyasharma
2017/01/20 04:04:45
Done.
| |
| 176 DictionaryPrefUpdate update_excluded_schemas(pref, prefs::kExcludedSchemes); | 197 if (localPref && profilePref) { // May be NULL during testing. |
| 177 | 198 DictionaryPrefUpdate update_excluded_schemas( |
| 199 localPref, prefs::kExcludedSchemes); | |
| 200 DictionaryPrefUpdate update_excluded_schemas_profile( | |
| 201 profilePref, prefs::kExcludedSchemes); | |
| 202 bool is_profile_state = !update_excluded_schemas_profile->empty(); | |
| 178 if (state == UNKNOWN) { | 203 if (state == UNKNOWN) { |
| 179 update_excluded_schemas->Remove(scheme, NULL); | 204 is_profile_state |
|
dominickn
2017/01/19 07:01:22
What do you think about migrating here as well? My
ramyasharma
2017/01/20 04:04:45
Yes, ideally that's how it is. Removed code that u
| |
| 180 } else { | 205 ? update_excluded_schemas_profile->Remove(scheme, NULL) |
| 181 update_excluded_schemas->SetBoolean(scheme, (state == BLOCK)); | 206 : update_excluded_schemas->Remove(scheme, NULL); |
| 207 } else { | |
| 208 is_profile_state | |
|
dominickn
2017/01/19 07:01:22
Nit: indentation.
ramyasharma
2017/01/20 04:04:45
Done.
| |
| 209 ? update_excluded_schemas_profile->SetBoolean( | |
| 210 scheme, (state == BLOCK)) | |
| 211 :update_excluded_schemas->SetBoolean(scheme, (state == BLOCK)); | |
|
dominickn
2017/01/19 07:01:22
Nit: space after :
ramyasharma
2017/01/20 04:04:45
Done.
| |
| 182 } | 212 } |
| 183 } | 213 } |
| 184 } | 214 } |
| 185 | 215 |
| 186 // static | 216 // static |
| 187 void ExternalProtocolHandler::LaunchUrlWithDelegate( | 217 void ExternalProtocolHandler::LaunchUrlWithDelegate( |
| 188 const GURL& url, | 218 const GURL& url, |
| 189 int render_process_host_id, | 219 int render_process_host_id, |
| 190 int render_view_routing_id, | 220 int render_view_routing_id, |
| 191 ui::PageTransition page_transition, | 221 ui::PageTransition page_transition, |
| 192 bool has_user_gesture, | 222 bool has_user_gesture, |
| 193 Delegate* delegate) { | 223 Delegate* delegate) { |
| 194 DCHECK(base::MessageLoopForUI::IsCurrent()); | 224 DCHECK(base::MessageLoopForUI::IsCurrent()); |
| 195 | 225 |
| 196 // Escape the input scheme to be sure that the command does not | 226 // Escape the input scheme to be sure that the command does not |
| 197 // have parameters unexpected by the external program. | 227 // have parameters unexpected by the external program. |
| 198 std::string escaped_url_string = net::EscapeExternalHandlerValue(url.spec()); | 228 std::string escaped_url_string = net::EscapeExternalHandlerValue(url.spec()); |
| 199 GURL escaped_url(escaped_url_string); | 229 GURL escaped_url(escaped_url_string); |
| 230 | |
| 231 content::WebContents* web_contents = tab_util::GetWebContentsByID( | |
| 232 render_process_host_id, render_view_routing_id); | |
| 233 Profile* profile = NULL; | |
|
dominickn
2017/01/19 07:01:22
Use nullptr instead of NULL (this is a very old fi
ramyasharma
2017/01/20 04:04:45
Done.
| |
| 234 if (web_contents) { // Maybe NULL during testing. | |
|
dominickn
2017/01/19 07:01:22
Nit: no braces around a one-line else.
ramyasharma
2017/01/20 04:04:45
Done.
| |
| 235 profile = Profile::FromBrowserContext(web_contents->GetBrowserContext()); | |
| 236 } | |
| 200 BlockState block_state = | 237 BlockState block_state = |
| 201 GetBlockStateWithDelegate(escaped_url.scheme(), delegate); | 238 GetBlockStateWithDelegate(escaped_url.scheme(), delegate, profile); |
| 202 if (block_state == BLOCK) { | 239 if (block_state == BLOCK) { |
| 203 if (delegate) | 240 if (delegate) |
| 204 delegate->BlockRequest(); | 241 delegate->BlockRequest(); |
| 205 return; | 242 return; |
| 206 } | 243 } |
| 207 | 244 |
| 208 g_accept_requests = false; | 245 g_accept_requests = false; |
| 209 | 246 |
| 210 // The worker creates tasks with references to itself and puts them into | 247 // The worker creates tasks with references to itself and puts them into |
| 211 // message loops. | 248 // message loops. |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 236 | 273 |
| 237 // static | 274 // static |
| 238 void ExternalProtocolHandler::PermitLaunchUrl() { | 275 void ExternalProtocolHandler::PermitLaunchUrl() { |
| 239 DCHECK(base::MessageLoopForUI::IsCurrent()); | 276 DCHECK(base::MessageLoopForUI::IsCurrent()); |
| 240 g_accept_requests = true; | 277 g_accept_requests = true; |
| 241 } | 278 } |
| 242 | 279 |
| 243 // static | 280 // static |
| 244 void ExternalProtocolHandler::PrepopulateDictionary( | 281 void ExternalProtocolHandler::PrepopulateDictionary( |
| 245 base::DictionaryValue* win_pref) { | 282 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[] = { | 283 static const char* const denied_schemes[] = { |
| 252 "afp", | 284 "afp", |
| 253 "data", | 285 "data", |
| 254 "disk", | 286 "disk", |
| 255 "disks", | 287 "disks", |
| 256 // ShellExecuting file:///C:/WINDOWS/system32/notepad.exe will simply | 288 // ShellExecuting file:///C:/WINDOWS/system32/notepad.exe will simply |
| 257 // execute the file specified! Hopefully we won't see any "file" schemes | 289 // 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 | 290 // 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. | 291 // than to let an attacker format the user's hard drive. |
| 260 "file", | 292 "file", |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 292 } | 324 } |
| 293 | 325 |
| 294 // static | 326 // static |
| 295 void ExternalProtocolHandler::RecordMetrics(bool selected) { | 327 void ExternalProtocolHandler::RecordMetrics(bool selected) { |
| 296 UMA_HISTOGRAM_BOOLEAN("BrowserDialogs.ExternalProtocol.RememberCheckbox", | 328 UMA_HISTOGRAM_BOOLEAN("BrowserDialogs.ExternalProtocol.RememberCheckbox", |
| 297 selected); | 329 selected); |
| 298 } | 330 } |
| 299 | 331 |
| 300 // static | 332 // static |
| 301 void ExternalProtocolHandler::RegisterPrefs(PrefRegistrySimple* registry) { | 333 void ExternalProtocolHandler::RegisterPrefs(PrefRegistrySimple* registry) { |
| 302 registry->RegisterDictionaryPref(prefs::kExcludedSchemes); | 334 registry->RegisterDictionaryPref(prefs::kExcludedSchemes); |
| 303 } | 335 } |
| OLD | NEW |