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

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

Issue 12655003: Buffer the entire http header to one packet, and buffer other data in chunks of 4-16 kb. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 9 months 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
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 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 431 matching lines...) Expand 10 before | Expand all | Expand 10 after
442 _ioSink = new IOSink(new _HttpOutboundConsumer(_ioSink, _consume, asGZip)); 442 _ioSink = new IOSink(new _HttpOutboundConsumer(_ioSink, _consume, asGZip));
443 _ioSink.encoding = encoding; 443 _ioSink.encoding = encoding;
444 } 444 }
445 445
446 Future _consume(IOSink ioSink, Stream<List<int>> stream, bool asGZip) { 446 Future _consume(IOSink ioSink, Stream<List<int>> stream, bool asGZip) {
447 int contentLength = headers.contentLength; 447 int contentLength = headers.contentLength;
448 if (_ignoreBody) { 448 if (_ignoreBody) {
449 ioSink.close(); 449 ioSink.close();
450 return stream.reduce(null, (x, y) {}).then((_) => this); 450 return stream.reduce(null, (x, y) {}).then((_) => this);
451 } 451 }
452 stream = stream.transform(new _BufferTransformer());
452 if (headers.chunkedTransferEncoding) { 453 if (headers.chunkedTransferEncoding) {
453 if (asGZip) { 454 if (asGZip) {
454 stream = stream.transform(new ZLibDeflater(gzip: true, level: 6)); 455 stream = stream.transform(new ZLibDeflater(gzip: true, level: 6));
455 } 456 }
456 stream = stream.transform(new _ChunkedTransformer()); 457 stream = stream.transform(new _ChunkedTransformer());
457 } else if (contentLength >= 0) { 458 } else if (contentLength >= 0) {
458 stream = stream.transform(new _ContentLengthValidator(contentLength)); 459 stream = stream.transform(new _ContentLengthValidator(contentLength));
459 } 460 }
460 return stream.pipe(ioSink).then((_) => this); 461 return stream.pipe(ioSink).then((_) => this);
461 } 462 }
462 463
463 void _writeHeader(); // TODO(ajohnsen): Better name. 464 void _writeHeader(); // TODO(ajohnsen): Better name.
464 } 465 }
465 466
466 467
467 class _HttpOutboundConsumer implements StreamConsumer { 468 class _HttpOutboundConsumer implements StreamConsumer {
468 Function _consume; 469 Function _consume;
469 IOSink _ioSink; 470 IOSink _ioSink;
470 bool _asGZip; 471 bool _asGZip;
471 _HttpOutboundConsumer(IOSink this._ioSink, 472 _HttpOutboundConsumer(IOSink this._ioSink,
472 Function this._consume, 473 Function this._consume,
473 bool this._asGZip); 474 bool this._asGZip);
474 475
475 Future consume(var stream) => _consume(_ioSink, stream, _asGZip); 476 Future consume(var stream) => _consume(_ioSink, stream, _asGZip);
476 } 477 }
477 478
479 class _BufferTransformer extends StreamEventTransformer<List<int>, List<int>> {
480 const int MIN_CHUNK_SIZE = 4 * 1024;
481 const int MAX_BUFFER_SIZE = 16 * 1024;
482
483 final _BufferList _buffer = new _BufferList();
484
485 void handleData(List<int> data, EventSink<List<int>> sink) {
486 // TODO(ajohnsen): Use timeout?
487 if (data.length == 0) return;
488 if (data.length >= MIN_CHUNK_SIZE) {
489 flush(sink);
490 sink.add(data);
491 } else {
492 _buffer.add(data);
493 if (_buffer.length >= MAX_BUFFER_SIZE) {
494 flush(sink);
495 }
496 }
497 }
498
499 void handleDone(EventSink<List<int>> sink) {
500 flush(sink);
501 sink.close();
502 }
503
504 void flush(EventSink<List<int>> sink) {
505 if (_buffer.length > 0) {
506 sink.add(_buffer.readBytes());
507 _buffer.clear();
508 }
509 }
510 }
511
478 512
479 class _HttpResponse extends _HttpOutboundMessage<HttpResponse> 513 class _HttpResponse extends _HttpOutboundMessage<HttpResponse>
480 implements HttpResponse { 514 implements HttpResponse {
481 int statusCode = 200; 515 int statusCode = 200;
482 String _reasonPhrase; 516 String _reasonPhrase;
483 List<Cookie> _cookies; 517 List<Cookie> _cookies;
484 _HttpRequest _httpRequest; 518 _HttpRequest _httpRequest;
485 519
486 _HttpResponse(String protocolVersion, 520 _HttpResponse(String protocolVersion,
487 _HttpOutgoing _outgoing) 521 _HttpOutgoing _outgoing)
(...skipping 19 matching lines...) Expand all
507 done.catchError((_) { 541 done.catchError((_) {
508 // Catch any error on done, as they automatically will be propegated to 542 // Catch any error on done, as they automatically will be propegated to
509 // the websocket. 543 // the websocket.
510 }); 544 });
511 return future; 545 return future;
512 } 546 }
513 547
514 HttpConnectionInfo get connectionInfo => _httpRequest.connectionInfo; 548 HttpConnectionInfo get connectionInfo => _httpRequest.connectionInfo;
515 549
516 void _writeHeader() { 550 void _writeHeader() {
517 writeSP() => _ioSink.writeBytes([_CharCode.SP]); 551 var buffer = new _BufferList();
518 writeCRLF() => _ioSink.writeBytes([_CharCode.CR, _CharCode.LF]); 552 writeSP() => buffer.add(const [_CharCode.SP]);
553 writeCRLF() => buffer.add(const [_CharCode.CR, _CharCode.LF]);
519 554
520 // Write status line. 555 // Write status line.
521 if (headers.protocolVersion == "1.1") { 556 if (headers.protocolVersion == "1.1") {
522 _ioSink.writeBytes(_Const.HTTP11); 557 buffer.add(_Const.HTTP11);
523 } else { 558 } else {
524 _ioSink.writeBytes(_Const.HTTP10); 559 buffer.add(_Const.HTTP10);
525 } 560 }
526 writeSP(); 561 writeSP();
527 _ioSink.write(statusCode.toString()); 562 buffer.add(statusCode.toString().codeUnits);
528 writeSP(); 563 writeSP();
529 _ioSink.write(reasonPhrase); 564 buffer.add(reasonPhrase.codeUnits);
530 writeCRLF(); 565 writeCRLF();
531 566
532 var session = _httpRequest._session; 567 var session = _httpRequest._session;
533 if (session != null && !session._destroyed) { 568 if (session != null && !session._destroyed) {
534 // Mark as not new. 569 // Mark as not new.
535 session._isNew = false; 570 session._isNew = false;
536 // Make sure we only send the current session id. 571 // Make sure we only send the current session id.
537 bool found = false; 572 bool found = false;
538 for (int i = 0; i < cookies.length; i++) { 573 for (int i = 0; i < cookies.length; i++) {
539 if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) { 574 if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) {
(...skipping 13 matching lines...) Expand all
553 // Add all the cookies set to the headers. 588 // Add all the cookies set to the headers.
554 if (_cookies != null) { 589 if (_cookies != null) {
555 _cookies.forEach((cookie) { 590 _cookies.forEach((cookie) {
556 headers.add(HttpHeaders.SET_COOKIE, cookie); 591 headers.add(HttpHeaders.SET_COOKIE, cookie);
557 }); 592 });
558 } 593 }
559 594
560 headers._finalize(); 595 headers._finalize();
561 596
562 // Write headers. 597 // Write headers.
563 headers._write(_ioSink); 598 headers._write(buffer);
564 writeCRLF(); 599 writeCRLF();
600 _ioSink.writeBytes(buffer.readBytes());
565 } 601 }
566 602
567 String _findReasonPhrase(int statusCode) { 603 String _findReasonPhrase(int statusCode) {
568 if (_reasonPhrase != null) { 604 if (_reasonPhrase != null) {
569 return _reasonPhrase; 605 return _reasonPhrase;
570 } 606 }
571 607
572 switch (statusCode) { 608 switch (statusCode) {
573 case HttpStatus.CONTINUE: return "Continue"; 609 case HttpStatus.CONTINUE: return "Continue";
574 case HttpStatus.SWITCHING_PROTOCOLS: return "Switching Protocols"; 610 case HttpStatus.SWITCHING_PROTOCOLS: return "Switching Protocols";
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
703 onError: (e) { 739 onError: (e) {
704 _responseCompleter.completeError(e); 740 _responseCompleter.completeError(e);
705 }); 741 });
706 } 742 }
707 743
708 void _onError(AsyncError error) { 744 void _onError(AsyncError error) {
709 _responseCompleter.completeError(error); 745 _responseCompleter.completeError(error);
710 } 746 }
711 747
712 void _writeHeader() { 748 void _writeHeader() {
713 writeSP() => _ioSink.writeBytes([_CharCode.SP]); 749 var buffer = new _BufferList();
Søren Gjesse 2013/03/12 11:30:55 I am not sure that using a _BufferList for the hea
Anders Johnsen 2013/03/12 12:11:30 Yes, we have to look into this once we really dive
714 writeCRLF() => _ioSink.writeBytes([_CharCode.CR, _CharCode.LF]); 750 writeSP() => buffer.add(const [_CharCode.SP]);
751 writeCRLF() => buffer.add(const [_CharCode.CR, _CharCode.LF]);
715 752
716 _ioSink.write(method); 753 buffer.add(method.codeUnits);
717 writeSP(); 754 writeSP();
718 // Send the path for direct connections and the whole URL for 755 // Send the path for direct connections and the whole URL for
719 // proxy connections. 756 // proxy connections.
720 if (!_usingProxy) { 757 if (!_usingProxy) {
721 String path = uri.path; 758 String path = uri.path;
722 if (path.length == 0) path = "/"; 759 if (path.length == 0) path = "/";
723 if (uri.query != "") { 760 if (uri.query != "") {
724 if (uri.fragment != "") { 761 if (uri.fragment != "") {
725 path = "${path}?${uri.query}#${uri.fragment}"; 762 path = "${path}?${uri.query}#${uri.fragment}";
726 } else { 763 } else {
727 path = "${path}?${uri.query}"; 764 path = "${path}?${uri.query}";
728 } 765 }
729 } 766 }
730 _ioSink.write(path); 767 buffer.add(path.codeUnits);
731 } else { 768 } else {
732 _ioSink.write(uri.toString()); 769 buffer.add(uri.toString().codeUnits);
733 } 770 }
734 writeSP(); 771 writeSP();
735 _ioSink.writeBytes(_Const.HTTP11); 772 buffer.add(_Const.HTTP11);
736 writeCRLF(); 773 writeCRLF();
737 774
738 // Add the cookies to the headers. 775 // Add the cookies to the headers.
739 if (!cookies.isEmpty) { 776 if (!cookies.isEmpty) {
740 StringBuffer sb = new StringBuffer(); 777 StringBuffer sb = new StringBuffer();
741 for (int i = 0; i < cookies.length; i++) { 778 for (int i = 0; i < cookies.length; i++) {
742 if (i > 0) sb.write("; "); 779 if (i > 0) sb.write("; ");
743 sb.write(cookies[i].name); 780 sb.write(cookies[i].name);
744 sb.write("="); 781 sb.write("=");
745 sb.write(cookies[i].value); 782 sb.write(cookies[i].value);
746 } 783 }
747 headers.add(HttpHeaders.COOKIE, sb.toString()); 784 headers.add(HttpHeaders.COOKIE, sb.toString());
748 } 785 }
749 786
750 headers._finalize(); 787 headers._finalize();
751 788
752 // Write headers. 789 // Write headers.
753 headers._write(_ioSink); 790 headers._write(buffer);
754 writeCRLF(); 791 writeCRLF();
792 _ioSink.writeBytes(buffer.readBytes());
755 } 793 }
756 } 794 }
757 795
758 796
759 // Transformer that transforms data to HTTP Chunked Encoding. 797 // Transformer that transforms data to HTTP Chunked Encoding.
760 class _ChunkedTransformer extends StreamEventTransformer<List<int>, List<int>> { 798 class _ChunkedTransformer extends StreamEventTransformer<List<int>, List<int>> {
761 void handleData(List<int> data, EventSink<List<int>> sink) { 799 void handleData(List<int> data, EventSink<List<int>> sink) {
762 sink.add(_chunkHeader(data.length)); 800 sink.add(_chunkHeader(data.length));
763 if (data.length > 0) sink.add(data); 801 if (data.length > 0) sink.add(data);
764 sink.add(_chunkFooter); 802 sink.add(_chunkFooter);
(...skipping 905 matching lines...) Expand 10 before | Expand all | Expand 10 after
1670 1708
1671 1709
1672 class _RedirectInfo implements RedirectInfo { 1710 class _RedirectInfo implements RedirectInfo {
1673 const _RedirectInfo(int this.statusCode, 1711 const _RedirectInfo(int this.statusCode,
1674 String this.method, 1712 String this.method,
1675 Uri this.location); 1713 Uri this.location);
1676 final int statusCode; 1714 final int statusCode;
1677 final String method; 1715 final String method;
1678 final Uri location; 1716 final Uri location;
1679 } 1717 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698