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

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

Powered by Google App Engine
This is Rietveld 408576698