Index: net/websockets/websocket_stream_test.cc |
diff --git a/net/websockets/websocket_stream_test.cc b/net/websockets/websocket_stream_test.cc |
index 3e11a95ac1c2d3c0b49ef1cd2e3136ee62cd3d87..f48dcbee9e4d73df998837c156a90695adf1ea44 100644 |
--- a/net/websockets/websocket_stream_test.cc |
+++ b/net/websockets/websocket_stream_test.cc |
@@ -45,7 +45,7 @@ class DeterministicKeyWebSocketHandshakeStreamCreateHelper |
class WebSocketStreamCreateTest : public ::testing::Test { |
protected: |
- WebSocketStreamCreateTest() : websocket_error_(0) {} |
+ WebSocketStreamCreateTest(): has_failed_(false) {} |
void CreateAndConnectCustomResponse( |
const std::string& socket_url, |
@@ -110,18 +110,21 @@ class WebSocketStreamCreateTest : public ::testing::Test { |
return std::vector<std::string>(); |
} |
- uint16 error() const { return websocket_error_; } |
+ const std::string& failure_message() const { return failure_message_; } |
+ bool has_failed() const { return has_failed_; } |
class TestConnectDelegate : public WebSocketStream::ConnectDelegate { |
public: |
- TestConnectDelegate(WebSocketStreamCreateTest* owner) : owner_(owner) {} |
+ explicit TestConnectDelegate(WebSocketStreamCreateTest* owner) |
+ : owner_(owner) {} |
virtual void OnSuccess(scoped_ptr<WebSocketStream> stream) OVERRIDE { |
stream.swap(owner_->stream_); |
} |
- virtual void OnFailure(uint16 websocket_error) OVERRIDE { |
- owner_->websocket_error_ = websocket_error; |
+ virtual void OnFailure(const std::string& message) OVERRIDE { |
+ owner_->has_failed_ = true; |
+ owner_->failure_message_ = message; |
} |
private: |
@@ -132,8 +135,9 @@ class WebSocketStreamCreateTest : public ::testing::Test { |
scoped_ptr<WebSocketStreamRequest> stream_request_; |
// Only set if the connection succeeded. |
scoped_ptr<WebSocketStream> stream_; |
- // Only set if the connection failed. 0 otherwise. |
- uint16 websocket_error_; |
+ // Only set if the connection failed. |
+ std::string failure_message_; |
+ bool has_failed_; |
}; |
// Confirm that the basic case works as expected. |
@@ -141,6 +145,7 @@ TEST_F(WebSocketStreamCreateTest, SimpleSuccess) { |
CreateAndConnectStandard( |
"ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", ""); |
RunUntilIdle(); |
+ EXPECT_FALSE(has_failed()); |
EXPECT_TRUE(stream_); |
} |
@@ -148,6 +153,7 @@ TEST_F(WebSocketStreamCreateTest, SimpleSuccess) { |
TEST_F(WebSocketStreamCreateTest, NeedsToRunLoop) { |
CreateAndConnectStandard( |
"ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", ""); |
+ EXPECT_FALSE(has_failed()); |
EXPECT_FALSE(stream_); |
} |
@@ -160,6 +166,7 @@ TEST_F(WebSocketStreamCreateTest, PathIsUsed) { |
"", |
""); |
RunUntilIdle(); |
+ EXPECT_FALSE(has_failed()); |
EXPECT_TRUE(stream_); |
} |
@@ -172,6 +179,7 @@ TEST_F(WebSocketStreamCreateTest, OriginIsUsed) { |
"", |
""); |
RunUntilIdle(); |
+ EXPECT_FALSE(has_failed()); |
EXPECT_TRUE(stream_); |
} |
@@ -189,6 +197,7 @@ TEST_F(WebSocketStreamCreateTest, SubProtocolIsUsed) { |
"Sec-WebSocket-Protocol: chatv20.chromium.org\r\n"); |
RunUntilIdle(); |
EXPECT_TRUE(stream_); |
+ EXPECT_FALSE(has_failed()); |
EXPECT_EQ("chatv20.chromium.org", stream_->GetSubProtocol()); |
} |
@@ -202,20 +211,30 @@ TEST_F(WebSocketStreamCreateTest, UnsolicitedSubProtocol) { |
"Sec-WebSocket-Protocol: chatv20.chromium.org\r\n"); |
RunUntilIdle(); |
EXPECT_FALSE(stream_); |
- EXPECT_EQ(1006, error()); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Error during WebSocket handshake: " |
+ "Response must not include 'Sec-WebSocket-Protocol' header " |
+ "if not present in request: chatv20.chromium.org", |
+ failure_message()); |
} |
// Missing sub-protocol response is rejected. |
TEST_F(WebSocketStreamCreateTest, UnacceptedSubProtocol) { |
+ std::vector<std::string> sub_protocols; |
+ sub_protocols.push_back("chat.example.com"); |
CreateAndConnectStandard("ws://localhost/testing_path", |
"/testing_path", |
- std::vector<std::string>(1, "chat.example.com"), |
+ sub_protocols, |
"http://localhost/", |
"Sec-WebSocket-Protocol: chat.example.com\r\n", |
""); |
RunUntilIdle(); |
EXPECT_FALSE(stream_); |
- EXPECT_EQ(1006, error()); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Error during WebSocket handshake: " |
+ "Sent non-empty 'Sec-WebSocket-Protocol' header " |
+ "but no response was received", |
+ failure_message()); |
} |
// Only one sub-protocol can be accepted. |
@@ -233,7 +252,32 @@ TEST_F(WebSocketStreamCreateTest, MultipleSubProtocolsInResponse) { |
"chatv20.chromium.org\r\n"); |
RunUntilIdle(); |
EXPECT_FALSE(stream_); |
- EXPECT_EQ(1006, error()); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Error during WebSocket handshake: " |
+ "'Sec-WebSocket-Protocol' header must not appear " |
+ "more than once in a response", |
+ failure_message()); |
+} |
+ |
+// Unmatched sub-protocol should be rejected. |
+TEST_F(WebSocketStreamCreateTest, UnmatchedSubProtocolInResponse) { |
+ std::vector<std::string> sub_protocols; |
+ sub_protocols.push_back("chatv11.chromium.org"); |
+ sub_protocols.push_back("chatv20.chromium.org"); |
+ CreateAndConnectStandard("ws://localhost/testing_path", |
+ "/testing_path", |
+ sub_protocols, |
+ "http://google.com/", |
+ "Sec-WebSocket-Protocol: chatv11.chromium.org, " |
+ "chatv20.chromium.org\r\n", |
+ "Sec-WebSocket-Protocol: chatv21.chromium.org\r\n"); |
+ RunUntilIdle(); |
+ EXPECT_FALSE(stream_); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Error during WebSocket handshake: " |
+ "'Sec-WebSocket-Protocol' header value 'chatv21.chromium.org' " |
+ "in response does not match any of sent values", |
+ failure_message()); |
} |
// Unknown extension in the response is rejected |
@@ -246,7 +290,11 @@ TEST_F(WebSocketStreamCreateTest, UnknownExtension) { |
"Sec-WebSocket-Extensions: x-unknown-extension\r\n"); |
RunUntilIdle(); |
EXPECT_FALSE(stream_); |
- EXPECT_EQ(1006, error()); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Error during WebSocket handshake: " |
+ "Found an unsupported extension 'x-unknown-extension' " |
+ "in 'Sec-WebSocket-Extensions' header", |
+ failure_message()); |
} |
// Additional Sec-WebSocket-Accept headers should be rejected. |
@@ -260,7 +308,11 @@ TEST_F(WebSocketStreamCreateTest, DoubleAccept) { |
"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"); |
RunUntilIdle(); |
EXPECT_FALSE(stream_); |
- EXPECT_EQ(1006, error()); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Error during WebSocket handshake: " |
+ "'Sec-WebSocket-Accept' header must not appear " |
+ "more than once in a response", |
+ failure_message()); |
} |
// Response code 200 must be rejected. |
@@ -278,7 +330,8 @@ TEST_F(WebSocketStreamCreateTest, InvalidStatusCode) { |
"", |
kInvalidStatusCodeResponse); |
RunUntilIdle(); |
- EXPECT_EQ(1006, error()); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Unexpected status code: 200", failure_message()); |
} |
// Redirects are not followed (according to the WHATWG WebSocket API, which |
@@ -299,7 +352,8 @@ TEST_F(WebSocketStreamCreateTest, RedirectsRejected) { |
"", |
kRedirectResponse); |
RunUntilIdle(); |
- EXPECT_EQ(1006, error()); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Unexpected status code: 302", failure_message()); |
} |
// Malformed responses should be rejected. HttpStreamParser will accept just |
@@ -321,7 +375,8 @@ TEST_F(WebSocketStreamCreateTest, MalformedResponse) { |
"", |
kMalformedResponse); |
RunUntilIdle(); |
- EXPECT_EQ(1006, error()); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Unexpected status code: 200", failure_message()); |
} |
// Upgrade header must be present. |
@@ -338,7 +393,9 @@ TEST_F(WebSocketStreamCreateTest, MissingUpgradeHeader) { |
"", |
kMissingUpgradeResponse); |
RunUntilIdle(); |
- EXPECT_EQ(1006, error()); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Error during WebSocket handshake: 'Upgrade' header is missing", |
+ failure_message()); |
} |
// There must only be one upgrade header. |
@@ -350,7 +407,31 @@ TEST_F(WebSocketStreamCreateTest, DoubleUpgradeHeader) { |
"http://localhost/", |
"", "Upgrade: HTTP/2.0\r\n"); |
RunUntilIdle(); |
- EXPECT_EQ(1006, error()); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Error during WebSocket handshake: " |
+ "'Upgrade' header must not appear more than once in a response", |
+ failure_message()); |
+} |
+ |
+// There must only be one correct upgrade header. |
+TEST_F(WebSocketStreamCreateTest, IncorrectUpgradeHeader) { |
+ static const char kMissingUpgradeResponse[] = |
+ "HTTP/1.1 101 Switching Protocols\r\n" |
+ "Connection: Upgrade\r\n" |
+ "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" |
+ "Upgrade: hogefuga\r\n" |
+ "\r\n"; |
+ CreateAndConnectCustomResponse("ws://localhost/", |
+ "/", |
+ NoSubProtocols(), |
+ "http://localhost/", |
+ "", |
+ kMissingUpgradeResponse); |
+ RunUntilIdle(); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Error during WebSocket handshake: " |
+ "'Upgrade' header value is not 'WebSocket': hogefuga", |
+ failure_message()); |
} |
// Connection header must be present. |
@@ -367,7 +448,31 @@ TEST_F(WebSocketStreamCreateTest, MissingConnectionHeader) { |
"", |
kMissingConnectionResponse); |
RunUntilIdle(); |
- EXPECT_EQ(1006, error()); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Error during WebSocket handshake: " |
+ "'Connection' header is missing", |
+ failure_message()); |
+} |
+ |
+// Connection header must contain "Upgrade". |
+TEST_F(WebSocketStreamCreateTest, IncorrectConnectionHeader) { |
+ static const char kMissingConnectionResponse[] = |
+ "HTTP/1.1 101 Switching Protocols\r\n" |
+ "Upgrade: websocket\r\n" |
+ "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" |
+ "Connection: hogefuga\r\n" |
+ "\r\n"; |
+ CreateAndConnectCustomResponse("ws://localhost/", |
+ "/", |
+ NoSubProtocols(), |
+ "http://localhost/", |
+ "", |
+ kMissingConnectionResponse); |
+ RunUntilIdle(); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Error during WebSocket handshake: " |
+ "'Connection' header value must contain 'Upgrade'", |
+ failure_message()); |
} |
// Connection header is permitted to contain other tokens. |
@@ -385,6 +490,7 @@ TEST_F(WebSocketStreamCreateTest, AdditionalTokenInConnectionHeader) { |
"", |
kAdditionalConnectionTokenResponse); |
RunUntilIdle(); |
+ EXPECT_FALSE(has_failed()); |
EXPECT_TRUE(stream_); |
} |
@@ -402,7 +508,10 @@ TEST_F(WebSocketStreamCreateTest, MissingSecWebSocketAccept) { |
"", |
kMissingAcceptResponse); |
RunUntilIdle(); |
- EXPECT_EQ(1006, error()); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Error during WebSocket handshake: " |
+ "'Sec-WebSocket-Accept' header is missing", |
+ failure_message()); |
} |
// Sec-WebSocket-Accept header must match the key that was sent. |
@@ -420,7 +529,10 @@ TEST_F(WebSocketStreamCreateTest, WrongSecWebSocketAccept) { |
"", |
kIncorrectAcceptResponse); |
RunUntilIdle(); |
- EXPECT_EQ(1006, error()); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Error during WebSocket handshake: " |
+ "Incorrect 'Sec-WebSocket-Accept' header value", |
+ failure_message()); |
} |
// Cancellation works. |
@@ -429,6 +541,7 @@ TEST_F(WebSocketStreamCreateTest, Cancellation) { |
"ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", ""); |
stream_request_.reset(); |
RunUntilIdle(); |
+ EXPECT_FALSE(has_failed()); |
EXPECT_FALSE(stream_); |
} |
@@ -441,7 +554,9 @@ TEST_F(WebSocketStreamCreateTest, ConnectionFailure) { |
CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), |
"http://localhost/", socket_data.Pass()); |
RunUntilIdle(); |
- EXPECT_EQ(1006, error()); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_REFUSED", |
+ failure_message()); |
} |
// Connect timeout must look just like any other failure. |
@@ -453,7 +568,9 @@ TEST_F(WebSocketStreamCreateTest, ConnectionTimeout) { |
CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), |
"http://localhost/", socket_data.Pass()); |
RunUntilIdle(); |
- EXPECT_EQ(1006, error()); |
+ EXPECT_TRUE(has_failed()); |
+ EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT", |
+ failure_message()); |
} |
// Cancellation during connect works. |
@@ -467,6 +584,7 @@ TEST_F(WebSocketStreamCreateTest, CancellationDuringConnect) { |
socket_data.Pass()); |
stream_request_.reset(); |
RunUntilIdle(); |
+ EXPECT_FALSE(has_failed()); |
EXPECT_FALSE(stream_); |
} |
@@ -487,6 +605,7 @@ TEST_F(WebSocketStreamCreateTest, CancellationDuringWrite) { |
socket_data->Run(); |
stream_request_.reset(); |
RunUntilIdle(); |
+ EXPECT_FALSE(has_failed()); |
EXPECT_FALSE(stream_); |
} |
@@ -508,6 +627,7 @@ TEST_F(WebSocketStreamCreateTest, CancellationDuringRead) { |
socket_data->Run(); |
stream_request_.reset(); |
RunUntilIdle(); |
+ EXPECT_FALSE(has_failed()); |
EXPECT_FALSE(stream_); |
} |