| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "services/network/throttling/throttling_network_transaction.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/callback_helpers.h" |
| #include "net/base/load_timing_info.h" |
| #include "net/base/net_errors.h" |
| #include "net/http/http_network_transaction.h" |
| #include "net/http/http_request_info.h" |
| #include "net/socket/connection_attempts.h" |
| #include "services/network/throttling/throttling_controller.h" |
| #include "services/network/throttling/throttling_network_interceptor.h" |
| #include "services/network/throttling/throttling_upload_data_stream.h" |
| |
| namespace network { |
| |
| ThrottlingNetworkTransaction::ThrottlingNetworkTransaction( |
| std::unique_ptr<net::HttpTransaction> network_transaction) |
| : throttled_byte_count_(0), |
| network_transaction_(std::move(network_transaction)), |
| request_(nullptr), |
| failed_(false) {} |
| |
| ThrottlingNetworkTransaction::~ThrottlingNetworkTransaction() { |
| if (interceptor_ && !throttle_callback_.is_null()) |
| interceptor_->StopThrottle(throttle_callback_); |
| } |
| |
| void ThrottlingNetworkTransaction::IOCallback( |
| bool start, |
| int result) { |
| DCHECK(callback_); |
| result = Throttle(start, result); |
| if (result != net::ERR_IO_PENDING) |
| std::move(callback_).Run(result); |
| } |
| |
| int ThrottlingNetworkTransaction::Throttle( |
| bool start, |
| int result) { |
| if (failed_) |
| return net::ERR_INTERNET_DISCONNECTED; |
| if (!interceptor_ || result < 0) |
| return result; |
| |
| base::TimeTicks send_end; |
| if (start) { |
| throttled_byte_count_ += network_transaction_->GetTotalReceivedBytes(); |
| net::LoadTimingInfo load_timing_info; |
| if (GetLoadTimingInfo(&load_timing_info)) { |
| send_end = load_timing_info.send_end; |
| if (!load_timing_info.push_start.is_null()) |
| start = false; |
| } |
| if (send_end.is_null()) |
| send_end = base::TimeTicks::Now(); |
| } |
| if (result > 0) |
| throttled_byte_count_ += result; |
| |
| throttle_callback_ = base::Bind( |
| &ThrottlingNetworkTransaction::ThrottleCallback, base::Unretained(this)); |
| int rv = interceptor_->StartThrottle(result, throttled_byte_count_, send_end, |
| start, false, throttle_callback_); |
| if (rv != net::ERR_IO_PENDING) |
| throttle_callback_.Reset(); |
| if (rv == net::ERR_INTERNET_DISCONNECTED) |
| Fail(); |
| return rv; |
| } |
| |
| void ThrottlingNetworkTransaction::ThrottleCallback( |
| int result, |
| int64_t bytes) { |
| DCHECK(callback_); |
| DCHECK(!throttle_callback_.is_null()); |
| |
| throttle_callback_.Reset(); |
| if (result == net::ERR_INTERNET_DISCONNECTED) |
| Fail(); |
| throttled_byte_count_ = bytes; |
| std::move(callback_).Run(result); |
| } |
| |
| void ThrottlingNetworkTransaction::Fail() { |
| DCHECK(request_); |
| DCHECK(!failed_); |
| failed_ = true; |
| network_transaction_->SetBeforeNetworkStartCallback( |
| BeforeNetworkStartCallback()); |
| if (interceptor_) |
| interceptor_.reset(); |
| } |
| |
| bool ThrottlingNetworkTransaction::CheckFailed() { |
| if (failed_) |
| return true; |
| if (interceptor_ && interceptor_->IsOffline()) { |
| Fail(); |
| return true; |
| } |
| return false; |
| } |
| |
| int ThrottlingNetworkTransaction::Start(const net::HttpRequestInfo* request, |
| net::CompletionOnceCallback callback, |
| const net::NetLogWithSource& net_log) { |
| DCHECK(request); |
| request_ = request; |
| |
| ThrottlingNetworkInterceptor* interceptor = |
| ThrottlingController::GetInterceptor(net_log.source().id); |
| |
| if (interceptor) { |
| custom_request_.reset(new net::HttpRequestInfo(*request_)); |
| |
| if (request_->upload_data_stream) { |
| custom_upload_data_stream_.reset( |
| new ThrottlingUploadDataStream(request_->upload_data_stream)); |
| custom_request_->upload_data_stream = custom_upload_data_stream_.get(); |
| } |
| |
| request_ = custom_request_.get(); |
| |
| interceptor_ = interceptor->GetWeakPtr(); |
| if (custom_upload_data_stream_) |
| custom_upload_data_stream_->SetInterceptor(interceptor); |
| } |
| |
| if (CheckFailed()) |
| return net::ERR_INTERNET_DISCONNECTED; |
| |
| if (!interceptor_) |
| return network_transaction_->Start(request_, std::move(callback), net_log); |
| |
| callback_ = std::move(callback); |
| int result = network_transaction_->Start( |
| request_, |
| base::BindOnce(&ThrottlingNetworkTransaction::IOCallback, |
| base::Unretained(this), true), |
| net_log); |
| return Throttle(true, result); |
| } |
| |
| int ThrottlingNetworkTransaction::RestartIgnoringLastError( |
| net::CompletionOnceCallback callback) { |
| if (CheckFailed()) |
| return net::ERR_INTERNET_DISCONNECTED; |
| if (!interceptor_) |
| return network_transaction_->RestartIgnoringLastError(std::move(callback)); |
| |
| callback_ = std::move(callback); |
| int result = network_transaction_->RestartIgnoringLastError(base::BindOnce( |
| &ThrottlingNetworkTransaction::IOCallback, base::Unretained(this), true)); |
| return Throttle(true, result); |
| } |
| |
| int ThrottlingNetworkTransaction::RestartWithCertificate( |
| scoped_refptr<net::X509Certificate> client_cert, |
| scoped_refptr<net::SSLPrivateKey> client_private_key, |
| net::CompletionOnceCallback callback) { |
| if (CheckFailed()) |
| return net::ERR_INTERNET_DISCONNECTED; |
| if (!interceptor_) { |
| return network_transaction_->RestartWithCertificate( |
| std::move(client_cert), std::move(client_private_key), |
| std::move(callback)); |
| } |
| |
| callback_ = std::move(callback); |
| int result = network_transaction_->RestartWithCertificate( |
| std::move(client_cert), std::move(client_private_key), |
| base::BindOnce(&ThrottlingNetworkTransaction::IOCallback, |
| base::Unretained(this), true)); |
| return Throttle(true, result); |
| } |
| |
| int ThrottlingNetworkTransaction::RestartWithAuth( |
| const net::AuthCredentials& credentials, |
| net::CompletionOnceCallback callback) { |
| if (CheckFailed()) |
| return net::ERR_INTERNET_DISCONNECTED; |
| if (!interceptor_) |
| return network_transaction_->RestartWithAuth(credentials, |
| std::move(callback)); |
| |
| callback_ = std::move(callback); |
| int result = network_transaction_->RestartWithAuth( |
| credentials, base::BindOnce(&ThrottlingNetworkTransaction::IOCallback, |
| base::Unretained(this), true)); |
| return Throttle(true, result); |
| } |
| |
| bool ThrottlingNetworkTransaction::IsReadyToRestartForAuth() { |
| return network_transaction_->IsReadyToRestartForAuth(); |
| } |
| |
| int ThrottlingNetworkTransaction::Read(net::IOBuffer* buf, |
| int buf_len, |
| net::CompletionOnceCallback callback) { |
| if (CheckFailed()) |
| return net::ERR_INTERNET_DISCONNECTED; |
| if (!interceptor_) |
| return network_transaction_->Read(buf, buf_len, std::move(callback)); |
| |
| callback_ = std::move(callback); |
| int result = network_transaction_->Read( |
| buf, buf_len, |
| base::BindOnce(&ThrottlingNetworkTransaction::IOCallback, |
| base::Unretained(this), false)); |
| // URLRequestJob relies on synchronous end-of-stream notification. |
| if (result == 0) |
| return result; |
| return Throttle(false, result); |
| } |
| |
| void ThrottlingNetworkTransaction::StopCaching() { |
| network_transaction_->StopCaching(); |
| } |
| |
| bool ThrottlingNetworkTransaction::GetFullRequestHeaders( |
| net::HttpRequestHeaders* headers) const { |
| return network_transaction_->GetFullRequestHeaders(headers); |
| } |
| |
| int64_t ThrottlingNetworkTransaction::GetTotalReceivedBytes() const { |
| return network_transaction_->GetTotalReceivedBytes(); |
| } |
| |
| int64_t ThrottlingNetworkTransaction::GetTotalSentBytes() const { |
| return network_transaction_->GetTotalSentBytes(); |
| } |
| |
| void ThrottlingNetworkTransaction::DoneReading() { |
| network_transaction_->DoneReading(); |
| } |
| |
| const net::HttpResponseInfo* ThrottlingNetworkTransaction::GetResponseInfo() |
| const { |
| return network_transaction_->GetResponseInfo(); |
| } |
| |
| net::LoadState ThrottlingNetworkTransaction::GetLoadState() const { |
| return network_transaction_->GetLoadState(); |
| } |
| |
| void ThrottlingNetworkTransaction::SetQuicServerInfo( |
| net::QuicServerInfo* quic_server_info) { |
| network_transaction_->SetQuicServerInfo(quic_server_info); |
| } |
| |
| bool ThrottlingNetworkTransaction::GetLoadTimingInfo( |
| net::LoadTimingInfo* load_timing_info) const { |
| return network_transaction_->GetLoadTimingInfo(load_timing_info); |
| } |
| |
| bool ThrottlingNetworkTransaction::GetRemoteEndpoint( |
| net::IPEndPoint* endpoint) const { |
| return network_transaction_->GetRemoteEndpoint(endpoint); |
| } |
| |
| void ThrottlingNetworkTransaction::PopulateNetErrorDetails( |
| net::NetErrorDetails* details) const { |
| return network_transaction_->PopulateNetErrorDetails(details); |
| } |
| |
| void ThrottlingNetworkTransaction::SetPriority(net::RequestPriority priority) { |
| network_transaction_->SetPriority(priority); |
| } |
| |
| void ThrottlingNetworkTransaction::SetWebSocketHandshakeStreamCreateHelper( |
| net::WebSocketHandshakeStreamBase::CreateHelper* create_helper) { |
| network_transaction_->SetWebSocketHandshakeStreamCreateHelper(create_helper); |
| } |
| |
| void ThrottlingNetworkTransaction::SetBeforeNetworkStartCallback( |
| const BeforeNetworkStartCallback& callback) { |
| network_transaction_->SetBeforeNetworkStartCallback(callback); |
| } |
| |
| void ThrottlingNetworkTransaction::SetRequestHeadersCallback( |
| net::RequestHeadersCallback callback) { |
| network_transaction_->SetRequestHeadersCallback(std::move(callback)); |
| } |
| |
| void ThrottlingNetworkTransaction::SetResponseHeadersCallback( |
| net::ResponseHeadersCallback callback) { |
| network_transaction_->SetResponseHeadersCallback(std::move(callback)); |
| } |
| |
| void ThrottlingNetworkTransaction::SetBeforeHeadersSentCallback( |
| const BeforeHeadersSentCallback& callback) { |
| network_transaction_->SetBeforeHeadersSentCallback(callback); |
| } |
| |
| int ThrottlingNetworkTransaction::ResumeNetworkStart() { |
| if (CheckFailed()) |
| return net::ERR_INTERNET_DISCONNECTED; |
| return network_transaction_->ResumeNetworkStart(); |
| } |
| |
| void ThrottlingNetworkTransaction::GetConnectionAttempts( |
| net::ConnectionAttempts* out) const { |
| network_transaction_->GetConnectionAttempts(out); |
| } |
| |
| } // namespace network |