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

Side by Side Diff: content/browser/download/url_downloader.cc

Issue 1418663010: Adding WebContent-free Download (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Cleaning up headers. Created 5 years, 1 month 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 2015 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/download/url_downloader.h"
6
7 #include "base/location.h"
8 #include "base/thread_task_runner_handle.h"
9 #include "content/browser/appcache/appcache_interceptor.h"
10 #include "content/browser/download/download_resource_handler.h"
11 #include "content/browser/loader/resource_request_info_impl.h"
12 #include "content/browser/service_worker/service_worker_request_handler.h"
13 #include "content/browser/ssl/ssl_policy.h"
14 #include "content/common/ssl_status_serialization.h"
15 #include "content/public/browser/cert_store.h"
16 #include "content/public/browser/download_save_info.h"
17 #include "content/public/browser/resource_context.h"
18 #include "content/public/browser/signed_certificate_timestamp_store.h"
19 #include "content/public/common/process_type.h"
20 #include "content/public/common/resource_response.h"
21 #include "content/public/common/security_style.h"
22 #include "net/base/io_buffer.h"
23 #include "net/base/load_flags.h"
24 #include "net/http/http_response_headers.h"
25 #include "net/http/http_status_code.h"
26 #include "ui/base/page_transition_types.h"
27
28 namespace content {
29 void SetReferrerForRequest(net::URLRequest* request, const Referrer& referrer) {
asanka 2015/11/20 19:57:46 For the URL downloader case, since the request is
svaldez 2015/11/23 15:18:57 Done.
30 if (!referrer.url.is_valid())
31 request->SetReferrer(std::string());
32 else
33 request->SetReferrer(referrer.url.spec());
34
35 net::URLRequest::ReferrerPolicy net_referrer_policy =
36 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
37 switch (referrer.policy) {
38 case blink::WebReferrerPolicyAlways:
39 case blink::WebReferrerPolicyNever:
40 case blink::WebReferrerPolicyOrigin:
41 net_referrer_policy = net::URLRequest::NEVER_CLEAR_REFERRER;
42 break;
43 case blink::WebReferrerPolicyNoReferrerWhenDowngrade:
44 net_referrer_policy =
45 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
46 break;
47 case blink::WebReferrerPolicyOriginWhenCrossOrigin:
48 net_referrer_policy =
49 net::URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN;
50 break;
51 case blink::WebReferrerPolicyDefault:
52 default:
53 net_referrer_policy =
54 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
55 break;
56 }
57 request->set_referrer_policy(net_referrer_policy);
58 }
59
60 // The average private bytes increase of the browser for each new pending
61 // request. Experimentally obtained.
62 static const int kAvgBytesPerOutstandingRequest = 4400;
63
64 int CalculateApproximateMemoryCost(net::URLRequest* request) {
65 // The following fields should be a minor size contribution (experimentally
66 // on the order of 100). However since they are variable length, it could
67 // in theory be a sizeable contribution.
68 int strings_cost = request->extra_request_headers().ToString().size() +
69 request->original_url().spec().size() +
70 request->referrer().size() + request->method().size();
71
72 // Note that this expression will typically be dominated by:
73 // |kAvgBytesPerOutstandingRequest|.
74 return kAvgBytesPerOutstandingRequest + strings_cost;
75 }
76
77 void StoreSignedCertificateTimestamps(
78 const net::SignedCertificateTimestampAndStatusList& sct_list,
79 int process_id,
80 SignedCertificateTimestampIDStatusList* sct_ids) {
81 SignedCertificateTimestampStore* sct_store(
82 SignedCertificateTimestampStore::GetInstance());
83
84 for (auto iter = sct_list.begin(); iter != sct_list.end(); ++iter) {
85 const int sct_id(sct_store->Store(iter->sct.get(), process_id));
86 sct_ids->push_back(
87 SignedCertificateTimestampIDAndStatus(sct_id, iter->status));
88 }
89 }
90
91 void GetSSLStatusForRequest(const GURL& url,
92 const net::SSLInfo& ssl_info,
93 int child_id,
94 SSLStatus* ssl_status) {
95 DCHECK(ssl_info.cert);
96
97 int cert_id =
98 CertStore::GetInstance()->StoreCert(ssl_info.cert.get(), child_id);
99
100 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
101 StoreSignedCertificateTimestamps(ssl_info.signed_certificate_timestamps,
102 child_id, &signed_certificate_timestamp_ids);
103
104 *ssl_status = SSLStatus(SSLPolicy::GetSecurityStyleForResource(
105 url, cert_id, ssl_info.cert_status),
106 cert_id, signed_certificate_timestamp_ids, ssl_info);
107 }
108
109 void PopulateResourceResponse(ResourceRequestInfoImpl* info,
110 net::URLRequest* request,
111 ResourceResponse* response) {
112 response->head.request_time = request->request_time();
113 response->head.response_time = request->response_time();
114 response->head.headers = request->response_headers();
115 request->GetCharset(&response->head.charset);
116 response->head.content_length = request->GetExpectedContentSize();
117 request->GetMimeType(&response->head.mime_type);
118 net::HttpResponseInfo response_info = request->response_info();
119 response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy;
120 response->head.was_npn_negotiated = response_info.was_npn_negotiated;
121 response->head.npn_negotiated_protocol =
122 response_info.npn_negotiated_protocol;
123 response->head.connection_info = response_info.connection_info;
124 response->head.was_fetched_via_proxy = request->was_fetched_via_proxy();
125 response->head.proxy_server = response_info.proxy_server;
126 response->head.socket_address = request->GetSocketAddress();
127 const content::ResourceRequestInfo* request_info =
128 content::ResourceRequestInfo::ForRequest(request);
129 if (request_info)
130 response->head.is_using_lofi = request_info->IsUsingLoFi();
131 if (ServiceWorkerRequestHandler* handler =
132 ServiceWorkerRequestHandler::GetHandler(request)) {
133 handler->GetExtraResponseInfo(&response->head);
134 }
135 AppCacheInterceptor::GetExtraResponseInfo(
136 request, &response->head.appcache_id,
137 &response->head.appcache_manifest_url);
138 if (info->is_load_timing_enabled())
139 request->GetLoadTimingInfo(&response->head.load_timing);
140
141 if (request->ssl_info().cert.get()) {
142 SSLStatus ssl_status;
143 GetSSLStatusForRequest(request->url(), request->ssl_info(),
144 info->GetChildID(), &ssl_status);
145 response->head.security_info = SerializeSecurityInfo(ssl_status);
146 } else {
147 // We should not have any SSL state.
148 DCHECK(!request->ssl_info().cert_status);
149 DCHECK_EQ(request->ssl_info().security_bits, -1);
150 DCHECK_EQ(request->ssl_info().key_exchange_info, 0);
151 DCHECK(!request->ssl_info().connection_status);
152 }
153 }
154
155 DownloadInterruptReason UrlDownloader::BeginDownload(
156 DownloadManager* download_manager,
157 scoped_ptr<net::URLRequest> request,
158 const Referrer& referrer,
159 bool is_content_initiated,
160 ResourceContext* context,
161 bool prefer_cache,
162 bool do_not_prompt_for_login,
163 scoped_ptr<DownloadSaveInfo> save_info,
164 uint32 download_id,
165 const DownloadUrlParameters::OnStartedCallback& started_callback) {
166 SetReferrerForRequest(request.get(), referrer);
167
168 int extra_load_flags = net::LOAD_NORMAL;
169 if (prefer_cache) {
170 // If there is upload data attached, only retrieve from cache because there
171 // is no current mechanism to prompt the user for their consent for a
172 // re-post. For GETs, try to retrieve data from the cache and skip
173 // validating the entry if present.
174 if (request->get_upload() != NULL)
175 extra_load_flags |= net::LOAD_ONLY_FROM_CACHE;
176 else
177 extra_load_flags |= net::LOAD_PREFERRING_CACHE;
178 } else {
179 extra_load_flags |= net::LOAD_DISABLE_CACHE;
180 }
181 request->SetLoadFlags(request->load_flags() | extra_load_flags);
182
183 // We treat a download as a main frame load, and thus update the policy URL on
184 // redirects.
185 //
186 // TODO(davidben): Is this correct? If this came from a
187 // ViewHostMsg_DownloadUrl in a frame, should it have first-party URL set
188 // appropriately?
189 request->set_first_party_url_policy(
190 net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT);
191
192 ResourceRequestInfoImpl* extra_info = new ResourceRequestInfoImpl(
193 PROCESS_TYPE_RENDERER, -1, -1,
194 -1, // frame_tree_node_id
195 0, -1, -1,
196 false, // is_main_frame
197 false, // parent_is_main_frame
198 -1, // parent_render_frame_id
199 RESOURCE_TYPE_SUB_RESOURCE, ui::PAGE_TRANSITION_LINK,
200 false, // should_replace_current_entry
201 true, // is_download
202 false, // is_stream
203 true, // allow_download
204 false, // has_user_gesture
205 false, // enable_load_timing
206 false, // enable_upload_progress
207 false, // do_not_prompt_for_login
208 blink::WebReferrerPolicyDefault, blink::WebPageVisibilityStateVisible,
209 context,
210 base::WeakPtr<ResourceMessageFilter>(), // filter
211 false, // report_raw_headers
212 true, // is_async
213 false); // is_using_lofi
214
215 extra_info->set_do_not_prompt_for_login(do_not_prompt_for_login);
216 extra_info->AssociateWithRequest(request.get()); // Request takes ownership.
217
218 if (request->url().SchemeIs(url::kBlobScheme))
219 return DOWNLOAD_INTERRUPT_REASON_FILE_FAILED;
220
221 extra_info->set_memory_cost(CalculateApproximateMemoryCost(request.get()));
222
223 DownloadResourceHandler* handler =
224 new DownloadResourceHandler(download_id, request.get(), started_callback,
225 save_info.Pass());
226 handler->set_parent_download_manager(download_manager);
227
228 // From this point forward, the |UrlDownloader| is responsible for
229 // |started_callback|.
230 linked_ptr<UrlDownloader> downloader(
231 new UrlDownloader(request.Pass(), scoped_ptr<ResourceHandler>(handler)));
232
233 downloader->Start();
234
235 g_active_downloaders.push_back(downloader);
236
237 return DOWNLOAD_INTERRUPT_REASON_NONE;
238 }
239
240 UrlDownloader::UrlDownloader(scoped_ptr<net::URLRequest> request,
241 scoped_ptr<ResourceHandler> handler)
242 : request_(request.Pass()),
243 handler_(handler.Pass()),
244 weak_ptr_factory_(this) {}
245
246 UrlDownloader::~UrlDownloader() {
247 handler_.reset();
248 }
249
250 void UrlDownloader::Start() {
251 // Give the handler a chance to delay the URLRequest from being started.
252 bool defer_start;
253 if (!handler_->OnWillStart(request_->url(), &defer_start)) {
254 request_->CancelWithError(net::ERR_ABORTED);
255 return;
256 }
257
258 DCHECK(!request_->is_pending());
259
260 if (!request_->status().is_success()) {
261 return;
262 }
263
264 request_->set_delegate(this);
265 request_->Start();
266 }
267
268 void UrlDownloader::OnResponseStarted(net::URLRequest* request) {
269 DVLOG(1) << "OnResponseStarted: " << request_->url().spec();
270
271 if (!request_->status().is_success()) {
272 ResponseCompleted();
273 return;
274 }
275
276 ResourceRequestInfoImpl* info =
277 ResourceRequestInfoImpl::ForRequest(request_.get());
278 scoped_refptr<ResourceResponse> response(new ResourceResponse());
279 PopulateResourceResponse(info, request_.get(), response.get());
280
281 bool defer;
asanka 2015/11/20 19:57:46 Initialize. OnResponseStarted() isn't required to
svaldez 2015/11/23 15:18:56 Done.
282 if (!handler_->OnResponseStarted(response.get(), &defer)) {
283 request_->CancelWithError(net::ERR_ABORTED);
284 return;
285 }
asanka 2015/11/20 19:57:46 Probably want to DCHECK(!defer) if we don't expect
svaldez 2015/11/23 15:18:57 Done.
286
287 if (request_->status().is_success())
288 StartReading(false); // Read the first chunk.
289 else
290 ResponseCompleted();
291 }
292
293 void UrlDownloader::OnReadCompleted(net::URLRequest* request, int bytes_read) {
294 DVLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
295 << " bytes_read = " << bytes_read;
296
297 // bytes_read == -1 always implies an error.
298 if (bytes_read == -1 || !request_->status().is_success()) {
299 ResponseCompleted();
300 return;
301 }
302
303 DCHECK(bytes_read >= 0);
304 DCHECK(request_->status().is_success());
305
306 bool defer;
307 if (!handler_->OnReadCompleted(bytes_read, &defer)) {
308 request_->CancelWithError(net::ERR_ABORTED);
309 return;
310 }
311
312 if (!request_->status().is_success())
313 return;
314
315 if (bytes_read > 0) {
316 StartReading(true); // Read the next chunk.
asanka 2015/11/20 19:57:46 Shall we call this ReadNextChunk() ?
svaldez 2015/11/23 15:18:56 Using ResourceLoader naming scheme.
317 } else {
318 // URLRequest reported an EOF. Call ResponseCompleted.
319 DCHECK_EQ(0, bytes_read);
320 ResponseCompleted();
321 }
322 }
323
324 void UrlDownloader::StartReading(bool is_continuation) {
325 int bytes_read;
326
327 // Make sure we track the buffer in at least one place. This ensures it gets
328 // deleted even in the case the request has already finished its job and
329 // doesn't use the buffer.
330 scoped_refptr<net::IOBuffer> buf;
331 int buf_size;
332 {
asanka 2015/11/20 19:57:46 Unnecessary {
svaldez 2015/11/23 15:18:56 Done.
333 if (!handler_->OnWillRead(&buf, &buf_size, -1)) {
334 request_->CancelWithError(net::ERR_ABORTED);
335 return;
336 }
337 }
338
339 DCHECK(buf.get());
340 DCHECK(buf_size > 0);
341
342 request_->Read(buf.get(), buf_size, &bytes_read);
343
344 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
345 if (request_->status().is_io_pending())
346 return;
347
348 if (!is_continuation || bytes_read <= 0) {
349 OnReadCompleted(request_.get(), bytes_read);
350 } else {
351 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
352 // thread in case the URLRequest can provide data synchronously.
353 base::ThreadTaskRunnerHandle::Get()->PostTask(
354 FROM_HERE,
355 base::Bind(&UrlDownloader::OnReadCompleted,
356 weak_ptr_factory_.GetWeakPtr(), request_.get(), bytes_read));
357 }
358 }
359
360 void UrlDownloader::ResponseCompleted() {
361 DVLOG(1) << "ResponseCompleted: " << request_->url().spec();
362
363 ResourceRequestInfoImpl* info =
364 ResourceRequestInfoImpl::ForRequest(request_.get());
365
366 std::string security_info;
367 const net::SSLInfo& ssl_info = request_->ssl_info();
368 if (ssl_info.cert.get() != NULL) {
369 SSLStatus ssl_status;
370 GetSSLStatusForRequest(request_->url(), ssl_info, info->GetChildID(),
371 &ssl_status);
372
373 security_info = SerializeSecurityInfo(ssl_status);
374 }
375
376 bool defer;
377 { handler_->OnResponseCompleted(request_->status(), security_info, &defer); }
asanka 2015/11/20 19:57:46 Unnecessary {
svaldez 2015/11/23 15:18:56 Done.
378 }
379
380 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698