Index: webkit/plugins/ppapi/ppb_websocket_impl.cc |
diff --git a/webkit/plugins/ppapi/ppb_websocket_impl.cc b/webkit/plugins/ppapi/ppb_websocket_impl.cc |
index ea3634b876beddfc24aa48ef1007ddf3c784ea3c..a316acb71ed74cc1aec5dbf17b51402103f4223b 100644 |
--- a/webkit/plugins/ppapi/ppb_websocket_impl.cc |
+++ b/webkit/plugins/ppapi/ppb_websocket_impl.cc |
@@ -64,6 +64,11 @@ uint64_t GetFrameSize(uint64_t payload_size) { |
return SaturateAdd(payload_size, overhead); |
} |
+bool InValidStateToReceive(PP_WebSocketReadyState_Dev state) { |
+ return state == PP_WEBSOCKETREADYSTATE_OPEN_DEV || |
+ state == PP_WEBSOCKETREADYSTATE_CLOSING_DEV; |
+} |
+ |
} // namespace |
namespace webkit { |
@@ -72,6 +77,7 @@ namespace ppapi { |
PPB_WebSocket_Impl::PPB_WebSocket_Impl(PP_Instance instance) |
: Resource(instance), |
state_(PP_WEBSOCKETREADYSTATE_INVALID_DEV), |
+ error_was_received_(false), |
receive_callback_var_(NULL), |
wait_for_receive_(false), |
close_code_(0), |
@@ -122,10 +128,6 @@ int32_t PPB_WebSocket_Impl::Connect(PP_Var url, |
return PP_ERROR_INPROGRESS; |
state_ = PP_WEBSOCKETREADYSTATE_CLOSED_DEV; |
- // Validate |callback| (Doesn't support blocking callback) |
- if (!callback.func) |
- return PP_ERROR_BLOCKS_MAIN_THREAD; |
- |
// Validate url and convert it to WebURL. |
scoped_refptr<StringVar> url_string = StringVar::FromPPVar(url); |
if (!url_string) |
@@ -178,7 +180,11 @@ int32_t PPB_WebSocket_Impl::Connect(PP_Var url, |
} |
WebString web_protocols = WebString::fromUTF8(protocol_string); |
- // Create WebKit::WebSocket object. |
+ // Validate |callback| (Doesn't support blocking callback) |
+ if (!callback.func) |
+ return PP_ERROR_BLOCKS_MAIN_THREAD; |
+ |
+ // Create WebKit::WebSocket object and connect. |
WebDocument document = plugin_instance->container()->element().document(); |
websocket_.reset(WebSocket::create(document, this)); |
DCHECK(websocket_.get()); |
@@ -201,10 +207,6 @@ int32_t PPB_WebSocket_Impl::Close(uint16_t code, |
if (!websocket_.get()) |
return PP_ERROR_FAILED; |
- // Validate |callback| (Doesn't support blocking callback) |
- if (!callback.func) |
- return PP_ERROR_BLOCKS_MAIN_THREAD; |
- |
// Validate |code|. |
if (code != WebSocket::CloseEventCodeNotSpecified) { |
if (!(code == WebSocket::CloseEventCodeNormalClosure || |
@@ -212,6 +214,7 @@ int32_t PPB_WebSocket_Impl::Close(uint16_t code, |
code <= WebSocket::CloseEventCodeMaximumUserDefined))) |
return PP_ERROR_NOACCESS; |
} |
+ |
// Validate |reason|. |
// TODO(toyoshim): Returns PP_ERROR_BADARGUMENT if |reason| contains any |
// surrogates. |
@@ -224,6 +227,10 @@ int32_t PPB_WebSocket_Impl::Close(uint16_t code, |
state_ == PP_WEBSOCKETREADYSTATE_CLOSED_DEV) |
return PP_ERROR_INPROGRESS; |
+ // Validate |callback| (Doesn't support blocking callback) |
+ if (!callback.func) |
+ return PP_ERROR_BLOCKS_MAIN_THREAD; |
+ |
// Install |callback|. |
close_callback_ = callback; |
@@ -235,6 +242,7 @@ int32_t PPB_WebSocket_Impl::Close(uint16_t code, |
return PP_OK_COMPLETIONPENDING; |
} |
+ // Close connection. |
state_ = PP_WEBSOCKETREADYSTATE_CLOSING_DEV; |
WebString web_reason = WebString::fromUTF8(reason_string->value()); |
websocket_->close(code, web_reason); |
@@ -253,6 +261,15 @@ int32_t PPB_WebSocket_Impl::ReceiveMessage(PP_Var* message, |
if (!received_messages_.empty()) |
return DoReceive(); |
+ // Returns PP_ERROR_FAILED after an error is received and received messages |
+ // is exhausted. |
+ if (error_was_received_) |
+ return PP_ERROR_FAILED; |
+ |
+ // Validate |callback| (Doesn't support blocking callback) |
+ if (!callback.func) |
+ return PP_ERROR_BLOCKS_MAIN_THREAD; |
+ |
// Or retain |message| as buffer to store and install |callback|. |
wait_for_receive_ = true; |
receive_callback_var_ = message; |
@@ -357,6 +374,10 @@ void PPB_WebSocket_Impl::didConnect() { |
} |
void PPB_WebSocket_Impl::didReceiveMessage(const WebString& message) { |
+ // Dispose packets after receiving an error or in invalid state. |
+ if (error_was_received_ || !InValidStateToReceive(state_)) |
+ return; |
+ |
// Append received data to queue. |
std::string string = message.utf8(); |
PP_Var var = StringVar::StringToPPVar( |
@@ -370,13 +391,30 @@ void PPB_WebSocket_Impl::didReceiveMessage(const WebString& message) { |
} |
void PPB_WebSocket_Impl::didReceiveBinaryData(const WebData& binaryData) { |
- DLOG(INFO) << "didReceiveBinaryData is not implemented yet."; |
+ // Dispose packets after receiving an error or in invalid state. |
+ if (error_was_received_ || !InValidStateToReceive(state_)) |
+ return; |
+ |
// TODO(toyoshim): Support to receive binary data. |
+ DLOG(INFO) << "didReceiveBinaryData is not implemented yet."; |
} |
void PPB_WebSocket_Impl::didReceiveMessageError() { |
- // TODO(toyoshim): Must implement. |
- DLOG(INFO) << "didReceiveMessageError is not implemented yet."; |
+ // Ignore error notification in invalid state. |
+ if (!InValidStateToReceive(state_)) |
+ return; |
+ |
+ // Records the error, then stops receiving any frames after this error. |
+ // The error will be notified after all queued messages are read via |
+ // ReceiveMessage(). |
+ error_was_received_ = true; |
+ if (!wait_for_receive_) |
+ return; |
+ |
+ // But, if no messages are queued and ReceiveMessage() is now on going. |
+ // We must invoke the callback with error code here. |
+ wait_for_receive_ = false; |
+ PP_RunAndClearCompletionCallback(&receive_callback_, PP_ERROR_FAILED); |
} |
void PPB_WebSocket_Impl::didUpdateBufferedAmount( |
@@ -387,11 +425,10 @@ void PPB_WebSocket_Impl::didUpdateBufferedAmount( |
} |
void PPB_WebSocket_Impl::didStartClosingHandshake() { |
- // TODO(toyoshim): Must implement. |
- DLOG(INFO) << "didStartClosingHandshake is not implemented yet."; |
+ state_ = PP_WEBSOCKETREADYSTATE_CLOSING_DEV; |
} |
-void PPB_WebSocket_Impl::didClose(unsigned long buffered_amount, |
+void PPB_WebSocket_Impl::didClose(unsigned long unhandled_buffered_amount, |
ClosingHandshakeCompletionStatus status, |
unsigned short code, |
const WebString& reason) { |
@@ -401,26 +438,33 @@ void PPB_WebSocket_Impl::didClose(unsigned long buffered_amount, |
close_reason_ = new StringVar( |
PpapiGlobals::Get()->GetModuleForInstance(pp_instance()), reason_string); |
- // TODO(toyoshim): Set close_was_clean_. |
+ // Set close_was_clean_. |
+ bool was_clean = |
+ state_ == PP_WEBSOCKETREADYSTATE_CLOSING_DEV && |
+ !unhandled_buffered_amount && |
+ status == WebSocketClient::ClosingHandshakeComplete; |
+ close_was_clean_ = was_clean ? PP_TRUE : PP_FALSE; |
+ |
+ // Update buffered_amount_. |
+ buffered_amount_ = unhandled_buffered_amount; |
// Handle state transition and invoking callback. |
DCHECK_NE(PP_WEBSOCKETREADYSTATE_CLOSED_DEV, state_); |
PP_WebSocketReadyState_Dev state = state_; |
state_ = PP_WEBSOCKETREADYSTATE_CLOSED_DEV; |
- // Update buffered_amount_. |
- buffered_amount_ = buffered_amount; |
- |
if (state == PP_WEBSOCKETREADYSTATE_CONNECTING_DEV) |
PP_RunAndClearCompletionCallback(&connect_callback_, PP_OK); |
if (state == PP_WEBSOCKETREADYSTATE_CLOSING_DEV) |
PP_RunAndClearCompletionCallback(&close_callback_, PP_OK); |
+ |
+ // Disconnect. |
+ if (websocket_.get()) |
+ websocket_->disconnect(); |
} |
int32_t PPB_WebSocket_Impl::DoReceive() { |
- // TODO(toyoshim): Check state. |
- |
if (!receive_callback_var_) |
return PP_OK; |