Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(108)

Side by Side Diff: webkit/plugins/ppapi/ppb_websocket_impl.cc

Issue 8772001: WebSocket Pepper API: error handling improvement (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase to remote/master Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/plugins/ppapi/ppb_websocket_impl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « webkit/plugins/ppapi/ppb_websocket_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698