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