Chromium Code Reviews| 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 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |