summaryrefslogtreecommitdiffstats
path: root/net/websockets
diff options
context:
space:
mode:
authorukai@chromium.org <ukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-05 09:09:16 +0000
committerukai@chromium.org <ukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-05 09:09:16 +0000
commitfee3eb776d9c2797be9ee0abc619f9b4e5fb6a2d (patch)
treed1a9919ca4c248eecc785a47256b9ca0da63cb5a /net/websockets
parent831d36b259bb29400123b7c186d67276cbbb9eb8 (diff)
downloadchromium_src-fee3eb776d9c2797be9ee0abc619f9b4e5fb6a2d.zip
chromium_src-fee3eb776d9c2797be9ee0abc619f9b4e5fb6a2d.tar.gz
chromium_src-fee3eb776d9c2797be9ee0abc619f9b4e5fb6a2d.tar.bz2
Update new WebSocket API.
Add new readyState CLOSING. Fix close() to match the API spec. OnError reports WebSocket error, and OnSocketError reports socket level error OnClose reports was_clean. BUG=none TEST=none Review URL: http://codereview.chromium.org/1587008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@43605 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/websockets')
-rw-r--r--net/websockets/websocket.cc75
-rw-r--r--net/websockets/websocket.h15
-rw-r--r--net/websockets/websocket_unittest.cc32
3 files changed, 95 insertions, 27 deletions
diff --git a/net/websockets/websocket.cc b/net/websockets/websocket.cc
index cf90fa7..c079aa5 100644
--- a/net/websockets/websocket.cc
+++ b/net/websockets/websocket.cc
@@ -64,7 +64,7 @@ void WebSocket::Connect() {
}
void WebSocket::Send(const std::string& msg) {
- if (ready_state_ == CLOSED) {
+ if (ready_state_ == CLOSING || ready_state_ == CLOSED) {
return;
}
if (client_closing_handshake_) {
@@ -86,21 +86,44 @@ void WebSocket::Send(const std::string& msg) {
void WebSocket::Close() {
DCHECK(MessageLoop::current() == origin_loop_);
+ // If connection has not yet started, do nothing.
if (ready_state_ == INITIALIZED) {
DCHECK(!socket_stream_);
ready_state_ = CLOSED;
return;
}
- if (ready_state_ == CLOSED)
+
+ // If the readyState attribute is in the CLOSING or CLOSED state, do nothing
+ if (ready_state_ == CLOSING || ready_state_ == CLOSED)
return;
+
if (request_->version() == DRAFT75) {
DCHECK(socket_stream_);
socket_stream_->Close();
return;
}
- origin_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &WebSocket::StartClosingHandshake));
+
+ // If the WebSocket connection is not yet established, fail the WebSocket
+ // connection and set the readyState attribute's value to CLOSING.
+ if (ready_state_ == CONNECTING) {
+ ready_state_ = CLOSING;
+ origin_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &WebSocket::FailConnection));
+ }
+
+ // If the WebSocket closing handshake has not yet been started, start
+ // the WebSocket closing handshake and set the readyState attribute's value
+ // to CLOSING.
+ if (!closing_handshake_started_) {
+ ready_state_ = CLOSING;
+ origin_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &WebSocket::StartClosingHandshake));
+ }
+
+ // Otherwise, set the readyState attribute's value to CLOSING.
+ ready_state_ = CLOSING;
}
void WebSocket::DetachDelegate() {
@@ -180,8 +203,8 @@ void WebSocket::OnClose(SocketStream* socket_stream) {
}
void WebSocket::OnError(const SocketStream* socket_stream, int error) {
- origin_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this, &WebSocket::DoError, error));
+ origin_loop_->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &WebSocket::DoSocketError, error));
}
void WebSocket::SendPending() {
@@ -252,6 +275,7 @@ void WebSocket::DoReceivedData() {
}
// FALL THROUGH
case OPEN:
+ case CLOSING: // need to process closing-frame from server.
ProcessFrameData();
break;
@@ -278,6 +302,10 @@ void WebSocket::ProcessFrameData() {
const char* end =
current_read_buf_->StartOfBuffer() + current_read_buf_->offset();
while (p < end) {
+ // Let /error/ be false.
+ bool error = false;
+
+ // Handle the /frame type/ byte as follows.
unsigned char frame_byte = static_cast<unsigned char>(*p++);
if ((frame_byte & 0x80) == 0x80) {
int length = 0;
@@ -320,8 +348,9 @@ void WebSocket::ProcessFrameData() {
return;
}
// 4.2 3-8 Otherwise, let /error/ be true.
- // TODO(ukai): report error event.
+ error = true;
} else {
+ // Not enough data in buffer.
break;
}
} else {
@@ -329,12 +358,21 @@ void WebSocket::ProcessFrameData() {
while (p < end && *p != '\xff')
++p;
if (p < end && *p == '\xff') {
- if (frame_byte == 0x00 && delegate_)
- delegate_->OnMessage(this, std::string(msg_start, p - msg_start));
+ if (frame_byte == 0x00) {
+ if (delegate_) {
+ delegate_->OnMessage(this, std::string(msg_start, p - msg_start));
+ }
+ } else {
+ // Otherwise, discard the data and let /error/ to be true.
+ error = true;
+ }
++p;
next_frame = p;
}
}
+ // If /error/ is true, then *a WebSocket error has been detected.*
+ if (error && delegate_)
+ delegate_->OnError(this);
}
SkipReadBuffer(next_frame - start_frame);
}
@@ -399,10 +437,18 @@ void WebSocket::DoForceCloseConnection() {
// doesn't finish.)
DCHECK(MessageLoop::current() == origin_loop_);
force_close_task_ = NULL;
+ FailConnection();
+}
+
+void WebSocket::FailConnection() {
+ DCHECK(MessageLoop::current() == origin_loop_);
+ // 6.1 Client-initiated closure.
+ // *fail the WebSocket connection*.
+ // the user agent must close the WebSocket connection, and may report the
+ // problem to the user.
if (!socket_stream_)
return;
socket_stream_->Close();
- // TODO(ukai): report error close here?
}
void WebSocket::DoClose() {
@@ -420,14 +466,15 @@ void WebSocket::DoClose() {
return;
socket_stream_ = NULL;
if (delegate)
- delegate->OnClose(this);
+ delegate->OnClose(this,
+ server_closing_handshake_ && closing_handshake_started_);
Release();
}
-void WebSocket::DoError(int error) {
+void WebSocket::DoSocketError(int error) {
DCHECK(MessageLoop::current() == origin_loop_);
if (delegate_)
- delegate_->OnError(this, error);
+ delegate_->OnSocketError(this, error);
}
} // namespace net
diff --git a/net/websockets/websocket.h b/net/websockets/websocket.h
index 006362b..373c5e4 100644
--- a/net/websockets/websocket.h
+++ b/net/websockets/websocket.h
@@ -44,11 +44,14 @@ class WebSocketDelegate {
// |msg| should be in UTF-8.
virtual void OnMessage(WebSocket* socket, const std::string& msg) = 0;
+ // Called when WebSocket error has been detected.
+ virtual void OnError(WebSocket* socket) {}
+
// Called when |socket| is closed.
- virtual void OnClose(WebSocket* socket) = 0;
+ virtual void OnClose(WebSocket* socket, bool was_clean) = 0;
// Called when an error occured on |socket|.
- virtual void OnError(const WebSocket* socket, int error) {}
+ virtual void OnSocketError(const WebSocket* socket, int error) {}
};
class WebSocket : public base::RefCountedThreadSafe<WebSocket>,
@@ -58,7 +61,8 @@ class WebSocket : public base::RefCountedThreadSafe<WebSocket>,
INITIALIZED = -1,
CONNECTING = 0,
OPEN = 1,
- CLOSED = 2,
+ CLOSING = 2,
+ CLOSED = 3,
};
enum ProtocolVersion {
DEFAULT_VERSION = 0,
@@ -176,11 +180,12 @@ class WebSocket : public base::RefCountedThreadSafe<WebSocket>,
void StartClosingHandshake();
void DoForceCloseConnection();
+ void FailConnection();
// Handles closed connection.
void DoClose();
- // Handles error report.
- void DoError(int error);
+ // Handles socket error report.
+ void DoSocketError(int error);
State ready_state_;
scoped_ptr<Request> request_;
diff --git a/net/websockets/websocket_unittest.cc b/net/websockets/websocket_unittest.cc
index 5f6e8e9..4b65ae9 100644
--- a/net/websockets/websocket_unittest.cc
+++ b/net/websockets/websocket_unittest.cc
@@ -19,16 +19,18 @@
struct WebSocketEvent {
enum EventType {
- EVENT_OPEN, EVENT_MESSAGE, EVENT_CLOSE,
+ EVENT_OPEN, EVENT_MESSAGE, EVENT_ERROR, EVENT_CLOSE,
};
WebSocketEvent(EventType type, net::WebSocket* websocket,
- const std::string& websocket_msg)
- : event_type(type), socket(websocket), msg(websocket_msg) {}
+ const std::string& websocket_msg, bool websocket_flag)
+ : event_type(type), socket(websocket), msg(websocket_msg),
+ flag(websocket_flag) {}
EventType event_type;
net::WebSocket* socket;
std::string msg;
+ bool flag;
};
class WebSocketEventRecorder : public net::WebSocketDelegate {
@@ -36,11 +38,13 @@ class WebSocketEventRecorder : public net::WebSocketDelegate {
explicit WebSocketEventRecorder(net::CompletionCallback* callback)
: onopen_(NULL),
onmessage_(NULL),
+ onerror_(NULL),
onclose_(NULL),
callback_(callback) {}
virtual ~WebSocketEventRecorder() {
delete onopen_;
delete onmessage_;
+ delete onerror_;
delete onclose_;
}
@@ -56,20 +60,29 @@ class WebSocketEventRecorder : public net::WebSocketDelegate {
virtual void OnOpen(net::WebSocket* socket) {
events_.push_back(
- WebSocketEvent(WebSocketEvent::EVENT_OPEN, socket, std::string()));
+ WebSocketEvent(WebSocketEvent::EVENT_OPEN, socket,
+ std::string(), false));
if (onopen_)
onopen_->Run(&events_.back());
}
virtual void OnMessage(net::WebSocket* socket, const std::string& msg) {
events_.push_back(
- WebSocketEvent(WebSocketEvent::EVENT_MESSAGE, socket, msg));
+ WebSocketEvent(WebSocketEvent::EVENT_MESSAGE, socket, msg, false));
if (onmessage_)
onmessage_->Run(&events_.back());
}
- virtual void OnClose(net::WebSocket* socket) {
+ virtual void OnError(net::WebSocket* socket) {
events_.push_back(
- WebSocketEvent(WebSocketEvent::EVENT_CLOSE, socket, std::string()));
+ WebSocketEvent(WebSocketEvent::EVENT_ERROR, socket,
+ std::string(), false));
+ if (onerror_)
+ onerror_->Run(&events_.back());
+ }
+ virtual void OnClose(net::WebSocket* socket, bool was_clean) {
+ events_.push_back(
+ WebSocketEvent(WebSocketEvent::EVENT_CLOSE, socket,
+ std::string(), was_clean));
if (onclose_)
onclose_->Run(&events_.back());
if (callback_)
@@ -88,6 +101,7 @@ class WebSocketEventRecorder : public net::WebSocketDelegate {
std::vector<WebSocketEvent> events_;
Callback1<WebSocketEvent*>::Type* onopen_;
Callback1<WebSocketEvent*>::Type* onmessage_;
+ Callback1<WebSocketEvent*>::Type* onerror_;
Callback1<WebSocketEvent*>::Type* onclose_;
net::CompletionCallback* callback_;
@@ -279,7 +293,9 @@ TEST_F(WebSocketTest, ProcessFrameDataForLengthCalculation) {
kExpectedRemainingFrame, kExpectedRemainingLength);
// No onmessage event expected.
const std::vector<WebSocketEvent>& events = delegate->GetSeenEvents();
- EXPECT_EQ(0U, events.size());
+ EXPECT_EQ(1U, events.size());
+
+ EXPECT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type);
websocket->DetachDelegate();
}