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

Side by Side Diff: runtime/bin/websocket_impl.dart

Issue 10907047: Use onClosed instead of onError in the WebSocket classes. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Review update. Created 8 years, 3 months 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 | « runtime/bin/websocket.dart ('k') | tests/standalone/io/web_socket_test.dart » ('j') | 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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 const String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; 5 const String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
6 6
7 class _WebSocketMessageType { 7 class _WebSocketMessageType {
8 static const int NONE = 0; 8 static const int NONE = 0;
9 static const int BINARY = 1; 9 static const int BINARY = 1;
10 static const int TEXT = 2; 10 static const int TEXT = 2;
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 if (_currentMessageType == _WebSocketMessageType.NONE) { 81 if (_currentMessageType == _WebSocketMessageType.NONE) {
82 throw new WebSocketException("Protocol error"); 82 throw new WebSocketException("Protocol error");
83 } 83 }
84 break; 84 break;
85 85
86 case _WebSocketOpcode.TEXT: 86 case _WebSocketOpcode.TEXT:
87 if (_currentMessageType != _WebSocketMessageType.NONE) { 87 if (_currentMessageType != _WebSocketMessageType.NONE) {
88 throw new WebSocketException("Protocol error"); 88 throw new WebSocketException("Protocol error");
89 } 89 }
90 _currentMessageType = _WebSocketMessageType.TEXT; 90 _currentMessageType = _WebSocketMessageType.TEXT;
91 if (onMessageStart != null) { 91 if (onMessageStart !== null) {
92 onMessageStart(_WebSocketMessageType.TEXT); 92 onMessageStart(_WebSocketMessageType.TEXT);
93 } 93 }
94 break; 94 break;
95 95
96 case _WebSocketOpcode.BINARY: 96 case _WebSocketOpcode.BINARY:
97 if (_currentMessageType != _WebSocketMessageType.NONE) { 97 if (_currentMessageType != _WebSocketMessageType.NONE) {
98 throw new WebSocketException("Protocol error"); 98 throw new WebSocketException("Protocol error");
99 } 99 }
100 _currentMessageType = _WebSocketMessageType.BINARY; 100 _currentMessageType = _WebSocketMessageType.BINARY;
101 if (onMessageStart != null) { 101 if (onMessageStart !== null) {
102 onMessageStart(_WebSocketMessageType.BINARY); 102 onMessageStart(_WebSocketMessageType.BINARY);
103 } 103 }
104 break; 104 break;
105 105
106 case _WebSocketOpcode.CLOSE: 106 case _WebSocketOpcode.CLOSE:
107 case _WebSocketOpcode.PING: 107 case _WebSocketOpcode.PING:
108 case _WebSocketOpcode.PONG: 108 case _WebSocketOpcode.PONG:
109 // Control frames cannot be fragmented. 109 // Control frames cannot be fragmented.
110 if (!_fin) throw new WebSocketException("Protocol error"); 110 if (!_fin) throw new WebSocketException("Protocol error");
111 break; 111 break;
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 _controlFrameEnd(); 187 _controlFrameEnd();
188 } 188 }
189 } else { 189 } else {
190 switch (_currentMessageType) { 190 switch (_currentMessageType) {
191 case _WebSocketMessageType.NONE: 191 case _WebSocketMessageType.NONE:
192 throw new WebSocketException("Protocol error"); 192 throw new WebSocketException("Protocol error");
193 break; 193 break;
194 194
195 case _WebSocketMessageType.TEXT: 195 case _WebSocketMessageType.TEXT:
196 case _WebSocketMessageType.BINARY: 196 case _WebSocketMessageType.BINARY:
197 if (onMessageData != null) { 197 if (onMessageData !== null) {
198 onMessageData(buffer, index, payload); 198 onMessageData(buffer, index, payload);
199 } 199 }
200 index += payload; 200 index += payload;
201 if (_remainingPayloadBytes == 0) { 201 if (_remainingPayloadBytes == 0) {
202 _messageFrameEnd(); 202 _messageFrameEnd();
203 } 203 }
204 break; 204 break;
205 205
206 default: 206 default:
207 throw new WebSocketException("Protocol error"); 207 throw new WebSocketException("Protocol error");
208 break; 208 break;
209 209
210 } 210 }
211 } 211 }
212 212
213 // Hack - as we always do index++ below. 213 // Hack - as we always do index++ below.
214 index--; 214 index--;
215 } 215 }
216 216
217 // Move to the next byte. 217 // Move to the next byte.
218 index++; 218 index++;
219 } 219 }
220 } catch (e) { 220 } catch (e) {
221 _reportError(e); 221 if (onClosed !== null) onClosed(1006, "Protocol error");
222 _state = FAILURE;
222 } 223 }
223 } 224 }
224 225
225 /** 226 /**
226 * Indicate that the underlying communication channel has been closed. 227 * Indicate that the underlying communication channel has been closed.
227 */ 228 */
228 void closed() { 229 void closed() {
229 if (_state == START || _state == CLOSED || _state == FAILURE) return; 230 if (_state == START || _state == CLOSED || _state == FAILURE) return;
230 _reportError(new WebSocketException("Protocol error $_state")); 231 if (onClosed !== null) onClosed(1006, "Connection closed unexpectedly");
231 _state = CLOSED; 232 _state = CLOSED;
232 } 233 }
233 234
234 void _lengthDone() { 235 void _lengthDone() {
235 if (_masked) { 236 if (_masked) {
236 _state = MASK; 237 _state = MASK;
237 _remainingMaskingKeyBytes = 4; 238 _remainingMaskingKeyBytes = 4;
238 } else { 239 } else {
239 _remainingPayloadBytes = _len; 240 _remainingPayloadBytes = _len;
240 _startPayload(); 241 _startPayload();
241 } 242 }
242 } 243 }
243 244
244 void _maskDone() { 245 void _maskDone() {
245 _remainingPayloadBytes = _len; 246 _remainingPayloadBytes = _len;
246 _startPayload(); 247 _startPayload();
247 } 248 }
248 249
249 void _startPayload() { 250 void _startPayload() {
250 // If there is no actual payload perform perform callbacks without 251 // If there is no actual payload perform perform callbacks without
251 // going through the PAYLOAD state. 252 // going through the PAYLOAD state.
252 if (_remainingPayloadBytes == 0) { 253 if (_remainingPayloadBytes == 0) {
253 if (_isControlFrame()) { 254 if (_isControlFrame()) {
254 switch (_opcode) { 255 switch (_opcode) {
255 case _WebSocketOpcode.CLOSE: 256 case _WebSocketOpcode.CLOSE:
256 if (onClosed != null) onClosed(null, null); 257 if (onClosed !== null) onClosed(1005, "");
257 _state = CLOSED; 258 _state = CLOSED;
258 break; 259 break;
259 case _WebSocketOpcode.PING: 260 case _WebSocketOpcode.PING:
260 if (onPing != null) onPing(null); 261 if (onPing !== null) onPing(null);
261 break; 262 break;
262 case _WebSocketOpcode.PONG: 263 case _WebSocketOpcode.PONG:
263 if (onPong != null) onPong(null); 264 if (onPong !== null) onPong(null);
264 break; 265 break;
265 } 266 }
266 _prepareForNextFrame(); 267 _prepareForNextFrame();
267 } else { 268 } else {
268 _messageFrameEnd(); 269 _messageFrameEnd();
269 } 270 }
270 } else { 271 } else {
271 _state = PAYLOAD; 272 _state = PAYLOAD;
272 } 273 }
273 } 274 }
274 275
275 void _messageFrameEnd() { 276 void _messageFrameEnd() {
276 if (_fin) { 277 if (_fin) {
277 if (onMessageEnd != null) onMessageEnd(); 278 if (onMessageEnd !== null) onMessageEnd();
278 _currentMessageType = _WebSocketMessageType.NONE; 279 _currentMessageType = _WebSocketMessageType.NONE;
279 } 280 }
280 _prepareForNextFrame(); 281 _prepareForNextFrame();
281 } 282 }
282 283
283 void _controlFrameEnd() { 284 void _controlFrameEnd() {
284 switch (_opcode) { 285 switch (_opcode) {
285 case _WebSocketOpcode.CLOSE: 286 case _WebSocketOpcode.CLOSE:
286 int status; 287 int status = 1005;
287 String reason; 288 String reason = "";
288 if (_controlPayload.length > 0) { 289 if (_controlPayload.length > 0) {
289 if (_controlPayload.length == 1) { 290 if (_controlPayload.length == 1) {
290 throw new WebSocketException("Protocol error"); 291 throw new WebSocketException("Protocol error");
291 } 292 }
292 status = _controlPayload[0] << 8 | _controlPayload[1]; 293 status = _controlPayload[0] << 8 | _controlPayload[1];
293 if (_controlPayload.length > 2) { 294 if (_controlPayload.length > 2) {
294 var decoder = _StringDecoders.decoder(Encoding.UTF_8); 295 var decoder = _StringDecoders.decoder(Encoding.UTF_8);
295 decoder.write( 296 decoder.write(
296 _controlPayload.getRange(2, _controlPayload.length - 2)); 297 _controlPayload.getRange(2, _controlPayload.length - 2));
297 reason = decoder.decoded; 298 reason = decoder.decoded;
298 } 299 }
299 } 300 }
300 if (onClosed != null) onClosed(status, reason); 301 if (onClosed !== null) onClosed(status, reason);
301 _state = CLOSED; 302 _state = CLOSED;
302 break; 303 break;
303 304
304 case _WebSocketOpcode.PING: 305 case _WebSocketOpcode.PING:
305 if (onPing != null) onPing(_controlPayload); 306 if (onPing !== null) onPing(_controlPayload);
306 break; 307 break;
307 308
308 case _WebSocketOpcode.PONG: 309 case _WebSocketOpcode.PONG:
309 if (onPong != null) onPong(_controlPayload); 310 if (onPong !== null) onPong(_controlPayload);
310 break; 311 break;
311 } 312 }
312 _prepareForNextFrame(); 313 _prepareForNextFrame();
313 } 314 }
314 315
315 bool _isControlFrame() { 316 bool _isControlFrame() {
316 return _opcode == _WebSocketOpcode.CLOSE || 317 return _opcode == _WebSocketOpcode.CLOSE ||
317 _opcode == _WebSocketOpcode.PING || 318 _opcode == _WebSocketOpcode.PING ||
318 _opcode == _WebSocketOpcode.PONG; 319 _opcode == _WebSocketOpcode.PONG;
319 } 320 }
320 321
321 void _prepareForNextFrame() { 322 void _prepareForNextFrame() {
322 if (_state != CLOSED && _state != FAILURE) _state = START; 323 if (_state != CLOSED && _state != FAILURE) _state = START;
323 _fin = null; 324 _fin = null;
324 _opcode = null; 325 _opcode = null;
325 _len = null; 326 _len = null;
326 _masked = null; 327 _masked = null;
327 _maskingKey = 0; 328 _maskingKey = 0;
328 _remainingLenBytes = null; 329 _remainingLenBytes = null;
329 _remainingMaskingKeyBytes = null; 330 _remainingMaskingKeyBytes = null;
330 _remainingPayloadBytes = null; 331 _remainingPayloadBytes = null;
331 _unmaskingIndex = 0; 332 _unmaskingIndex = 0;
332 _controlPayload = null; 333 _controlPayload = null;
333 } 334 }
334 335
335 void _reportError(e) {
336 // Report the error through the error callback if any. Otherwise
337 // throw the error.
338 if (onError != null) {
339 onError(e);
340 _state = FAILURE;
341 } else {
342 throw e;
343 }
344 }
345
346 int _state; 336 int _state;
347 bool _fin; 337 bool _fin;
348 int _opcode; 338 int _opcode;
349 int _len; 339 int _len;
350 bool _masked; 340 bool _masked;
351 int _maskingKey; 341 int _maskingKey;
352 int _remainingLenBytes; 342 int _remainingLenBytes;
353 int _remainingMaskingKeyBytes; 343 int _remainingMaskingKeyBytes;
354 int _remainingPayloadBytes; 344 int _remainingPayloadBytes;
355 int _unmaskingIndex; 345 int _unmaskingIndex;
356 346
357 int _currentMessageType; 347 int _currentMessageType;
358 List<int> _controlPayload; 348 List<int> _controlPayload;
359 349
360 Function onMessageStart; 350 Function onMessageStart;
361 Function onMessageData; 351 Function onMessageData;
362 Function onMessageEnd; 352 Function onMessageEnd;
363 Function onPing; 353 Function onPing;
364 Function onPong; 354 Function onPong;
365 Function onClosed; 355 Function onClosed;
366 Function onError;
367 } 356 }
368 357
369 358
370 class _WebSocketConnectionBase { 359 class _WebSocketConnectionBase {
371 void _socketConnected(Socket socket) { 360 void _socketConnected(Socket socket) {
372 _socket = socket; 361 _socket = socket;
373 _socket.onError = (e) { 362 _socket.onError = (e) => _socket.close();
374 _reportError(e);
375 _socket.close();
376 };
377 } 363 }
378 364
379 void _startProcessing(List<int> unparsedData) { 365 void _startProcessing(List<int> unparsedData) {
380 _WebSocketProtocolProcessor processor = new _WebSocketProtocolProcessor(); 366 _WebSocketProtocolProcessor processor = new _WebSocketProtocolProcessor();
381 processor.onMessageStart = _onWebSocketMessageStart; 367 processor.onMessageStart = _onWebSocketMessageStart;
382 processor.onMessageData = _onWebSocketMessageData; 368 processor.onMessageData = _onWebSocketMessageData;
383 processor.onMessageEnd = _onWebSocketMessageEnd; 369 processor.onMessageEnd = _onWebSocketMessageEnd;
384 processor.onPing = _onWebSocketPing; 370 processor.onPing = _onWebSocketPing;
385 processor.onPong = _onWebSocketPong; 371 processor.onPong = _onWebSocketPong;
386 processor.onClosed = _onWebSocketClosed; 372 processor.onClosed = _onWebSocketClosed;
387 processor.onError = _onWebSocketError; 373 if (unparsedData !== null) {
388 if (unparsedData != null) {
389 processor.update(unparsedData, 0, unparsedData.length); 374 processor.update(unparsedData, 0, unparsedData.length);
390 } 375 }
391 _socket.onData = () { 376 _socket.onData = () {
392 int available = _socket.available(); 377 int available = _socket.available();
393 List<int> data = new List<int>(available); 378 List<int> data = new List<int>(available);
394 int read = _socket.readList(data, 0, available); 379 int read = _socket.readList(data, 0, available);
395 processor.update(data, 0, read); 380 processor.update(data, 0, read);
396 }; 381 };
397 _socket.onClosed = () { 382 _socket.onClosed = () {
398 processor.closed(); 383 processor.closed();
399 if (_closeSent) { 384 if (_closeSent) {
400 // Got socket close in response to close frame. Don't treat 385 // Got socket close in response to close frame. Don't treat
401 // that as an error. 386 // that as an error.
402 if (_closeTimer != null) _closeTimer.cancel(); 387 if (_closeTimer !== null) _closeTimer.cancel();
403 } else { 388 } else {
404 _reportError(new WebSocketException("Unexpected close")); 389 if (_onClosed !== null) _onClosed(1006, "Unexpected close");
405 } 390 }
406 _socket.close(); 391 _socket.close();
407 }; 392 };
408 } 393 }
409 394
410 void set onMessage(void callback(Object message)) { 395 void set onMessage(void callback(Object message)) {
411 _onMessage = callback; 396 _onMessage = callback;
412 } 397 }
413 398
414 void set onClosed(void callback(int status, String reason)) { 399 void set onClosed(void callback(int status, String reason)) {
415 _onClosed = callback; 400 _onClosed = callback;
416 } 401 }
417 402
418 void set onError(void callback(e)) {
419 _onError = callback;
420 }
421
422 send(message) { 403 send(message) {
423 if (_closeSent) { 404 if (_closeSent) {
424 throw new WebSocketException("Connection closed"); 405 throw new WebSocketException("Connection closed");
425 } 406 }
426 List<int> data; 407 List<int> data;
427 int opcode; 408 int opcode;
428 if (message != null) { 409 if (message !== null) {
429 if (message is String) { 410 if (message is String) {
430 opcode = _WebSocketOpcode.TEXT; 411 opcode = _WebSocketOpcode.TEXT;
431 data = _StringEncoders.encoder(Encoding.UTF_8).encodeString(message); 412 data = _StringEncoders.encoder(Encoding.UTF_8).encodeString(message);
432 } else { 413 } else {
433 if (message is !List<int>) { 414 if (message is !List<int>) {
434 throw new IllegalArgumentException(message); 415 throw new IllegalArgumentException(message);
435 } 416 }
436 opcode = _WebSocketOpcode.BINARY; 417 opcode = _WebSocketOpcode.BINARY;
437 data = message; 418 data = message;
438 } 419 }
439 } else { 420 } else {
440 opcode = _WebSocketOpcode.TEXT; 421 opcode = _WebSocketOpcode.TEXT;
441 } 422 }
442 _sendFrame(opcode, data); 423 _sendFrame(opcode, data);
443 } 424 }
444 425
445 close([int status, String reason]) { 426 close([int status, String reason]) {
446 if (_closeSent) return; 427 if (_closeSent) return;
447 List<int> data; 428 List<int> data;
448 if (status != null) { 429 if (status !== null) {
449 data = new List<int>(); 430 data = new List<int>();
450 data.add((status >> 8) & 0xFF); 431 data.add((status >> 8) & 0xFF);
451 data.add(status & 0xFF); 432 data.add(status & 0xFF);
452 if (reason != null) { 433 if (reason !== null) {
453 data.addAll( 434 data.addAll(
454 _StringEncoders.encoder(Encoding.UTF_8).encodeString(reason)); 435 _StringEncoders.encoder(Encoding.UTF_8).encodeString(reason));
455 } 436 }
456 } 437 }
457 _sendFrame(_WebSocketOpcode.CLOSE, data); 438 _sendFrame(_WebSocketOpcode.CLOSE, data);
458 439
459 if (_closeReceived) { 440 if (_closeReceived) {
460 // Close the socket when the close frame has been sent - if it 441 // Close the socket when the close frame has been sent - if it
461 // does not take too long. 442 // does not take too long.
462 _socket.outputStream.close(); 443 _socket.outputStream.close();
463 _socket.outputStream.onClosed = () { 444 _socket.outputStream.onClosed = () {
464 if (_closeTimer != null) _closeTimer.cancel(); 445 if (_closeTimer !== null) _closeTimer.cancel();
465 _socket.close(); 446 _socket.close();
466 }; 447 };
467 _closeTimer = new Timer(5000, (t) { 448 _closeTimer = new Timer(5000, (t) {
468 _socket.close(); 449 _socket.close();
469 }); 450 });
470 } else { 451 } else {
471 // Half close the socket and expect a close frame in response 452 // Half close the socket and expect a close frame in response
472 // before closing the socket. If a close frame does not arrive 453 // before closing the socket. If a close frame does not arrive
473 // within a reasonable amount of time just close the socket. 454 // within a reasonable amount of time just close the socket.
474 _socket.outputStream.close(); 455 _socket.outputStream.close();
(...skipping 17 matching lines...) Expand all
492 473
493 _onWebSocketMessageData(List<int> buffer, int offset, int count) { 474 _onWebSocketMessageData(List<int> buffer, int offset, int count) {
494 if (_currentMessageType == _WebSocketMessageType.TEXT) { 475 if (_currentMessageType == _WebSocketMessageType.TEXT) {
495 _decoder.write(buffer.getRange(offset, count)); 476 _decoder.write(buffer.getRange(offset, count));
496 } else { 477 } else {
497 _outputStream.write(buffer.getRange(offset, count)); 478 _outputStream.write(buffer.getRange(offset, count));
498 } 479 }
499 } 480 }
500 481
501 _onWebSocketMessageEnd() { 482 _onWebSocketMessageEnd() {
502 if (_onMessage != null) { 483 if (_onMessage !== null) {
503 if (_currentMessageType == _WebSocketMessageType.TEXT) { 484 if (_currentMessageType == _WebSocketMessageType.TEXT) {
504 _onMessage(_decoder.decoded); 485 _onMessage(_decoder.decoded);
505 } else { 486 } else {
506 _onMessage(_outputStream.read()); 487 _onMessage(_outputStream.read());
507 } 488 }
508 } 489 }
509 _decoder = null; 490 _decoder = null;
510 _outputStream = null; 491 _outputStream = null;
511 } 492 }
512 493
513 _onWebSocketPing(List<int> payload) { 494 _onWebSocketPing(List<int> payload) {
514 _sendFrame(_WebSocketOpcode.PONG, payload); 495 _sendFrame(_WebSocketOpcode.PONG, payload);
515 } 496 }
516 497
517 _onWebSocketPong(List<int> payload) { 498 _onWebSocketPong(List<int> payload) {
518 // Currently pong messages are ignored. 499 // Currently pong messages are ignored.
519 } 500 }
520 501
521 _onWebSocketClosed(int status, String reason) { 502 _onWebSocketClosed(int status, String reason) {
522 _closeReceived = true; 503 _closeReceived = true;
523 if (_onClosed != null) _onClosed(status, reason); 504 if (_onClosed !== null) _onClosed(status, reason);
524 if (_closeSent) { 505 if (_closeSent) {
525 // Got close frame in response to close frame. Now close the socket. 506 // Got close frame in response to close frame. Now close the socket.
526 if (_closeTimer != null) _closeTimer.cancel(); 507 if (_closeTimer !== null) _closeTimer.cancel();
527 _socket.close(); 508 _socket.close();
528 } else { 509 } else {
529 close(status); 510 close(status);
530 } 511 }
531 } 512 }
532 513
533 _onWebSocketError(e) {
534 _reportError(e);
535 _socket.close();
536 }
537
538 _sendFrame(int opcode, [List<int> data]) { 514 _sendFrame(int opcode, [List<int> data]) {
539 bool mask = false; // Masking not implemented for server. 515 bool mask = false; // Masking not implemented for server.
540 int dataLength = data == null ? 0 : data.length; 516 int dataLength = data == null ? 0 : data.length;
541 // Determine the header size. 517 // Determine the header size.
542 int headerSize = (mask) ? 6 : 2; 518 int headerSize = (mask) ? 6 : 2;
543 if (dataLength > 65535) { 519 if (dataLength > 65535) {
544 headerSize += 8; 520 headerSize += 8;
545 } else if (dataLength > 125) { 521 } else if (dataLength > 125) {
546 headerSize += 2; 522 headerSize += 2;
547 } 523 }
(...skipping 10 matching lines...) Expand all
558 } else if (dataLength > 125) { 534 } else if (dataLength > 125) {
559 header[index++] = 126; 535 header[index++] = 126;
560 lengthBytes = 2; 536 lengthBytes = 2;
561 } 537 }
562 // Write the length in network byte order into the header. 538 // Write the length in network byte order into the header.
563 for (int i = 0; i < lengthBytes; i++) { 539 for (int i = 0; i < lengthBytes; i++) {
564 header[index++] = dataLength >> (((lengthBytes - 1) - i) * 8) & 0xFF; 540 header[index++] = dataLength >> (((lengthBytes - 1) - i) * 8) & 0xFF;
565 } 541 }
566 assert(index == headerSize); 542 assert(index == headerSize);
567 _socket.outputStream.write(header); 543 _socket.outputStream.write(header);
568 if (data != null) { 544 if (data !== null) {
569 _socket.outputStream.write(data); 545 _socket.outputStream.write(data);
570 } 546 }
571 } 547 }
572 548
573 void _reportError(e) {
574 if (_onError != null) {
575 _onError(e);
576 } else {
577 throw e;
578 }
579 }
580
581 Socket _socket; 549 Socket _socket;
582 Timer _closeTimer; 550 Timer _closeTimer;
583 int _hash; 551 int _hash;
584 552
585 Function _onMessage; 553 Function _onMessage;
586 Function _onClosed; 554 Function _onClosed;
587 Function _onError;
588 555
589 int _currentMessageType = _WebSocketMessageType.NONE; 556 int _currentMessageType = _WebSocketMessageType.NONE;
590 _StringDecoder _decoder; 557 _StringDecoder _decoder;
591 ListOutputStream _outputStream; 558 ListOutputStream _outputStream;
592 bool _closeReceived = false; 559 bool _closeReceived = false;
593 bool _closeSent = false; 560 bool _closeSent = false;
594 } 561 }
595 562
596 563
597 class _WebSocketConnection 564 class _WebSocketConnection
(...skipping 22 matching lines...) Expand all
620 String key = request.headers.value("Sec-WebSocket-Key"); 587 String key = request.headers.value("Sec-WebSocket-Key");
621 SHA1 sha1 = new SHA1(); 588 SHA1 sha1 = new SHA1();
622 sha1.update("$key$_webSocketGUID".charCodes()); 589 sha1.update("$key$_webSocketGUID".charCodes());
623 String accept = _Base64._encode(sha1.digest()); 590 String accept = _Base64._encode(sha1.digest());
624 response.headers.add("Sec-WebSocket-Accept", accept); 591 response.headers.add("Sec-WebSocket-Accept", accept);
625 response.contentLength = 0; 592 response.contentLength = 0;
626 593
627 // Upgrade the connection and get the underlying socket. 594 // Upgrade the connection and get the underlying socket.
628 WebSocketConnection conn = 595 WebSocketConnection conn =
629 new _WebSocketConnection(response.detachSocket()); 596 new _WebSocketConnection(response.detachSocket());
630 if (_onOpen != null) _onOpen(conn); 597 if (_onOpen !== null) _onOpen(conn);
631 } 598 }
632 599
633 void set onOpen(callback(WebSocketConnection connection)) { 600 void set onOpen(callback(WebSocketConnection connection)) {
634 _onOpen = callback; 601 _onOpen = callback;
635 } 602 }
636 603
637 bool _isWebSocketUpgrade(HttpRequest request) { 604 bool _isWebSocketUpgrade(HttpRequest request) {
638 if (request.method != "GET") { 605 if (request.method != "GET") {
639 return false; 606 return false;
640 } 607 }
(...skipping 23 matching lines...) Expand all
664 Function _onOpen; 631 Function _onOpen;
665 } 632 }
666 633
667 634
668 class _WebSocketClientConnection 635 class _WebSocketClientConnection
669 extends _WebSocketConnectionBase implements WebSocketClientConnection { 636 extends _WebSocketConnectionBase implements WebSocketClientConnection {
670 _WebSocketClientConnection(HttpClientConnection this._conn, 637 _WebSocketClientConnection(HttpClientConnection this._conn,
671 [List<String> protocols]) { 638 [List<String> protocols]) {
672 _conn.onRequest = _onHttpClientRequest; 639 _conn.onRequest = _onHttpClientRequest;
673 _conn.onResponse = _onHttpClientResponse; 640 _conn.onResponse = _onHttpClientResponse;
674 _conn.onError = (e) => _reportError(e); 641 _conn.onError = (e) {
642 if (_onClosed !== null) {
643 _onClosed(1006, "$e");
644 }
645 };
675 646
676 // Generate the nonce now as it is also used to set the hash code. 647 // Generate the nonce now as it is also used to set the hash code.
677 _generateNonceAndHash(); 648 _generateNonceAndHash();
678 } 649 }
679 650
680 void set onRequest(void callback(HttpClientRequest request)) { 651 void set onRequest(void callback(HttpClientRequest request)) {
681 _onRequest = callback; 652 _onRequest = callback;
682 } 653 }
683 654
684 void set onOpen(void callback()) { 655 void set onOpen(void callback()) {
685 _onOpen = callback; 656 _onOpen = callback;
686 } 657 }
687 658
688 void set onNoUpgrade(void callback(HttpClientResponse request)) { 659 void set onNoUpgrade(void callback(HttpClientResponse request)) {
689 _onNoUpgrade = callback; 660 _onNoUpgrade = callback;
690 } 661 }
691 662
692 void _onHttpClientRequest(HttpClientRequest request) { 663 void _onHttpClientRequest(HttpClientRequest request) {
693 if (_onRequest != null) { 664 if (_onRequest !== null) {
694 _onRequest(request); 665 _onRequest(request);
695 } 666 }
696 // Setup the initial handshake. 667 // Setup the initial handshake.
697 request.headers.add(HttpHeaders.CONNECTION, "upgrade"); 668 request.headers.add(HttpHeaders.CONNECTION, "upgrade");
698 request.headers.set(HttpHeaders.UPGRADE, "websocket"); 669 request.headers.set(HttpHeaders.UPGRADE, "websocket");
699 request.headers.set("Sec-WebSocket-Key", _nonce); 670 request.headers.set("Sec-WebSocket-Key", _nonce);
700 request.headers.set("Sec-WebSocket-Version", "13"); 671 request.headers.set("Sec-WebSocket-Version", "13");
701 request.contentLength = 0; 672 request.contentLength = 0;
702 request.outputStream.close(); 673 request.outputStream.close();
703 } 674 }
704 675
705 void _onHttpClientResponse(HttpClientResponse response) { 676 void _onHttpClientResponse(HttpClientResponse response) {
706 if (response.statusCode != HttpStatus.SWITCHING_PROTOCOLS) { 677 if (response.statusCode != HttpStatus.SWITCHING_PROTOCOLS) {
707 if (_onNoUpgrade != null) { 678 if (_onNoUpgrade !== null) {
708 _onNoUpgrade(response); 679 _onNoUpgrade(response);
709 } else { 680 } else {
710 _conn.detachSocket().socket.close(); 681 _conn.detachSocket().socket.close();
711 throw new WebSocketException("Protocol upgrade refused"); 682 throw new WebSocketException("Protocol upgrade refused");
712 } 683 }
713 return; 684 return;
714 } 685 }
715 686
716 if (!_isWebSocketUpgrade(response)) { 687 if (!_isWebSocketUpgrade(response)) {
717 _conn.detachSocket().socket.close(); 688 _conn.detachSocket().socket.close();
718 throw new WebSocketException("Protocol upgrade failed"); 689 throw new WebSocketException("Protocol upgrade failed");
719 return; 690 return;
720 } 691 }
721 692
722 // Connection upgrade successful. 693 // Connection upgrade successful.
723 DetachedSocket detached = _conn.detachSocket(); 694 DetachedSocket detached = _conn.detachSocket();
724 _socketConnected(detached.socket); 695 _socketConnected(detached.socket);
725 if (_onOpen != null) _onOpen(); 696 if (_onOpen !== null) _onOpen();
726 _startProcessing(detached.unparsedData); 697 _startProcessing(detached.unparsedData);
727 } 698 }
728 699
729 void _generateNonceAndHash() { 700 void _generateNonceAndHash() {
730 Random random = new Random(); 701 Random random = new Random();
731 assert(_nonce == null); 702 assert(_nonce == null);
732 void intToBigEndianBytes(int value, List<int> bytes, int offset) { 703 void intToBigEndianBytes(int value, List<int> bytes, int offset) {
733 bytes[offset] = (value >> 24) & 0xFF; 704 bytes[offset] = (value >> 24) & 0xFF;
734 bytes[offset + 1] = (value >> 16) & 0xFF; 705 bytes[offset + 1] = (value >> 16) & 0xFF;
735 bytes[offset + 2] = (value >> 8) & 0xFF; 706 bytes[offset + 2] = (value >> 8) & 0xFF;
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
805 776
806 HttpClient client = new HttpClient(); 777 HttpClient client = new HttpClient();
807 HttpClientConnection conn = client.open("GET", uri.domain, port, path); 778 HttpClientConnection conn = client.open("GET", uri.domain, port, path);
808 if (protocols is String) protocols = [protocols]; 779 if (protocols is String) protocols = [protocols];
809 _wsconn = new WebSocketClientConnection(conn, protocols); 780 _wsconn = new WebSocketClientConnection(conn, protocols);
810 _wsconn.onOpen = () { 781 _wsconn.onOpen = () {
811 // HTTP client not needed after socket have been detached. 782 // HTTP client not needed after socket have been detached.
812 client.shutdown(); 783 client.shutdown();
813 client = null; 784 client = null;
814 _readyState = WebSocket.OPEN; 785 _readyState = WebSocket.OPEN;
815 if (_onopen != null) _onopen(); 786 if (_onopen !== null) _onopen();
816 }; 787 };
817 _wsconn.onMessage = (message) { 788 _wsconn.onMessage = (message) {
818 if (_onmessage != null) { 789 if (_onmessage !== null) {
819 _onmessage(new _WebSocketMessageEvent(message)); 790 _onmessage(new _WebSocketMessageEvent(message));
820 } 791 }
821 }; 792 };
822 _wsconn.onClosed = (status, reason) { 793 _wsconn.onClosed = (status, reason) {
823 _readyState = WebSocket.CLOSED; 794 _readyState = WebSocket.CLOSED;
824 if (_onclose != null) { 795 if (_onclose !== null) {
825 _onclose(new _WebSocketCloseEvent(true, status, reason)); 796 _onclose(new _WebSocketCloseEvent(true, status, reason));
826 } 797 }
827 }; 798 };
828 _wsconn.onNoUpgrade = (response) { 799 _wsconn.onNoUpgrade = (response) {
829 if (_onerror != null) _onerror("Failed web socket connection"); 800 if (_onclose !== null) {
830 }; 801 _onclose(
831 _wsconn.onError = (e) { 802 new _WebSocketCloseEvent(true, 1006, "Connection not upgraded"));
832 if (_onerror != null) _onerror(e); 803 }
833 }; 804 };
834 } 805 }
835 806
836 int get readyState => _readyState; 807 int get readyState => _readyState;
837 int get bufferedAmount => 0; 808 int get bufferedAmount => 0;
838 809
839 void set onopen(Function callback) { 810 void set onopen(Function callback) {
840 _onopen = callback; 811 _onopen = callback;
841 } 812 }
842 813
843 void set onerror(Function callback) { 814 void set onerror(Function callback) {}
844 _onerror = callback;
845 }
846 815
847 void set onclose(Function callback) { 816 void set onclose(Function callback) {
848 _onclose = callback; 817 _onclose = callback;
849 } 818 }
850 819
851 String get extensions => null; 820 String get extensions => null;
852 String get protocol => null; 821 String get protocol => null;
853 822
854 void close(int code, String reason) { 823 void close(int code, String reason) {
855 if (_readyState < WebSocket.CLOSING) _readyState = WebSocket.CLOSING; 824 if (_readyState < WebSocket.CLOSING) _readyState = WebSocket.CLOSING;
856 _wsconn.close(code, reason); 825 _wsconn.close(code, reason);
857 } 826 }
858 827
859 void set onmessage(Function callback) { 828 void set onmessage(Function callback) {
860 _onmessage = callback; 829 _onmessage = callback;
861 } 830 }
862 831
863 void send(data) { 832 void send(data) {
864 _wsconn.send(data); 833 _wsconn.send(data);
865 } 834 }
866 835
867 WebSocketClientConnection _wsconn; 836 WebSocketClientConnection _wsconn;
868 int _readyState = WebSocket.CONNECTING; 837 int _readyState = WebSocket.CONNECTING;
869 Function _onopen; 838 Function _onopen;
870 Function _onerror;
871 Function _onclose; 839 Function _onclose;
872 Function _onmessage; 840 Function _onmessage;
873 } 841 }
874 842
875 843
876 class _WebSocketMessageEvent implements MessageEvent { 844 class _WebSocketMessageEvent implements MessageEvent {
877 _WebSocketMessageEvent(this._data); 845 _WebSocketMessageEvent(this._data);
878 get data => _data; 846 get data => _data;
879 var _data; 847 var _data;
880 } 848 }
881 849
882 850
883 class _WebSocketCloseEvent implements CloseEvent { 851 class _WebSocketCloseEvent implements CloseEvent {
884 _WebSocketCloseEvent(this._wasClean, this._code, this._reason); 852 _WebSocketCloseEvent(this._wasClean, this._code, this._reason);
885 bool get wasClean => _wasClean; 853 bool get wasClean => _wasClean;
886 int get code => _code; 854 int get code => _code;
887 String get reason => _reason; 855 String get reason => _reason;
888 bool _wasClean; 856 bool _wasClean;
889 int _code; 857 int _code;
890 String _reason; 858 String _reason;
891 } 859 }
OLDNEW
« no previous file with comments | « runtime/bin/websocket.dart ('k') | tests/standalone/io/web_socket_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698