| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "webkit/plugins/ppapi/ppb_websocket_impl.h" | |
| 6 | |
| 7 #include <set> | |
| 8 #include <string> | |
| 9 | |
| 10 #include "base/basictypes.h" | |
| 11 #include "googleurl/src/gurl.h" | |
| 12 #include "net/base/net_util.h" | |
| 13 #include "ppapi/c/pp_completion_callback.h" | |
| 14 #include "ppapi/c/pp_errors.h" | |
| 15 #include "ppapi/c/pp_var.h" | |
| 16 #include "ppapi/c/ppb_var.h" | |
| 17 #include "ppapi/c/ppb_var_array_buffer.h" | |
| 18 #include "ppapi/shared_impl/var.h" | |
| 19 #include "ppapi/shared_impl/var_tracker.h" | |
| 20 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" | |
| 21 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h" | |
| 22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebArrayBuffer.h" | |
| 23 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" | |
| 24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h" | |
| 25 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h" | |
| 26 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSocket.h" | |
| 27 #include "webkit/plugins/ppapi/host_array_buffer_var.h" | |
| 28 #include "webkit/plugins/ppapi/host_globals.h" | |
| 29 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" | |
| 30 #include "webkit/plugins/ppapi/resource_helper.h" | |
| 31 | |
| 32 using ppapi::ArrayBufferVar; | |
| 33 using ppapi::PpapiGlobals; | |
| 34 using ppapi::StringVar; | |
| 35 using ppapi::thunk::PPB_WebSocket_API; | |
| 36 using ppapi::TrackedCallback; | |
| 37 using ppapi::Var; | |
| 38 using ppapi::VarTracker; | |
| 39 using WebKit::WebArrayBuffer; | |
| 40 using WebKit::WebDocument; | |
| 41 using WebKit::WebString; | |
| 42 using WebKit::WebSocket; | |
| 43 using WebKit::WebSocketClient; | |
| 44 using WebKit::WebURL; | |
| 45 | |
| 46 const uint32_t kMaxReasonSizeInBytes = 123; | |
| 47 const size_t kHybiBaseFramingOverhead = 2; | |
| 48 const size_t kHybiMaskingKeyLength = 4; | |
| 49 const size_t kMinimumPayloadSizeWithTwoByteExtendedPayloadLength = 126; | |
| 50 const size_t kMinimumPayloadSizeWithEightByteExtendedPayloadLength = 0x10000; | |
| 51 | |
| 52 namespace { | |
| 53 | |
| 54 uint64_t SaturateAdd(uint64_t a, uint64_t b) { | |
| 55 if (kuint64max - a < b) | |
| 56 return kuint64max; | |
| 57 return a + b; | |
| 58 } | |
| 59 | |
| 60 uint64_t GetFrameSize(uint64_t payload_size) { | |
| 61 uint64_t overhead = kHybiBaseFramingOverhead + kHybiMaskingKeyLength; | |
| 62 if (payload_size > kMinimumPayloadSizeWithEightByteExtendedPayloadLength) | |
| 63 overhead += 8; | |
| 64 else if (payload_size > kMinimumPayloadSizeWithTwoByteExtendedPayloadLength) | |
| 65 overhead += 2; | |
| 66 return SaturateAdd(payload_size, overhead); | |
| 67 } | |
| 68 | |
| 69 bool InValidStateToReceive(PP_WebSocketReadyState state) { | |
| 70 return state == PP_WEBSOCKETREADYSTATE_OPEN || | |
| 71 state == PP_WEBSOCKETREADYSTATE_CLOSING; | |
| 72 } | |
| 73 | |
| 74 } // namespace | |
| 75 | |
| 76 namespace webkit { | |
| 77 namespace ppapi { | |
| 78 | |
| 79 PPB_WebSocket_Impl::PPB_WebSocket_Impl(PP_Instance instance) | |
| 80 : Resource(::ppapi::OBJECT_IS_IMPL, instance), | |
| 81 state_(PP_WEBSOCKETREADYSTATE_INVALID), | |
| 82 error_was_received_(false), | |
| 83 receive_callback_var_(NULL), | |
| 84 wait_for_receive_(false), | |
| 85 close_code_(0), | |
| 86 close_was_clean_(PP_FALSE), | |
| 87 empty_string_(new StringVar("", 0)), | |
| 88 buffered_amount_(0), | |
| 89 buffered_amount_after_close_(0) { | |
| 90 } | |
| 91 | |
| 92 PPB_WebSocket_Impl::~PPB_WebSocket_Impl() { | |
| 93 if (websocket_.get()) | |
| 94 websocket_->disconnect(); | |
| 95 } | |
| 96 | |
| 97 // static | |
| 98 PP_Resource PPB_WebSocket_Impl::Create(PP_Instance instance) { | |
| 99 scoped_refptr<PPB_WebSocket_Impl> ws(new PPB_WebSocket_Impl(instance)); | |
| 100 return ws->GetReference(); | |
| 101 } | |
| 102 | |
| 103 PPB_WebSocket_API* PPB_WebSocket_Impl::AsPPB_WebSocket_API() { | |
| 104 return this; | |
| 105 } | |
| 106 | |
| 107 int32_t PPB_WebSocket_Impl::Connect(PP_Var url, | |
| 108 const PP_Var protocols[], | |
| 109 uint32_t protocol_count, | |
| 110 scoped_refptr<TrackedCallback> callback) { | |
| 111 // Check mandatory interfaces. | |
| 112 PluginInstance* plugin_instance = ResourceHelper::GetPluginInstance(this); | |
| 113 DCHECK(plugin_instance); | |
| 114 if (!plugin_instance) | |
| 115 return PP_ERROR_FAILED; | |
| 116 | |
| 117 // Connect() can be called at most once. | |
| 118 if (websocket_.get()) | |
| 119 return PP_ERROR_INPROGRESS; | |
| 120 if (state_ != PP_WEBSOCKETREADYSTATE_INVALID) | |
| 121 return PP_ERROR_INPROGRESS; | |
| 122 state_ = PP_WEBSOCKETREADYSTATE_CLOSED; | |
| 123 | |
| 124 // Validate url and convert it to WebURL. | |
| 125 scoped_refptr<StringVar> url_string = StringVar::FromPPVar(url); | |
| 126 if (!url_string) | |
| 127 return PP_ERROR_BADARGUMENT; | |
| 128 GURL gurl(url_string->value()); | |
| 129 url_ = new StringVar(gurl.spec()); | |
| 130 if (!gurl.is_valid()) | |
| 131 return PP_ERROR_BADARGUMENT; | |
| 132 if (!gurl.SchemeIs("ws") && !gurl.SchemeIs("wss")) | |
| 133 return PP_ERROR_BADARGUMENT; | |
| 134 if (gurl.has_ref()) | |
| 135 return PP_ERROR_BADARGUMENT; | |
| 136 if (!net::IsPortAllowedByDefault(gurl.IntPort())) | |
| 137 return PP_ERROR_BADARGUMENT; | |
| 138 WebURL web_url(gurl); | |
| 139 | |
| 140 // Validate protocols and convert it to WebString. | |
| 141 std::string protocol_string; | |
| 142 std::set<std::string> protocol_set; | |
| 143 for (uint32_t i = 0; i < protocol_count; i++) { | |
| 144 // TODO(toyoshim): Similar function exist in WebKit::WebSocket. | |
| 145 // We must rearrange them into WebKit::WebChannel and share its protocol | |
| 146 // related implementation via WebKit API. | |
| 147 scoped_refptr<StringVar> protocol(StringVar::FromPPVar(protocols[i])); | |
| 148 | |
| 149 // Check invalid and empty entries. | |
| 150 if (!protocol || !protocol->value().length()) | |
| 151 return PP_ERROR_BADARGUMENT; | |
| 152 | |
| 153 // Check duplicated protocol entries. | |
| 154 if (protocol_set.find(protocol->value()) != protocol_set.end()) | |
| 155 return PP_ERROR_BADARGUMENT; | |
| 156 protocol_set.insert(protocol->value()); | |
| 157 | |
| 158 // Check containing characters. | |
| 159 for (std::string::const_iterator it = protocol->value().begin(); | |
| 160 it != protocol->value().end(); | |
| 161 ++it) { | |
| 162 uint8_t character = *it; | |
| 163 // WebSocket specification says "(Subprotocol string must consist of) | |
| 164 // characters in the range U+0021 to U+007E not including separator | |
| 165 // characters as defined in [RFC2616]." | |
| 166 const uint8_t minimumProtocolCharacter = '!'; // U+0021. | |
| 167 const uint8_t maximumProtocolCharacter = '~'; // U+007E. | |
| 168 if (character < minimumProtocolCharacter || | |
| 169 character > maximumProtocolCharacter || | |
| 170 character == '"' || character == '(' || character == ')' || | |
| 171 character == ',' || character == '/' || | |
| 172 (character >= ':' && character <= '@') || // U+003A - U+0040 | |
| 173 (character >= '[' && character <= ']') || // U+005B - u+005D | |
| 174 character == '{' || character == '}') | |
| 175 return PP_ERROR_BADARGUMENT; | |
| 176 } | |
| 177 // Join protocols with the comma separator. | |
| 178 if (i != 0) | |
| 179 protocol_string.append(","); | |
| 180 protocol_string.append(protocol->value()); | |
| 181 } | |
| 182 WebString web_protocols = WebString::fromUTF8(protocol_string); | |
| 183 | |
| 184 // Create WebKit::WebSocket object and connect. | |
| 185 WebDocument document = plugin_instance->container()->element().document(); | |
| 186 websocket_.reset(WebSocket::create(document, this)); | |
| 187 DCHECK(websocket_.get()); | |
| 188 if (!websocket_.get()) | |
| 189 return PP_ERROR_NOTSUPPORTED; | |
| 190 | |
| 191 // Set receiving binary object type. | |
| 192 websocket_->setBinaryType(WebSocket::BinaryTypeArrayBuffer); | |
| 193 | |
| 194 websocket_->connect(web_url, web_protocols); | |
| 195 state_ = PP_WEBSOCKETREADYSTATE_CONNECTING; | |
| 196 | |
| 197 // Install callback. | |
| 198 connect_callback_ = callback; | |
| 199 | |
| 200 return PP_OK_COMPLETIONPENDING; | |
| 201 } | |
| 202 | |
| 203 int32_t PPB_WebSocket_Impl::Close(uint16_t code, | |
| 204 PP_Var reason, | |
| 205 scoped_refptr<TrackedCallback> callback) { | |
| 206 // Check mandarory interfaces. | |
| 207 if (!websocket_.get()) | |
| 208 return PP_ERROR_FAILED; | |
| 209 | |
| 210 // Validate |code| and |reason|. | |
| 211 scoped_refptr<StringVar> reason_string; | |
| 212 WebString web_reason; | |
| 213 WebSocket::CloseEventCode event_code = | |
| 214 static_cast<WebSocket::CloseEventCode>(code); | |
| 215 if (code == PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED) { | |
| 216 // PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED and CloseEventCodeNotSpecified are | |
| 217 // assigned to different values. A conversion is needed if | |
| 218 // PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED is specified. | |
| 219 event_code = WebSocket::CloseEventCodeNotSpecified; | |
| 220 } else { | |
| 221 if (!(code == PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE || | |
| 222 (PP_WEBSOCKETSTATUSCODE_USER_REGISTERED_MIN <= code && | |
| 223 code <= PP_WEBSOCKETSTATUSCODE_USER_PRIVATE_MAX))) | |
| 224 // RFC 6455 limits applications to use reserved connection close code in | |
| 225 // section 7.4.2.. The WebSocket API (http://www.w3.org/TR/websockets/) | |
| 226 // defines this out of range error as InvalidAccessError in JavaScript. | |
| 227 return PP_ERROR_NOACCESS; | |
| 228 | |
| 229 // |reason| must be ignored if it is PP_VARTYPE_UNDEFINED or |code| is | |
| 230 // PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED. | |
| 231 if (reason.type != PP_VARTYPE_UNDEFINED) { | |
| 232 // Validate |reason|. | |
| 233 reason_string = StringVar::FromPPVar(reason); | |
| 234 if (!reason_string || | |
| 235 reason_string->value().size() > kMaxReasonSizeInBytes) | |
| 236 return PP_ERROR_BADARGUMENT; | |
| 237 web_reason = WebString::fromUTF8(reason_string->value()); | |
| 238 } | |
| 239 } | |
| 240 | |
| 241 // Check state. | |
| 242 if (state_ == PP_WEBSOCKETREADYSTATE_CLOSING) | |
| 243 return PP_ERROR_INPROGRESS; | |
| 244 if (state_ == PP_WEBSOCKETREADYSTATE_CLOSED) | |
| 245 return PP_OK; | |
| 246 | |
| 247 // Install |callback|. | |
| 248 close_callback_ = callback; | |
| 249 | |
| 250 // Abort ongoing connect. | |
| 251 if (state_ == PP_WEBSOCKETREADYSTATE_CONNECTING) { | |
| 252 state_ = PP_WEBSOCKETREADYSTATE_CLOSING; | |
| 253 // Need to do a "Post" to avoid reentering the plugin. | |
| 254 connect_callback_->PostAbort(); | |
| 255 connect_callback_ = NULL; | |
| 256 websocket_->fail( | |
| 257 "WebSocket was closed before the connection was established."); | |
| 258 return PP_OK_COMPLETIONPENDING; | |
| 259 } | |
| 260 | |
| 261 // Abort ongoing receive. | |
| 262 if (wait_for_receive_) { | |
| 263 wait_for_receive_ = false; | |
| 264 receive_callback_var_ = NULL; | |
| 265 | |
| 266 // Need to do a "Post" to avoid reentering the plugin. | |
| 267 receive_callback_->PostAbort(); | |
| 268 receive_callback_ = NULL; | |
| 269 } | |
| 270 | |
| 271 // Close connection. | |
| 272 state_ = PP_WEBSOCKETREADYSTATE_CLOSING; | |
| 273 websocket_->close(event_code, web_reason); | |
| 274 | |
| 275 return PP_OK_COMPLETIONPENDING; | |
| 276 } | |
| 277 | |
| 278 int32_t PPB_WebSocket_Impl::ReceiveMessage( | |
| 279 PP_Var* message, | |
| 280 scoped_refptr<TrackedCallback> callback) { | |
| 281 // Check state. | |
| 282 if (state_ == PP_WEBSOCKETREADYSTATE_INVALID || | |
| 283 state_ == PP_WEBSOCKETREADYSTATE_CONNECTING) | |
| 284 return PP_ERROR_BADARGUMENT; | |
| 285 | |
| 286 // Just return received message if any received message is queued. | |
| 287 if (!received_messages_.empty()) { | |
| 288 receive_callback_var_ = message; | |
| 289 return DoReceive(); | |
| 290 } | |
| 291 | |
| 292 // Check state again. In CLOSED state, no more messages will be received. | |
| 293 if (state_ == PP_WEBSOCKETREADYSTATE_CLOSED) | |
| 294 return PP_ERROR_BADARGUMENT; | |
| 295 | |
| 296 // Returns PP_ERROR_FAILED after an error is received and received messages | |
| 297 // is exhausted. | |
| 298 if (error_was_received_) | |
| 299 return PP_ERROR_FAILED; | |
| 300 | |
| 301 // Or retain |message| as buffer to store and install |callback|. | |
| 302 wait_for_receive_ = true; | |
| 303 receive_callback_var_ = message; | |
| 304 receive_callback_ = callback; | |
| 305 | |
| 306 return PP_OK_COMPLETIONPENDING; | |
| 307 } | |
| 308 | |
| 309 int32_t PPB_WebSocket_Impl::SendMessage(PP_Var message) { | |
| 310 // Check mandatory interfaces. | |
| 311 if (!websocket_.get()) | |
| 312 return PP_ERROR_FAILED; | |
| 313 | |
| 314 // Check state. | |
| 315 if (state_ == PP_WEBSOCKETREADYSTATE_INVALID || | |
| 316 state_ == PP_WEBSOCKETREADYSTATE_CONNECTING) | |
| 317 return PP_ERROR_BADARGUMENT; | |
| 318 | |
| 319 if (state_ == PP_WEBSOCKETREADYSTATE_CLOSING || | |
| 320 state_ == PP_WEBSOCKETREADYSTATE_CLOSED) { | |
| 321 // Handle buffered_amount_after_close_. | |
| 322 uint64_t payload_size = 0; | |
| 323 if (message.type == PP_VARTYPE_STRING) { | |
| 324 scoped_refptr<StringVar> message_string = StringVar::FromPPVar(message); | |
| 325 if (message_string) | |
| 326 payload_size += message_string->value().length(); | |
| 327 } else if (message.type == PP_VARTYPE_ARRAY_BUFFER) { | |
| 328 scoped_refptr<ArrayBufferVar> message_array_buffer = | |
| 329 ArrayBufferVar::FromPPVar(message); | |
| 330 if (message_array_buffer) | |
| 331 payload_size += message_array_buffer->ByteLength(); | |
| 332 } else { | |
| 333 // TODO(toyoshim): Support Blob. | |
| 334 return PP_ERROR_NOTSUPPORTED; | |
| 335 } | |
| 336 | |
| 337 buffered_amount_after_close_ = | |
| 338 SaturateAdd(buffered_amount_after_close_, GetFrameSize(payload_size)); | |
| 339 | |
| 340 return PP_ERROR_FAILED; | |
| 341 } | |
| 342 | |
| 343 // Send the message. | |
| 344 if (message.type == PP_VARTYPE_STRING) { | |
| 345 // Convert message to WebString. | |
| 346 scoped_refptr<StringVar> message_string = StringVar::FromPPVar(message); | |
| 347 if (!message_string) | |
| 348 return PP_ERROR_BADARGUMENT; | |
| 349 WebString web_message = WebString::fromUTF8(message_string->value()); | |
| 350 if (!websocket_->sendText(web_message)) | |
| 351 return PP_ERROR_BADARGUMENT; | |
| 352 } else if (message.type == PP_VARTYPE_ARRAY_BUFFER) { | |
| 353 // Convert message to WebArrayBuffer. | |
| 354 scoped_refptr<HostArrayBufferVar> host_message = | |
| 355 static_cast<HostArrayBufferVar*>(ArrayBufferVar::FromPPVar(message)); | |
| 356 if (!host_message) | |
| 357 return PP_ERROR_BADARGUMENT; | |
| 358 WebArrayBuffer& web_message = host_message->webkit_buffer(); | |
| 359 if (!websocket_->sendArrayBuffer(web_message)) | |
| 360 return PP_ERROR_BADARGUMENT; | |
| 361 } else { | |
| 362 // TODO(toyoshim): Support Blob. | |
| 363 return PP_ERROR_NOTSUPPORTED; | |
| 364 } | |
| 365 | |
| 366 return PP_OK; | |
| 367 } | |
| 368 | |
| 369 uint64_t PPB_WebSocket_Impl::GetBufferedAmount() { | |
| 370 return SaturateAdd(buffered_amount_, buffered_amount_after_close_); | |
| 371 } | |
| 372 | |
| 373 uint16_t PPB_WebSocket_Impl::GetCloseCode() { | |
| 374 return close_code_; | |
| 375 } | |
| 376 | |
| 377 PP_Var PPB_WebSocket_Impl::GetCloseReason() { | |
| 378 if (!close_reason_) | |
| 379 return empty_string_->GetPPVar(); | |
| 380 return close_reason_->GetPPVar(); | |
| 381 } | |
| 382 | |
| 383 PP_Bool PPB_WebSocket_Impl::GetCloseWasClean() { | |
| 384 return close_was_clean_; | |
| 385 } | |
| 386 | |
| 387 PP_Var PPB_WebSocket_Impl::GetExtensions() { | |
| 388 // Check mandatory interfaces. | |
| 389 if (!websocket_.get()) | |
| 390 return empty_string_->GetPPVar(); | |
| 391 | |
| 392 std::string extensions = websocket_->extensions().utf8(); | |
| 393 return StringVar::StringToPPVar(extensions); | |
| 394 } | |
| 395 | |
| 396 PP_Var PPB_WebSocket_Impl::GetProtocol() { | |
| 397 // Check mandatory interfaces. | |
| 398 if (!websocket_.get()) | |
| 399 return empty_string_->GetPPVar(); | |
| 400 | |
| 401 std::string protocol = websocket_->subprotocol().utf8(); | |
| 402 return StringVar::StringToPPVar(protocol); | |
| 403 } | |
| 404 | |
| 405 PP_WebSocketReadyState PPB_WebSocket_Impl::GetReadyState() { | |
| 406 return state_; | |
| 407 } | |
| 408 | |
| 409 PP_Var PPB_WebSocket_Impl::GetURL() { | |
| 410 if (!url_) | |
| 411 return empty_string_->GetPPVar(); | |
| 412 return url_->GetPPVar(); | |
| 413 } | |
| 414 | |
| 415 void PPB_WebSocket_Impl::didConnect() { | |
| 416 DCHECK_EQ(PP_WEBSOCKETREADYSTATE_CONNECTING, state_); | |
| 417 state_ = PP_WEBSOCKETREADYSTATE_OPEN; | |
| 418 TrackedCallback::ClearAndRun(&connect_callback_, PP_OK); | |
| 419 } | |
| 420 | |
| 421 void PPB_WebSocket_Impl::didReceiveMessage(const WebString& message) { | |
| 422 // Dispose packets after receiving an error or in invalid state. | |
| 423 if (error_was_received_ || !InValidStateToReceive(state_)) | |
| 424 return; | |
| 425 | |
| 426 // Append received data to queue. | |
| 427 std::string string = message.utf8(); | |
| 428 received_messages_.push(scoped_refptr<Var>(new StringVar(string))); | |
| 429 | |
| 430 if (!wait_for_receive_) | |
| 431 return; | |
| 432 | |
| 433 TrackedCallback::ClearAndRun(&receive_callback_, DoReceive()); | |
| 434 } | |
| 435 | |
| 436 void PPB_WebSocket_Impl::didReceiveArrayBuffer( | |
| 437 const WebArrayBuffer& binaryData) { | |
| 438 // Dispose packets after receiving an error or in invalid state. | |
| 439 if (error_was_received_ || !InValidStateToReceive(state_)) | |
| 440 return; | |
| 441 | |
| 442 // Append received data to queue. | |
| 443 received_messages_.push( | |
| 444 scoped_refptr<Var>(new HostArrayBufferVar(binaryData))); | |
| 445 | |
| 446 if (!wait_for_receive_) | |
| 447 return; | |
| 448 | |
| 449 TrackedCallback::ClearAndRun(&receive_callback_, DoReceive()); | |
| 450 } | |
| 451 | |
| 452 void PPB_WebSocket_Impl::didReceiveMessageError() { | |
| 453 // Ignore error notification in invalid state. | |
| 454 if (!InValidStateToReceive(state_)) | |
| 455 return; | |
| 456 | |
| 457 // Records the error, then stops receiving any frames after this error. | |
| 458 // The error will be notified after all queued messages are read via | |
| 459 // ReceiveMessage(). | |
| 460 error_was_received_ = true; | |
| 461 if (!wait_for_receive_) | |
| 462 return; | |
| 463 | |
| 464 // But, if no messages are queued and ReceiveMessage() is now on going. | |
| 465 // We must invoke the callback with error code here. | |
| 466 wait_for_receive_ = false; | |
| 467 receive_callback_var_ = NULL; | |
| 468 TrackedCallback::ClearAndRun(&receive_callback_, PP_ERROR_FAILED); | |
| 469 } | |
| 470 | |
| 471 void PPB_WebSocket_Impl::didUpdateBufferedAmount( | |
| 472 unsigned long buffered_amount) { | |
| 473 if (state_ == PP_WEBSOCKETREADYSTATE_CLOSED) | |
| 474 return; | |
| 475 buffered_amount_ = buffered_amount; | |
| 476 } | |
| 477 | |
| 478 void PPB_WebSocket_Impl::didStartClosingHandshake() { | |
| 479 state_ = PP_WEBSOCKETREADYSTATE_CLOSING; | |
| 480 } | |
| 481 | |
| 482 void PPB_WebSocket_Impl::didClose(unsigned long unhandled_buffered_amount, | |
| 483 ClosingHandshakeCompletionStatus status, | |
| 484 unsigned short code, | |
| 485 const WebString& reason) { | |
| 486 // Store code and reason. | |
| 487 close_code_ = code; | |
| 488 close_reason_ = new StringVar(reason.utf8()); | |
| 489 | |
| 490 // Set close_was_clean_. | |
| 491 bool was_clean = | |
| 492 state_ == PP_WEBSOCKETREADYSTATE_CLOSING && | |
| 493 !unhandled_buffered_amount && | |
| 494 status == WebSocketClient::ClosingHandshakeComplete; | |
| 495 close_was_clean_ = was_clean ? PP_TRUE : PP_FALSE; | |
| 496 | |
| 497 // Update buffered_amount_. | |
| 498 buffered_amount_ = unhandled_buffered_amount; | |
| 499 | |
| 500 // Handle state transition and invoking callback. | |
| 501 DCHECK_NE(PP_WEBSOCKETREADYSTATE_CLOSED, state_); | |
| 502 PP_WebSocketReadyState state = state_; | |
| 503 state_ = PP_WEBSOCKETREADYSTATE_CLOSED; | |
| 504 | |
| 505 // User handlers may release WebSocket PP_Resource in the following | |
| 506 // completion callbacks. Retain |this| here to assure that this object | |
| 507 // keep on being valid in this function. | |
| 508 scoped_refptr<PPB_WebSocket_Impl> retain_this(this); | |
| 509 if (state == PP_WEBSOCKETREADYSTATE_CONNECTING) | |
| 510 TrackedCallback::ClearAndRun(&connect_callback_, PP_ERROR_FAILED); | |
| 511 | |
| 512 if (wait_for_receive_) { | |
| 513 wait_for_receive_ = false; | |
| 514 receive_callback_var_ = NULL; | |
| 515 TrackedCallback::ClearAndRun(&receive_callback_, PP_ERROR_FAILED); | |
| 516 } | |
| 517 | |
| 518 if ((state == PP_WEBSOCKETREADYSTATE_CLOSING) && close_callback_.get()) | |
| 519 TrackedCallback::ClearAndRun(&close_callback_, PP_OK); | |
| 520 | |
| 521 // Disconnect. | |
| 522 if (websocket_.get()) | |
| 523 websocket_->disconnect(); | |
| 524 } | |
| 525 | |
| 526 int32_t PPB_WebSocket_Impl::DoReceive() { | |
| 527 if (!receive_callback_var_) | |
| 528 return PP_OK; | |
| 529 | |
| 530 *receive_callback_var_ = received_messages_.front()->GetPPVar(); | |
| 531 received_messages_.pop(); | |
| 532 receive_callback_var_ = NULL; | |
| 533 wait_for_receive_ = false; | |
| 534 return PP_OK; | |
| 535 } | |
| 536 | |
| 537 } // namespace ppapi | |
| 538 } // namespace webkit | |
| OLD | NEW |