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 1649 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1660 _httpConnection._flush(); | 1660 _httpConnection._flush(); |
1661 } | 1661 } |
1662 | 1662 |
1663 void _streamClose() { | 1663 void _streamClose() { |
1664 _ensureHeadersSent(); | 1664 _ensureHeadersSent(); |
1665 _state = DONE; | 1665 _state = DONE; |
1666 // Stop tracking no pending write events. | 1666 // Stop tracking no pending write events. |
1667 _httpConnection._onNoPendingWrites = null; | 1667 _httpConnection._onNoPendingWrites = null; |
1668 // Ensure that any trailing data is written. | 1668 // Ensure that any trailing data is written. |
1669 _writeDone(); | 1669 _writeDone(); |
| 1670 _connection._requestDone(); |
1670 } | 1671 } |
1671 | 1672 |
1672 void _streamSetNoPendingWriteHandler(callback()) { | 1673 void _streamSetNoPendingWriteHandler(callback()) { |
1673 if (_state != DONE) { | 1674 if (_state != DONE) { |
1674 _httpConnection._onNoPendingWrites = callback; | 1675 _httpConnection._onNoPendingWrites = callback; |
1675 } | 1676 } |
1676 } | 1677 } |
1677 | 1678 |
1678 void _streamSetCloseHandler(callback()) { | 1679 void _streamSetCloseHandler(callback()) { |
1679 // TODO(sgjesse): Handle this. | 1680 // TODO(sgjesse): Handle this. |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1796 } | 1797 } |
1797 | 1798 |
1798 void _handleUnauthorized() { | 1799 void _handleUnauthorized() { |
1799 | 1800 |
1800 void retryRequest(_Credentials cr) { | 1801 void retryRequest(_Credentials cr) { |
1801 if (cr != null) { | 1802 if (cr != null) { |
1802 // Drain body and retry. | 1803 // Drain body and retry. |
1803 // TODO(sgjesse): Support digest. | 1804 // TODO(sgjesse): Support digest. |
1804 if (cr.scheme == _AuthenticationScheme.BASIC) { | 1805 if (cr.scheme == _AuthenticationScheme.BASIC) { |
1805 inputStream.onData = inputStream.read; | 1806 inputStream.onData = inputStream.read; |
1806 inputStream.onClosed = _connection.retry; | 1807 _connection._retry(); |
1807 return; | 1808 return; |
1808 } | 1809 } |
1809 } | 1810 } |
1810 | 1811 |
1811 // Fall through to here to perform normal response handling if | 1812 // Fall through to here to perform normal response handling if |
1812 // there is no sensible authorization handling. | 1813 // there is no sensible authorization handling. |
1813 if (_connection._onResponse != null) { | 1814 if (_connection._onResponse != null) { |
1814 _connection._onResponse(this); | 1815 _connection._onResponse(this); |
1815 } | 1816 } |
1816 } | 1817 } |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1890 Uri redirectUrl = new Uri.fromString(location[0]); | 1891 Uri redirectUrl = new Uri.fromString(location[0]); |
1891 for (int i = 0; i < _connection._redirects.length; i++) { | 1892 for (int i = 0; i < _connection._redirects.length; i++) { |
1892 if (_connection._redirects[i].location.toString() == | 1893 if (_connection._redirects[i].location.toString() == |
1893 redirectUrl.toString()) { | 1894 redirectUrl.toString()) { |
1894 throw new RedirectLoopException(_connection._redirects); | 1895 throw new RedirectLoopException(_connection._redirects); |
1895 } | 1896 } |
1896 } | 1897 } |
1897 } | 1898 } |
1898 // Drain body and redirect. | 1899 // Drain body and redirect. |
1899 inputStream.onData = inputStream.read; | 1900 inputStream.onData = inputStream.read; |
1900 inputStream.onClosed = _connection.redirect; | 1901 _connection.redirect(); |
1901 } else { | 1902 } else { |
1902 throw new RedirectLimitExceededException(_connection._redirects); | 1903 throw new RedirectLimitExceededException(_connection._redirects); |
1903 } | 1904 } |
1904 } else if (statusCode == HttpStatus.UNAUTHORIZED) { | 1905 } else if (statusCode == HttpStatus.UNAUTHORIZED) { |
1905 _handleUnauthorized(); | 1906 _handleUnauthorized(); |
1906 } else if (_connection._onResponse != null) { | 1907 } else if (_connection._onResponse != null) { |
1907 _connection._onResponse(this); | 1908 _connection._onResponse(this); |
1908 } | 1909 } |
1909 } | 1910 } |
1910 | 1911 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1945 _HttpInputStream _inputStream; | 1946 _HttpInputStream _inputStream; |
1946 _BufferList _buffer; | 1947 _BufferList _buffer; |
1947 bool _dataEndCalled = false; | 1948 bool _dataEndCalled = false; |
1948 | 1949 |
1949 Function _streamErrorHandler; | 1950 Function _streamErrorHandler; |
1950 } | 1951 } |
1951 | 1952 |
1952 | 1953 |
1953 class _HttpClientConnection | 1954 class _HttpClientConnection |
1954 extends _HttpConnectionBase implements HttpClientConnection { | 1955 extends _HttpConnectionBase implements HttpClientConnection { |
| 1956 static const int NONE = 0; |
| 1957 static const int REQUEST_DONE = 1; |
| 1958 static const int RESPONSE_DONE = 2; |
| 1959 static const int ALL_DONE = REQUEST_DONE | RESPONSE_DONE; |
| 1960 |
1955 _HttpClientConnection(_HttpClient this._client); | 1961 _HttpClientConnection(_HttpClient this._client); |
1956 | 1962 |
1957 void _connectionEstablished(_SocketConnection socketConn) { | 1963 void _connectionEstablished(_SocketConnection socketConn) { |
1958 super._connectionEstablished(socketConn._socket); | 1964 super._connectionEstablished(socketConn._socket); |
1959 _socketConn = socketConn; | 1965 _socketConn = socketConn; |
1960 // Register HTTP parser callbacks. | 1966 // Register HTTP parser callbacks. |
1961 _httpParser.requestStart = | 1967 _httpParser.requestStart = |
1962 (method, uri, version) => _onRequestStart(method, uri, version); | 1968 (method, uri, version) => _onRequestStart(method, uri, version); |
1963 _httpParser.responseStart = | 1969 _httpParser.responseStart = |
1964 (statusCode, reasonPhrase, version) => | 1970 (statusCode, reasonPhrase, version) => |
1965 _onResponseStart(statusCode, reasonPhrase, version); | 1971 _onResponseStart(statusCode, reasonPhrase, version); |
1966 _httpParser.headerReceived = | 1972 _httpParser.headerReceived = |
1967 (name, value) => _onHeaderReceived(name, value); | 1973 (name, value) => _onHeaderReceived(name, value); |
1968 _httpParser.headersComplete = () => _onHeadersComplete(); | 1974 _httpParser.headersComplete = () => _onHeadersComplete(); |
1969 _httpParser.dataReceived = (data) => _onDataReceived(data); | 1975 _httpParser.dataReceived = (data) => _onDataReceived(data); |
1970 _httpParser.dataEnd = (closed) => _onDataEnd(closed); | 1976 _httpParser.dataEnd = (closed) => _onDataEnd(closed); |
1971 _httpParser.error = (e) => _onError(e); | 1977 _httpParser.error = (e) => _onError(e); |
1972 } | 1978 } |
1973 | 1979 |
| 1980 bool get _isRequestDone => (_state & REQUEST_DONE) == REQUEST_DONE; |
| 1981 bool get _isResponseDone => (_state & RESPONSE_DONE) == RESPONSE_DONE; |
| 1982 bool get _isAllDone => (_state & ALL_DONE) == ALL_DONE; |
| 1983 |
| 1984 void _checkSocketDone() { |
| 1985 if (_isAllDone) { |
| 1986 if (!_closing) { |
| 1987 _client._returnSocketConnection(_socketConn); |
| 1988 } |
| 1989 _socket = null; |
| 1990 _socketConn = null; |
| 1991 assert(_pendingRedirect == null || _pendingRetry == null); |
| 1992 if (_pendingRedirect != null) { |
| 1993 _doRedirect(_pendingRedirect); |
| 1994 _pendingRedirect = null; |
| 1995 } else if (_pendingRetry != null) { |
| 1996 _doRetry(_pendingRetry); |
| 1997 _pendingRetry = null; |
| 1998 } |
| 1999 } |
| 2000 } |
| 2001 |
| 2002 void _requestDone() { |
| 2003 _state |= REQUEST_DONE; |
| 2004 _checkSocketDone(); |
| 2005 } |
| 2006 |
1974 void _responseDone() { | 2007 void _responseDone() { |
1975 if (_closing) { | 2008 if (_closing) { |
1976 if (_socket != null) { | 2009 if (_socket != null) { |
1977 _socket.close(); | 2010 _socket.close(); |
1978 } | 2011 } |
1979 } else { | |
1980 _client._returnSocketConnection(_socketConn); | |
1981 } | 2012 } |
1982 _socket = null; | 2013 _state |= RESPONSE_DONE; |
1983 _socketConn = null; | 2014 _checkSocketDone(); |
1984 } | 2015 } |
1985 | 2016 |
1986 HttpClientRequest open(String method, Uri uri) { | 2017 HttpClientRequest open(String method, Uri uri) { |
1987 _method = method; | 2018 _method = method; |
1988 // Tell the HTTP parser the method it is expecting a response to. | 2019 // Tell the HTTP parser the method it is expecting a response to. |
1989 _httpParser.responseToMethod = method; | 2020 _httpParser.responseToMethod = method; |
1990 _request = new _HttpClientRequest(method, uri, this); | 2021 _request = new _HttpClientRequest(method, uri, this); |
1991 _response = new _HttpClientResponse(this); | 2022 _response = new _HttpClientResponse(this); |
1992 return _request; | 2023 return _request; |
1993 } | 2024 } |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2050 } | 2081 } |
2051 | 2082 |
2052 void set onResponse(void handler(HttpClientResponse response)) { | 2083 void set onResponse(void handler(HttpClientResponse response)) { |
2053 _onResponse = handler; | 2084 _onResponse = handler; |
2054 } | 2085 } |
2055 | 2086 |
2056 void set onError(void callback(e)) { | 2087 void set onError(void callback(e)) { |
2057 _onErrorCallback = callback; | 2088 _onErrorCallback = callback; |
2058 } | 2089 } |
2059 | 2090 |
2060 void retry() { | 2091 void _doRetry(_RedirectInfo retry) { |
2061 if (_socketConn != null) { | 2092 assert(_socketConn == null); |
2062 throw new HttpException("Cannot retry with body data pending"); | 2093 _request = null; |
| 2094 _response = null; |
| 2095 |
| 2096 // Retry the URL using the same connection instance. |
| 2097 _state = NONE; |
| 2098 _client._openUrl(retry.method, retry.location, this); |
| 2099 } |
| 2100 |
| 2101 void _retry() { |
| 2102 var retry = new _RedirectInfo(_response.statusCode, _method, _request._uri); |
| 2103 // The actual retry is postponed until both response and request |
| 2104 // are done. |
| 2105 if (_isAllDone) { |
| 2106 _doRetry(retry); |
| 2107 } else { |
| 2108 // Prepare for retry. |
| 2109 assert(_pendingRedirect == null); |
| 2110 _pendingRetry = retry; |
2063 } | 2111 } |
2064 // Retry the URL using the same connection instance. | 2112 } |
2065 _client._openUrl(_method, _request._uri, this); | 2113 |
| 2114 void _doRedirect(_RedirectInfo redirect) { |
| 2115 assert(_socketConn == null); |
| 2116 |
| 2117 if (_redirects == null) { |
| 2118 _redirects = new List<_RedirectInfo>(); |
| 2119 } |
| 2120 _redirects.add(redirect); |
| 2121 _doRetry(redirect); |
2066 } | 2122 } |
2067 | 2123 |
2068 void redirect([String method, Uri url]) { | 2124 void redirect([String method, Uri url]) { |
2069 if (_socketConn != null) { | |
2070 throw new HttpException("Cannot redirect with body data pending"); | |
2071 } | |
2072 if (method == null) method = _method; | 2125 if (method == null) method = _method; |
2073 if (url == null) { | 2126 if (url == null) { |
2074 url = new Uri.fromString(_response.headers.value(HttpHeaders.LOCATION)); | 2127 url = new Uri.fromString(_response.headers.value(HttpHeaders.LOCATION)); |
2075 } | 2128 } |
2076 if (_redirects == null) { | 2129 var redirect = new _RedirectInfo(_response.statusCode, method, url); |
2077 _redirects = new List<_RedirectInfo>(); | 2130 // The actual redirect is postponed until both response and |
| 2131 // request are done. |
| 2132 if (_isAllDone) { |
| 2133 _doRedirect(redirect); |
| 2134 } else { |
| 2135 // Prepare for redirect. |
| 2136 assert(_pendingRetry == null); |
| 2137 _pendingRedirect = redirect; |
2078 } | 2138 } |
2079 _redirects.add(new _RedirectInfo(_response.statusCode, method, url)); | |
2080 _request = null; | |
2081 _response = null; | |
2082 // Open redirect URL using the same connection instance. | |
2083 _client._openUrl(method, url, this); | |
2084 } | 2139 } |
2085 | 2140 |
| 2141 int _state = NONE; |
| 2142 |
2086 List<RedirectInfo> get redirects => _redirects; | 2143 List<RedirectInfo> get redirects => _redirects; |
2087 | 2144 |
2088 Function _onRequest; | 2145 Function _onRequest; |
2089 Function _onResponse; | 2146 Function _onResponse; |
2090 Function _onErrorCallback; | 2147 Function _onErrorCallback; |
2091 | 2148 |
2092 _HttpClient _client; | 2149 _HttpClient _client; |
2093 _SocketConnection _socketConn; | 2150 _SocketConnection _socketConn; |
2094 HttpClientRequest _request; | 2151 HttpClientRequest _request; |
2095 HttpClientResponse _response; | 2152 HttpClientResponse _response; |
2096 String _method; | 2153 String _method; |
2097 bool _usingProxy; | 2154 bool _usingProxy; |
2098 | 2155 |
2099 // Redirect handling | 2156 // Redirect handling |
2100 bool followRedirects = true; | 2157 bool followRedirects = true; |
2101 int maxRedirects = 5; | 2158 int maxRedirects = 5; |
2102 List<_RedirectInfo> _redirects; | 2159 List<_RedirectInfo> _redirects; |
| 2160 _RedirectInfo _pendingRedirect; |
| 2161 _RedirectInfo _pendingRetry; |
2103 | 2162 |
2104 // Callbacks. | 2163 // Callbacks. |
2105 var requestReceived; | 2164 var requestReceived; |
2106 } | 2165 } |
2107 | 2166 |
2108 | 2167 |
2109 // Class for holding keep-alive sockets in the cache for the HTTP | 2168 // Class for holding keep-alive sockets in the cache for the HTTP |
2110 // client together with the connection information. | 2169 // client together with the connection information. |
2111 class _SocketConnection { | 2170 class _SocketConnection { |
2112 _SocketConnection(String this._host, | 2171 _SocketConnection(String this._host, |
(...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2596 | 2655 |
2597 | 2656 |
2598 class _RedirectInfo implements RedirectInfo { | 2657 class _RedirectInfo implements RedirectInfo { |
2599 const _RedirectInfo(int this.statusCode, | 2658 const _RedirectInfo(int this.statusCode, |
2600 String this.method, | 2659 String this.method, |
2601 Uri this.location); | 2660 Uri this.location); |
2602 final int statusCode; | 2661 final int statusCode; |
2603 final String method; | 2662 final String method; |
2604 final Uri location; | 2663 final Uri location; |
2605 } | 2664 } |
OLD | NEW |