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

Side by Side Diff: content/network/url_loader_impl.cc

Issue 2817453002: Bring back the URLLoader from the old Mandoline network service. (Closed)
Patch Set: fix checkdeps 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
« no previous file with comments | « content/network/url_loader_impl.h ('k') | content/network/url_loader_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/network/url_loader_impl.h"
6
7 #include "base/task_scheduler/post_task.h"
8 #include "base/threading/thread_task_runner_handle.h"
9 #include "content/network/net_adapters.h"
10 #include "content/network/network_context.h"
11 #include "content/public/common/referrer.h"
12 #include "content/public/common/resource_response.h"
13 #include "net/base/elements_upload_data_stream.h"
14 #include "net/base/load_flags.h"
15 #include "net/base/upload_bytes_element_reader.h"
16 #include "net/base/upload_file_element_reader.h"
17 #include "net/url_request/url_request_context.h"
18
19 namespace content {
20
21 namespace {
22 constexpr size_t kDefaultAllocationSize = 512 * 1024;
23
24 // TODO: this duplicates ResourceDispatcherHostImpl::BuildLoadFlagsForRequest.
25 int BuildLoadFlagsForRequest(const ResourceRequest& request,
26 bool is_sync_load) {
27 int load_flags = request.load_flags;
28
29 // Although EV status is irrelevant to sub-frames and sub-resources, we have
30 // to perform EV certificate verification on all resources because an HTTP
31 // keep-alive connection created to load a sub-frame or a sub-resource could
32 // be reused to load a main frame.
33 load_flags |= net::LOAD_VERIFY_EV_CERT;
34 if (request.resource_type == RESOURCE_TYPE_MAIN_FRAME) {
35 load_flags |= net::LOAD_MAIN_FRAME_DEPRECATED;
36 } else if (request.resource_type == RESOURCE_TYPE_PREFETCH) {
37 load_flags |= net::LOAD_PREFETCH;
38 }
39
40 if (is_sync_load)
41 load_flags |= net::LOAD_IGNORE_LIMITS;
42
43 return load_flags;
44 }
45
46 // TODO: this duplicates some of PopulateResourceResponse in
47 // content/browser/loader/resource_loader.cc
48 void PopulateResourceResponse(net::URLRequest* request,
49 ResourceResponse* response) {
50 response->head.request_time = request->request_time();
51 response->head.response_time = request->response_time();
52 response->head.headers = request->response_headers();
53 request->GetCharset(&response->head.charset);
54 response->head.content_length = request->GetExpectedContentSize();
55 request->GetMimeType(&response->head.mime_type);
56 net::HttpResponseInfo response_info = request->response_info();
57 response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy;
58 response->head.was_alpn_negotiated = response_info.was_alpn_negotiated;
59 response->head.alpn_negotiated_protocol =
60 response_info.alpn_negotiated_protocol;
61 response->head.connection_info = response_info.connection_info;
62 response->head.socket_address = response_info.socket_address;
63
64 response->head.effective_connection_type =
65 net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
66 }
67
68 // A subclass of net::UploadBytesElementReader which owns
69 // ResourceRequestBodyImpl.
70 class BytesElementReader : public net::UploadBytesElementReader {
71 public:
72 BytesElementReader(ResourceRequestBodyImpl* resource_request_body,
73 const ResourceRequestBodyImpl::Element& element)
74 : net::UploadBytesElementReader(element.bytes(), element.length()),
75 resource_request_body_(resource_request_body) {
76 DCHECK_EQ(ResourceRequestBodyImpl::Element::TYPE_BYTES, element.type());
77 }
78
79 ~BytesElementReader() override {}
80
81 private:
82 scoped_refptr<ResourceRequestBodyImpl> resource_request_body_;
83
84 DISALLOW_COPY_AND_ASSIGN(BytesElementReader);
85 };
86
87 // A subclass of net::UploadFileElementReader which owns
88 // ResourceRequestBodyImpl.
89 // This class is necessary to ensure the BlobData and any attached shareable
90 // files survive until upload completion.
91 class FileElementReader : public net::UploadFileElementReader {
92 public:
93 FileElementReader(ResourceRequestBodyImpl* resource_request_body,
94 base::TaskRunner* task_runner,
95 const ResourceRequestBodyImpl::Element& element)
96 : net::UploadFileElementReader(task_runner,
97 element.path(),
98 element.offset(),
99 element.length(),
100 element.expected_modification_time()),
101 resource_request_body_(resource_request_body) {
102 DCHECK_EQ(ResourceRequestBodyImpl::Element::TYPE_FILE, element.type());
103 }
104
105 ~FileElementReader() override {}
106
107 private:
108 scoped_refptr<ResourceRequestBodyImpl> resource_request_body_;
109
110 DISALLOW_COPY_AND_ASSIGN(FileElementReader);
111 };
112
113 // TODO: copied from content/browser/loader/upload_data_stream_builder.cc.
114 std::unique_ptr<net::UploadDataStream> CreateUploadDataStream(
115 ResourceRequestBodyImpl* body,
116 base::SequencedTaskRunner* file_task_runner) {
117 std::vector<std::unique_ptr<net::UploadElementReader>> element_readers;
118 for (const auto& element : *body->elements()) {
119 switch (element.type()) {
120 case ResourceRequestBodyImpl::Element::TYPE_BYTES:
121 element_readers.push_back(
122 base::MakeUnique<BytesElementReader>(body, element));
123 break;
124 case ResourceRequestBodyImpl::Element::TYPE_FILE:
125 element_readers.push_back(base::MakeUnique<FileElementReader>(
126 body, file_task_runner, element));
127 break;
128 case ResourceRequestBodyImpl::Element::TYPE_FILE_FILESYSTEM:
129 NOTIMPLEMENTED();
130 break;
131 case ResourceRequestBodyImpl::Element::TYPE_BLOB: {
132 NOTIMPLEMENTED();
133 break;
134 }
135 case ResourceRequestBodyImpl::Element::TYPE_DISK_CACHE_ENTRY:
136 case ResourceRequestBodyImpl::Element::TYPE_BYTES_DESCRIPTION:
137 case ResourceRequestBodyImpl::Element::TYPE_UNKNOWN:
138 NOTREACHED();
139 break;
140 }
141 }
142
143 return base::MakeUnique<net::ElementsUploadDataStream>(
144 std::move(element_readers), body->identifier());
145 }
146
147 } // namespace
148
149 URLLoaderImpl::URLLoaderImpl(NetworkContext* context,
150 mojom::URLLoaderRequest url_loader_request,
151 const ResourceRequest& request,
152 mojom::URLLoaderClientPtr url_loader_client)
153 : context_(context),
154 connected_(true),
155 binding_(this, std::move(url_loader_request)),
156 url_loader_client_(std::move(url_loader_client)),
157 writable_handle_watcher_(FROM_HERE,
158 mojo::SimpleWatcher::ArmingPolicy::MANUAL),
159 peer_closed_handle_watcher_(FROM_HERE,
160 mojo::SimpleWatcher::ArmingPolicy::MANUAL),
161 weak_ptr_factory_(this) {
162 binding_.set_connection_error_handler(
163 base::Bind(&URLLoaderImpl::OnConnectionError, base::Unretained(this)));
164
165 url_request_ = context_->url_request_context()->CreateRequest(
166 GURL(request.url), net::DEFAULT_PRIORITY, this);
167 url_request_->set_method(request.method);
168
169 const Referrer referrer(request.referrer, request.referrer_policy);
170 Referrer::SetReferrerForRequest(url_request_.get(), referrer);
171
172 net::HttpRequestHeaders headers;
173 headers.AddHeadersFromString(request.headers);
174 url_request_->SetExtraRequestHeaders(headers);
175
176 // Resolve elements from request_body and prepare upload data.
177 if (request.request_body.get()) {
178 scoped_refptr<base::SequencedTaskRunner> task_runner =
179 base::CreateSequencedTaskRunnerWithTraits(
180 base::TaskTraits().MayBlock().WithPriority(
181 base::TaskPriority::USER_VISIBLE));
182 url_request_->set_upload(
183 CreateUploadDataStream(request.request_body.get(), task_runner.get()));
184 }
185
186 int load_flags = BuildLoadFlagsForRequest(request, false);
187 url_request_->SetLoadFlags(load_flags);
188
189 url_request_->Start();
190 }
191
192 URLLoaderImpl::~URLLoaderImpl() {}
193
194 void URLLoaderImpl::Cleanup() {
195 // The associated network context is going away and we have to destroy
196 // net::URLRequest hold by this loader.
197 delete this;
198 }
199
200 void URLLoaderImpl::FollowRedirect() {
201 if (!url_request_) {
202 NotifyCompleted(net::ERR_UNEXPECTED);
203 return;
204 }
205
206 url_request_->FollowDeferredRedirect();
207 }
208
209 void URLLoaderImpl::SetPriority(net::RequestPriority priority,
210 int32_t intra_priority_value) {
211 NOTIMPLEMENTED();
212 }
213
214 void URLLoaderImpl::OnReceivedRedirect(net::URLRequest* url_request,
215 const net::RedirectInfo& redirect_info,
216 bool* defer_redirect) {
217 DCHECK(url_request == url_request_.get());
218 DCHECK(url_request->status().is_success());
219
220 // Send the redirect response to the client, allowing them to inspect it and
221 // optionally follow the redirect.
222 *defer_redirect = true;
223
224 scoped_refptr<ResourceResponse> response = new ResourceResponse();
225 PopulateResourceResponse(url_request_.get(), response.get());
226
227 url_loader_client_->OnReceiveRedirect(redirect_info, response->head);
228 }
229
230 void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) {
231 DCHECK(url_request == url_request_.get());
232
233 // TODO: Add support for optional MIME sniffing.
234
235 scoped_refptr<ResourceResponse> response = new ResourceResponse();
236 PopulateResourceResponse(url_request_.get(), response.get());
237
238 mojom::DownloadedTempFilePtr downloaded_file_ptr;
239 url_loader_client_->OnReceiveResponse(response->head,
240 std::move(downloaded_file_ptr));
241
242 net::IOBufferWithSize* metadata = url_request->response_info().metadata.get();
243 if (metadata) {
244 const uint8_t* data = reinterpret_cast<const uint8_t*>(metadata->data());
245
246 url_loader_client_->OnReceiveCachedMetadata(
247 std::vector<uint8_t>(data, data + metadata->size()));
248 }
249
250 MojoCreateDataPipeOptions options;
251 options.struct_size = sizeof(MojoCreateDataPipeOptions);
252 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
253 options.element_num_bytes = 1;
254 options.capacity_num_bytes = kDefaultAllocationSize;
255 mojo::DataPipe data_pipe(options);
256
257 DCHECK(data_pipe.producer_handle.is_valid());
258 DCHECK(data_pipe.consumer_handle.is_valid());
259
260 response_body_stream_ = std::move(data_pipe.producer_handle);
261 response_body_consumer_handle_ = std::move(data_pipe.consumer_handle);
262 peer_closed_handle_watcher_.Watch(
263 response_body_stream_.get(), MOJO_HANDLE_SIGNAL_PEER_CLOSED,
264 base::Bind(&URLLoaderImpl::OnResponseBodyStreamClosed,
265 base::Unretained(this)));
266 peer_closed_handle_watcher_.ArmOrNotify();
267
268 writable_handle_watcher_.Watch(
269 response_body_stream_.get(), MOJO_HANDLE_SIGNAL_WRITABLE,
270 base::Bind(&URLLoaderImpl::OnResponseBodyStreamReady,
271 base::Unretained(this)));
272
273 // Start reading...
274 ReadMore();
275 }
276
277 void URLLoaderImpl::ReadMore() {
278 DCHECK(!pending_write_.get());
279
280 uint32_t num_bytes;
281 // TODO: we should use the abstractions in MojoAsyncResourceHandler.
282 MojoResult result = NetToMojoPendingBuffer::BeginWrite(
283 &response_body_stream_, &pending_write_, &num_bytes);
284 if (result == MOJO_RESULT_SHOULD_WAIT) {
285 // The pipe is full. We need to wait for it to have more space.
286 writable_handle_watcher_.ArmOrNotify();
287 return;
288 } else if (result != MOJO_RESULT_OK) {
289 // The response body stream is in a bad state. Bail.
290 // TODO: How should this be communicated to our client?
291 writable_handle_watcher_.Cancel();
292 response_body_stream_.reset();
293 DeleteIfNeeded();
294 return;
295 }
296
297 CHECK_GT(static_cast<uint32_t>(std::numeric_limits<int>::max()), num_bytes);
298 scoped_refptr<net::IOBuffer> buf(new NetToMojoIOBuffer(pending_write_.get()));
299 int bytes_read;
300 url_request_->Read(buf.get(), static_cast<int>(num_bytes), &bytes_read);
301 if (url_request_->status().is_io_pending()) {
302 // Wait for OnReadCompleted.
303 } else if (url_request_->status().is_success() && bytes_read > 0) {
304 SendDataPipeIfNecessary();
305 DidRead(static_cast<uint32_t>(bytes_read), true);
306 } else {
307 NotifyCompleted(net::OK);
308 writable_handle_watcher_.Cancel();
309 pending_write_->Complete(0);
310 pending_write_ = nullptr; // This closes the data pipe.
311 DeleteIfNeeded();
312 return;
313 }
314 }
315
316 void URLLoaderImpl::DidRead(uint32_t num_bytes, bool completed_synchronously) {
317 DCHECK(url_request_->status().is_success());
318 response_body_stream_ = pending_write_->Complete(num_bytes);
319 pending_write_ = nullptr;
320 if (completed_synchronously) {
321 base::ThreadTaskRunnerHandle::Get()->PostTask(
322 FROM_HERE,
323 base::Bind(&URLLoaderImpl::ReadMore, weak_ptr_factory_.GetWeakPtr()));
324 } else {
325 ReadMore();
326 }
327 }
328
329 void URLLoaderImpl::OnReadCompleted(net::URLRequest* url_request,
330 int bytes_read) {
331 DCHECK(url_request == url_request_.get());
332
333 if (!url_request->status().is_success()) {
334 writable_handle_watcher_.Cancel();
335 pending_write_ = nullptr; // This closes the data pipe.
336 DeleteIfNeeded();
337 return;
338 }
339
340 SendDataPipeIfNecessary();
341
342 DidRead(static_cast<uint32_t>(bytes_read), false);
343 }
344
345 void URLLoaderImpl::NotifyCompleted(int error_code) {
346 ResourceRequestCompletionStatus request_complete_data;
347 request_complete_data.error_code = error_code;
348 request_complete_data.exists_in_cache =
349 url_request_->response_info().was_cached;
350 request_complete_data.completion_time = base::TimeTicks::Now();
351 request_complete_data.encoded_data_length =
352 url_request_->GetTotalReceivedBytes();
353 request_complete_data.encoded_body_length = url_request_->GetRawBodyBytes();
354
355 url_loader_client_->OnComplete(request_complete_data);
356 DeleteIfNeeded();
357 }
358
359 void URLLoaderImpl::SendDataPipeIfNecessary() {
360 if (response_body_consumer_handle_.is_valid()) {
361 // Send the data pipe on the first OnReadCompleted call.
362 url_loader_client_->OnStartLoadingResponseBody(
363 std::move(response_body_consumer_handle_));
364 }
365 }
366
367 void URLLoaderImpl::OnConnectionError() {
368 connected_ = false;
369 DeleteIfNeeded();
370 }
371
372 void URLLoaderImpl::OnResponseBodyStreamClosed(MojoResult result) {
373 url_request_.reset();
374 response_body_stream_.reset();
375 pending_write_ = nullptr;
376 DeleteIfNeeded();
377 }
378
379 void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) {
380 // TODO: Handle a bad |result| value.
381 DCHECK_EQ(result, MOJO_RESULT_OK);
382 ReadMore();
383 }
384
385 void URLLoaderImpl::DeleteIfNeeded() {
386 bool has_data_pipe = pending_write_.get() || response_body_stream_.is_valid();
387 if (!connected_ && !has_data_pipe)
388 delete this;
389 }
390
391 } // namespace content
OLDNEW
« no previous file with comments | « content/network/url_loader_impl.h ('k') | content/network/url_loader_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698