Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / child / web_url_loader_impl.cc
blob5758e343f8b719f5b7afe1f6e3c47bfbc9bfbf4a
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
3 // found in the LICENSE file.
5 #include "content/child/web_url_loader_impl.h"
7 #include <algorithm>
8 #include <string>
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/files/file_path.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string_util.h"
16 #include "base/time/time.h"
17 #include "components/mime_util/mime_util.h"
18 #include "content/child/child_thread_impl.h"
19 #include "content/child/ftp_directory_listing_response_delegate.h"
20 #include "content/child/multipart_response_delegate.h"
21 #include "content/child/request_extra_data.h"
22 #include "content/child/request_info.h"
23 #include "content/child/resource_dispatcher.h"
24 #include "content/child/shared_memory_data_consumer_handle.h"
25 #include "content/child/sync_load_response.h"
26 #include "content/child/web_url_request_util.h"
27 #include "content/child/weburlresponse_extradata_impl.h"
28 #include "content/common/resource_messages.h"
29 #include "content/common/resource_request_body.h"
30 #include "content/common/service_worker/service_worker_types.h"
31 #include "content/public/child/fixed_received_data.h"
32 #include "content/public/child/request_peer.h"
33 #include "content/public/common/content_switches.h"
34 #include "net/base/data_url.h"
35 #include "net/base/filename_util.h"
36 #include "net/base/net_errors.h"
37 #include "net/http/http_response_headers.h"
38 #include "net/http/http_util.h"
39 #include "net/url_request/redirect_info.h"
40 #include "net/url_request/url_request_data_job.h"
41 #include "third_party/WebKit/public/platform/WebHTTPLoadInfo.h"
42 #include "third_party/WebKit/public/platform/WebURL.h"
43 #include "third_party/WebKit/public/platform/WebURLError.h"
44 #include "third_party/WebKit/public/platform/WebURLLoadTiming.h"
45 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
46 #include "third_party/WebKit/public/platform/WebURLRequest.h"
47 #include "third_party/WebKit/public/platform/WebURLResponse.h"
48 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
50 using base::Time;
51 using base::TimeTicks;
52 using blink::WebData;
53 using blink::WebHTTPBody;
54 using blink::WebHTTPHeaderVisitor;
55 using blink::WebHTTPLoadInfo;
56 using blink::WebReferrerPolicy;
57 using blink::WebSecurityPolicy;
58 using blink::WebString;
59 using blink::WebURL;
60 using blink::WebURLError;
61 using blink::WebURLLoadTiming;
62 using blink::WebURLLoader;
63 using blink::WebURLLoaderClient;
64 using blink::WebURLRequest;
65 using blink::WebURLResponse;
67 namespace content {
69 // Utilities ------------------------------------------------------------------
71 namespace {
73 using HeadersVector = ResourceDevToolsInfo::HeadersVector;
75 // Converts timing data from |load_timing| to the format used by WebKit.
76 void PopulateURLLoadTiming(const net::LoadTimingInfo& load_timing,
77 WebURLLoadTiming* url_timing) {
78 DCHECK(!load_timing.request_start.is_null());
80 const TimeTicks kNullTicks;
81 url_timing->initialize();
82 url_timing->setRequestTime(
83 (load_timing.request_start - kNullTicks).InSecondsF());
84 url_timing->setProxyStart(
85 (load_timing.proxy_resolve_start - kNullTicks).InSecondsF());
86 url_timing->setProxyEnd(
87 (load_timing.proxy_resolve_end - kNullTicks).InSecondsF());
88 url_timing->setDNSStart(
89 (load_timing.connect_timing.dns_start - kNullTicks).InSecondsF());
90 url_timing->setDNSEnd(
91 (load_timing.connect_timing.dns_end - kNullTicks).InSecondsF());
92 url_timing->setConnectStart(
93 (load_timing.connect_timing.connect_start - kNullTicks).InSecondsF());
94 url_timing->setConnectEnd(
95 (load_timing.connect_timing.connect_end - kNullTicks).InSecondsF());
96 url_timing->setSSLStart(
97 (load_timing.connect_timing.ssl_start - kNullTicks).InSecondsF());
98 url_timing->setSSLEnd(
99 (load_timing.connect_timing.ssl_end - kNullTicks).InSecondsF());
100 url_timing->setSendStart(
101 (load_timing.send_start - kNullTicks).InSecondsF());
102 url_timing->setSendEnd(
103 (load_timing.send_end - kNullTicks).InSecondsF());
104 url_timing->setReceiveHeadersEnd(
105 (load_timing.receive_headers_end - kNullTicks).InSecondsF());
108 net::RequestPriority ConvertWebKitPriorityToNetPriority(
109 const WebURLRequest::Priority& priority) {
110 switch (priority) {
111 case WebURLRequest::PriorityVeryHigh:
112 return net::HIGHEST;
114 case WebURLRequest::PriorityHigh:
115 return net::MEDIUM;
117 case WebURLRequest::PriorityMedium:
118 return net::LOW;
120 case WebURLRequest::PriorityLow:
121 return net::LOWEST;
123 case WebURLRequest::PriorityVeryLow:
124 return net::IDLE;
126 case WebURLRequest::PriorityUnresolved:
127 default:
128 NOTREACHED();
129 return net::LOW;
133 // Extracts info from a data scheme URL |url| into |info| and |data|. Returns
134 // net::OK if successful. Returns a net error code otherwise.
135 int GetInfoFromDataURL(const GURL& url,
136 ResourceResponseInfo* info,
137 std::string* data) {
138 // Assure same time for all time fields of data: URLs.
139 Time now = Time::Now();
140 info->load_timing.request_start = TimeTicks::Now();
141 info->load_timing.request_start_time = now;
142 info->request_time = now;
143 info->response_time = now;
145 std::string mime_type;
146 std::string charset;
147 scoped_refptr<net::HttpResponseHeaders> headers(
148 new net::HttpResponseHeaders(std::string()));
149 int result = net::URLRequestDataJob::BuildResponse(
150 url, &mime_type, &charset, data, headers.get());
151 if (result != net::OK)
152 return result;
154 info->headers = headers;
155 info->mime_type.swap(mime_type);
156 info->charset.swap(charset);
157 info->security_info.clear();
158 info->content_length = data->length();
159 info->encoded_data_length = 0;
161 return net::OK;
164 #define STATIC_ASSERT_MATCHING_ENUMS(content_name, blink_name) \
165 static_assert( \
166 static_cast<int>(content_name) == static_cast<int>(blink_name), \
167 "mismatching enums: " #content_name)
169 STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_SAME_ORIGIN,
170 WebURLRequest::FetchRequestModeSameOrigin);
171 STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_NO_CORS,
172 WebURLRequest::FetchRequestModeNoCORS);
173 STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_CORS,
174 WebURLRequest::FetchRequestModeCORS);
175 STATIC_ASSERT_MATCHING_ENUMS(
176 FETCH_REQUEST_MODE_CORS_WITH_FORCED_PREFLIGHT,
177 WebURLRequest::FetchRequestModeCORSWithForcedPreflight);
179 FetchRequestMode GetFetchRequestMode(const WebURLRequest& request) {
180 return static_cast<FetchRequestMode>(request.fetchRequestMode());
183 STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_OMIT,
184 WebURLRequest::FetchCredentialsModeOmit);
185 STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_SAME_ORIGIN,
186 WebURLRequest::FetchCredentialsModeSameOrigin);
187 STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_INCLUDE,
188 WebURLRequest::FetchCredentialsModeInclude);
190 FetchCredentialsMode GetFetchCredentialsMode(const WebURLRequest& request) {
191 return static_cast<FetchCredentialsMode>(request.fetchCredentialsMode());
194 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_AUXILIARY,
195 WebURLRequest::FrameTypeAuxiliary);
196 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_NESTED,
197 WebURLRequest::FrameTypeNested);
198 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_NONE,
199 WebURLRequest::FrameTypeNone);
200 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
201 WebURLRequest::FrameTypeTopLevel);
203 RequestContextFrameType GetRequestContextFrameType(
204 const WebURLRequest& request) {
205 return static_cast<RequestContextFrameType>(request.frameType());
208 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_UNSPECIFIED,
209 WebURLRequest::RequestContextUnspecified);
210 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_AUDIO,
211 WebURLRequest::RequestContextAudio);
212 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_BEACON,
213 WebURLRequest::RequestContextBeacon);
214 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_CSP_REPORT,
215 WebURLRequest::RequestContextCSPReport);
216 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_DOWNLOAD,
217 WebURLRequest::RequestContextDownload);
218 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_EMBED,
219 WebURLRequest::RequestContextEmbed);
220 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_EVENT_SOURCE,
221 WebURLRequest::RequestContextEventSource);
222 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FAVICON,
223 WebURLRequest::RequestContextFavicon);
224 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FETCH,
225 WebURLRequest::RequestContextFetch);
226 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FONT,
227 WebURLRequest::RequestContextFont);
228 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FORM,
229 WebURLRequest::RequestContextForm);
230 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FRAME,
231 WebURLRequest::RequestContextFrame);
232 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_HYPERLINK,
233 WebURLRequest::RequestContextHyperlink);
234 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IFRAME,
235 WebURLRequest::RequestContextIframe);
236 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMAGE,
237 WebURLRequest::RequestContextImage);
238 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMAGE_SET,
239 WebURLRequest::RequestContextImageSet);
240 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMPORT,
241 WebURLRequest::RequestContextImport);
242 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_INTERNAL,
243 WebURLRequest::RequestContextInternal);
244 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_LOCATION,
245 WebURLRequest::RequestContextLocation);
246 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_MANIFEST,
247 WebURLRequest::RequestContextManifest);
248 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_OBJECT,
249 WebURLRequest::RequestContextObject);
250 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PING,
251 WebURLRequest::RequestContextPing);
252 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PLUGIN,
253 WebURLRequest::RequestContextPlugin);
254 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PREFETCH,
255 WebURLRequest::RequestContextPrefetch);
256 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SCRIPT,
257 WebURLRequest::RequestContextScript);
258 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SERVICE_WORKER,
259 WebURLRequest::RequestContextServiceWorker);
260 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SHARED_WORKER,
261 WebURLRequest::RequestContextSharedWorker);
262 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SUBRESOURCE,
263 WebURLRequest::RequestContextSubresource);
264 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_STYLE,
265 WebURLRequest::RequestContextStyle);
266 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_TRACK,
267 WebURLRequest::RequestContextTrack);
268 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_VIDEO,
269 WebURLRequest::RequestContextVideo);
270 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_WORKER,
271 WebURLRequest::RequestContextWorker);
272 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_XML_HTTP_REQUEST,
273 WebURLRequest::RequestContextXMLHttpRequest);
274 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_XSLT,
275 WebURLRequest::RequestContextXSLT);
277 RequestContextType GetRequestContextType(const WebURLRequest& request) {
278 return static_cast<RequestContextType>(request.requestContext());
281 } // namespace
283 // WebURLLoaderImpl::Context --------------------------------------------------
285 // This inner class exists since the WebURLLoader may be deleted while inside a
286 // call to WebURLLoaderClient. Refcounting is to keep the context from being
287 // deleted if it may have work to do after calling into the client.
288 class WebURLLoaderImpl::Context : public base::RefCounted<Context>,
289 public RequestPeer {
290 public:
291 Context(WebURLLoaderImpl* loader,
292 ResourceDispatcher* resource_dispatcher,
293 scoped_refptr<base::SingleThreadTaskRunner> task_runner);
295 WebURLLoaderClient* client() const { return client_; }
296 void set_client(WebURLLoaderClient* client) { client_ = client; }
298 void Cancel();
299 void SetDefersLoading(bool value);
300 void DidChangePriority(WebURLRequest::Priority new_priority,
301 int intra_priority_value);
302 bool AttachThreadedDataReceiver(
303 blink::WebThreadedDataReceiver* threaded_data_receiver);
304 void Start(const WebURLRequest& request,
305 SyncLoadResponse* sync_load_response);
307 // RequestPeer methods:
308 void OnUploadProgress(uint64 position, uint64 size) override;
309 bool OnReceivedRedirect(const net::RedirectInfo& redirect_info,
310 const ResourceResponseInfo& info) override;
311 void OnReceivedResponse(const ResourceResponseInfo& info) override;
312 void OnDownloadedData(int len, int encoded_data_length) override;
313 void OnReceivedData(scoped_ptr<ReceivedData> data) override;
314 void OnReceivedCachedMetadata(const char* data, int len) override;
315 void OnCompletedRequest(int error_code,
316 bool was_ignored_by_handler,
317 bool stale_copy_in_cache,
318 const std::string& security_info,
319 const base::TimeTicks& completion_time,
320 int64 total_transfer_size) override;
321 void OnReceivedCompletedResponse(const ResourceResponseInfo& info,
322 scoped_ptr<ReceivedData> data,
323 int error_code,
324 bool was_ignored_by_handler,
325 bool stale_copy_in_cache,
326 const std::string& security_info,
327 const base::TimeTicks& completion_time,
328 int64 total_transfer_size) override;
330 private:
331 friend class base::RefCounted<Context>;
332 ~Context() override;
334 // Called when the body data stream is detached from the reader side.
335 void CancelBodyStreaming();
336 // We can optimize the handling of data URLs in most cases.
337 bool CanHandleDataURLRequestLocally() const;
338 void HandleDataURL();
340 WebURLLoaderImpl* loader_;
341 WebURLRequest request_;
342 WebURLLoaderClient* client_;
343 ResourceDispatcher* resource_dispatcher_;
344 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
345 WebReferrerPolicy referrer_policy_;
346 scoped_ptr<FtpDirectoryListingResponseDelegate> ftp_listing_delegate_;
347 scoped_ptr<MultipartResponseDelegate> multipart_delegate_;
348 scoped_ptr<StreamOverrideParameters> stream_override_;
349 scoped_ptr<SharedMemoryDataConsumerHandle::Writer> body_stream_writer_;
350 enum DeferState {NOT_DEFERRING, SHOULD_DEFER, DEFERRED_DATA};
351 DeferState defers_loading_;
352 int request_id_;
355 WebURLLoaderImpl::Context::Context(
356 WebURLLoaderImpl* loader,
357 ResourceDispatcher* resource_dispatcher,
358 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
359 : loader_(loader),
360 client_(NULL),
361 resource_dispatcher_(resource_dispatcher),
362 task_runner_(task_runner),
363 referrer_policy_(blink::WebReferrerPolicyDefault),
364 defers_loading_(NOT_DEFERRING),
365 request_id_(-1) {
368 void WebURLLoaderImpl::Context::Cancel() {
369 if (resource_dispatcher_ && // NULL in unittest.
370 request_id_ != -1) {
371 resource_dispatcher_->Cancel(request_id_);
372 request_id_ = -1;
375 if (body_stream_writer_)
376 body_stream_writer_->Fail();
378 // Ensure that we do not notify the multipart delegate anymore as it has
379 // its own pointer to the client.
380 if (multipart_delegate_)
381 multipart_delegate_->Cancel();
382 // Ditto for the ftp delegate.
383 if (ftp_listing_delegate_)
384 ftp_listing_delegate_->Cancel();
386 // Do not make any further calls to the client.
387 client_ = NULL;
388 loader_ = NULL;
391 void WebURLLoaderImpl::Context::SetDefersLoading(bool value) {
392 if (request_id_ != -1)
393 resource_dispatcher_->SetDefersLoading(request_id_, value);
394 if (value && defers_loading_ == NOT_DEFERRING) {
395 defers_loading_ = SHOULD_DEFER;
396 } else if (!value && defers_loading_ != NOT_DEFERRING) {
397 if (defers_loading_ == DEFERRED_DATA) {
398 task_runner_->PostTask(FROM_HERE,
399 base::Bind(&Context::HandleDataURL, this));
401 defers_loading_ = NOT_DEFERRING;
405 void WebURLLoaderImpl::Context::DidChangePriority(
406 WebURLRequest::Priority new_priority, int intra_priority_value) {
407 if (request_id_ != -1) {
408 resource_dispatcher_->DidChangePriority(
409 request_id_,
410 ConvertWebKitPriorityToNetPriority(new_priority),
411 intra_priority_value);
415 bool WebURLLoaderImpl::Context::AttachThreadedDataReceiver(
416 blink::WebThreadedDataReceiver* threaded_data_receiver) {
417 if (request_id_ != -1) {
418 return resource_dispatcher_->AttachThreadedDataReceiver(
419 request_id_, threaded_data_receiver);
422 return false;
425 void WebURLLoaderImpl::Context::Start(const WebURLRequest& request,
426 SyncLoadResponse* sync_load_response) {
427 DCHECK(request_id_ == -1);
428 request_ = request; // Save the request.
429 if (request.extraData()) {
430 RequestExtraData* extra_data =
431 static_cast<RequestExtraData*>(request.extraData());
432 stream_override_ = extra_data->TakeStreamOverrideOwnership();
435 GURL url = request.url();
437 // PlzNavigate: during navigation, the renderer should request a stream which
438 // contains the body of the response. The request has already been made by the
439 // browser.
440 if (stream_override_.get()) {
441 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
442 switches::kEnableBrowserSideNavigation));
443 DCHECK(!sync_load_response);
444 DCHECK_NE(WebURLRequest::FrameTypeNone, request.frameType());
445 DCHECK_EQ("GET", request.httpMethod().latin1());
446 url = stream_override_->stream_url;
449 if (CanHandleDataURLRequestLocally()) {
450 if (sync_load_response) {
451 // This is a sync load. Do the work now.
452 sync_load_response->url = url;
453 sync_load_response->error_code =
454 GetInfoFromDataURL(sync_load_response->url, sync_load_response,
455 &sync_load_response->data);
456 } else {
457 task_runner_->PostTask(FROM_HERE,
458 base::Bind(&Context::HandleDataURL, this));
460 return;
463 // PlzNavigate: outside of tests, the only navigation requests going through
464 // the WebURLLoader are the ones created by CommitNavigation. Several browser
465 // tests load HTML directly through a data url which will be handled by the
466 // block above.
467 DCHECK_IMPLIES(base::CommandLine::ForCurrentProcess()->HasSwitch(
468 switches::kEnableBrowserSideNavigation),
469 stream_override_.get() ||
470 request.frameType() == WebURLRequest::FrameTypeNone);
472 GURL referrer_url(
473 request.httpHeaderField(WebString::fromUTF8("Referer")).latin1());
474 const std::string& method = request.httpMethod().latin1();
476 // TODO(brettw) this should take parameter encoding into account when
477 // creating the GURLs.
479 // TODO(horo): Check credentials flag is unset when credentials mode is omit.
480 // Check credentials flag is set when credentials mode is include.
482 RequestInfo request_info;
483 request_info.method = method;
484 request_info.url = url;
485 request_info.first_party_for_cookies = request.firstPartyForCookies();
486 referrer_policy_ = request.referrerPolicy();
487 request_info.referrer = Referrer(referrer_url, referrer_policy_);
488 request_info.headers = GetWebURLRequestHeaders(request);
489 request_info.load_flags = GetLoadFlagsForWebURLRequest(request);
490 request_info.enable_load_timing = true;
491 request_info.enable_upload_progress = request.reportUploadProgress();
492 if (request.requestContext() == WebURLRequest::RequestContextXMLHttpRequest &&
493 (url.has_username() || url.has_password())) {
494 request_info.do_not_prompt_for_login = true;
496 // requestor_pid only needs to be non-zero if the request originates outside
497 // the render process, so we can use requestorProcessID even for requests
498 // from in-process plugins.
499 request_info.requestor_pid = request.requestorProcessID();
500 request_info.request_type = WebURLRequestToResourceType(request);
501 request_info.priority =
502 ConvertWebKitPriorityToNetPriority(request.priority());
503 request_info.appcache_host_id = request.appCacheHostID();
504 request_info.routing_id = request.requestorID();
505 request_info.download_to_file = request.downloadToFile();
506 request_info.has_user_gesture = request.hasUserGesture();
507 request_info.skip_service_worker = request.skipServiceWorker();
508 request_info.should_reset_appcache = request.shouldResetAppCache();
509 request_info.fetch_request_mode = GetFetchRequestMode(request);
510 request_info.fetch_credentials_mode = GetFetchCredentialsMode(request);
511 request_info.fetch_request_context_type = GetRequestContextType(request);
512 request_info.fetch_frame_type = GetRequestContextFrameType(request);
513 request_info.extra_data = request.extraData();
515 scoped_refptr<ResourceRequestBody> request_body =
516 GetRequestBodyForWebURLRequest(request).get();
518 if (sync_load_response) {
519 resource_dispatcher_->StartSync(
520 request_info, request_body.get(), sync_load_response);
521 return;
524 request_id_ = resource_dispatcher_->StartAsync(
525 request_info, request_body.get(), this);
528 void WebURLLoaderImpl::Context::OnUploadProgress(uint64 position, uint64 size) {
529 if (client_)
530 client_->didSendData(loader_, position, size);
533 bool WebURLLoaderImpl::Context::OnReceivedRedirect(
534 const net::RedirectInfo& redirect_info,
535 const ResourceResponseInfo& info) {
536 if (!client_)
537 return false;
539 WebURLResponse response;
540 response.initialize();
541 PopulateURLResponse(request_.url(), info, &response);
543 // TODO(darin): We lack sufficient information to construct the actual
544 // request that resulted from the redirect.
545 WebURLRequest new_request(redirect_info.new_url);
546 new_request.setFirstPartyForCookies(
547 redirect_info.new_first_party_for_cookies);
548 new_request.setDownloadToFile(request_.downloadToFile());
549 new_request.setUseStreamOnResponse(request_.useStreamOnResponse());
550 new_request.setRequestContext(request_.requestContext());
551 new_request.setFrameType(request_.frameType());
552 new_request.setSkipServiceWorker(request_.skipServiceWorker());
553 new_request.setShouldResetAppCache(request_.shouldResetAppCache());
554 new_request.setFetchRequestMode(request_.fetchRequestMode());
555 new_request.setFetchCredentialsMode(request_.fetchCredentialsMode());
557 new_request.setHTTPReferrer(WebString::fromUTF8(redirect_info.new_referrer),
558 referrer_policy_);
560 std::string old_method = request_.httpMethod().utf8();
561 new_request.setHTTPMethod(WebString::fromUTF8(redirect_info.new_method));
562 if (redirect_info.new_method == old_method)
563 new_request.setHTTPBody(request_.httpBody());
565 // Protect from deletion during call to willSendRequest.
566 scoped_refptr<Context> protect(this);
568 client_->willSendRequest(loader_, new_request, response);
569 request_ = new_request;
571 // Only follow the redirect if WebKit left the URL unmodified.
572 if (redirect_info.new_url == GURL(new_request.url())) {
573 // First-party cookie logic moved from DocumentLoader in Blink to
574 // net::URLRequest in the browser. Assert that Blink didn't try to change it
575 // to something else.
576 DCHECK_EQ(redirect_info.new_first_party_for_cookies.spec(),
577 request_.firstPartyForCookies().string().utf8());
578 return true;
581 // We assume that WebKit only changes the URL to suppress a redirect, and we
582 // assume that it does so by setting it to be invalid.
583 DCHECK(!new_request.url().isValid());
584 return false;
587 void WebURLLoaderImpl::Context::OnReceivedResponse(
588 const ResourceResponseInfo& initial_info) {
589 if (!client_)
590 return;
592 ResourceResponseInfo info = initial_info;
594 // PlzNavigate: during navigations, the ResourceResponse has already been
595 // received on the browser side, and has been passed down to the renderer.
596 if (stream_override_.get()) {
597 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
598 switches::kEnableBrowserSideNavigation));
599 info = stream_override_->response;
602 WebURLResponse response;
603 response.initialize();
604 PopulateURLResponse(request_.url(), info, &response);
606 bool show_raw_listing = (GURL(request_.url()).query() == "raw");
608 if (info.mime_type == "text/vnd.chromium.ftp-dir") {
609 if (show_raw_listing) {
610 // Set the MIME type to plain text to prevent any active content.
611 response.setMIMEType("text/plain");
612 } else {
613 // We're going to produce a parsed listing in HTML.
614 response.setMIMEType("text/html");
618 // Prevent |this| from being destroyed if the client destroys the loader,
619 // ether in didReceiveResponse, or when the multipart/ftp delegate calls into
620 // it.
621 scoped_refptr<Context> protect(this);
623 if (request_.useStreamOnResponse()) {
624 SharedMemoryDataConsumerHandle::BackpressureMode mode =
625 SharedMemoryDataConsumerHandle::kDoNotApplyBackpressure;
626 if (info.headers &&
627 info.headers->HasHeaderValue("Cache-Control", "no-store")) {
628 mode = SharedMemoryDataConsumerHandle::kApplyBackpressure;
631 auto read_handle = make_scoped_ptr(new SharedMemoryDataConsumerHandle(
632 mode, base::Bind(&Context::CancelBodyStreaming, this),
633 &body_stream_writer_));
635 // Here |body_stream_writer_| has an indirect reference to |this| and that
636 // creates a reference cycle, but it is not a problem because the cycle
637 // will break if one of the following happens:
638 // 1) The body data transfer is done (with or without an error).
639 // 2) |read_handle| (and its reader) is detached.
641 // The client takes |read_handle|'s ownership.
642 client_->didReceiveResponse(loader_, response, read_handle.release());
643 // TODO(yhirano): Support ftp listening and multipart
644 return;
645 } else {
646 client_->didReceiveResponse(loader_, response);
649 // We may have been cancelled after didReceiveResponse, which would leave us
650 // without a client and therefore without much need to do further handling.
651 if (!client_)
652 return;
654 DCHECK(!ftp_listing_delegate_.get());
655 DCHECK(!multipart_delegate_.get());
656 if (info.headers.get() && info.mime_type == "multipart/x-mixed-replace") {
657 std::string content_type;
658 info.headers->EnumerateHeader(NULL, "content-type", &content_type);
660 std::string mime_type;
661 std::string charset;
662 bool had_charset = false;
663 std::string boundary;
664 net::HttpUtil::ParseContentType(content_type, &mime_type, &charset,
665 &had_charset, &boundary);
666 base::TrimString(boundary, " \"", &boundary);
668 // If there's no boundary, just handle the request normally. In the gecko
669 // code, nsMultiMixedConv::OnStartRequest throws an exception.
670 if (!boundary.empty()) {
671 multipart_delegate_.reset(
672 new MultipartResponseDelegate(client_, loader_, response, boundary));
674 } else if (info.mime_type == "text/vnd.chromium.ftp-dir" &&
675 !show_raw_listing) {
676 ftp_listing_delegate_.reset(
677 new FtpDirectoryListingResponseDelegate(client_, loader_, response));
681 void WebURLLoaderImpl::Context::OnDownloadedData(int len,
682 int encoded_data_length) {
683 if (client_)
684 client_->didDownloadData(loader_, len, encoded_data_length);
687 void WebURLLoaderImpl::Context::OnReceivedData(scoped_ptr<ReceivedData> data) {
688 const char* payload = data->payload();
689 int data_length = data->length();
690 int encoded_data_length = data->encoded_length();
691 if (!client_)
692 return;
694 if (ftp_listing_delegate_) {
695 // The FTP listing delegate will make the appropriate calls to
696 // client_->didReceiveData and client_->didReceiveResponse. Since the
697 // delegate may want to do work after sending data to the delegate, keep
698 // |this| and the delegate alive until it's finished handling the data.
699 scoped_refptr<Context> protect(this);
700 ftp_listing_delegate_->OnReceivedData(payload, data_length);
701 } else if (multipart_delegate_) {
702 // The multipart delegate will make the appropriate calls to
703 // client_->didReceiveData and client_->didReceiveResponse. Since the
704 // delegate may want to do work after sending data to the delegate, keep
705 // |this| and the delegate alive until it's finished handling the data.
706 scoped_refptr<Context> protect(this);
707 multipart_delegate_->OnReceivedData(payload, data_length,
708 encoded_data_length);
709 } else {
710 scoped_refptr<Context> protect(this);
711 // We dispatch the data even when |useStreamOnResponse()| is set, in order
712 // to make Devtools work.
713 client_->didReceiveData(loader_, payload, data_length, encoded_data_length);
715 if (request_.useStreamOnResponse()) {
716 // We don't support ftp_listening_delegate_ and multipart_delegate_ for
717 // now.
718 // TODO(yhirano): Support ftp listening and multipart.
719 body_stream_writer_->AddData(data.Pass());
724 void WebURLLoaderImpl::Context::OnReceivedCachedMetadata(
725 const char* data, int len) {
726 if (client_)
727 client_->didReceiveCachedMetadata(loader_, data, len);
730 void WebURLLoaderImpl::Context::OnCompletedRequest(
731 int error_code,
732 bool was_ignored_by_handler,
733 bool stale_copy_in_cache,
734 const std::string& security_info,
735 const base::TimeTicks& completion_time,
736 int64 total_transfer_size) {
737 // The WebURLLoaderImpl may be deleted in any of the calls to the client or
738 // the delegates below (As they also may call in to the client). Keep |this|
739 // alive in that case, to avoid a crash. If that happens, the request will be
740 // cancelled and |client_| will be set to NULL.
741 scoped_refptr<Context> protect(this);
743 if (ftp_listing_delegate_) {
744 ftp_listing_delegate_->OnCompletedRequest();
745 ftp_listing_delegate_.reset(NULL);
746 } else if (multipart_delegate_) {
747 multipart_delegate_->OnCompletedRequest();
748 multipart_delegate_.reset(NULL);
751 if (body_stream_writer_ && error_code != net::OK)
752 body_stream_writer_->Fail();
753 body_stream_writer_.reset();
755 if (client_) {
756 if (error_code != net::OK) {
757 client_->didFail(
758 loader_,
759 CreateWebURLError(request_.url(), stale_copy_in_cache, error_code,
760 was_ignored_by_handler));
761 } else {
762 client_->didFinishLoading(loader_,
763 (completion_time - TimeTicks()).InSecondsF(),
764 total_transfer_size);
769 void WebURLLoaderImpl::Context::OnReceivedCompletedResponse(
770 const ResourceResponseInfo& info,
771 scoped_ptr<ReceivedData> data,
772 int error_code,
773 bool was_ignored_by_handler,
774 bool stale_copy_in_cache,
775 const std::string& security_info,
776 const base::TimeTicks& completion_time,
777 int64 total_transfer_size) {
778 scoped_refptr<Context> protect(this);
780 OnReceivedResponse(info);
781 if (data)
782 OnReceivedData(data.Pass());
783 OnCompletedRequest(error_code, was_ignored_by_handler, stale_copy_in_cache,
784 security_info, completion_time, total_transfer_size);
787 WebURLLoaderImpl::Context::~Context() {
788 if (request_id_ >= 0) {
789 resource_dispatcher_->RemovePendingRequest(request_id_);
793 void WebURLLoaderImpl::Context::CancelBodyStreaming() {
794 scoped_refptr<Context> protect(this);
796 // Notify renderer clients that the request is canceled.
797 if (ftp_listing_delegate_) {
798 ftp_listing_delegate_->OnCompletedRequest();
799 ftp_listing_delegate_.reset(NULL);
800 } else if (multipart_delegate_) {
801 multipart_delegate_->OnCompletedRequest();
802 multipart_delegate_.reset(NULL);
805 if (body_stream_writer_) {
806 body_stream_writer_->Fail();
807 body_stream_writer_.reset();
809 if (client_) {
810 // TODO(yhirano): Set |stale_copy_in_cache| appropriately if possible.
811 client_->didFail(
812 loader_, CreateWebURLError(request_.url(), false, net::ERR_ABORTED));
815 // Notify the browser process that the request is canceled.
816 Cancel();
819 bool WebURLLoaderImpl::Context::CanHandleDataURLRequestLocally() const {
820 GURL url = request_.url();
821 if (!url.SchemeIs(url::kDataScheme))
822 return false;
824 // The fast paths for data URL, Start() and HandleDataURL(), don't support
825 // the downloadToFile option.
826 if (request_.downloadToFile())
827 return false;
829 // Data url requests from object tags may need to be intercepted as streams
830 // and so need to be sent to the browser.
831 if (request_.requestContext() == WebURLRequest::RequestContextObject)
832 return false;
834 // Optimize for the case where we can handle a data URL locally. We must
835 // skip this for data URLs targetted at frames since those could trigger a
836 // download.
838 // NOTE: We special case MIME types we can render both for performance
839 // reasons as well as to support unit tests.
841 #if defined(OS_ANDROID)
842 // For compatibility reasons on Android we need to expose top-level data://
843 // to the browser.
844 if (request_.frameType() == WebURLRequest::FrameTypeTopLevel)
845 return false;
846 #endif
848 if (request_.frameType() != WebURLRequest::FrameTypeTopLevel &&
849 request_.frameType() != WebURLRequest::FrameTypeNested)
850 return true;
852 std::string mime_type, unused_charset;
853 if (net::DataURL::Parse(request_.url(), &mime_type, &unused_charset, NULL) &&
854 mime_util::IsSupportedMimeType(mime_type))
855 return true;
857 return false;
860 void WebURLLoaderImpl::Context::HandleDataURL() {
861 DCHECK_NE(defers_loading_, DEFERRED_DATA);
862 if (defers_loading_ == SHOULD_DEFER) {
863 defers_loading_ = DEFERRED_DATA;
864 return;
867 ResourceResponseInfo info;
868 std::string data;
870 int error_code = GetInfoFromDataURL(request_.url(), &info, &data);
872 if (error_code == net::OK) {
873 OnReceivedResponse(info);
874 if (!data.empty())
875 OnReceivedData(
876 make_scoped_ptr(new FixedReceivedData(data.data(), data.size(), 0)));
879 OnCompletedRequest(error_code, false, false, info.security_info,
880 base::TimeTicks::Now(), 0);
883 // WebURLLoaderImpl -----------------------------------------------------------
885 WebURLLoaderImpl::WebURLLoaderImpl(
886 ResourceDispatcher* resource_dispatcher,
887 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
888 : context_(new Context(this, resource_dispatcher, task_runner)) {
891 WebURLLoaderImpl::~WebURLLoaderImpl() {
892 cancel();
895 void WebURLLoaderImpl::PopulateURLResponse(const GURL& url,
896 const ResourceResponseInfo& info,
897 WebURLResponse* response) {
898 response->setURL(url);
899 response->setResponseTime(info.response_time.ToInternalValue());
900 response->setMIMEType(WebString::fromUTF8(info.mime_type));
901 response->setTextEncodingName(WebString::fromUTF8(info.charset));
902 response->setExpectedContentLength(info.content_length);
903 response->setSecurityInfo(info.security_info);
904 response->setAppCacheID(info.appcache_id);
905 response->setAppCacheManifestURL(info.appcache_manifest_url);
906 response->setWasCached(!info.load_timing.request_start_time.is_null() &&
907 info.response_time < info.load_timing.request_start_time);
908 response->setRemoteIPAddress(
909 WebString::fromUTF8(info.socket_address.host()));
910 response->setRemotePort(info.socket_address.port());
911 response->setConnectionID(info.load_timing.socket_log_id);
912 response->setConnectionReused(info.load_timing.socket_reused);
913 response->setDownloadFilePath(info.download_file_path.AsUTF16Unsafe());
914 response->setWasFetchedViaSPDY(info.was_fetched_via_spdy);
915 response->setWasFetchedViaServiceWorker(info.was_fetched_via_service_worker);
916 response->setWasFallbackRequiredByServiceWorker(
917 info.was_fallback_required_by_service_worker);
918 response->setServiceWorkerResponseType(info.response_type_via_service_worker);
919 response->setOriginalURLViaServiceWorker(
920 info.original_url_via_service_worker);
922 WebURLResponseExtraDataImpl* extra_data =
923 new WebURLResponseExtraDataImpl(info.npn_negotiated_protocol);
924 response->setExtraData(extra_data);
925 extra_data->set_was_fetched_via_spdy(info.was_fetched_via_spdy);
926 extra_data->set_was_npn_negotiated(info.was_npn_negotiated);
927 extra_data->set_was_alternate_protocol_available(
928 info.was_alternate_protocol_available);
929 extra_data->set_connection_info(info.connection_info);
930 extra_data->set_was_fetched_via_proxy(info.was_fetched_via_proxy);
931 extra_data->set_proxy_server(info.proxy_server);
933 // If there's no received headers end time, don't set load timing. This is
934 // the case for non-HTTP requests, requests that don't go over the wire, and
935 // certain error cases.
936 if (!info.load_timing.receive_headers_end.is_null()) {
937 WebURLLoadTiming timing;
938 PopulateURLLoadTiming(info.load_timing, &timing);
939 const TimeTicks kNullTicks;
940 timing.setWorkerStart(
941 (info.service_worker_start_time - kNullTicks).InSecondsF());
942 timing.setWorkerReady(
943 (info.service_worker_ready_time - kNullTicks).InSecondsF());
944 response->setLoadTiming(timing);
947 if (info.devtools_info.get()) {
948 WebHTTPLoadInfo load_info;
950 load_info.setHTTPStatusCode(info.devtools_info->http_status_code);
951 load_info.setHTTPStatusText(WebString::fromLatin1(
952 info.devtools_info->http_status_text));
953 load_info.setEncodedDataLength(info.encoded_data_length);
955 load_info.setRequestHeadersText(WebString::fromLatin1(
956 info.devtools_info->request_headers_text));
957 load_info.setResponseHeadersText(WebString::fromLatin1(
958 info.devtools_info->response_headers_text));
959 const HeadersVector& request_headers = info.devtools_info->request_headers;
960 for (HeadersVector::const_iterator it = request_headers.begin();
961 it != request_headers.end(); ++it) {
962 load_info.addRequestHeader(WebString::fromLatin1(it->first),
963 WebString::fromLatin1(it->second));
965 const HeadersVector& response_headers =
966 info.devtools_info->response_headers;
967 for (HeadersVector::const_iterator it = response_headers.begin();
968 it != response_headers.end(); ++it) {
969 load_info.addResponseHeader(WebString::fromLatin1(it->first),
970 WebString::fromLatin1(it->second));
972 load_info.setNPNNegotiatedProtocol(WebString::fromLatin1(
973 info.npn_negotiated_protocol));
974 response->setHTTPLoadInfo(load_info);
977 const net::HttpResponseHeaders* headers = info.headers.get();
978 if (!headers)
979 return;
981 WebURLResponse::HTTPVersion version = WebURLResponse::Unknown;
982 if (headers->GetHttpVersion() == net::HttpVersion(0, 9))
983 version = WebURLResponse::HTTP_0_9;
984 else if (headers->GetHttpVersion() == net::HttpVersion(1, 0))
985 version = WebURLResponse::HTTP_1_0;
986 else if (headers->GetHttpVersion() == net::HttpVersion(1, 1))
987 version = WebURLResponse::HTTP_1_1;
988 response->setHTTPVersion(version);
989 response->setHTTPStatusCode(headers->response_code());
990 response->setHTTPStatusText(WebString::fromLatin1(headers->GetStatusText()));
992 // TODO(darin): We should leverage HttpResponseHeaders for this, and this
993 // should be using the same code as ResourceDispatcherHost.
994 // TODO(jungshik): Figure out the actual value of the referrer charset and
995 // pass it to GetSuggestedFilename.
996 std::string value;
997 headers->EnumerateHeader(NULL, "content-disposition", &value);
998 response->setSuggestedFileName(
999 net::GetSuggestedFilename(url,
1000 value,
1001 std::string(), // referrer_charset
1002 std::string(), // suggested_name
1003 std::string(), // mime_type
1004 std::string())); // default_name
1006 Time time_val;
1007 if (headers->GetLastModifiedValue(&time_val))
1008 response->setLastModifiedDate(time_val.ToDoubleT());
1010 // Build up the header map.
1011 void* iter = NULL;
1012 std::string name;
1013 while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
1014 response->addHTTPHeaderField(WebString::fromLatin1(name),
1015 WebString::fromLatin1(value));
1019 void WebURLLoaderImpl::loadSynchronously(const WebURLRequest& request,
1020 WebURLResponse& response,
1021 WebURLError& error,
1022 WebData& data) {
1023 SyncLoadResponse sync_load_response;
1024 context_->Start(request, &sync_load_response);
1026 const GURL& final_url = sync_load_response.url;
1028 // TODO(tc): For file loads, we may want to include a more descriptive
1029 // status code or status text.
1030 int error_code = sync_load_response.error_code;
1031 if (error_code != net::OK) {
1032 response.setURL(final_url);
1033 error.domain = WebString::fromUTF8(net::kErrorDomain);
1034 error.reason = error_code;
1035 error.unreachableURL = final_url;
1036 return;
1039 PopulateURLResponse(final_url, sync_load_response, &response);
1041 data.assign(sync_load_response.data.data(),
1042 sync_load_response.data.size());
1045 void WebURLLoaderImpl::loadAsynchronously(const WebURLRequest& request,
1046 WebURLLoaderClient* client) {
1047 DCHECK(!context_->client());
1049 context_->set_client(client);
1050 context_->Start(request, NULL);
1053 void WebURLLoaderImpl::cancel() {
1054 context_->Cancel();
1057 void WebURLLoaderImpl::setDefersLoading(bool value) {
1058 context_->SetDefersLoading(value);
1061 void WebURLLoaderImpl::didChangePriority(WebURLRequest::Priority new_priority,
1062 int intra_priority_value) {
1063 context_->DidChangePriority(new_priority, intra_priority_value);
1066 bool WebURLLoaderImpl::attachThreadedDataReceiver(
1067 blink::WebThreadedDataReceiver* threaded_data_receiver) {
1068 return context_->AttachThreadedDataReceiver(threaded_data_receiver);
1071 } // namespace content