update devtools network interceptor to throttle uploads

This commit is contained in:
Robo 2016-03-14 02:35:22 +05:30
parent 95e63f6b8e
commit 215a81d0e6
13 changed files with 598 additions and 392 deletions

View file

@ -158,6 +158,12 @@ DevToolsManagerDelegate::DevToolsManagerDelegate()
DevToolsManagerDelegate::~DevToolsManagerDelegate() { DevToolsManagerDelegate::~DevToolsManagerDelegate() {
} }
void DevToolsManagerDelegate::DevToolsAgentStateChanged(
content::DevToolsAgentHost* agent_host,
bool attached) {
handler_->DevToolsAgentStateChanged(agent_host, attached);
}
base::DictionaryValue* DevToolsManagerDelegate::HandleCommand( base::DictionaryValue* DevToolsManagerDelegate::HandleCommand(
content::DevToolsAgentHost* agent_host, content::DevToolsAgentHost* agent_host,
base::DictionaryValue* command) { base::DictionaryValue* command) {

View file

@ -29,7 +29,7 @@ class DevToolsManagerDelegate : public content::DevToolsManagerDelegate {
void Inspect(content::BrowserContext* browser_context, void Inspect(content::BrowserContext* browser_context,
content::DevToolsAgentHost* agent_host) override {} content::DevToolsAgentHost* agent_host) override {}
void DevToolsAgentStateChanged(content::DevToolsAgentHost* agent_host, void DevToolsAgentStateChanged(content::DevToolsAgentHost* agent_host,
bool attached) override {} bool attached) override;
base::DictionaryValue* HandleCommand(content::DevToolsAgentHost* agent_host, base::DictionaryValue* HandleCommand(content::DevToolsAgentHost* agent_host,
base::DictionaryValue* command) override; base::DictionaryValue* command) override;

View file

@ -16,7 +16,7 @@ using content::BrowserThread;
namespace brightray { namespace brightray {
DevToolsNetworkController::DevToolsNetworkController() DevToolsNetworkController::DevToolsNetworkController()
: default_interceptor_(new DevToolsNetworkInterceptor) { : appcache_interceptor_(new DevToolsNetworkInterceptor) {
} }
DevToolsNetworkController::~DevToolsNetworkController() { DevToolsNetworkController::~DevToolsNetworkController() {
@ -27,14 +27,7 @@ void DevToolsNetworkController::SetNetworkState(
scoped_ptr<DevToolsNetworkConditions> conditions) { scoped_ptr<DevToolsNetworkConditions> conditions) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (client_id.empty()) { DevToolsNetworkInterceptor* interceptor = interceptors_.get(client_id);
if (!conditions)
return;
default_interceptor_->UpdateConditions(std::move(conditions));
return;
}
auto interceptor = interceptors_.get(client_id);
if (!interceptor) { if (!interceptor) {
if (!conditions) if (!conditions)
return; return;
@ -52,23 +45,36 @@ void DevToolsNetworkController::SetNetworkState(
interceptor->UpdateConditions(std::move(conditions)); interceptor->UpdateConditions(std::move(conditions));
} }
} }
bool has_offline_interceptors = false;
InterceptorMap::iterator it = interceptors_.begin();
for (; it != interceptors_.end(); ++it) {
if (it->second->IsOffline()) {
has_offline_interceptors = true;
break;
}
}
bool is_appcache_offline = appcache_interceptor_->IsOffline();
if (is_appcache_offline != has_offline_interceptors) {
scoped_ptr<DevToolsNetworkConditions> appcache_conditions(
new DevToolsNetworkConditions(has_offline_interceptors));
appcache_interceptor_->UpdateConditions(std::move(appcache_conditions));
}
} }
base::WeakPtr<DevToolsNetworkInterceptor> DevToolsNetworkInterceptor*
DevToolsNetworkController::GetInterceptor(DevToolsNetworkTransaction* transaction) { DevToolsNetworkController::GetInterceptor(const std::string& client_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(transaction->request());
if (!interceptors_.size()) if (!interceptors_.size() || client_id.empty())
return default_interceptor_->GetWeakPtr(); return nullptr;
transaction->ProcessRequest(); DevToolsNetworkInterceptor* interceptor = interceptors_.get(client_id);
auto& client_id = transaction->client_id();
auto interceptor = interceptors_.get(client_id);
if (!interceptor) if (!interceptor)
return default_interceptor_->GetWeakPtr(); return nullptr;
return interceptor->GetWeakPtr(); return interceptor;
} }
} // namespace brightray } // namespace brightray

View file

@ -8,7 +8,6 @@
#include "base/containers/scoped_ptr_hash_map.h" #include "base/containers/scoped_ptr_hash_map.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
namespace brightray { namespace brightray {
@ -23,13 +22,13 @@ class DevToolsNetworkController {
void SetNetworkState(const std::string& client_id, void SetNetworkState(const std::string& client_id,
scoped_ptr<DevToolsNetworkConditions> conditions); scoped_ptr<DevToolsNetworkConditions> conditions);
base::WeakPtr<DevToolsNetworkInterceptor> GetInterceptor( DevToolsNetworkInterceptor* GetInterceptor(const std::string& client_id);
DevToolsNetworkTransaction* transaction);
private: private:
using InterceptorMap = base::ScopedPtrHashMap<std::string, using InterceptorMap = base::ScopedPtrHashMap<std::string,
scoped_ptr<DevToolsNetworkInterceptor>>; scoped_ptr<DevToolsNetworkInterceptor>>;
scoped_ptr<DevToolsNetworkInterceptor> default_interceptor_;
scoped_ptr<DevToolsNetworkInterceptor> appcache_interceptor_;
InterceptorMap interceptors_; InterceptorMap interceptors_;
DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkController); DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkController);

View file

@ -4,13 +4,12 @@
#include "browser/net/devtools_network_interceptor.h" #include "browser/net/devtools_network_interceptor.h"
#include <algorithm>
#include <limits> #include <limits>
#include "browser/net/devtools_network_conditions.h"
#include "browser/net/devtools_network_transaction.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "net/base/load_timing_info.h" #include "browser/net/devtools_network_conditions.h"
#include "net/base/net_errors.h"
namespace brightray { namespace brightray {
@ -18,10 +17,31 @@ namespace {
int64_t kPacketSize = 1500; int64_t kPacketSize = 1500;
base::TimeDelta CalculateTickLength(double throughput) {
if (!throughput)
return base::TimeDelta();
int64_t us_tick_length = (1000000L * kPacketSize) / throughput;
if (us_tick_length == 0)
us_tick_length = 1;
return base::TimeDelta::FromMicroseconds(us_tick_length);
}
} // namespace } // namespace
DevToolsNetworkInterceptor::ThrottleRecord::ThrottleRecord() {
}
DevToolsNetworkInterceptor::ThrottleRecord::ThrottleRecord(
const ThrottleRecord& other) = default;
DevToolsNetworkInterceptor::ThrottleRecord::~ThrottleRecord() {
}
DevToolsNetworkInterceptor::DevToolsNetworkInterceptor() DevToolsNetworkInterceptor::DevToolsNetworkInterceptor()
: conditions_(new DevToolsNetworkConditions(false)), : conditions_(new DevToolsNetworkConditions(false)),
download_last_tick_(0),
upload_last_tick_(0),
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
} }
@ -33,186 +53,164 @@ DevToolsNetworkInterceptor::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr(); return weak_ptr_factory_.GetWeakPtr();
} }
void DevToolsNetworkInterceptor::FinishRecords(
ThrottleRecords* records, bool offline) {
ThrottleRecords temp;
temp.swap(*records);
for (const ThrottleRecord& record : temp) {
bool failed = offline && !record.is_upload;
record.callback.Run(
failed ? net::ERR_INTERNET_DISCONNECTED : record.result,
record.bytes);
}
}
void DevToolsNetworkInterceptor::UpdateConditions( void DevToolsNetworkInterceptor::UpdateConditions(
scoped_ptr<DevToolsNetworkConditions> conditions) { scoped_ptr<DevToolsNetworkConditions> conditions) {
DCHECK(conditions); DCHECK(conditions);
base::TimeTicks now = base::TimeTicks::Now(); base::TimeTicks now = base::TimeTicks::Now();
if (conditions_->IsThrottling()) if (conditions_->IsThrottling())
UpdateThrottledTransactions(now); UpdateThrottled(now);
conditions_ = std::move(conditions); conditions_ = std::move(conditions);
if (conditions_->offline()) { bool offline = conditions_->offline();
if (offline || conditions_->IsThrottling()) {
timer_.Stop(); timer_.Stop();
throttled_transactions_.clear(); FinishRecords(&download_, offline);
suspended_transactions_.clear(); FinishRecords(&upload_, offline);
Transactions old_transactions(transactions_); FinishRecords(&suspended_, offline);
Transactions::iterator it = old_transactions.begin();
for (; it != old_transactions.end(); ++it) {
if (transactions_.find(*it) == transactions_.end())
continue;
if (!(*it)->request() || (*it)->failed())
continue;
if (ShouldFail(*it))
(*it)->Fail();
}
return; return;
} }
if (conditions_->IsThrottling()) { // Throttling.
DCHECK_NE(conditions_->download_throughput(), 0); DCHECK(conditions_->download_throughput() != 0 ||
offset_ = now; conditions_->upload_throughput() != 0);
last_tick_ = 0; offset_ = now;
int64_t us_tick_length =
(1000000L * kPacketSize) / conditions_->download_throughput();
DCHECK_NE(us_tick_length, 0);
if (us_tick_length == 0)
us_tick_length = 1;
tick_length_ = base::TimeDelta::FromMicroseconds(us_tick_length);
latency_length_ = base::TimeDelta();
double latency = conditions_->latency();
if (latency > 0)
latency_length_ = base::TimeDelta::FromMillisecondsD(latency);
ArmTimer(now);
} else {
timer_.Stop();
std::vector<DevToolsNetworkTransaction*> throttled_transactions; download_last_tick_ = 0;
throttled_transactions.swap(throttled_transactions_); download_tick_length_ = CalculateTickLength(
for (auto& throttled_transaction : throttled_transactions) conditions_->download_throughput());
FireThrottledCallback(throttled_transaction);
SuspendedTransactions suspended_transactions; upload_last_tick_ = 0;
suspended_transactions.swap(suspended_transactions_); upload_tick_length_ = CalculateTickLength(conditions_->upload_throughput());
for (auto& suspended_transaction : suspended_transactions)
FireThrottledCallback(suspended_transaction.first);
}
}
void DevToolsNetworkInterceptor::AddTransaction(
DevToolsNetworkTransaction* transaction) {
DCHECK(transactions_.find(transaction) == transactions_.end());
transactions_.insert(transaction);
}
void DevToolsNetworkInterceptor::RemoveTransaction(
DevToolsNetworkTransaction* transaction) {
DCHECK(transactions_.find(transaction) != transactions_.end());
transactions_.erase(transaction);
if (!conditions_->IsThrottling())
return;
base::TimeTicks now = base::TimeTicks::Now();
UpdateThrottledTransactions(now);
throttled_transactions_.erase(std::remove(throttled_transactions_.begin(),
throttled_transactions_.end(), transaction),
throttled_transactions_.end());
SuspendedTransactions::iterator it = suspended_transactions_.begin();
for (; it != suspended_transactions_.end(); ++it) {
if (it->first == transaction) {
suspended_transactions_.erase(it);
break;
}
}
latency_length_ = base::TimeDelta();
double latency = conditions_->latency();
if (latency > 0)
latency_length_ = base::TimeDelta::FromMilliseconds(latency);
ArmTimer(now); ArmTimer(now);
} }
bool DevToolsNetworkInterceptor::ShouldFail( uint64_t DevToolsNetworkInterceptor::UpdateThrottledRecords(
const DevToolsNetworkTransaction* transaction) { base::TimeTicks now,
return conditions_->offline(); ThrottleRecords* records,
} uint64_t last_tick,
base::TimeDelta tick_length) {
bool DevToolsNetworkInterceptor::ShouldThrottle( if (tick_length.is_zero()) {
const DevToolsNetworkTransaction* transaction) { DCHECK(!records->size());
return conditions_->IsThrottling(); return last_tick;
}
void DevToolsNetworkInterceptor::ThrottleTransaction(
DevToolsNetworkTransaction* transaction, bool start) {
base::TimeTicks now = base::TimeTicks::Now();
UpdateThrottledTransactions(now);
if (start && latency_length_ != base::TimeDelta()) {
net::LoadTimingInfo load_timing_info;
base::TimeTicks send_end;
if (transaction->GetLoadTimingInfo(&load_timing_info))
send_end = load_timing_info.send_end;
if (send_end.is_null())
send_end = now;
int64_t us_send_end = (send_end - base::TimeTicks()).InMicroseconds();
suspended_transactions_.push_back(
SuspendedTransaction(transaction, us_send_end));
UpdateSuspendedTransactions(now);
} else {
throttled_transactions_.push_back(transaction);
} }
ArmTimer(now);
}
void DevToolsNetworkInterceptor::UpdateThrottledTransactions( int64_t new_tick = (now - offset_) / tick_length;
base::TimeTicks now) { int64_t ticks = new_tick - last_tick;
int64_t last_tick = (now - offset_) / tick_length_;
int64_t ticks = last_tick - last_tick_;
last_tick_ = last_tick;
int64_t length = throttled_transactions_.size(); int64_t length = records->size();
if (!length) { if (!length)
UpdateSuspendedTransactions(now); return new_tick;
return;
}
int64_t shift = ticks % length; int64_t shift = ticks % length;
for (int64_t i = 0; i < length; ++i) { for (int64_t i = 0; i < length; ++i) {
throttled_transactions_[i]->DecreaseThrottledByteCount( (*records)[i].bytes -=
(ticks / length) * kPacketSize + (i < shift ? kPacketSize : 0)); (ticks / length) * kPacketSize + (i < shift ? kPacketSize : 0);
} }
std::rotate(throttled_transactions_.begin(), std::rotate(records->begin(), records->end() + shift, records->end());
throttled_transactions_.begin() + shift, throttled_transactions_.end()); return new_tick;
UpdateSuspendedTransactions(now);
} }
void DevToolsNetworkInterceptor::UpdateSuspendedTransactions( void DevToolsNetworkInterceptor::UpdateThrottled(base::TimeTicks now) {
base::TimeTicks now) { download_last_tick_ = UpdateThrottledRecords(
now, &download_, download_last_tick_, download_tick_length_);
upload_last_tick_ = UpdateThrottledRecords(
now, &upload_, upload_last_tick_, upload_tick_length_);
UpdateSuspended(now);
}
void DevToolsNetworkInterceptor::UpdateSuspended(base::TimeTicks now) {
int64_t activation_baseline = int64_t activation_baseline =
(now - latency_length_ - base::TimeTicks()).InMicroseconds(); (now - latency_length_ - base::TimeTicks::Now()).InMicroseconds();
SuspendedTransactions suspended_transactions; ThrottleRecords suspended;
SuspendedTransactions::iterator it = suspended_transactions_.begin(); for (const ThrottleRecord& record : suspended_) {
for (; it != suspended_transactions_.end(); ++it) { if (record.send_end <= activation_baseline) {
if (it->second <= activation_baseline) if (record.is_upload)
throttled_transactions_.push_back(it->first); upload_.push_back(record);
else else
suspended_transactions.push_back(*it); download_.push_back(record);
} else {
suspended.push_back(record);
}
} }
suspended_transactions_.swap(suspended_transactions); suspended_.swap(suspended);
} }
void DevToolsNetworkInterceptor::ArmTimer(base::TimeTicks now) { void DevToolsNetworkInterceptor::CollectFinished(
size_t throttle_count = throttled_transactions_.size(); ThrottleRecords* records, ThrottleRecords* finished) {
size_t suspend_count = suspended_transactions_.size(); ThrottleRecords active;
if (!throttle_count && !suspend_count) for (const ThrottleRecord& record : *records) {
return; if (record.bytes < 0)
finished->push_back(record);
else
active.push_back(record);
}
records->swap(active);
}
void DevToolsNetworkInterceptor::OnTimer() {
base::TimeTicks now = base::TimeTicks::Now();
UpdateThrottled(now);
ThrottleRecords finished;
CollectFinished(&download_, &finished);
CollectFinished(&upload_, &finished);
for (const ThrottleRecord& record : finished)
record.callback.Run(record.result, record.bytes);
ArmTimer(now);
}
base::TimeTicks DevToolsNetworkInterceptor::CalculateDesiredTime(
const ThrottleRecords& records,
uint64_t last_tick,
base::TimeDelta tick_length) {
int64_t min_ticks_left = 0x10000L; int64_t min_ticks_left = 0x10000L;
for (size_t i = 0; i < throttle_count; ++i) { size_t count = records.size();
int64_t packets_left = (throttled_transactions_[i]->throttled_byte_count() + for (size_t i = 0; i < count; ++i) {
kPacketSize - 1) / kPacketSize; int64_t packets_left = (records[i].bytes + kPacketSize - 1) / kPacketSize;
int64_t ticks_left = (i + 1) + throttle_count * (packets_left - 1); int64_t ticks_left = (i + 1) + count * (packets_left - 1);
if (i == 0 || ticks_left < min_ticks_left) if (i == 0 || ticks_left < min_ticks_left)
min_ticks_left = ticks_left; min_ticks_left = ticks_left;
} }
return offset_ + tick_length * (last_tick + min_ticks_left);
}
base::TimeTicks desired_time = void DevToolsNetworkInterceptor::ArmTimer(base::TimeTicks now) {
offset_ + tick_length_ * (last_tick_ + min_ticks_left); size_t suspend_count = suspended_.size();
if (!download_.size() && !upload_.size() && !suspend_count)
return;
base::TimeTicks desired_time = CalculateDesiredTime(
download_, download_last_tick_, download_tick_length_);
base::TimeTicks upload_time = CalculateDesiredTime(
upload_, upload_last_tick_, upload_tick_length_);
if (upload_time < desired_time)
desired_time = upload_time;
int64_t min_baseline = std::numeric_limits<int64_t>::max(); int64_t min_baseline = std::numeric_limits<int64_t>::max();
for (size_t i = 0; i < suspend_count; ++i) { for (size_t i = 0; i < suspend_count; ++i) {
if (suspended_transactions_[i].second < min_baseline) if (suspended_[i].send_end < min_baseline)
min_baseline = suspended_transactions_[i].second; min_baseline = suspended_[i].send_end;
} }
if (suspend_count) { if (suspend_count) {
base::TimeTicks activation_time = base::TimeTicks() + base::TimeTicks activation_time = base::TimeTicks() +
base::TimeDelta::FromMicroseconds(min_baseline) + latency_length_; base::TimeDelta::FromMicroseconds(min_baseline) + latency_length_;
@ -222,34 +220,69 @@ void DevToolsNetworkInterceptor::ArmTimer(base::TimeTicks now) {
timer_.Start(FROM_HERE, desired_time - now, timer_.Start(FROM_HERE, desired_time - now,
base::Bind(&DevToolsNetworkInterceptor::OnTimer, base::Bind(&DevToolsNetworkInterceptor::OnTimer,
base::Unretained(this))); base::Unretained(this)));
} }
void DevToolsNetworkInterceptor::OnTimer() { int DevToolsNetworkInterceptor::StartThrottle(
base::TimeTicks now = base::TimeTicks::Now(); int result,
UpdateThrottledTransactions(now); int64_t bytes,
base::TimeTicks send_end,
bool start,
bool is_upload,
const ThrottleCallback& callback) {
if (result < 0)
return result;
std::vector<DevToolsNetworkTransaction*> active_transactions; if (conditions_->offline())
std::vector<DevToolsNetworkTransaction*> finished_transactions; return is_upload ? result : net::ERR_INTERNET_DISCONNECTED;
size_t length = throttled_transactions_.size();
for (size_t i = 0; i < length; ++i) { if ((is_upload && !conditions_->upload_throughput()) ||
if (throttled_transactions_[i]->throttled_byte_count() < 0) (!is_upload && !conditions_->download_throughput())) {
finished_transactions.push_back(throttled_transactions_[i]); return result;
else
active_transactions.push_back(throttled_transactions_[i]);
} }
throttled_transactions_.swap(active_transactions);
for (auto& transaction : finished_transactions) ThrottleRecord record;
FireThrottledCallback(transaction); record.result = result;
record.bytes = bytes;
record.callback = callback;
record.is_upload = is_upload;
base::TimeTicks now = base::TimeTicks::Now();
UpdateThrottled(now);
if (start && latency_length_ != base::TimeDelta()) {
record.send_end = (send_end - base::TimeTicks()).InMicroseconds();
suspended_.push_back(record);
UpdateSuspended(now);
} else {
if (is_upload)
upload_.push_back(record);
else
download_.push_back(record);
}
ArmTimer(now); ArmTimer(now);
return net::ERR_IO_PENDING;
} }
void DevToolsNetworkInterceptor::FireThrottledCallback( void DevToolsNetworkInterceptor::StopThrottle(
DevToolsNetworkTransaction* transaction) { const ThrottleCallback& callback) {
if (transactions_.find(transaction) != transactions_.end()) RemoveRecord(&download_, callback);
transaction->FireThrottledCallback(); RemoveRecord(&upload_, callback);
RemoveRecord(&suspended_, callback);
}
void DevToolsNetworkInterceptor::RemoveRecord(
ThrottleRecords* records, const ThrottleCallback& callback) {
records->erase(
std::remove_if(records->begin(), records->end(),
[&callback](const ThrottleRecord& record){
return record.callback.Equals(callback);
}),
records->end());
}
bool DevToolsNetworkInterceptor::IsOffline() {
return conditions_->offline();
} }
} // namespace brightray } // namespace brightray

View file

@ -5,7 +5,6 @@
#ifndef BROWSER_DEVTOOLS_NETWORK_INTERCEPTOR_H_ #ifndef BROWSER_DEVTOOLS_NETWORK_INTERCEPTOR_H_
#define BROWSER_DEVTOOLS_NETWORK_INTERCEPTOR_H_ #define BROWSER_DEVTOOLS_NETWORK_INTERCEPTOR_H_
#include <set>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
@ -26,6 +25,8 @@ class DevToolsNetworkTransaction;
class DevToolsNetworkInterceptor { class DevToolsNetworkInterceptor {
public: public:
using ThrottleCallback = base::Callback<void(int, int64_t)>;
DevToolsNetworkInterceptor(); DevToolsNetworkInterceptor();
virtual ~DevToolsNetworkInterceptor(); virtual ~DevToolsNetworkInterceptor();
@ -34,45 +35,68 @@ class DevToolsNetworkInterceptor {
// Applies network emulation configuration. // Applies network emulation configuration.
void UpdateConditions(scoped_ptr<DevToolsNetworkConditions> conditions); void UpdateConditions(scoped_ptr<DevToolsNetworkConditions> conditions);
void AddTransaction(DevToolsNetworkTransaction* transaction); // Throttles with |is_upload == true| always succeed, even in offline mode.
void RemoveTransaction(DevToolsNetworkTransaction* transaction); int StartThrottle(int result,
int64_t bytes,
base::TimeTicks send_end,
bool start,
bool is_upload,
const ThrottleCallback& callback);
void StopThrottle(const ThrottleCallback& callback);
// Returns whether transaction should fail with |net::ERR_INTERNET_DISCONNECTED| bool IsOffline();
bool ShouldFail(const DevToolsNetworkTransaction* transaction);
// Returns whether transaction should be throttled.
bool ShouldThrottle(const DevToolsNetworkTransaction* transaction);
void ThrottleTransaction(DevToolsNetworkTransaction* transaction, bool start);
const DevToolsNetworkConditions* conditions() const {
return conditions_.get();
}
private: private:
void UpdateThrottledTransactions(base::TimeTicks now); struct ThrottleRecord {
void UpdateSuspendedTransactions(base::TimeTicks now); public:
void ArmTimer(base::TimeTicks now); ThrottleRecord();
ThrottleRecord(const ThrottleRecord& other);
~ThrottleRecord();
int result;
int64_t bytes;
int64_t send_end;
bool is_upload;
ThrottleCallback callback;
};
using ThrottleRecords = std::vector<ThrottleRecord>;
void FinishRecords(ThrottleRecords* records, bool offline);
uint64_t UpdateThrottledRecords(base::TimeTicks now,
ThrottleRecords* records,
uint64_t last_tick,
base::TimeDelta tick_length);
void UpdateThrottled(base::TimeTicks now);
void UpdateSuspended(base::TimeTicks now);
void CollectFinished(ThrottleRecords* records, ThrottleRecords* finished);
void OnTimer(); void OnTimer();
void FireThrottledCallback(DevToolsNetworkTransaction* transaction);
base::TimeTicks CalculateDesiredTime(const ThrottleRecords& records,
uint64_t last_tick,
base::TimeDelta tick_length);
void ArmTimer(base::TimeTicks now);
void RemoveRecord(ThrottleRecords* records, const ThrottleCallback& callback);
scoped_ptr<DevToolsNetworkConditions> conditions_; scoped_ptr<DevToolsNetworkConditions> conditions_;
using Transactions = std::set<DevToolsNetworkTransaction*>; // Throttables suspended for a "latency" period.
Transactions transactions_; ThrottleRecords suspended_;
// Transactions suspended for a latency period. // Throttables waiting for certain amount of transfer to be "accounted".
using SuspendedTransaction = std::pair<DevToolsNetworkTransaction*, int64_t>; ThrottleRecords download_;
using SuspendedTransactions = std::vector<SuspendedTransaction>; ThrottleRecords upload_;
SuspendedTransactions suspended_transactions_;
// Transactions waiting certain amount of transfer to be accounted.
std::vector<DevToolsNetworkTransaction*> throttled_transactions_;
base::OneShotTimer timer_; base::OneShotTimer timer_;
base::TimeTicks offset_; base::TimeTicks offset_;
base::TimeDelta tick_length_; base::TimeDelta download_tick_length_;
base::TimeDelta upload_tick_length_;
base::TimeDelta latency_length_; base::TimeDelta latency_length_;
uint64_t last_tick_; uint64_t download_last_tick_;
uint64_t upload_last_tick_;
base::WeakPtrFactory<DevToolsNetworkInterceptor> weak_ptr_factory_; base::WeakPtrFactory<DevToolsNetworkInterceptor> weak_ptr_factory_;

View file

@ -112,6 +112,15 @@ base::DictionaryValue* DevToolsNetworkProtocolHandler::HandleCommand(
return nullptr; return nullptr;
} }
void DevToolsNetworkProtocolHandler::DevToolsAgentStateChanged(
content::DevToolsAgentHost* agent_host,
bool attached) {
scoped_ptr<DevToolsNetworkConditions> conditions;
if (attached)
conditions.reset(new DevToolsNetworkConditions(false));
UpdateNetworkState(agent_host, std::move(conditions));
}
scoped_ptr<base::DictionaryValue> scoped_ptr<base::DictionaryValue>
DevToolsNetworkProtocolHandler::CanEmulateNetworkConditions( DevToolsNetworkProtocolHandler::CanEmulateNetworkConditions(
content::DevToolsAgentHost* agent_host, content::DevToolsAgentHost* agent_host,

View file

@ -25,6 +25,8 @@ class DevToolsNetworkProtocolHandler {
base::DictionaryValue* HandleCommand( base::DictionaryValue* HandleCommand(
content::DevToolsAgentHost* agent_host, content::DevToolsAgentHost* agent_host,
base::DictionaryValue* command); base::DictionaryValue* command);
void DevToolsAgentStateChanged(content::DevToolsAgentHost* agent_host,
bool attached);
private: private:
scoped_ptr<base::DictionaryValue> CanEmulateNetworkConditions( scoped_ptr<base::DictionaryValue> CanEmulateNetworkConditions(

View file

@ -5,8 +5,8 @@
#include "browser/net/devtools_network_transaction.h" #include "browser/net/devtools_network_transaction.h"
#include "browser/net/devtools_network_controller.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/net_errors.h"
#include "net/base/upload_progress.h" #include "net/base/upload_progress.h"
#include "net/http/http_network_transaction.h" #include "net/http/http_network_transaction.h"
@ -23,58 +23,84 @@ const char
DevToolsNetworkTransaction::DevToolsNetworkTransaction( DevToolsNetworkTransaction::DevToolsNetworkTransaction(
DevToolsNetworkController* controller, DevToolsNetworkController* controller,
scoped_ptr<net::HttpTransaction> transaction) scoped_ptr<net::HttpTransaction> transaction)
: controller_(controller), : throttled_byte_count_(0),
controller_(controller),
transaction_(std::move(transaction)), transaction_(std::move(transaction)),
request_(nullptr), request_(nullptr),
failed_(false), failed_(false) {
throttled_byte_count_(0), DCHECK(controller);
callback_type_(NONE) {
proxy_callback_ = base::Bind(&DevToolsNetworkTransaction::OnCallback,
base::Unretained(this));
} }
DevToolsNetworkTransaction::~DevToolsNetworkTransaction() { DevToolsNetworkTransaction::~DevToolsNetworkTransaction() {
if (interceptor_) if (interceptor_ && !throttle_callback_.is_null())
interceptor_->RemoveTransaction(this); interceptor_->StopThrottle(throttle_callback_);
} }
void DevToolsNetworkTransaction::ProcessRequest() { void DevToolsNetworkTransaction::IOCallback(
DCHECK(request_); 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( int DevToolsNetworkTransaction::Throttle(
kDevToolsEmulateNetworkConditionsClientId); const net::CompletionCallback& callback, bool start, int result) {
if (!has_devtools_client_id) if (failed_)
return; return net::ERR_INTERNET_DISCONNECTED;
if (!interceptor_ || result < 0)
return result;
custom_request_.reset(new net::HttpRequestInfo(*request_)); base::TimeTicks send_end;
custom_request_->extra_headers.GetHeader( if (start) {
kDevToolsEmulateNetworkConditionsClientId, &client_id_); throttled_byte_count_ += transaction_->GetTotalReceivedBytes();
custom_request_->extra_headers.RemoveHeader( net::LoadTimingInfo load_timing_info;
kDevToolsEmulateNetworkConditionsClientId); 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() { void DevToolsNetworkTransaction::Fail() {
DCHECK(request_); DCHECK(request_);
DCHECK(!failed_); DCHECK(!failed_);
failed_ = true; failed_ = true;
transaction_->SetBeforeNetworkStartCallback( transaction_->SetBeforeNetworkStartCallback(BeforeNetworkStartCallback());
BeforeNetworkStartCallback()); if (interceptor_)
interceptor_.reset();
if (callback_.is_null())
return;
net::CompletionCallback original_callback = callback_;
callback_.Reset();
callback_type_ = NONE;
original_callback.Run(net::ERR_INTERNET_DISCONNECTED);
} }
void DevToolsNetworkTransaction::DecreaseThrottledByteCount( bool DevToolsNetworkTransaction::CheckFailed() {
int64_t delta) { if (failed_)
throttled_byte_count_ -= delta; return true;
if (interceptor_ && interceptor_->IsOffline()) {
Fail();
return true;
}
return false;
} }
int DevToolsNetworkTransaction::Start( int DevToolsNetworkTransaction::Start(
@ -82,45 +108,90 @@ int DevToolsNetworkTransaction::Start(
const net::CompletionCallback& callback, const net::CompletionCallback& callback,
const net::BoundNetLog& net_log) { const net::BoundNetLog& net_log) {
DCHECK(request); DCHECK(request);
request_ = request; request_ = request;
interceptor_ = controller_->GetInterceptor(this);
interceptor_->AddTransaction(this);
if (interceptor_->ShouldFail(this)) { std::string client_id;
failed_ = true; bool has_devtools_client_id = request_->extra_headers.HasHeader(
transaction_->SetBeforeNetworkStartCallback(BeforeNetworkStartCallback()); kDevToolsEmulateNetworkConditionsClientId);
return net::ERR_INTERNET_DISCONNECTED; 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( int DevToolsNetworkTransaction::RestartIgnoringLastError(
const net::CompletionCallback& callback) { const net::CompletionCallback& callback) {
if (failed_) if (CheckFailed())
return net::ERR_INTERNET_DISCONNECTED; return net::ERR_INTERNET_DISCONNECTED;
int rv = transaction_->RestartIgnoringLastError(proxy_callback_); if (!interceptor_)
return SetupCallback(callback, rv, RESTART_IGNORING_LAST_ERROR); 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( int DevToolsNetworkTransaction::RestartWithCertificate(
net::X509Certificate* client_certificate, net::X509Certificate* client_cert,
net::SSLPrivateKey* client_private_key, net::SSLPrivateKey* client_private_key,
const net::CompletionCallback& callback) { const net::CompletionCallback& callback) {
if (failed_) if (CheckFailed())
return net::ERR_INTERNET_DISCONNECTED; return net::ERR_INTERNET_DISCONNECTED;
int rv = transaction_->RestartWithCertificate(client_certificate, client_private_key, proxy_callback_); if (!interceptor_) {
return SetupCallback(callback, rv, RESTART_WITH_CERTIFICATE); 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( int DevToolsNetworkTransaction::RestartWithAuth(
const net::AuthCredentials& credentials, const net::AuthCredentials& credentials,
const net::CompletionCallback& callback) { const net::CompletionCallback& callback) {
if (failed_) if (CheckFailed())
return net::ERR_INTERNET_DISCONNECTED; return net::ERR_INTERNET_DISCONNECTED;
int rv = transaction_->RestartWithAuth(credentials, proxy_callback_); if (!interceptor_)
return SetupCallback(callback, rv, RESTART_WITH_AUTH); 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() { bool DevToolsNetworkTransaction::IsReadyToRestartForAuth() {
@ -128,13 +199,21 @@ bool DevToolsNetworkTransaction::IsReadyToRestartForAuth() {
} }
int DevToolsNetworkTransaction::Read( int DevToolsNetworkTransaction::Read(
net::IOBuffer* buffer, net::IOBuffer* buf,
int length, int buf_len,
const net::CompletionCallback& callback) { const net::CompletionCallback& callback) {
if (failed_) if (CheckFailed())
return net::ERR_INTERNET_DISCONNECTED; return net::ERR_INTERNET_DISCONNECTED;
int rv = transaction_->Read(buffer, length, proxy_callback_); if (!interceptor_)
return SetupCallback(callback, rv, READ); 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() { void DevToolsNetworkTransaction::StopCaching() {
@ -221,76 +300,4 @@ void DevToolsNetworkTransaction::GetConnectionAttempts(
transaction_->GetConnectionAttempts(out); 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 } // namespace brightray

View file

@ -9,6 +9,7 @@
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "browser/net/devtools_network_interceptor.h"
#include "net/base/completion_callback.h" #include "net/base/completion_callback.h"
#include "net/base/load_states.h" #include "net/base/load_states.h"
#include "net/base/request_priority.h" #include "net/base/request_priority.h"
@ -18,7 +19,7 @@
namespace brightray { namespace brightray {
class DevToolsNetworkController; class DevToolsNetworkController;
class DevToolsNetworkInterceptor; class DevToolsNetworkUploadDataStream;
class DevToolsNetworkTransaction : public net::HttpTransaction { class DevToolsNetworkTransaction : public net::HttpTransaction {
public: public:
@ -29,16 +30,6 @@ class DevToolsNetworkTransaction : public net::HttpTransaction {
scoped_ptr<net::HttpTransaction> network_transaction); scoped_ptr<net::HttpTransaction> network_transaction);
~DevToolsNetworkTransaction() override; ~DevToolsNetworkTransaction() override;
// Checks if request contains DevTools specific headers. Found values are
// remembered and corresponding keys are removed from headers.
void ProcessRequest();
// Runs callback with net::ERR_INTERNET_DISCONNECTED result.
void Fail();
void DecreaseThrottledByteCount(int64_t delta);
void FireThrottledCallback();
// HttpTransaction methods: // HttpTransaction methods:
int Start(const net::HttpRequestInfo* request, int Start(const net::HttpRequestInfo* request,
const net::CompletionCallback& callback, const net::CompletionCallback& callback,
@ -77,39 +68,30 @@ class DevToolsNetworkTransaction : public net::HttpTransaction {
int ResumeNetworkStart() override; int ResumeNetworkStart() override;
void GetConnectionAttempts(net::ConnectionAttempts* out) const override; void GetConnectionAttempts(net::ConnectionAttempts* out) const override;
bool failed() const { return failed_; }
const net::HttpRequestInfo* request() const { return request_; }
int64_t throttled_byte_count() const { return throttled_byte_count_; }
const std::string& client_id() const {
return client_id_;
}
private: private:
enum CallbackType { void Fail();
NONE, bool CheckFailed();
READ,
RESTART_IGNORING_LAST_ERROR,
RESTART_WITH_AUTH,
RESTART_WITH_CERTIFICATE,
START
};
// Proxy callback handler. Runs saved callback. void IOCallback(const net::CompletionCallback& callback,
void OnCallback(int result); bool start,
int result);
int Throttle(const net::CompletionCallback& callback,
bool start,
int result);
void ThrottleCallback(const net::CompletionCallback& callback,
int result,
int64_t bytes);
int SetupCallback( DevToolsNetworkInterceptor::ThrottleCallback throttle_callback_;
net::CompletionCallback callback, int64_t throttled_byte_count_;
int result,
CallbackType callback_type);
void Throttle(int result);
DevToolsNetworkController* controller_; DevToolsNetworkController* controller_;
base::WeakPtr<DevToolsNetworkInterceptor> interceptor_; base::WeakPtr<DevToolsNetworkInterceptor> interceptor_;
// Modified request. Should be destructed after |transaction_| // Modified upload data stream. Should be destructed after |custom_request_|.
scoped_ptr<DevToolsNetworkUploadDataStream> custom_upload_data_stream_;
// Modified request. Should be destructed after |transaction_|.
scoped_ptr<net::HttpRequestInfo> custom_request_; scoped_ptr<net::HttpRequestInfo> custom_request_;
// Original network transaction. // Original network transaction.
@ -120,15 +102,6 @@ class DevToolsNetworkTransaction : public net::HttpTransaction {
// True if Fail was already invoked. // True if Fail was already invoked.
bool failed_; bool failed_;
// Value of "X-DevTools-Emulate-Network-Conditions-Client-Id" request header.
std::string client_id_;
int throttled_result_;
int64_t throttled_byte_count_;
CallbackType callback_type_;
net::CompletionCallback proxy_callback_;
net::CompletionCallback callback_;
DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkTransaction); DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkTransaction);
}; };

View file

@ -0,0 +1,94 @@
// Copyright 2015 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 "browser/net/devtools_network_upload_data_stream.h"
#include "net/base/net_errors.h"
namespace brightray {
DevToolsNetworkUploadDataStream::DevToolsNetworkUploadDataStream(
net::UploadDataStream* upload_data_stream)
: net::UploadDataStream(upload_data_stream->is_chunked(),
upload_data_stream->identifier()),
throttle_callback_(
base::Bind(&DevToolsNetworkUploadDataStream::ThrottleCallback,
base::Unretained(this))),
throttled_byte_count_(0),
upload_data_stream_(upload_data_stream) {
}
DevToolsNetworkUploadDataStream::~DevToolsNetworkUploadDataStream() {
if (interceptor_)
interceptor_->StopThrottle(throttle_callback_);
}
void DevToolsNetworkUploadDataStream::SetInterceptor(
DevToolsNetworkInterceptor* interceptor) {
DCHECK(!interceptor_);
if (interceptor)
interceptor_ = interceptor->GetWeakPtr();
}
bool DevToolsNetworkUploadDataStream::IsInMemory() const {
return false;
}
int DevToolsNetworkUploadDataStream::InitInternal() {
throttled_byte_count_ = 0;
int result = upload_data_stream_->Init(
base::Bind(&DevToolsNetworkUploadDataStream::StreamInitCallback,
base::Unretained(this)));
if (result == net::OK && !is_chunked())
SetSize(upload_data_stream_->size());
return result;
}
void DevToolsNetworkUploadDataStream::StreamInitCallback(int result) {
if (!is_chunked())
SetSize(upload_data_stream_->size());
OnInitCompleted(result);
}
int DevToolsNetworkUploadDataStream::ReadInternal(
net::IOBuffer* buf, int buf_len) {
int result = upload_data_stream_->Read(buf, buf_len,
base::Bind(&DevToolsNetworkUploadDataStream::StreamReadCallback,
base::Unretained(this)));
return ThrottleRead(result);
}
void DevToolsNetworkUploadDataStream::StreamReadCallback(int result) {
result = ThrottleRead(result);
if (result != net::ERR_IO_PENDING)
OnReadCompleted(result);
}
int DevToolsNetworkUploadDataStream::ThrottleRead(int result) {
if (is_chunked() && upload_data_stream_->IsEOF())
SetIsFinalChunk();
if (!interceptor_ || result < 0)
return result;
if (result > 0)
throttled_byte_count_ += result;
return interceptor_->StartThrottle(result, throttled_byte_count_,
base::TimeTicks(), false, true, throttle_callback_);
}
void DevToolsNetworkUploadDataStream::ThrottleCallback(
int result, int64_t bytes) {
throttled_byte_count_ = bytes;
OnReadCompleted(result);
}
void DevToolsNetworkUploadDataStream::ResetInternal() {
upload_data_stream_->Reset();
throttled_byte_count_ = 0;
if (interceptor_)
interceptor_->StopThrottle(throttle_callback_);
}
} // namespace brightray

View file

@ -0,0 +1,51 @@
// Copyright 2015 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.
#ifndef BROWSER_DEVTOOLS_NETWORK_UPLOAD_DATA_STREAM_H_
#define BROWSER_DEVTOOLS_NETWORK_UPLOAD_DATA_STREAM_H_
#include <stdint.h>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "browser/net/devtools_network_interceptor.h"
#include "net/base/completion_callback.h"
#include "net/base/upload_data_stream.h"
namespace brightray {
class DevToolsNetworkUploadDataStream : public net::UploadDataStream {
public:
// Supplied |upload_data_stream| must outlive this object.
explicit DevToolsNetworkUploadDataStream(
net::UploadDataStream* upload_data_stream);
~DevToolsNetworkUploadDataStream() override;
void SetInterceptor(DevToolsNetworkInterceptor* interceptor);
private:
// net::UploadDataStream implementation.
bool IsInMemory() const override;
int InitInternal() override;
int ReadInternal(net::IOBuffer* buf, int buf_len) override;
void ResetInternal() override;
void StreamInitCallback(int result);
void StreamReadCallback(int result);
int ThrottleRead(int result);
void ThrottleCallback(int result, int64_t bytes);
DevToolsNetworkInterceptor::ThrottleCallback throttle_callback_;
int64_t throttled_byte_count_;
net::UploadDataStream* upload_data_stream_;
base::WeakPtr<DevToolsNetworkInterceptor> interceptor_;
DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkUploadDataStream);
};
} // namespace brightray
#endif // BROWSER_DEVTOOLS_NETWORK_UPLOAD_DATA_STREAM_H_

View file

@ -53,6 +53,8 @@
'browser/net/devtools_network_transaction_factory.h', 'browser/net/devtools_network_transaction_factory.h',
'browser/net/devtools_network_transaction.cc', 'browser/net/devtools_network_transaction.cc',
'browser/net/devtools_network_transaction.h', 'browser/net/devtools_network_transaction.h',
'browser/net/devtools_network_upload_data_stream.cc',
'browser/net/devtools_network_upload_data_stream.h',
'browser/net_log.cc', 'browser/net_log.cc',
'browser/net_log.h', 'browser/net_log.h',
'browser/network_delegate.cc', 'browser/network_delegate.cc',