| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 part of dart.io; | 5 part of dart.io; |
| 6 | 6 |
| 7 class _HttpIncoming | 7 class _HttpIncoming |
| 8 extends Stream<List<int>> implements StreamSink<List<int>> { | 8 extends Stream<List<int>> implements StreamSink<List<int>> { |
| 9 final int _transferLength; | 9 final int _transferLength; |
| 10 final Completer _dataCompleter = new Completer(); | 10 final Completer _dataCompleter = new Completer(); |
| (...skipping 720 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 731 _onDone(); | 731 _onDone(); |
| 732 _controller.close(); | 732 _controller.close(); |
| 733 }); | 733 }); |
| 734 return _controller.stream; | 734 return _controller.stream; |
| 735 } | 735 } |
| 736 } | 736 } |
| 737 | 737 |
| 738 // Transformer that validates the data written. | 738 // Transformer that validates the data written. |
| 739 class _DataValidatorTransformer | 739 class _DataValidatorTransformer |
| 740 implements StreamTransformer<List<int>, List<int>> { | 740 implements StreamTransformer<List<int>, List<int>> { |
| 741 final StreamController<List<int>> _controller | 741 final StreamController<List<int>> _controller = |
| 742 = new StreamController<List<int>>(); | 742 new StreamController<List<int>>(); |
| 743 int _bytesWritten = 0; | 743 int _bytesWritten = 0; |
| 744 Completer _completer = new Completer(); | |
| 745 | 744 |
| 746 int expectedTransferLength; | 745 int expectedTransferLength; |
| 747 | 746 |
| 748 _DataValidatorTransformer(); | |
| 749 | |
| 750 Future get validatorFuture => _completer.future; | |
| 751 | |
| 752 Stream<List<int>> bind(Stream<List<int>> stream) { | 747 Stream<List<int>> bind(Stream<List<int>> stream) { |
| 753 var subscription; | 748 var subscription; |
| 754 subscription = stream.listen( | 749 subscription = stream.listen( |
| 755 (data) { | 750 (data) { |
| 756 if (expectedTransferLength != null) { | 751 if (expectedTransferLength != null) { |
| 757 _bytesWritten += data.length; | 752 _bytesWritten += data.length; |
| 758 if (_bytesWritten > expectedTransferLength) { | 753 if (_bytesWritten > expectedTransferLength) { |
| 754 subscription.cancel(); |
| 755 _controller.signalError(new HttpException( |
| 756 "Content size exceeds specified contentLength. " |
| 757 "$_bytesWritten bytes written while expected " |
| 758 "$expectedTransferLength.")); |
| 759 _controller.close(); | 759 _controller.close(); |
| 760 subscription.cancel(); | |
| 761 if (_completer != null) { | |
| 762 _completer.completeError(new HttpException( | |
| 763 "Content size exceeds specified contentLength. " | |
| 764 "$_bytesWritten bytes written while expected " | |
| 765 "$expectedTransferLength.")); | |
| 766 _completer = null; | |
| 767 } | |
| 768 return; | 760 return; |
| 769 } | 761 } |
| 770 } | 762 } |
| 771 _controller.add(data); | 763 _controller.add(data); |
| 772 }, | 764 }, |
| 773 onError: (error) { | 765 onError: (error) { |
| 766 _controller.signalError(error); |
| 774 _controller.close(); | 767 _controller.close(); |
| 775 if (_completer != null) { | |
| 776 _completer.completeError(error); | |
| 777 _completer = null; | |
| 778 } | |
| 779 }, | 768 }, |
| 780 onDone: () { | 769 onDone: () { |
| 781 _controller.close(); | |
| 782 if (expectedTransferLength != null) { | 770 if (expectedTransferLength != null) { |
| 783 if (_bytesWritten < expectedTransferLength) { | 771 if (_bytesWritten < expectedTransferLength) { |
| 784 if (_completer != null) { | 772 _controller.signalError(new HttpException( |
| 785 _completer.completeError(new HttpException( | 773 "Content size below specified contentLength. " |
| 786 "Content size below specified contentLength. " | 774 " $_bytesWritten bytes written while expected " |
| 787 " $_bytesWritten bytes written while expected " | 775 "$expectedTransferLength.")); |
| 788 "$expectedTransferLength.")); | |
| 789 _completer = null; | |
| 790 return; | |
| 791 } | |
| 792 } | 776 } |
| 793 } | 777 } |
| 794 if (_completer != null) { | 778 _controller.close(); |
| 795 _completer.complete(this); | |
| 796 _completer = null; | |
| 797 } | |
| 798 }, | 779 }, |
| 799 unsubscribeOnError: true); | 780 unsubscribeOnError: true); |
| 800 return _controller.stream; | 781 return _controller.stream; |
| 801 } | 782 } |
| 802 } | 783 } |
| 803 | 784 |
| 804 // Extends StreamConsumer as this is an internal type, only used to pipe to. | 785 // Extends StreamConsumer as this is an internal type, only used to pipe to. |
| 805 class _HttpOutgoing implements StreamConsumer<List<int>, dynamic> { | 786 class _HttpOutgoing implements StreamConsumer<List<int>, dynamic> { |
| 806 final Completer _dataCompleter = new Completer(); | |
| 807 final Completer _streamCompleter = new Completer(); | |
| 808 final _DataValidatorTransformer _validator = new _DataValidatorTransformer(); | 787 final _DataValidatorTransformer _validator = new _DataValidatorTransformer(); |
| 788 Function _onStream; |
| 789 final Completer _consumeCompleter = new Completer(); |
| 809 | 790 |
| 810 // Future that completes when all data is written. | 791 Future onStream(Future callback(Stream<List<int>> stream)) { |
| 811 Future get dataDone => _dataCompleter.future; | 792 _onStream = callback; |
| 812 | 793 return _consumeCompleter.future; |
| 813 // Future that completes with the Stream, once the _HttpClientConnection is | 794 } |
| 814 // bound to one. | |
| 815 Future<Stream<List<int>>> get stream => _streamCompleter.future; | |
| 816 | 795 |
| 817 void setTransferLength(int transferLength) { | 796 void setTransferLength(int transferLength) { |
| 818 _validator.expectedTransferLength = transferLength; | 797 _validator.expectedTransferLength = transferLength; |
| 819 } | 798 } |
| 820 | 799 |
| 821 Future consume(Stream<List<int>> stream) { | 800 Future consume(Stream<List<int>> stream) { |
| 822 stream = stream.transform(_validator); | 801 _onStream(stream.transform(_validator)) |
| 823 _streamCompleter.complete(stream); | 802 .then((_) => _consumeCompleter.complete(), |
| 824 _validator.validatorFuture.catchError((e) { | 803 onError: _consumeCompleter.completeError); |
| 825 _dataCompleter.completeError(e); | 804 // Use .then to ensure a Future branch. |
| 826 }); | 805 return _consumeCompleter.future.then((_) => this); |
| 827 return _validator.validatorFuture.then((v) { | |
| 828 _dataCompleter.complete(); | |
| 829 return v; | |
| 830 }); | |
| 831 } | 806 } |
| 832 } | 807 } |
| 833 | 808 |
| 834 | 809 |
| 835 class _HttpClientConnection { | 810 class _HttpClientConnection { |
| 836 final String key; | 811 final String key; |
| 837 final Socket _socket; | 812 final Socket _socket; |
| 838 final _HttpParser _httpParser; | 813 final _HttpParser _httpParser; |
| 839 StreamSubscription _subscription; | 814 StreamSubscription _subscription; |
| 840 final _HttpClient _httpClient; | 815 final _HttpClient _httpClient; |
| 841 | 816 |
| 842 Completer<_HttpIncoming> _nextResponseCompleter; | 817 Completer<_HttpIncoming> _nextResponseCompleter; |
| 843 Future _writeDoneFuture; | 818 Future _streamFuture; |
| 844 | 819 |
| 845 _HttpClientConnection(String this.key, | 820 _HttpClientConnection(String this.key, |
| 846 Socket this._socket, | 821 Socket this._socket, |
| 847 _HttpClient this._httpClient) | 822 _HttpClient this._httpClient) |
| 848 : _httpParser = new _HttpParser.responseParser() { | 823 : _httpParser = new _HttpParser.responseParser() { |
| 849 _socket.pipe(_httpParser); | 824 _socket.pipe(_httpParser); |
| 850 _socket.done.catchError((e) { destroy(); }); | 825 _socket.done.catchError((e) { destroy(); }); |
| 851 | 826 |
| 852 // Set up handlers on the parser here, so we are sure to get 'onDone' from | 827 // Set up handlers on the parser here, so we are sure to get 'onDone' from |
| 853 // the parser. | 828 // the parser. |
| 854 _subscription = _httpParser.listen( | 829 _subscription = _httpParser.listen( |
| 855 (incoming) { | 830 (incoming) { |
| 856 // Only handle one incoming response at the time. Keep the | 831 // Only handle one incoming response at the time. Keep the |
| 857 // stream paused until the response have been processed. | 832 // stream paused until the response have been processed. |
| 858 _subscription.pause(); | 833 _subscription.pause(); |
| 859 // We assume the response is not here, until we have send the request. | 834 // We assume the response is not here, until we have send the request. |
| 860 assert(_nextResponseCompleter != null); | 835 assert(_nextResponseCompleter != null); |
| 861 _nextResponseCompleter.complete(incoming); | 836 _nextResponseCompleter.complete(incoming); |
| 862 }, | 837 }, |
| 863 onError: (error) { | 838 onError: (error) { |
| 864 if (_nextResponseCompleter != null) { | 839 if (_nextResponseCompleter != null) { |
| 865 _nextResponseCompleter.completeError(error); | 840 _nextResponseCompleter.completeError(error); |
| 866 } | 841 } |
| 867 }, | 842 }, |
| 868 onDone: () { | 843 onDone: () { |
| 869 close(); | 844 close(); |
| 870 }); | 845 }); |
| 871 } | 846 } |
| 872 | 847 |
| 873 Future<_HttpIncoming> sendRequest(_HttpOutgoing outgoing) { | 848 _HttpClientRequest send(Uri uri, int port, String method, bool isDirect) { |
| 874 return outgoing.stream | 849 var outgoing = new _HttpOutgoing(); |
| 875 .then((stream) { | 850 // Create new request object, wrapping the outgoing connection. |
| 876 // Close socket if output data is invalid. | 851 var request = new _HttpClientRequest(outgoing, |
| 877 outgoing.dataDone.catchError((e) { | 852 uri, |
| 878 close(); | 853 method, |
| 879 }); | 854 !isDirect, |
| 855 _httpClient, |
| 856 this); |
| 857 request.headers.host = uri.domain; |
| 858 request.headers.port = port; |
| 859 if (uri.userInfo != null && !uri.userInfo.isEmpty) { |
| 860 // If the URL contains user information use that for basic |
| 861 // authorization |
| 862 String auth = |
| 863 CryptoUtils.bytesToBase64(_encodeString(uri.userInfo)); |
| 864 request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth"); |
| 865 } else { |
| 866 // Look for credentials. |
| 867 _Credentials cr = _httpClient._findCredentials(uri); |
| 868 if (cr != null) { |
| 869 cr.authorize(request); |
| 870 } |
| 871 } |
| 872 // Start sending the request (lazy, delayed until the user provides |
| 873 // data). |
| 874 _httpParser.responseToMethod = method; |
| 875 _streamFuture = outgoing.onStream((stream) { |
| 880 // Sending request, set up response completer. | 876 // Sending request, set up response completer. |
| 881 _nextResponseCompleter = new Completer(); | 877 _nextResponseCompleter = new Completer(); |
| 882 _writeDoneFuture = _socket.addStream(stream); | |
| 883 // Listen for response. | 878 // Listen for response. |
| 884 return _nextResponseCompleter.future | 879 _nextResponseCompleter.future |
| 885 .whenComplete(() { | 880 .whenComplete(() { |
| 886 _nextResponseCompleter = null; | 881 _nextResponseCompleter = null; |
| 887 }) | 882 }) |
| 888 .then((incoming) { | 883 .then((incoming) { |
| 889 incoming.dataDone.then((_) { | 884 incoming.dataDone.then((_) { |
| 890 if (!incoming.headers.persistentConnection) { | 885 if (incoming.headers.persistentConnection && |
| 891 close(); | 886 request.persistentConnection) { |
| 887 _subscription.resume(); |
| 888 // Return connection, now we are done. |
| 889 _httpClient._returnConnection(this); |
| 892 } else { | 890 } else { |
| 893 // Wait for the socket to be done with writing, before we | 891 destroy(); |
| 894 // continue. | |
| 895 _writeDoneFuture.then((_) { | |
| 896 _subscription.resume(); | |
| 897 // Return connection, now we are done. | |
| 898 _httpClient._returnConnection(this); | |
| 899 }); | |
| 900 } | 892 } |
| 901 }); | 893 }); |
| 902 // TODO(ajohnsen): Can there be an error on dataDone? | 894 request._onIncoming(incoming); |
| 903 return incoming; | |
| 904 }) | 895 }) |
| 905 // If we see a state error, we failed to get the 'first' element. | 896 // If we see a state error, we failed to get the 'first' element. |
| 906 // Transform the error to a HttpParserException, for consistency. | 897 // Transform the error to a HttpParserException, for consistency. |
| 907 .catchError((error) { | 898 .catchError((error) { |
| 908 throw new HttpParserException( | 899 throw new HttpParserException( |
| 909 "Connection closed before data was received"); | 900 "Connection closed before data was received"); |
| 910 }, test: (error) => error is StateError) | 901 }, test: (error) => error is StateError) |
| 911 .catchError((error) { | 902 .catchError((error) { |
| 912 // We are done with the socket. | 903 // We are done with the socket. |
| 913 destroy(); | 904 destroy(); |
| 914 throw error; | 905 request._onError(error); |
| 915 }); | 906 }); |
| 916 }); | 907 |
| 908 return _socket.addStream(stream) |
| 909 .catchError((e) { |
| 910 destroy(); |
| 911 if (e.error is HttpException) throw e; |
| 912 // TODO(ajohnsen): Where to send Socket errors? |
| 913 }); |
| 914 }); |
| 915 return request; |
| 917 } | 916 } |
| 918 | 917 |
| 919 Future<Socket> detachSocket() { | 918 Future<Socket> detachSocket() { |
| 920 return _writeDoneFuture.then((_) => | 919 return _streamFuture |
| 921 new _DetachedSocket(_socket, _httpParser.detachIncoming())); | 920 .then((_) => new _DetachedSocket(_socket, _httpParser.detachIncoming()), |
| 921 onError: (_) {}); |
| 922 } | 922 } |
| 923 | 923 |
| 924 void destroy() { | 924 void destroy() { |
| 925 _httpClient._connectionClosed(this); |
| 925 _socket.destroy(); | 926 _socket.destroy(); |
| 926 _httpClient._connectionClosed(this); | |
| 927 } | 927 } |
| 928 | 928 |
| 929 void close() { | 929 void close() { |
| 930 var future = _writeDoneFuture; | |
| 931 if (future == null) future = new Future.immediate(null); | |
| 932 _httpClient._connectionClosed(this); | 930 _httpClient._connectionClosed(this); |
| 933 future.then((_) { | 931 _streamFuture |
| 934 _socket.close(); | 932 // TODO(ajohnsen): Add timeout. |
| 935 // TODO(ajohnsen): Add timeout. | 933 .then((_) => _socket.destroy(), |
| 936 // Delay destroy until socket is actually done writing. | 934 onError: (_) {}); |
| 937 _socket.done.then((_) => _socket.destroy(), | |
| 938 onError: (_) => _socket.destroy()); | |
| 939 }); | |
| 940 } | 935 } |
| 941 | 936 |
| 942 HttpConnectionInfo get connectionInfo => _HttpConnectionInfo.create(_socket); | 937 HttpConnectionInfo get connectionInfo => _HttpConnectionInfo.create(_socket); |
| 943 } | 938 } |
| 944 | 939 |
| 945 class _ConnnectionInfo { | 940 class _ConnnectionInfo { |
| 946 _ConnnectionInfo(_HttpClientConnection this.connection, _Proxy this.proxy); | 941 _ConnnectionInfo(_HttpClientConnection this.connection, _Proxy this.proxy); |
| 947 final _HttpClientConnection connection; | 942 final _HttpClientConnection connection; |
| 948 final _Proxy proxy; | 943 final _Proxy proxy; |
| 949 } | 944 } |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1048 var proxyConf = const _ProxyConfiguration.direct(); | 1043 var proxyConf = const _ProxyConfiguration.direct(); |
| 1049 if (_findProxy != null) { | 1044 if (_findProxy != null) { |
| 1050 // TODO(sgjesse): Keep a map of these as normally only a few | 1045 // TODO(sgjesse): Keep a map of these as normally only a few |
| 1051 // configuration strings will be used. | 1046 // configuration strings will be used. |
| 1052 try { | 1047 try { |
| 1053 proxyConf = new _ProxyConfiguration(_findProxy(uri)); | 1048 proxyConf = new _ProxyConfiguration(_findProxy(uri)); |
| 1054 } catch (error, stackTrace) { | 1049 } catch (error, stackTrace) { |
| 1055 return new Future.immediateError(error, stackTrace); | 1050 return new Future.immediateError(error, stackTrace); |
| 1056 } | 1051 } |
| 1057 } | 1052 } |
| 1058 return _getConnection(uri.domain, port, proxyConf, isSecure).then((info) { | 1053 return _getConnection(uri.domain, port, proxyConf, isSecure) |
| 1059 // Create new internal outgoing connection. | 1054 .then((info) { |
| 1060 var outgoing = new _HttpOutgoing(); | 1055 return info.connection.send(uri, |
| 1061 // Create new request object, wrapping the outgoing connection. | 1056 port, |
| 1062 var request = new _HttpClientRequest(outgoing, | 1057 method.toUpperCase(), |
| 1063 uri, | 1058 info.proxy.isDirect); |
| 1064 method.toUpperCase(), | |
| 1065 !info.proxy.isDirect, | |
| 1066 this, | |
| 1067 info.connection); | |
| 1068 request.headers.host = uri.domain; | |
| 1069 request.headers.port = port; | |
| 1070 if (uri.userInfo != null && !uri.userInfo.isEmpty) { | |
| 1071 // If the URL contains user information use that for basic | |
| 1072 // authorization | |
| 1073 String auth = | |
| 1074 CryptoUtils.bytesToBase64(_encodeString(uri.userInfo)); | |
| 1075 request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth"); | |
| 1076 } else { | |
| 1077 // Look for credentials. | |
| 1078 _Credentials cr = _findCredentials(uri); | |
| 1079 if (cr != null) { | |
| 1080 cr.authorize(request); | |
| 1081 } | |
| 1082 } | |
| 1083 // Start sending the request (lazy, delayed until the user provides | |
| 1084 // data). | |
| 1085 info.connection._httpParser.responseToMethod = method; | |
| 1086 info.connection.sendRequest(outgoing) | |
| 1087 .then((incoming) { | |
| 1088 // The full request have been sent and a response is received | |
| 1089 // containing status-code, headers and etc. | |
| 1090 request._onIncoming(incoming); | |
| 1091 }) | |
| 1092 .catchError((error) { | |
| 1093 // An error occoured before the http-header was parsed. This | |
| 1094 // could be either a socket-error or parser-error. | |
| 1095 request._onError(error); | |
| 1096 }); | |
| 1097 // Return the request to the user. Immediate socket errors are not | |
| 1098 // handled, thus forwarded to the user. | |
| 1099 return request; | |
| 1100 }); | 1059 }); |
| 1101 } | 1060 } |
| 1102 | 1061 |
| 1103 Future<HttpClientRequest> _openUrlFromRequest(String method, | 1062 Future<HttpClientRequest> _openUrlFromRequest(String method, |
| 1104 Uri uri, | 1063 Uri uri, |
| 1105 _HttpClientRequest previous) { | 1064 _HttpClientRequest previous) { |
| 1106 return openUrl(method, uri).then((request) { | 1065 return openUrl(method, uri).then((request) { |
| 1107 // Only follow redirects if initial request did. | 1066 // Only follow redirects if initial request did. |
| 1108 request.followRedirects = previous.followRedirects; | 1067 request.followRedirects = previous.followRedirects; |
| 1109 // Allow same number of redirects. | 1068 // Allow same number of redirects. |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1213 static const _CLOSING = 2; | 1172 static const _CLOSING = 2; |
| 1214 static const _DETACHED = 3; | 1173 static const _DETACHED = 3; |
| 1215 | 1174 |
| 1216 int _state = _IDLE; | 1175 int _state = _IDLE; |
| 1217 | 1176 |
| 1218 final Socket _socket; | 1177 final Socket _socket; |
| 1219 final _HttpServer _httpServer; | 1178 final _HttpServer _httpServer; |
| 1220 final _HttpParser _httpParser; | 1179 final _HttpParser _httpParser; |
| 1221 StreamSubscription _subscription; | 1180 StreamSubscription _subscription; |
| 1222 | 1181 |
| 1223 Future _writeDoneFuture; | 1182 Future _streamFuture; |
| 1224 | 1183 |
| 1225 _HttpConnection(Socket this._socket, _HttpServer this._httpServer) | 1184 _HttpConnection(Socket this._socket, _HttpServer this._httpServer) |
| 1226 : _httpParser = new _HttpParser.requestParser() { | 1185 : _httpParser = new _HttpParser.requestParser() { |
| 1227 _socket.pipe(_httpParser); | 1186 _socket.pipe(_httpParser); |
| 1228 _socket.done.catchError((e) => destroy()); | 1187 _socket.done.catchError((e) => destroy()); |
| 1229 _subscription = _httpParser.listen( | 1188 _subscription = _httpParser.listen( |
| 1230 (incoming) { | 1189 (incoming) { |
| 1231 // Only handle one incoming request at the time. Keep the | 1190 // Only handle one incoming request at the time. Keep the |
| 1232 // stream paused until the request has been send. | 1191 // stream paused until the request has been send. |
| 1233 _subscription.pause(); | 1192 _subscription.pause(); |
| 1234 _state = _ACTIVE; | 1193 _state = _ACTIVE; |
| 1235 var outgoing = new _HttpOutgoing(); | 1194 var outgoing = new _HttpOutgoing(); |
| 1236 _writeDoneFuture = outgoing.stream.then(_socket.addStream); | 1195 var response = new _HttpResponse(incoming.headers.protocolVersion, |
| 1237 var response = new _HttpResponse( | 1196 outgoing); |
| 1238 incoming.headers.protocolVersion, | |
| 1239 outgoing); | |
| 1240 var request = new _HttpRequest(response, incoming, _httpServer, this); | 1197 var request = new _HttpRequest(response, incoming, _httpServer, this); |
| 1198 outgoing.onStream((stream) { |
| 1199 return _streamFuture = _socket.addStream(stream) |
| 1200 .then((_) { |
| 1201 if (_state == _DETACHED) return; |
| 1202 if (response.persistentConnection && |
| 1203 request.persistentConnection && |
| 1204 incoming.fullBodyRead) { |
| 1205 _state = _IDLE; |
| 1206 // Resume the subscription for incoming requests as the |
| 1207 // request is now processed. |
| 1208 _subscription.resume(); |
| 1209 } else { |
| 1210 // Close socket, keep-alive not used or body sent before |
| 1211 // received data was handled. |
| 1212 destroy(); |
| 1213 } |
| 1214 }) |
| 1215 .catchError((e) { |
| 1216 destroy(); |
| 1217 if (e.error is HttpException) throw e; |
| 1218 // TODO(ajohnsen): Where to send Socket errors? |
| 1219 }); |
| 1220 }); |
| 1241 response._ignoreBody = request.method == "HEAD"; | 1221 response._ignoreBody = request.method == "HEAD"; |
| 1242 response._httpRequest = request; | 1222 response._httpRequest = request; |
| 1243 outgoing.dataDone.then((_) { | |
| 1244 if (_state == _DETACHED) return; | |
| 1245 if (response.headers.persistentConnection && | |
| 1246 incoming.fullBodyRead) { | |
| 1247 // Wait for the socket to be done with writing, before we | |
| 1248 // continue. | |
| 1249 _writeDoneFuture.then((_) { | |
| 1250 _state = _IDLE; | |
| 1251 // Resume the subscription for incoming requests as the | |
| 1252 // request is now processed. | |
| 1253 _subscription.resume(); | |
| 1254 }); | |
| 1255 } else { | |
| 1256 // Close socket, keep-alive not used or body sent before received | |
| 1257 // data was handled. | |
| 1258 close(); | |
| 1259 } | |
| 1260 }).catchError((e) { | |
| 1261 close(); | |
| 1262 }); | |
| 1263 _httpServer._handleRequest(request); | 1223 _httpServer._handleRequest(request); |
| 1264 }, | 1224 }, |
| 1265 onDone: () { | 1225 onDone: () { |
| 1266 close(); | 1226 destroy(); |
| 1267 }, | 1227 }, |
| 1268 onError: (error) { | 1228 onError: (error) { |
| 1269 _httpServer._handleError(error); | 1229 _httpServer._handleError(error); |
| 1270 destroy(); | 1230 destroy(); |
| 1271 }); | 1231 }); |
| 1272 } | 1232 } |
| 1273 | 1233 |
| 1274 void destroy() { | 1234 void destroy() { |
| 1275 if (_state == _CLOSING || _state == _DETACHED) return; | 1235 if (_state == _CLOSING || _state == _DETACHED) return; |
| 1276 _state = _CLOSING; | 1236 _state = _CLOSING; |
| 1277 _socket.destroy(); | 1237 _socket.destroy(); |
| 1278 _httpServer._connectionClosed(this); | 1238 _httpServer._connectionClosed(this); |
| 1279 } | 1239 } |
| 1280 | 1240 |
| 1281 void close() { | |
| 1282 if (_state == _CLOSING || _state == _DETACHED) return; | |
| 1283 _state = _CLOSING; | |
| 1284 var future = _writeDoneFuture; | |
| 1285 if (future == null) future = new Future.immediate(null); | |
| 1286 _httpServer._connectionClosed(this); | |
| 1287 future.then((_) { | |
| 1288 _socket.close(); | |
| 1289 // TODO(ajohnsen): Add timeout. | |
| 1290 // Delay destroy until socket is actually done writing. | |
| 1291 _socket.done.then((_) => _socket.destroy(), | |
| 1292 onError: (_) => _socket.destroy()); | |
| 1293 }); | |
| 1294 } | |
| 1295 | |
| 1296 Future<Socket> detachSocket() { | 1241 Future<Socket> detachSocket() { |
| 1297 _state = _DETACHED; | 1242 _state = _DETACHED; |
| 1298 // Remove connection from server. | 1243 // Remove connection from server. |
| 1299 _httpServer._connectionClosed(this); | 1244 _httpServer._connectionClosed(this); |
| 1300 | 1245 |
| 1301 _HttpDetachedIncoming detachedIncoming = _httpParser.detachIncoming(); | 1246 _HttpDetachedIncoming detachedIncoming = _httpParser.detachIncoming(); |
| 1302 | 1247 |
| 1303 return _writeDoneFuture.then((_) { | 1248 return _streamFuture.then((_) { |
| 1304 return new _DetachedSocket(_socket, detachedIncoming); | 1249 return new _DetachedSocket(_socket, detachedIncoming); |
| 1305 }); | 1250 }); |
| 1306 } | 1251 } |
| 1307 | 1252 |
| 1308 HttpConnectionInfo get connectionInfo => _HttpConnectionInfo.create(_socket); | 1253 HttpConnectionInfo get connectionInfo => _HttpConnectionInfo.create(_socket); |
| 1309 | 1254 |
| 1310 bool get _isActive => _state == _ACTIVE; | 1255 bool get _isActive => _state == _ACTIVE; |
| 1311 bool get _isIdle => _state == _IDLE; | 1256 bool get _isIdle => _state == _IDLE; |
| 1312 bool get _isClosing => _state == _CLOSING; | 1257 bool get _isClosing => _state == _CLOSING; |
| 1313 bool get _isDetached => _state == _DETACHED; | 1258 bool get _isDetached => _state == _DETACHED; |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1656 | 1601 |
| 1657 | 1602 |
| 1658 class _RedirectInfo implements RedirectInfo { | 1603 class _RedirectInfo implements RedirectInfo { |
| 1659 const _RedirectInfo(int this.statusCode, | 1604 const _RedirectInfo(int this.statusCode, |
| 1660 String this.method, | 1605 String this.method, |
| 1661 Uri this.location); | 1606 Uri this.location); |
| 1662 final int statusCode; | 1607 final int statusCode; |
| 1663 final String method; | 1608 final String method; |
| 1664 final Uri location; | 1609 final Uri location; |
| 1665 } | 1610 } |
| OLD | NEW |