OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 <set> | 7 #include <set> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
12 #include "base/threading/thread.h" | 12 #include "base/threading/thread.h" |
13 #include "build/build_config.h" | 13 #include "build/build_config.h" |
14 #include "chrome/browser/browser_process_impl.h" | 14 #include "chrome/browser/browser_process_impl.h" |
15 #include "chrome/browser/platform_util.h" | 15 #include "chrome/browser/platform_util.h" |
16 #include "chrome/browser/prefs/pref_service.h" | 16 #include "chrome/browser/prefs/pref_service.h" |
17 #include "chrome/browser/prefs/scoped_user_pref_update.h" | 17 #include "chrome/browser/prefs/scoped_user_pref_update.h" |
18 #include "chrome/common/pref_names.h" | 18 #include "chrome/common/pref_names.h" |
19 #include "googleurl/src/gurl.h" | 19 #include "googleurl/src/gurl.h" |
20 #include "net/base/escape.h" | 20 #include "net/base/escape.h" |
21 | 21 |
22 // Whether we accept requests for launching external protocols. This is set to | 22 // Whether we accept requests for launching external protocols. This is set to |
23 // false every time an external protocol is requested, and set back to true on | 23 // false every time an external protocol is requested, and set back to true on |
24 // each user gesture. This variable should only be accessed from the UI thread. | 24 // each user gesture. This variable should only be accessed from the UI thread. |
25 static bool g_accept_requests = true; | 25 static bool g_accept_requests = true; |
26 | 26 |
| 27 namespace { |
| 28 |
| 29 // Functions enabling unit testing. Using a NULL delegate will use the default |
| 30 // behavior; if a delegate is provided it will be used instead. |
| 31 ShellIntegration::DefaultProtocolClientWorker* CreateShellWorker( |
| 32 ShellIntegration::DefaultWebClientObserver* observer, |
| 33 const std::string& protocol, |
| 34 ExternalProtocolHandler::Delegate* delegate) { |
| 35 if (!delegate) |
| 36 return new ShellIntegration::DefaultProtocolClientWorker(observer, |
| 37 protocol); |
| 38 |
| 39 return delegate->CreateShellWorker(observer, protocol); |
| 40 } |
| 41 |
| 42 ExternalProtocolHandler::BlockState GetBlockStateWithDelegate( |
| 43 const std::string& scheme, |
| 44 ExternalProtocolHandler::Delegate* delegate) { |
| 45 if (!delegate) |
| 46 return ExternalProtocolHandler::GetBlockState(scheme); |
| 47 |
| 48 return delegate->GetBlockState(scheme); |
| 49 } |
| 50 |
| 51 void RunExternalProtocolDialogWithDelegate( |
| 52 const GURL& url, |
| 53 int render_process_host_id, |
| 54 int routing_id, |
| 55 ExternalProtocolHandler::Delegate* delegate) { |
| 56 if (!delegate) { |
| 57 ExternalProtocolHandler::RunExternalProtocolDialog(url, |
| 58 render_process_host_id, |
| 59 routing_id); |
| 60 } else { |
| 61 delegate->RunExternalProtocolDialog(url, render_process_host_id, |
| 62 routing_id); |
| 63 } |
| 64 } |
| 65 |
| 66 void LaunchUrlWithoutSecurityCheckWithDelegate( |
| 67 const GURL& url, |
| 68 ExternalProtocolHandler::Delegate* delegate) { |
| 69 if (!delegate) |
| 70 ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(url); |
| 71 else |
| 72 delegate->LaunchUrlWithoutSecurityCheck(url); |
| 73 } |
| 74 |
| 75 // When we are about to launch a URL with the default OS level application, |
| 76 // we check if that external application will be us. If it is we just ignore |
| 77 // the request. |
| 78 class ExternalDefaultProtocolObserver |
| 79 : public ShellIntegration::DefaultWebClientObserver { |
| 80 public: |
| 81 ExternalDefaultProtocolObserver(const GURL& escaped_url, |
| 82 int render_process_host_id, |
| 83 int tab_contents_id, |
| 84 bool prompt_user, |
| 85 ExternalProtocolHandler::Delegate* delegate) |
| 86 : delegate_(delegate), |
| 87 escaped_url_(escaped_url), |
| 88 render_process_host_id_(render_process_host_id), |
| 89 tab_contents_id_(tab_contents_id), |
| 90 prompt_user_(prompt_user) {} |
| 91 |
| 92 virtual void SetDefaultWebClientUIState( |
| 93 ShellIntegration::DefaultWebClientUIState state) OVERRIDE { |
| 94 DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type()); |
| 95 |
| 96 // If we are still working out if we're the default, or we've found |
| 97 // out we definately are the default, we end here. |
| 98 if (state == ShellIntegration::STATE_PROCESSING) { |
| 99 return; |
| 100 } |
| 101 |
| 102 if (delegate_) |
| 103 delegate_->FinishedProcessingCheck(); |
| 104 |
| 105 if (state == ShellIntegration::STATE_IS_DEFAULT) { |
| 106 if (delegate_) |
| 107 delegate_->BlockRequest(); |
| 108 return; |
| 109 } |
| 110 |
| 111 // If we get here, either we are not the default or we cannot work out |
| 112 // what the default is, so we proceed. |
| 113 if (prompt_user_) { |
| 114 // Ask the user if they want to allow the protocol. This will call |
| 115 // LaunchUrlWithoutSecurityCheck if the user decides to accept the |
| 116 // protocol. |
| 117 RunExternalProtocolDialogWithDelegate(escaped_url_, |
| 118 render_process_host_id_, tab_contents_id_, delegate_); |
| 119 return; |
| 120 } |
| 121 |
| 122 LaunchUrlWithoutSecurityCheckWithDelegate(escaped_url_, delegate_); |
| 123 } |
| 124 |
| 125 virtual bool IsOwnedByWorker() OVERRIDE { return true; } |
| 126 |
| 127 private: |
| 128 ExternalProtocolHandler::Delegate* delegate_; |
| 129 GURL escaped_url_; |
| 130 int render_process_host_id_; |
| 131 int tab_contents_id_; |
| 132 bool prompt_user_; |
| 133 }; |
| 134 |
| 135 } // namespace |
| 136 |
27 // static | 137 // static |
28 void ExternalProtocolHandler::PrepopulateDictionary(DictionaryValue* win_pref) { | 138 void ExternalProtocolHandler::PrepopulateDictionary(DictionaryValue* win_pref) { |
29 static bool is_warm = false; | 139 static bool is_warm = false; |
30 if (is_warm) | 140 if (is_warm) |
31 return; | 141 return; |
32 is_warm = true; | 142 is_warm = true; |
33 | 143 |
34 static const char* const denied_schemes[] = { | 144 static const char* const denied_schemes[] = { |
35 "afp", | 145 "afp", |
36 "data", | 146 "data", |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 if (state == UNKNOWN) { | 229 if (state == UNKNOWN) { |
120 update_excluded_schemas->Remove(scheme, NULL); | 230 update_excluded_schemas->Remove(scheme, NULL); |
121 } else { | 231 } else { |
122 update_excluded_schemas->SetBoolean(scheme, | 232 update_excluded_schemas->SetBoolean(scheme, |
123 state == BLOCK ? true : false); | 233 state == BLOCK ? true : false); |
124 } | 234 } |
125 } | 235 } |
126 } | 236 } |
127 | 237 |
128 // static | 238 // static |
129 void ExternalProtocolHandler::LaunchUrl(const GURL& url, | 239 void ExternalProtocolHandler::LaunchUrlWithDelegate(const GURL& url, |
130 int render_process_host_id, | 240 int render_process_host_id, |
131 int tab_contents_id) { | 241 int tab_contents_id, |
| 242 Delegate* delegate) { |
132 DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type()); | 243 DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type()); |
133 | 244 |
134 // Escape the input scheme to be sure that the command does not | 245 // Escape the input scheme to be sure that the command does not |
135 // have parameters unexpected by the external program. | 246 // have parameters unexpected by the external program. |
136 std::string escaped_url_string = EscapeExternalHandlerValue(url.spec()); | 247 std::string escaped_url_string = EscapeExternalHandlerValue(url.spec()); |
137 GURL escaped_url(escaped_url_string); | 248 GURL escaped_url(escaped_url_string); |
138 BlockState block_state = GetBlockState(escaped_url.scheme()); | 249 BlockState block_state = GetBlockStateWithDelegate(escaped_url.scheme(), |
139 if (block_state == BLOCK) | 250 delegate); |
| 251 if (block_state == BLOCK) { |
| 252 if (delegate) |
| 253 delegate->BlockRequest(); |
140 return; | 254 return; |
| 255 } |
141 | 256 |
142 g_accept_requests = false; | 257 g_accept_requests = false; |
143 | 258 |
144 if (block_state == UNKNOWN) { | 259 // The worker creates tasks with references to itself and puts them into |
145 // Ask the user if they want to allow the protocol. This will call | 260 // message loops. When no tasks are left it will delete the observer and |
146 // LaunchUrlWithoutSecurityCheck if the user decides to accept the protocol. | 261 // eventually be deleted itself. |
147 RunExternalProtocolDialog(escaped_url, | 262 ShellIntegration::DefaultWebClientObserver* observer = |
148 render_process_host_id, | 263 new ExternalDefaultProtocolObserver(url, |
149 tab_contents_id); | 264 render_process_host_id, |
150 return; | 265 tab_contents_id, |
151 } | 266 block_state == UNKNOWN, |
| 267 delegate); |
| 268 scoped_refptr<ShellIntegration::DefaultProtocolClientWorker> worker = |
| 269 CreateShellWorker(observer, escaped_url.scheme(), delegate); |
152 | 270 |
153 LaunchUrlWithoutSecurityCheck(escaped_url); | 271 // Start the check process running. This will send tasks to the FILE thread |
| 272 // and when the answer is known will send the result back to the observer on |
| 273 // the UI thread. |
| 274 worker->StartCheckIsDefault(); |
154 } | 275 } |
155 | 276 |
156 // static | 277 // static |
157 void ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(const GURL& url) { | 278 void ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(const GURL& url) { |
158 #if defined(OS_MACOSX) | 279 #if defined(OS_MACOSX) |
159 // This must run on the UI thread on OS X. | 280 // This must run on the UI thread on OS X. |
160 platform_util::OpenExternal(url); | 281 platform_util::OpenExternal(url); |
161 #else | 282 #else |
162 // Otherwise put this work on the file thread. On Windows ShellExecute may | 283 // Otherwise put this work on the file thread. On Windows ShellExecute may |
163 // block for a significant amount of time, and it shouldn't hurt on Linux. | 284 // block for a significant amount of time, and it shouldn't hurt on Linux. |
(...skipping 10 matching lines...) Expand all Loading... |
174 // static | 295 // static |
175 void ExternalProtocolHandler::RegisterPrefs(PrefService* prefs) { | 296 void ExternalProtocolHandler::RegisterPrefs(PrefService* prefs) { |
176 prefs->RegisterDictionaryPref(prefs::kExcludedSchemes); | 297 prefs->RegisterDictionaryPref(prefs::kExcludedSchemes); |
177 } | 298 } |
178 | 299 |
179 // static | 300 // static |
180 void ExternalProtocolHandler::PermitLaunchUrl() { | 301 void ExternalProtocolHandler::PermitLaunchUrl() { |
181 DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type()); | 302 DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type()); |
182 g_accept_requests = true; | 303 g_accept_requests = true; |
183 } | 304 } |
OLD | NEW |