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 extends Stream<List<int>> { | 7 class _HttpIncoming extends Stream<List<int>> { |
8 final int _transferLength; | 8 final int _transferLength; |
9 final Completer _dataCompleter = new Completer(); | 9 final Completer _dataCompleter = new Completer(); |
10 Stream<List<int>> _stream; | 10 Stream<List<int>> _stream; |
(...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
506 } | 506 } |
507 | 507 |
508 Future _addStream(Stream<List<int>> stream) { | 508 Future _addStream(Stream<List<int>> stream) { |
509 return _writeHeaders() | 509 return _writeHeaders() |
510 .then((_) { | 510 .then((_) { |
511 int contentLength = headers.contentLength; | 511 int contentLength = headers.contentLength; |
512 if (_ignoreBody) { | 512 if (_ignoreBody) { |
513 stream.drain().catchError((_) {}); | 513 stream.drain().catchError((_) {}); |
514 return _headersSink.close(); | 514 return _headersSink.close(); |
515 } | 515 } |
516 stream = stream.transform(new _BufferTransformer()); | 516 stream = stream.transform(const _BufferTransformer()); |
517 if (headers.chunkedTransferEncoding) { | 517 if (headers.chunkedTransferEncoding) { |
518 if (_asGZip) { | 518 if (_asGZip) { |
519 stream = stream.transform(GZIP.encoder); | 519 stream = stream.transform(GZIP.encoder); |
520 } | 520 } |
521 stream = stream.transform(new _ChunkedTransformer()); | 521 stream = stream.transform(const _ChunkedTransformer()); |
522 } else if (contentLength >= 0) { | 522 } else if (contentLength >= 0) { |
523 stream = stream.transform( | 523 stream = stream.transform( |
524 new _ContentLengthValidator(contentLength, _uri)); | 524 new _ContentLengthValidator(contentLength, _uri)); |
525 } | 525 } |
526 return _headersSink.addStream(stream); | 526 return _headersSink.addStream(stream); |
527 }); | 527 }); |
528 } | 528 } |
529 | 529 |
530 Future _close() { | 530 Future _close() { |
531 // TODO(ajohnsen): Currently, contentLength, chunkedTransferEncoding and | 531 // TODO(ajohnsen): Currently, contentLength, chunkedTransferEncoding and |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
639 .catchError((_) {}, test: _ignoreError) | 639 .catchError((_) {}, test: _ignoreError) |
640 .then((_) => _outbound); | 640 .then((_) => _outbound); |
641 } | 641 } |
642 if (_controller == null) return closeOutbound(); | 642 if (_controller == null) return closeOutbound(); |
643 _controller.close(); | 643 _controller.close(); |
644 return _closeCompleter.future.then((_) => closeOutbound()); | 644 return _closeCompleter.future.then((_) => closeOutbound()); |
645 } | 645 } |
646 } | 646 } |
647 | 647 |
648 | 648 |
649 class _BufferTransformer extends StreamEventTransformer<List<int>, List<int>> { | 649 class _BufferTransformerSink implements EventSink<List<int>> { |
650 static const int MIN_CHUNK_SIZE = 4 * 1024; | 650 static const int MIN_CHUNK_SIZE = 4 * 1024; |
651 static const int MAX_BUFFER_SIZE = 16 * 1024; | 651 static const int MAX_BUFFER_SIZE = 16 * 1024; |
652 | 652 |
653 final BytesBuilder _builder = new BytesBuilder(); | 653 final BytesBuilder _builder = new BytesBuilder(); |
| 654 final EventSink<List<int>> _outSink; |
654 | 655 |
655 void handleData(List<int> data, EventSink<List<int>> sink) { | 656 _BufferTransformerSink(this._outSink); |
| 657 |
| 658 void add(List<int> data) { |
656 // TODO(ajohnsen): Use timeout? | 659 // TODO(ajohnsen): Use timeout? |
657 if (data.length == 0) return; | 660 if (data.length == 0) return; |
658 if (data.length >= MIN_CHUNK_SIZE) { | 661 if (data.length >= MIN_CHUNK_SIZE) { |
659 flush(sink); | 662 flush(); |
660 sink.add(data); | 663 _outSink.add(data); |
661 } else { | 664 } else { |
662 _builder.add(data); | 665 _builder.add(data); |
663 if (_builder.length >= MAX_BUFFER_SIZE) { | 666 if (_builder.length >= MAX_BUFFER_SIZE) { |
664 flush(sink); | 667 flush(); |
665 } | 668 } |
666 } | 669 } |
667 } | 670 } |
668 | 671 |
669 void handleDone(EventSink<List<int>> sink) { | 672 void addError(Object error, [StackTrace stackTrace]) { |
670 flush(sink); | 673 _outSink.addError(error, stackTrace); |
671 sink.close(); | |
672 } | 674 } |
673 | 675 |
674 void flush(EventSink<List<int>> sink) { | 676 void close() { |
| 677 flush(); |
| 678 _outSink.close(); |
| 679 } |
| 680 |
| 681 void flush() { |
675 if (_builder.length > 0) { | 682 if (_builder.length > 0) { |
676 // takeBytes will clear the BytesBuilder. | 683 // takeBytes will clear the BytesBuilder. |
677 sink.add(_builder.takeBytes()); | 684 _outSink.add(_builder.takeBytes()); |
678 } | 685 } |
679 } | 686 } |
680 } | 687 } |
681 | 688 |
| 689 class _BufferTransformer implements StreamTransformer<List<int>, List<int>> { |
| 690 const _BufferTransformer(); |
| 691 |
| 692 Stream<List<int>> bind(Stream<List<int>> stream) { |
| 693 return new Stream<List<int>>.eventTransformed( |
| 694 stream, |
| 695 (EventSink outSink) => new _BufferTransformerSink(outSink)); |
| 696 } |
| 697 } |
| 698 |
682 | 699 |
683 class _HttpResponse extends _HttpOutboundMessage<HttpResponse> | 700 class _HttpResponse extends _HttpOutboundMessage<HttpResponse> |
684 implements HttpResponse { | 701 implements HttpResponse { |
685 int statusCode = 200; | 702 int statusCode = 200; |
686 String _reasonPhrase; | 703 String _reasonPhrase; |
687 List<Cookie> _cookies; | 704 List<Cookie> _cookies; |
688 _HttpRequest _httpRequest; | 705 _HttpRequest _httpRequest; |
689 Duration _deadline; | 706 Duration _deadline; |
690 Timer _deadlineTimer; | 707 Timer _deadlineTimer; |
691 | 708 |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1018 headers._finalize(); | 1035 headers._finalize(); |
1019 | 1036 |
1020 // Write headers. | 1037 // Write headers. |
1021 headers._write(builder); | 1038 headers._write(builder); |
1022 writeCRLF(); | 1039 writeCRLF(); |
1023 _headersSink.add(builder.takeBytes()); | 1040 _headersSink.add(builder.takeBytes()); |
1024 } | 1041 } |
1025 } | 1042 } |
1026 | 1043 |
1027 | 1044 |
1028 // Transformer that transforms data to HTTP Chunked Encoding. | 1045 class _ChunkedTransformerSink implements EventSink<List<int>> { |
1029 class _ChunkedTransformer extends StreamEventTransformer<List<int>, List<int>> { | 1046 |
1030 int _pendingFooter = 0; | 1047 int _pendingFooter = 0; |
| 1048 final EventSink<List<int>> _outSink; |
1031 | 1049 |
1032 void handleData(List<int> data, EventSink<List<int>> sink) { | 1050 _ChunkedTransformerSink(this._outSink); |
1033 sink.add(_chunkHeader(data.length)); | 1051 |
1034 if (data.length > 0) sink.add(data); | 1052 void add(List<int> data) { |
| 1053 _outSink.add(_chunkHeader(data.length)); |
| 1054 if (data.length > 0) _outSink.add(data); |
1035 _pendingFooter = 2; | 1055 _pendingFooter = 2; |
1036 } | 1056 } |
1037 | 1057 |
1038 void handleDone(EventSink<List<int>> sink) { | 1058 void addError(Object error, [StackTrace stackTrace]) { |
1039 handleData(const [], sink); | 1059 _outSink.addError(error, stackTrace); |
1040 sink.close(); | 1060 } |
| 1061 |
| 1062 void close() { |
| 1063 add(const []); |
| 1064 _outSink.close(); |
1041 } | 1065 } |
1042 | 1066 |
1043 List<int> _chunkHeader(int length) { | 1067 List<int> _chunkHeader(int length) { |
1044 const hexDigits = const [0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, | 1068 const hexDigits = const [0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, |
1045 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46]; | 1069 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46]; |
1046 if (length == 0) { | 1070 if (length == 0) { |
1047 if (_pendingFooter == 2) return _footerAndChunk0Length; | 1071 if (_pendingFooter == 2) return _footerAndChunk0Length; |
1048 return _chunk0Length; | 1072 return _chunk0Length; |
1049 } | 1073 } |
1050 int size = _pendingFooter; | 1074 int size = _pendingFooter; |
(...skipping 19 matching lines...) Expand all Loading... |
1070 } | 1094 } |
1071 | 1095 |
1072 static List<int> get _footerAndChunk0Length => new Uint8List.fromList( | 1096 static List<int> get _footerAndChunk0Length => new Uint8List.fromList( |
1073 const [_CharCode.CR, _CharCode.LF, 0x30, _CharCode.CR, _CharCode.LF, | 1097 const [_CharCode.CR, _CharCode.LF, 0x30, _CharCode.CR, _CharCode.LF, |
1074 _CharCode.CR, _CharCode.LF]); | 1098 _CharCode.CR, _CharCode.LF]); |
1075 | 1099 |
1076 static List<int> get _chunk0Length => new Uint8List.fromList( | 1100 static List<int> get _chunk0Length => new Uint8List.fromList( |
1077 const [0x30, _CharCode.CR, _CharCode.LF, _CharCode.CR, _CharCode.LF]); | 1101 const [0x30, _CharCode.CR, _CharCode.LF, _CharCode.CR, _CharCode.LF]); |
1078 } | 1102 } |
1079 | 1103 |
| 1104 // Transformer that transforms data to HTTP Chunked Encoding. |
| 1105 class _ChunkedTransformer implements StreamTransformer<List<int>, List<int>> { |
| 1106 const _ChunkedTransformer(); |
| 1107 |
| 1108 Stream<List<int>> bind(Stream<List<int>> stream) { |
| 1109 return new Stream<List<int>>.eventTransformed( |
| 1110 stream, |
| 1111 (EventSink<List<int>> sink) => new _ChunkedTransformerSink(sink)); |
| 1112 } |
| 1113 } |
1080 | 1114 |
1081 // Transformer that validates the content length. | 1115 // Transformer that validates the content length. |
1082 class _ContentLengthValidator | 1116 class _ContentLengthValidator |
1083 extends StreamEventTransformer<List<int>, List<int>> { | 1117 implements StreamTransformer<List<int>, List<int>>, EventSink<List<int>> { |
1084 final int expectedContentLength; | 1118 final int expectedContentLength; |
1085 final Uri uri; | 1119 final Uri uri; |
1086 int _bytesWritten = 0; | 1120 int _bytesWritten = 0; |
1087 | 1121 |
| 1122 EventSink<List<int>> _outSink; |
| 1123 |
1088 _ContentLengthValidator(int this.expectedContentLength, Uri this.uri); | 1124 _ContentLengthValidator(int this.expectedContentLength, Uri this.uri); |
1089 | 1125 |
1090 void handleData(List<int> data, EventSink<List<int>> sink) { | 1126 Stream<List<int>> bind(Stream<List<int>> stream) { |
| 1127 return new Stream.eventTransformed( |
| 1128 stream, |
| 1129 (EventSink sink) { |
| 1130 if (_outSink != null) { |
| 1131 throw new StateError("Validator transformer already used"); |
| 1132 } |
| 1133 _outSink = sink; |
| 1134 return this; |
| 1135 }); |
| 1136 } |
| 1137 |
| 1138 void add(List<int> data) { |
1091 _bytesWritten += data.length; | 1139 _bytesWritten += data.length; |
1092 if (_bytesWritten > expectedContentLength) { | 1140 if (_bytesWritten > expectedContentLength) { |
1093 sink.addError(new HttpException( | 1141 _outSink.addError(new HttpException( |
1094 "Content size exceeds specified contentLength. " | 1142 "Content size exceeds specified contentLength. " |
1095 "$_bytesWritten bytes written while expected " | 1143 "$_bytesWritten bytes written while expected " |
1096 "$expectedContentLength. " | 1144 "$expectedContentLength. " |
1097 "[${new String.fromCharCodes(data)}]", | 1145 "[${new String.fromCharCodes(data)}]", |
1098 uri: uri)); | 1146 uri: uri)); |
1099 sink.close(); | 1147 _outSink.close(); |
1100 } else { | 1148 } else { |
1101 sink.add(data); | 1149 _outSink.add(data); |
1102 } | 1150 } |
1103 } | 1151 } |
1104 | 1152 |
1105 void handleDone(EventSink<List<int>> sink) { | 1153 void addError(Object error, [StackTrace stackTrace]) { |
| 1154 _outSink.addError(error, stackTrace); |
| 1155 } |
| 1156 |
| 1157 void close() { |
1106 if (_bytesWritten < expectedContentLength) { | 1158 if (_bytesWritten < expectedContentLength) { |
1107 sink.addError(new HttpException( | 1159 _outSink.addError(new HttpException( |
1108 "Content size below specified contentLength. " | 1160 "Content size below specified contentLength. " |
1109 " $_bytesWritten bytes written while expected " | 1161 " $_bytesWritten bytes written while expected " |
1110 "$expectedContentLength.", | 1162 "$expectedContentLength.", |
1111 uri: uri)); | 1163 uri: uri)); |
1112 } | 1164 } |
1113 sink.close(); | 1165 _outSink.close(); |
1114 } | 1166 } |
1115 } | 1167 } |
1116 | 1168 |
1117 | 1169 |
1118 // Extends StreamConsumer as this is an internal type, only used to pipe to. | 1170 // Extends StreamConsumer as this is an internal type, only used to pipe to. |
1119 class _HttpOutgoing implements StreamConsumer<List<int>> { | 1171 class _HttpOutgoing implements StreamConsumer<List<int>> { |
1120 final Completer _doneCompleter = new Completer(); | 1172 final Completer _doneCompleter = new Completer(); |
1121 final Socket socket; | 1173 final Socket socket; |
1122 | 1174 |
1123 _HttpOutgoing(Socket this.socket); | 1175 _HttpOutgoing(Socket this.socket); |
(...skipping 1318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2442 final Uri location; | 2494 final Uri location; |
2443 } | 2495 } |
2444 | 2496 |
2445 String _getHttpVersion() { | 2497 String _getHttpVersion() { |
2446 var version = Platform.version; | 2498 var version = Platform.version; |
2447 // Only include major and minor version numbers. | 2499 // Only include major and minor version numbers. |
2448 int index = version.indexOf('.', version.indexOf('.') + 1); | 2500 int index = version.indexOf('.', version.indexOf('.') + 1); |
2449 version = version.substring(0, index); | 2501 version = version.substring(0, index); |
2450 return 'Dart/$version (dart:io)'; | 2502 return 'Dart/$version (dart:io)'; |
2451 } | 2503 } |
OLD | NEW |