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

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 from ajohnsen@ 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 1338 matching lines...) Expand 10 before | Expand all | Expand 10 after
1773 _reasonPhrase = reasonPhrase; 1779 _reasonPhrase = reasonPhrase;
1774 } 1780 }
1775 1781
1776 void _onHeaderReceived(String name, String value) { 1782 void _onHeaderReceived(String name, String value) {
1777 _headers.add(name, value); 1783 _headers.add(name, value);
1778 if (name == "content-length") { 1784 if (name == "content-length") {
1779 _contentLength = parseInt(value); 1785 _contentLength = parseInt(value);
1780 } 1786 }
1781 } 1787 }
1782 1788
1789 void _handleUnauthorized() {
1790
1791 void retryRequest(_Credentials cr) {
1792 if (cr != null) {
1793 if (cr.scheme == _AuthenticationScheme.DIGEST) {
1794 cr.nonce = header.parameters["nonce"];
1795 cr.algorithm = header.parameters["algorithm"];
1796 cr.qop = header.parameters["qop"];
1797 }
1798 // Drain body and retry.
1799 // TODO(sjgesse): Support digest.
1800 if (cr.scheme == _AuthenticationScheme.BASIC) {
1801 inputStream.onData = inputStream.read;
1802 inputStream.onClosed = _connection.retry;
1803 return;
1804 }
1805 }
1806
1807 // Fall through to here to perform normal response handling if
1808 // there is no sensible authorization handling.
1809 if (_connection._onResponse != null) {
1810 _connection._onResponse(this);
1811 }
1812 }
1813
1814 // Only try to authenticate if there is a challenge in the response.
1815 List<String> challenge = _headers[HttpHeaders.WWW_AUTHENTICATE];
1816 if (challenge != null && challenge.length == 1) {
1817 _HeaderValue header =
1818 new _HeaderValue.fromString(challenge[0], parameterSeparator: ",");
1819 _AuthenticationScheme scheme =
1820 new _AuthenticationScheme.fromString(header.value);
1821 String realm = header.parameters["realm"];
1822
1823 // See if any credentials are available.
1824 _Credentials cr =
1825 _connection._client._findCredentials(
1826 _connection._request._uri, scheme);
1827
1828 // Ask for more credentials if none found or the one found has
1829 // already been used. If it has already been used it must now be
1830 // invalid and is removed.
1831 if (cr == null || cr.used) {
1832 if (cr != null) {
1833 _connection._client._removeCredentials(cr);
1834 }
1835 cr = null;
1836 if (_connection._client._authenticate != null) {
1837 Future authComplete =
1838 _connection._client._authenticate(
1839 _connection._request._uri, scheme.toString(), realm);
1840 authComplete.then((credsAvailable) {
1841 if (credsAvailable) {
1842 cr = _connection._client._findCredentials(
1843 _connection._request._uri, scheme);
1844 retryRequest(cr);
1845 } else {
1846 if (_connection._onResponse != null) {
1847 _connection._onResponse(this);
1848 }
1849 }
1850 });
1851 return;
1852 }
1853 } else {
1854 // If credentials found prepare for retrying the request.
1855 retryRequest(cr);
1856 return;
1857 }
1858 }
1859
1860 // Fall through to here to perform normal response handling if
1861 // there is no sensible authorization handling.
1862 if (_connection._onResponse != null) {
1863 _connection._onResponse(this);
1864 }
1865 }
1866
1783 void _onHeadersComplete() { 1867 void _onHeadersComplete() {
1784 _headers._mutable = false; 1868 _headers._mutable = false;
1785 _buffer = new _BufferList(); 1869 _buffer = new _BufferList();
1786 if (isRedirect && _connection.followRedirects) { 1870 if (isRedirect && _connection.followRedirects) {
1787 if (_connection._redirects == null || 1871 if (_connection._redirects == null ||
1788 _connection._redirects.length < _connection.maxRedirects) { 1872 _connection._redirects.length < _connection.maxRedirects) {
1789 // Check the location header. 1873 // Check the location header.
1790 List<String> location = headers[HttpHeaders.LOCATION]; 1874 List<String> location = headers[HttpHeaders.LOCATION];
1791 if (location == null || location.length > 1) { 1875 if (location == null || location.length > 1) {
1792 throw new RedirectException("Invalid redirect", 1876 throw new RedirectException("Invalid redirect",
1793 _connection._redirects); 1877 _connection._redirects);
1794 } 1878 }
1795 // Check for redirect loop 1879 // Check for redirect loop
1796 if (_connection._redirects != null) { 1880 if (_connection._redirects != null) {
1797 Uri redirectUrl = new Uri.fromString(location[0]); 1881 Uri redirectUrl = new Uri.fromString(location[0]);
1798 for (int i = 0; i < _connection._redirects.length; i++) { 1882 for (int i = 0; i < _connection._redirects.length; i++) {
1799 if (_connection._redirects[i].location.toString() == 1883 if (_connection._redirects[i].location.toString() ==
1800 redirectUrl.toString()) { 1884 redirectUrl.toString()) {
1801 throw new RedirectLoopException(_connection._redirects); 1885 throw new RedirectLoopException(_connection._redirects);
1802 } 1886 }
1803 } 1887 }
1804 } 1888 }
1805 // Drain body and redirect. 1889 // Drain body and redirect.
1806 inputStream.onData = inputStream.read; 1890 inputStream.onData = inputStream.read;
1807 inputStream.onClosed = _connection.redirect; 1891 inputStream.onClosed = _connection.redirect;
1808 } else { 1892 } else {
1809 throw new RedirectLimitExceededException(_connection._redirects); 1893 throw new RedirectLimitExceededException(_connection._redirects);
1810 } 1894 }
1895 } else if (statusCode == HttpStatus.UNAUTHORIZED) {
1896 _handleUnauthorized();
1811 } else if (_connection._onResponse != null) { 1897 } else if (_connection._onResponse != null) {
1812 _connection._onResponse(this); 1898 _connection._onResponse(this);
1813 } 1899 }
1814 } 1900 }
1815 1901
1816 void _onDataReceived(List<int> data) { 1902 void _onDataReceived(List<int> data) {
1817 _buffer.add(data); 1903 _buffer.add(data);
1818 if (_inputStream != null) _inputStream._dataReceived(); 1904 if (_inputStream != null) _inputStream._dataReceived();
1819 } 1905 }
1820 1906
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
1955 } 2041 }
1956 2042
1957 void set onResponse(void handler(HttpClientResponse response)) { 2043 void set onResponse(void handler(HttpClientResponse response)) {
1958 _onResponse = handler; 2044 _onResponse = handler;
1959 } 2045 }
1960 2046
1961 void set onError(void callback(e)) { 2047 void set onError(void callback(e)) {
1962 _onErrorCallback = callback; 2048 _onErrorCallback = callback;
1963 } 2049 }
1964 2050
2051 void retry() {
2052 if (_socketConn != null) {
2053 throw new HttpException("Cannot retry with body data pending");
2054 }
2055 // Retry the URL using the same connection instance.
2056 _client._openUrl(_method, _request._uri, this);
2057 }
2058
1965 void redirect([String method, Uri url]) { 2059 void redirect([String method, Uri url]) {
1966 if (_socketConn != null) { 2060 if (_socketConn != null) {
1967 throw new HttpException("Cannot redirect with body data pending"); 2061 throw new HttpException("Cannot redirect with body data pending");
1968 } 2062 }
1969 if (method == null) method = _method; 2063 if (method == null) method = _method;
1970 if (url == null) { 2064 if (url == null) {
1971 url = new Uri.fromString(_response.headers.value(HttpHeaders.LOCATION)); 2065 url = new Uri.fromString(_response.headers.value(HttpHeaders.LOCATION));
1972 } 2066 }
1973 if (_redirects == null) { 2067 if (_redirects == null) {
1974 _redirects = new List<_RedirectInfo>(); 2068 _redirects = new List<_RedirectInfo>();
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
2079 final String host; 2173 final String host;
2080 final int port; 2174 final int port;
2081 final bool isDirect; 2175 final bool isDirect;
2082 } 2176 }
2083 2177
2084 class _HttpClient implements HttpClient { 2178 class _HttpClient implements HttpClient {
2085 static const int DEFAULT_EVICTION_TIMEOUT = 60000; 2179 static const int DEFAULT_EVICTION_TIMEOUT = 60000;
2086 2180
2087 _HttpClient() : _openSockets = new Map(), 2181 _HttpClient() : _openSockets = new Map(),
2088 _activeSockets = new Set(), 2182 _activeSockets = new Set(),
2183 credentials = new List<_Credentials>(),
2089 _shutdown = false; 2184 _shutdown = false;
2090 2185
2091 HttpClientConnection open( 2186 HttpClientConnection open(
2092 String method, String host, int port, String path) { 2187 String method, String host, int port, String path) {
2093 // TODO(sgjesse): The path set here can contain both query and 2188 // TODO(sgjesse): The path set here can contain both query and
2094 // fragment. They should be cracked and set correctly. 2189 // fragment. They should be cracked and set correctly.
2095 return _open(method, new Uri.fromComponents( 2190 return _open(method, new Uri.fromComponents(
2096 scheme: "http", domain: host, port: port, path: path)); 2191 scheme: "http", domain: host, port: port, path: path));
2097 } 2192 }
2098 2193
(...skipping 10 matching lines...) Expand all
2109 HttpClientConnection openUrl(String method, Uri url) { 2204 HttpClientConnection openUrl(String method, Uri url) {
2110 return _openUrl(method, url); 2205 return _openUrl(method, url);
2111 } 2206 }
2112 2207
2113 HttpClientConnection _openUrl(String method, 2208 HttpClientConnection _openUrl(String method,
2114 Uri url, 2209 Uri url,
2115 [_HttpClientConnection connection]) { 2210 [_HttpClientConnection connection]) {
2116 if (url.scheme != "http") { 2211 if (url.scheme != "http") {
2117 throw new HttpException("Unsupported URL scheme ${url.scheme}"); 2212 throw new HttpException("Unsupported URL scheme ${url.scheme}");
2118 } 2213 }
2119 if (url.userInfo != "") {
2120 throw new HttpException("Unsupported user info ${url.userInfo}");
2121 }
2122 return _open(method, url, connection); 2214 return _open(method, url, connection);
2123 } 2215 }
2124 2216
2125 HttpClientConnection get(String host, int port, String path) { 2217 HttpClientConnection get(String host, int port, String path) {
2126 return open("GET", host, port, path); 2218 return open("GET", host, port, path);
2127 } 2219 }
2128 2220
2129 HttpClientConnection getUrl(Uri url) => _openUrl("GET", url); 2221 HttpClientConnection getUrl(Uri url) => _openUrl("GET", url);
2130 2222
2131 HttpClientConnection post(String host, int port, String path) { 2223 HttpClientConnection post(String host, int port, String path) {
2132 return open("POST", host, port, path); 2224 return open("POST", host, port, path);
2133 } 2225 }
2134 2226
2135 HttpClientConnection postUrl(Uri url) => _openUrl("POST", url); 2227 HttpClientConnection postUrl(Uri url) => _openUrl("POST", url);
2136 2228
2229 set authenticate(bool f(Uri url, String scheme, String realm)) {
2230 _authenticate = f;
2231 }
2232
2233 void addCredentials(
2234 Uri url, String realm, HttpClientCredentials cr) {
2235 credentials.add(new _Credentials(url, realm, cr));
2236 }
2237
2137 set findProxy(String f(Uri uri)) => _findProxy = f; 2238 set findProxy(String f(Uri uri)) => _findProxy = f;
2138 2239
2139 void shutdown() { 2240 void shutdown() {
2140 _openSockets.forEach((String key, Queue<_SocketConnection> connections) { 2241 _openSockets.forEach((String key, Queue<_SocketConnection> connections) {
2141 while (!connections.isEmpty) { 2242 while (!connections.isEmpty) {
2142 _SocketConnection socketConn = connections.removeFirst(); 2243 _SocketConnection socketConn = connections.removeFirst();
2143 socketConn._socket.close(); 2244 socketConn._socket.close();
2144 } 2245 }
2145 }); 2246 });
2146 _activeSockets.forEach((_SocketConnection socketConn) { 2247 _activeSockets.forEach((_SocketConnection socketConn) {
(...skipping 23 matching lines...) Expand all
2170 int proxyIndex) { 2271 int proxyIndex) {
2171 2272
2172 void _connectionOpened(_SocketConnection socketConn, 2273 void _connectionOpened(_SocketConnection socketConn,
2173 _HttpClientConnection connection, 2274 _HttpClientConnection connection,
2174 bool usingProxy) { 2275 bool usingProxy) {
2175 connection._usingProxy = usingProxy; 2276 connection._usingProxy = usingProxy;
2176 connection._connectionEstablished(socketConn); 2277 connection._connectionEstablished(socketConn);
2177 HttpClientRequest request = connection.open(method, url); 2278 HttpClientRequest request = connection.open(method, url);
2178 request.headers.host = host; 2279 request.headers.host = host;
2179 request.headers.port = port; 2280 request.headers.port = port;
2281 if (url.userInfo != null && !url.userInfo.isEmpty) {
2282 // If the URL contains user information use that for basic
2283 // authorization
2284 _UTF8Encoder encoder = new _UTF8Encoder();
2285 String auth =
2286 CryptoUtils.bytesToBase64(encoder.encodeString(url.userInfo));
2287 request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth");
2288 } else {
2289 // Look for credentials.
2290 _Credentials cr = _findCredentials(url);
2291 if (cr != null) {
2292 cr.authorize(request);
2293 }
2294 }
2180 if (connection._onRequest != null) { 2295 if (connection._onRequest != null) {
2181 connection._onRequest(request); 2296 connection._onRequest(request);
2182 } else { 2297 } else {
2183 request.outputStream.close(); 2298 request.outputStream.close();
2184 } 2299 }
2185 } 2300 }
2186 2301
2187 assert(proxyIndex < proxyConfiguration.proxies.length); 2302 assert(proxyIndex < proxyConfiguration.proxies.length);
2188 2303
2189 // Determine the actual host to connect to. 2304 // Determine the actual host to connect to.
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
2313 if (_openSockets.isEmpty) _cancelEvictionTimer(); 2428 if (_openSockets.isEmpty) _cancelEvictionTimer();
2314 } 2429 }
2315 _evictionTimer = new Timer.repeating(10000, _handleEviction); 2430 _evictionTimer = new Timer.repeating(10000, _handleEviction);
2316 } 2431 }
2317 2432
2318 // Return connection. 2433 // Return connection.
2319 _activeSockets.remove(socketConn); 2434 _activeSockets.remove(socketConn);
2320 sockets.addFirst(socketConn); 2435 sockets.addFirst(socketConn);
2321 } 2436 }
2322 2437
2438 _Credentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) {
2439 // Look for credentials.
2440 _Credentials cr =
2441 credentials.reduce(null, (_Credentials prev, _Credentials value) {
2442 if (value.applies(url, scheme)) {
2443 if (prev == null) return value;
2444 return value.uri.path.length > prev.uri.path.length ? value : prev;
2445 } else {
2446 return prev;
2447 }
2448 });
2449 return cr;
2450 }
2451
2452 void _removeCredentials(_Credentials cr) {
2453 int index = credentials.indexOf(cr);
2454 if (index != -1) {
2455 credentials.removeAt(index);
2456 }
2457 }
2458
2323 Function _onOpen; 2459 Function _onOpen;
2324 Map<String, Queue<_SocketConnection>> _openSockets; 2460 Map<String, Queue<_SocketConnection>> _openSockets;
2325 Set<_SocketConnection> _activeSockets; 2461 Set<_SocketConnection> _activeSockets;
2462 List<_Credentials> credentials;
2326 Timer _evictionTimer; 2463 Timer _evictionTimer;
2327 Function _findProxy; 2464 Function _findProxy;
2465 Function _authenticate;
2328 bool _shutdown; // Has this HTTP client been shutdown? 2466 bool _shutdown; // Has this HTTP client been shutdown?
2329 } 2467 }
2330 2468
2331 2469
2332 class _HttpConnectionInfo implements HttpConnectionInfo { 2470 class _HttpConnectionInfo implements HttpConnectionInfo {
2333 String remoteHost; 2471 String remoteHost;
2334 int remotePort; 2472 int remotePort;
2335 int localPort; 2473 int localPort;
2336 } 2474 }
2337 2475
2338 2476
2339 class _DetachedSocket implements DetachedSocket { 2477 class _DetachedSocket implements DetachedSocket {
2340 _DetachedSocket(this._socket, this._unparsedData); 2478 _DetachedSocket(this._socket, this._unparsedData);
2341 Socket get socket => _socket; 2479 Socket get socket => _socket;
2342 List<int> get unparsedData => _unparsedData; 2480 List<int> get unparsedData => _unparsedData;
2343 Socket _socket; 2481 Socket _socket;
2344 List<int> _unparsedData; 2482 List<int> _unparsedData;
2345 } 2483 }
2346 2484
2347 2485
2486 class _AuthenticationScheme {
2487 static const UNKNOWN = const _AuthenticationScheme(-1);
2488 static const BASIC = const _AuthenticationScheme(0);
2489 static const DIGEST = const _AuthenticationScheme(1);
2490
2491 const _AuthenticationScheme(this._scheme);
2492
2493 factory _AuthenticationScheme.fromString(String scheme) {
2494 if (scheme.toLowerCase() == "basic") return BASIC;
2495 if (scheme.toLowerCase() == "digest") return DIGEST;
2496 return UNKNOWN;
2497 }
2498
2499 String toString() {
2500 if (this == BASIC) return "Basic";
2501 if (this == DIGEST) return "Digest";
2502 return "Unknown";
2503 }
2504
2505 final int _scheme;
2506 }
2507
2508
2509 class _Credentials {
2510 _Credentials(this.uri, this.realm, this.credentials);
2511
2512 _AuthenticationScheme get scheme => credentials.scheme;
2513
2514 bool applies(Uri uri, _AuthenticationScheme scheme) {
2515 if (scheme != null && credentials.scheme != scheme) return false;
2516 if (uri.domain != this.uri.domain) return false;
2517 int thisPort =
2518 this.uri.port == 0 ? HttpClient.DEFAULT_HTTP_PORT : this.uri.port;
2519 int otherPort = uri.port == 0 ? HttpClient.DEFAULT_HTTP_PORT : uri.port;
2520 if (otherPort != thisPort) return false;
2521 return uri.path.startsWith(this.uri.path);
2522 }
2523
2524 void authorize(HttpClientRequest request) {
2525 credentials.authorize(this, request);
2526 used = true;
2527 }
2528
2529 bool used = false;
2530 Uri uri;
2531 String realm;
2532 HttpClientCredentials credentials;
2533
2534 // Digest specific fields.
2535 String nonce;
2536 String algorithm;
2537 String qop;
2538 }
2539
2540
2541 class _HttpClientCredentials implements HttpClientCredentials {
2542 abstract _AuthenticationScheme get scheme;
2543 abstract void authorize(HttpClientRequest request);
2544 }
2545
2546
2547 class _HttpClientBasicCredentials implements HttpClientBasicCredentials {
2548 _HttpClientBasicCredentials(this.username,
2549 this.password);
2550
2551 _AuthenticationScheme get scheme => _AuthenticationScheme.BASIC;
2552
2553 void authorize(_Credentials _, HttpClientRequest request) {
2554 // There is no mentioning of username/password encoding in RFC
2555 // 2617. However there is an open draft for adding an additional
2556 // accept-charset parameter to the WWW-Authenticate and
2557 // Proxy-Authenticate headers, see
2558 // http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For
2559 // now always use UTF-8 encoding.
2560 _UTF8Encoder encoder = new _UTF8Encoder();
2561 String auth =
2562 CryptoUtils.bytesToBase64(encoder.encodeString(
2563 "$username:$password"));
2564 request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth");
2565 }
2566
2567 String username;
2568 String password;
2569 }
2570
2571
2572 class _HttpClientDigestCredentials implements HttpClientDigestCredentials {
2573 _HttpClientDigestCredentials(this.username,
2574 this.password);
2575
2576 _AuthenticationScheme get scheme => _AuthenticationScheme.DIGEST;
2577
2578 void authorize(_Credentials credentials, HttpClientRequest request) {
2579 // TODO(sgjesse): Implement!!!
2580 throw new UnsupportedOperationException();
2581 }
2582
2583 String username;
2584 String password;
2585 }
2586
2587
2588
2348 class _RedirectInfo implements RedirectInfo { 2589 class _RedirectInfo implements RedirectInfo {
2349 const _RedirectInfo(int this.statusCode, 2590 const _RedirectInfo(int this.statusCode,
2350 String this.method, 2591 String this.method,
2351 Uri this.location); 2592 Uri this.location);
2352 final int statusCode; 2593 final int statusCode;
2353 final String method; 2594 final String method;
2354 final Uri location; 2595 final Uri location;
2355 } 2596 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698