summaryrefslogtreecommitdiffstats
path: root/chrome/browser/devtools
diff options
context:
space:
mode:
authoreustas@chromium.org <eustas@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-02 16:03:08 +0000
committereustas@chromium.org <eustas@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-02 16:03:08 +0000
commita4205207e8e6bba4ebe0946b9d0b34abe946065f (patch)
treed3eb03bd5a2b18d30be9a887bc0291e4a93ce455 /chrome/browser/devtools
parentdbe9bfab6e9b264b1b339e8c1c422f0b5dfa2a6c (diff)
downloadchromium_src-a4205207e8e6bba4ebe0946b9d0b34abe946065f.zip
chromium_src-a4205207e8e6bba4ebe0946b9d0b34abe946065f.tar.gz
chromium_src-a4205207e8e6bba4ebe0946b9d0b34abe946065f.tar.bz2
Add the ability for DevTools to wrap network transactions.
The eventual goal is to allow it to simulate flaky network connections. Docs: https://docs.google.com/a/google.com/document/d/1SkuWqLYIUpMDI05n7vgx8zdkunyUsxGs9tvUPDOqEJY/edit https://docs.google.com/a/google.com/document/d/19O_UeUfCFZg5cEnH5jkkZ6_tqsfaLQLYUEIGyXw3oTo/edit BUG=245436 Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=273584 Review URL: https://codereview.chromium.org/182993003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274253 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/devtools')
-rw-r--r--chrome/browser/devtools/chrome_devtools_manager_delegate.cc76
-rw-r--r--chrome/browser/devtools/chrome_devtools_manager_delegate.h19
-rw-r--r--chrome/browser/devtools/devtools_network_controller.cc92
-rw-r--r--chrome/browser/devtools/devtools_network_controller.h73
-rw-r--r--chrome/browser/devtools/devtools_network_controller_unittest.cc193
-rw-r--r--chrome/browser/devtools/devtools_network_transaction.cc178
-rw-r--r--chrome/browser/devtools/devtools_network_transaction.h111
-rw-r--r--chrome/browser/devtools/devtools_network_transaction_factory.cc42
-rw-r--r--chrome/browser/devtools/devtools_network_transaction_factory.h43
9 files changed, 826 insertions, 1 deletions
diff --git a/chrome/browser/devtools/chrome_devtools_manager_delegate.cc b/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
index 9b1f08b..9eb641c 100644
--- a/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
+++ b/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
@@ -4,14 +4,40 @@
#include "chrome/browser/devtools/chrome_devtools_manager_delegate.h"
+#include "base/values.h"
+#include "chrome/browser/devtools/devtools_network_controller.h"
+#include "chrome/browser/devtools/devtools_protocol.h"
+#include "chrome/browser/devtools/devtools_protocol_constants.h"
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/devtools_agent_host.h"
+#include "content/public/browser/devtools_manager.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/site_instance.h"
-ChromeDevToolsManagerDelegate::ChromeDevToolsManagerDelegate() {
+ChromeDevToolsManagerDelegate::ChromeDevToolsManagerDelegate()
+ : devtools_callback_(base::Bind(
+ &ChromeDevToolsManagerDelegate::OnDevToolsStateChanged,
+ base::Unretained(this))),
+ devtools_callback_registered_(false) {
+ // This constructor is invoked from DevToolsManagerImpl constructor, so it
+ // shouldn't call DevToolsManager::GetInstance()
}
ChromeDevToolsManagerDelegate::~ChromeDevToolsManagerDelegate() {
+ // This destructor is invoked from DevToolsManagerImpl destructor, so it
+ // shouldn't call DevToolsManager::GetInstance()
+}
+
+void ChromeDevToolsManagerDelegate::EnsureDevtoolsCallbackRegistered() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ if (!devtools_callback_registered_) {
+ content::DevToolsManager::GetInstance()->AddAgentStateCallback(
+ devtools_callback_);
+ devtools_callback_registered_ = true;
+ }
}
void ChromeDevToolsManagerDelegate::Inspect(
@@ -30,5 +56,53 @@ void ChromeDevToolsManagerDelegate::Inspect(
base::DictionaryValue* ChromeDevToolsManagerDelegate::HandleCommand(
content::DevToolsAgentHost* agent_host,
base::DictionaryValue* command_dict) {
+ scoped_ptr<DevToolsProtocol::Command> command(
+ DevToolsProtocol::ParseCommand(command_dict));
+ if (!command)
+ return NULL;
+ const std::string method = command->method();
+ if (method == chrome::devtools::Network::emulateNetworkConditions::kName)
+ return EmulateNetworkConditions(agent_host, command.get())->Serialize();
return NULL;
}
+
+Profile* ChromeDevToolsManagerDelegate::GetProfile(
+ content::DevToolsAgentHost* agent_host) {
+ content::RenderViewHost* host = agent_host->GetRenderViewHost();
+ if (!host)
+ return NULL;
+ return Profile::FromBrowserContext(host->GetSiteInstance()->GetProcess()->
+ GetBrowserContext());
+}
+
+scoped_ptr<DevToolsProtocol::Response>
+ChromeDevToolsManagerDelegate::EmulateNetworkConditions(
+ content::DevToolsAgentHost* agent_host,
+ DevToolsProtocol::Command* command) {
+ base::DictionaryValue* params = command->params();
+ bool offline = false;
+ const char* offline_param =
+ chrome::devtools::Network::emulateNetworkConditions::kParamOffline;
+ if (!params || !params->GetBoolean(offline_param, &offline))
+ return command->InvalidParamResponse(offline_param);
+
+ EnsureDevtoolsCallbackRegistered();
+ UpdateNetworkState(agent_host, offline);
+ return command->SuccessResponse(NULL);
+}
+
+void ChromeDevToolsManagerDelegate::UpdateNetworkState(
+ content::DevToolsAgentHost* agent_host,
+ bool offline) {
+ Profile* profile = GetProfile(agent_host);
+ if (!profile)
+ return;
+ profile->GetDevToolsNetworkController()->SetNetworkState(
+ agent_host->GetId(), offline);
+}
+
+void ChromeDevToolsManagerDelegate::OnDevToolsStateChanged(
+ content::DevToolsAgentHost* agent_host,
+ bool attached) {
+ UpdateNetworkState(agent_host, false);
+}
diff --git a/chrome/browser/devtools/chrome_devtools_manager_delegate.h b/chrome/browser/devtools/chrome_devtools_manager_delegate.h
index 4de8369..9b38332 100644
--- a/chrome/browser/devtools/chrome_devtools_manager_delegate.h
+++ b/chrome/browser/devtools/chrome_devtools_manager_delegate.h
@@ -5,10 +5,14 @@
#ifndef CHROME_BROWSER_DEVTOOLS_CHROME_DEVTOOLS_MANAGER_DELEGATE_H_
#define CHROME_BROWSER_DEVTOOLS_CHROME_DEVTOOLS_MANAGER_DELEGATE_H_
+#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "chrome/browser/devtools/devtools_protocol.h"
#include "content/public/browser/devtools_manager_delegate.h"
+class Profile;
+
class ChromeDevToolsManagerDelegate : public content::DevToolsManagerDelegate {
public:
ChromeDevToolsManagerDelegate();
@@ -22,6 +26,21 @@ class ChromeDevToolsManagerDelegate : public content::DevToolsManagerDelegate {
base::DictionaryValue* command_dict) OVERRIDE;
private:
+ base::Callback<void(content::DevToolsAgentHost*, bool)> devtools_callback_;
+ bool devtools_callback_registered_;
+ void EnsureDevtoolsCallbackRegistered();
+
+ Profile* GetProfile(content::DevToolsAgentHost* agent_host);
+
+ scoped_ptr<DevToolsProtocol::Response> EmulateNetworkConditions(
+ content::DevToolsAgentHost* agent_host,
+ DevToolsProtocol::Command* command);
+
+ void UpdateNetworkState(content::DevToolsAgentHost* agent_host, bool offline);
+
+ void OnDevToolsStateChanged(content::DevToolsAgentHost* agent_host,
+ bool attached);
+
DISALLOW_COPY_AND_ASSIGN(ChromeDevToolsManagerDelegate);
};
diff --git a/chrome/browser/devtools/devtools_network_controller.cc b/chrome/browser/devtools/devtools_network_controller.cc
new file mode 100644
index 0000000..4ed7dfa
--- /dev/null
+++ b/chrome/browser/devtools/devtools_network_controller.cc
@@ -0,0 +1,92 @@
+// 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_controller.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/resource_context.h"
+
+using content::BrowserThread;
+
+namespace {
+
+const char kDevToolsRequestInitiator[] = "X-DevTools-Request-Initiator";
+
+} // namespace
+
+DevToolsNetworkController::DevToolsNetworkController()
+ : weak_ptr_factory_(this) {
+}
+
+DevToolsNetworkController::~DevToolsNetworkController() {
+}
+
+void DevToolsNetworkController::AddTransaction(
+ DevToolsNetworkTransaction* transaction) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ transactions_.insert(transaction);
+}
+
+void DevToolsNetworkController::RemoveTransaction(
+ DevToolsNetworkTransaction* transaction) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(transactions_.find(transaction) != transactions_.end());
+ transactions_.erase(transaction);
+}
+
+void DevToolsNetworkController::SetNetworkState(
+ const std::string& client_id,
+ bool offline) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(
+ content::BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(
+ &DevToolsNetworkController::SetNetworkStateOnIO,
+ weak_ptr_factory_.GetWeakPtr(),
+ client_id,
+ offline));
+}
+
+void DevToolsNetworkController::SetNetworkStateOnIO(
+ const std::string& client_id,
+ bool offline) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!offline) {
+ clients_.erase(client_id);
+ return;
+ }
+ clients_.insert(client_id);
+
+ // Iterate over a copy of set, because failing of transaction could result in
+ // creating a new one, or (theoretically) destroying one.
+ Transactions old_transactions(transactions_);
+ for (Transactions::iterator it = old_transactions.begin();
+ it != old_transactions.end(); ++it) {
+ if (transactions_.find(*it) == transactions_.end())
+ continue;
+ if (!(*it)->request() || (*it)->failed())
+ continue;
+ if (ShouldFail((*it)->request()))
+ (*it)->Fail();
+ }
+}
+
+bool DevToolsNetworkController::ShouldFail(
+ const net::HttpRequestInfo* request) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(request);
+ if (clients_.empty())
+ return false;
+
+ if (request->extra_headers.HasHeader(kDevToolsRequestInitiator))
+ return false;
+
+ // TODO: Add domain blacklist.
+
+ return true;
+}
diff --git a/chrome/browser/devtools/devtools_network_controller.h b/chrome/browser/devtools/devtools_network_controller.h
new file mode 100644
index 0000000..b917049
--- /dev/null
+++ b/chrome/browser/devtools/devtools_network_controller.h
@@ -0,0 +1,73 @@
+// 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_CONTROLLER_H_
+#define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_CONTROLLER_H_
+
+#include <set>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
+
+class DevToolsNetworkTransaction;
+class GURL;
+class Profile;
+
+namespace content {
+class ResourceContext;
+}
+
+namespace net {
+struct HttpRequestInfo;
+}
+
+namespace test {
+class DevToolsNetworkControllerHelper;
+}
+
+// DevToolsNetworkController tracks DevToolsNetworkTransactions.
+class DevToolsNetworkController {
+
+ public:
+ DevToolsNetworkController();
+ virtual ~DevToolsNetworkController();
+
+ void AddTransaction(DevToolsNetworkTransaction* transaction);
+
+ void RemoveTransaction(DevToolsNetworkTransaction* transaction);
+
+ // Applies network emulation configuration.
+ // |client_id| should be DevToolsAgentHost GUID.
+ void SetNetworkState(
+ const std::string& client_id,
+ bool disable_network);
+
+ bool ShouldFail(const net::HttpRequestInfo* request);
+
+ protected:
+ friend class test::DevToolsNetworkControllerHelper;
+
+ private:
+ // Controller must be constructed on IO thread.
+ base::ThreadChecker thread_checker_;
+
+ void SetNetworkStateOnIO(
+ const std::string& client_id,
+ bool disable_network);
+
+ typedef std::set<DevToolsNetworkTransaction*> Transactions;
+ Transactions transactions_;
+
+ typedef std::set<std::string> Clients;
+ Clients clients_;
+
+ base::WeakPtrFactory<DevToolsNetworkController> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkController);
+};
+
+#endif // CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_CONTROLLER_H_
diff --git a/chrome/browser/devtools/devtools_network_controller_unittest.cc b/chrome/browser/devtools/devtools_network_controller_unittest.cc
new file mode 100644
index 0000000..6fe6256
--- /dev/null
+++ b/chrome/browser/devtools/devtools_network_controller_unittest.cc
@@ -0,0 +1,193 @@
+// 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 <string>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "chrome/browser/devtools/devtools_network_controller.h"
+#include "chrome/browser/devtools/devtools_network_transaction.h"
+#include "net/http/http_transaction_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace test {
+
+const char kClientId[] = "42";
+const char kAnotherClientId[] = "24";
+
+class TestCallback {
+ public:
+ TestCallback() : run_count_(0), value_(0) {}
+ void Run(int value) {
+ run_count_++;
+ value_ = value;
+ }
+ int run_count() { return run_count_; }
+ int value() { return value_; }
+
+ private:
+ int run_count_;
+ int value_;
+};
+
+class DevToolsNetworkControllerHelper {
+ public:
+ DevToolsNetworkControllerHelper() :
+ completion_callback_(
+ base::Bind(&TestCallback::Run, base::Unretained(&callback_))),
+ mock_transaction_(kSimpleGET_Transaction),
+ buffer_(new net::IOBuffer(64)) {
+ mock_transaction_.test_mode = TEST_MODE_SYNC_NET_START;
+ mock_transaction_.url = "http://dot.com";
+ AddMockTransaction(&mock_transaction_);
+
+ scoped_ptr<net::HttpTransaction> network_transaction;
+ network_layer_.CreateTransaction(
+ net::DEFAULT_PRIORITY, &network_transaction);
+ transaction_.reset(new DevToolsNetworkTransaction(
+ &controller_, network_transaction.Pass()));
+ }
+
+ net::HttpRequestInfo* GetRequest() {
+ if (!request_)
+ request_.reset(new MockHttpRequest(mock_transaction_));
+ return request_.get();
+ }
+
+ void SetNetworkState(const std::string& client_id, bool offline) {
+ controller_.SetNetworkStateOnIO(client_id, offline);
+ }
+
+ int Start() {
+ return transaction_->Start(
+ GetRequest(), completion_callback_, net::BoundNetLog());
+ }
+
+ int Read() {
+ return transaction_->Read(buffer_.get(), 64, completion_callback_);
+ }
+
+ ~DevToolsNetworkControllerHelper() {
+ RemoveMockTransaction(&mock_transaction_);
+ }
+
+ TestCallback* callback() { return &callback_; }
+ MockTransaction* mock_transaction() { return &mock_transaction_; }
+ DevToolsNetworkController* controller() { return &controller_; }
+ DevToolsNetworkTransaction* transaction() { return transaction_.get(); }
+
+ private:
+ base::MessageLoop message_loop_;
+ MockNetworkLayer network_layer_;
+ TestCallback callback_;
+ net::CompletionCallback completion_callback_;
+ MockTransaction mock_transaction_;
+ DevToolsNetworkController controller_;
+ scoped_ptr<DevToolsNetworkTransaction> transaction_;
+ scoped_refptr<net::IOBuffer> buffer_;
+ scoped_ptr<MockHttpRequest> request_;
+};
+
+TEST(DevToolsNetworkControllerTest, SingleDisableEnable) {
+ DevToolsNetworkControllerHelper helper;
+ DevToolsNetworkController* controller = helper.controller();
+ net::HttpRequestInfo* request = helper.GetRequest();
+
+ EXPECT_FALSE(controller->ShouldFail(request));
+ helper.SetNetworkState(kClientId, true);
+ EXPECT_TRUE(controller->ShouldFail(request));
+ helper.SetNetworkState(kClientId, false);
+ EXPECT_FALSE(controller->ShouldFail(request));
+}
+
+TEST(DevToolsNetworkControllerTest, DoubleDisableEnable) {
+ DevToolsNetworkControllerHelper helper;
+ DevToolsNetworkController* controller = helper.controller();
+ net::HttpRequestInfo* request = helper.GetRequest();
+
+ EXPECT_FALSE(controller->ShouldFail(request));
+ helper.SetNetworkState(kClientId, true);
+ EXPECT_TRUE(controller->ShouldFail(request));
+ helper.SetNetworkState(kAnotherClientId, true);
+ EXPECT_TRUE(controller->ShouldFail(request));
+ helper.SetNetworkState(kClientId, false);
+ EXPECT_TRUE(controller->ShouldFail(request));
+ helper.SetNetworkState(kAnotherClientId, false);
+ EXPECT_FALSE(controller->ShouldFail(request));
+}
+
+TEST(DevToolsNetworkControllerTest, FailOnStart) {
+ DevToolsNetworkControllerHelper helper;
+ helper.SetNetworkState(kClientId, true);
+
+ int rv = helper.Start();
+ EXPECT_EQ(rv, net::ERR_INTERNET_DISCONNECTED);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(helper.callback()->run_count(), 0);
+}
+
+TEST(DevToolsNetworkControllerTest, FailRunningTransaction) {
+ DevToolsNetworkControllerHelper helper;
+ TestCallback* callback = helper.callback();
+
+ int rv = helper.Start();
+ EXPECT_EQ(rv, net::OK);
+
+ scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(64));
+ rv = helper.Read();
+ EXPECT_EQ(rv, net::ERR_IO_PENDING);
+ EXPECT_EQ(callback->run_count(), 0);
+
+ helper.SetNetworkState(kClientId, true);
+ EXPECT_EQ(callback->run_count(), 1);
+ EXPECT_EQ(callback->value(), net::ERR_INTERNET_DISCONNECTED);
+
+ // Wait until HttpTrancation completes reading and invokes callback.
+ // DevToolsNetworkTransaction should ignore callback, because it has
+ // reported network error already.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(callback->run_count(), 1);
+
+ // Check that transaction in not failed second time.
+ helper.SetNetworkState(kClientId, false);
+ helper.SetNetworkState(kClientId, true);
+ EXPECT_EQ(callback->run_count(), 1);
+}
+
+TEST(DevToolsNetworkControllerTest, ReadAfterFail) {
+ DevToolsNetworkControllerHelper helper;
+
+ int rv = helper.Start();
+ EXPECT_EQ(rv, net::OK);
+ EXPECT_TRUE(helper.transaction()->request());
+
+ helper.SetNetworkState(kClientId, true);
+ EXPECT_TRUE(helper.transaction()->failed());
+
+ scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(64));
+ rv = helper.Read();
+ EXPECT_EQ(rv, net::ERR_INTERNET_DISCONNECTED);
+
+ // Check that callback is never invoked.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(helper.callback()->run_count(), 0);
+}
+
+TEST(DevToolsNetworkControllerTest, AllowsDevToolsRequests) {
+ DevToolsNetworkControllerHelper helper;
+ helper.mock_transaction()->request_headers =
+ "X-DevTools-Request-Initiator: frontend\r\n";
+ DevToolsNetworkController* controller = helper.controller();
+ net::HttpRequestInfo* request = helper.GetRequest();
+
+ EXPECT_FALSE(controller->ShouldFail(request));
+ helper.SetNetworkState(kClientId, true);
+ EXPECT_FALSE(controller->ShouldFail(request));
+}
+
+} // namespace test
diff --git a/chrome/browser/devtools/devtools_network_transaction.cc b/chrome/browser/devtools/devtools_network_transaction.cc
new file mode 100644
index 0000000..bba196c
--- /dev/null
+++ b/chrome/browser/devtools/devtools_network_transaction.cc
@@ -0,0 +1,178 @@
+// 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_transaction.h"
+
+#include "chrome/browser/devtools/devtools_network_controller.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"
+
+DevToolsNetworkTransaction::DevToolsNetworkTransaction(
+ DevToolsNetworkController* controller,
+ scoped_ptr<net::HttpTransaction> network_transaction)
+ : controller_(controller),
+ network_transaction_(network_transaction.Pass()),
+ request_(NULL),
+ failed_(false),
+ proxy_callback_(base::Bind(&DevToolsNetworkTransaction::OnCallback,
+ base::Unretained(this))) {
+ DCHECK(controller);
+ controller->AddTransaction(this);
+}
+
+DevToolsNetworkTransaction::~DevToolsNetworkTransaction() {
+ controller_->RemoveTransaction(this);
+}
+
+void DevToolsNetworkTransaction::OnCallback(int rv) {
+ if (failed_)
+ return;
+ DCHECK(!callback_.is_null());
+ net::CompletionCallback callback = callback_;
+ callback_.Reset();
+ callback.Run(rv);
+}
+
+void DevToolsNetworkTransaction::Fail() {
+ DCHECK(request_);
+ DCHECK(!failed_);
+ failed_ = true;
+ network_transaction_->SetBeforeNetworkStartCallback(
+ BeforeNetworkStartCallback());
+ if (callback_.is_null())
+ return;
+ net::CompletionCallback callback = callback_;
+ callback_.Reset();
+ callback.Run(net::ERR_INTERNET_DISCONNECTED);
+}
+
+int DevToolsNetworkTransaction::Start(
+ const net::HttpRequestInfo* request,
+ const net::CompletionCallback& callback,
+ const net::BoundNetLog& net_log) {
+ DCHECK(request);
+ request_ = request;
+
+ if (controller_->ShouldFail(request_)) {
+ failed_ = true;
+ network_transaction_->SetBeforeNetworkStartCallback(
+ BeforeNetworkStartCallback());
+ return net::ERR_INTERNET_DISCONNECTED;
+ }
+ int rv = network_transaction_->Start(request, proxy_callback_, net_log);
+ if (rv == net::ERR_IO_PENDING)
+ callback_ = callback;
+ return rv;
+}
+
+int DevToolsNetworkTransaction::RestartIgnoringLastError(
+ const net::CompletionCallback& callback) {
+ if (failed_)
+ return net::ERR_INTERNET_DISCONNECTED;
+ int rv = network_transaction_->RestartIgnoringLastError(proxy_callback_);
+ if (rv == net::ERR_IO_PENDING)
+ callback_ = callback;
+ return rv;
+}
+
+int DevToolsNetworkTransaction::RestartWithCertificate(
+ net::X509Certificate* client_cert,
+ const net::CompletionCallback& callback) {
+ if (failed_)
+ return net::ERR_INTERNET_DISCONNECTED;
+ int rv = network_transaction_->RestartWithCertificate(
+ client_cert, proxy_callback_);
+ if (rv == net::ERR_IO_PENDING)
+ callback_ = callback;
+ return rv;
+}
+
+int DevToolsNetworkTransaction::RestartWithAuth(
+ const net::AuthCredentials& credentials,
+ const net::CompletionCallback& callback) {
+ if (failed_)
+ return net::ERR_INTERNET_DISCONNECTED;
+ int rv = network_transaction_->RestartWithAuth(credentials, proxy_callback_);
+ if (rv == net::ERR_IO_PENDING)
+ callback_ = callback;
+ return rv;
+}
+
+bool DevToolsNetworkTransaction::IsReadyToRestartForAuth() {
+ return network_transaction_->IsReadyToRestartForAuth();
+}
+
+int DevToolsNetworkTransaction::Read(
+ net::IOBuffer* buf,
+ int buf_len,
+ const net::CompletionCallback& callback) {
+ if (failed_)
+ return net::ERR_INTERNET_DISCONNECTED;
+ int rv = network_transaction_->Read(buf, buf_len, proxy_callback_);
+ if (rv == net::ERR_IO_PENDING)
+ callback_ = callback;
+ return rv;
+}
+
+void DevToolsNetworkTransaction::StopCaching() {
+ network_transaction_->StopCaching();
+}
+
+bool DevToolsNetworkTransaction::GetFullRequestHeaders(
+ net::HttpRequestHeaders* headers) const {
+ return network_transaction_->GetFullRequestHeaders(headers);
+}
+
+int64 DevToolsNetworkTransaction::GetTotalReceivedBytes() const {
+ return network_transaction_->GetTotalReceivedBytes();
+}
+
+void DevToolsNetworkTransaction::DoneReading() {
+ network_transaction_->DoneReading();
+}
+
+const net::HttpResponseInfo*
+DevToolsNetworkTransaction::GetResponseInfo() const {
+ return network_transaction_->GetResponseInfo();
+}
+
+net::LoadState DevToolsNetworkTransaction::GetLoadState() const {
+ return network_transaction_->GetLoadState();
+}
+
+net::UploadProgress DevToolsNetworkTransaction::GetUploadProgress() const {
+ return network_transaction_->GetUploadProgress();
+}
+
+void DevToolsNetworkTransaction::SetQuicServerInfo(
+ net::QuicServerInfo* quic_server_info) {
+ network_transaction_->SetQuicServerInfo(quic_server_info);
+}
+
+bool DevToolsNetworkTransaction::GetLoadTimingInfo(
+ net::LoadTimingInfo* load_timing_info) const {
+ return network_transaction_->GetLoadTimingInfo(load_timing_info);
+}
+
+void DevToolsNetworkTransaction::SetPriority(net::RequestPriority priority) {
+ network_transaction_->SetPriority(priority);
+}
+
+void DevToolsNetworkTransaction::SetWebSocketHandshakeStreamCreateHelper(
+ net::WebSocketHandshakeStreamBase::CreateHelper* create_helper) {
+ network_transaction_->SetWebSocketHandshakeStreamCreateHelper(create_helper);
+}
+
+void DevToolsNetworkTransaction::SetBeforeNetworkStartCallback(
+ const BeforeNetworkStartCallback& callback) {
+ network_transaction_->SetBeforeNetworkStartCallback(callback);
+}
+
+int DevToolsNetworkTransaction::ResumeNetworkStart() {
+ if (failed_)
+ return net::ERR_INTERNET_DISCONNECTED;
+ return network_transaction_->ResumeNetworkStart();
+}
diff --git a/chrome/browser/devtools/devtools_network_transaction.h b/chrome/browser/devtools/devtools_network_transaction.h
new file mode 100644
index 0000000..5a51ab2
--- /dev/null
+++ b/chrome/browser/devtools/devtools_network_transaction.h
@@ -0,0 +1,111 @@
+// 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_TRANSACTION_H_
+#define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_TRANSACTION_H_
+
+#include "base/memory/scoped_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"
+
+class DevToolsNetworkController;
+class GURL;
+
+namespace net {
+class AuthCredentials;
+class BoundNetLog;
+class HttpRequestHeaders;
+struct HttpRequestInfo;
+class HttpResponseInfo;
+class HttpNetworkSession;
+class IOBuffer;
+struct LoadTimingInfo;
+class UploadProgress;
+class X509Certificate;
+}
+
+// DevToolsNetworkTransaction is a wrapper for network transaction. All
+// HttpTransaction methods are proxied to real transaction, but |callback|
+// parameter is saved and replaced with proxy callback. Fail method should be
+// used to simulate network outage. It runs saved callback (if any) with
+// net::ERR_INTERNET_DISCONNECTED result value.
+class DevToolsNetworkTransaction : public net::HttpTransaction {
+ public:
+ DevToolsNetworkTransaction(
+ DevToolsNetworkController* controller,
+ scoped_ptr<net::HttpTransaction> network_transaction);
+
+ virtual ~DevToolsNetworkTransaction();
+
+ const net::HttpRequestInfo* request() const { return request_; }
+ bool failed() const { return failed_; }
+
+ // Runs callback (if any) with net::ERR_INTERNET_DISCONNECTED result value.
+ void Fail();
+
+ // HttpTransaction methods:
+ virtual int Start(
+ const net::HttpRequestInfo* request,
+ const net::CompletionCallback& callback,
+ const net::BoundNetLog& net_log) OVERRIDE;
+ virtual int RestartIgnoringLastError(
+ const net::CompletionCallback& callback) OVERRIDE;
+ virtual int RestartWithCertificate(
+ net::X509Certificate* client_cert,
+ const net::CompletionCallback& callback) OVERRIDE;
+ virtual int RestartWithAuth(
+ const net::AuthCredentials& credentials,
+ const net::CompletionCallback& callback) OVERRIDE;
+ virtual bool IsReadyToRestartForAuth() OVERRIDE;
+
+ virtual int Read(
+ net::IOBuffer* buf,
+ int buf_len,
+ const net::CompletionCallback& callback) OVERRIDE;
+ virtual void StopCaching() OVERRIDE;
+ virtual bool GetFullRequestHeaders(
+ net::HttpRequestHeaders* headers) const OVERRIDE;
+ virtual int64 GetTotalReceivedBytes() const OVERRIDE;
+ virtual void DoneReading() OVERRIDE;
+ virtual const net::HttpResponseInfo* GetResponseInfo() const OVERRIDE;
+ virtual net::LoadState GetLoadState() const OVERRIDE;
+ virtual net::UploadProgress GetUploadProgress() const OVERRIDE;
+ virtual void SetQuicServerInfo(
+ net::QuicServerInfo* quic_server_info) OVERRIDE;
+ virtual bool GetLoadTimingInfo(
+ net::LoadTimingInfo* load_timing_info) const OVERRIDE;
+ virtual void SetPriority(net::RequestPriority priority) OVERRIDE;
+ virtual void SetWebSocketHandshakeStreamCreateHelper(
+ net::WebSocketHandshakeStreamBase::CreateHelper* create_helper) OVERRIDE;
+ virtual void SetBeforeNetworkStartCallback(
+ const BeforeNetworkStartCallback& callback) OVERRIDE;
+ virtual int ResumeNetworkStart() OVERRIDE;
+
+ private:
+ // Proxy callback handler. Runs saved callback.
+ void OnCallback(int result);
+
+ DevToolsNetworkController* controller_;
+
+ // Real network transaction.
+ scoped_ptr<net::HttpTransaction> network_transaction_;
+
+ const net::HttpRequestInfo* request_;
+
+ // True if Start was already invoked.
+ bool started_;
+
+ // True if Fail was already invoked.
+ bool failed_;
+
+ net::CompletionCallback proxy_callback_;
+ net::CompletionCallback callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkTransaction);
+};
+
+#endif // CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_TRANSACTION_H_
diff --git a/chrome/browser/devtools/devtools_network_transaction_factory.cc b/chrome/browser/devtools/devtools_network_transaction_factory.cc
new file mode 100644
index 0000000..3fd8b84
--- /dev/null
+++ b/chrome/browser/devtools/devtools_network_transaction_factory.cc
@@ -0,0 +1,42 @@
+// 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_transaction_factory.h"
+
+#include "chrome/browser/devtools/devtools_network_controller.h"
+#include "chrome/browser/devtools/devtools_network_transaction.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_network_layer.h"
+#include "net/http/http_network_transaction.h"
+
+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>* trans) {
+ scoped_ptr<net::HttpTransaction> network_transaction;
+ int rv = network_layer_->CreateTransaction(priority, &network_transaction);
+ if (rv != net::OK) {
+ return rv;
+ }
+ trans->reset(
+ new DevToolsNetworkTransaction(controller_, network_transaction.Pass()));
+ return net::OK;
+}
+
+net::HttpCache* DevToolsNetworkTransactionFactory::GetCache() {
+ return network_layer_->GetCache();
+}
+
+net::HttpNetworkSession* DevToolsNetworkTransactionFactory::GetSession() {
+ return network_layer_->GetSession();
+}
diff --git a/chrome/browser/devtools/devtools_network_transaction_factory.h b/chrome/browser/devtools/devtools_network_transaction_factory.h
new file mode 100644
index 0000000..9faec2c
--- /dev/null
+++ b/chrome/browser/devtools/devtools_network_transaction_factory.h
@@ -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 CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_TRANSACTION_FACTORY_H_
+#define CHROME_BROWSER_DEVTOOLS_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"
+
+class DevToolsNetworkController;
+
+namespace net {
+class HttpCache;
+class HttpNetworkSession;
+class HttpTransaction;
+}
+
+// NetworkTransactionFactory wraps HttpNetworkTransactions.
+class DevToolsNetworkTransactionFactory : public net::HttpTransactionFactory {
+ public:
+ DevToolsNetworkTransactionFactory(
+ DevToolsNetworkController* controller,
+ net::HttpNetworkSession* session);
+ virtual ~DevToolsNetworkTransactionFactory();
+
+ // net::HttpTransactionFactory methods:
+ virtual int CreateTransaction(
+ net::RequestPriority priority,
+ scoped_ptr<net::HttpTransaction>* trans) OVERRIDE;
+ virtual net::HttpCache* GetCache() OVERRIDE;
+ virtual net::HttpNetworkSession* GetSession() OVERRIDE;
+
+ private:
+ DevToolsNetworkController* controller_;
+ scoped_ptr<net::HttpTransactionFactory> network_layer_;
+
+ DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkTransactionFactory);
+};
+
+#endif // CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_TRANSACTION_FACTORY_H_