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 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 325 bool _headersWritten = false; | 325 bool _headersWritten = false; |
| 326 bool _chunked = false; | 326 bool _chunked = false; |
| 327 | 327 |
| 328 final IOSink _ioSink; | 328 final IOSink _ioSink; |
| 329 final _HttpOutgoing _outgoing; | 329 final _HttpOutgoing _outgoing; |
| 330 | 330 |
| 331 final _HttpHeaders headers; | 331 final _HttpHeaders headers; |
| 332 | 332 |
| 333 _HttpOutboundMessage(String protocolVersion, _HttpOutgoing outgoing) | 333 _HttpOutboundMessage(String protocolVersion, _HttpOutgoing outgoing) |
| 334 : _outgoing = outgoing, | 334 : _outgoing = outgoing, |
| 335 _ioSink = new IOSink(outgoing), | 335 _ioSink = new IOSink(outgoing, Encoding.ASCII), |
| 336 headers = new _HttpHeaders(protocolVersion); | 336 headers = new _HttpHeaders(protocolVersion); |
| 337 | 337 |
| 338 int get contentLength => headers.contentLength; | 338 int get contentLength => headers.contentLength; |
| 339 void set contentLength(int contentLength) { | 339 void set contentLength(int contentLength) { |
| 340 headers.contentLength = contentLength; | 340 headers.contentLength = contentLength; |
| 341 } | 341 } |
| 342 | 342 |
| 343 bool get persistentConnection => headers.persistentConnection; | 343 bool get persistentConnection => headers.persistentConnection; |
| 344 void set persistentConnection(bool p) { | 344 void set persistentConnection(bool p) { |
| 345 headers.persistentConnection = p; | 345 headers.persistentConnection = p; |
| 346 } | 346 } |
| 347 | 347 |
| 348 Encoding get encoding { | |
| 349 return headers.contentType != null ? headers.contentType.encoding | |
| 350 : Encoding.ISO_8859_1; | |
| 351 } | |
| 352 void set encoding(Encoding value) { | |
| 353 throw new StateError("IOSink encoding is not mutable"); | |
| 354 } | |
| 355 | |
| 356 void write(Object obj) { | |
| 357 _writeHeaders(); | |
| 358 if (_ignoreBody) return; | |
| 359 // This comment is copied from runtime/lib/string_buffer_patch.dart. | |
| 360 // TODO(srdjan): The following four lines could be replaced by | |
| 361 // '$obj', but apparently this is too slow on the Dart VM. | |
| 362 String string; | |
| 363 if (obj is String) { | |
| 364 string = obj; | |
| 365 } else { | |
| 366 string = obj.toString(); | |
| 367 if (string is! String) { | |
| 368 throw new ArgumentError('toString() did not return a string'); | |
| 369 } | |
| 370 } | |
| 371 if (string.isEmpty) return; | |
| 372 if (_chunked) { | |
| 373 _ChunkedTransformer._addChunk(_encodeString(string, encoding), | |
| 374 _ioSink.writeBytes); | |
| 375 } else { | |
| 376 _ioSink.write(string); | |
| 377 } | |
| 378 } | |
| 379 | |
| 380 void writeAll(Iterable objects) { | |
| 381 for (Object obj in objects) write(obj); | |
| 382 } | |
| 383 | |
| 384 void writeln(Object obj) { | |
| 385 write(obj); | |
| 386 write("\n"); | |
| 387 } | |
| 388 | |
| 389 void writeCharCode(int charCode) { | |
| 390 write(new String.fromCharCode(charCode)); | |
| 391 } | |
| 392 | |
| 393 void writeBytes(List<int> data) { | |
| 394 _writeHeaders(); | |
| 395 if (_ignoreBody || data.length == 0) return; | |
| 396 if (_chunked) { | |
| 397 _ChunkedTransformer._addChunk(data, _ioSink.writeBytes); | |
| 398 } else { | |
| 399 _ioSink.writeBytes(data); | |
| 400 } | |
| 401 } | |
| 402 | |
| 348 Future<T> consume(Stream<List<int>> stream) { | 403 Future<T> consume(Stream<List<int>> stream) { |
| 349 _writeHeaders(); | 404 _writeHeaders(); |
| 350 if (_ignoreBody) return new Future.immediate(this); | 405 if (_ignoreBody) return new Future.immediate(this); |
| 351 if (_chunked) { | 406 if (_chunked) { |
| 352 // Transform when chunked. | 407 // Transform when chunked. |
| 353 stream = stream.transform(new _ChunkedTransformer()); | 408 stream = stream.transform(new _ChunkedTransformer()); |
| 354 } | 409 } |
| 355 return _ioSink.consume(stream).then((_) => this); | 410 return _ioSink.consume(stream).then((_) => this); |
| 356 } | 411 } |
| 357 | 412 |
| 358 void add(List<int> data) { | 413 void add(List<int> data) => writeBytes(data); |
| 359 _writeHeaders(); | |
| 360 if (_ignoreBody || data.length == 0) return; | |
| 361 if (_chunked) { | |
| 362 _ChunkedTransformer._addChunk(data, _ioSink.add); | |
| 363 } else { | |
| 364 _ioSink.add(data); | |
| 365 } | |
| 366 } | |
| 367 | 414 |
| 368 void addString(String string, [Encoding encoding = Encoding.UTF_8]) { | 415 void addString(String string, [Encoding encoding = Encoding.UTF_8]) { |
| 369 add(_encodeString(string, encoding)); | 416 writeBytes(_encodeString(string, encoding)); |
| 370 } | 417 } |
| 371 | 418 |
| 372 Future<T> addStream(Stream<List<int>> stream) { | 419 Future<T> addStream(Stream<List<int>> stream) { |
| 373 _writeHeaders(); | 420 _writeHeaders(); |
| 374 if (_ignoreBody) return new Future.immediate(this); | 421 if (_ignoreBody) return new Future.immediate(this); |
| 375 if (_chunked) { | 422 if (_chunked) { |
| 376 // Transform when chunked. | 423 // Transform when chunked. |
| 377 stream = stream.transform(new _ChunkedTransformer(writeEnd: false)); | 424 stream = stream.transform(new _ChunkedTransformer(writeEnd: false)); |
| 378 } | 425 } |
| 379 return _ioSink.addStream(stream).then((_) => this); | 426 return _ioSink.addStream(stream).then((_) => this); |
| 380 } | 427 } |
| 381 | 428 |
| 382 void close() { | 429 void close() { |
| 383 if (!_headersWritten && !_ignoreBody && headers.chunkedTransferEncoding) { | 430 if (!_headersWritten && !_ignoreBody && headers.chunkedTransferEncoding) { |
| 384 // If no body was written, _ignoreBody is false (it's not a HEAD | 431 // If no body was written, _ignoreBody is false (it's not a HEAD |
| 385 // request) and the content-length is unspecified, set contentLength to 0. | 432 // request) and the content-length is unspecified, set contentLength to 0. |
| 386 headers.contentLength = 0; | 433 headers.contentLength = 0; |
| 387 } | 434 } |
| 388 _writeHeaders(); | 435 _writeHeaders(); |
| 389 if (!_ignoreBody) { | 436 if (!_ignoreBody) { |
| 390 if (_chunked) { | 437 if (_chunked) { |
| 391 _ChunkedTransformer._addChunk([], _ioSink.add); | 438 _ChunkedTransformer._addChunk([], _ioSink.writeBytes); |
| 392 } | 439 } |
| 393 } | 440 } |
| 394 _ioSink.close(); | 441 _ioSink.close(); |
| 395 } | 442 } |
| 396 | 443 |
| 397 Future<T> get done => _ioSink.done.then((_) => this); | 444 Future<T> get done => _ioSink.done.then((_) => this); |
| 398 | 445 |
| 399 void _writeHeaders() { | 446 void _writeHeaders() { |
| 400 if (_headersWritten) return; | 447 if (_headersWritten) return; |
| 401 bool _tmpIgnoreBody = _ignoreBody; | 448 bool _tmpIgnoreBody = _ignoreBody; |
| 402 _ignoreBody = false; | 449 _ignoreBody = false; |
| 403 _headersWritten = true; | 450 _headersWritten = true; |
| 451 _ioSink.encoding = Encoding.ASCII; | |
| 404 _writeHeader(); | 452 _writeHeader(); |
| 453 _ioSink.encoding = | |
| 454 headers.contentType != null ? headers.contentType.encoding | |
| 455 : Encoding.ISO_8859_1; | |
| 405 _ignoreBody = _tmpIgnoreBody; | 456 _ignoreBody = _tmpIgnoreBody; |
| 406 if (_ignoreBody) { | 457 if (_ignoreBody) { |
| 407 _ioSink.close(); | 458 _ioSink.close(); |
| 408 return; | 459 return; |
| 409 } | 460 } |
| 410 _chunked = headers.chunkedTransferEncoding; | 461 _chunked = headers.chunkedTransferEncoding; |
| 411 if (headers.contentLength >= 0) { | 462 if (headers.contentLength >= 0) { |
| 412 _outgoing.setTransferLength(headers.contentLength); | 463 _outgoing.setTransferLength(headers.contentLength); |
| 413 } | 464 } |
| 414 } | 465 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 448 done.catchError((_) { | 499 done.catchError((_) { |
| 449 // Catch any error on done, as they automatically will be propegated to | 500 // Catch any error on done, as they automatically will be propegated to |
| 450 // the websocket. | 501 // the websocket. |
| 451 }); | 502 }); |
| 452 return future; | 503 return future; |
| 453 } | 504 } |
| 454 | 505 |
| 455 HttpConnectionInfo get connectionInfo => _httpRequest.connectionInfo; | 506 HttpConnectionInfo get connectionInfo => _httpRequest.connectionInfo; |
| 456 | 507 |
| 457 void _writeHeader() { | 508 void _writeHeader() { |
| 458 writeSP() => add([_CharCode.SP]); | 509 writeSP() => writeBytes([_CharCode.SP]); |
| 459 writeCRLF() => add([_CharCode.CR, _CharCode.LF]); | 510 writeCRLF() => writeBytes([_CharCode.CR, _CharCode.LF]); |
| 460 | 511 |
| 461 // Write status line. | 512 // Write status line. |
| 462 if (headers.protocolVersion == "1.1") { | 513 if (headers.protocolVersion == "1.1") { |
| 463 add(_Const.HTTP11); | 514 writeBytes(_Const.HTTP11); |
| 464 } else { | 515 } else { |
| 465 add(_Const.HTTP10); | 516 writeBytes(_Const.HTTP10); |
| 466 } | 517 } |
| 467 writeSP(); | 518 writeSP(); |
| 468 addString(statusCode.toString()); | 519 write(statusCode.toString()); |
| 469 writeSP(); | 520 writeSP(); |
| 470 addString(reasonPhrase); | 521 write(reasonPhrase); |
| 471 writeCRLF(); | 522 writeCRLF(); |
| 472 | 523 |
| 473 var session = _httpRequest._session; | 524 var session = _httpRequest._session; |
| 474 if (session != null && !session._destroyed) { | 525 if (session != null && !session._destroyed) { |
| 475 // Mark as not new. | 526 // Mark as not new. |
| 476 session._isNew = false; | 527 session._isNew = false; |
| 477 // Make sure we only send the current session id. | 528 // Make sure we only send the current session id. |
| 478 bool found = false; | 529 bool found = false; |
| 479 for (int i = 0; i < cookies.length; i++) { | 530 for (int i = 0; i < cookies.length; i++) { |
| 480 if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) { | 531 if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) { |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 641 onError: (e) { | 692 onError: (e) { |
| 642 _responseCompleter.completeError(e); | 693 _responseCompleter.completeError(e); |
| 643 }); | 694 }); |
| 644 } | 695 } |
| 645 | 696 |
| 646 void _onError(AsyncError error) { | 697 void _onError(AsyncError error) { |
| 647 _responseCompleter.completeError(error); | 698 _responseCompleter.completeError(error); |
| 648 } | 699 } |
| 649 | 700 |
| 650 void _writeHeader() { | 701 void _writeHeader() { |
| 651 writeSP() => add([_CharCode.SP]); | 702 writeSP() => writeBytes([_CharCode.SP]); |
| 652 writeCRLF() => add([_CharCode.CR, _CharCode.LF]); | 703 writeCRLF() => writeBytes([_CharCode.CR, _CharCode.LF]); |
| 653 | 704 |
| 654 addString(method); | 705 write(method); |
| 655 writeSP(); | 706 writeSP(); |
| 656 // Send the path for direct connections and the whole URL for | 707 // Send the path for direct connections and the whole URL for |
| 657 // proxy connections. | 708 // proxy connections. |
| 658 if (!_usingProxy) { | 709 if (!_usingProxy) { |
| 659 String path = uri.path; | 710 String path = uri.path; |
| 660 if (path.length == 0) path = "/"; | 711 if (path.length == 0) path = "/"; |
| 661 if (uri.query != "") { | 712 if (uri.query != "") { |
| 662 if (uri.fragment != "") { | 713 if (uri.fragment != "") { |
| 663 path = "${path}?${uri.query}#${uri.fragment}"; | 714 path = "${path}?${uri.query}#${uri.fragment}"; |
| 664 } else { | 715 } else { |
| 665 path = "${path}?${uri.query}"; | 716 path = "${path}?${uri.query}"; |
| 666 } | 717 } |
| 667 } | 718 } |
| 668 addString(path); | 719 write(path); |
| 669 } else { | 720 } else { |
| 670 addString(uri.toString()); | 721 write(uri.toString()); |
| 671 } | 722 } |
| 672 writeSP(); | 723 writeSP(); |
| 673 add(_Const.HTTP11); | 724 writeBytes(_Const.HTTP11); |
| 674 writeCRLF(); | 725 writeCRLF(); |
| 675 | 726 |
| 676 // Add the cookies to the headers. | 727 // Add the cookies to the headers. |
| 677 if (!cookies.isEmpty) { | 728 if (!cookies.isEmpty) { |
| 678 StringBuffer sb = new StringBuffer(); | 729 StringBuffer sb = new StringBuffer(); |
| 679 for (int i = 0; i < cookies.length; i++) { | 730 for (int i = 0; i < cookies.length; i++) { |
| 680 if (i > 0) sb.write("; "); | 731 if (i > 0) sb.write("; "); |
| 681 sb.write(cookies[i].name); | 732 sb.write(cookies[i].name); |
| 682 sb.write("="); | 733 sb.write("="); |
| 683 sb.write(cookies[i].value); | 734 sb.write(cookies[i].value); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 771 var subscription; | 822 var subscription; |
| 772 subscription = stream.listen( | 823 subscription = stream.listen( |
| 773 (data) { | 824 (data) { |
| 774 if (expectedTransferLength != null) { | 825 if (expectedTransferLength != null) { |
| 775 _bytesWritten += data.length; | 826 _bytesWritten += data.length; |
| 776 if (_bytesWritten > expectedTransferLength) { | 827 if (_bytesWritten > expectedTransferLength) { |
| 777 subscription.cancel(); | 828 subscription.cancel(); |
| 778 _controller.signalError(new HttpException( | 829 _controller.signalError(new HttpException( |
| 779 "Content size exceeds specified contentLength. " | 830 "Content size exceeds specified contentLength. " |
| 780 "$_bytesWritten bytes written while expected " | 831 "$_bytesWritten bytes written while expected " |
| 781 "$expectedTransferLength.")); | 832 "$expectedTransferLength. " |
| 833 "[${new String.fromCharCodes(data)}]")); | |
| 782 _controller.close(); | 834 _controller.close(); |
| 783 return; | 835 return; |
| 784 } | 836 } |
| 785 } | 837 } |
| 786 _controller.add(data); | 838 _controller.add(data); |
| 787 }, | 839 }, |
| 788 onError: (error) { | 840 onError: (error) { |
| 789 _controller.signalError(error); | 841 _controller.signalError(error); |
| 790 _controller.close(); | 842 _controller.close(); |
| 791 }, | 843 }, |
| (...skipping 713 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1505 StreamSubscription<List<int>> listen(void onData(List<int> event), | 1557 StreamSubscription<List<int>> listen(void onData(List<int> event), |
| 1506 {void onError(AsyncError error), | 1558 {void onError(AsyncError error), |
| 1507 void onDone(), | 1559 void onDone(), |
| 1508 bool unsubscribeOnError}) { | 1560 bool unsubscribeOnError}) { |
| 1509 return _incoming.listen(onData, | 1561 return _incoming.listen(onData, |
| 1510 onError: onError, | 1562 onError: onError, |
| 1511 onDone: onDone, | 1563 onDone: onDone, |
| 1512 unsubscribeOnError: unsubscribeOnError); | 1564 unsubscribeOnError: unsubscribeOnError); |
| 1513 } | 1565 } |
| 1514 | 1566 |
| 1567 Encoding get encoding => _socket.encoding; | |
| 1568 void set encoding(Encoding value) => _socket.encoding = value; | |
| 1569 | |
| 1570 void write(Object obj) => _socket.write(obj); | |
| 1571 void writeln(Object obj) => _socket.writeln(obj); | |
| 1572 void writeCharCode(int charCode) => _socket.writeCharCode(charCode); | |
| 1573 void writeAll(Iterable objects) => _socket.writeAll(objects); | |
| 1574 | |
|
Mads Ager (google)
2013/03/07 07:57:36
Nit: consistently have blank line between write me
Søren Gjesse
2013/03/07 16:28:47
Done.
| |
| 1575 void writeBytes(List<int> bytes) => _socket.writeBytes(bytes); | |
| 1576 | |
| 1515 Future<Socket> consume(Stream<List<int>> stream) { | 1577 Future<Socket> consume(Stream<List<int>> stream) { |
| 1516 return _socket.consume(stream); | 1578 return _socket.consume(stream); |
| 1517 } | 1579 } |
| 1518 | 1580 |
| 1519 Future<Socket> addStream(Stream<List<int>> stream) { | 1581 Future<Socket> addStream(Stream<List<int>> stream) { |
| 1520 return _socket.addStream(stream); | 1582 return _socket.addStream(stream); |
| 1521 } | 1583 } |
| 1522 | 1584 |
| 1523 void addString(String string, [Encoding encoding = Encoding.UTF_8]) { | 1585 void addString(String string, [Encoding encoding = Encoding.UTF_8]) { |
| 1524 return _socket.addString(string, encoding); | 1586 return _socket.addString(string, encoding); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1639 | 1701 |
| 1640 | 1702 |
| 1641 class _RedirectInfo implements RedirectInfo { | 1703 class _RedirectInfo implements RedirectInfo { |
| 1642 const _RedirectInfo(int this.statusCode, | 1704 const _RedirectInfo(int this.statusCode, |
| 1643 String this.method, | 1705 String this.method, |
| 1644 Uri this.location); | 1706 Uri this.location); |
| 1645 final int statusCode; | 1707 final int statusCode; |
| 1646 final String method; | 1708 final String method; |
| 1647 final Uri location; | 1709 final Uri location; |
| 1648 } | 1710 } |
| OLD | NEW |