1 // Copyright 2014 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.
5 #include "chrome/browser/devtools/devtools_ui_bindings.h"
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/metrics/histogram.h"
10 #include "base/prefs/scoped_user_pref_update.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/values.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/devtools/devtools_target_impl.h"
18 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
19 #include "chrome/browser/infobars/infobar_service.h"
20 #include "chrome/browser/prefs/pref_service_syncable.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/browser_iterator.h"
24 #include "chrome/browser/ui/browser_list.h"
25 #include "chrome/browser/ui/browser_window.h"
26 #include "chrome/browser/ui/tabs/tab_strip_model.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/extensions/chrome_manifest_url_handlers.h"
29 #include "chrome/common/pref_names.h"
30 #include "chrome/common/url_constants.h"
31 #include "chrome/grit/generated_resources.h"
32 #include "components/infobars/core/confirm_infobar_delegate.h"
33 #include "components/infobars/core/infobar.h"
34 #include "components/ui/zoom/page_zoom.h"
35 #include "content/public/browser/favicon_status.h"
36 #include "content/public/browser/invalidate_type.h"
37 #include "content/public/browser/navigation_controller.h"
38 #include "content/public/browser/navigation_entry.h"
39 #include "content/public/browser/notification_source.h"
40 #include "content/public/browser/render_frame_host.h"
41 #include "content/public/browser/render_view_host.h"
42 #include "content/public/browser/user_metrics.h"
43 #include "content/public/browser/web_contents.h"
44 #include "content/public/browser/web_contents_observer.h"
45 #include "content/public/common/renderer_preferences.h"
46 #include "content/public/common/url_constants.h"
47 #include "extensions/browser/extension_registry.h"
48 #include "extensions/common/permissions/permissions_data.h"
49 #include "net/base/io_buffer.h"
50 #include "net/base/net_errors.h"
51 #include "net/http/http_response_headers.h"
52 #include "net/url_request/url_fetcher.h"
53 #include "net/url_request/url_fetcher_response_writer.h"
54 #include "ui/base/l10n/l10n_util.h"
55 #include "ui/base/page_transition_types.h"
57 using base::DictionaryValue
;
58 using content::BrowserThread
;
61 struct LoadCommittedDetails
;
62 struct FrameNavigateParams
;
67 static const char kFrontendHostId
[] = "id";
68 static const char kFrontendHostMethod
[] = "method";
69 static const char kFrontendHostParams
[] = "params";
70 static const char kTitleFormat
[] = "Developer Tools - %s";
72 static const char kDevToolsActionTakenHistogram
[] = "DevTools.ActionTaken";
73 static const char kDevToolsPanelShownHistogram
[] = "DevTools.PanelShown";
75 // This constant should be in sync with
76 // the constant at shell_devtools_frontend.cc.
77 const size_t kMaxMessageChunkSize
= IPC::Channel::kMaximumMessageSize
/ 4;
79 typedef std::vector
<DevToolsUIBindings
*> DevToolsUIBindingsList
;
80 base::LazyInstance
<DevToolsUIBindingsList
>::Leaky g_instances
=
81 LAZY_INSTANCE_INITIALIZER
;
83 base::DictionaryValue
* CreateFileSystemValue(
84 DevToolsFileHelper::FileSystem file_system
) {
85 base::DictionaryValue
* file_system_value
= new base::DictionaryValue();
86 file_system_value
->SetString("fileSystemName", file_system
.file_system_name
);
87 file_system_value
->SetString("rootURL", file_system
.root_url
);
88 file_system_value
->SetString("fileSystemPath", file_system
.file_system_path
);
89 return file_system_value
;
92 Browser
* FindBrowser(content::WebContents
* web_contents
) {
93 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
94 int tab_index
= it
->tab_strip_model()->GetIndexOfWebContents(
96 if (tab_index
!= TabStripModel::kNoTab
)
102 // DevToolsConfirmInfoBarDelegate ---------------------------------------------
104 typedef base::Callback
<void(bool)> InfoBarCallback
;
106 class DevToolsConfirmInfoBarDelegate
: public ConfirmInfoBarDelegate
{
108 // If |infobar_service| is NULL, runs |callback| with a single argument with
109 // value "false". Otherwise, creates a dev tools confirm infobar and delegate
110 // and adds the infobar to |infobar_service|.
111 static void Create(InfoBarService
* infobar_service
,
112 const InfoBarCallback
& callback
,
113 const base::string16
& message
);
116 DevToolsConfirmInfoBarDelegate(
117 const InfoBarCallback
& callback
,
118 const base::string16
& message
);
119 ~DevToolsConfirmInfoBarDelegate() override
;
121 base::string16
GetMessageText() const override
;
122 base::string16
GetButtonLabel(InfoBarButton button
) const override
;
123 bool Accept() override
;
124 bool Cancel() override
;
126 InfoBarCallback callback_
;
127 const base::string16 message_
;
129 DISALLOW_COPY_AND_ASSIGN(DevToolsConfirmInfoBarDelegate
);
132 void DevToolsConfirmInfoBarDelegate::Create(
133 InfoBarService
* infobar_service
,
134 const InfoBarCallback
& callback
,
135 const base::string16
& message
) {
136 if (!infobar_service
) {
141 infobar_service
->AddInfoBar(
142 infobar_service
->CreateConfirmInfoBar(scoped_ptr
<ConfirmInfoBarDelegate
>(
143 new DevToolsConfirmInfoBarDelegate(callback
, message
))));
146 DevToolsConfirmInfoBarDelegate::DevToolsConfirmInfoBarDelegate(
147 const InfoBarCallback
& callback
,
148 const base::string16
& message
)
149 : ConfirmInfoBarDelegate(),
154 DevToolsConfirmInfoBarDelegate::~DevToolsConfirmInfoBarDelegate() {
155 if (!callback_
.is_null())
156 callback_
.Run(false);
159 base::string16
DevToolsConfirmInfoBarDelegate::GetMessageText() const {
163 base::string16
DevToolsConfirmInfoBarDelegate::GetButtonLabel(
164 InfoBarButton button
) const {
165 return l10n_util::GetStringUTF16((button
== BUTTON_OK
) ?
166 IDS_DEV_TOOLS_CONFIRM_ALLOW_BUTTON
: IDS_DEV_TOOLS_CONFIRM_DENY_BUTTON
);
169 bool DevToolsConfirmInfoBarDelegate::Accept() {
175 bool DevToolsConfirmInfoBarDelegate::Cancel() {
176 callback_
.Run(false);
181 // DevToolsUIDefaultDelegate --------------------------------------------------
183 class DefaultBindingsDelegate
: public DevToolsUIBindings::Delegate
{
185 explicit DefaultBindingsDelegate(content::WebContents
* web_contents
)
186 : web_contents_(web_contents
) {}
189 ~DefaultBindingsDelegate() override
{}
191 void ActivateWindow() override
;
192 void CloseWindow() override
{}
193 void SetInspectedPageBounds(const gfx::Rect
& rect
) override
{}
194 void InspectElementCompleted() override
{}
195 void SetIsDocked(bool is_docked
) override
{}
196 void OpenInNewTab(const std::string
& url
) override
;
197 void SetWhitelistedShortcuts(const std::string
& message
) override
{}
198 using DispatchCallback
=
199 DevToolsEmbedderMessageDispatcher::Delegate::DispatchCallback
;
201 void InspectedContentsClosing() override
;
202 void OnLoadCompleted() override
{}
203 InfoBarService
* GetInfoBarService() override
;
204 void RenderProcessGone(bool crashed
) override
{}
206 content::WebContents
* web_contents_
;
207 DISALLOW_COPY_AND_ASSIGN(DefaultBindingsDelegate
);
210 void DefaultBindingsDelegate::ActivateWindow() {
211 web_contents_
->GetDelegate()->ActivateContents(web_contents_
);
212 web_contents_
->Focus();
215 void DefaultBindingsDelegate::OpenInNewTab(const std::string
& url
) {
216 content::OpenURLParams
params(
217 GURL(url
), content::Referrer(), NEW_FOREGROUND_TAB
,
218 ui::PAGE_TRANSITION_LINK
, false);
219 Browser
* browser
= FindBrowser(web_contents_
);
220 browser
->OpenURL(params
);
223 void DefaultBindingsDelegate::InspectedContentsClosing() {
224 web_contents_
->ClosePage();
227 InfoBarService
* DefaultBindingsDelegate::GetInfoBarService() {
228 return InfoBarService::FromWebContents(web_contents_
);
231 // ResponseWriter -------------------------------------------------------------
233 class ResponseWriter
: public net::URLFetcherResponseWriter
{
235 ResponseWriter(base::WeakPtr
<DevToolsUIBindings
> bindings
, int stream_id
);
236 ~ResponseWriter() override
;
238 // URLFetcherResponseWriter overrides:
239 int Initialize(const net::CompletionCallback
& callback
) override
;
240 int Write(net::IOBuffer
* buffer
,
242 const net::CompletionCallback
& callback
) override
;
243 int Finish(const net::CompletionCallback
& callback
) override
;
246 base::WeakPtr
<DevToolsUIBindings
> bindings_
;
249 DISALLOW_COPY_AND_ASSIGN(ResponseWriter
);
252 ResponseWriter::ResponseWriter(base::WeakPtr
<DevToolsUIBindings
> bindings
,
254 : bindings_(bindings
),
255 stream_id_(stream_id
) {
258 ResponseWriter::~ResponseWriter() {
261 int ResponseWriter::Initialize(const net::CompletionCallback
& callback
) {
265 int ResponseWriter::Write(net::IOBuffer
* buffer
,
267 const net::CompletionCallback
& callback
) {
268 base::FundamentalValue
* id
= new base::FundamentalValue(stream_id_
);
269 base::StringValue
* chunk
=
270 new base::StringValue(std::string(buffer
->data(), num_bytes
));
272 content::BrowserThread::PostTask(
273 content::BrowserThread::UI
, FROM_HERE
,
274 base::Bind(&DevToolsUIBindings::CallClientFunction
,
275 bindings_
, "DevToolsAPI.streamWrite",
276 base::Owned(id
), base::Owned(chunk
), nullptr));
280 int ResponseWriter::Finish(const net::CompletionCallback
& callback
) {
286 // DevToolsUIBindings::FrontendWebContentsObserver ----------------------------
288 class DevToolsUIBindings::FrontendWebContentsObserver
289 : public content::WebContentsObserver
{
291 explicit FrontendWebContentsObserver(DevToolsUIBindings
* ui_bindings
);
292 ~FrontendWebContentsObserver() override
;
295 // contents::WebContentsObserver:
296 void RenderProcessGone(base::TerminationStatus status
) override
;
297 // TODO(creis): Replace with RenderFrameCreated when http://crbug.com/425397
298 // is fixed. See also http://crbug.com/424641.
299 void AboutToNavigateRenderFrame(
300 content::RenderFrameHost
* old_host
,
301 content::RenderFrameHost
* new_host
) override
;
302 void DocumentOnLoadCompletedInMainFrame() override
;
303 void DidNavigateMainFrame(
304 const content::LoadCommittedDetails
& details
,
305 const content::FrameNavigateParams
& params
) override
;
307 DevToolsUIBindings
* devtools_bindings_
;
308 DISALLOW_COPY_AND_ASSIGN(FrontendWebContentsObserver
);
311 DevToolsUIBindings::FrontendWebContentsObserver::FrontendWebContentsObserver(
312 DevToolsUIBindings
* devtools_ui_bindings
)
313 : WebContentsObserver(devtools_ui_bindings
->web_contents()),
314 devtools_bindings_(devtools_ui_bindings
) {
317 DevToolsUIBindings::FrontendWebContentsObserver::
318 ~FrontendWebContentsObserver() {
321 void DevToolsUIBindings::FrontendWebContentsObserver::RenderProcessGone(
322 base::TerminationStatus status
) {
325 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION
:
326 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED
:
327 #if defined(OS_CHROMEOS)
328 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM
:
330 case base::TERMINATION_STATUS_PROCESS_CRASHED
:
331 if (devtools_bindings_
->agent_host_
.get())
332 devtools_bindings_
->Detach();
338 devtools_bindings_
->delegate_
->RenderProcessGone(crashed
);
341 void DevToolsUIBindings::FrontendWebContentsObserver::
342 AboutToNavigateRenderFrame(content::RenderFrameHost
* old_host
,
343 content::RenderFrameHost
* new_host
) {
344 if (new_host
->GetParent())
346 devtools_bindings_
->frontend_host_
.reset(
347 content::DevToolsFrontendHost::Create(new_host
,
348 devtools_bindings_
));
351 void DevToolsUIBindings::FrontendWebContentsObserver::
352 DocumentOnLoadCompletedInMainFrame() {
353 devtools_bindings_
->DocumentOnLoadCompletedInMainFrame();
356 void DevToolsUIBindings::FrontendWebContentsObserver::
357 DidNavigateMainFrame(const content::LoadCommittedDetails
& details
,
358 const content::FrameNavigateParams
& params
) {
359 devtools_bindings_
->DidNavigateMainFrame();
362 // DevToolsUIBindings ---------------------------------------------------------
364 DevToolsUIBindings
* DevToolsUIBindings::ForWebContents(
365 content::WebContents
* web_contents
) {
366 if (g_instances
== NULL
)
368 DevToolsUIBindingsList
* instances
= g_instances
.Pointer();
369 for (DevToolsUIBindingsList::iterator
it(instances
->begin());
370 it
!= instances
->end(); ++it
) {
371 if ((*it
)->web_contents() == web_contents
)
377 DevToolsUIBindings::DevToolsUIBindings(content::WebContents
* web_contents
)
378 : profile_(Profile::FromBrowserContext(web_contents
->GetBrowserContext())),
379 android_bridge_(DevToolsAndroidBridge::Factory::GetForProfile(profile_
)),
380 web_contents_(web_contents
),
381 delegate_(new DefaultBindingsDelegate(web_contents_
)),
382 devices_updates_enabled_(false),
383 frontend_loaded_(false),
384 weak_factory_(this) {
385 g_instances
.Get().push_back(this);
386 frontend_contents_observer_
.reset(new FrontendWebContentsObserver(this));
387 web_contents_
->GetMutableRendererPrefs()->can_accept_load_drops
= false;
389 file_helper_
.reset(new DevToolsFileHelper(web_contents_
, profile_
));
390 file_system_indexer_
= new DevToolsFileSystemIndexer();
391 extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
394 // Wipe out page icon so that the default application icon is used.
395 content::NavigationEntry
* entry
=
396 web_contents_
->GetController().GetActiveEntry();
397 entry
->GetFavicon().image
= gfx::Image();
398 entry
->GetFavicon().valid
= true;
400 // Register on-load actions.
401 embedder_message_dispatcher_
.reset(
402 DevToolsEmbedderMessageDispatcher::CreateForDevToolsFrontend(this));
404 frontend_host_
.reset(content::DevToolsFrontendHost::Create(
405 web_contents_
->GetMainFrame(), this));
408 DevToolsUIBindings::~DevToolsUIBindings() {
409 for (const auto& pair
: pending_requests_
)
412 if (agent_host_
.get())
413 agent_host_
->DetachClient();
415 for (IndexingJobsMap::const_iterator
jobs_it(indexing_jobs_
.begin());
416 jobs_it
!= indexing_jobs_
.end(); ++jobs_it
) {
417 jobs_it
->second
->Stop();
419 indexing_jobs_
.clear();
420 SetDevicesUpdatesEnabled(false);
422 // Remove self from global list.
423 DevToolsUIBindingsList
* instances
= g_instances
.Pointer();
424 DevToolsUIBindingsList::iterator
it(
425 std::find(instances
->begin(), instances
->end(), this));
426 DCHECK(it
!= instances
->end());
427 instances
->erase(it
);
430 // content::DevToolsFrontendHost::Delegate implementation ---------------------
431 void DevToolsUIBindings::HandleMessageFromDevToolsFrontend(
432 const std::string
& message
) {
434 base::ListValue empty_params
;
435 base::ListValue
* params
= &empty_params
;
437 base::DictionaryValue
* dict
= NULL
;
438 scoped_ptr
<base::Value
> parsed_message
= base::JSONReader::Read(message
);
439 if (!parsed_message
||
440 !parsed_message
->GetAsDictionary(&dict
) ||
441 !dict
->GetString(kFrontendHostMethod
, &method
) ||
442 (dict
->HasKey(kFrontendHostParams
) &&
443 !dict
->GetList(kFrontendHostParams
, ¶ms
))) {
444 LOG(ERROR
) << "Invalid message was sent to embedder: " << message
;
448 dict
->GetInteger(kFrontendHostId
, &id
);
449 embedder_message_dispatcher_
->Dispatch(
450 base::Bind(&DevToolsUIBindings::SendMessageAck
,
451 weak_factory_
.GetWeakPtr(),
457 void DevToolsUIBindings::HandleMessageFromDevToolsFrontendToBackend(
458 const std::string
& message
) {
459 if (agent_host_
.get())
460 agent_host_
->DispatchProtocolMessage(message
);
463 // content::DevToolsAgentHostClient implementation --------------------------
464 void DevToolsUIBindings::DispatchProtocolMessage(
465 content::DevToolsAgentHost
* agent_host
, const std::string
& message
) {
466 DCHECK(agent_host
== agent_host_
.get());
468 if (message
.length() < kMaxMessageChunkSize
) {
469 base::string16 javascript
= base::UTF8ToUTF16(
470 "DevToolsAPI.dispatchMessage(" + message
+ ");");
471 web_contents_
->GetMainFrame()->ExecuteJavaScript(javascript
);
475 base::FundamentalValue
total_size(static_cast<int>(message
.length()));
476 for (size_t pos
= 0; pos
< message
.length(); pos
+= kMaxMessageChunkSize
) {
477 base::StringValue
message_value(message
.substr(pos
, kMaxMessageChunkSize
));
478 CallClientFunction("DevToolsAPI.dispatchMessageChunk",
479 &message_value
, pos
? NULL
: &total_size
, NULL
);
483 void DevToolsUIBindings::AgentHostClosed(
484 content::DevToolsAgentHost
* agent_host
,
485 bool replaced_with_another_client
) {
486 DCHECK(agent_host
== agent_host_
.get());
488 delegate_
->InspectedContentsClosing();
491 void DevToolsUIBindings::SendMessageAck(int request_id
,
492 const base::Value
* arg
) {
493 base::FundamentalValue
id_value(request_id
);
494 CallClientFunction("DevToolsAPI.embedderMessageAck",
495 &id_value
, arg
, nullptr);
498 // DevToolsEmbedderMessageDispatcher::Delegate implementation -----------------
499 void DevToolsUIBindings::ActivateWindow() {
500 delegate_
->ActivateWindow();
503 void DevToolsUIBindings::CloseWindow() {
504 delegate_
->CloseWindow();
507 void DevToolsUIBindings::LoadCompleted() {
511 void DevToolsUIBindings::SetInspectedPageBounds(const gfx::Rect
& rect
) {
512 delegate_
->SetInspectedPageBounds(rect
);
515 void DevToolsUIBindings::SetIsDocked(const DispatchCallback
& callback
,
516 bool dock_requested
) {
517 delegate_
->SetIsDocked(dock_requested
);
518 callback
.Run(nullptr);
521 void DevToolsUIBindings::InspectElementCompleted() {
522 delegate_
->InspectElementCompleted();
525 void DevToolsUIBindings::InspectedURLChanged(const std::string
& url
) {
526 content::NavigationController
& controller
= web_contents()->GetController();
527 content::NavigationEntry
* entry
= controller
.GetActiveEntry();
528 // DevTools UI is not localized.
530 base::UTF8ToUTF16(base::StringPrintf(kTitleFormat
, url
.c_str())));
531 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE
);
534 void DevToolsUIBindings::LoadNetworkResource(const DispatchCallback
& callback
,
535 const std::string
& url
,
536 const std::string
& headers
,
539 if (!gurl
.is_valid()) {
540 base::DictionaryValue response
;
541 response
.SetInteger("statusCode", 404);
542 callback
.Run(&response
);
546 net::URLFetcher
* fetcher
=
547 net::URLFetcher::Create(gurl
, net::URLFetcher::GET
, this).release();
548 pending_requests_
[fetcher
] = callback
;
549 fetcher
->SetRequestContext(profile_
->GetRequestContext());
550 fetcher
->SetExtraRequestHeaders(headers
);
551 fetcher
->SaveResponseWithWriter(scoped_ptr
<net::URLFetcherResponseWriter
>(
552 new ResponseWriter(weak_factory_
.GetWeakPtr(), stream_id
)));
556 void DevToolsUIBindings::OpenInNewTab(const std::string
& url
) {
557 delegate_
->OpenInNewTab(url
);
560 void DevToolsUIBindings::SaveToFile(const std::string
& url
,
561 const std::string
& content
,
563 file_helper_
->Save(url
, content
, save_as
,
564 base::Bind(&DevToolsUIBindings::FileSavedAs
,
565 weak_factory_
.GetWeakPtr(), url
),
566 base::Bind(&DevToolsUIBindings::CanceledFileSaveAs
,
567 weak_factory_
.GetWeakPtr(), url
));
570 void DevToolsUIBindings::AppendToFile(const std::string
& url
,
571 const std::string
& content
) {
572 file_helper_
->Append(url
, content
,
573 base::Bind(&DevToolsUIBindings::AppendedTo
,
574 weak_factory_
.GetWeakPtr(), url
));
577 void DevToolsUIBindings::RequestFileSystems() {
578 CHECK(web_contents_
->GetURL().SchemeIs(content::kChromeDevToolsScheme
));
579 file_helper_
->RequestFileSystems(base::Bind(
580 &DevToolsUIBindings::FileSystemsLoaded
, weak_factory_
.GetWeakPtr()));
583 void DevToolsUIBindings::AddFileSystem() {
584 CHECK(web_contents_
->GetURL().SchemeIs(content::kChromeDevToolsScheme
));
585 file_helper_
->AddFileSystem(
586 base::Bind(&DevToolsUIBindings::FileSystemAdded
,
587 weak_factory_
.GetWeakPtr()),
588 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar
,
589 weak_factory_
.GetWeakPtr()));
592 void DevToolsUIBindings::RemoveFileSystem(const std::string
& file_system_path
) {
593 CHECK(web_contents_
->GetURL().SchemeIs(content::kChromeDevToolsScheme
));
594 file_helper_
->RemoveFileSystem(file_system_path
);
595 base::StringValue
file_system_path_value(file_system_path
);
596 CallClientFunction("DevToolsAPI.fileSystemRemoved",
597 &file_system_path_value
, NULL
, NULL
);
600 void DevToolsUIBindings::UpgradeDraggedFileSystemPermissions(
601 const std::string
& file_system_url
) {
602 CHECK(web_contents_
->GetURL().SchemeIs(content::kChromeDevToolsScheme
));
603 file_helper_
->UpgradeDraggedFileSystemPermissions(
605 base::Bind(&DevToolsUIBindings::FileSystemAdded
,
606 weak_factory_
.GetWeakPtr()),
607 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar
,
608 weak_factory_
.GetWeakPtr()));
611 void DevToolsUIBindings::IndexPath(int index_request_id
,
612 const std::string
& file_system_path
) {
613 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
614 CHECK(web_contents_
->GetURL().SchemeIs(content::kChromeDevToolsScheme
));
615 if (!file_helper_
->IsFileSystemAdded(file_system_path
)) {
616 IndexingDone(index_request_id
, file_system_path
);
619 if (indexing_jobs_
.count(index_request_id
) != 0)
621 indexing_jobs_
[index_request_id
] =
622 scoped_refptr
<DevToolsFileSystemIndexer::FileSystemIndexingJob
>(
623 file_system_indexer_
->IndexPath(
625 Bind(&DevToolsUIBindings::IndexingTotalWorkCalculated
,
626 weak_factory_
.GetWeakPtr(),
629 Bind(&DevToolsUIBindings::IndexingWorked
,
630 weak_factory_
.GetWeakPtr(),
633 Bind(&DevToolsUIBindings::IndexingDone
,
634 weak_factory_
.GetWeakPtr(),
639 void DevToolsUIBindings::StopIndexing(int index_request_id
) {
640 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
641 IndexingJobsMap::iterator it
= indexing_jobs_
.find(index_request_id
);
642 if (it
== indexing_jobs_
.end())
645 indexing_jobs_
.erase(it
);
648 void DevToolsUIBindings::SearchInPath(int search_request_id
,
649 const std::string
& file_system_path
,
650 const std::string
& query
) {
651 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
652 CHECK(web_contents_
->GetURL().SchemeIs(content::kChromeDevToolsScheme
));
653 if (!file_helper_
->IsFileSystemAdded(file_system_path
)) {
654 SearchCompleted(search_request_id
,
656 std::vector
<std::string
>());
659 file_system_indexer_
->SearchInPath(file_system_path
,
661 Bind(&DevToolsUIBindings::SearchCompleted
,
662 weak_factory_
.GetWeakPtr(),
667 void DevToolsUIBindings::SetWhitelistedShortcuts(const std::string
& message
) {
668 delegate_
->SetWhitelistedShortcuts(message
);
671 void DevToolsUIBindings::ZoomIn() {
672 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_IN
);
675 void DevToolsUIBindings::ZoomOut() {
676 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_OUT
);
679 void DevToolsUIBindings::ResetZoom() {
680 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_RESET
);
683 void DevToolsUIBindings::SetDevicesUpdatesEnabled(bool enabled
) {
684 if (devices_updates_enabled_
== enabled
)
686 devices_updates_enabled_
= enabled
;
688 remote_targets_handler_
= DevToolsTargetsUIHandler::CreateForAdb(
689 base::Bind(&DevToolsUIBindings::DevicesUpdated
,
690 base::Unretained(this)),
693 remote_targets_handler_
.reset();
697 void DevToolsUIBindings::GetPreferences(const DispatchCallback
& callback
) {
698 const DictionaryValue
* prefs
=
699 profile_
->GetPrefs()->GetDictionary(prefs::kDevToolsPreferences
);
703 void DevToolsUIBindings::SetPreference(const std::string
& name
,
704 const std::string
& value
) {
705 DictionaryPrefUpdate
update(profile_
->GetPrefs(),
706 prefs::kDevToolsPreferences
);
707 update
.Get()->SetStringWithoutPathExpansion(name
, value
);
710 void DevToolsUIBindings::RemovePreference(const std::string
& name
) {
711 DictionaryPrefUpdate
update(profile_
->GetPrefs(),
712 prefs::kDevToolsPreferences
);
713 update
.Get()->RemoveWithoutPathExpansion(name
, nullptr);
716 void DevToolsUIBindings::ClearPreferences() {
717 DictionaryPrefUpdate
update(profile_
->GetPrefs(),
718 prefs::kDevToolsPreferences
);
719 update
.Get()->Clear();
722 void DevToolsUIBindings::SendMessageToBrowser(const std::string
& message
) {
723 if (agent_host_
.get())
724 agent_host_
->DispatchProtocolMessage(message
);
727 void DevToolsUIBindings::RecordEnumeratedHistogram(const std::string
& name
,
729 int boundary_value
) {
730 if (!(boundary_value
>= 0 && boundary_value
<= 100 && sample
>= 0 &&
731 sample
< boundary_value
)) {
732 // TODO(nick): Replace with chrome::bad_message::ReceivedBadMessage().
733 frontend_host_
->BadMessageRecieved();
736 // Each histogram name must follow a different code path in
737 // order to UMA_HISTOGRAM_ENUMERATION work correctly.
738 if (name
== kDevToolsActionTakenHistogram
)
739 UMA_HISTOGRAM_ENUMERATION(name
, sample
, boundary_value
);
740 else if (name
== kDevToolsPanelShownHistogram
)
741 UMA_HISTOGRAM_ENUMERATION(name
, sample
, boundary_value
);
743 frontend_host_
->BadMessageRecieved();
746 void DevToolsUIBindings::SendJsonRequest(const DispatchCallback
& callback
,
747 const std::string
& browser_id
,
748 const std::string
& url
) {
749 if (!android_bridge_
) {
750 callback
.Run(nullptr);
753 android_bridge_
->SendJsonRequest(browser_id
, url
,
754 base::Bind(&DevToolsUIBindings::JsonReceived
,
755 weak_factory_
.GetWeakPtr(),
759 void DevToolsUIBindings::JsonReceived(const DispatchCallback
& callback
,
761 const std::string
& message
) {
762 if (result
!= net::OK
) {
763 callback
.Run(nullptr);
766 base::StringValue
message_value(message
);
767 callback
.Run(&message_value
);
770 void DevToolsUIBindings::OnURLFetchComplete(const net::URLFetcher
* source
) {
772 PendingRequestsMap::iterator it
= pending_requests_
.find(source
);
773 DCHECK(it
!= pending_requests_
.end());
775 base::DictionaryValue response
;
776 base::DictionaryValue
* headers
= new base::DictionaryValue();
777 net::HttpResponseHeaders
* rh
= source
->GetResponseHeaders();
778 response
.SetInteger("statusCode", rh
? rh
->response_code() : 200);
779 response
.Set("headers", headers
);
781 void* iterator
= NULL
;
784 while (rh
&& rh
->EnumerateHeaderLines(&iterator
, &name
, &value
))
785 headers
->SetString(name
, value
);
787 it
->second
.Run(&response
);
788 pending_requests_
.erase(it
);
792 void DevToolsUIBindings::DeviceCountChanged(int count
) {
793 base::FundamentalValue
value(count
);
794 CallClientFunction("DevToolsAPI.deviceCountUpdated", &value
, NULL
,
798 void DevToolsUIBindings::DevicesUpdated(
799 const std::string
& source
,
800 const base::ListValue
& targets
) {
801 CallClientFunction("DevToolsAPI.devicesUpdated", &targets
, NULL
,
805 void DevToolsUIBindings::FileSavedAs(const std::string
& url
) {
806 base::StringValue
url_value(url
);
807 CallClientFunction("DevToolsAPI.savedURL", &url_value
, NULL
, NULL
);
810 void DevToolsUIBindings::CanceledFileSaveAs(const std::string
& url
) {
811 base::StringValue
url_value(url
);
812 CallClientFunction("DevToolsAPI.canceledSaveURL",
813 &url_value
, NULL
, NULL
);
816 void DevToolsUIBindings::AppendedTo(const std::string
& url
) {
817 base::StringValue
url_value(url
);
818 CallClientFunction("DevToolsAPI.appendedToURL", &url_value
, NULL
,
822 void DevToolsUIBindings::FileSystemsLoaded(
823 const std::vector
<DevToolsFileHelper::FileSystem
>& file_systems
) {
824 base::ListValue file_systems_value
;
825 for (size_t i
= 0; i
< file_systems
.size(); ++i
)
826 file_systems_value
.Append(CreateFileSystemValue(file_systems
[i
]));
827 CallClientFunction("DevToolsAPI.fileSystemsLoaded",
828 &file_systems_value
, NULL
, NULL
);
831 void DevToolsUIBindings::FileSystemAdded(
832 const DevToolsFileHelper::FileSystem
& file_system
) {
833 scoped_ptr
<base::StringValue
> error_string_value(
834 new base::StringValue(std::string()));
835 scoped_ptr
<base::DictionaryValue
> file_system_value
;
836 if (!file_system
.file_system_path
.empty())
837 file_system_value
.reset(CreateFileSystemValue(file_system
));
838 CallClientFunction("DevToolsAPI.fileSystemAdded",
839 error_string_value
.get(), file_system_value
.get(), NULL
);
842 void DevToolsUIBindings::IndexingTotalWorkCalculated(
844 const std::string
& file_system_path
,
846 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
847 base::FundamentalValue
request_id_value(request_id
);
848 base::StringValue
file_system_path_value(file_system_path
);
849 base::FundamentalValue
total_work_value(total_work
);
850 CallClientFunction("DevToolsAPI.indexingTotalWorkCalculated",
851 &request_id_value
, &file_system_path_value
,
855 void DevToolsUIBindings::IndexingWorked(int request_id
,
856 const std::string
& file_system_path
,
858 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
859 base::FundamentalValue
request_id_value(request_id
);
860 base::StringValue
file_system_path_value(file_system_path
);
861 base::FundamentalValue
worked_value(worked
);
862 CallClientFunction("DevToolsAPI.indexingWorked", &request_id_value
,
863 &file_system_path_value
, &worked_value
);
866 void DevToolsUIBindings::IndexingDone(int request_id
,
867 const std::string
& file_system_path
) {
868 indexing_jobs_
.erase(request_id
);
869 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
870 base::FundamentalValue
request_id_value(request_id
);
871 base::StringValue
file_system_path_value(file_system_path
);
872 CallClientFunction("DevToolsAPI.indexingDone", &request_id_value
,
873 &file_system_path_value
, NULL
);
876 void DevToolsUIBindings::SearchCompleted(
878 const std::string
& file_system_path
,
879 const std::vector
<std::string
>& file_paths
) {
880 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
881 base::ListValue file_paths_value
;
882 for (std::vector
<std::string
>::const_iterator
it(file_paths
.begin());
883 it
!= file_paths
.end(); ++it
) {
884 file_paths_value
.AppendString(*it
);
886 base::FundamentalValue
request_id_value(request_id
);
887 base::StringValue
file_system_path_value(file_system_path
);
888 CallClientFunction("DevToolsAPI.searchCompleted", &request_id_value
,
889 &file_system_path_value
, &file_paths_value
);
892 void DevToolsUIBindings::ShowDevToolsConfirmInfoBar(
893 const base::string16
& message
,
894 const InfoBarCallback
& callback
) {
895 DevToolsConfirmInfoBarDelegate::Create(delegate_
->GetInfoBarService(),
899 void DevToolsUIBindings::AddDevToolsExtensionsToClient() {
900 const extensions::ExtensionRegistry
* registry
=
901 extensions::ExtensionRegistry::Get(profile_
->GetOriginalProfile());
905 base::ListValue results
;
906 for (const scoped_refptr
<const extensions::Extension
>& extension
:
907 registry
->enabled_extensions()) {
908 if (extensions::chrome_manifest_urls::GetDevToolsPage(extension
.get())
911 base::DictionaryValue
* extension_info
= new base::DictionaryValue();
914 new base::StringValue(extensions::chrome_manifest_urls::GetDevToolsPage(
915 extension
.get()).spec()));
916 extension_info
->Set("name", new base::StringValue(extension
->name()));
917 extension_info
->Set("exposeExperimentalAPIs",
918 new base::FundamentalValue(
919 extension
->permissions_data()->HasAPIPermission(
920 extensions::APIPermission::kExperimental
)));
921 results
.Append(extension_info
);
923 CallClientFunction("DevToolsAPI.addExtensions",
924 &results
, NULL
, NULL
);
927 void DevToolsUIBindings::SetDelegate(Delegate
* delegate
) {
928 delegate_
.reset(delegate
);
931 void DevToolsUIBindings::AttachTo(
932 const scoped_refptr
<content::DevToolsAgentHost
>& agent_host
) {
933 if (agent_host_
.get())
935 agent_host_
= agent_host
;
936 agent_host_
->AttachClient(this);
939 void DevToolsUIBindings::Reattach() {
940 DCHECK(agent_host_
.get());
941 agent_host_
->DetachClient();
942 agent_host_
->AttachClient(this);
945 void DevToolsUIBindings::Detach() {
946 if (agent_host_
.get())
947 agent_host_
->DetachClient();
951 bool DevToolsUIBindings::IsAttachedTo(content::DevToolsAgentHost
* agent_host
) {
952 return agent_host_
.get() == agent_host
;
955 void DevToolsUIBindings::CallClientFunction(const std::string
& function_name
,
956 const base::Value
* arg1
,
957 const base::Value
* arg2
,
958 const base::Value
* arg3
) {
959 std::string javascript
= function_name
+ "(";
962 base::JSONWriter::Write(*arg1
, &json
);
963 javascript
.append(json
);
965 base::JSONWriter::Write(*arg2
, &json
);
966 javascript
.append(", ").append(json
);
968 base::JSONWriter::Write(*arg3
, &json
);
969 javascript
.append(", ").append(json
);
973 javascript
.append(");");
974 web_contents_
->GetMainFrame()->ExecuteJavaScript(
975 base::UTF8ToUTF16(javascript
));
978 void DevToolsUIBindings::DocumentOnLoadCompletedInMainFrame() {
979 // In the DEBUG_DEVTOOLS mode, the DocumentOnLoadCompletedInMainFrame event
980 // arrives before the LoadCompleted event, thus it should not trigger the
981 // frontend load handling.
982 #if !defined(DEBUG_DEVTOOLS)
987 void DevToolsUIBindings::DidNavigateMainFrame() {
988 frontend_loaded_
= false;
991 void DevToolsUIBindings::FrontendLoaded() {
992 if (frontend_loaded_
)
994 frontend_loaded_
= true;
996 // Call delegate first - it seeds importants bit of information.
997 delegate_
->OnLoadCompleted();
999 AddDevToolsExtensionsToClient();