1f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Use of this source code is governed by a BSD-style license that can be 3f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// found in the LICENSE file. 4f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 5f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/test/chromedriver/chrome/devtools_http_client.h" 6f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 7f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/bind.h" 8f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/bind_helpers.h" 9f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/json/json_reader.h" 10f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/strings/stringprintf.h" 11f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/threading/platform_thread.h" 12f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/time/time.h" 13f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/values.h" 14f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/test/chromedriver/chrome/device_metrics.h" 15f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/test/chromedriver/chrome/devtools_client_impl.h" 16f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/test/chromedriver/chrome/log.h" 17f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/test/chromedriver/chrome/status.h" 18f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/test/chromedriver/chrome/web_view_impl.h" 19f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/test/chromedriver/net/net_util.h" 20f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/test/chromedriver/net/url_request_context_getter.h" 21f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 22f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgWebViewInfo::WebViewInfo(const std::string& id, 23f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const std::string& debugger_url, 24f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const std::string& url, 25f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org Type type) 26f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org : id(id), debugger_url(debugger_url), url(url), type(type) {} 27f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 28f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgWebViewInfo::~WebViewInfo() {} 29f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 30f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgbool WebViewInfo::IsFrontend() const { 31f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return url.find("chrome-devtools://") == 0u; 32f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 33f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 34f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgWebViewsInfo::WebViewsInfo() {} 35f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 36f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgWebViewsInfo::WebViewsInfo(const std::vector<WebViewInfo>& info) 37f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org : views_info(info) {} 38f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 39f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgWebViewsInfo::~WebViewsInfo() {} 40f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 41f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgconst WebViewInfo& WebViewsInfo::Get(int index) const { 42f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return views_info[index]; 43f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 44f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 45f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgsize_t WebViewsInfo::GetSize() const { 46f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return views_info.size(); 47f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 48f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 49f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgconst WebViewInfo* WebViewsInfo::GetForId(const std::string& id) const { 50f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for (size_t i = 0; i < views_info.size(); ++i) { 51f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (views_info[i].id == id) 52f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return &views_info[i]; 53f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 54f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return NULL; 55f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 56f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 57f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgDevToolsHttpClient::DevToolsHttpClient( 58f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const NetAddress& address, 59f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org scoped_refptr<URLRequestContextGetter> context_getter, 60f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const SyncWebSocketFactory& socket_factory, 61f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org scoped_ptr<DeviceMetrics> device_metrics) 62f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org : context_getter_(context_getter), 63f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org socket_factory_(socket_factory), 64f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org server_url_("http://" + address.ToString()), 65f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org web_socket_url_prefix_(base::StringPrintf( 66f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org "ws://%s/devtools/page/", address.ToString().c_str())), 67f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org device_metrics_(device_metrics.Pass()) {} 68f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 69f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgDevToolsHttpClient::~DevToolsHttpClient() {} 70f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 71f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgStatus DevToolsHttpClient::Init(const base::TimeDelta& timeout) { 72f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org base::TimeTicks deadline = base::TimeTicks::Now() + timeout; 73f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org std::string version_url = server_url_ + "/json/version"; 74f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org std::string data; 75f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 76f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org while (!FetchUrlAndLog(version_url, context_getter_.get(), &data) 77f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org || data.empty()) { 78f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (base::TimeTicks::Now() > deadline) 79f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kChromeNotReachable); 80f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50)); 81f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 82f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 83f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return ParseBrowserInfo(data, &browser_info_); 84f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 85f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 86f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgStatus DevToolsHttpClient::GetWebViewsInfo(WebViewsInfo* views_info) { 87f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org std::string data; 88f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!FetchUrlAndLog(server_url_ + "/json", context_getter_.get(), &data)) 89f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kChromeNotReachable); 90f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 91f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return internal::ParseWebViewsInfo(data, views_info); 92f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 93f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 94f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgscoped_ptr<DevToolsClient> DevToolsHttpClient::CreateClient( 95f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const std::string& id) { 96f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return scoped_ptr<DevToolsClient>(new DevToolsClientImpl( 97f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org socket_factory_, 98f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org web_socket_url_prefix_ + id, 99f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org id, 100f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org base::Bind( 101f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org &DevToolsHttpClient::CloseFrontends, base::Unretained(this), id))); 102f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 103f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 104f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgStatus DevToolsHttpClient::CloseWebView(const std::string& id) { 105f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org std::string data; 106f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!FetchUrlAndLog( 107f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org server_url_ + "/json/close/" + id, context_getter_.get(), &data)) { 108f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kOk); // Closing the last web view leads chrome to quit. 109f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 110f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 111f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // Wait for the target window to be completely closed. 112f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org base::TimeTicks deadline = 113f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org base::TimeTicks::Now() + base::TimeDelta::FromSeconds(20); 114f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org while (base::TimeTicks::Now() < deadline) { 115f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org WebViewsInfo views_info; 116f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org Status status = GetWebViewsInfo(&views_info); 117f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (status.code() == kChromeNotReachable) 118f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kOk); 119f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (status.IsError()) 120f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return status; 121f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!views_info.GetForId(id)) 122f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kOk); 123f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50)); 124f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 125f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kUnknownError, "failed to close window in 20 seconds"); 126f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 127f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 128f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgStatus DevToolsHttpClient::ActivateWebView(const std::string& id) { 129f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org std::string data; 130f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!FetchUrlAndLog( 131f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org server_url_ + "/json/activate/" + id, context_getter_.get(), &data)) 132f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kUnknownError, "cannot activate web view"); 133f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kOk); 134f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 135f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 136f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgconst BrowserInfo* DevToolsHttpClient::browser_info() { 137f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return &browser_info_; 138f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 139f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 140f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgconst DeviceMetrics* DevToolsHttpClient::device_metrics() { 141f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return device_metrics_.get(); 142f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 143f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 144f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgStatus DevToolsHttpClient::CloseFrontends(const std::string& for_client_id) { 145f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org WebViewsInfo views_info; 146f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org Status status = GetWebViewsInfo(&views_info); 147f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (status.IsError()) 148f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return status; 149f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 150f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // Close frontends. Usually frontends are docked in the same page, although 151f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // some may be in tabs (undocked, chrome://inspect, the DevTools 152f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // discovery page, etc.). Tabs can be closed via the DevTools HTTP close 153f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // URL, but docked frontends can only be closed, by design, by connecting 154f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // to them and clicking the close button. Close the tab frontends first 155f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // in case one of them is debugging a docked frontend, which would prevent 156f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // the code from being able to connect to the docked one. 157f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org std::list<std::string> tab_frontend_ids; 158f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org std::list<std::string> docked_frontend_ids; 159f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for (size_t i = 0; i < views_info.GetSize(); ++i) { 160f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const WebViewInfo& view_info = views_info.Get(i); 161f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (view_info.IsFrontend()) { 162f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (view_info.type == WebViewInfo::kPage) 163f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org tab_frontend_ids.push_back(view_info.id); 164f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org else if (view_info.type == WebViewInfo::kOther) 165f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org docked_frontend_ids.push_back(view_info.id); 166f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org else 167f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kUnknownError, "unknown type of DevTools frontend"); 168f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 169f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 170f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 171f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for (std::list<std::string>::const_iterator it = tab_frontend_ids.begin(); 172f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org it != tab_frontend_ids.end(); ++it) { 173f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org status = CloseWebView(*it); 174f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (status.IsError()) 175f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return status; 176f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 177f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 178f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for (std::list<std::string>::const_iterator it = docked_frontend_ids.begin(); 179f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org it != docked_frontend_ids.end(); ++it) { 180f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org scoped_ptr<DevToolsClient> client(new DevToolsClientImpl( 181f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org socket_factory_, 182f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org web_socket_url_prefix_ + *it, 183f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *it)); 184f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org scoped_ptr<WebViewImpl> web_view( 185f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org new WebViewImpl(*it, &browser_info_, client.Pass(), NULL)); 186f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 187f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org status = web_view->ConnectIfNecessary(); 188f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // Ignore disconnected error, because the debugger might have closed when 189f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // its container page was closed above. 190f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (status.IsError() && status.code() != kDisconnected) 191f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return status; 192f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 193f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org scoped_ptr<base::Value> result; 194f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org status = web_view->EvaluateScript( 195f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org std::string(), 196f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org "document.querySelector('*[id^=\"close-button-\"]').click();", 197f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org &result); 198f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // Ignore disconnected error, because it may be closed already. 199f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (status.IsError() && status.code() != kDisconnected) 200f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return status; 201f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 202f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 203f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // Wait until DevTools UI disconnects from the given web view. 204f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org base::TimeTicks deadline = 205f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org base::TimeTicks::Now() + base::TimeDelta::FromSeconds(20); 206f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org while (base::TimeTicks::Now() < deadline) { 207f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org status = GetWebViewsInfo(&views_info); 208f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (status.IsError()) 209f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return status; 210f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 211f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const WebViewInfo* view_info = views_info.GetForId(for_client_id); 212f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!view_info) 213f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kNoSuchWindow, "window was already closed"); 214f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (view_info->debugger_url.size()) 215f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kOk); 216f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 217f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50)); 218f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 219f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kUnknownError, "failed to close UI debuggers"); 220f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 221f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 222f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgbool DevToolsHttpClient::FetchUrlAndLog(const std::string& url, 223f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org URLRequestContextGetter* getter, 224f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org std::string* response) { 225f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org VLOG(1) << "DevTools request: " << url; 226f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org bool ok = FetchUrl(url, getter, response); 227f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (ok) { 228f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org VLOG(1) << "DevTools response: " << *response; 229f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } else { 230f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org VLOG(1) << "DevTools request failed"; 231f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 232f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return ok; 233f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 234f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 235f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnamespace internal { 236f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 237f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgStatus ParseWebViewsInfo(const std::string& data, 238f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org WebViewsInfo* views_info) { 239f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org scoped_ptr<base::Value> value(base::JSONReader::Read(data)); 240f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!value.get()) 241f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kUnknownError, "DevTools returned invalid JSON"); 242f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org base::ListValue* list; 243f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!value->GetAsList(&list)) 244f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kUnknownError, "DevTools did not return list"); 245f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 246f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org std::vector<WebViewInfo> temp_views_info; 247f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for (size_t i = 0; i < list->GetSize(); ++i) { 248f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org base::DictionaryValue* info; 249f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!list->GetDictionary(i, &info)) 250f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kUnknownError, "DevTools contains non-dictionary item"); 251f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org std::string id; 252f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!info->GetString("id", &id)) 253f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kUnknownError, "DevTools did not include id"); 254f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org std::string type_as_string; 255f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!info->GetString("type", &type_as_string)) 256f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kUnknownError, "DevTools did not include type"); 257f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org std::string url; 258f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!info->GetString("url", &url)) 259f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return Status(kUnknownError, "DevTools did not include url"); 260 std::string debugger_url; 261 info->GetString("webSocketDebuggerUrl", &debugger_url); 262 WebViewInfo::Type type; 263 if (type_as_string == "app") 264 type = WebViewInfo::kApp; 265 else if (type_as_string == "background_page") 266 type = WebViewInfo::kBackgroundPage; 267 else if (type_as_string == "page") 268 type = WebViewInfo::kPage; 269 else if (type_as_string == "worker") 270 type = WebViewInfo::kWorker; 271 else if (type_as_string == "other") 272 type = WebViewInfo::kOther; 273 else 274 return Status(kUnknownError, 275 "DevTools returned unknown type:" + type_as_string); 276 temp_views_info.push_back(WebViewInfo(id, debugger_url, url, type)); 277 } 278 *views_info = WebViewsInfo(temp_views_info); 279 return Status(kOk); 280} 281 282} // namespace internal 283