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 // An implementation of WebURLLoader in terms of ResourceLoaderBridge.
7 #include "content/child/web_url_loader_impl.h"
13 #include "base/bind.h"
14 #include "base/command_line.h"
15 #include "base/files/file_path.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/strings/string_util.h"
19 #include "base/time/time.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/resource_loader_bridge.h"
26 #include "content/child/sync_load_response.h"
27 #include "content/child/web_data_consumer_handle_impl.h"
28 #include "content/child/web_url_request_util.h"
29 #include "content/child/weburlresponse_extradata_impl.h"
30 #include "content/common/resource_request_body.h"
31 #include "content/common/service_worker/service_worker_types.h"
32 #include "content/public/child/request_peer.h"
33 #include "content/public/common/content_switches.h"
34 #include "mojo/public/cpp/system/data_pipe.h"
35 #include "net/base/data_url.h"
36 #include "net/base/filename_util.h"
37 #include "net/base/mime_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/url_request/redirect_info.h"
42 #include "net/url_request/url_request_data_job.h"
43 #include "third_party/WebKit/public/platform/WebHTTPLoadInfo.h"
44 #include "third_party/WebKit/public/platform/WebURL.h"
45 #include "third_party/WebKit/public/platform/WebURLError.h"
46 #include "third_party/WebKit/public/platform/WebURLLoadTiming.h"
47 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
48 #include "third_party/WebKit/public/platform/WebURLRequest.h"
49 #include "third_party/WebKit/public/platform/WebURLResponse.h"
50 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
53 using base::TimeTicks
;
55 using blink::WebHTTPBody
;
56 using blink::WebHTTPHeaderVisitor
;
57 using blink::WebHTTPLoadInfo
;
58 using blink::WebReferrerPolicy
;
59 using blink::WebSecurityPolicy
;
60 using blink::WebString
;
62 using blink::WebURLError
;
63 using blink::WebURLLoadTiming
;
64 using blink::WebURLLoader
;
65 using blink::WebURLLoaderClient
;
66 using blink::WebURLRequest
;
67 using blink::WebURLResponse
;
71 // Utilities ------------------------------------------------------------------
75 const char kThrottledErrorDescription
[] =
76 "Request throttled. Visit http://dev.chromium.org/throttling for more "
78 const size_t kBodyStreamPipeCapacity
= 4 * 1024;
80 typedef ResourceDevToolsInfo::HeadersVector HeadersVector
;
82 // Converts timing data from |load_timing| to the format used by WebKit.
83 void PopulateURLLoadTiming(const net::LoadTimingInfo
& load_timing
,
84 WebURLLoadTiming
* url_timing
) {
85 DCHECK(!load_timing
.request_start
.is_null());
87 const TimeTicks kNullTicks
;
88 url_timing
->initialize();
89 url_timing
->setRequestTime(
90 (load_timing
.request_start
- kNullTicks
).InSecondsF());
91 url_timing
->setProxyStart(
92 (load_timing
.proxy_resolve_start
- kNullTicks
).InSecondsF());
93 url_timing
->setProxyEnd(
94 (load_timing
.proxy_resolve_end
- kNullTicks
).InSecondsF());
95 url_timing
->setDNSStart(
96 (load_timing
.connect_timing
.dns_start
- kNullTicks
).InSecondsF());
97 url_timing
->setDNSEnd(
98 (load_timing
.connect_timing
.dns_end
- kNullTicks
).InSecondsF());
99 url_timing
->setConnectStart(
100 (load_timing
.connect_timing
.connect_start
- kNullTicks
).InSecondsF());
101 url_timing
->setConnectEnd(
102 (load_timing
.connect_timing
.connect_end
- kNullTicks
).InSecondsF());
103 url_timing
->setSSLStart(
104 (load_timing
.connect_timing
.ssl_start
- kNullTicks
).InSecondsF());
105 url_timing
->setSSLEnd(
106 (load_timing
.connect_timing
.ssl_end
- kNullTicks
).InSecondsF());
107 url_timing
->setSendStart(
108 (load_timing
.send_start
- kNullTicks
).InSecondsF());
109 url_timing
->setSendEnd(
110 (load_timing
.send_end
- kNullTicks
).InSecondsF());
111 url_timing
->setReceiveHeadersEnd(
112 (load_timing
.receive_headers_end
- kNullTicks
).InSecondsF());
115 net::RequestPriority
ConvertWebKitPriorityToNetPriority(
116 const WebURLRequest::Priority
& priority
) {
118 case WebURLRequest::PriorityVeryHigh
:
121 case WebURLRequest::PriorityHigh
:
124 case WebURLRequest::PriorityMedium
:
127 case WebURLRequest::PriorityLow
:
130 case WebURLRequest::PriorityVeryLow
:
133 case WebURLRequest::PriorityUnresolved
:
140 // Extracts info from a data scheme URL into |info| and |data|. Returns net::OK
141 // if successful. Returns a net error code otherwise. Exported only for testing.
142 int GetInfoFromDataURL(const GURL
& url
,
143 ResourceResponseInfo
* info
,
145 // Assure same time for all time fields of data: URLs.
146 Time now
= Time::Now();
147 info
->load_timing
.request_start
= TimeTicks::Now();
148 info
->load_timing
.request_start_time
= now
;
149 info
->request_time
= now
;
150 info
->response_time
= now
;
152 std::string mime_type
;
154 scoped_refptr
<net::HttpResponseHeaders
> headers(
155 new net::HttpResponseHeaders(std::string()));
156 int result
= net::URLRequestDataJob::BuildResponse(
157 url
, &mime_type
, &charset
, data
, headers
.get());
158 if (result
!= net::OK
)
161 info
->headers
= headers
;
162 info
->mime_type
.swap(mime_type
);
163 info
->charset
.swap(charset
);
164 info
->security_info
.clear();
165 info
->content_length
= data
->length();
166 info
->encoded_data_length
= 0;
171 #define STATIC_ASSERT_MATCHING_ENUMS(content_name, blink_name) \
173 static_cast<int>(content_name) == static_cast<int>(blink_name), \
174 "mismatching enums: " #content_name)
176 STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_SAME_ORIGIN
,
177 WebURLRequest::FetchRequestModeSameOrigin
);
178 STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_NO_CORS
,
179 WebURLRequest::FetchRequestModeNoCORS
);
180 STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_CORS
,
181 WebURLRequest::FetchRequestModeCORS
);
182 STATIC_ASSERT_MATCHING_ENUMS(
183 FETCH_REQUEST_MODE_CORS_WITH_FORCED_PREFLIGHT
,
184 WebURLRequest::FetchRequestModeCORSWithForcedPreflight
);
186 FetchRequestMode
GetFetchRequestMode(const WebURLRequest
& request
) {
187 return static_cast<FetchRequestMode
>(request
.fetchRequestMode());
190 STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_OMIT
,
191 WebURLRequest::FetchCredentialsModeOmit
);
192 STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_SAME_ORIGIN
,
193 WebURLRequest::FetchCredentialsModeSameOrigin
);
194 STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_INCLUDE
,
195 WebURLRequest::FetchCredentialsModeInclude
);
197 FetchCredentialsMode
GetFetchCredentialsMode(const WebURLRequest
& request
) {
198 return static_cast<FetchCredentialsMode
>(request
.fetchCredentialsMode());
201 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_AUXILIARY
,
202 WebURLRequest::FrameTypeAuxiliary
);
203 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_NESTED
,
204 WebURLRequest::FrameTypeNested
);
205 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_NONE
,
206 WebURLRequest::FrameTypeNone
);
207 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL
,
208 WebURLRequest::FrameTypeTopLevel
);
210 RequestContextFrameType
GetRequestContextFrameType(
211 const WebURLRequest
& request
) {
212 return static_cast<RequestContextFrameType
>(request
.frameType());
215 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_UNSPECIFIED
,
216 WebURLRequest::RequestContextUnspecified
);
217 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_AUDIO
,
218 WebURLRequest::RequestContextAudio
);
219 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_BEACON
,
220 WebURLRequest::RequestContextBeacon
);
221 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_CSP_REPORT
,
222 WebURLRequest::RequestContextCSPReport
);
223 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_DOWNLOAD
,
224 WebURLRequest::RequestContextDownload
);
225 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_EMBED
,
226 WebURLRequest::RequestContextEmbed
);
227 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_EVENT_SOURCE
,
228 WebURLRequest::RequestContextEventSource
);
229 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FAVICON
,
230 WebURLRequest::RequestContextFavicon
);
231 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FETCH
,
232 WebURLRequest::RequestContextFetch
);
233 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FONT
,
234 WebURLRequest::RequestContextFont
);
235 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FORM
,
236 WebURLRequest::RequestContextForm
);
237 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FRAME
,
238 WebURLRequest::RequestContextFrame
);
239 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_HYPERLINK
,
240 WebURLRequest::RequestContextHyperlink
);
241 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IFRAME
,
242 WebURLRequest::RequestContextIframe
);
243 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMAGE
,
244 WebURLRequest::RequestContextImage
);
245 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMAGE_SET
,
246 WebURLRequest::RequestContextImageSet
);
247 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMPORT
,
248 WebURLRequest::RequestContextImport
);
249 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_INTERNAL
,
250 WebURLRequest::RequestContextInternal
);
251 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_LOCATION
,
252 WebURLRequest::RequestContextLocation
);
253 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_MANIFEST
,
254 WebURLRequest::RequestContextManifest
);
255 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_OBJECT
,
256 WebURLRequest::RequestContextObject
);
257 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PING
,
258 WebURLRequest::RequestContextPing
);
259 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PLUGIN
,
260 WebURLRequest::RequestContextPlugin
);
261 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PREFETCH
,
262 WebURLRequest::RequestContextPrefetch
);
263 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SCRIPT
,
264 WebURLRequest::RequestContextScript
);
265 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SERVICE_WORKER
,
266 WebURLRequest::RequestContextServiceWorker
);
267 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SHARED_WORKER
,
268 WebURLRequest::RequestContextSharedWorker
);
269 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SUBRESOURCE
,
270 WebURLRequest::RequestContextSubresource
);
271 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_STYLE
,
272 WebURLRequest::RequestContextStyle
);
273 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_TRACK
,
274 WebURLRequest::RequestContextTrack
);
275 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_VIDEO
,
276 WebURLRequest::RequestContextVideo
);
277 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_WORKER
,
278 WebURLRequest::RequestContextWorker
);
279 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_XML_HTTP_REQUEST
,
280 WebURLRequest::RequestContextXMLHttpRequest
);
281 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_XSLT
,
282 WebURLRequest::RequestContextXSLT
);
284 RequestContextType
GetRequestContextType(const WebURLRequest
& request
) {
285 return static_cast<RequestContextType
>(request
.requestContext());
290 // WebURLLoaderImpl::Context --------------------------------------------------
292 // This inner class exists since the WebURLLoader may be deleted while inside a
293 // call to WebURLLoaderClient. Refcounting is to keep the context from being
294 // deleted if it may have work to do after calling into the client.
295 class WebURLLoaderImpl::Context
: public base::RefCounted
<Context
>,
298 Context(WebURLLoaderImpl
* loader
,
299 ResourceDispatcher
* resource_dispatcher
,
300 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
);
302 WebURLLoaderClient
* client() const { return client_
; }
303 void set_client(WebURLLoaderClient
* client
) { client_
= client
; }
306 void SetDefersLoading(bool value
);
307 void DidChangePriority(WebURLRequest::Priority new_priority
,
308 int intra_priority_value
);
309 bool AttachThreadedDataReceiver(
310 blink::WebThreadedDataReceiver
* threaded_data_receiver
);
311 void Start(const WebURLRequest
& request
,
312 SyncLoadResponse
* sync_load_response
);
314 // RequestPeer methods:
315 void OnUploadProgress(uint64 position
, uint64 size
) override
;
316 bool OnReceivedRedirect(const net::RedirectInfo
& redirect_info
,
317 const ResourceResponseInfo
& info
) override
;
318 void OnReceivedResponse(const ResourceResponseInfo
& info
) override
;
319 void OnDownloadedData(int len
, int encoded_data_length
) override
;
320 void OnReceivedData(const char* data
,
322 int encoded_data_length
) override
;
323 void OnReceivedCachedMetadata(const char* data
, int len
) override
;
324 void OnCompletedRequest(int error_code
,
325 bool was_ignored_by_handler
,
326 bool stale_copy_in_cache
,
327 const std::string
& security_info
,
328 const base::TimeTicks
& completion_time
,
329 int64 total_transfer_size
) override
;
332 friend class base::RefCounted
<Context
>;
333 ~Context() override
{}
335 // We can optimize the handling of data URLs in most cases.
336 bool CanHandleDataURLRequestLocally() const;
337 void HandleDataURL();
338 MojoResult
WriteDataOnBodyStream(const char* data
, size_t size
);
339 void OnHandleGotWritable(MojoResult
);
341 WebURLLoaderImpl
* loader_
;
342 WebURLRequest request_
;
343 WebURLLoaderClient
* client_
;
344 ResourceDispatcher
* resource_dispatcher_
;
345 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
346 WebReferrerPolicy referrer_policy_
;
347 scoped_ptr
<ResourceLoaderBridge
> bridge_
;
348 scoped_ptr
<FtpDirectoryListingResponseDelegate
> ftp_listing_delegate_
;
349 scoped_ptr
<MultipartResponseDelegate
> multipart_delegate_
;
350 scoped_ptr
<ResourceLoaderBridge
> completed_bridge_
;
351 scoped_ptr
<StreamOverrideParameters
> stream_override_
;
352 mojo::ScopedDataPipeProducerHandle body_stream_writer_
;
353 mojo::common::HandleWatcher body_stream_writer_watcher_
;
354 // TODO(yhirano): Delete this buffer after implementing the back-pressure
356 std::deque
<char> body_stream_buffer_
;
357 bool got_all_stream_body_data_
;
358 enum DeferState
{NOT_DEFERRING
, SHOULD_DEFER
, DEFERRED_DATA
};
359 DeferState defers_loading_
;
362 WebURLLoaderImpl::Context::Context(
363 WebURLLoaderImpl
* loader
,
364 ResourceDispatcher
* resource_dispatcher
,
365 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
)
368 resource_dispatcher_(resource_dispatcher
),
369 task_runner_(task_runner
),
370 referrer_policy_(blink::WebReferrerPolicyDefault
),
371 got_all_stream_body_data_(false),
372 defers_loading_(NOT_DEFERRING
) {
375 void WebURLLoaderImpl::Context::Cancel() {
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
) {
396 bridge_
->SetDefersLoading(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
) {
411 bridge_
->DidChangePriority(
412 ConvertWebKitPriorityToNetPriority(new_priority
), intra_priority_value
);
415 bool WebURLLoaderImpl::Context::AttachThreadedDataReceiver(
416 blink::WebThreadedDataReceiver
* threaded_data_receiver
) {
418 return bridge_
->AttachThreadedDataReceiver(threaded_data_receiver
);
423 void WebURLLoaderImpl::Context::Start(const WebURLRequest
& request
,
424 SyncLoadResponse
* sync_load_response
) {
425 DCHECK(!bridge_
.get());
427 request_
= request
; // Save the request.
428 if (request
.extraData()) {
429 RequestExtraData
* extra_data
=
430 static_cast<RequestExtraData
*>(request
.extraData());
431 stream_override_
= extra_data
->TakeStreamOverrideOwnership();
434 GURL url
= request
.url();
436 // PlzNavigate: during navigation, the renderer should request a stream which
437 // contains the body of the response. The request has already been made by the
439 if (stream_override_
.get()) {
440 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
441 switches::kEnableBrowserSideNavigation
));
442 DCHECK(!sync_load_response
);
443 DCHECK_NE(WebURLRequest::FrameTypeNone
, request
.frameType());
444 DCHECK_EQ("GET", request
.httpMethod().latin1());
445 url
= stream_override_
->stream_url
;
448 // PlzNavigate: the only navigation requests going through the WebURLLoader
449 // are the ones created by CommitNavigation.
450 DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
451 switches::kEnableBrowserSideNavigation
) ||
452 stream_override_
.get() ||
453 request
.frameType() == WebURLRequest::FrameTypeNone
);
455 if (CanHandleDataURLRequestLocally()) {
456 if (sync_load_response
) {
457 // This is a sync load. Do the work now.
458 sync_load_response
->url
= url
;
459 sync_load_response
->error_code
=
460 GetInfoFromDataURL(sync_load_response
->url
, sync_load_response
,
461 &sync_load_response
->data
);
463 task_runner_
->PostTask(FROM_HERE
,
464 base::Bind(&Context::HandleDataURL
, this));
470 request
.httpHeaderField(WebString::fromUTF8("Referer")).latin1());
471 const std::string
& method
= request
.httpMethod().latin1();
473 // TODO(brettw) this should take parameter encoding into account when
474 // creating the GURLs.
476 // TODO(horo): Check credentials flag is unset when credentials mode is omit.
477 // Check credentials flag is set when credentials mode is include.
479 RequestInfo request_info
;
480 request_info
.method
= method
;
481 request_info
.url
= url
;
482 request_info
.first_party_for_cookies
= request
.firstPartyForCookies();
483 referrer_policy_
= request
.referrerPolicy();
484 request_info
.referrer
= Referrer(referrer_url
, referrer_policy_
);
485 request_info
.headers
= GetWebURLRequestHeaders(request
);
486 request_info
.load_flags
= GetLoadFlagsForWebURLRequest(request
);
487 request_info
.enable_load_timing
= true;
488 request_info
.enable_upload_progress
= request
.reportUploadProgress();
489 if (request
.requestContext() == WebURLRequest::RequestContextXMLHttpRequest
&&
490 (url
.has_username() || url
.has_password())) {
491 request_info
.do_not_prompt_for_login
= true;
493 // requestor_pid only needs to be non-zero if the request originates outside
494 // the render process, so we can use requestorProcessID even for requests
495 // from in-process plugins.
496 request_info
.requestor_pid
= request
.requestorProcessID();
497 request_info
.request_type
= WebURLRequestToResourceType(request
);
498 request_info
.priority
=
499 ConvertWebKitPriorityToNetPriority(request
.priority());
500 request_info
.appcache_host_id
= request
.appCacheHostID();
501 request_info
.routing_id
= request
.requestorID();
502 request_info
.download_to_file
= request
.downloadToFile();
503 request_info
.has_user_gesture
= request
.hasUserGesture();
504 request_info
.skip_service_worker
= request
.skipServiceWorker();
505 request_info
.should_reset_appcache
= request
.shouldResetAppCache();
506 request_info
.fetch_request_mode
= GetFetchRequestMode(request
);
507 request_info
.fetch_credentials_mode
= GetFetchCredentialsMode(request
);
508 request_info
.fetch_request_context_type
= GetRequestContextType(request
);
509 request_info
.fetch_frame_type
= GetRequestContextFrameType(request
);
510 request_info
.extra_data
= request
.extraData();
511 bridge_
.reset(resource_dispatcher_
->CreateBridge(request_info
));
512 bridge_
->SetRequestBody(GetRequestBodyForWebURLRequest(request
).get());
514 if (sync_load_response
) {
515 bridge_
->SyncLoad(sync_load_response
);
519 // TODO(mmenke): This case probably never happens, anyways. Probably should
520 // not handle this case at all. If it's worth handling, this code currently
521 // results in the request just hanging, which should be fixed.
522 if (!bridge_
->Start(this))
526 void WebURLLoaderImpl::Context::OnUploadProgress(uint64 position
, uint64 size
) {
528 client_
->didSendData(loader_
, position
, size
);
531 bool WebURLLoaderImpl::Context::OnReceivedRedirect(
532 const net::RedirectInfo
& redirect_info
,
533 const ResourceResponseInfo
& info
) {
537 WebURLResponse response
;
538 response
.initialize();
539 PopulateURLResponse(request_
.url(), info
, &response
);
541 // TODO(darin): We lack sufficient information to construct the actual
542 // request that resulted from the redirect.
543 WebURLRequest
new_request(redirect_info
.new_url
);
544 new_request
.setFirstPartyForCookies(
545 redirect_info
.new_first_party_for_cookies
);
546 new_request
.setDownloadToFile(request_
.downloadToFile());
547 new_request
.setRequestContext(request_
.requestContext());
548 new_request
.setFrameType(request_
.frameType());
549 new_request
.setSkipServiceWorker(request_
.skipServiceWorker());
550 new_request
.setShouldResetAppCache(request_
.shouldResetAppCache());
551 new_request
.setFetchRequestMode(request_
.fetchRequestMode());
552 new_request
.setFetchCredentialsMode(request_
.fetchCredentialsMode());
554 new_request
.setHTTPReferrer(WebString::fromUTF8(redirect_info
.new_referrer
),
557 std::string old_method
= request_
.httpMethod().utf8();
558 new_request
.setHTTPMethod(WebString::fromUTF8(redirect_info
.new_method
));
559 if (redirect_info
.new_method
== old_method
)
560 new_request
.setHTTPBody(request_
.httpBody());
562 // Protect from deletion during call to willSendRequest.
563 scoped_refptr
<Context
> protect(this);
565 client_
->willSendRequest(loader_
, new_request
, response
);
566 request_
= new_request
;
568 // Only follow the redirect if WebKit left the URL unmodified.
569 if (redirect_info
.new_url
== GURL(new_request
.url())) {
570 // First-party cookie logic moved from DocumentLoader in Blink to
571 // net::URLRequest in the browser. Assert that Blink didn't try to change it
572 // to something else.
573 DCHECK_EQ(redirect_info
.new_first_party_for_cookies
.spec(),
574 request_
.firstPartyForCookies().string().utf8());
578 // We assume that WebKit only changes the URL to suppress a redirect, and we
579 // assume that it does so by setting it to be invalid.
580 DCHECK(!new_request
.url().isValid());
584 void WebURLLoaderImpl::Context::OnReceivedResponse(
585 const ResourceResponseInfo
& initial_info
) {
589 ResourceResponseInfo info
= initial_info
;
591 // PlzNavigate: during navigations, the ResourceResponse has already been
592 // received on the browser side, and has been passed down to the renderer.
593 if (stream_override_
.get()) {
594 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
595 switches::kEnableBrowserSideNavigation
));
596 info
= stream_override_
->response
;
599 WebURLResponse response
;
600 response
.initialize();
601 PopulateURLResponse(request_
.url(), info
, &response
);
603 bool show_raw_listing
= (GURL(request_
.url()).query() == "raw");
605 if (info
.mime_type
== "text/vnd.chromium.ftp-dir") {
606 if (show_raw_listing
) {
607 // Set the MIME type to plain text to prevent any active content.
608 response
.setMIMEType("text/plain");
610 // We're going to produce a parsed listing in HTML.
611 response
.setMIMEType("text/html");
615 // Prevent |this| from being destroyed if the client destroys the loader,
616 // ether in didReceiveResponse, or when the multipart/ftp delegate calls into
618 scoped_refptr
<Context
> protect(this);
620 if (request_
.useStreamOnResponse()) {
621 MojoCreateDataPipeOptions options
;
622 options
.struct_size
= sizeof(MojoCreateDataPipeOptions
);
623 options
.flags
= MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE
;
624 options
.element_num_bytes
= 1;
625 options
.capacity_num_bytes
= kBodyStreamPipeCapacity
;
627 mojo::ScopedDataPipeConsumerHandle consumer
;
628 MojoResult result
= mojo::CreateDataPipe(&options
,
629 &body_stream_writer_
,
631 if (result
!= MOJO_RESULT_OK
) {
632 // TODO(yhirano): Handle the error.
635 client_
->didReceiveResponse(
636 loader_
, response
, new WebDataConsumerHandleImpl(consumer
.Pass()));
638 client_
->didReceiveResponse(loader_
, response
);
641 // We may have been cancelled after didReceiveResponse, which would leave us
642 // without a client and therefore without much need to do further handling.
646 DCHECK(!ftp_listing_delegate_
.get());
647 DCHECK(!multipart_delegate_
.get());
648 if (info
.headers
.get() && info
.mime_type
== "multipart/x-mixed-replace") {
649 std::string content_type
;
650 info
.headers
->EnumerateHeader(NULL
, "content-type", &content_type
);
652 std::string mime_type
;
654 bool had_charset
= false;
655 std::string boundary
;
656 net::HttpUtil::ParseContentType(content_type
, &mime_type
, &charset
,
657 &had_charset
, &boundary
);
658 base::TrimString(boundary
, " \"", &boundary
);
660 // If there's no boundary, just handle the request normally. In the gecko
661 // code, nsMultiMixedConv::OnStartRequest throws an exception.
662 if (!boundary
.empty()) {
663 multipart_delegate_
.reset(
664 new MultipartResponseDelegate(client_
, loader_
, response
, boundary
));
666 } else if (info
.mime_type
== "text/vnd.chromium.ftp-dir" &&
668 ftp_listing_delegate_
.reset(
669 new FtpDirectoryListingResponseDelegate(client_
, loader_
, response
));
673 void WebURLLoaderImpl::Context::OnDownloadedData(int len
,
674 int encoded_data_length
) {
676 client_
->didDownloadData(loader_
, len
, encoded_data_length
);
679 void WebURLLoaderImpl::Context::OnReceivedData(const char* data
,
681 int encoded_data_length
) {
685 if (request_
.useStreamOnResponse()) {
686 // We don't support ftp_listening_delegate_ and multipart_delegate_ for now.
687 // TODO(yhirano): Support ftp listening and multipart.
688 MojoResult rv
= WriteDataOnBodyStream(data
, data_length
);
689 if (rv
!= MOJO_RESULT_OK
&& client_
) {
690 client_
->didFail(loader_
,
691 loader_
->CreateError(request_
.url(),
695 } else if (ftp_listing_delegate_
) {
696 // The FTP listing delegate will make the appropriate calls to
697 // client_->didReceiveData and client_->didReceiveResponse. Since the
698 // delegate may want to do work after sending data to the delegate, keep
699 // |this| and the delegate alive until it's finished handling the data.
700 scoped_refptr
<Context
> protect(this);
701 ftp_listing_delegate_
->OnReceivedData(data
, data_length
);
702 } else if (multipart_delegate_
) {
703 // The multipart delegate will make the appropriate calls to
704 // client_->didReceiveData and client_->didReceiveResponse. Since the
705 // delegate may want to do work after sending data to the delegate, keep
706 // |this| and the delegate alive until it's finished handling the data.
707 scoped_refptr
<Context
> protect(this);
708 multipart_delegate_
->OnReceivedData(data
, data_length
, encoded_data_length
);
710 client_
->didReceiveData(loader_
, data
, data_length
, encoded_data_length
);
714 void WebURLLoaderImpl::Context::OnReceivedCachedMetadata(
715 const char* data
, int len
) {
717 client_
->didReceiveCachedMetadata(loader_
, data
, len
);
720 void WebURLLoaderImpl::Context::OnCompletedRequest(
722 bool was_ignored_by_handler
,
723 bool stale_copy_in_cache
,
724 const std::string
& security_info
,
725 const base::TimeTicks
& completion_time
,
726 int64 total_transfer_size
) {
727 // The WebURLLoaderImpl may be deleted in any of the calls to the client or
728 // the delegates below (As they also may call in to the client). Keep |this|
729 // alive in that case, to avoid a crash. If that happens, the request will be
730 // cancelled and |client_| will be set to NULL.
731 scoped_refptr
<Context
> protect(this);
733 if (ftp_listing_delegate_
) {
734 ftp_listing_delegate_
->OnCompletedRequest();
735 ftp_listing_delegate_
.reset(NULL
);
736 } else if (multipart_delegate_
) {
737 multipart_delegate_
->OnCompletedRequest();
738 multipart_delegate_
.reset(NULL
);
741 // Prevent any further IPC to the browser now that we're complete, but
742 // don't delete it to keep any downloaded temp files alive.
743 DCHECK(!completed_bridge_
.get());
744 completed_bridge_
.swap(bridge_
);
747 if (error_code
!= net::OK
) {
748 client_
->didFail(loader_
, CreateError(request_
.url(),
752 if (request_
.useStreamOnResponse()) {
753 got_all_stream_body_data_
= true;
754 if (body_stream_buffer_
.empty()) {
755 // Close the handle to notify the end of data.
756 body_stream_writer_
.reset();
757 client_
->didFinishLoading(
758 loader_
, (completion_time
- TimeTicks()).InSecondsF(),
759 total_transfer_size
);
762 client_
->didFinishLoading(
763 loader_
, (completion_time
- TimeTicks()).InSecondsF(),
764 total_transfer_size
);
770 bool WebURLLoaderImpl::Context::CanHandleDataURLRequestLocally() const {
771 GURL url
= request_
.url();
772 if (!url
.SchemeIs(url::kDataScheme
))
775 // The fast paths for data URL, Start() and HandleDataURL(), don't support
776 // the downloadToFile option.
777 if (request_
.downloadToFile())
780 // Optimize for the case where we can handle a data URL locally. We must
781 // skip this for data URLs targetted at frames since those could trigger a
784 // NOTE: We special case MIME types we can render both for performance
785 // reasons as well as to support unit tests, which do not have an underlying
786 // ResourceLoaderBridge implementation.
788 #if defined(OS_ANDROID)
789 // For compatibility reasons on Android we need to expose top-level data://
791 if (request_
.frameType() == WebURLRequest::FrameTypeTopLevel
)
795 if (request_
.frameType() != WebURLRequest::FrameTypeTopLevel
&&
796 request_
.frameType() != WebURLRequest::FrameTypeNested
)
799 std::string mime_type
, unused_charset
;
800 if (net::DataURL::Parse(request_
.url(), &mime_type
, &unused_charset
, NULL
) &&
801 net::IsSupportedMimeType(mime_type
))
807 void WebURLLoaderImpl::Context::HandleDataURL() {
808 DCHECK_NE(defers_loading_
, DEFERRED_DATA
);
809 if (defers_loading_
== SHOULD_DEFER
) {
810 defers_loading_
= DEFERRED_DATA
;
814 ResourceResponseInfo info
;
817 int error_code
= GetInfoFromDataURL(request_
.url(), &info
, &data
);
819 if (error_code
== net::OK
) {
820 OnReceivedResponse(info
);
822 OnReceivedData(data
.data(), data
.size(), 0);
825 OnCompletedRequest(error_code
, false, false, info
.security_info
,
826 base::TimeTicks::Now(), 0);
829 MojoResult
WebURLLoaderImpl::Context::WriteDataOnBodyStream(const char* data
,
831 if (body_stream_buffer_
.empty() && size
== 0) {
833 return MOJO_RESULT_OK
;
836 if (!body_stream_writer_
.is_valid()) {
837 // The handle is already cleared.
838 return MOJO_RESULT_OK
;
841 char* buffer
= nullptr;
842 uint32_t num_bytes_writable
= 0;
843 MojoResult rv
= mojo::BeginWriteDataRaw(body_stream_writer_
.get(),
844 reinterpret_cast<void**>(&buffer
),
846 MOJO_WRITE_DATA_FLAG_NONE
);
847 if (rv
== MOJO_RESULT_SHOULD_WAIT
) {
848 body_stream_buffer_
.insert(body_stream_buffer_
.end(), data
, data
+ size
);
849 body_stream_writer_watcher_
.Start(
850 body_stream_writer_
.get(),
851 MOJO_HANDLE_SIGNAL_WRITABLE
,
852 MOJO_DEADLINE_INDEFINITE
,
853 base::Bind(&WebURLLoaderImpl::Context::OnHandleGotWritable
,
854 base::Unretained(this)));
855 return MOJO_RESULT_OK
;
858 if (rv
!= MOJO_RESULT_OK
)
861 uint32_t num_bytes_to_write
= 0;
862 if (num_bytes_writable
< body_stream_buffer_
.size()) {
863 auto begin
= body_stream_buffer_
.begin();
864 auto end
= body_stream_buffer_
.begin() + num_bytes_writable
;
866 std::copy(begin
, end
, buffer
);
867 num_bytes_to_write
= num_bytes_writable
;
868 body_stream_buffer_
.erase(begin
, end
);
869 body_stream_buffer_
.insert(body_stream_buffer_
.end(), data
, data
+ size
);
871 std::copy(body_stream_buffer_
.begin(), body_stream_buffer_
.end(), buffer
);
872 num_bytes_writable
-= body_stream_buffer_
.size();
873 num_bytes_to_write
+= body_stream_buffer_
.size();
874 buffer
+= body_stream_buffer_
.size();
875 body_stream_buffer_
.clear();
877 size_t num_newbytes_to_write
=
878 std::min(size
, static_cast<size_t>(num_bytes_writable
));
879 std::copy(data
, data
+ num_newbytes_to_write
, buffer
);
880 num_bytes_to_write
+= num_newbytes_to_write
;
881 body_stream_buffer_
.insert(body_stream_buffer_
.end(),
882 data
+ num_newbytes_to_write
,
886 rv
= mojo::EndWriteDataRaw(body_stream_writer_
.get(), num_bytes_to_write
);
887 if (rv
== MOJO_RESULT_OK
&& !body_stream_buffer_
.empty()) {
888 body_stream_writer_watcher_
.Start(
889 body_stream_writer_
.get(),
890 MOJO_HANDLE_SIGNAL_WRITABLE
,
891 MOJO_DEADLINE_INDEFINITE
,
892 base::Bind(&WebURLLoaderImpl::Context::OnHandleGotWritable
,
893 base::Unretained(this)));
898 void WebURLLoaderImpl::Context::OnHandleGotWritable(MojoResult result
) {
899 if (result
!= MOJO_RESULT_OK
) {
901 client_
->didFail(loader_
,
902 loader_
->CreateError(request_
.url(),
905 // |this| can be deleted here.
910 if (body_stream_buffer_
.empty())
913 MojoResult rv
= WriteDataOnBodyStream(nullptr, 0);
914 if (rv
== MOJO_RESULT_OK
) {
915 if (got_all_stream_body_data_
&& body_stream_buffer_
.empty()) {
916 // Close the handle to notify the end of data.
917 body_stream_writer_
.reset();
919 // TODO(yhirano): Pass appropriate arguments.
920 client_
->didFinishLoading(loader_
, 0, 0);
921 // |this| can be deleted here.
926 client_
->didFail(loader_
, loader_
->CreateError(request_
.url(),
929 // |this| can be deleted here.
934 // WebURLLoaderImpl -----------------------------------------------------------
936 WebURLLoaderImpl::WebURLLoaderImpl(
937 ResourceDispatcher
* resource_dispatcher
,
938 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
)
939 : context_(new Context(this, resource_dispatcher
, task_runner
)) {
942 WebURLLoaderImpl::~WebURLLoaderImpl() {
946 WebURLError
WebURLLoaderImpl::CreateError(const WebURL
& unreachable_url
,
947 bool stale_copy_in_cache
,
950 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
951 error
.reason
= reason
;
952 error
.unreachableURL
= unreachable_url
;
953 error
.staleCopyInCache
= stale_copy_in_cache
;
954 if (reason
== net::ERR_ABORTED
) {
955 error
.isCancellation
= true;
956 } else if (reason
== net::ERR_TEMPORARILY_THROTTLED
) {
957 error
.localizedDescription
= WebString::fromUTF8(
958 kThrottledErrorDescription
);
960 error
.localizedDescription
= WebString::fromUTF8(
961 net::ErrorToString(reason
));
966 void WebURLLoaderImpl::PopulateURLResponse(const GURL
& url
,
967 const ResourceResponseInfo
& info
,
968 WebURLResponse
* response
) {
969 response
->setURL(url
);
970 response
->setResponseTime(info
.response_time
.ToDoubleT());
971 response
->setMIMEType(WebString::fromUTF8(info
.mime_type
));
972 response
->setTextEncodingName(WebString::fromUTF8(info
.charset
));
973 response
->setExpectedContentLength(info
.content_length
);
974 response
->setSecurityInfo(info
.security_info
);
975 response
->setAppCacheID(info
.appcache_id
);
976 response
->setAppCacheManifestURL(info
.appcache_manifest_url
);
977 response
->setWasCached(!info
.load_timing
.request_start_time
.is_null() &&
978 info
.response_time
< info
.load_timing
.request_start_time
);
979 response
->setRemoteIPAddress(
980 WebString::fromUTF8(info
.socket_address
.host()));
981 response
->setRemotePort(info
.socket_address
.port());
982 response
->setConnectionID(info
.load_timing
.socket_log_id
);
983 response
->setConnectionReused(info
.load_timing
.socket_reused
);
984 response
->setDownloadFilePath(info
.download_file_path
.AsUTF16Unsafe());
985 response
->setWasFetchedViaSPDY(info
.was_fetched_via_spdy
);
986 response
->setWasFetchedViaServiceWorker(info
.was_fetched_via_service_worker
);
987 response
->setWasFallbackRequiredByServiceWorker(
988 info
.was_fallback_required_by_service_worker
);
989 response
->setServiceWorkerResponseType(info
.response_type_via_service_worker
);
990 response
->setOriginalURLViaServiceWorker(
991 info
.original_url_via_service_worker
);
993 WebURLResponseExtraDataImpl
* extra_data
=
994 new WebURLResponseExtraDataImpl(info
.npn_negotiated_protocol
);
995 response
->setExtraData(extra_data
);
996 extra_data
->set_was_fetched_via_spdy(info
.was_fetched_via_spdy
);
997 extra_data
->set_was_npn_negotiated(info
.was_npn_negotiated
);
998 extra_data
->set_was_alternate_protocol_available(
999 info
.was_alternate_protocol_available
);
1000 extra_data
->set_connection_info(info
.connection_info
);
1001 extra_data
->set_was_fetched_via_proxy(info
.was_fetched_via_proxy
);
1002 extra_data
->set_proxy_server(info
.proxy_server
);
1004 // If there's no received headers end time, don't set load timing. This is
1005 // the case for non-HTTP requests, requests that don't go over the wire, and
1006 // certain error cases.
1007 if (!info
.load_timing
.receive_headers_end
.is_null()) {
1008 WebURLLoadTiming timing
;
1009 PopulateURLLoadTiming(info
.load_timing
, &timing
);
1010 const TimeTicks kNullTicks
;
1011 timing
.setServiceWorkerFetchStart(
1012 (info
.service_worker_fetch_start
- kNullTicks
).InSecondsF());
1013 timing
.setServiceWorkerFetchReady(
1014 (info
.service_worker_fetch_ready
- kNullTicks
).InSecondsF());
1015 timing
.setServiceWorkerFetchEnd(
1016 (info
.service_worker_fetch_end
- kNullTicks
).InSecondsF());
1017 response
->setLoadTiming(timing
);
1020 if (info
.devtools_info
.get()) {
1021 WebHTTPLoadInfo load_info
;
1023 load_info
.setHTTPStatusCode(info
.devtools_info
->http_status_code
);
1024 load_info
.setHTTPStatusText(WebString::fromLatin1(
1025 info
.devtools_info
->http_status_text
));
1026 load_info
.setEncodedDataLength(info
.encoded_data_length
);
1028 load_info
.setRequestHeadersText(WebString::fromLatin1(
1029 info
.devtools_info
->request_headers_text
));
1030 load_info
.setResponseHeadersText(WebString::fromLatin1(
1031 info
.devtools_info
->response_headers_text
));
1032 const HeadersVector
& request_headers
= info
.devtools_info
->request_headers
;
1033 for (HeadersVector::const_iterator it
= request_headers
.begin();
1034 it
!= request_headers
.end(); ++it
) {
1035 load_info
.addRequestHeader(WebString::fromLatin1(it
->first
),
1036 WebString::fromLatin1(it
->second
));
1038 const HeadersVector
& response_headers
=
1039 info
.devtools_info
->response_headers
;
1040 for (HeadersVector::const_iterator it
= response_headers
.begin();
1041 it
!= response_headers
.end(); ++it
) {
1042 load_info
.addResponseHeader(WebString::fromLatin1(it
->first
),
1043 WebString::fromLatin1(it
->second
));
1045 load_info
.setNPNNegotiatedProtocol(WebString::fromLatin1(
1046 info
.npn_negotiated_protocol
));
1047 response
->setHTTPLoadInfo(load_info
);
1050 const net::HttpResponseHeaders
* headers
= info
.headers
.get();
1054 WebURLResponse::HTTPVersion version
= WebURLResponse::Unknown
;
1055 if (headers
->GetHttpVersion() == net::HttpVersion(0, 9))
1056 version
= WebURLResponse::HTTP_0_9
;
1057 else if (headers
->GetHttpVersion() == net::HttpVersion(1, 0))
1058 version
= WebURLResponse::HTTP_1_0
;
1059 else if (headers
->GetHttpVersion() == net::HttpVersion(1, 1))
1060 version
= WebURLResponse::HTTP_1_1
;
1061 response
->setHTTPVersion(version
);
1062 response
->setHTTPStatusCode(headers
->response_code());
1063 response
->setHTTPStatusText(WebString::fromLatin1(headers
->GetStatusText()));
1065 // TODO(darin): We should leverage HttpResponseHeaders for this, and this
1066 // should be using the same code as ResourceDispatcherHost.
1067 // TODO(jungshik): Figure out the actual value of the referrer charset and
1068 // pass it to GetSuggestedFilename.
1070 headers
->EnumerateHeader(NULL
, "content-disposition", &value
);
1071 response
->setSuggestedFileName(
1072 net::GetSuggestedFilename(url
,
1074 std::string(), // referrer_charset
1075 std::string(), // suggested_name
1076 std::string(), // mime_type
1077 std::string())); // default_name
1080 if (headers
->GetLastModifiedValue(&time_val
))
1081 response
->setLastModifiedDate(time_val
.ToDoubleT());
1083 // Build up the header map.
1086 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
1087 response
->addHTTPHeaderField(WebString::fromLatin1(name
),
1088 WebString::fromLatin1(value
));
1092 void WebURLLoaderImpl::loadSynchronously(const WebURLRequest
& request
,
1093 WebURLResponse
& response
,
1096 SyncLoadResponse sync_load_response
;
1097 context_
->Start(request
, &sync_load_response
);
1099 const GURL
& final_url
= sync_load_response
.url
;
1101 // TODO(tc): For file loads, we may want to include a more descriptive
1102 // status code or status text.
1103 int error_code
= sync_load_response
.error_code
;
1104 if (error_code
!= net::OK
) {
1105 response
.setURL(final_url
);
1106 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1107 error
.reason
= error_code
;
1108 error
.unreachableURL
= final_url
;
1112 PopulateURLResponse(final_url
, sync_load_response
, &response
);
1114 data
.assign(sync_load_response
.data
.data(),
1115 sync_load_response
.data
.size());
1118 void WebURLLoaderImpl::loadAsynchronously(const WebURLRequest
& request
,
1119 WebURLLoaderClient
* client
) {
1120 DCHECK(!context_
->client());
1122 context_
->set_client(client
);
1123 context_
->Start(request
, NULL
);
1126 void WebURLLoaderImpl::cancel() {
1130 void WebURLLoaderImpl::setDefersLoading(bool value
) {
1131 context_
->SetDefersLoading(value
);
1134 void WebURLLoaderImpl::didChangePriority(WebURLRequest::Priority new_priority
,
1135 int intra_priority_value
) {
1136 context_
->DidChangePriority(new_priority
, intra_priority_value
);
1139 bool WebURLLoaderImpl::attachThreadedDataReceiver(
1140 blink::WebThreadedDataReceiver
* threaded_data_receiver
) {
1141 return context_
->AttachThreadedDataReceiver(threaded_data_receiver
);
1144 } // namespace content