| 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 class _HttpHeaders implements HttpHeaders { | 5 class _HttpHeaders implements HttpHeaders { |
| 6 _HttpHeaders() : _headers = new Map<String, List<String>>(); | 6 _HttpHeaders() : _headers = new Map<String, List<String>>(); |
| 7 | 7 |
| 8 List<String> operator[](String name) { | 8 List<String> operator[](String name) { |
| 9 name = name.toLowerCase(); | 9 name = name.toLowerCase(); |
| 10 return _headers[name]; | 10 return _headers[name]; |
| (...skipping 558 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 569 | 569 |
| 570 class _HttpRequestResponseBase { | 570 class _HttpRequestResponseBase { |
| 571 final int START = 0; | 571 final int START = 0; |
| 572 final int HEADER_SENT = 1; | 572 final int HEADER_SENT = 1; |
| 573 final int DONE = 2; | 573 final int DONE = 2; |
| 574 final int UPGRADED = 3; | 574 final int UPGRADED = 3; |
| 575 | 575 |
| 576 _HttpRequestResponseBase(_HttpConnectionBase this._httpConnection) | 576 _HttpRequestResponseBase(_HttpConnectionBase this._httpConnection) |
| 577 : _headers = new _HttpHeaders() { | 577 : _headers = new _HttpHeaders() { |
| 578 _state = START; | 578 _state = START; |
| 579 _headResponse = false; |
| 579 } | 580 } |
| 580 | 581 |
| 581 int get contentLength() => _contentLength; | 582 int get contentLength() => _contentLength; |
| 582 HttpHeaders get headers() => _headers; | 583 HttpHeaders get headers() => _headers; |
| 583 | 584 |
| 584 bool get persistentConnection() { | 585 bool get persistentConnection() { |
| 585 List<String> connection = headers[HttpHeaders.CONNECTION]; | 586 List<String> connection = headers[HttpHeaders.CONNECTION]; |
| 586 if (_protocolVersion == "1.1") { | 587 if (_protocolVersion == "1.1") { |
| 587 if (connection == null) return true; | 588 if (connection == null) return true; |
| 588 return !headers[HttpHeaders.CONNECTION].some( | 589 return !headers[HttpHeaders.CONNECTION].some( |
| (...skipping 13 matching lines...) Expand all Loading... |
| 602 headers.remove(HttpHeaders.CONNECTION, "keep-alive"); | 603 headers.remove(HttpHeaders.CONNECTION, "keep-alive"); |
| 603 if (_protocolVersion == "1.1" && !persistentConnection) { | 604 if (_protocolVersion == "1.1" && !persistentConnection) { |
| 604 headers.add(HttpHeaders.CONNECTION, "close"); | 605 headers.add(HttpHeaders.CONNECTION, "close"); |
| 605 } else if (_protocolVersion == "1.0" && persistentConnection) { | 606 } else if (_protocolVersion == "1.0" && persistentConnection) { |
| 606 headers.add(HttpHeaders.CONNECTION, "keep-alive"); | 607 headers.add(HttpHeaders.CONNECTION, "keep-alive"); |
| 607 } | 608 } |
| 608 } | 609 } |
| 609 | 610 |
| 610 | 611 |
| 611 bool _write(List<int> data, bool copyBuffer) { | 612 bool _write(List<int> data, bool copyBuffer) { |
| 613 if (_headResponse) return; |
| 612 _ensureHeadersSent(); | 614 _ensureHeadersSent(); |
| 613 bool allWritten = true; | 615 bool allWritten = true; |
| 614 if (data.length > 0) { | 616 if (data.length > 0) { |
| 615 if (_contentLength < 0) { | 617 if (_contentLength < 0) { |
| 616 // Write chunk size if transfer encoding is chunked. | 618 // Write chunk size if transfer encoding is chunked. |
| 617 _writeHexString(data.length); | 619 _writeHexString(data.length); |
| 618 _writeCRLF(); | 620 _writeCRLF(); |
| 619 _httpConnection._write(data, copyBuffer); | 621 _httpConnection._write(data, copyBuffer); |
| 620 allWritten = _writeCRLF(); | 622 allWritten = _writeCRLF(); |
| 621 } else { | 623 } else { |
| 622 _updateContentLength(data.length); | 624 _updateContentLength(data.length); |
| 623 allWritten = _httpConnection._write(data, copyBuffer); | 625 allWritten = _httpConnection._write(data, copyBuffer); |
| 624 } | 626 } |
| 625 } | 627 } |
| 626 return allWritten; | 628 return allWritten; |
| 627 } | 629 } |
| 628 | 630 |
| 629 bool _writeList(List<int> data, int offset, int count) { | 631 bool _writeList(List<int> data, int offset, int count) { |
| 632 if (_headResponse) return; |
| 630 _ensureHeadersSent(); | 633 _ensureHeadersSent(); |
| 631 bool allWritten = true; | 634 bool allWritten = true; |
| 632 if (count > 0) { | 635 if (count > 0) { |
| 633 if (_contentLength < 0) { | 636 if (_contentLength < 0) { |
| 634 // Write chunk size if transfer encoding is chunked. | 637 // Write chunk size if transfer encoding is chunked. |
| 635 _writeHexString(count); | 638 _writeHexString(count); |
| 636 _writeCRLF(); | 639 _writeCRLF(); |
| 637 _httpConnection._writeFrom(data, offset, count); | 640 _httpConnection._writeFrom(data, offset, count); |
| 638 allWritten = _writeCRLF(); | 641 allWritten = _writeCRLF(); |
| 639 } else { | 642 } else { |
| 640 _updateContentLength(count); | 643 _updateContentLength(count); |
| 641 allWritten = _httpConnection._writeFrom(data, offset, count); | 644 allWritten = _httpConnection._writeFrom(data, offset, count); |
| 642 } | 645 } |
| 643 } | 646 } |
| 644 return allWritten; | 647 return allWritten; |
| 645 } | 648 } |
| 646 | 649 |
| 647 bool _writeDone() { | 650 bool _writeDone() { |
| 648 bool allWritten = true; | 651 bool allWritten = true; |
| 649 if (_contentLength < 0) { | 652 if (_contentLength < 0) { |
| 650 // Terminate the content if transfer encoding is chunked. | 653 // Terminate the content if transfer encoding is chunked. |
| 651 allWritten = _httpConnection._write(_Const.END_CHUNKED); | 654 allWritten = _httpConnection._write(_Const.END_CHUNKED); |
| 652 } else { | 655 } else { |
| 653 if (_bodyBytesWritten < _contentLength) { | 656 if (!_headResponse && _bodyBytesWritten < _contentLength) { |
| 654 throw new HttpException("Sending less than specified content length"); | 657 throw new HttpException("Sending less than specified content length"); |
| 655 } | 658 } |
| 656 assert(_bodyBytesWritten == _contentLength); | 659 assert(_headResponse || _bodyBytesWritten == _contentLength); |
| 657 } | 660 } |
| 658 if (!persistentConnection) _httpConnection._close(); | 661 if (!persistentConnection) _httpConnection._close(); |
| 659 return allWritten; | 662 return allWritten; |
| 660 } | 663 } |
| 661 | 664 |
| 662 bool _writeHeaders() { | 665 bool _writeHeaders() { |
| 663 _headers._mutable = false; | 666 _headers._mutable = false; |
| 664 _headers._write(_httpConnection); | 667 _headers._write(_httpConnection); |
| 665 // Terminate header. | 668 // Terminate header. |
| 666 return _writeCRLF(); | 669 return _writeCRLF(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 698 } | 701 } |
| 699 | 702 |
| 700 void _updateContentLength(int bytes) { | 703 void _updateContentLength(int bytes) { |
| 701 if (_bodyBytesWritten + bytes > _contentLength) { | 704 if (_bodyBytesWritten + bytes > _contentLength) { |
| 702 throw new HttpException("Writing more than specified content length"); | 705 throw new HttpException("Writing more than specified content length"); |
| 703 } | 706 } |
| 704 _bodyBytesWritten += bytes; | 707 _bodyBytesWritten += bytes; |
| 705 } | 708 } |
| 706 | 709 |
| 707 int _state; | 710 int _state; |
| 711 bool _headResponse; |
| 708 | 712 |
| 709 _HttpConnectionBase _httpConnection; | 713 _HttpConnectionBase _httpConnection; |
| 710 _HttpHeaders _headers; | 714 _HttpHeaders _headers; |
| 711 List<Cookie> _cookies; | 715 List<Cookie> _cookies; |
| 712 String _protocolVersion = "1.1"; | 716 String _protocolVersion = "1.1"; |
| 713 | 717 |
| 714 // Length of the content body. If this is set to -1 (default value) | 718 // Length of the content body. If this is set to -1 (default value) |
| 715 // when starting to send data chunked transfer encoding will be | 719 // when starting to send data chunked transfer encoding will be |
| 716 // used. | 720 // used. |
| 717 int _contentLength = -1; | 721 int _contentLength = -1; |
| (...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1057 _headers.add("set-cookie", cookie); | 1061 _headers.add("set-cookie", cookie); |
| 1058 }); | 1062 }); |
| 1059 } | 1063 } |
| 1060 | 1064 |
| 1061 // Write headers. | 1065 // Write headers. |
| 1062 bool allWritten = _writeHeaders(); | 1066 bool allWritten = _writeHeaders(); |
| 1063 _state = HEADER_SENT; | 1067 _state = HEADER_SENT; |
| 1064 return allWritten; | 1068 return allWritten; |
| 1065 } | 1069 } |
| 1066 | 1070 |
| 1067 // Response status code. | 1071 int _statusCode; // Response status code. |
| 1068 int _statusCode; | 1072 String _reasonPhrase; // Response reason phrase. |
| 1069 String _reasonPhrase; | |
| 1070 _HttpOutputStream _outputStream; | 1073 _HttpOutputStream _outputStream; |
| 1071 Function _streamErrorHandler; | 1074 Function _streamErrorHandler; |
| 1072 } | 1075 } |
| 1073 | 1076 |
| 1074 | 1077 |
| 1075 class _HttpInputStream extends _BaseDataInputStream implements InputStream { | 1078 class _HttpInputStream extends _BaseDataInputStream implements InputStream { |
| 1076 _HttpInputStream(_HttpRequestResponseBase this._requestOrResponse) { | 1079 _HttpInputStream(_HttpRequestResponseBase this._requestOrResponse) { |
| 1077 _checkScheduleCallbacks(); | 1080 _checkScheduleCallbacks(); |
| 1078 } | 1081 } |
| 1079 | 1082 |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1309 } | 1312 } |
| 1310 } | 1313 } |
| 1311 | 1314 |
| 1312 void _onRequestStart(String method, String uri, String version) { | 1315 void _onRequestStart(String method, String uri, String version) { |
| 1313 // Create new request and response objects for this request. | 1316 // Create new request and response objects for this request. |
| 1314 _request = new _HttpRequest(this); | 1317 _request = new _HttpRequest(this); |
| 1315 _response = new _HttpResponse(this); | 1318 _response = new _HttpResponse(this); |
| 1316 _request._onRequestStart(method, uri, version); | 1319 _request._onRequestStart(method, uri, version); |
| 1317 _request._protocolVersion = version; | 1320 _request._protocolVersion = version; |
| 1318 _response._protocolVersion = version; | 1321 _response._protocolVersion = version; |
| 1322 _response._headResponse = method == "HEAD"; |
| 1319 } | 1323 } |
| 1320 | 1324 |
| 1321 void _onResponseStart(int statusCode, String reasonPhrase, String version) { | 1325 void _onResponseStart(int statusCode, String reasonPhrase, String version) { |
| 1322 // TODO(sgjesse): Error handling. | 1326 // TODO(sgjesse): Error handling. |
| 1323 } | 1327 } |
| 1324 | 1328 |
| 1325 void _onHeaderReceived(String name, String value) { | 1329 void _onHeaderReceived(String name, String value) { |
| 1326 _request._onHeaderReceived(name, value); | 1330 _request._onHeaderReceived(name, value); |
| 1327 } | 1331 } |
| 1328 | 1332 |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1476 } | 1480 } |
| 1477 | 1481 |
| 1478 | 1482 |
| 1479 class _HttpClientRequest | 1483 class _HttpClientRequest |
| 1480 extends _HttpRequestResponseBase implements HttpClientRequest { | 1484 extends _HttpRequestResponseBase implements HttpClientRequest { |
| 1481 _HttpClientRequest(String this._method, | 1485 _HttpClientRequest(String this._method, |
| 1482 String this._uri, | 1486 String this._uri, |
| 1483 _HttpClientConnection connection) | 1487 _HttpClientConnection connection) |
| 1484 : super(connection) { | 1488 : super(connection) { |
| 1485 _connection = connection; | 1489 _connection = connection; |
| 1486 // Default GET requests to have no content. | 1490 // Default GET and HEAD requests to have no content. |
| 1487 if (_method == "GET") { | 1491 if (_method == "GET" || _method == "HEAD") { |
| 1488 _contentLength = 0; | 1492 _contentLength = 0; |
| 1489 } | 1493 } |
| 1490 } | 1494 } |
| 1491 | 1495 |
| 1492 void set contentLength(int contentLength) { | 1496 void set contentLength(int contentLength) { |
| 1493 if (_state >= HEADER_SENT) throw new HttpException("Header already sent"); | 1497 if (_state >= HEADER_SENT) throw new HttpException("Header already sent"); |
| 1494 _contentLength = contentLength; | 1498 _contentLength = contentLength; |
| 1495 } | 1499 } |
| 1496 | 1500 |
| 1497 List<Cookie> get cookies() { | 1501 List<Cookie> get cookies() { |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1628 // TODO(sgjesse): Error handling | 1632 // TODO(sgjesse): Error handling |
| 1629 } | 1633 } |
| 1630 | 1634 |
| 1631 void _onResponseStart(int statusCode, String reasonPhrase, String version) { | 1635 void _onResponseStart(int statusCode, String reasonPhrase, String version) { |
| 1632 _statusCode = statusCode; | 1636 _statusCode = statusCode; |
| 1633 _reasonPhrase = reasonPhrase; | 1637 _reasonPhrase = reasonPhrase; |
| 1634 } | 1638 } |
| 1635 | 1639 |
| 1636 void _onHeaderReceived(String name, String value) { | 1640 void _onHeaderReceived(String name, String value) { |
| 1637 _headers.add(name, value); | 1641 _headers.add(name, value); |
| 1642 if (name == "content-length") { |
| 1643 _contentLength = Math.parseInt(value); |
| 1644 } |
| 1638 } | 1645 } |
| 1639 | 1646 |
| 1640 void _onHeadersComplete() { | 1647 void _onHeadersComplete() { |
| 1641 _headers._mutable = false; | 1648 _headers._mutable = false; |
| 1642 _buffer = new _BufferList(); | 1649 _buffer = new _BufferList(); |
| 1643 if (isRedirect && _connection.followRedirects) { | 1650 if (isRedirect && _connection.followRedirects) { |
| 1644 if (_connection._redirects == null || | 1651 if (_connection._redirects == null || |
| 1645 _connection._redirects.length < _connection.maxRedirects) { | 1652 _connection._redirects.length < _connection.maxRedirects) { |
| 1646 // Check the location header. | 1653 // Check the location header. |
| 1647 List<String> location = headers[HttpHeaders.LOCATION]; | 1654 List<String> location = headers[HttpHeaders.LOCATION]; |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1721 (method, uri, version) => _onRequestStart(method, uri, version); | 1728 (method, uri, version) => _onRequestStart(method, uri, version); |
| 1722 _httpParser.responseStart = | 1729 _httpParser.responseStart = |
| 1723 (statusCode, reasonPhrase, version) => | 1730 (statusCode, reasonPhrase, version) => |
| 1724 _onResponseStart(statusCode, reasonPhrase, version); | 1731 _onResponseStart(statusCode, reasonPhrase, version); |
| 1725 _httpParser.headerReceived = | 1732 _httpParser.headerReceived = |
| 1726 (name, value) => _onHeaderReceived(name, value); | 1733 (name, value) => _onHeaderReceived(name, value); |
| 1727 _httpParser.headersComplete = () => _onHeadersComplete(); | 1734 _httpParser.headersComplete = () => _onHeadersComplete(); |
| 1728 _httpParser.dataReceived = (data) => _onDataReceived(data); | 1735 _httpParser.dataReceived = (data) => _onDataReceived(data); |
| 1729 _httpParser.dataEnd = (closed) => _onDataEnd(closed); | 1736 _httpParser.dataEnd = (closed) => _onDataEnd(closed); |
| 1730 _httpParser.error = (e) => _onError(e); | 1737 _httpParser.error = (e) => _onError(e); |
| 1731 // Tell the HTTP parser the method it is expecting a response to. | |
| 1732 _httpParser.responseToMethod = _method; | |
| 1733 } | 1738 } |
| 1734 | 1739 |
| 1735 void _responseDone() { | 1740 void _responseDone() { |
| 1736 if (_closing) { | 1741 if (_closing) { |
| 1737 if (_socket != null) { | 1742 if (_socket != null) { |
| 1738 _socket.close(); | 1743 _socket.close(); |
| 1739 } | 1744 } |
| 1740 } else { | 1745 } else { |
| 1741 _client._returnSocketConnection(_socketConn); | 1746 _client._returnSocketConnection(_socketConn); |
| 1742 } | 1747 } |
| 1743 _socket = null; | 1748 _socket = null; |
| 1744 _socketConn = null; | 1749 _socketConn = null; |
| 1745 } | 1750 } |
| 1746 | 1751 |
| 1747 HttpClientRequest open(String method, String uri) { | 1752 HttpClientRequest open(String method, String uri) { |
| 1748 _method = method; | 1753 _method = method; |
| 1754 // Tell the HTTP parser the method it is expecting a response to. |
| 1755 _httpParser.responseToMethod = method; |
| 1749 _request = new _HttpClientRequest(method, uri, this); | 1756 _request = new _HttpClientRequest(method, uri, this); |
| 1750 _response = new _HttpClientResponse(this); | 1757 _response = new _HttpClientResponse(this); |
| 1751 return _request; | 1758 return _request; |
| 1752 } | 1759 } |
| 1753 | 1760 |
| 1754 DetachedSocket detachSocket() { | 1761 DetachedSocket detachSocket() { |
| 1755 return _detachSocket(); | 1762 return _detachSocket(); |
| 1756 } | 1763 } |
| 1757 | 1764 |
| 1758 void _onConnectionClosed(e) { | 1765 void _onConnectionClosed(e) { |
| (...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2094 | 2101 |
| 2095 | 2102 |
| 2096 class _RedirectInfo implements RedirectInfo { | 2103 class _RedirectInfo implements RedirectInfo { |
| 2097 const _RedirectInfo(int this.statusCode, | 2104 const _RedirectInfo(int this.statusCode, |
| 2098 String this.method, | 2105 String this.method, |
| 2099 Uri this.location); | 2106 Uri this.location); |
| 2100 final int statusCode; | 2107 final int statusCode; |
| 2101 final String method; | 2108 final String method; |
| 2102 final Uri location; | 2109 final Uri location; |
| 2103 } | 2110 } |
| OLD | NEW |