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 const int _OUTGOING_BUFFER_SIZE = 8 * 1024; | 7 const int _OUTGOING_BUFFER_SIZE = 8 * 1024; |
8 | 8 |
9 typedef void _BytesConsumer(List<int> bytes); | |
10 | |
11 class _HttpIncoming extends Stream<List<int>> { | 9 class _HttpIncoming extends Stream<List<int>> { |
12 final int _transferLength; | 10 final int _transferLength; |
13 final Completer _dataCompleter = new Completer(); | 11 final Completer _dataCompleter = new Completer(); |
14 Stream<List<int>> _stream; | 12 Stream<List<int>> _stream; |
15 | 13 |
16 bool fullBodyRead = false; | 14 bool fullBodyRead = false; |
17 | 15 |
18 // Common properties. | 16 // Common properties. |
19 final _HttpHeaders headers; | 17 final _HttpHeaders headers; |
20 bool upgraded = false; | 18 bool upgraded = false; |
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 | 259 |
262 StreamSubscription<List<int>> listen(void onData(List<int> event), | 260 StreamSubscription<List<int>> listen(void onData(List<int> event), |
263 {Function onError, | 261 {Function onError, |
264 void onDone(), | 262 void onDone(), |
265 bool cancelOnError}) { | 263 bool cancelOnError}) { |
266 if (_incoming.upgraded) { | 264 if (_incoming.upgraded) { |
267 // If upgraded, the connection is already 'removed' form the client. | 265 // If upgraded, the connection is already 'removed' form the client. |
268 // Since listening to upgraded data is 'bogus', simply close and | 266 // Since listening to upgraded data is 'bogus', simply close and |
269 // return empty stream subscription. | 267 // return empty stream subscription. |
270 _httpRequest._httpClientConnection.destroy(); | 268 _httpRequest._httpClientConnection.destroy(); |
271 return new Stream<List<int>>.empty().listen(null, onDone: onDone); | 269 return new Stream.fromIterable([]).listen(null, onDone: onDone); |
272 } | 270 } |
273 var stream = _incoming; | 271 var stream = _incoming; |
274 if (_httpClient.autoUncompress && | 272 if (_httpClient.autoUncompress && |
275 headers.value(HttpHeaders.CONTENT_ENCODING) == "gzip") { | 273 headers.value(HttpHeaders.CONTENT_ENCODING) == "gzip") { |
276 stream = stream.transform(GZIP.decoder); | 274 stream = stream.transform(GZIP.decoder); |
277 } | 275 } |
278 return stream.listen(onData, | 276 return stream.listen(onData, |
279 onError: onError, | 277 onError: onError, |
280 onDone: onDone, | 278 onDone: onDone, |
281 cancelOnError: cancelOnError); | 279 cancelOnError: cancelOnError); |
(...skipping 474 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
756 } | 754 } |
757 | 755 |
758 HttpConnectionInfo get connectionInfo => _httpClientConnection.connectionInfo; | 756 HttpConnectionInfo get connectionInfo => _httpClientConnection.connectionInfo; |
759 | 757 |
760 void _onIncoming(_HttpIncoming incoming) { | 758 void _onIncoming(_HttpIncoming incoming) { |
761 var response = new _HttpClientResponse(incoming, this, _httpClient); | 759 var response = new _HttpClientResponse(incoming, this, _httpClient); |
762 Future<HttpClientResponse> future; | 760 Future<HttpClientResponse> future; |
763 if (followRedirects && response.isRedirect) { | 761 if (followRedirects && response.isRedirect) { |
764 if (response.redirects.length < maxRedirects) { | 762 if (response.redirects.length < maxRedirects) { |
765 // Redirect and drain response. | 763 // Redirect and drain response. |
766 future = response.drain() | 764 future = response.drain().then((_) => response.redirect()); |
767 .then/*<HttpClientResponse>*/((_) => response.redirect()); | |
768 } else { | 765 } else { |
769 // End with exception, too many redirects. | 766 // End with exception, too many redirects. |
770 future = response.drain() | 767 future = response.drain() |
771 .then/*<HttpClientResponse>*/((_) { | 768 .then((_) => new Future.error( |
772 return new Future<HttpClientResponse>.error( | 769 new RedirectException("Redirect limit exceeded", |
773 new RedirectException("Redirect limit exceeded", | 770 response.redirects))); |
774 response.redirects)); | |
775 }); | |
776 } | 771 } |
777 } else if (response._shouldAuthenticateProxy) { | 772 } else if (response._shouldAuthenticateProxy) { |
778 future = response._authenticate(true); | 773 future = response._authenticate(true); |
779 } else if (response._shouldAuthenticate) { | 774 } else if (response._shouldAuthenticate) { |
780 future = response._authenticate(false); | 775 future = response._authenticate(false); |
781 } else { | 776 } else { |
782 future = new Future<HttpClientResponse>.value(response); | 777 future = new Future<HttpClientResponse>.value(response); |
783 } | 778 } |
784 future.then( | 779 future.then( |
785 (v) => _responseCompleter.complete(v), | 780 (v) => _responseCompleter.complete(v), |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
859 offset = headers._write(buffer, offset); | 854 offset = headers._write(buffer, offset); |
860 buffer[offset++] = _CharCode.CR; | 855 buffer[offset++] = _CharCode.CR; |
861 buffer[offset++] = _CharCode.LF; | 856 buffer[offset++] = _CharCode.LF; |
862 _outgoing.setHeader(buffer, offset); | 857 _outgoing.setHeader(buffer, offset); |
863 } | 858 } |
864 } | 859 } |
865 | 860 |
866 // Used by _HttpOutgoing as a target of a chunked converter for gzip | 861 // Used by _HttpOutgoing as a target of a chunked converter for gzip |
867 // compression. | 862 // compression. |
868 class _HttpGZipSink extends ByteConversionSink { | 863 class _HttpGZipSink extends ByteConversionSink { |
869 final _BytesConsumer _consume; | 864 final Function _consume; |
870 _HttpGZipSink(this._consume); | 865 _HttpGZipSink(this._consume); |
871 | 866 |
872 void add(List<int> chunk) { | 867 void add(List<int> chunk) { |
873 _consume(chunk); | 868 _consume(chunk); |
874 } | 869 } |
875 | 870 |
876 void addSlice(List<int> chunk, int start, int end, bool isLast) { | 871 void addSlice(List<int> chunk, int start, int end, bool isLast) { |
877 if (chunk is Uint8List) { | 872 if (chunk is Uint8List) { |
878 _consume(new Uint8List.view(chunk.buffer, start, end - start)); | 873 _consume(new Uint8List.view(chunk.buffer, start, end - start)); |
879 } else { | 874 } else { |
(...skipping 14 matching lines...) Expand all Loading... |
894 // Most notable is the GZip compression, that uses a double-buffering system, | 889 // Most notable is the GZip compression, that uses a double-buffering system, |
895 // one before gzip (_gzipBuffer) and one after (_buffer). | 890 // one before gzip (_gzipBuffer) and one after (_buffer). |
896 class _HttpOutgoing implements StreamConsumer<List<int>> { | 891 class _HttpOutgoing implements StreamConsumer<List<int>> { |
897 static const List<int> _footerAndChunk0Length = | 892 static const List<int> _footerAndChunk0Length = |
898 const [_CharCode.CR, _CharCode.LF, 0x30, _CharCode.CR, _CharCode.LF, | 893 const [_CharCode.CR, _CharCode.LF, 0x30, _CharCode.CR, _CharCode.LF, |
899 _CharCode.CR, _CharCode.LF]; | 894 _CharCode.CR, _CharCode.LF]; |
900 | 895 |
901 static const List<int> _chunk0Length = | 896 static const List<int> _chunk0Length = |
902 const [0x30, _CharCode.CR, _CharCode.LF, _CharCode.CR, _CharCode.LF]; | 897 const [0x30, _CharCode.CR, _CharCode.LF, _CharCode.CR, _CharCode.LF]; |
903 | 898 |
904 final Completer<Socket> _doneCompleter = new Completer<Socket>(); | 899 final Completer _doneCompleter = new Completer(); |
905 final Socket socket; | 900 final Socket socket; |
906 | 901 |
907 bool ignoreBody = false; | 902 bool ignoreBody = false; |
908 bool headersWritten = false; | 903 bool headersWritten = false; |
909 | 904 |
910 Uint8List _buffer; | 905 Uint8List _buffer; |
911 int _length = 0; | 906 int _length = 0; |
912 | 907 |
913 Future _closeFuture; | 908 Future _closeFuture; |
914 | 909 |
915 bool chunked = false; | 910 bool chunked = false; |
916 int _pendingChunkedFooter = 0; | 911 int _pendingChunkedFooter = 0; |
917 | 912 |
918 int contentLength; | 913 int contentLength; |
919 int _bytesWritten = 0; | 914 int _bytesWritten = 0; |
920 | 915 |
921 bool _gzip = false; | 916 bool _gzip = false; |
922 ByteConversionSink _gzipSink; | 917 ByteConversionSink _gzipSink; |
923 // _gzipAdd is set iff the sink is being added to. It's used to specify where | 918 // _gzipAdd is set iff the sink is being added to. It's used to specify where |
924 // gzipped data should be taken (sometimes a controller, sometimes a socket). | 919 // gzipped data should be taken (sometimes a controller, sometimes a socket). |
925 _BytesConsumer _gzipAdd; | 920 Function _gzipAdd; |
926 Uint8List _gzipBuffer; | 921 Uint8List _gzipBuffer; |
927 int _gzipBufferLength = 0; | 922 int _gzipBufferLength = 0; |
928 | 923 |
929 bool _socketError = false; | 924 bool _socketError = false; |
930 | 925 |
931 _HttpOutboundMessage outbound; | 926 _HttpOutboundMessage outbound; |
932 | 927 |
933 _HttpOutgoing(this.socket); | 928 _HttpOutgoing(this.socket); |
934 | 929 |
935 // Returns either a future or 'null', if it was able to write headers | 930 // Returns either a future or 'null', if it was able to write headers |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1000 return new Future.value(outbound); | 995 return new Future.value(outbound); |
1001 } | 996 } |
1002 if (ignoreBody) { | 997 if (ignoreBody) { |
1003 stream.drain().catchError((_) {}); | 998 stream.drain().catchError((_) {}); |
1004 var future = writeHeaders(); | 999 var future = writeHeaders(); |
1005 if (future != null) { | 1000 if (future != null) { |
1006 return future.then((_) => close()); | 1001 return future.then((_) => close()); |
1007 } | 1002 } |
1008 return close(); | 1003 return close(); |
1009 } | 1004 } |
1010 StreamSubscription<List<int>> sub; | 1005 var sub; |
1011 // Use new stream so we are able to pause (see below listen). The | 1006 // Use new stream so we are able to pause (see below listen). The |
1012 // alternative is to use stream.extand, but that won't give us a way of | 1007 // alternative is to use stream.extand, but that won't give us a way of |
1013 // pausing. | 1008 // pausing. |
1014 var controller = new StreamController<List<int>>( | 1009 var controller = new StreamController( |
1015 onPause: () => sub.pause(), | 1010 onPause: () => sub.pause(), |
1016 onResume: () => sub.resume(), | 1011 onResume: () => sub.resume(), |
1017 sync: true); | 1012 sync: true); |
1018 | 1013 |
1019 void onData(List<int> data) { | 1014 void onData(data) { |
1020 if (_socketError) return; | 1015 if (_socketError) return; |
1021 if (data.length == 0) return; | 1016 if (data.length == 0) return; |
1022 if (chunked) { | 1017 if (chunked) { |
1023 if (_gzip) { | 1018 if (_gzip) { |
1024 _gzipAdd = controller.add; | 1019 _gzipAdd = controller.add; |
1025 _addGZipChunk(data, _gzipSink.add); | 1020 _addGZipChunk(data, _gzipSink.add); |
1026 _gzipAdd = null; | 1021 _gzipAdd = null; |
1027 return; | 1022 return; |
1028 } | 1023 } |
1029 _addChunk(_chunkHeader(data.length), controller.add); | 1024 _addChunk(_chunkHeader(data.length), controller.add); |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1149 }); | 1144 }); |
1150 } | 1145 } |
1151 | 1146 |
1152 var future = writeHeaders(); | 1147 var future = writeHeaders(); |
1153 if (future != null) { | 1148 if (future != null) { |
1154 return _closeFuture = future.whenComplete(finalize); | 1149 return _closeFuture = future.whenComplete(finalize); |
1155 } | 1150 } |
1156 return _closeFuture = finalize(); | 1151 return _closeFuture = finalize(); |
1157 } | 1152 } |
1158 | 1153 |
1159 Future<Socket> get done => _doneCompleter.future; | 1154 Future get done => _doneCompleter.future; |
1160 | 1155 |
1161 void setHeader(List<int> data, int length) { | 1156 void setHeader(List<int> data, int length) { |
1162 assert(_length == 0); | 1157 assert(_length == 0); |
1163 assert(data.length == _OUTGOING_BUFFER_SIZE); | 1158 assert(data.length == _OUTGOING_BUFFER_SIZE); |
1164 _buffer = data; | 1159 _buffer = data; |
1165 _length = length; | 1160 _length = length; |
1166 } | 1161 } |
1167 | 1162 |
1168 void set gzip(bool value) { | 1163 void set gzip(bool value) { |
1169 _gzip = value; | 1164 _gzip = value; |
1170 if (_gzip) { | 1165 if (_gzip) { |
1171 _gzipBuffer = new Uint8List(_OUTGOING_BUFFER_SIZE); | 1166 _gzipBuffer = new Uint8List(_OUTGOING_BUFFER_SIZE); |
1172 assert(_gzipSink == null); | 1167 assert(_gzipSink == null); |
1173 _gzipSink = new ZLibEncoder(gzip: true) | 1168 _gzipSink = new ZLibEncoder(gzip: true) |
1174 .startChunkedConversion( | 1169 .startChunkedConversion( |
1175 new _HttpGZipSink((data) { | 1170 new _HttpGZipSink((data) { |
1176 // We are closing down prematurely, due to an error. Discard. | 1171 // We are closing down prematurely, due to an error. Discard. |
1177 if (_gzipAdd == null) return; | 1172 if (_gzipAdd == null) return; |
1178 _addChunk(_chunkHeader(data.length), _gzipAdd); | 1173 _addChunk(_chunkHeader(data.length), _gzipAdd); |
1179 _pendingChunkedFooter = 2; | 1174 _pendingChunkedFooter = 2; |
1180 _addChunk(data, _gzipAdd); | 1175 _addChunk(data, _gzipAdd); |
1181 })); | 1176 })); |
1182 } | 1177 } |
1183 } | 1178 } |
1184 | 1179 |
1185 bool _ignoreError(error) | 1180 bool _ignoreError(error) |
1186 => (error is SocketException || error is TlsException) && | 1181 => (error is SocketException || error is TlsException) && |
1187 outbound is HttpResponse; | 1182 outbound is HttpResponse; |
1188 | 1183 |
1189 void _addGZipChunk(List<int> chunk, void add(List<int> data)) { | 1184 void _addGZipChunk(chunk, void add(List<int> data)) { |
1190 if (!outbound.bufferOutput) { | 1185 if (!outbound.bufferOutput) { |
1191 add(chunk); | 1186 add(chunk); |
1192 return; | 1187 return; |
1193 } | 1188 } |
1194 if (chunk.length > _gzipBuffer.length - _gzipBufferLength) { | 1189 if (chunk.length > _gzipBuffer.length - _gzipBufferLength) { |
1195 add(new Uint8List.view( | 1190 add(new Uint8List.view( |
1196 _gzipBuffer.buffer, 0, _gzipBufferLength)); | 1191 _gzipBuffer.buffer, 0, _gzipBufferLength)); |
1197 _gzipBuffer = new Uint8List(_OUTGOING_BUFFER_SIZE); | 1192 _gzipBuffer = new Uint8List(_OUTGOING_BUFFER_SIZE); |
1198 _gzipBufferLength = 0; | 1193 _gzipBufferLength = 0; |
1199 } | 1194 } |
1200 if (chunk.length > _OUTGOING_BUFFER_SIZE) { | 1195 if (chunk.length > _OUTGOING_BUFFER_SIZE) { |
1201 add(chunk); | 1196 add(chunk); |
1202 } else { | 1197 } else { |
1203 _gzipBuffer.setRange(_gzipBufferLength, | 1198 _gzipBuffer.setRange(_gzipBufferLength, |
1204 _gzipBufferLength + chunk.length, | 1199 _gzipBufferLength + chunk.length, |
1205 chunk); | 1200 chunk); |
1206 _gzipBufferLength += chunk.length; | 1201 _gzipBufferLength += chunk.length; |
1207 } | 1202 } |
1208 } | 1203 } |
1209 | 1204 |
1210 void _addChunk(List<int> chunk, void add(List<int> data)) { | 1205 void _addChunk(chunk, void add(List<int> data)) { |
1211 if (!outbound.bufferOutput) { | 1206 if (!outbound.bufferOutput) { |
1212 if (_buffer != null) { | 1207 if (_buffer != null) { |
1213 // If _buffer is not null, we have not written the header yet. Write | 1208 // If _buffer is not null, we have not written the header yet. Write |
1214 // it now. | 1209 // it now. |
1215 add(new Uint8List.view(_buffer.buffer, 0, _length)); | 1210 add(new Uint8List.view(_buffer.buffer, 0, _length)); |
1216 _buffer = null; | 1211 _buffer = null; |
1217 _length = 0; | 1212 _length = 0; |
1218 } | 1213 } |
1219 add(chunk); | 1214 add(chunk); |
1220 return; | 1215 return; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1269 final SecurityContext _context; | 1264 final SecurityContext _context; |
1270 final _HttpParser _httpParser; | 1265 final _HttpParser _httpParser; |
1271 StreamSubscription _subscription; | 1266 StreamSubscription _subscription; |
1272 final _HttpClient _httpClient; | 1267 final _HttpClient _httpClient; |
1273 bool _dispose = false; | 1268 bool _dispose = false; |
1274 Timer _idleTimer; | 1269 Timer _idleTimer; |
1275 bool closed = false; | 1270 bool closed = false; |
1276 Uri _currentUri; | 1271 Uri _currentUri; |
1277 | 1272 |
1278 Completer<_HttpIncoming> _nextResponseCompleter; | 1273 Completer<_HttpIncoming> _nextResponseCompleter; |
1279 Future<Socket> _streamFuture; | 1274 Future _streamFuture; |
1280 | 1275 |
1281 _HttpClientConnection(this.key, this._socket, this._httpClient, | 1276 _HttpClientConnection(this.key, this._socket, this._httpClient, |
1282 [this._proxyTunnel = false, this._context]) | 1277 [this._proxyTunnel = false, this._context]) |
1283 : _httpParser = new _HttpParser.responseParser() { | 1278 : _httpParser = new _HttpParser.responseParser() { |
1284 _httpParser.listenToStream(_socket); | 1279 _httpParser.listenToStream(_socket); |
1285 | 1280 |
1286 // Set up handlers on the parser here, so we are sure to get 'onDone' from | 1281 // Set up handlers on the parser here, so we are sure to get 'onDone' from |
1287 // the parser. | 1282 // the parser. |
1288 _subscription = _httpParser.listen( | 1283 _subscription = _httpParser.listen( |
1289 (incoming) { | 1284 (incoming) { |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1384 // Look for credentials. | 1379 // Look for credentials. |
1385 creds = _httpClient._findCredentials(uri); | 1380 creds = _httpClient._findCredentials(uri); |
1386 if (creds != null) { | 1381 if (creds != null) { |
1387 creds.authorize(request); | 1382 creds.authorize(request); |
1388 } | 1383 } |
1389 } | 1384 } |
1390 // Start sending the request (lazy, delayed until the user provides | 1385 // Start sending the request (lazy, delayed until the user provides |
1391 // data). | 1386 // data). |
1392 _httpParser.isHead = method == "HEAD"; | 1387 _httpParser.isHead = method == "HEAD"; |
1393 _streamFuture = outgoing.done | 1388 _streamFuture = outgoing.done |
1394 .then/*<Socket>*/((Socket s) { | 1389 .then((s) { |
1395 // Request sent, set up response completer. | 1390 // Request sent, set up response completer. |
1396 _nextResponseCompleter = new Completer(); | 1391 _nextResponseCompleter = new Completer(); |
1397 | 1392 |
1398 // Listen for response. | 1393 // Listen for response. |
1399 _nextResponseCompleter.future | 1394 _nextResponseCompleter.future |
1400 .then((incoming) { | 1395 .then((incoming) { |
1401 _currentUri = null; | 1396 _currentUri = null; |
1402 incoming.dataDone.then((closing) { | 1397 incoming.dataDone.then((closing) { |
1403 if (incoming.upgraded) { | 1398 if (incoming.upgraded) { |
1404 _httpClient._connectionClosed(this); | 1399 _httpClient._connectionClosed(this); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1479 } | 1474 } |
1480 | 1475 |
1481 void close() { | 1476 void close() { |
1482 closed = true; | 1477 closed = true; |
1483 _httpClient._connectionClosed(this); | 1478 _httpClient._connectionClosed(this); |
1484 _streamFuture | 1479 _streamFuture |
1485 // TODO(ajohnsen): Add timeout. | 1480 // TODO(ajohnsen): Add timeout. |
1486 .then((_) => _socket.destroy()); | 1481 .then((_) => _socket.destroy()); |
1487 } | 1482 } |
1488 | 1483 |
1489 Future<_HttpClientConnection> createProxyTunnel(String host, int port, | 1484 Future<_HttpClientConnection> createProxyTunnel(host, port, proxy, callback) { |
1490 _Proxy proxy, bool callback(X509Certificate certificate)) { | |
1491 _HttpClientRequest request = | 1485 _HttpClientRequest request = |
1492 send(new Uri(host: host, port: port), | 1486 send(new Uri(host: host, port: port), |
1493 port, | 1487 port, |
1494 "CONNECT", | 1488 "CONNECT", |
1495 proxy); | 1489 proxy); |
1496 if (proxy.isAuthenticated) { | 1490 if (proxy.isAuthenticated) { |
1497 // If the proxy configuration contains user information use that | 1491 // If the proxy configuration contains user information use that |
1498 // for proxy basic authorization. | 1492 // for proxy basic authorization. |
1499 String auth = _CryptoUtils.bytesToBase64( | 1493 String auth = _CryptoUtils.bytesToBase64( |
1500 UTF8.encode("${proxy.username}:${proxy.password}")); | 1494 UTF8.encode("${proxy.username}:${proxy.password}")); |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1626 int uriPort, | 1620 int uriPort, |
1627 _Proxy proxy, | 1621 _Proxy proxy, |
1628 _HttpClient client) { | 1622 _HttpClient client) { |
1629 if (hasIdle) { | 1623 if (hasIdle) { |
1630 var connection = takeIdle(); | 1624 var connection = takeIdle(); |
1631 client._connectionsChanged(); | 1625 client._connectionsChanged(); |
1632 return new Future.value(new _ConnectionInfo(connection, proxy)); | 1626 return new Future.value(new _ConnectionInfo(connection, proxy)); |
1633 } | 1627 } |
1634 if (client.maxConnectionsPerHost != null && | 1628 if (client.maxConnectionsPerHost != null && |
1635 _active.length + _connecting >= client.maxConnectionsPerHost) { | 1629 _active.length + _connecting >= client.maxConnectionsPerHost) { |
1636 var completer = new Completer<_ConnectionInfo>(); | 1630 var completer = new Completer(); |
1637 _pending.add(() { | 1631 _pending.add(() { |
1638 completer.complete(connect(uriHost, uriPort, proxy, client)); | 1632 connect(uriHost, uriPort, proxy, client) |
| 1633 .then(completer.complete, onError: completer.completeError); |
1639 }); | 1634 }); |
1640 return completer.future; | 1635 return completer.future; |
1641 } | 1636 } |
1642 var currentBadCertificateCallback = client._badCertificateCallback; | 1637 var currentBadCertificateCallback = client._badCertificateCallback; |
1643 | 1638 |
1644 bool callback(X509Certificate certificate) { | 1639 bool callback(X509Certificate certificate) { |
1645 if (currentBadCertificateCallback == null) return false; | 1640 if (currentBadCertificateCallback == null) return false; |
1646 return currentBadCertificateCallback(certificate, uriHost, uriPort); | 1641 return currentBadCertificateCallback(certificate, uriHost, uriPort); |
1647 } | 1642 } |
1648 | 1643 |
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1944 int port = proxy.isDirect ? uriPort: proxy.port; | 1939 int port = proxy.isDirect ? uriPort: proxy.port; |
1945 return _getConnectionTarget(host, port, isSecure) | 1940 return _getConnectionTarget(host, port, isSecure) |
1946 .connect(uriHost, uriPort, proxy, this) | 1941 .connect(uriHost, uriPort, proxy, this) |
1947 // On error, continue with next proxy. | 1942 // On error, continue with next proxy. |
1948 .catchError(connect); | 1943 .catchError(connect); |
1949 } | 1944 } |
1950 // Make sure we go through the event loop before taking a | 1945 // Make sure we go through the event loop before taking a |
1951 // connection from the pool. For long-running synchronous code the | 1946 // connection from the pool. For long-running synchronous code the |
1952 // server might have closed the connection, so this lowers the | 1947 // server might have closed the connection, so this lowers the |
1953 // probability of getting a connection that was already closed. | 1948 // probability of getting a connection that was already closed. |
1954 return new Future<_ConnectionInfo>( | 1949 return new Future(() => connect(new HttpException("No proxies given"))); |
1955 () => connect(new HttpException("No proxies given"))); | |
1956 } | 1950 } |
1957 | 1951 |
1958 _SiteCredentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) { | 1952 _SiteCredentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) { |
1959 // Look for credentials. | 1953 // Look for credentials. |
1960 _SiteCredentials cr = | 1954 _SiteCredentials cr = |
1961 _credentials.fold(null, (_SiteCredentials prev, value) { | 1955 _credentials.fold(null, (_SiteCredentials prev, value) { |
1962 var siteCredentials = value as _SiteCredentials; | 1956 var siteCredentials = value as _SiteCredentials; |
1963 if (siteCredentials.applies(url, scheme)) { | 1957 if (siteCredentials.applies(url, scheme)) { |
1964 if (prev == null) return value; | 1958 if (prev == null) return value; |
1965 return siteCredentials.uri.path.length > prev.uri.path.length | 1959 return siteCredentials.uri.path.length > prev.uri.path.length |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2073 extends LinkedListEntry<_HttpConnection> with _ServiceObject { | 2067 extends LinkedListEntry<_HttpConnection> with _ServiceObject { |
2074 static const _ACTIVE = 0; | 2068 static const _ACTIVE = 0; |
2075 static const _IDLE = 1; | 2069 static const _IDLE = 1; |
2076 static const _CLOSING = 2; | 2070 static const _CLOSING = 2; |
2077 static const _DETACHED = 3; | 2071 static const _DETACHED = 3; |
2078 | 2072 |
2079 // Use HashMap, as we don't need to keep order. | 2073 // Use HashMap, as we don't need to keep order. |
2080 static Map<int, _HttpConnection> _connections = | 2074 static Map<int, _HttpConnection> _connections = |
2081 new HashMap<int, _HttpConnection>(); | 2075 new HashMap<int, _HttpConnection>(); |
2082 | 2076 |
2083 final /*_ServerSocket*/ _socket; | 2077 final _socket; |
2084 final _HttpServer _httpServer; | 2078 final _HttpServer _httpServer; |
2085 final _HttpParser _httpParser; | 2079 final _HttpParser _httpParser; |
2086 int _state = _IDLE; | 2080 int _state = _IDLE; |
2087 StreamSubscription _subscription; | 2081 StreamSubscription _subscription; |
2088 bool _idleMark = false; | 2082 bool _idleMark = false; |
2089 Future _streamFuture; | 2083 Future _streamFuture; |
2090 | 2084 |
2091 _HttpConnection(this._socket, this._httpServer) | 2085 _HttpConnection(this._socket, this._httpServer) |
2092 : _httpParser = new _HttpParser.requestParser() { | 2086 : _httpParser = new _HttpParser.requestParser() { |
2093 try { _socket._owner = this; } catch (_) { print(_); } | 2087 try { _socket._owner = this; } catch (_) { print(_); } |
2094 _connections[_serviceId] = this; | 2088 _connections[_serviceId] = this; |
2095 _httpParser.listenToStream(_socket as Object/*=Socket*/); | 2089 _httpParser.listenToStream(_socket); |
2096 _subscription = _httpParser.listen( | 2090 _subscription = _httpParser.listen( |
2097 (incoming) { | 2091 (incoming) { |
2098 _httpServer._markActive(this); | 2092 _httpServer._markActive(this); |
2099 // If the incoming was closed, close the connection. | 2093 // If the incoming was closed, close the connection. |
2100 incoming.dataDone.then((closing) { | 2094 incoming.dataDone.then((closing) { |
2101 if (closing) destroy(); | 2095 if (closing) destroy(); |
2102 }); | 2096 }); |
2103 // Only handle one incoming request at the time. Keep the | 2097 // Only handle one incoming request at the time. Keep the |
2104 // stream paused until the request has been send. | 2098 // stream paused until the request has been send. |
2105 _subscription.pause(); | 2099 _subscription.pause(); |
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2461 return r; | 2455 return r; |
2462 } | 2456 } |
2463 | 2457 |
2464 _HttpSessionManager _sessionManagerInstance; | 2458 _HttpSessionManager _sessionManagerInstance; |
2465 | 2459 |
2466 // Indicated if the http server has been closed. | 2460 // Indicated if the http server has been closed. |
2467 bool closed = false; | 2461 bool closed = false; |
2468 | 2462 |
2469 // The server listen socket. Untyped as it can be both ServerSocket and | 2463 // The server listen socket. Untyped as it can be both ServerSocket and |
2470 // SecureServerSocket. | 2464 // SecureServerSocket. |
2471 final dynamic/*ServerSocket|SecureServerSocket*/ _serverSocket; | 2465 final _serverSocket; |
2472 final bool _closeServer; | 2466 final bool _closeServer; |
2473 | 2467 |
2474 // Set of currently connected clients. | 2468 // Set of currently connected clients. |
2475 final LinkedList<_HttpConnection> _activeConnections | 2469 final LinkedList<_HttpConnection> _activeConnections |
2476 = new LinkedList<_HttpConnection>(); | 2470 = new LinkedList<_HttpConnection>(); |
2477 final LinkedList<_HttpConnection> _idleConnections | 2471 final LinkedList<_HttpConnection> _idleConnections |
2478 = new LinkedList<_HttpConnection>(); | 2472 = new LinkedList<_HttpConnection>(); |
2479 StreamController<HttpRequest> _controller; | 2473 StreamController<HttpRequest> _controller; |
2480 } | 2474 } |
2481 | 2475 |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2576 ..remotePort = socket.remotePort | 2570 ..remotePort = socket.remotePort |
2577 ..localPort = socket.port; | 2571 ..localPort = socket.port; |
2578 } catch (e) { } | 2572 } catch (e) { } |
2579 return null; | 2573 return null; |
2580 } | 2574 } |
2581 } | 2575 } |
2582 | 2576 |
2583 | 2577 |
2584 class _DetachedSocket extends Stream<List<int>> implements Socket { | 2578 class _DetachedSocket extends Stream<List<int>> implements Socket { |
2585 final Stream<List<int>> _incoming; | 2579 final Stream<List<int>> _incoming; |
2586 final Socket _socket; | 2580 final _socket; |
2587 | 2581 |
2588 _DetachedSocket(this._socket, this._incoming); | 2582 _DetachedSocket(this._socket, this._incoming); |
2589 | 2583 |
2590 StreamSubscription<List<int>> listen(void onData(List<int> event), | 2584 StreamSubscription<List<int>> listen(void onData(List<int> event), |
2591 {Function onError, | 2585 {Function onError, |
2592 void onDone(), | 2586 void onDone(), |
2593 bool cancelOnError}) { | 2587 bool cancelOnError}) { |
2594 return _incoming.listen(onData, | 2588 return _incoming.listen(onData, |
2595 onError: onError, | 2589 onError: onError, |
2596 onDone: onDone, | 2590 onDone: onDone, |
(...skipping 14 matching lines...) Expand all Loading... |
2611 | 2605 |
2612 void writeAll(Iterable objects, [String separator = ""]) { | 2606 void writeAll(Iterable objects, [String separator = ""]) { |
2613 _socket.writeAll(objects, separator); | 2607 _socket.writeAll(objects, separator); |
2614 } | 2608 } |
2615 | 2609 |
2616 void add(List<int> bytes) { _socket.add(bytes); } | 2610 void add(List<int> bytes) { _socket.add(bytes); } |
2617 | 2611 |
2618 void addError(error, [StackTrace stackTrace]) => | 2612 void addError(error, [StackTrace stackTrace]) => |
2619 _socket.addError(error, stackTrace); | 2613 _socket.addError(error, stackTrace); |
2620 | 2614 |
2621 Future addStream(Stream<List<int>> stream) { | 2615 Future<Socket> addStream(Stream<List<int>> stream) { |
2622 return _socket.addStream(stream); | 2616 return _socket.addStream(stream); |
2623 } | 2617 } |
2624 | 2618 |
2625 void destroy() { _socket.destroy(); } | 2619 void destroy() { _socket.destroy(); } |
2626 | 2620 |
2627 Future flush() => _socket.flush(); | 2621 Future flush() => _socket.flush(); |
2628 | 2622 |
2629 Future<Socket> close() => _socket.close(); | 2623 Future close() => _socket.close(); |
2630 | 2624 |
2631 Future<Socket> get done => _socket.done; | 2625 Future<Socket> get done => _socket.done; |
2632 | 2626 |
2633 int get port => _socket.port; | 2627 int get port => _socket.port; |
2634 | 2628 |
2635 InternetAddress get address => _socket.address; | 2629 InternetAddress get address => _socket.address; |
2636 | 2630 |
2637 InternetAddress get remoteAddress => _socket.remoteAddress; | 2631 InternetAddress get remoteAddress => _socket.remoteAddress; |
2638 | 2632 |
2639 int get remotePort => _socket.remotePort; | 2633 int get remotePort => _socket.remotePort; |
2640 | 2634 |
2641 bool setOption(SocketOption option, bool enabled) { | 2635 bool setOption(SocketOption option, bool enabled) { |
2642 return _socket.setOption(option, enabled); | 2636 return _socket.setOption(option, enabled); |
2643 } | 2637 } |
2644 | 2638 |
2645 Map _toJSON(bool ref) { | 2639 Map _toJSON(bool ref) => _socket._toJSON(ref); |
2646 return (_socket as dynamic)._toJSON(ref); | 2640 void set _owner(owner) { _socket._owner = owner; } |
2647 } | |
2648 void set _owner(owner) { | |
2649 (_socket as dynamic)._owner = owner; | |
2650 } | |
2651 } | 2641 } |
2652 | 2642 |
2653 | 2643 |
2654 class _AuthenticationScheme { | 2644 class _AuthenticationScheme { |
2655 final int _scheme; | 2645 final int _scheme; |
2656 | 2646 |
2657 static const UNKNOWN = const _AuthenticationScheme(-1); | 2647 static const UNKNOWN = const _AuthenticationScheme(-1); |
2658 static const BASIC = const _AuthenticationScheme(0); | 2648 static const BASIC = const _AuthenticationScheme(0); |
2659 static const DIGEST = const _AuthenticationScheme(1); | 2649 static const DIGEST = const _AuthenticationScheme(1); |
2660 | 2650 |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2891 const _RedirectInfo(this.statusCode, this.method, this.location); | 2881 const _RedirectInfo(this.statusCode, this.method, this.location); |
2892 } | 2882 } |
2893 | 2883 |
2894 String _getHttpVersion() { | 2884 String _getHttpVersion() { |
2895 var version = Platform.version; | 2885 var version = Platform.version; |
2896 // Only include major and minor version numbers. | 2886 // Only include major and minor version numbers. |
2897 int index = version.indexOf('.', version.indexOf('.') + 1); | 2887 int index = version.indexOf('.', version.indexOf('.') + 1); |
2898 version = version.substring(0, index); | 2888 version = version.substring(0, index); |
2899 return 'Dart/$version (dart:io)'; | 2889 return 'Dart/$version (dart:io)'; |
2900 } | 2890 } |
OLD | NEW |