1 // Copyright (c) 2012 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.
4
5 #include "net/url_request/url_fetcher_core.h"
6
7 #include <stdint.h>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/callback_helpers.h"
12 #include "base/check_op.h"
13 #include "base/notreached.h"
14 #include "base/sequenced_task_runner.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/stl_util.h"
17 #include "base/threading/sequenced_task_runner_handle.h"
18 #include "net/base/elements_upload_data_stream.h"
19 #include "net/base/io_buffer.h"
20 #include "net/base/load_flags.h"
21 #include "net/base/net_errors.h"
22 #include "net/base/request_priority.h"
23 #include "net/base/upload_bytes_element_reader.h"
24 #include "net/base/upload_data_stream.h"
25 #include "net/base/upload_file_element_reader.h"
26 #include "net/http/http_response_headers.h"
27 #include "net/url_request/redirect_info.h"
28 #include "net/url_request/url_fetcher_delegate.h"
29 #include "net/url_request/url_fetcher_response_writer.h"
30 #include "net/url_request/url_request_context.h"
31 #include "net/url_request/url_request_context_getter.h"
32 #include "net/url_request/url_request_throttler_manager.h"
33 #include "url/origin.h"
34
35 namespace {
36
37 const int kBufferSize = 4096;
38 const int kUploadProgressTimerInterval = 100;
39 bool g_ignore_certificate_requests = false;
40
41 } // namespace
42
43 namespace net {
44
45 // URLFetcherCore::Registry ---------------------------------------------------
46
47 URLFetcherCore::Registry::Registry() = default;
48 URLFetcherCore::Registry::~Registry() = default;
49
AddURLFetcherCore(URLFetcherCore * core)50 void URLFetcherCore::Registry::AddURLFetcherCore(URLFetcherCore* core) {
51 DCHECK(!base::Contains(fetchers_, core));
52 fetchers_.insert(core);
53 }
54
RemoveURLFetcherCore(URLFetcherCore * core)55 void URLFetcherCore::Registry::RemoveURLFetcherCore(URLFetcherCore* core) {
56 DCHECK(base::Contains(fetchers_, core));
57 fetchers_.erase(core);
58 }
59
CancelAll()60 void URLFetcherCore::Registry::CancelAll() {
61 while (!fetchers_.empty())
62 (*fetchers_.begin())->CancelURLRequest(ERR_ABORTED);
63 }
64
65 // URLFetcherCore -------------------------------------------------------------
66
67 // static
68 base::LazyInstance<URLFetcherCore::Registry>::DestructorAtExit
69 URLFetcherCore::g_registry = LAZY_INSTANCE_INITIALIZER;
70
URLFetcherCore(URLFetcher * fetcher,const GURL & original_url,URLFetcher::RequestType request_type,URLFetcherDelegate * d,net::NetworkTrafficAnnotationTag traffic_annotation)71 URLFetcherCore::URLFetcherCore(
72 URLFetcher* fetcher,
73 const GURL& original_url,
74 URLFetcher::RequestType request_type,
75 URLFetcherDelegate* d,
76 net::NetworkTrafficAnnotationTag traffic_annotation)
77 : fetcher_(fetcher),
78 original_url_(original_url),
79 request_type_(request_type),
80 delegate_(d),
81 delegate_task_runner_(base::SequencedTaskRunnerHandle::Get()),
82 load_flags_(LOAD_NORMAL),
83 allow_credentials_(base::nullopt),
84 response_code_(URLFetcher::RESPONSE_CODE_INVALID),
85 url_request_data_key_(nullptr),
86 was_cached_(false),
87 received_response_content_length_(0),
88 total_received_bytes_(0),
89 upload_content_set_(false),
90 upload_range_offset_(0),
91 upload_range_length_(0),
92 referrer_policy_(
93 ReferrerPolicy::CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE),
94 is_chunked_upload_(false),
95 was_cancelled_(false),
96 stop_on_redirect_(false),
97 stopped_on_redirect_(false),
98 automatically_retry_on_5xx_(true),
99 num_retries_on_5xx_(0),
100 max_retries_on_5xx_(0),
101 num_retries_on_network_changes_(0),
102 max_retries_on_network_changes_(0),
103 current_upload_bytes_(-1),
104 current_response_bytes_(0),
105 total_response_bytes_(-1),
106 traffic_annotation_(traffic_annotation) {
107 CHECK(original_url_.is_valid());
108 }
109
Start()110 void URLFetcherCore::Start() {
111 DCHECK(delegate_task_runner_);
112 DCHECK(request_context_getter_.get()) << "We need an URLRequestContext!";
113 if (network_task_runner_.get()) {
114 DCHECK_EQ(network_task_runner_,
115 request_context_getter_->GetNetworkTaskRunner());
116 } else {
117 network_task_runner_ = request_context_getter_->GetNetworkTaskRunner();
118 }
119 DCHECK(network_task_runner_.get()) << "We need an IO task runner";
120
121 network_task_runner_->PostTask(
122 FROM_HERE, base::BindOnce(&URLFetcherCore::StartOnIOThread, this));
123 }
124
Stop()125 void URLFetcherCore::Stop() {
126 if (delegate_task_runner_) // May be NULL in tests.
127 DCHECK(delegate_task_runner_->RunsTasksInCurrentSequence());
128
129 delegate_ = nullptr;
130 fetcher_ = nullptr;
131 if (!network_task_runner_.get())
132 return;
133 if (network_task_runner_->RunsTasksInCurrentSequence()) {
134 CancelURLRequest(ERR_ABORTED);
135 } else {
136 network_task_runner_->PostTask(
137 FROM_HERE,
138 base::BindOnce(&URLFetcherCore::CancelURLRequest, this, ERR_ABORTED));
139 }
140 }
141
SetUploadData(const std::string & upload_content_type,const std::string & upload_content)142 void URLFetcherCore::SetUploadData(const std::string& upload_content_type,
143 const std::string& upload_content) {
144 AssertHasNoUploadData();
145 DCHECK(!is_chunked_upload_);
146 DCHECK(upload_content_type_.empty());
147
148 // Empty |upload_content_type| is allowed iff the |upload_content| is empty.
149 DCHECK(upload_content.empty() || !upload_content_type.empty());
150
151 upload_content_type_ = upload_content_type;
152 upload_content_ = upload_content;
153 upload_content_set_ = true;
154 }
155
SetUploadFilePath(const std::string & upload_content_type,const base::FilePath & file_path,uint64_t range_offset,uint64_t range_length,scoped_refptr<base::TaskRunner> file_task_runner)156 void URLFetcherCore::SetUploadFilePath(
157 const std::string& upload_content_type,
158 const base::FilePath& file_path,
159 uint64_t range_offset,
160 uint64_t range_length,
161 scoped_refptr<base::TaskRunner> file_task_runner) {
162 AssertHasNoUploadData();
163 DCHECK(!is_chunked_upload_);
164 DCHECK_EQ(upload_range_offset_, 0ULL);
165 DCHECK_EQ(upload_range_length_, 0ULL);
166 DCHECK(upload_content_type_.empty());
167 DCHECK(!upload_content_type.empty());
168
169 upload_content_type_ = upload_content_type;
170 upload_file_path_ = file_path;
171 upload_range_offset_ = range_offset;
172 upload_range_length_ = range_length;
173 upload_file_task_runner_ = file_task_runner;
174 upload_content_set_ = true;
175 }
176
SetUploadStreamFactory(const std::string & upload_content_type,const URLFetcher::CreateUploadStreamCallback & factory)177 void URLFetcherCore::SetUploadStreamFactory(
178 const std::string& upload_content_type,
179 const URLFetcher::CreateUploadStreamCallback& factory) {
180 AssertHasNoUploadData();
181 DCHECK(!is_chunked_upload_);
182 DCHECK(upload_content_type_.empty());
183
184 upload_content_type_ = upload_content_type;
185 upload_stream_factory_ = factory;
186 upload_content_set_ = true;
187 }
188
SetChunkedUpload(const std::string & content_type)189 void URLFetcherCore::SetChunkedUpload(const std::string& content_type) {
190 if (!is_chunked_upload_) {
191 AssertHasNoUploadData();
192 DCHECK(upload_content_type_.empty());
193 }
194
195 // Empty |content_type| is not allowed here, because it is impossible
196 // to ensure non-empty upload content as it is not yet supplied.
197 DCHECK(!content_type.empty());
198
199 upload_content_type_ = content_type;
200 base::STLClearObject(&upload_content_);
201 is_chunked_upload_ = true;
202 }
203
AppendChunkToUpload(const std::string & content,bool is_last_chunk)204 void URLFetcherCore::AppendChunkToUpload(const std::string& content,
205 bool is_last_chunk) {
206 DCHECK(delegate_task_runner_);
207 DCHECK(network_task_runner_.get());
208 DCHECK(is_chunked_upload_);
209 network_task_runner_->PostTask(
210 FROM_HERE, base::BindOnce(&URLFetcherCore::CompleteAddingUploadDataChunk,
211 this, content, is_last_chunk));
212 }
213
SetLoadFlags(int load_flags)214 void URLFetcherCore::SetLoadFlags(int load_flags) {
215 load_flags_ = load_flags;
216 }
217
SetAllowCredentials(bool allow_credentials)218 void URLFetcherCore::SetAllowCredentials(bool allow_credentials) {
219 allow_credentials_ = base::make_optional<bool>(allow_credentials);
220 }
221
GetLoadFlags() const222 int URLFetcherCore::GetLoadFlags() const {
223 return load_flags_;
224 }
225
SetReferrer(const std::string & referrer)226 void URLFetcherCore::SetReferrer(const std::string& referrer) {
227 referrer_ = referrer;
228 }
229
SetReferrerPolicy(ReferrerPolicy referrer_policy)230 void URLFetcherCore::SetReferrerPolicy(ReferrerPolicy referrer_policy) {
231 referrer_policy_ = referrer_policy;
232 }
233
SetExtraRequestHeaders(const std::string & extra_request_headers)234 void URLFetcherCore::SetExtraRequestHeaders(
235 const std::string& extra_request_headers) {
236 extra_request_headers_.Clear();
237 extra_request_headers_.AddHeadersFromString(extra_request_headers);
238 }
239
AddExtraRequestHeader(const std::string & header_line)240 void URLFetcherCore::AddExtraRequestHeader(const std::string& header_line) {
241 extra_request_headers_.AddHeaderFromString(header_line);
242 }
243
SetRequestContext(URLRequestContextGetter * request_context_getter)244 void URLFetcherCore::SetRequestContext(
245 URLRequestContextGetter* request_context_getter) {
246 DCHECK(!request_context_getter_.get());
247 DCHECK(request_context_getter);
248 request_context_getter_ = request_context_getter;
249 }
250
SetInitiator(const base::Optional<url::Origin> & initiator)251 void URLFetcherCore::SetInitiator(
252 const base::Optional<url::Origin>& initiator) {
253 DCHECK(!initiator_.has_value());
254 initiator_ = initiator;
255 }
256
SetURLRequestUserData(const void * key,const URLFetcher::CreateDataCallback & create_data_callback)257 void URLFetcherCore::SetURLRequestUserData(
258 const void* key,
259 const URLFetcher::CreateDataCallback& create_data_callback) {
260 DCHECK(key);
261 DCHECK(!create_data_callback.is_null());
262 url_request_data_key_ = key;
263 url_request_create_data_callback_ = create_data_callback;
264 }
265
SetStopOnRedirect(bool stop_on_redirect)266 void URLFetcherCore::SetStopOnRedirect(bool stop_on_redirect) {
267 stop_on_redirect_ = stop_on_redirect;
268 }
269
SetAutomaticallyRetryOn5xx(bool retry)270 void URLFetcherCore::SetAutomaticallyRetryOn5xx(bool retry) {
271 automatically_retry_on_5xx_ = retry;
272 }
273
SetMaxRetriesOn5xx(int max_retries)274 void URLFetcherCore::SetMaxRetriesOn5xx(int max_retries) {
275 max_retries_on_5xx_ = max_retries;
276 }
277
GetMaxRetriesOn5xx() const278 int URLFetcherCore::GetMaxRetriesOn5xx() const {
279 return max_retries_on_5xx_;
280 }
281
GetBackoffDelay() const282 base::TimeDelta URLFetcherCore::GetBackoffDelay() const {
283 return backoff_delay_;
284 }
285
SetAutomaticallyRetryOnNetworkChanges(int max_retries)286 void URLFetcherCore::SetAutomaticallyRetryOnNetworkChanges(int max_retries) {
287 max_retries_on_network_changes_ = max_retries;
288 }
289
SaveResponseToFileAtPath(const base::FilePath & file_path,scoped_refptr<base::SequencedTaskRunner> file_task_runner)290 void URLFetcherCore::SaveResponseToFileAtPath(
291 const base::FilePath& file_path,
292 scoped_refptr<base::SequencedTaskRunner> file_task_runner) {
293 DCHECK(delegate_task_runner_->RunsTasksInCurrentSequence());
294 SaveResponseWithWriter(std::unique_ptr<URLFetcherResponseWriter>(
295 new URLFetcherFileWriter(file_task_runner, file_path)));
296 }
297
SaveResponseToTemporaryFile(scoped_refptr<base::SequencedTaskRunner> file_task_runner)298 void URLFetcherCore::SaveResponseToTemporaryFile(
299 scoped_refptr<base::SequencedTaskRunner> file_task_runner) {
300 DCHECK(delegate_task_runner_->RunsTasksInCurrentSequence());
301 SaveResponseWithWriter(std::unique_ptr<URLFetcherResponseWriter>(
302 new URLFetcherFileWriter(file_task_runner, base::FilePath())));
303 }
304
SaveResponseWithWriter(std::unique_ptr<URLFetcherResponseWriter> response_writer)305 void URLFetcherCore::SaveResponseWithWriter(
306 std::unique_ptr<URLFetcherResponseWriter> response_writer) {
307 DCHECK(delegate_task_runner_->RunsTasksInCurrentSequence());
308 response_writer_ = std::move(response_writer);
309 }
310
GetResponseHeaders() const311 HttpResponseHeaders* URLFetcherCore::GetResponseHeaders() const {
312 return response_headers_.get();
313 }
314
315 // TODO(panayiotis): remote_endpoint_ is written in the IO thread,
316 // if this is accessed in the UI thread, this could result in a race.
317 // Same for response_headers_ above.
GetSocketAddress() const318 IPEndPoint URLFetcherCore::GetSocketAddress() const {
319 return remote_endpoint_;
320 }
321
ProxyServerUsed() const322 const ProxyServer& URLFetcherCore::ProxyServerUsed() const {
323 return proxy_server_;
324 }
325
WasCached() const326 bool URLFetcherCore::WasCached() const {
327 return was_cached_;
328 }
329
GetReceivedResponseContentLength() const330 int64_t URLFetcherCore::GetReceivedResponseContentLength() const {
331 return received_response_content_length_;
332 }
333
GetTotalReceivedBytes() const334 int64_t URLFetcherCore::GetTotalReceivedBytes() const {
335 return total_received_bytes_;
336 }
337
GetOriginalURL() const338 const GURL& URLFetcherCore::GetOriginalURL() const {
339 return original_url_;
340 }
341
GetURL() const342 const GURL& URLFetcherCore::GetURL() const {
343 return url_;
344 }
345
GetError() const346 Error URLFetcherCore::GetError() const {
347 return error_;
348 }
349
GetResponseCode() const350 int URLFetcherCore::GetResponseCode() const {
351 return response_code_;
352 }
353
ReceivedContentWasMalformed()354 void URLFetcherCore::ReceivedContentWasMalformed() {
355 DCHECK(delegate_task_runner_->RunsTasksInCurrentSequence());
356 if (network_task_runner_.get()) {
357 network_task_runner_->PostTask(
358 FROM_HERE,
359 base::BindOnce(&URLFetcherCore::NotifyMalformedContent, this));
360 }
361 }
362
GetResponseAsString(std::string * out_response_string) const363 bool URLFetcherCore::GetResponseAsString(
364 std::string* out_response_string) const {
365 URLFetcherStringWriter* string_writer =
366 response_writer_ ? response_writer_->AsStringWriter() : nullptr;
367 if (!string_writer)
368 return false;
369
370 *out_response_string = string_writer->data();
371 return true;
372 }
373
GetResponseAsFilePath(bool take_ownership,base::FilePath * out_response_path)374 bool URLFetcherCore::GetResponseAsFilePath(bool take_ownership,
375 base::FilePath* out_response_path) {
376 DCHECK(delegate_task_runner_->RunsTasksInCurrentSequence());
377
378 URLFetcherFileWriter* file_writer =
379 response_writer_ ? response_writer_->AsFileWriter() : nullptr;
380 if (!file_writer)
381 return false;
382
383 *out_response_path = file_writer->file_path();
384
385 if (take_ownership) {
386 // Intentionally calling a file_writer_ method directly without posting
387 // the task to network_task_runner_.
388 //
389 // This is for correctly handling the case when file_writer_->DisownFile()
390 // is soon followed by URLFetcherCore::Stop(). We have to make sure that
391 // DisownFile takes effect before Stop deletes file_writer_.
392 //
393 // This direct call should be thread-safe, since DisownFile itself does no
394 // file operation. It just flips the state to be referred in destruction.
395 file_writer->DisownFile();
396 }
397 return true;
398 }
399
OnReceivedRedirect(URLRequest * request,const RedirectInfo & redirect_info,bool * defer_redirect)400 void URLFetcherCore::OnReceivedRedirect(URLRequest* request,
401 const RedirectInfo& redirect_info,
402 bool* defer_redirect) {
403 DCHECK_EQ(request, request_.get());
404 DCHECK(network_task_runner_->BelongsToCurrentThread());
405 if (stop_on_redirect_) {
406 stopped_on_redirect_ = true;
407 url_ = redirect_info.new_url;
408 response_code_ = request_->GetResponseCode();
409 response_headers_ = request_->response_headers();
410 proxy_server_ = request_->proxy_server();
411 was_cached_ = request_->was_cached();
412 total_received_bytes_ += request_->GetTotalReceivedBytes();
413 int result = request->Cancel();
414 OnReadCompleted(request, result);
415 }
416 }
417
OnResponseStarted(URLRequest * request,int net_error)418 void URLFetcherCore::OnResponseStarted(URLRequest* request, int net_error) {
419 DCHECK_EQ(request, request_.get());
420 DCHECK(network_task_runner_->BelongsToCurrentThread());
421 DCHECK_NE(ERR_IO_PENDING, net_error);
422
423 if (net_error == OK) {
424 response_code_ = request_->GetResponseCode();
425 response_headers_ = request_->response_headers();
426 remote_endpoint_ = request_->GetResponseRemoteEndpoint();
427 proxy_server_ = request_->proxy_server();
428 was_cached_ = request_->was_cached();
429 total_response_bytes_ = request_->GetExpectedContentSize();
430 }
431
432 DCHECK(!buffer_);
433 if (request_type_ != URLFetcher::HEAD)
434 buffer_ = base::MakeRefCounted<IOBuffer>(kBufferSize);
435 ReadResponse();
436 }
437
OnCertificateRequested(URLRequest * request,SSLCertRequestInfo * cert_request_info)438 void URLFetcherCore::OnCertificateRequested(
439 URLRequest* request,
440 SSLCertRequestInfo* cert_request_info) {
441 DCHECK_EQ(request, request_.get());
442 DCHECK(network_task_runner_->BelongsToCurrentThread());
443
444 if (g_ignore_certificate_requests) {
445 request->ContinueWithCertificate(nullptr, nullptr);
446 } else {
447 request->Cancel();
448 }
449 }
450
OnReadCompleted(URLRequest * request,int bytes_read)451 void URLFetcherCore::OnReadCompleted(URLRequest* request,
452 int bytes_read) {
453 DCHECK_EQ(request, request_.get());
454 DCHECK(network_task_runner_->BelongsToCurrentThread());
455
456 if (!stopped_on_redirect_)
457 url_ = request->url();
458 URLRequestThrottlerManager* throttler_manager =
459 request->context()->throttler_manager();
460 if (throttler_manager)
461 url_throttler_entry_ = throttler_manager->RegisterRequestUrl(url_);
462
463 while (bytes_read > 0) {
464 current_response_bytes_ += bytes_read;
465 InformDelegateDownloadProgress();
466
467 const int result = WriteBuffer(
468 base::MakeRefCounted<DrainableIOBuffer>(buffer_, bytes_read));
469 if (result < 0) {
470 // Write failed or waiting for write completion.
471 return;
472 }
473 bytes_read = request_->Read(buffer_.get(), kBufferSize);
474 }
475
476 // See comments re: HEAD requests in ReadResponse().
477 if (bytes_read != ERR_IO_PENDING || request_type_ == URLFetcher::HEAD) {
478 error_ = static_cast<Error>(bytes_read);
479 received_response_content_length_ =
480 request_->received_response_content_length();
481 total_received_bytes_ += request_->GetTotalReceivedBytes();
482 ReleaseRequest();
483
484 // No more data to write.
485 const int result = response_writer_->Finish(
486 bytes_read > 0 ? OK : bytes_read,
487 base::BindOnce(&URLFetcherCore::DidFinishWriting, this));
488 if (result != ERR_IO_PENDING)
489 DidFinishWriting(result);
490 }
491 }
492
OnContextShuttingDown()493 void URLFetcherCore::OnContextShuttingDown() {
494 DCHECK(request_);
495 CancelRequestAndInformDelegate(ERR_CONTEXT_SHUT_DOWN);
496 }
497
CancelAll()498 void URLFetcherCore::CancelAll() {
499 g_registry.Get().CancelAll();
500 }
501
GetNumFetcherCores()502 int URLFetcherCore::GetNumFetcherCores() {
503 return g_registry.Get().size();
504 }
505
SetIgnoreCertificateRequests(bool ignored)506 void URLFetcherCore::SetIgnoreCertificateRequests(bool ignored) {
507 g_ignore_certificate_requests = ignored;
508 }
509
~URLFetcherCore()510 URLFetcherCore::~URLFetcherCore() {
511 // |request_| should be NULL. If not, it's unsafe to delete it here since we
512 // may not be on the IO thread.
513 DCHECK(!request_.get());
514 }
515
StartOnIOThread()516 void URLFetcherCore::StartOnIOThread() {
517 DCHECK(network_task_runner_->BelongsToCurrentThread());
518
519 // Create ChunkedUploadDataStream, if needed, so the consumer can start
520 // appending data. Have to do it here because StartURLRequest() may be called
521 // asynchonously.
522 if (is_chunked_upload_) {
523 chunked_stream_.reset(new ChunkedUploadDataStream(0));
524 chunked_stream_writer_ = chunked_stream_->CreateWriter();
525 }
526
527 if (!response_writer_)
528 response_writer_.reset(new URLFetcherStringWriter);
529
530 const int result = response_writer_->Initialize(
531 base::BindOnce(&URLFetcherCore::DidInitializeWriter, this));
532 if (result != ERR_IO_PENDING)
533 DidInitializeWriter(result);
534 }
535
StartURLRequest()536 void URLFetcherCore::StartURLRequest() {
537 DCHECK(network_task_runner_->BelongsToCurrentThread());
538
539 if (was_cancelled_) {
540 // Since StartURLRequest() is posted as a *delayed* task, it may
541 // run after the URLFetcher was already stopped.
542 return;
543 }
544
545 DCHECK(request_context_getter_);
546 if (!request_context_getter_->GetURLRequestContext()) {
547 CancelRequestAndInformDelegate(ERR_CONTEXT_SHUT_DOWN);
548 return;
549 }
550
551 DCHECK(!request_.get());
552
553 g_registry.Get().AddURLFetcherCore(this);
554 current_response_bytes_ = 0;
555 request_context_getter_->AddObserver(this);
556 request_ = request_context_getter_->GetURLRequestContext()->CreateRequest(
557 original_url_, DEFAULT_PRIORITY, this, traffic_annotation_);
558 int flags = request_->load_flags() | load_flags_;
559
560 // TODO(mmenke): This should really be with the other code to set the upload
561 // body, below.
562 if (chunked_stream_)
563 request_->set_upload(std::move(chunked_stream_));
564
565 request_->SetLoadFlags(flags);
566 if (allow_credentials_) {
567 request_->set_allow_credentials(allow_credentials_.value());
568 }
569 request_->SetReferrer(referrer_);
570 request_->set_referrer_policy(referrer_policy_);
571 request_->set_site_for_cookies(SiteForCookies::FromUrl(
572 initiator_.has_value() && !initiator_.value().opaque()
573 ? initiator_.value().GetURL()
574 : original_url_));
575 request_->set_initiator(initiator_);
576 if (url_request_data_key_ && !url_request_create_data_callback_.is_null()) {
577 request_->SetUserData(url_request_data_key_,
578 url_request_create_data_callback_.Run());
579 }
580
581 switch (request_type_) {
582 case URLFetcher::GET:
583 break;
584
585 case URLFetcher::POST:
586 case URLFetcher::PUT:
587 case URLFetcher::PATCH: {
588 // Upload content must be set.
589 DCHECK(is_chunked_upload_ || upload_content_set_);
590
591 request_->set_method(
592 request_type_ == URLFetcher::POST ? "POST" :
593 request_type_ == URLFetcher::PUT ? "PUT" : "PATCH");
594 if (!upload_content_type_.empty()) {
595 extra_request_headers_.SetHeader(HttpRequestHeaders::kContentType,
596 upload_content_type_);
597 }
598 if (!upload_content_.empty()) {
599 std::unique_ptr<UploadElementReader> reader(
600 new UploadBytesElementReader(upload_content_.data(),
601 upload_content_.size()));
602 request_->set_upload(
603 ElementsUploadDataStream::CreateWithReader(std::move(reader), 0));
604 } else if (!upload_file_path_.empty()) {
605 std::unique_ptr<UploadElementReader> reader(new UploadFileElementReader(
606 upload_file_task_runner_.get(), upload_file_path_,
607 upload_range_offset_, upload_range_length_, base::Time()));
608 request_->set_upload(
609 ElementsUploadDataStream::CreateWithReader(std::move(reader), 0));
610 } else if (!upload_stream_factory_.is_null()) {
611 std::unique_ptr<UploadDataStream> stream = upload_stream_factory_.Run();
612 DCHECK(stream);
613 request_->set_upload(std::move(stream));
614 }
615
616 current_upload_bytes_ = -1;
617 // TODO(kinaba): http://crbug.com/118103. Implement upload callback in the
618 // layer and avoid using timer here.
619 upload_progress_checker_timer_.reset(new base::RepeatingTimer());
620 upload_progress_checker_timer_->Start(
621 FROM_HERE,
622 base::TimeDelta::FromMilliseconds(kUploadProgressTimerInterval),
623 this,
624 &URLFetcherCore::InformDelegateUploadProgress);
625 break;
626 }
627
628 case URLFetcher::HEAD:
629 request_->set_method("HEAD");
630 break;
631
632 case URLFetcher::DELETE_REQUEST:
633 request_->set_method("DELETE");
634 break;
635
636 default:
637 NOTREACHED();
638 }
639
640 if (!extra_request_headers_.IsEmpty())
641 request_->SetExtraRequestHeaders(extra_request_headers_);
642
643 request_->Start();
644 }
645
DidInitializeWriter(int result)646 void URLFetcherCore::DidInitializeWriter(int result) {
647 if (result != OK) {
648 CancelRequestAndInformDelegate(result);
649 return;
650 }
651 StartURLRequestWhenAppropriate();
652 }
653
StartURLRequestWhenAppropriate()654 void URLFetcherCore::StartURLRequestWhenAppropriate() {
655 DCHECK(network_task_runner_->BelongsToCurrentThread());
656
657 if (was_cancelled_)
658 return;
659
660 DCHECK(request_context_getter_.get());
661
662 // Check if the request should be delayed, and if so, post a task to start it
663 // after the delay has expired. Otherwise, start it now.
664
665 URLRequestContext* context = request_context_getter_->GetURLRequestContext();
666 // If the context has been shut down, or there's no ThrottlerManager, just
667 // start the request. In the former case, StartURLRequest() will just inform
668 // the URLFetcher::Delegate the request has been canceled.
669 if (context && context->throttler_manager()) {
670 if (!original_url_throttler_entry_.get()) {
671 original_url_throttler_entry_ =
672 context->throttler_manager()->RegisterRequestUrl(original_url_);
673 }
674
675 if (original_url_throttler_entry_.get()) {
676 int64_t delay =
677 original_url_throttler_entry_->ReserveSendingTimeForNextRequest(
678 GetBackoffReleaseTime());
679 if (delay != 0) {
680 network_task_runner_->PostDelayedTask(
681 FROM_HERE, base::BindOnce(&URLFetcherCore::StartURLRequest, this),
682 base::TimeDelta::FromMilliseconds(delay));
683 return;
684 }
685 }
686 }
687
688 StartURLRequest();
689 }
690
CancelURLRequest(int error)691 void URLFetcherCore::CancelURLRequest(int error) {
692 DCHECK(network_task_runner_->BelongsToCurrentThread());
693
694 if (request_.get()) {
695 request_->CancelWithError(error);
696 ReleaseRequest();
697 }
698 error_ = static_cast<Error>(error);
699
700 // Release the reference to the request context. There could be multiple
701 // references to URLFetcher::Core at this point so it may take a while to
702 // delete the object, but we cannot delay the destruction of the request
703 // context.
704 request_context_getter_ = nullptr;
705 initiator_.reset();
706 url_request_data_key_ = nullptr;
707 url_request_create_data_callback_.Reset();
708 was_cancelled_ = true;
709 }
710
OnCompletedURLRequest(base::TimeDelta backoff_delay)711 void URLFetcherCore::OnCompletedURLRequest(
712 base::TimeDelta backoff_delay) {
713 DCHECK(delegate_task_runner_->RunsTasksInCurrentSequence());
714
715 // Save the status and backoff_delay so that delegates can read it.
716 if (delegate_) {
717 backoff_delay_ = backoff_delay;
718 InformDelegateFetchIsComplete();
719 }
720 }
721
InformDelegateFetchIsComplete()722 void URLFetcherCore::InformDelegateFetchIsComplete() {
723 DCHECK(delegate_task_runner_->RunsTasksInCurrentSequence());
724 if (delegate_)
725 delegate_->OnURLFetchComplete(fetcher_);
726 }
727
NotifyMalformedContent()728 void URLFetcherCore::NotifyMalformedContent() {
729 DCHECK(network_task_runner_->BelongsToCurrentThread());
730 if (url_throttler_entry_.get()) {
731 int status_code = response_code_;
732 if (status_code == URLFetcher::RESPONSE_CODE_INVALID) {
733 // The status code will generally be known by the time clients
734 // call the |ReceivedContentWasMalformed()| function (which ends up
735 // calling the current function) but if it's not, we need to assume
736 // the response was successful so that the total failure count
737 // used to calculate exponential back-off goes up.
738 status_code = 200;
739 }
740 url_throttler_entry_->ReceivedContentWasMalformed(status_code);
741 }
742 }
743
DidFinishWriting(int result)744 void URLFetcherCore::DidFinishWriting(int result) {
745 if (result != OK) {
746 CancelRequestAndInformDelegate(result);
747 return;
748 }
749 // If the file was successfully closed, then the URL request is complete.
750 RetryOrCompleteUrlFetch();
751 }
752
RetryOrCompleteUrlFetch()753 void URLFetcherCore::RetryOrCompleteUrlFetch() {
754 DCHECK(network_task_runner_->BelongsToCurrentThread());
755 base::TimeDelta backoff_delay;
756
757 // Checks the response from server.
758 if (response_code_ >= 500 || error_ == ERR_TEMPORARILY_THROTTLED) {
759 // When encountering a server error, we will send the request again
760 // after backoff time.
761 ++num_retries_on_5xx_;
762
763 // Note that backoff_delay may be 0 because (a) the
764 // URLRequestThrottlerManager and related code does not
765 // necessarily back off on the first error, (b) it only backs off
766 // on some of the 5xx status codes, (c) not all URLRequestContexts
767 // have a throttler manager.
768 base::TimeTicks backoff_release_time = GetBackoffReleaseTime();
769 backoff_delay = backoff_release_time - base::TimeTicks::Now();
770 if (backoff_delay < base::TimeDelta())
771 backoff_delay = base::TimeDelta();
772
773 if (automatically_retry_on_5xx_ &&
774 num_retries_on_5xx_ <= max_retries_on_5xx_) {
775 StartOnIOThread();
776 return;
777 }
778 } else {
779 backoff_delay = base::TimeDelta();
780 }
781
782 // Retry if the request failed due to network changes.
783 if (error_ == ERR_NETWORK_CHANGED &&
784 num_retries_on_network_changes_ < max_retries_on_network_changes_) {
785 ++num_retries_on_network_changes_;
786
787 // Retry soon, after flushing all the current tasks which may include
788 // further network change observers.
789 network_task_runner_->PostTask(
790 FROM_HERE, base::BindOnce(&URLFetcherCore::StartOnIOThread, this));
791 return;
792 }
793
794 request_context_getter_ = nullptr;
795 initiator_.reset();
796 url_request_data_key_ = nullptr;
797 url_request_create_data_callback_.Reset();
798 bool posted = delegate_task_runner_->PostTask(
799 FROM_HERE, base::BindOnce(&URLFetcherCore::OnCompletedURLRequest, this,
800 backoff_delay));
801
802 // If the delegate message loop does not exist any more, then the delegate
803 // should be gone too.
804 DCHECK(posted || !delegate_);
805 }
806
CancelRequestAndInformDelegate(int result)807 void URLFetcherCore::CancelRequestAndInformDelegate(int result) {
808 CancelURLRequest(result);
809 delegate_task_runner_->PostTask(
810 FROM_HERE,
811 base::BindOnce(&URLFetcherCore::InformDelegateFetchIsComplete, this));
812 }
813
ReleaseRequest()814 void URLFetcherCore::ReleaseRequest() {
815 request_context_getter_->RemoveObserver(this);
816 upload_progress_checker_timer_.reset();
817 request_.reset();
818 buffer_ = nullptr;
819 g_registry.Get().RemoveURLFetcherCore(this);
820 }
821
GetBackoffReleaseTime()822 base::TimeTicks URLFetcherCore::GetBackoffReleaseTime() {
823 DCHECK(network_task_runner_->BelongsToCurrentThread());
824
825 if (!original_url_throttler_entry_.get())
826 return base::TimeTicks();
827
828 base::TimeTicks original_url_backoff =
829 original_url_throttler_entry_->GetExponentialBackoffReleaseTime();
830 base::TimeTicks destination_url_backoff;
831 if (url_throttler_entry_.get() &&
832 original_url_throttler_entry_.get() != url_throttler_entry_.get()) {
833 destination_url_backoff =
834 url_throttler_entry_->GetExponentialBackoffReleaseTime();
835 }
836
837 return original_url_backoff > destination_url_backoff ?
838 original_url_backoff : destination_url_backoff;
839 }
840
CompleteAddingUploadDataChunk(const std::string & content,bool is_last_chunk)841 void URLFetcherCore::CompleteAddingUploadDataChunk(
842 const std::string& content, bool is_last_chunk) {
843 DCHECK(is_chunked_upload_);
844 DCHECK(!content.empty());
845 chunked_stream_writer_->AppendData(
846 content.data(), static_cast<int>(content.length()), is_last_chunk);
847 }
848
WriteBuffer(scoped_refptr<DrainableIOBuffer> data)849 int URLFetcherCore::WriteBuffer(scoped_refptr<DrainableIOBuffer> data) {
850 while (data->BytesRemaining() > 0) {
851 const int result = response_writer_->Write(
852 data.get(), data->BytesRemaining(),
853 base::BindOnce(&URLFetcherCore::DidWriteBuffer, this, data));
854 if (result < 0) {
855 if (result != ERR_IO_PENDING)
856 DidWriteBuffer(data, result);
857 return result;
858 }
859 data->DidConsume(result);
860 }
861 return OK;
862 }
863
DidWriteBuffer(scoped_refptr<DrainableIOBuffer> data,int result)864 void URLFetcherCore::DidWriteBuffer(scoped_refptr<DrainableIOBuffer> data,
865 int result) {
866 if (result < 0) { // Handle errors.
867 response_writer_->Finish(result, base::DoNothing());
868 CancelRequestAndInformDelegate(result);
869 return;
870 }
871
872 // Continue writing.
873 data->DidConsume(result);
874 if (WriteBuffer(data) < 0)
875 return;
876
877 // Finished writing buffer_. Read some more, unless the request has been
878 // cancelled and deleted.
879 DCHECK_EQ(0, data->BytesRemaining());
880 if (request_.get())
881 ReadResponse();
882 }
883
ReadResponse()884 void URLFetcherCore::ReadResponse() {
885 // Some servers may treat HEAD requests as GET requests. To free up the
886 // network connection as soon as possible, signal that the request has
887 // completed immediately, without trying to read any data back (all we care
888 // about is the response code and headers, which we already have).
889 int bytes_read = 0;
890 if (request_type_ != URLFetcher::HEAD)
891 bytes_read = request_->Read(buffer_.get(), kBufferSize);
892
893 OnReadCompleted(request_.get(), bytes_read);
894 }
895
InformDelegateUploadProgress()896 void URLFetcherCore::InformDelegateUploadProgress() {
897 DCHECK(network_task_runner_->BelongsToCurrentThread());
898 if (request_.get()) {
899 int64_t current = request_->GetUploadProgress().position();
900 if (current_upload_bytes_ != current) {
901 current_upload_bytes_ = current;
902 int64_t total = -1;
903 if (!is_chunked_upload_) {
904 total = static_cast<int64_t>(request_->GetUploadProgress().size());
905 // Total may be zero if the UploadDataStream::Init has not been called
906 // yet. Don't send the upload progress until the size is initialized.
907 if (!total)
908 return;
909 }
910 delegate_task_runner_->PostTask(
911 FROM_HERE,
912 base::BindOnce(
913 &URLFetcherCore::InformDelegateUploadProgressInDelegateSequence,
914 this, current, total));
915 }
916 }
917 }
918
InformDelegateUploadProgressInDelegateSequence(int64_t current,int64_t total)919 void URLFetcherCore::InformDelegateUploadProgressInDelegateSequence(
920 int64_t current,
921 int64_t total) {
922 DCHECK(delegate_task_runner_->RunsTasksInCurrentSequence());
923 if (delegate_)
924 delegate_->OnURLFetchUploadProgress(fetcher_, current, total);
925 }
926
InformDelegateDownloadProgress()927 void URLFetcherCore::InformDelegateDownloadProgress() {
928 DCHECK(network_task_runner_->BelongsToCurrentThread());
929 delegate_task_runner_->PostTask(
930 FROM_HERE,
931 base::BindOnce(
932 &URLFetcherCore::InformDelegateDownloadProgressInDelegateSequence,
933 this, current_response_bytes_, total_response_bytes_,
934 request_->GetTotalReceivedBytes()));
935 }
936
InformDelegateDownloadProgressInDelegateSequence(int64_t current,int64_t total,int64_t current_network_bytes)937 void URLFetcherCore::InformDelegateDownloadProgressInDelegateSequence(
938 int64_t current,
939 int64_t total,
940 int64_t current_network_bytes) {
941 DCHECK(delegate_task_runner_->RunsTasksInCurrentSequence());
942 if (delegate_)
943 delegate_->OnURLFetchDownloadProgress(fetcher_, current, total,
944 current_network_bytes);
945 }
946
AssertHasNoUploadData() const947 void URLFetcherCore::AssertHasNoUploadData() const {
948 DCHECK(!upload_content_set_);
949 DCHECK(upload_content_.empty());
950 DCHECK(upload_file_path_.empty());
951 DCHECK(upload_stream_factory_.is_null());
952 }
953
954 } // namespace net
955