Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: content/browser/webui/web_ui_url_loader_factory.cc

Issue 2860903006: Handle webuis when using the network service. (Closed)
Patch Set: review comments Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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 "content/browser/webui/web_ui_url_loader_factory.h"
6
7 #include <map>
8
9 #include "base/bind.h"
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "base/memory/ref_counted_memory.h"
13 #include "base/strings/string_piece.h"
14 #include "base/sys_byteorder.h"
15 #include "content/browser/frame_host/frame_tree_node.h"
16 #include "content/browser/frame_host/render_frame_host_impl.h"
17 #include "content/browser/resource_context_impl.h"
18 #include "content/browser/webui/url_data_manager_backend.h"
19 #include "content/browser/webui/url_data_source_impl.h"
20 #include "content/public/browser/browser_context.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/web_contents.h"
24 #include "mojo/public/cpp/bindings/binding_set.h"
25 #include "third_party/zlib/google/compression_utils.h"
26 #include "ui/base/template_expressions.h"
27
28 namespace content {
29
30 namespace {
scottmg 2017/05/05 22:38:10 super nit; \n after opening { to match the blank l
jam 2017/05/05 23:25:07 Done.
31 class WebUIURLLoaderFactory;
32 base::LazyInstance<std::map<int, std::unique_ptr<WebUIURLLoaderFactory>>>::Leaky
33 g_factories = LAZY_INSTANCE_INITIALIZER;
34
35 class URLLoaderImpl : public mojom::URLLoader {
36 public:
37 static void Create(mojom::URLLoaderAssociatedRequest loader,
38 const ResourceRequest& request,
39 int frame_tree_node_id,
40 mojo::InterfacePtrInfo<mojom::URLLoaderClient> client_info,
41 ResourceContext* resource_context) {
42 mojom::URLLoaderClientPtr client;
43 client.Bind(std::move(client_info));
44 new URLLoaderImpl(std::move(loader), request, frame_tree_node_id,
45 std::move(client), resource_context);
46 }
47
48 private:
49 URLLoaderImpl(mojom::URLLoaderAssociatedRequest loader,
50 const ResourceRequest& request,
51 int frame_tree_node_id,
52 mojom::URLLoaderClientPtr client,
53 ResourceContext* resource_context)
54 : binding_(this, std::move(loader)),
55 client_(std::move(client)),
56 replacements_(nullptr),
57 weak_factory_(this) {
58 // NOTE: this duplicates code in URLDataManagerBackend::StartRequest.
59 if (!URLDataManagerBackend::CheckURLIsValid(request.url)) {
60 OnError(net::ERR_INVALID_URL);
61 return;
62 }
63
64 URLDataSourceImpl* source =
65 GetURLDataManagerForResourceContext(resource_context)
66 ->GetDataSourceFromURL(request.url);
67 if (!source) {
68 OnError(net::ERR_INVALID_URL);
69 return;
70 }
71
72 if (!source->source()->ShouldServiceRequest(request.url, resource_context,
73 -1)) {
74 OnError(net::ERR_INVALID_URL);
75 return;
76 }
77
78 std::string path;
79 URLDataManagerBackend::URLToRequestPath(request.url, &path);
80 gzipped_ = source->source()->IsGzipped(path);
81 if (source->source()->GetMimeType(path) == "text/html")
82 replacements_ = source->GetReplacements();
83
84 net::HttpRequestHeaders request_headers;
85 request_headers.AddHeadersFromString(request.headers);
86 std::string origin_header;
87 request_headers.GetHeader(net::HttpRequestHeaders::kOrigin, &origin_header);
88
89 scoped_refptr<net::HttpResponseHeaders> headers =
90 URLDataManagerBackend::GetHeaders(source, path, origin_header);
91
92 ResourceResponseHead head;
93 head.headers = headers;
94 head.mime_type = source->source()->GetMimeType(path);
95 // TODO: fill all the time related field i.e. request_time response_time
96 // request_start response_start
97 client_->OnReceiveResponse(head, base::nullopt, nullptr);
98
99 ResourceRequestInfo::WebContentsGetter wc_getter =
100 base::Bind(WebContents::FromFrameTreeNodeId, frame_tree_node_id);
101
102 // Forward along the request to the data source.
103 // TODO(jam): once we only have this code path for WebUI, and not the
104 // URLLRequestJob one, then we should switch data sources to run on the UI
105 // thread by default.
106 scoped_refptr<base::SingleThreadTaskRunner> target_runner =
107 source->source()->TaskRunnerForRequestPath(path);
108 if (!target_runner) {
109 source->source()->StartDataRequest(
110 path, wc_getter,
111 base::Bind(&URLLoaderImpl::DataAvailable,
112 weak_factory_.GetWeakPtr()));
113 } else {
114 // The DataSource wants StartDataRequest to be called on a specific
115 // thread, usually the UI thread, for this path.
116 target_runner->PostTask(
117 FROM_HERE, base::Bind(&URLLoaderImpl::CallStartDataRequest,
118 base::RetainedRef(source), path, wc_getter,
119 weak_factory_.GetWeakPtr()));
120 }
121 }
122
123 void FollowRedirect() override { NOTREACHED(); }
124 void SetPriority(net::RequestPriority priority,
125 int32_t intra_priority_value) override {
126 NOTREACHED();
127 }
128
129 static void CallStartDataRequest(
130 scoped_refptr<URLDataSourceImpl> source,
131 const std::string& path,
132 const ResourceRequestInfo::WebContentsGetter& wc_getter,
133 const base::WeakPtr<URLLoaderImpl>& weak_ptr) {
134 source->source()->StartDataRequest(
135 path, wc_getter,
136 base::Bind(URLLoaderImpl::DataAvailableOnTargetThread, weak_ptr));
137 }
138
139 static void DataAvailableOnTargetThread(
140 const base::WeakPtr<URLLoaderImpl>& weak_ptr,
141 scoped_refptr<base::RefCountedMemory> bytes) {
142 BrowserThread::PostTask(
143 BrowserThread::IO, FROM_HERE,
144 base::Bind(&URLLoaderImpl::DataAvailable, weak_ptr, bytes));
145 }
146
147 void DataAvailable(scoped_refptr<base::RefCountedMemory> bytes) {
148 if (!bytes) {
149 OnError(net::ERR_FAILED);
150 return;
151 }
152
153 base::StringPiece input(reinterpret_cast<const char*>(bytes->front()),
154 bytes->size());
155 if (replacements_) {
156 std::string temp_string;
157 // We won't know the the final output size ahead of time, so we have to
158 // use an intermediate string.
159 base::StringPiece source;
160 std::string temp_str;
161 if (gzipped_) {
162 temp_str.resize(compression::GetUncompressedSize(input));
163 source.set(temp_str.c_str(), temp_str.size());
164 CHECK(compression::GzipUncompress(input, source));
165 gzipped_ = false;
166 } else {
167 source = input;
168 }
169 temp_str = ui::ReplaceTemplateExpressions(source, *replacements_);
170 bytes = base::RefCountedString::TakeString(&temp_str);
171 input.set(reinterpret_cast<const char*>(bytes->front()), bytes->size());
172 }
173
174 uint32_t output_size =
175 gzipped_ ? compression::GetUncompressedSize(input) : bytes->size();
176
177 MojoCreateDataPipeOptions options;
178 options.struct_size = sizeof(MojoCreateDataPipeOptions);
179 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
180 options.element_num_bytes = 1;
181 options.capacity_num_bytes = output_size;
182 mojo::DataPipe data_pipe(options);
183
184 DCHECK(data_pipe.producer_handle.is_valid());
185 DCHECK(data_pipe.consumer_handle.is_valid());
186
187 void* buffer = nullptr;
188 uint32_t num_bytes = output_size;
189 MojoResult result =
190 BeginWriteDataRaw(data_pipe.producer_handle.get(), &buffer, &num_bytes,
191 MOJO_WRITE_DATA_FLAG_NONE);
192 CHECK_EQ(result, MOJO_RESULT_OK);
193 CHECK_EQ(num_bytes, output_size);
194
195 if (gzipped_) {
196 base::StringPiece output(static_cast<char*>(buffer), num_bytes);
197 CHECK(compression::GzipUncompress(input, output));
198 } else {
199 memcpy(buffer, bytes->front(), output_size);
200 }
201 result = EndWriteDataRaw(data_pipe.producer_handle.get(), num_bytes);
202 CHECK_EQ(result, MOJO_RESULT_OK);
203
204 client_->OnStartLoadingResponseBody(std::move(data_pipe.consumer_handle));
205
206 ResourceRequestCompletionStatus request_complete_data;
207 request_complete_data.error_code = net::OK;
208 request_complete_data.exists_in_cache = false;
209 request_complete_data.completion_time = base::TimeTicks::Now();
210 request_complete_data.encoded_data_length = output_size;
211 request_complete_data.encoded_body_length = output_size;
212 client_->OnComplete(request_complete_data);
213 delete this;
214 }
215
216 void OnError(int error_code) {
217 ResourceRequestCompletionStatus status;
218 status.error_code = error_code;
219 client_->OnComplete(status);
220 delete this;
221 }
222
223 mojo::AssociatedBinding<mojom::URLLoader> binding_;
224 mojom::URLLoaderClientPtr client_;
225 bool gzipped_;
226 // Replacement dictionary for i18n.
227 const ui::TemplateReplacements* replacements_;
228 base::WeakPtrFactory<URLLoaderImpl> weak_factory_;
229
230 DISALLOW_COPY_AND_ASSIGN(URLLoaderImpl);
231 };
232
233 class WebUIURLLoaderFactory : public mojom::URLLoaderFactory,
234 public FrameTreeNode::Observer {
235 public:
236 WebUIURLLoaderFactory(FrameTreeNode* ftn)
237 : frame_tree_node_id_(ftn->frame_tree_node_id()),
238 resource_context_(ftn->current_frame_host()
239 ->GetProcess()
240 ->GetBrowserContext()
241 ->GetResourceContext()) {
242 ftn->AddObserver(this);
243 }
244
245 ~WebUIURLLoaderFactory() override {}
246
247 mojom::URLLoaderFactoryPtr CreateBinding() {
248 return loader_factory_bindings_.CreateInterfacePtrAndBind(this);
249 }
250
251 // mojom::URLLoaderFactory implementation:
252 void CreateLoaderAndStart(mojom::URLLoaderAssociatedRequest loader,
253 int32_t routing_id,
254 int32_t request_id,
255 uint32_t options,
256 const ResourceRequest& request,
257 mojom::URLLoaderClientPtr client) override {
258 DCHECK_CURRENTLY_ON(BrowserThread::UI);
259 BrowserThread::PostTask(
260 BrowserThread::IO, FROM_HERE,
261 base::BindOnce(&URLLoaderImpl::Create, std::move(loader), request,
262 frame_tree_node_id_, client.PassInterface(),
263 resource_context_));
264 }
265
266 void SyncLoad(int32_t routing_id,
267 int32_t request_id,
268 const ResourceRequest& request,
269 SyncLoadCallback callback) override {
270 NOTREACHED();
271 }
272
273 // FrameTreeNode::Observer implementation:
274 void OnFrameTreeNodeDestroyed(FrameTreeNode* node) override {
275 g_factories.Get().erase(frame_tree_node_id_);
276 }
277
278 private:
279 int frame_tree_node_id_;
280 ResourceContext* resource_context_;
281 mojo::BindingSet<mojom::URLLoaderFactory> loader_factory_bindings_;
282
283 DISALLOW_COPY_AND_ASSIGN(WebUIURLLoaderFactory);
284 };
285
286 } // namespace
287
288 mojom::URLLoaderFactoryPtr GetWebUIURLLoader(FrameTreeNode* node) {
289 int ftn_id = node->frame_tree_node_id();
290 if (g_factories.Get()[ftn_id].get() == nullptr)
291 g_factories.Get()[ftn_id] = base::MakeUnique<WebUIURLLoaderFactory>(node);
292 return g_factories.Get()[ftn_id]->CreateBinding();
293 }
294
295 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698