Index: trunk/src/net/websockets/websocket_stream_test.cc |
=================================================================== |
--- trunk/src/net/websockets/websocket_stream_test.cc (revision 282330) |
+++ trunk/src/net/websockets/websocket_stream_test.cc (working copy) |
@@ -56,29 +56,6 @@ |
return result; |
} |
-// Simple builder for a DeterministicSocketData object to save repetitive code. |
-// It always sets the connect data to MockConnect(SYNCHRONOUS, OK), so it cannot |
-// be used in tests where the connect fails. In practice, those tests never have |
-// any read/write data and so can't benefit from it anyway. The arrays are not |
-// copied. It is up to the caller to ensure they stay in scope until the test |
-// ends. |
-template <size_t reads_count, size_t writes_count> |
-scoped_ptr<DeterministicSocketData> BuildSocketData( |
- MockRead (&reads)[reads_count], |
- MockWrite (&writes)[writes_count]) { |
- scoped_ptr<DeterministicSocketData> socket_data( |
- new DeterministicSocketData(reads, reads_count, writes, writes_count)); |
- socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); |
- socket_data->SetStop(reads_count + writes_count); |
- return socket_data.Pass(); |
-} |
- |
-// Builder for a DeterministicSocketData that expects nothing. This does not |
-// set the connect data, so the calling code must do that explicitly. |
-scoped_ptr<DeterministicSocketData> BuildNullSocketData() { |
- return make_scoped_ptr(new DeterministicSocketData(NULL, 0, NULL, 0)); |
-} |
- |
// A sub-class of WebSocketHandshakeStreamCreateHelper which always sets a |
// deterministic key to use in the WebSocket handshake. |
class DeterministicKeyWebSocketHandshakeStreamCreateHelper |
@@ -134,15 +111,10 @@ |
const std::vector<std::string>& sub_protocols, |
const std::string& origin, |
scoped_ptr<DeterministicSocketData> socket_data) { |
- AddRawExpectations(socket_data.Pass()); |
+ url_request_context_host_.AddRawExpectations(socket_data.Pass()); |
CreateAndConnectStream(socket_url, sub_protocols, origin); |
} |
- // Add additional raw expectations for sockets created before the final one. |
- void AddRawExpectations(scoped_ptr<DeterministicSocketData> socket_data) { |
- url_request_context_host_.AddRawExpectations(socket_data.Pass()); |
- } |
- |
// A wrapper for CreateAndConnectStreamForTesting that knows about our default |
// parameters. |
void CreateAndConnectStream(const std::string& socket_url, |
@@ -195,8 +167,8 @@ |
virtual void OnStartOpeningHandshake( |
scoped_ptr<WebSocketHandshakeRequestInfo> request) OVERRIDE { |
- // Can be called multiple times (in the case of HTTP auth). Last call |
- // wins. |
+ if (owner_->request_info_) |
+ ADD_FAILURE(); |
owner_->request_info_ = request.Pass(); |
} |
virtual void OnFinishOpeningHandshake( |
@@ -254,132 +226,6 @@ |
} |
}; |
-// Common code to construct expectations for authentication tests that receive |
-// the auth challenge on one connection and then create a second connection to |
-// send the authenticated request on. |
-class CommonAuthTestHelper { |
- public: |
- CommonAuthTestHelper() : reads1_(), writes1_(), reads2_(), writes2_() {} |
- |
- scoped_ptr<DeterministicSocketData> BuildSocketData1( |
- const std::string& response) { |
- request1_ = WebSocketStandardRequest("/", "http://localhost", ""); |
- writes1_[0] = MockWrite(SYNCHRONOUS, 0, request1_.c_str()); |
- response1_ = response; |
- reads1_[0] = MockRead(SYNCHRONOUS, 1, response1_.c_str()); |
- reads1_[1] = MockRead(SYNCHRONOUS, OK, 2); // Close connection |
- |
- return BuildSocketData(reads1_, writes1_); |
- } |
- |
- scoped_ptr<DeterministicSocketData> BuildSocketData2( |
- const std::string& request, |
- const std::string& response) { |
- request2_ = request; |
- response2_ = response; |
- writes2_[0] = MockWrite(SYNCHRONOUS, 0, request2_.c_str()); |
- reads2_[0] = MockRead(SYNCHRONOUS, 1, response2_.c_str()); |
- return BuildSocketData(reads2_, writes2_); |
- } |
- |
- private: |
- // These need to be object-scoped since they have to remain valid until all |
- // socket operations in the test are complete. |
- std::string request1_; |
- std::string request2_; |
- std::string response1_; |
- std::string response2_; |
- MockRead reads1_[2]; |
- MockWrite writes1_[1]; |
- MockRead reads2_[1]; |
- MockWrite writes2_[1]; |
- |
- DISALLOW_COPY_AND_ASSIGN(CommonAuthTestHelper); |
-}; |
- |
-// Data and methods for BasicAuth tests. |
-class WebSocketStreamCreateBasicAuthTest : public WebSocketStreamCreateTest { |
- protected: |
- void CreateAndConnectAuthHandshake(const std::string& url, |
- const std::string& base64_user_pass, |
- const std::string& response2) { |
- AddRawExpectations(helper_.BuildSocketData1(kUnauthorizedResponse)); |
- |
- static const char request2format[] = |
- "GET / HTTP/1.1\r\n" |
- "Host: localhost\r\n" |
- "Connection: Upgrade\r\n" |
- "Pragma: no-cache\r\n" |
- "Cache-Control: no-cache\r\n" |
- "Authorization: Basic %s\r\n" |
- "Upgrade: websocket\r\n" |
- "Origin: http://localhost\r\n" |
- "Sec-WebSocket-Version: 13\r\n" |
- "User-Agent:\r\n" |
- "Accept-Encoding: gzip,deflate\r\n" |
- "Accept-Language: en-us,fr\r\n" |
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" |
- "Sec-WebSocket-Extensions: permessage-deflate; " |
- "client_max_window_bits\r\n" |
- "\r\n"; |
- const std::string request = |
- base::StringPrintf(request2format, base64_user_pass.c_str()); |
- CreateAndConnectRawExpectations( |
- url, |
- NoSubProtocols(), |
- "http://localhost", |
- helper_.BuildSocketData2(request, response2)); |
- } |
- |
- static const char kUnauthorizedResponse[]; |
- |
- CommonAuthTestHelper helper_; |
-}; |
- |
-class WebSocketStreamCreateDigestAuthTest : public WebSocketStreamCreateTest { |
- protected: |
- static const char kUnauthorizedResponse[]; |
- static const char kAuthorizedRequest[]; |
- |
- CommonAuthTestHelper helper_; |
-}; |
- |
-const char WebSocketStreamCreateBasicAuthTest::kUnauthorizedResponse[] = |
- "HTTP/1.1 401 Unauthorized\r\n" |
- "Content-Length: 0\r\n" |
- "WWW-Authenticate: Basic realm=\"camelot\"\r\n" |
- "\r\n"; |
- |
-// These negotiation values are borrowed from |
-// http_auth_handler_digest_unittest.cc. Feel free to come up with new ones if |
-// you are bored. Only the weakest (no qop) variants of Digest authentication |
-// can be tested by this method, because the others involve random input. |
-const char WebSocketStreamCreateDigestAuthTest::kUnauthorizedResponse[] = |
- "HTTP/1.1 401 Unauthorized\r\n" |
- "Content-Length: 0\r\n" |
- "WWW-Authenticate: Digest realm=\"Oblivion\", nonce=\"nonce-value\"\r\n" |
- "\r\n"; |
- |
-const char WebSocketStreamCreateDigestAuthTest::kAuthorizedRequest[] = |
- "GET / HTTP/1.1\r\n" |
- "Host: localhost\r\n" |
- "Connection: Upgrade\r\n" |
- "Pragma: no-cache\r\n" |
- "Cache-Control: no-cache\r\n" |
- "Authorization: Digest username=\"FooBar\", realm=\"Oblivion\", " |
- "nonce=\"nonce-value\", uri=\"/\", " |
- "response=\"f72ff54ebde2f928860f806ec04acd1b\"\r\n" |
- "Upgrade: websocket\r\n" |
- "Origin: http://localhost\r\n" |
- "Sec-WebSocket-Version: 13\r\n" |
- "User-Agent:\r\n" |
- "Accept-Encoding: gzip,deflate\r\n" |
- "Accept-Language: en-us,fr\r\n" |
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" |
- "Sec-WebSocket-Extensions: permessage-deflate; " |
- "client_max_window_bits\r\n" |
- "\r\n"; |
- |
class WebSocketStreamCreateUMATest : public ::testing::Test { |
public: |
// This enum should match with the enum in Delegate in websocket_stream.cc. |
@@ -1072,7 +918,8 @@ |
// Connect failure must look just like negotiation failure. |
TEST_F(WebSocketStreamCreateTest, ConnectionFailure) { |
- scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData()); |
+ scoped_ptr<DeterministicSocketData> socket_data( |
+ new DeterministicSocketData(NULL, 0, NULL, 0)); |
socket_data->set_connect_data( |
MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED)); |
CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), |
@@ -1087,7 +934,8 @@ |
// Connect timeout must look just like any other failure. |
TEST_F(WebSocketStreamCreateTest, ConnectionTimeout) { |
- scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData()); |
+ scoped_ptr<DeterministicSocketData> socket_data( |
+ new DeterministicSocketData(NULL, 0, NULL, 0)); |
socket_data->set_connect_data( |
MockConnect(ASYNC, ERR_CONNECTION_TIMED_OUT)); |
CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), |
@@ -1100,7 +948,8 @@ |
// Cancellation during connect works. |
TEST_F(WebSocketStreamCreateTest, CancellationDuringConnect) { |
- scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData()); |
+ scoped_ptr<DeterministicSocketData> socket_data( |
+ new DeterministicSocketData(NULL, 0, NULL, 0)); |
socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING)); |
CreateAndConnectRawExpectations("ws://localhost/", |
NoSubProtocols(), |
@@ -1142,15 +991,15 @@ |
MockRead reads[] = { |
MockRead(ASYNC, 1, "HTTP/1.1 101 Switching Protocols\r\nUpgr"), |
}; |
- scoped_ptr<DeterministicSocketData> socket_data( |
- BuildSocketData(reads, writes)); |
+ DeterministicSocketData* socket_data(new DeterministicSocketData( |
+ reads, arraysize(reads), writes, arraysize(writes))); |
+ socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); |
socket_data->SetStop(1); |
- DeterministicSocketData* socket_data_raw_ptr = socket_data.get(); |
CreateAndConnectRawExpectations("ws://localhost/", |
NoSubProtocols(), |
"http://localhost", |
- socket_data.Pass()); |
- socket_data_raw_ptr->Run(); |
+ make_scoped_ptr(socket_data)); |
+ socket_data->Run(); |
stream_request_.reset(); |
RunUntilIdle(); |
EXPECT_FALSE(has_failed()); |
@@ -1183,14 +1032,14 @@ |
std::string request = WebSocketStandardRequest("/", "http://localhost", ""); |
MockWrite writes[] = {MockWrite(ASYNC, request.data(), request.size(), 0)}; |
MockRead reads[] = {MockRead(ASYNC, 0, 1)}; |
- scoped_ptr<DeterministicSocketData> socket_data( |
- BuildSocketData(reads, writes)); |
- DeterministicSocketData* socket_data_raw_ptr = socket_data.get(); |
+ DeterministicSocketData* socket_data(new DeterministicSocketData( |
+ reads, arraysize(reads), writes, arraysize(writes))); |
+ socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); |
CreateAndConnectRawExpectations("ws://localhost/", |
NoSubProtocols(), |
"http://localhost", |
- socket_data.Pass()); |
- socket_data_raw_ptr->RunFor(2); |
+ make_scoped_ptr(socket_data)); |
+ socket_data->RunFor(2); |
EXPECT_TRUE(has_failed()); |
EXPECT_FALSE(stream_); |
EXPECT_FALSE(response_info_); |
@@ -1204,7 +1053,8 @@ |
ssl_data_[0]->cert = |
ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der"); |
ASSERT_TRUE(ssl_data_[0]->cert); |
- scoped_ptr<DeterministicSocketData> raw_socket_data(BuildNullSocketData()); |
+ scoped_ptr<DeterministicSocketData> raw_socket_data( |
+ new DeterministicSocketData(NULL, 0, NULL, 0)); |
CreateAndConnectRawExpectations("wss://localhost/", |
NoSubProtocols(), |
"http://localhost", |
@@ -1227,7 +1077,8 @@ |
ssl_data_.push_back(ssl_data.release()); |
ssl_data.reset(new SSLSocketDataProvider(ASYNC, OK)); |
ssl_data_.push_back(ssl_data.release()); |
- url_request_context_host_.AddRawExpectations(BuildNullSocketData()); |
+ url_request_context_host_.AddRawExpectations( |
+ make_scoped_ptr(new DeterministicSocketData(NULL, 0, NULL, 0))); |
CreateAndConnectStandard( |
"wss://localhost/", "/", NoSubProtocols(), "http://localhost", "", ""); |
RunUntilIdle(); |
@@ -1238,60 +1089,6 @@ |
EXPECT_TRUE(stream_); |
} |
-// If the server requests authorisation, but we have no credentials, the |
-// connection should fail cleanly. |
-TEST_F(WebSocketStreamCreateBasicAuthTest, FailureNoCredentials) { |
- CreateAndConnectCustomResponse("ws://localhost/", |
- "/", |
- NoSubProtocols(), |
- "http://localhost", |
- "", |
- kUnauthorizedResponse); |
- RunUntilIdle(); |
- EXPECT_TRUE(has_failed()); |
- EXPECT_EQ("HTTP Authentication failed; no valid credentials available", |
- failure_message()); |
- EXPECT_TRUE(response_info_); |
-} |
- |
-TEST_F(WebSocketStreamCreateBasicAuthTest, SuccessPasswordInUrl) { |
- CreateAndConnectAuthHandshake("ws://foo:bar@localhost/", |
- "Zm9vOmJhcg==", |
- WebSocketStandardResponse(std::string())); |
- RunUntilIdle(); |
- EXPECT_FALSE(has_failed()); |
- EXPECT_TRUE(stream_); |
- ASSERT_TRUE(response_info_); |
- EXPECT_EQ(101, response_info_->status_code); |
-} |
- |
-TEST_F(WebSocketStreamCreateBasicAuthTest, FailureIncorrectPasswordInUrl) { |
- CreateAndConnectAuthHandshake( |
- "ws://foo:baz@localhost/", "Zm9vOmJheg==", kUnauthorizedResponse); |
- RunUntilIdle(); |
- EXPECT_TRUE(has_failed()); |
- EXPECT_TRUE(response_info_); |
-} |
- |
-// Digest auth has the same connection semantics as Basic auth, so we can |
-// generally assume that whatever works for Basic auth will also work for |
-// Digest. There's just one test here, to confirm that it works at all. |
-TEST_F(WebSocketStreamCreateDigestAuthTest, DigestPasswordInUrl) { |
- AddRawExpectations(helper_.BuildSocketData1(kUnauthorizedResponse)); |
- |
- CreateAndConnectRawExpectations( |
- "ws://FooBar:pass@localhost/", |
- NoSubProtocols(), |
- "http://localhost", |
- helper_.BuildSocketData2(kAuthorizedRequest, |
- WebSocketStandardResponse(std::string()))); |
- RunUntilIdle(); |
- EXPECT_FALSE(has_failed()); |
- EXPECT_TRUE(stream_); |
- ASSERT_TRUE(response_info_); |
- EXPECT_EQ(101, response_info_->status_code); |
-} |
- |
TEST_F(WebSocketStreamCreateUMATest, Incomplete) { |
const std::string name("Net.WebSocket.HandshakeResult"); |
scoped_ptr<base::HistogramSamples> original(GetSamples(name)); |