1 // Copyright 2020 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 "chromecast/browser/webui/cast_resource_data_source.h"
6 
7 #include "base/bind.h"
8 #include "base/files/file_path.h"
9 #include "base/memory/ref_counted_memory.h"
10 #include "chromecast/base/cast_constants.h"
11 #include "net/base/mime_util.h"
12 #include "net/url_request/url_request.h"
13 #include "services/network/public/mojom/content_security_policy.mojom.h"
14 
15 namespace chromecast {
16 
17 namespace {
18 
GotData(base::OnceCallback<void (scoped_refptr<base::RefCountedMemory>)> cb,scoped_refptr<base::RefCountedMemory> memory)19 void GotData(base::OnceCallback<void(scoped_refptr<base::RefCountedMemory>)> cb,
20              scoped_refptr<base::RefCountedMemory> memory) {
21   std::move(cb).Run(std::move(memory));
22 }
23 
24 }  // namespace
25 
CastResourceDataSource(const std::string & host,bool for_webui)26 CastResourceDataSource::CastResourceDataSource(const std::string& host,
27                                                bool for_webui)
28     : host_(host), for_webui_(for_webui) {}
29 
30 CastResourceDataSource::~CastResourceDataSource() = default;
31 
GetSource()32 std::string CastResourceDataSource::GetSource() {
33   return host_;
34 }
35 
StartDataRequest(const GURL & url,const content::WebContents::Getter & wc_getter,content::URLDataSource::GotDataCallback callback)36 void CastResourceDataSource::StartDataRequest(
37     const GURL& url,
38     const content::WebContents::Getter& wc_getter,
39     content::URLDataSource::GotDataCallback callback) {
40   std::string path = content::URLDataSource::URLToRequestPath(url);
41   remote_->RequestResourceBytes(path,
42                                 base::BindOnce(&GotData, std::move(callback)));
43 }
44 
GetMimeType(const std::string & path)45 std::string CastResourceDataSource::GetMimeType(const std::string& path) {
46   if (!for_webui_) {
47     std::string mime_type;
48     base::FilePath::StringType file_ext =
49         base::FilePath().AppendASCII(path).Extension();
50     // net::GetMimeTypeFromFile() will crash at base::nix::GetFileMimeType()
51     // because IO is not allowed.
52     if (!file_ext.empty())
53       net::GetWellKnownMimeTypeFromExtension(file_ext.substr(1), &mime_type);
54     return mime_type;
55   }
56 
57   // Remove the query string for to determine the mime type.
58   std::string file_path = path.substr(0, path.find_first_of('?'));
59 
60   if (base::EndsWith(file_path, ".css", base::CompareCase::INSENSITIVE_ASCII))
61     return "text/css";
62 
63   if (base::EndsWith(file_path, ".js", base::CompareCase::INSENSITIVE_ASCII))
64     return "application/javascript";
65 
66   if (base::EndsWith(file_path, ".json", base::CompareCase::INSENSITIVE_ASCII))
67     return "application/json";
68 
69   if (base::EndsWith(file_path, ".pdf", base::CompareCase::INSENSITIVE_ASCII))
70     return "application/pdf";
71 
72   if (base::EndsWith(file_path, ".svg", base::CompareCase::INSENSITIVE_ASCII))
73     return "image/svg+xml";
74 
75   if (base::EndsWith(file_path, ".jpg", base::CompareCase::INSENSITIVE_ASCII))
76     return "image/jpeg";
77 
78   if (base::EndsWith(file_path, ".png", base::CompareCase::INSENSITIVE_ASCII))
79     return "image/png";
80 
81   return "text/html";
82 }
83 
ShouldServiceRequest(const GURL & url,content::BrowserContext * browser_context,int render_process_id)84 bool CastResourceDataSource::ShouldServiceRequest(
85     const GURL& url,
86     content::BrowserContext* browser_context,
87     int render_process_id) {
88   if (url.SchemeIs(kChromeResourceScheme))
89     return true;
90   return URLDataSource::ShouldServiceRequest(url, browser_context,
91                                              render_process_id);
92 }
93 
GetAccessControlAllowOriginForOrigin(const std::string & origin)94 std::string CastResourceDataSource::GetAccessControlAllowOriginForOrigin(
95     const std::string& origin) {
96   // For now we give access for all "chrome://*" origins.
97   std::string allowed_origin_prefix = "chrome://";
98   if (!base::StartsWith(origin, allowed_origin_prefix,
99                         base::CompareCase::SENSITIVE)) {
100     return "";
101   }
102   return origin;
103 }
104 
105 mojo::PendingReceiver<mojom::Resources>
BindNewPipeAndPassReceiver()106 CastResourceDataSource::BindNewPipeAndPassReceiver() {
107   return remote_.BindNewPipeAndPassReceiver();
108 }
109 
OverrideContentSecurityPolicyChildSrc(const std::string & data)110 void CastResourceDataSource::OverrideContentSecurityPolicyChildSrc(
111     const std::string& data) {
112   frame_src_ = data;
113 }
114 
DisableDenyXFrameOptions()115 void CastResourceDataSource::DisableDenyXFrameOptions() {
116   deny_xframe_options_ = false;
117 }
118 
GetContentSecurityPolicy(network::mojom::CSPDirectiveName directive)119 std::string CastResourceDataSource::GetContentSecurityPolicy(
120     network::mojom::CSPDirectiveName directive) {
121   if (directive == network::mojom::CSPDirectiveName::ChildSrc && frame_src_) {
122     return *frame_src_;
123   }
124   return URLDataSource::GetContentSecurityPolicy(directive);
125 }
126 
ShouldDenyXFrameOptions()127 bool CastResourceDataSource::ShouldDenyXFrameOptions() {
128   return deny_xframe_options_;
129 }
130 
131 }  // namespace chromecast
132