Refactor WebsiteSettings to operate on a SecurityInfo
[chromium-blink-merge.git] / chrome / browser / devtools / devtools_ui_bindings.cc
blob8ebae8cad50890e1fa0dec0ded36f41d4720d072
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/profiles/profile.h"
21 #include "chrome/browser/ui/browser.h"
22 #include "chrome/browser/ui/browser_iterator.h"
23 #include "chrome/browser/ui/browser_list.h"
24 #include "chrome/browser/ui/browser_window.h"
25 #include "chrome/browser/ui/tabs/tab_strip_model.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/extensions/chrome_manifest_url_handlers.h"
28 #include "chrome/common/pref_names.h"
29 #include "chrome/common/url_constants.h"
30 #include "chrome/grit/generated_resources.h"
31 #include "components/infobars/core/confirm_infobar_delegate.h"
32 #include "components/infobars/core/infobar.h"
33 #include "components/syncable_prefs/pref_service_syncable.h"
34 #include "components/ui/zoom/page_zoom.h"
35 #include "content/public/browser/devtools_external_agent_proxy.h"
36 #include "content/public/browser/devtools_external_agent_proxy_delegate.h"
37 #include "content/public/browser/invalidate_type.h"
38 #include "content/public/browser/navigation_controller.h"
39 #include "content/public/browser/navigation_entry.h"
40 #include "content/public/browser/notification_source.h"
41 #include "content/public/browser/render_frame_host.h"
42 #include "content/public/browser/render_view_host.h"
43 #include "content/public/browser/user_metrics.h"
44 #include "content/public/browser/web_contents.h"
45 #include "content/public/browser/web_contents_observer.h"
46 #include "content/public/common/renderer_preferences.h"
47 #include "content/public/common/url_constants.h"
48 #include "extensions/browser/extension_registry.h"
49 #include "extensions/common/permissions/permissions_data.h"
50 #include "net/base/io_buffer.h"
51 #include "net/base/net_errors.h"
52 #include "net/http/http_response_headers.h"
53 #include "net/url_request/url_fetcher.h"
54 #include "net/url_request/url_fetcher_response_writer.h"
55 #include "ui/base/l10n/l10n_util.h"
56 #include "ui/base/page_transition_types.h"
58 using base::DictionaryValue;
59 using content::BrowserThread;
61 namespace content {
62 struct LoadCommittedDetails;
63 struct FrameNavigateParams;
66 namespace {
68 static const char kFrontendHostId[] = "id";
69 static const char kFrontendHostMethod[] = "method";
70 static const char kFrontendHostParams[] = "params";
71 static const char kTitleFormat[] = "Developer Tools - %s";
73 static const char kDevToolsActionTakenHistogram[] = "DevTools.ActionTaken";
74 static const char kDevToolsPanelShownHistogram[] = "DevTools.PanelShown";
76 static const char kRemotePageActionInspect[] = "inspect";
77 static const char kRemotePageActionReload[] = "reload";
78 static const char kRemotePageActionActivate[] = "activate";
79 static const char kRemotePageActionClose[] = "close";
81 // This constant should be in sync with
82 // the constant at shell_devtools_frontend.cc.
83 const size_t kMaxMessageChunkSize = IPC::Channel::kMaximumMessageSize / 4;
85 typedef std::vector<DevToolsUIBindings*> DevToolsUIBindingsList;
86 base::LazyInstance<DevToolsUIBindingsList>::Leaky g_instances =
87 LAZY_INSTANCE_INITIALIZER;
89 base::DictionaryValue* CreateFileSystemValue(
90 DevToolsFileHelper::FileSystem file_system) {
91 base::DictionaryValue* file_system_value = new base::DictionaryValue();
92 file_system_value->SetString("fileSystemName", file_system.file_system_name);
93 file_system_value->SetString("rootURL", file_system.root_url);
94 file_system_value->SetString("fileSystemPath", file_system.file_system_path);
95 return file_system_value;
98 Browser* FindBrowser(content::WebContents* web_contents) {
99 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
100 int tab_index = it->tab_strip_model()->GetIndexOfWebContents(
101 web_contents);
102 if (tab_index != TabStripModel::kNoTab)
103 return *it;
105 return NULL;
108 // DevToolsConfirmInfoBarDelegate ---------------------------------------------
110 typedef base::Callback<void(bool)> InfoBarCallback;
112 class DevToolsConfirmInfoBarDelegate : public ConfirmInfoBarDelegate {
113 public:
114 // If |infobar_service| is NULL, runs |callback| with a single argument with
115 // value "false". Otherwise, creates a dev tools confirm infobar and delegate
116 // and adds the infobar to |infobar_service|.
117 static void Create(InfoBarService* infobar_service,
118 const InfoBarCallback& callback,
119 const base::string16& message);
121 private:
122 DevToolsConfirmInfoBarDelegate(
123 const InfoBarCallback& callback,
124 const base::string16& message);
125 ~DevToolsConfirmInfoBarDelegate() override;
127 base::string16 GetMessageText() const override;
128 base::string16 GetButtonLabel(InfoBarButton button) const override;
129 bool Accept() override;
130 bool Cancel() override;
132 InfoBarCallback callback_;
133 const base::string16 message_;
135 DISALLOW_COPY_AND_ASSIGN(DevToolsConfirmInfoBarDelegate);
138 void DevToolsConfirmInfoBarDelegate::Create(
139 InfoBarService* infobar_service,
140 const InfoBarCallback& callback,
141 const base::string16& message) {
142 if (!infobar_service) {
143 callback.Run(false);
144 return;
147 infobar_service->AddInfoBar(
148 infobar_service->CreateConfirmInfoBar(scoped_ptr<ConfirmInfoBarDelegate>(
149 new DevToolsConfirmInfoBarDelegate(callback, message))));
152 DevToolsConfirmInfoBarDelegate::DevToolsConfirmInfoBarDelegate(
153 const InfoBarCallback& callback,
154 const base::string16& message)
155 : ConfirmInfoBarDelegate(),
156 callback_(callback),
157 message_(message) {
160 DevToolsConfirmInfoBarDelegate::~DevToolsConfirmInfoBarDelegate() {
161 if (!callback_.is_null())
162 callback_.Run(false);
165 base::string16 DevToolsConfirmInfoBarDelegate::GetMessageText() const {
166 return message_;
169 base::string16 DevToolsConfirmInfoBarDelegate::GetButtonLabel(
170 InfoBarButton button) const {
171 return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
172 IDS_DEV_TOOLS_CONFIRM_ALLOW_BUTTON : IDS_DEV_TOOLS_CONFIRM_DENY_BUTTON);
175 bool DevToolsConfirmInfoBarDelegate::Accept() {
176 callback_.Run(true);
177 callback_.Reset();
178 return true;
181 bool DevToolsConfirmInfoBarDelegate::Cancel() {
182 callback_.Run(false);
183 callback_.Reset();
184 return true;
187 // DevToolsUIDefaultDelegate --------------------------------------------------
189 class DefaultBindingsDelegate : public DevToolsUIBindings::Delegate {
190 public:
191 explicit DefaultBindingsDelegate(content::WebContents* web_contents)
192 : web_contents_(web_contents) {}
194 private:
195 ~DefaultBindingsDelegate() override {}
197 void ActivateWindow() override;
198 void CloseWindow() override {}
199 void SetInspectedPageBounds(const gfx::Rect& rect) override {}
200 void InspectElementCompleted() override {}
201 void SetIsDocked(bool is_docked) override {}
202 void OpenInNewTab(const std::string& url) override;
203 void SetWhitelistedShortcuts(const std::string& message) override {}
204 using DispatchCallback =
205 DevToolsEmbedderMessageDispatcher::Delegate::DispatchCallback;
207 void InspectedContentsClosing() override;
208 void OnLoadCompleted() override {}
209 InfoBarService* GetInfoBarService() override;
210 void RenderProcessGone(bool crashed) override {}
212 content::WebContents* web_contents_;
213 DISALLOW_COPY_AND_ASSIGN(DefaultBindingsDelegate);
216 void DefaultBindingsDelegate::ActivateWindow() {
217 web_contents_->GetDelegate()->ActivateContents(web_contents_);
218 web_contents_->Focus();
221 void DefaultBindingsDelegate::OpenInNewTab(const std::string& url) {
222 content::OpenURLParams params(
223 GURL(url), content::Referrer(), NEW_FOREGROUND_TAB,
224 ui::PAGE_TRANSITION_LINK, false);
225 Browser* browser = FindBrowser(web_contents_);
226 browser->OpenURL(params);
229 void DefaultBindingsDelegate::InspectedContentsClosing() {
230 web_contents_->ClosePage();
233 InfoBarService* DefaultBindingsDelegate::GetInfoBarService() {
234 return InfoBarService::FromWebContents(web_contents_);
237 // ResponseWriter -------------------------------------------------------------
239 class ResponseWriter : public net::URLFetcherResponseWriter {
240 public:
241 ResponseWriter(base::WeakPtr<DevToolsUIBindings> bindings, int stream_id);
242 ~ResponseWriter() override;
244 // URLFetcherResponseWriter overrides:
245 int Initialize(const net::CompletionCallback& callback) override;
246 int Write(net::IOBuffer* buffer,
247 int num_bytes,
248 const net::CompletionCallback& callback) override;
249 int Finish(const net::CompletionCallback& callback) override;
251 private:
252 base::WeakPtr<DevToolsUIBindings> bindings_;
253 int stream_id_;
255 DISALLOW_COPY_AND_ASSIGN(ResponseWriter);
258 ResponseWriter::ResponseWriter(base::WeakPtr<DevToolsUIBindings> bindings,
259 int stream_id)
260 : bindings_(bindings),
261 stream_id_(stream_id) {
264 ResponseWriter::~ResponseWriter() {
267 int ResponseWriter::Initialize(const net::CompletionCallback& callback) {
268 return net::OK;
271 int ResponseWriter::Write(net::IOBuffer* buffer,
272 int num_bytes,
273 const net::CompletionCallback& callback) {
274 base::FundamentalValue* id = new base::FundamentalValue(stream_id_);
275 base::StringValue* chunk =
276 new base::StringValue(std::string(buffer->data(), num_bytes));
278 content::BrowserThread::PostTask(
279 content::BrowserThread::UI, FROM_HERE,
280 base::Bind(&DevToolsUIBindings::CallClientFunction,
281 bindings_, "DevToolsAPI.streamWrite",
282 base::Owned(id), base::Owned(chunk), nullptr));
283 return num_bytes;
286 int ResponseWriter::Finish(const net::CompletionCallback& callback) {
287 return net::OK;
290 } // namespace
292 // DevToolsUIBindings::FrontendWebContentsObserver ----------------------------
294 class DevToolsUIBindings::FrontendWebContentsObserver
295 : public content::WebContentsObserver {
296 public:
297 explicit FrontendWebContentsObserver(DevToolsUIBindings* ui_bindings);
298 ~FrontendWebContentsObserver() override;
300 private:
301 // contents::WebContentsObserver:
302 void RenderProcessGone(base::TerminationStatus status) override;
303 // TODO(creis): Replace with RenderFrameCreated when http://crbug.com/425397
304 // is fixed. See also http://crbug.com/424641.
305 void AboutToNavigateRenderFrame(
306 content::RenderFrameHost* old_host,
307 content::RenderFrameHost* new_host) override;
308 void DocumentOnLoadCompletedInMainFrame() override;
309 void DidNavigateMainFrame(
310 const content::LoadCommittedDetails& details,
311 const content::FrameNavigateParams& params) override;
313 DevToolsUIBindings* devtools_bindings_;
314 DISALLOW_COPY_AND_ASSIGN(FrontendWebContentsObserver);
317 DevToolsUIBindings::FrontendWebContentsObserver::FrontendWebContentsObserver(
318 DevToolsUIBindings* devtools_ui_bindings)
319 : WebContentsObserver(devtools_ui_bindings->web_contents()),
320 devtools_bindings_(devtools_ui_bindings) {
323 DevToolsUIBindings::FrontendWebContentsObserver::
324 ~FrontendWebContentsObserver() {
327 void DevToolsUIBindings::FrontendWebContentsObserver::RenderProcessGone(
328 base::TerminationStatus status) {
329 bool crashed = true;
330 switch (status) {
331 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
332 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
333 #if defined(OS_CHROMEOS)
334 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
335 #endif
336 case base::TERMINATION_STATUS_PROCESS_CRASHED:
337 case base::TERMINATION_STATUS_LAUNCH_FAILED:
338 if (devtools_bindings_->agent_host_.get())
339 devtools_bindings_->Detach();
340 break;
341 default:
342 crashed = false;
343 break;
345 devtools_bindings_->delegate_->RenderProcessGone(crashed);
348 void DevToolsUIBindings::FrontendWebContentsObserver::
349 AboutToNavigateRenderFrame(content::RenderFrameHost* old_host,
350 content::RenderFrameHost* new_host) {
351 if (new_host->GetParent())
352 return;
353 devtools_bindings_->frontend_host_.reset(
354 content::DevToolsFrontendHost::Create(new_host,
355 devtools_bindings_));
358 void DevToolsUIBindings::FrontendWebContentsObserver::
359 DocumentOnLoadCompletedInMainFrame() {
360 devtools_bindings_->DocumentOnLoadCompletedInMainFrame();
363 void DevToolsUIBindings::FrontendWebContentsObserver::
364 DidNavigateMainFrame(const content::LoadCommittedDetails& details,
365 const content::FrameNavigateParams& params) {
366 devtools_bindings_->DidNavigateMainFrame();
369 // WebSocketAPIChannel --------------------------------------------------------
371 class DevToolsUIBindings::WebSocketAPIChannel :
372 public content::DevToolsExternalAgentProxyDelegate {
373 public :
374 explicit WebSocketAPIChannel(base::WeakPtr<DevToolsUIBindings> bindings);
375 ~WebSocketAPIChannel() override;
376 void DispatchOnClientHost(const std::string& message);
377 void ConnectionClosed();
379 private:
380 // content::DevToolsExternalAgentProxyDelegate implementation.
381 void Attach(content::DevToolsExternalAgentProxy* proxy) override;
382 void Detach() override;
383 void SendMessageToBackend(const std::string& message) override;
385 base::WeakPtr<DevToolsUIBindings> bindings_;
386 content::DevToolsExternalAgentProxy* attached_proxy_;
387 DISALLOW_COPY_AND_ASSIGN(WebSocketAPIChannel);
390 DevToolsUIBindings::WebSocketAPIChannel::WebSocketAPIChannel(
391 base::WeakPtr<DevToolsUIBindings> bindings)
392 : bindings_(bindings),
393 attached_proxy_(nullptr) {
394 bindings->open_api_channel_ = this;
397 DevToolsUIBindings::WebSocketAPIChannel::~WebSocketAPIChannel() {
398 if (bindings_)
399 bindings_->open_api_channel_ = nullptr;
402 void DevToolsUIBindings::WebSocketAPIChannel::DispatchOnClientHost(
403 const std::string& message) {
404 if (attached_proxy_)
405 attached_proxy_->DispatchOnClientHost(message);
408 void DevToolsUIBindings::WebSocketAPIChannel::ConnectionClosed() {
409 if (bindings_) {
410 bindings_->CallClientFunction("DevToolsAPI.frontendAPIDetached",
411 nullptr, nullptr, nullptr);
413 if (attached_proxy_)
414 attached_proxy_->ConnectionClosed();
417 void DevToolsUIBindings::WebSocketAPIChannel::Attach(
418 content::DevToolsExternalAgentProxy* proxy) {
419 attached_proxy_ = proxy;
420 if (bindings_) {
421 bindings_->CallClientFunction("DevToolsAPI.frontendAPIAttached",
422 nullptr, nullptr, nullptr);
426 void DevToolsUIBindings::WebSocketAPIChannel::Detach() {
427 attached_proxy_ = nullptr;
428 if (bindings_) {
429 bindings_->open_api_channel_ = nullptr;
430 bindings_->CallClientFunction("DevToolsAPI.frontendAPIDetached",
431 nullptr, nullptr, nullptr);
435 void DevToolsUIBindings::WebSocketAPIChannel::SendMessageToBackend(
436 const std::string& message) {
437 if (!bindings_)
438 return;
439 base::StringValue message_value(message);
440 bindings_->CallClientFunction("DevToolsAPI.dispatchFrontendAPIMessage",
441 &message_value, nullptr, nullptr);
444 // DevToolsUIBindings ---------------------------------------------------------
446 DevToolsUIBindings* DevToolsUIBindings::ForWebContents(
447 content::WebContents* web_contents) {
448 if (g_instances == NULL)
449 return NULL;
450 DevToolsUIBindingsList* instances = g_instances.Pointer();
451 for (DevToolsUIBindingsList::iterator it(instances->begin());
452 it != instances->end(); ++it) {
453 if ((*it)->web_contents() == web_contents)
454 return *it;
456 return NULL;
459 DevToolsUIBindings::DevToolsUIBindings(content::WebContents* web_contents)
460 : profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
461 android_bridge_(DevToolsAndroidBridge::Factory::GetForProfile(profile_)),
462 web_contents_(web_contents),
463 delegate_(new DefaultBindingsDelegate(web_contents_)),
464 devices_updates_enabled_(false),
465 frontend_loaded_(false),
466 open_api_channel_(nullptr),
467 weak_factory_(this) {
468 g_instances.Get().push_back(this);
469 frontend_contents_observer_.reset(new FrontendWebContentsObserver(this));
470 web_contents_->GetMutableRendererPrefs()->can_accept_load_drops = false;
472 file_helper_.reset(new DevToolsFileHelper(web_contents_, profile_));
473 file_system_indexer_ = new DevToolsFileSystemIndexer();
474 extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
475 web_contents_);
477 // Register on-load actions.
478 embedder_message_dispatcher_.reset(
479 DevToolsEmbedderMessageDispatcher::CreateForDevToolsFrontend(this));
481 frontend_host_.reset(content::DevToolsFrontendHost::Create(
482 web_contents_->GetMainFrame(), this));
485 DevToolsUIBindings::~DevToolsUIBindings() {
486 for (const auto& pair : pending_requests_)
487 delete pair.first;
489 if (agent_host_.get())
490 agent_host_->DetachClient();
492 for (IndexingJobsMap::const_iterator jobs_it(indexing_jobs_.begin());
493 jobs_it != indexing_jobs_.end(); ++jobs_it) {
494 jobs_it->second->Stop();
496 indexing_jobs_.clear();
497 SetDevicesUpdatesEnabled(false);
499 if (open_api_channel_)
500 open_api_channel_->ConnectionClosed();
502 // Remove self from global list.
503 DevToolsUIBindingsList* instances = g_instances.Pointer();
504 DevToolsUIBindingsList::iterator it(
505 std::find(instances->begin(), instances->end(), this));
506 DCHECK(it != instances->end());
507 instances->erase(it);
510 // content::DevToolsFrontendHost::Delegate implementation ---------------------
511 void DevToolsUIBindings::HandleMessageFromDevToolsFrontend(
512 const std::string& message) {
513 std::string method;
514 base::ListValue empty_params;
515 base::ListValue* params = &empty_params;
517 base::DictionaryValue* dict = NULL;
518 scoped_ptr<base::Value> parsed_message = base::JSONReader::Read(message);
519 if (!parsed_message ||
520 !parsed_message->GetAsDictionary(&dict) ||
521 !dict->GetString(kFrontendHostMethod, &method) ||
522 (dict->HasKey(kFrontendHostParams) &&
523 !dict->GetList(kFrontendHostParams, &params))) {
524 LOG(ERROR) << "Invalid message was sent to embedder: " << message;
525 return;
527 int id = 0;
528 dict->GetInteger(kFrontendHostId, &id);
529 embedder_message_dispatcher_->Dispatch(
530 base::Bind(&DevToolsUIBindings::SendMessageAck,
531 weak_factory_.GetWeakPtr(),
532 id),
533 method,
534 params);
537 void DevToolsUIBindings::HandleMessageFromDevToolsFrontendToBackend(
538 const std::string& message) {
539 if (agent_host_.get())
540 agent_host_->DispatchProtocolMessage(message);
543 // content::DevToolsAgentHostClient implementation --------------------------
544 void DevToolsUIBindings::DispatchProtocolMessage(
545 content::DevToolsAgentHost* agent_host, const std::string& message) {
546 DCHECK(agent_host == agent_host_.get());
548 if (message.length() < kMaxMessageChunkSize) {
549 base::string16 javascript = base::UTF8ToUTF16(
550 "DevToolsAPI.dispatchMessage(" + message + ");");
551 web_contents_->GetMainFrame()->ExecuteJavaScript(javascript);
552 return;
555 base::FundamentalValue total_size(static_cast<int>(message.length()));
556 for (size_t pos = 0; pos < message.length(); pos += kMaxMessageChunkSize) {
557 base::StringValue message_value(message.substr(pos, kMaxMessageChunkSize));
558 CallClientFunction("DevToolsAPI.dispatchMessageChunk",
559 &message_value, pos ? NULL : &total_size, NULL);
563 void DevToolsUIBindings::AgentHostClosed(
564 content::DevToolsAgentHost* agent_host,
565 bool replaced_with_another_client) {
566 DCHECK(agent_host == agent_host_.get());
567 agent_host_ = NULL;
568 delegate_->InspectedContentsClosing();
571 void DevToolsUIBindings::SendMessageAck(int request_id,
572 const base::Value* arg) {
573 base::FundamentalValue id_value(request_id);
574 CallClientFunction("DevToolsAPI.embedderMessageAck",
575 &id_value, arg, nullptr);
578 // DevToolsEmbedderMessageDispatcher::Delegate implementation -----------------
579 void DevToolsUIBindings::ActivateWindow() {
580 delegate_->ActivateWindow();
583 void DevToolsUIBindings::CloseWindow() {
584 delegate_->CloseWindow();
587 void DevToolsUIBindings::LoadCompleted() {
588 FrontendLoaded();
591 void DevToolsUIBindings::SetInspectedPageBounds(const gfx::Rect& rect) {
592 delegate_->SetInspectedPageBounds(rect);
595 void DevToolsUIBindings::SetIsDocked(const DispatchCallback& callback,
596 bool dock_requested) {
597 delegate_->SetIsDocked(dock_requested);
598 callback.Run(nullptr);
601 void DevToolsUIBindings::InspectElementCompleted() {
602 delegate_->InspectElementCompleted();
605 void DevToolsUIBindings::InspectedURLChanged(const std::string& url) {
606 content::NavigationController& controller = web_contents()->GetController();
607 content::NavigationEntry* entry = controller.GetActiveEntry();
608 // DevTools UI is not localized.
609 entry->SetTitle(
610 base::UTF8ToUTF16(base::StringPrintf(kTitleFormat, url.c_str())));
611 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE);
614 void DevToolsUIBindings::LoadNetworkResource(const DispatchCallback& callback,
615 const std::string& url,
616 const std::string& headers,
617 int stream_id) {
618 GURL gurl(url);
619 if (!gurl.is_valid()) {
620 base::DictionaryValue response;
621 response.SetInteger("statusCode", 404);
622 callback.Run(&response);
623 return;
626 net::URLFetcher* fetcher =
627 net::URLFetcher::Create(gurl, net::URLFetcher::GET, this).release();
628 pending_requests_[fetcher] = callback;
629 fetcher->SetRequestContext(profile_->GetRequestContext());
630 fetcher->SetExtraRequestHeaders(headers);
631 fetcher->SaveResponseWithWriter(scoped_ptr<net::URLFetcherResponseWriter>(
632 new ResponseWriter(weak_factory_.GetWeakPtr(), stream_id)));
633 fetcher->Start();
636 void DevToolsUIBindings::OpenInNewTab(const std::string& url) {
637 delegate_->OpenInNewTab(url);
640 void DevToolsUIBindings::SaveToFile(const std::string& url,
641 const std::string& content,
642 bool save_as) {
643 file_helper_->Save(url, content, save_as,
644 base::Bind(&DevToolsUIBindings::FileSavedAs,
645 weak_factory_.GetWeakPtr(), url),
646 base::Bind(&DevToolsUIBindings::CanceledFileSaveAs,
647 weak_factory_.GetWeakPtr(), url));
650 void DevToolsUIBindings::AppendToFile(const std::string& url,
651 const std::string& content) {
652 file_helper_->Append(url, content,
653 base::Bind(&DevToolsUIBindings::AppendedTo,
654 weak_factory_.GetWeakPtr(), url));
657 void DevToolsUIBindings::RequestFileSystems() {
658 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
659 file_helper_->RequestFileSystems(base::Bind(
660 &DevToolsUIBindings::FileSystemsLoaded, weak_factory_.GetWeakPtr()));
663 void DevToolsUIBindings::AddFileSystem() {
664 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
665 file_helper_->AddFileSystem(
666 base::Bind(&DevToolsUIBindings::FileSystemAdded,
667 weak_factory_.GetWeakPtr()),
668 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar,
669 weak_factory_.GetWeakPtr()));
672 void DevToolsUIBindings::RemoveFileSystem(const std::string& file_system_path) {
673 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
674 file_helper_->RemoveFileSystem(file_system_path);
675 base::StringValue file_system_path_value(file_system_path);
676 CallClientFunction("DevToolsAPI.fileSystemRemoved",
677 &file_system_path_value, NULL, NULL);
680 void DevToolsUIBindings::UpgradeDraggedFileSystemPermissions(
681 const std::string& file_system_url) {
682 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
683 file_helper_->UpgradeDraggedFileSystemPermissions(
684 file_system_url,
685 base::Bind(&DevToolsUIBindings::FileSystemAdded,
686 weak_factory_.GetWeakPtr()),
687 base::Bind(&DevToolsUIBindings::ShowDevToolsConfirmInfoBar,
688 weak_factory_.GetWeakPtr()));
691 void DevToolsUIBindings::IndexPath(int index_request_id,
692 const std::string& file_system_path) {
693 DCHECK_CURRENTLY_ON(BrowserThread::UI);
694 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
695 if (!file_helper_->IsFileSystemAdded(file_system_path)) {
696 IndexingDone(index_request_id, file_system_path);
697 return;
699 if (indexing_jobs_.count(index_request_id) != 0)
700 return;
701 indexing_jobs_[index_request_id] =
702 scoped_refptr<DevToolsFileSystemIndexer::FileSystemIndexingJob>(
703 file_system_indexer_->IndexPath(
704 file_system_path,
705 Bind(&DevToolsUIBindings::IndexingTotalWorkCalculated,
706 weak_factory_.GetWeakPtr(),
707 index_request_id,
708 file_system_path),
709 Bind(&DevToolsUIBindings::IndexingWorked,
710 weak_factory_.GetWeakPtr(),
711 index_request_id,
712 file_system_path),
713 Bind(&DevToolsUIBindings::IndexingDone,
714 weak_factory_.GetWeakPtr(),
715 index_request_id,
716 file_system_path)));
719 void DevToolsUIBindings::StopIndexing(int index_request_id) {
720 DCHECK_CURRENTLY_ON(BrowserThread::UI);
721 IndexingJobsMap::iterator it = indexing_jobs_.find(index_request_id);
722 if (it == indexing_jobs_.end())
723 return;
724 it->second->Stop();
725 indexing_jobs_.erase(it);
728 void DevToolsUIBindings::SearchInPath(int search_request_id,
729 const std::string& file_system_path,
730 const std::string& query) {
731 DCHECK_CURRENTLY_ON(BrowserThread::UI);
732 CHECK(web_contents_->GetURL().SchemeIs(content::kChromeDevToolsScheme));
733 if (!file_helper_->IsFileSystemAdded(file_system_path)) {
734 SearchCompleted(search_request_id,
735 file_system_path,
736 std::vector<std::string>());
737 return;
739 file_system_indexer_->SearchInPath(file_system_path,
740 query,
741 Bind(&DevToolsUIBindings::SearchCompleted,
742 weak_factory_.GetWeakPtr(),
743 search_request_id,
744 file_system_path));
747 void DevToolsUIBindings::SetWhitelistedShortcuts(const std::string& message) {
748 delegate_->SetWhitelistedShortcuts(message);
751 void DevToolsUIBindings::ZoomIn() {
752 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_IN);
755 void DevToolsUIBindings::ZoomOut() {
756 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_OUT);
759 void DevToolsUIBindings::ResetZoom() {
760 ui_zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_RESET);
763 void DevToolsUIBindings::SetDevicesDiscoveryConfig(
764 bool discover_usb_devices,
765 bool port_forwarding_enabled,
766 const std::string& port_forwarding_config) {
767 base::DictionaryValue* config_dict = nullptr;
768 scoped_ptr<base::Value> parsed_config =
769 base::JSONReader::Read(port_forwarding_config);
770 if (!parsed_config || !parsed_config->GetAsDictionary(&config_dict))
771 return;
773 profile_->GetPrefs()->SetBoolean(
774 prefs::kDevToolsDiscoverUsbDevicesEnabled, discover_usb_devices);
775 profile_->GetPrefs()->SetBoolean(
776 prefs::kDevToolsPortForwardingEnabled, port_forwarding_enabled);
777 profile_->GetPrefs()->Set(
778 prefs::kDevToolsPortForwardingConfig, *config_dict);
781 void DevToolsUIBindings::DevicesDiscoveryConfigUpdated() {
782 CallClientFunction(
783 "DevToolsAPI.devicesDiscoveryConfigChanged",
784 profile_->GetPrefs()->FindPreference(
785 prefs::kDevToolsDiscoverUsbDevicesEnabled)->GetValue(),
786 profile_->GetPrefs()->FindPreference(
787 prefs::kDevToolsPortForwardingEnabled)->GetValue(),
788 profile_->GetPrefs()->FindPreference(
789 prefs::kDevToolsPortForwardingConfig)->GetValue());
792 void DevToolsUIBindings::SetDevicesUpdatesEnabled(bool enabled) {
793 if (devices_updates_enabled_ == enabled)
794 return;
795 devices_updates_enabled_ = enabled;
796 if (enabled) {
797 remote_targets_handler_ = DevToolsTargetsUIHandler::CreateForAdb(
798 base::Bind(&DevToolsUIBindings::DevicesUpdated,
799 base::Unretained(this)),
800 profile_);
801 pref_change_registrar_.Init(profile_->GetPrefs());
802 pref_change_registrar_.Add(prefs::kDevToolsDiscoverUsbDevicesEnabled,
803 base::Bind(&DevToolsUIBindings::DevicesDiscoveryConfigUpdated,
804 base::Unretained(this)));
805 pref_change_registrar_.Add(prefs::kDevToolsPortForwardingEnabled,
806 base::Bind(&DevToolsUIBindings::DevicesDiscoveryConfigUpdated,
807 base::Unretained(this)));
808 pref_change_registrar_.Add(prefs::kDevToolsPortForwardingConfig,
809 base::Bind(&DevToolsUIBindings::DevicesDiscoveryConfigUpdated,
810 base::Unretained(this)));
811 DevicesDiscoveryConfigUpdated();
812 } else {
813 remote_targets_handler_.reset();
814 pref_change_registrar_.RemoveAll();
818 void DevToolsUIBindings::PerformActionOnRemotePage(const std::string& page_id,
819 const std::string& action) {
820 if (!remote_targets_handler_)
821 return;
822 DevToolsTargetImpl* target = remote_targets_handler_->GetTarget(page_id);
823 if (!target)
824 return;
825 if (action == kRemotePageActionInspect)
826 target->Inspect(profile_);
827 if (action == kRemotePageActionReload)
828 target->Reload();
829 if (action == kRemotePageActionActivate)
830 target->Activate();
831 if (action == kRemotePageActionClose)
832 target->Close();
835 void DevToolsUIBindings::GetPreferences(const DispatchCallback& callback) {
836 const DictionaryValue* prefs =
837 profile_->GetPrefs()->GetDictionary(prefs::kDevToolsPreferences);
838 callback.Run(prefs);
841 void DevToolsUIBindings::SetPreference(const std::string& name,
842 const std::string& value) {
843 DictionaryPrefUpdate update(profile_->GetPrefs(),
844 prefs::kDevToolsPreferences);
845 update.Get()->SetStringWithoutPathExpansion(name, value);
848 void DevToolsUIBindings::RemovePreference(const std::string& name) {
849 DictionaryPrefUpdate update(profile_->GetPrefs(),
850 prefs::kDevToolsPreferences);
851 update.Get()->RemoveWithoutPathExpansion(name, nullptr);
854 void DevToolsUIBindings::ClearPreferences() {
855 DictionaryPrefUpdate update(profile_->GetPrefs(),
856 prefs::kDevToolsPreferences);
857 update.Get()->Clear();
860 void DevToolsUIBindings::SendMessageToBrowser(const std::string& message) {
861 if (agent_host_.get())
862 agent_host_->DispatchProtocolMessage(message);
865 void DevToolsUIBindings::RecordEnumeratedHistogram(const std::string& name,
866 int sample,
867 int boundary_value) {
868 if (!(boundary_value >= 0 && boundary_value <= 100 && sample >= 0 &&
869 sample < boundary_value)) {
870 // TODO(nick): Replace with chrome::bad_message::ReceivedBadMessage().
871 frontend_host_->BadMessageRecieved();
872 return;
874 // Each histogram name must follow a different code path in
875 // order to UMA_HISTOGRAM_ENUMERATION work correctly.
876 if (name == kDevToolsActionTakenHistogram)
877 UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value);
878 else if (name == kDevToolsPanelShownHistogram)
879 UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value);
880 else
881 frontend_host_->BadMessageRecieved();
884 void DevToolsUIBindings::SendJsonRequest(const DispatchCallback& callback,
885 const std::string& browser_id,
886 const std::string& url) {
887 if (!android_bridge_) {
888 callback.Run(nullptr);
889 return;
891 android_bridge_->SendJsonRequest(browser_id, url,
892 base::Bind(&DevToolsUIBindings::JsonReceived,
893 weak_factory_.GetWeakPtr(),
894 callback));
897 void DevToolsUIBindings::SendFrontendAPINotification(
898 const std::string& message) {
899 if (!open_api_channel_)
900 return;
901 open_api_channel_->DispatchOnClientHost(message);
904 void DevToolsUIBindings::JsonReceived(const DispatchCallback& callback,
905 int result,
906 const std::string& message) {
907 if (result != net::OK) {
908 callback.Run(nullptr);
909 return;
911 base::StringValue message_value(message);
912 callback.Run(&message_value);
915 void DevToolsUIBindings::OnURLFetchComplete(const net::URLFetcher* source) {
916 DCHECK(source);
917 PendingRequestsMap::iterator it = pending_requests_.find(source);
918 DCHECK(it != pending_requests_.end());
920 base::DictionaryValue response;
921 base::DictionaryValue* headers = new base::DictionaryValue();
922 net::HttpResponseHeaders* rh = source->GetResponseHeaders();
923 response.SetInteger("statusCode", rh ? rh->response_code() : 200);
924 response.Set("headers", headers);
926 void* iterator = NULL;
927 std::string name;
928 std::string value;
929 while (rh && rh->EnumerateHeaderLines(&iterator, &name, &value))
930 headers->SetString(name, value);
932 it->second.Run(&response);
933 pending_requests_.erase(it);
934 delete source;
937 void DevToolsUIBindings::DeviceCountChanged(int count) {
938 base::FundamentalValue value(count);
939 CallClientFunction("DevToolsAPI.deviceCountUpdated", &value, NULL,
940 NULL);
943 void DevToolsUIBindings::DevicesUpdated(
944 const std::string& source,
945 const base::ListValue& targets) {
946 CallClientFunction("DevToolsAPI.devicesUpdated", &targets, NULL,
947 NULL);
950 void DevToolsUIBindings::FileSavedAs(const std::string& url) {
951 base::StringValue url_value(url);
952 CallClientFunction("DevToolsAPI.savedURL", &url_value, NULL, NULL);
955 void DevToolsUIBindings::CanceledFileSaveAs(const std::string& url) {
956 base::StringValue url_value(url);
957 CallClientFunction("DevToolsAPI.canceledSaveURL",
958 &url_value, NULL, NULL);
961 void DevToolsUIBindings::AppendedTo(const std::string& url) {
962 base::StringValue url_value(url);
963 CallClientFunction("DevToolsAPI.appendedToURL", &url_value, NULL,
964 NULL);
967 void DevToolsUIBindings::FileSystemsLoaded(
968 const std::vector<DevToolsFileHelper::FileSystem>& file_systems) {
969 base::ListValue file_systems_value;
970 for (size_t i = 0; i < file_systems.size(); ++i)
971 file_systems_value.Append(CreateFileSystemValue(file_systems[i]));
972 CallClientFunction("DevToolsAPI.fileSystemsLoaded",
973 &file_systems_value, NULL, NULL);
976 void DevToolsUIBindings::FileSystemAdded(
977 const DevToolsFileHelper::FileSystem& file_system) {
978 scoped_ptr<base::StringValue> error_string_value(
979 new base::StringValue(std::string()));
980 scoped_ptr<base::DictionaryValue> file_system_value;
981 if (!file_system.file_system_path.empty())
982 file_system_value.reset(CreateFileSystemValue(file_system));
983 CallClientFunction("DevToolsAPI.fileSystemAdded",
984 error_string_value.get(), file_system_value.get(), NULL);
987 void DevToolsUIBindings::IndexingTotalWorkCalculated(
988 int request_id,
989 const std::string& file_system_path,
990 int total_work) {
991 DCHECK_CURRENTLY_ON(BrowserThread::UI);
992 base::FundamentalValue request_id_value(request_id);
993 base::StringValue file_system_path_value(file_system_path);
994 base::FundamentalValue total_work_value(total_work);
995 CallClientFunction("DevToolsAPI.indexingTotalWorkCalculated",
996 &request_id_value, &file_system_path_value,
997 &total_work_value);
1000 void DevToolsUIBindings::IndexingWorked(int request_id,
1001 const std::string& file_system_path,
1002 int worked) {
1003 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1004 base::FundamentalValue request_id_value(request_id);
1005 base::StringValue file_system_path_value(file_system_path);
1006 base::FundamentalValue worked_value(worked);
1007 CallClientFunction("DevToolsAPI.indexingWorked", &request_id_value,
1008 &file_system_path_value, &worked_value);
1011 void DevToolsUIBindings::IndexingDone(int request_id,
1012 const std::string& file_system_path) {
1013 indexing_jobs_.erase(request_id);
1014 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1015 base::FundamentalValue request_id_value(request_id);
1016 base::StringValue file_system_path_value(file_system_path);
1017 CallClientFunction("DevToolsAPI.indexingDone", &request_id_value,
1018 &file_system_path_value, NULL);
1021 void DevToolsUIBindings::SearchCompleted(
1022 int request_id,
1023 const std::string& file_system_path,
1024 const std::vector<std::string>& file_paths) {
1025 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1026 base::ListValue file_paths_value;
1027 for (std::vector<std::string>::const_iterator it(file_paths.begin());
1028 it != file_paths.end(); ++it) {
1029 file_paths_value.AppendString(*it);
1031 base::FundamentalValue request_id_value(request_id);
1032 base::StringValue file_system_path_value(file_system_path);
1033 CallClientFunction("DevToolsAPI.searchCompleted", &request_id_value,
1034 &file_system_path_value, &file_paths_value);
1037 void DevToolsUIBindings::ShowDevToolsConfirmInfoBar(
1038 const base::string16& message,
1039 const InfoBarCallback& callback) {
1040 DevToolsConfirmInfoBarDelegate::Create(delegate_->GetInfoBarService(),
1041 callback, message);
1044 void DevToolsUIBindings::AddDevToolsExtensionsToClient() {
1045 const extensions::ExtensionRegistry* registry =
1046 extensions::ExtensionRegistry::Get(profile_->GetOriginalProfile());
1047 if (!registry)
1048 return;
1050 base::ListValue results;
1051 for (const scoped_refptr<const extensions::Extension>& extension :
1052 registry->enabled_extensions()) {
1053 if (extensions::chrome_manifest_urls::GetDevToolsPage(extension.get())
1054 .is_empty())
1055 continue;
1056 base::DictionaryValue* extension_info = new base::DictionaryValue();
1057 extension_info->Set(
1058 "startPage",
1059 new base::StringValue(extensions::chrome_manifest_urls::GetDevToolsPage(
1060 extension.get()).spec()));
1061 extension_info->Set("name", new base::StringValue(extension->name()));
1062 extension_info->Set("exposeExperimentalAPIs",
1063 new base::FundamentalValue(
1064 extension->permissions_data()->HasAPIPermission(
1065 extensions::APIPermission::kExperimental)));
1066 results.Append(extension_info);
1068 CallClientFunction("DevToolsAPI.addExtensions",
1069 &results, NULL, NULL);
1072 void DevToolsUIBindings::SetDelegate(Delegate* delegate) {
1073 delegate_.reset(delegate);
1076 void DevToolsUIBindings::AttachTo(
1077 const scoped_refptr<content::DevToolsAgentHost>& agent_host) {
1078 if (agent_host_.get())
1079 Detach();
1080 agent_host_ = agent_host;
1081 agent_host_->AttachClient(this);
1084 void DevToolsUIBindings::Reattach() {
1085 DCHECK(agent_host_.get());
1086 agent_host_->DetachClient();
1087 agent_host_->AttachClient(this);
1090 void DevToolsUIBindings::Detach() {
1091 if (agent_host_.get())
1092 agent_host_->DetachClient();
1093 agent_host_ = NULL;
1096 bool DevToolsUIBindings::IsAttachedTo(content::DevToolsAgentHost* agent_host) {
1097 return agent_host_.get() == agent_host;
1100 content::DevToolsExternalAgentProxyDelegate*
1101 DevToolsUIBindings::CreateWebSocketAPIChannel() {
1102 if (open_api_channel_)
1103 open_api_channel_->ConnectionClosed();
1104 return new WebSocketAPIChannel(weak_factory_.GetWeakPtr());
1107 void DevToolsUIBindings::CallClientFunction(const std::string& function_name,
1108 const base::Value* arg1,
1109 const base::Value* arg2,
1110 const base::Value* arg3) {
1111 std::string javascript = function_name + "(";
1112 if (arg1) {
1113 std::string json;
1114 base::JSONWriter::Write(*arg1, &json);
1115 javascript.append(json);
1116 if (arg2) {
1117 base::JSONWriter::Write(*arg2, &json);
1118 javascript.append(", ").append(json);
1119 if (arg3) {
1120 base::JSONWriter::Write(*arg3, &json);
1121 javascript.append(", ").append(json);
1125 javascript.append(");");
1126 web_contents_->GetMainFrame()->ExecuteJavaScript(
1127 base::UTF8ToUTF16(javascript));
1130 void DevToolsUIBindings::DocumentOnLoadCompletedInMainFrame() {
1131 // In the DEBUG_DEVTOOLS mode, the DocumentOnLoadCompletedInMainFrame event
1132 // arrives before the LoadCompleted event, thus it should not trigger the
1133 // frontend load handling.
1134 #if !defined(DEBUG_DEVTOOLS)
1135 FrontendLoaded();
1136 #endif
1139 void DevToolsUIBindings::DidNavigateMainFrame() {
1140 frontend_loaded_ = false;
1143 void DevToolsUIBindings::FrontendLoaded() {
1144 if (frontend_loaded_)
1145 return;
1146 frontend_loaded_ = true;
1148 // Call delegate first - it seeds importants bit of information.
1149 delegate_->OnLoadCompleted();
1151 AddDevToolsExtensionsToClient();