Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Side by Side Diff: runtime/bin/http_impl.dart

Issue 11118021: Add support for authorization of HTTP client requests (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addressed more comments + made the authenticate callback async Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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() || s[index] != expected) {
358 if (s[index] != expected) { 360 throw new HttpException("Failed to parse header value");
359 throw new HttpException("Failed to parse header value [$s]");
360 } 361 }
361 index++; 362 index++;
362 } 363 }
363 364
365 void maybeExpect(String expected) {
366 if (s[index] == expected) index++;
367 }
368
364 void parseParameters() { 369 void parseParameters() {
365 _parameters = new Map<String, String>(); 370 _parameters = new Map<String, String>();
366 371
367 String parseParameterName() { 372 String parseParameterName() {
368 int start = index; 373 int start = index;
369 while (!done()) { 374 while (!done()) {
370 if (s[index] == " " || s[index] == "\t" || s[index] == "=") break; 375 if (s[index] == " " || s[index] == "\t" || s[index] == "=") break;
371 index++; 376 index++;
372 } 377 }
373 return s.substring(start, index).toLowerCase(); 378 return s.substring(start, index).toLowerCase();
374 } 379 }
375 380
376 String parseParameterValue() { 381 String parseParameterValue() {
377 if (s[index] == "\"") { 382 if (s[index] == "\"") {
378 // Parse quoted value. 383 // Parse quoted value.
379 StringBuffer sb = new StringBuffer(); 384 StringBuffer sb = new StringBuffer();
380 index++; 385 index++;
381 while (!done()) { 386 while (!done()) {
382 if (s[index] == "\\") { 387 if (s[index] == "\\") {
383 if (index + 1 == s.length) { 388 if (index + 1 == s.length) {
384 throw new HttpException("Failed to parse header value [$s]"); 389 throw new HttpException("Failed to parse header value");
385 } 390 }
386 index++; 391 index++;
387 } else if (s[index] == "\"") { 392 } else if (s[index] == "\"") {
388 index++; 393 index++;
389 break; 394 break;
390 } 395 }
391 sb.add(s[index]); 396 sb.add(s[index]);
392 index++; 397 index++;
393 } 398 }
394 return sb.toString(); 399 return sb.toString();
395 } else { 400 } else {
396 // Parse non-quoted value. 401 // Parse non-quoted value.
397 return parseValue(); 402 return parseValue();
398 } 403 }
399 } 404 }
400 405
401 while (!done()) { 406 while (!done()) {
402 skipWS(); 407 skipWS();
403 if (done()) return; 408 if (done()) return;
404 String name = parseParameterName(); 409 String name = parseParameterName();
405 skipWS(); 410 skipWS();
406 expect("="); 411 expect("=");
407 skipWS(); 412 skipWS();
408 String value = parseParameterValue(); 413 String value = parseParameterValue();
409 _parameters[name] = value; 414 _parameters[name] = value;
410 skipWS(); 415 skipWS();
411 if (done()) return; 416 if (done()) return;
412 expect(";"); 417 expect(parameterSeparator);
413 } 418 }
414 } 419 }
415 420
416 skipWS(); 421 skipWS();
417 value = parseValue(); 422 value = parseValue();
418 skipWS(); 423 skipWS();
419 if (done()) return; 424 if (done()) return;
420 expect(";"); 425 maybeExpect(parameterSeparator);
421 parseParameters(); 426 parseParameters();
422 } 427 }
423 428
424 String value; 429 String value;
430 String parameterSeparator;
425 Map<String, String> _parameters; 431 Map<String, String> _parameters;
426 } 432 }
427 433
428 434
429 class _ContentType extends _HeaderValue implements ContentType { 435 class _ContentType extends _HeaderValue implements ContentType {
430 _ContentType(String primaryType, String subType) 436 _ContentType(String primaryType, String subType)
431 : _primaryType = primaryType, _subType = subType, super(""); 437 : _primaryType = primaryType, _subType = subType, super("");
432 438
433 _ContentType.fromString(String value) : super.fromString(value); 439 _ContentType.fromString(String value) : super.fromString(value);
434 440
(...skipping 1283 matching lines...) Expand 10 before | Expand all | Expand 10 after
1718 _reasonPhrase = reasonPhrase; 1724 _reasonPhrase = reasonPhrase;
1719 } 1725 }
1720 1726
1721 void _onHeaderReceived(String name, String value) { 1727 void _onHeaderReceived(String name, String value) {
1722 _headers.add(name, value); 1728 _headers.add(name, value);
1723 if (name == "content-length") { 1729 if (name == "content-length") {
1724 _contentLength = parseInt(value); 1730 _contentLength = parseInt(value);
1725 } 1731 }
1726 } 1732 }
1727 1733
1734 void _handleUnauthorized() {
1735
1736 void retryRequest(_Credentials cr) {
1737 if (cr != null) {
1738 if (cr.scheme == _AuthenticationScheme.DIGEST) {
1739 cr.nonce = header.parameters["nonce"];
1740 cr.algorithm = header.parameters["algorithm"];
1741 cr.qop = header.parameters["qop"];
1742 }
1743 // Drain body and retry.
1744 // TODO(sjgesse): Support digest.
1745 if (cr.scheme == _AuthenticationScheme.BASIC) {
1746 inputStream.onData = inputStream.read;
1747 inputStream.onClosed = _connection.retry;
1748 return;
1749 }
1750 }
1751
1752 // Fall through to here to perform normal response handling if
1753 // there is no sensible authorization handling.
1754 if (_connection._onResponse != null) {
1755 _connection._onResponse(this);
1756 }
1757 }
1758
1759 // Only try to authenticate if there is a challenge in the response.
1760 List<String> challenge = _headers[HttpHeaders.WWW_AUTHENTICATE];
1761 if (challenge != null && challenge.length == 1) {
1762 HeaderValue header =
1763 new HeaderValue.fromString(challenge[0], parameterSeparator: ",");
1764 _AuthenticationScheme scheme =
1765 new _AuthenticationScheme.fromString(header.value);
1766 String realm = header.parameters["realm"];
1767
1768 // See if any credentials are available.
1769 _Credentials cr =
1770 _connection._client._findCredentials(
1771 _connection._request._uri, scheme);
1772
1773 // Ask for more credentials if none found or the one found has
1774 // already been used. If it has already been used it must now be
1775 // invalid and is removed.
1776 if (cr == null || cr.used) {
1777 if (cr != null) {
1778 _connection._client._removeCredentials(cr);
1779 }
1780 cr = null;
1781 if (_connection._client._authenticate != null) {
1782 Future authComplete =
1783 _connection._client._authenticate(
1784 _connection._request._uri, scheme.toString(), realm);
1785 authComplete.then((credsAvailable) {
1786 if (credsAvailable) {
1787 cr = _connection._client._findCredentials(
1788 _connection._request._uri, scheme);
1789 retryRequest(cr);
1790 } else {
1791 if (_connection._onResponse != null) {
1792 _connection._onResponse(this);
1793 }
1794 }
1795 });
1796 return;
1797 }
1798 } else {
1799 // If credentials found prepare for retrying the request.
1800 retryRequest(cr);
1801 return;
1802 }
1803 }
1804
1805 // Fall through to here to perform normal response handling if
1806 // there is no sensible authorization handling.
1807 if (_connection._onResponse != null) {
1808 _connection._onResponse(this);
1809 }
1810 }
1811
1728 void _onHeadersComplete() { 1812 void _onHeadersComplete() {
1729 _headers._mutable = false; 1813 _headers._mutable = false;
1730 _buffer = new _BufferList(); 1814 _buffer = new _BufferList();
1731 if (isRedirect && _connection.followRedirects) { 1815 if (isRedirect && _connection.followRedirects) {
1732 if (_connection._redirects == null || 1816 if (_connection._redirects == null ||
1733 _connection._redirects.length < _connection.maxRedirects) { 1817 _connection._redirects.length < _connection.maxRedirects) {
1734 // Check the location header. 1818 // Check the location header.
1735 List<String> location = headers[HttpHeaders.LOCATION]; 1819 List<String> location = headers[HttpHeaders.LOCATION];
1736 if (location == null || location.length > 1) { 1820 if (location == null || location.length > 1) {
1737 throw new RedirectException("Invalid redirect", 1821 throw new RedirectException("Invalid redirect",
1738 _connection._redirects); 1822 _connection._redirects);
1739 } 1823 }
1740 // Check for redirect loop 1824 // Check for redirect loop
1741 if (_connection._redirects != null) { 1825 if (_connection._redirects != null) {
1742 Uri redirectUrl = new Uri.fromString(location[0]); 1826 Uri redirectUrl = new Uri.fromString(location[0]);
1743 for (int i = 0; i < _connection._redirects.length; i++) { 1827 for (int i = 0; i < _connection._redirects.length; i++) {
1744 if (_connection._redirects[i].location.toString() == 1828 if (_connection._redirects[i].location.toString() ==
1745 redirectUrl.toString()) { 1829 redirectUrl.toString()) {
1746 throw new RedirectLoopException(_connection._redirects); 1830 throw new RedirectLoopException(_connection._redirects);
1747 } 1831 }
1748 } 1832 }
1749 } 1833 }
1750 // Drain body and redirect. 1834 // Drain body and redirect.
1751 inputStream.onData = inputStream.read; 1835 inputStream.onData = inputStream.read;
1752 inputStream.onClosed = _connection.redirect; 1836 inputStream.onClosed = _connection.redirect;
1753 } else { 1837 } else {
1754 throw new RedirectLimitExceededException(_connection._redirects); 1838 throw new RedirectLimitExceededException(_connection._redirects);
1755 } 1839 }
1840 } else if (statusCode == HttpStatus.UNAUTHORIZED) {
1841 _handleUnauthorized();
1756 } else if (_connection._onResponse != null) { 1842 } else if (_connection._onResponse != null) {
1757 _connection._onResponse(this); 1843 _connection._onResponse(this);
1758 } 1844 }
1759 } 1845 }
1760 1846
1761 void _onDataReceived(List<int> data) { 1847 void _onDataReceived(List<int> data) {
1762 _buffer.add(data); 1848 _buffer.add(data);
1763 if (_inputStream != null) _inputStream._dataReceived(); 1849 if (_inputStream != null) _inputStream._dataReceived();
1764 } 1850 }
1765 1851
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
1900 } 1986 }
1901 1987
1902 void set onResponse(void handler(HttpClientResponse response)) { 1988 void set onResponse(void handler(HttpClientResponse response)) {
1903 _onResponse = handler; 1989 _onResponse = handler;
1904 } 1990 }
1905 1991
1906 void set onError(void callback(e)) { 1992 void set onError(void callback(e)) {
1907 _onErrorCallback = callback; 1993 _onErrorCallback = callback;
1908 } 1994 }
1909 1995
1996 void retry() {
1997 if (_socketConn != null) {
1998 throw new HttpException("Cannot retry with body data pending");
1999 }
2000 // Retry the URL using the same connection instance.
2001 _client._openUrl(_method, _request._uri, this);
2002 }
2003
1910 void redirect([String method, Uri url]) { 2004 void redirect([String method, Uri url]) {
1911 if (_socketConn != null) { 2005 if (_socketConn != null) {
1912 throw new HttpException("Cannot redirect with body data pending"); 2006 throw new HttpException("Cannot redirect with body data pending");
1913 } 2007 }
1914 if (method == null) method = _method; 2008 if (method == null) method = _method;
1915 if (url == null) { 2009 if (url == null) {
1916 url = new Uri.fromString(_response.headers.value(HttpHeaders.LOCATION)); 2010 url = new Uri.fromString(_response.headers.value(HttpHeaders.LOCATION));
1917 } 2011 }
1918 if (_redirects == null) { 2012 if (_redirects == null) {
1919 _redirects = new List<_RedirectInfo>(); 2013 _redirects = new List<_RedirectInfo>();
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
2024 final String host; 2118 final String host;
2025 final int port; 2119 final int port;
2026 final bool isDirect; 2120 final bool isDirect;
2027 } 2121 }
2028 2122
2029 class _HttpClient implements HttpClient { 2123 class _HttpClient implements HttpClient {
2030 static const int DEFAULT_EVICTION_TIMEOUT = 60000; 2124 static const int DEFAULT_EVICTION_TIMEOUT = 60000;
2031 2125
2032 _HttpClient() : _openSockets = new Map(), 2126 _HttpClient() : _openSockets = new Map(),
2033 _activeSockets = new Set(), 2127 _activeSockets = new Set(),
2128 credentials = new List<_Credentials>(),
2034 _shutdown = false; 2129 _shutdown = false;
2035 2130
2036 HttpClientConnection open( 2131 HttpClientConnection open(
2037 String method, String host, int port, String path) { 2132 String method, String host, int port, String path) {
2038 // TODO(sgjesse): The path set here can contain both query and 2133 // TODO(sgjesse): The path set here can contain both query and
2039 // fragment. They should be cracked and set correctly. 2134 // fragment. They should be cracked and set correctly.
2040 return _open(method, new Uri.fromComponents( 2135 return _open(method, new Uri.fromComponents(
2041 scheme: "http", domain: host, port: port, path: path)); 2136 scheme: "http", domain: host, port: port, path: path));
2042 } 2137 }
2043 2138
(...skipping 10 matching lines...) Expand all
2054 HttpClientConnection openUrl(String method, Uri url) { 2149 HttpClientConnection openUrl(String method, Uri url) {
2055 return _openUrl(method, url); 2150 return _openUrl(method, url);
2056 } 2151 }
2057 2152
2058 HttpClientConnection _openUrl(String method, 2153 HttpClientConnection _openUrl(String method,
2059 Uri url, 2154 Uri url,
2060 [_HttpClientConnection connection]) { 2155 [_HttpClientConnection connection]) {
2061 if (url.scheme != "http") { 2156 if (url.scheme != "http") {
2062 throw new HttpException("Unsupported URL scheme ${url.scheme}"); 2157 throw new HttpException("Unsupported URL scheme ${url.scheme}");
2063 } 2158 }
2064 if (url.userInfo != "") {
2065 throw new HttpException("Unsupported user info ${url.userInfo}");
2066 }
2067 return _open(method, url, connection); 2159 return _open(method, url, connection);
2068 } 2160 }
2069 2161
2070 HttpClientConnection get(String host, int port, String path) { 2162 HttpClientConnection get(String host, int port, String path) {
2071 return open("GET", host, port, path); 2163 return open("GET", host, port, path);
2072 } 2164 }
2073 2165
2074 HttpClientConnection getUrl(Uri url) => _openUrl("GET", url); 2166 HttpClientConnection getUrl(Uri url) => _openUrl("GET", url);
2075 2167
2076 HttpClientConnection post(String host, int port, String path) { 2168 HttpClientConnection post(String host, int port, String path) {
2077 return open("POST", host, port, path); 2169 return open("POST", host, port, path);
2078 } 2170 }
2079 2171
2080 HttpClientConnection postUrl(Uri url) => _openUrl("POST", url); 2172 HttpClientConnection postUrl(Uri url) => _openUrl("POST", url);
2081 2173
2174 set authenticate(bool f(Uri url, String scheme, String realm)) {
2175 _authenticate = f;
2176 }
2177
2178 void addCredentials(
2179 Uri url, String realm, HttpClientCredentials cr) {
2180 credentials.add(new _Credentials(url, realm, cr));
2181 }
2182
2082 set findProxy(String f(Uri uri)) => _findProxy = f; 2183 set findProxy(String f(Uri uri)) => _findProxy = f;
2083 2184
2084 void shutdown() { 2185 void shutdown() {
2085 _openSockets.forEach((String key, Queue<_SocketConnection> connections) { 2186 _openSockets.forEach((String key, Queue<_SocketConnection> connections) {
2086 while (!connections.isEmpty()) { 2187 while (!connections.isEmpty()) {
2087 _SocketConnection socketConn = connections.removeFirst(); 2188 _SocketConnection socketConn = connections.removeFirst();
2088 socketConn._socket.close(); 2189 socketConn._socket.close();
2089 } 2190 }
2090 }); 2191 });
2091 _activeSockets.forEach((_SocketConnection socketConn) { 2192 _activeSockets.forEach((_SocketConnection socketConn) {
(...skipping 23 matching lines...) Expand all
2115 int proxyIndex) { 2216 int proxyIndex) {
2116 2217
2117 void _connectionOpened(_SocketConnection socketConn, 2218 void _connectionOpened(_SocketConnection socketConn,
2118 _HttpClientConnection connection, 2219 _HttpClientConnection connection,
2119 bool usingProxy) { 2220 bool usingProxy) {
2120 connection._usingProxy = usingProxy; 2221 connection._usingProxy = usingProxy;
2121 connection._connectionEstablished(socketConn); 2222 connection._connectionEstablished(socketConn);
2122 HttpClientRequest request = connection.open(method, url); 2223 HttpClientRequest request = connection.open(method, url);
2123 request.headers.host = host; 2224 request.headers.host = host;
2124 request.headers.port = port; 2225 request.headers.port = port;
2226 if (url.userInfo != null && !url.userInfo.isEmpty()) {
2227 // If the URL contains user information use that for basic
2228 // authorization
2229 _UTF8Encoder encoder = new _UTF8Encoder();
2230 String auth =
2231 CryptoUtils.bytesToBase64(encoder.encodeString(url.userInfo));
2232 request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth");
2233 } else {
2234 // Look for credentials.
2235 _Credentials cr = _findCredentials(url);
2236 if (cr != null) {
2237 cr.authorize(request);
2238 }
2239 }
2125 if (connection._onRequest != null) { 2240 if (connection._onRequest != null) {
2126 connection._onRequest(request); 2241 connection._onRequest(request);
2127 } else { 2242 } else {
2128 request.outputStream.close(); 2243 request.outputStream.close();
2129 } 2244 }
2130 } 2245 }
2131 2246
2132 assert(proxyIndex < proxyConfiguration.proxies.length); 2247 assert(proxyIndex < proxyConfiguration.proxies.length);
2133 2248
2134 // Determine the actual host to connect to. 2249 // Determine the actual host to connect to.
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
2258 if (_openSockets.isEmpty()) _cancelEvictionTimer(); 2373 if (_openSockets.isEmpty()) _cancelEvictionTimer();
2259 } 2374 }
2260 _evictionTimer = new Timer.repeating(10000, _handleEviction); 2375 _evictionTimer = new Timer.repeating(10000, _handleEviction);
2261 } 2376 }
2262 2377
2263 // Return connection. 2378 // Return connection.
2264 _activeSockets.remove(socketConn); 2379 _activeSockets.remove(socketConn);
2265 sockets.addFirst(socketConn); 2380 sockets.addFirst(socketConn);
2266 } 2381 }
2267 2382
2383 _Credentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) {
2384 // Look for credentials.
2385 _Credentials cr =
2386 credentials.reduce(null, (_Credentials prev, _Credentials value) {
2387 if (value.applies(url, scheme)) {
2388 if (prev == null) return value;
2389 return value.uri.path.length > prev.uri.path.length ? value : prev;
2390 } else {
2391 return prev;
2392 }
2393 });
2394 return cr;
2395 }
2396
2397 void _removeCredentials(_Credentials cr) {
2398 int index = credentials.indexOf(cr);
2399 if (index != -1) {
2400 credentials.removeAt(index);
2401 }
2402 }
2403
2268 Function _onOpen; 2404 Function _onOpen;
2269 Map<String, Queue<_SocketConnection>> _openSockets; 2405 Map<String, Queue<_SocketConnection>> _openSockets;
2270 Set<_SocketConnection> _activeSockets; 2406 Set<_SocketConnection> _activeSockets;
2407 List<_Credentials> credentials;
2271 Timer _evictionTimer; 2408 Timer _evictionTimer;
2272 Function _findProxy; 2409 Function _findProxy;
2410 Function _authenticate;
2273 bool _shutdown; // Has this HTTP client been shutdown? 2411 bool _shutdown; // Has this HTTP client been shutdown?
2274 } 2412 }
2275 2413
2276 2414
2277 class _HttpConnectionInfo implements HttpConnectionInfo { 2415 class _HttpConnectionInfo implements HttpConnectionInfo {
2278 String remoteHost; 2416 String remoteHost;
2279 int remotePort; 2417 int remotePort;
2280 int localPort; 2418 int localPort;
2281 } 2419 }
2282 2420
2283 2421
2284 class _DetachedSocket implements DetachedSocket { 2422 class _DetachedSocket implements DetachedSocket {
2285 _DetachedSocket(this._socket, this._unparsedData); 2423 _DetachedSocket(this._socket, this._unparsedData);
2286 Socket get socket => _socket; 2424 Socket get socket => _socket;
2287 List<int> get unparsedData => _unparsedData; 2425 List<int> get unparsedData => _unparsedData;
2288 Socket _socket; 2426 Socket _socket;
2289 List<int> _unparsedData; 2427 List<int> _unparsedData;
2290 } 2428 }
2291 2429
2292 2430
2431 class _AuthenticationScheme {
2432 static const UNKNOWN = const _AuthenticationScheme(-1);
2433 static const BASIC = const _AuthenticationScheme(0);
2434 static const DIGEST = const _AuthenticationScheme(1);
2435
2436 const _AuthenticationScheme(this._scheme);
2437
2438 factory _AuthenticationScheme.fromString(String scheme) {
2439 if (scheme.toLowerCase() == "basic") return BASIC;
2440 if (scheme.toLowerCase() == "digest") return DIGEST;
2441 return UNKNOWN;
2442 }
2443
2444 String toString() {
2445 if (this == BASIC) return "Basic";
2446 if (this == DIGEST) return "Digest";
2447 return "Unknown";
2448 }
2449
2450 final int _scheme;
2451 }
2452
2453
2454 class _Credentials {
2455 _Credentials(this.uri, this.realm, this.credentials);
2456
2457 _AuthenticationScheme get scheme => credentials.scheme;
2458
2459 bool applies(Uri uri, _AuthenticationScheme scheme) {
2460 if (scheme != null && credentials.scheme != scheme) return false;
2461 if (uri.domain != this.uri.domain) return false;
2462 int thisPort =
2463 this.uri.port == 0 ? HttpClient.DEFAULT_HTTP_PORT : this.uri.port;
2464 int otherPort = uri.port == 0 ? HttpClient.DEFAULT_HTTP_PORT : uri.port;
2465 if (otherPort != thisPort) return false;
2466 return uri.path.startsWith(this.uri.path);
2467 }
2468
2469 void authorize(HttpClientRequest request) {
2470 credentials.authorize(this, request);
2471 used = true;
2472 }
2473
2474 bool used = false;
2475 Uri uri;
2476 String realm;
2477 HttpClientCredentials credentials;
2478
2479 // Digest specific fields.
2480 String nonce;
2481 String algorithm;
2482 String qop;
2483 }
2484
2485
2486 class _HttpClientCredentials implements HttpClientCredentials {
2487 abstract _AuthenticationScheme get scheme;
2488 abstract void authorize(HttpClientRequest request);
2489 }
2490
2491
2492 class _HttpClientBasicCredentials implements HttpClientBasicCredentials {
2493 _HttpClientBasicCredentials(this.username,
2494 this.password);
2495
2496 _AuthenticationScheme get scheme => _AuthenticationScheme.BASIC;
2497
2498 void authorize(_Credentials _, HttpClientRequest request) {
2499 // There is no mentioning of username/password encoding in RFC
2500 // 2617. However there is an open draft for adding an additional
2501 // accept-charset parameter to the WWW-Authenticate and
2502 // Proxy-Authenticate headers, see
2503 // http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For
2504 // now always use UTF-8 encoding.
2505 _UTF8Encoder encoder = new _UTF8Encoder();
2506 String auth =
2507 CryptoUtils.bytesToBase64(encoder.encodeString(
2508 "$username:$password"));
2509 request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth");
2510 }
2511
2512 String username;
2513 String password;
2514 }
2515
2516
2517 class _HttpClientDigestCredentials implements HttpClientDigestCredentials {
2518 _HttpClientDigestCredentials(this.username,
2519 this.password);
2520
2521 _AuthenticationScheme get scheme => _AuthenticationScheme.DIGEST;
2522
2523 void authorize(_Credentials credentials, HttpClientRequest request) {
2524 // TODO(sgjesse): Implement!!!
2525 throw new UnsupportedOperationException();
2526 }
2527
2528 String username;
2529 String password;
2530 }
2531
2532
2533
2293 class _RedirectInfo implements RedirectInfo { 2534 class _RedirectInfo implements RedirectInfo {
2294 const _RedirectInfo(int this.statusCode, 2535 const _RedirectInfo(int this.statusCode,
2295 String this.method, 2536 String this.method,
2296 Uri this.location); 2537 Uri this.location);
2297 final int statusCode; 2538 final int statusCode;
2298 final String method; 2539 final String method;
2299 final Uri location; 2540 final Uri location;
2300 } 2541 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698