summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/test/ppapi/ppapi_browsertest.cc25
-rw-r--r--content/content_renderer.gypi2
-rw-r--r--content/public/renderer/renderer_ppapi_host.h9
-rw-r--r--content/renderer/pepper/content_renderer_pepper_host_factory.cc8
-rw-r--r--content/renderer/pepper/mock_renderer_ppapi_host.cc6
-rw-r--r--content/renderer/pepper/mock_renderer_ppapi_host.h3
-rw-r--r--content/renderer/pepper/pepper_in_process_resource_creation.cc8
-rw-r--r--content/renderer/pepper/pepper_in_process_resource_creation.h2
-rw-r--r--content/renderer/pepper/pepper_websocket_host.cc290
-rw-r--r--content/renderer/pepper/pepper_websocket_host.h99
-rw-r--r--content/renderer/pepper/renderer_ppapi_host_impl.cc8
-rw-r--r--content/renderer/pepper/renderer_ppapi_host_impl.h2
-rw-r--r--ppapi/host/ppapi_host.cc6
-rw-r--r--ppapi/host/ppapi_host.h3
-rw-r--r--ppapi/ppapi_proxy.gypi2
-rw-r--r--ppapi/ppapi_shared.gypi1
-rw-r--r--ppapi/ppapi_tests.gypi1
-rw-r--r--ppapi/proxy/plugin_dispatcher.cc3
-rw-r--r--ppapi/proxy/ppapi_messages.h80
-rw-r--r--ppapi/proxy/resource_creation_proxy.cc10
-rw-r--r--ppapi/proxy/resource_creation_proxy.h2
-rw-r--r--ppapi/proxy/websocket_resource.cc509
-rw-r--r--ppapi/proxy/websocket_resource.h157
-rw-r--r--ppapi/proxy/websocket_resource_unittest.cc168
-rw-r--r--ppapi/tests/test_websocket.cc25
-rw-r--r--ppapi/thunk/interfaces_ppb_public_dev.h3
-rw-r--r--ppapi/thunk/interfaces_ppb_public_stable.h1
-rw-r--r--ppapi/thunk/ppb_websocket_api.h9
-rw-r--r--ppapi/thunk/resource_creation_api.h2
-rw-r--r--ppapi/thunk/thunk.h2
-rw-r--r--webkit/glue/webkit_glue.gypi2
-rw-r--r--webkit/plugins/ppapi/ppb_websocket_impl.cc538
-rw-r--r--webkit/plugins/ppapi/ppb_websocket_impl.h155
-rw-r--r--webkit/plugins/ppapi/resource_creation_impl.cc5
-rw-r--r--webkit/plugins/ppapi/resource_creation_impl.h1
35 files changed, 1424 insertions, 723 deletions
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index 5e215f5..c164b50 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -746,6 +746,31 @@ TEST_PPAPI_IN_PROCESS_WITH_WS(WebSocket_UtilityGetProtocol)
TEST_PPAPI_IN_PROCESS_WITH_WS(WebSocket_UtilityTextSendReceive)
TEST_PPAPI_IN_PROCESS_WITH_WS(WebSocket_UtilityBinarySendReceive)
TEST_PPAPI_IN_PROCESS_WITH_WS(WebSocket_UtilityBufferedAmount)
+TEST_PPAPI_OUT_OF_PROCESS(WebSocket_IsWebSocket)
+TEST_PPAPI_OUT_OF_PROCESS(WebSocket_UninitializedPropertiesAccess)
+TEST_PPAPI_OUT_OF_PROCESS(WebSocket_InvalidConnect)
+TEST_PPAPI_OUT_OF_PROCESS(WebSocket_Protocols)
+TEST_PPAPI_OUT_OF_PROCESS(WebSocket_GetURL)
+TEST_PPAPI_OUT_OF_PROCESS_WITH_WS(WebSocket_ValidConnect)
+TEST_PPAPI_OUT_OF_PROCESS_WITH_WS(WebSocket_InvalidClose)
+TEST_PPAPI_OUT_OF_PROCESS_WITH_WS(WebSocket_ValidClose)
+TEST_PPAPI_OUT_OF_PROCESS_WITH_WS(WebSocket_GetProtocol)
+TEST_PPAPI_OUT_OF_PROCESS_WITH_WS(WebSocket_TextSendReceive)
+TEST_PPAPI_OUT_OF_PROCESS_WITH_WS(WebSocket_BinarySendReceive)
+TEST_PPAPI_OUT_OF_PROCESS_WITH_WS(WebSocket_StressedSendReceive)
+TEST_PPAPI_OUT_OF_PROCESS_WITH_WS(WebSocket_BufferedAmount)
+TEST_PPAPI_OUT_OF_PROCESS_WITH_WS(WebSocket_AbortCalls)
+TEST_PPAPI_OUT_OF_PROCESS_WITH_WS(WebSocket_CcInterfaces)
+TEST_PPAPI_OUT_OF_PROCESS(WebSocket_UtilityInvalidConnect)
+TEST_PPAPI_OUT_OF_PROCESS(WebSocket_UtilityProtocols)
+TEST_PPAPI_OUT_OF_PROCESS(WebSocket_UtilityGetURL)
+TEST_PPAPI_OUT_OF_PROCESS_WITH_WS(WebSocket_UtilityValidConnect)
+TEST_PPAPI_OUT_OF_PROCESS_WITH_WS(WebSocket_UtilityInvalidClose)
+TEST_PPAPI_OUT_OF_PROCESS_WITH_WS(WebSocket_UtilityValidClose)
+TEST_PPAPI_OUT_OF_PROCESS_WITH_WS(WebSocket_UtilityGetProtocol)
+TEST_PPAPI_OUT_OF_PROCESS_WITH_WS(WebSocket_UtilityTextSendReceive)
+TEST_PPAPI_OUT_OF_PROCESS_WITH_WS(WebSocket_UtilityBinarySendReceive)
+TEST_PPAPI_OUT_OF_PROCESS_WITH_WS(WebSocket_UtilityBufferedAmount)
TEST_PPAPI_NACL_VIA_HTTP(WebSocket_IsWebSocket)
TEST_PPAPI_NACL_VIA_HTTP(WebSocket_UninitializedPropertiesAccess)
TEST_PPAPI_NACL_VIA_HTTP(WebSocket_InvalidConnect)
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index 139b125..5e482da 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -189,6 +189,8 @@
'renderer/pepper/pepper_plugin_delegate_impl.h',
'renderer/pepper/pepper_proxy_channel_delegate_impl.cc',
'renderer/pepper/pepper_proxy_channel_delegate_impl.h',
+ 'renderer/pepper/pepper_websocket_host.cc',
+ 'renderer/pepper/pepper_websocket_host.h',
'renderer/pepper/renderer_ppapi_host_impl.cc',
'renderer/pepper/renderer_ppapi_host_impl.h',
'renderer/plugin_channel_host.cc',
diff --git a/content/public/renderer/renderer_ppapi_host.h b/content/public/renderer/renderer_ppapi_host.h
index 8fda769..d6cc28f 100644
--- a/content/public/renderer/renderer_ppapi_host.h
+++ b/content/public/renderer/renderer_ppapi_host.h
@@ -13,6 +13,10 @@ class PpapiHost;
}
}
+namespace WebKit {
+class WebPluginContainer;
+}
+
namespace content {
class RenderView;
@@ -34,6 +38,11 @@ class RendererPpapiHost {
// instance is invalid.
virtual RenderView* GetRenderViewForInstance(PP_Instance instance) const = 0;
+ // Returns the WebPluginContainer for the given plugin instance, or NULL if
+ // the instance is invalid.
+ virtual WebKit::WebPluginContainer* GetContainerForInstance(
+ PP_Instance instance) const = 0;
+
// Returns true if the given instance is considered to be currently
// processing a user gesture or the plugin module has the "override user
// gesture" flag set (in which case it can always do things normally
diff --git a/content/renderer/pepper/content_renderer_pepper_host_factory.cc b/content/renderer/pepper/content_renderer_pepper_host_factory.cc
index 538fd9b..6d77832 100644
--- a/content/renderer/pepper/content_renderer_pepper_host_factory.cc
+++ b/content/renderer/pepper/content_renderer_pepper_host_factory.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "content/renderer/pepper/pepper_file_chooser_host.h"
+#include "content/renderer/pepper/pepper_websocket_host.h"
#include "content/renderer/pepper/renderer_ppapi_host_impl.h"
#include "ppapi/host/resource_host.h"
#include "ppapi/proxy/ppapi_messages.h"
@@ -33,6 +34,13 @@ scoped_ptr<ResourceHost> ContentRendererPepperHostFactory::CreateResourceHost(
if (!host_->IsValidInstance(instance))
return scoped_ptr<ResourceHost>();
+ // Stable interfaces.
+ switch (message.type()) {
+ case PpapiHostMsg_WebSocket_Create::ID:
+ return scoped_ptr<ResourceHost>(new PepperWebSocketHost(
+ host_, instance, params.pp_resource()));
+ }
+
// Resources for dev interfaces.
// TODO(brettw) when we support any public or private interfaces, put them in
// a separate switch above.
diff --git a/content/renderer/pepper/mock_renderer_ppapi_host.cc b/content/renderer/pepper/mock_renderer_ppapi_host.cc
index 9a31ecd..bf7d269 100644
--- a/content/renderer/pepper/mock_renderer_ppapi_host.cc
+++ b/content/renderer/pepper/mock_renderer_ppapi_host.cc
@@ -34,6 +34,12 @@ RenderView* MockRendererPpapiHost::GetRenderViewForInstance(
return NULL;
}
+WebKit::WebPluginContainer* MockRendererPpapiHost::GetContainerForInstance(
+ PP_Instance instance) const {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
bool MockRendererPpapiHost::HasUserGesture(PP_Instance instance) const {
return has_user_gesture_;
}
diff --git a/content/renderer/pepper/mock_renderer_ppapi_host.h b/content/renderer/pepper/mock_renderer_ppapi_host.h
index 471c2b1..115cb57 100644
--- a/content/renderer/pepper/mock_renderer_ppapi_host.h
+++ b/content/renderer/pepper/mock_renderer_ppapi_host.h
@@ -41,6 +41,8 @@ class MockRendererPpapiHost : public RendererPpapiHost {
virtual bool IsValidInstance(PP_Instance instance) const OVERRIDE;
virtual RenderView* GetRenderViewForInstance(
PP_Instance instance) const OVERRIDE;
+ virtual WebKit::WebPluginContainer* GetContainerForInstance(
+ PP_Instance instance) const OVERRIDE;
virtual bool HasUserGesture(PP_Instance instance) const OVERRIDE;
private:
@@ -58,4 +60,3 @@ class MockRendererPpapiHost : public RendererPpapiHost {
} // namespace content
#endif // CONTENT_RENDERER_PEPPER_MOCK_RENDERER_PPAPI_HOST_H_
-
diff --git a/content/renderer/pepper/pepper_in_process_resource_creation.cc b/content/renderer/pepper/pepper_in_process_resource_creation.cc
index 46b0eac..1854e9e 100644
--- a/content/renderer/pepper/pepper_in_process_resource_creation.cc
+++ b/content/renderer/pepper/pepper_in_process_resource_creation.cc
@@ -17,6 +17,7 @@
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/printing_resource.h"
#include "ppapi/proxy/url_request_info_resource.h"
+#include "ppapi/proxy/websocket_resource.h"
#include "ppapi/shared_impl/ppapi_globals.h"
#include "ppapi/shared_impl/ppapi_permissions.h"
#include "ppapi/shared_impl/resource_tracker.h"
@@ -64,4 +65,11 @@ PP_Resource PepperInProcessResourceCreation::CreateURLRequestInfo(
instance, data))->GetReference();
}
+PP_Resource PepperInProcessResourceCreation::CreateWebSocket(
+ PP_Instance instance) {
+ return (new ppapi::proxy::WebSocketResource(
+ host_impl_->in_process_router()->GetPluginConnection(),
+ instance))->GetReference();
+}
+
} // namespace content
diff --git a/content/renderer/pepper/pepper_in_process_resource_creation.h b/content/renderer/pepper/pepper_in_process_resource_creation.h
index 029311d..e5b3fa5 100644
--- a/content/renderer/pepper/pepper_in_process_resource_creation.h
+++ b/content/renderer/pepper/pepper_in_process_resource_creation.h
@@ -51,6 +51,8 @@ class PepperInProcessResourceCreation
virtual PP_Resource CreateURLRequestInfo(
PP_Instance instance,
const ::ppapi::URLRequestInfoData& data) OVERRIDE;
+ virtual PP_Resource CreateWebSocket(
+ PP_Instance instance) OVERRIDE;
private:
// Non-owning pointer to the host for the current plugin.
diff --git a/content/renderer/pepper/pepper_websocket_host.cc b/content/renderer/pepper/pepper_websocket_host.cc
new file mode 100644
index 0000000..ec6341a
--- /dev/null
+++ b/content/renderer/pepper/pepper_websocket_host.cc
@@ -0,0 +1,290 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/pepper/pepper_websocket_host.h"
+
+#include <string>
+
+#include "content/public/renderer/renderer_ppapi_host.h"
+#include "net/base/net_util.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/ppb_websocket.h"
+#include "ppapi/host/dispatch_host_message.h"
+#include "ppapi/host/host_message_context.h"
+#include "ppapi/host/ppapi_host.h"
+#include "ppapi/proxy/ppapi_messages.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebArrayBuffer.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebSocket.h"
+
+using WebKit::WebArrayBuffer;
+using WebKit::WebDocument;
+using WebKit::WebString;
+using WebKit::WebSocket;
+using WebKit::WebURL;
+
+namespace content {
+
+PepperWebSocketHost::PepperWebSocketHost(
+ RendererPpapiHost* host,
+ PP_Instance instance,
+ PP_Resource resource)
+ : ResourceHost(host->GetPpapiHost(), instance, resource),
+ renderer_ppapi_host_(host),
+ connecting_(false),
+ initiating_close_(false),
+ accepting_close_(false),
+ error_was_received_(false) {
+}
+
+PepperWebSocketHost::~PepperWebSocketHost() {
+ if (websocket_.get())
+ websocket_->disconnect();
+}
+
+int32_t PepperWebSocketHost::OnResourceMessageReceived(
+ const IPC::Message& msg,
+ ppapi::host::HostMessageContext* context) {
+ IPC_BEGIN_MESSAGE_MAP(PepperWebSocketHost, msg)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_WebSocket_Connect,
+ OnHostMsgConnect)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_WebSocket_Close,
+ OnHostMsgClose)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_WebSocket_SendText,
+ OnHostMsgSendText)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_WebSocket_SendBinary,
+ OnHostMsgSendBinary)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_WebSocket_Fail,
+ OnHostMsgFail)
+ IPC_END_MESSAGE_MAP()
+ return PP_ERROR_FAILED;
+}
+
+void PepperWebSocketHost::didConnect() {
+ std::string protocol;
+ if (websocket_.get())
+ protocol = websocket_->subprotocol().utf8();
+ connecting_ = false;
+ connect_reply_.params.set_result(PP_OK);
+ host()->SendReply(connect_reply_,
+ PpapiPluginMsg_WebSocket_ConnectReply(
+ url_,
+ protocol));
+}
+
+void PepperWebSocketHost::didReceiveMessage(const WebKit::WebString& message) {
+ // Dispose packets after receiving an error.
+ if (error_was_received_)
+ return;
+
+ // Send an IPC to transport received data.
+ std::string string_message = message.utf8();
+ host()->SendUnsolicitedReply(pp_resource(),
+ PpapiPluginMsg_WebSocket_ReceiveTextReply(
+ string_message));
+}
+
+void PepperWebSocketHost::didReceiveArrayBuffer(
+ const WebKit::WebArrayBuffer& binaryData) {
+ // Dispose packets after receiving an error.
+ if (error_was_received_)
+ return;
+
+ // Send an IPC to transport received data.
+ uint8_t* data = static_cast<uint8_t*>(binaryData.data());
+ std::vector<uint8_t> array_message(data, data + binaryData.byteLength());
+ host()->SendUnsolicitedReply(pp_resource(),
+ PpapiPluginMsg_WebSocket_ReceiveBinaryReply(
+ array_message));
+}
+
+void PepperWebSocketHost::didReceiveMessageError() {
+ // Records the error, then stops receiving any frames after this error.
+ // The error must be notified after all queued messages are read.
+ error_was_received_ = true;
+
+ // Send an IPC to report the error. After this IPC, ReceiveTextReply and
+ // ReceiveBinaryReply IPC are not sent anymore because |error_was_received_|
+ // blocks.
+ host()->SendUnsolicitedReply(pp_resource(),
+ PpapiPluginMsg_WebSocket_ErrorReply());
+}
+
+void PepperWebSocketHost::didUpdateBufferedAmount(
+ unsigned long buffered_amount) {
+ // Send an IPC to update buffered amount.
+ host()->SendUnsolicitedReply(pp_resource(),
+ PpapiPluginMsg_WebSocket_BufferedAmountReply(
+ buffered_amount));
+}
+
+void PepperWebSocketHost::didStartClosingHandshake() {
+ accepting_close_ = true;
+
+ // Send an IPC to notice that server starts closing handshake.
+ host()->SendUnsolicitedReply(pp_resource(),
+ PpapiPluginMsg_WebSocket_StateReply(
+ PP_WEBSOCKETREADYSTATE_CLOSING));
+}
+
+void PepperWebSocketHost::didClose(unsigned long unhandled_buffered_amount,
+ ClosingHandshakeCompletionStatus status,
+ unsigned short code,
+ const WebKit::WebString& reason) {
+ if (connecting_) {
+ connecting_ = false;
+ connect_reply_.params.set_result(PP_ERROR_FAILED);
+ host()->SendReply(
+ connect_reply_,
+ PpapiPluginMsg_WebSocket_ConnectReply(url_, std::string()));
+ }
+
+ // Set close_was_clean_.
+ bool was_clean =
+ (initiating_close_ || accepting_close_) &&
+ !unhandled_buffered_amount &&
+ status == WebSocketClient::ClosingHandshakeComplete;
+
+ if (initiating_close_) {
+ initiating_close_ = false;
+ close_reply_.params.set_result(PP_OK);
+ host()->SendReply(close_reply_, PpapiPluginMsg_WebSocket_CloseReply(
+ unhandled_buffered_amount,
+ was_clean,
+ code,
+ reason.utf8()));
+ } else {
+ accepting_close_ = false;
+ host()->SendUnsolicitedReply(pp_resource(),
+ PpapiPluginMsg_WebSocket_ClosedReply(
+ unhandled_buffered_amount,
+ was_clean,
+ code,
+ reason.utf8()));
+ }
+
+ // Disconnect.
+ if (websocket_.get())
+ websocket_->disconnect();
+}
+
+int32_t PepperWebSocketHost::OnHostMsgConnect(
+ ppapi::host::HostMessageContext* context,
+ const std::string& url,
+ const std::vector<std::string>& protocols) {
+ // Validate url and convert it to WebURL.
+ GURL gurl(url);
+ url_ = gurl.spec();
+ if (!gurl.is_valid())
+ return PP_ERROR_BADARGUMENT;
+ if (!gurl.SchemeIs("ws") && !gurl.SchemeIs("wss"))
+ return PP_ERROR_BADARGUMENT;
+ if (gurl.has_ref())
+ return PP_ERROR_BADARGUMENT;
+ if (!net::IsPortAllowedByDefault(gurl.IntPort()))
+ return PP_ERROR_BADARGUMENT;
+ WebURL web_url(gurl);
+
+ // Validate protocols.
+ std::string protocol_string;
+ for (std::vector<std::string>::const_iterator vector_it = protocols.begin();
+ vector_it != protocols.end();
+ ++vector_it) {
+
+ // Check containing characters.
+ for (std::string::const_iterator string_it = vector_it->begin();
+ string_it != vector_it->end();
+ ++string_it) {
+ uint8_t character = *string_it;
+ // WebSocket specification says "(Subprotocol string must consist of)
+ // characters in the range U+0021 to U+007E not including separator
+ // characters as defined in [RFC2616]."
+ const uint8_t minimumProtocolCharacter = '!'; // U+0021.
+ const uint8_t maximumProtocolCharacter = '~'; // U+007E.
+ if (character < minimumProtocolCharacter ||
+ character > maximumProtocolCharacter ||
+ character == '"' || character == '(' || character == ')' ||
+ character == ',' || character == '/' ||
+ (character >= ':' && character <= '@') || // U+003A - U+0040
+ (character >= '[' && character <= ']') || // U+005B - u+005D
+ character == '{' || character == '}')
+ return PP_ERROR_BADARGUMENT;
+ }
+ // Join protocols with the comma separator.
+ if (vector_it != protocols.begin())
+ protocol_string.append(",");
+ protocol_string.append(*vector_it);
+ }
+
+ // Convert protocols to WebString.
+ WebString web_protocols = WebString::fromUTF8(protocol_string);
+
+ // Create WebKit::WebSocket object and connect.
+ WebKit::WebPluginContainer* container =
+ renderer_ppapi_host_->GetContainerForInstance(pp_instance());
+ if (!container)
+ return PP_ERROR_BADARGUMENT;
+ // TODO(toyoshim) Remove following WebDocument object copy.
+ WebDocument document = container->element().document();
+ websocket_.reset(WebSocket::create(document, this));
+ DCHECK(websocket_.get());
+ if (!websocket_.get())
+ return PP_ERROR_NOTSUPPORTED;
+
+ // Set receiving binary object type.
+ websocket_->setBinaryType(WebSocket::BinaryTypeArrayBuffer);
+ websocket_->connect(web_url, web_protocols);
+
+ connect_reply_ = context->MakeReplyMessageContext();
+ connecting_ = true;
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PepperWebSocketHost::OnHostMsgClose(
+ ppapi::host::HostMessageContext* context,
+ int32_t code,
+ const std::string& reason) {
+ if (!websocket_.get())
+ return PP_ERROR_FAILED;
+ close_reply_ = context->MakeReplyMessageContext();
+ initiating_close_ = true;
+ WebString web_reason = WebString::fromUTF8(reason);
+ websocket_->close(code, web_reason);
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PepperWebSocketHost::OnHostMsgSendText(
+ ppapi::host::HostMessageContext* context,
+ const std::string& message) {
+ if (websocket_.get()) {
+ WebString web_message = WebString::fromUTF8(message);
+ websocket_->sendText(web_message);
+ }
+ return PP_OK;
+}
+
+int32_t PepperWebSocketHost::OnHostMsgSendBinary(
+ ppapi::host::HostMessageContext* context,
+ const std::vector<uint8_t>& message) {
+ if (websocket_.get()) {
+ WebArrayBuffer web_message = WebArrayBuffer::create(message.size(), 1);
+ memcpy(web_message.data(), &message.front(), message.size());
+ websocket_->sendArrayBuffer(web_message);
+ }
+ return PP_OK;
+}
+
+int32_t PepperWebSocketHost::OnHostMsgFail(
+ ppapi::host::HostMessageContext* context,
+ const std::string& message) {
+ if (websocket_.get())
+ websocket_->fail(WebString::fromUTF8(message));
+ return PP_OK;
+}
+
+} // namespace content
diff --git a/content/renderer/pepper/pepper_websocket_host.h b/content/renderer/pepper/pepper_websocket_host.h
new file mode 100644
index 0000000..8c6c8c9
--- /dev/null
+++ b/content/renderer/pepper/pepper_websocket_host.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_PEPPER_PEPPER_WEBSOCKET_HOST_H_
+#define CONTENT_RENDERER_PEPPER_PEPPER_WEBSOCKET_HOST_H_
+
+#include <queue>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "ppapi/host/host_message_context.h"
+#include "ppapi/host/resource_host.h"
+#include "ppapi/proxy/resource_message_params.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebSocket.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebSocketClient.h"
+
+namespace ppapi {
+class StringVar;
+class Var;
+} // namespace ppapi
+
+namespace content {
+
+class RendererPpapiHost;
+
+class CONTENT_EXPORT PepperWebSocketHost
+ : public ppapi::host::ResourceHost,
+ public NON_EXPORTED_BASE(::WebKit::WebSocketClient) {
+ public:
+ explicit PepperWebSocketHost(RendererPpapiHost* host,
+ PP_Instance instance,
+ PP_Resource resource);
+ virtual ~PepperWebSocketHost();
+
+ virtual int32_t OnResourceMessageReceived(
+ const IPC::Message& msg,
+ ppapi::host::HostMessageContext* context) OVERRIDE;
+
+ // WebSocketClient implementation.
+ virtual void didConnect();
+ virtual void didReceiveMessage(const WebKit::WebString& message);
+ virtual void didReceiveArrayBuffer(const WebKit::WebArrayBuffer& binaryData);
+ virtual void didReceiveMessageError();
+ virtual void didUpdateBufferedAmount(unsigned long buffered_amount);
+ virtual void didStartClosingHandshake();
+ virtual void didClose(unsigned long unhandled_buffered_amount,
+ ClosingHandshakeCompletionStatus status,
+ unsigned short code,
+ const WebKit::WebString& reason);
+ private:
+ // IPC message handlers.
+ int32_t OnHostMsgConnect(ppapi::host::HostMessageContext* context,
+ const std::string& url,
+ const std::vector<std::string>& protocols);
+ int32_t OnHostMsgClose(ppapi::host::HostMessageContext* context,
+ int32_t code,
+ const std::string& reason);
+ int32_t OnHostMsgSendText(ppapi::host::HostMessageContext* context,
+ const std::string& message);
+ int32_t OnHostMsgSendBinary(ppapi::host::HostMessageContext* context,
+ const std::vector<uint8_t>& message);
+ int32_t OnHostMsgFail(ppapi::host::HostMessageContext* context,
+ const std::string& message);
+
+ // Non-owning pointer.
+ RendererPpapiHost* renderer_ppapi_host_;
+
+ // IPC reply parameters.
+ ppapi::host::ReplyMessageContext connect_reply_;
+ ppapi::host::ReplyMessageContext close_reply_;
+
+ // The server URL to which this instance connects.
+ std::string url_;
+
+ // A flag to indicate if opening handshake is going on.
+ bool connecting_;
+
+ // A flag to indicate if client initiated closing handshake is performed.
+ bool initiating_close_;
+
+ // A flag to indicate if server initiated closing handshake is performed.
+ bool accepting_close_;
+
+ // Becomes true if any error is detected. Incoming data will be disposed
+ // if this variable is true.
+ bool error_was_received_;
+
+ // Keeps the WebKit side WebSocket object. This is used for calling WebKit
+ // side functions via WebKit API.
+ scoped_ptr<WebKit::WebSocket> websocket_;
+
+ DISALLOW_COPY_AND_ASSIGN(PepperWebSocketHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_PEPPER_PEPPER_WEBSOCKET_HOST_H_
diff --git a/content/renderer/pepper/renderer_ppapi_host_impl.cc b/content/renderer/pepper/renderer_ppapi_host_impl.cc
index 0dde8e2..f3bbb9b 100644
--- a/content/renderer/pepper/renderer_ppapi_host_impl.cc
+++ b/content/renderer/pepper/renderer_ppapi_host_impl.cc
@@ -120,6 +120,14 @@ bool RendererPpapiHostImpl::IsValidInstance(
return !!GetAndValidateInstance(instance);
}
+WebKit::WebPluginContainer* RendererPpapiHostImpl::GetContainerForInstance(
+ PP_Instance instance) const {
+ PluginInstance* instance_object = GetAndValidateInstance(instance);
+ if (!instance_object)
+ return NULL;
+ return instance_object->container();
+}
+
bool RendererPpapiHostImpl::HasUserGesture(PP_Instance instance) const {
PluginInstance* instance_object = GetAndValidateInstance(instance);
if (!instance_object)
diff --git a/content/renderer/pepper/renderer_ppapi_host_impl.h b/content/renderer/pepper/renderer_ppapi_host_impl.h
index ff0341d..3625de2 100644
--- a/content/renderer/pepper/renderer_ppapi_host_impl.h
+++ b/content/renderer/pepper/renderer_ppapi_host_impl.h
@@ -86,6 +86,8 @@ class RendererPpapiHostImpl
virtual bool IsValidInstance(PP_Instance instance) const OVERRIDE;
virtual RenderView* GetRenderViewForInstance(
PP_Instance instance) const OVERRIDE;
+ virtual WebKit::WebPluginContainer* GetContainerForInstance(
+ PP_Instance instance) const OVERRIDE;
virtual bool HasUserGesture(PP_Instance instance) const OVERRIDE;
private:
diff --git a/ppapi/host/ppapi_host.cc b/ppapi/host/ppapi_host.cc
index f13cea0..1361da2 100644
--- a/ppapi/host/ppapi_host.cc
+++ b/ppapi/host/ppapi_host.cc
@@ -79,6 +79,12 @@ void PpapiHost::SendReply(const ReplyMessageContext& context,
}
}
+void PpapiHost::SendUnsolicitedReply(PP_Resource resource,
+ const IPC::Message& msg) {
+ proxy::ResourceMessageReplyParams params(resource, 0);
+ Send(new PpapiPluginMsg_ResourceReply(params, msg));
+}
+
void PpapiHost::AddHostFactoryFilter(scoped_ptr<HostFactory> filter) {
host_factory_filters_.push_back(filter.release());
}
diff --git a/ppapi/host/ppapi_host.h b/ppapi/host/ppapi_host.h
index 79731e6..3597093 100644
--- a/ppapi/host/ppapi_host.h
+++ b/ppapi/host/ppapi_host.h
@@ -58,6 +58,9 @@ class PPAPI_HOST_EXPORT PpapiHost : public IPC::Sender, public IPC::Listener {
void SendReply(const ReplyMessageContext& context,
const IPC::Message& msg);
+ // Sends the given unsolicited reply message to the plugin.
+ void SendUnsolicitedReply(PP_Resource resource, const IPC::Message& msg);
+
// Adds the given host factory filter to the host. The PpapiHost will take
// ownership of the pointer.
void AddHostFactoryFilter(scoped_ptr<HostFactory> filter);
diff --git a/ppapi/ppapi_proxy.gypi b/ppapi/ppapi_proxy.gypi
index 56dbb8c..a483945 100644
--- a/ppapi/ppapi_proxy.gypi
+++ b/ppapi/ppapi_proxy.gypi
@@ -156,6 +156,8 @@
'proxy/url_request_info_resource.cc',
'proxy/url_request_info_resource.h',
'proxy/var_serialization_rules.h',
+ 'proxy/websocket_resource.cc',
+ 'proxy/websocket_resource.h',
],
'defines': [
'PPAPI_PROXY_IMPLEMENTATION',
diff --git a/ppapi/ppapi_shared.gypi b/ppapi/ppapi_shared.gypi
index 7832527..3bcec1d 100644
--- a/ppapi/ppapi_shared.gypi
+++ b/ppapi/ppapi_shared.gypi
@@ -286,7 +286,6 @@
'thunk/ppb_url_util_thunk.cc',
'thunk/ppb_video_capture_thunk.cc',
'thunk/ppb_video_decoder_thunk.cc',
- 'thunk/ppb_websocket_thunk.cc',
],
}],
# We exclude a few more things for nacl_win64, to avoid pulling in
diff --git a/ppapi/ppapi_tests.gypi b/ppapi/ppapi_tests.gypi
index ea156dd..9edc419 100644
--- a/ppapi/ppapi_tests.gypi
+++ b/ppapi/ppapi_tests.gypi
@@ -153,6 +153,7 @@
'proxy/ppp_messaging_proxy_unittest.cc',
'proxy/printing_resource_unittest.cc',
'proxy/serialized_var_unittest.cc',
+ 'proxy/websocket_resource_unittest.cc',
'shared_impl/resource_tracker_unittest.cc',
'shared_impl/tracked_callback_unittest.cc',
'shared_impl/var_tracker_unittest.cc',
diff --git a/ppapi/proxy/plugin_dispatcher.cc b/ppapi/proxy/plugin_dispatcher.cc
index 51a8ff2..51272fd 100644
--- a/ppapi/proxy/plugin_dispatcher.cc
+++ b/ppapi/proxy/plugin_dispatcher.cc
@@ -272,7 +272,8 @@ void PluginDispatcher::DispatchResourceReply(
Resource* resource = PpapiGlobals::Get()->GetResourceTracker()->GetResource(
reply_params.pp_resource());
if (!resource) {
- NOTREACHED();
+ if (reply_params.sequence())
+ NOTREACHED();
return;
}
resource->OnReplyReceived(reply_params, nested_msg);
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h
index 8ac0886..3e9dca2 100644
--- a/ppapi/proxy/ppapi_messages.h
+++ b/ppapi/proxy/ppapi_messages.h
@@ -1582,3 +1582,83 @@ IPC_MESSAGE_CONTROL0(PpapiHostMsg_Printing_Create)
IPC_MESSAGE_CONTROL0(PpapiHostMsg_Printing_GetDefaultPrintSettings)
IPC_MESSAGE_CONTROL1(PpapiPluginMsg_Printing_GetDefaultPrintSettingsReply,
PP_PrintSettings_Dev /* print_settings */)
+
+// WebSocket ------------------------------------------------------------------
+
+IPC_MESSAGE_CONTROL0(PpapiHostMsg_WebSocket_Create)
+
+// Establishes the connection to a server. This message requires
+// WebSocket_ConnectReply as a reply message.
+IPC_MESSAGE_CONTROL2(PpapiHostMsg_WebSocket_Connect,
+ std::string /* url */,
+ std::vector<std::string> /* protocols */)
+
+// Closes established connection with graceful closing handshake. This message
+// requires WebSocket_CloseReply as a reply message.
+IPC_MESSAGE_CONTROL2(PpapiHostMsg_WebSocket_Close,
+ int32_t /* code */,
+ std::string /* reason */)
+
+// Sends a text frame to the server. No reply is defined.
+IPC_MESSAGE_CONTROL1(PpapiHostMsg_WebSocket_SendText,
+ std::string /* message */)
+
+// Sends a binary frame to the server. No reply is defined.
+IPC_MESSAGE_CONTROL1(PpapiHostMsg_WebSocket_SendBinary,
+ std::vector<uint8_t> /* message */)
+
+// Fails the connection. This message invokes RFC6455 defined
+// _Fail the WebSocket Connection_ operation. No reply is defined.
+IPC_MESSAGE_CONTROL1(PpapiHostMsg_WebSocket_Fail,
+ std::string /* message */)
+
+// This message is a reply to WebSocket_Connect. If the |url| and |protocols|
+// are invalid, WebSocket_ConnectReply is issued immediately and it contains
+// proper error code in its result. Otherwise, WebSocket_ConnectReply is sent
+// with valid |url|, |protocol|, and result PP_OK. |protocol| is not a passed
+// |protocols|, but a result of opening handshake negotiation. If the
+// connection can not be established successfully, WebSocket_ConnectReply is
+// not issued, but WebSocket_ClosedReply is sent instead.
+IPC_MESSAGE_CONTROL2(PpapiPluginMsg_WebSocket_ConnectReply,
+ std::string /* url */,
+ std::string /* protocol */)
+
+// This message is a reply to WebSocket_Close. If the operation fails,
+// WebSocket_CloseReply is issued immediately and it contains PP_ERROR_FAILED.
+// Otherwise, CloseReply will be issued after the closing handshake is
+// finished. All arguments will be valid iff the result is PP_OK and it means
+// that the client initiated closing handshake is finished gracefully.
+IPC_MESSAGE_CONTROL4(PpapiPluginMsg_WebSocket_CloseReply,
+ unsigned long /* buffered_amount */,
+ bool /* was_clean */,
+ unsigned short /* code */,
+ std::string /* reason */)
+
+// Unsolicited reply message to transmit a receiving text frame.
+IPC_MESSAGE_CONTROL1(PpapiPluginMsg_WebSocket_ReceiveTextReply,
+ std::string /* message */)
+
+// Unsolicited reply message to transmit a receiving binary frame.
+IPC_MESSAGE_CONTROL1(PpapiPluginMsg_WebSocket_ReceiveBinaryReply,
+ std::vector<uint8_t> /* message */)
+
+// Unsolicited reply message to notify a error on underlying network connetion.
+IPC_MESSAGE_CONTROL0(PpapiPluginMsg_WebSocket_ErrorReply)
+
+// Unsolicited reply message to update the buffered amount value.
+IPC_MESSAGE_CONTROL1(PpapiPluginMsg_WebSocket_BufferedAmountReply,
+ unsigned long /* buffered_amount */)
+
+// Unsolicited reply message to update |state| because of incoming external
+// events, e.g., protocol error, or unexpected network closure.
+IPC_MESSAGE_CONTROL1(PpapiPluginMsg_WebSocket_StateReply,
+ int32_t /* state */)
+
+// Unsolicited reply message to notify that the connection is closed without
+// any WebSocket_Close request. Server initiated closing handshake or
+// unexpected network errors will invoke this message.
+IPC_MESSAGE_CONTROL4(PpapiPluginMsg_WebSocket_ClosedReply,
+ unsigned long /* buffered_amount */,
+ bool /* was_clean */,
+ unsigned short /* code */,
+ std::string /* reason */)
diff --git a/ppapi/proxy/resource_creation_proxy.cc b/ppapi/proxy/resource_creation_proxy.cc
index 373b9d7..78123a6 100644
--- a/ppapi/proxy/resource_creation_proxy.cc
+++ b/ppapi/proxy/resource_creation_proxy.cc
@@ -39,6 +39,7 @@
#include "ppapi/proxy/ppb_x509_certificate_private_proxy.h"
#include "ppapi/proxy/printing_resource.h"
#include "ppapi/proxy/url_request_info_resource.h"
+#include "ppapi/proxy/websocket_resource.h"
#include "ppapi/shared_impl/api_id.h"
#include "ppapi/shared_impl/host_resource.h"
#include "ppapi/shared_impl/ppb_audio_config_shared.h"
@@ -256,6 +257,10 @@ PP_Resource ResourceCreationProxy::CreateUDPSocketPrivate(
return PPB_UDPSocket_Private_Proxy::CreateProxyResource(instance);
}
+PP_Resource ResourceCreationProxy::CreateWebSocket(PP_Instance instance) {
+ return (new WebSocketResource(GetConnection(), instance))->GetReference();
+}
+
PP_Resource ResourceCreationProxy::CreateX509CertificatePrivate(
PP_Instance instance) {
return PPB_X509Certificate_Private_Proxy::CreateProxyResource(instance);
@@ -351,11 +356,6 @@ PP_Resource ResourceCreationProxy::CreateVideoDecoder(
instance, context3d_id, profile);
}
-PP_Resource ResourceCreationProxy::CreateWebSocket(PP_Instance instance) {
- NOTIMPLEMENTED();
- return 0;
-}
-
#endif // !defined(OS_NACL)
bool ResourceCreationProxy::Send(IPC::Message* msg) {
diff --git a/ppapi/proxy/resource_creation_proxy.h b/ppapi/proxy/resource_creation_proxy.h
index 7ab07e0..4860cbf 100644
--- a/ppapi/proxy/resource_creation_proxy.h
+++ b/ppapi/proxy/resource_creation_proxy.h
@@ -122,6 +122,7 @@ class ResourceCreationProxy : public InterfaceProxy,
PP_Instance instance) OVERRIDE;
virtual PP_Resource CreateTCPSocketPrivate(PP_Instance instance) OVERRIDE;
virtual PP_Resource CreateUDPSocketPrivate(PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateWebSocket(PP_Instance instance) OVERRIDE;
virtual PP_Resource CreateX509CertificatePrivate(
PP_Instance instance) OVERRIDE;
#if !defined(OS_NACL)
@@ -155,7 +156,6 @@ class ResourceCreationProxy : public InterfaceProxy,
PP_Instance instance,
PP_Resource context3d_id,
PP_VideoDecoder_Profile profile) OVERRIDE;
- virtual PP_Resource CreateWebSocket(PP_Instance instance) OVERRIDE;
#endif // !defined(OS_NACL)
virtual bool Send(IPC::Message* msg) OVERRIDE;
diff --git a/ppapi/proxy/websocket_resource.cc b/ppapi/proxy/websocket_resource.cc
new file mode 100644
index 0000000..de9ee2b
--- /dev/null
+++ b/ppapi/proxy/websocket_resource.cc
@@ -0,0 +1,509 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ppapi/proxy/websocket_resource.h"
+
+#include <set>
+#include <vector>
+
+#include "base/bind.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/shared_impl/ppapi_globals.h"
+#include "ppapi/shared_impl/var.h"
+#include "ppapi/shared_impl/var_tracker.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebSocket.h"
+
+namespace {
+
+const uint32_t kMaxReasonSizeInBytes = 123;
+const size_t kBaseFramingOverhead = 2;
+const size_t kMaskingKeyLength = 4;
+const size_t kMinimumPayloadSizeWithTwoByteExtendedPayloadLength = 126;
+const size_t kMinimumPayloadSizeWithEightByteExtendedPayloadLength = 0x10000;
+
+uint64_t SaturateAdd(uint64_t a, uint64_t b) {
+ if (kuint64max - a < b)
+ return kuint64max;
+ return a + b;
+}
+
+uint64_t GetFrameSize(uint64_t payload_size) {
+ uint64_t overhead = kBaseFramingOverhead + kMaskingKeyLength;
+ if (payload_size > kMinimumPayloadSizeWithEightByteExtendedPayloadLength)
+ overhead += 8;
+ else if (payload_size > kMinimumPayloadSizeWithTwoByteExtendedPayloadLength)
+ overhead += 2;
+ return SaturateAdd(payload_size, overhead);
+}
+
+bool InValidStateToReceive(PP_WebSocketReadyState state) {
+ return state == PP_WEBSOCKETREADYSTATE_OPEN ||
+ state == PP_WEBSOCKETREADYSTATE_CLOSING;
+}
+
+} // namespace
+
+
+namespace ppapi {
+namespace proxy {
+
+WebSocketResource::WebSocketResource(Connection connection,
+ PP_Instance instance)
+ : PluginResource(connection, instance),
+ state_(PP_WEBSOCKETREADYSTATE_INVALID),
+ error_was_received_(false),
+ receive_callback_var_(NULL),
+ empty_string_(new StringVar(std::string())),
+ close_code_(0),
+ close_reason_(NULL),
+ close_was_clean_(PP_FALSE),
+ extensions_(NULL),
+ protocol_(NULL),
+ url_(NULL),
+ buffered_amount_(0),
+ buffered_amount_after_close_(0) {
+}
+
+WebSocketResource::~WebSocketResource() {
+}
+
+thunk::PPB_WebSocket_API* WebSocketResource::AsPPB_WebSocket_API() {
+ return this;
+}
+
+int32_t WebSocketResource::Connect(
+ const PP_Var& url,
+ const PP_Var protocols[],
+ uint32_t protocol_count,
+ scoped_refptr<TrackedCallback> callback) {
+ if (TrackedCallback::IsPending(connect_callback_))
+ return PP_ERROR_INPROGRESS;
+
+ // Connect() can be called at most once.
+ if (state_ != PP_WEBSOCKETREADYSTATE_INVALID)
+ return PP_ERROR_INPROGRESS;
+ state_ = PP_WEBSOCKETREADYSTATE_CLOSED;
+
+ // Get the URL.
+ url_ = StringVar::FromPPVar(url);
+ if (!url_)
+ return PP_ERROR_BADARGUMENT;
+
+ // Get the protocols.
+ std::set<std::string> protocol_set;
+ std::vector<std::string> protocol_strings;
+ protocol_strings.reserve(protocol_count);
+ for (uint32_t i = 0; i < protocol_count; ++i) {
+ scoped_refptr<StringVar> protocol(StringVar::FromPPVar(protocols[i]));
+
+ // Check invalid and empty entries.
+ if (!protocol || !protocol->value().length())
+ return PP_ERROR_BADARGUMENT;
+
+ // Check duplicated protocol entries.
+ if (protocol_set.find(protocol->value()) != protocol_set.end())
+ return PP_ERROR_BADARGUMENT;
+ protocol_set.insert(protocol->value());
+
+ protocol_strings.push_back(protocol->value());
+ }
+
+ // Install callback.
+ connect_callback_ = callback;
+
+ // Create remote host in the renderer, then request to check the URL and
+ // establish the connection.
+ state_ = PP_WEBSOCKETREADYSTATE_CONNECTING;
+ SendCreateToRenderer(PpapiHostMsg_WebSocket_Create());
+ PpapiHostMsg_WebSocket_Connect msg(url_->value(), protocol_strings);
+ CallRenderer<PpapiPluginMsg_WebSocket_ConnectReply>(msg,
+ base::Bind(&WebSocketResource::OnPluginMsgConnectReply, this));
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t WebSocketResource::Close(uint16_t code,
+ const PP_Var& reason,
+ scoped_refptr<TrackedCallback> callback) {
+ if (TrackedCallback::IsPending(close_callback_))
+ return PP_ERROR_INPROGRESS;
+ if (state_ == PP_WEBSOCKETREADYSTATE_INVALID)
+ return PP_ERROR_FAILED;
+
+ // Validate |code| and |reason|.
+ scoped_refptr<StringVar> reason_string_var;
+ std::string reason_string;
+ WebKit::WebSocket::CloseEventCode event_code =
+ static_cast<WebKit::WebSocket::CloseEventCode>(code);
+ if (code == PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED) {
+ // PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED and CloseEventCodeNotSpecified are
+ // assigned to different values. A conversion is needed if
+ // PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED is specified.
+ event_code = WebKit::WebSocket::CloseEventCodeNotSpecified;
+ } else {
+ if (!(code == PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE ||
+ (PP_WEBSOCKETSTATUSCODE_USER_REGISTERED_MIN <= code &&
+ code <= PP_WEBSOCKETSTATUSCODE_USER_PRIVATE_MAX)))
+ // RFC 6455 limits applications to use reserved connection close code in
+ // section 7.4.2.. The WebSocket API (http://www.w3.org/TR/websockets/)
+ // defines this out of range error as InvalidAccessError in JavaScript.
+ return PP_ERROR_NOACCESS;
+
+ // |reason| must be ignored if it is PP_VARTYPE_UNDEFINED or |code| is
+ // PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED.
+ if (reason.type != PP_VARTYPE_UNDEFINED) {
+ // Validate |reason|.
+ reason_string_var = StringVar::FromPPVar(reason);
+ if (!reason_string_var ||
+ reason_string_var->value().size() > kMaxReasonSizeInBytes)
+ return PP_ERROR_BADARGUMENT;
+ reason_string = reason_string_var->value();
+ }
+ }
+
+ // Check state.
+ if (state_ == PP_WEBSOCKETREADYSTATE_CLOSING)
+ return PP_ERROR_INPROGRESS;
+ if (state_ == PP_WEBSOCKETREADYSTATE_CLOSED)
+ return PP_OK;
+
+ // Install |callback|.
+ close_callback_ = callback;
+
+ // Abort ongoing connect.
+ if (TrackedCallback::IsPending(connect_callback_)) {
+ state_ = PP_WEBSOCKETREADYSTATE_CLOSING;
+ // Need to do a "Post" to avoid reentering the plugin.
+ connect_callback_->PostAbort();
+ connect_callback_ = NULL;
+ PostToRenderer(PpapiHostMsg_WebSocket_Fail(
+ "WebSocket was closed before the connection was established."));
+ return PP_OK_COMPLETIONPENDING;
+ }
+
+ // Abort ongoing receive.
+ if (TrackedCallback::IsPending(receive_callback_)) {
+ receive_callback_var_ = NULL;
+ // Need to do a "Post" to avoid reentering the plugin.
+ receive_callback_->PostAbort();
+ receive_callback_ = NULL;
+ }
+
+ // Close connection.
+ state_ = PP_WEBSOCKETREADYSTATE_CLOSING;
+ PpapiHostMsg_WebSocket_Close msg(static_cast<int32_t>(event_code),
+ reason_string);
+ CallRenderer<PpapiPluginMsg_WebSocket_CloseReply>(msg,
+ base::Bind(&WebSocketResource::OnPluginMsgCloseReply, this));
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t WebSocketResource::ReceiveMessage(
+ PP_Var* message,
+ scoped_refptr<TrackedCallback> callback) {
+ if (TrackedCallback::IsPending(receive_callback_))
+ return PP_ERROR_INPROGRESS;
+
+ // Check state.
+ if (state_ == PP_WEBSOCKETREADYSTATE_INVALID ||
+ state_ == PP_WEBSOCKETREADYSTATE_CONNECTING)
+ return PP_ERROR_BADARGUMENT;
+
+ // Just return received message if any received message is queued.
+ if (!received_messages_.empty()) {
+ receive_callback_var_ = message;
+ return DoReceive();
+ }
+
+ // Check state again. In CLOSED state, no more messages will be received.
+ if (state_ == PP_WEBSOCKETREADYSTATE_CLOSED)
+ return PP_ERROR_BADARGUMENT;
+
+ // Returns PP_ERROR_FAILED after an error is received and received messages
+ // is exhausted.
+ if (error_was_received_)
+ return PP_ERROR_FAILED;
+
+ // Or retain |message| as buffer to store and install |callback|.
+ receive_callback_var_ = message;
+ receive_callback_ = callback;
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t WebSocketResource::SendMessage(const PP_Var& message) {
+ // Check state.
+ if (state_ == PP_WEBSOCKETREADYSTATE_INVALID ||
+ state_ == PP_WEBSOCKETREADYSTATE_CONNECTING)
+ return PP_ERROR_BADARGUMENT;
+
+ if (state_ == PP_WEBSOCKETREADYSTATE_CLOSING ||
+ state_ == PP_WEBSOCKETREADYSTATE_CLOSED) {
+ // Handle buffered_amount_after_close_.
+ uint64_t payload_size = 0;
+ if (message.type == PP_VARTYPE_STRING) {
+ scoped_refptr<StringVar> message_string = StringVar::FromPPVar(message);
+ if (message_string)
+ payload_size += message_string->value().length();
+ } else if (message.type == PP_VARTYPE_ARRAY_BUFFER) {
+ scoped_refptr<ArrayBufferVar> message_array_buffer =
+ ArrayBufferVar::FromPPVar(message);
+ if (message_array_buffer)
+ payload_size += message_array_buffer->ByteLength();
+ } else {
+ // TODO(toyoshim): Support Blob.
+ return PP_ERROR_NOTSUPPORTED;
+ }
+
+ buffered_amount_after_close_ =
+ SaturateAdd(buffered_amount_after_close_, GetFrameSize(payload_size));
+
+ return PP_ERROR_FAILED;
+ }
+
+ // Send the message.
+ if (message.type == PP_VARTYPE_STRING) {
+ // Convert message to std::string, then send it.
+ scoped_refptr<StringVar> message_string = StringVar::FromPPVar(message);
+ if (!message_string)
+ return PP_ERROR_BADARGUMENT;
+ PostToRenderer(PpapiHostMsg_WebSocket_SendText(message_string->value()));
+ } else if (message.type == PP_VARTYPE_ARRAY_BUFFER) {
+ // Convert message to std::vector<uint8_t>, then send it.
+ scoped_refptr<ArrayBufferVar> message_arraybuffer =
+ ArrayBufferVar::FromPPVar(message);
+ if (!message_arraybuffer)
+ return PP_ERROR_BADARGUMENT;
+ uint8_t* message_data = static_cast<uint8_t*>(message_arraybuffer->Map());
+ uint32 message_length = message_arraybuffer->ByteLength();
+ std::vector<uint8_t> message_vector(message_data,
+ message_data + message_length);
+ PostToRenderer(PpapiHostMsg_WebSocket_SendBinary(message_vector));
+ } else {
+ // TODO(toyoshim): Support Blob.
+ return PP_ERROR_NOTSUPPORTED;
+ }
+ return PP_OK;
+}
+
+uint64_t WebSocketResource::GetBufferedAmount() {
+ return SaturateAdd(buffered_amount_, buffered_amount_after_close_);
+}
+
+uint16_t WebSocketResource::GetCloseCode() {
+ return close_code_;
+}
+
+PP_Var WebSocketResource::GetCloseReason() {
+ if (!close_reason_)
+ return empty_string_->GetPPVar();
+ return close_reason_->GetPPVar();
+}
+
+PP_Bool WebSocketResource::GetCloseWasClean() {
+ return close_was_clean_;
+}
+
+PP_Var WebSocketResource::GetExtensions() {
+ return StringVar::StringToPPVar(std::string());
+}
+
+PP_Var WebSocketResource::GetProtocol() {
+ if (!protocol_)
+ return empty_string_->GetPPVar();
+ return protocol_->GetPPVar();
+}
+
+PP_WebSocketReadyState WebSocketResource::GetReadyState() {
+ return state_;
+}
+
+PP_Var WebSocketResource::GetURL() {
+ if (!url_)
+ return empty_string_->GetPPVar();
+ return url_->GetPPVar();
+}
+
+void WebSocketResource::OnReplyReceived(
+ const ResourceMessageReplyParams& params,
+ const IPC::Message& msg) {
+ if (params.sequence())
+ return PluginResource::OnReplyReceived(params, msg);
+
+ // TODO(toyoshim): Currently, following unsolicited reply IPCs are handled
+ // manually. We should introduce more useful mechanism for that.
+ switch (msg.type()) {
+ case PpapiPluginMsg_WebSocket_ReceiveTextReply::ID: {
+ PpapiPluginMsg_WebSocket_ReceiveTextReply::Schema::Param p;
+ if (PpapiPluginMsg_WebSocket_ReceiveTextReply::Read(&msg, &p))
+ OnPluginMsgReceiveTextReply(params, p.a);
+ else
+ NOTREACHED();
+ break;
+ }
+ case PpapiPluginMsg_WebSocket_ReceiveBinaryReply::ID: {
+ PpapiPluginMsg_WebSocket_ReceiveBinaryReply::Schema::Param p;
+ if (PpapiPluginMsg_WebSocket_ReceiveBinaryReply::Read(&msg, &p))
+ OnPluginMsgReceiveBinaryReply(params, p.a);
+ else
+ NOTREACHED();
+ break;
+ }
+ case PpapiPluginMsg_WebSocket_ErrorReply::ID: {
+ OnPluginMsgErrorReply(params);
+ break;
+ }
+ case PpapiPluginMsg_WebSocket_BufferedAmountReply::ID: {
+ PpapiPluginMsg_WebSocket_BufferedAmountReply::Schema::Param p;
+ if (PpapiPluginMsg_WebSocket_BufferedAmountReply::Read(&msg, &p))
+ OnPluginMsgBufferedAmountReply(params, p.a);
+ else
+ NOTREACHED();
+ break;
+ }
+ case PpapiPluginMsg_WebSocket_StateReply::ID: {
+ PpapiPluginMsg_WebSocket_StateReply::Schema::Param p;
+ if (PpapiPluginMsg_WebSocket_StateReply::Read(&msg, &p))
+ OnPluginMsgStateReply(params, p.a);
+ else
+ NOTREACHED();
+ break;
+ }
+ case PpapiPluginMsg_WebSocket_ClosedReply::ID: {
+ PpapiPluginMsg_WebSocket_ClosedReply::Schema::Param p;
+ if (PpapiPluginMsg_WebSocket_ClosedReply::Read(&msg, &p))
+ OnPluginMsgClosedReply(params, p.a, p.b, p.c, p.d);
+ else
+ NOTREACHED();
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+}
+
+void WebSocketResource::OnPluginMsgConnectReply(
+ const ResourceMessageReplyParams& params,
+ const std::string& url,
+ const std::string& protocol) {
+ if (!TrackedCallback::IsPending(connect_callback_))
+ return;
+
+ int32_t result = params.result();
+ if (result == PP_OK) {
+ state_ = PP_WEBSOCKETREADYSTATE_OPEN;
+ protocol_ = new StringVar(protocol);
+ url_ = new StringVar(url);
+ }
+ TrackedCallback::ClearAndRun(&connect_callback_, params.result());
+}
+
+void WebSocketResource::OnPluginMsgCloseReply(
+ const ResourceMessageReplyParams& params,
+ unsigned long buffered_amount,
+ bool was_clean,
+ unsigned short code,
+ const std::string& reason) {
+ // Set close related properties.
+ state_ = PP_WEBSOCKETREADYSTATE_CLOSED;
+ buffered_amount_ = buffered_amount;
+ close_was_clean_ = PP_FromBool(was_clean);
+ close_code_ = code;
+ close_reason_ = new StringVar(reason);
+
+ if (TrackedCallback::IsPending(receive_callback_)) {
+ receive_callback_var_ = NULL;
+ receive_callback_->PostRun(PP_ERROR_FAILED);
+ receive_callback_ = NULL;
+ }
+
+ if (TrackedCallback::IsPending(close_callback_)) {
+ close_callback_->PostRun(params.result());
+ close_callback_ = NULL;
+ }
+}
+
+void WebSocketResource::OnPluginMsgReceiveTextReply(
+ const ResourceMessageReplyParams& params,
+ const std::string& message) {
+ // Dispose packets after receiving an error or in invalid state.
+ if (error_was_received_ || !InValidStateToReceive(state_))
+ return;
+
+ // Append received data to queue.
+ received_messages_.push(scoped_refptr<Var>(new StringVar(message)));
+
+ if (!TrackedCallback::IsPending(receive_callback_))
+ return;
+
+ TrackedCallback::ClearAndRun(&receive_callback_, DoReceive());
+}
+
+void WebSocketResource::OnPluginMsgReceiveBinaryReply(
+ const ResourceMessageReplyParams& params,
+ const std::vector<uint8_t>& message) {
+ // Dispose packets after receiving an error or in invalid state.
+ if (error_was_received_ || !InValidStateToReceive(state_))
+ return;
+
+ // Append received data to queue.
+ scoped_refptr<Var> message_var(ArrayBufferVar::FromPPVar(
+ PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
+ message.size(),
+ &message.front())));
+ received_messages_.push(message_var);
+
+ if (!TrackedCallback::IsPending(receive_callback_))
+ return;
+
+ TrackedCallback::ClearAndRun(&receive_callback_, DoReceive());
+}
+
+void WebSocketResource::OnPluginMsgErrorReply(
+ const ResourceMessageReplyParams& params) {
+ error_was_received_ = true;
+
+ if (!TrackedCallback::IsPending(receive_callback_))
+ return;
+
+ // No more text or binary messages will be received. If there is ongoing
+ // ReceiveMessage(), we must invoke the callback with error code here.
+ receive_callback_var_ = NULL;
+ TrackedCallback::ClearAndRun(&receive_callback_, PP_ERROR_FAILED);
+}
+
+void WebSocketResource::OnPluginMsgBufferedAmountReply(
+ const ResourceMessageReplyParams& params,
+ unsigned long buffered_amount) {
+ buffered_amount_ = buffered_amount;
+}
+
+void WebSocketResource::OnPluginMsgStateReply(
+ const ResourceMessageReplyParams& params,
+ int32_t state) {
+ state_ = static_cast<PP_WebSocketReadyState>(state);
+}
+
+void WebSocketResource::OnPluginMsgClosedReply(
+ const ResourceMessageReplyParams& params,
+ unsigned long buffered_amount,
+ bool was_clean,
+ unsigned short code,
+ const std::string& reason) {
+ OnPluginMsgCloseReply(params, buffered_amount, was_clean, code, reason);
+}
+
+int32_t WebSocketResource::DoReceive() {
+ if (!receive_callback_var_)
+ return PP_OK;
+
+ *receive_callback_var_ = received_messages_.front()->GetPPVar();
+ received_messages_.pop();
+ receive_callback_var_ = NULL;
+ return PP_OK;
+}
+
+} // namespace proxy
+} // namespace ppapi
diff --git a/ppapi/proxy/websocket_resource.h b/ppapi/proxy/websocket_resource.h
new file mode 100644
index 0000000..49353e4
--- /dev/null
+++ b/ppapi/proxy/websocket_resource.h
@@ -0,0 +1,157 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PPAPI_PROXY_WEBSOCKET_RESOURCE_H_
+#define PPAPI_PROXY_WEBSOCKET_RESOURCE_H_
+
+#include <queue>
+
+#include "ppapi/c/ppb_websocket.h"
+#include "ppapi/proxy/plugin_resource.h"
+#include "ppapi/shared_impl/tracked_callback.h"
+#include "ppapi/thunk/ppb_websocket_api.h"
+
+namespace ppapi {
+
+class StringVar;
+class Var;
+
+namespace proxy {
+
+// This class contains protocol checks which doesn't affect security when it
+// run with untrusted code.
+class PPAPI_PROXY_EXPORT WebSocketResource
+ : public PluginResource,
+ public NON_EXPORTED_BASE(thunk::PPB_WebSocket_API) {
+ public:
+ WebSocketResource(Connection connection, PP_Instance instance);
+ virtual ~WebSocketResource();
+
+ // PluginResource implementation.
+ virtual thunk::PPB_WebSocket_API* AsPPB_WebSocket_API() OVERRIDE;
+
+ // PPB_WebSocket_API implementation.
+ virtual int32_t Connect(const PP_Var& url,
+ const PP_Var protocols[],
+ uint32_t protocol_count,
+ scoped_refptr<TrackedCallback> callback) OVERRIDE;
+ virtual int32_t Close(uint16_t code,
+ const PP_Var& reason,
+ scoped_refptr<TrackedCallback> callback) OVERRIDE;
+ virtual int32_t ReceiveMessage(
+ PP_Var* message,
+ scoped_refptr<TrackedCallback> callback) OVERRIDE;
+ virtual int32_t SendMessage(const PP_Var& message) OVERRIDE;
+ virtual uint64_t GetBufferedAmount() OVERRIDE;
+ virtual uint16_t GetCloseCode() OVERRIDE;
+ virtual PP_Var GetCloseReason() OVERRIDE;
+ virtual PP_Bool GetCloseWasClean() OVERRIDE;
+ virtual PP_Var GetExtensions() OVERRIDE;
+ virtual PP_Var GetProtocol() OVERRIDE;
+ virtual PP_WebSocketReadyState GetReadyState() OVERRIDE;
+ virtual PP_Var GetURL() OVERRIDE;
+
+ private:
+ // PluginResource override.
+ virtual void OnReplyReceived(const ResourceMessageReplyParams& params,
+ const IPC::Message& msg) OVERRIDE;
+
+ // IPC message handlers.
+ void OnPluginMsgConnectReply(const ResourceMessageReplyParams& params,
+ const std::string& url,
+ const std::string& protocol);
+ void OnPluginMsgCloseReply(const ResourceMessageReplyParams& params,
+ unsigned long buffered_amount,
+ bool was_clean,
+ unsigned short code,
+ const std::string& reason);
+ void OnPluginMsgReceiveTextReply(const ResourceMessageReplyParams& params,
+ const std::string& message);
+ void OnPluginMsgReceiveBinaryReply(const ResourceMessageReplyParams& params,
+ const std::vector<uint8_t>& message);
+ void OnPluginMsgErrorReply(const ResourceMessageReplyParams& params);
+ void OnPluginMsgBufferedAmountReply(const ResourceMessageReplyParams& params,
+ unsigned long buffered_amount);
+ void OnPluginMsgStateReply(const ResourceMessageReplyParams& params,
+ int32_t state);
+ void OnPluginMsgClosedReply(const ResourceMessageReplyParams& params,
+ unsigned long buffered_amount,
+ bool was_clean,
+ unsigned short code,
+ const std::string& reason);
+
+ // Picks up a received message and moves it to user receiving buffer. This
+ // function is used in both ReceiveMessage for fast returning path, and
+ // OnPluginMsgReceiveTextReply and OnPluginMsgReceiveBinaryReply for delayed
+ // callback invocations.
+ int32_t DoReceive();
+
+ // Holds user callbacks to invoke later.
+ scoped_refptr<TrackedCallback> connect_callback_;
+ scoped_refptr<TrackedCallback> close_callback_;
+ scoped_refptr<TrackedCallback> receive_callback_;
+
+ // Represents readyState described in the WebSocket API specification. It can
+ // be read via GetReadyState().
+ PP_WebSocketReadyState state_;
+
+ // Becomes true if any error is detected. Incoming data will be disposed
+ // if this variable is true, then ReceiveMessage() returns PP_ERROR_FAILED
+ // after returning all received data.
+ bool error_was_received_;
+
+ // Keeps a pointer to PP_Var which is provided via ReceiveMessage().
+ // Received data will be copied to this PP_Var on ready.
+ PP_Var* receive_callback_var_;
+
+ // Keeps received data until ReceiveMessage() requests.
+ std::queue<scoped_refptr<Var> > received_messages_;
+
+ // Keeps empty string for functions to return empty string.
+ scoped_refptr<StringVar> empty_string_;
+
+ // Keeps the status code field of closing handshake. It can be read via
+ // GetCloseCode().
+ uint16_t close_code_;
+
+ // Keeps the reason field of closing handshake. It can be read via
+ // GetCloseReason().
+ scoped_refptr<StringVar> close_reason_;
+
+ // Becomes true when closing handshake is performed successfully. It can be
+ // read via GetCloseWasClean().
+ PP_Bool close_was_clean_;
+
+ // Represents extensions described in the WebSocket API specification. It can
+ // be read via GetExtensions().
+ scoped_refptr<StringVar> extensions_;
+
+ // Represents protocol described in the WebSocket API specification. It can be
+ // read via GetProtocol().
+ scoped_refptr<StringVar> protocol_;
+
+ // Represents url described in the WebSocket API specification. It can be
+ // read via GetURL().
+ scoped_refptr<StringVar> url_;
+
+ // Keeps the number of bytes of application data that have been queued using
+ // SendMessage(). WebKit side implementation calculates the actual amount.
+ // This is a cached value which is notified through a WebKit callback.
+ // This value is used to calculate bufferedAmount in the WebSocket API
+ // specification. The calculated value can be read via GetBufferedAmount().
+ uint64_t buffered_amount_;
+
+ // Keeps the number of bytes of application data that have been ignored
+ // because the connection was already closed.
+ // This value is used to calculate bufferedAmount in the WebSocket API
+ // specification. The calculated value can be read via GetBufferedAmount().
+ uint64_t buffered_amount_after_close_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebSocketResource);
+};
+
+} // namespace proxy
+} // namespace ppapi
+
+#endif // PPAPI_PROXY_WEBSOCKET_RESOURCE_H_
diff --git a/ppapi/proxy/websocket_resource_unittest.cc b/ppapi/proxy/websocket_resource_unittest.cc
new file mode 100644
index 0000000..61e8925
--- /dev/null
+++ b/ppapi/proxy/websocket_resource_unittest.cc
@@ -0,0 +1,168 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/ref_counted.h"
+#include "base/message_loop.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/ppb_websocket.h"
+#include "ppapi/c/ppb_var.h"
+#include "ppapi/proxy/websocket_resource.h"
+#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/proxy/ppapi_proxy_test.h"
+#include "ppapi/shared_impl/ppb_var_shared.h"
+#include "ppapi/shared_impl/scoped_pp_resource.h"
+#include "ppapi/shared_impl/scoped_pp_var.h"
+#include "ppapi/shared_impl/tracked_callback.h"
+#include "ppapi/shared_impl/var.h"
+#include "ppapi/thunk/thunk.h"
+
+namespace ppapi {
+namespace proxy {
+
+namespace {
+
+typedef PluginProxyTest WebSocketResourceTest;
+
+bool g_callback_called;
+int32_t g_callback_result;
+const PPB_Var* ppb_var_ = NULL;
+
+void Callback(void* user_data, int32_t result) {
+ g_callback_called = true;
+ g_callback_result = result;
+}
+
+PP_CompletionCallback MakeCallback() {
+ g_callback_called = false;
+ g_callback_result = PP_OK;
+ return PP_MakeCompletionCallback(Callback, NULL);
+}
+
+PP_Var MakeStringVar(const std::string& string) {
+ if (!ppb_var_)
+ ppb_var_ = ppapi::PPB_Var_Shared::GetVarInterface1_1();
+ return ppb_var_->VarFromUtf8(string.c_str(), string.length());
+}
+
+} // namespace
+
+
+// Does a test of Connect().
+TEST_F(WebSocketResourceTest, Connect) {
+ const PPB_WebSocket_1_0* websocket_iface =
+ thunk::GetPPB_WebSocket_1_0_Thunk();
+
+ std::string url("ws://ws.google.com");
+ std::string protocol0("x-foo");
+ std::string protocol1("x-bar");
+ PP_Var url_var = MakeStringVar(url);
+ PP_Var protocols[] = { MakeStringVar(protocol0), MakeStringVar(protocol1) };
+
+ ScopedPPResource res(ScopedPPResource::PassRef(),
+ websocket_iface->Create(pp_instance()));
+
+ int32_t result =
+ websocket_iface->Connect(res, url_var, protocols, 2, MakeCallback());
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
+
+ // Should be sent a "Connect" message.
+ ResourceMessageCallParams params;
+ IPC::Message msg;
+ ASSERT_TRUE(sink().GetFirstResourceCallMatching(
+ PpapiHostMsg_WebSocket_Connect::ID, &params, &msg));
+ PpapiHostMsg_WebSocket_Connect::Schema::Param p;
+ PpapiHostMsg_WebSocket_Connect::Read(&msg, &p);
+ EXPECT_EQ(url, p.a);
+ EXPECT_EQ(protocol0, p.b[0]);
+ EXPECT_EQ(protocol1, p.b[1]);
+
+ // Synthesize a response.
+ ResourceMessageReplyParams reply_params(params.pp_resource(),
+ params.sequence());
+ reply_params.set_result(PP_OK);
+ ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(
+ PpapiPluginMsg_ResourceReply(reply_params,
+ PpapiPluginMsg_WebSocket_ConnectReply(url, protocol1))));
+
+ EXPECT_EQ(PP_OK, g_callback_result);
+ EXPECT_EQ(true, g_callback_called);
+}
+
+// Does a test for unsolicited replies.
+TEST_F(WebSocketResourceTest, UnsolicitedReplies) {
+ const PPB_WebSocket_1_0* websocket_iface =
+ thunk::GetPPB_WebSocket_1_0_Thunk();
+
+ ScopedPPResource res(ScopedPPResource::PassRef(),
+ websocket_iface->Create(pp_instance()));
+
+ // Check if BufferedAmountReply is handled.
+ ResourceMessageReplyParams reply_params(res, 0);
+ reply_params.set_result(PP_OK);
+ ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(
+ PpapiPluginMsg_ResourceReply(
+ reply_params,
+ PpapiPluginMsg_WebSocket_BufferedAmountReply(19760227u))));
+
+ uint64_t amount = websocket_iface->GetBufferedAmount(res);
+ EXPECT_EQ(19760227u, amount);
+
+ // Check if StateReply is handled.
+ ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(
+ PpapiPluginMsg_ResourceReply(
+ reply_params,
+ PpapiPluginMsg_WebSocket_StateReply(
+ static_cast<int32_t>(PP_WEBSOCKETREADYSTATE_CLOSING)))));
+
+ PP_WebSocketReadyState state = websocket_iface->GetReadyState(res);
+ EXPECT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING, state);
+}
+
+TEST_F(WebSocketResourceTest, MessageError) {
+ const PPB_WebSocket_1_0* websocket_iface =
+ thunk::GetPPB_WebSocket_1_0_Thunk();
+
+ std::string url("ws://ws.google.com");
+ PP_Var url_var = MakeStringVar(url);
+
+ ScopedPPResource res(ScopedPPResource::PassRef(),
+ websocket_iface->Create(pp_instance()));
+
+ // Establish the connection virtually.
+ int32_t result =
+ websocket_iface->Connect(res, url_var, NULL, 0, MakeCallback());
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
+
+ ResourceMessageCallParams params;
+ IPC::Message msg;
+ ASSERT_TRUE(sink().GetFirstResourceCallMatching(
+ PpapiHostMsg_WebSocket_Connect::ID, &params, &msg));
+
+ ResourceMessageReplyParams connect_reply_params(params.pp_resource(),
+ params.sequence());
+ connect_reply_params.set_result(PP_OK);
+ ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(
+ PpapiPluginMsg_ResourceReply(connect_reply_params,
+ PpapiPluginMsg_WebSocket_ConnectReply(url, std::string()))));
+
+ EXPECT_EQ(PP_OK, g_callback_result);
+ EXPECT_EQ(true, g_callback_called);
+
+ PP_Var message;
+ result = websocket_iface->ReceiveMessage(res, &message, MakeCallback());
+ EXPECT_EQ(false, g_callback_called);
+
+ // Synthesize a WebSocket_ErrorReply message.
+ ResourceMessageReplyParams error_reply_params(res, 0);
+ error_reply_params.set_result(PP_OK);
+ ASSERT_TRUE(plugin_dispatcher()->OnMessageReceived(
+ PpapiPluginMsg_ResourceReply(error_reply_params,
+ PpapiPluginMsg_WebSocket_ErrorReply())));
+
+ EXPECT_EQ(PP_ERROR_FAILED, g_callback_result);
+ EXPECT_EQ(true, g_callback_called);
+}
+
+} // namespace proxy
+} // namespace ppapi
diff --git a/ppapi/tests/test_websocket.cc b/ppapi/tests/test_websocket.cc
index 81ea021..2707b4f 100644
--- a/ppapi/tests/test_websocket.cc
+++ b/ppapi/tests/test_websocket.cc
@@ -1148,8 +1148,16 @@ std::string TestWebSocket::TestUtilityInvalidConnect() {
for (int i = 0; kInvalidURLs[i]; ++i) {
TestWebSocketAPI ws(instance_);
result = ws.Connect(pp::Var(std::string(kInvalidURLs[i])), protocols, 0U);
- ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
- ASSERT_EQ(0U, ws.GetSeenEvents().size());
+ if (result == PP_OK_COMPLETIONPENDING) {
+ ws.WaitForClosed();
+ const std::vector<WebSocketEvent>& events = ws.GetSeenEvents();
+ ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type);
+ ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
+ ASSERT_EQ(2U, ws.GetSeenEvents().size());
+ } else {
+ ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
+ ASSERT_EQ(0U, ws.GetSeenEvents().size());
+ }
}
PASS();
@@ -1195,10 +1203,18 @@ std::string TestWebSocket::TestUtilityGetURL() {
TestWebSocketAPI websocket(instance_);
int32_t result = websocket.Connect(
pp::Var(std::string(kInvalidURLs[i])), protocols, 0U);
- ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
+ if (result == PP_OK_COMPLETIONPENDING) {
+ websocket.WaitForClosed();
+ const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
+ ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type);
+ ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
+ ASSERT_EQ(2U, events.size());
+ } else {
+ ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
+ ASSERT_EQ(0U, websocket.GetSeenEvents().size());
+ }
pp::Var url = websocket.GetURL();
ASSERT_TRUE(AreEqualWithString(url.pp_var(), kInvalidURLs[i]));
- ASSERT_EQ(0U, websocket.GetSeenEvents().size());
}
PASS();
@@ -1337,7 +1353,6 @@ std::string TestWebSocket::TestUtilityGetProtocol() {
ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type);
ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), protocol.c_str()));
- ASSERT_TRUE(events[1].was_clean);
PASS();
}
diff --git a/ppapi/thunk/interfaces_ppb_public_dev.h b/ppapi/thunk/interfaces_ppb_public_dev.h
index 98d3d46..9790192 100644
--- a/ppapi/thunk/interfaces_ppb_public_dev.h
+++ b/ppapi/thunk/interfaces_ppb_public_dev.h
@@ -17,7 +17,6 @@ UNPROXIED_API(PPB_DirectoryReader)
UNPROXIED_API(PPB_Scrollbar)
PROXIED_API(PPB_VideoCapture)
PROXIED_API(PPB_VideoDecoder)
-UNPROXIED_API(PPB_WebSocket)
UNPROXIED_API(PPB_Widget)
PROXIED_IFACE(PPB_AudioInput, PPB_AUDIO_INPUT_DEV_INTERFACE_0_1,
@@ -70,8 +69,6 @@ PROXIED_IFACE(PPB_VideoDecoder, PPB_VIDEODECODER_DEV_INTERFACE_0_16,
PPB_VideoDecoder_Dev_0_16)
PROXIED_IFACE(NoAPIName, PPB_VIEW_DEV_INTERFACE_0_1,
PPB_View_Dev_0_1)
-UNPROXIED_IFACE(PPB_WebSocket, PPB_WEBSOCKET_INTERFACE_1_0,
- PPB_WebSocket_1_0)
UNPROXIED_IFACE(PPB_Widget, PPB_WIDGET_DEV_INTERFACE_0_3, PPB_Widget_Dev_0_3)
UNPROXIED_IFACE(PPB_Widget, PPB_WIDGET_DEV_INTERFACE_0_4, PPB_Widget_Dev_0_4)
#endif // !defined(OS_NACL)
diff --git a/ppapi/thunk/interfaces_ppb_public_stable.h b/ppapi/thunk/interfaces_ppb_public_stable.h
index 635cb3a..f4ad0b9 100644
--- a/ppapi/thunk/interfaces_ppb_public_stable.h
+++ b/ppapi/thunk/interfaces_ppb_public_stable.h
@@ -77,6 +77,7 @@ PROXIED_IFACE(NoAPIName, PPB_URLREQUESTINFO_INTERFACE_1_0,
PPB_URLRequestInfo_1_0)
PROXIED_IFACE(PPB_URLResponseInfo, PPB_URLRESPONSEINFO_INTERFACE_1_0,
PPB_URLResponseInfo_1_0)
+PROXIED_IFACE(NoAPIName, PPB_WEBSOCKET_INTERFACE_1_0, PPB_WebSocket_1_0)
// Note: PPB_Var and PPB_VarArrayBuffer are special and registered manually.
PROXIED_IFACE(NoAPIName, PPB_VIEW_INTERFACE_1_0, PPB_View_1_0)
diff --git a/ppapi/thunk/ppb_websocket_api.h b/ppapi/thunk/ppb_websocket_api.h
index e5b7791..546ed99 100644
--- a/ppapi/thunk/ppb_websocket_api.h
+++ b/ppapi/thunk/ppb_websocket_api.h
@@ -8,6 +8,7 @@
#include "base/memory/ref_counted.h"
#include "ppapi/c/pp_completion_callback.h"
#include "ppapi/c/ppb_websocket.h"
+#include "ppapi/thunk/ppapi_thunk_export.h"
namespace ppapi {
@@ -19,14 +20,14 @@ namespace thunk {
// WebSocket API. See also following official specifications.
// - The WebSocket Protocol http://tools.ietf.org/html/rfc6455
// - The WebSocket API http://dev.w3.org/html5/websockets/
-class PPB_WebSocket_API {
+class PPAPI_THUNK_EXPORT PPB_WebSocket_API {
public:
virtual ~PPB_WebSocket_API() {}
// Connects to the specified WebSocket server with |protocols| argument
// defined by the WebSocket API. Returns an int32_t error code from
// pp_errors.h.
- virtual int32_t Connect(PP_Var url,
+ virtual int32_t Connect(const PP_Var& url,
const PP_Var protocols[],
uint32_t protocol_count,
scoped_refptr<TrackedCallback> callback) = 0;
@@ -34,7 +35,7 @@ class PPB_WebSocket_API {
// Closes the established connection with specified |code| and |reason|.
// Returns an int32_t error code from pp_errors.h.
virtual int32_t Close(uint16_t code,
- PP_Var reason,
+ const PP_Var& reason,
scoped_refptr<TrackedCallback> callback) = 0;
// Receives a message from the WebSocket server. Caller must keep specified
@@ -45,7 +46,7 @@ class PPB_WebSocket_API {
// Sends a message to the WebSocket server. Returns an int32_t error code
// from pp_errors.h.
- virtual int32_t SendMessage(PP_Var message) = 0;
+ virtual int32_t SendMessage(const PP_Var& message) = 0;
// Returns the bufferedAmount attribute of The WebSocket API.
virtual uint64_t GetBufferedAmount() = 0;
diff --git a/ppapi/thunk/resource_creation_api.h b/ppapi/thunk/resource_creation_api.h
index b0e1069..0832dc2 100644
--- a/ppapi/thunk/resource_creation_api.h
+++ b/ppapi/thunk/resource_creation_api.h
@@ -123,6 +123,7 @@ class ResourceCreationAPI {
virtual PP_Resource CreateTCPServerSocketPrivate(PP_Instance instance) = 0;
virtual PP_Resource CreateTCPSocketPrivate(PP_Instance instace) = 0;
virtual PP_Resource CreateUDPSocketPrivate(PP_Instance instace) = 0;
+ virtual PP_Resource CreateWebSocket(PP_Instance instance) = 0;
virtual PP_Resource CreateX509CertificatePrivate(PP_Instance instance) = 0;
#if !defined(OS_NACL)
virtual PP_Resource CreateAudioInput0_1(
@@ -154,7 +155,6 @@ class ResourceCreationAPI {
PP_Instance instance,
PP_Resource context3d_id,
PP_VideoDecoder_Profile profile) = 0;
- virtual PP_Resource CreateWebSocket(PP_Instance instance) = 0;
#endif // !defined(OS_NACL)
static const ApiID kApiID = API_ID_RESOURCE_CREATION;
diff --git a/ppapi/thunk/thunk.h b/ppapi/thunk/thunk.h
index 09086de..f40f806 100644
--- a/ppapi/thunk/thunk.h
+++ b/ppapi/thunk/thunk.h
@@ -76,6 +76,8 @@ PPAPI_THUNK_EXPORT const PPB_UDPSocket_Private_0_2*
GetPPB_UDPSocket_Private_0_2_Thunk();
PPAPI_THUNK_EXPORT const PPB_URLLoaderTrusted_0_3*
GetPPB_URLLoaderTrusted_0_3_Thunk();
+PPAPI_THUNK_EXPORT const PPB_WebSocket_1_0*
+ GetPPB_WebSocket_1_0_Thunk();
} // namespace thunk
} // namespace ppapi
diff --git a/webkit/glue/webkit_glue.gypi b/webkit/glue/webkit_glue.gypi
index 0adca67..57388f6 100644
--- a/webkit/glue/webkit_glue.gypi
+++ b/webkit/glue/webkit_glue.gypi
@@ -252,8 +252,6 @@
'../plugins/ppapi/ppb_video_capture_impl.h',
'../plugins/ppapi/ppb_video_decoder_impl.cc',
'../plugins/ppapi/ppb_video_decoder_impl.h',
- '../plugins/ppapi/ppb_websocket_impl.cc',
- '../plugins/ppapi/ppb_websocket_impl.h',
'../plugins/ppapi/ppb_widget_impl.cc',
'../plugins/ppapi/ppb_widget_impl.h',
'../plugins/ppapi/ppb_x509_certificate_private_impl.cc',
diff --git a/webkit/plugins/ppapi/ppb_websocket_impl.cc b/webkit/plugins/ppapi/ppb_websocket_impl.cc
deleted file mode 100644
index 2893fea..0000000
--- a/webkit/plugins/ppapi/ppb_websocket_impl.cc
+++ /dev/null
@@ -1,538 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "webkit/plugins/ppapi/ppb_websocket_impl.h"
-
-#include <set>
-#include <string>
-
-#include "base/basictypes.h"
-#include "googleurl/src/gurl.h"
-#include "net/base/net_util.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "ppapi/c/pp_errors.h"
-#include "ppapi/c/pp_var.h"
-#include "ppapi/c/ppb_var.h"
-#include "ppapi/c/ppb_var_array_buffer.h"
-#include "ppapi/shared_impl/var.h"
-#include "ppapi/shared_impl/var_tracker.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebArrayBuffer.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebSocket.h"
-#include "webkit/plugins/ppapi/host_array_buffer_var.h"
-#include "webkit/plugins/ppapi/host_globals.h"
-#include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
-#include "webkit/plugins/ppapi/resource_helper.h"
-
-using ppapi::ArrayBufferVar;
-using ppapi::PpapiGlobals;
-using ppapi::StringVar;
-using ppapi::thunk::PPB_WebSocket_API;
-using ppapi::TrackedCallback;
-using ppapi::Var;
-using ppapi::VarTracker;
-using WebKit::WebArrayBuffer;
-using WebKit::WebDocument;
-using WebKit::WebString;
-using WebKit::WebSocket;
-using WebKit::WebSocketClient;
-using WebKit::WebURL;
-
-const uint32_t kMaxReasonSizeInBytes = 123;
-const size_t kHybiBaseFramingOverhead = 2;
-const size_t kHybiMaskingKeyLength = 4;
-const size_t kMinimumPayloadSizeWithTwoByteExtendedPayloadLength = 126;
-const size_t kMinimumPayloadSizeWithEightByteExtendedPayloadLength = 0x10000;
-
-namespace {
-
-uint64_t SaturateAdd(uint64_t a, uint64_t b) {
- if (kuint64max - a < b)
- return kuint64max;
- return a + b;
-}
-
-uint64_t GetFrameSize(uint64_t payload_size) {
- uint64_t overhead = kHybiBaseFramingOverhead + kHybiMaskingKeyLength;
- if (payload_size > kMinimumPayloadSizeWithEightByteExtendedPayloadLength)
- overhead += 8;
- else if (payload_size > kMinimumPayloadSizeWithTwoByteExtendedPayloadLength)
- overhead += 2;
- return SaturateAdd(payload_size, overhead);
-}
-
-bool InValidStateToReceive(PP_WebSocketReadyState state) {
- return state == PP_WEBSOCKETREADYSTATE_OPEN ||
- state == PP_WEBSOCKETREADYSTATE_CLOSING;
-}
-
-} // namespace
-
-namespace webkit {
-namespace ppapi {
-
-PPB_WebSocket_Impl::PPB_WebSocket_Impl(PP_Instance instance)
- : Resource(::ppapi::OBJECT_IS_IMPL, instance),
- state_(PP_WEBSOCKETREADYSTATE_INVALID),
- error_was_received_(false),
- receive_callback_var_(NULL),
- wait_for_receive_(false),
- close_code_(0),
- close_was_clean_(PP_FALSE),
- empty_string_(new StringVar("", 0)),
- buffered_amount_(0),
- buffered_amount_after_close_(0) {
-}
-
-PPB_WebSocket_Impl::~PPB_WebSocket_Impl() {
- if (websocket_.get())
- websocket_->disconnect();
-}
-
-// static
-PP_Resource PPB_WebSocket_Impl::Create(PP_Instance instance) {
- scoped_refptr<PPB_WebSocket_Impl> ws(new PPB_WebSocket_Impl(instance));
- return ws->GetReference();
-}
-
-PPB_WebSocket_API* PPB_WebSocket_Impl::AsPPB_WebSocket_API() {
- return this;
-}
-
-int32_t PPB_WebSocket_Impl::Connect(PP_Var url,
- const PP_Var protocols[],
- uint32_t protocol_count,
- scoped_refptr<TrackedCallback> callback) {
- // Check mandatory interfaces.
- PluginInstance* plugin_instance = ResourceHelper::GetPluginInstance(this);
- DCHECK(plugin_instance);
- if (!plugin_instance)
- return PP_ERROR_FAILED;
-
- // Connect() can be called at most once.
- if (websocket_.get())
- return PP_ERROR_INPROGRESS;
- if (state_ != PP_WEBSOCKETREADYSTATE_INVALID)
- return PP_ERROR_INPROGRESS;
- state_ = PP_WEBSOCKETREADYSTATE_CLOSED;
-
- // Validate url and convert it to WebURL.
- scoped_refptr<StringVar> url_string = StringVar::FromPPVar(url);
- if (!url_string)
- return PP_ERROR_BADARGUMENT;
- GURL gurl(url_string->value());
- url_ = new StringVar(gurl.spec());
- if (!gurl.is_valid())
- return PP_ERROR_BADARGUMENT;
- if (!gurl.SchemeIs("ws") && !gurl.SchemeIs("wss"))
- return PP_ERROR_BADARGUMENT;
- if (gurl.has_ref())
- return PP_ERROR_BADARGUMENT;
- if (!net::IsPortAllowedByDefault(gurl.IntPort()))
- return PP_ERROR_BADARGUMENT;
- WebURL web_url(gurl);
-
- // Validate protocols and convert it to WebString.
- std::string protocol_string;
- std::set<std::string> protocol_set;
- for (uint32_t i = 0; i < protocol_count; i++) {
- // TODO(toyoshim): Similar function exist in WebKit::WebSocket.
- // We must rearrange them into WebKit::WebChannel and share its protocol
- // related implementation via WebKit API.
- scoped_refptr<StringVar> protocol(StringVar::FromPPVar(protocols[i]));
-
- // Check invalid and empty entries.
- if (!protocol || !protocol->value().length())
- return PP_ERROR_BADARGUMENT;
-
- // Check duplicated protocol entries.
- if (protocol_set.find(protocol->value()) != protocol_set.end())
- return PP_ERROR_BADARGUMENT;
- protocol_set.insert(protocol->value());
-
- // Check containing characters.
- for (std::string::const_iterator it = protocol->value().begin();
- it != protocol->value().end();
- ++it) {
- uint8_t character = *it;
- // WebSocket specification says "(Subprotocol string must consist of)
- // characters in the range U+0021 to U+007E not including separator
- // characters as defined in [RFC2616]."
- const uint8_t minimumProtocolCharacter = '!'; // U+0021.
- const uint8_t maximumProtocolCharacter = '~'; // U+007E.
- if (character < minimumProtocolCharacter ||
- character > maximumProtocolCharacter ||
- character == '"' || character == '(' || character == ')' ||
- character == ',' || character == '/' ||
- (character >= ':' && character <= '@') || // U+003A - U+0040
- (character >= '[' && character <= ']') || // U+005B - u+005D
- character == '{' || character == '}')
- return PP_ERROR_BADARGUMENT;
- }
- // Join protocols with the comma separator.
- if (i != 0)
- protocol_string.append(",");
- protocol_string.append(protocol->value());
- }
- WebString web_protocols = WebString::fromUTF8(protocol_string);
-
- // Create WebKit::WebSocket object and connect.
- WebDocument document = plugin_instance->container()->element().document();
- websocket_.reset(WebSocket::create(document, this));
- DCHECK(websocket_.get());
- if (!websocket_.get())
- return PP_ERROR_NOTSUPPORTED;
-
- // Set receiving binary object type.
- websocket_->setBinaryType(WebSocket::BinaryTypeArrayBuffer);
-
- websocket_->connect(web_url, web_protocols);
- state_ = PP_WEBSOCKETREADYSTATE_CONNECTING;
-
- // Install callback.
- connect_callback_ = callback;
-
- return PP_OK_COMPLETIONPENDING;
-}
-
-int32_t PPB_WebSocket_Impl::Close(uint16_t code,
- PP_Var reason,
- scoped_refptr<TrackedCallback> callback) {
- // Check mandarory interfaces.
- if (!websocket_.get())
- return PP_ERROR_FAILED;
-
- // Validate |code| and |reason|.
- scoped_refptr<StringVar> reason_string;
- WebString web_reason;
- WebSocket::CloseEventCode event_code =
- static_cast<WebSocket::CloseEventCode>(code);
- if (code == PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED) {
- // PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED and CloseEventCodeNotSpecified are
- // assigned to different values. A conversion is needed if
- // PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED is specified.
- event_code = WebSocket::CloseEventCodeNotSpecified;
- } else {
- if (!(code == PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE ||
- (PP_WEBSOCKETSTATUSCODE_USER_REGISTERED_MIN <= code &&
- code <= PP_WEBSOCKETSTATUSCODE_USER_PRIVATE_MAX)))
- // RFC 6455 limits applications to use reserved connection close code in
- // section 7.4.2.. The WebSocket API (http://www.w3.org/TR/websockets/)
- // defines this out of range error as InvalidAccessError in JavaScript.
- return PP_ERROR_NOACCESS;
-
- // |reason| must be ignored if it is PP_VARTYPE_UNDEFINED or |code| is
- // PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED.
- if (reason.type != PP_VARTYPE_UNDEFINED) {
- // Validate |reason|.
- reason_string = StringVar::FromPPVar(reason);
- if (!reason_string ||
- reason_string->value().size() > kMaxReasonSizeInBytes)
- return PP_ERROR_BADARGUMENT;
- web_reason = WebString::fromUTF8(reason_string->value());
- }
- }
-
- // Check state.
- if (state_ == PP_WEBSOCKETREADYSTATE_CLOSING)
- return PP_ERROR_INPROGRESS;
- if (state_ == PP_WEBSOCKETREADYSTATE_CLOSED)
- return PP_OK;
-
- // Install |callback|.
- close_callback_ = callback;
-
- // Abort ongoing connect.
- if (state_ == PP_WEBSOCKETREADYSTATE_CONNECTING) {
- state_ = PP_WEBSOCKETREADYSTATE_CLOSING;
- // Need to do a "Post" to avoid reentering the plugin.
- connect_callback_->PostAbort();
- connect_callback_ = NULL;
- websocket_->fail(
- "WebSocket was closed before the connection was established.");
- return PP_OK_COMPLETIONPENDING;
- }
-
- // Abort ongoing receive.
- if (wait_for_receive_) {
- wait_for_receive_ = false;
- receive_callback_var_ = NULL;
-
- // Need to do a "Post" to avoid reentering the plugin.
- receive_callback_->PostAbort();
- receive_callback_ = NULL;
- }
-
- // Close connection.
- state_ = PP_WEBSOCKETREADYSTATE_CLOSING;
- websocket_->close(event_code, web_reason);
-
- return PP_OK_COMPLETIONPENDING;
-}
-
-int32_t PPB_WebSocket_Impl::ReceiveMessage(
- PP_Var* message,
- scoped_refptr<TrackedCallback> callback) {
- // Check state.
- if (state_ == PP_WEBSOCKETREADYSTATE_INVALID ||
- state_ == PP_WEBSOCKETREADYSTATE_CONNECTING)
- return PP_ERROR_BADARGUMENT;
-
- // Just return received message if any received message is queued.
- if (!received_messages_.empty()) {
- receive_callback_var_ = message;
- return DoReceive();
- }
-
- // Check state again. In CLOSED state, no more messages will be received.
- if (state_ == PP_WEBSOCKETREADYSTATE_CLOSED)
- return PP_ERROR_BADARGUMENT;
-
- // Returns PP_ERROR_FAILED after an error is received and received messages
- // is exhausted.
- if (error_was_received_)
- return PP_ERROR_FAILED;
-
- // Or retain |message| as buffer to store and install |callback|.
- wait_for_receive_ = true;
- receive_callback_var_ = message;
- receive_callback_ = callback;
-
- return PP_OK_COMPLETIONPENDING;
-}
-
-int32_t PPB_WebSocket_Impl::SendMessage(PP_Var message) {
- // Check mandatory interfaces.
- if (!websocket_.get())
- return PP_ERROR_FAILED;
-
- // Check state.
- if (state_ == PP_WEBSOCKETREADYSTATE_INVALID ||
- state_ == PP_WEBSOCKETREADYSTATE_CONNECTING)
- return PP_ERROR_BADARGUMENT;
-
- if (state_ == PP_WEBSOCKETREADYSTATE_CLOSING ||
- state_ == PP_WEBSOCKETREADYSTATE_CLOSED) {
- // Handle buffered_amount_after_close_.
- uint64_t payload_size = 0;
- if (message.type == PP_VARTYPE_STRING) {
- scoped_refptr<StringVar> message_string = StringVar::FromPPVar(message);
- if (message_string)
- payload_size += message_string->value().length();
- } else if (message.type == PP_VARTYPE_ARRAY_BUFFER) {
- scoped_refptr<ArrayBufferVar> message_array_buffer =
- ArrayBufferVar::FromPPVar(message);
- if (message_array_buffer)
- payload_size += message_array_buffer->ByteLength();
- } else {
- // TODO(toyoshim): Support Blob.
- return PP_ERROR_NOTSUPPORTED;
- }
-
- buffered_amount_after_close_ =
- SaturateAdd(buffered_amount_after_close_, GetFrameSize(payload_size));
-
- return PP_ERROR_FAILED;
- }
-
- // Send the message.
- if (message.type == PP_VARTYPE_STRING) {
- // Convert message to WebString.
- scoped_refptr<StringVar> message_string = StringVar::FromPPVar(message);
- if (!message_string)
- return PP_ERROR_BADARGUMENT;
- WebString web_message = WebString::fromUTF8(message_string->value());
- if (!websocket_->sendText(web_message))
- return PP_ERROR_BADARGUMENT;
- } else if (message.type == PP_VARTYPE_ARRAY_BUFFER) {
- // Convert message to WebArrayBuffer.
- scoped_refptr<HostArrayBufferVar> host_message =
- static_cast<HostArrayBufferVar*>(ArrayBufferVar::FromPPVar(message));
- if (!host_message)
- return PP_ERROR_BADARGUMENT;
- WebArrayBuffer& web_message = host_message->webkit_buffer();
- if (!websocket_->sendArrayBuffer(web_message))
- return PP_ERROR_BADARGUMENT;
- } else {
- // TODO(toyoshim): Support Blob.
- return PP_ERROR_NOTSUPPORTED;
- }
-
- return PP_OK;
-}
-
-uint64_t PPB_WebSocket_Impl::GetBufferedAmount() {
- return SaturateAdd(buffered_amount_, buffered_amount_after_close_);
-}
-
-uint16_t PPB_WebSocket_Impl::GetCloseCode() {
- return close_code_;
-}
-
-PP_Var PPB_WebSocket_Impl::GetCloseReason() {
- if (!close_reason_)
- return empty_string_->GetPPVar();
- return close_reason_->GetPPVar();
-}
-
-PP_Bool PPB_WebSocket_Impl::GetCloseWasClean() {
- return close_was_clean_;
-}
-
-PP_Var PPB_WebSocket_Impl::GetExtensions() {
- // Check mandatory interfaces.
- if (!websocket_.get())
- return empty_string_->GetPPVar();
-
- std::string extensions = websocket_->extensions().utf8();
- return StringVar::StringToPPVar(extensions);
-}
-
-PP_Var PPB_WebSocket_Impl::GetProtocol() {
- // Check mandatory interfaces.
- if (!websocket_.get())
- return empty_string_->GetPPVar();
-
- std::string protocol = websocket_->subprotocol().utf8();
- return StringVar::StringToPPVar(protocol);
-}
-
-PP_WebSocketReadyState PPB_WebSocket_Impl::GetReadyState() {
- return state_;
-}
-
-PP_Var PPB_WebSocket_Impl::GetURL() {
- if (!url_)
- return empty_string_->GetPPVar();
- return url_->GetPPVar();
-}
-
-void PPB_WebSocket_Impl::didConnect() {
- DCHECK_EQ(PP_WEBSOCKETREADYSTATE_CONNECTING, state_);
- state_ = PP_WEBSOCKETREADYSTATE_OPEN;
- TrackedCallback::ClearAndRun(&connect_callback_, PP_OK);
-}
-
-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();
- received_messages_.push(scoped_refptr<Var>(new StringVar(string)));
-
- if (!wait_for_receive_)
- return;
-
- TrackedCallback::ClearAndRun(&receive_callback_, DoReceive());
-}
-
-void PPB_WebSocket_Impl::didReceiveArrayBuffer(
- const WebArrayBuffer& binaryData) {
- // Dispose packets after receiving an error or in invalid state.
- if (error_was_received_ || !InValidStateToReceive(state_))
- return;
-
- // Append received data to queue.
- received_messages_.push(
- scoped_refptr<Var>(new HostArrayBufferVar(binaryData)));
-
- if (!wait_for_receive_)
- return;
-
- TrackedCallback::ClearAndRun(&receive_callback_, DoReceive());
-}
-
-void PPB_WebSocket_Impl::didReceiveMessageError() {
- // 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;
- receive_callback_var_ = NULL;
- TrackedCallback::ClearAndRun(&receive_callback_, PP_ERROR_FAILED);
-}
-
-void PPB_WebSocket_Impl::didUpdateBufferedAmount(
- unsigned long buffered_amount) {
- if (state_ == PP_WEBSOCKETREADYSTATE_CLOSED)
- return;
- buffered_amount_ = buffered_amount;
-}
-
-void PPB_WebSocket_Impl::didStartClosingHandshake() {
- state_ = PP_WEBSOCKETREADYSTATE_CLOSING;
-}
-
-void PPB_WebSocket_Impl::didClose(unsigned long unhandled_buffered_amount,
- ClosingHandshakeCompletionStatus status,
- unsigned short code,
- const WebString& reason) {
- // Store code and reason.
- close_code_ = code;
- close_reason_ = new StringVar(reason.utf8());
-
- // Set close_was_clean_.
- bool was_clean =
- state_ == PP_WEBSOCKETREADYSTATE_CLOSING &&
- !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, state_);
- PP_WebSocketReadyState state = state_;
- state_ = PP_WEBSOCKETREADYSTATE_CLOSED;
-
- // User handlers may release WebSocket PP_Resource in the following
- // completion callbacks. Retain |this| here to assure that this object
- // keep on being valid in this function.
- scoped_refptr<PPB_WebSocket_Impl> retain_this(this);
- if (state == PP_WEBSOCKETREADYSTATE_CONNECTING)
- TrackedCallback::ClearAndRun(&connect_callback_, PP_ERROR_FAILED);
-
- if (wait_for_receive_) {
- wait_for_receive_ = false;
- receive_callback_var_ = NULL;
- TrackedCallback::ClearAndRun(&receive_callback_, PP_ERROR_FAILED);
- }
-
- if ((state == PP_WEBSOCKETREADYSTATE_CLOSING) && close_callback_.get())
- TrackedCallback::ClearAndRun(&close_callback_, PP_OK);
-
- // Disconnect.
- if (websocket_.get())
- websocket_->disconnect();
-}
-
-int32_t PPB_WebSocket_Impl::DoReceive() {
- if (!receive_callback_var_)
- return PP_OK;
-
- *receive_callback_var_ = received_messages_.front()->GetPPVar();
- received_messages_.pop();
- receive_callback_var_ = NULL;
- wait_for_receive_ = false;
- return PP_OK;
-}
-
-} // namespace ppapi
-} // namespace webkit
diff --git a/webkit/plugins/ppapi/ppb_websocket_impl.h b/webkit/plugins/ppapi/ppb_websocket_impl.h
deleted file mode 100644
index 0bdaf4b..0000000
--- a/webkit/plugins/ppapi/ppb_websocket_impl.h
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef WEBKIT_PLUGINS_PPAPI_PPB_WEBSOCKET_IMPL_H_
-#define WEBKIT_PLUGINS_PPAPI_PPB_WEBSOCKET_IMPL_H_
-
-#include <queue>
-
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "ppapi/shared_impl/resource.h"
-#include "ppapi/shared_impl/tracked_callback.h"
-#include "ppapi/thunk/ppb_websocket_api.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebSocket.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebSocketClient.h"
-
-namespace ppapi {
-class StringVar;
-class Var;
-} // namespace ppapi
-
-namespace webkit {
-namespace ppapi {
-
-// All implementation is in this class for now. We should move some common
-// implementation to shared_impl when we implement proxy interfaces.
-class PPB_WebSocket_Impl : public ::ppapi::Resource,
- public ::ppapi::thunk::PPB_WebSocket_API,
- public ::WebKit::WebSocketClient {
- public:
- explicit PPB_WebSocket_Impl(PP_Instance instance);
- virtual ~PPB_WebSocket_Impl();
-
- static PP_Resource Create(PP_Instance instance);
-
- // Resource overrides.
- // Returns the pointer to the thunk::PPB_WebSocket_API if it's supported.
- virtual ::ppapi::thunk::PPB_WebSocket_API* AsPPB_WebSocket_API() OVERRIDE;
-
- // PPB_WebSocket_API implementation.
- virtual int32_t Connect(
- PP_Var url,
- const PP_Var protocols[],
- uint32_t protocol_count,
- scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
- virtual int32_t Close(
- uint16_t code,
- PP_Var reason,
- scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
- virtual int32_t ReceiveMessage(
- PP_Var* message,
- scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
- virtual int32_t SendMessage(PP_Var message) OVERRIDE;
- virtual uint64_t GetBufferedAmount() OVERRIDE;
- virtual uint16_t GetCloseCode() OVERRIDE;
- virtual PP_Var GetCloseReason() OVERRIDE;
- virtual PP_Bool GetCloseWasClean() OVERRIDE;
- virtual PP_Var GetExtensions() OVERRIDE;
- virtual PP_Var GetProtocol() OVERRIDE;
- virtual PP_WebSocketReadyState GetReadyState() OVERRIDE;
- virtual PP_Var GetURL() OVERRIDE;
-
- // WebSocketClient implementation.
- virtual void didConnect();
- virtual void didReceiveMessage(const WebKit::WebString& message);
- virtual void didReceiveArrayBuffer(const WebKit::WebArrayBuffer& binaryData);
- virtual void didReceiveMessageError();
- virtual void didUpdateBufferedAmount(unsigned long buffered_amount);
- virtual void didStartClosingHandshake();
- virtual void didClose(unsigned long unhandled_buffered_amount,
- ClosingHandshakeCompletionStatus status,
- unsigned short code,
- const WebKit::WebString& reason);
- private:
- // Picks up a received message and moves it to user receiving buffer. This
- // function is used in both ReceiveMessage for fast returning path and
- // didReceiveMessage callback.
- int32_t DoReceive();
-
- // Keeps the WebKit side WebSocket object. This is used for calling WebKit
- // side functions via WebKit API.
- scoped_ptr<WebKit::WebSocket> websocket_;
-
- // Represents readyState described in the WebSocket API specification. It can
- // be read via GetReadyState().
- PP_WebSocketReadyState state_;
-
- // Becomes true if any error is detected. Incoming data will be disposed
- // if this variable is true, then ReceiveMessage() returns PP_ERROR_FAILED
- // after returning all received data.
- bool error_was_received_;
-
- // Keeps a completion callback for asynchronous Connect().
- scoped_refptr< ::ppapi::TrackedCallback> connect_callback_;
-
- // Keeps a completion callback for asynchronous ReceiveMessage().
- scoped_refptr< ::ppapi::TrackedCallback> receive_callback_;
-
- // Keeps a pointer to PP_Var which is provided via ReceiveMessage().
- // Received data will be copied to this PP_Var on ready.
- PP_Var* receive_callback_var_;
-
- // Becomes true when asynchronous ReceiveMessage() is processed.
- bool wait_for_receive_;
-
- // Keeps received data until ReceiveMessage() requests.
- std::queue< scoped_refptr< ::ppapi::Var> > received_messages_;
-
- // Keeps a completion callback for asynchronous Close().
- scoped_refptr< ::ppapi::TrackedCallback> close_callback_;
-
- // Keeps the status code field of closing handshake. It can be read via
- // GetCloseCode().
- uint16_t close_code_;
-
- // Keeps the reason field of closing handshake. It can be read via
- // GetCloseReason().
- scoped_refptr< ::ppapi::StringVar> close_reason_;
-
- // Becomes true when closing handshake is performed successfully. It can be
- // read via GetCloseWasClean().
- PP_Bool close_was_clean_;
-
- // Keeps empty string for functions to return empty string.
- scoped_refptr< ::ppapi::StringVar> empty_string_;
-
- // Represents extensions described in the WebSocket API specification. It can
- // be read via GetExtensions().
- scoped_refptr< ::ppapi::StringVar> extensions_;
-
- // Represents url described in the WebSocket API specification. It can be
- // read via GetURL().
- scoped_refptr< ::ppapi::StringVar> url_;
-
- // Keeps the number of bytes of application data that have been queued using
- // SendMessage(). WebKit side implementation calculates the actual amount.
- // This is a cached value which is notified through a WebKit callback.
- // This value is used to calculate bufferedAmount in the WebSocket API
- // specification. The calculated value can be read via GetBufferedAmount().
- uint64_t buffered_amount_;
-
- // Keeps the number of bytes of application data that have been ignored
- // because the connection was already closed.
- // This value is used to calculate bufferedAmount in the WebSocket API
- // specification. The calculated value can be read via GetBufferedAmount().
- uint64_t buffered_amount_after_close_;
-
- DISALLOW_COPY_AND_ASSIGN(PPB_WebSocket_Impl);
-};
-
-} // namespace ppapi
-} // namespace webkit
-
-#endif // WEBKIT_PLUGINS_PPAPI_PPB_WEBSOCKET_IMPL_H_
diff --git a/webkit/plugins/ppapi/resource_creation_impl.cc b/webkit/plugins/ppapi/resource_creation_impl.cc
index 1b172bc..22ac0b2 100644
--- a/webkit/plugins/ppapi/resource_creation_impl.cc
+++ b/webkit/plugins/ppapi/resource_creation_impl.cc
@@ -33,7 +33,6 @@
#include "webkit/plugins/ppapi/ppb_url_loader_impl.h"
#include "webkit/plugins/ppapi/ppb_video_capture_impl.h"
#include "webkit/plugins/ppapi/ppb_video_decoder_impl.h"
-#include "webkit/plugins/ppapi/ppb_websocket_impl.h"
#include "webkit/plugins/ppapi/ppb_x509_certificate_private_impl.h"
#include "webkit/plugins/ppapi/resource_helper.h"
@@ -291,10 +290,6 @@ PP_Resource ResourceCreationImpl::CreateVideoDecoder(
return PPB_VideoDecoder_Impl::Create(instance, graphics3d_id, profile);
}
-PP_Resource ResourceCreationImpl::CreateWebSocket(PP_Instance instance) {
- return PPB_WebSocket_Impl::Create(instance);
-}
-
PP_Resource ResourceCreationImpl::CreateWheelInputEvent(
PP_Instance instance,
PP_TimeTicks time_stamp,
diff --git a/webkit/plugins/ppapi/resource_creation_impl.h b/webkit/plugins/ppapi/resource_creation_impl.h
index 8d445a7..77a7b99 100644
--- a/webkit/plugins/ppapi/resource_creation_impl.h
+++ b/webkit/plugins/ppapi/resource_creation_impl.h
@@ -121,7 +121,6 @@ class WEBKIT_PLUGINS_EXPORT ResourceCreationImpl
PP_Instance instance,
PP_Resource graphics3d_id,
PP_VideoDecoder_Profile profile) OVERRIDE;
- virtual PP_Resource CreateWebSocket(PP_Instance instance) OVERRIDE;
virtual PP_Resource CreateWheelInputEvent(
PP_Instance instance,
PP_TimeTicks time_stamp,