Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(210)

Side by Side Diff: sdk/lib/io/http_impl.dart

Issue 65043019: Use a re-usable buffer for writing HTTP headers. This includes a new header limit of 8192 bytes. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Cleanup. Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sdk/lib/io/http_headers.dart ('k') | tests/standalone/io/http_client_request_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 _HEADERS_BUFFER_SIZE = 8 * 1024;
8
7 class _HttpIncoming extends Stream<List<int>> { 9 class _HttpIncoming extends Stream<List<int>> {
8 final int _transferLength; 10 final int _transferLength;
9 final Completer _dataCompleter = new Completer(); 11 final Completer _dataCompleter = new Completer();
10 Stream<List<int>> _stream; 12 Stream<List<int>> _stream;
11 13
12 bool fullBodyRead = false; 14 bool fullBodyRead = false;
13 15
14 // Common properties. 16 // Common properties.
15 final _HttpHeaders headers; 17 final _HttpHeaders headers;
16 bool upgraded = false; 18 bool upgraded = false;
(...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after
472 return _dataSink.flush(); 474 return _dataSink.flush();
473 } 475 }
474 476
475 Future close() { 477 Future close() {
476 return _dataSink.close(); 478 return _dataSink.close();
477 } 479 }
478 480
479 Future<T> get done => _dataSink.done; 481 Future<T> get done => _dataSink.done;
480 482
481 Future _writeHeaders({bool drainRequest: true}) { 483 Future _writeHeaders({bool drainRequest: true}) {
484 void write() {
485 try {
486 _writeHeader();
487 } catch (error) {
488 // Headers too large.
489 throw new HttpException(
490 "Headers size exceeded the of '$_HEADERS_BUFFER_SIZE' bytes");
491 }
492 }
482 if (_headersWritten) return new Future.value(); 493 if (_headersWritten) return new Future.value();
483 _headersWritten = true; 494 _headersWritten = true;
484 headers._synchronize(); // Be sure the 'chunked' option is updated. 495 headers._synchronize(); // Be sure the 'chunked' option is updated.
485 _dataSink.encoding = encoding; 496 _dataSink.encoding = encoding;
486 bool isServerSide = this is _HttpResponse; 497 bool isServerSide = this is _HttpResponse;
487 if (isServerSide) { 498 if (isServerSide) {
488 var response = this; 499 var response = this;
489 if (headers.chunkedTransferEncoding) { 500 if (headers.chunkedTransferEncoding) {
490 List acceptEncodings = 501 List acceptEncodings =
491 response._httpRequest.headers[HttpHeaders.ACCEPT_ENCODING]; 502 response._httpRequest.headers[HttpHeaders.ACCEPT_ENCODING];
492 List contentEncoding = headers[HttpHeaders.CONTENT_ENCODING]; 503 List contentEncoding = headers[HttpHeaders.CONTENT_ENCODING];
493 if (acceptEncodings != null && 504 if (acceptEncodings != null &&
494 acceptEncodings 505 acceptEncodings
495 .expand((list) => list.split(",")) 506 .expand((list) => list.split(","))
496 .any((encoding) => encoding.trim().toLowerCase() == "gzip") && 507 .any((encoding) => encoding.trim().toLowerCase() == "gzip") &&
497 contentEncoding == null) { 508 contentEncoding == null) {
498 headers.set(HttpHeaders.CONTENT_ENCODING, "gzip"); 509 headers.set(HttpHeaders.CONTENT_ENCODING, "gzip");
499 _asGZip = true; 510 _asGZip = true;
500 } 511 }
501 } 512 }
502 if (drainRequest && !response._httpRequest._incoming.hasSubscriber) { 513 if (drainRequest && !response._httpRequest._incoming.hasSubscriber) {
503 return response._httpRequest.drain() 514 return response._httpRequest.drain()
504 // TODO(ajohnsen): Timeout on drain? 515 // TODO(ajohnsen): Timeout on drain?
505 .catchError((_) {}) // Ignore errors. 516 .catchError((_) {}) // Ignore errors.
506 .then((_) => _writeHeader()); 517 .then((_) => write());
507 } 518 }
508 } 519 }
509 return new Future.sync(_writeHeader); 520 return new Future.sync(write);
510 } 521 }
511 522
512 Future _addStream(Stream<List<int>> stream) { 523 Future _addStream(Stream<List<int>> stream) {
513 return _writeHeaders() 524 return _writeHeaders()
514 .then((_) { 525 .then((_) {
515 int contentLength = headers.contentLength; 526 int contentLength = headers.contentLength;
516 if (_ignoreBody) { 527 if (_ignoreBody) {
517 stream.drain().catchError((_) {}); 528 stream.drain().catchError((_) {});
518 return _headersSink.close(); 529 return _headersSink.close();
519 } 530 }
(...skipping 22 matching lines...) Expand all
542 headers.chunkedTransferEncoding = false; 553 headers.chunkedTransferEncoding = false;
543 headers.contentLength = 0; 554 headers.contentLength = 0;
544 } else if (!_ignoreBody && headers.contentLength > 0) { 555 } else if (!_ignoreBody && headers.contentLength > 0) {
545 _headersSink.addError(new HttpException( 556 _headersSink.addError(new HttpException(
546 "No content while contentLength was specified to be greater " 557 "No content while contentLength was specified to be greater "
547 "than 0: ${headers.contentLength}.", 558 "than 0: ${headers.contentLength}.",
548 uri: _uri)); 559 uri: _uri));
549 return _headersSink.done; 560 return _headersSink.done;
550 } 561 }
551 } 562 }
552 return _writeHeaders().then((_) => _headersSink.close()); 563 return _writeHeaders().whenComplete(_headersSink.close);
553 } 564 }
554 565
555 void _writeHeader(); // TODO(ajohnsen): Better name. 566 void _writeHeader();
556 } 567 }
557 568
558 569
559 class _HttpOutboundConsumer implements StreamConsumer { 570 class _HttpOutboundConsumer implements StreamConsumer {
560 final _HttpOutboundMessage _outbound; 571 final _HttpOutboundMessage _outbound;
561 StreamController _controller; 572 StreamController _controller;
562 StreamSubscription _subscription; 573 StreamSubscription _subscription;
563 Completer _closeCompleter = new Completer(); 574 Completer _closeCompleter = new Completer();
564 Completer _completer; 575 Completer _completer;
565 bool _socketError = false; 576 bool _socketError = false;
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
762 if (_deadlineTimer != null) _deadlineTimer.cancel(); 773 if (_deadlineTimer != null) _deadlineTimer.cancel();
763 _deadline = d; 774 _deadline = d;
764 775
765 if (_deadline == null) return; 776 if (_deadline == null) return;
766 _deadlineTimer = new Timer(_deadline, () { 777 _deadlineTimer = new Timer(_deadline, () {
767 _outgoing.socket.destroy(); 778 _outgoing.socket.destroy();
768 }); 779 });
769 } 780 }
770 781
771 void _writeHeader() { 782 void _writeHeader() {
772 var builder = new BytesBuilder(); 783 Uint8List buffer = _httpRequest._httpConnection._headersBuffer;
773 writeSP() => builder.add(const [_CharCode.SP]); 784 int offset = 0;
774 writeCRLF() => builder.add(const [_CharCode.CR, _CharCode.LF]); 785
786 void write(List<int> bytes) {
787 int len = bytes.length;
788 for (int i = 0; i < len; i++) {
789 buffer[offset + i] = bytes[i];
790 }
791 offset += len;
792 }
775 793
776 // Write status line. 794 // Write status line.
777 if (headers.protocolVersion == "1.1") { 795 if (headers.protocolVersion == "1.1") {
778 builder.add(_Const.HTTP11); 796 write(_Const.HTTP11);
779 } else { 797 } else {
780 builder.add(_Const.HTTP10); 798 write(_Const.HTTP10);
781 } 799 }
782 writeSP(); 800 buffer[offset++] = _CharCode.SP;
783 builder.add(statusCode.toString().codeUnits); 801 write(statusCode.toString().codeUnits);
784 writeSP(); 802 buffer[offset++] = _CharCode.SP;
785 builder.add(reasonPhrase.codeUnits); 803 write(reasonPhrase.codeUnits);
786 writeCRLF(); 804 buffer[offset++] = _CharCode.CR;
805 buffer[offset++] = _CharCode.LF;
787 806
788 var session = _httpRequest._session; 807 var session = _httpRequest._session;
789 if (session != null && !session._destroyed) { 808 if (session != null && !session._destroyed) {
790 // Mark as not new. 809 // Mark as not new.
791 session._isNew = false; 810 session._isNew = false;
792 // Make sure we only send the current session id. 811 // Make sure we only send the current session id.
793 bool found = false; 812 bool found = false;
794 for (int i = 0; i < cookies.length; i++) { 813 for (int i = 0; i < cookies.length; i++) {
795 if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) { 814 if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) {
796 cookies[i].value = session.id; 815 cookies[i].value = session.id;
(...skipping 12 matching lines...) Expand all
809 // Add all the cookies set to the headers. 828 // Add all the cookies set to the headers.
810 if (_cookies != null) { 829 if (_cookies != null) {
811 _cookies.forEach((cookie) { 830 _cookies.forEach((cookie) {
812 headers.add(HttpHeaders.SET_COOKIE, cookie); 831 headers.add(HttpHeaders.SET_COOKIE, cookie);
813 }); 832 });
814 } 833 }
815 834
816 headers._finalize(); 835 headers._finalize();
817 836
818 // Write headers. 837 // Write headers.
819 headers._write(builder); 838 offset = headers._write(buffer, offset);
820 writeCRLF(); 839 buffer[offset++] = _CharCode.CR;
821 _headersSink.add(builder.takeBytes()); 840 buffer[offset++] = _CharCode.LF;
841 _headersSink.add(new Uint8List.view(buffer.buffer, 0, offset));
822 } 842 }
823 843
824 String _findReasonPhrase(int statusCode) { 844 String _findReasonPhrase(int statusCode) {
825 if (_reasonPhrase != null) { 845 if (_reasonPhrase != null) {
826 return _reasonPhrase; 846 return _reasonPhrase;
827 } 847 }
828 848
829 switch (statusCode) { 849 switch (statusCode) {
830 case HttpStatus.CONTINUE: return "Continue"; 850 case HttpStatus.CONTINUE: return "Continue";
831 case HttpStatus.SWITCHING_PROTOCOLS: return "Switching Protocols"; 851 case HttpStatus.SWITCHING_PROTOCOLS: return "Switching Protocols";
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
1005 if (_httpClientConnection._proxyTunnel) { 1025 if (_httpClientConnection._proxyTunnel) {
1006 return uriStartingFromPath(); 1026 return uriStartingFromPath();
1007 } else { 1027 } else {
1008 return uri.toString(); 1028 return uri.toString();
1009 } 1029 }
1010 } 1030 }
1011 } 1031 }
1012 } 1032 }
1013 1033
1014 void _writeHeader() { 1034 void _writeHeader() {
1015 var builder = new BytesBuilder(); 1035 Uint8List buffer = _httpClientConnection._headersBuffer;
1036 int offset = 0;
1016 1037
1017 writeSP() => builder.add(const [_CharCode.SP]); 1038 void write(List<int> bytes) {
1018 1039 int len = bytes.length;
1019 writeCRLF() => builder.add(const [_CharCode.CR, _CharCode.LF]); 1040 for (int i = 0; i < len; i++) {
1041 buffer[offset + i] = bytes[i];
1042 }
1043 offset += len;
1044 }
1020 1045
1021 // Write the request method. 1046 // Write the request method.
1022 builder.add(method.codeUnits); 1047 write(method.codeUnits);
1023 writeSP(); 1048 buffer[offset++] = _CharCode.SP;
1024 // Write the request URI. 1049 // Write the request URI.
1025 builder.add(_requestUri().codeUnits); 1050 write(_requestUri().codeUnits);
1026 writeSP(); 1051 buffer[offset++] = _CharCode.SP;
1027 // Write HTTP/1.1. 1052 // Write HTTP/1.1.
1028 builder.add(_Const.HTTP11); 1053 write(_Const.HTTP11);
1029 writeCRLF(); 1054 buffer[offset++] = _CharCode.CR;
1055 buffer[offset++] = _CharCode.LF;
1030 1056
1031 // Add the cookies to the headers. 1057 // Add the cookies to the headers.
1032 if (!cookies.isEmpty) { 1058 if (!cookies.isEmpty) {
1033 StringBuffer sb = new StringBuffer(); 1059 StringBuffer sb = new StringBuffer();
1034 for (int i = 0; i < cookies.length; i++) { 1060 for (int i = 0; i < cookies.length; i++) {
1035 if (i > 0) sb.write("; "); 1061 if (i > 0) sb.write("; ");
1036 sb.write(cookies[i].name); 1062 sb.write(cookies[i].name);
1037 sb.write("="); 1063 sb.write("=");
1038 sb.write(cookies[i].value); 1064 sb.write(cookies[i].value);
1039 } 1065 }
1040 headers.add(HttpHeaders.COOKIE, sb.toString()); 1066 headers.add(HttpHeaders.COOKIE, sb.toString());
1041 } 1067 }
1042 1068
1043 headers._finalize(); 1069 headers._finalize();
1044 1070
1045 // Write headers. 1071 // Write headers.
1046 headers._write(builder); 1072 offset = headers._write(buffer, offset);
1047 writeCRLF(); 1073 buffer[offset++] = _CharCode.CR;
1048 _headersSink.add(builder.takeBytes()); 1074 buffer[offset++] = _CharCode.LF;
1075 _headersSink.add(new Uint8List.view(buffer.buffer, 0, offset));
1049 } 1076 }
1050 } 1077 }
1051 1078
1052 1079
1053 class _ChunkedTransformerSink implements EventSink<List<int>> { 1080 class _ChunkedTransformerSink implements EventSink<List<int>> {
1054 1081
1055 int _pendingFooter = 0; 1082 int _pendingFooter = 0;
1056 final EventSink<List<int>> _outSink; 1083 final EventSink<List<int>> _outSink;
1057 1084
1058 _ChunkedTransformerSink(this._outSink); 1085 _ChunkedTransformerSink(this._outSink);
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
1202 final String key; 1229 final String key;
1203 final Socket _socket; 1230 final Socket _socket;
1204 final bool _proxyTunnel; 1231 final bool _proxyTunnel;
1205 final _HttpParser _httpParser; 1232 final _HttpParser _httpParser;
1206 StreamSubscription _subscription; 1233 StreamSubscription _subscription;
1207 final _HttpClient _httpClient; 1234 final _HttpClient _httpClient;
1208 bool _dispose = false; 1235 bool _dispose = false;
1209 Timer _idleTimer; 1236 Timer _idleTimer;
1210 bool closed = false; 1237 bool closed = false;
1211 Uri _currentUri; 1238 Uri _currentUri;
1239 final Uint8List _headersBuffer = new Uint8List(_HEADERS_BUFFER_SIZE);
1212 1240
1213 Completer<_HttpIncoming> _nextResponseCompleter; 1241 Completer<_HttpIncoming> _nextResponseCompleter;
1214 Future _streamFuture; 1242 Future _streamFuture;
1215 1243
1216 _HttpClientConnection(String this.key, 1244 _HttpClientConnection(String this.key,
1217 Socket this._socket, 1245 Socket this._socket,
1218 _HttpClient this._httpClient, 1246 _HttpClient this._httpClient,
1219 [this._proxyTunnel = false]) 1247 [this._proxyTunnel = false])
1220 : _httpParser = new _HttpParser.responseParser() { 1248 : _httpParser = new _HttpParser.responseParser() {
1221 _socket.pipe(_httpParser); 1249 _socket.pipe(_httpParser);
(...skipping 629 matching lines...) Expand 10 before | Expand all | Expand 10 after
1851 static const _CLOSING = 2; 1879 static const _CLOSING = 2;
1852 static const _DETACHED = 3; 1880 static const _DETACHED = 3;
1853 1881
1854 int _state = _IDLE; 1882 int _state = _IDLE;
1855 1883
1856 final Socket _socket; 1884 final Socket _socket;
1857 final _HttpServer _httpServer; 1885 final _HttpServer _httpServer;
1858 final _HttpParser _httpParser; 1886 final _HttpParser _httpParser;
1859 StreamSubscription _subscription; 1887 StreamSubscription _subscription;
1860 Timer _idleTimer; 1888 Timer _idleTimer;
1889 final Uint8List _headersBuffer = new Uint8List(_HEADERS_BUFFER_SIZE);
1861 1890
1862 Future _streamFuture; 1891 Future _streamFuture;
1863 1892
1864 _HttpConnection(Socket this._socket, _HttpServer this._httpServer) 1893 _HttpConnection(Socket this._socket, _HttpServer this._httpServer)
1865 : _httpParser = new _HttpParser.requestParser() { 1894 : _httpParser = new _HttpParser.requestParser() {
1866 _startTimeout(); 1895 _startTimeout();
1867 _socket.pipe(_httpParser); 1896 _socket.pipe(_httpParser);
1868 _subscription = _httpParser.listen( 1897 _subscription = _httpParser.listen(
1869 (incoming) { 1898 (incoming) {
1870 _stopTimeout(); 1899 _stopTimeout();
(...skipping 650 matching lines...) Expand 10 before | Expand all | Expand 10 after
2521 final Uri location; 2550 final Uri location;
2522 } 2551 }
2523 2552
2524 String _getHttpVersion() { 2553 String _getHttpVersion() {
2525 var version = Platform.version; 2554 var version = Platform.version;
2526 // Only include major and minor version numbers. 2555 // Only include major and minor version numbers.
2527 int index = version.indexOf('.', version.indexOf('.') + 1); 2556 int index = version.indexOf('.', version.indexOf('.') + 1);
2528 version = version.substring(0, index); 2557 version = version.substring(0, index);
2529 return 'Dart/$version (dart:io)'; 2558 return 'Dart/$version (dart:io)';
2530 } 2559 }
2560
2561
OLDNEW
« no previous file with comments | « sdk/lib/io/http_headers.dart ('k') | tests/standalone/io/http_client_request_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698