Chromium Code Reviews| 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 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 301 List<String> _noFoldingHeaders; | 301 List<String> _noFoldingHeaders; |
| 302 | 302 |
| 303 String _host; | 303 String _host; |
| 304 int _port; | 304 int _port; |
| 305 } | 305 } |
| 306 | 306 |
| 307 | 307 |
| 308 class _HeaderValue implements HeaderValue { | 308 class _HeaderValue implements HeaderValue { |
| 309 _HeaderValue([String this.value = ""]); | 309 _HeaderValue([String this.value = ""]); |
| 310 | 310 |
| 311 _HeaderValue.fromString(String value) { | 311 _HeaderValue.fromString(String value, [this.parameterSeparator = ";"]) { |
| 312 // Parse the string. | 312 // Parse the string. |
| 313 _parse(value); | 313 _parse(value); |
| 314 } | 314 } |
| 315 | 315 |
| 316 Map<String, String> get parameters { | 316 Map<String, String> get parameters { |
| 317 if (_parameters == null) _parameters = new Map<String, String>(); | 317 if (_parameters == null) _parameters = new Map<String, String>(); |
| 318 return _parameters; | 318 return _parameters; |
| 319 } | 319 } |
| 320 | 320 |
| 321 String toString() { | 321 String toString() { |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 340 void skipWS() { | 340 void skipWS() { |
| 341 while (!done()) { | 341 while (!done()) { |
| 342 if (s[index] != " " && s[index] != "\t") return; | 342 if (s[index] != " " && s[index] != "\t") return; |
| 343 index++; | 343 index++; |
| 344 } | 344 } |
| 345 } | 345 } |
| 346 | 346 |
| 347 String parseValue() { | 347 String parseValue() { |
| 348 int start = index; | 348 int start = index; |
| 349 while (!done()) { | 349 while (!done()) { |
| 350 if (s[index] == " " || s[index] == "\t" || s[index] == ";") break; | 350 if (s[index] == " " || |
| 351 s[index] == "\t" || | |
| 352 s[index] == parameterSeparator) break; | |
| 351 index++; | 353 index++; |
| 352 } | 354 } |
| 353 return s.substring(start, index).toLowerCase(); | 355 return s.substring(start, index).toLowerCase(); |
| 354 } | 356 } |
| 355 | 357 |
| 356 void expect(String expected) { | 358 void expect(String expected) { |
| 357 if (done()) throw new HttpException("Failed to parse header value [$s]"); | 359 if (done()) throw new HttpException("Failed to parse header value $expecte d [$s]"); |
|
Mads Ager (google)
2012/10/17 11:26:43
Long line.
Søren Gjesse
2012/10/26 09:43:00
Done.
| |
| 358 if (s[index] != expected) { | 360 if (s[index] != expected) { |
| 359 throw new HttpException("Failed to parse header value [$s]"); | 361 throw new HttpException("Failed to parse header value x $expected [$s]") ; |
|
Mads Ager (google)
2012/10/17 11:26:43
Ditto.
Søren Gjesse
2012/10/26 09:43:00
Done.
| |
| 360 } | 362 } |
| 361 index++; | 363 index++; |
| 362 } | 364 } |
| 363 | 365 |
| 366 void maybeExpect(String expected) { | |
| 367 if (s[index] == expected) index++; | |
| 368 } | |
| 369 | |
| 364 void parseParameters() { | 370 void parseParameters() { |
| 365 _parameters = new Map<String, String>(); | 371 _parameters = new Map<String, String>(); |
| 366 | 372 |
| 367 String parseParameterName() { | 373 String parseParameterName() { |
| 368 int start = index; | 374 int start = index; |
| 369 while (!done()) { | 375 while (!done()) { |
| 370 if (s[index] == " " || s[index] == "\t" || s[index] == "=") break; | 376 if (s[index] == " " || s[index] == "\t" || s[index] == "=") break; |
| 371 index++; | 377 index++; |
| 372 } | 378 } |
| 373 return s.substring(start, index).toLowerCase(); | 379 return s.substring(start, index).toLowerCase(); |
| 374 } | 380 } |
| 375 | 381 |
| 376 String parseParameterValue() { | 382 String parseParameterValue() { |
| 377 if (s[index] == "\"") { | 383 if (s[index] == "\"") { |
| 378 // Parse quoted value. | 384 // Parse quoted value. |
| 379 StringBuffer sb = new StringBuffer(); | 385 StringBuffer sb = new StringBuffer(); |
| 380 index++; | 386 index++; |
| 381 while (!done()) { | 387 while (!done()) { |
| 382 if (s[index] == "\\") { | 388 if (s[index] == "\\") { |
| 383 if (index + 1 == s.length) { | 389 if (index + 1 == s.length) { |
| 384 throw new HttpException("Failed to parse header value [$s]"); | 390 throw new HttpException("Failed to parse header value y [$s]"); |
|
Mads Ager (google)
2012/10/17 11:26:43
Accidental edit?
Søren Gjesse
2012/10/26 09:43:00
Done.
| |
| 385 } | 391 } |
| 386 index++; | 392 index++; |
| 387 } else if (s[index] == "\"") { | 393 } else if (s[index] == "\"") { |
| 388 index++; | 394 index++; |
| 389 break; | 395 break; |
| 390 } | 396 } |
| 391 sb.add(s[index]); | 397 sb.add(s[index]); |
| 392 index++; | 398 index++; |
| 393 } | 399 } |
| 394 return sb.toString(); | 400 return sb.toString(); |
| 395 } else { | 401 } else { |
| 396 // Parse non-quoted value. | 402 // Parse non-quoted value. |
| 397 return parseValue(); | 403 return parseValue(); |
| 398 } | 404 } |
| 399 } | 405 } |
| 400 | 406 |
| 401 while (!done()) { | 407 while (!done()) { |
| 402 skipWS(); | 408 skipWS(); |
| 403 if (done()) return; | 409 if (done()) return; |
| 404 String name = parseParameterName(); | 410 String name = parseParameterName(); |
| 405 skipWS(); | 411 skipWS(); |
| 406 expect("="); | 412 expect("="); |
| 407 skipWS(); | 413 skipWS(); |
| 408 String value = parseParameterValue(); | 414 String value = parseParameterValue(); |
| 409 _parameters[name] = value; | 415 _parameters[name] = value; |
| 410 skipWS(); | 416 skipWS(); |
| 411 if (done()) return; | 417 if (done()) return; |
| 412 expect(";"); | 418 expect(parameterSeparator); |
| 413 } | 419 } |
| 414 } | 420 } |
| 415 | 421 |
| 416 skipWS(); | 422 skipWS(); |
| 417 value = parseValue(); | 423 value = parseValue(); |
| 418 skipWS(); | 424 skipWS(); |
| 419 if (done()) return; | 425 if (done()) return; |
| 420 expect(";"); | 426 maybeExpect(parameterSeparator); |
| 421 parseParameters(); | 427 parseParameters(); |
| 422 } | 428 } |
| 423 | 429 |
| 424 String value; | 430 String value; |
| 431 String parameterSeparator; | |
| 425 Map<String, String> _parameters; | 432 Map<String, String> _parameters; |
| 426 } | 433 } |
| 427 | 434 |
| 428 | 435 |
| 429 class _ContentType extends _HeaderValue implements ContentType { | 436 class _ContentType extends _HeaderValue implements ContentType { |
| 430 _ContentType(String primaryType, String subType) | 437 _ContentType(String primaryType, String subType) |
| 431 : _primaryType = primaryType, _subType = subType, super(""); | 438 : _primaryType = primaryType, _subType = subType, super(""); |
| 432 | 439 |
| 433 _ContentType.fromString(String value) : super.fromString(value); | 440 _ContentType.fromString(String value) : super.fromString(value); |
| 434 | 441 |
| (...skipping 1283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1718 _reasonPhrase = reasonPhrase; | 1725 _reasonPhrase = reasonPhrase; |
| 1719 } | 1726 } |
| 1720 | 1727 |
| 1721 void _onHeaderReceived(String name, String value) { | 1728 void _onHeaderReceived(String name, String value) { |
| 1722 _headers.add(name, value); | 1729 _headers.add(name, value); |
| 1723 if (name == "content-length") { | 1730 if (name == "content-length") { |
| 1724 _contentLength = parseInt(value); | 1731 _contentLength = parseInt(value); |
| 1725 } | 1732 } |
| 1726 } | 1733 } |
| 1727 | 1734 |
| 1735 void _handleUnauthorized() { | |
| 1736 // Only try to authenticate if there is a challenge in the response. | |
| 1737 List<String> challenge = _headers[HttpHeaders.WWW_AUTHENTICATE]; | |
| 1738 if (challenge != null && challenge.length == 1) { | |
| 1739 HeaderValue header = | |
| 1740 new HeaderValue.fromString(challenge[0], parameterSeparator: ","); | |
| 1741 _AuthenticationScheme scheme = | |
| 1742 new _AuthenticationScheme.fromString(header.value); | |
| 1743 String realm = header.parameters["realm"]; | |
| 1744 | |
| 1745 // See if any credentials are available. | |
| 1746 _Credentials cr = | |
|
Mads Ager (google)
2012/10/17 11:26:43
What if we authorize once and the credentials are
Søren Gjesse
2012/10/26 09:43:00
Added a used flag on credentials in the cache so t
| |
| 1747 _connection._client._findCredentials( | |
| 1748 _connection._request._uri, scheme); | |
| 1749 | |
| 1750 // Ask for more credentials if none found. | |
| 1751 if (cr == null) { | |
| 1752 if (_connection._client._authenticate( | |
| 1753 _connection._request._uri, scheme, realm)) { | |
| 1754 cr = _connection._client._findCredentials(_connection._request._uri, | |
| 1755 scheme); | |
| 1756 } | |
| 1757 } | |
| 1758 | |
| 1759 // If credentials found prepare for retrying the request. | |
| 1760 if (cr != null) { | |
| 1761 if (cr.scheme == _AuthenticationScheme.DIGEST) { | |
| 1762 cr.nonce = header.parameters["nonce"]; | |
| 1763 cr.algorithm = header.parameters["algorithm"]; | |
| 1764 cr.qop = header.parameters["qop"]; | |
| 1765 } | |
| 1766 // Drain body and retry. | |
| 1767 // TODO(sgesse): Support digest. | |
| 1768 if (cr.scheme == _AuthenticationScheme.DIGEST) { | |
| 1769 inputStream.onData = inputStream.read; | |
| 1770 inputStream.onClosed = _connection.retry; | |
| 1771 return; | |
| 1772 } | |
| 1773 } | |
| 1774 } | |
| 1775 | |
| 1776 // Fall through to here to perform normal response handling if | |
| 1777 // there is no sensible authorization handling. | |
| 1778 if (_connection._onResponse != null) { | |
| 1779 _connection._onResponse(this); | |
| 1780 } | |
| 1781 } | |
| 1782 | |
| 1728 void _onHeadersComplete() { | 1783 void _onHeadersComplete() { |
| 1729 _headers._mutable = false; | 1784 _headers._mutable = false; |
| 1730 _buffer = new _BufferList(); | 1785 _buffer = new _BufferList(); |
| 1731 if (isRedirect && _connection.followRedirects) { | 1786 if (isRedirect && _connection.followRedirects) { |
| 1732 if (_connection._redirects == null || | 1787 if (_connection._redirects == null || |
| 1733 _connection._redirects.length < _connection.maxRedirects) { | 1788 _connection._redirects.length < _connection.maxRedirects) { |
| 1734 // Check the location header. | 1789 // Check the location header. |
| 1735 List<String> location = headers[HttpHeaders.LOCATION]; | 1790 List<String> location = headers[HttpHeaders.LOCATION]; |
| 1736 if (location == null || location.length > 1) { | 1791 if (location == null || location.length > 1) { |
| 1737 throw new RedirectException("Invalid redirect", | 1792 throw new RedirectException("Invalid redirect", |
| 1738 _connection._redirects); | 1793 _connection._redirects); |
| 1739 } | 1794 } |
| 1740 // Check for redirect loop | 1795 // Check for redirect loop |
| 1741 if (_connection._redirects != null) { | 1796 if (_connection._redirects != null) { |
| 1742 Uri redirectUrl = new Uri.fromString(location[0]); | 1797 Uri redirectUrl = new Uri.fromString(location[0]); |
| 1743 for (int i = 0; i < _connection._redirects.length; i++) { | 1798 for (int i = 0; i < _connection._redirects.length; i++) { |
| 1744 if (_connection._redirects[i].location.toString() == | 1799 if (_connection._redirects[i].location.toString() == |
| 1745 redirectUrl.toString()) { | 1800 redirectUrl.toString()) { |
| 1746 throw new RedirectLoopException(_connection._redirects); | 1801 throw new RedirectLoopException(_connection._redirects); |
| 1747 } | 1802 } |
| 1748 } | 1803 } |
| 1749 } | 1804 } |
| 1750 // Drain body and redirect. | 1805 // Drain body and redirect. |
| 1751 inputStream.onData = inputStream.read; | 1806 inputStream.onData = inputStream.read; |
| 1752 inputStream.onClosed = _connection.redirect; | 1807 inputStream.onClosed = _connection.redirect; |
| 1753 } else { | 1808 } else { |
| 1754 throw new RedirectLimitExceededException(_connection._redirects); | 1809 throw new RedirectLimitExceededException(_connection._redirects); |
| 1755 } | 1810 } |
| 1811 } else if (statusCode == HttpStatus.UNAUTHORIZED) { | |
| 1812 _handleUnauthorized(); | |
| 1756 } else if (_connection._onResponse != null) { | 1813 } else if (_connection._onResponse != null) { |
| 1757 _connection._onResponse(this); | 1814 _connection._onResponse(this); |
| 1758 } | 1815 } |
| 1759 } | 1816 } |
| 1760 | 1817 |
| 1761 void _onDataReceived(List<int> data) { | 1818 void _onDataReceived(List<int> data) { |
| 1762 _buffer.add(data); | 1819 _buffer.add(data); |
| 1763 if (_inputStream != null) _inputStream._dataReceived(); | 1820 if (_inputStream != null) _inputStream._dataReceived(); |
| 1764 } | 1821 } |
| 1765 | 1822 |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1900 } | 1957 } |
| 1901 | 1958 |
| 1902 void set onResponse(void handler(HttpClientResponse response)) { | 1959 void set onResponse(void handler(HttpClientResponse response)) { |
| 1903 _onResponse = handler; | 1960 _onResponse = handler; |
| 1904 } | 1961 } |
| 1905 | 1962 |
| 1906 void set onError(void callback(e)) { | 1963 void set onError(void callback(e)) { |
| 1907 _onErrorCallback = callback; | 1964 _onErrorCallback = callback; |
| 1908 } | 1965 } |
| 1909 | 1966 |
| 1967 void retry() { | |
| 1968 if (_socketConn != null) { | |
| 1969 throw new HttpException("Cannot retry with body data pending"); | |
| 1970 } | |
| 1971 // Retry the URL using the same connection instance. | |
| 1972 _client._openUrl(_method, _request._uri, this); | |
| 1973 } | |
| 1974 | |
| 1910 void redirect([String method, Uri url]) { | 1975 void redirect([String method, Uri url]) { |
| 1911 if (_socketConn != null) { | 1976 if (_socketConn != null) { |
| 1912 throw new HttpException("Cannot redirect with body data pending"); | 1977 throw new HttpException("Cannot redirect with body data pending"); |
| 1913 } | 1978 } |
| 1914 if (method == null) method = _method; | 1979 if (method == null) method = _method; |
| 1915 if (url == null) { | 1980 if (url == null) { |
| 1916 url = new Uri.fromString(_response.headers.value(HttpHeaders.LOCATION)); | 1981 url = new Uri.fromString(_response.headers.value(HttpHeaders.LOCATION)); |
| 1917 } | 1982 } |
| 1918 if (_redirects == null) { | 1983 if (_redirects == null) { |
| 1919 _redirects = new List<_RedirectInfo>(); | 1984 _redirects = new List<_RedirectInfo>(); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2024 final String host; | 2089 final String host; |
| 2025 final int port; | 2090 final int port; |
| 2026 final bool isDirect; | 2091 final bool isDirect; |
| 2027 } | 2092 } |
| 2028 | 2093 |
| 2029 class _HttpClient implements HttpClient { | 2094 class _HttpClient implements HttpClient { |
| 2030 static const int DEFAULT_EVICTION_TIMEOUT = 60000; | 2095 static const int DEFAULT_EVICTION_TIMEOUT = 60000; |
| 2031 | 2096 |
| 2032 _HttpClient() : _openSockets = new Map(), | 2097 _HttpClient() : _openSockets = new Map(), |
| 2033 _activeSockets = new Set(), | 2098 _activeSockets = new Set(), |
| 2099 credentials = new List<_HttpClientCredentials>(), | |
| 2034 _shutdown = false; | 2100 _shutdown = false; |
| 2035 | 2101 |
| 2036 HttpClientConnection open( | 2102 HttpClientConnection open( |
| 2037 String method, String host, int port, String path) { | 2103 String method, String host, int port, String path) { |
| 2038 // TODO(sgjesse): The path set here can contain both query and | 2104 // TODO(sgjesse): The path set here can contain both query and |
| 2039 // fragment. They should be cracked and set correctly. | 2105 // fragment. They should be cracked and set correctly. |
| 2040 return _open(method, new Uri.fromComponents( | 2106 return _open(method, new Uri.fromComponents( |
| 2041 scheme: "http", domain: host, port: port, path: path)); | 2107 scheme: "http", domain: host, port: port, path: path)); |
| 2042 } | 2108 } |
| 2043 | 2109 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 2054 HttpClientConnection openUrl(String method, Uri url) { | 2120 HttpClientConnection openUrl(String method, Uri url) { |
| 2055 return _openUrl(method, url); | 2121 return _openUrl(method, url); |
| 2056 } | 2122 } |
| 2057 | 2123 |
| 2058 HttpClientConnection _openUrl(String method, | 2124 HttpClientConnection _openUrl(String method, |
| 2059 Uri url, | 2125 Uri url, |
| 2060 [_HttpClientConnection connection]) { | 2126 [_HttpClientConnection connection]) { |
| 2061 if (url.scheme != "http") { | 2127 if (url.scheme != "http") { |
| 2062 throw new HttpException("Unsupported URL scheme ${url.scheme}"); | 2128 throw new HttpException("Unsupported URL scheme ${url.scheme}"); |
| 2063 } | 2129 } |
| 2064 if (url.userInfo != "") { | |
| 2065 throw new HttpException("Unsupported user info ${url.userInfo}"); | |
| 2066 } | |
| 2067 return _open(method, url, connection); | 2130 return _open(method, url, connection); |
| 2068 } | 2131 } |
| 2069 | 2132 |
| 2070 HttpClientConnection get(String host, int port, String path) { | 2133 HttpClientConnection get(String host, int port, String path) { |
| 2071 return open("GET", host, port, path); | 2134 return open("GET", host, port, path); |
| 2072 } | 2135 } |
| 2073 | 2136 |
| 2074 HttpClientConnection getUrl(Uri url) => _openUrl("GET", url); | 2137 HttpClientConnection getUrl(Uri url) => _openUrl("GET", url); |
| 2075 | 2138 |
| 2076 HttpClientConnection post(String host, int port, String path) { | 2139 HttpClientConnection post(String host, int port, String path) { |
| 2077 return open("POST", host, port, path); | 2140 return open("POST", host, port, path); |
| 2078 } | 2141 } |
| 2079 | 2142 |
| 2080 HttpClientConnection postUrl(Uri url) => _openUrl("POST", url); | 2143 HttpClientConnection postUrl(Uri url) => _openUrl("POST", url); |
| 2081 | 2144 |
| 2145 set authenticate(f(Uri uri, String realm)) => _authenticate = f; | |
| 2146 | |
| 2147 void addCredentials( | |
| 2148 Uri url, String realm, HttpClientCredentials cr) { | |
| 2149 credentials.add(new _Credentials(url, realm, cr)); | |
| 2150 } | |
| 2151 | |
| 2082 set findProxy(String f(Uri uri)) => _findProxy = f; | 2152 set findProxy(String f(Uri uri)) => _findProxy = f; |
| 2083 | 2153 |
| 2084 void shutdown() { | 2154 void shutdown() { |
| 2085 _openSockets.forEach((String key, Queue<_SocketConnection> connections) { | 2155 _openSockets.forEach((String key, Queue<_SocketConnection> connections) { |
| 2086 while (!connections.isEmpty()) { | 2156 while (!connections.isEmpty()) { |
| 2087 _SocketConnection socketConn = connections.removeFirst(); | 2157 _SocketConnection socketConn = connections.removeFirst(); |
| 2088 socketConn._socket.close(); | 2158 socketConn._socket.close(); |
| 2089 } | 2159 } |
| 2090 }); | 2160 }); |
| 2091 _activeSockets.forEach((_SocketConnection socketConn) { | 2161 _activeSockets.forEach((_SocketConnection socketConn) { |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 2115 int proxyIndex) { | 2185 int proxyIndex) { |
| 2116 | 2186 |
| 2117 void _connectionOpened(_SocketConnection socketConn, | 2187 void _connectionOpened(_SocketConnection socketConn, |
| 2118 _HttpClientConnection connection, | 2188 _HttpClientConnection connection, |
| 2119 bool usingProxy) { | 2189 bool usingProxy) { |
| 2120 connection._usingProxy = usingProxy; | 2190 connection._usingProxy = usingProxy; |
| 2121 connection._connectionEstablished(socketConn); | 2191 connection._connectionEstablished(socketConn); |
| 2122 HttpClientRequest request = connection.open(method, url); | 2192 HttpClientRequest request = connection.open(method, url); |
| 2123 request.headers.host = host; | 2193 request.headers.host = host; |
| 2124 request.headers.port = port; | 2194 request.headers.port = port; |
| 2195 if (url.userInfo != null && !url.userInfo.isEmpty()) { | |
| 2196 // If the URL contains user information use that for basic | |
| 2197 // authorization | |
| 2198 _UTF8Encoder encoder = new _UTF8Encoder(); | |
| 2199 String auth = | |
| 2200 CryptoUtils.bytesToBase64(encoder.encodeString(url.userInfo)); | |
| 2201 request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth"); | |
| 2202 } else { | |
| 2203 // Look for credentials. | |
| 2204 _Credentials cr = _findCredentials(url); | |
| 2205 if (cr != null) { | |
| 2206 cr.authorize(request); | |
| 2207 } | |
| 2208 } | |
| 2125 if (connection._onRequest != null) { | 2209 if (connection._onRequest != null) { |
| 2126 connection._onRequest(request); | 2210 connection._onRequest(request); |
| 2127 } else { | 2211 } else { |
| 2128 request.outputStream.close(); | 2212 request.outputStream.close(); |
| 2129 } | 2213 } |
| 2130 } | 2214 } |
| 2131 | 2215 |
| 2132 assert(proxyIndex < proxyConfiguration.proxies.length); | 2216 assert(proxyIndex < proxyConfiguration.proxies.length); |
| 2133 | 2217 |
| 2134 // Determine the actual host to connect to. | 2218 // Determine the actual host to connect to. |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2258 if (_openSockets.isEmpty()) _cancelEvictionTimer(); | 2342 if (_openSockets.isEmpty()) _cancelEvictionTimer(); |
| 2259 } | 2343 } |
| 2260 _evictionTimer = new Timer.repeating(10000, _handleEviction); | 2344 _evictionTimer = new Timer.repeating(10000, _handleEviction); |
| 2261 } | 2345 } |
| 2262 | 2346 |
| 2263 // Return connection. | 2347 // Return connection. |
| 2264 _activeSockets.remove(socketConn); | 2348 _activeSockets.remove(socketConn); |
| 2265 sockets.addFirst(socketConn); | 2349 sockets.addFirst(socketConn); |
| 2266 } | 2350 } |
| 2267 | 2351 |
| 2352 _Credentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) { | |
| 2353 // Look for credentials. | |
| 2354 _Credentials cr = | |
| 2355 credentials.reduce(null, (_Credentials prev, _Credentials value) { | |
| 2356 if (prev != null) return prev; | |
|
Mads Ager (google)
2012/10/17 11:26:43
I would use a two-space indent for these three lin
Søren Gjesse
2012/10/26 09:43:00
Done.
| |
| 2357 if (value.applies(url, scheme)) return value; | |
| 2358 }); | |
| 2359 return cr; | |
| 2360 } | |
| 2361 | |
| 2268 Function _onOpen; | 2362 Function _onOpen; |
| 2269 Map<String, Queue<_SocketConnection>> _openSockets; | 2363 Map<String, Queue<_SocketConnection>> _openSockets; |
| 2270 Set<_SocketConnection> _activeSockets; | 2364 Set<_SocketConnection> _activeSockets; |
| 2365 List<_HttpClientCredentials> credentials; | |
| 2271 Timer _evictionTimer; | 2366 Timer _evictionTimer; |
| 2272 Function _findProxy; | 2367 Function _findProxy; |
| 2368 Function _authenticate; | |
| 2273 bool _shutdown; // Has this HTTP client been shutdown? | 2369 bool _shutdown; // Has this HTTP client been shutdown? |
| 2274 } | 2370 } |
| 2275 | 2371 |
| 2276 | 2372 |
| 2277 class _HttpConnectionInfo implements HttpConnectionInfo { | 2373 class _HttpConnectionInfo implements HttpConnectionInfo { |
| 2278 String remoteHost; | 2374 String remoteHost; |
| 2279 int remotePort; | 2375 int remotePort; |
| 2280 int localPort; | 2376 int localPort; |
| 2281 } | 2377 } |
| 2282 | 2378 |
| 2283 | 2379 |
| 2284 class _DetachedSocket implements DetachedSocket { | 2380 class _DetachedSocket implements DetachedSocket { |
| 2285 _DetachedSocket(this._socket, this._unparsedData); | 2381 _DetachedSocket(this._socket, this._unparsedData); |
| 2286 Socket get socket => _socket; | 2382 Socket get socket => _socket; |
| 2287 List<int> get unparsedData => _unparsedData; | 2383 List<int> get unparsedData => _unparsedData; |
| 2288 Socket _socket; | 2384 Socket _socket; |
| 2289 List<int> _unparsedData; | 2385 List<int> _unparsedData; |
| 2290 } | 2386 } |
| 2291 | 2387 |
| 2292 | 2388 |
| 2389 class _AuthenticationScheme { | |
| 2390 static const UNKNOWN = const _AuthenticationScheme(-1); | |
| 2391 static const BASIC = const _AuthenticationScheme(0); | |
| 2392 static const DIGEST = const _AuthenticationScheme(1); | |
| 2393 | |
| 2394 const _AuthenticationScheme(this._scheme); | |
| 2395 | |
| 2396 factory _AuthenticationScheme.fromString(String scheme) { | |
| 2397 if (scheme.toLowerCase() == "basic") return BASIC; | |
| 2398 if (scheme.toLowerCase() == "digest") return DIGEST; | |
| 2399 return UNKNOWN; | |
| 2400 } | |
| 2401 | |
| 2402 String toString() { | |
| 2403 if (this == BASIC) return "Basic"; | |
| 2404 if (this == DIGEST) return "Digest"; | |
| 2405 return "Unknown"; | |
| 2406 } | |
| 2407 | |
| 2408 final int _scheme; | |
| 2409 } | |
| 2410 | |
| 2411 | |
| 2412 class _Credentials { | |
| 2413 _Credentials(this.uri, this.realm, this.credentials); | |
| 2414 | |
| 2415 _AuthenticationScheme get scheme => credentials.scheme; | |
| 2416 | |
| 2417 bool applies(Uri uri, _AuthenticationScheme scheme) { | |
| 2418 if (scheme != null && credentials.scheme != scheme) return false; | |
| 2419 if (uri.domain != this.uri.domain) return false; | |
| 2420 int thisPort = | |
| 2421 this.uri.port == 0 ? HttpClient.DEFAULT_HTTP_PORT : this.uri.port; | |
| 2422 int otherPort = uri.port == 0 ? HttpClient.DEFAULT_HTTP_PORT : uri.port; | |
| 2423 if (otherPort != thisPort) return false; | |
| 2424 return uri.path.startsWith(this.uri.path); | |
| 2425 } | |
| 2426 | |
| 2427 | |
| 2428 void authorize(HttpClientRequest request) { | |
| 2429 credentials.authorize(this, request); | |
| 2430 } | |
| 2431 | |
| 2432 Uri uri; | |
| 2433 String realm; | |
| 2434 _HttpClientCredentials credentials; | |
| 2435 | |
| 2436 // Digest specific fields. | |
| 2437 String nonce; | |
| 2438 String algorithm; | |
| 2439 String qop; | |
| 2440 } | |
| 2441 | |
| 2442 | |
| 2443 class _HttpClientCredentials implements HttpClientCredentials { | |
| 2444 abstract _AuthenticationScheme get scheme; | |
| 2445 abstract void authorize(HttpClientRequest request); | |
| 2446 } | |
| 2447 | |
| 2448 | |
| 2449 class _HttpClientBasicCredentials implements HttpClientBasicCredentials { | |
| 2450 _HttpClientBasicCredentials(this.username, | |
| 2451 this.password); | |
| 2452 | |
| 2453 _AuthenticationScheme get scheme => _AuthenticationScheme.BASIC; | |
| 2454 | |
| 2455 void authorize(_Credentials _, HttpClientRequest request) { | |
| 2456 // There is no mentioning of username/password encoding in RFC | |
| 2457 // 2617. However there is an open draft for adding an additional | |
| 2458 // accept-charset parameter to the WWW-Authenticate and | |
| 2459 // Proxy-Authenticate headers, see | |
| 2460 // http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For | |
| 2461 // now always use UTF-8 encoding. | |
| 2462 _UTF8Encoder encoder = new _UTF8Encoder(); | |
| 2463 String auth = | |
| 2464 CryptoUtils.bytesToBase64(encoder.encodeString( | |
| 2465 "$username:$password")); | |
| 2466 request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth"); | |
| 2467 } | |
| 2468 | |
| 2469 String username; | |
| 2470 String password; | |
| 2471 } | |
| 2472 | |
| 2473 | |
| 2474 class _HttpClientDigestCredentials implements HttpClientDigestCredentials { | |
| 2475 _HttpClientDigestCredentials(this.username, | |
| 2476 this.password); | |
| 2477 | |
| 2478 _AuthenticationScheme get scheme => _AuthenticationScheme.DIGEST; | |
| 2479 | |
| 2480 void authorize(_Credentials credentials, HttpClientRequest request) { | |
| 2481 // TODO(sgjesse): Implement!!! | |
| 2482 } | |
| 2483 | |
| 2484 String username; | |
| 2485 String password; | |
| 2486 } | |
| 2487 | |
| 2488 | |
| 2489 | |
| 2293 class _RedirectInfo implements RedirectInfo { | 2490 class _RedirectInfo implements RedirectInfo { |
| 2294 const _RedirectInfo(int this.statusCode, | 2491 const _RedirectInfo(int this.statusCode, |
| 2295 String this.method, | 2492 String this.method, |
| 2296 Uri this.location); | 2493 Uri this.location); |
| 2297 final int statusCode; | 2494 final int statusCode; |
| 2298 final String method; | 2495 final String method; |
| 2299 final Uri location; | 2496 final Uri location; |
| 2300 } | 2497 } |
| OLD | NEW |