Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(714)

Side by Side Diff: chrome/browser/extensions/extension_debugger_api.cc

Issue 10762006: Moved c/b/e/*debugger* to c/b/e/api/debugger/ (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Missed some files =) Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 // Implements the Chrome Extensions Debugger API.
6
7 #include "chrome/browser/extensions/extension_debugger_api.h"
8
9 #include <map>
10 #include <set>
11
12 #include "base/json/json_reader.h"
13 #include "base/json/json_writer.h"
14 #include "base/memory/singleton.h"
15 #include "base/string_number_conversions.h"
16 #include "base/utf_string_conversions.h"
17 #include "base/values.h"
18 #include "chrome/browser/extensions/extension_debugger_api_constants.h"
19 #include "chrome/browser/extensions/extension_event_router.h"
20 #include "chrome/browser/extensions/extension_tab_util.h"
21 #include "chrome/browser/infobars/infobar.h"
22 #include "chrome/browser/infobars/infobar_tab_helper.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
25 #include "chrome/browser/ui/tab_contents/tab_contents.h"
26 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
27 #include "chrome/common/chrome_notification_types.h"
28 #include "chrome/common/extensions/extension.h"
29 #include "chrome/common/extensions/extension_error_utils.h"
30 #include "content/public/browser/devtools_agent_host_registry.h"
31 #include "content/public/browser/devtools_client_host.h"
32 #include "content/public/browser/devtools_manager.h"
33 #include "content/public/browser/notification_service.h"
34 #include "content/public/browser/notification_source.h"
35 #include "content/public/browser/render_view_host.h"
36 #include "content/public/browser/web_contents.h"
37 #include "content/public/common/content_client.h"
38 #include "grit/generated_resources.h"
39 #include "ui/base/l10n/l10n_util.h"
40 #include "webkit/glue/webkit_glue.h"
41
42 using content::DevToolsAgentHost;
43 using content::DevToolsAgentHostRegistry;
44 using content::DevToolsClientHost;
45 using content::DevToolsManager;
46 using content::WebContents;
47
48 namespace keys = extension_debugger_api_constants;
49
50
51 class ExtensionDevToolsInfoBarDelegate : public ConfirmInfoBarDelegate {
52 public:
53 ExtensionDevToolsInfoBarDelegate(
54 InfoBarTabHelper* infobar_helper,
55 const std::string& client_name);
56 virtual ~ExtensionDevToolsInfoBarDelegate();
57
58 private:
59 // ConfirmInfoBarDelegate:
60 virtual bool ShouldExpire(
61 const content::LoadCommittedDetails& details) const OVERRIDE;
62 virtual int GetButtons() const OVERRIDE;
63 virtual Type GetInfoBarType() const OVERRIDE;
64 virtual string16 GetMessageText() const OVERRIDE;
65
66 std::string client_name_;
67 DISALLOW_COPY_AND_ASSIGN(ExtensionDevToolsInfoBarDelegate);
68 };
69
70 class ExtensionDevToolsClientHost : public DevToolsClientHost,
71 public content::NotificationObserver {
72 public:
73 ExtensionDevToolsClientHost(WebContents* web_contents,
74 const std::string& extension_id,
75 const std::string& extension_name,
76 int tab_id);
77
78 ~ExtensionDevToolsClientHost();
79
80 bool MatchesContentsAndExtensionId(WebContents* web_contents,
81 const std::string& extension_id);
82 void Close();
83 void SendMessageToBackend(SendCommandDebuggerFunction* function,
84 const std::string& method,
85 Value* params);
86
87 // DevToolsClientHost interface
88 virtual void InspectedContentsClosing() OVERRIDE;
89 virtual void DispatchOnInspectorFrontend(const std::string& message) OVERRIDE;
90 virtual void ContentsReplaced(WebContents* web_contents) OVERRIDE;
91 virtual void FrameNavigating(const std::string& url) OVERRIDE {}
92
93 private:
94 void SendDetachedEvent();
95
96 // content::NotificationObserver implementation.
97 virtual void Observe(int type,
98 const content::NotificationSource& source,
99 const content::NotificationDetails& details);
100
101 WebContents* web_contents_;
102 std::string extension_id_;
103 int tab_id_;
104 content::NotificationRegistrar registrar_;
105 int last_request_id_;
106 typedef std::map<int, scoped_refptr<SendCommandDebuggerFunction> >
107 PendingRequests;
108 PendingRequests pending_requests_;
109 ExtensionDevToolsInfoBarDelegate* infobar_delegate_;
110
111 DISALLOW_COPY_AND_ASSIGN(ExtensionDevToolsClientHost);
112 };
113
114 namespace {
115
116 static Value* CreateDebuggeeId(int tab_id) {
117 DictionaryValue* debuggeeId = new DictionaryValue();
118 debuggeeId->SetInteger(keys::kTabIdKey, tab_id);
119 return debuggeeId;
120 }
121
122 class AttachedClientHosts {
123 public:
124 AttachedClientHosts() {}
125
126 // Returns the singleton instance of this class
127 static AttachedClientHosts* GetInstance() {
128 return Singleton<AttachedClientHosts>::get();
129 }
130
131 void Add(ExtensionDevToolsClientHost* client_host) {
132 client_hosts_.insert(client_host);
133 }
134
135 void Remove(ExtensionDevToolsClientHost* client_host) {
136 client_hosts_.erase(client_host);
137 }
138
139 ExtensionDevToolsClientHost* Lookup(WebContents* contents) {
140 for (std::set<DevToolsClientHost*>::iterator it = client_hosts_.begin();
141 it != client_hosts_.end(); ++it) {
142 DevToolsAgentHost* agent_host =
143 DevToolsManager::GetInstance()->GetDevToolsAgentHostFor(*it);
144 if (!agent_host)
145 continue;
146 content::RenderViewHost* rvh =
147 DevToolsAgentHostRegistry::GetRenderViewHost(agent_host);
148 if (rvh && WebContents::FromRenderViewHost(rvh) == contents)
149 return static_cast<ExtensionDevToolsClientHost*>(*it);
150 }
151 return NULL;
152 }
153
154 private:
155 std::set<DevToolsClientHost*> client_hosts_;
156 };
157
158 } // namespace
159
160 ExtensionDevToolsClientHost::ExtensionDevToolsClientHost(
161 WebContents* web_contents,
162 const std::string& extension_id,
163 const std::string& extension_name,
164 int tab_id)
165 : web_contents_(web_contents),
166 extension_id_(extension_id),
167 tab_id_(tab_id),
168 last_request_id_(0),
169 infobar_delegate_(NULL) {
170 AttachedClientHosts::GetInstance()->Add(this);
171
172 // Detach from debugger when extension unloads.
173 Profile* profile =
174 Profile::FromBrowserContext(web_contents_->GetBrowserContext());
175 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
176 content::Source<Profile>(profile));
177
178 // Attach to debugger and tell it we are ready.
179 DevToolsAgentHost* agent = DevToolsAgentHostRegistry::GetDevToolsAgentHost(
180 web_contents_->GetRenderViewHost());
181 DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(agent, this);
182
183 InfoBarTabHelper* infobar_helper =
184 TabContents::FromWebContents(web_contents_)->infobar_tab_helper();
185 infobar_delegate_ =
186 new ExtensionDevToolsInfoBarDelegate(infobar_helper, extension_name);
187 if (infobar_helper->AddInfoBar(infobar_delegate_)) {
188 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
189 content::Source<InfoBarTabHelper>(infobar_helper));
190 } else {
191 infobar_delegate_ = NULL;
192 }
193 }
194
195 ExtensionDevToolsClientHost::~ExtensionDevToolsClientHost() {
196 // Ensure calling RemoveInfoBar() below won't result in Observe() trying to
197 // Close() us.
198 registrar_.RemoveAll();
199
200 if (infobar_delegate_) {
201 TabContents* tab_contents = TabContents::FromWebContents(web_contents_);
202 InfoBarTabHelper* helper = tab_contents->infobar_tab_helper();
203 if (helper)
204 helper->RemoveInfoBar(infobar_delegate_);
205 }
206 AttachedClientHosts::GetInstance()->Remove(this);
207 }
208
209 bool ExtensionDevToolsClientHost::MatchesContentsAndExtensionId(
210 WebContents* web_contents,
211 const std::string& extension_id) {
212 return web_contents == web_contents_ && extension_id_ == extension_id;
213 }
214
215 // DevToolsClientHost interface
216 void ExtensionDevToolsClientHost::InspectedContentsClosing() {
217 SendDetachedEvent();
218 delete this;
219 }
220
221 void ExtensionDevToolsClientHost::ContentsReplaced(WebContents* web_contents) {
222 web_contents_ = web_contents;
223 }
224
225 void ExtensionDevToolsClientHost::Close() {
226 DevToolsManager::GetInstance()->ClientHostClosing(this);
227 delete this;
228 }
229
230 void ExtensionDevToolsClientHost::SendMessageToBackend(
231 SendCommandDebuggerFunction* function,
232 const std::string& method,
233 Value* params) {
234 DictionaryValue protocol_request;
235 int request_id = ++last_request_id_;
236 pending_requests_[request_id] = function;
237 protocol_request.SetInteger("id", request_id);
238 protocol_request.SetString("method", method);
239 if (params)
240 protocol_request.Set("params", params->DeepCopy());
241
242 std::string json_args;
243 base::JSONWriter::Write(&protocol_request, &json_args);
244 DevToolsManager::GetInstance()->DispatchOnInspectorBackend(this, json_args);
245 }
246
247 void ExtensionDevToolsClientHost::SendDetachedEvent() {
248 Profile* profile =
249 Profile::FromBrowserContext(web_contents_->GetBrowserContext());
250 if (profile != NULL && profile->GetExtensionEventRouter()) {
251 ListValue args;
252 args.Append(CreateDebuggeeId(tab_id_));
253
254 std::string json_args;
255 base::JSONWriter::Write(&args, &json_args);
256
257 profile->GetExtensionEventRouter()->DispatchEventToExtension(
258 extension_id_, keys::kOnDetach, json_args, profile, GURL());
259 }
260 }
261
262 void ExtensionDevToolsClientHost::Observe(
263 int type,
264 const content::NotificationSource& source,
265 const content::NotificationDetails& details) {
266 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) {
267 std::string id =
268 content::Details<extensions::UnloadedExtensionInfo>(details)->
269 extension->id();
270 if (id == extension_id_)
271 Close();
272 } else {
273 DCHECK_EQ(chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, type);
274 if (content::Details<InfoBarRemovedDetails>(details)->first ==
275 infobar_delegate_) {
276 infobar_delegate_ = NULL;
277 SendDetachedEvent();
278 Close();
279 }
280 }
281 }
282
283 void ExtensionDevToolsClientHost::DispatchOnInspectorFrontend(
284 const std::string& message) {
285 Profile* profile =
286 Profile::FromBrowserContext(web_contents_->GetBrowserContext());
287 if (profile == NULL || !profile->GetExtensionEventRouter())
288 return;
289
290 scoped_ptr<Value> result(base::JSONReader::Read(message));
291 if (!result->IsType(Value::TYPE_DICTIONARY))
292 return;
293 DictionaryValue* dictionary = static_cast<DictionaryValue*>(result.get());
294
295 int id;
296 if (!dictionary->GetInteger("id", &id)) {
297 std::string method_name;
298 if (!dictionary->GetString("method", &method_name))
299 return;
300
301 ListValue args;
302 args.Append(CreateDebuggeeId(tab_id_));
303 args.Append(Value::CreateStringValue(method_name));
304 Value* params_value;
305 if (dictionary->Get("params", &params_value))
306 args.Append(params_value->DeepCopy());
307
308 std::string json_args;
309 base::JSONWriter::Write(&args, &json_args);
310
311 profile->GetExtensionEventRouter()->DispatchEventToExtension(
312 extension_id_, keys::kOnEvent, json_args, profile, GURL());
313 } else {
314 SendCommandDebuggerFunction* function = pending_requests_[id];
315 if (!function)
316 return;
317
318 function->SendResponseBody(dictionary);
319 pending_requests_.erase(id);
320 }
321 }
322
323 ExtensionDevToolsInfoBarDelegate::ExtensionDevToolsInfoBarDelegate(
324 InfoBarTabHelper* infobar_helper,
325 const std::string& client_name)
326 : ConfirmInfoBarDelegate(infobar_helper),
327 client_name_(client_name) {
328 }
329
330 ExtensionDevToolsInfoBarDelegate::~ExtensionDevToolsInfoBarDelegate() {
331 }
332
333 bool ExtensionDevToolsInfoBarDelegate::ShouldExpire(
334 const content::LoadCommittedDetails& details) const {
335 return false;
336 }
337
338 int ExtensionDevToolsInfoBarDelegate::GetButtons() const {
339 return BUTTON_CANCEL;
340 }
341
342 InfoBarDelegate::Type ExtensionDevToolsInfoBarDelegate::GetInfoBarType() const {
343 return WARNING_TYPE;
344 }
345
346 string16 ExtensionDevToolsInfoBarDelegate::GetMessageText() const {
347 return l10n_util::GetStringFUTF16(IDS_DEV_TOOLS_INFOBAR_LABEL,
348 UTF8ToUTF16(client_name_));
349 }
350
351 DebuggerFunction::DebuggerFunction()
352 : contents_(0),
353 tab_id_(0),
354 client_host_(0) {
355 }
356
357 bool DebuggerFunction::InitTabContents() {
358 Value* debuggee;
359 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &debuggee));
360
361 DictionaryValue* dict = static_cast<DictionaryValue*>(debuggee);
362 EXTENSION_FUNCTION_VALIDATE(dict->GetInteger(keys::kTabIdKey, &tab_id_));
363
364 // Find the TabContents that contains this tab id.
365 contents_ = NULL;
366 TabContents* tab_contents = NULL;
367 bool result = ExtensionTabUtil::GetTabById(
368 tab_id_, profile(), include_incognito(), NULL, NULL, &tab_contents, NULL);
369 if (!result || !tab_contents) {
370 error_ = ExtensionErrorUtils::FormatErrorMessage(
371 keys::kNoTabError,
372 base::IntToString(tab_id_));
373 return false;
374 }
375 contents_ = tab_contents->web_contents();
376
377 if (content::GetContentClient()->HasWebUIScheme(
378 contents_->GetURL())) {
379 error_ = ExtensionErrorUtils::FormatErrorMessage(
380 keys::kAttachToWebUIError,
381 contents_->GetURL().scheme());
382 return false;
383 }
384
385 return true;
386 }
387
388 bool DebuggerFunction::InitClientHost() {
389 if (!InitTabContents())
390 return false;
391
392 // Don't fetch rvh from the contents since it'll be wrong upon navigation.
393 client_host_ = AttachedClientHosts::GetInstance()->Lookup(contents_);
394
395 if (!client_host_ ||
396 !client_host_->MatchesContentsAndExtensionId(contents_,
397 GetExtension()->id())) {
398 error_ = ExtensionErrorUtils::FormatErrorMessage(
399 keys::kNotAttachedError,
400 base::IntToString(tab_id_));
401 return false;
402 }
403 return true;
404 }
405
406 AttachDebuggerFunction::AttachDebuggerFunction() {}
407
408 AttachDebuggerFunction::~AttachDebuggerFunction() {}
409
410 bool AttachDebuggerFunction::RunImpl() {
411 if (!InitTabContents())
412 return false;
413
414 std::string version;
415 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &version));
416
417 if (!webkit_glue::IsInspectorProtocolVersionSupported(version)) {
418 error_ = ExtensionErrorUtils::FormatErrorMessage(
419 keys::kProtocolVersionNotSupportedError,
420 version);
421 return false;
422 }
423
424 DevToolsAgentHost* agent = DevToolsAgentHostRegistry::GetDevToolsAgentHost(
425 contents_->GetRenderViewHost());
426 DevToolsClientHost* client_host = DevToolsManager::GetInstance()->
427 GetDevToolsClientHostFor(agent);
428
429 if (client_host != NULL) {
430 error_ = ExtensionErrorUtils::FormatErrorMessage(
431 keys::kAlreadyAttachedError,
432 base::IntToString(tab_id_));
433 return false;
434 }
435
436 new ExtensionDevToolsClientHost(contents_,
437 GetExtension()->id(),
438 GetExtension()->name(),
439 tab_id_);
440 SendResponse(true);
441 return true;
442 }
443
444 DetachDebuggerFunction::DetachDebuggerFunction() {}
445
446 DetachDebuggerFunction::~DetachDebuggerFunction() {}
447
448 bool DetachDebuggerFunction::RunImpl() {
449 if (!InitClientHost())
450 return false;
451
452 client_host_->Close();
453 SendResponse(true);
454 return true;
455 }
456
457 SendCommandDebuggerFunction::SendCommandDebuggerFunction() {}
458
459 SendCommandDebuggerFunction::~SendCommandDebuggerFunction() {}
460
461 bool SendCommandDebuggerFunction::RunImpl() {
462
463 if (!InitClientHost())
464 return false;
465
466 std::string method;
467 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &method));
468
469 Value *params;
470 if (!args_->Get(2, &params))
471 params = NULL;
472
473 client_host_->SendMessageToBackend(this, method, params);
474 return true;
475 }
476
477 void SendCommandDebuggerFunction::SendResponseBody(
478 DictionaryValue* dictionary) {
479 Value* error_body;
480 if (dictionary->Get("error", &error_body)) {
481 base::JSONWriter::Write(error_body, &error_);
482 SendResponse(false);
483 return;
484 }
485
486 Value* result_body;
487 if (dictionary->Get("result", &result_body))
488 result_.reset(result_body->DeepCopy());
489 else
490 result_.reset(new DictionaryValue());
491 SendResponse(true);
492 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698