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"
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/files/file_path.h"
13 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/strings/string_util.h"
17 #include "base/time/time.h"
18 #include "components/mime_util/mime_util.h"
19 #include "content/child/child_thread_impl.h"
20 #include "content/child/ftp_directory_listing_response_delegate.h"
21 #include "content/child/multipart_response_delegate.h"
22 #include "content/child/request_extra_data.h"
23 #include "content/child/request_info.h"
24 #include "content/child/resource_dispatcher.h"
25 #include "content/child/shared_memory_data_consumer_handle.h"
26 #include "content/child/sync_load_response.h"
27 #include "content/child/web_url_request_util.h"
28 #include "content/child/weburlresponse_extradata_impl.h"
29 #include "content/common/resource_messages.h"
30 #include "content/common/resource_request_body.h"
31 #include "content/common/service_worker/service_worker_types.h"
32 #include "content/common/ssl_status_serialization.h"
33 #include "content/public/child/fixed_received_data.h"
34 #include "content/public/child/request_peer.h"
35 #include "content/public/common/content_switches.h"
36 #include "net/base/data_url.h"
37 #include "net/base/filename_util.h"
38 #include "net/base/net_errors.h"
39 #include "net/http/http_response_headers.h"
40 #include "net/http/http_util.h"
41 #include "net/ssl/ssl_cipher_suite_names.h"
42 #include "net/ssl/ssl_connection_status_flags.h"
43 #include "net/url_request/redirect_info.h"
44 #include "net/url_request/url_request_data_job.h"
45 #include "third_party/WebKit/public/platform/WebHTTPLoadInfo.h"
46 #include "third_party/WebKit/public/platform/WebURL.h"
47 #include "third_party/WebKit/public/platform/WebURLError.h"
48 #include "third_party/WebKit/public/platform/WebURLLoadTiming.h"
49 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
50 #include "third_party/WebKit/public/platform/WebURLRequest.h"
51 #include "third_party/WebKit/public/platform/WebURLResponse.h"
52 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
55 using base::TimeTicks
;
57 using blink::WebHTTPBody
;
58 using blink::WebHTTPHeaderVisitor
;
59 using blink::WebHTTPLoadInfo
;
60 using blink::WebReferrerPolicy
;
61 using blink::WebSecurityPolicy
;
62 using blink::WebString
;
64 using blink::WebURLError
;
65 using blink::WebURLLoadTiming
;
66 using blink::WebURLLoader
;
67 using blink::WebURLLoaderClient
;
68 using blink::WebURLRequest
;
69 using blink::WebURLResponse
;
73 // Utilities ------------------------------------------------------------------
77 using HeadersVector
= ResourceDevToolsInfo::HeadersVector
;
79 // Converts timing data from |load_timing| to the format used by WebKit.
80 void PopulateURLLoadTiming(const net::LoadTimingInfo
& load_timing
,
81 WebURLLoadTiming
* url_timing
) {
82 DCHECK(!load_timing
.request_start
.is_null());
84 const TimeTicks kNullTicks
;
85 url_timing
->initialize();
86 url_timing
->setRequestTime(
87 (load_timing
.request_start
- kNullTicks
).InSecondsF());
88 url_timing
->setProxyStart(
89 (load_timing
.proxy_resolve_start
- kNullTicks
).InSecondsF());
90 url_timing
->setProxyEnd(
91 (load_timing
.proxy_resolve_end
- kNullTicks
).InSecondsF());
92 url_timing
->setDNSStart(
93 (load_timing
.connect_timing
.dns_start
- kNullTicks
).InSecondsF());
94 url_timing
->setDNSEnd(
95 (load_timing
.connect_timing
.dns_end
- kNullTicks
).InSecondsF());
96 url_timing
->setConnectStart(
97 (load_timing
.connect_timing
.connect_start
- kNullTicks
).InSecondsF());
98 url_timing
->setConnectEnd(
99 (load_timing
.connect_timing
.connect_end
- kNullTicks
).InSecondsF());
100 url_timing
->setSSLStart(
101 (load_timing
.connect_timing
.ssl_start
- kNullTicks
).InSecondsF());
102 url_timing
->setSSLEnd(
103 (load_timing
.connect_timing
.ssl_end
- kNullTicks
).InSecondsF());
104 url_timing
->setSendStart(
105 (load_timing
.send_start
- kNullTicks
).InSecondsF());
106 url_timing
->setSendEnd(
107 (load_timing
.send_end
- kNullTicks
).InSecondsF());
108 url_timing
->setReceiveHeadersEnd(
109 (load_timing
.receive_headers_end
- kNullTicks
).InSecondsF());
112 net::RequestPriority
ConvertWebKitPriorityToNetPriority(
113 const WebURLRequest::Priority
& priority
) {
115 case WebURLRequest::PriorityVeryHigh
:
118 case WebURLRequest::PriorityHigh
:
121 case WebURLRequest::PriorityMedium
:
124 case WebURLRequest::PriorityLow
:
127 case WebURLRequest::PriorityVeryLow
:
130 case WebURLRequest::PriorityUnresolved
:
137 // Extracts info from a data scheme URL |url| into |info| and |data|. Returns
138 // net::OK if successful. Returns a net error code otherwise.
139 int GetInfoFromDataURL(const GURL
& url
,
140 ResourceResponseInfo
* info
,
142 // Assure same time for all time fields of data: URLs.
143 Time now
= Time::Now();
144 info
->load_timing
.request_start
= TimeTicks::Now();
145 info
->load_timing
.request_start_time
= now
;
146 info
->request_time
= now
;
147 info
->response_time
= now
;
149 std::string mime_type
;
151 scoped_refptr
<net::HttpResponseHeaders
> headers(
152 new net::HttpResponseHeaders(std::string()));
153 int result
= net::URLRequestDataJob::BuildResponse(
154 url
, &mime_type
, &charset
, data
, headers
.get());
155 if (result
!= net::OK
)
158 info
->headers
= headers
;
159 info
->mime_type
.swap(mime_type
);
160 info
->charset
.swap(charset
);
161 info
->security_info
.clear();
162 info
->content_length
= data
->length();
163 info
->encoded_data_length
= 0;
168 #define STATIC_ASSERT_MATCHING_ENUMS(content_name, blink_name) \
170 static_cast<int>(content_name) == static_cast<int>(blink_name), \
171 "mismatching enums: " #content_name)
173 STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_SAME_ORIGIN
,
174 WebURLRequest::FetchRequestModeSameOrigin
);
175 STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_NO_CORS
,
176 WebURLRequest::FetchRequestModeNoCORS
);
177 STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_CORS
,
178 WebURLRequest::FetchRequestModeCORS
);
179 STATIC_ASSERT_MATCHING_ENUMS(
180 FETCH_REQUEST_MODE_CORS_WITH_FORCED_PREFLIGHT
,
181 WebURLRequest::FetchRequestModeCORSWithForcedPreflight
);
183 FetchRequestMode
GetFetchRequestMode(const WebURLRequest
& request
) {
184 return static_cast<FetchRequestMode
>(request
.fetchRequestMode());
187 STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_OMIT
,
188 WebURLRequest::FetchCredentialsModeOmit
);
189 STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_SAME_ORIGIN
,
190 WebURLRequest::FetchCredentialsModeSameOrigin
);
191 STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_INCLUDE
,
192 WebURLRequest::FetchCredentialsModeInclude
);
194 FetchCredentialsMode
GetFetchCredentialsMode(const WebURLRequest
& request
) {
195 return static_cast<FetchCredentialsMode
>(request
.fetchCredentialsMode());
198 STATIC_ASSERT_MATCHING_ENUMS(FetchRedirectMode::FOLLOW_MODE
,
199 WebURLRequest::FetchRedirectModeFollow
);
200 STATIC_ASSERT_MATCHING_ENUMS(FetchRedirectMode::ERROR_MODE
,
201 WebURLRequest::FetchRedirectModeError
);
202 STATIC_ASSERT_MATCHING_ENUMS(FetchRedirectMode::MANUAL_MODE
,
203 WebURLRequest::FetchRedirectModeManual
);
205 FetchRedirectMode
GetFetchRedirectMode(const WebURLRequest
& request
) {
206 return static_cast<FetchRedirectMode
>(request
.fetchRedirectMode());
209 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_AUXILIARY
,
210 WebURLRequest::FrameTypeAuxiliary
);
211 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_NESTED
,
212 WebURLRequest::FrameTypeNested
);
213 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_NONE
,
214 WebURLRequest::FrameTypeNone
);
215 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL
,
216 WebURLRequest::FrameTypeTopLevel
);
218 RequestContextFrameType
GetRequestContextFrameType(
219 const WebURLRequest
& request
) {
220 return static_cast<RequestContextFrameType
>(request
.frameType());
223 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_UNSPECIFIED
,
224 WebURLRequest::RequestContextUnspecified
);
225 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_AUDIO
,
226 WebURLRequest::RequestContextAudio
);
227 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_BEACON
,
228 WebURLRequest::RequestContextBeacon
);
229 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_CSP_REPORT
,
230 WebURLRequest::RequestContextCSPReport
);
231 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_DOWNLOAD
,
232 WebURLRequest::RequestContextDownload
);
233 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_EMBED
,
234 WebURLRequest::RequestContextEmbed
);
235 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_EVENT_SOURCE
,
236 WebURLRequest::RequestContextEventSource
);
237 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FAVICON
,
238 WebURLRequest::RequestContextFavicon
);
239 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FETCH
,
240 WebURLRequest::RequestContextFetch
);
241 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FONT
,
242 WebURLRequest::RequestContextFont
);
243 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FORM
,
244 WebURLRequest::RequestContextForm
);
245 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FRAME
,
246 WebURLRequest::RequestContextFrame
);
247 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_HYPERLINK
,
248 WebURLRequest::RequestContextHyperlink
);
249 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IFRAME
,
250 WebURLRequest::RequestContextIframe
);
251 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMAGE
,
252 WebURLRequest::RequestContextImage
);
253 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMAGE_SET
,
254 WebURLRequest::RequestContextImageSet
);
255 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMPORT
,
256 WebURLRequest::RequestContextImport
);
257 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_INTERNAL
,
258 WebURLRequest::RequestContextInternal
);
259 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_LOCATION
,
260 WebURLRequest::RequestContextLocation
);
261 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_MANIFEST
,
262 WebURLRequest::RequestContextManifest
);
263 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_OBJECT
,
264 WebURLRequest::RequestContextObject
);
265 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PING
,
266 WebURLRequest::RequestContextPing
);
267 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PLUGIN
,
268 WebURLRequest::RequestContextPlugin
);
269 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PREFETCH
,
270 WebURLRequest::RequestContextPrefetch
);
271 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SCRIPT
,
272 WebURLRequest::RequestContextScript
);
273 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SERVICE_WORKER
,
274 WebURLRequest::RequestContextServiceWorker
);
275 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SHARED_WORKER
,
276 WebURLRequest::RequestContextSharedWorker
);
277 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SUBRESOURCE
,
278 WebURLRequest::RequestContextSubresource
);
279 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_STYLE
,
280 WebURLRequest::RequestContextStyle
);
281 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_TRACK
,
282 WebURLRequest::RequestContextTrack
);
283 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_VIDEO
,
284 WebURLRequest::RequestContextVideo
);
285 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_WORKER
,
286 WebURLRequest::RequestContextWorker
);
287 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_XML_HTTP_REQUEST
,
288 WebURLRequest::RequestContextXMLHttpRequest
);
289 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_XSLT
,
290 WebURLRequest::RequestContextXSLT
);
292 RequestContextType
GetRequestContextType(const WebURLRequest
& request
) {
293 return static_cast<RequestContextType
>(request
.requestContext());
296 void SetSecurityStyleAndDetails(const GURL
& url
,
297 const std::string
& security_info
,
298 WebURLResponse
* response
,
299 bool report_security_info
) {
300 if (!report_security_info
) {
301 response
->setSecurityStyle(WebURLResponse::SecurityStyleUnknown
);
304 if (!url
.SchemeIsCryptographic()) {
305 response
->setSecurityStyle(WebURLResponse::SecurityStyleUnauthenticated
);
309 // There are cases where an HTTPS request can come in without security
310 // info attached (such as a redirect response).
311 if (security_info
.empty()) {
312 response
->setSecurityStyle(WebURLResponse::SecurityStyleUnknown
);
316 SSLStatus ssl_status
;
317 if (!DeserializeSecurityInfo(security_info
, &ssl_status
)) {
318 response
->setSecurityStyle(WebURLResponse::SecurityStyleUnknown
);
320 << "DeserializeSecurityInfo() failed for an authenticated request.";
325 net::SSLConnectionStatusToVersion(ssl_status
.connection_status
);
326 const char* protocol
;
327 net::SSLVersionToString(&protocol
, ssl_version
);
329 const char* key_exchange
;
333 uint16_t cipher_suite
=
334 net::SSLConnectionStatusToCipherSuite(ssl_status
.connection_status
);
335 net::SSLCipherSuiteToStrings(&key_exchange
, &cipher
, &mac
, &is_aead
,
342 blink::WebURLResponse::SecurityStyle securityStyle
=
343 WebURLResponse::SecurityStyleUnknown
;
344 switch (ssl_status
.security_style
) {
345 case SECURITY_STYLE_UNKNOWN
:
346 securityStyle
= WebURLResponse::SecurityStyleUnknown
;
348 case SECURITY_STYLE_UNAUTHENTICATED
:
349 securityStyle
= WebURLResponse::SecurityStyleUnauthenticated
;
351 case SECURITY_STYLE_AUTHENTICATION_BROKEN
:
352 securityStyle
= WebURLResponse::SecurityStyleAuthenticationBroken
;
354 case SECURITY_STYLE_WARNING
:
355 securityStyle
= WebURLResponse::SecurityStyleWarning
;
357 case SECURITY_STYLE_AUTHENTICATED
:
358 securityStyle
= WebURLResponse::SecurityStyleAuthenticated
;
362 response
->setSecurityStyle(securityStyle
);
364 blink::WebString protocol_string
= blink::WebString::fromUTF8(protocol
);
365 blink::WebString cipher_string
= blink::WebString::fromUTF8(cipher
);
366 blink::WebString key_exchange_string
=
367 blink::WebString::fromUTF8(key_exchange
);
368 blink::WebString mac_string
= blink::WebString::fromUTF8(mac
);
369 response
->setSecurityDetails(protocol_string
, key_exchange_string
,
370 cipher_string
, mac_string
,
376 // WebURLLoaderImpl::Context --------------------------------------------------
378 // This inner class exists since the WebURLLoader may be deleted while inside a
379 // call to WebURLLoaderClient. Refcounting is to keep the context from being
380 // deleted if it may have work to do after calling into the client.
381 class WebURLLoaderImpl::Context
: public base::RefCounted
<Context
>,
384 Context(WebURLLoaderImpl
* loader
,
385 ResourceDispatcher
* resource_dispatcher
,
386 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
);
388 WebURLLoaderClient
* client() const { return client_
; }
389 void set_client(WebURLLoaderClient
* client
) { client_
= client
; }
392 void SetDefersLoading(bool value
);
393 void DidChangePriority(WebURLRequest::Priority new_priority
,
394 int intra_priority_value
);
395 bool AttachThreadedDataReceiver(
396 blink::WebThreadedDataReceiver
* threaded_data_receiver
);
397 void Start(const WebURLRequest
& request
,
398 SyncLoadResponse
* sync_load_response
);
400 // RequestPeer methods:
401 void OnUploadProgress(uint64 position
, uint64 size
) override
;
402 bool OnReceivedRedirect(const net::RedirectInfo
& redirect_info
,
403 const ResourceResponseInfo
& info
) override
;
404 void OnReceivedResponse(const ResourceResponseInfo
& info
) override
;
405 void OnDownloadedData(int len
, int encoded_data_length
) override
;
406 void OnReceivedData(scoped_ptr
<ReceivedData
> data
) override
;
407 void OnReceivedCachedMetadata(const char* data
, int len
) override
;
408 void OnCompletedRequest(int error_code
,
409 bool was_ignored_by_handler
,
410 bool stale_copy_in_cache
,
411 const std::string
& security_info
,
412 const base::TimeTicks
& completion_time
,
413 int64 total_transfer_size
) override
;
414 void OnReceivedCompletedResponse(const ResourceResponseInfo
& info
,
415 scoped_ptr
<ReceivedData
> data
,
417 bool was_ignored_by_handler
,
418 bool stale_copy_in_cache
,
419 const std::string
& security_info
,
420 const base::TimeTicks
& completion_time
,
421 int64 total_transfer_size
) override
;
424 friend class base::RefCounted
<Context
>;
427 // Called when the body data stream is detached from the reader side.
428 void CancelBodyStreaming();
429 // We can optimize the handling of data URLs in most cases.
430 bool CanHandleDataURLRequestLocally() const;
431 void HandleDataURL();
433 WebURLLoaderImpl
* loader_
;
434 WebURLRequest request_
;
435 WebURLLoaderClient
* client_
;
436 ResourceDispatcher
* resource_dispatcher_
;
437 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
438 WebReferrerPolicy referrer_policy_
;
439 scoped_ptr
<FtpDirectoryListingResponseDelegate
> ftp_listing_delegate_
;
440 scoped_ptr
<MultipartResponseDelegate
> multipart_delegate_
;
441 scoped_ptr
<StreamOverrideParameters
> stream_override_
;
442 scoped_ptr
<SharedMemoryDataConsumerHandle::Writer
> body_stream_writer_
;
443 enum DeferState
{NOT_DEFERRING
, SHOULD_DEFER
, DEFERRED_DATA
};
444 DeferState defers_loading_
;
448 WebURLLoaderImpl::Context::Context(
449 WebURLLoaderImpl
* loader
,
450 ResourceDispatcher
* resource_dispatcher
,
451 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
)
454 resource_dispatcher_(resource_dispatcher
),
455 task_runner_(task_runner
),
456 referrer_policy_(blink::WebReferrerPolicyDefault
),
457 defers_loading_(NOT_DEFERRING
),
461 void WebURLLoaderImpl::Context::Cancel() {
462 if (resource_dispatcher_
&& // NULL in unittest.
464 resource_dispatcher_
->Cancel(request_id_
);
468 if (body_stream_writer_
)
469 body_stream_writer_
->Fail();
471 // Ensure that we do not notify the multipart delegate anymore as it has
472 // its own pointer to the client.
473 if (multipart_delegate_
)
474 multipart_delegate_
->Cancel();
475 // Ditto for the ftp delegate.
476 if (ftp_listing_delegate_
)
477 ftp_listing_delegate_
->Cancel();
479 // Do not make any further calls to the client.
484 void WebURLLoaderImpl::Context::SetDefersLoading(bool value
) {
485 if (request_id_
!= -1)
486 resource_dispatcher_
->SetDefersLoading(request_id_
, value
);
487 if (value
&& defers_loading_
== NOT_DEFERRING
) {
488 defers_loading_
= SHOULD_DEFER
;
489 } else if (!value
&& defers_loading_
!= NOT_DEFERRING
) {
490 if (defers_loading_
== DEFERRED_DATA
) {
491 task_runner_
->PostTask(FROM_HERE
,
492 base::Bind(&Context::HandleDataURL
, this));
494 defers_loading_
= NOT_DEFERRING
;
498 void WebURLLoaderImpl::Context::DidChangePriority(
499 WebURLRequest::Priority new_priority
, int intra_priority_value
) {
500 if (request_id_
!= -1) {
501 resource_dispatcher_
->DidChangePriority(
503 ConvertWebKitPriorityToNetPriority(new_priority
),
504 intra_priority_value
);
508 bool WebURLLoaderImpl::Context::AttachThreadedDataReceiver(
509 blink::WebThreadedDataReceiver
* threaded_data_receiver
) {
510 if (request_id_
!= -1) {
511 return resource_dispatcher_
->AttachThreadedDataReceiver(
512 request_id_
, threaded_data_receiver
);
518 void WebURLLoaderImpl::Context::Start(const WebURLRequest
& request
,
519 SyncLoadResponse
* sync_load_response
) {
520 DCHECK(request_id_
== -1);
521 request_
= request
; // Save the request.
522 if (request
.extraData()) {
523 RequestExtraData
* extra_data
=
524 static_cast<RequestExtraData
*>(request
.extraData());
525 stream_override_
= extra_data
->TakeStreamOverrideOwnership();
528 GURL url
= request
.url();
530 // PlzNavigate: during navigation, the renderer should request a stream which
531 // contains the body of the response. The request has already been made by the
533 if (stream_override_
.get()) {
534 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
535 switches::kEnableBrowserSideNavigation
));
536 DCHECK(!sync_load_response
);
537 DCHECK_NE(WebURLRequest::FrameTypeNone
, request
.frameType());
538 DCHECK_EQ("GET", request
.httpMethod().latin1());
539 url
= stream_override_
->stream_url
;
542 if (CanHandleDataURLRequestLocally()) {
543 if (sync_load_response
) {
544 // This is a sync load. Do the work now.
545 sync_load_response
->url
= url
;
546 sync_load_response
->error_code
=
547 GetInfoFromDataURL(sync_load_response
->url
, sync_load_response
,
548 &sync_load_response
->data
);
550 task_runner_
->PostTask(FROM_HERE
,
551 base::Bind(&Context::HandleDataURL
, this));
556 // PlzNavigate: outside of tests, the only navigation requests going through
557 // the WebURLLoader are the ones created by CommitNavigation. Several browser
558 // tests load HTML directly through a data url which will be handled by the
560 DCHECK_IMPLIES(base::CommandLine::ForCurrentProcess()->HasSwitch(
561 switches::kEnableBrowserSideNavigation
),
562 stream_override_
.get() ||
563 request
.frameType() == WebURLRequest::FrameTypeNone
);
566 request
.httpHeaderField(WebString::fromUTF8("Referer")).latin1());
567 const std::string
& method
= request
.httpMethod().latin1();
569 // TODO(brettw) this should take parameter encoding into account when
570 // creating the GURLs.
572 // TODO(horo): Check credentials flag is unset when credentials mode is omit.
573 // Check credentials flag is set when credentials mode is include.
575 RequestInfo request_info
;
576 request_info
.method
= method
;
577 request_info
.url
= url
;
578 request_info
.first_party_for_cookies
= request
.firstPartyForCookies();
579 referrer_policy_
= request
.referrerPolicy();
580 request_info
.referrer
= Referrer(referrer_url
, referrer_policy_
);
581 request_info
.headers
= GetWebURLRequestHeaders(request
);
582 request_info
.load_flags
= GetLoadFlagsForWebURLRequest(request
);
583 request_info
.enable_load_timing
= true;
584 request_info
.enable_upload_progress
= request
.reportUploadProgress();
585 if (request
.requestContext() == WebURLRequest::RequestContextXMLHttpRequest
&&
586 (url
.has_username() || url
.has_password())) {
587 request_info
.do_not_prompt_for_login
= true;
589 // requestor_pid only needs to be non-zero if the request originates outside
590 // the render process, so we can use requestorProcessID even for requests
591 // from in-process plugins.
592 request_info
.requestor_pid
= request
.requestorProcessID();
593 request_info
.request_type
= WebURLRequestToResourceType(request
);
594 request_info
.priority
=
595 ConvertWebKitPriorityToNetPriority(request
.priority());
596 request_info
.appcache_host_id
= request
.appCacheHostID();
597 request_info
.routing_id
= request
.requestorID();
598 request_info
.download_to_file
= request
.downloadToFile();
599 request_info
.has_user_gesture
= request
.hasUserGesture();
600 request_info
.skip_service_worker
= request
.skipServiceWorker();
601 request_info
.should_reset_appcache
= request
.shouldResetAppCache();
602 request_info
.fetch_request_mode
= GetFetchRequestMode(request
);
603 request_info
.fetch_credentials_mode
= GetFetchCredentialsMode(request
);
604 request_info
.fetch_redirect_mode
= GetFetchRedirectMode(request
);
605 request_info
.fetch_request_context_type
= GetRequestContextType(request
);
606 request_info
.fetch_frame_type
= GetRequestContextFrameType(request
);
607 request_info
.extra_data
= request
.extraData();
608 request_info
.report_raw_headers
= request
.reportRawHeaders();
610 scoped_refptr
<ResourceRequestBody
> request_body
=
611 GetRequestBodyForWebURLRequest(request
).get();
613 if (sync_load_response
) {
614 resource_dispatcher_
->StartSync(
615 request_info
, request_body
.get(), sync_load_response
);
619 request_id_
= resource_dispatcher_
->StartAsync(
620 request_info
, request_body
.get(), this);
623 void WebURLLoaderImpl::Context::OnUploadProgress(uint64 position
, uint64 size
) {
625 client_
->didSendData(loader_
, position
, size
);
628 bool WebURLLoaderImpl::Context::OnReceivedRedirect(
629 const net::RedirectInfo
& redirect_info
,
630 const ResourceResponseInfo
& info
) {
634 WebURLResponse response
;
635 response
.initialize();
636 PopulateURLResponse(request_
.url(), info
, &response
,
637 request_
.reportRawHeaders());
639 // TODO(darin): We lack sufficient information to construct the actual
640 // request that resulted from the redirect.
641 WebURLRequest
new_request(redirect_info
.new_url
);
642 new_request
.setFirstPartyForCookies(
643 redirect_info
.new_first_party_for_cookies
);
644 new_request
.setDownloadToFile(request_
.downloadToFile());
645 new_request
.setUseStreamOnResponse(request_
.useStreamOnResponse());
646 new_request
.setRequestContext(request_
.requestContext());
647 new_request
.setFrameType(request_
.frameType());
648 new_request
.setSkipServiceWorker(!info
.was_fetched_via_service_worker
);
649 new_request
.setShouldResetAppCache(request_
.shouldResetAppCache());
650 new_request
.setFetchRequestMode(request_
.fetchRequestMode());
651 new_request
.setFetchCredentialsMode(request_
.fetchCredentialsMode());
653 new_request
.setHTTPReferrer(WebString::fromUTF8(redirect_info
.new_referrer
),
656 std::string old_method
= request_
.httpMethod().utf8();
657 new_request
.setHTTPMethod(WebString::fromUTF8(redirect_info
.new_method
));
658 if (redirect_info
.new_method
== old_method
)
659 new_request
.setHTTPBody(request_
.httpBody());
661 // Protect from deletion during call to willSendRequest.
662 scoped_refptr
<Context
> protect(this);
664 client_
->willSendRequest(loader_
, new_request
, response
);
665 request_
= new_request
;
667 // Only follow the redirect if WebKit left the URL unmodified.
668 if (redirect_info
.new_url
== GURL(new_request
.url())) {
669 // First-party cookie logic moved from DocumentLoader in Blink to
670 // net::URLRequest in the browser. Assert that Blink didn't try to change it
671 // to something else.
672 DCHECK_EQ(redirect_info
.new_first_party_for_cookies
.spec(),
673 request_
.firstPartyForCookies().string().utf8());
677 // We assume that WebKit only changes the URL to suppress a redirect, and we
678 // assume that it does so by setting it to be invalid.
679 DCHECK(!new_request
.url().isValid());
683 void WebURLLoaderImpl::Context::OnReceivedResponse(
684 const ResourceResponseInfo
& initial_info
) {
688 ResourceResponseInfo info
= initial_info
;
690 // PlzNavigate: during navigations, the ResourceResponse has already been
691 // received on the browser side, and has been passed down to the renderer.
692 if (stream_override_
.get()) {
693 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
694 switches::kEnableBrowserSideNavigation
));
695 info
= stream_override_
->response
;
698 WebURLResponse response
;
699 response
.initialize();
700 PopulateURLResponse(request_
.url(), info
, &response
,
701 request_
.reportRawHeaders());
703 bool show_raw_listing
= (GURL(request_
.url()).query() == "raw");
705 if (info
.mime_type
== "text/vnd.chromium.ftp-dir") {
706 if (show_raw_listing
) {
707 // Set the MIME type to plain text to prevent any active content.
708 response
.setMIMEType("text/plain");
710 // We're going to produce a parsed listing in HTML.
711 response
.setMIMEType("text/html");
715 // Prevent |this| from being destroyed if the client destroys the loader,
716 // ether in didReceiveResponse, or when the multipart/ftp delegate calls into
718 scoped_refptr
<Context
> protect(this);
720 if (request_
.useStreamOnResponse()) {
721 SharedMemoryDataConsumerHandle::BackpressureMode mode
=
722 SharedMemoryDataConsumerHandle::kDoNotApplyBackpressure
;
724 info
.headers
->HasHeaderValue("Cache-Control", "no-store")) {
725 mode
= SharedMemoryDataConsumerHandle::kApplyBackpressure
;
728 auto read_handle
= make_scoped_ptr(new SharedMemoryDataConsumerHandle(
729 mode
, base::Bind(&Context::CancelBodyStreaming
, this),
730 &body_stream_writer_
));
732 // Here |body_stream_writer_| has an indirect reference to |this| and that
733 // creates a reference cycle, but it is not a problem because the cycle
734 // will break if one of the following happens:
735 // 1) The body data transfer is done (with or without an error).
736 // 2) |read_handle| (and its reader) is detached.
738 // The client takes |read_handle|'s ownership.
739 client_
->didReceiveResponse(loader_
, response
, read_handle
.release());
740 // TODO(yhirano): Support ftp listening and multipart
743 client_
->didReceiveResponse(loader_
, response
);
746 // We may have been cancelled after didReceiveResponse, which would leave us
747 // without a client and therefore without much need to do further handling.
751 DCHECK(!ftp_listing_delegate_
.get());
752 DCHECK(!multipart_delegate_
.get());
753 if (info
.headers
.get() && info
.mime_type
== "multipart/x-mixed-replace") {
754 std::string content_type
;
755 info
.headers
->EnumerateHeader(NULL
, "content-type", &content_type
);
757 std::string mime_type
;
759 bool had_charset
= false;
760 std::string boundary
;
761 net::HttpUtil::ParseContentType(content_type
, &mime_type
, &charset
,
762 &had_charset
, &boundary
);
763 base::TrimString(boundary
, " \"", &boundary
);
765 // If there's no boundary, just handle the request normally. In the gecko
766 // code, nsMultiMixedConv::OnStartRequest throws an exception.
767 if (!boundary
.empty()) {
768 multipart_delegate_
.reset(
769 new MultipartResponseDelegate(client_
, loader_
, response
, boundary
));
771 } else if (info
.mime_type
== "text/vnd.chromium.ftp-dir" &&
773 ftp_listing_delegate_
.reset(
774 new FtpDirectoryListingResponseDelegate(client_
, loader_
, response
));
778 void WebURLLoaderImpl::Context::OnDownloadedData(int len
,
779 int encoded_data_length
) {
781 client_
->didDownloadData(loader_
, len
, encoded_data_length
);
784 void WebURLLoaderImpl::Context::OnReceivedData(scoped_ptr
<ReceivedData
> data
) {
785 const char* payload
= data
->payload();
786 int data_length
= data
->length();
787 int encoded_data_length
= data
->encoded_length();
791 if (ftp_listing_delegate_
) {
792 // The FTP listing delegate will make the appropriate calls to
793 // client_->didReceiveData and client_->didReceiveResponse. Since the
794 // delegate may want to do work after sending data to the delegate, keep
795 // |this| and the delegate alive until it's finished handling the data.
796 scoped_refptr
<Context
> protect(this);
797 ftp_listing_delegate_
->OnReceivedData(payload
, data_length
);
798 } else if (multipart_delegate_
) {
799 // The multipart delegate will make the appropriate calls to
800 // client_->didReceiveData and client_->didReceiveResponse. Since the
801 // delegate may want to do work after sending data to the delegate, keep
802 // |this| and the delegate alive until it's finished handling the data.
803 scoped_refptr
<Context
> protect(this);
804 multipart_delegate_
->OnReceivedData(payload
, data_length
,
805 encoded_data_length
);
807 scoped_refptr
<Context
> protect(this);
808 // We dispatch the data even when |useStreamOnResponse()| is set, in order
809 // to make Devtools work.
810 client_
->didReceiveData(loader_
, payload
, data_length
, encoded_data_length
);
812 if (request_
.useStreamOnResponse()) {
813 // We don't support ftp_listening_delegate_ and multipart_delegate_ for
815 // TODO(yhirano): Support ftp listening and multipart.
816 body_stream_writer_
->AddData(data
.Pass());
821 void WebURLLoaderImpl::Context::OnReceivedCachedMetadata(
822 const char* data
, int len
) {
824 client_
->didReceiveCachedMetadata(loader_
, data
, len
);
827 void WebURLLoaderImpl::Context::OnCompletedRequest(
829 bool was_ignored_by_handler
,
830 bool stale_copy_in_cache
,
831 const std::string
& security_info
,
832 const base::TimeTicks
& completion_time
,
833 int64 total_transfer_size
) {
834 // The WebURLLoaderImpl may be deleted in any of the calls to the client or
835 // the delegates below (As they also may call in to the client). Keep |this|
836 // alive in that case, to avoid a crash. If that happens, the request will be
837 // cancelled and |client_| will be set to NULL.
838 scoped_refptr
<Context
> protect(this);
840 if (ftp_listing_delegate_
) {
841 ftp_listing_delegate_
->OnCompletedRequest();
842 ftp_listing_delegate_
.reset(NULL
);
843 } else if (multipart_delegate_
) {
844 multipart_delegate_
->OnCompletedRequest();
845 multipart_delegate_
.reset(NULL
);
848 if (body_stream_writer_
&& error_code
!= net::OK
)
849 body_stream_writer_
->Fail();
850 body_stream_writer_
.reset();
853 if (error_code
!= net::OK
) {
856 CreateWebURLError(request_
.url(), stale_copy_in_cache
, error_code
,
857 was_ignored_by_handler
));
859 client_
->didFinishLoading(loader_
,
860 (completion_time
- TimeTicks()).InSecondsF(),
861 total_transfer_size
);
866 void WebURLLoaderImpl::Context::OnReceivedCompletedResponse(
867 const ResourceResponseInfo
& info
,
868 scoped_ptr
<ReceivedData
> data
,
870 bool was_ignored_by_handler
,
871 bool stale_copy_in_cache
,
872 const std::string
& security_info
,
873 const base::TimeTicks
& completion_time
,
874 int64 total_transfer_size
) {
875 scoped_refptr
<Context
> protect(this);
877 OnReceivedResponse(info
);
879 OnReceivedData(data
.Pass());
880 OnCompletedRequest(error_code
, was_ignored_by_handler
, stale_copy_in_cache
,
881 security_info
, completion_time
, total_transfer_size
);
884 WebURLLoaderImpl::Context::~Context() {
885 if (request_id_
>= 0) {
886 resource_dispatcher_
->RemovePendingRequest(request_id_
);
890 void WebURLLoaderImpl::Context::CancelBodyStreaming() {
891 scoped_refptr
<Context
> protect(this);
893 // Notify renderer clients that the request is canceled.
894 if (ftp_listing_delegate_
) {
895 ftp_listing_delegate_
->OnCompletedRequest();
896 ftp_listing_delegate_
.reset(NULL
);
897 } else if (multipart_delegate_
) {
898 multipart_delegate_
->OnCompletedRequest();
899 multipart_delegate_
.reset(NULL
);
902 if (body_stream_writer_
) {
903 body_stream_writer_
->Fail();
904 body_stream_writer_
.reset();
907 // TODO(yhirano): Set |stale_copy_in_cache| appropriately if possible.
909 loader_
, CreateWebURLError(request_
.url(), false, net::ERR_ABORTED
));
912 // Notify the browser process that the request is canceled.
916 bool WebURLLoaderImpl::Context::CanHandleDataURLRequestLocally() const {
917 GURL url
= request_
.url();
918 if (!url
.SchemeIs(url::kDataScheme
))
921 // The fast paths for data URL, Start() and HandleDataURL(), don't support
922 // the downloadToFile option.
923 if (request_
.downloadToFile())
926 // Data url requests from object tags may need to be intercepted as streams
927 // and so need to be sent to the browser.
928 if (request_
.requestContext() == WebURLRequest::RequestContextObject
)
931 // Optimize for the case where we can handle a data URL locally. We must
932 // skip this for data URLs targetted at frames since those could trigger a
935 // NOTE: We special case MIME types we can render both for performance
936 // reasons as well as to support unit tests.
938 #if defined(OS_ANDROID)
939 // For compatibility reasons on Android we need to expose top-level data://
941 if (request_
.frameType() == WebURLRequest::FrameTypeTopLevel
)
945 if (request_
.frameType() != WebURLRequest::FrameTypeTopLevel
&&
946 request_
.frameType() != WebURLRequest::FrameTypeNested
)
949 std::string mime_type
, unused_charset
;
950 if (net::DataURL::Parse(request_
.url(), &mime_type
, &unused_charset
, NULL
) &&
951 mime_util::IsSupportedMimeType(mime_type
))
957 void WebURLLoaderImpl::Context::HandleDataURL() {
958 DCHECK_NE(defers_loading_
, DEFERRED_DATA
);
959 if (defers_loading_
== SHOULD_DEFER
) {
960 defers_loading_
= DEFERRED_DATA
;
964 ResourceResponseInfo info
;
967 int error_code
= GetInfoFromDataURL(request_
.url(), &info
, &data
);
969 if (error_code
== net::OK
) {
970 OnReceivedResponse(info
);
973 make_scoped_ptr(new FixedReceivedData(data
.data(), data
.size(), 0)));
976 OnCompletedRequest(error_code
, false, false, info
.security_info
,
977 base::TimeTicks::Now(), 0);
980 // WebURLLoaderImpl -----------------------------------------------------------
982 WebURLLoaderImpl::WebURLLoaderImpl(
983 ResourceDispatcher
* resource_dispatcher
,
984 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
)
985 : context_(new Context(this, resource_dispatcher
, task_runner
)) {
988 WebURLLoaderImpl::~WebURLLoaderImpl() {
992 void WebURLLoaderImpl::PopulateURLResponse(const GURL
& url
,
993 const ResourceResponseInfo
& info
,
994 WebURLResponse
* response
,
995 bool report_security_info
) {
996 response
->setURL(url
);
997 response
->setResponseTime(info
.response_time
.ToInternalValue());
998 response
->setMIMEType(WebString::fromUTF8(info
.mime_type
));
999 response
->setTextEncodingName(WebString::fromUTF8(info
.charset
));
1000 response
->setExpectedContentLength(info
.content_length
);
1001 response
->setSecurityInfo(info
.security_info
);
1002 response
->setAppCacheID(info
.appcache_id
);
1003 response
->setAppCacheManifestURL(info
.appcache_manifest_url
);
1004 response
->setWasCached(!info
.load_timing
.request_start_time
.is_null() &&
1005 info
.response_time
< info
.load_timing
.request_start_time
);
1006 response
->setRemoteIPAddress(
1007 WebString::fromUTF8(info
.socket_address
.host()));
1008 response
->setRemotePort(info
.socket_address
.port());
1009 response
->setConnectionID(info
.load_timing
.socket_log_id
);
1010 response
->setConnectionReused(info
.load_timing
.socket_reused
);
1011 response
->setDownloadFilePath(info
.download_file_path
.AsUTF16Unsafe());
1012 response
->setWasFetchedViaSPDY(info
.was_fetched_via_spdy
);
1013 response
->setWasFetchedViaServiceWorker(info
.was_fetched_via_service_worker
);
1014 response
->setWasFallbackRequiredByServiceWorker(
1015 info
.was_fallback_required_by_service_worker
);
1016 response
->setServiceWorkerResponseType(info
.response_type_via_service_worker
);
1017 response
->setOriginalURLViaServiceWorker(
1018 info
.original_url_via_service_worker
);
1020 SetSecurityStyleAndDetails(url
, info
.security_info
, response
,
1021 report_security_info
);
1023 WebURLResponseExtraDataImpl
* extra_data
=
1024 new WebURLResponseExtraDataImpl(info
.npn_negotiated_protocol
);
1025 response
->setExtraData(extra_data
);
1026 extra_data
->set_was_fetched_via_spdy(info
.was_fetched_via_spdy
);
1027 extra_data
->set_was_npn_negotiated(info
.was_npn_negotiated
);
1028 extra_data
->set_was_alternate_protocol_available(
1029 info
.was_alternate_protocol_available
);
1030 extra_data
->set_connection_info(info
.connection_info
);
1031 extra_data
->set_was_fetched_via_proxy(info
.was_fetched_via_proxy
);
1032 extra_data
->set_proxy_server(info
.proxy_server
);
1034 // If there's no received headers end time, don't set load timing. This is
1035 // the case for non-HTTP requests, requests that don't go over the wire, and
1036 // certain error cases.
1037 if (!info
.load_timing
.receive_headers_end
.is_null()) {
1038 WebURLLoadTiming timing
;
1039 PopulateURLLoadTiming(info
.load_timing
, &timing
);
1040 const TimeTicks kNullTicks
;
1041 timing
.setWorkerStart(
1042 (info
.service_worker_start_time
- kNullTicks
).InSecondsF());
1043 timing
.setWorkerReady(
1044 (info
.service_worker_ready_time
- kNullTicks
).InSecondsF());
1045 response
->setLoadTiming(timing
);
1048 if (info
.devtools_info
.get()) {
1049 WebHTTPLoadInfo load_info
;
1051 load_info
.setHTTPStatusCode(info
.devtools_info
->http_status_code
);
1052 load_info
.setHTTPStatusText(WebString::fromLatin1(
1053 info
.devtools_info
->http_status_text
));
1054 load_info
.setEncodedDataLength(info
.encoded_data_length
);
1056 load_info
.setRequestHeadersText(WebString::fromLatin1(
1057 info
.devtools_info
->request_headers_text
));
1058 load_info
.setResponseHeadersText(WebString::fromLatin1(
1059 info
.devtools_info
->response_headers_text
));
1060 const HeadersVector
& request_headers
= info
.devtools_info
->request_headers
;
1061 for (HeadersVector::const_iterator it
= request_headers
.begin();
1062 it
!= request_headers
.end(); ++it
) {
1063 load_info
.addRequestHeader(WebString::fromLatin1(it
->first
),
1064 WebString::fromLatin1(it
->second
));
1066 const HeadersVector
& response_headers
=
1067 info
.devtools_info
->response_headers
;
1068 for (HeadersVector::const_iterator it
= response_headers
.begin();
1069 it
!= response_headers
.end(); ++it
) {
1070 load_info
.addResponseHeader(WebString::fromLatin1(it
->first
),
1071 WebString::fromLatin1(it
->second
));
1073 load_info
.setNPNNegotiatedProtocol(WebString::fromLatin1(
1074 info
.npn_negotiated_protocol
));
1075 response
->setHTTPLoadInfo(load_info
);
1078 const net::HttpResponseHeaders
* headers
= info
.headers
.get();
1082 WebURLResponse::HTTPVersion version
= WebURLResponse::Unknown
;
1083 if (headers
->GetHttpVersion() == net::HttpVersion(0, 9))
1084 version
= WebURLResponse::HTTP_0_9
;
1085 else if (headers
->GetHttpVersion() == net::HttpVersion(1, 0))
1086 version
= WebURLResponse::HTTP_1_0
;
1087 else if (headers
->GetHttpVersion() == net::HttpVersion(1, 1))
1088 version
= WebURLResponse::HTTP_1_1
;
1089 response
->setHTTPVersion(version
);
1090 response
->setHTTPStatusCode(headers
->response_code());
1091 response
->setHTTPStatusText(WebString::fromLatin1(headers
->GetStatusText()));
1093 // TODO(darin): We should leverage HttpResponseHeaders for this, and this
1094 // should be using the same code as ResourceDispatcherHost.
1095 // TODO(jungshik): Figure out the actual value of the referrer charset and
1096 // pass it to GetSuggestedFilename.
1098 headers
->EnumerateHeader(NULL
, "content-disposition", &value
);
1099 response
->setSuggestedFileName(
1100 net::GetSuggestedFilename(url
,
1102 std::string(), // referrer_charset
1103 std::string(), // suggested_name
1104 std::string(), // mime_type
1105 std::string())); // default_name
1108 if (headers
->GetLastModifiedValue(&time_val
))
1109 response
->setLastModifiedDate(time_val
.ToDoubleT());
1111 // Build up the header map.
1114 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
1115 response
->addHTTPHeaderField(WebString::fromLatin1(name
),
1116 WebString::fromLatin1(value
));
1120 void WebURLLoaderImpl::loadSynchronously(const WebURLRequest
& request
,
1121 WebURLResponse
& response
,
1124 SyncLoadResponse sync_load_response
;
1125 context_
->Start(request
, &sync_load_response
);
1127 const GURL
& final_url
= sync_load_response
.url
;
1129 // TODO(tc): For file loads, we may want to include a more descriptive
1130 // status code or status text.
1131 int error_code
= sync_load_response
.error_code
;
1132 if (error_code
!= net::OK
) {
1133 response
.setURL(final_url
);
1134 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1135 error
.reason
= error_code
;
1136 error
.unreachableURL
= final_url
;
1140 PopulateURLResponse(final_url
, sync_load_response
, &response
,
1141 request
.reportRawHeaders());
1143 data
.assign(sync_load_response
.data
.data(),
1144 sync_load_response
.data
.size());
1147 void WebURLLoaderImpl::loadAsynchronously(const WebURLRequest
& request
,
1148 WebURLLoaderClient
* client
) {
1149 DCHECK(!context_
->client());
1151 context_
->set_client(client
);
1152 context_
->Start(request
, NULL
);
1155 void WebURLLoaderImpl::cancel() {
1159 void WebURLLoaderImpl::setDefersLoading(bool value
) {
1160 context_
->SetDefersLoading(value
);
1163 void WebURLLoaderImpl::didChangePriority(WebURLRequest::Priority new_priority
,
1164 int intra_priority_value
) {
1165 context_
->DidChangePriority(new_priority
, intra_priority_value
);
1168 bool WebURLLoaderImpl::attachThreadedDataReceiver(
1169 blink::WebThreadedDataReceiver
* threaded_data_receiver
) {
1170 return context_
->AttachThreadedDataReceiver(threaded_data_receiver
);
1173 } // namespace content