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

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

Issue 10205012: Initial web socket server implementation (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addressed review comments from vsm@ Created 8 years, 7 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/http.dart ('k') | runtime/bin/http_parser.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 class _HttpHeaders implements HttpHeaders { 5 class _HttpHeaders implements HttpHeaders {
6 _HttpHeaders() : _headers = new Map<String, List<String>>(); 6 _HttpHeaders() : _headers = new Map<String, List<String>>();
7 7
8 List<String> operator[](String name) { 8 List<String> operator[](String name) {
9 name = name.toLowerCase(); 9 name = name.toLowerCase();
10 return _headers[name]; 10 return _headers[name];
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after
354 _BufferList _buffer; 354 _BufferList _buffer;
355 Function _streamErrorHandler; 355 Function _streamErrorHandler;
356 } 356 }
357 357
358 358
359 // HTTP response object for sending a HTTP response. 359 // HTTP response object for sending a HTTP response.
360 class _HttpResponse extends _HttpRequestResponseBase implements HttpResponse { 360 class _HttpResponse extends _HttpRequestResponseBase implements HttpResponse {
361 static final int START = 0; 361 static final int START = 0;
362 static final int HEADERS_SENT = 1; 362 static final int HEADERS_SENT = 1;
363 static final int DONE = 2; 363 static final int DONE = 2;
364 static final int UPGRADED = 3;
364 365
365 _HttpResponse(_HttpConnection httpConnection) 366 _HttpResponse(_HttpConnection httpConnection)
366 : super(httpConnection), 367 : super(httpConnection),
367 _statusCode = HttpStatus.OK, 368 _statusCode = HttpStatus.OK,
368 _state = START; 369 _state = START;
369 370
370 void set contentLength(int contentLength) { 371 void set contentLength(int contentLength) {
371 if (_outputStream != null) throw new HttpException("Header already sent"); 372 if (_outputStream != null) throw new HttpException("Header already sent");
372 _contentLength = contentLength; 373 _contentLength = contentLength;
373 } 374 }
374 375
375 int get statusCode() => _statusCode; 376 int get statusCode() => _statusCode;
376 void set statusCode(int statusCode) { 377 void set statusCode(int statusCode) {
377 if (_outputStream != null) throw new HttpException("Header already sent"); 378 if (_outputStream != null) throw new HttpException("Header already sent");
378 _statusCode = statusCode; 379 _statusCode = statusCode;
379 } 380 }
380 381
381 String get reasonPhrase() => _findReasonPhrase(_statusCode); 382 String get reasonPhrase() => _findReasonPhrase(_statusCode);
382 void set reasonPhrase(String reasonPhrase) { 383 void set reasonPhrase(String reasonPhrase) {
383 if (_outputStream != null) throw new HttpException("Header already sent"); 384 if (_outputStream != null) throw new HttpException("Header already sent");
384 _reasonPhrase = reasonPhrase; 385 _reasonPhrase = reasonPhrase;
385 } 386 }
386 387
387 OutputStream get outputStream() { 388 OutputStream get outputStream() {
388 if (_state == DONE) throw new HttpException("Response closed"); 389 if (_state >= DONE) throw new HttpException("Response closed");
389 if (_outputStream == null) { 390 if (_outputStream == null) {
390 // Ensure that headers are written. 391 // Ensure that headers are written.
391 if (_state == START) { 392 if (_state == START) {
392 _writeHeader(); 393 _writeHeader();
393 } 394 }
394 _outputStream = new _HttpOutputStream(this); 395 _outputStream = new _HttpOutputStream(this);
395 } 396 }
396 return _outputStream; 397 return _outputStream;
397 } 398 }
398 399
400 Socket detachSocket() {
401 if (_state >= DONE) throw new HttpException("Response closed");
402 // Ensure that headers are written.
403 if (_state == START) {
404 _writeHeader();
405 }
406 _state = UPGRADED;
407 // Ensure that any trailing data is written.
408 _writeDone();
409 // Indicate to the connection that the response handling is done.
410 return _httpConnection._detachSocket();
411 }
412
399 void _responseEnd() { 413 void _responseEnd() {
400 _state = DONE; 414 _state = DONE;
401 // Stop tracking no pending write events. 415 // Stop tracking no pending write events.
402 _httpConnection._onNoPendingWrites = null; 416 _httpConnection._onNoPendingWrites = null;
403 // Ensure that any trailing data is written. 417 // Ensure that any trailing data is written.
404 _writeDone(); 418 _writeDone();
405 // Indicate to the connection that the response handling is done. 419 // Indicate to the connection that the response handling is done.
406 _httpConnection._responseDone(); 420 _httpConnection._responseDone();
407 } 421 }
408 422
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 _writeCRLF(); 520 _writeCRLF();
507 521
508 // Determine the value of the "Connection" header. 522 // Determine the value of the "Connection" header.
509 if (_protocolVersion == "1.1" && !_persistentConnection) { 523 if (_protocolVersion == "1.1" && !_persistentConnection) {
510 _headers.set("Connection", "close"); 524 _headers.set("Connection", "close");
511 } else if (_protocolVersion == "1.0" && _persistentConnection) { 525 } else if (_protocolVersion == "1.0" && _persistentConnection) {
512 _headers.set("Connection", "keep-alive"); 526 _headers.set("Connection", "keep-alive");
513 } 527 }
514 // Determine the value of the "Transfer-Encoding" header based on 528 // Determine the value of the "Transfer-Encoding" header based on
515 // whether the content length is known. 529 // whether the content length is known.
516 if (_contentLength >= 0) { 530 if (_contentLength > 0) {
517 _headers.set("Content-Length", _contentLength.toString()); 531 _headers.set("Content-Length", _contentLength.toString());
518 } else { 532 } else {
519 _headers.set("Transfer-Encoding", "chunked"); 533 _headers.set("Transfer-Encoding", "chunked");
520 } 534 }
521 535
522 // Write headers. 536 // Write headers.
523 bool allWritten = _writeHeaders(); 537 bool allWritten = _writeHeaders();
524 _state = HEADERS_SENT; 538 _state = HEADERS_SENT;
525 return allWritten; 539 return allWritten;
526 } 540 }
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
607 void set onError(void callback(Exception e)) { 621 void set onError(void callback(Exception e)) {
608 _requestOrResponse._streamSetErrorHandler(callback); 622 _requestOrResponse._streamSetErrorHandler(callback);
609 } 623 }
610 624
611 _HttpRequestResponseBase _requestOrResponse; 625 _HttpRequestResponseBase _requestOrResponse;
612 } 626 }
613 627
614 628
615 class _HttpConnectionBase implements Hashable { 629 class _HttpConnectionBase implements Hashable {
616 _HttpConnectionBase() : _sendBuffers = new Queue(), 630 _HttpConnectionBase() : _sendBuffers = new Queue(),
617 _httpParser = new _HttpParser(); 631 _httpParser = new _HttpParser() {
632 _hashCode = _nextHashCode;
633 _nextHashCode = (_nextHashCode + 1) & 0xFFFFFFF;
634 }
618 635
619 void _connectionEstablished(Socket socket) { 636 void _connectionEstablished(Socket socket) {
620 _socket = socket; 637 _socket = socket;
621 // Register handler for socket events. 638 // Register handler for socket events.
622 _socket.onData = _onData; 639 _socket.onData = _onData;
623 _socket.onClosed = _onClosed; 640 _socket.onClosed = _onClosed;
624 _socket.onError = _onError; 641 _socket.onError = _onError;
625 } 642 }
626 643
627 bool _write(List<int> data, [bool copyBuffer = false]) { 644 bool _write(List<int> data, [bool copyBuffer = false]) {
(...skipping 16 matching lines...) Expand all
644 void _onData() { 661 void _onData() {
645 int available = _socket.available(); 662 int available = _socket.available();
646 if (available == 0) { 663 if (available == 0) {
647 return; 664 return;
648 } 665 }
649 666
650 ByteArray buffer = new ByteArray(available); 667 ByteArray buffer = new ByteArray(available);
651 int bytesRead = _socket.readList(buffer, 0, available); 668 int bytesRead = _socket.readList(buffer, 0, available);
652 if (bytesRead > 0) { 669 if (bytesRead > 0) {
653 int parsed = _httpParser.writeList(buffer, 0, bytesRead); 670 int parsed = _httpParser.writeList(buffer, 0, bytesRead);
654 if (parsed != bytesRead) { 671 if (!_httpParser.upgrade) {
655 // TODO(sgjesse): Error handling. 672 if (parsed != bytesRead) {
656 _close(); 673 // TODO(sgjesse): Error handling.
674 _close();
675 }
657 } 676 }
658 } 677 }
659 } 678 }
660 679
661 void _onClosed() { 680 void _onClosed() {
662 _closing = true; 681 _closing = true;
663 _onConnectionClosed(null); 682 _onConnectionClosed(null);
664 } 683 }
665 684
666 void _onError(Exception e) { 685 void _onError(Exception e) {
667 // If an error occurs, make sure to close the socket if one is associated. 686 // If an error occurs, make sure to close the socket if one is associated.
668 _error = true; 687 _error = true;
669 if (_socket != null) { 688 if (_socket != null) {
670 _socket.close(); 689 _socket.close();
671 } 690 }
672 _onConnectionClosed(e); 691 _onConnectionClosed(e);
673 } 692 }
674 693
694 Socket _detachSocket() {
695 _socket.onData = null;
696 // TODO(sgjesse): Handle getting the write handler when using output stream.
697 //_socket.onWrite = null;
698 _socket.onClosed = null;
699 _socket.onError = null;
700 Socket socket = _socket;
701 _socket = null;
702 if (onDetach) onDetach();
703 return socket;
704 }
705
675 abstract void _onConnectionClosed(Exception e); 706 abstract void _onConnectionClosed(Exception e);
676 abstract void _responseDone(); 707 abstract void _responseDone();
677 708
678 void set _onNoPendingWrites(void callback()) { 709 void set _onNoPendingWrites(void callback()) {
679 if (!_error) { 710 if (!_error) {
680 _socket.outputStream.onNoPendingWrites = callback; 711 _socket.outputStream.onNoPendingWrites = callback;
681 } 712 }
682 } 713 }
683 714
684 int hashCode() => _socket.hashCode(); 715 int hashCode() => _hashCode;
685 716
686 Socket _socket; 717 Socket _socket;
687 bool _closing = false; // Is the socket closed by the client? 718 bool _closing = false; // Is the socket closed by the client?
688 bool _error = false; // Is the socket closed due to an error? 719 bool _error = false; // Is the socket closed due to an error?
689 _HttpParser _httpParser; 720 _HttpParser _httpParser;
690 721
691 Queue _sendBuffers; 722 Queue _sendBuffers;
723
724 Function onDetach;
725
726 // Hash code for HTTP connection. Currently this is just a counter.
727 int _hashCode;
728 static int _nextHashCode = 0;
692 } 729 }
693 730
694 731
695 // HTTP server connection over a socket. 732 // HTTP server connection over a socket.
696 class _HttpConnection extends _HttpConnectionBase { 733 class _HttpConnection extends _HttpConnectionBase {
697 _HttpConnection(HttpServer this._server) { 734 _HttpConnection(HttpServer this._server) {
698 // Register HTTP parser callbacks. 735 // Register HTTP parser callbacks.
699 _httpParser.requestStart = 736 _httpParser.requestStart =
700 (method, uri, version) => _onRequestStart(method, uri, version); 737 (method, uri, version) => _onRequestStart(method, uri, version);
701 _httpParser.responseStart = 738 _httpParser.responseStart =
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
819 _closeServer = true; 856 _closeServer = true;
820 } 857 }
821 858
822 void listenOn(ServerSocket serverSocket) { 859 void listenOn(ServerSocket serverSocket) {
823 void onConnection(Socket socket) { 860 void onConnection(Socket socket) {
824 // Accept the client connection. 861 // Accept the client connection.
825 _HttpConnection connection = new _HttpConnection(this); 862 _HttpConnection connection = new _HttpConnection(this);
826 connection._connectionEstablished(socket); 863 connection._connectionEstablished(socket);
827 connection.onRequestReceived = _handleRequest; 864 connection.onRequestReceived = _handleRequest;
828 connection.onClosed = () => _connections.remove(connection); 865 connection.onClosed = () => _connections.remove(connection);
866 connection.onDetach = () => _connections.remove(connection);
829 connection.onError = (e) { 867 connection.onError = (e) {
830 _connections.remove(connection); 868 _connections.remove(connection);
831 if (_onError != null) _onError(e); 869 if (_onError != null) _onError(e);
832 }; 870 };
833 connection._connectionEstablished(socket); 871 connection._connectionEstablished(socket);
834 _connections.add(connection); 872 _connections.add(connection);
835 } 873 }
836 serverSocket.onConnection = onConnection; 874 serverSocket.onConnection = onConnection;
837 _server = serverSocket; 875 _server = serverSocket;
838 _closeServer = false; 876 _closeServer = false;
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
978 data = _method.toString().charCodes(); 1016 data = _method.toString().charCodes();
979 _httpConnection._write(data); 1017 _httpConnection._write(data);
980 _writeSP(); 1018 _writeSP();
981 data = _uri.toString().charCodes(); 1019 data = _uri.toString().charCodes();
982 _httpConnection._write(data); 1020 _httpConnection._write(data);
983 _writeSP(); 1021 _writeSP();
984 _httpConnection._write(_Const.HTTP11); 1022 _httpConnection._write(_Const.HTTP11);
985 _writeCRLF(); 1023 _writeCRLF();
986 1024
987 // Determine the value of the "Transfer-Encoding" header based on 1025 // Determine the value of the "Transfer-Encoding" header based on
988 // whether the content length is known. 1026 // whether the content length is known. If there is no content
989 if (_contentLength >= 0) { 1027 // neither "Content-Length" nor "Transfer-Encoding" is set
1028 if (_contentLength > 0) {
990 _headers.set("Content-Length", _contentLength.toString()); 1029 _headers.set("Content-Length", _contentLength.toString());
991 } else { 1030 } else if (_contentLength < 0) {
992 _headers.set("Transfer-Encoding", "chunked"); 1031 _headers.set("Transfer-Encoding", "chunked");
993 } 1032 }
994 1033
995 // Write headers. 1034 // Write headers.
996 _writeHeaders(); 1035 _writeHeaders();
997 _state = HEADERS_SENT; 1036 _state = HEADERS_SENT;
998 } 1037 }
999 1038
1000 String _method; 1039 String _method;
1001 String _uri; 1040 String _uri;
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after
1392 _activeSockets.remove(socketConn); 1431 _activeSockets.remove(socketConn);
1393 sockets.addFirst(socketConn); 1432 sockets.addFirst(socketConn);
1394 } 1433 }
1395 1434
1396 Function _onOpen; 1435 Function _onOpen;
1397 Map<String, Queue<_SocketConnection>> _openSockets; 1436 Map<String, Queue<_SocketConnection>> _openSockets;
1398 Set<_SocketConnection> _activeSockets; 1437 Set<_SocketConnection> _activeSockets;
1399 Timer _evictionTimer; 1438 Timer _evictionTimer;
1400 bool _shutdown; // Has this HTTP client been shutdown? 1439 bool _shutdown; // Has this HTTP client been shutdown?
1401 } 1440 }
OLDNEW
« no previous file with comments | « runtime/bin/http.dart ('k') | runtime/bin/http_parser.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698