| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 // Global constants. | 5 // Global constants. |
| 6 class _Const { | 6 class _Const { |
| 7 // Bytes for "HTTP/1.0". | 7 // Bytes for "HTTP/1.0". |
| 8 static final HTTP10 = const [72, 84, 84, 80, 47, 49, 46, 48]; | 8 static final HTTP10 = const [72, 84, 84, 80, 47, 49, 46, 48]; |
| 9 // Bytes for "HTTP/1.1". | 9 // Bytes for "HTTP/1.1". |
| 10 static final HTTP11 = const [72, 84, 84, 80, 47, 49, 46, 49]; | 10 static final HTTP11 = const [72, 84, 84, 80, 47, 49, 46, 49]; |
| (...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 StringBuffer _headerField; | 399 StringBuffer _headerField; |
| 400 StringBuffer _headerValue; | 400 StringBuffer _headerValue; |
| 401 | 401 |
| 402 int _contentLength; | 402 int _contentLength; |
| 403 bool _keepAlive; | 403 bool _keepAlive; |
| 404 bool _chunked; | 404 bool _chunked; |
| 405 | 405 |
| 406 int _remainingContent; | 406 int _remainingContent; |
| 407 | 407 |
| 408 // Callbacks. | 408 // Callbacks. |
| 409 var requestStart; | 409 Function requestStart; |
| 410 var responseStart; | 410 Function responseStart; |
| 411 var headerReceived; | 411 Function headerReceived; |
| 412 var headersComplete; | 412 Function headersComplete; |
| 413 var dataReceived; | 413 Function dataReceived; |
| 414 var dataEnd; | 414 Function dataEnd; |
| 415 } | 415 } |
| 416 | 416 |
| 417 | 417 |
| 418 // Utility class which can deliver bytes one by one from a number of | |
| 419 // buffers added. | |
| 420 class _BufferList { | |
| 421 _BufferList() : _index = 0, _length = 0, _buffers = new Queue(); | |
| 422 | |
| 423 void add(List<int> buffer) { | |
| 424 _buffers.addLast(buffer); | |
| 425 _length += buffer.length; | |
| 426 } | |
| 427 | |
| 428 int next() { | |
| 429 int value = _buffers.first()[_index++]; | |
| 430 _length--; | |
| 431 if (_index == _buffers.first().length) { | |
| 432 _buffers.removeFirst(); | |
| 433 _index = 0; | |
| 434 } | |
| 435 return value; | |
| 436 } | |
| 437 | |
| 438 int get length() => _length; | |
| 439 | |
| 440 int _length; | |
| 441 Queue<List<int>> _buffers; | |
| 442 int _index; | |
| 443 } | |
| 444 | |
| 445 | |
| 446 // Utility class for decoding UTF-8 from data delivered as a stream of | |
| 447 // bytes. | |
| 448 class _UTF8Decoder { | |
| 449 _UTF8Decoder() | |
| 450 : _bufferList = new _BufferList(), | |
| 451 _result = new StringBuffer(); | |
| 452 | |
| 453 // Add UTF-8 encoded data. | |
| 454 int writeList(List<int> buffer) { | |
| 455 _bufferList.add(buffer); | |
| 456 // Only process as much data as we know is safe. | |
| 457 while (_bufferList.length >= 4) { | |
| 458 _processNext(); | |
| 459 } | |
| 460 } | |
| 461 | |
| 462 // Return the decoded string. | |
| 463 String toString() { | |
| 464 // Process any leftover data. | |
| 465 while (_bufferList.length > 0) { | |
| 466 _processNext(); | |
| 467 } | |
| 468 return _result.toString(); | |
| 469 } | |
| 470 | |
| 471 // Process the next UTF-8 encoded character. | |
| 472 void _processNext() { | |
| 473 int value = _bufferList.next() & 0xFF; | |
| 474 if ((value & 0x80) == 0x80) { | |
| 475 int additionalBytes; | |
| 476 if ((value & 0xe0) == 0xc0) { // 110xxxxx | |
| 477 value = value & 0x1F; | |
| 478 additionalBytes = 1; | |
| 479 } else if ((value & 0xf0) == 0xe0) { // 1110xxxx | |
| 480 value = value & 0x0F; | |
| 481 additionalBytes = 2; | |
| 482 } else { // 11110xxx | |
| 483 value = value & 0x07; | |
| 484 additionalBytes = 3; | |
| 485 } | |
| 486 for (int i = 0; i < additionalBytes; i++) { | |
| 487 int byte = _bufferList.next(); | |
| 488 value = value << 6 | (byte & 0x3F); | |
| 489 } | |
| 490 } | |
| 491 _result.addCharCode(value); | |
| 492 } | |
| 493 | |
| 494 _BufferList _bufferList; | |
| 495 StringBuffer _result; | |
| 496 } | |
| 497 | |
| 498 | |
| 499 // Utility class for encoding a string into UTF-8 byte stream. | 418 // Utility class for encoding a string into UTF-8 byte stream. |
| 500 class _UTF8Encoder { | 419 class _UTF8Encoder { |
| 501 static List<int> encodeString(String string) { | 420 static List<int> encodeString(String string) { |
| 502 int size = _encodingSize(string); | 421 int size = _encodingSize(string); |
| 503 ByteArray result = new ByteArray(size); | 422 ByteArray result = new ByteArray(size); |
| 504 _encodeString(string, result); | 423 _encodeString(string, result); |
| 505 return result; | 424 return result; |
| 506 } | 425 } |
| 507 | 426 |
| 508 static int _encodingSize(String string) => _encodeString(string, null); | 427 static int _encodingSize(String string) => _encodeString(string, null); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 537 } | 456 } |
| 538 } else { | 457 } else { |
| 539 pos += additionalBytes; | 458 pos += additionalBytes; |
| 540 } | 459 } |
| 541 } | 460 } |
| 542 return pos; | 461 return pos; |
| 543 } | 462 } |
| 544 } | 463 } |
| 545 | 464 |
| 546 | 465 |
| 547 class _HTTPRequestOrResponse { | 466 class _HTTPRequestResponseBase { |
| 548 _HTTPRequestOrResponse(_HTTPConnectionBase this._httpConnection) | 467 _HTTPRequestResponseBase(_HTTPConnectionBase this._httpConnection) |
| 549 : _contentLength = -1, | 468 : _contentLength = -1, |
| 550 _keepAlive = false, | 469 _keepAlive = false, |
| 551 _headers = new Map(); | 470 _headers = new Map(); |
| 552 | 471 |
| 553 int get contentLength() => _contentLength; | 472 int get contentLength() => _contentLength; |
| 554 bool get keepAlive() => _keepAlive; | 473 bool get keepAlive() => _keepAlive; |
| 555 | 474 |
| 556 void _setHeader(String name, String value) { | 475 void _setHeader(String name, String value) { |
| 557 _headers[name] = value; | 476 _headers[name] = value; |
| 558 } | 477 } |
| 559 | 478 |
| 560 void _write(List<int> data, bool copyBuffer) { | 479 bool _write(List<int> data, bool copyBuffer) { |
| 480 bool allWritten = true; |
| 561 if (data.length > 0) { | 481 if (data.length > 0) { |
| 562 if (_contentLength < 0) { | 482 if (_contentLength < 0) { |
| 563 // Write chunk size if transfer encoding is chunked. | 483 // Write chunk size if transfer encoding is chunked. |
| 564 _writeHexString(data.length); | 484 _writeHexString(data.length); |
| 565 _writeCRLF(); | 485 _writeCRLF(); |
| 566 _httpConnection.outputStream.write(data, copyBuffer); | 486 _httpConnection.outputStream.write(data, copyBuffer); |
| 567 _writeCRLF(); | 487 allWritten = _writeCRLF(); |
| 568 } else { | 488 } else { |
| 569 _httpConnection.outputStream.write(data, copyBuffer); | 489 allWritten = _httpConnection.outputStream.write(data, copyBuffer); |
| 570 } | 490 } |
| 571 } | 491 } |
| 492 return allWritten; |
| 572 } | 493 } |
| 573 | 494 |
| 574 void _writeList(List<int> data, int offset, int count) { | 495 bool _writeList(List<int> data, int offset, int count) { |
| 496 bool allWritten = true; |
| 575 if (count > 0) { | 497 if (count > 0) { |
| 576 if (_contentLength < 0) { | 498 if (_contentLength < 0) { |
| 577 // Write chunk size if transfer encoding is chunked. | 499 // Write chunk size if transfer encoding is chunked. |
| 578 _writeHexString(count); | 500 _writeHexString(count); |
| 579 _writeCRLF(); | 501 _writeCRLF(); |
| 580 _httpConnection.outputStream.writeFrom(data, offset, count); | 502 _httpConnection.outputStream.writeFrom(data, offset, count); |
| 581 _writeCRLF(); | 503 allWritten = _writeCRLF(); |
| 582 } else { | 504 } else { |
| 583 _httpConnection.outputStream.writeFrom(data, offset, count); | 505 allWritten = _httpConnection.outputStream.writeFrom(data, offset, count)
; |
| 584 } | 506 } |
| 585 } | 507 } |
| 508 return allWritten; |
| 586 } | 509 } |
| 587 | 510 |
| 588 void _writeString(String string) { | 511 bool _writeString(String string) { |
| 512 bool allWritten = true; |
| 589 if (string.length > 0) { | 513 if (string.length > 0) { |
| 590 // Encode as UTF-8 and write data. | 514 // Encode as UTF-8 and write data. |
| 591 List<int> data = _UTF8Encoder.encodeString(string); | 515 List<int> data = _UTF8Encoder.encodeString(string); |
| 592 _writeList(data, 0, data.length); | 516 allWritten = _writeList(data, 0, data.length); |
| 593 } | 517 } |
| 518 return allWritten; |
| 594 } | 519 } |
| 595 | 520 |
| 596 void _writeDone() { | 521 bool _writeDone() { |
| 522 bool allWritten = true; |
| 597 if (_contentLength < 0) { | 523 if (_contentLength < 0) { |
| 598 // Terminate the content if transfer encoding is chunked. | 524 // Terminate the content if transfer encoding is chunked. |
| 599 _httpConnection.outputStream.write(_Const.END_CHUNKED); | 525 allWritten = _httpConnection.outputStream.write(_Const.END_CHUNKED); |
| 600 } | 526 } |
| 527 return allWritten; |
| 601 } | 528 } |
| 602 | 529 |
| 603 void _writeHeaders() { | 530 bool _writeHeaders() { |
| 604 List<int> data; | 531 List<int> data; |
| 605 | 532 |
| 606 // Format headers. | 533 // Format headers. |
| 607 _headers.forEach((String name, String value) { | 534 _headers.forEach((String name, String value) { |
| 608 data = name.charCodes(); | 535 data = name.charCodes(); |
| 609 _httpConnection.outputStream.write(data); | 536 _httpConnection.outputStream.write(data); |
| 610 data = ": ".charCodes(); | 537 data = ": ".charCodes(); |
| 611 _httpConnection.outputStream.write(data); | 538 _httpConnection.outputStream.write(data); |
| 612 data = value.charCodes(); | 539 data = value.charCodes(); |
| 613 _httpConnection.outputStream.write(data); | 540 _httpConnection.outputStream.write(data); |
| 614 _writeCRLF(); | 541 _writeCRLF(); |
| 615 }); | 542 }); |
| 616 // Terminate header. | 543 // Terminate header. |
| 617 _writeCRLF(); | 544 return _writeCRLF(); |
| 618 } | 545 } |
| 619 | 546 |
| 620 void _writeHexString(int x) { | 547 bool _writeHexString(int x) { |
| 621 final List<int> hexDigits = [0x30, 0x31, 0x32, 0x33, 0x34, | 548 final List<int> hexDigits = [0x30, 0x31, 0x32, 0x33, 0x34, |
| 622 0x35, 0x36, 0x37, 0x38, 0x39, | 549 0x35, 0x36, 0x37, 0x38, 0x39, |
| 623 0x41, 0x42, 0x43, 0x44, 0x45, 0x46]; | 550 0x41, 0x42, 0x43, 0x44, 0x45, 0x46]; |
| 624 ByteArray hex = new ByteArray(10); | 551 ByteArray hex = new ByteArray(10); |
| 625 int index = hex.length; | 552 int index = hex.length; |
| 626 while (x > 0) { | 553 while (x > 0) { |
| 627 index--; | 554 index--; |
| 628 hex[index] = hexDigits[x % 16]; | 555 hex[index] = hexDigits[x % 16]; |
| 629 x = x >> 4; | 556 x = x >> 4; |
| 630 } | 557 } |
| 631 _httpConnection.outputStream.writeFrom(hex, index, hex.length - index); | 558 return _httpConnection.outputStream.writeFrom(hex, index, hex.length - index
); |
| 632 } | 559 } |
| 633 | 560 |
| 634 void _writeCRLF() { | 561 bool _writeCRLF() { |
| 635 final CRLF = const [_CharCode.CR, _CharCode.LF]; | 562 final CRLF = const [_CharCode.CR, _CharCode.LF]; |
| 636 _httpConnection.outputStream.write(CRLF); | 563 return _httpConnection.outputStream.write(CRLF); |
| 637 } | 564 } |
| 638 | 565 |
| 639 void _writeSP() { | 566 bool _writeSP() { |
| 640 final SP = const [_CharCode.SP]; | 567 final SP = const [_CharCode.SP]; |
| 641 _httpConnection.outputStream.write(SP); | 568 return _httpConnection.outputStream.write(SP); |
| 642 } | |
| 643 | |
| 644 void _dataReceivedHandler(List<int> data) { | |
| 645 // If no data received handler exists collect data as a string. | |
| 646 if (dataReceived != null) { | |
| 647 dataReceived(data); | |
| 648 } else { | |
| 649 if (_decoder == null) _decoder = new _UTF8Decoder(); | |
| 650 _decoder.writeList(data); | |
| 651 } | |
| 652 } | |
| 653 | |
| 654 void _dataEndHandler() { | |
| 655 if (dataEnd != null) { | |
| 656 // Pass the string collected if any. | |
| 657 dataEnd(_decoder != null ? _decoder.toString() : null); | |
| 658 } | |
| 659 } | 569 } |
| 660 | 570 |
| 661 _HTTPConnectionBase _httpConnection; | 571 _HTTPConnectionBase _httpConnection; |
| 662 Map<String, String> _headers; | 572 Map<String, String> _headers; |
| 663 | 573 |
| 664 // Length of the content body. If this is set to -1 (default value) | 574 // Length of the content body. If this is set to -1 (default value) |
| 665 // when starting to send data chunked transfer encoding will be | 575 // when starting to send data chunked transfer encoding will be |
| 666 // used. | 576 // used. |
| 667 int _contentLength; | 577 int _contentLength; |
| 668 bool _keepAlive; | 578 bool _keepAlive; |
| 669 | |
| 670 _UTF8Decoder _decoder; | |
| 671 | |
| 672 // Callbacks. | |
| 673 var dataReceived; | |
| 674 var dataEnd; | |
| 675 } | 579 } |
| 676 | 580 |
| 677 | 581 |
| 678 // Parsed HTTP request providing information on the HTTP headers. | 582 // Parsed HTTP request providing information on the HTTP headers. |
| 679 class _HTTPRequest extends _HTTPRequestOrResponse implements HTTPRequest { | 583 class _HTTPRequest extends _HTTPRequestResponseBase implements HTTPRequest { |
| 680 _HTTPRequest(_HTTPConnection connection) : super(connection); | 584 _HTTPRequest(_HTTPConnection connection) : super(connection); |
| 681 | 585 |
| 682 String get method() => _method; | 586 String get method() => _method; |
| 683 String get uri() => _uri; | 587 String get uri() => _uri; |
| 684 String get path() => _path; | 588 String get path() => _path; |
| 685 Map get headers() => _headers; | 589 Map get headers() => _headers; |
| 686 String get queryString() => _queryString; | 590 String get queryString() => _queryString; |
| 687 Map get queryParameters() => _queryParameters; | 591 Map get queryParameters() => _queryParameters; |
| 688 | 592 |
| 593 InputStream get inputStream() { |
| 594 if (_inputStream == null) { |
| 595 _inputStream = new _HTTPInputStream(this); |
| 596 } |
| 597 return _inputStream; |
| 598 } |
| 599 |
| 689 void _requestStartHandler(String method, String uri) { | 600 void _requestStartHandler(String method, String uri) { |
| 690 _method = method; | 601 _method = method; |
| 691 _uri = uri; | 602 _uri = uri; |
| 692 _parseRequestUri(uri); | 603 _parseRequestUri(uri); |
| 693 } | 604 } |
| 694 | 605 |
| 695 void _headerReceivedHandler(String name, String value) { | 606 void _headerReceivedHandler(String name, String value) { |
| 696 _setHeader(name, value); | 607 _setHeader(name, value); |
| 697 } | 608 } |
| 698 | 609 |
| 699 void _headersCompleteHandler() { | 610 void _headersCompleteHandler() { |
| 700 // Nothing to do. | 611 // Prepare for receiving data. |
| 612 _buffer = new _BufferList(); |
| 613 } |
| 614 |
| 615 void _dataReceivedHandler(List<int> data) { |
| 616 _buffer.add(data); |
| 617 if (_inputStream != null) _inputStream._dataReceived(); |
| 618 } |
| 619 |
| 620 void _dataEndHandler() { |
| 621 if (_inputStream != null) _inputStream._closeReceived(); |
| 701 } | 622 } |
| 702 | 623 |
| 703 // Escaped characters in uri are expected to have been parsed. | 624 // Escaped characters in uri are expected to have been parsed. |
| 704 void _parseRequestUri(String uri) { | 625 void _parseRequestUri(String uri) { |
| 705 int position; | 626 int position; |
| 706 position = uri.indexOf("?", 0); | 627 position = uri.indexOf("?", 0); |
| 707 if (position == -1) { | 628 if (position == -1) { |
| 708 _path = HTTPUtil.decodeUrlEncodedString(_uri); | 629 _path = HTTPUtil.decodeUrlEncodedString(_uri); |
| 709 _queryString = null; | 630 _queryString = null; |
| 710 _queryParameters = new Map(); | 631 _queryParameters = new Map(); |
| 711 } else { | 632 } else { |
| 712 _path = HTTPUtil.decodeUrlEncodedString(_uri.substring(0, position)); | 633 _path = HTTPUtil.decodeUrlEncodedString(_uri.substring(0, position)); |
| 713 _queryString = _uri.substring(position + 1); | 634 _queryString = _uri.substring(position + 1); |
| 714 _queryParameters = HTTPUtil.splitQueryString(_queryString); | 635 _queryParameters = HTTPUtil.splitQueryString(_queryString); |
| 715 } | 636 } |
| 716 } | 637 } |
| 717 | 638 |
| 639 // Delegate functions for the HTTPInputStream implementation. |
| 640 int _streamAvailable() { |
| 641 return _buffer.length; |
| 642 } |
| 643 |
| 644 List<int> _streamRead(int bytesToRead) { |
| 645 return _buffer.readBytes(bytesToRead); |
| 646 } |
| 647 |
| 648 int _streamReadInto(List<int> buffer, int offset, int len) { |
| 649 List<int> data = _buffer.readBytes(len); |
| 650 buffer.setRange(offset, data.length, data); |
| 651 } |
| 652 |
| 718 String _method; | 653 String _method; |
| 719 String _uri; | 654 String _uri; |
| 720 String _path; | 655 String _path; |
| 721 String _queryString; | 656 String _queryString; |
| 722 Map<String, String> _queryParameters; | 657 Map<String, String> _queryParameters; |
| 658 _HTTPInputStream _inputStream; |
| 659 _BufferList _buffer; |
| 723 } | 660 } |
| 724 | 661 |
| 725 | 662 |
| 726 // HTTP response object for sending a HTTP response. | 663 // HTTP response object for sending a HTTP response. |
| 727 class _HTTPResponse extends _HTTPRequestOrResponse implements HTTPResponse { | 664 class _HTTPResponse extends _HTTPRequestResponseBase implements HTTPResponse { |
| 728 static final int START = 0; | 665 static final int START = 0; |
| 729 static final int HEADERS_SENT = 1; | 666 static final int HEADERS_SENT = 1; |
| 730 static final int DONE = 2; | 667 static final int DONE = 2; |
| 731 | 668 |
| 732 _HTTPResponse(_HTTPConnection httpConnection) | 669 _HTTPResponse(_HTTPConnection httpConnection) |
| 733 : super(httpConnection), | 670 : super(httpConnection), |
| 734 statusCode = HTTPStatus.OK, | 671 statusCode = HTTPStatus.OK, |
| 735 _state = START; | 672 _state = START; |
| 736 | 673 |
| 737 void set contentLength(int contentLength) { | 674 void set contentLength(int contentLength) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 758 _writeHeader(); | 695 _writeHeader(); |
| 759 } | 696 } |
| 760 _outputStream = new _HTTPOutputStream(this); | 697 _outputStream = new _HTTPOutputStream(this); |
| 761 } | 698 } |
| 762 return _outputStream; | 699 return _outputStream; |
| 763 } | 700 } |
| 764 | 701 |
| 765 bool writeString(String string) { | 702 bool writeString(String string) { |
| 766 // Invoke the output stream getter to make sure the header is sent. | 703 // Invoke the output stream getter to make sure the header is sent. |
| 767 outputStream; | 704 outputStream; |
| 768 _writeString(string); | 705 return _writeString(string); |
| 769 return true; | |
| 770 } | 706 } |
| 771 | 707 |
| 772 /* | 708 // Delegate functions for the HTTPOutputStream implementation. |
| 773 * Delegate functions for the HTTPOutputStream implementation. | |
| 774 */ | |
| 775 bool _streamWrite(List<int> buffer, bool copyBuffer) { | 709 bool _streamWrite(List<int> buffer, bool copyBuffer) { |
| 776 _write(buffer, copyBuffer); | 710 return _write(buffer, copyBuffer); |
| 777 } | 711 } |
| 778 | 712 |
| 779 bool _streamWriteFrom(List<int> buffer, int offset, int len) { | 713 bool _streamWriteFrom(List<int> buffer, int offset, int len) { |
| 780 _writeList(buffer, offset, len); | 714 return _writeList(buffer, offset, len); |
| 781 } | 715 } |
| 782 | 716 |
| 783 void _streamClose() { | 717 void _streamClose() { |
| 718 _state = DONE; |
| 784 // Stop tracking no pending write events. | 719 // Stop tracking no pending write events. |
| 785 _httpConnection.outputStream.noPendingWriteHandler = null; | 720 _httpConnection.outputStream.noPendingWriteHandler = null; |
| 786 | |
| 787 // Ensure that any trailing data is written. | 721 // Ensure that any trailing data is written. |
| 788 _writeDone(); | 722 _writeDone(); |
| 789 _state = DONE; | 723 // If the connection is closing then close the output stream to |
| 724 // fully close the socket. |
| 725 if (_httpConnection._closing) { |
| 726 _httpConnection.outputStream.close(); |
| 727 } |
| 790 } | 728 } |
| 791 | 729 |
| 792 void _streamSetNoPendingWriteHandler(callback()) { | 730 void _streamSetNoPendingWriteHandler(callback()) { |
| 793 _httpConnection.outputStream.noPendingWriteHandler = callback; | 731 if (_state != DONE) { |
| 732 _httpConnection.outputStream.noPendingWriteHandler = callback; |
| 733 } |
| 794 } | 734 } |
| 795 | 735 |
| 796 void _streamSetCloseHandler(callback()) { | 736 void _streamSetCloseHandler(callback()) { |
| 797 // TODO(sgjesse): Handle this. | 737 // TODO(sgjesse): Handle this. |
| 798 } | 738 } |
| 799 | 739 |
| 800 void _streamSetErrorHandler(callback()) { | 740 void _streamSetErrorHandler(callback()) { |
| 801 // TODO(sgjesse): Handle this. | 741 // TODO(sgjesse): Handle this. |
| 802 } | 742 } |
| 803 | 743 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 849 case HTTPStatus.NOT_IMPLEMENTED: return "Not Implemented"; | 789 case HTTPStatus.NOT_IMPLEMENTED: return "Not Implemented"; |
| 850 case HTTPStatus.BAD_GATEWAY: return "Bad Gateway"; | 790 case HTTPStatus.BAD_GATEWAY: return "Bad Gateway"; |
| 851 case HTTPStatus.SERVICE_UNAVAILABLE: return "Service Unavailable"; | 791 case HTTPStatus.SERVICE_UNAVAILABLE: return "Service Unavailable"; |
| 852 case HTTPStatus.GATEWAY_TIMEOUT: return "Gateway Time-out"; | 792 case HTTPStatus.GATEWAY_TIMEOUT: return "Gateway Time-out"; |
| 853 case HTTPStatus.HTTP_VERSION_NOT_SUPPORTED: | 793 case HTTPStatus.HTTP_VERSION_NOT_SUPPORTED: |
| 854 return "HTTP Version not supported"; | 794 return "HTTP Version not supported"; |
| 855 default: return "Status " + statusCode.toString(); | 795 default: return "Status " + statusCode.toString(); |
| 856 } | 796 } |
| 857 } | 797 } |
| 858 | 798 |
| 859 void _writeHeader() { | 799 bool _writeHeader() { |
| 860 List<int> data; | 800 List<int> data; |
| 861 OutputStream stream = _httpConnection.outputStream; | 801 OutputStream stream = _httpConnection.outputStream; |
| 862 | 802 |
| 863 // Write status line. | 803 // Write status line. |
| 864 stream.write(_Const.HTTP11); | 804 stream.write(_Const.HTTP11); |
| 865 _writeSP(); | 805 _writeSP(); |
| 866 data = statusCode.toString().charCodes(); | 806 data = statusCode.toString().charCodes(); |
| 867 stream.write(data); | 807 stream.write(data); |
| 868 _writeSP(); | 808 _writeSP(); |
| 869 data = _findReasonPhrase(statusCode).charCodes(); | 809 data = _findReasonPhrase(statusCode).charCodes(); |
| 870 stream.write(data); | 810 stream.write(data); |
| 871 _writeCRLF(); | 811 _writeCRLF(); |
| 872 | 812 |
| 873 // Determine the value of the "Connection" header | 813 // Determine the value of the "Connection" header |
| 874 // based on the keep alive state. | 814 // based on the keep alive state. |
| 875 setHeader("Connection", keepAlive ? "keep-alive" : "close"); | 815 setHeader("Connection", keepAlive ? "keep-alive" : "close"); |
| 876 // Determine the value of the "Transfer-Encoding" header based on | 816 // Determine the value of the "Transfer-Encoding" header based on |
| 877 // whether the content length is known. | 817 // whether the content length is known. |
| 878 if (_contentLength >= 0) { | 818 if (_contentLength >= 0) { |
| 879 setHeader("Content-Length", _contentLength.toString()); | 819 setHeader("Content-Length", _contentLength.toString()); |
| 880 } else { | 820 } else { |
| 881 setHeader("Transfer-Encoding", "chunked"); | 821 setHeader("Transfer-Encoding", "chunked"); |
| 882 } | 822 } |
| 883 | 823 |
| 884 // Write headers. | 824 // Write headers. |
| 885 _writeHeaders(); | 825 bool allWritten = _writeHeaders(); |
| 886 _state = HEADERS_SENT; | 826 _state = HEADERS_SENT; |
| 827 return allWritten; |
| 887 } | 828 } |
| 888 | 829 |
| 889 // Response status code. | 830 // Response status code. |
| 890 int statusCode; | 831 int statusCode; |
| 891 String reasonPhrase; | 832 String reasonPhrase; |
| 892 _HTTPOutputStream _outputStream; | 833 _HTTPOutputStream _outputStream; |
| 893 int _state; | 834 int _state; |
| 894 } | 835 } |
| 895 | 836 |
| 896 | 837 |
| 838 class _HTTPInputStream extends _BaseDataInputStream implements InputStream { |
| 839 _HTTPInputStream(_HTTPRequestResponseBase this._requestOrResponse) { |
| 840 _checkScheduleCallbacks(); |
| 841 } |
| 842 |
| 843 int available() { |
| 844 return _requestOrResponse._streamAvailable(); |
| 845 } |
| 846 |
| 847 void pipe(OutputStream output, [bool close = true]) { |
| 848 _pipe(this, output, close: close); |
| 849 } |
| 850 |
| 851 List<int> _read(int bytesToRead) { |
| 852 List<int> result = _requestOrResponse._streamRead(bytesToRead); |
| 853 _checkScheduleCallbacks(); |
| 854 return result; |
| 855 } |
| 856 |
| 857 int _readInto(List<int> buffer, int offset, int len) { |
| 858 int result = _requestOrResponse._streamReadInto(buffer, offset, len); |
| 859 _checkScheduleCallbacks(); |
| 860 return result; |
| 861 } |
| 862 |
| 863 void _close() { |
| 864 // TODO(sgjesse): Handle this. |
| 865 } |
| 866 |
| 867 void _dataReceived() { |
| 868 super._dataReceived(); |
| 869 } |
| 870 |
| 871 _HTTPRequestResponseBase _requestOrResponse; |
| 872 } |
| 873 |
| 874 |
| 897 class _HTTPOutputStream implements OutputStream { | 875 class _HTTPOutputStream implements OutputStream { |
| 898 _HTTPOutputStream(_HTTPRequestOrResponse this._requestOrResponse); | 876 _HTTPOutputStream(_HTTPRequestResponseBase this._requestOrResponse); |
| 899 | 877 |
| 900 bool write(List<int> buffer, [bool copyBuffer = true]) => | 878 bool write(List<int> buffer, [bool copyBuffer = true]) { |
| 901 _requestOrResponse._streamWrite(buffer, copyBuffer); | 879 return _requestOrResponse._streamWrite(buffer, copyBuffer); |
| 880 } |
| 902 | 881 |
| 903 bool writeFrom(List<int> buffer, [int offset = 0, int len]) => | 882 bool writeFrom(List<int> buffer, [int offset = 0, int len]) { |
| 904 _requestOrResponse._streamWriteFrom(buffer, offset, len); | 883 return _requestOrResponse._streamWriteFrom(buffer, offset, len); |
| 884 } |
| 905 | 885 |
| 906 void close() => _requestOrResponse._streamClose(); | 886 void close() { |
| 887 _requestOrResponse._streamClose(); |
| 888 } |
| 907 | 889 |
| 908 void destroy() { throw "Not implemented"; } | 890 void destroy() { |
| 891 throw "Not implemented"; |
| 892 } |
| 909 | 893 |
| 910 void set noPendingWriteHandler(void callback()) => | 894 void set noPendingWriteHandler(void callback()) { |
| 911 _requestOrResponse._streamSetNoPendingWriteHandler(callback); | 895 _requestOrResponse._streamSetNoPendingWriteHandler(callback); |
| 896 } |
| 912 | 897 |
| 913 void set closeHandler(void callback()) => | 898 void set closeHandler(void callback()) { |
| 914 _requestOrResponse._streamSetCloseHandler(callback); | 899 _requestOrResponse._streamSetCloseHandler(callback); |
| 900 } |
| 915 | 901 |
| 916 void set errorHandler(void callback()) => | 902 void set errorHandler(void callback()) { |
| 917 _requestOrResponse._streamSetErrorHandler(callback); | 903 _requestOrResponse._streamSetErrorHandler(callback); |
| 904 } |
| 918 | 905 |
| 919 _HTTPRequestOrResponse _requestOrResponse; | 906 _HTTPRequestResponseBase _requestOrResponse; |
| 920 } | 907 } |
| 921 | 908 |
| 922 | 909 |
| 923 class _HTTPConnectionBase { | 910 class _HTTPConnectionBase { |
| 924 _HTTPConnectionBase() : _sendBuffers = new Queue(), | 911 _HTTPConnectionBase() : _sendBuffers = new Queue(), |
| 925 _httpParser = new HTTPParser(); | 912 _httpParser = new HTTPParser(); |
| 926 | 913 |
| 927 void _connectionEstablished(Socket socket) { | 914 void _connectionEstablished(Socket socket) { |
| 928 _socket = socket; | 915 _socket = socket; |
| 929 // Register handler for socket events. | 916 // Register handler for socket events. |
| 930 _socket.dataHandler = _dataHandler; | 917 _socket.dataHandler = _dataHandler; |
| 931 _socket.closeHandler = _closeHandler; | 918 _socket.closeHandler = _closeHandler; |
| 932 _socket.errorHandler = _errorHandler; | 919 _socket.errorHandler = _errorHandler; |
| 933 } | 920 } |
| 934 | 921 |
| 935 OutputStream get outputStream() { | 922 OutputStream get outputStream() { |
| 936 if (_socket == null) throw new HTTPException("Connection closed"); | |
| 937 return _socket.outputStream; | 923 return _socket.outputStream; |
| 938 } | 924 } |
| 939 | 925 |
| 940 void _dataHandler() { | 926 void _dataHandler() { |
| 941 int available = _socket.available(); | 927 int available = _socket.available(); |
| 942 if (available == 0) { | 928 if (available == 0) { |
| 943 return; | 929 return; |
| 944 } | 930 } |
| 945 | 931 |
| 946 ByteArray buffer = new ByteArray(available); | 932 ByteArray buffer = new ByteArray(available); |
| 947 int bytesRead = _socket.readList(buffer, 0, available); | 933 int bytesRead = _socket.readList(buffer, 0, available); |
| 948 if (bytesRead > 0) { | 934 if (bytesRead > 0) { |
| 949 int parsed = _httpParser.writeList(buffer, 0, bytesRead); | 935 int parsed = _httpParser.writeList(buffer, 0, bytesRead); |
| 950 if (parsed != bytesRead) { | 936 if (parsed != bytesRead) { |
| 951 print("Failed to parse HTTP data $parsed $bytesRead"); | 937 print("Failed to parse HTTP data $parsed $bytesRead"); |
| 952 _socket.close(); | 938 _socket.close(); |
| 953 } | 939 } |
| 954 } | 940 } |
| 955 } | 941 } |
| 956 | 942 |
| 957 void _closeHandler() { | 943 void _closeHandler() { |
| 958 _socket.close(); | 944 // Client closed socket for writing. Socket should still be open |
| 959 // Set to null to avoid further write attempts. | 945 // for writing the response. |
| 960 _socket = null; | 946 _closing = true; |
| 961 if (_disconnectHandlerCallback != null) _disconnectHandlerCallback(); | 947 if (_disconnectHandlerCallback != null) _disconnectHandlerCallback(); |
| 962 } | 948 } |
| 963 | 949 |
| 964 void _errorHandler() { | 950 void _errorHandler() { |
| 965 // If an error occours, treat the socket as closed. | 951 // If an error occours, treat the socket as closed. |
| 966 _closeHandler(); | 952 _closeHandler(); |
| 967 if (_errorHandlerCallback != null) { | 953 if (_errorHandlerCallback != null) { |
| 968 _errorHandlerCallback("Connection closed while sending data to client."); | 954 _errorHandlerCallback("Connection closed while sending data to client."); |
| 969 } | 955 } |
| 970 } | 956 } |
| 971 | 957 |
| 972 void set disconnectHandler(void callback()) { | 958 void set disconnectHandler(void callback()) { |
| 973 _disconnectHandlerCallback = callback; | 959 _disconnectHandlerCallback = callback; |
| 974 } | 960 } |
| 975 | 961 |
| 976 void set errorHandler(void callback(String errorMessage)) { | 962 void set errorHandler(void callback(String errorMessage)) { |
| 977 _errorHandlerCallback = callback; | 963 _errorHandlerCallback = callback; |
| 978 } | 964 } |
| 979 | 965 |
| 980 Socket _socket; | 966 Socket _socket; |
| 967 bool _closing = false; // Is the socket closed by the client? |
| 981 HTTPParser _httpParser; | 968 HTTPParser _httpParser; |
| 982 | 969 |
| 983 Queue _sendBuffers; | 970 Queue _sendBuffers; |
| 984 | 971 |
| 985 Function _disconnectHandlerCallback; | 972 Function _disconnectHandlerCallback; |
| 986 Function _errorHandlerCallback; | 973 Function _errorHandlerCallback; |
| 987 } | 974 } |
| 988 | 975 |
| 989 | 976 |
| 990 // HTTP server connection over a socket. | 977 // HTTP server connection over a socket. |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1095 | 1082 |
| 1096 ServerSocket _server; // The server listen socket. | 1083 ServerSocket _server; // The server listen socket. |
| 1097 List<_HTTPConnection> _connections; // List of currently connected clients. | 1084 List<_HTTPConnection> _connections; // List of currently connected clients. |
| 1098 Function _requestHandler; | 1085 Function _requestHandler; |
| 1099 Function _errorHandler; | 1086 Function _errorHandler; |
| 1100 bool _debugTrace; | 1087 bool _debugTrace; |
| 1101 } | 1088 } |
| 1102 | 1089 |
| 1103 | 1090 |
| 1104 class _HTTPClientRequest | 1091 class _HTTPClientRequest |
| 1105 extends _HTTPRequestOrResponse implements HTTPClientRequest { | 1092 extends _HTTPRequestResponseBase implements HTTPClientRequest { |
| 1106 static final int START = 0; | 1093 static final int START = 0; |
| 1107 static final int HEADERS_SENT = 1; | 1094 static final int HEADERS_SENT = 1; |
| 1108 static final int DONE = 2; | 1095 static final int DONE = 2; |
| 1109 | 1096 |
| 1110 _HTTPClientRequest(String this._method, | 1097 _HTTPClientRequest(String this._method, |
| 1111 String this._uri, | 1098 String this._uri, |
| 1112 _HTTPClientConnection connection) | 1099 _HTTPClientConnection connection) |
| 1113 : super(connection), | 1100 : super(connection), |
| 1114 _state = START { | 1101 _state = START { |
| 1115 _connection = connection; | 1102 _connection = connection; |
| 1116 // Default GET requests to have no content. | 1103 // Default GET requests to have no content. |
| 1117 if (_method == "GET") { | 1104 if (_method == "GET") { |
| 1118 _contentLength = 0; | 1105 _contentLength = 0; |
| 1119 } | 1106 } |
| 1120 } | 1107 } |
| 1121 | 1108 |
| 1122 void set contentLength(int contentLength) => _contentLength = contentLength; | 1109 void set contentLength(int contentLength) => _contentLength = contentLength; |
| 1123 void set keepAlive(bool keepAlive) => _keepAlive = keepAlive; | 1110 void set keepAlive(bool keepAlive) => _keepAlive = keepAlive; |
| 1124 int get statusCode() { return _statusCode; } | 1111 int get statusCode() { return _statusCode; } |
| 1125 String get reasonPhrase() { return _reasonPhrase; } | 1112 String get reasonPhrase() { return _reasonPhrase; } |
| 1126 | 1113 |
| 1127 void setHeader(String name, String value) { | 1114 void setHeader(String name, String value) { |
| 1128 _setHeader(name, value); | 1115 _setHeader(name, value); |
| 1129 } | 1116 } |
| 1130 | 1117 |
| 1131 bool writeString(String string) { | 1118 bool writeString(String string) { |
| 1132 outputStream; | 1119 outputStream; |
| 1133 _writeString(string); | 1120 return _writeString(string); |
| 1134 return true; | |
| 1135 } | 1121 } |
| 1136 | 1122 |
| 1137 OutputStream get outputStream() { | 1123 OutputStream get outputStream() { |
| 1138 if (_state == DONE) throw new HTTPException("Request closed"); | 1124 if (_state == DONE) throw new HTTPException("Request closed"); |
| 1139 if (_outputStream == null) { | 1125 if (_outputStream == null) { |
| 1140 // Ensure that headers are written. | 1126 // Ensure that headers are written. |
| 1141 if (_state == START) { | 1127 if (_state == START) { |
| 1142 _writeHeader(); | 1128 _writeHeader(); |
| 1143 } | 1129 } |
| 1144 _outputStream = new _HTTPOutputStream(this); | 1130 _outputStream = new _HTTPOutputStream(this); |
| 1145 } | 1131 } |
| 1146 return _outputStream; | 1132 return _outputStream; |
| 1147 } | 1133 } |
| 1148 | 1134 |
| 1149 /* | 1135 // Delegate functions for the HTTPOutputStream implementation. |
| 1150 * Delegate functions for the HTTPOutputStream implementation. | 1136 bool _streamWrite(List<int> buffer, bool copyBuffer) { |
| 1151 */ | 1137 return _write(buffer, copyBuffer); |
| 1152 void _streamWrite(List<int> buffer, bool copyBuffer) { | |
| 1153 _write(buffer, copyBuffer); | |
| 1154 } | 1138 } |
| 1155 | 1139 |
| 1156 void _streamWriteFrom(List<int> buffer, int offset, int len) { | 1140 bool _streamWriteFrom(List<int> buffer, int offset, int len) { |
| 1157 _writeList(buffer, offset, len); | 1141 return _writeList(buffer, offset, len); |
| 1158 } | 1142 } |
| 1159 | 1143 |
| 1160 void _streamClose() { | 1144 void _streamClose() { |
| 1145 _state = DONE; |
| 1146 // Stop tracking no pending write events. |
| 1147 _httpConnection.outputStream.noPendingWriteHandler = null; |
| 1161 // Ensure that any trailing data is written. | 1148 // Ensure that any trailing data is written. |
| 1162 _writeDone(); | 1149 _writeDone(); |
| 1163 _state = DONE; | 1150 // If the connection is closing then close the output stream to |
| 1151 // fully close the socket. |
| 1152 if (_httpConnection._closing) { |
| 1153 _httpConnection.outputStream.close(); |
| 1154 } |
| 1164 } | 1155 } |
| 1165 | 1156 |
| 1166 void _streamSetNoPendingWriteHandler(callback()) { | 1157 void _streamSetNoPendingWriteHandler(callback()) { |
| 1167 _httpConnection.outputStream.noPendingWriteHandler = callback; | 1158 if (_state != DONE) { |
| 1159 _httpConnection.outputStream.noPendingWriteHandler = callback; |
| 1160 } |
| 1168 } | 1161 } |
| 1169 | 1162 |
| 1170 void _streamSetCloseHandler(callback()) { | 1163 void _streamSetCloseHandler(callback()) { |
| 1171 // TODO(sgjesse): Handle this. | 1164 // TODO(sgjesse): Handle this. |
| 1172 } | 1165 } |
| 1173 | 1166 |
| 1174 void _streamSetErrorHandler(callback()) { | 1167 void _streamSetErrorHandler(callback()) { |
| 1175 // TODO(sgjesse): Handle this. | 1168 // TODO(sgjesse): Handle this. |
| 1176 } | 1169 } |
| 1177 | 1170 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1207 | 1200 |
| 1208 String _method; | 1201 String _method; |
| 1209 String _uri; | 1202 String _uri; |
| 1210 _HTTPClientConnection _connection; | 1203 _HTTPClientConnection _connection; |
| 1211 _HTTPOutputStream _outputStream; | 1204 _HTTPOutputStream _outputStream; |
| 1212 int _state; | 1205 int _state; |
| 1213 } | 1206 } |
| 1214 | 1207 |
| 1215 | 1208 |
| 1216 class _HTTPClientResponse | 1209 class _HTTPClientResponse |
| 1217 extends _HTTPRequestOrResponse implements HTTPClientResponse { | 1210 extends _HTTPRequestResponseBase implements HTTPClientResponse { |
| 1218 _HTTPClientResponse(_HTTPClientConnection connection) | 1211 _HTTPClientResponse(_HTTPClientConnection connection) |
| 1219 : super(connection) { | 1212 : super(connection) { |
| 1220 _connection = connection; | 1213 _connection = connection; |
| 1221 } | 1214 } |
| 1222 | 1215 |
| 1223 int get statusCode() { return _statusCode; } | 1216 int get statusCode() { return _statusCode; } |
| 1224 int get reasonPhrase() { return _reasonPhrase; } | 1217 int get reasonPhrase() { return _reasonPhrase; } |
| 1225 Map get headers() => _headers; | 1218 Map get headers() => _headers; |
| 1226 | 1219 |
| 1220 InputStream get inputStream() { |
| 1221 if (_inputStream == null) { |
| 1222 _inputStream = new _HTTPInputStream(this); |
| 1223 } |
| 1224 return _inputStream; |
| 1225 } |
| 1226 |
| 1227 void _requestStartHandler(String method, String uri) { | 1227 void _requestStartHandler(String method, String uri) { |
| 1228 // TODO(sgjesse): Error handling | 1228 // TODO(sgjesse): Error handling |
| 1229 } | 1229 } |
| 1230 | 1230 |
| 1231 void _responseStartHandler(int statusCode, String reasonPhrase) { | 1231 void _responseStartHandler(int statusCode, String reasonPhrase) { |
| 1232 _statusCode = statusCode; | 1232 _statusCode = statusCode; |
| 1233 _reasonPhrase = reasonPhrase; | 1233 _reasonPhrase = reasonPhrase; |
| 1234 } | 1234 } |
| 1235 | 1235 |
| 1236 void _headerReceivedHandler(String name, String value) { | 1236 void _headerReceivedHandler(String name, String value) { |
| 1237 _setHeader(name, value); | 1237 _setHeader(name, value); |
| 1238 } | 1238 } |
| 1239 | 1239 |
| 1240 void _headersCompleteHandler() { | 1240 void _headersCompleteHandler() { |
| 1241 _buffer = new _BufferList(); |
| 1241 if (_connection._responseHandler != null) { | 1242 if (_connection._responseHandler != null) { |
| 1242 _connection._responseHandler(this); | 1243 _connection._responseHandler(this); |
| 1243 } | 1244 } |
| 1244 } | 1245 } |
| 1245 | 1246 |
| 1247 void _dataReceivedHandler(List<int> data) { |
| 1248 _buffer.add(data); |
| 1249 if (_inputStream != null) _inputStream._dataReceived(); |
| 1250 } |
| 1251 |
| 1252 void _dataEndHandler() { |
| 1253 if (_inputStream != null) _inputStream._closeReceived(); |
| 1254 } |
| 1255 |
| 1256 // Delegate functions for the HTTPInputStream implementation. |
| 1257 int _streamAvailable() { |
| 1258 return _buffer.length; |
| 1259 } |
| 1260 |
| 1261 List<int> _streamRead(int bytesToRead) { |
| 1262 return _buffer.readBytes(bytesToRead); |
| 1263 } |
| 1264 |
| 1265 int _streamReadInto(List<int> buffer, int offset, int len) { |
| 1266 List<int> data = _buffer.readBytes(len); |
| 1267 buffer.setRange(offset, data.length, data); |
| 1268 return data.length; |
| 1269 } |
| 1270 |
| 1246 int _statusCode; | 1271 int _statusCode; |
| 1247 String _reasonPhrase; | 1272 String _reasonPhrase; |
| 1248 | 1273 |
| 1249 _HTTPClientConnection _connection; | 1274 _HTTPClientConnection _connection; |
| 1250 var _responseReceived; | 1275 _HTTPInputStream _inputStream; |
| 1276 _BufferList _buffer; |
| 1251 } | 1277 } |
| 1252 | 1278 |
| 1253 | 1279 |
| 1254 class _HTTPClientConnection | 1280 class _HTTPClientConnection |
| 1255 extends _HTTPConnectionBase implements HTTPClientConnection { | 1281 extends _HTTPConnectionBase implements HTTPClientConnection { |
| 1256 _HTTPClientConnection(_HTTPClient this._client); | 1282 _HTTPClientConnection(_HTTPClient this._client); |
| 1257 | 1283 |
| 1258 void _connectionEstablished(_SocketConnection socketConn) { | 1284 void _connectionEstablished(_SocketConnection socketConn) { |
| 1259 super._connectionEstablished(socketConn._socket); | 1285 super._connectionEstablished(socketConn._socket); |
| 1260 _socketConn = socketConn; | 1286 _socketConn = socketConn; |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1544 } else { | 1570 } else { |
| 1545 value = queryString.substring(currentPosition, position); | 1571 value = queryString.substring(currentPosition, position); |
| 1546 currentPosition = position + 1; | 1572 currentPosition = position + 1; |
| 1547 } | 1573 } |
| 1548 result[HTTPUtil.decodeUrlEncodedString(name)] = | 1574 result[HTTPUtil.decodeUrlEncodedString(name)] = |
| 1549 HTTPUtil.decodeUrlEncodedString(value); | 1575 HTTPUtil.decodeUrlEncodedString(value); |
| 1550 } | 1576 } |
| 1551 return result; | 1577 return result; |
| 1552 } | 1578 } |
| 1553 } | 1579 } |
| OLD | NEW |