Merge pull request #145 from deepak1556/devtools_network_emulation_patch

enabling network emulation in devtools
This commit is contained in:
Cheng Zhao 2015-09-28 12:14:14 +08:00
commit 3f3fbc03fc
19 changed files with 1292 additions and 3 deletions

View file

@ -136,6 +136,7 @@ net::URLRequestContextGetter* BrowserContext::CreateRequestContext(
DCHECK(!url_request_getter_.get());
url_request_getter_ = new URLRequestContextGetter(
this,
GetDevToolsNetworkController(),
net_log,
GetPath(),
in_memory_,
@ -147,6 +148,12 @@ net::URLRequestContextGetter* BrowserContext::CreateRequestContext(
return url_request_getter_.get();
}
DevToolsNetworkController* BrowserContext::GetDevToolsNetworkController() {
if (!controller_)
controller_.reset(new DevToolsNetworkController);
return controller_.get();
}
net::NetworkDelegate* BrowserContext::CreateNetworkDelegate() {
return new NetworkDelegate;
}

View file

@ -7,6 +7,7 @@
#include <map>
#include "browser/net/devtools_network_controller.h"
#include "browser/permission_manager.h"
#include "browser/url_request_context_getter.h"
@ -57,6 +58,7 @@ class BrowserContext : public base::RefCounted<BrowserContext>,
NetLog* net_log,
content::ProtocolHandlerMap* protocol_handlers,
content::URLRequestInterceptorScopedVector protocol_interceptors);
DevToolsNetworkController* GetDevToolsNetworkController();
net::URLRequestContextGetter* url_request_context_getter() const {
return url_request_getter_.get();
@ -107,6 +109,7 @@ class BrowserContext : public base::RefCounted<BrowserContext>,
base::FilePath path_;
bool in_memory_;
scoped_ptr<ResourceContext> resource_context_;
scoped_ptr<DevToolsNetworkController> controller_;
scoped_refptr<URLRequestContextGetter> url_request_getter_;
scoped_ptr<PrefService> prefs_;
scoped_ptr<PermissionManager> permission_manager_;

View file

@ -6,6 +6,8 @@
#include <vector>
#include "browser/net/devtools_network_protocol_handler.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
@ -140,7 +142,8 @@ DevToolsManagerDelegate::CreateHttpHandler() {
GetBrightrayUserAgent());
}
DevToolsManagerDelegate::DevToolsManagerDelegate() {
DevToolsManagerDelegate::DevToolsManagerDelegate()
: handler_(new DevToolsNetworkProtocolHandler) {
// NB(zcbenz): This call does nothing, the only purpose is to make sure the
// devtools_discovery module is linked into the final executable on Linux.
// Though it is possible to achieve this by modifying the gyp settings, it
@ -155,7 +158,7 @@ DevToolsManagerDelegate::~DevToolsManagerDelegate() {
base::DictionaryValue* DevToolsManagerDelegate::HandleCommand(
content::DevToolsAgentHost* agent_host,
base::DictionaryValue* command) {
return NULL;
return handler_->HandleCommand(agent_host, command);
}
} // namespace brightray

View file

@ -16,6 +16,8 @@ class DevToolsHttpHandler;
namespace brightray {
class DevToolsNetworkProtocolHandler;
class DevToolsManagerDelegate : public content::DevToolsManagerDelegate {
public:
static devtools_http_handler::DevToolsHttpHandler* CreateHttpHandler();
@ -32,6 +34,8 @@ class DevToolsManagerDelegate : public content::DevToolsManagerDelegate {
base::DictionaryValue* command) override;
private:
scoped_ptr<DevToolsNetworkProtocolHandler> handler_;
DISALLOW_COPY_AND_ASSIGN(DevToolsManagerDelegate);
};

View file

@ -0,0 +1,35 @@
// 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 "browser/net/devtools_network_conditions.h"
namespace brightray {
DevToolsNetworkConditions::DevToolsNetworkConditions(bool offline)
: offline_(offline),
latency_(0),
download_throughput_(0),
upload_throughput_(0) {
}
DevToolsNetworkConditions::DevToolsNetworkConditions(
bool offline,
double latency,
double download_throughput,
double upload_throughput)
: offline_(offline),
latency_(latency),
download_throughput_(download_throughput),
upload_throughput_(upload_throughput) {
}
DevToolsNetworkConditions::~DevToolsNetworkConditions() {
}
bool DevToolsNetworkConditions::IsThrottling() const {
return !offline_ && ((latency_ != 0.0) || (download_throughput_ != 0.0) ||
(upload_throughput_ != 0.0));
}
} // namespace brightray

View file

@ -0,0 +1,43 @@
// 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 BROWSER_DEVTOOLS_NETWORK_CONDITIONS_H_
#define BROWSER_DEVTOOLS_NETWORK_CONDITIONS_H_
#include <string>
#include <vector>
#include "base/macros.h"
#include "url/gurl.h"
namespace brightray {
class DevToolsNetworkConditions {
public:
explicit DevToolsNetworkConditions(bool offline);
DevToolsNetworkConditions(bool offline,
double latency,
double download_throughput,
double upload_throughput);
~DevToolsNetworkConditions();
bool IsThrottling() const;
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:
const bool offline_;
const double latency_;
const double download_throughput_;
const double upload_throughput_;
DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkConditions);
};
} // namespace brightray
#endif // BROWSER_DEVTOOLS_NETWORK_CONDITIONS_H_

View file

@ -0,0 +1,74 @@
// Copyright (c) 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-CHROMIUM file.
#include "browser/net/devtools_network_controller.h"
#include "browser/net/devtools_network_conditions.h"
#include "browser/net/devtools_network_interceptor.h"
#include "browser/net/devtools_network_transaction.h"
#include "base/bind.h"
#include "content/public/browser/browser_thread.h"
using content::BrowserThread;
namespace brightray {
DevToolsNetworkController::DevToolsNetworkController()
: default_interceptor_(new DevToolsNetworkInterceptor) {
}
DevToolsNetworkController::~DevToolsNetworkController() {
}
void DevToolsNetworkController::SetNetworkState(
const std::string& client_id,
scoped_ptr<DevToolsNetworkConditions> conditions) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (client_id.empty()) {
if (!conditions)
return;
default_interceptor_->UpdateConditions(conditions.Pass());
return;
}
auto interceptor = interceptors_.get(client_id);
if (!interceptor) {
if (!conditions)
return;
scoped_ptr<DevToolsNetworkInterceptor> new_interceptor(
new DevToolsNetworkInterceptor);
new_interceptor->UpdateConditions(conditions.Pass());
interceptors_.set(client_id, new_interceptor.Pass());
} else {
if (!conditions) {
scoped_ptr<DevToolsNetworkConditions> online_conditions(
new DevToolsNetworkConditions(false));
interceptor->UpdateConditions(online_conditions.Pass());
interceptors_.erase(client_id);
} else {
interceptor->UpdateConditions(conditions.Pass());
}
}
}
base::WeakPtr<DevToolsNetworkInterceptor>
DevToolsNetworkController::GetInterceptor(DevToolsNetworkTransaction* transaction) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(transaction->request());
if (!interceptors_.size())
return default_interceptor_->GetWeakPtr();
transaction->ProcessRequest();
auto& client_id = transaction->client_id();
auto interceptor = interceptors_.get(client_id);
if (!interceptor)
return default_interceptor_->GetWeakPtr();
return interceptor->GetWeakPtr();
}
} // namespace brightray

View file

@ -0,0 +1,40 @@
// Copyright (c) 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-CHROMIUM file.
#ifndef BROWSER_DEVTOOLS_NETWORK_CONTROLLER_H_
#define BROWSER_DEVTOOLS_NETWORK_CONTROLLER_H_
#include "base/containers/scoped_ptr_hash_map.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
namespace brightray {
class DevToolsNetworkConditions;
class DevToolsNetworkInterceptor;
class DevToolsNetworkTransaction;
class DevToolsNetworkController {
public:
DevToolsNetworkController();
virtual ~DevToolsNetworkController();
void SetNetworkState(const std::string& client_id,
scoped_ptr<DevToolsNetworkConditions> conditions);
base::WeakPtr<DevToolsNetworkInterceptor> GetInterceptor(
DevToolsNetworkTransaction* transaction);
private:
using InterceptorMap = base::ScopedPtrHashMap<std::string,
scoped_ptr<DevToolsNetworkInterceptor>>;
scoped_ptr<DevToolsNetworkInterceptor> default_interceptor_;
InterceptorMap interceptors_;
DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkController);
};
} // namespace brightray
#endif // BROWSER_DEVTOOLS_NETWORK_CONTROLLER_H_

View file

@ -0,0 +1,255 @@
// 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 "browser/net/devtools_network_interceptor.h"
#include <limits>
#include "browser/net/devtools_network_conditions.h"
#include "browser/net/devtools_network_transaction.h"
#include "base/time/time.h"
#include "net/base/load_timing_info.h"
namespace brightray {
namespace {
int64_t kPacketSize = 1500;
} // namespace
DevToolsNetworkInterceptor::DevToolsNetworkInterceptor()
: conditions_(new DevToolsNetworkConditions(false)),
weak_ptr_factory_(this) {
}
DevToolsNetworkInterceptor::~DevToolsNetworkInterceptor() {
}
base::WeakPtr<DevToolsNetworkInterceptor>
DevToolsNetworkInterceptor::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
void DevToolsNetworkInterceptor::UpdateConditions(
scoped_ptr<DevToolsNetworkConditions> conditions) {
DCHECK(conditions);
base::TimeTicks now = base::TimeTicks::Now();
if (conditions_->IsThrottling())
UpdateThrottledTransactions(now);
conditions_ = conditions.Pass();
if (conditions_->offline()) {
timer_.Stop();
throttled_transactions_.clear();
suspended_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_NE(conditions_->download_throughput(), 0);
offset_ = now;
last_tick_ = 0;
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;
throttled_transactions.swap(throttled_transactions_);
for (auto& throttled_transaction : throttled_transactions)
FireThrottledCallback(throttled_transaction);
SuspendedTransactions suspended_transactions;
suspended_transactions.swap(suspended_transactions_);
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;
}
}
ArmTimer(now);
}
bool DevToolsNetworkInterceptor::ShouldFail(
const DevToolsNetworkTransaction* transaction) {
return conditions_->offline();
}
bool DevToolsNetworkInterceptor::ShouldThrottle(
const DevToolsNetworkTransaction* transaction) {
return conditions_->IsThrottling();
}
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(
base::TimeTicks now) {
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();
if (!length) {
UpdateSuspendedTransactions(now);
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());
UpdateSuspendedTransactions(now);
}
void DevToolsNetworkInterceptor::UpdateSuspendedTransactions(
base::TimeTicks now) {
int64_t activation_baseline =
(now - latency_length_ - base::TimeTicks()).InMicroseconds();
SuspendedTransactions suspended_transactions;
SuspendedTransactions::iterator it = suspended_transactions_.begin();
for (; it != suspended_transactions_.end(); ++it) {
if (it->second <= activation_baseline)
throttled_transactions_.push_back(it->first);
else
suspended_transactions.push_back(*it);
}
suspended_transactions_.swap(suspended_transactions);
}
void DevToolsNetworkInterceptor::ArmTimer(base::TimeTicks now) {
size_t throttle_count = throttled_transactions_.size();
size_t suspend_count = suspended_transactions_.size();
if (!throttle_count && !suspend_count)
return;
int64_t min_ticks_left = 0x10000L;
for (size_t i = 0; i < throttle_count; ++i) {
int64_t packets_left = (throttled_transactions_[i]->throttled_byte_count() +
kPacketSize - 1) / kPacketSize;
int64_t ticks_left = (i + 1) + throttle_count * (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);
int64_t min_baseline = std::numeric_limits<int64>::max();
for (size_t i = 0; i < suspend_count; ++i) {
if (suspended_transactions_[i].second < min_baseline)
min_baseline = suspended_transactions_[i].second;
}
if (suspend_count) {
base::TimeTicks activation_time = base::TimeTicks() +
base::TimeDelta::FromMicroseconds(min_baseline) + latency_length_;
if (activation_time < desired_time)
desired_time = activation_time;
}
timer_.Start(FROM_HERE, desired_time - now,
base::Bind(&DevToolsNetworkInterceptor::OnTimer,
base::Unretained(this)));
}
void DevToolsNetworkInterceptor::OnTimer() {
base::TimeTicks now = base::TimeTicks::Now();
UpdateThrottledTransactions(now);
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);
for (auto& transaction : finished_transactions)
FireThrottledCallback(transaction);
ArmTimer(now);
}
void DevToolsNetworkInterceptor::FireThrottledCallback(
DevToolsNetworkTransaction* transaction) {
if (transactions_.find(transaction) != transactions_.end())
transaction->FireThrottledCallback();
}
} // namespace brightray

View file

@ -0,0 +1,84 @@
// 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 BROWSER_DEVTOOLS_NETWORK_INTERCEPTOR_H_
#define BROWSER_DEVTOOLS_NETWORK_INTERCEPTOR_H_
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/timer/timer.h"
namespace base {
class TimeDelta;
class TimeTicks;
}
namespace brightray {
class DevToolsNetworkConditions;
class DevToolsNetworkTransaction;
class DevToolsNetworkInterceptor {
public:
DevToolsNetworkInterceptor();
virtual ~DevToolsNetworkInterceptor();
base::WeakPtr<DevToolsNetworkInterceptor> GetWeakPtr();
// Applies network emulation configuration.
void UpdateConditions(scoped_ptr<DevToolsNetworkConditions> conditions);
void AddTransaction(DevToolsNetworkTransaction* transaction);
void RemoveTransaction(DevToolsNetworkTransaction* transaction);
// Returns whether transaction should fail with |net::ERR_INTERNET_DISCONNECTED|
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:
void UpdateThrottledTransactions(base::TimeTicks now);
void UpdateSuspendedTransactions(base::TimeTicks now);
void ArmTimer(base::TimeTicks now);
void OnTimer();
void FireThrottledCallback(DevToolsNetworkTransaction* transaction);
scoped_ptr<DevToolsNetworkConditions> conditions_;
using Transactions = std::set<DevToolsNetworkTransaction*>;
Transactions transactions_;
// Transactions suspended for a latency period.
using SuspendedTransaction = std::pair<DevToolsNetworkTransaction*, int64_t>;
using SuspendedTransactions = std::vector<SuspendedTransaction>;
SuspendedTransactions suspended_transactions_;
// Transactions waiting certain amount of transfer to be accounted.
std::vector<DevToolsNetworkTransaction*> throttled_transactions_;
base::OneShotTimer<DevToolsNetworkInterceptor> timer_;
base::TimeTicks offset_;
base::TimeDelta tick_length_;
base::TimeDelta latency_length_;
uint64_t last_tick_;
base::WeakPtrFactory<DevToolsNetworkInterceptor> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkInterceptor);
};
} // namespace brightray
#endif // BROWSER_DEVTOOLS_NETWORK_INTERCEPTOR_H_

View file

@ -0,0 +1,173 @@
// Copyright (c) 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-CHROMIUM file.
#include "browser/net/devtools_network_protocol_handler.h"
#include "browser/browser_context.h"
#include "browser/net/devtools_network_conditions.h"
#include "browser/net/devtools_network_controller.h"
#include "base/strings/stringprintf.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/devtools_agent_host.h"
using content::BrowserThread;
namespace brightray {
namespace {
namespace params {
const char kDownloadThroughput[] = "downloadThroughput";
const char kLatency[] = "latency";
const char kOffline[] = "offline";
const char kUploadThroughput[] = "uploadThroughput";
const char kResult[] = "result";
const char kErrorCode[] = "code";
const char kErrorMessage[] = "message";
} // namespace params
const char kEmulateNetworkConditions[] = "Network.emulateNetworkConditions";
const char kCanEmulateNetworkConditions[] = "Network.canEmulateNetworkConditions";
const char kId[] = "id";
const char kMethod[] = "method";
const char kParams[] = "params";
const char kError[] = "error";
// JSON RPC 2.0 spec: http://www.jsonrpc.org/specification#error_object
const int kErrorInvalidParams = -32602;
bool ParseCommand(const base::DictionaryValue* command,
int* id,
std::string* method,
const base::DictionaryValue** params) {
if (!command)
return false;
if (!command->GetInteger(kId, id) || *id < 0)
return false;
if (!command->GetString(kMethod, method))
return false;
if (!command->GetDictionary(kParams, params))
*params = nullptr;
return true;
}
scoped_ptr<base::DictionaryValue>
CreateSuccessResponse(int id, scoped_ptr<base::DictionaryValue> result) {
scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue);
response->SetInteger(kId, id);
response->Set(params::kResult, result.release());
return response.Pass();
}
scoped_ptr<base::DictionaryValue>
CreateFailureResponse(int id, const std::string& param) {
scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue);
auto error_object = new base::DictionaryValue;
response->Set(kError, error_object);
error_object->SetInteger(params::kErrorCode, kErrorInvalidParams);
error_object->SetString(params::kErrorMessage,
base::StringPrintf("Missing or Invalid '%s' parameter", param.c_str()));
return response.Pass();
}
void UpdateNetworkStateInIO(brightray::DevToolsNetworkController* controller,
const std::string& client_id,
scoped_ptr<brightray::DevToolsNetworkConditions> conditions) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
controller->SetNetworkState(client_id, conditions.Pass());
}
} // namespace
DevToolsNetworkProtocolHandler::DevToolsNetworkProtocolHandler() {
}
DevToolsNetworkProtocolHandler::~DevToolsNetworkProtocolHandler() {
}
base::DictionaryValue* DevToolsNetworkProtocolHandler::HandleCommand(
content::DevToolsAgentHost* agent_host,
base::DictionaryValue* command) {
int id = 0;
std::string method;
const base::DictionaryValue* params = nullptr;
if (!ParseCommand(command, &id, &method, &params))
return nullptr;
if (method == kEmulateNetworkConditions)
return EmulateNetworkConditions(agent_host, id, params).release();
if (method == kCanEmulateNetworkConditions)
return CanEmulateNetworkConditions(agent_host, id, params).release();
return nullptr;
}
scoped_ptr<base::DictionaryValue>
DevToolsNetworkProtocolHandler::CanEmulateNetworkConditions(
content::DevToolsAgentHost* agent_host,
int id,
const base::DictionaryValue* params) {
scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
result->SetBoolean(params::kResult, true);
return CreateSuccessResponse(id, result.Pass());
}
scoped_ptr<base::DictionaryValue>
DevToolsNetworkProtocolHandler::EmulateNetworkConditions(
content::DevToolsAgentHost* agent_host,
int id,
const base::DictionaryValue* params) {
bool offline = false;
if (!params || !params->GetBoolean(params::kOffline, &offline))
return CreateFailureResponse(id, params::kOffline);
double latency = 0.0;
if (!params->GetDouble(params::kLatency, &latency))
return CreateFailureResponse(id, params::kLatency);
if (latency < 0.0)
latency = 0.0;
double download_throughput = 0.0;
if (!params->GetDouble(params::kDownloadThroughput, &download_throughput))
return CreateFailureResponse(id, params::kDownloadThroughput);
if (download_throughput < 0.0)
download_throughput = 0.0;
double upload_throughput = 0.0;
if (!params->GetDouble(params::kUploadThroughput, &upload_throughput))
return CreateFailureResponse(id, params::kUploadThroughput);
if (upload_throughput < 0.0)
upload_throughput = 0.0;
scoped_ptr<DevToolsNetworkConditions> conditions(
new DevToolsNetworkConditions(offline,
latency,
download_throughput,
upload_throughput));
UpdateNetworkState(agent_host, conditions.Pass());
return scoped_ptr<base::DictionaryValue>();
}
void DevToolsNetworkProtocolHandler::UpdateNetworkState(
content::DevToolsAgentHost* agent_host,
scoped_ptr<DevToolsNetworkConditions> conditions) {
auto browser_context =
static_cast<brightray::BrowserContext*>(agent_host->GetBrowserContext());
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&UpdateNetworkStateInIO,
browser_context->GetDevToolsNetworkController(),
agent_host->GetId(),
base::Passed(&conditions)));
}
} // namespace brightray

View file

@ -0,0 +1,47 @@
// 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 BROWSER_DEVTOOLS_NETWORK_PROTOCOL_HANDLER_H_
#define BROWSER_DEVTOOLS_NETWORK_PROTOCOL_HANDLER_H_
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
namespace content {
class DevToolsAgentHost;
}
namespace brightray {
class DevToolsNetworkConditions;
class DevToolsNetworkProtocolHandler {
public:
DevToolsNetworkProtocolHandler();
~DevToolsNetworkProtocolHandler();
base::DictionaryValue* HandleCommand(
content::DevToolsAgentHost* agent_host,
base::DictionaryValue* command);
private:
scoped_ptr<base::DictionaryValue> CanEmulateNetworkConditions(
content::DevToolsAgentHost* agent_host,
int command_id,
const base::DictionaryValue* params);
scoped_ptr<base::DictionaryValue> EmulateNetworkConditions(
content::DevToolsAgentHost* agent_host,
int command_id,
const base::DictionaryValue* params);
void UpdateNetworkState(
content::DevToolsAgentHost* agent_host,
scoped_ptr<DevToolsNetworkConditions> conditions);
DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkProtocolHandler);
};
} // namespace brightray
#endif // BROWSER_DEVTOOLS_NETWORK_PROTOCOL_HANDLER_H_

View file

@ -0,0 +1,283 @@
// Copyright (c) 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-CHROMIUM file.
#include "browser/net/devtools_network_transaction.h"
#include "browser/net/devtools_network_controller.h"
#include "browser/net/devtools_network_interceptor.h"
#include "net/base/net_errors.h"
#include "net/base/upload_progress.h"
#include "net/http/http_network_transaction.h"
#include "net/http/http_request_info.h"
#include "net/socket/connection_attempts.h"
namespace brightray {
namespace {
const char kDevToolsEmulateNetworkConditionsClientId[] =
"X-DevTools-Emulate-Network-Conditions-Client-Id";
} // namespace
DevToolsNetworkTransaction::DevToolsNetworkTransaction(
DevToolsNetworkController* controller,
scoped_ptr<net::HttpTransaction> transaction)
: controller_(controller),
transaction_(transaction.Pass()),
request_(nullptr),
failed_(false),
throttled_byte_count_(0),
callback_type_(NONE) {
proxy_callback_ = base::Bind(&DevToolsNetworkTransaction::OnCallback,
base::Unretained(this));
}
DevToolsNetworkTransaction::~DevToolsNetworkTransaction() {
if (interceptor_)
interceptor_->RemoveTransaction(this);
}
void DevToolsNetworkTransaction::ProcessRequest() {
DCHECK(request_);
bool has_devtools_client_id = request_->extra_headers.HasHeader(
kDevToolsEmulateNetworkConditionsClientId);
if (!has_devtools_client_id)
return;
custom_request_.reset(new net::HttpRequestInfo(*request_));
custom_request_->extra_headers.GetHeader(
kDevToolsEmulateNetworkConditionsClientId, &client_id_);
custom_request_->extra_headers.RemoveHeader(
kDevToolsEmulateNetworkConditionsClientId);
request_ = custom_request_.get();
}
void DevToolsNetworkTransaction::Fail() {
DCHECK(request_);
DCHECK(!failed_);
failed_ = true;
transaction_->SetBeforeNetworkStartCallback(
BeforeNetworkStartCallback());
if (callback_.is_null())
return;
net::CompletionCallback original_callback = callback_;
callback_.Reset();
callback_type_ = NONE;
original_callback.Run(net::ERR_INTERNET_DISCONNECTED);
}
void DevToolsNetworkTransaction::DecreaseThrottledByteCount(
int64_t delta) {
throttled_byte_count_ -= delta;
}
int DevToolsNetworkTransaction::Start(
const net::HttpRequestInfo* request,
const net::CompletionCallback& callback,
const net::BoundNetLog& net_log) {
DCHECK(request);
request_ = request;
interceptor_ = controller_->GetInterceptor(this);
interceptor_->AddTransaction(this);
if (interceptor_->ShouldFail(this)) {
failed_ = true;
transaction_->SetBeforeNetworkStartCallback(BeforeNetworkStartCallback());
return net::ERR_INTERNET_DISCONNECTED;
}
int rv = transaction_->Start(request_, proxy_callback_, net_log);
return SetupCallback(callback, rv, START);
}
int DevToolsNetworkTransaction::RestartIgnoringLastError(
const net::CompletionCallback& callback) {
if (failed_)
return net::ERR_INTERNET_DISCONNECTED;
int rv = transaction_->RestartIgnoringLastError(proxy_callback_);
return SetupCallback(callback, rv, RESTART_IGNORING_LAST_ERROR);
}
int DevToolsNetworkTransaction::RestartWithCertificate(
net::X509Certificate* client_certificate,
const net::CompletionCallback& callback) {
if (failed_)
return net::ERR_INTERNET_DISCONNECTED;
int rv = transaction_->RestartWithCertificate(client_certificate, proxy_callback_);
return SetupCallback(callback, rv, RESTART_WITH_CERTIFICATE);
}
int DevToolsNetworkTransaction::RestartWithAuth(
const net::AuthCredentials& credentials,
const net::CompletionCallback& callback) {
if (failed_)
return net::ERR_INTERNET_DISCONNECTED;
int rv = transaction_->RestartWithAuth(credentials, proxy_callback_);
return SetupCallback(callback, rv, RESTART_WITH_AUTH);
}
bool DevToolsNetworkTransaction::IsReadyToRestartForAuth() {
return transaction_->IsReadyToRestartForAuth();
}
int DevToolsNetworkTransaction::Read(
net::IOBuffer* buffer,
int length,
const net::CompletionCallback& callback) {
if (failed_)
return net::ERR_INTERNET_DISCONNECTED;
int rv = transaction_->Read(buffer, length, proxy_callback_);
return SetupCallback(callback, rv, READ);
}
void DevToolsNetworkTransaction::StopCaching() {
transaction_->StopCaching();
}
bool DevToolsNetworkTransaction::GetFullRequestHeaders(
net::HttpRequestHeaders* headers) const {
return transaction_->GetFullRequestHeaders(headers);
}
int64_t DevToolsNetworkTransaction::GetTotalReceivedBytes() const {
return transaction_->GetTotalReceivedBytes();
}
void DevToolsNetworkTransaction::DoneReading() {
transaction_->DoneReading();
}
const net::HttpResponseInfo*
DevToolsNetworkTransaction::GetResponseInfo() const {
return transaction_->GetResponseInfo();
}
net::LoadState DevToolsNetworkTransaction::GetLoadState() const {
return transaction_->GetLoadState();
}
net::UploadProgress DevToolsNetworkTransaction::GetUploadProgress() const {
return transaction_->GetUploadProgress();
}
void DevToolsNetworkTransaction::SetQuicServerInfo(
net::QuicServerInfo* info) {
transaction_->SetQuicServerInfo(info);
}
bool DevToolsNetworkTransaction::GetLoadTimingInfo(
net::LoadTimingInfo* info) const {
return transaction_->GetLoadTimingInfo(info);
}
void DevToolsNetworkTransaction::SetPriority(net::RequestPriority priority) {
transaction_->SetPriority(priority);
}
void DevToolsNetworkTransaction::SetWebSocketHandshakeStreamCreateHelper(
net::WebSocketHandshakeStreamBase::CreateHelper* helper) {
transaction_->SetWebSocketHandshakeStreamCreateHelper(helper);
}
void DevToolsNetworkTransaction::SetBeforeNetworkStartCallback(
const BeforeNetworkStartCallback& callback) {
transaction_->SetBeforeNetworkStartCallback(callback);
}
void DevToolsNetworkTransaction::SetBeforeProxyHeadersSentCallback(
const BeforeProxyHeadersSentCallback& callback) {
transaction_->SetBeforeProxyHeadersSentCallback(callback);
}
int DevToolsNetworkTransaction::ResumeNetworkStart() {
if (failed_)
return net::ERR_INTERNET_DISCONNECTED;
return transaction_->ResumeNetworkStart();
}
void DevToolsNetworkTransaction::GetConnectionAttempts(
net::ConnectionAttempts* out) const {
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

View file

@ -0,0 +1,131 @@
// 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 BROWSER_DEVTOOLS_NETWORK_TRANSACTION_H_
#define BROWSER_DEVTOOLS_NETWORK_TRANSACTION_H_
#include <stdint.h>
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "net/base/completion_callback.h"
#include "net/base/load_states.h"
#include "net/base/request_priority.h"
#include "net/http/http_transaction.h"
#include "net/websockets/websocket_handshake_stream_base.h"
namespace brightray {
class DevToolsNetworkController;
class DevToolsNetworkInterceptor;
class DevToolsNetworkTransaction : public net::HttpTransaction {
public:
DevToolsNetworkTransaction(
DevToolsNetworkController* controller,
scoped_ptr<net::HttpTransaction> network_transaction);
~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:
int Start(const net::HttpRequestInfo* request,
const net::CompletionCallback& callback,
const net::BoundNetLog& net_log) override;
int RestartIgnoringLastError(
const net::CompletionCallback& callback) override;
int RestartWithCertificate(net::X509Certificate* client_cert,
const net::CompletionCallback& callback) override;
int RestartWithAuth(const net::AuthCredentials& credentials,
const net::CompletionCallback& callback) override;
bool IsReadyToRestartForAuth() override;
int Read(net::IOBuffer* buf,
int buf_len,
const net::CompletionCallback& callback) override;
void StopCaching() override;
bool GetFullRequestHeaders(net::HttpRequestHeaders* headers) const override;
int64_t GetTotalReceivedBytes() const override;
void DoneReading() override;
const net::HttpResponseInfo* GetResponseInfo() const override;
net::LoadState GetLoadState() const override;
net::UploadProgress GetUploadProgress() const override;
void SetQuicServerInfo(net::QuicServerInfo* quic_server_info) override;
bool GetLoadTimingInfo(net::LoadTimingInfo* load_timing_info) const override;
void SetPriority(net::RequestPriority priority) override;
void SetWebSocketHandshakeStreamCreateHelper(
net::WebSocketHandshakeStreamBase::CreateHelper* create_helper) override;
void SetBeforeNetworkStartCallback(
const BeforeNetworkStartCallback& callback) override;
void SetBeforeProxyHeadersSentCallback(
const BeforeProxyHeadersSentCallback& callback) override;
int ResumeNetworkStart() 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:
enum CallbackType {
NONE,
READ,
RESTART_IGNORING_LAST_ERROR,
RESTART_WITH_AUTH,
RESTART_WITH_CERTIFICATE,
START
};
// Proxy callback handler. Runs saved callback.
void OnCallback(int result);
int SetupCallback(
net::CompletionCallback callback,
int result,
CallbackType callback_type);
void Throttle(int result);
DevToolsNetworkController* controller_;
base::WeakPtr<DevToolsNetworkInterceptor> interceptor_;
// Modified request. Should be destructed after |transaction_|
scoped_ptr<net::HttpRequestInfo> custom_request_;
// Original network transaction.
scoped_ptr<net::HttpTransaction> transaction_;
const net::HttpRequestInfo* request_;
// True if Fail was already invoked.
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);
};
} // namespace brightray
#endif // BROWSER_DEVTOOLS_NETWORK_TRANSACTION_H_

View file

@ -0,0 +1,45 @@
// Copyright (c) 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-CHROMIUM file.
#include "browser/net/devtools_network_transaction_factory.h"
#include "browser/net/devtools_network_controller.h"
#include "browser/net/devtools_network_transaction.h"
#include "net/base/net_errors.h"
#include "net/http/http_network_layer.h"
#include "net/http/http_network_transaction.h"
namespace brightray {
DevToolsNetworkTransactionFactory::DevToolsNetworkTransactionFactory(
DevToolsNetworkController* controller,
net::HttpNetworkSession* session)
: controller_(controller),
network_layer_(new net::HttpNetworkLayer(session)) {
}
DevToolsNetworkTransactionFactory::~DevToolsNetworkTransactionFactory() {
}
int DevToolsNetworkTransactionFactory::CreateTransaction(
net::RequestPriority priority,
scoped_ptr<net::HttpTransaction>* transaction) {
scoped_ptr<net::HttpTransaction> new_transaction;
int rv = network_layer_->CreateTransaction(priority, &new_transaction);
if (rv != net::OK)
return rv;
transaction->reset(new DevToolsNetworkTransaction(controller_, new_transaction.Pass()));
return net::OK;
}
net::HttpCache* DevToolsNetworkTransactionFactory::GetCache() {
return network_layer_->GetCache();
}
net::HttpNetworkSession* DevToolsNetworkTransactionFactory::GetSession() {
return network_layer_->GetSession();
}
} // namespace brightray

View file

@ -0,0 +1,39 @@
// Copyright (c) 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-CHROMIUM file.
#ifndef BROWSER_DEVTOOLS_NETWORK_TRANSACTION_FACTORY_H_
#define BROWSER_DEVTOOLS_NETWORK_TRANSACTION_FACTORY_H_
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "net/base/request_priority.h"
#include "net/http/http_transaction_factory.h"
namespace brightray {
class DevToolsNetworkController;
class DevToolsNetworkTransactionFactory : public net::HttpTransactionFactory {
public:
explicit DevToolsNetworkTransactionFactory(
DevToolsNetworkController* controller,
net::HttpNetworkSession* session);
~DevToolsNetworkTransactionFactory() override;
// net::HttpTransactionFactory:
int CreateTransaction(net::RequestPriority priority,
scoped_ptr<net::HttpTransaction>* transaction) override;
net::HttpCache* GetCache() override;
net::HttpNetworkSession* GetSession() override;
private:
DevToolsNetworkController* controller_;
scoped_ptr<net::HttpTransactionFactory> network_layer_;
DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkTransactionFactory);
};
} // namespace brightray
#endif // BROWSER_DEVTOOLS_NETWORK_TRANSACTION_FACTORY_H_

View file

@ -6,6 +6,8 @@
#include <algorithm>
#include "browser/net/devtools_network_controller.h"
#include "browser/net/devtools_network_transaction_factory.h"
#include "browser/net_log.h"
#include "browser/network_delegate.h"
@ -123,6 +125,7 @@ net::SSLConfigService* URLRequestContextGetter::Delegate::CreateSSLConfigService
URLRequestContextGetter::URLRequestContextGetter(
Delegate* delegate,
DevToolsNetworkController* controller,
NetLog* net_log,
const base::FilePath& base_path,
bool in_memory,
@ -131,6 +134,7 @@ URLRequestContextGetter::URLRequestContextGetter(
content::ProtocolHandlerMap* protocol_handlers,
content::URLRequestInterceptorScopedVector protocol_interceptors)
: delegate_(delegate),
controller_(controller),
net_log_(net_log),
base_path_(base_path),
in_memory_(in_memory),
@ -279,13 +283,17 @@ net::URLRequestContext* URLRequestContextGetter::GetURLRequestContext() {
storage_->set_host_resolver(host_resolver.Pass());
network_session_params.host_resolver = url_request_context_->host_resolver();
net::HttpNetworkSession* session = new net::HttpNetworkSession(network_session_params);
net::HttpCache::BackendFactory* backend = nullptr;
if (in_memory_) {
backend = net::HttpCache::DefaultBackend::InMemory(0);
} else {
backend = delegate_->CreateHttpCacheBackendFactory(base_path_);
}
storage_->set_http_transaction_factory(new net::HttpCache(network_session_params, backend));
storage_->set_http_transaction_factory(new net::HttpCache(
new DevToolsNetworkTransactionFactory(controller_, session),
url_request_context_->net_log(),
backend));
storage_->set_job_factory(delegate_->CreateURLRequestJobFactory(
&protocol_handlers_, &protocol_interceptors_));

View file

@ -27,6 +27,7 @@ class URLRequestJobFactory;
namespace brightray {
class DevToolsNetworkController;
class NetLog;
class URLRequestContextGetter : public net::URLRequestContextGetter {
@ -48,6 +49,7 @@ class URLRequestContextGetter : public net::URLRequestContextGetter {
URLRequestContextGetter(
Delegate* delegate,
DevToolsNetworkController* controller,
NetLog* net_log,
const base::FilePath& base_path,
bool in_memory,
@ -66,6 +68,7 @@ class URLRequestContextGetter : public net::URLRequestContextGetter {
private:
Delegate* delegate_;
DevToolsNetworkController* controller_;
NetLog* net_log_;
base::FilePath base_path_;
bool in_memory_;

View file

@ -38,6 +38,18 @@
'browser/media/media_capture_devices_dispatcher.h',
'browser/media/media_stream_devices_controller.cc',
'browser/media/media_stream_devices_controller.h',
'browser/net/devtools_network_conditions.cc',
'browser/net/devtools_network_conditions.h',
'browser/net/devtools_network_controller.cc',
'browser/net/devtools_network_controller.h',
'browser/net/devtools_network_interceptor.cc',
'browser/net/devtools_network_interceptor.h',
'browser/net/devtools_network_protocol_handler.cc',
'browser/net/devtools_network_protocol_handler.h',
'browser/net/devtools_network_transaction_factory.cc',
'browser/net/devtools_network_transaction_factory.h',
'browser/net/devtools_network_transaction.cc',
'browser/net/devtools_network_transaction.h',
'browser/net_log.cc',
'browser/net_log.h',
'browser/network_delegate.cc',