diff options
author | gagansingh@google.com <gagansingh@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-27 17:26:41 +0000 |
---|---|---|
committer | gagansingh@google.com <gagansingh@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-27 17:26:41 +0000 |
commit | 5e6efa537dc4c06912f0bb42f16991c7ee7eafbc (patch) | |
tree | bd1336ab3629d3afd20c57c2c9d6de04603e1a10 /net | |
parent | 0d1293040f1f79e3cddc52ba18fc6ec85f140800 (diff) | |
download | chromium_src-5e6efa537dc4c06912f0bb42f16991c7ee7eafbc.zip chromium_src-5e6efa537dc4c06912f0bb42f16991c7ee7eafbc.tar.gz chromium_src-5e6efa537dc4c06912f0bb42f16991c7ee7eafbc.tar.bz2 |
Warmth of a connection (cwnd) is estimated by the amount of data written to the socket.
Choosing the warmest connection would mean faster resource load times.
idle time is the time a socket has remained idle (no http requests being served on it).
Probability of server resetting a connection increases with idle time duration.
Using a cost function that takes into account bytes transferred and idle time to pick best connection to schedule http requests on.
CODEREVIEW done in http://codereview.chromium.org/6990036/
Contributed by gagansingh@google.com
Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=90373
Reverted: http://codereview.chromium.org/7255002 :(
Have fixed 2 things since:
1. Removed LOG(ERROR) from http_basic_stream.cc that was causing layout tests to fail.
2. Initialized class variables in http_basic_stream.cc that was causing uninitialized memory bugs in valgrind: http://code.google.com/p/chromium/issues/detail?id=87423
Review URL: http://codereview.chromium.org/7251004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@90601 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
38 files changed, 483 insertions, 11 deletions
diff --git a/net/curvecp/curvecp_client_socket.cc b/net/curvecp/curvecp_client_socket.cc index f28e839..95b36f6 100644 --- a/net/curvecp/curvecp_client_socket.cc +++ b/net/curvecp/curvecp_client_socket.cc @@ -88,6 +88,14 @@ bool CurveCPClientSocket::UsingTCPFastOpen() const { return false; } +int64 CurveCPClientSocket::NumBytesRead() const { + return -1; +} + +base::TimeDelta CurveCPClientSocket::GetConnectTimeMicros() const { + return base::TimeDelta::FromMicroseconds(-1); +} + int CurveCPClientSocket::Read(IOBuffer* buf, int buf_len, CompletionCallback* callback) { diff --git a/net/curvecp/curvecp_client_socket.h b/net/curvecp/curvecp_client_socket.h index 213b13d..c9faa63 100644 --- a/net/curvecp/curvecp_client_socket.h +++ b/net/curvecp/curvecp_client_socket.h @@ -36,6 +36,8 @@ class CurveCPClientSocket : public StreamSocket { virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; virtual bool UsingTCPFastOpen() const; + virtual int64 NumBytesRead() const; + virtual base::TimeDelta GetConnectTimeMicros() const; // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback); diff --git a/net/http/http_basic_stream.cc b/net/http/http_basic_stream.cc index 6501a59..08785b8 100644 --- a/net/http/http_basic_stream.cc +++ b/net/http/http_basic_stream.cc @@ -4,6 +4,8 @@ #include "net/http/http_basic_stream.h" +#include "base/format_macros.h" +#include "base/metrics/histogram.h" #include "base/stringprintf.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" @@ -12,6 +14,7 @@ #include "net/http/http_stream_parser.h" #include "net/http/http_util.h" #include "net/socket/client_socket_handle.h" +#include "net/socket/client_socket_pool_base.h" namespace net { @@ -22,7 +25,9 @@ HttpBasicStream::HttpBasicStream(ClientSocketHandle* connection, parser_(parser), connection_(connection), using_proxy_(using_proxy), - request_info_(NULL) { + request_info_(NULL), + response_(NULL), + bytes_read_offset_(0) { } HttpBasicStream::~HttpBasicStream() {} @@ -34,6 +39,7 @@ int HttpBasicStream::InitializeStream(const HttpRequestInfo* request_info, request_info_ = request_info; parser_.reset(new HttpStreamParser(connection_.get(), request_info, read_buf_, net_log)); + bytes_read_offset_ = connection_->socket()->NumBytesRead(); return OK; } @@ -50,6 +56,7 @@ int HttpBasicStream::SendRequest(const HttpRequestHeaders& headers, request_line_ = base::StringPrintf("%s %s HTTP/1.1\r\n", request_info_->method.c_str(), path.c_str()); + response_ = response; return parser_->SendRequest(request_line_, headers, request_body, response, callback); } @@ -119,4 +126,44 @@ bool HttpBasicStream::IsSpdyHttpStream() const { return false; } +void HttpBasicStream::LogNumRttVsBytesMetrics() const { + int socket_reuse_policy = GetSocketReusePolicy(); + if (socket_reuse_policy > 2 || socket_reuse_policy < 0) { + return; + } + + int64 total_bytes_read = connection_->socket()->NumBytesRead(); + int64 bytes_received = total_bytes_read - bytes_read_offset_; + int64 num_kb = bytes_received / 1024; + double rtt = connection_->socket()->GetConnectTimeMicros().ToInternalValue(); + rtt /= 1000.0; + + if (num_kb < 1024 && rtt > 0) { // Ignore responses > 1MB + base::TimeDelta duration = base::Time::Now() - + response_->request_time; + double num_rtt = static_cast<double>(duration.InMilliseconds()) / rtt; + int64 num_rtt_scaled = (4 * num_rtt); + + static const char* const kGroups[] = { + "warmest_socket", "warm_socket", "last_accessed_socket" + }; + int bucket = (num_kb / 5) * 5; + const std::string histogram(StringPrintf("Net.Num_RTT_vs_KB_%s_%dKB", + kGroups[socket_reuse_policy], + bucket)); + base::Histogram* counter = base::Histogram::FactoryGet( + histogram, 0, 1000, 2, base::Histogram::kUmaTargetedHistogramFlag); + DCHECK_EQ(histogram, counter->histogram_name()); + counter->Add(num_rtt_scaled); + + VLOG(2) << StringPrintf("%s\nrtt = %f\tnum_rtt = %f\t" + "num_kb = %" PRId64 "\t" + "total bytes = %" PRId64 "\t" + "histogram = %s", + request_line_.data(), + rtt, num_rtt, num_kb, total_bytes_read, + histogram.data()); + } +} + } // namespace net diff --git a/net/http/http_basic_stream.h b/net/http/http_basic_stream.h index 267c7c1..303d68f 100644 --- a/net/http/http_basic_stream.h +++ b/net/http/http_basic_stream.h @@ -81,6 +81,8 @@ class HttpBasicStream : public HttpStream { virtual bool IsSpdyHttpStream() const OVERRIDE; + virtual void LogNumRttVsBytesMetrics() const OVERRIDE; + private: scoped_refptr<GrowableIOBuffer> read_buf_; @@ -94,6 +96,10 @@ class HttpBasicStream : public HttpStream { const HttpRequestInfo* request_info_; + const HttpResponseInfo* response_; + + int64 bytes_read_offset_; + DISALLOW_COPY_AND_ASSIGN(HttpBasicStream); }; diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index d7a65e2..403f60f 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -920,6 +920,7 @@ int HttpNetworkTransaction::DoReadBodyComplete(int result) { // Clean up connection if we are done. if (done) { LogTransactionMetrics(); + stream_->LogNumRttVsBytesMetrics(); stream_->Close(!keep_alive); // Note: we don't reset the stream here. We've closed it, but we still // need it around so that callers can call methods such as diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index 65d699e..a1de71f 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -12,6 +12,7 @@ #include "base/file_path.h" #include "base/file_util.h" #include "base/memory/scoped_ptr.h" +#include "base/metrics/histogram.h" #include "base/utf_string_conversions.h" #include "net/base/auth.h" #include "net/base/capturing_net_log.h" @@ -333,6 +334,34 @@ static const char kExpectedNPNString[] = "\x08http/1.1\x06spdy/2"; static const char kAlternateProtocolHttpHeader[] = "Alternate-Protocol: 443:npn-spdy/2\r\n\r\n"; +TEST_F(HttpNetworkTransactionTest, LogNumRttVsBytesMetrics_WarmestSocket) { + MockRead data_reads[1000]; + data_reads[0] = MockRead("HTTP/1.0 200 OK\r\n\r\n"); + for (int i = 1; i < 999; i++) { + data_reads[i] = MockRead("Gagan is a good boy!"); + } + data_reads[999] = MockRead(false, OK); + + net::SetSocketReusePolicy(0); + SimpleGetHelperResult out = SimpleGetHelper(data_reads, + arraysize(data_reads)); + + base::Histogram* histogram = NULL; + base::StatisticsRecorder::FindHistogram( + "Net.Num_RTT_vs_KB_warmest_socket_15KB", &histogram); + CHECK(histogram); + + base::Histogram::SampleSet sample_set; + histogram->SnapshotSample(&sample_set); + EXPECT_EQ(1, sample_set.TotalCount()); + + EXPECT_EQ(OK, out.rv); + EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); +} + +// TODO(gagansingh): Add test for LogNumRttVsBytesMetrics_LastAccessSocket once +// it is possible to clear histograms from previous tests. + TEST_F(HttpNetworkTransactionTest, Basic) { SessionDependencies session_deps; scoped_ptr<HttpTransaction> trans( diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc index 0a41c1f..584cecd 100644 --- a/net/http/http_proxy_client_socket.cc +++ b/net/http/http_proxy_client_socket.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -165,6 +165,22 @@ bool HttpProxyClientSocket::UsingTCPFastOpen() const { return false; } +int64 HttpProxyClientSocket::NumBytesRead() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->NumBytesRead(); + } + NOTREACHED(); + return -1; +} + +base::TimeDelta HttpProxyClientSocket::GetConnectTimeMicros() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->GetConnectTimeMicros(); + } + NOTREACHED(); + return base::TimeDelta::FromMicroseconds(-1); +} + int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len, CompletionCallback* callback) { DCHECK(!user_callback_); diff --git a/net/http/http_proxy_client_socket.h b/net/http/http_proxy_client_socket.h index bd25bab..b1f32a6 100644 --- a/net/http/http_proxy_client_socket.h +++ b/net/http/http_proxy_client_socket.h @@ -78,6 +78,8 @@ class HttpProxyClientSocket : public ProxyClientSocket { virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; virtual bool UsingTCPFastOpen() const; + virtual int64 NumBytesRead() const; + virtual base::TimeDelta GetConnectTimeMicros() const; // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback); diff --git a/net/http/http_response_body_drainer_unittest.cc b/net/http/http_response_body_drainer_unittest.cc index 45c826e..47602e9 100644 --- a/net/http/http_response_body_drainer_unittest.cc +++ b/net/http/http_response_body_drainer_unittest.cc @@ -117,6 +117,8 @@ class MockHttpStream : public HttpStream { virtual bool IsSpdyHttpStream() const OVERRIDE { return false; } + virtual void LogNumRttVsBytesMetrics() const OVERRIDE {} + // Methods to tweak/observer mock behavior: void StallReadsForever() { stall_reads_forever_ = true; } diff --git a/net/http/http_stream.h b/net/http/http_stream.h index 7ca2203..66fd97c 100644 --- a/net/http/http_stream.h +++ b/net/http/http_stream.h @@ -135,6 +135,10 @@ class NET_TEST HttpStream { // the HttpStream implementation. This is just a quick hack. virtual bool IsSpdyHttpStream() const = 0; + // Record histogram of number of round trips taken to download the full + // response body vs bytes transferred. + virtual void LogNumRttVsBytesMetrics() const = 0; + private: DISALLOW_COPY_AND_ASSIGN(HttpStream); }; diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc index ddcbba6..d39890b 100644 --- a/net/socket/client_socket_pool_base.cc +++ b/net/socket/client_socket_pool_base.cc @@ -4,11 +4,14 @@ #include "net/socket/client_socket_pool_base.h" +#include <math.h> #include "base/compiler_specific.h" #include "base/format_macros.h" +#include "base/logging.h" #include "base/message_loop.h" #include "base/metrics/stats_counters.h" #include "base/stl_util-inl.h" +#include "base/string_number_conversions.h" #include "base/string_util.h" #include "base/time.h" #include "base/values.h" @@ -32,10 +35,33 @@ const int kCleanupInterval = 10; // DO NOT INCREASE THIS TIMEOUT. // after a certain timeout has passed without receiving an ACK. bool g_connect_backup_jobs_enabled = true; +double g_socket_reuse_policy_penalty_exponent = -1; +int g_socket_reuse_policy = -1; + } // namespace namespace net { +int GetSocketReusePolicy() { + return g_socket_reuse_policy; +} + +void SetSocketReusePolicy(int policy) { + DCHECK_GE(policy, 0); + DCHECK_LE(policy, 2); + if (policy > 2 || policy < 0) { + LOG(ERROR) << "Invalid socket reuse policy"; + return; + } + + double exponents[] = { 0, 0.25, -1 }; + g_socket_reuse_policy_penalty_exponent = exponents[policy]; + g_socket_reuse_policy = policy; + + VLOG(1) << "Setting g_socket_reuse_policy_penalty_exponent = " + << g_socket_reuse_policy_penalty_exponent; +} + ConnectJob::ConnectJob(const std::string& group_name, base::TimeDelta timeout_duration, Delegate* delegate, @@ -363,6 +389,7 @@ bool ClientSocketPoolBaseHelper::AssignIdleSocketToGroup( const Request* request, Group* group) { std::list<IdleSocket>* idle_sockets = group->mutable_idle_sockets(); std::list<IdleSocket>::iterator idle_socket_it = idle_sockets->end(); + double max_score = -1; // Iterate through the idle sockets forwards (oldest to newest) // * Delete any disconnected ones. @@ -379,7 +406,22 @@ bool ClientSocketPoolBaseHelper::AssignIdleSocketToGroup( if (it->socket->WasEverUsed()) { // We found one we can reuse! - idle_socket_it = it; + double score = 0; + int64 bytes_read = it->socket->NumBytesRead(); + double num_kb = static_cast<double>(bytes_read) / 1024.0; + int idle_time_sec = (base::TimeTicks::Now() - it->start_time).InSeconds(); + idle_time_sec = std::max(1, idle_time_sec); + + if (g_socket_reuse_policy_penalty_exponent >= 0 && num_kb >= 0) { + score = num_kb / pow(idle_time_sec, + g_socket_reuse_policy_penalty_exponent); + } + + // Equality to prefer recently used connection. + if (score >= max_score) { + idle_socket_it = it; + max_score = score; + } } ++it; diff --git a/net/socket/client_socket_pool_base.h b/net/socket/client_socket_pool_base.h index a5defdf..2490c02 100644 --- a/net/socket/client_socket_pool_base.h +++ b/net/socket/client_socket_pool_base.h @@ -50,6 +50,13 @@ namespace net { class ClientSocketHandle; +// Returns the client socket reuse policy. +int GetSocketReusePolicy(); + +// Sets the client socket reuse policy. +// NOTE: 'policy' should be a valid ClientSocketReusePolicy enum value. +NET_API void SetSocketReusePolicy(int policy); + // ConnectJob provides an abstract interface for "connecting" a socket. // The connection may involve host resolution, tcp connection, ssl connection, // etc. @@ -167,6 +174,17 @@ class NET_TEST ClientSocketPoolBaseHelper NO_IDLE_SOCKETS = 0x1, // Do not return an idle socket. Create a new one. }; + enum ClientSocketReusePolicy { + // Socket with largest amount of bytes transferred. + USE_WARMEST_SOCKET = 0, + + // Socket which scores highest on large bytes transferred and low idle time. + USE_WARM_SOCKET = 1, + + // Socket which was most recently used. + USE_LAST_ACCESSED_SOCKET = 2, + }; + class NET_TEST Request { public: Request(ClientSocketHandle* handle, diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc index 4864001..6cdbdd3 100644 --- a/net/socket/client_socket_pool_base_unittest.cc +++ b/net/socket/client_socket_pool_base_unittest.cc @@ -45,12 +45,14 @@ typedef ClientSocketPoolBase<TestSocketParams> TestClientSocketPoolBase; class MockClientSocket : public StreamSocket { public: - MockClientSocket() : connected_(false), was_used_to_convey_data_(false) {} + MockClientSocket() : connected_(false), was_used_to_convey_data_(false), + num_bytes_read_(0) {} // Socket methods: virtual int Read( - IOBuffer* /* buf */, int /* len */, CompletionCallback* /* callback */) { - return ERR_UNEXPECTED; + IOBuffer* /* buf */, int len, CompletionCallback* /* callback */) { + num_bytes_read_ += len; + return len; } virtual int Write( @@ -86,13 +88,22 @@ class MockClientSocket : public StreamSocket { virtual void SetSubresourceSpeculation() {} virtual void SetOmniboxSpeculation() {} - virtual bool WasEverUsed() const { return was_used_to_convey_data_; } + virtual bool WasEverUsed() const { + return was_used_to_convey_data_ || num_bytes_read_ > 0; + } virtual bool UsingTCPFastOpen() const { return false; } + virtual int64 NumBytesRead() const { return num_bytes_read_; } + virtual base::TimeDelta GetConnectTimeMicros() const { + static const base::TimeDelta kDummyConnectTimeMicros = + base::TimeDelta::FromMicroseconds(10); + return kDummyConnectTimeMicros; // Dummy value. + } private: bool connected_; BoundNetLog net_log_; bool was_used_to_convey_data_; + int num_bytes_read_; DISALLOW_COPY_AND_ASSIGN(MockClientSocket); }; @@ -604,6 +615,71 @@ class ClientSocketPoolBaseTest : public testing::Test { ClientSocketPoolTest test_base_; }; +TEST_F(ClientSocketPoolBaseTest, AssignIdleSocketToGroup_WarmestSocket) { + CreatePool(4, 4); + net::SetSocketReusePolicy(0); + + EXPECT_EQ(OK, StartRequest("a", kDefaultPriority)); + EXPECT_EQ(OK, StartRequest("a", kDefaultPriority)); + EXPECT_EQ(OK, StartRequest("a", kDefaultPriority)); + EXPECT_EQ(OK, StartRequest("a", kDefaultPriority)); + + std::map<int, StreamSocket*> sockets_; + for (size_t i = 0; i < test_base_.requests_size(); i++) { + TestSocketRequest* req = test_base_.request(i); + StreamSocket* s = req->handle()->socket(); + MockClientSocket* sock = static_cast<MockClientSocket*>(s); + CHECK(sock); + sockets_[i] = sock; + sock->Read(NULL, 1024 - i, NULL); + } + + ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE); + + EXPECT_EQ(OK, StartRequest("a", kDefaultPriority)); + TestSocketRequest* req = test_base_.request(test_base_.requests_size() - 1); + + // First socket is warmest. + EXPECT_EQ(sockets_[0], req->handle()->socket()); + + // Test that NumBytes are as expected. + EXPECT_EQ(1024, sockets_[0]->NumBytesRead()); + EXPECT_EQ(1023, sockets_[1]->NumBytesRead()); + EXPECT_EQ(1022, sockets_[2]->NumBytesRead()); + EXPECT_EQ(1021, sockets_[3]->NumBytesRead()); + + ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE); +} + +TEST_F(ClientSocketPoolBaseTest, AssignIdleSocketToGroup_LastAccessedSocket) { + CreatePool(4, 4); + net::SetSocketReusePolicy(2); + + EXPECT_EQ(OK, StartRequest("a", kDefaultPriority)); + EXPECT_EQ(OK, StartRequest("a", kDefaultPriority)); + EXPECT_EQ(OK, StartRequest("a", kDefaultPriority)); + EXPECT_EQ(OK, StartRequest("a", kDefaultPriority)); + + std::map<int, StreamSocket*> sockets_; + for (size_t i = 0; i < test_base_.requests_size(); i++) { + TestSocketRequest* req = test_base_.request(i); + StreamSocket* s = req->handle()->socket(); + MockClientSocket* sock = static_cast<MockClientSocket*>(s); + CHECK(sock); + sockets_[i] = sock; + sock->Read(NULL, 1024 - i, NULL); + } + + ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE); + + EXPECT_EQ(OK, StartRequest("a", kDefaultPriority)); + TestSocketRequest* req = test_base_.request(test_base_.requests_size() - 1); + + // Last socket is most recently accessed. + EXPECT_EQ(sockets_[3], req->handle()->socket()); + ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE); +} + // Even though a timeout is specified, it doesn't time out on a synchronous // completion. TEST_F(ClientSocketPoolBaseTest, ConnectJob_NoTimeoutOnSynchronousCompletion) { diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc index 4e4e8fe..0573f73 100644 --- a/net/socket/socket_test_util.cc +++ b/net/socket/socket_test_util.cc @@ -707,6 +707,7 @@ MockTCPClientSocket::MockTCPClientSocket(const net::AddressList& addresses, addresses_(addresses), data_(data), read_offset_(0), + num_bytes_read_(0), read_data_(false, net::ERR_UNEXPECTED), need_read_data_(true), peer_closed_connection_(false), @@ -811,6 +812,17 @@ bool MockTCPClientSocket::UsingTCPFastOpen() const { return false; } +int64 MockTCPClientSocket::NumBytesRead() const { + return num_bytes_read_; +} + +base::TimeDelta MockTCPClientSocket::GetConnectTimeMicros() const { + // Dummy value. + static const base::TimeDelta kTestingConnectTimeMicros = + base::TimeDelta::FromMicroseconds(20); + return kTestingConnectTimeMicros; +} + void MockTCPClientSocket::OnReadComplete(const MockRead& data) { // There must be a read pending. DCHECK(pending_buf_); @@ -853,6 +865,7 @@ int MockTCPClientSocket::CompleteRead() { result = std::min(buf_len, read_data_.data_len - read_offset_); memcpy(buf->data(), read_data_.data + read_offset_, result); read_offset_ += result; + num_bytes_read_ += result; if (read_offset_ == read_data_.data_len) { need_read_data_ = true; read_offset_ = 0; @@ -1001,6 +1014,14 @@ bool DeterministicMockTCPClientSocket::UsingTCPFastOpen() const { return false; } +int64 DeterministicMockTCPClientSocket::NumBytesRead() const { + return -1; +} + +base::TimeDelta DeterministicMockTCPClientSocket::GetConnectTimeMicros() const { + return base::TimeDelta::FromMicroseconds(-1); +} + void DeterministicMockTCPClientSocket::OnReadComplete(const MockRead& data) {} class MockSSLClientSocket::ConnectCallback @@ -1094,6 +1115,14 @@ bool MockSSLClientSocket::UsingTCPFastOpen() const { return transport_->socket()->UsingTCPFastOpen(); } +int64 MockSSLClientSocket::NumBytesRead() const { + return -1; +} + +base::TimeDelta MockSSLClientSocket::GetConnectTimeMicros() const { + return base::TimeDelta::FromMicroseconds(-1); +} + void MockSSLClientSocket::GetSSLInfo(net::SSLInfo* ssl_info) { ssl_info->Reset(); ssl_info->cert = data_->cert_; diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h index 9a31288..d1f4816 100644 --- a/net/socket/socket_test_util.h +++ b/net/socket/socket_test_util.h @@ -631,6 +631,8 @@ class MockTCPClientSocket : public MockClientSocket { virtual int GetPeerAddress(AddressList* address) const; virtual bool WasEverUsed() const; virtual bool UsingTCPFastOpen() const; + virtual int64 NumBytesRead() const; + virtual base::TimeDelta GetConnectTimeMicros() const; // MockClientSocket: virtual void OnReadComplete(const MockRead& data); @@ -642,6 +644,7 @@ class MockTCPClientSocket : public MockClientSocket { net::SocketDataProvider* data_; int read_offset_; + int num_bytes_read_; net::MockRead read_data_; bool need_read_data_; @@ -683,6 +686,8 @@ class DeterministicMockTCPClientSocket : public MockClientSocket, virtual bool IsConnectedAndIdle() const; virtual bool WasEverUsed() const; virtual bool UsingTCPFastOpen() const; + virtual int64 NumBytesRead() const; + virtual base::TimeDelta GetConnectTimeMicros() const; // MockClientSocket: virtual void OnReadComplete(const MockRead& data); @@ -724,6 +729,8 @@ class MockSSLClientSocket : public MockClientSocket { virtual bool IsConnected() const; virtual bool WasEverUsed() const; virtual bool UsingTCPFastOpen() const; + virtual int64 NumBytesRead() const; + virtual base::TimeDelta GetConnectTimeMicros() const; // SSLClientSocket methods: virtual void GetSSLInfo(net::SSLInfo* ssl_info); diff --git a/net/socket/socks5_client_socket.cc b/net/socket/socks5_client_socket.cc index 7a1c10d..2f5cee4 100644 --- a/net/socket/socks5_client_socket.cc +++ b/net/socket/socks5_client_socket.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -142,6 +142,22 @@ bool SOCKS5ClientSocket::UsingTCPFastOpen() const { return false; } +int64 SOCKS5ClientSocket::NumBytesRead() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->NumBytesRead(); + } + NOTREACHED(); + return -1; +} + +base::TimeDelta SOCKS5ClientSocket::GetConnectTimeMicros() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->GetConnectTimeMicros(); + } + NOTREACHED(); + return base::TimeDelta::FromMicroseconds(-1); +} + // Read is called by the transport layer above to read. This can only be done // if the SOCKS handshake is complete. int SOCKS5ClientSocket::Read(IOBuffer* buf, int buf_len, diff --git a/net/socket/socks5_client_socket.h b/net/socket/socks5_client_socket.h index 955ad90..a9d30df 100644 --- a/net/socket/socks5_client_socket.h +++ b/net/socket/socks5_client_socket.h @@ -60,6 +60,8 @@ class NET_TEST SOCKS5ClientSocket : public StreamSocket { virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; virtual bool UsingTCPFastOpen() const; + virtual int64 NumBytesRead() const; + virtual base::TimeDelta GetConnectTimeMicros() const; // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback); diff --git a/net/socket/socks_client_socket.cc b/net/socket/socks_client_socket.cc index d885f15..4a45b01 100644 --- a/net/socket/socks_client_socket.cc +++ b/net/socket/socks_client_socket.cc @@ -169,6 +169,22 @@ bool SOCKSClientSocket::UsingTCPFastOpen() const { return false; } +int64 SOCKSClientSocket::NumBytesRead() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->NumBytesRead(); + } + NOTREACHED(); + return -1; +} + +base::TimeDelta SOCKSClientSocket::GetConnectTimeMicros() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->GetConnectTimeMicros(); + } + NOTREACHED(); + return base::TimeDelta::FromMicroseconds(-1); +} + // Read is called by the transport layer above to read. This can only be done // if the SOCKS handshake is complete. diff --git a/net/socket/socks_client_socket.h b/net/socket/socks_client_socket.h index 7c4ba35..286538f 100644 --- a/net/socket/socks_client_socket.h +++ b/net/socket/socks_client_socket.h @@ -58,6 +58,8 @@ class NET_TEST SOCKSClientSocket : public StreamSocket { virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; virtual bool UsingTCPFastOpen() const; + virtual int64 NumBytesRead() const; + virtual base::TimeDelta GetConnectTimeMicros() const; // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback); diff --git a/net/socket/ssl_client_socket_mac.cc b/net/socket/ssl_client_socket_mac.cc index 2fc11ec..c38b78a 100644 --- a/net/socket/ssl_client_socket_mac.cc +++ b/net/socket/ssl_client_socket_mac.cc @@ -658,6 +658,22 @@ bool SSLClientSocketMac::UsingTCPFastOpen() const { return false; } +int64 SSLClientSocketMac::NumBytesRead() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->NumBytesRead(); + } + NOTREACHED(); + return -1; +} + +base::TimeDelta SSLClientSocketMac::GetConnectTimeMicros() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->GetConnectTimeMicros(); + } + NOTREACHED(); + return base::TimeDelta::FromMicroseconds(-1); +} + int SSLClientSocketMac::Read(IOBuffer* buf, int buf_len, CompletionCallback* callback) { DCHECK(completed_handshake()); diff --git a/net/socket/ssl_client_socket_mac.h b/net/socket/ssl_client_socket_mac.h index 4dbffe6..8ef33e9 100644 --- a/net/socket/ssl_client_socket_mac.h +++ b/net/socket/ssl_client_socket_mac.h @@ -57,6 +57,8 @@ class SSLClientSocketMac : public SSLClientSocket { virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; virtual bool UsingTCPFastOpen() const; + virtual int64 NumBytesRead() const; + virtual base::TimeDelta GetConnectTimeMicros() const; // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback); diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc index 18b4e58..9657026 100644 --- a/net/socket/ssl_client_socket_nss.cc +++ b/net/socket/ssl_client_socket_nss.cc @@ -714,6 +714,22 @@ bool SSLClientSocketNSS::UsingTCPFastOpen() const { return false; } +int64 SSLClientSocketNSS::NumBytesRead() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->NumBytesRead(); + } + NOTREACHED(); + return -1; +} + +base::TimeDelta SSLClientSocketNSS::GetConnectTimeMicros() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->GetConnectTimeMicros(); + } + NOTREACHED(); + return base::TimeDelta::FromMicroseconds(-1); +} + int SSLClientSocketNSS::Read(IOBuffer* buf, int buf_len, CompletionCallback* callback) { EnterFunction(buf_len); diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h index 1c5d80e..7d2f7cf 100644 --- a/net/socket/ssl_client_socket_nss.h +++ b/net/socket/ssl_client_socket_nss.h @@ -75,6 +75,8 @@ class SSLClientSocketNSS : public SSLClientSocket { virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; virtual bool UsingTCPFastOpen() const; + virtual int64 NumBytesRead() const; + virtual base::TimeDelta GetConnectTimeMicros() const; // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback); diff --git a/net/socket/ssl_client_socket_win.cc b/net/socket/ssl_client_socket_win.cc index 1392e1d..4cc3103 100644 --- a/net/socket/ssl_client_socket_win.cc +++ b/net/socket/ssl_client_socket_win.cc @@ -731,6 +731,22 @@ bool SSLClientSocketWin::UsingTCPFastOpen() const { return false; } +int64 SSLClientSocketWin::NumBytesRead() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->NumBytesRead(); + } + NOTREACHED(); + return -1; +} + +base::TimeDelta SSLClientSocketWin::GetConnectTimeMicros() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->GetConnectTimeMicros(); + } + NOTREACHED(); + return base::TimeDelta::FromMicroseconds(-1); +} + int SSLClientSocketWin::Read(IOBuffer* buf, int buf_len, CompletionCallback* callback) { DCHECK(completed_handshake()); diff --git a/net/socket/ssl_client_socket_win.h b/net/socket/ssl_client_socket_win.h index fb54c43..59f403a 100644 --- a/net/socket/ssl_client_socket_win.h +++ b/net/socket/ssl_client_socket_win.h @@ -62,6 +62,8 @@ class SSLClientSocketWin : public SSLClientSocket { virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; virtual bool UsingTCPFastOpen() const; + virtual int64 NumBytesRead() const; + virtual base::TimeDelta GetConnectTimeMicros() const; // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback); diff --git a/net/socket/ssl_server_socket_nss.cc b/net/socket/ssl_server_socket_nss.cc index 0f35ce9c..b272f8e 100644 --- a/net/socket/ssl_server_socket_nss.cc +++ b/net/socket/ssl_server_socket_nss.cc @@ -226,6 +226,14 @@ bool SSLServerSocketNSS::UsingTCPFastOpen() const { return transport_socket_->UsingTCPFastOpen(); } +int64 SSLServerSocketNSS::NumBytesRead() const { + return transport_socket_->NumBytesRead(); +} + +base::TimeDelta SSLServerSocketNSS::GetConnectTimeMicros() const { + return transport_socket_->GetConnectTimeMicros(); +} + int SSLServerSocketNSS::InitializeSSLOptions() { // Transport connected, now hook it up to nss // TODO(port): specify rx and tx buffer sizes separately diff --git a/net/socket/ssl_server_socket_nss.h b/net/socket/ssl_server_socket_nss.h index 366a915..5903c17 100644 --- a/net/socket/ssl_server_socket_nss.h +++ b/net/socket/ssl_server_socket_nss.h @@ -54,6 +54,8 @@ class SSLServerSocketNSS : public SSLServerSocket { virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; virtual bool UsingTCPFastOpen() const; + virtual int64 NumBytesRead() const; + virtual base::TimeDelta GetConnectTimeMicros() const; private: enum State { diff --git a/net/socket/ssl_server_socket_unittest.cc b/net/socket/ssl_server_socket_unittest.cc index 02f333b..de89c20 100644 --- a/net/socket/ssl_server_socket_unittest.cc +++ b/net/socket/ssl_server_socket_unittest.cc @@ -171,6 +171,14 @@ class FakeSocket : public StreamSocket { return false; } + virtual int64 NumBytesRead() const { + return -1; + } + + virtual base::TimeDelta GetConnectTimeMicros() const { + return base::TimeDelta::FromMicroseconds(-1); + } + private: net::BoundNetLog net_log_; FakeDataChannel* incoming_; diff --git a/net/socket/stream_socket.h b/net/socket/stream_socket.h index 544fbcd..ef2f698 100644 --- a/net/socket/stream_socket.h +++ b/net/socket/stream_socket.h @@ -6,6 +6,7 @@ #define NET_SOCKET_STREAM_SOCKET_H_ #pragma once +#include "base/time.h" #include "net/base/net_log.h" #include "net/socket/socket.h" @@ -79,6 +80,12 @@ class NET_TEST StreamSocket : public Socket { // TCP FastOpen is an experiment with sending data in the TCP SYN packet. virtual bool UsingTCPFastOpen() const = 0; + // Returns the number of bytes successfully read from this socket. + virtual int64 NumBytesRead() const = 0; + + // Returns the connection setup time of this socket. + virtual base::TimeDelta GetConnectTimeMicros() const = 0; + protected: // The following class is only used to gather statistics about the history of // a socket. It is only instantiated and used in basic sockets, such as diff --git a/net/socket/tcp_client_socket_libevent.cc b/net/socket/tcp_client_socket_libevent.cc index 3c5ec13..bc6270d 100644 --- a/net/socket/tcp_client_socket_libevent.cc +++ b/net/socket/tcp_client_socket_libevent.cc @@ -137,7 +137,8 @@ TCPClientSocketLibevent::TCPClientSocketLibevent( net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)), previously_disconnected_(false), use_tcp_fastopen_(false), - tcp_fastopen_connected_(false) { + tcp_fastopen_connected_(false), + num_bytes_read_(0) { scoped_refptr<NetLog::EventParameters> params; if (source.is_valid()) params = new NetLogSourceParameter("source_dependency", source); @@ -298,6 +299,7 @@ int TCPClientSocketLibevent::DoConnect() { // Connect the socket. if (!use_tcp_fastopen_) { + connect_start_time_ = base::TimeTicks::Now(); if (!HANDLE_EINTR(connect(socket_, current_ai_->ai_addr, static_cast<int>(current_ai_->ai_addrlen)))) { // Connected without waiting! @@ -337,6 +339,7 @@ int TCPClientSocketLibevent::DoConnectComplete(int result) { net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT, params); if (result == OK) { + connect_time_micros_ = base::TimeTicks::Now() - connect_start_time_; write_socket_watcher_.StopWatchingFileDescriptor(); use_history_.set_was_ever_connected(); return OK; // Done! @@ -439,6 +442,7 @@ int TCPClientSocketLibevent::Read(IOBuffer* buf, if (nread >= 0) { base::StatsCounter read_bytes("tcp.read_bytes"); read_bytes.Add(nread); + num_bytes_read_ += static_cast<int64>(nread); if (nread > 0) use_history_.set_was_used_to_convey_data(); net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, nread, @@ -633,6 +637,7 @@ void TCPClientSocketLibevent::DidCompleteRead() { result = bytes_transferred; base::StatsCounter read_bytes("tcp.read_bytes"); read_bytes.Add(bytes_transferred); + num_bytes_read_ += static_cast<int64>(bytes_transferred); if (bytes_transferred > 0) use_history_.set_was_used_to_convey_data(); net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, result, @@ -722,4 +727,12 @@ bool TCPClientSocketLibevent::UsingTCPFastOpen() const { return use_tcp_fastopen_; } +int64 TCPClientSocketLibevent::NumBytesRead() const { + return num_bytes_read_; +} + +base::TimeDelta TCPClientSocketLibevent::GetConnectTimeMicros() const { + return connect_time_micros_; +} + } // namespace net diff --git a/net/socket/tcp_client_socket_libevent.h b/net/socket/tcp_client_socket_libevent.h index 607b9ee..f5e4a28 100644 --- a/net/socket/tcp_client_socket_libevent.h +++ b/net/socket/tcp_client_socket_libevent.h @@ -53,6 +53,8 @@ class TCPClientSocketLibevent : public StreamSocket, base::NonThreadSafe { virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; virtual bool UsingTCPFastOpen() const; + virtual int64 NumBytesRead() const; + virtual base::TimeDelta GetConnectTimeMicros() const; // Socket methods: // Multiple outstanding requests are not supported. @@ -195,6 +197,10 @@ class TCPClientSocketLibevent : public StreamSocket, base::NonThreadSafe { // True when TCP FastOpen is in use and we have done the connect. bool tcp_fastopen_connected_; + base::TimeTicks connect_start_time_; + base::TimeDelta connect_time_micros_; + int64 num_bytes_read_; + DISALLOW_COPY_AND_ASSIGN(TCPClientSocketLibevent); }; diff --git a/net/socket/tcp_client_socket_win.cc b/net/socket/tcp_client_socket_win.cc index 71187a1..f4026b7 100644 --- a/net/socket/tcp_client_socket_win.cc +++ b/net/socket/tcp_client_socket_win.cc @@ -323,7 +323,8 @@ TCPClientSocketWin::TCPClientSocketWin(const AddressList& addresses, next_connect_state_(CONNECT_STATE_NONE), connect_os_error_(0), net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)), - previously_disconnected_(false) { + previously_disconnected_(false), + num_bytes_read_(0) { scoped_refptr<NetLog::EventParameters> params; if (source.is_valid()) params = new NetLogSourceParameter("source_dependency", source); @@ -484,6 +485,7 @@ int TCPClientSocketWin::DoConnect() { core_->write_overlapped_.hEvent = WSACreateEvent(); + connect_start_time_ = base::TimeTicks::Now(); if (!connect(socket_, ai->ai_addr, static_cast<int>(ai->ai_addrlen))) { // Connected without waiting! // @@ -522,6 +524,7 @@ int TCPClientSocketWin::DoConnectComplete(int result) { net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT, params); if (result == OK) { + connect_time_micros_ = base::TimeTicks::Now() - connect_start_time_; use_history_.set_was_ever_connected(); return OK; // Done! } @@ -658,6 +661,14 @@ bool TCPClientSocketWin::UsingTCPFastOpen() const { return false; } +int64 TCPClientSocketWin::NumBytesRead() const { + return num_bytes_read_; +} + +base::TimeDelta TCPClientSocketWin::GetConnectTimeMicros() const { + return connect_time_micros_; +} + int TCPClientSocketWin::Read(IOBuffer* buf, int buf_len, CompletionCallback* callback) { @@ -688,6 +699,7 @@ int TCPClientSocketWin::Read(IOBuffer* buf, base::MemoryDebug::MarkAsInitialized(core_->read_buffer_.buf, num); base::StatsCounter read_bytes("tcp.read_bytes"); read_bytes.Add(num); + num_bytes_read_ += num; if (num > 0) use_history_.set_was_used_to_convey_data(); net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, num, @@ -858,6 +870,7 @@ void TCPClientSocketWin::DidCompleteRead() { if (ok) { base::StatsCounter read_bytes("tcp.read_bytes"); read_bytes.Add(num_bytes); + num_bytes_read_ += num_bytes; if (num_bytes > 0) use_history_.set_was_used_to_convey_data(); net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, diff --git a/net/socket/tcp_client_socket_win.h b/net/socket/tcp_client_socket_win.h index 3282772..b1f9f3b 100644 --- a/net/socket/tcp_client_socket_win.h +++ b/net/socket/tcp_client_socket_win.h @@ -53,6 +53,8 @@ class NET_API TCPClientSocketWin : public StreamSocket, virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; virtual bool UsingTCPFastOpen() const; + virtual int64 NumBytesRead() const; + virtual base::TimeDelta GetConnectTimeMicros() const; // Socket methods: // Multiple outstanding requests are not supported. @@ -141,6 +143,10 @@ class NET_API TCPClientSocketWin : public StreamSocket, // histograms. UseHistory use_history_; + base::TimeTicks connect_start_time_; + base::TimeDelta connect_time_micros_; + int64 num_bytes_read_; + DISALLOW_COPY_AND_ASSIGN(TCPClientSocketWin); }; diff --git a/net/socket/transport_client_socket_pool_unittest.cc b/net/socket/transport_client_socket_pool_unittest.cc index 5716a4d..d12cd9d 100644 --- a/net/socket/transport_client_socket_pool_unittest.cc +++ b/net/socket/transport_client_socket_pool_unittest.cc @@ -85,6 +85,10 @@ class MockClientSocket : public StreamSocket { virtual void SetOmniboxSpeculation() {} virtual bool WasEverUsed() const { return false; } virtual bool UsingTCPFastOpen() const { return false; } + virtual int64 NumBytesRead() const { return -1; } + virtual base::TimeDelta GetConnectTimeMicros() const { + return base::TimeDelta::FromMicroseconds(-1); + } // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, @@ -135,6 +139,10 @@ class MockFailingClientSocket : public StreamSocket { virtual void SetOmniboxSpeculation() {} virtual bool WasEverUsed() const { return false; } virtual bool UsingTCPFastOpen() const { return false; } + virtual int64 NumBytesRead() const { return -1; } + virtual base::TimeDelta GetConnectTimeMicros() const { + return base::TimeDelta::FromMicroseconds(-1); + } // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, @@ -209,6 +217,10 @@ class MockPendingClientSocket : public StreamSocket { virtual void SetOmniboxSpeculation() {} virtual bool WasEverUsed() const { return false; } virtual bool UsingTCPFastOpen() const { return false; } + virtual int64 NumBytesRead() const { return -1; } + virtual base::TimeDelta GetConnectTimeMicros() const { + return base::TimeDelta::FromMicroseconds(-1); + } // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, diff --git a/net/socket/transport_client_socket_unittest.cc b/net/socket/transport_client_socket_unittest.cc index bb0be35..8f377e5 100644 --- a/net/socket/transport_client_socket_unittest.cc +++ b/net/socket/transport_client_socket_unittest.cc @@ -277,6 +277,8 @@ TEST_P(TransportClientSocketTest, Read) { rv = sock_->Read(buf, 4096, &callback); ASSERT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(static_cast<int64>(std::string(kServerReply).size()), + sock_->NumBytesRead()); CloseServerSocket(); EXPECT_EQ(0, callback.WaitForResult()); } @@ -309,6 +311,8 @@ TEST_P(TransportClientSocketTest, Read_SmallChunks) { // then close the server socket, and note the close. rv = sock_->Read(buf, 1, &callback); + EXPECT_EQ(static_cast<int64>(std::string(kServerReply).size()), + sock_->NumBytesRead()); ASSERT_EQ(ERR_IO_PENDING, rv); CloseServerSocket(); EXPECT_EQ(0, callback.WaitForResult()); @@ -329,9 +333,12 @@ TEST_P(TransportClientSocketTest, Read_Interrupted) { scoped_refptr<IOBuffer> buf(new IOBuffer(16)); rv = sock_->Read(buf, 16, &callback); EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING); + EXPECT_EQ(0, sock_->NumBytesRead()); - if (rv == ERR_IO_PENDING) + if (rv == ERR_IO_PENDING) { rv = callback.WaitForResult(); + EXPECT_EQ(16, sock_->NumBytesRead()); + } EXPECT_NE(0, rv); } diff --git a/net/spdy/spdy_http_stream.h b/net/spdy/spdy_http_stream.h index 88c627d..b6727e5 100644 --- a/net/spdy/spdy_http_stream.h +++ b/net/spdy/spdy_http_stream.h @@ -68,6 +68,7 @@ class NET_TEST SpdyHttpStream : public SpdyStream::Delegate, public HttpStream { virtual void GetSSLCertRequestInfo( SSLCertRequestInfo* cert_request_info) OVERRIDE; virtual bool IsSpdyHttpStream() const OVERRIDE; + virtual void LogNumRttVsBytesMetrics() const OVERRIDE {} // SpdyStream::Delegate methods: virtual bool OnSendHeadersComplete(int status) OVERRIDE; diff --git a/net/spdy/spdy_proxy_client_socket.cc b/net/spdy/spdy_proxy_client_socket.cc index 1e6e23a..c5733cf 100644 --- a/net/spdy/spdy_proxy_client_socket.cc +++ b/net/spdy/spdy_proxy_client_socket.cc @@ -138,6 +138,14 @@ bool SpdyProxyClientSocket::UsingTCPFastOpen() const { return false; } +int64 SpdyProxyClientSocket::NumBytesRead() const { + return -1; +} + +base::TimeDelta SpdyProxyClientSocket::GetConnectTimeMicros() const { + return base::TimeDelta::FromMicroseconds(-1); +} + int SpdyProxyClientSocket::Read(IOBuffer* buf, int buf_len, CompletionCallback* callback) { DCHECK(!read_callback_); diff --git a/net/spdy/spdy_proxy_client_socket.h b/net/spdy/spdy_proxy_client_socket.h index d7510d1..e6598ea 100644 --- a/net/spdy/spdy_proxy_client_socket.h +++ b/net/spdy/spdy_proxy_client_socket.h @@ -77,6 +77,8 @@ class NET_TEST SpdyProxyClientSocket : public ProxyClientSocket, virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; virtual bool UsingTCPFastOpen() const; + virtual int64 NumBytesRead() const; + virtual base::TimeDelta GetConnectTimeMicros() const; // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback); |