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"
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/files/file_path.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 "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/sync_load_response.h"
25 #include "content/child/web_data_consumer_handle_impl.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/request_peer.h"
32 #include "content/public/common/content_switches.h"
33 #include "net/base/data_url.h"
34 #include "net/base/filename_util.h"
35 #include "net/base/mime_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"
49 #include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h"
52 using base::TimeTicks
;
54 using blink::WebHTTPBody
;
55 using blink::WebHTTPHeaderVisitor
;
56 using blink::WebHTTPLoadInfo
;
57 using blink::WebReferrerPolicy
;
58 using blink::WebSecurityPolicy
;
59 using blink::WebString
;
61 using blink::WebURLError
;
62 using blink::WebURLLoadTiming
;
63 using blink::WebURLLoader
;
64 using blink::WebURLLoaderClient
;
65 using blink::WebURLRequest
;
66 using blink::WebURLResponse
;
70 // Utilities ------------------------------------------------------------------
74 const char kThrottledErrorDescription
[] =
75 "Request throttled. Visit http://dev.chromium.org/throttling for more "
77 const size_t kBodyStreamPipeCapacity
= 4 * 1024;
79 typedef ResourceDevToolsInfo::HeadersVector HeadersVector
;
81 // Converts timing data from |load_timing| to the format used by WebKit.
82 void PopulateURLLoadTiming(const net::LoadTimingInfo
& load_timing
,
83 WebURLLoadTiming
* url_timing
) {
84 DCHECK(!load_timing
.request_start
.is_null());
86 const TimeTicks kNullTicks
;
87 url_timing
->initialize();
88 url_timing
->setRequestTime(
89 (load_timing
.request_start
- kNullTicks
).InSecondsF());
90 url_timing
->setProxyStart(
91 (load_timing
.proxy_resolve_start
- kNullTicks
).InSecondsF());
92 url_timing
->setProxyEnd(
93 (load_timing
.proxy_resolve_end
- kNullTicks
).InSecondsF());
94 url_timing
->setDNSStart(
95 (load_timing
.connect_timing
.dns_start
- kNullTicks
).InSecondsF());
96 url_timing
->setDNSEnd(
97 (load_timing
.connect_timing
.dns_end
- kNullTicks
).InSecondsF());
98 url_timing
->setConnectStart(
99 (load_timing
.connect_timing
.connect_start
- kNullTicks
).InSecondsF());
100 url_timing
->setConnectEnd(
101 (load_timing
.connect_timing
.connect_end
- kNullTicks
).InSecondsF());
102 url_timing
->setSSLStart(
103 (load_timing
.connect_timing
.ssl_start
- kNullTicks
).InSecondsF());
104 url_timing
->setSSLEnd(
105 (load_timing
.connect_timing
.ssl_end
- kNullTicks
).InSecondsF());
106 url_timing
->setSendStart(
107 (load_timing
.send_start
- kNullTicks
).InSecondsF());
108 url_timing
->setSendEnd(
109 (load_timing
.send_end
- kNullTicks
).InSecondsF());
110 url_timing
->setReceiveHeadersEnd(
111 (load_timing
.receive_headers_end
- kNullTicks
).InSecondsF());
114 net::RequestPriority
ConvertWebKitPriorityToNetPriority(
115 const WebURLRequest::Priority
& priority
) {
117 case WebURLRequest::PriorityVeryHigh
:
120 case WebURLRequest::PriorityHigh
:
123 case WebURLRequest::PriorityMedium
:
126 case WebURLRequest::PriorityLow
:
129 case WebURLRequest::PriorityVeryLow
:
132 case WebURLRequest::PriorityUnresolved
:
139 // Extracts info from a data scheme URL into |info| and |data|. Returns net::OK
140 // if successful. Returns a net error code otherwise. Exported only for testing.
141 int GetInfoFromDataURL(const GURL
& url
,
142 ResourceResponseInfo
* info
,
144 // Assure same time for all time fields of data: URLs.
145 Time now
= Time::Now();
146 info
->load_timing
.request_start
= TimeTicks::Now();
147 info
->load_timing
.request_start_time
= now
;
148 info
->request_time
= now
;
149 info
->response_time
= now
;
151 std::string mime_type
;
153 scoped_refptr
<net::HttpResponseHeaders
> headers(
154 new net::HttpResponseHeaders(std::string()));
155 int result
= net::URLRequestDataJob::BuildResponse(
156 url
, &mime_type
, &charset
, data
, headers
.get());
157 if (result
!= net::OK
)
160 info
->headers
= headers
;
161 info
->mime_type
.swap(mime_type
);
162 info
->charset
.swap(charset
);
163 info
->security_info
.clear();
164 info
->content_length
= data
->length();
165 info
->encoded_data_length
= 0;
170 #define STATIC_ASSERT_MATCHING_ENUMS(content_name, blink_name) \
172 static_cast<int>(content_name) == static_cast<int>(blink_name), \
173 "mismatching enums: " #content_name)
175 STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_SAME_ORIGIN
,
176 WebURLRequest::FetchRequestModeSameOrigin
);
177 STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_NO_CORS
,
178 WebURLRequest::FetchRequestModeNoCORS
);
179 STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_CORS
,
180 WebURLRequest::FetchRequestModeCORS
);
181 STATIC_ASSERT_MATCHING_ENUMS(
182 FETCH_REQUEST_MODE_CORS_WITH_FORCED_PREFLIGHT
,
183 WebURLRequest::FetchRequestModeCORSWithForcedPreflight
);
185 FetchRequestMode
GetFetchRequestMode(const WebURLRequest
& request
) {
186 return static_cast<FetchRequestMode
>(request
.fetchRequestMode());
189 STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_OMIT
,
190 WebURLRequest::FetchCredentialsModeOmit
);
191 STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_SAME_ORIGIN
,
192 WebURLRequest::FetchCredentialsModeSameOrigin
);
193 STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_INCLUDE
,
194 WebURLRequest::FetchCredentialsModeInclude
);
196 FetchCredentialsMode
GetFetchCredentialsMode(const WebURLRequest
& request
) {
197 return static_cast<FetchCredentialsMode
>(request
.fetchCredentialsMode());
200 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_AUXILIARY
,
201 WebURLRequest::FrameTypeAuxiliary
);
202 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_NESTED
,
203 WebURLRequest::FrameTypeNested
);
204 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_NONE
,
205 WebURLRequest::FrameTypeNone
);
206 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL
,
207 WebURLRequest::FrameTypeTopLevel
);
209 RequestContextFrameType
GetRequestContextFrameType(
210 const WebURLRequest
& request
) {
211 return static_cast<RequestContextFrameType
>(request
.frameType());
214 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_UNSPECIFIED
,
215 WebURLRequest::RequestContextUnspecified
);
216 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_AUDIO
,
217 WebURLRequest::RequestContextAudio
);
218 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_BEACON
,
219 WebURLRequest::RequestContextBeacon
);
220 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_CSP_REPORT
,
221 WebURLRequest::RequestContextCSPReport
);
222 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_DOWNLOAD
,
223 WebURLRequest::RequestContextDownload
);
224 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_EMBED
,
225 WebURLRequest::RequestContextEmbed
);
226 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_EVENT_SOURCE
,
227 WebURLRequest::RequestContextEventSource
);
228 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FAVICON
,
229 WebURLRequest::RequestContextFavicon
);
230 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FETCH
,
231 WebURLRequest::RequestContextFetch
);
232 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FONT
,
233 WebURLRequest::RequestContextFont
);
234 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FORM
,
235 WebURLRequest::RequestContextForm
);
236 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FRAME
,
237 WebURLRequest::RequestContextFrame
);
238 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_HYPERLINK
,
239 WebURLRequest::RequestContextHyperlink
);
240 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IFRAME
,
241 WebURLRequest::RequestContextIframe
);
242 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMAGE
,
243 WebURLRequest::RequestContextImage
);
244 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMAGE_SET
,
245 WebURLRequest::RequestContextImageSet
);
246 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMPORT
,
247 WebURLRequest::RequestContextImport
);
248 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_INTERNAL
,
249 WebURLRequest::RequestContextInternal
);
250 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_LOCATION
,
251 WebURLRequest::RequestContextLocation
);
252 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_MANIFEST
,
253 WebURLRequest::RequestContextManifest
);
254 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_OBJECT
,
255 WebURLRequest::RequestContextObject
);
256 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PING
,
257 WebURLRequest::RequestContextPing
);
258 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PLUGIN
,
259 WebURLRequest::RequestContextPlugin
);
260 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PREFETCH
,
261 WebURLRequest::RequestContextPrefetch
);
262 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SCRIPT
,
263 WebURLRequest::RequestContextScript
);
264 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SERVICE_WORKER
,
265 WebURLRequest::RequestContextServiceWorker
);
266 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SHARED_WORKER
,
267 WebURLRequest::RequestContextSharedWorker
);
268 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SUBRESOURCE
,
269 WebURLRequest::RequestContextSubresource
);
270 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_STYLE
,
271 WebURLRequest::RequestContextStyle
);
272 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_TRACK
,
273 WebURLRequest::RequestContextTrack
);
274 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_VIDEO
,
275 WebURLRequest::RequestContextVideo
);
276 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_WORKER
,
277 WebURLRequest::RequestContextWorker
);
278 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_XML_HTTP_REQUEST
,
279 WebURLRequest::RequestContextXMLHttpRequest
);
280 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_XSLT
,
281 WebURLRequest::RequestContextXSLT
);
283 RequestContextType
GetRequestContextType(const WebURLRequest
& request
) {
284 return static_cast<RequestContextType
>(request
.requestContext());
289 // WebURLLoaderImpl::Context --------------------------------------------------
291 // This inner class exists since the WebURLLoader may be deleted while inside a
292 // call to WebURLLoaderClient. Refcounting is to keep the context from being
293 // deleted if it may have work to do after calling into the client.
294 class WebURLLoaderImpl::Context
: public base::RefCounted
<Context
>,
297 Context(WebURLLoaderImpl
* loader
,
298 ResourceDispatcher
* resource_dispatcher
,
299 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
);
301 WebURLLoaderClient
* client() const { return client_
; }
302 void set_client(WebURLLoaderClient
* client
) { client_
= client
; }
305 void SetDefersLoading(bool value
);
306 void DidChangePriority(WebURLRequest::Priority new_priority
,
307 int intra_priority_value
);
308 bool AttachThreadedDataReceiver(
309 blink::WebThreadedDataReceiver
* threaded_data_receiver
);
310 void Start(const WebURLRequest
& request
,
311 SyncLoadResponse
* sync_load_response
);
313 // RequestPeer methods:
314 void OnUploadProgress(uint64 position
, uint64 size
) override
;
315 bool OnReceivedRedirect(const net::RedirectInfo
& redirect_info
,
316 const ResourceResponseInfo
& info
) override
;
317 void OnReceivedResponse(const ResourceResponseInfo
& info
) override
;
318 void OnDownloadedData(int len
, int encoded_data_length
) override
;
319 void OnReceivedData(const char* data
,
321 int encoded_data_length
) override
;
322 void OnReceivedCachedMetadata(const char* data
, int len
) override
;
323 void OnCompletedRequest(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
;
331 friend class base::RefCounted
<Context
>;
334 // We can optimize the handling of data URLs in most cases.
335 bool CanHandleDataURLRequestLocally() const;
336 void HandleDataURL();
337 MojoResult
WriteDataOnBodyStream(const char* data
, size_t size
);
338 void OnHandleGotWritable(MojoResult
);
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 mojo::ScopedDataPipeProducerHandle body_stream_writer_
;
350 mojo::common::HandleWatcher body_stream_writer_watcher_
;
351 // TODO(yhirano): Delete this buffer after implementing the back-pressure
353 std::deque
<char> body_stream_buffer_
;
354 bool got_all_stream_body_data_
;
355 enum DeferState
{NOT_DEFERRING
, SHOULD_DEFER
, DEFERRED_DATA
};
356 DeferState defers_loading_
;
360 WebURLLoaderImpl::Context::Context(
361 WebURLLoaderImpl
* loader
,
362 ResourceDispatcher
* resource_dispatcher
,
363 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
)
366 resource_dispatcher_(resource_dispatcher
),
367 task_runner_(task_runner
),
368 referrer_policy_(blink::WebReferrerPolicyDefault
),
369 got_all_stream_body_data_(false),
370 defers_loading_(NOT_DEFERRING
),
374 void WebURLLoaderImpl::Context::Cancel() {
375 if (resource_dispatcher_
&& // NULL in unittest.
377 resource_dispatcher_
->Cancel(request_id_
);
381 // Ensure that we do not notify the multipart delegate anymore as it has
382 // its own pointer to the client.
383 if (multipart_delegate_
)
384 multipart_delegate_
->Cancel();
385 // Ditto for the ftp delegate.
386 if (ftp_listing_delegate_
)
387 ftp_listing_delegate_
->Cancel();
389 // Do not make any further calls to the client.
394 void WebURLLoaderImpl::Context::SetDefersLoading(bool value
) {
395 if (request_id_
!= -1)
396 resource_dispatcher_
->SetDefersLoading(request_id_
, value
);
397 if (value
&& defers_loading_
== NOT_DEFERRING
) {
398 defers_loading_
= SHOULD_DEFER
;
399 } else if (!value
&& defers_loading_
!= NOT_DEFERRING
) {
400 if (defers_loading_
== DEFERRED_DATA
) {
401 task_runner_
->PostTask(FROM_HERE
,
402 base::Bind(&Context::HandleDataURL
, this));
404 defers_loading_
= NOT_DEFERRING
;
408 void WebURLLoaderImpl::Context::DidChangePriority(
409 WebURLRequest::Priority new_priority
, int intra_priority_value
) {
410 if (request_id_
!= -1) {
411 resource_dispatcher_
->DidChangePriority(
413 ConvertWebKitPriorityToNetPriority(new_priority
),
414 intra_priority_value
);
418 bool WebURLLoaderImpl::Context::AttachThreadedDataReceiver(
419 blink::WebThreadedDataReceiver
* threaded_data_receiver
) {
420 if (request_id_
!= -1) {
421 return resource_dispatcher_
->AttachThreadedDataReceiver(
422 request_id_
, threaded_data_receiver
);
428 void WebURLLoaderImpl::Context::Start(const WebURLRequest
& request
,
429 SyncLoadResponse
* sync_load_response
) {
430 DCHECK(request_id_
== -1);
431 request_
= request
; // Save the request.
432 if (request
.extraData()) {
433 RequestExtraData
* extra_data
=
434 static_cast<RequestExtraData
*>(request
.extraData());
435 stream_override_
= extra_data
->TakeStreamOverrideOwnership();
438 GURL url
= request
.url();
440 // PlzNavigate: during navigation, the renderer should request a stream which
441 // contains the body of the response. The request has already been made by the
443 if (stream_override_
.get()) {
444 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
445 switches::kEnableBrowserSideNavigation
));
446 DCHECK(!sync_load_response
);
447 DCHECK_NE(WebURLRequest::FrameTypeNone
, request
.frameType());
448 DCHECK_EQ("GET", request
.httpMethod().latin1());
449 url
= stream_override_
->stream_url
;
452 // PlzNavigate: the only navigation requests going through the WebURLLoader
453 // are the ones created by CommitNavigation.
454 DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
455 switches::kEnableBrowserSideNavigation
) ||
456 stream_override_
.get() ||
457 request
.frameType() == WebURLRequest::FrameTypeNone
);
459 if (CanHandleDataURLRequestLocally()) {
460 if (sync_load_response
) {
461 // This is a sync load. Do the work now.
462 sync_load_response
->url
= url
;
463 sync_load_response
->error_code
=
464 GetInfoFromDataURL(sync_load_response
->url
, sync_load_response
,
465 &sync_load_response
->data
);
467 task_runner_
->PostTask(FROM_HERE
,
468 base::Bind(&Context::HandleDataURL
, this));
474 request
.httpHeaderField(WebString::fromUTF8("Referer")).latin1());
475 const std::string
& method
= request
.httpMethod().latin1();
477 // TODO(brettw) this should take parameter encoding into account when
478 // creating the GURLs.
480 // TODO(horo): Check credentials flag is unset when credentials mode is omit.
481 // Check credentials flag is set when credentials mode is include.
483 RequestInfo request_info
;
484 request_info
.method
= method
;
485 request_info
.url
= url
;
486 request_info
.first_party_for_cookies
= request
.firstPartyForCookies();
487 referrer_policy_
= request
.referrerPolicy();
488 request_info
.referrer
= Referrer(referrer_url
, referrer_policy_
);
489 request_info
.headers
= GetWebURLRequestHeaders(request
);
490 request_info
.load_flags
= GetLoadFlagsForWebURLRequest(request
);
491 request_info
.enable_load_timing
= true;
492 request_info
.enable_upload_progress
= request
.reportUploadProgress();
493 if (request
.requestContext() == WebURLRequest::RequestContextXMLHttpRequest
&&
494 (url
.has_username() || url
.has_password())) {
495 request_info
.do_not_prompt_for_login
= true;
497 // requestor_pid only needs to be non-zero if the request originates outside
498 // the render process, so we can use requestorProcessID even for requests
499 // from in-process plugins.
500 request_info
.requestor_pid
= request
.requestorProcessID();
501 request_info
.request_type
= WebURLRequestToResourceType(request
);
502 request_info
.priority
=
503 ConvertWebKitPriorityToNetPriority(request
.priority());
504 request_info
.appcache_host_id
= request
.appCacheHostID();
505 request_info
.routing_id
= request
.requestorID();
506 request_info
.download_to_file
= request
.downloadToFile();
507 request_info
.has_user_gesture
= request
.hasUserGesture();
508 request_info
.skip_service_worker
= request
.skipServiceWorker();
509 request_info
.should_reset_appcache
= request
.shouldResetAppCache();
510 request_info
.fetch_request_mode
= GetFetchRequestMode(request
);
511 request_info
.fetch_credentials_mode
= GetFetchCredentialsMode(request
);
512 request_info
.fetch_request_context_type
= GetRequestContextType(request
);
513 request_info
.fetch_frame_type
= GetRequestContextFrameType(request
);
514 request_info
.extra_data
= request
.extraData();
516 scoped_refptr
<ResourceRequestBody
> request_body
=
517 GetRequestBodyForWebURLRequest(request
).get();
519 if (sync_load_response
) {
520 resource_dispatcher_
->StartSync(
521 request_info
, request_body
.get(), sync_load_response
);
525 request_id_
= resource_dispatcher_
->StartAsync(
526 request_info
, request_body
.get(), this);
529 void WebURLLoaderImpl::Context::OnUploadProgress(uint64 position
, uint64 size
) {
531 client_
->didSendData(loader_
, position
, size
);
534 bool WebURLLoaderImpl::Context::OnReceivedRedirect(
535 const net::RedirectInfo
& redirect_info
,
536 const ResourceResponseInfo
& info
) {
540 WebURLResponse response
;
541 response
.initialize();
542 PopulateURLResponse(request_
.url(), info
, &response
);
544 // TODO(darin): We lack sufficient information to construct the actual
545 // request that resulted from the redirect.
546 WebURLRequest
new_request(redirect_info
.new_url
);
547 new_request
.setFirstPartyForCookies(
548 redirect_info
.new_first_party_for_cookies
);
549 new_request
.setDownloadToFile(request_
.downloadToFile());
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
),
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());
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());
587 void WebURLLoaderImpl::Context::OnReceivedResponse(
588 const ResourceResponseInfo
& initial_info
) {
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");
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
621 scoped_refptr
<Context
> protect(this);
623 if (request_
.useStreamOnResponse()) {
624 MojoCreateDataPipeOptions options
;
625 options
.struct_size
= sizeof(MojoCreateDataPipeOptions
);
626 options
.flags
= MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE
;
627 options
.element_num_bytes
= 1;
628 options
.capacity_num_bytes
= kBodyStreamPipeCapacity
;
630 mojo::ScopedDataPipeConsumerHandle consumer
;
631 MojoResult result
= mojo::CreateDataPipe(&options
,
632 &body_stream_writer_
,
634 if (result
!= MOJO_RESULT_OK
) {
635 // TODO(yhirano): Handle the error.
638 client_
->didReceiveResponse(
639 loader_
, response
, new WebDataConsumerHandleImpl(consumer
.Pass()));
641 client_
->didReceiveResponse(loader_
, response
);
644 // We may have been cancelled after didReceiveResponse, which would leave us
645 // without a client and therefore without much need to do further handling.
649 DCHECK(!ftp_listing_delegate_
.get());
650 DCHECK(!multipart_delegate_
.get());
651 if (info
.headers
.get() && info
.mime_type
== "multipart/x-mixed-replace") {
652 std::string content_type
;
653 info
.headers
->EnumerateHeader(NULL
, "content-type", &content_type
);
655 std::string mime_type
;
657 bool had_charset
= false;
658 std::string boundary
;
659 net::HttpUtil::ParseContentType(content_type
, &mime_type
, &charset
,
660 &had_charset
, &boundary
);
661 base::TrimString(boundary
, " \"", &boundary
);
663 // If there's no boundary, just handle the request normally. In the gecko
664 // code, nsMultiMixedConv::OnStartRequest throws an exception.
665 if (!boundary
.empty()) {
666 multipart_delegate_
.reset(
667 new MultipartResponseDelegate(client_
, loader_
, response
, boundary
));
669 } else if (info
.mime_type
== "text/vnd.chromium.ftp-dir" &&
671 ftp_listing_delegate_
.reset(
672 new FtpDirectoryListingResponseDelegate(client_
, loader_
, response
));
676 void WebURLLoaderImpl::Context::OnDownloadedData(int len
,
677 int encoded_data_length
) {
679 client_
->didDownloadData(loader_
, len
, encoded_data_length
);
682 void WebURLLoaderImpl::Context::OnReceivedData(const char* data
,
684 int encoded_data_length
) {
688 if (request_
.useStreamOnResponse()) {
689 // We don't support ftp_listening_delegate_ and multipart_delegate_ for now.
690 // TODO(yhirano): Support ftp listening and multipart.
691 MojoResult rv
= WriteDataOnBodyStream(data
, data_length
);
692 if (rv
!= MOJO_RESULT_OK
&& client_
) {
693 client_
->didFail(loader_
,
694 loader_
->CreateError(request_
.url(),
698 } else if (ftp_listing_delegate_
) {
699 // The FTP listing delegate will make the appropriate calls to
700 // client_->didReceiveData and client_->didReceiveResponse. Since the
701 // delegate may want to do work after sending data to the delegate, keep
702 // |this| and the delegate alive until it's finished handling the data.
703 scoped_refptr
<Context
> protect(this);
704 ftp_listing_delegate_
->OnReceivedData(data
, data_length
);
705 } else if (multipart_delegate_
) {
706 // The multipart delegate will make the appropriate calls to
707 // client_->didReceiveData and client_->didReceiveResponse. Since the
708 // delegate may want to do work after sending data to the delegate, keep
709 // |this| and the delegate alive until it's finished handling the data.
710 scoped_refptr
<Context
> protect(this);
711 multipart_delegate_
->OnReceivedData(data
, data_length
, encoded_data_length
);
713 client_
->didReceiveData(loader_
, data
, data_length
, encoded_data_length
);
717 void WebURLLoaderImpl::Context::OnReceivedCachedMetadata(
718 const char* data
, int len
) {
720 client_
->didReceiveCachedMetadata(loader_
, data
, len
);
723 void WebURLLoaderImpl::Context::OnCompletedRequest(
725 bool was_ignored_by_handler
,
726 bool stale_copy_in_cache
,
727 const std::string
& security_info
,
728 const base::TimeTicks
& completion_time
,
729 int64 total_transfer_size
) {
730 // The WebURLLoaderImpl may be deleted in any of the calls to the client or
731 // the delegates below (As they also may call in to the client). Keep |this|
732 // alive in that case, to avoid a crash. If that happens, the request will be
733 // cancelled and |client_| will be set to NULL.
734 scoped_refptr
<Context
> protect(this);
736 if (ftp_listing_delegate_
) {
737 ftp_listing_delegate_
->OnCompletedRequest();
738 ftp_listing_delegate_
.reset(NULL
);
739 } else if (multipart_delegate_
) {
740 multipart_delegate_
->OnCompletedRequest();
741 multipart_delegate_
.reset(NULL
);
745 if (error_code
!= net::OK
) {
746 client_
->didFail(loader_
, CreateError(request_
.url(),
750 if (request_
.useStreamOnResponse()) {
751 got_all_stream_body_data_
= true;
752 if (body_stream_buffer_
.empty()) {
753 // Close the handle to notify the end of data.
754 body_stream_writer_
.reset();
755 client_
->didFinishLoading(
756 loader_
, (completion_time
- TimeTicks()).InSecondsF(),
757 total_transfer_size
);
760 client_
->didFinishLoading(
761 loader_
, (completion_time
- TimeTicks()).InSecondsF(),
762 total_transfer_size
);
768 WebURLLoaderImpl::Context::~Context() {
769 if (request_id_
>= 0) {
770 resource_dispatcher_
->RemovePendingRequest(request_id_
);
774 bool WebURLLoaderImpl::Context::CanHandleDataURLRequestLocally() const {
775 GURL url
= request_
.url();
776 if (!url
.SchemeIs(url::kDataScheme
))
779 // The fast paths for data URL, Start() and HandleDataURL(), don't support
780 // the downloadToFile option.
781 if (request_
.downloadToFile())
784 // Optimize for the case where we can handle a data URL locally. We must
785 // skip this for data URLs targetted at frames since those could trigger a
788 // NOTE: We special case MIME types we can render both for performance
789 // reasons as well as to support unit tests.
791 #if defined(OS_ANDROID)
792 // For compatibility reasons on Android we need to expose top-level data://
794 if (request_
.frameType() == WebURLRequest::FrameTypeTopLevel
)
798 if (request_
.frameType() != WebURLRequest::FrameTypeTopLevel
&&
799 request_
.frameType() != WebURLRequest::FrameTypeNested
)
802 std::string mime_type
, unused_charset
;
803 if (net::DataURL::Parse(request_
.url(), &mime_type
, &unused_charset
, NULL
) &&
804 net::IsSupportedMimeType(mime_type
))
810 void WebURLLoaderImpl::Context::HandleDataURL() {
811 DCHECK_NE(defers_loading_
, DEFERRED_DATA
);
812 if (defers_loading_
== SHOULD_DEFER
) {
813 defers_loading_
= DEFERRED_DATA
;
817 ResourceResponseInfo info
;
820 int error_code
= GetInfoFromDataURL(request_
.url(), &info
, &data
);
822 if (error_code
== net::OK
) {
823 OnReceivedResponse(info
);
825 OnReceivedData(data
.data(), data
.size(), 0);
828 OnCompletedRequest(error_code
, false, false, info
.security_info
,
829 base::TimeTicks::Now(), 0);
832 MojoResult
WebURLLoaderImpl::Context::WriteDataOnBodyStream(const char* data
,
834 if (body_stream_buffer_
.empty() && size
== 0) {
836 return MOJO_RESULT_OK
;
839 if (!body_stream_writer_
.is_valid()) {
840 // The handle is already cleared.
841 return MOJO_RESULT_OK
;
844 char* buffer
= nullptr;
845 uint32_t num_bytes_writable
= 0;
846 MojoResult rv
= mojo::BeginWriteDataRaw(body_stream_writer_
.get(),
847 reinterpret_cast<void**>(&buffer
),
849 MOJO_WRITE_DATA_FLAG_NONE
);
850 if (rv
== MOJO_RESULT_SHOULD_WAIT
) {
851 body_stream_buffer_
.insert(body_stream_buffer_
.end(), data
, data
+ size
);
852 body_stream_writer_watcher_
.Start(
853 body_stream_writer_
.get(),
854 MOJO_HANDLE_SIGNAL_WRITABLE
,
855 MOJO_DEADLINE_INDEFINITE
,
856 base::Bind(&WebURLLoaderImpl::Context::OnHandleGotWritable
,
857 base::Unretained(this)));
858 return MOJO_RESULT_OK
;
861 if (rv
!= MOJO_RESULT_OK
)
864 uint32_t num_bytes_to_write
= 0;
865 if (num_bytes_writable
< body_stream_buffer_
.size()) {
866 auto begin
= body_stream_buffer_
.begin();
867 auto end
= body_stream_buffer_
.begin() + num_bytes_writable
;
869 std::copy(begin
, end
, buffer
);
870 num_bytes_to_write
= num_bytes_writable
;
871 body_stream_buffer_
.erase(begin
, end
);
872 body_stream_buffer_
.insert(body_stream_buffer_
.end(), data
, data
+ size
);
874 std::copy(body_stream_buffer_
.begin(), body_stream_buffer_
.end(), buffer
);
875 num_bytes_writable
-= body_stream_buffer_
.size();
876 num_bytes_to_write
+= body_stream_buffer_
.size();
877 buffer
+= body_stream_buffer_
.size();
878 body_stream_buffer_
.clear();
880 size_t num_newbytes_to_write
=
881 std::min(size
, static_cast<size_t>(num_bytes_writable
));
882 std::copy(data
, data
+ num_newbytes_to_write
, buffer
);
883 num_bytes_to_write
+= num_newbytes_to_write
;
884 body_stream_buffer_
.insert(body_stream_buffer_
.end(),
885 data
+ num_newbytes_to_write
,
889 rv
= mojo::EndWriteDataRaw(body_stream_writer_
.get(), num_bytes_to_write
);
890 if (rv
== MOJO_RESULT_OK
&& !body_stream_buffer_
.empty()) {
891 body_stream_writer_watcher_
.Start(
892 body_stream_writer_
.get(),
893 MOJO_HANDLE_SIGNAL_WRITABLE
,
894 MOJO_DEADLINE_INDEFINITE
,
895 base::Bind(&WebURLLoaderImpl::Context::OnHandleGotWritable
,
896 base::Unretained(this)));
901 void WebURLLoaderImpl::Context::OnHandleGotWritable(MojoResult result
) {
902 if (result
!= MOJO_RESULT_OK
) {
904 client_
->didFail(loader_
,
905 loader_
->CreateError(request_
.url(),
908 // |this| can be deleted here.
913 if (body_stream_buffer_
.empty())
916 MojoResult rv
= WriteDataOnBodyStream(nullptr, 0);
917 if (rv
== MOJO_RESULT_OK
) {
918 if (got_all_stream_body_data_
&& body_stream_buffer_
.empty()) {
919 // Close the handle to notify the end of data.
920 body_stream_writer_
.reset();
922 // TODO(yhirano): Pass appropriate arguments.
923 client_
->didFinishLoading(loader_
, 0, 0);
924 // |this| can be deleted here.
929 client_
->didFail(loader_
, loader_
->CreateError(request_
.url(),
932 // |this| can be deleted here.
937 // WebURLLoaderImpl -----------------------------------------------------------
939 WebURLLoaderImpl::WebURLLoaderImpl(
940 ResourceDispatcher
* resource_dispatcher
,
941 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
)
942 : context_(new Context(this, resource_dispatcher
, task_runner
)) {
945 WebURLLoaderImpl::~WebURLLoaderImpl() {
949 WebURLError
WebURLLoaderImpl::CreateError(const WebURL
& unreachable_url
,
950 bool stale_copy_in_cache
,
953 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
954 error
.reason
= reason
;
955 error
.unreachableURL
= unreachable_url
;
956 error
.staleCopyInCache
= stale_copy_in_cache
;
957 if (reason
== net::ERR_ABORTED
) {
958 error
.isCancellation
= true;
959 } else if (reason
== net::ERR_TEMPORARILY_THROTTLED
) {
960 error
.localizedDescription
= WebString::fromUTF8(
961 kThrottledErrorDescription
);
963 error
.localizedDescription
= WebString::fromUTF8(
964 net::ErrorToString(reason
));
969 void WebURLLoaderImpl::PopulateURLResponse(const GURL
& url
,
970 const ResourceResponseInfo
& info
,
971 WebURLResponse
* response
) {
972 response
->setURL(url
);
973 response
->setResponseTime(info
.response_time
.ToInternalValue());
974 response
->setMIMEType(WebString::fromUTF8(info
.mime_type
));
975 response
->setTextEncodingName(WebString::fromUTF8(info
.charset
));
976 response
->setExpectedContentLength(info
.content_length
);
977 response
->setSecurityInfo(info
.security_info
);
978 response
->setAppCacheID(info
.appcache_id
);
979 response
->setAppCacheManifestURL(info
.appcache_manifest_url
);
980 response
->setWasCached(!info
.load_timing
.request_start_time
.is_null() &&
981 info
.response_time
< info
.load_timing
.request_start_time
);
982 response
->setRemoteIPAddress(
983 WebString::fromUTF8(info
.socket_address
.host()));
984 response
->setRemotePort(info
.socket_address
.port());
985 response
->setConnectionID(info
.load_timing
.socket_log_id
);
986 response
->setConnectionReused(info
.load_timing
.socket_reused
);
987 response
->setDownloadFilePath(info
.download_file_path
.AsUTF16Unsafe());
988 response
->setWasFetchedViaSPDY(info
.was_fetched_via_spdy
);
989 response
->setWasFetchedViaServiceWorker(info
.was_fetched_via_service_worker
);
990 response
->setWasFallbackRequiredByServiceWorker(
991 info
.was_fallback_required_by_service_worker
);
992 response
->setServiceWorkerResponseType(info
.response_type_via_service_worker
);
993 response
->setOriginalURLViaServiceWorker(
994 info
.original_url_via_service_worker
);
996 WebURLResponseExtraDataImpl
* extra_data
=
997 new WebURLResponseExtraDataImpl(info
.npn_negotiated_protocol
);
998 response
->setExtraData(extra_data
);
999 extra_data
->set_was_fetched_via_spdy(info
.was_fetched_via_spdy
);
1000 extra_data
->set_was_npn_negotiated(info
.was_npn_negotiated
);
1001 extra_data
->set_was_alternate_protocol_available(
1002 info
.was_alternate_protocol_available
);
1003 extra_data
->set_connection_info(info
.connection_info
);
1004 extra_data
->set_was_fetched_via_proxy(info
.was_fetched_via_proxy
);
1005 extra_data
->set_proxy_server(info
.proxy_server
);
1007 // If there's no received headers end time, don't set load timing. This is
1008 // the case for non-HTTP requests, requests that don't go over the wire, and
1009 // certain error cases.
1010 if (!info
.load_timing
.receive_headers_end
.is_null()) {
1011 WebURLLoadTiming timing
;
1012 PopulateURLLoadTiming(info
.load_timing
, &timing
);
1013 const TimeTicks kNullTicks
;
1014 timing
.setServiceWorkerFetchStart(
1015 (info
.service_worker_fetch_start
- kNullTicks
).InSecondsF());
1016 timing
.setServiceWorkerFetchReady(
1017 (info
.service_worker_fetch_ready
- kNullTicks
).InSecondsF());
1018 timing
.setServiceWorkerFetchEnd(
1019 (info
.service_worker_fetch_end
- kNullTicks
).InSecondsF());
1020 response
->setLoadTiming(timing
);
1023 if (info
.devtools_info
.get()) {
1024 WebHTTPLoadInfo load_info
;
1026 load_info
.setHTTPStatusCode(info
.devtools_info
->http_status_code
);
1027 load_info
.setHTTPStatusText(WebString::fromLatin1(
1028 info
.devtools_info
->http_status_text
));
1029 load_info
.setEncodedDataLength(info
.encoded_data_length
);
1031 load_info
.setRequestHeadersText(WebString::fromLatin1(
1032 info
.devtools_info
->request_headers_text
));
1033 load_info
.setResponseHeadersText(WebString::fromLatin1(
1034 info
.devtools_info
->response_headers_text
));
1035 const HeadersVector
& request_headers
= info
.devtools_info
->request_headers
;
1036 for (HeadersVector::const_iterator it
= request_headers
.begin();
1037 it
!= request_headers
.end(); ++it
) {
1038 load_info
.addRequestHeader(WebString::fromLatin1(it
->first
),
1039 WebString::fromLatin1(it
->second
));
1041 const HeadersVector
& response_headers
=
1042 info
.devtools_info
->response_headers
;
1043 for (HeadersVector::const_iterator it
= response_headers
.begin();
1044 it
!= response_headers
.end(); ++it
) {
1045 load_info
.addResponseHeader(WebString::fromLatin1(it
->first
),
1046 WebString::fromLatin1(it
->second
));
1048 load_info
.setNPNNegotiatedProtocol(WebString::fromLatin1(
1049 info
.npn_negotiated_protocol
));
1050 response
->setHTTPLoadInfo(load_info
);
1053 const net::HttpResponseHeaders
* headers
= info
.headers
.get();
1057 WebURLResponse::HTTPVersion version
= WebURLResponse::Unknown
;
1058 if (headers
->GetHttpVersion() == net::HttpVersion(0, 9))
1059 version
= WebURLResponse::HTTP_0_9
;
1060 else if (headers
->GetHttpVersion() == net::HttpVersion(1, 0))
1061 version
= WebURLResponse::HTTP_1_0
;
1062 else if (headers
->GetHttpVersion() == net::HttpVersion(1, 1))
1063 version
= WebURLResponse::HTTP_1_1
;
1064 response
->setHTTPVersion(version
);
1065 response
->setHTTPStatusCode(headers
->response_code());
1066 response
->setHTTPStatusText(WebString::fromLatin1(headers
->GetStatusText()));
1068 // TODO(darin): We should leverage HttpResponseHeaders for this, and this
1069 // should be using the same code as ResourceDispatcherHost.
1070 // TODO(jungshik): Figure out the actual value of the referrer charset and
1071 // pass it to GetSuggestedFilename.
1073 headers
->EnumerateHeader(NULL
, "content-disposition", &value
);
1074 response
->setSuggestedFileName(
1075 net::GetSuggestedFilename(url
,
1077 std::string(), // referrer_charset
1078 std::string(), // suggested_name
1079 std::string(), // mime_type
1080 std::string())); // default_name
1083 if (headers
->GetLastModifiedValue(&time_val
))
1084 response
->setLastModifiedDate(time_val
.ToDoubleT());
1086 // Build up the header map.
1089 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
1090 response
->addHTTPHeaderField(WebString::fromLatin1(name
),
1091 WebString::fromLatin1(value
));
1095 void WebURLLoaderImpl::loadSynchronously(const WebURLRequest
& request
,
1096 WebURLResponse
& response
,
1099 SyncLoadResponse sync_load_response
;
1100 context_
->Start(request
, &sync_load_response
);
1102 const GURL
& final_url
= sync_load_response
.url
;
1104 // TODO(tc): For file loads, we may want to include a more descriptive
1105 // status code or status text.
1106 int error_code
= sync_load_response
.error_code
;
1107 if (error_code
!= net::OK
) {
1108 response
.setURL(final_url
);
1109 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1110 error
.reason
= error_code
;
1111 error
.unreachableURL
= final_url
;
1115 PopulateURLResponse(final_url
, sync_load_response
, &response
);
1117 data
.assign(sync_load_response
.data
.data(),
1118 sync_load_response
.data
.size());
1121 void WebURLLoaderImpl::loadAsynchronously(const WebURLRequest
& request
,
1122 WebURLLoaderClient
* client
) {
1123 DCHECK(!context_
->client());
1125 context_
->set_client(client
);
1126 context_
->Start(request
, NULL
);
1129 void WebURLLoaderImpl::cancel() {
1133 void WebURLLoaderImpl::setDefersLoading(bool value
) {
1134 context_
->SetDefersLoading(value
);
1137 void WebURLLoaderImpl::didChangePriority(WebURLRequest::Priority new_priority
,
1138 int intra_priority_value
) {
1139 context_
->DidChangePriority(new_priority
, intra_priority_value
);
1142 bool WebURLLoaderImpl::attachThreadedDataReceiver(
1143 blink::WebThreadedDataReceiver
* threaded_data_receiver
) {
1144 return context_
->AttachThreadedDataReceiver(threaded_data_receiver
);
1147 } // namespace content