GPU workaround to simulate Out of Memory errors with large textures
[chromium-blink-merge.git] / content / child / web_url_loader_impl.cc
blobe2cec70d33531e72ea4eb4d3a7a83f4120a9b233
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/child/web_url_loader_impl.h"
7 #include <algorithm>
8 #include <deque>
9 #include <string>
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"
51 using base::Time;
52 using base::TimeTicks;
53 using blink::WebData;
54 using blink::WebHTTPBody;
55 using blink::WebHTTPHeaderVisitor;
56 using blink::WebHTTPLoadInfo;
57 using blink::WebReferrerPolicy;
58 using blink::WebSecurityPolicy;
59 using blink::WebString;
60 using blink::WebURL;
61 using blink::WebURLError;
62 using blink::WebURLLoadTiming;
63 using blink::WebURLLoader;
64 using blink::WebURLLoaderClient;
65 using blink::WebURLRequest;
66 using blink::WebURLResponse;
68 namespace content {
70 // Utilities ------------------------------------------------------------------
72 namespace {
74 const char kThrottledErrorDescription[] =
75 "Request throttled. Visit http://dev.chromium.org/throttling for more "
76 "information.";
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) {
116 switch (priority) {
117 case WebURLRequest::PriorityVeryHigh:
118 return net::HIGHEST;
120 case WebURLRequest::PriorityHigh:
121 return net::MEDIUM;
123 case WebURLRequest::PriorityMedium:
124 return net::LOW;
126 case WebURLRequest::PriorityLow:
127 return net::LOWEST;
129 case WebURLRequest::PriorityVeryLow:
130 return net::IDLE;
132 case WebURLRequest::PriorityUnresolved:
133 default:
134 NOTREACHED();
135 return net::LOW;
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,
143 std::string* data) {
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;
152 std::string charset;
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)
158 return result;
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;
167 return net::OK;
170 #define STATIC_ASSERT_MATCHING_ENUMS(content_name, blink_name) \
171 static_assert( \
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());
287 } // namespace
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>,
295 public RequestPeer {
296 public:
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; }
304 void Cancel();
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,
320 int data_length,
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;
330 private:
331 friend class base::RefCounted<Context>;
332 ~Context() override;
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
352 // mechanism.
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_;
357 int request_id_;
360 WebURLLoaderImpl::Context::Context(
361 WebURLLoaderImpl* loader,
362 ResourceDispatcher* resource_dispatcher,
363 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
364 : loader_(loader),
365 client_(NULL),
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),
371 request_id_(-1) {
374 void WebURLLoaderImpl::Context::Cancel() {
375 if (resource_dispatcher_ && // NULL in unittest.
376 request_id_ != -1) {
377 resource_dispatcher_->Cancel(request_id_);
378 request_id_ = -1;
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.
390 client_ = NULL;
391 loader_ = NULL;
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(
412 request_id_,
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);
425 return false;
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
442 // browser.
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);
466 } else {
467 task_runner_->PostTask(FROM_HERE,
468 base::Bind(&Context::HandleDataURL, this));
470 return;
473 GURL referrer_url(
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);
522 return;
525 request_id_ = resource_dispatcher_->StartAsync(
526 request_info, request_body.get(), this);
529 void WebURLLoaderImpl::Context::OnUploadProgress(uint64 position, uint64 size) {
530 if (client_)
531 client_->didSendData(loader_, position, size);
534 bool WebURLLoaderImpl::Context::OnReceivedRedirect(
535 const net::RedirectInfo& redirect_info,
536 const ResourceResponseInfo& info) {
537 if (!client_)
538 return false;
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),
558 referrer_policy_);
560 std::string old_method = request_.httpMethod().utf8();
561 new_request.setHTTPMethod(WebString::fromUTF8(redirect_info.new_method));
562 if (redirect_info.new_method == old_method)
563 new_request.setHTTPBody(request_.httpBody());
565 // Protect from deletion during call to willSendRequest.
566 scoped_refptr<Context> protect(this);
568 client_->willSendRequest(loader_, new_request, response);
569 request_ = new_request;
571 // Only follow the redirect if WebKit left the URL unmodified.
572 if (redirect_info.new_url == GURL(new_request.url())) {
573 // First-party cookie logic moved from DocumentLoader in Blink to
574 // net::URLRequest in the browser. Assert that Blink didn't try to change it
575 // to something else.
576 DCHECK_EQ(redirect_info.new_first_party_for_cookies.spec(),
577 request_.firstPartyForCookies().string().utf8());
578 return true;
581 // We assume that WebKit only changes the URL to suppress a redirect, and we
582 // assume that it does so by setting it to be invalid.
583 DCHECK(!new_request.url().isValid());
584 return false;
587 void WebURLLoaderImpl::Context::OnReceivedResponse(
588 const ResourceResponseInfo& initial_info) {
589 if (!client_)
590 return;
592 ResourceResponseInfo info = initial_info;
594 // PlzNavigate: during navigations, the ResourceResponse has already been
595 // received on the browser side, and has been passed down to the renderer.
596 if (stream_override_.get()) {
597 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
598 switches::kEnableBrowserSideNavigation));
599 info = stream_override_->response;
602 WebURLResponse response;
603 response.initialize();
604 PopulateURLResponse(request_.url(), info, &response);
606 bool show_raw_listing = (GURL(request_.url()).query() == "raw");
608 if (info.mime_type == "text/vnd.chromium.ftp-dir") {
609 if (show_raw_listing) {
610 // Set the MIME type to plain text to prevent any active content.
611 response.setMIMEType("text/plain");
612 } else {
613 // We're going to produce a parsed listing in HTML.
614 response.setMIMEType("text/html");
618 // Prevent |this| from being destroyed if the client destroys the loader,
619 // ether in didReceiveResponse, or when the multipart/ftp delegate calls into
620 // it.
621 scoped_refptr<Context> protect(this);
623 if (request_.useStreamOnResponse()) {
624 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_,
633 &consumer);
634 if (result != MOJO_RESULT_OK) {
635 // TODO(yhirano): Handle the error.
636 return;
638 client_->didReceiveResponse(
639 loader_, response, new WebDataConsumerHandleImpl(consumer.Pass()));
640 } else {
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.
646 if (!client_)
647 return;
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;
656 std::string charset;
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" &&
670 !show_raw_listing) {
671 ftp_listing_delegate_.reset(
672 new FtpDirectoryListingResponseDelegate(client_, loader_, response));
676 void WebURLLoaderImpl::Context::OnDownloadedData(int len,
677 int encoded_data_length) {
678 if (client_)
679 client_->didDownloadData(loader_, len, encoded_data_length);
682 void WebURLLoaderImpl::Context::OnReceivedData(const char* data,
683 int data_length,
684 int encoded_data_length) {
685 if (!client_)
686 return;
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(),
695 false,
696 net::ERR_FAILED));
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);
712 } else {
713 client_->didReceiveData(loader_, data, data_length, encoded_data_length);
717 void WebURLLoaderImpl::Context::OnReceivedCachedMetadata(
718 const char* data, int len) {
719 if (client_)
720 client_->didReceiveCachedMetadata(loader_, data, len);
723 void WebURLLoaderImpl::Context::OnCompletedRequest(
724 int error_code,
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);
744 if (client_) {
745 if (error_code != net::OK) {
746 client_->didFail(loader_, CreateError(request_.url(),
747 stale_copy_in_cache,
748 error_code));
749 } else {
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);
759 } else {
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))
777 return false;
779 // The fast paths for data URL, Start() and HandleDataURL(), don't support
780 // the downloadToFile option.
781 if (request_.downloadToFile())
782 return false;
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
786 // download.
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://
793 // to the browser.
794 if (request_.frameType() == WebURLRequest::FrameTypeTopLevel)
795 return false;
796 #endif
798 if (request_.frameType() != WebURLRequest::FrameTypeTopLevel &&
799 request_.frameType() != WebURLRequest::FrameTypeNested)
800 return true;
802 std::string mime_type, unused_charset;
803 if (net::DataURL::Parse(request_.url(), &mime_type, &unused_charset, NULL) &&
804 net::IsSupportedMimeType(mime_type))
805 return true;
807 return false;
810 void WebURLLoaderImpl::Context::HandleDataURL() {
811 DCHECK_NE(defers_loading_, DEFERRED_DATA);
812 if (defers_loading_ == SHOULD_DEFER) {
813 defers_loading_ = DEFERRED_DATA;
814 return;
817 ResourceResponseInfo info;
818 std::string data;
820 int error_code = GetInfoFromDataURL(request_.url(), &info, &data);
822 if (error_code == net::OK) {
823 OnReceivedResponse(info);
824 if (!data.empty())
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,
833 size_t size) {
834 if (body_stream_buffer_.empty() && size == 0) {
835 // Nothing to do.
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),
848 &num_bytes_writable,
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)
862 return rv;
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);
873 } else {
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,
886 data + size);
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)));
898 return rv;
901 void WebURLLoaderImpl::Context::OnHandleGotWritable(MojoResult result) {
902 if (result != MOJO_RESULT_OK) {
903 if (client_) {
904 client_->didFail(loader_,
905 loader_->CreateError(request_.url(),
906 false,
907 net::ERR_FAILED));
908 // |this| can be deleted here.
910 return;
913 if (body_stream_buffer_.empty())
914 return;
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();
921 if (client_) {
922 // TODO(yhirano): Pass appropriate arguments.
923 client_->didFinishLoading(loader_, 0, 0);
924 // |this| can be deleted here.
927 } else {
928 if (client_) {
929 client_->didFail(loader_, loader_->CreateError(request_.url(),
930 false,
931 net::ERR_FAILED));
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() {
946 cancel();
949 WebURLError WebURLLoaderImpl::CreateError(const WebURL& unreachable_url,
950 bool stale_copy_in_cache,
951 int reason) {
952 WebURLError error;
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);
962 } else {
963 error.localizedDescription = WebString::fromUTF8(
964 net::ErrorToString(reason));
966 return error;
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();
1054 if (!headers)
1055 return;
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.
1072 std::string value;
1073 headers->EnumerateHeader(NULL, "content-disposition", &value);
1074 response->setSuggestedFileName(
1075 net::GetSuggestedFilename(url,
1076 value,
1077 std::string(), // referrer_charset
1078 std::string(), // suggested_name
1079 std::string(), // mime_type
1080 std::string())); // default_name
1082 Time time_val;
1083 if (headers->GetLastModifiedValue(&time_val))
1084 response->setLastModifiedDate(time_val.ToDoubleT());
1086 // Build up the header map.
1087 void* iter = NULL;
1088 std::string name;
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,
1097 WebURLError& error,
1098 WebData& data) {
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;
1112 return;
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() {
1130 context_->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