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

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 review comments 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
« no previous file with comments | « runtime/bin/http.dart ('k') | tests/standalone/io/http_auth_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // Only try to authenticate if there is a challenge in the response.
1736 List<String> challenge = _headers[HttpHeaders.WWW_AUTHENTICATE];
1737 if (challenge != null && challenge.length == 1) {
1738 HeaderValue header =
1739 new HeaderValue.fromString(challenge[0], parameterSeparator: ",");
1740 _AuthenticationScheme scheme =
1741 new _AuthenticationScheme.fromString(header.value);
1742 String realm = header.parameters["realm"];
1743
1744 // See if any credentials are available.
1745 _Credentials cr =
1746 _connection._client._findCredentials(
1747 _connection._request._uri, scheme);
1748
1749 // Ask for more credentials if none found or the one found has
1750 // already been used. If is has already been used it must now be
Mads Ager (google) 2012/10/26 11:07:02 is -> it
Søren Gjesse 2012/10/26 12:59:02 Done.
1751 // invalid and is removed.
1752 if (cr == null || cr.used) {
1753 if (cr != null) {
1754 _connection._client._removeCredentials(cr);
1755 }
1756 cr = null;
1757 if (_connection._client._authenticate != null &&
1758 _connection._client._authenticate(
1759 _connection._request._uri, scheme.toString(), realm)) {
1760 cr = _connection._client._findCredentials(_connection._request._uri,
1761 scheme);
1762 }
1763 }
1764
1765 // If credentials found prepare for retrying the request.
1766 if (cr != null) {
1767 if (cr.scheme == _AuthenticationScheme.DIGEST) {
1768 cr.nonce = header.parameters["nonce"];
1769 cr.algorithm = header.parameters["algorithm"];
1770 cr.qop = header.parameters["qop"];
1771 }
1772 // Drain body and retry.
1773 // TODO(sgesse): Support digest.
Mads Ager (google) 2012/10/26 11:07:02 Should we throw an Unsupported exception for now o
Søren Gjesse 2012/10/26 12:59:02 As it is it will just fall through and pass the st
1774 if (cr.scheme == _AuthenticationScheme.BASIC) {
1775 inputStream.onData = inputStream.read;
1776 inputStream.onClosed = _connection.retry;
1777 return;
1778 }
1779 }
1780 }
1781
1782 // Fall through to here to perform normal response handling if
1783 // there is no sensible authorization handling.
1784 if (_connection._onResponse != null) {
1785 _connection._onResponse(this);
1786 }
1787 }
1788
1728 void _onHeadersComplete() { 1789 void _onHeadersComplete() {
1729 _headers._mutable = false; 1790 _headers._mutable = false;
1730 _buffer = new _BufferList(); 1791 _buffer = new _BufferList();
1731 if (isRedirect && _connection.followRedirects) { 1792 if (isRedirect && _connection.followRedirects) {
1732 if (_connection._redirects == null || 1793 if (_connection._redirects == null ||
1733 _connection._redirects.length < _connection.maxRedirects) { 1794 _connection._redirects.length < _connection.maxRedirects) {
1734 // Check the location header. 1795 // Check the location header.
1735 List<String> location = headers[HttpHeaders.LOCATION]; 1796 List<String> location = headers[HttpHeaders.LOCATION];
1736 if (location == null || location.length > 1) { 1797 if (location == null || location.length > 1) {
1737 throw new RedirectException("Invalid redirect", 1798 throw new RedirectException("Invalid redirect",
1738 _connection._redirects); 1799 _connection._redirects);
1739 } 1800 }
1740 // Check for redirect loop 1801 // Check for redirect loop
1741 if (_connection._redirects != null) { 1802 if (_connection._redirects != null) {
1742 Uri redirectUrl = new Uri.fromString(location[0]); 1803 Uri redirectUrl = new Uri.fromString(location[0]);
1743 for (int i = 0; i < _connection._redirects.length; i++) { 1804 for (int i = 0; i < _connection._redirects.length; i++) {
1744 if (_connection._redirects[i].location.toString() == 1805 if (_connection._redirects[i].location.toString() ==
1745 redirectUrl.toString()) { 1806 redirectUrl.toString()) {
1746 throw new RedirectLoopException(_connection._redirects); 1807 throw new RedirectLoopException(_connection._redirects);
1747 } 1808 }
1748 } 1809 }
1749 } 1810 }
1750 // Drain body and redirect. 1811 // Drain body and redirect.
1751 inputStream.onData = inputStream.read; 1812 inputStream.onData = inputStream.read;
1752 inputStream.onClosed = _connection.redirect; 1813 inputStream.onClosed = _connection.redirect;
1753 } else { 1814 } else {
1754 throw new RedirectLimitExceededException(_connection._redirects); 1815 throw new RedirectLimitExceededException(_connection._redirects);
1755 } 1816 }
1817 } else if (statusCode == HttpStatus.UNAUTHORIZED) {
1818 _handleUnauthorized();
1756 } else if (_connection._onResponse != null) { 1819 } else if (_connection._onResponse != null) {
1757 _connection._onResponse(this); 1820 _connection._onResponse(this);
1758 } 1821 }
1759 } 1822 }
1760 1823
1761 void _onDataReceived(List<int> data) { 1824 void _onDataReceived(List<int> data) {
1762 _buffer.add(data); 1825 _buffer.add(data);
1763 if (_inputStream != null) _inputStream._dataReceived(); 1826 if (_inputStream != null) _inputStream._dataReceived();
1764 } 1827 }
1765 1828
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
1900 } 1963 }
1901 1964
1902 void set onResponse(void handler(HttpClientResponse response)) { 1965 void set onResponse(void handler(HttpClientResponse response)) {
1903 _onResponse = handler; 1966 _onResponse = handler;
1904 } 1967 }
1905 1968
1906 void set onError(void callback(e)) { 1969 void set onError(void callback(e)) {
1907 _onErrorCallback = callback; 1970 _onErrorCallback = callback;
1908 } 1971 }
1909 1972
1973 void retry() {
1974 if (_socketConn != null) {
1975 throw new HttpException("Cannot retry with body data pending");
1976 }
1977 // Retry the URL using the same connection instance.
1978 _client._openUrl(_method, _request._uri, this);
1979 }
1980
1910 void redirect([String method, Uri url]) { 1981 void redirect([String method, Uri url]) {
1911 if (_socketConn != null) { 1982 if (_socketConn != null) {
1912 throw new HttpException("Cannot redirect with body data pending"); 1983 throw new HttpException("Cannot redirect with body data pending");
1913 } 1984 }
1914 if (method == null) method = _method; 1985 if (method == null) method = _method;
1915 if (url == null) { 1986 if (url == null) {
1916 url = new Uri.fromString(_response.headers.value(HttpHeaders.LOCATION)); 1987 url = new Uri.fromString(_response.headers.value(HttpHeaders.LOCATION));
1917 } 1988 }
1918 if (_redirects == null) { 1989 if (_redirects == null) {
1919 _redirects = new List<_RedirectInfo>(); 1990 _redirects = new List<_RedirectInfo>();
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
2024 final String host; 2095 final String host;
2025 final int port; 2096 final int port;
2026 final bool isDirect; 2097 final bool isDirect;
2027 } 2098 }
2028 2099
2029 class _HttpClient implements HttpClient { 2100 class _HttpClient implements HttpClient {
2030 static const int DEFAULT_EVICTION_TIMEOUT = 60000; 2101 static const int DEFAULT_EVICTION_TIMEOUT = 60000;
2031 2102
2032 _HttpClient() : _openSockets = new Map(), 2103 _HttpClient() : _openSockets = new Map(),
2033 _activeSockets = new Set(), 2104 _activeSockets = new Set(),
2105 credentials = new List<_Credentials>(),
2034 _shutdown = false; 2106 _shutdown = false;
2035 2107
2036 HttpClientConnection open( 2108 HttpClientConnection open(
2037 String method, String host, int port, String path) { 2109 String method, String host, int port, String path) {
2038 // TODO(sgjesse): The path set here can contain both query and 2110 // TODO(sgjesse): The path set here can contain both query and
2039 // fragment. They should be cracked and set correctly. 2111 // fragment. They should be cracked and set correctly.
2040 return _open(method, new Uri.fromComponents( 2112 return _open(method, new Uri.fromComponents(
2041 scheme: "http", domain: host, port: port, path: path)); 2113 scheme: "http", domain: host, port: port, path: path));
2042 } 2114 }
2043 2115
(...skipping 10 matching lines...) Expand all
2054 HttpClientConnection openUrl(String method, Uri url) { 2126 HttpClientConnection openUrl(String method, Uri url) {
2055 return _openUrl(method, url); 2127 return _openUrl(method, url);
2056 } 2128 }
2057 2129
2058 HttpClientConnection _openUrl(String method, 2130 HttpClientConnection _openUrl(String method,
2059 Uri url, 2131 Uri url,
2060 [_HttpClientConnection connection]) { 2132 [_HttpClientConnection connection]) {
2061 if (url.scheme != "http") { 2133 if (url.scheme != "http") {
2062 throw new HttpException("Unsupported URL scheme ${url.scheme}"); 2134 throw new HttpException("Unsupported URL scheme ${url.scheme}");
2063 } 2135 }
2064 if (url.userInfo != "") {
2065 throw new HttpException("Unsupported user info ${url.userInfo}");
2066 }
2067 return _open(method, url, connection); 2136 return _open(method, url, connection);
2068 } 2137 }
2069 2138
2070 HttpClientConnection get(String host, int port, String path) { 2139 HttpClientConnection get(String host, int port, String path) {
2071 return open("GET", host, port, path); 2140 return open("GET", host, port, path);
2072 } 2141 }
2073 2142
2074 HttpClientConnection getUrl(Uri url) => _openUrl("GET", url); 2143 HttpClientConnection getUrl(Uri url) => _openUrl("GET", url);
2075 2144
2076 HttpClientConnection post(String host, int port, String path) { 2145 HttpClientConnection post(String host, int port, String path) {
2077 return open("POST", host, port, path); 2146 return open("POST", host, port, path);
2078 } 2147 }
2079 2148
2080 HttpClientConnection postUrl(Uri url) => _openUrl("POST", url); 2149 HttpClientConnection postUrl(Uri url) => _openUrl("POST", url);
2081 2150
2151 set authenticate(bool f(Uri url, String scheme, String realm)) {
2152 _authenticate = f;
2153 }
2154
2155 void addCredentials(
2156 Uri url, String realm, HttpClientCredentials cr) {
2157 credentials.add(new _Credentials(url, realm, cr));
2158 }
2159
2082 set findProxy(String f(Uri uri)) => _findProxy = f; 2160 set findProxy(String f(Uri uri)) => _findProxy = f;
2083 2161
2084 void shutdown() { 2162 void shutdown() {
2085 _openSockets.forEach((String key, Queue<_SocketConnection> connections) { 2163 _openSockets.forEach((String key, Queue<_SocketConnection> connections) {
2086 while (!connections.isEmpty()) { 2164 while (!connections.isEmpty()) {
2087 _SocketConnection socketConn = connections.removeFirst(); 2165 _SocketConnection socketConn = connections.removeFirst();
2088 socketConn._socket.close(); 2166 socketConn._socket.close();
2089 } 2167 }
2090 }); 2168 });
2091 _activeSockets.forEach((_SocketConnection socketConn) { 2169 _activeSockets.forEach((_SocketConnection socketConn) {
(...skipping 23 matching lines...) Expand all
2115 int proxyIndex) { 2193 int proxyIndex) {
2116 2194
2117 void _connectionOpened(_SocketConnection socketConn, 2195 void _connectionOpened(_SocketConnection socketConn,
2118 _HttpClientConnection connection, 2196 _HttpClientConnection connection,
2119 bool usingProxy) { 2197 bool usingProxy) {
2120 connection._usingProxy = usingProxy; 2198 connection._usingProxy = usingProxy;
2121 connection._connectionEstablished(socketConn); 2199 connection._connectionEstablished(socketConn);
2122 HttpClientRequest request = connection.open(method, url); 2200 HttpClientRequest request = connection.open(method, url);
2123 request.headers.host = host; 2201 request.headers.host = host;
2124 request.headers.port = port; 2202 request.headers.port = port;
2203 if (url.userInfo != null && !url.userInfo.isEmpty()) {
2204 // If the URL contains user information use that for basic
2205 // authorization
2206 _UTF8Encoder encoder = new _UTF8Encoder();
2207 String auth =
2208 CryptoUtils.bytesToBase64(encoder.encodeString(url.userInfo));
2209 request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth");
2210 } else {
2211 // Look for credentials.
2212 _Credentials cr = _findCredentials(url);
2213 if (cr != null) {
2214 cr.authorize(request);
2215 }
2216 }
2125 if (connection._onRequest != null) { 2217 if (connection._onRequest != null) {
2126 connection._onRequest(request); 2218 connection._onRequest(request);
2127 } else { 2219 } else {
2128 request.outputStream.close(); 2220 request.outputStream.close();
2129 } 2221 }
2130 } 2222 }
2131 2223
2132 assert(proxyIndex < proxyConfiguration.proxies.length); 2224 assert(proxyIndex < proxyConfiguration.proxies.length);
2133 2225
2134 // Determine the actual host to connect to. 2226 // Determine the actual host to connect to.
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
2258 if (_openSockets.isEmpty()) _cancelEvictionTimer(); 2350 if (_openSockets.isEmpty()) _cancelEvictionTimer();
2259 } 2351 }
2260 _evictionTimer = new Timer.repeating(10000, _handleEviction); 2352 _evictionTimer = new Timer.repeating(10000, _handleEviction);
2261 } 2353 }
2262 2354
2263 // Return connection. 2355 // Return connection.
2264 _activeSockets.remove(socketConn); 2356 _activeSockets.remove(socketConn);
2265 sockets.addFirst(socketConn); 2357 sockets.addFirst(socketConn);
2266 } 2358 }
2267 2359
2360 _Credentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) {
2361 // Look for credentials.
2362 _Credentials cr =
2363 credentials.reduce(null, (_Credentials prev, _Credentials value) {
2364 if (value.applies(url, scheme)) {
2365 if (prev == null) return value;
2366 return value.uri.path.length > prev.uri.path.length ? value : prev;
2367 } else {
2368 return prev;
2369 }
2370 });
2371 return cr;
2372 }
2373
2374 void _removeCredentials(_Credentials cr) {
2375 int index = credentials.indexOf(cr);
2376 if (index != -1) {
2377 credentials.removeAt(index);
2378 }
2379 }
2380
2268 Function _onOpen; 2381 Function _onOpen;
2269 Map<String, Queue<_SocketConnection>> _openSockets; 2382 Map<String, Queue<_SocketConnection>> _openSockets;
2270 Set<_SocketConnection> _activeSockets; 2383 Set<_SocketConnection> _activeSockets;
2384 List<_Credentials> credentials;
2271 Timer _evictionTimer; 2385 Timer _evictionTimer;
2272 Function _findProxy; 2386 Function _findProxy;
2387 Function _authenticate;
2273 bool _shutdown; // Has this HTTP client been shutdown? 2388 bool _shutdown; // Has this HTTP client been shutdown?
2274 } 2389 }
2275 2390
2276 2391
2277 class _HttpConnectionInfo implements HttpConnectionInfo { 2392 class _HttpConnectionInfo implements HttpConnectionInfo {
2278 String remoteHost; 2393 String remoteHost;
2279 int remotePort; 2394 int remotePort;
2280 int localPort; 2395 int localPort;
2281 } 2396 }
2282 2397
2283 2398
2284 class _DetachedSocket implements DetachedSocket { 2399 class _DetachedSocket implements DetachedSocket {
2285 _DetachedSocket(this._socket, this._unparsedData); 2400 _DetachedSocket(this._socket, this._unparsedData);
2286 Socket get socket => _socket; 2401 Socket get socket => _socket;
2287 List<int> get unparsedData => _unparsedData; 2402 List<int> get unparsedData => _unparsedData;
2288 Socket _socket; 2403 Socket _socket;
2289 List<int> _unparsedData; 2404 List<int> _unparsedData;
2290 } 2405 }
2291 2406
2292 2407
2408 class _AuthenticationScheme {
2409 static const UNKNOWN = const _AuthenticationScheme(-1);
2410 static const BASIC = const _AuthenticationScheme(0);
2411 static const DIGEST = const _AuthenticationScheme(1);
2412
2413 const _AuthenticationScheme(this._scheme);
2414
2415 factory _AuthenticationScheme.fromString(String scheme) {
2416 if (scheme.toLowerCase() == "basic") return BASIC;
2417 if (scheme.toLowerCase() == "digest") return DIGEST;
2418 return UNKNOWN;
2419 }
2420
2421 String toString() {
2422 if (this == BASIC) return "Basic";
2423 if (this == DIGEST) return "Digest";
2424 return "Unknown";
2425 }
2426
2427 final int _scheme;
2428 }
2429
2430
2431 class _Credentials {
2432 _Credentials(this.uri, this.realm, this.credentials);
2433
2434 _AuthenticationScheme get scheme => credentials.scheme;
2435
2436 bool applies(Uri uri, _AuthenticationScheme scheme) {
2437 if (scheme != null && credentials.scheme != scheme) return false;
2438 if (uri.domain != this.uri.domain) return false;
2439 int thisPort =
2440 this.uri.port == 0 ? HttpClient.DEFAULT_HTTP_PORT : this.uri.port;
2441 int otherPort = uri.port == 0 ? HttpClient.DEFAULT_HTTP_PORT : uri.port;
2442 if (otherPort != thisPort) return false;
2443 return uri.path.startsWith(this.uri.path);
2444 }
2445
2446 void authorize(HttpClientRequest request) {
2447 credentials.authorize(this, request);
2448 used = true;
2449 }
2450
2451 bool used = false;
2452 Uri uri;
2453 String realm;
2454 HttpClientCredentials credentials;
2455
2456 // Digest specific fields.
2457 String nonce;
2458 String algorithm;
2459 String qop;
2460 }
2461
2462
2463 class _HttpClientCredentials implements HttpClientCredentials {
2464 abstract _AuthenticationScheme get scheme;
2465 abstract void authorize(HttpClientRequest request);
2466 }
2467
2468
2469 class _HttpClientBasicCredentials implements HttpClientBasicCredentials {
2470 _HttpClientBasicCredentials(this.username,
2471 this.password);
2472
2473 _AuthenticationScheme get scheme => _AuthenticationScheme.BASIC;
2474
2475 void authorize(_Credentials _, HttpClientRequest request) {
2476 // There is no mentioning of username/password encoding in RFC
2477 // 2617. However there is an open draft for adding an additional
2478 // accept-charset parameter to the WWW-Authenticate and
2479 // Proxy-Authenticate headers, see
2480 // http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For
2481 // now always use UTF-8 encoding.
2482 _UTF8Encoder encoder = new _UTF8Encoder();
2483 String auth =
2484 CryptoUtils.bytesToBase64(encoder.encodeString(
2485 "$username:$password"));
2486 request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth");
2487 }
2488
2489 String username;
2490 String password;
2491 }
2492
2493
2494 class _HttpClientDigestCredentials implements HttpClientDigestCredentials {
2495 _HttpClientDigestCredentials(this.username,
2496 this.password);
2497
2498 _AuthenticationScheme get scheme => _AuthenticationScheme.DIGEST;
2499
2500 void authorize(_Credentials credentials, HttpClientRequest request) {
2501 // TODO(sgjesse): Implement!!!
Mads Ager (google) 2012/10/26 11:07:02 Throw unsupported exception?
Søren Gjesse 2012/10/26 12:59:02 Done.
2502 }
2503
2504 String username;
2505 String password;
2506 }
2507
2508
2509
2293 class _RedirectInfo implements RedirectInfo { 2510 class _RedirectInfo implements RedirectInfo {
2294 const _RedirectInfo(int this.statusCode, 2511 const _RedirectInfo(int this.statusCode,
2295 String this.method, 2512 String this.method,
2296 Uri this.location); 2513 Uri this.location);
2297 final int statusCode; 2514 final int statusCode;
2298 final String method; 2515 final String method;
2299 final Uri location; 2516 final Uri location;
2300 } 2517 }
OLDNEW
« no previous file with comments | « runtime/bin/http.dart ('k') | tests/standalone/io/http_auth_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698