Commit 60c5dad3 authored by eustas@chromium.org's avatar eustas@chromium.org

DevTools: make network conditions emulation scoped (browser)

Currently network conditions are applied browser-wide.

To restrict conditions to one tab requests are marked with specific
headers.

Those specific headers are removed before sending headers to network.

BUG=245436

Review URL: https://codereview.chromium.org/342473004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278109 0039d316-1c4b-4281-b951-d872f2087c98
parent 01db472d
...@@ -61,9 +61,15 @@ base::DictionaryValue* ChromeDevToolsManagerDelegate::HandleCommand( ...@@ -61,9 +61,15 @@ base::DictionaryValue* ChromeDevToolsManagerDelegate::HandleCommand(
DevToolsProtocol::ParseCommand(command_dict)); DevToolsProtocol::ParseCommand(command_dict));
if (!command) if (!command)
return NULL; return NULL;
const std::string method = command->method(); const std::string method = command->method();
scoped_ptr<DevToolsProtocol::Response> response;
if (method == chrome::devtools::Network::emulateNetworkConditions::kName) if (method == chrome::devtools::Network::emulateNetworkConditions::kName)
return EmulateNetworkConditions(agent_host, command.get())->Serialize(); response = EmulateNetworkConditions(agent_host, command.get());
if (response)
return response->Serialize();
return NULL; return NULL;
} }
...@@ -81,41 +87,35 @@ ChromeDevToolsManagerDelegate::EmulateNetworkConditions( ...@@ -81,41 +87,35 @@ ChromeDevToolsManagerDelegate::EmulateNetworkConditions(
content::DevToolsAgentHost* agent_host, content::DevToolsAgentHost* agent_host,
DevToolsProtocol::Command* command) { DevToolsProtocol::Command* command) {
base::DictionaryValue* params = command->params(); base::DictionaryValue* params = command->params();
namespace names = ::chrome::devtools::Network::emulateNetworkConditions;
std::vector<std::string> domains;
base::ListValue* domain_list = NULL;
const char* domains_param =
chrome::devtools::Network::emulateNetworkConditions::kParamDomains;
if (!params || !params->GetList(domains_param, &domain_list))
return command->InvalidParamResponse(domains_param);
size_t size = domain_list->GetSize();
for (size_t i = 0; i < size; ++i) {
std::string domain;
if (!domain_list->GetString(i, &domain))
return command->InvalidParamResponse(domains_param);
domains.push_back(domain);
}
bool offline = false; bool offline = false;
const char* offline_param = if (!params || !params->GetBoolean(names::kParamOffline, &offline))
chrome::devtools::Network::emulateNetworkConditions::kParamOffline; return command->InvalidParamResponse(names::kParamOffline);
if (!params->GetBoolean(offline_param, &offline))
return command->InvalidParamResponse(offline_param); double latency = 0.0;
if (!params->GetDouble(names::kParamLatency, &latency))
double maximal_throughput = 0.0; return command->InvalidParamResponse(names::kParamLatency);
const char* maximal_throughput_param = if (latency < 0.0)
chrome::devtools::Network::emulateNetworkConditions::kParamMaximalThroughput; latency = 0.0;
if (!params->GetDouble(maximal_throughput_param, &maximal_throughput))
return command->InvalidParamResponse(maximal_throughput_param); double download_throughput = 0.0;
if (maximal_throughput < 0.0) if (!params->GetDouble(names::kParamDownloadThroughput, &download_throughput))
maximal_throughput = 0.0; return command->InvalidParamResponse(names::kParamDownloadThroughput);
if (download_throughput < 0.0)
download_throughput = 0.0;
double upload_throughput = 0.0;
if (!params->GetDouble(names::kParamUploadThroughput, &upload_throughput))
return command->InvalidParamResponse(names::kParamUploadThroughput);
if (upload_throughput < 0.0)
upload_throughput = 0.0;
EnsureDevtoolsCallbackRegistered(); EnsureDevtoolsCallbackRegistered();
scoped_refptr<DevToolsNetworkConditions> conditions; scoped_refptr<DevToolsNetworkConditions> conditions(
if (offline || maximal_throughput) new DevToolsNetworkConditions(
conditions = new DevToolsNetworkConditions(domains, maximal_throughput); offline, latency, download_throughput, upload_throughput));
emulate_network_conditions_client_id_ = agent_host->GetId();
UpdateNetworkState(agent_host, conditions); UpdateNetworkState(agent_host, conditions);
return command->SuccessResponse(NULL); return command->SuccessResponse(NULL);
} }
...@@ -126,14 +126,15 @@ void ChromeDevToolsManagerDelegate::UpdateNetworkState( ...@@ -126,14 +126,15 @@ void ChromeDevToolsManagerDelegate::UpdateNetworkState(
Profile* profile = GetProfile(agent_host); Profile* profile = GetProfile(agent_host);
if (!profile) if (!profile)
return; return;
profile->GetDevToolsNetworkController()->SetNetworkState(conditions); profile->GetDevToolsNetworkController()->SetNetworkState(
agent_host->GetId(), conditions);
} }
void ChromeDevToolsManagerDelegate::OnDevToolsStateChanged( void ChromeDevToolsManagerDelegate::OnDevToolsStateChanged(
content::DevToolsAgentHost* agent_host, content::DevToolsAgentHost* agent_host,
bool attached) { bool attached) {
if (agent_host->GetId() == emulate_network_conditions_client_id_) { scoped_refptr<DevToolsNetworkConditions> conditions;
emulate_network_conditions_client_id_ = std::string(); if (attached)
UpdateNetworkState(agent_host, scoped_refptr<DevToolsNetworkConditions>()); conditions = new DevToolsNetworkConditions();
} UpdateNetworkState(agent_host, conditions);
} }
...@@ -37,7 +37,6 @@ class ChromeDevToolsManagerDelegate : public content::DevToolsManagerDelegate { ...@@ -37,7 +37,6 @@ class ChromeDevToolsManagerDelegate : public content::DevToolsManagerDelegate {
scoped_ptr<DevToolsProtocol::Response> EmulateNetworkConditions( scoped_ptr<DevToolsProtocol::Response> EmulateNetworkConditions(
content::DevToolsAgentHost* agent_host, content::DevToolsAgentHost* agent_host,
DevToolsProtocol::Command* command); DevToolsProtocol::Command* command);
std::string emulate_network_conditions_client_id_;
void UpdateNetworkState( void UpdateNetworkState(
content::DevToolsAgentHost* agent_host, content::DevToolsAgentHost* agent_host,
......
...@@ -6,31 +6,35 @@ ...@@ -6,31 +6,35 @@
#include "url/gurl.h" #include "url/gurl.h"
DevToolsNetworkConditions::DevToolsNetworkConditions( DevToolsNetworkConditions::DevToolsNetworkConditions()
const std::vector<std::string>& domains, : offline_(false),
double maximal_throughput) latency_(0),
: domains_(domains), download_throughput_(0),
maximal_throughput_(maximal_throughput) { upload_throughput_(0) {
} }
DevToolsNetworkConditions::~DevToolsNetworkConditions() { DevToolsNetworkConditions::DevToolsNetworkConditions(bool offline)
: offline_(offline),
latency_(0),
download_throughput_(0),
upload_throughput_(0) {
} }
bool DevToolsNetworkConditions::HasMatchingDomain(const GURL& url) const { DevToolsNetworkConditions::DevToolsNetworkConditions(
Domains::const_iterator domain = domains_.begin(); bool offline,
if (domain == domains_.end()) double latency,
return true; double download_throughput,
for (; domain != domains_.end(); ++domain) { double upload_throughput)
if (url.DomainIs(domain->data())) : offline_(offline),
return true; latency_(latency),
} download_throughput_(download_throughput),
return false; upload_throughput_(upload_throughput) {
} }
bool DevToolsNetworkConditions::IsOffline() const { DevToolsNetworkConditions::~DevToolsNetworkConditions() {
return maximal_throughput_ == 0.0;
} }
bool DevToolsNetworkConditions::IsThrottling() const { bool DevToolsNetworkConditions::IsThrottling() const {
return maximal_throughput_ != 0.0; return (latency_ != 0) || (download_throughput_ != 0.0) ||
(upload_throughput_ != 0);
} }
...@@ -16,24 +16,29 @@ class GURL; ...@@ -16,24 +16,29 @@ class GURL;
class DevToolsNetworkConditions class DevToolsNetworkConditions
: public base::RefCounted<DevToolsNetworkConditions> { : public base::RefCounted<DevToolsNetworkConditions> {
public: public:
DevToolsNetworkConditions(const std::vector<std::string>& domains, DevToolsNetworkConditions();
double maximal_throughput); explicit DevToolsNetworkConditions(bool offline);
DevToolsNetworkConditions(bool offline,
double latency,
double download_throughput,
double upload_throughput);
bool HasMatchingDomain(const GURL& url) const;
bool IsOffline() const;
bool IsThrottling() const; bool IsThrottling() const;
double maximal_throughput() const { return maximal_throughput_; } bool offline() const { return offline_; }
double latency() const { return latency_; }
double download_throughput() const { return download_throughput_; }
double upload_throughput() const { return upload_throughput_; }
private: private:
friend class base::RefCounted<DevToolsNetworkConditions>; friend class base::RefCounted<DevToolsNetworkConditions>;
virtual ~DevToolsNetworkConditions(); virtual ~DevToolsNetworkConditions();
// List of domains that will be affected by network conditions. const bool offline_;
typedef std::vector<std::string> Domains; const double latency_;
const Domains domains_; const double download_throughput_;
const double maximal_throughput_; const double upload_throughput_;
DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkConditions); DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkConditions);
}; };
......
...@@ -4,52 +4,52 @@ ...@@ -4,52 +4,52 @@
#include "chrome/browser/devtools/devtools_network_controller.h" #include "chrome/browser/devtools/devtools_network_controller.h"
#include "base/time/time.h"
#include "chrome/browser/devtools/devtools_network_conditions.h" #include "chrome/browser/devtools/devtools_network_conditions.h"
#include "chrome/browser/devtools/devtools_network_interceptor.h"
#include "chrome/browser/devtools/devtools_network_transaction.h" #include "chrome/browser/devtools/devtools_network_transaction.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_io_data.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/resource_context.h" #include "net/base/load_flags.h"
#include "net/http/http_request_info.h"
using content::BrowserThread; using content::BrowserThread;
namespace {
const char kDevToolsRequestInitiator[] = "X-DevTools-Request-Initiator";
int64_t kPacketSize = 1500;
} // namespace
DevToolsNetworkController::DevToolsNetworkController() DevToolsNetworkController::DevToolsNetworkController()
: weak_ptr_factory_(this) { : default_interceptor_(new DevToolsNetworkInterceptor()),
appcache_interceptor_(new DevToolsNetworkInterceptor()),
weak_ptr_factory_(this) {
} }
DevToolsNetworkController::~DevToolsNetworkController() { DevToolsNetworkController::~DevToolsNetworkController() {
} }
void DevToolsNetworkController::AddTransaction( base::WeakPtr<DevToolsNetworkInterceptor>
DevToolsNetworkController::GetInterceptor(
DevToolsNetworkTransaction* transaction) { DevToolsNetworkTransaction* transaction) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
transactions_.insert(transaction); DCHECK(transaction->request());
}
void DevToolsNetworkController::RemoveTransaction( if (!interceptors_.size())
DevToolsNetworkTransaction* transaction) { return default_interceptor_->GetWeakPtr();
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(transactions_.find(transaction) != transactions_.end()); if (transaction->request()->load_flags & net::LOAD_DISABLE_INTERCEPT)
transactions_.erase(transaction); return appcache_interceptor_->GetWeakPtr();
if (conditions_ && conditions_->IsThrottling()) { transaction->ProcessRequest();
UpdateThrottles();
throttled_transactions_.erase(std::remove(throttled_transactions_.begin(), const std::string& client_id = transaction->client_id();
throttled_transactions_.end(), transaction), if (client_id.empty())
throttled_transactions_.end()); return default_interceptor_->GetWeakPtr();
ArmTimer();
} DevToolsNetworkInterceptor* interceptor = interceptors_.get(client_id);
DCHECK(interceptor);
if (!interceptor)
return default_interceptor_->GetWeakPtr();
return interceptor->GetWeakPtr();
} }
void DevToolsNetworkController::SetNetworkState( void DevToolsNetworkController::SetNetworkState(
const std::string& client_id,
const scoped_refptr<DevToolsNetworkConditions> conditions) { const scoped_refptr<DevToolsNetworkConditions> conditions) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserThread::PostTask( BrowserThread::PostTask(
...@@ -58,146 +58,47 @@ void DevToolsNetworkController::SetNetworkState( ...@@ -58,146 +58,47 @@ void DevToolsNetworkController::SetNetworkState(
base::Bind( base::Bind(
&DevToolsNetworkController::SetNetworkStateOnIO, &DevToolsNetworkController::SetNetworkStateOnIO,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr(),
client_id,
conditions)); conditions));
} }
void DevToolsNetworkController::SetNetworkStateOnIO( void DevToolsNetworkController::SetNetworkStateOnIO(
const std::string& client_id,
const scoped_refptr<DevToolsNetworkConditions> conditions) { const scoped_refptr<DevToolsNetworkConditions> conditions) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
if (conditions_ && conditions_->IsThrottling())
UpdateThrottles();
conditions_ = conditions;
if (!conditions || !(conditions->IsThrottling() || conditions->IsOffline())) {
timer_.Stop();
int64_t length = throttled_transactions_.size();
for (int64_t i = 0; i < length; ++i)
throttled_transactions_[i]->FireThrottledCallback();
throttled_transactions_.clear();
}
if (!conditions) DevToolsNetworkInterceptor* interceptor = interceptors_.get(client_id);
return; if (!interceptor) {
DCHECK(conditions);
if (conditions_->IsOffline()) { if (!conditions)
// Iterate over a copy of set, because failing of transaction could return;
// result in creating a new one, or (theoretically) destroying one. Interceptor new_interceptor = Interceptor(new DevToolsNetworkInterceptor());
Transactions old_transactions(transactions_); new_interceptor->UpdateConditions(conditions);
for (Transactions::iterator it = old_transactions.begin(); interceptors_.set(client_id, new_interceptor.Pass());
it != old_transactions.end(); ++it) { } else {
if (transactions_.find(*it) == transactions_.end()) if (!conditions) {
continue; scoped_refptr<DevToolsNetworkConditions> online_conditions(
if (!(*it)->request() || (*it)->failed()) new DevToolsNetworkConditions());
continue; interceptor->UpdateConditions(online_conditions);
if (ShouldFail((*it)->request())) interceptors_.erase(client_id);
(*it)->Fail(); } else {
interceptor->UpdateConditions(conditions);
} }
} }
if (conditions_->IsThrottling()) { bool has_offline_interceptors = false;
DCHECK(conditions_->maximal_throughput() != 0); Interceptors::iterator it = interceptors_.begin();
offset_ = base::TimeTicks::Now(); for (; it != interceptors_.end(); ++it) {
last_tick_ = 0; if (it->second->conditions()->offline()) {
int64_t us_tick_length = has_offline_interceptors = true;
(1000000L * kPacketSize) / conditions_->maximal_throughput(); break;
DCHECK(us_tick_length != 0); }
if (us_tick_length == 0)
us_tick_length = 1;
tick_length_ = base::TimeDelta::FromMicroseconds(us_tick_length);
ArmTimer();
}
}
bool DevToolsNetworkController::ShouldFail(
const net::HttpRequestInfo* request) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(request);
if (!conditions_ || !conditions_->IsOffline())
return false;
if (!conditions_->HasMatchingDomain(request->url))
return false;
return !request->extra_headers.HasHeader(kDevToolsRequestInitiator);
}
bool DevToolsNetworkController::ShouldThrottle(
const net::HttpRequestInfo* request) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(request);
if (!conditions_ || !conditions_->IsThrottling())
return false;
if (!conditions_->HasMatchingDomain(request->url))
return false;
return !request->extra_headers.HasHeader(kDevToolsRequestInitiator);
}
void DevToolsNetworkController::UpdateThrottles() {
int64_t last_tick = (base::TimeTicks::Now() - offset_) / tick_length_;
int64_t ticks = last_tick - last_tick_;
last_tick_ = last_tick;
int64_t length = throttled_transactions_.size();
if (!length)
return;
int64_t shift = ticks % length;
for (int64_t i = 0; i < length; ++i) {
throttled_transactions_[i]->DecreaseThrottledByteCount(
(ticks / length) * kPacketSize + (i < shift ? kPacketSize : 0));
}
std::rotate(throttled_transactions_.begin(),
throttled_transactions_.begin() + shift, throttled_transactions_.end());
}
void DevToolsNetworkController::OnTimer() {
UpdateThrottles();
std::vector<DevToolsNetworkTransaction*> active_transactions;
std::vector<DevToolsNetworkTransaction*> finished_transactions;
size_t length = throttled_transactions_.size();
for (size_t i = 0; i < length; ++i) {
if (throttled_transactions_[i]->throttled_byte_count() < 0)
finished_transactions.push_back(throttled_transactions_[i]);
else
active_transactions.push_back(throttled_transactions_[i]);
} }
throttled_transactions_.swap(active_transactions);
length = finished_transactions.size();
for (size_t i = 0; i < length; ++i)
finished_transactions[i]->FireThrottledCallback();
ArmTimer();
}
void DevToolsNetworkController::ArmTimer() { bool is_appcache_offline = appcache_interceptor_->conditions()->offline();
size_t length = throttled_transactions_.size(); if (is_appcache_offline != has_offline_interceptors) {
if (!length) scoped_refptr<DevToolsNetworkConditions> appcache_conditions(
return; new DevToolsNetworkConditions(has_offline_interceptors));
int64_t min_ticks_left = 0x10000L; appcache_interceptor_->UpdateConditions(appcache_conditions);
for (size_t i = 0; i < length; ++i) {
int64_t packets_left = (throttled_transactions_[i]->throttled_byte_count() +
kPacketSize - 1) / kPacketSize;
int64_t ticks_left = (i + 1) + length * (packets_left - 1);
if (i == 0 || ticks_left < min_ticks_left)
min_ticks_left = ticks_left;
} }
base::TimeTicks desired_time =
offset_ + tick_length_ * (last_tick_ + min_ticks_left);
timer_.Start(
FROM_HERE,
desired_time - base::TimeTicks::Now(),
base::Bind(
&DevToolsNetworkController::OnTimer,
weak_ptr_factory_.GetWeakPtr()));
}
void DevToolsNetworkController::ThrottleTransaction(
DevToolsNetworkTransaction* transaction) {
UpdateThrottles();
throttled_transactions_.push_back(transaction);
ArmTimer();
} }
...@@ -5,34 +5,18 @@ ...@@ -5,34 +5,18 @@
#ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_CONTROLLER_H_ #ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_CONTROLLER_H_
#define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_CONTROLLER_H_ #define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_CONTROLLER_H_
#include <set>
#include <string> #include <string>
#include <vector>
#include "base/containers/scoped_ptr_hash_map.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#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 "base/threading/thread_checker.h" #include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
class DevToolsNetworkConditions; class DevToolsNetworkConditions;
class DevToolsNetworkInterceptor;
class DevToolsNetworkTransaction; class DevToolsNetworkTransaction;
class GURL;
class Profile;
namespace base {
class TimeDelta;
class TimeTicks;
}
namespace content {
class ResourceContext;
}
namespace net {
struct HttpRequestInfo;
}
namespace test { namespace test {
class DevToolsNetworkControllerHelper; class DevToolsNetworkControllerHelper;
...@@ -45,17 +29,13 @@ class DevToolsNetworkController { ...@@ -45,17 +29,13 @@ class DevToolsNetworkController {
DevToolsNetworkController(); DevToolsNetworkController();
virtual ~DevToolsNetworkController(); virtual ~DevToolsNetworkController();
void AddTransaction(DevToolsNetworkTransaction* transaction);
void RemoveTransaction(DevToolsNetworkTransaction* transaction);
// Applies network emulation configuration. // Applies network emulation configuration.
void SetNetworkState( void SetNetworkState(
const std::string& client_id,
const scoped_refptr<DevToolsNetworkConditions> conditions); const scoped_refptr<DevToolsNetworkConditions> conditions);
bool ShouldFail(const net::HttpRequestInfo* request); base::WeakPtr<DevToolsNetworkInterceptor> GetInterceptor(
bool ShouldThrottle(const net::HttpRequestInfo* request); DevToolsNetworkTransaction* transaction);
void ThrottleTransaction(DevToolsNetworkTransaction* transaction);
protected: protected:
friend class test::DevToolsNetworkControllerHelper; friend class test::DevToolsNetworkControllerHelper;
...@@ -64,24 +44,16 @@ class DevToolsNetworkController { ...@@ -64,24 +44,16 @@ class DevToolsNetworkController {
// Controller must be constructed on IO thread. // Controller must be constructed on IO thread.
base::ThreadChecker thread_checker_; base::ThreadChecker thread_checker_;
typedef scoped_refptr<DevToolsNetworkConditions> Conditions; void SetNetworkStateOnIO(
const std::string& client_id,
void SetNetworkStateOnIO(const Conditions conditions); const scoped_refptr<DevToolsNetworkConditions> conditions);
typedef std::set<DevToolsNetworkTransaction*> Transactions;
Transactions transactions_;
Conditions conditions_;
void UpdateThrottles();
void ArmTimer();
void OnTimer();
std::vector<DevToolsNetworkTransaction*> throttled_transactions_; typedef scoped_ptr<DevToolsNetworkInterceptor> Interceptor;
base::OneShotTimer<DevToolsNetworkController> timer_; Interceptor default_interceptor_;
base::TimeTicks offset_; Interceptor appcache_interceptor_;
base::TimeDelta tick_length_; typedef base::ScopedPtrHashMap<std::string, DevToolsNetworkInterceptor>
uint64_t last_tick_; Interceptors;
Interceptors interceptors_;
base::WeakPtrFactory<DevToolsNetworkController> weak_ptr_factory_; base::WeakPtrFactory<DevToolsNetworkController> weak_ptr_factory_;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/run_loop.h" #include "base/run_loop.h"
#include "chrome/browser/devtools/devtools_network_conditions.h" #include "chrome/browser/devtools/devtools_network_conditions.h"
#include "chrome/browser/devtools/devtools_network_controller.h" #include "chrome/browser/devtools/devtools_network_controller.h"
#include "chrome/browser/devtools/devtools_network_interceptor.h"
#include "chrome/browser/devtools/devtools_network_transaction.h" #include "chrome/browser/devtools/devtools_network_transaction.h"
#include "net/http/http_transaction_test_util.h" #include "net/http/http_transaction_test_util.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -17,9 +18,8 @@ ...@@ -17,9 +18,8 @@
namespace test { namespace test {
const char kHttpDotCom[] = "http://dot.com"; const char kClientId[] = "42";
const char kHttpDotOrg[] = "http://dot.org"; const char kAnotherClientId[] = "24";
const char kCom[] = "com";
class TestCallback { class TestCallback {
public: public:
...@@ -44,7 +44,9 @@ class DevToolsNetworkControllerHelper { ...@@ -44,7 +44,9 @@ class DevToolsNetworkControllerHelper {
mock_transaction_(kSimpleGET_Transaction), mock_transaction_(kSimpleGET_Transaction),
buffer_(new net::IOBuffer(64)) { buffer_(new net::IOBuffer(64)) {
mock_transaction_.test_mode = TEST_MODE_SYNC_NET_START; mock_transaction_.test_mode = TEST_MODE_SYNC_NET_START;
mock_transaction_.url = kHttpDotCom; mock_transaction_.url = "http://dot.com";
mock_transaction_.request_headers =
"X-DevTools-Emulate-Network-Conditions-Client-Id: 42\r\n";
AddMockTransaction(&mock_transaction_); AddMockTransaction(&mock_transaction_);
scoped_ptr<net::HttpTransaction> network_transaction; scoped_ptr<net::HttpTransaction> network_transaction;
...@@ -60,13 +62,10 @@ class DevToolsNetworkControllerHelper { ...@@ -60,13 +62,10 @@ class DevToolsNetworkControllerHelper {
return request_.get(); return request_.get();
} }
void SetNetworkState(bool offline) { void SetNetworkState(const std::string id, bool offline) {
std::vector<std::string> domains; scoped_refptr<DevToolsNetworkConditions> conditions(
domains.push_back(kCom); new DevToolsNetworkConditions(offline));
scoped_refptr<DevToolsNetworkConditions> conditions; controller_.SetNetworkStateOnIO(id, conditions);
if (offline)
conditions = new DevToolsNetworkConditions(domains, 0.0);
controller_.SetNetworkStateOnIO(conditions);
} }
int Start() { int Start() {
...@@ -78,6 +77,10 @@ class DevToolsNetworkControllerHelper { ...@@ -78,6 +77,10 @@ class DevToolsNetworkControllerHelper {
return transaction_->Read(buffer_.get(), 64, completion_callback_); return transaction_->Read(buffer_.get(), 64, completion_callback_);
} }
bool ShouldFail() {
return transaction_->interceptor_->ShouldFail(transaction_.get());
}
~DevToolsNetworkControllerHelper() { ~DevToolsNetworkControllerHelper() {
RemoveMockTransaction(&mock_transaction_); RemoveMockTransaction(&mock_transaction_);
} }
...@@ -101,19 +104,37 @@ class DevToolsNetworkControllerHelper { ...@@ -101,19 +104,37 @@ class DevToolsNetworkControllerHelper {
TEST(DevToolsNetworkControllerTest, SingleDisableEnable) { TEST(DevToolsNetworkControllerTest, SingleDisableEnable) {
DevToolsNetworkControllerHelper helper; DevToolsNetworkControllerHelper helper;
DevToolsNetworkController* controller = helper.controller(); helper.SetNetworkState(kClientId, false);
net::HttpRequestInfo* request = helper.GetRequest(); helper.Start();
EXPECT_FALSE(controller->ShouldFail(request)); EXPECT_FALSE(helper.ShouldFail());
helper.SetNetworkState(true); helper.SetNetworkState(kClientId, true);
EXPECT_TRUE(controller->ShouldFail(request)); EXPECT_TRUE(helper.ShouldFail());
helper.SetNetworkState(false); helper.SetNetworkState(kClientId, false);
EXPECT_FALSE(controller->ShouldFail(request)); EXPECT_FALSE(helper.ShouldFail());
base::RunLoop().RunUntilIdle();
}
TEST(DevToolsNetworkControllerTest, InterceptorIsolation) {
DevToolsNetworkControllerHelper helper;
helper.SetNetworkState(kClientId, false);
helper.Start();
EXPECT_FALSE(helper.ShouldFail());
helper.SetNetworkState(kAnotherClientId, true);
EXPECT_FALSE(helper.ShouldFail());
helper.SetNetworkState(kClientId, true);
EXPECT_TRUE(helper.ShouldFail());
helper.SetNetworkState(kAnotherClientId, false);
helper.SetNetworkState(kClientId, false);
base::RunLoop().RunUntilIdle();
} }
TEST(DevToolsNetworkControllerTest, FailOnStart) { TEST(DevToolsNetworkControllerTest, FailOnStart) {
DevToolsNetworkControllerHelper helper; DevToolsNetworkControllerHelper helper;
helper.SetNetworkState(true); helper.SetNetworkState(kClientId, true);
int rv = helper.Start(); int rv = helper.Start();
EXPECT_EQ(rv, net::ERR_INTERNET_DISCONNECTED); EXPECT_EQ(rv, net::ERR_INTERNET_DISCONNECTED);
...@@ -124,6 +145,7 @@ TEST(DevToolsNetworkControllerTest, FailOnStart) { ...@@ -124,6 +145,7 @@ TEST(DevToolsNetworkControllerTest, FailOnStart) {
TEST(DevToolsNetworkControllerTest, FailRunningTransaction) { TEST(DevToolsNetworkControllerTest, FailRunningTransaction) {
DevToolsNetworkControllerHelper helper; DevToolsNetworkControllerHelper helper;
helper.SetNetworkState(kClientId, false);
TestCallback* callback = helper.callback(); TestCallback* callback = helper.callback();
int rv = helper.Start(); int rv = helper.Start();
...@@ -134,7 +156,7 @@ TEST(DevToolsNetworkControllerTest, FailRunningTransaction) { ...@@ -134,7 +156,7 @@ TEST(DevToolsNetworkControllerTest, FailRunningTransaction) {
EXPECT_EQ(rv, net::ERR_IO_PENDING); EXPECT_EQ(rv, net::ERR_IO_PENDING);
EXPECT_EQ(callback->run_count(), 0); EXPECT_EQ(callback->run_count(), 0);
helper.SetNetworkState(true); helper.SetNetworkState(kClientId, true);
EXPECT_EQ(callback->run_count(), 1); EXPECT_EQ(callback->run_count(), 1);
EXPECT_EQ(callback->value(), net::ERR_INTERNET_DISCONNECTED); EXPECT_EQ(callback->value(), net::ERR_INTERNET_DISCONNECTED);
...@@ -145,19 +167,20 @@ TEST(DevToolsNetworkControllerTest, FailRunningTransaction) { ...@@ -145,19 +167,20 @@ TEST(DevToolsNetworkControllerTest, FailRunningTransaction) {
EXPECT_EQ(callback->run_count(), 1); EXPECT_EQ(callback->run_count(), 1);
// Check that transaction in not failed second time. // Check that transaction in not failed second time.
helper.SetNetworkState(false); helper.SetNetworkState(kClientId, false);
helper.SetNetworkState(true); helper.SetNetworkState(kClientId, true);
EXPECT_EQ(callback->run_count(), 1); EXPECT_EQ(callback->run_count(), 1);
} }
TEST(DevToolsNetworkControllerTest, ReadAfterFail) { TEST(DevToolsNetworkControllerTest, ReadAfterFail) {
DevToolsNetworkControllerHelper helper; DevToolsNetworkControllerHelper helper;
helper.SetNetworkState(kClientId, false);
int rv = helper.Start(); int rv = helper.Start();
EXPECT_EQ(rv, net::OK); EXPECT_EQ(rv, net::OK);
EXPECT_TRUE(helper.transaction()->request()); EXPECT_TRUE(helper.transaction()->request());
helper.SetNetworkState(true); helper.SetNetworkState(kClientId, true);
EXPECT_TRUE(helper.transaction()->failed()); EXPECT_TRUE(helper.transaction()->failed());
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(64)); scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(64));
...@@ -171,25 +194,15 @@ TEST(DevToolsNetworkControllerTest, ReadAfterFail) { ...@@ -171,25 +194,15 @@ TEST(DevToolsNetworkControllerTest, ReadAfterFail) {
TEST(DevToolsNetworkControllerTest, AllowsDevToolsRequests) { TEST(DevToolsNetworkControllerTest, AllowsDevToolsRequests) {
DevToolsNetworkControllerHelper helper; DevToolsNetworkControllerHelper helper;
helper.SetNetworkState(kClientId, false);
helper.mock_transaction()->request_headers = helper.mock_transaction()->request_headers =
"X-DevTools-Emulate-Network-Conditions-Client-Id: 42\r\n"
"X-DevTools-Request-Initiator: frontend\r\n"; "X-DevTools-Request-Initiator: frontend\r\n";
DevToolsNetworkController* controller = helper.controller(); helper.Start();
net::HttpRequestInfo* request = helper.GetRequest();
EXPECT_FALSE(controller->ShouldFail(request));
helper.SetNetworkState(true);
EXPECT_FALSE(controller->ShouldFail(request));
}
TEST(DevToolsNetworkControllerTest, AllowsNotMatchingRequests) {
DevToolsNetworkControllerHelper helper;
helper.mock_transaction()->url = kHttpDotOrg;
DevToolsNetworkController* controller = helper.controller();
net::HttpRequestInfo* request = helper.GetRequest();
EXPECT_FALSE(controller->ShouldFail(request)); EXPECT_FALSE(helper.ShouldFail());
helper.SetNetworkState(true); helper.SetNetworkState(kClientId, true);
EXPECT_FALSE(controller->ShouldFail(request)); EXPECT_FALSE(helper.ShouldFail());
} }
} // namespace test } // namespace test
// 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 "chrome/browser/devtools/devtools_network_interceptor.h"
#include "base/time/time.h"
#include "chrome/browser/devtools/devtools_network_conditions.h"
#include "chrome/browser/devtools/devtools_network_transaction.h"
namespace {
int64_t kPacketSize = 1500;
} // namespace
DevToolsNetworkInterceptor::DevToolsNetworkInterceptor()
: conditions_(new DevToolsNetworkConditions()),
weak_ptr_factory_(this) {
}
DevToolsNetworkInterceptor::~DevToolsNetworkInterceptor() {
}
base::WeakPtr<DevToolsNetworkInterceptor>
DevToolsNetworkInterceptor::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
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;
UpdateThrottles();
throttled_transactions_.erase(std::remove(throttled_transactions_.begin(),
throttled_transactions_.end(), transaction),
throttled_transactions_.end());
ArmTimer();
}
void DevToolsNetworkInterceptor::UpdateConditions(
const scoped_refptr<DevToolsNetworkConditions> conditions) {
DCHECK(conditions);
if (conditions_->IsThrottling())
UpdateThrottles();
conditions_ = conditions;
if (conditions->offline()) {
timer_.Stop();
throttled_transactions_.clear();
Transactions old_transactions(transactions_);
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;
}
if (conditions->IsThrottling()) {
DCHECK(conditions->download_throughput() != 0);
offset_ = base::TimeTicks::Now();
last_tick_ = 0;
int64_t us_tick_length =
(1000000L * kPacketSize) / conditions->download_throughput();
DCHECK(us_tick_length != 0);
if (us_tick_length == 0)
us_tick_length = 1;
tick_length_ = base::TimeDelta::FromMicroseconds(us_tick_length);
ArmTimer();
} else {
timer_.Stop();
int64_t length = throttled_transactions_.size();
for (int64_t i = 0; i < length; ++i)
throttled_transactions_[i]->FireThrottledCallback();
throttled_transactions_.clear();
}
}
void DevToolsNetworkInterceptor::UpdateThrottles() {
int64_t last_tick = (base::TimeTicks::Now() - offset_) / tick_length_;
int64_t ticks = last_tick - last_tick_;
last_tick_ = last_tick;
int64_t length = throttled_transactions_.size();
if (!length)
return;
int64_t shift = ticks % length;
for (int64_t i = 0; i < length; ++i) {
throttled_transactions_[i]->DecreaseThrottledByteCount(
(ticks / length) * kPacketSize + (i < shift ? kPacketSize : 0));
}
std::rotate(throttled_transactions_.begin(),
throttled_transactions_.begin() + shift, throttled_transactions_.end());
}
void DevToolsNetworkInterceptor::OnTimer() {
UpdateThrottles();
std::vector<DevToolsNetworkTransaction*> active_transactions;
std::vector<DevToolsNetworkTransaction*> finished_transactions;
size_t length = throttled_transactions_.size();
for (size_t i = 0; i < length; ++i) {
if (throttled_transactions_[i]->throttled_byte_count() < 0)
finished_transactions.push_back(throttled_transactions_[i]);
else
active_transactions.push_back(throttled_transactions_[i]);
}
throttled_transactions_.swap(active_transactions);
length = finished_transactions.size();
for (size_t i = 0; i < length; ++i)
finished_transactions[i]->FireThrottledCallback();
ArmTimer();
}
void DevToolsNetworkInterceptor::ArmTimer() {
size_t length = throttled_transactions_.size();
if (!length)
return;
int64_t min_ticks_left = 0x10000L;
for (size_t i = 0; i < length; ++i) {
int64_t packets_left = (throttled_transactions_[i]->throttled_byte_count() +
kPacketSize - 1) / kPacketSize;
int64_t ticks_left = (i + 1) + length * (packets_left - 1);
if (i == 0 || ticks_left < min_ticks_left)
min_ticks_left = ticks_left;
}
base::TimeTicks desired_time =
offset_ + tick_length_ * (last_tick_ + min_ticks_left);
timer_.Start(
FROM_HERE,
desired_time - base::TimeTicks::Now(),
base::Bind(
&DevToolsNetworkInterceptor::OnTimer,
base::Unretained(this)));
}
void DevToolsNetworkInterceptor::ThrottleTransaction(
DevToolsNetworkTransaction* transaction) {
UpdateThrottles();
throttled_transactions_.push_back(transaction);
ArmTimer();
}
bool DevToolsNetworkInterceptor::ShouldFail(
const DevToolsNetworkTransaction* transaction) {
if (!conditions_->offline())
return false;
if (!transaction->request_initiator().empty())
return false;
return true;
}
bool DevToolsNetworkInterceptor::ShouldThrottle(
const DevToolsNetworkTransaction* transaction) {
if (!conditions_->IsThrottling())
return false;
if (!transaction->request_initiator().empty())
return false;
return true;
}
// 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.
#ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_INTERCEPTOR_H_
#define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_INTERCEPTOR_H_
#include <set>
#include <string>
#include <vector>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/timer/timer.h"
class DevToolsNetworkConditions;
class DevToolsNetworkTransaction;
namespace base {
class TimeDelta;
class TimeTicks;
}
// DevToolsNetworkInterceptor emulates network conditions for transactions with
// specific client id.
class DevToolsNetworkInterceptor {
public:
DevToolsNetworkInterceptor();
virtual ~DevToolsNetworkInterceptor();
base::WeakPtr<DevToolsNetworkInterceptor> GetWeakPtr();
// Applies network emulation configuration.
void UpdateConditions(
const scoped_refptr<DevToolsNetworkConditions> conditions);
void AddTransaction(DevToolsNetworkTransaction* transaction);
void RemoveTransaction(DevToolsNetworkTransaction* transaction);
bool ShouldFail(const DevToolsNetworkTransaction* transaction);
bool ShouldThrottle(const DevToolsNetworkTransaction* transaction);
void ThrottleTransaction(DevToolsNetworkTransaction* transaction);
const DevToolsNetworkConditions* conditions() const {
return conditions_.get();
}
private:
scoped_refptr<DevToolsNetworkConditions> conditions_;
void UpdateThrottles();
void ArmTimer();
void OnTimer();
typedef std::set<DevToolsNetworkTransaction*> Transactions;
Transactions transactions_;
std::vector<DevToolsNetworkTransaction*> throttled_transactions_;
base::OneShotTimer<DevToolsNetworkInterceptor> timer_;
base::TimeTicks offset_;
base::TimeDelta tick_length_;
uint64_t last_tick_;
base::WeakPtrFactory<DevToolsNetworkInterceptor> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkInterceptor);
};
#endif // CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_INTERCEPTOR_H_
...@@ -5,11 +5,20 @@ ...@@ -5,11 +5,20 @@
#include "chrome/browser/devtools/devtools_network_transaction.h" #include "chrome/browser/devtools/devtools_network_transaction.h"
#include "chrome/browser/devtools/devtools_network_controller.h" #include "chrome/browser/devtools/devtools_network_controller.h"
#include "chrome/browser/devtools/devtools_network_interceptor.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"
#include "net/http/http_request_info.h" #include "net/http/http_request_info.h"
namespace {
const char kDevToolsRequestInitiator[] = "X-DevTools-Request-Initiator";
const char kDevToolsEmulateNetworkConditionsClientId[] =
"X-DevTools-Emulate-Network-Conditions-Client-Id";
} // namespace
DevToolsNetworkTransaction::DevToolsNetworkTransaction( DevToolsNetworkTransaction::DevToolsNetworkTransaction(
DevToolsNetworkController* controller, DevToolsNetworkController* controller,
scoped_ptr<net::HttpTransaction> network_transaction) scoped_ptr<net::HttpTransaction> network_transaction)
...@@ -22,11 +31,11 @@ DevToolsNetworkTransaction::DevToolsNetworkTransaction( ...@@ -22,11 +31,11 @@ DevToolsNetworkTransaction::DevToolsNetworkTransaction(
proxy_callback_(base::Bind(&DevToolsNetworkTransaction::OnCallback, proxy_callback_(base::Bind(&DevToolsNetworkTransaction::OnCallback,
base::Unretained(this))) { base::Unretained(this))) {
DCHECK(controller); DCHECK(controller);
controller->AddTransaction(this);
} }
DevToolsNetworkTransaction::~DevToolsNetworkTransaction() { DevToolsNetworkTransaction::~DevToolsNetworkTransaction() {
controller_->RemoveTransaction(this); if (interceptor_)
interceptor_->RemoveTransaction(this);
} }
void DevToolsNetworkTransaction::Throttle(int result) { void DevToolsNetworkTransaction::Throttle(int result) {
...@@ -37,7 +46,8 @@ void DevToolsNetworkTransaction::Throttle(int result) { ...@@ -37,7 +46,8 @@ void DevToolsNetworkTransaction::Throttle(int result) {
if (result > 0) if (result > 0)
throttled_byte_count_ += result; throttled_byte_count_ += result;
controller_->ThrottleTransaction(this); if (interceptor_)
interceptor_->ThrottleTransaction(this);
} }
void DevToolsNetworkTransaction::OnCallback(int rv) { void DevToolsNetworkTransaction::OnCallback(int rv) {
...@@ -45,7 +55,7 @@ void DevToolsNetworkTransaction::OnCallback(int rv) { ...@@ -45,7 +55,7 @@ void DevToolsNetworkTransaction::OnCallback(int rv) {
return; return;
DCHECK(!callback_.is_null()); DCHECK(!callback_.is_null());
if (callback_type_ == START || callback_type_ == READ) { if (callback_type_ == START || callback_type_ == READ) {
if (controller_->ShouldThrottle(request_)) { if (interceptor_ && interceptor_->ShouldThrottle(this)) {
Throttle(rv); Throttle(rv);
return; return;
} }
...@@ -68,7 +78,7 @@ int DevToolsNetworkTransaction::SetupCallback( ...@@ -68,7 +78,7 @@ int DevToolsNetworkTransaction::SetupCallback(
return result; return result;
} }
if (!controller_->ShouldThrottle(request_)) if (!interceptor_ || !interceptor_->ShouldThrottle(this))
return result; return result;
// Only START and READ operation throttling is supported. // Only START and READ operation throttling is supported.
...@@ -109,17 +119,46 @@ int DevToolsNetworkTransaction::Start( ...@@ -109,17 +119,46 @@ int DevToolsNetworkTransaction::Start(
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 (controller_->ShouldFail(request_)) { if (interceptor_->ShouldFail(this)) {
failed_ = true; failed_ = true;
network_transaction_->SetBeforeNetworkStartCallback( network_transaction_->SetBeforeNetworkStartCallback(
BeforeNetworkStartCallback()); BeforeNetworkStartCallback());
return net::ERR_INTERNET_DISCONNECTED; return net::ERR_INTERNET_DISCONNECTED;
} }
int rv = network_transaction_->Start(request, proxy_callback_, net_log); int rv = network_transaction_->Start(request_, proxy_callback_, net_log);
return SetupCallback(callback, rv, START); return SetupCallback(callback, rv, START);
} }
void DevToolsNetworkTransaction::ProcessRequest() {
DCHECK(request_);
bool has_devtools_client_id = request_->extra_headers.HasHeader(
kDevToolsEmulateNetworkConditionsClientId);
bool has_devtools_request_initiator = request_->extra_headers.HasHeader(
kDevToolsRequestInitiator);
if (!has_devtools_client_id && !has_devtools_request_initiator)
return;
custom_request_.reset(new net::HttpRequestInfo(*request_));
if (has_devtools_client_id) {
custom_request_->extra_headers.GetHeader(
kDevToolsEmulateNetworkConditionsClientId, &client_id_);
custom_request_->extra_headers.RemoveHeader(
kDevToolsEmulateNetworkConditionsClientId);
}
if (has_devtools_request_initiator) {
custom_request_->extra_headers.GetHeader(
kDevToolsRequestInitiator, &request_initiator_);
custom_request_->extra_headers.RemoveHeader(kDevToolsRequestInitiator);
}
request_ = custom_request_.get();
}
int DevToolsNetworkTransaction::RestartIgnoringLastError( int DevToolsNetworkTransaction::RestartIgnoringLastError(
const net::CompletionCallback& callback) { const net::CompletionCallback& callback) {
if (failed_) if (failed_)
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_TRANSACTION_H_ #define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_TRANSACTION_H_
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.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"
...@@ -13,6 +14,7 @@ ...@@ -13,6 +14,7 @@
#include "net/websockets/websocket_handshake_stream_base.h" #include "net/websockets/websocket_handshake_stream_base.h"
class DevToolsNetworkController; class DevToolsNetworkController;
class DevToolsNetworkInterceptor;
class GURL; class GURL;
namespace net { namespace net {
...@@ -26,6 +28,10 @@ class IOBuffer; ...@@ -26,6 +28,10 @@ class IOBuffer;
struct LoadTimingInfo; struct LoadTimingInfo;
class UploadProgress; class UploadProgress;
class X509Certificate; class X509Certificate;
} // namespace net
namespace test {
class DevToolsNetworkControllerHelper;
} }
// DevToolsNetworkTransaction is a wrapper for network transaction. All // DevToolsNetworkTransaction is a wrapper for network transaction. All
...@@ -42,6 +48,11 @@ class DevToolsNetworkTransaction : public net::HttpTransaction { ...@@ -42,6 +48,11 @@ class DevToolsNetworkTransaction : public net::HttpTransaction {
virtual ~DevToolsNetworkTransaction(); virtual ~DevToolsNetworkTransaction();
const net::HttpRequestInfo* request() const { return request_; } const net::HttpRequestInfo* request() const { return request_; }
// Checks if request contains DevTools specific headers. Found values are
// remembered and corresponding keys are removed from headers.
void ProcessRequest();
bool failed() const { return failed_; } bool failed() const { return failed_; }
// Runs callback (if any) with net::ERR_INTERNET_DISCONNECTED result value. // Runs callback (if any) with net::ERR_INTERNET_DISCONNECTED result value.
...@@ -52,6 +63,12 @@ class DevToolsNetworkTransaction : public net::HttpTransaction { ...@@ -52,6 +63,12 @@ class DevToolsNetworkTransaction : public net::HttpTransaction {
throttled_byte_count_ -= delta; throttled_byte_count_ -= delta;
} }
const std::string& request_initiator() const { return request_initiator_; }
const std::string& client_id() const {
return client_id_;
}
void FireThrottledCallback(); void FireThrottledCallback();
// HttpTransaction methods: // HttpTransaction methods:
...@@ -92,11 +109,15 @@ class DevToolsNetworkTransaction : public net::HttpTransaction { ...@@ -92,11 +109,15 @@ class DevToolsNetworkTransaction : public net::HttpTransaction {
const BeforeNetworkStartCallback& callback) OVERRIDE; const BeforeNetworkStartCallback& callback) OVERRIDE;
virtual int ResumeNetworkStart() OVERRIDE; virtual int ResumeNetworkStart() OVERRIDE;
protected:
friend class test::DevToolsNetworkControllerHelper;
private: private:
// Proxy callback handler. Runs saved callback. // Proxy callback handler. Runs saved callback.
void OnCallback(int result); void OnCallback(int result);
DevToolsNetworkController* controller_; DevToolsNetworkController* controller_;
base::WeakPtr<DevToolsNetworkInterceptor> interceptor_;
// Real network transaction. // Real network transaction.
scoped_ptr<net::HttpTransaction> network_transaction_; scoped_ptr<net::HttpTransaction> network_transaction_;
...@@ -109,6 +130,14 @@ class DevToolsNetworkTransaction : public net::HttpTransaction { ...@@ -109,6 +130,14 @@ 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-Request-Initiator" request header.
std::string request_initiator_;
// Value of "X-DevTools-Emulate-Network-Conditions-Client-Id" request header.
std::string client_id_;
scoped_ptr<net::HttpRequestInfo> custom_request_;
enum CallbackType { enum CallbackType {
NONE, NONE,
READ, READ,
......
...@@ -68,6 +68,8 @@ ...@@ -68,6 +68,8 @@
'browser/devtools/devtools_network_conditions.h', 'browser/devtools/devtools_network_conditions.h',
'browser/devtools/devtools_network_controller.cc', 'browser/devtools/devtools_network_controller.cc',
'browser/devtools/devtools_network_controller.h', 'browser/devtools/devtools_network_controller.h',
'browser/devtools/devtools_network_interceptor.cc',
'browser/devtools/devtools_network_interceptor.h',
'browser/devtools/devtools_network_transaction.cc', 'browser/devtools/devtools_network_transaction.cc',
'browser/devtools/devtools_network_transaction.h', 'browser/devtools/devtools_network_transaction.h',
'browser/devtools/devtools_network_transaction_factory.cc', 'browser/devtools/devtools_network_transaction_factory.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment