1 // Copyright 2018 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 #include "chrome/browser/devtools/protocol/target_handler.h"
6 
7 #include "chrome/browser/devtools/chrome_devtools_manager_delegate.h"
8 #include "chrome/browser/devtools/devtools_browser_context_manager.h"
9 #include "chrome/browser/profiles/profile_manager.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/browser/ui/browser_list.h"
12 #include "chrome/browser/ui/browser_navigator.h"
13 #include "content/public/browser/devtools_agent_host.h"
14 
15 namespace {
CreateNavigateParams(Profile * profile,const GURL & url,ui::PageTransition transition,bool new_window,bool background,Browser * browser)16 NavigateParams CreateNavigateParams(Profile* profile,
17                                     const GURL& url,
18                                     ui::PageTransition transition,
19                                     bool new_window,
20                                     bool background,
21                                     Browser* browser) {
22   DCHECK(new_window || browser);
23   NavigateParams params(profile, url, transition);
24   if (new_window) {
25     params.disposition = WindowOpenDisposition::NEW_WINDOW;
26     if (background)
27       params.window_action = NavigateParams::WindowAction::SHOW_WINDOW_INACTIVE;
28   } else {
29     params.disposition = (background)
30                              ? WindowOpenDisposition::NEW_BACKGROUND_TAB
31                              : WindowOpenDisposition::NEW_FOREGROUND_TAB;
32     params.browser = browser;
33   }
34   return params;
35 }
36 }  // namespace
37 
TargetHandler(protocol::UberDispatcher * dispatcher)38 TargetHandler::TargetHandler(protocol::UberDispatcher* dispatcher) {
39   protocol::Target::Dispatcher::wire(dispatcher, this);
40 }
41 
~TargetHandler()42 TargetHandler::~TargetHandler() {
43   ChromeDevToolsManagerDelegate* delegate =
44       ChromeDevToolsManagerDelegate::GetInstance();
45   if (delegate)
46     delegate->UpdateDeviceDiscovery();
47 }
48 
SetRemoteLocations(std::unique_ptr<protocol::Array<protocol::Target::RemoteLocation>> locations)49 protocol::Response TargetHandler::SetRemoteLocations(
50     std::unique_ptr<protocol::Array<protocol::Target::RemoteLocation>>
51         locations) {
52   remote_locations_.clear();
53   if (!locations)
54     return protocol::Response::Success();
55 
56   for (const auto& location : *locations) {
57     remote_locations_.insert(
58         net::HostPortPair(location->GetHost(), location->GetPort()));
59   }
60 
61   ChromeDevToolsManagerDelegate* delegate =
62       ChromeDevToolsManagerDelegate::GetInstance();
63   if (delegate)
64     delegate->UpdateDeviceDiscovery();
65   return protocol::Response::Success();
66 }
67 
CreateTarget(const std::string & url,protocol::Maybe<int> width,protocol::Maybe<int> height,protocol::Maybe<std::string> browser_context_id,protocol::Maybe<bool> enable_begin_frame_control,protocol::Maybe<bool> new_window,protocol::Maybe<bool> background,std::string * out_target_id)68 protocol::Response TargetHandler::CreateTarget(
69     const std::string& url,
70     protocol::Maybe<int> width,
71     protocol::Maybe<int> height,
72     protocol::Maybe<std::string> browser_context_id,
73     protocol::Maybe<bool> enable_begin_frame_control,
74     protocol::Maybe<bool> new_window,
75     protocol::Maybe<bool> background,
76     std::string* out_target_id) {
77   Profile* profile = ProfileManager::GetActiveUserProfile();
78   if (browser_context_id.isJust()) {
79     std::string profile_id = browser_context_id.fromJust();
80     profile =
81         DevToolsBrowserContextManager::GetInstance().GetProfileById(profile_id);
82     if (!profile) {
83       return protocol::Response::ServerError(
84           "Failed to find browser context with id " + profile_id);
85     }
86   }
87   bool create_new_window = new_window.fromMaybe(false);
88   bool create_in_background = background.fromMaybe(false);
89   Browser* target_browser = nullptr;
90 
91   // Must find target_browser if new_window not explicitly true.
92   if (!create_new_window) {
93     // Find a browser to open a new tab.
94     // We shouldn't use browser that is scheduled to close.
95     for (auto* browser : *BrowserList::GetInstance()) {
96       if (browser->profile() == profile &&
97           !browser->IsAttemptingToCloseBrowser()) {
98         target_browser = browser;
99         break;
100       }
101     }
102   }
103 
104   bool explicit_old_window = !new_window.fromMaybe(true);
105   if (explicit_old_window && !target_browser) {
106     return protocol::Response::ServerError(
107         "Failed to open new tab - "
108         "no browser is open");
109   }
110 
111   create_new_window = !target_browser;
112   NavigateParams params = CreateNavigateParams(
113       profile, GURL(url), ui::PAGE_TRANSITION_AUTO_TOPLEVEL, create_new_window,
114       create_in_background, target_browser);
115   Navigate(&params);
116   if (!params.navigated_or_inserted_contents)
117     return protocol::Response::ServerError("Failed to open a new tab");
118 
119   *out_target_id = content::DevToolsAgentHost::GetOrCreateFor(
120                        params.navigated_or_inserted_contents)
121                        ->GetId();
122   return protocol::Response::Success();
123 }
124