Pepper WebSocket API: Implement new design Chrome IPC.
This change implements new Chrome IPC for PPB_WebSocket. After this change, all mode including out of process will work with new design. It doesn't depend on old SRPC design any more. BUG=87310,116317 Review URL: https://chromiumcodereview.appspot.com/10944005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@160783 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
chrome/test/ppapi
content
ppapi
host
ppapi_proxy.gypippapi_shared.gypippapi_tests.gypiproxy
plugin_dispatcher.ccppapi_messages.hresource_creation_proxy.ccresource_creation_proxy.hwebsocket_resource.ccwebsocket_resource.hwebsocket_resource_unittest.cc
tests
thunk
webkit
@ -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)
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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_;
|
||||
}
|
||||
|
@ -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_
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
290
content/renderer/pepper/pepper_websocket_host.cc
Normal file
290
content/renderer/pepper/pepper_websocket_host.cc
Normal file
@ -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
|
99
content/renderer/pepper/pepper_websocket_host.h
Normal file
99
content/renderer/pepper/pepper_websocket_host.h
Normal file
@ -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_
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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',
|
||||
|
@ -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);
|
||||
|
@ -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 */)
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
509
ppapi/proxy/websocket_resource.cc
Normal file
509
ppapi/proxy/websocket_resource.cc
Normal file
@ -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
|
157
ppapi/proxy/websocket_resource.h
Normal file
157
ppapi/proxy/websocket_resource.h
Normal file
@ -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_
|
168
ppapi/proxy/websocket_resource_unittest.cc
Normal file
168
ppapi/proxy/websocket_resource_unittest.cc
Normal file
@ -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, ¶ms, &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, ¶ms, &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
|
@ -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();
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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',
|
||||
|
@ -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
|
@ -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_
|
@ -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,
|
||||
|
@ -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,
|
||||
|
Reference in New Issue
Block a user