15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/proxy/websocket_resource.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
8558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include <string>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/c/pp_errors.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/proxy/dispatch_reply_message.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/proxy/ppapi_messages.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/shared_impl/ppapi_globals.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/shared_impl/var.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/shared_impl/var_tracker.h"
187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebSocket.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint32_t kMaxReasonSizeInBytes = 123;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kBaseFramingOverhead = 2;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kMaskingKeyLength = 4;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kMinimumPayloadSizeWithTwoByteExtendedPayloadLength = 126;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kMinimumPayloadSizeWithEightByteExtendedPayloadLength = 0x10000;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint64_t SaturateAdd(uint64_t a, uint64_t b) {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kuint64max - a < b)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return kuint64max;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return a + b;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint64_t GetFrameSize(uint64_t payload_size) {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint64_t overhead = kBaseFramingOverhead + kMaskingKeyLength;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (payload_size > kMinimumPayloadSizeWithEightByteExtendedPayloadLength)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overhead += 8;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if (payload_size > kMinimumPayloadSizeWithTwoByteExtendedPayloadLength)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overhead += 2;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SaturateAdd(payload_size, overhead);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool InValidStateToReceive(PP_WebSocketReadyState state) {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return state == PP_WEBSOCKETREADYSTATE_OPEN ||
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         state == PP_WEBSOCKETREADYSTATE_CLOSING;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ppapi {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace proxy {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebSocketResource::WebSocketResource(Connection connection,
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     PP_Instance instance)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : PluginResource(connection, instance),
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      state_(PP_WEBSOCKETREADYSTATE_INVALID),
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_was_received_(false),
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      receive_callback_var_(NULL),
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      empty_string_(new StringVar(std::string())),
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      close_code_(0),
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      close_reason_(NULL),
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      close_was_clean_(PP_FALSE),
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extensions_(NULL),
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      protocol_(NULL),
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_(NULL),
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buffered_amount_(0),
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buffered_amount_after_close_(0) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebSocketResource::~WebSocketResource() {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)thunk::PPB_WebSocket_API* WebSocketResource::AsPPB_WebSocket_API() {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int32_t WebSocketResource::Connect(
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PP_Var& url,
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PP_Var protocols[],
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t protocol_count,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<TrackedCallback> callback) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (TrackedCallback::IsPending(connect_callback_))
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PP_ERROR_INPROGRESS;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Connect() can be called at most once.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ != PP_WEBSOCKETREADYSTATE_INVALID)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PP_ERROR_INPROGRESS;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = PP_WEBSOCKETREADYSTATE_CLOSED;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the URL.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_ = StringVar::FromPPVar(url);
93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!url_.get())
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PP_ERROR_BADARGUMENT;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the protocols.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<std::string> protocol_set;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> protocol_strings;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  protocol_strings.reserve(protocol_count);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (uint32_t i = 0; i < protocol_count; ++i) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<StringVar> protocol(StringVar::FromPPVar(protocols[i]));
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check invalid and empty entries.
104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!protocol.get() || !protocol->value().length())
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return PP_ERROR_BADARGUMENT;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check duplicated protocol entries.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (protocol_set.find(protocol->value()) != protocol_set.end())
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return PP_ERROR_BADARGUMENT;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    protocol_set.insert(protocol->value());
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    protocol_strings.push_back(protocol->value());
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Install callback.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connect_callback_ = callback;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create remote host in the renderer, then request to check the URL and
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // establish the connection.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = PP_WEBSOCKETREADYSTATE_CONNECTING;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendCreate(RENDERER, PpapiHostMsg_WebSocket_Create());
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PpapiHostMsg_WebSocket_Connect msg(url_->value(), protocol_strings);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Call<PpapiPluginMsg_WebSocket_ConnectReply>(RENDERER, msg,
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&WebSocketResource::OnPluginMsgConnectReply, this));
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return PP_OK_COMPLETIONPENDING;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int32_t WebSocketResource::Close(uint16_t code,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 const PP_Var& reason,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 scoped_refptr<TrackedCallback> callback) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (TrackedCallback::IsPending(close_callback_))
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PP_ERROR_INPROGRESS;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == PP_WEBSOCKETREADYSTATE_INVALID)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PP_ERROR_FAILED;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Validate |code| and |reason|.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<StringVar> reason_string_var;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string reason_string;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebKit::WebSocket::CloseEventCode event_code =
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<WebKit::WebSocket::CloseEventCode>(code);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (code == PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED and CloseEventCodeNotSpecified are
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // assigned to different values. A conversion is needed if
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED is specified.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    event_code = WebKit::WebSocket::CloseEventCodeNotSpecified;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!(code == PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE ||
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (PP_WEBSOCKETSTATUSCODE_USER_REGISTERED_MIN <= code &&
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        code <= PP_WEBSOCKETSTATUSCODE_USER_PRIVATE_MAX)))
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // RFC 6455 limits applications to use reserved connection close code in
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // section 7.4.2.. The WebSocket API (http://www.w3.org/TR/websockets/)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // defines this out of range error as InvalidAccessError in JavaScript.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return PP_ERROR_NOACCESS;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |reason| must be ignored if it is PP_VARTYPE_UNDEFINED or |code| is
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (reason.type != PP_VARTYPE_UNDEFINED) {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Validate |reason|.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reason_string_var = StringVar::FromPPVar(reason);
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (!reason_string_var.get() ||
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          reason_string_var->value().size() > kMaxReasonSizeInBytes)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return PP_ERROR_BADARGUMENT;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reason_string = reason_string_var->value();
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check state.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == PP_WEBSOCKETREADYSTATE_CLOSING)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PP_ERROR_INPROGRESS;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == PP_WEBSOCKETREADYSTATE_CLOSED)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PP_OK;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Install |callback|.
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  close_callback_ = callback;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Abort ongoing connect.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (TrackedCallback::IsPending(connect_callback_)) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = PP_WEBSOCKETREADYSTATE_CLOSING;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Need to do a "Post" to avoid reentering the plugin.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    connect_callback_->PostAbort();
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    connect_callback_ = NULL;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Post(RENDERER, PpapiHostMsg_WebSocket_Fail(
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "WebSocket was closed before the connection was established."));
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PP_OK_COMPLETIONPENDING;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Abort ongoing receive.
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (TrackedCallback::IsPending(receive_callback_)) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    receive_callback_var_ = NULL;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Need to do a "Post" to avoid reentering the plugin.
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    receive_callback_->PostAbort();
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    receive_callback_ = NULL;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Close connection.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = PP_WEBSOCKETREADYSTATE_CLOSING;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PpapiHostMsg_WebSocket_Close msg(static_cast<int32_t>(event_code),
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   reason_string);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Call<PpapiPluginMsg_WebSocket_CloseReply>(RENDERER, msg,
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&WebSocketResource::OnPluginMsgCloseReply, this));
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return PP_OK_COMPLETIONPENDING;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int32_t WebSocketResource::ReceiveMessage(
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PP_Var* message,
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<TrackedCallback> callback) {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (TrackedCallback::IsPending(receive_callback_))
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PP_ERROR_INPROGRESS;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check state.
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == PP_WEBSOCKETREADYSTATE_INVALID ||
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      state_ == PP_WEBSOCKETREADYSTATE_CONNECTING)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PP_ERROR_BADARGUMENT;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Just return received message if any received message is queued.
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!received_messages_.empty()) {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    receive_callback_var_ = message;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return DoReceive();
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check state again. In CLOSED state, no more messages will be received.
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == PP_WEBSOCKETREADYSTATE_CLOSED)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PP_ERROR_BADARGUMENT;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns PP_ERROR_FAILED after an error is received and received messages
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is exhausted.
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error_was_received_)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PP_ERROR_FAILED;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Or retain |message| as buffer to store and install |callback|.
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  receive_callback_var_ = message;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  receive_callback_ = callback;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return PP_OK_COMPLETIONPENDING;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int32_t WebSocketResource::SendMessage(const PP_Var& message) {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check state.
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == PP_WEBSOCKETREADYSTATE_INVALID ||
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      state_ == PP_WEBSOCKETREADYSTATE_CONNECTING)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PP_ERROR_BADARGUMENT;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == PP_WEBSOCKETREADYSTATE_CLOSING ||
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      state_ == PP_WEBSOCKETREADYSTATE_CLOSED) {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Handle buffered_amount_after_close_.
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint64_t payload_size = 0;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (message.type == PP_VARTYPE_STRING) {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_refptr<StringVar> message_string = StringVar::FromPPVar(message);
250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (message_string.get())
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        payload_size += message_string->value().length();
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (message.type == PP_VARTYPE_ARRAY_BUFFER) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_refptr<ArrayBufferVar> message_array_buffer =
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ArrayBufferVar::FromPPVar(message);
255868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (message_array_buffer.get())
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        payload_size += message_array_buffer->ByteLength();
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(toyoshim): Support Blob.
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return PP_ERROR_NOTSUPPORTED;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buffered_amount_after_close_ =
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SaturateAdd(buffered_amount_after_close_, GetFrameSize(payload_size));
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PP_ERROR_FAILED;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Send the message.
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (message.type == PP_VARTYPE_STRING) {
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Convert message to std::string, then send it.
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<StringVar> message_string = StringVar::FromPPVar(message);
272868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!message_string.get())
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return PP_ERROR_BADARGUMENT;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Post(RENDERER, PpapiHostMsg_WebSocket_SendText(message_string->value()));
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (message.type == PP_VARTYPE_ARRAY_BUFFER) {
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Convert message to std::vector<uint8_t>, then send it.
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<ArrayBufferVar> message_arraybuffer =
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ArrayBufferVar::FromPPVar(message);
279868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!message_arraybuffer.get())
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return PP_ERROR_BADARGUMENT;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint8_t* message_data = static_cast<uint8_t*>(message_arraybuffer->Map());
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32 message_length = message_arraybuffer->ByteLength();
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<uint8_t> message_vector(message_data,
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        message_data + message_length);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Post(RENDERER, PpapiHostMsg_WebSocket_SendBinary(message_vector));
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(toyoshim): Support Blob.
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PP_ERROR_NOTSUPPORTED;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return PP_OK;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint64_t WebSocketResource::GetBufferedAmount() {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SaturateAdd(buffered_amount_, buffered_amount_after_close_);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint16_t WebSocketResource::GetCloseCode() {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return close_code_;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PP_Var WebSocketResource::GetCloseReason() {
302868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!close_reason_.get())
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return empty_string_->GetPPVar();
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return close_reason_->GetPPVar();
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PP_Bool WebSocketResource::GetCloseWasClean() {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return close_was_clean_;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PP_Var WebSocketResource::GetExtensions() {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return StringVar::StringToPPVar(std::string());
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PP_Var WebSocketResource::GetProtocol() {
316868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!protocol_.get())
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return empty_string_->GetPPVar();
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return protocol_->GetPPVar();
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PP_WebSocketReadyState WebSocketResource::GetReadyState() {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return state_;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PP_Var WebSocketResource::GetURL() {
326868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!url_.get())
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return empty_string_->GetPPVar();
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return url_->GetPPVar();
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketResource::OnReplyReceived(
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ResourceMessageReplyParams& params,
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const IPC::Message& msg) {
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params.sequence()) {
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PluginResource::OnReplyReceived(params, msg);
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPC_BEGIN_MESSAGE_MAP(WebSocketResource, msg)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PpapiPluginMsg_WebSocket_ReceiveTextReply,
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OnPluginMsgReceiveTextReply)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PpapiPluginMsg_WebSocket_ReceiveBinaryReply,
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OnPluginMsgReceiveBinaryReply)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_0(
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PpapiPluginMsg_WebSocket_ErrorReply,
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OnPluginMsgErrorReply)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PpapiPluginMsg_WebSocket_BufferedAmountReply,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OnPluginMsgBufferedAmountReply)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PpapiPluginMsg_WebSocket_StateReply,
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OnPluginMsgStateReply)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PpapiPluginMsg_WebSocket_ClosedReply,
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OnPluginMsgClosedReply)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(NOTREACHED())
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPC_END_MESSAGE_MAP()
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketResource::OnPluginMsgConnectReply(
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ResourceMessageReplyParams& params,
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& url,
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& protocol) {
366558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (!TrackedCallback::IsPending(connect_callback_) ||
367558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      TrackedCallback::IsScheduledToRun(connect_callback_)) {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
369558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32_t result = params.result();
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == PP_OK) {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = PP_WEBSOCKETREADYSTATE_OPEN;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    protocol_ = new StringVar(protocol);
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_ = new StringVar(url);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connect_callback_->Run(params.result());
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketResource::OnPluginMsgCloseReply(
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ResourceMessageReplyParams& params,
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned long buffered_amount,
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool was_clean,
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned short code,
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& reason) {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set close related properties.
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = PP_WEBSOCKETREADYSTATE_CLOSED;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buffered_amount_ = buffered_amount;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  close_was_clean_ = PP_FromBool(was_clean);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  close_code_ = code;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  close_reason_ = new StringVar(reason);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (TrackedCallback::IsPending(receive_callback_)) {
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    receive_callback_var_ = NULL;
395558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if (!TrackedCallback::IsScheduledToRun(receive_callback_))
396558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      receive_callback_->PostRun(PP_ERROR_FAILED);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    receive_callback_ = NULL;
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (TrackedCallback::IsPending(close_callback_)) {
401558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if (!TrackedCallback::IsScheduledToRun(close_callback_))
402558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      close_callback_->PostRun(params.result());
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    close_callback_ = NULL;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketResource::OnPluginMsgReceiveTextReply(
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ResourceMessageReplyParams& params,
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& message) {
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Dispose packets after receiving an error or in invalid state.
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error_was_received_ || !InValidStateToReceive(state_))
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Append received data to queue.
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  received_messages_.push(scoped_refptr<Var>(new StringVar(message)));
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
417558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (!TrackedCallback::IsPending(receive_callback_) ||
418558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      TrackedCallback::IsScheduledToRun(receive_callback_)) {
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
420558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  receive_callback_->Run(DoReceive());
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketResource::OnPluginMsgReceiveBinaryReply(
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ResourceMessageReplyParams& params,
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<uint8_t>& message) {
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Dispose packets after receiving an error or in invalid state.
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error_was_received_ || !InValidStateToReceive(state_))
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Append received data to queue.
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<Var> message_var(
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferVar(
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          message.size(),
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &message.front()));
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  received_messages_.push(message_var);
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
439558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (!TrackedCallback::IsPending(receive_callback_) ||
440558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      TrackedCallback::IsScheduledToRun(receive_callback_)) {
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
442558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  receive_callback_->Run(DoReceive());
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketResource::OnPluginMsgErrorReply(
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ResourceMessageReplyParams& params) {
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  error_was_received_ = true;
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
451558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (!TrackedCallback::IsPending(receive_callback_) ||
452558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      TrackedCallback::IsScheduledToRun(receive_callback_)) {
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
454558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No more text or binary messages will be received. If there is ongoing
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ReceiveMessage(), we must invoke the callback with error code here.
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  receive_callback_var_ = NULL;
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  receive_callback_->Run(PP_ERROR_FAILED);
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketResource::OnPluginMsgBufferedAmountReply(
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ResourceMessageReplyParams& params,
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned long buffered_amount) {
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buffered_amount_ = buffered_amount;
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketResource::OnPluginMsgStateReply(
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ResourceMessageReplyParams& params,
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int32_t state) {
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = static_cast<PP_WebSocketReadyState>(state);
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketResource::OnPluginMsgClosedReply(
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ResourceMessageReplyParams& params,
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned long buffered_amount,
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool was_clean,
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned short code,
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& reason) {
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnPluginMsgCloseReply(params, buffered_amount, was_clean, code, reason);
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int32_t WebSocketResource::DoReceive() {
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!receive_callback_var_)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PP_OK;
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *receive_callback_var_ = received_messages_.front()->GetPPVar();
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  received_messages_.pop();
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  receive_callback_var_ = NULL;
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return PP_OK;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace proxy
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace ppapi
495