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

Side by Side Diff: content/browser/loader/navigation_resource_handler.cc

Issue 2797443005: PlzNavigate data pipe
Patch Set: cleanup Created 3 years, 8 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
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/loader/navigation_resource_handler.h" 5 #include "content/browser/loader/navigation_resource_handler.h"
6 6
7 #include <memory> 7 #include <memory>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "content/browser/loader/navigation_url_loader_impl_core.h" 11 #include "content/browser/loader/navigation_url_loader_impl_core.h"
12 #include "content/browser/loader/netlog_observer.h" 12 #include "content/browser/loader/netlog_observer.h"
13 #include "content/browser/loader/resource_controller.h" 13 #include "content/browser/loader/resource_controller.h"
14 #include "content/browser/loader/resource_loader.h" 14 #include "content/browser/loader/resource_loader.h"
15 #include "content/browser/loader/resource_request_info_impl.h" 15 #include "content/browser/loader/resource_request_info_impl.h"
16 #include "content/browser/resource_context_impl.h" 16 #include "content/browser/resource_context_impl.h"
17 #include "content/browser/streams/stream.h" 17 #include "content/browser/streams/stream.h"
18 #include "content/browser/streams/stream_context.h" 18 #include "content/browser/streams/stream_context.h"
19 #include "content/public/browser/navigation_data.h" 19 #include "content/public/browser/navigation_data.h"
20 #include "content/public/browser/resource_dispatcher_host_delegate.h" 20 #include "content/public/browser/resource_dispatcher_host_delegate.h"
21 #include "content/public/browser/ssl_status.h" 21 #include "content/public/browser/ssl_status.h"
22 #include "content/public/browser/stream_handle.h" 22 #include "content/public/browser/stream_handle.h"
23 #include "content/public/common/resource_response.h" 23 #include "content/public/common/resource_response.h"
24 #include "net/base/io_buffer.h"
25 #include "net/base/mime_sniffer.h"
24 #include "net/base/net_errors.h" 26 #include "net/base/net_errors.h"
25 #include "net/url_request/url_request.h" 27 #include "net/url_request/url_request.h"
26 28
27 namespace content { 29 namespace content {
28 30
31 namespace {
32
33 // TODO(kinuko): Most of the code below is dup'ed from MojoAsyncResourceHandler,
34 // we should unify the implementation.
35
36 // For MimeSniffingResourceHandler.
37 constexpr size_t kMinAllocationSize = 2 * net::kMaxBytesToSniff;
38
39 constexpr size_t kMaxChunkSize = 32 * 1024;
40
41 constexpr size_t kDefaultAllocationSize = 512 * 1024;
42
43 } // namespace
44
45 // This class is for sharing the ownership of a ScopedDataPipeProducerHandle
46 // between WriterIOBuffer and other class.
47 class NavigationResourceHandler::SharedWriter final
48 : public base::RefCountedThreadSafe<SharedWriter> {
49 public:
50 explicit SharedWriter(mojo::ScopedDataPipeProducerHandle writer)
51 : writer_(std::move(writer)) {}
52 mojo::DataPipeProducerHandle writer() { return writer_.get(); }
53
54 private:
55 friend class base::RefCountedThreadSafe<SharedWriter>;
56 ~SharedWriter() {}
57
58 const mojo::ScopedDataPipeProducerHandle writer_;
59
60 DISALLOW_COPY_AND_ASSIGN(SharedWriter);
61 };
62
63 // This class is a IOBuffer subclass for data gotten from a
64 // ScopedDataPipeProducerHandle.
65 class NavigationResourceHandler::WriterIOBuffer final
66 : public net::IOBufferWithSize {
67 public:
68 // |data| and |size| should be gotten from |writer| via BeginWriteDataRaw.
69 // They will be accesible via IOBuffer methods. As |writer| is stored in this
70 // instance, |data| will be kept valid as long as the following conditions
71 // hold:
72 // 1. |data| is not invalidated via EndWriteDataRaw.
73 // 2. |this| instance is alive.
74 WriterIOBuffer(scoped_refptr<SharedWriter> writer, void* data, size_t size)
75 : net::IOBufferWithSize(static_cast<char*>(data), size),
76 writer_(std::move(writer)) {}
77
78 private:
79 ~WriterIOBuffer() override {
80 // Avoid deleting |data_| in the IOBuffer destructor.
81 data_ = nullptr;
82 }
83
84 // This member is for keeping the writer alive.
85 scoped_refptr<SharedWriter> writer_;
86
87 DISALLOW_COPY_AND_ASSIGN(WriterIOBuffer);
88 };
89
29 void NavigationResourceHandler::GetSSLStatusForRequest( 90 void NavigationResourceHandler::GetSSLStatusForRequest(
30 const GURL& url, 91 const GURL& url,
31 const net::SSLInfo& ssl_info, 92 const net::SSLInfo& ssl_info,
32 int child_id, 93 int child_id,
33 SSLStatus* ssl_status) { 94 SSLStatus* ssl_status) {
34 DCHECK(ssl_info.cert); 95 DCHECK(ssl_info.cert);
35 *ssl_status = SSLStatus(ssl_info); 96 *ssl_status = SSLStatus(ssl_info);
36 } 97 }
37 98
38 NavigationResourceHandler::NavigationResourceHandler( 99 NavigationResourceHandler::NavigationResourceHandler(
39 net::URLRequest* request, 100 net::URLRequest* request,
40 NavigationURLLoaderImplCore* core, 101 NavigationURLLoaderImplCore* core,
41 ResourceDispatcherHostDelegate* resource_dispatcher_host_delegate) 102 ResourceDispatcherHostDelegate* resource_dispatcher_host_delegate)
42 : ResourceHandler(request), 103 : ResourceHandler(request),
43 core_(core), 104 core_(core),
44 resource_dispatcher_host_delegate_(resource_dispatcher_host_delegate) { 105 resource_dispatcher_host_delegate_(resource_dispatcher_host_delegate),
106 handle_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL) {
45 core_->set_resource_handler(this); 107 core_->set_resource_handler(this);
46 writer_.set_immediate_mode(true);
47 } 108 }
48 109
49 NavigationResourceHandler::~NavigationResourceHandler() { 110 NavigationResourceHandler::~NavigationResourceHandler() {
50 if (core_) { 111 if (core_) {
51 core_->NotifyRequestFailed(false, net::ERR_ABORTED); 112 core_->NotifyRequestFailed(false, net::ERR_ABORTED);
52 DetachFromCore(); 113 DetachFromCore();
53 } 114 }
54 } 115 }
55 116
56 void NavigationResourceHandler::Cancel() { 117 void NavigationResourceHandler::Cancel() {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 } 149 }
89 150
90 void NavigationResourceHandler::OnResponseStarted( 151 void NavigationResourceHandler::OnResponseStarted(
91 ResourceResponse* response, 152 ResourceResponse* response,
92 std::unique_ptr<ResourceController> controller) { 153 std::unique_ptr<ResourceController> controller) {
93 DCHECK(core_); 154 DCHECK(core_);
94 DCHECK(!has_controller()); 155 DCHECK(!has_controller());
95 156
96 ResourceRequestInfoImpl* info = GetRequestInfo(); 157 ResourceRequestInfoImpl* info = GetRequestInfo();
97 158
98 StreamContext* stream_context = 159 mojo::ScopedDataPipeConsumerHandle data_consumer_handle;
99 GetStreamContextForResourceContext(info->GetContext()); 160 InitializeDataPipe(&data_consumer_handle);
100 writer_.InitializeStream(
101 stream_context->registry(), request()->url().GetOrigin(),
102 base::Bind(&NavigationResourceHandler::OutOfBandCancel,
103 base::Unretained(this), net::ERR_ABORTED,
104 true /* tell_renderer */));
105 161
106 NetLogObserver::PopulateResponseInfo(request(), response); 162 NetLogObserver::PopulateResponseInfo(request(), response);
107 response->head.encoded_data_length = request()->raw_header_size(); 163 response->head.encoded_data_length = request()->raw_header_size();
108 164
109 std::unique_ptr<NavigationData> cloned_data; 165 std::unique_ptr<NavigationData> cloned_data;
110 if (resource_dispatcher_host_delegate_) { 166 if (resource_dispatcher_host_delegate_) {
111 // Ask the embedder for a NavigationData instance. 167 // Ask the embedder for a NavigationData instance.
112 NavigationData* navigation_data = 168 NavigationData* navigation_data =
113 resource_dispatcher_host_delegate_->GetNavigationData(request()); 169 resource_dispatcher_host_delegate_->GetNavigationData(request());
114 170
115 // Clone the embedder's NavigationData before moving it to the UI thread. 171 // Clone the embedder's NavigationData before moving it to the UI thread.
116 if (navigation_data) 172 if (navigation_data)
117 cloned_data = navigation_data->Clone(); 173 cloned_data = navigation_data->Clone();
118 } 174 }
119 175
120 SSLStatus ssl_status; 176 SSLStatus ssl_status;
121 if (request()->ssl_info().cert.get()) { 177 if (request()->ssl_info().cert.get()) {
122 GetSSLStatusForRequest(request()->url(), request()->ssl_info(), 178 GetSSLStatusForRequest(request()->url(), request()->ssl_info(),
123 info->GetChildID(), &ssl_status); 179 info->GetChildID(), &ssl_status);
124 } 180 }
125 181
126 core_->NotifyResponseStarted(response, writer_.stream()->CreateHandle(), 182 core_->NotifyResponseStarted(response, std::move(data_consumer_handle),
127 ssl_status, std::move(cloned_data), 183 ssl_status, std::move(cloned_data),
128 info->GetGlobalRequestID(), info->IsDownload(), 184 info->GetGlobalRequestID(), info->IsDownload(),
129 info->is_stream()); 185 info->is_stream());
130 // Don't defer stream based requests. This includes requests initiated via 186 // Don't defer stream based requests. This includes requests initiated via
131 // mime type sniffing, etc. 187 // mime type sniffing, etc.
132 // TODO(ananta) 188 // TODO(ananta)
133 // Make sure that the requests go through the throttle checks. Currently this 189 // Make sure that the requests go through the throttle checks. Currently this
134 // does not work as the InterceptingResourceHandler is above us and hence it 190 // does not work as the InterceptingResourceHandler is above us and hence it
135 // does not expect the old handler to defer the request. 191 // does not expect the old handler to defer the request.
136 // TODO(clamy): We should also make the downloads wait on the 192 // TODO(clamy): We should also make the downloads wait on the
(...skipping 15 matching lines...) Expand all
152 std::unique_ptr<ResourceController> controller) { 208 std::unique_ptr<ResourceController> controller) {
153 DCHECK(!has_controller()); 209 DCHECK(!has_controller());
154 controller->Resume(); 210 controller->Resume();
155 } 211 }
156 212
157 void NavigationResourceHandler::OnWillRead( 213 void NavigationResourceHandler::OnWillRead(
158 scoped_refptr<net::IOBuffer>* buf, 214 scoped_refptr<net::IOBuffer>* buf,
159 int* buf_size, 215 int* buf_size,
160 std::unique_ptr<ResourceController> controller) { 216 std::unique_ptr<ResourceController> controller) {
161 DCHECK(!has_controller()); 217 DCHECK(!has_controller());
162 writer_.OnWillRead(buf, buf_size, -1); 218
219 DCHECK(shared_writer_);
220 DCHECK(!buffer_);
221 DCHECK_EQ(0u, buffer_offset_);
222
223 bool first_call = first_read_;
224
225 if (first_read_) {
226 first_read_ = false;
227 handle_watcher_.Watch(shared_writer_->writer(), MOJO_HANDLE_SIGNAL_WRITABLE,
228 base::Bind(&NavigationResourceHandler::OnWritable,
229 base::Unretained(this)));
230 handle_watcher_.ArmOrNotify();
231 }
232
233 bool defer = false;
234 if (!AllocateWriterIOBuffer(&buffer_, &defer)) {
235 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
236 return;
237 }
238
239 if (defer) {
240 parent_buffer_ = buf;
241 parent_buffer_size_ = buf_size;
242 HoldController(std::move(controller));
243 request()->LogBlockedBy("MojoStreamWriter");
244 did_defer_on_will_read_ = true;
245 return;
246 }
247
248 // The first call to OnWillRead must return a buffer of at least
249 // kMinAllocationSize. If the Mojo buffer is too small, need to allocate an
250 // intermediary buffer.
251 if (first_call && static_cast<size_t>(buffer_->size()) < kMinAllocationSize) {
252 // The allocated buffer is too small, so need to create an intermediary one.
253 if (EndWrite(0) != MOJO_RESULT_OK) {
254 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
255 return;
256 }
257 DCHECK(!is_using_io_buffer_not_from_writer_);
258 is_using_io_buffer_not_from_writer_ = true;
259 buffer_ = new net::IOBufferWithSize(kMinAllocationSize);
260 }
261
262 *buf = buffer_;
263 *buf_size = buffer_->size();
163 controller->Resume(); 264 controller->Resume();
164 } 265 }
165 266
166 void NavigationResourceHandler::OnReadCompleted( 267 void NavigationResourceHandler::OnReadCompleted(
167 int bytes_read, 268 int bytes_read,
168 std::unique_ptr<ResourceController> controller) { 269 std::unique_ptr<ResourceController> controller) {
169 DCHECK(!has_controller()); 270 DCHECK(!has_controller());
170 writer_.OnReadCompleted(bytes_read, 271 DCHECK_GE(bytes_read, 0);
171 base::Bind(&ResourceController::Resume, 272 DCHECK(buffer_);
172 base::Passed(std::move(controller)))); 273
274 if (bytes_read == 0) {
275 // Note that |buffer_| is not cleared here, which will cause a DCHECK on
276 // subsequent OnWillRead calls.
277 controller->Resume();
278 return;
279 }
280
281 if (is_using_io_buffer_not_from_writer_) {
282 // Couldn't allocate a large enough buffer on the data pipe in OnWillRead.
283 DCHECK_EQ(0u, buffer_bytes_read_);
284 buffer_bytes_read_ = bytes_read;
285 bool defer = false;
286 if (!CopyReadDataToDataPipe(&defer)) {
287 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
288 return;
289 }
290 if (defer) {
291 request()->LogBlockedBy("NavigationResourceHandler");
292 did_defer_on_writing_ = true;
293 HoldController(std::move(controller));
294 return;
295 }
296 controller->Resume();
297 return;
298 }
299
300 if (EndWrite(bytes_read) != MOJO_RESULT_OK) {
301 controller->Cancel();
302 return;
303 }
304
305 buffer_ = nullptr;
306 controller->Resume();
173 } 307 }
174 308
175 void NavigationResourceHandler::OnResponseCompleted( 309 void NavigationResourceHandler::OnResponseCompleted(
176 const net::URLRequestStatus& status, 310 const net::URLRequestStatus& status,
177 std::unique_ptr<ResourceController> controller) { 311 std::unique_ptr<ResourceController> controller) {
178 // If the request has already committed, close the stream and leave it as-is. 312 if (shared_writer_) {
179 if (writer_.stream()) { 313 shared_writer_ = nullptr;
180 writer_.Finalize(status.error()); 314 buffer_ = nullptr;
315 handle_watcher_.Cancel();
181 controller->Resume(); 316 controller->Resume();
182 return; 317 return;
183 } 318 }
184 319
185 if (core_) { 320 if (core_) {
186 DCHECK_NE(net::OK, status.error()); 321 DCHECK_NE(net::OK, status.error());
187 core_->NotifyRequestFailed(request()->response_info().was_cached, 322 core_->NotifyRequestFailed(request()->response_info().was_cached,
188 status.error()); 323 status.error());
189 DetachFromCore(); 324 DetachFromCore();
190 } 325 }
191 controller->Resume(); 326 controller->Resume();
192 } 327 }
193 328
194 void NavigationResourceHandler::OnDataDownloaded(int bytes_downloaded) { 329 void NavigationResourceHandler::OnDataDownloaded(int bytes_downloaded) {
195 NOTREACHED(); 330 NOTREACHED();
196 } 331 }
197 332
198 void NavigationResourceHandler::DetachFromCore() { 333 void NavigationResourceHandler::DetachFromCore() {
199 DCHECK(core_); 334 DCHECK(core_);
200 core_->set_resource_handler(nullptr); 335 core_->set_resource_handler(nullptr);
201 core_ = nullptr; 336 core_ = nullptr;
202 } 337 }
203 338
339 void NavigationResourceHandler::InitializeDataPipe(
340 mojo::ScopedDataPipeConsumerHandle* consumer_handle) {
341 DCHECK(!shared_writer_);
342
343 MojoCreateDataPipeOptions options;
344 options.struct_size = sizeof(MojoCreateDataPipeOptions);
345 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
346 options.element_num_bytes = 1;
347 options.capacity_num_bytes = kDefaultAllocationSize;
348 mojo::DataPipe data_pipe(options);
349
350 DCHECK(data_pipe.producer_handle.is_valid());
351 DCHECK(data_pipe.consumer_handle.is_valid());
352
353 *consumer_handle = std::move(data_pipe.consumer_handle);
354 shared_writer_ = new SharedWriter(std::move(data_pipe.producer_handle));
355 }
356
357 MojoResult NavigationResourceHandler::BeginWrite(void** data,
358 uint32_t* available) {
359 MojoResult result = mojo::BeginWriteDataRaw(
360 shared_writer_->writer(), data, available, MOJO_WRITE_DATA_FLAG_NONE);
361 if (result == MOJO_RESULT_OK)
362 *available = std::min(*available, static_cast<uint32_t>(kMaxChunkSize));
363 else if (result == MOJO_RESULT_SHOULD_WAIT)
364 handle_watcher_.ArmOrNotify();
365 return result;
366 }
367
368 MojoResult NavigationResourceHandler::EndWrite(uint32_t written) {
369 MojoResult result = mojo::EndWriteDataRaw(shared_writer_->writer(), written);
370 if (result == MOJO_RESULT_OK)
371 handle_watcher_.ArmOrNotify();
372 return result;
373 }
374
375 bool NavigationResourceHandler::CopyReadDataToDataPipe(bool* defer) {
376 while (buffer_bytes_read_ > 0) {
377 scoped_refptr<net::IOBufferWithSize> dest;
378 if (!AllocateWriterIOBuffer(&dest, defer))
379 return false;
380 if (*defer)
381 return true;
382
383 size_t copied_size =
384 std::min(buffer_bytes_read_, static_cast<size_t>(dest->size()));
385 memcpy(dest->data(), buffer_->data() + buffer_offset_, copied_size);
386 buffer_offset_ += copied_size;
387 buffer_bytes_read_ -= copied_size;
388 if (EndWrite(copied_size) != MOJO_RESULT_OK)
389 return false;
390 }
391
392 // All bytes are copied.
393 buffer_ = nullptr;
394 buffer_offset_ = 0;
395 is_using_io_buffer_not_from_writer_ = false;
396 return true;
397 }
398
399 bool NavigationResourceHandler::AllocateWriterIOBuffer(
400 scoped_refptr<net::IOBufferWithSize>* buf,
401 bool* defer) {
402 void* data = nullptr;
403 uint32_t available = 0;
404 MojoResult result = BeginWrite(&data, &available);
405 if (result == MOJO_RESULT_SHOULD_WAIT) {
406 *defer = true;
407 return true;
408 }
409 if (result != MOJO_RESULT_OK)
410 return false;
411 DCHECK_GT(available, 0u);
412 *buf = new WriterIOBuffer(shared_writer_, data, available);
413 return true;
414 }
415
416 void NavigationResourceHandler::OnWritable(MojoResult result) {
417 if (did_defer_on_will_read_) {
418 DCHECK(has_controller());
419 DCHECK(!did_defer_on_writing_);
420 DCHECK(!did_defer_on_redirect_);
421
422 did_defer_on_will_read_ = false;
423
424 scoped_refptr<net::IOBuffer>* parent_buffer = parent_buffer_;
425 parent_buffer_ = nullptr;
426 int* parent_buffer_size = parent_buffer_size_;
427 parent_buffer_size_ = nullptr;
428
429 request()->LogUnblocked();
430 OnWillRead(parent_buffer, parent_buffer_size, ReleaseController());
431 return;
432 }
433
434 if (!did_defer_on_writing_)
435 return;
436 DCHECK(has_controller());
437 DCHECK(!did_defer_on_redirect_);
438 did_defer_on_writing_ = false;
439
440 DCHECK(is_using_io_buffer_not_from_writer_);
441 // |buffer_| is set to a net::IOBufferWithSize. Write the buffer contents
442 // to the data pipe.
443 DCHECK_GT(buffer_bytes_read_, 0u);
444 if (!CopyReadDataToDataPipe(&did_defer_on_writing_)) {
445 CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
446 return;
447 }
448
449 if (did_defer_on_writing_) {
450 // Continue waiting.
451 return;
452 }
453 request()->LogUnblocked();
454 Resume();
455 }
456
204 } // namespace content 457 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/loader/navigation_resource_handler.h ('k') | content/browser/loader/navigation_url_loader_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698