diff options
author | ukai@chromium.org <ukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-05 09:09:16 +0000 |
---|---|---|
committer | ukai@chromium.org <ukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-05 09:09:16 +0000 |
commit | fee3eb776d9c2797be9ee0abc619f9b4e5fb6a2d (patch) | |
tree | d1a9919ca4c248eecc785a47256b9ca0da63cb5a /net/websockets | |
parent | 831d36b259bb29400123b7c186d67276cbbb9eb8 (diff) | |
download | chromium_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.cc | 75 | ||||
-rw-r--r-- | net/websockets/websocket.h | 15 | ||||
-rw-r--r-- | net/websockets/websocket_unittest.cc | 32 |
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(); } |