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); | 9 typedef void _BytesConsumer(List<int> bytes); |
10 | 10 |
(...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
567 if (_deadlineTimer != null) _deadlineTimer.cancel(); | 567 if (_deadlineTimer != null) _deadlineTimer.cancel(); |
568 _deadline = d; | 568 _deadline = d; |
569 | 569 |
570 if (_deadline == null) return; | 570 if (_deadline == null) return; |
571 _deadlineTimer = new Timer(_deadline, () { | 571 _deadlineTimer = new Timer(_deadline, () { |
572 _httpRequest._httpConnection.destroy(); | 572 _httpRequest._httpConnection.destroy(); |
573 }); | 573 }); |
574 } | 574 } |
575 | 575 |
576 void _writeHeader() { | 576 void _writeHeader() { |
577 Uint8List buffer = new Uint8List(_OUTGOING_BUFFER_SIZE); | 577 BytesBuilder buffer = new _CopyingBytesBuilder(_OUTGOING_BUFFER_SIZE); |
578 int offset = 0; | |
579 | |
580 void write(List<int> bytes) { | |
581 int len = bytes.length; | |
582 for (int i = 0; i < len; i++) { | |
583 buffer[offset + i] = bytes[i]; | |
584 } | |
585 offset += len; | |
586 } | |
587 | 578 |
588 // Write status line. | 579 // Write status line. |
589 if (headers.protocolVersion == "1.1") { | 580 if (headers.protocolVersion == "1.1") { |
590 write(_Const.HTTP11); | 581 buffer.add(_Const.HTTP11); |
591 } else { | 582 } else { |
592 write(_Const.HTTP10); | 583 buffer.add(_Const.HTTP10); |
593 } | 584 } |
594 buffer[offset++] = _CharCode.SP; | 585 buffer.addByte(_CharCode.SP); |
595 write(statusCode.toString().codeUnits); | 586 buffer.add(statusCode.toString().codeUnits); |
596 buffer[offset++] = _CharCode.SP; | 587 buffer.addByte(_CharCode.SP); |
597 write(reasonPhrase.codeUnits); | 588 buffer.add(reasonPhrase.codeUnits); |
598 buffer[offset++] = _CharCode.CR; | 589 buffer.addByte(_CharCode.CR); |
599 buffer[offset++] = _CharCode.LF; | 590 buffer.addByte(_CharCode.LF); |
600 | 591 |
601 var session = _httpRequest._session; | 592 var session = _httpRequest._session; |
602 if (session != null && !session._destroyed) { | 593 if (session != null && !session._destroyed) { |
603 // Mark as not new. | 594 // Mark as not new. |
604 session._isNew = false; | 595 session._isNew = false; |
605 // Make sure we only send the current session id. | 596 // Make sure we only send the current session id. |
606 bool found = false; | 597 bool found = false; |
607 for (int i = 0; i < cookies.length; i++) { | 598 for (int i = 0; i < cookies.length; i++) { |
608 if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) { | 599 if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) { |
609 cookies[i] | 600 cookies[i] |
(...skipping 13 matching lines...) Expand all Loading... |
623 // Add all the cookies set to the headers. | 614 // Add all the cookies set to the headers. |
624 if (_cookies != null) { | 615 if (_cookies != null) { |
625 _cookies.forEach((cookie) { | 616 _cookies.forEach((cookie) { |
626 headers.add(HttpHeaders.SET_COOKIE, cookie); | 617 headers.add(HttpHeaders.SET_COOKIE, cookie); |
627 }); | 618 }); |
628 } | 619 } |
629 | 620 |
630 headers._finalize(); | 621 headers._finalize(); |
631 | 622 |
632 // Write headers. | 623 // Write headers. |
633 offset = headers._write(buffer, offset); | 624 headers._build(buffer); |
634 buffer[offset++] = _CharCode.CR; | 625 buffer.addByte(_CharCode.CR); |
635 buffer[offset++] = _CharCode.LF; | 626 buffer.addByte(_CharCode.LF); |
636 _outgoing.setHeader(buffer, offset); | 627 Uint8List headerBytes = buffer.takeBytes(); |
| 628 _outgoing.setHeader(headerBytes, headerBytes.length); |
637 } | 629 } |
638 | 630 |
639 String _findReasonPhrase(int statusCode) { | 631 String _findReasonPhrase(int statusCode) { |
640 if (_reasonPhrase != null) { | 632 if (_reasonPhrase != null) { |
641 return _reasonPhrase; | 633 return _reasonPhrase; |
642 } | 634 } |
643 | 635 |
644 switch (statusCode) { | 636 switch (statusCode) { |
645 case HttpStatus.CONTINUE: return "Continue"; | 637 case HttpStatus.CONTINUE: return "Continue"; |
646 case HttpStatus.SWITCHING_PROTOCOLS: return "Switching Protocols"; | 638 case HttpStatus.SWITCHING_PROTOCOLS: return "Switching Protocols"; |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
814 if (_httpClientConnection._proxyTunnel) { | 806 if (_httpClientConnection._proxyTunnel) { |
815 return uriStartingFromPath(); | 807 return uriStartingFromPath(); |
816 } else { | 808 } else { |
817 return uri.removeFragment().toString(); | 809 return uri.removeFragment().toString(); |
818 } | 810 } |
819 } | 811 } |
820 } | 812 } |
821 } | 813 } |
822 | 814 |
823 void _writeHeader() { | 815 void _writeHeader() { |
824 Uint8List buffer = new Uint8List(_OUTGOING_BUFFER_SIZE); | 816 BytesBuilder buffer = new _CopyingBytesBuilder(_OUTGOING_BUFFER_SIZE); |
825 int offset = 0; | |
826 | |
827 void write(List<int> bytes) { | |
828 int len = bytes.length; | |
829 for (int i = 0; i < len; i++) { | |
830 buffer[offset + i] = bytes[i]; | |
831 } | |
832 offset += len; | |
833 } | |
834 | 817 |
835 // Write the request method. | 818 // Write the request method. |
836 write(method.codeUnits); | 819 buffer.add(method.codeUnits); |
837 buffer[offset++] = _CharCode.SP; | 820 buffer.addByte(_CharCode.SP); |
838 // Write the request URI. | 821 // Write the request URI. |
839 write(_requestUri().codeUnits); | 822 buffer.add(_requestUri().codeUnits); |
840 buffer[offset++] = _CharCode.SP; | 823 buffer.addByte(_CharCode.SP); |
841 // Write HTTP/1.1. | 824 // Write HTTP/1.1. |
842 write(_Const.HTTP11); | 825 buffer.add(_Const.HTTP11); |
843 buffer[offset++] = _CharCode.CR; | 826 buffer.addByte(_CharCode.CR); |
844 buffer[offset++] = _CharCode.LF; | 827 buffer.addByte(_CharCode.LF); |
845 | 828 |
846 // Add the cookies to the headers. | 829 // Add the cookies to the headers. |
847 if (!cookies.isEmpty) { | 830 if (!cookies.isEmpty) { |
848 StringBuffer sb = new StringBuffer(); | 831 StringBuffer sb = new StringBuffer(); |
849 for (int i = 0; i < cookies.length; i++) { | 832 for (int i = 0; i < cookies.length; i++) { |
850 if (i > 0) sb.write("; "); | 833 if (i > 0) sb.write("; "); |
851 sb..write(cookies[i].name)..write("=")..write(cookies[i].value); | 834 sb..write(cookies[i].name)..write("=")..write(cookies[i].value); |
852 } | 835 } |
853 headers.add(HttpHeaders.COOKIE, sb.toString()); | 836 headers.add(HttpHeaders.COOKIE, sb.toString()); |
854 } | 837 } |
855 | 838 |
856 headers._finalize(); | 839 headers._finalize(); |
857 | 840 |
858 // Write headers. | 841 // Write headers. |
859 offset = headers._write(buffer, offset); | 842 headers._build(buffer); |
860 buffer[offset++] = _CharCode.CR; | 843 buffer.addByte(_CharCode.CR); |
861 buffer[offset++] = _CharCode.LF; | 844 buffer.addByte(_CharCode.LF); |
862 _outgoing.setHeader(buffer, offset); | 845 Uint8List headerBytes = buffer.takeBytes(); |
| 846 _outgoing.setHeader(headerBytes, headerBytes.length); |
863 } | 847 } |
864 } | 848 } |
865 | 849 |
866 // Used by _HttpOutgoing as a target of a chunked converter for gzip | 850 // Used by _HttpOutgoing as a target of a chunked converter for gzip |
867 // compression. | 851 // compression. |
868 class _HttpGZipSink extends ByteConversionSink { | 852 class _HttpGZipSink extends ByteConversionSink { |
869 final _BytesConsumer _consume; | 853 final _BytesConsumer _consume; |
870 _HttpGZipSink(this._consume); | 854 _HttpGZipSink(this._consume); |
871 | 855 |
872 void add(List<int> chunk) { | 856 void add(List<int> chunk) { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
928 | 912 |
929 bool _socketError = false; | 913 bool _socketError = false; |
930 | 914 |
931 _HttpOutboundMessage outbound; | 915 _HttpOutboundMessage outbound; |
932 | 916 |
933 _HttpOutgoing(this.socket); | 917 _HttpOutgoing(this.socket); |
934 | 918 |
935 // Returns either a future or 'null', if it was able to write headers | 919 // Returns either a future or 'null', if it was able to write headers |
936 // immediately. | 920 // immediately. |
937 Future writeHeaders({bool drainRequest: true, bool setOutgoing: true}) { | 921 Future writeHeaders({bool drainRequest: true, bool setOutgoing: true}) { |
938 Future write() { | |
939 try { | |
940 outbound._writeHeader(); | |
941 } catch (_) { | |
942 // Headers too large. | |
943 return new Future.error(new HttpException( | |
944 "Headers size exceeded the of '$_OUTGOING_BUFFER_SIZE'" | |
945 " bytes")); | |
946 } | |
947 return null; | |
948 } | |
949 | |
950 if (headersWritten) return null; | 922 if (headersWritten) return null; |
951 headersWritten = true; | 923 headersWritten = true; |
952 Future drainFuture; | 924 Future drainFuture; |
953 bool gzip = false; | 925 bool gzip = false; |
954 if (outbound is _HttpResponse) { | 926 if (outbound is _HttpResponse) { |
955 // Server side. | 927 // Server side. |
956 _HttpResponse response = outbound; | 928 _HttpResponse response = outbound; |
957 if (response._httpRequest._httpServer.autoCompress && | 929 if (response._httpRequest._httpServer.autoCompress && |
958 outbound.bufferOutput && | 930 outbound.bufferOutput && |
959 outbound.headers.chunkedTransferEncoding) { | 931 outbound.headers.chunkedTransferEncoding) { |
960 List acceptEncodings = | 932 List acceptEncodings = |
961 response._httpRequest.headers[HttpHeaders.ACCEPT_ENCODING]; | 933 response._httpRequest.headers[HttpHeaders.ACCEPT_ENCODING]; |
962 List contentEncoding = outbound.headers[HttpHeaders.CONTENT_ENCODING]; | 934 List contentEncoding = outbound.headers[HttpHeaders.CONTENT_ENCODING]; |
963 if (acceptEncodings != null && | 935 if (acceptEncodings != null && |
964 acceptEncodings | 936 acceptEncodings |
965 .expand((list) => list.split(",")) | 937 .expand((list) => list.split(",")) |
966 .any((encoding) => encoding.trim().toLowerCase() == "gzip") && | 938 .any((encoding) => encoding.trim().toLowerCase() == "gzip") && |
967 contentEncoding == null) { | 939 contentEncoding == null) { |
968 outbound.headers.set(HttpHeaders.CONTENT_ENCODING, "gzip"); | 940 outbound.headers.set(HttpHeaders.CONTENT_ENCODING, "gzip"); |
969 gzip = true; | 941 gzip = true; |
970 } | 942 } |
971 } | 943 } |
972 if (drainRequest && !response._httpRequest._incoming.hasSubscriber) { | 944 if (drainRequest && !response._httpRequest._incoming.hasSubscriber) { |
973 drainFuture = response._httpRequest.drain().catchError((_) {}); | 945 drainFuture = response._httpRequest.drain().catchError((_) {}); |
974 } | 946 } |
975 } else { | 947 } else { |
976 drainRequest = false; | 948 drainRequest = false; |
977 } | 949 } |
978 if (ignoreBody) { | 950 if (!ignoreBody) { |
979 return write(); | 951 if (setOutgoing) { |
980 } | 952 int contentLength = outbound.headers.contentLength; |
981 if (setOutgoing) { | 953 if (outbound.headers.chunkedTransferEncoding) { |
982 int contentLength = outbound.headers.contentLength; | 954 chunked = true; |
983 if (outbound.headers.chunkedTransferEncoding) { | 955 if (gzip) this.gzip = true; |
984 chunked = true; | 956 } else if (contentLength >= 0) { |
985 if (gzip) this.gzip = true; | 957 this.contentLength = contentLength; |
986 } else if (contentLength >= 0) { | 958 } |
987 this.contentLength = contentLength; | 959 } |
| 960 if (drainFuture != null) { |
| 961 return drainFuture.then((_) => outbound._writeHeader()); |
988 } | 962 } |
989 } | 963 } |
990 if (drainFuture != null) { | 964 outbound._writeHeader(); |
991 return drainFuture.then((_) => write()); | 965 return null; |
992 } | |
993 return write(); | |
994 } | 966 } |
995 | 967 |
996 | 968 |
997 Future addStream(Stream<List<int>> stream) { | 969 Future addStream(Stream<List<int>> stream) { |
998 if (_socketError) { | 970 if (_socketError) { |
999 stream.listen(null).cancel(); | 971 stream.listen(null).cancel(); |
1000 return new Future.value(outbound); | 972 return new Future.value(outbound); |
1001 } | 973 } |
1002 if (ignoreBody) { | 974 if (ignoreBody) { |
1003 stream.drain().catchError((_) {}); | 975 stream.drain().catchError((_) {}); |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1153 if (future != null) { | 1125 if (future != null) { |
1154 return _closeFuture = future.whenComplete(finalize); | 1126 return _closeFuture = future.whenComplete(finalize); |
1155 } | 1127 } |
1156 return _closeFuture = finalize(); | 1128 return _closeFuture = finalize(); |
1157 } | 1129 } |
1158 | 1130 |
1159 Future<Socket> get done => _doneCompleter.future; | 1131 Future<Socket> get done => _doneCompleter.future; |
1160 | 1132 |
1161 void setHeader(List<int> data, int length) { | 1133 void setHeader(List<int> data, int length) { |
1162 assert(_length == 0); | 1134 assert(_length == 0); |
1163 assert(data.length == _OUTGOING_BUFFER_SIZE); | |
1164 _buffer = data; | 1135 _buffer = data; |
1165 _length = length; | 1136 _length = length; |
1166 } | 1137 } |
1167 | 1138 |
1168 void set gzip(bool value) { | 1139 void set gzip(bool value) { |
1169 _gzip = value; | 1140 _gzip = value; |
1170 if (_gzip) { | 1141 if (_gzip) { |
1171 _gzipBuffer = new Uint8List(_OUTGOING_BUFFER_SIZE); | 1142 _gzipBuffer = new Uint8List(_OUTGOING_BUFFER_SIZE); |
1172 assert(_gzipSink == null); | 1143 assert(_gzipSink == null); |
1173 _gzipSink = new ZLibEncoder(gzip: true) | 1144 _gzipSink = new ZLibEncoder(gzip: true) |
(...skipping 1717 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2891 const _RedirectInfo(this.statusCode, this.method, this.location); | 2862 const _RedirectInfo(this.statusCode, this.method, this.location); |
2892 } | 2863 } |
2893 | 2864 |
2894 String _getHttpVersion() { | 2865 String _getHttpVersion() { |
2895 var version = Platform.version; | 2866 var version = Platform.version; |
2896 // Only include major and minor version numbers. | 2867 // Only include major and minor version numbers. |
2897 int index = version.indexOf('.', version.indexOf('.') + 1); | 2868 int index = version.indexOf('.', version.indexOf('.') + 1); |
2898 version = version.substring(0, index); | 2869 version = version.substring(0, index); |
2899 return 'Dart/$version (dart:io)'; | 2870 return 'Dart/$version (dart:io)'; |
2900 } | 2871 } |
OLD | NEW |