summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrtenneti@google.com <rtenneti@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-10 04:52:10 +0000
committerrtenneti@google.com <rtenneti@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-10 04:52:10 +0000
commit42baef7a5c2658d767cc15db5834e1f4b7bd4746 (patch)
treeacc5161c111cbf1db516538acfc660dd1caa32e2
parent83260e00ec89e0a98492a1d3f5aad64684c3316d (diff)
downloadchromium_src-42baef7a5c2658d767cc15db5834e1f4b7bd4746.zip
chromium_src-42baef7a5c2658d767cc15db5834e1f4b7bd4746.tar.gz
chromium_src-42baef7a5c2658d767cc15db5834e1f4b7bd4746.tar.bz2
SPDY - add support for spdy/2.1 to support flow control.
1) Add spdy/2.1 as a supported NPN protocol. 2) Advertise that chrome supports spdy/2.1 when --flow-control (spdy flag) is enabled. 3) When SPDY protocol is negotiated, enable flow_control in spdy_session if spdy/2.1 is negotiated as NPN protocol. BUG=106911 R=willchan TEST=network unit tests and if possible test with SPDY 2.1 server with command line flag --flow-control. This CL is same as the following CL. Implemented changes suggested by willchan in the following review. http://codereview.chromium.org/8890044/ Review URL: http://codereview.chromium.org/8892026 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@113942 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/http/http_network_layer.cc6
-rw-r--r--net/http/http_network_transaction_unittest.cc5
-rw-r--r--net/http/http_server_properties.cc2
-rw-r--r--net/http/http_server_properties.h1
-rw-r--r--net/socket/socket_test_util.cc17
-rw-r--r--net/socket/socket_test_util.h5
-rw-r--r--net/socket/ssl_client_socket.cc11
-rw-r--r--net/socket/ssl_client_socket.h8
-rw-r--r--net/socket/ssl_client_socket_pool.cc4
-rw-r--r--net/spdy/spdy_http_stream.cc2
-rw-r--r--net/spdy/spdy_network_transaction_unittest.cc17
-rw-r--r--net/spdy/spdy_session.cc13
-rw-r--r--net/spdy/spdy_session.h14
-rw-r--r--net/spdy/spdy_stream.cc2
14 files changed, 87 insertions, 20 deletions
diff --git a/net/http/http_network_layer.cc b/net/http/http_network_layer.cc
index 0ff32d6..5690f6d 100644
--- a/net/http/http_network_layer.cc
+++ b/net/http/http_network_layer.cc
@@ -121,7 +121,11 @@ void HttpNetworkLayer::EnableSpdy(const std::string& mode) {
use_alt_protocols = false;
HttpStreamFactory::set_use_alternate_protocols(false);
} else if (option == kEnableFlowControl) {
- SpdySession::set_flow_control(true);
+ std::vector<std::string> next_protos;
+ next_protos.push_back("http/1.1");
+ next_protos.push_back("spdy/2");
+ next_protos.push_back("spdy/2.1");
+ HttpStreamFactory::set_next_protos(next_protos);
} else if (option == kForceAltProtocols) {
PortAlternateProtocolPair pair;
pair.port = 443;
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 0a6a163..60febd5 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -95,7 +95,7 @@ std::vector<std::string> MakeNextProtos(const char* a, ...) {
// SpdyNextProtos returns a vector of NPN protocol strings for negotiating
// SPDY.
std::vector<std::string> SpdyNextProtos() {
- return MakeNextProtos("http/1.1", "spdy/2", NULL);
+ return MakeNextProtos("http/1.1", "spdy/2", "spdy/2.1", NULL);
}
} // namespace
@@ -8544,7 +8544,8 @@ TEST_F(HttpNetworkTransactionTest, SpdyAlternateProtocolThroughProxy) {
// to https when doing an Alternate Protocol upgrade.
HttpStreamFactory::set_use_alternate_protocols(true);
HttpStreamFactory::set_next_protos(
- MakeNextProtos("http/1.1", "http1.1", "spdy/2", "spdy", NULL));
+ MakeNextProtos(
+ "http/1.1", "http1.1", "spdy/2.1", "spdy/2", "spdy", NULL));
SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70"));
HttpAuthHandlerMock::Factory* auth_factory =
diff --git a/net/http/http_server_properties.cc b/net/http/http_server_properties.cc
index 06f519e..b685900 100644
--- a/net/http/http_server_properties.cc
+++ b/net/http/http_server_properties.cc
@@ -13,12 +13,14 @@ const char kAlternateProtocolHeader[] = "Alternate-Protocol";
const char* const kAlternateProtocolStrings[] = {
"npn-spdy/1",
"npn-spdy/2",
+ "npn-spdy/2.1",
};
static const char* AlternateProtocolToString(AlternateProtocol protocol) {
switch (protocol) {
case NPN_SPDY_1:
case NPN_SPDY_2:
+ case NPN_SPDY_21:
return kAlternateProtocolStrings[protocol];
case ALTERNATE_PROTOCOL_BROKEN:
return "Broken";
diff --git a/net/http/http_server_properties.h b/net/http/http_server_properties.h
index cd4ae4b..d9d60fd 100644
--- a/net/http/http_server_properties.h
+++ b/net/http/http_server_properties.h
@@ -18,6 +18,7 @@ namespace net {
enum AlternateProtocol {
NPN_SPDY_1 = 0,
NPN_SPDY_2,
+ NPN_SPDY_21,
NUM_ALTERNATE_PROTOCOLS,
ALTERNATE_PROTOCOL_BROKEN, // The alternate protocol is known to be broken.
UNINITIALIZED_ALTERNATE_PROTOCOL,
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index 6b4e00f..ff8bc50 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -1063,7 +1063,9 @@ MockSSLClientSocket::MockSSLClientSocket(
transport_(transport_socket),
data_(data),
is_npn_state_set_(false),
- new_npn_value_(false) {
+ new_npn_value_(false),
+ is_next_protocol_set_(false),
+ next_protocol_(kProtoHTTP11) {
DCHECK(data_);
delete ssl_host_info; // we take ownership but don't use it.
}
@@ -1159,6 +1161,19 @@ bool MockSSLClientSocket::set_was_npn_negotiated(bool negotiated) {
return new_npn_value_ = negotiated;
}
+SSLClientSocket::NextProto MockSSLClientSocket::next_protocol_negotiated()
+ const {
+ if (is_next_protocol_set_)
+ return next_protocol_;
+ return SSLClientSocket::NextProtoFromString(data_->next_proto);
+}
+
+void MockSSLClientSocket::set_next_protocol_negotiated(
+ SSLClientSocket::NextProto next_protocol) {
+ is_next_protocol_set_ = true;
+ next_protocol_ = next_protocol;
+}
+
void MockSSLClientSocket::OnReadComplete(const MockRead& data) {
NOTIMPLEMENTED();
}
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index 84c9c05..e4909c5 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -761,6 +761,9 @@ class MockSSLClientSocket : public MockClientSocket, public AsyncSocket {
std::string* server_protos) OVERRIDE;
virtual bool was_npn_negotiated() const OVERRIDE;
virtual bool set_was_npn_negotiated(bool negotiated) OVERRIDE;
+ virtual SSLClientSocket::NextProto next_protocol_negotiated() const OVERRIDE;
+ virtual void set_next_protocol_negotiated(
+ SSLClientSocket::NextProto next_protocol) OVERRIDE;
// This MockSocket does not implement the manual async IO feature.
virtual void OnReadComplete(const MockRead& data) OVERRIDE;
@@ -775,6 +778,8 @@ class MockSSLClientSocket : public MockClientSocket, public AsyncSocket {
bool is_npn_state_set_;
bool new_npn_value_;
bool was_used_to_convey_data_;
+ bool is_next_protocol_set_;
+ SSLClientSocket::NextProto next_protocol_;
};
class MockUDPClientSocket : public DatagramClientSocket,
diff --git a/net/socket/ssl_client_socket.cc b/net/socket/ssl_client_socket.cc
index b1e31f5..6bcbe7e 100644
--- a/net/socket/ssl_client_socket.cc
+++ b/net/socket/ssl_client_socket.cc
@@ -22,6 +22,8 @@ SSLClientSocket::NextProto SSLClientSocket::NextProtoFromString(
return kProtoSPDY1;
} else if (proto_string == "spdy/2") {
return kProtoSPDY2;
+ } else if (proto_string == "spdy/2.1") {
+ return kProtoSPDY21;
} else {
return kProtoUnknown;
}
@@ -91,6 +93,15 @@ bool SSLClientSocket::set_was_spdy_negotiated(bool negotiated) {
return was_spdy_negotiated_ = negotiated;
}
+SSLClientSocket::NextProto SSLClientSocket::next_protocol_negotiated() const {
+ return next_protocol_;
+}
+
+void SSLClientSocket::set_next_protocol_negotiated(
+ SSLClientSocket::NextProto next_protocol) {
+ next_protocol_ = next_protocol;
+}
+
bool SSLClientSocket::was_origin_bound_cert_sent() const {
return was_origin_bound_cert_sent_;
}
diff --git a/net/socket/ssl_client_socket.h b/net/socket/ssl_client_socket.h
index c847e9f..63ad321 100644
--- a/net/socket/ssl_client_socket.h
+++ b/net/socket/ssl_client_socket.h
@@ -83,6 +83,7 @@ class NET_EXPORT SSLClientSocket : public SSLSocket {
kProtoHTTP11 = 1,
kProtoSPDY1 = 2,
kProtoSPDY2 = 3,
+ kProtoSPDY21 = 4,
};
// Gets the SSL connection information of the socket.
@@ -126,6 +127,11 @@ class NET_EXPORT SSLClientSocket : public SSLSocket {
virtual bool set_was_spdy_negotiated(bool negotiated);
+ virtual SSLClientSocket::NextProto next_protocol_negotiated() const;
+
+ virtual void set_next_protocol_negotiated(
+ SSLClientSocket::NextProto next_protocol);
+
// Returns true if an origin bound certificate was sent on this connection.
// This may be useful for protocols, like SPDY, which allow the same
// connection to be shared between multiple origins, each of which need
@@ -139,6 +145,8 @@ class NET_EXPORT SSLClientSocket : public SSLSocket {
bool was_npn_negotiated_;
// True if NPN successfully negotiated SPDY.
bool was_spdy_negotiated_;
+ // Protocol that we negotiated with the server.
+ SSLClientSocket::NextProto next_protocol_;
// True if an origin bound certificate was sent.
bool was_origin_bound_cert_sent_;
};
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc
index 2cc1cde..1ec0453 100644
--- a/net/socket/ssl_client_socket_pool.cc
+++ b/net/socket/ssl_client_socket_pool.cc
@@ -302,8 +302,10 @@ int SSLConnectJob::DoSSLConnectComplete(int result) {
// advertised it, so allow it.
// TODO(mbelshe): verify it was a protocol we advertised?
if (next_protocol == SSLClientSocket::kProtoSPDY1 ||
- next_protocol == SSLClientSocket::kProtoSPDY2) {
+ next_protocol == SSLClientSocket::kProtoSPDY2 ||
+ next_protocol == SSLClientSocket::kProtoSPDY21) {
ssl_socket_->set_was_spdy_negotiated(true);
+ ssl_socket_->set_next_protocol_negotiated(next_protocol);
}
}
if (params_->want_spdy_over_npn() && !ssl_socket_->was_spdy_negotiated())
diff --git a/net/spdy/spdy_http_stream.cc b/net/spdy/spdy_http_stream.cc
index 175f827..8445898 100644
--- a/net/spdy/spdy_http_stream.cc
+++ b/net/spdy/spdy_http_stream.cc
@@ -128,7 +128,7 @@ int SpdyHttpStream::ReadResponseBody(
}
bytes_read += bytes_to_copy;
}
- if (SpdySession::flow_control())
+ if (spdy_session_ && spdy_session_->is_flow_control_enabled())
stream_->IncreaseRecvWindowSize(bytes_read);
return bytes_read;
} else if (stream_->closed()) {
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index d0f0d2b..901c1eb 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -122,6 +122,7 @@ class SpdyNetworkTransactionTest
std::vector<std::string> next_protos;
next_protos.push_back("http/1.1");
next_protos.push_back("spdy/2");
+ next_protos.push_back("spdy/2.1");
switch (test_type_) {
case SPDYNPN:
@@ -1851,7 +1852,7 @@ TEST_P(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
// limitations as described above and it's not deterministic, tests may
// fail under specific circumstances.
TEST_P(SpdyNetworkTransactionTest, WindowUpdateReceived) {
- SpdySession::set_flow_control(true);
+ SpdySession::set_use_flow_control(true);
static int kFrameCount = 2;
scoped_ptr<std::string> content(
@@ -1922,13 +1923,13 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateReceived) {
kMaxSpdyFrameChunkSize * kFrameCount,
stream->stream()->send_window_size());
helper.VerifyDataConsumed();
- SpdySession::set_flow_control(false);
+ SpdySession::set_use_flow_control(false);
}
// Test that received data frames and sent WINDOW_UPDATE frames change
// the recv_window_size_ correctly.
TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) {
- SpdySession::set_flow_control(true);
+ SpdySession::set_use_flow_control(true);
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
scoped_ptr<spdy::SpdyFrame> window_update(
@@ -2005,13 +2006,13 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) {
data->CompleteRead();
helper.VerifyDataConsumed();
- SpdySession::set_flow_control(false);
+ SpdySession::set_use_flow_control(false);
}
// Test that WINDOW_UPDATE frame causing overflow is handled correctly. We
// use the same trick as in the above test to enforce our scenario.
TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
- SpdySession::set_flow_control(true);
+ SpdySession::set_use_flow_control(true);
// number of full frames we hope to write (but will not, used to
// set content-length header correctly)
@@ -2084,7 +2085,7 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
helper.session()->spdy_session_pool()->CloseAllSessions();
helper.VerifyDataConsumed();
- SpdySession::set_flow_control(false);
+ SpdySession::set_use_flow_control(false);
}
// Test that after hitting a send window size of 0, the write process
@@ -2103,7 +2104,7 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
// After that, next read is artifically enforced, which causes a
// WINDOW_UPDATE to be read and I/O process resumes.
TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
- SpdySession::set_flow_control(true);
+ SpdySession::set_use_flow_control(true);
// Number of frames we need to send to zero out the window size: data
// frames plus SYN_STREAM plus the last data frame; also we need another
@@ -2194,7 +2195,7 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
rv = callback.WaitForResult();
helper.VerifyDataConsumed();
- SpdySession::set_flow_control(false);
+ SpdySession::set_use_flow_control(false);
}
TEST_P(SpdyNetworkTransactionTest, CancelledTransaction) {
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index 17c18eb..1b0d591 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -282,6 +282,7 @@ SpdySession::SpdySession(const HostPortProxyPair& host_port_proxy_pair,
trailing_ping_pending_(false),
check_ping_status_pending_(false),
need_to_send_ping_(false),
+ flow_control_(use_flow_control_),
initial_send_window_size_(spdy::kSpdyStreamInitialWindowSize),
initial_recv_window_size_(spdy::kSpdyStreamInitialWindowSize),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)),
@@ -336,6 +337,14 @@ net::Error SpdySession::InitializeWithSocket(
is_secure_ = is_secure;
certificate_error_code_ = certificate_error_code;
+ if (is_secure_) {
+ SSLClientSocket* ssl_socket =
+ reinterpret_cast<SSLClientSocket*>(connection_->socket());
+ DCHECK(ssl_socket);
+ if (ssl_socket->next_protocol_negotiated() == SSLClientSocket::kProtoSPDY21)
+ flow_control_ = true;
+ }
+
// Write out any data that we might have to send, such as the settings frame.
WriteSocketLater();
net::Error error = ReadSocket();
@@ -557,7 +566,7 @@ int SpdySession::WriteStreamData(spdy::SpdyStreamId stream_id,
}
// Obey send window size of the stream if flow control is enabled.
- if (use_flow_control_) {
+ if (flow_control_) {
if (stream->send_window_size() <= 0) {
// Because we queue frames onto the session, it is possible that
// a stream was not flow controlled at the time it attempted the
@@ -1463,7 +1472,7 @@ void SpdySession::OnWindowUpdate(
CHECK_EQ(stream->stream_id(), stream_id);
CHECK(!stream->cancelled());
- if (use_flow_control_)
+ if (flow_control_)
stream->IncreaseSendWindowSize(delta_window_size);
net_log_.AddEvent(
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index a05bd3c..3da2f1e 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -149,9 +149,9 @@ class NET_EXPORT SpdySession : public base::RefCounted<SpdySession>,
static void SetSSLMode(bool enable) { use_ssl_ = enable; }
static bool SSLMode() { return use_ssl_; }
- // Enable or disable flow control.
- static void set_flow_control(bool enable) { use_flow_control_ = enable; }
- static bool flow_control() { return use_flow_control_; }
+ // Enable or disable flow control used by unit tests. This only applies for
+ // new SpdySessions.
+ static void set_use_flow_control(bool enable) { use_flow_control_ = enable; }
// Sets the max concurrent streams per session, as a ceiling on any server
// specific SETTINGS value.
@@ -224,6 +224,11 @@ class NET_EXPORT SpdySession : public base::RefCounted<SpdySession>,
return unclaimed_pushed_streams_.size();
}
+ // Returns true if flow control is enabled for the session.
+ bool is_flow_control_enabled() const {
+ return flow_control_;
+ }
+
const BoundNetLog& net_log() const { return net_log_; }
int GetPeerAddress(AddressList* address) const;
@@ -540,6 +545,9 @@ class NET_EXPORT SpdySession : public base::RefCounted<SpdySession>,
// waste of effort (and MUST not be done).
bool need_to_send_ping_;
+ // Indicate if flow control is enabled or not.
+ bool flow_control_;
+
// Initial send window size for the session; can be changed by an
// arriving SETTINGS frame; newly created streams use this value for the
// initial send window size.
diff --git a/net/spdy/spdy_stream.cc b/net/spdy/spdy_stream.cc
index 00e66e4..088d89fa 100644
--- a/net/spdy/spdy_stream.cc
+++ b/net/spdy/spdy_stream.cc
@@ -325,7 +325,7 @@ void SpdyStream::OnDataReceived(const char* data, int length) {
return;
}
- if (session_->flow_control())
+ if (session_->is_flow_control_enabled())
DecreaseRecvWindowSize(length);
// Track our bandwidth.