OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "webkit/plugins/ppapi/ppb_websocket_impl.h" | 5 #include "webkit/plugins/ppapi/ppb_websocket_impl.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 return 0; | 57 return 0; |
58 | 58 |
59 uint64_t overhead = kHybiBaseFramingOverhead + kHybiMaskingKeyLength; | 59 uint64_t overhead = kHybiBaseFramingOverhead + kHybiMaskingKeyLength; |
60 if (payload_size > kMinimumPayloadSizeWithEightByteExtendedPayloadLength) | 60 if (payload_size > kMinimumPayloadSizeWithEightByteExtendedPayloadLength) |
61 overhead += 8; | 61 overhead += 8; |
62 else if (payload_size > kMinimumPayloadSizeWithTwoByteExtendedPayloadLength) | 62 else if (payload_size > kMinimumPayloadSizeWithTwoByteExtendedPayloadLength) |
63 overhead += 2; | 63 overhead += 2; |
64 return SaturateAdd(payload_size, overhead); | 64 return SaturateAdd(payload_size, overhead); |
65 } | 65 } |
66 | 66 |
| 67 bool InValidStateToReceive(PP_WebSocketReadyState_Dev state) { |
| 68 return state == PP_WEBSOCKETREADYSTATE_OPEN_DEV || |
| 69 state == PP_WEBSOCKETREADYSTATE_CLOSING_DEV; |
| 70 } |
| 71 |
67 } // namespace | 72 } // namespace |
68 | 73 |
69 namespace webkit { | 74 namespace webkit { |
70 namespace ppapi { | 75 namespace ppapi { |
71 | 76 |
72 PPB_WebSocket_Impl::PPB_WebSocket_Impl(PP_Instance instance) | 77 PPB_WebSocket_Impl::PPB_WebSocket_Impl(PP_Instance instance) |
73 : Resource(instance), | 78 : Resource(instance), |
74 state_(PP_WEBSOCKETREADYSTATE_INVALID_DEV), | 79 state_(PP_WEBSOCKETREADYSTATE_INVALID_DEV), |
| 80 error_was_received_(false), |
75 receive_callback_var_(NULL), | 81 receive_callback_var_(NULL), |
76 wait_for_receive_(false), | 82 wait_for_receive_(false), |
77 close_code_(0), | 83 close_code_(0), |
78 close_was_clean_(PP_FALSE), | 84 close_was_clean_(PP_FALSE), |
79 buffered_amount_(0), | 85 buffered_amount_(0), |
80 buffered_amount_after_close_(0) { | 86 buffered_amount_after_close_(0) { |
81 empty_string_ = new StringVar( | 87 empty_string_ = new StringVar( |
82 PpapiGlobals::Get()->GetModuleForInstance(instance), "", 0); | 88 PpapiGlobals::Get()->GetModuleForInstance(instance), "", 0); |
83 } | 89 } |
84 | 90 |
(...skipping 30 matching lines...) Expand all Loading... |
115 if (!plugin_instance) | 121 if (!plugin_instance) |
116 return PP_ERROR_FAILED; | 122 return PP_ERROR_FAILED; |
117 | 123 |
118 // Connect() can be called at most once. | 124 // Connect() can be called at most once. |
119 if (websocket_.get()) | 125 if (websocket_.get()) |
120 return PP_ERROR_INPROGRESS; | 126 return PP_ERROR_INPROGRESS; |
121 if (state_ != PP_WEBSOCKETREADYSTATE_INVALID_DEV) | 127 if (state_ != PP_WEBSOCKETREADYSTATE_INVALID_DEV) |
122 return PP_ERROR_INPROGRESS; | 128 return PP_ERROR_INPROGRESS; |
123 state_ = PP_WEBSOCKETREADYSTATE_CLOSED_DEV; | 129 state_ = PP_WEBSOCKETREADYSTATE_CLOSED_DEV; |
124 | 130 |
125 // Validate |callback| (Doesn't support blocking callback) | |
126 if (!callback.func) | |
127 return PP_ERROR_BLOCKS_MAIN_THREAD; | |
128 | |
129 // Validate url and convert it to WebURL. | 131 // Validate url and convert it to WebURL. |
130 scoped_refptr<StringVar> url_string = StringVar::FromPPVar(url); | 132 scoped_refptr<StringVar> url_string = StringVar::FromPPVar(url); |
131 if (!url_string) | 133 if (!url_string) |
132 return PP_ERROR_BADARGUMENT; | 134 return PP_ERROR_BADARGUMENT; |
133 GURL gurl(url_string->value()); | 135 GURL gurl(url_string->value()); |
134 url_ = new StringVar( | 136 url_ = new StringVar( |
135 PpapiGlobals::Get()->GetModuleForInstance(pp_instance()), gurl.spec()); | 137 PpapiGlobals::Get()->GetModuleForInstance(pp_instance()), gurl.spec()); |
136 if (!gurl.is_valid()) | 138 if (!gurl.is_valid()) |
137 return PP_ERROR_BADARGUMENT; | 139 return PP_ERROR_BADARGUMENT; |
138 if (!gurl.SchemeIs("ws") && !gurl.SchemeIs("wss")) | 140 if (!gurl.SchemeIs("ws") && !gurl.SchemeIs("wss")) |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
171 (character >= '[' && character <= ']') || // U+005B - u+005D | 173 (character >= '[' && character <= ']') || // U+005B - u+005D |
172 character == '{' || character == '}') | 174 character == '{' || character == '}') |
173 return PP_ERROR_BADARGUMENT; | 175 return PP_ERROR_BADARGUMENT; |
174 } | 176 } |
175 if (i != 0) | 177 if (i != 0) |
176 protocol_string.append(","); | 178 protocol_string.append(","); |
177 protocol_string.append(string_var->value()); | 179 protocol_string.append(string_var->value()); |
178 } | 180 } |
179 WebString web_protocols = WebString::fromUTF8(protocol_string); | 181 WebString web_protocols = WebString::fromUTF8(protocol_string); |
180 | 182 |
181 // Create WebKit::WebSocket object. | 183 // Validate |callback| (Doesn't support blocking callback) |
| 184 if (!callback.func) |
| 185 return PP_ERROR_BLOCKS_MAIN_THREAD; |
| 186 |
| 187 // Create WebKit::WebSocket object and connect. |
182 WebDocument document = plugin_instance->container()->element().document(); | 188 WebDocument document = plugin_instance->container()->element().document(); |
183 websocket_.reset(WebSocket::create(document, this)); | 189 websocket_.reset(WebSocket::create(document, this)); |
184 DCHECK(websocket_.get()); | 190 DCHECK(websocket_.get()); |
185 if (!websocket_.get()) | 191 if (!websocket_.get()) |
186 return PP_ERROR_NOTSUPPORTED; | 192 return PP_ERROR_NOTSUPPORTED; |
187 | 193 |
188 websocket_->connect(web_url, web_protocols); | 194 websocket_->connect(web_url, web_protocols); |
189 state_ = PP_WEBSOCKETREADYSTATE_CONNECTING_DEV; | 195 state_ = PP_WEBSOCKETREADYSTATE_CONNECTING_DEV; |
190 | 196 |
191 // Install callback. | 197 // Install callback. |
192 connect_callback_ = callback; | 198 connect_callback_ = callback; |
193 | 199 |
194 return PP_OK_COMPLETIONPENDING; | 200 return PP_OK_COMPLETIONPENDING; |
195 } | 201 } |
196 | 202 |
197 int32_t PPB_WebSocket_Impl::Close(uint16_t code, | 203 int32_t PPB_WebSocket_Impl::Close(uint16_t code, |
198 PP_Var reason, | 204 PP_Var reason, |
199 PP_CompletionCallback callback) { | 205 PP_CompletionCallback callback) { |
200 // Check mandarory interfaces. | 206 // Check mandarory interfaces. |
201 if (!websocket_.get()) | 207 if (!websocket_.get()) |
202 return PP_ERROR_FAILED; | 208 return PP_ERROR_FAILED; |
203 | 209 |
204 // Validate |callback| (Doesn't support blocking callback) | |
205 if (!callback.func) | |
206 return PP_ERROR_BLOCKS_MAIN_THREAD; | |
207 | |
208 // Validate |code|. | 210 // Validate |code|. |
209 if (code != WebSocket::CloseEventCodeNotSpecified) { | 211 if (code != WebSocket::CloseEventCodeNotSpecified) { |
210 if (!(code == WebSocket::CloseEventCodeNormalClosure || | 212 if (!(code == WebSocket::CloseEventCodeNormalClosure || |
211 (WebSocket::CloseEventCodeMinimumUserDefined <= code && | 213 (WebSocket::CloseEventCodeMinimumUserDefined <= code && |
212 code <= WebSocket::CloseEventCodeMaximumUserDefined))) | 214 code <= WebSocket::CloseEventCodeMaximumUserDefined))) |
213 return PP_ERROR_NOACCESS; | 215 return PP_ERROR_NOACCESS; |
214 } | 216 } |
| 217 |
215 // Validate |reason|. | 218 // Validate |reason|. |
216 // TODO(toyoshim): Returns PP_ERROR_BADARGUMENT if |reason| contains any | 219 // TODO(toyoshim): Returns PP_ERROR_BADARGUMENT if |reason| contains any |
217 // surrogates. | 220 // surrogates. |
218 scoped_refptr<StringVar> reason_string = StringVar::FromPPVar(reason); | 221 scoped_refptr<StringVar> reason_string = StringVar::FromPPVar(reason); |
219 if (!reason_string || reason_string->value().size() > kMaxReasonSizeInBytes) | 222 if (!reason_string || reason_string->value().size() > kMaxReasonSizeInBytes) |
220 return PP_ERROR_BADARGUMENT; | 223 return PP_ERROR_BADARGUMENT; |
221 | 224 |
222 // Check state. | 225 // Check state. |
223 if (state_ == PP_WEBSOCKETREADYSTATE_CLOSING_DEV || | 226 if (state_ == PP_WEBSOCKETREADYSTATE_CLOSING_DEV || |
224 state_ == PP_WEBSOCKETREADYSTATE_CLOSED_DEV) | 227 state_ == PP_WEBSOCKETREADYSTATE_CLOSED_DEV) |
225 return PP_ERROR_INPROGRESS; | 228 return PP_ERROR_INPROGRESS; |
226 | 229 |
| 230 // Validate |callback| (Doesn't support blocking callback) |
| 231 if (!callback.func) |
| 232 return PP_ERROR_BLOCKS_MAIN_THREAD; |
| 233 |
227 // Install |callback|. | 234 // Install |callback|. |
228 close_callback_ = callback; | 235 close_callback_ = callback; |
229 | 236 |
230 if (state_ == PP_WEBSOCKETREADYSTATE_CONNECTING_DEV) { | 237 if (state_ == PP_WEBSOCKETREADYSTATE_CONNECTING_DEV) { |
231 state_ = PP_WEBSOCKETREADYSTATE_CLOSING_DEV; | 238 state_ = PP_WEBSOCKETREADYSTATE_CLOSING_DEV; |
232 PP_RunAndClearCompletionCallback(&connect_callback_, PP_ERROR_ABORTED); | 239 PP_RunAndClearCompletionCallback(&connect_callback_, PP_ERROR_ABORTED); |
233 websocket_->fail( | 240 websocket_->fail( |
234 "WebSocket was closed before the connection was established."); | 241 "WebSocket was closed before the connection was established."); |
235 return PP_OK_COMPLETIONPENDING; | 242 return PP_OK_COMPLETIONPENDING; |
236 } | 243 } |
237 | 244 |
| 245 // Close connection. |
238 state_ = PP_WEBSOCKETREADYSTATE_CLOSING_DEV; | 246 state_ = PP_WEBSOCKETREADYSTATE_CLOSING_DEV; |
239 WebString web_reason = WebString::fromUTF8(reason_string->value()); | 247 WebString web_reason = WebString::fromUTF8(reason_string->value()); |
240 websocket_->close(code, web_reason); | 248 websocket_->close(code, web_reason); |
241 | 249 |
242 return PP_OK_COMPLETIONPENDING; | 250 return PP_OK_COMPLETIONPENDING; |
243 } | 251 } |
244 | 252 |
245 int32_t PPB_WebSocket_Impl::ReceiveMessage(PP_Var* message, | 253 int32_t PPB_WebSocket_Impl::ReceiveMessage(PP_Var* message, |
246 PP_CompletionCallback callback) { | 254 PP_CompletionCallback callback) { |
247 // Check state. | 255 // Check state. |
248 if (state_ == PP_WEBSOCKETREADYSTATE_INVALID_DEV || | 256 if (state_ == PP_WEBSOCKETREADYSTATE_INVALID_DEV || |
249 state_ == PP_WEBSOCKETREADYSTATE_CONNECTING_DEV) | 257 state_ == PP_WEBSOCKETREADYSTATE_CONNECTING_DEV) |
250 return PP_ERROR_BADARGUMENT; | 258 return PP_ERROR_BADARGUMENT; |
251 | 259 |
252 // Just return received message if any received message is queued. | 260 // Just return received message if any received message is queued. |
253 if (!received_messages_.empty()) | 261 if (!received_messages_.empty()) |
254 return DoReceive(); | 262 return DoReceive(); |
255 | 263 |
| 264 // Returns PP_ERROR_FAILED after an error is received and received messages |
| 265 // is exhausted. |
| 266 if (error_was_received_) |
| 267 return PP_ERROR_FAILED; |
| 268 |
| 269 // Validate |callback| (Doesn't support blocking callback) |
| 270 if (!callback.func) |
| 271 return PP_ERROR_BLOCKS_MAIN_THREAD; |
| 272 |
256 // Or retain |message| as buffer to store and install |callback|. | 273 // Or retain |message| as buffer to store and install |callback|. |
257 wait_for_receive_ = true; | 274 wait_for_receive_ = true; |
258 receive_callback_var_ = message; | 275 receive_callback_var_ = message; |
259 receive_callback_ = callback; | 276 receive_callback_ = callback; |
260 | 277 |
261 return PP_OK_COMPLETIONPENDING; | 278 return PP_OK_COMPLETIONPENDING; |
262 } | 279 } |
263 | 280 |
264 int32_t PPB_WebSocket_Impl::SendMessage(PP_Var message) { | 281 int32_t PPB_WebSocket_Impl::SendMessage(PP_Var message) { |
265 // Check mandatory interfaces. | 282 // Check mandatory interfaces. |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
350 return url_->GetPPVar(); | 367 return url_->GetPPVar(); |
351 } | 368 } |
352 | 369 |
353 void PPB_WebSocket_Impl::didConnect() { | 370 void PPB_WebSocket_Impl::didConnect() { |
354 DCHECK_EQ(PP_WEBSOCKETREADYSTATE_CONNECTING_DEV, state_); | 371 DCHECK_EQ(PP_WEBSOCKETREADYSTATE_CONNECTING_DEV, state_); |
355 state_ = PP_WEBSOCKETREADYSTATE_OPEN_DEV; | 372 state_ = PP_WEBSOCKETREADYSTATE_OPEN_DEV; |
356 PP_RunAndClearCompletionCallback(&connect_callback_, PP_OK); | 373 PP_RunAndClearCompletionCallback(&connect_callback_, PP_OK); |
357 } | 374 } |
358 | 375 |
359 void PPB_WebSocket_Impl::didReceiveMessage(const WebString& message) { | 376 void PPB_WebSocket_Impl::didReceiveMessage(const WebString& message) { |
| 377 // Dispose packets after receiving an error or in invalid state. |
| 378 if (error_was_received_ || !InValidStateToReceive(state_)) |
| 379 return; |
| 380 |
360 // Append received data to queue. | 381 // Append received data to queue. |
361 std::string string = message.utf8(); | 382 std::string string = message.utf8(); |
362 PP_Var var = StringVar::StringToPPVar( | 383 PP_Var var = StringVar::StringToPPVar( |
363 PpapiGlobals::Get()->GetModuleForInstance(pp_instance()), string); | 384 PpapiGlobals::Get()->GetModuleForInstance(pp_instance()), string); |
364 received_messages_.push(var); | 385 received_messages_.push(var); |
365 | 386 |
366 if (!wait_for_receive_) | 387 if (!wait_for_receive_) |
367 return; | 388 return; |
368 | 389 |
369 PP_RunAndClearCompletionCallback(&receive_callback_, DoReceive()); | 390 PP_RunAndClearCompletionCallback(&receive_callback_, DoReceive()); |
370 } | 391 } |
371 | 392 |
372 void PPB_WebSocket_Impl::didReceiveBinaryData(const WebData& binaryData) { | 393 void PPB_WebSocket_Impl::didReceiveBinaryData(const WebData& binaryData) { |
| 394 // Dispose packets after receiving an error or in invalid state. |
| 395 if (error_was_received_ || !InValidStateToReceive(state_)) |
| 396 return; |
| 397 |
| 398 // TODO(toyoshim): Support to receive binary data. |
373 DLOG(INFO) << "didReceiveBinaryData is not implemented yet."; | 399 DLOG(INFO) << "didReceiveBinaryData is not implemented yet."; |
374 // TODO(toyoshim): Support to receive binary data. | |
375 } | 400 } |
376 | 401 |
377 void PPB_WebSocket_Impl::didReceiveMessageError() { | 402 void PPB_WebSocket_Impl::didReceiveMessageError() { |
378 // TODO(toyoshim): Must implement. | 403 // Ignore error notification in invalid state. |
379 DLOG(INFO) << "didReceiveMessageError is not implemented yet."; | 404 if (!InValidStateToReceive(state_)) |
| 405 return; |
| 406 |
| 407 // Records the error, then stops receiving any frames after this error. |
| 408 // The error will be notified after all queued messages are read via |
| 409 // ReceiveMessage(). |
| 410 error_was_received_ = true; |
| 411 if (!wait_for_receive_) |
| 412 return; |
| 413 |
| 414 // But, if no messages are queued and ReceiveMessage() is now on going. |
| 415 // We must invoke the callback with error code here. |
| 416 wait_for_receive_ = false; |
| 417 PP_RunAndClearCompletionCallback(&receive_callback_, PP_ERROR_FAILED); |
380 } | 418 } |
381 | 419 |
382 void PPB_WebSocket_Impl::didUpdateBufferedAmount( | 420 void PPB_WebSocket_Impl::didUpdateBufferedAmount( |
383 unsigned long buffered_amount) { | 421 unsigned long buffered_amount) { |
384 if (state_ == PP_WEBSOCKETREADYSTATE_CLOSED_DEV) | 422 if (state_ == PP_WEBSOCKETREADYSTATE_CLOSED_DEV) |
385 return; | 423 return; |
386 buffered_amount_ = buffered_amount; | 424 buffered_amount_ = buffered_amount; |
387 } | 425 } |
388 | 426 |
389 void PPB_WebSocket_Impl::didStartClosingHandshake() { | 427 void PPB_WebSocket_Impl::didStartClosingHandshake() { |
390 // TODO(toyoshim): Must implement. | 428 state_ = PP_WEBSOCKETREADYSTATE_CLOSING_DEV; |
391 DLOG(INFO) << "didStartClosingHandshake is not implemented yet."; | |
392 } | 429 } |
393 | 430 |
394 void PPB_WebSocket_Impl::didClose(unsigned long buffered_amount, | 431 void PPB_WebSocket_Impl::didClose(unsigned long unhandled_buffered_amount, |
395 ClosingHandshakeCompletionStatus status, | 432 ClosingHandshakeCompletionStatus status, |
396 unsigned short code, | 433 unsigned short code, |
397 const WebString& reason) { | 434 const WebString& reason) { |
398 // Store code and reason. | 435 // Store code and reason. |
399 close_code_ = code; | 436 close_code_ = code; |
400 std::string reason_string = reason.utf8(); | 437 std::string reason_string = reason.utf8(); |
401 close_reason_ = new StringVar( | 438 close_reason_ = new StringVar( |
402 PpapiGlobals::Get()->GetModuleForInstance(pp_instance()), reason_string); | 439 PpapiGlobals::Get()->GetModuleForInstance(pp_instance()), reason_string); |
403 | 440 |
404 // TODO(toyoshim): Set close_was_clean_. | 441 // Set close_was_clean_. |
| 442 bool was_clean = |
| 443 state_ == PP_WEBSOCKETREADYSTATE_CLOSING_DEV && |
| 444 !unhandled_buffered_amount && |
| 445 status == WebSocketClient::ClosingHandshakeComplete; |
| 446 close_was_clean_ = was_clean ? PP_TRUE : PP_FALSE; |
| 447 |
| 448 // Update buffered_amount_. |
| 449 buffered_amount_ = unhandled_buffered_amount; |
405 | 450 |
406 // Handle state transition and invoking callback. | 451 // Handle state transition and invoking callback. |
407 DCHECK_NE(PP_WEBSOCKETREADYSTATE_CLOSED_DEV, state_); | 452 DCHECK_NE(PP_WEBSOCKETREADYSTATE_CLOSED_DEV, state_); |
408 PP_WebSocketReadyState_Dev state = state_; | 453 PP_WebSocketReadyState_Dev state = state_; |
409 state_ = PP_WEBSOCKETREADYSTATE_CLOSED_DEV; | 454 state_ = PP_WEBSOCKETREADYSTATE_CLOSED_DEV; |
410 | 455 |
411 // Update buffered_amount_. | |
412 buffered_amount_ = buffered_amount; | |
413 | |
414 if (state == PP_WEBSOCKETREADYSTATE_CONNECTING_DEV) | 456 if (state == PP_WEBSOCKETREADYSTATE_CONNECTING_DEV) |
415 PP_RunAndClearCompletionCallback(&connect_callback_, PP_OK); | 457 PP_RunAndClearCompletionCallback(&connect_callback_, PP_OK); |
416 | 458 |
417 if (state == PP_WEBSOCKETREADYSTATE_CLOSING_DEV) | 459 if (state == PP_WEBSOCKETREADYSTATE_CLOSING_DEV) |
418 PP_RunAndClearCompletionCallback(&close_callback_, PP_OK); | 460 PP_RunAndClearCompletionCallback(&close_callback_, PP_OK); |
| 461 |
| 462 // Disconnect. |
| 463 if (websocket_.get()) |
| 464 websocket_->disconnect(); |
419 } | 465 } |
420 | 466 |
421 int32_t PPB_WebSocket_Impl::DoReceive() { | 467 int32_t PPB_WebSocket_Impl::DoReceive() { |
422 // TODO(toyoshim): Check state. | |
423 | |
424 if (!receive_callback_var_) | 468 if (!receive_callback_var_) |
425 return PP_OK; | 469 return PP_OK; |
426 | 470 |
427 *receive_callback_var_ = received_messages_.front(); | 471 *receive_callback_var_ = received_messages_.front(); |
428 received_messages_.pop(); | 472 received_messages_.pop(); |
429 receive_callback_var_ = NULL; | 473 receive_callback_var_ = NULL; |
430 wait_for_receive_ = false; | 474 wait_for_receive_ = false; |
431 return PP_OK; | 475 return PP_OK; |
432 } | 476 } |
433 | 477 |
434 } // namespace ppapi | 478 } // namespace ppapi |
435 } // namespace webkit | 479 } // namespace webkit |
OLD | NEW |