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

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: Created 8 years, 2 months 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()) 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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698