| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |