| 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 |