update devtools network interceptor to throttle uploads
This commit is contained in:
parent
95e63f6b8e
commit
215a81d0e6
13 changed files with 598 additions and 392 deletions
|
@ -5,8 +5,8 @@
|
|||
#include "browser/net/devtools_network_transaction.h"
|
||||
|
||||
#include "browser/net/devtools_network_controller.h"
|
||||
#include "browser/net/devtools_network_interceptor.h"
|
||||
|
||||
#include "browser/net/devtools_network_upload_data_stream.h"
|
||||
#include "net/base/load_timing_info.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "net/base/upload_progress.h"
|
||||
#include "net/http/http_network_transaction.h"
|
||||
|
@ -23,58 +23,84 @@ const char
|
|||
DevToolsNetworkTransaction::DevToolsNetworkTransaction(
|
||||
DevToolsNetworkController* controller,
|
||||
scoped_ptr<net::HttpTransaction> transaction)
|
||||
: controller_(controller),
|
||||
: throttled_byte_count_(0),
|
||||
controller_(controller),
|
||||
transaction_(std::move(transaction)),
|
||||
request_(nullptr),
|
||||
failed_(false),
|
||||
throttled_byte_count_(0),
|
||||
callback_type_(NONE) {
|
||||
proxy_callback_ = base::Bind(&DevToolsNetworkTransaction::OnCallback,
|
||||
base::Unretained(this));
|
||||
failed_(false) {
|
||||
DCHECK(controller);
|
||||
}
|
||||
|
||||
DevToolsNetworkTransaction::~DevToolsNetworkTransaction() {
|
||||
if (interceptor_)
|
||||
interceptor_->RemoveTransaction(this);
|
||||
if (interceptor_ && !throttle_callback_.is_null())
|
||||
interceptor_->StopThrottle(throttle_callback_);
|
||||
}
|
||||
|
||||
void DevToolsNetworkTransaction::ProcessRequest() {
|
||||
DCHECK(request_);
|
||||
void DevToolsNetworkTransaction::IOCallback(
|
||||
const net::CompletionCallback& callback, bool start, int result) {
|
||||
result = Throttle(callback, start, result);
|
||||
if (result != net::ERR_IO_PENDING)
|
||||
callback.Run(result);
|
||||
}
|
||||
|
||||
bool has_devtools_client_id = request_->extra_headers.HasHeader(
|
||||
kDevToolsEmulateNetworkConditionsClientId);
|
||||
if (!has_devtools_client_id)
|
||||
return;
|
||||
int DevToolsNetworkTransaction::Throttle(
|
||||
const net::CompletionCallback& callback, bool start, int result) {
|
||||
if (failed_)
|
||||
return net::ERR_INTERNET_DISCONNECTED;
|
||||
if (!interceptor_ || result < 0)
|
||||
return result;
|
||||
|
||||
custom_request_.reset(new net::HttpRequestInfo(*request_));
|
||||
custom_request_->extra_headers.GetHeader(
|
||||
kDevToolsEmulateNetworkConditionsClientId, &client_id_);
|
||||
custom_request_->extra_headers.RemoveHeader(
|
||||
kDevToolsEmulateNetworkConditionsClientId);
|
||||
base::TimeTicks send_end;
|
||||
if (start) {
|
||||
throttled_byte_count_ += transaction_->GetTotalReceivedBytes();
|
||||
net::LoadTimingInfo load_timing_info;
|
||||
if (GetLoadTimingInfo(&load_timing_info))
|
||||
send_end = load_timing_info.send_end;
|
||||
if (send_end.is_null())
|
||||
send_end = base::TimeTicks::Now();
|
||||
}
|
||||
if (result > 0)
|
||||
throttled_byte_count_ += result;
|
||||
|
||||
request_ = custom_request_.get();
|
||||
throttle_callback_ = base::Bind(&DevToolsNetworkTransaction::ThrottleCallback,
|
||||
base::Unretained(this),
|
||||
callback);
|
||||
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 DevToolsNetworkTransaction::ThrottleCallback(
|
||||
const net::CompletionCallback& callback, int result, int64_t bytes) {
|
||||
DCHECK(!throttle_callback_.is_null());
|
||||
throttle_callback_.Reset();
|
||||
if (result == net::ERR_INTERNET_DISCONNECTED)
|
||||
Fail();
|
||||
throttled_byte_count_ = bytes;
|
||||
callback.Run(result);
|
||||
}
|
||||
|
||||
void DevToolsNetworkTransaction::Fail() {
|
||||
DCHECK(request_);
|
||||
DCHECK(!failed_);
|
||||
|
||||
failed_ = true;
|
||||
transaction_->SetBeforeNetworkStartCallback(
|
||||
BeforeNetworkStartCallback());
|
||||
|
||||
if (callback_.is_null())
|
||||
return;
|
||||
|
||||
net::CompletionCallback original_callback = callback_;
|
||||
callback_.Reset();
|
||||
callback_type_ = NONE;
|
||||
original_callback.Run(net::ERR_INTERNET_DISCONNECTED);
|
||||
transaction_->SetBeforeNetworkStartCallback(BeforeNetworkStartCallback());
|
||||
if (interceptor_)
|
||||
interceptor_.reset();
|
||||
}
|
||||
|
||||
void DevToolsNetworkTransaction::DecreaseThrottledByteCount(
|
||||
int64_t delta) {
|
||||
throttled_byte_count_ -= delta;
|
||||
bool DevToolsNetworkTransaction::CheckFailed() {
|
||||
if (failed_)
|
||||
return true;
|
||||
if (interceptor_ && interceptor_->IsOffline()) {
|
||||
Fail();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int DevToolsNetworkTransaction::Start(
|
||||
|
@ -82,45 +108,90 @@ int DevToolsNetworkTransaction::Start(
|
|||
const net::CompletionCallback& callback,
|
||||
const net::BoundNetLog& net_log) {
|
||||
DCHECK(request);
|
||||
|
||||
request_ = request;
|
||||
interceptor_ = controller_->GetInterceptor(this);
|
||||
interceptor_->AddTransaction(this);
|
||||
|
||||
if (interceptor_->ShouldFail(this)) {
|
||||
failed_ = true;
|
||||
transaction_->SetBeforeNetworkStartCallback(BeforeNetworkStartCallback());
|
||||
return net::ERR_INTERNET_DISCONNECTED;
|
||||
std::string client_id;
|
||||
bool has_devtools_client_id = request_->extra_headers.HasHeader(
|
||||
kDevToolsEmulateNetworkConditionsClientId);
|
||||
if (has_devtools_client_id) {
|
||||
custom_request_.reset(new net::HttpRequestInfo(*request_));
|
||||
custom_request_->extra_headers.GetHeader(
|
||||
kDevToolsEmulateNetworkConditionsClientId, &client_id);
|
||||
custom_request_->extra_headers.RemoveHeader(
|
||||
kDevToolsEmulateNetworkConditionsClientId);
|
||||
|
||||
if (request_->upload_data_stream) {
|
||||
custom_upload_data_stream_.reset(
|
||||
new DevToolsNetworkUploadDataStream(request_->upload_data_stream));
|
||||
custom_request_->upload_data_stream = custom_upload_data_stream_.get();
|
||||
}
|
||||
|
||||
request_ = custom_request_.get();
|
||||
}
|
||||
int rv = transaction_->Start(request_, proxy_callback_, net_log);
|
||||
return SetupCallback(callback, rv, START);
|
||||
|
||||
DevToolsNetworkInterceptor* interceptor = controller_->GetInterceptor(client_id);
|
||||
if (interceptor) {
|
||||
interceptor_ = interceptor->GetWeakPtr();
|
||||
if (custom_upload_data_stream_)
|
||||
custom_upload_data_stream_->SetInterceptor(interceptor);
|
||||
}
|
||||
|
||||
if (CheckFailed())
|
||||
return net::ERR_INTERNET_DISCONNECTED;
|
||||
|
||||
if (!interceptor_)
|
||||
return transaction_->Start(request_, callback, net_log);
|
||||
|
||||
int result = transaction_->Start(request_,
|
||||
base::Bind(&DevToolsNetworkTransaction::IOCallback,
|
||||
base::Unretained(this), callback, true),
|
||||
net_log);
|
||||
return Throttle(callback, true, result);
|
||||
}
|
||||
|
||||
int DevToolsNetworkTransaction::RestartIgnoringLastError(
|
||||
const net::CompletionCallback& callback) {
|
||||
if (failed_)
|
||||
if (CheckFailed())
|
||||
return net::ERR_INTERNET_DISCONNECTED;
|
||||
int rv = transaction_->RestartIgnoringLastError(proxy_callback_);
|
||||
return SetupCallback(callback, rv, RESTART_IGNORING_LAST_ERROR);
|
||||
if (!interceptor_)
|
||||
return transaction_->RestartIgnoringLastError(callback);
|
||||
|
||||
int result = transaction_->RestartIgnoringLastError(
|
||||
base::Bind(&DevToolsNetworkTransaction::IOCallback,
|
||||
base::Unretained(this), callback, true));
|
||||
return Throttle(callback, true, result);
|
||||
}
|
||||
|
||||
int DevToolsNetworkTransaction::RestartWithCertificate(
|
||||
net::X509Certificate* client_certificate,
|
||||
net::X509Certificate* client_cert,
|
||||
net::SSLPrivateKey* client_private_key,
|
||||
const net::CompletionCallback& callback) {
|
||||
if (failed_)
|
||||
if (CheckFailed())
|
||||
return net::ERR_INTERNET_DISCONNECTED;
|
||||
int rv = transaction_->RestartWithCertificate(client_certificate, client_private_key, proxy_callback_);
|
||||
return SetupCallback(callback, rv, RESTART_WITH_CERTIFICATE);
|
||||
if (!interceptor_) {
|
||||
return transaction_->RestartWithCertificate(
|
||||
client_cert, client_private_key, callback);
|
||||
}
|
||||
|
||||
int result = transaction_->RestartWithCertificate(
|
||||
client_cert, client_private_key,
|
||||
base::Bind(&DevToolsNetworkTransaction::IOCallback,
|
||||
base::Unretained(this), callback, true));
|
||||
return Throttle(callback, true, result);
|
||||
}
|
||||
|
||||
int DevToolsNetworkTransaction::RestartWithAuth(
|
||||
const net::AuthCredentials& credentials,
|
||||
const net::CompletionCallback& callback) {
|
||||
if (failed_)
|
||||
if (CheckFailed())
|
||||
return net::ERR_INTERNET_DISCONNECTED;
|
||||
int rv = transaction_->RestartWithAuth(credentials, proxy_callback_);
|
||||
return SetupCallback(callback, rv, RESTART_WITH_AUTH);
|
||||
if (!interceptor_)
|
||||
return transaction_->RestartWithAuth(credentials, callback);
|
||||
|
||||
int result = transaction_->RestartWithAuth(credentials,
|
||||
base::Bind(&DevToolsNetworkTransaction::IOCallback,
|
||||
base::Unretained(this), callback, true));
|
||||
return Throttle(callback, true, result);
|
||||
}
|
||||
|
||||
bool DevToolsNetworkTransaction::IsReadyToRestartForAuth() {
|
||||
|
@ -128,13 +199,21 @@ bool DevToolsNetworkTransaction::IsReadyToRestartForAuth() {
|
|||
}
|
||||
|
||||
int DevToolsNetworkTransaction::Read(
|
||||
net::IOBuffer* buffer,
|
||||
int length,
|
||||
net::IOBuffer* buf,
|
||||
int buf_len,
|
||||
const net::CompletionCallback& callback) {
|
||||
if (failed_)
|
||||
if (CheckFailed())
|
||||
return net::ERR_INTERNET_DISCONNECTED;
|
||||
int rv = transaction_->Read(buffer, length, proxy_callback_);
|
||||
return SetupCallback(callback, rv, READ);
|
||||
if (!interceptor_)
|
||||
return transaction_->Read(buf, buf_len, callback);
|
||||
|
||||
int result = transaction_->Read(buf, buf_len,
|
||||
base::Bind(&DevToolsNetworkTransaction::IOCallback,
|
||||
base::Unretained(this), callback, false));
|
||||
// URLRequestJob relies on synchronous end-of-stream notification.
|
||||
if (result == 0)
|
||||
return result;
|
||||
return Throttle(callback, false, result);
|
||||
}
|
||||
|
||||
void DevToolsNetworkTransaction::StopCaching() {
|
||||
|
@ -221,76 +300,4 @@ void DevToolsNetworkTransaction::GetConnectionAttempts(
|
|||
transaction_->GetConnectionAttempts(out);
|
||||
}
|
||||
|
||||
void DevToolsNetworkTransaction::OnCallback(int rv) {
|
||||
if (failed_ || callback_.is_null())
|
||||
return;
|
||||
|
||||
if (callback_type_ == START || callback_type_ == READ) {
|
||||
if (interceptor_ && interceptor_->ShouldThrottle(this)) {
|
||||
Throttle(rv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
net::CompletionCallback original_callback = callback_;
|
||||
callback_.Reset();
|
||||
callback_type_ = NONE;
|
||||
original_callback.Run(rv);
|
||||
}
|
||||
|
||||
int DevToolsNetworkTransaction::SetupCallback(
|
||||
net::CompletionCallback callback,
|
||||
int result,
|
||||
CallbackType callback_type) {
|
||||
DCHECK(callback_type_ == NONE);
|
||||
|
||||
if (result == net::ERR_IO_PENDING) {
|
||||
callback_type_ = callback_type;
|
||||
callback_ = callback;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!interceptor_ || !interceptor_->ShouldThrottle(this))
|
||||
return result;
|
||||
|
||||
// Only START and READ operation throttling is supported.
|
||||
if (callback_type != START && callback_type != READ)
|
||||
return result;
|
||||
|
||||
// In case of error |throttled_byte_count_| is unknown.
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
// URLRequestJob relies on synchronous end-of-stream notification.
|
||||
if (callback_type == READ && result == 0)
|
||||
return result;
|
||||
|
||||
callback_type_ = callback_type;
|
||||
callback_ = callback;
|
||||
Throttle(result);
|
||||
return net::ERR_IO_PENDING;
|
||||
}
|
||||
|
||||
void DevToolsNetworkTransaction::Throttle(int result) {
|
||||
throttled_result_ = result;
|
||||
|
||||
if (callback_type_ == START)
|
||||
throttled_byte_count_ += transaction_->GetTotalReceivedBytes();
|
||||
if (result > 0)
|
||||
throttled_byte_count_ += result;
|
||||
|
||||
if (interceptor_)
|
||||
interceptor_->ThrottleTransaction(this, callback_type_ == START);
|
||||
}
|
||||
|
||||
void DevToolsNetworkTransaction::FireThrottledCallback() {
|
||||
DCHECK(!callback_.is_null());
|
||||
DCHECK(callback_type_ == READ || callback_type_ == START);
|
||||
|
||||
net::CompletionCallback original_callback = callback_;
|
||||
callback_.Reset();
|
||||
callback_type_ = NONE;
|
||||
original_callback.Run(throttled_result_);
|
||||
}
|
||||
|
||||
} // namespace brightray
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue