Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / ui / webui / devtools_ui.cc
blob6daac95ffdc0e2e9b9fec335cf004bec558537f7
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/webui/devtools_ui.h"
7 #include "base/memory/ref_counted_memory.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/stringprintf.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/common/url_constants.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/devtools_http_handler.h"
14 #include "content/public/browser/url_data_source.h"
15 #include "content/public/browser/web_contents.h"
16 #include "content/public/browser/web_ui.h"
17 #include "content/public/common/user_agent.h"
18 #include "net/url_request/url_fetcher.h"
19 #include "net/url_request/url_fetcher_delegate.h"
20 #include "net/url_request/url_request_context_getter.h"
21 #include "ui/base/resource/resource_bundle.h"
23 using content::BrowserThread;
24 using content::WebContents;
26 namespace {
28 std::string PathWithoutParams(const std::string& path) {
29 return GURL(std::string("chrome-devtools://devtools/") + path)
30 .path().substr(1);
33 const char kRemoteFrontendDomain[] = "chrome-devtools-frontend.appspot.com";
34 const char kRemoteFrontendBase[] =
35 "https://chrome-devtools-frontend.appspot.com/";
36 const char kRemoteFrontendPath[] = "serve_file";
37 const char kHttpNotFound[] = "HTTP/1.1 404 Not Found\n\n";
39 #if defined(DEBUG_DEVTOOLS)
40 // Local frontend url provided by InspectUI.
41 const char kFallbackFrontendURL[] =
42 "chrome-devtools://devtools/bundled/inspector.html";
43 #else
44 // URL causing the DevTools window to display a plain text warning.
45 const char kFallbackFrontendURL[] =
46 "data:text/plain,Cannot load DevTools frontend from an untrusted origin";
47 #endif // defined(DEBUG_DEVTOOLS)
49 // DevToolsDataSource ---------------------------------------------------------
51 std::string GetMimeTypeForPath(const std::string& path) {
52 std::string filename = PathWithoutParams(path);
53 if (EndsWith(filename, ".html", false)) {
54 return "text/html";
55 } else if (EndsWith(filename, ".css", false)) {
56 return "text/css";
57 } else if (EndsWith(filename, ".js", false)) {
58 return "application/javascript";
59 } else if (EndsWith(filename, ".png", false)) {
60 return "image/png";
61 } else if (EndsWith(filename, ".gif", false)) {
62 return "image/gif";
63 } else if (EndsWith(filename, ".svg", false)) {
64 return "image/svg+xml";
65 } else if (EndsWith(filename, ".manifest", false)) {
66 return "text/cache-manifest";
68 return "text/html";
71 // An URLDataSource implementation that handles chrome-devtools://devtools/
72 // requests. Three types of requests could be handled based on the URL path:
73 // 1. /bundled/: bundled DevTools frontend is served.
74 // 2. /remote/: remote DevTools frontend is served from App Engine.
75 class DevToolsDataSource : public content::URLDataSource,
76 public net::URLFetcherDelegate {
77 public:
78 using GotDataCallback = content::URLDataSource::GotDataCallback;
80 explicit DevToolsDataSource(net::URLRequestContextGetter* request_context);
82 // content::URLDataSource implementation.
83 std::string GetSource() const override;
85 void StartDataRequest(const std::string& path,
86 int render_process_id,
87 int render_frame_id,
88 const GotDataCallback& callback) override;
90 private:
91 // content::URLDataSource overrides.
92 std::string GetMimeType(const std::string& path) const override;
93 bool ShouldAddContentSecurityPolicy() const override;
94 bool ShouldDenyXFrameOptions() const override;
95 bool ShouldServeMimeTypeAsContentTypeHeader() const override;
97 // net::URLFetcherDelegate overrides.
98 void OnURLFetchComplete(const net::URLFetcher* source) override;
100 // Serves bundled DevTools frontend from ResourceBundle.
101 void StartBundledDataRequest(const std::string& path,
102 int render_process_id,
103 int render_frame_id,
104 const GotDataCallback& callback);
106 // Serves remote DevTools frontend from hard-coded App Engine domain.
107 void StartRemoteDataRequest(const std::string& path,
108 int render_process_id,
109 int render_frame_id,
110 const GotDataCallback& callback);
112 ~DevToolsDataSource() override;
114 scoped_refptr<net::URLRequestContextGetter> request_context_;
116 using PendingRequestsMap = std::map<const net::URLFetcher*, GotDataCallback>;
117 PendingRequestsMap pending_;
119 DISALLOW_COPY_AND_ASSIGN(DevToolsDataSource);
122 DevToolsDataSource::DevToolsDataSource(
123 net::URLRequestContextGetter* request_context)
124 : request_context_(request_context) {
127 DevToolsDataSource::~DevToolsDataSource() {
128 for (const auto& pair : pending_) {
129 delete pair.first;
130 pair.second.Run(
131 new base::RefCountedStaticMemory(kHttpNotFound, strlen(kHttpNotFound)));
135 std::string DevToolsDataSource::GetSource() const {
136 return chrome::kChromeUIDevToolsHost;
139 void DevToolsDataSource::StartDataRequest(
140 const std::string& path,
141 int render_process_id,
142 int render_frame_id,
143 const content::URLDataSource::GotDataCallback& callback) {
144 // Serve request from local bundle.
145 std::string bundled_path_prefix(chrome::kChromeUIDevToolsBundledPath);
146 bundled_path_prefix += "/";
147 if (StartsWithASCII(path, bundled_path_prefix, false)) {
148 StartBundledDataRequest(path.substr(bundled_path_prefix.length()),
149 render_process_id, render_frame_id, callback);
150 return;
153 // Serve request from remote location.
154 std::string remote_path_prefix(chrome::kChromeUIDevToolsRemotePath);
155 remote_path_prefix += "/";
156 if (StartsWithASCII(path, remote_path_prefix, false)) {
157 StartRemoteDataRequest(path.substr(remote_path_prefix.length()),
158 render_process_id, render_frame_id, callback);
159 return;
162 callback.Run(NULL);
165 std::string DevToolsDataSource::GetMimeType(const std::string& path) const {
166 return GetMimeTypeForPath(path);
169 bool DevToolsDataSource::ShouldAddContentSecurityPolicy() const {
170 return false;
173 bool DevToolsDataSource::ShouldDenyXFrameOptions() const {
174 return false;
177 bool DevToolsDataSource::ShouldServeMimeTypeAsContentTypeHeader() const {
178 return true;
181 void DevToolsDataSource::StartBundledDataRequest(
182 const std::string& path,
183 int render_process_id,
184 int render_frame_id,
185 const content::URLDataSource::GotDataCallback& callback) {
186 std::string filename = PathWithoutParams(path);
188 int resource_id =
189 content::DevToolsHttpHandler::GetFrontendResourceId(filename);
191 DLOG_IF(WARNING, resource_id == -1)
192 << "Unable to find dev tool resource: " << filename
193 << ". If you compiled with debug_devtools=1, try running with "
194 "--debug-devtools.";
195 const ResourceBundle& rb = ResourceBundle::GetSharedInstance();
196 scoped_refptr<base::RefCountedStaticMemory> bytes(rb.LoadDataResourceBytes(
197 resource_id));
198 callback.Run(bytes.get());
201 void DevToolsDataSource::StartRemoteDataRequest(
202 const std::string& path,
203 int render_process_id,
204 int render_frame_id,
205 const content::URLDataSource::GotDataCallback& callback) {
206 GURL url = GURL(kRemoteFrontendBase + path);
207 CHECK_EQ(url.host(), kRemoteFrontendDomain);
208 if (!url.is_valid()) {
209 callback.Run(
210 new base::RefCountedStaticMemory(kHttpNotFound, strlen(kHttpNotFound)));
211 return;
213 net::URLFetcher* fetcher =
214 net::URLFetcher::Create(url, net::URLFetcher::GET, this);
215 pending_[fetcher] = callback;
216 fetcher->SetRequestContext(request_context_.get());
217 fetcher->Start();
220 void DevToolsDataSource::OnURLFetchComplete(const net::URLFetcher* source) {
221 DCHECK(source);
222 PendingRequestsMap::iterator it = pending_.find(source);
223 DCHECK(it != pending_.end());
224 std::string response;
225 source->GetResponseAsString(&response);
226 delete source;
227 it->second.Run(base::RefCountedString::TakeString(&response));
228 pending_.erase(it);
231 } // namespace
233 // DevToolsUI -----------------------------------------------------------------
235 // static
236 GURL DevToolsUI::GetProxyURL(const std::string& frontend_url) {
237 GURL url(frontend_url);
238 if (!url.is_valid() || url.host() != kRemoteFrontendDomain)
239 return GURL(kFallbackFrontendURL);
240 return GURL(base::StringPrintf("%s://%s/%s/%s",
241 content::kChromeDevToolsScheme,
242 chrome::kChromeUIDevToolsHost,
243 chrome::kChromeUIDevToolsRemotePath,
244 url.path().substr(1).c_str()));
247 // static
248 GURL DevToolsUI::GetRemoteBaseURL() {
249 return GURL(base::StringPrintf(
250 "%s%s/%s/",
251 kRemoteFrontendBase,
252 kRemoteFrontendPath,
253 content::GetWebKitRevision().c_str()));
256 DevToolsUI::DevToolsUI(content::WebUI* web_ui)
257 : WebUIController(web_ui),
258 bindings_(web_ui->GetWebContents()) {
259 web_ui->SetBindings(0);
260 Profile* profile = Profile::FromWebUI(web_ui);
261 content::URLDataSource::Add(
262 profile,
263 new DevToolsDataSource(profile->GetRequestContext()));
266 DevToolsUI::~DevToolsUI() {