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

Side by Side Diff: sdk/lib/io/http_impl.dart

Issue 13915007: Add support for proxies requiing authentication (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 8 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) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 part of dart.io; 5 part of dart.io;
6 6
7 class _HttpIncoming extends Stream<List<int>> { 7 class _HttpIncoming extends Stream<List<int>> {
8 final int _transferLength; 8 final int _transferLength;
9 final Completer _dataCompleter = new Completer(); 9 final Completer _dataCompleter = new Completer();
10 Stream<List<int>> _stream; 10 Stream<List<int>> _stream;
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 unsubscribeOnError: unsubscribeOnError); 244 unsubscribeOnError: unsubscribeOnError);
245 } 245 }
246 246
247 Future<Socket> detachSocket() { 247 Future<Socket> detachSocket() {
248 _httpClient._connectionClosed(_httpRequest._httpClientConnection); 248 _httpClient._connectionClosed(_httpRequest._httpClientConnection);
249 return _httpRequest._httpClientConnection.detachSocket(); 249 return _httpRequest._httpClientConnection.detachSocket();
250 } 250 }
251 251
252 HttpConnectionInfo get connectionInfo => _httpRequest.connectionInfo; 252 HttpConnectionInfo get connectionInfo => _httpRequest.connectionInfo;
253 253
254 bool get _shouldAuthenticateProxy {
255 // Only try to authenticate if there is a challenge in the response.
256 List<String> challenge = headers[HttpHeaders.PROXY_AUTHENTICATE];
Anders Johnsen 2013/04/15 07:07:19 Use headers.value? It should do the length == 1 ch
Søren Gjesse 2013/04/15 07:42:00 Value throws, and I don't want that here.
257 return statusCode == HttpStatus.PROXY_AUTHENTICATION_REQUIRED &&
258 challenge != null && challenge.length == 1;
259 }
260
254 bool get _shouldAuthenticate { 261 bool get _shouldAuthenticate {
255 // Only try to authenticate if there is a challenge in the response. 262 // Only try to authenticate if there is a challenge in the response.
256 List<String> challenge = headers[HttpHeaders.WWW_AUTHENTICATE]; 263 List<String> challenge = headers[HttpHeaders.WWW_AUTHENTICATE];
257 return statusCode == HttpStatus.UNAUTHORIZED && 264 return statusCode == HttpStatus.UNAUTHORIZED &&
258 challenge != null && challenge.length == 1; 265 challenge != null && challenge.length == 1;
259 } 266 }
260 267
261 Future<HttpClientResponse> _authenticate() { 268 Future<HttpClientResponse> _authenticate() {
262 Future<HttpClientResponse> retryWithCredentials(_Credentials cr) { 269 Future<HttpClientResponse> retryWithCredentials(_Credentials cr) {
263 if (cr != null) { 270 if (cr != null) {
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 return authComplete.then((credsAvailable) { 315 return authComplete.then((credsAvailable) {
309 if (credsAvailable) { 316 if (credsAvailable) {
310 cr = _httpClient._findCredentials(_httpRequest.uri, scheme); 317 cr = _httpClient._findCredentials(_httpRequest.uri, scheme);
311 return retryWithCredentials(cr); 318 return retryWithCredentials(cr);
312 } else { 319 } else {
313 // No credentials available, complete with original response. 320 // No credentials available, complete with original response.
314 return this; 321 return this;
315 } 322 }
316 }); 323 });
317 } 324 }
325
318 // No credentials were found and the callback was not set. 326 // No credentials were found and the callback was not set.
319 return new Future.immediate(this); 327 return new Future.immediate(this);
320 } 328 }
329
330 Future<HttpClientResponse> _authenticateProxy() {
331 Future<HttpClientResponse> retryWithProxyCredentials(_ProxyCredentials cr) {
332 _httpRequest.headers._mutable = true;
Anders Johnsen 2013/04/15 07:07:19 Are you sure about this? Don't you want to modify
Søren Gjesse 2013/04/15 07:42:00 Not needed - removed.
333 cr.authorize(_httpRequest);
Anders Johnsen 2013/04/15 07:07:19 This should be done automatically in _HttpClientRe
Søren Gjesse 2013/04/15 07:42:00 Good point - removed.
334 return fold(null, (x, y) {}).then((_) {
335 return _httpClient._openUrlFromRequest(_httpRequest.method,
336 _httpRequest.uri,
337 _httpRequest)
338 .then((request) => request.close());
339 });
340 }
341
342 List<String> challenge = headers[HttpHeaders.PROXY_AUTHENTICATE];
343 assert(challenge != null || challenge.length == 1);
344 _HeaderValue header =
345 new _HeaderValue.fromString(challenge[0], parameterSeparator: ",");
346 _AuthenticationScheme scheme =
347 new _AuthenticationScheme.fromString(header.value);
348 String realm = header.parameters["realm"];
349
350 // See if any credentials are available.
351 var proxy = _httpRequest._proxy;
352
353 var cr = _httpClient._findProxyCredentials(proxy);
354 if (cr != null) {
355 return retryWithProxyCredentials(cr);
356 }
357
358 // Ask for more credentials if none found.
359 if (_httpClient._authenticateProxy != null) {
360 Future authComplete = _httpClient._authenticateProxy(proxy.host,
361 proxy.port,
362 "basic",
363 realm);
364 return authComplete.then((credsAvailable) {
365 if (credsAvailable) {
366 var cr = _httpClient._findProxyCredentials(proxy);
367 return retryWithProxyCredentials(cr);
368 } else {
369 // No credentials available, complete with original response.
370 return this;
371 }
372 });
373 }
374
375 // No credentials were found and the callback was not set.
376 return new Future.immediate(this);
377 }
321 } 378 }
322 379
323 380
324 abstract class _HttpOutboundMessage<T> implements IOSink { 381 abstract class _HttpOutboundMessage<T> implements IOSink {
325 // Used to mark when the body should be written. This is used for HEAD 382 // Used to mark when the body should be written. This is used for HEAD
326 // requests and in error handling. 383 // requests and in error handling.
327 bool _ignoreBody = false; 384 bool _ignoreBody = false;
328 bool _headersWritten = false; 385 bool _headersWritten = false;
329 386
330 IOSink _ioSink; 387 IOSink _ioSink;
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after
698 final Uri uri; 755 final Uri uri;
699 final List<Cookie> cookies = new List<Cookie>(); 756 final List<Cookie> cookies = new List<Cookie>();
700 757
701 // The HttpClient this request belongs to. 758 // The HttpClient this request belongs to.
702 final _HttpClient _httpClient; 759 final _HttpClient _httpClient;
703 final _HttpClientConnection _httpClientConnection; 760 final _HttpClientConnection _httpClientConnection;
704 761
705 final Completer<HttpClientResponse> _responseCompleter 762 final Completer<HttpClientResponse> _responseCompleter
706 = new Completer<HttpClientResponse>(); 763 = new Completer<HttpClientResponse>();
707 764
708 final bool _usingProxy; 765 final _Proxy _proxy;
709 766
710 Future<HttpClientResponse> _response; 767 Future<HttpClientResponse> _response;
711 768
712 // TODO(ajohnsen): Get default value from client? 769 // TODO(ajohnsen): Get default value from client?
713 bool _followRedirects = true; 770 bool _followRedirects = true;
714 771
715 int _maxRedirects = 5; 772 int _maxRedirects = 5;
716 773
717 List<RedirectInfo> _responseRedirects = []; 774 List<RedirectInfo> _responseRedirects = [];
718 775
719 _HttpClientRequest(_HttpOutgoing outgoing, 776 _HttpClientRequest(_HttpOutgoing outgoing,
720 Uri this.uri, 777 Uri this.uri,
721 String this.method, 778 String this.method,
722 bool this._usingProxy, 779 _Proxy this._proxy,
723 _HttpClient this._httpClient, 780 _HttpClient this._httpClient,
724 _HttpClientConnection this._httpClientConnection) 781 _HttpClientConnection this._httpClientConnection)
725 : super("1.1", outgoing) { 782 : super("1.1", outgoing) {
726 // GET and HEAD have 'content-length: 0' by default. 783 // GET and HEAD have 'content-length: 0' by default.
727 if (method == "GET" || method == "HEAD") { 784 if (method == "GET" || method == "HEAD") {
728 contentLength = 0; 785 contentLength = 0;
729 } 786 }
730 } 787 }
731 788
732 Future<HttpClientResponse> get done { 789 Future<HttpClientResponse> get done {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
770 if (response.redirects.length < maxRedirects) { 827 if (response.redirects.length < maxRedirects) {
771 // Redirect and drain response. 828 // Redirect and drain response.
772 future = response.fold(null, (x, y) {}) 829 future = response.fold(null, (x, y) {})
773 .then((_) => response.redirect()); 830 .then((_) => response.redirect());
774 } else { 831 } else {
775 // End with exception, too many redirects. 832 // End with exception, too many redirects.
776 future = response.fold(null, (x, y) {}) 833 future = response.fold(null, (x, y) {})
777 .then((_) => new Future.immediateError( 834 .then((_) => new Future.immediateError(
778 new RedirectLimitExceededException(response.redirects))); 835 new RedirectLimitExceededException(response.redirects)));
779 } 836 }
837 } else if (response._shouldAuthenticateProxy) {
838 future = response._authenticateProxy();
780 } else if (response._shouldAuthenticate) { 839 } else if (response._shouldAuthenticate) {
781 future = response._authenticate(); 840 future = response._authenticate();
782 } else { 841 } else {
783 future = new Future<HttpClientResponse>.immediate(response); 842 future = new Future<HttpClientResponse>.immediate(response);
784 } 843 }
785 future.then( 844 future.then(
786 (v) => _responseCompleter.complete(v), 845 (v) => _responseCompleter.complete(v),
787 onError: (e) { 846 onError: (e) {
788 _responseCompleter.completeError(e); 847 _responseCompleter.completeError(e);
789 }); 848 });
790 } 849 }
791 850
792 void _onError(AsyncError error) { 851 void _onError(AsyncError error) {
793 _responseCompleter.completeError(error); 852 _responseCompleter.completeError(error);
794 } 853 }
795 854
796 void _writeHeader() { 855 void _writeHeader() {
797 var buffer = new _BufferList(); 856 var buffer = new _BufferList();
798 writeSP() => buffer.add(const [_CharCode.SP]); 857 writeSP() => buffer.add(const [_CharCode.SP]);
799 writeCRLF() => buffer.add(const [_CharCode.CR, _CharCode.LF]); 858 writeCRLF() => buffer.add(const [_CharCode.CR, _CharCode.LF]);
800 859
801 buffer.add(method.codeUnits); 860 buffer.add(method.codeUnits);
802 writeSP(); 861 writeSP();
803 // Send the path for direct connections and the whole URL for 862 // Send the path for direct connections and the whole URL for
804 // proxy connections. 863 // proxy connections.
805 if (!_usingProxy) { 864 if (_proxy.isDirect) {
806 String path = uri.path; 865 String path = uri.path;
807 if (path.length == 0) path = "/"; 866 if (path.length == 0) path = "/";
808 if (uri.query != "") { 867 if (uri.query != "") {
809 if (uri.fragment != "") { 868 if (uri.fragment != "") {
810 path = "${path}?${uri.query}#${uri.fragment}"; 869 path = "${path}?${uri.query}#${uri.fragment}";
811 } else { 870 } else {
812 path = "${path}?${uri.query}"; 871 path = "${path}?${uri.query}";
813 } 872 }
814 } 873 }
815 buffer.add(path.codeUnits); 874 buffer.add(path.codeUnits);
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
973 if (_nextResponseCompleter != null) { 1032 if (_nextResponseCompleter != null) {
974 _nextResponseCompleter.completeError(error); 1033 _nextResponseCompleter.completeError(error);
975 _nextResponseCompleter = null; 1034 _nextResponseCompleter = null;
976 } 1035 }
977 }, 1036 },
978 onDone: () { 1037 onDone: () {
979 close(); 1038 close();
980 }); 1039 });
981 } 1040 }
982 1041
983 _HttpClientRequest send(Uri uri, int port, String method, bool isDirect) { 1042 _HttpClientRequest send(Uri uri, int port, String method, _Proxy proxy) {
984 // Start with pausing the parser. 1043 // Start with pausing the parser.
985 _subscription.pause(); 1044 _subscription.pause();
986 var outgoing = new _HttpOutgoing(); 1045 var outgoing = new _HttpOutgoing();
987 // Create new request object, wrapping the outgoing connection. 1046 // Create new request object, wrapping the outgoing connection.
988 var request = new _HttpClientRequest(outgoing, 1047 var request = new _HttpClientRequest(outgoing,
989 uri, 1048 uri,
990 method, 1049 method,
991 !isDirect, 1050 proxy,
992 _httpClient, 1051 _httpClient,
993 this); 1052 this);
994 request.headers.host = uri.domain; 1053 request.headers.host = uri.domain;
995 request.headers.port = port; 1054 request.headers.port = port;
996 request.headers.set(HttpHeaders.ACCEPT_ENCODING, "gzip"); 1055 request.headers.set(HttpHeaders.ACCEPT_ENCODING, "gzip");
1056 if (proxy.isAuthenticated) {
1057 // If the proxy configuration contains user information use that
1058 // for proxy basic authorization.
1059 String auth = CryptoUtils.bytesToBase64(
1060 _encodeString("${proxy.username}:${proxy.password}"));
1061 request.headers.set(HttpHeaders.PROXY_AUTHORIZATION, "Basic $auth");
1062 } else if (!proxy.isDirect && _httpClient._proxyCredentials.length > 0) {
1063 var cr = _httpClient._findProxyCredentials(proxy);
1064 if (cr != null) {
1065 cr.authorize(request);
1066 }
1067 }
997 if (uri.userInfo != null && !uri.userInfo.isEmpty) { 1068 if (uri.userInfo != null && !uri.userInfo.isEmpty) {
998 // If the URL contains user information use that for basic 1069 // If the URL contains user information use that for basic
999 // authorization 1070 // authorization.
1000 String auth = 1071 String auth =
1001 CryptoUtils.bytesToBase64(_encodeString(uri.userInfo)); 1072 CryptoUtils.bytesToBase64(_encodeString(uri.userInfo));
1002 request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth"); 1073 request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth");
1003 } else { 1074 } else {
1004 // Look for credentials. 1075 // Look for credentials.
1005 _Credentials cr = _httpClient._findCredentials(uri); 1076 _Credentials cr = _httpClient._findCredentials(uri);
1006 if (cr != null) { 1077 if (cr != null) {
1007 cr.authorize(request); 1078 cr.authorize(request);
1008 } 1079 }
1009 } 1080 }
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
1088 class _HttpClient implements HttpClient { 1159 class _HttpClient implements HttpClient {
1089 // TODO(ajohnsen): Use eviction timeout. 1160 // TODO(ajohnsen): Use eviction timeout.
1090 static const int DEFAULT_EVICTION_TIMEOUT = 60000; 1161 static const int DEFAULT_EVICTION_TIMEOUT = 60000;
1091 bool _closing = false; 1162 bool _closing = false;
1092 1163
1093 final Map<String, Queue<_HttpClientConnection>> _idleConnections 1164 final Map<String, Queue<_HttpClientConnection>> _idleConnections
1094 = new Map<String, Queue<_HttpClientConnection>>(); 1165 = new Map<String, Queue<_HttpClientConnection>>();
1095 final Set<_HttpClientConnection> _activeConnections 1166 final Set<_HttpClientConnection> _activeConnections
1096 = new Set<_HttpClientConnection>(); 1167 = new Set<_HttpClientConnection>();
1097 final List<_Credentials> _credentials = []; 1168 final List<_Credentials> _credentials = [];
1169 final List<_ProxyCredentials> _proxyCredentials = [];
1098 Function _authenticate; 1170 Function _authenticate;
1171 Function _authenticateProxy;
1099 Function _findProxy = HttpClient.findProxyFromEnvironment; 1172 Function _findProxy = HttpClient.findProxyFromEnvironment;
1100 1173
1101 Future<HttpClientRequest> open(String method, 1174 Future<HttpClientRequest> open(String method,
1102 String host, 1175 String host,
1103 int port, 1176 int port,
1104 String path) { 1177 String path) {
1105 // TODO(sgjesse): The path set here can contain both query and 1178 // TODO(sgjesse): The path set here can contain both query and
1106 // fragment. They should be cracked and set correctly. 1179 // fragment. They should be cracked and set correctly.
1107 return _openUrl(method, new Uri.fromComponents( 1180 return _openUrl(method, new Uri.fromComponents(
1108 scheme: "http", domain: host, port: port, path: path)); 1181 scheme: "http", domain: host, port: port, path: path));
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1156 } 1229 }
1157 1230
1158 set authenticate(Future<bool> f(Uri url, String scheme, String realm)) { 1231 set authenticate(Future<bool> f(Uri url, String scheme, String realm)) {
1159 _authenticate = f; 1232 _authenticate = f;
1160 } 1233 }
1161 1234
1162 void addCredentials(Uri url, String realm, HttpClientCredentials cr) { 1235 void addCredentials(Uri url, String realm, HttpClientCredentials cr) {
1163 _credentials.add(new _Credentials(url, realm, cr)); 1236 _credentials.add(new _Credentials(url, realm, cr));
1164 } 1237 }
1165 1238
1239 set authenticateProxy(
1240 Future<bool> f(String host, int port, String scheme, String realm)) {
1241 _authenticateProxy = f;
1242 }
1243
1244 void addProxyCredentials(String host,
1245 int port,
1246 String realm,
1247 HttpClientCredentials cr) {
1248 _proxyCredentials.add(new _ProxyCredentials(host, port, realm, cr));
1249 }
1250
1166 set findProxy(String f(Uri uri)) => _findProxy = f; 1251 set findProxy(String f(Uri uri)) => _findProxy = f;
1167 1252
1168 Future<HttpClientRequest> _openUrl(String method, Uri uri) { 1253 Future<HttpClientRequest> _openUrl(String method, Uri uri) {
1169 if (method == null) { 1254 if (method == null) {
1170 throw new ArgumentError(method); 1255 throw new ArgumentError(method);
1171 } 1256 }
1172 if (uri.domain.isEmpty || (uri.scheme != "http" && uri.scheme != "https")) { 1257 if (uri.domain.isEmpty || (uri.scheme != "http" && uri.scheme != "https")) {
1173 throw new ArgumentError("Unsupported scheme '${uri.scheme}' in $uri"); 1258 throw new ArgumentError("Unsupported scheme '${uri.scheme}' in $uri");
1174 } 1259 }
1175 1260
(...skipping 13 matching lines...) Expand all
1189 proxyConf = new _ProxyConfiguration(_findProxy(uri)); 1274 proxyConf = new _ProxyConfiguration(_findProxy(uri));
1190 } catch (error, stackTrace) { 1275 } catch (error, stackTrace) {
1191 return new Future.immediateError(error, stackTrace); 1276 return new Future.immediateError(error, stackTrace);
1192 } 1277 }
1193 } 1278 }
1194 return _getConnection(uri.domain, port, proxyConf, isSecure) 1279 return _getConnection(uri.domain, port, proxyConf, isSecure)
1195 .then((info) { 1280 .then((info) {
1196 return info.connection.send(uri, 1281 return info.connection.send(uri,
1197 port, 1282 port,
1198 method.toUpperCase(), 1283 method.toUpperCase(),
1199 info.proxy.isDirect); 1284 info.proxy);
1200 }); 1285 });
1201 } 1286 }
1202 1287
1203 Future<HttpClientRequest> _openUrlFromRequest(String method, 1288 Future<HttpClientRequest> _openUrlFromRequest(String method,
1204 Uri uri, 1289 Uri uri,
1205 _HttpClientRequest previous) { 1290 _HttpClientRequest previous) {
1206 return openUrl(method, uri).then((_HttpClientRequest request) { 1291 return openUrl(method, uri).then((_HttpClientRequest request) {
1207 // Only follow redirects if initial request did. 1292 // Only follow redirects if initial request did.
1208 request.followRedirects = previous.followRedirects; 1293 request.followRedirects = previous.followRedirects;
1209 // Allow same number of redirects. 1294 // Allow same number of redirects.
1210 request.maxRedirects = previous.maxRedirects; 1295 request.maxRedirects = previous.maxRedirects;
1211 // Copy headers 1296 // Copy headers.
1212 for (var header in previous.headers._headers.keys) { 1297 for (var header in previous.headers._headers.keys) {
1213 if (request.headers[header] == null) { 1298 if (request.headers[header] == null) {
1214 request.headers.set(header, previous.headers[header]); 1299 request.headers.set(header, previous.headers[header]);
1215 } 1300 }
1216 } 1301 }
1217 request.headers.chunkedTransferEncoding = false; 1302 request.headers.chunkedTransferEncoding = false;
1218 request.contentLength = 0; 1303 request.contentLength = 0;
1219 return request; 1304 return request;
1220 }); 1305 });
1221 } 1306 }
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1292 if (value.applies(url, scheme)) { 1377 if (value.applies(url, scheme)) {
1293 if (prev == null) return value; 1378 if (prev == null) return value;
1294 return value.uri.path.length > prev.uri.path.length ? value : prev; 1379 return value.uri.path.length > prev.uri.path.length ? value : prev;
1295 } else { 1380 } else {
1296 return prev; 1381 return prev;
1297 } 1382 }
1298 }); 1383 });
1299 return cr; 1384 return cr;
1300 } 1385 }
1301 1386
1387 _ProxyCredentials _findProxyCredentials(_Proxy proxy) {
1388 // Look for credentials.
1389 var it = _proxyCredentials.iterator;
1390 while (it.moveNext()) {
1391 if (it.current.applies(proxy, _AuthenticationScheme.BASIC)) {
1392 return it.current;
1393 }
1394 }
1395 }
1396
1302 void _removeCredentials(_Credentials cr) { 1397 void _removeCredentials(_Credentials cr) {
1303 int index = _credentials.indexOf(cr); 1398 int index = _credentials.indexOf(cr);
1304 if (index != -1) { 1399 if (index != -1) {
1305 _credentials.removeAt(index); 1400 _credentials.removeAt(index);
1306 } 1401 }
1307 } 1402 }
1308 1403
1309 static String _findProxyFromEnvironment(Uri url, 1404 static String _findProxyFromEnvironment(Uri url,
1310 Map<String, String> environment) { 1405 Map<String, String> environment) {
1311 checkNoProxy(String option) { 1406 checkNoProxy(String option) {
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after
1583 1678
1584 _ProxyConfiguration(String configuration) : proxies = new List<_Proxy>() { 1679 _ProxyConfiguration(String configuration) : proxies = new List<_Proxy>() {
1585 if (configuration == null) { 1680 if (configuration == null) {
1586 throw new HttpException("Invalid proxy configuration $configuration"); 1681 throw new HttpException("Invalid proxy configuration $configuration");
1587 } 1682 }
1588 List<String> list = configuration.split(";"); 1683 List<String> list = configuration.split(";");
1589 list.forEach((String proxy) { 1684 list.forEach((String proxy) {
1590 proxy = proxy.trim(); 1685 proxy = proxy.trim();
1591 if (!proxy.isEmpty) { 1686 if (!proxy.isEmpty) {
1592 if (proxy.startsWith(PROXY_PREFIX)) { 1687 if (proxy.startsWith(PROXY_PREFIX)) {
1688 String username;
1689 String password;
1690 // Skip the "PROXY " prefix.
1691 proxy = proxy.substring(PROXY_PREFIX.length).trim();
1692 // Look for proxy authentication.
1693 int at = proxy.indexOf("@");
1694 if (at != -1) {
1695 String userinfo = proxy.substring(0, at).trim();
1696 proxy = proxy.substring(at + 1).trim();
1697 int colon = userinfo.indexOf(":");
1698 if (colon == -1 || colon == 0 || colon == proxy.length - 1) {
1699 throw new HttpException(
1700 "Invalid proxy configuration $configuration");
1701 }
1702 username = userinfo.substring(0, colon).trim();
1703 password = userinfo.substring(colon + 1).trim();
1704 }
1705 // Look for proxy host and port.
1593 int colon = proxy.indexOf(":"); 1706 int colon = proxy.indexOf(":");
1594 if (colon == -1 || colon == 0 || colon == proxy.length - 1) { 1707 if (colon == -1 || colon == 0 || colon == proxy.length - 1) {
1595 throw new HttpException( 1708 throw new HttpException(
1596 "Invalid proxy configuration $configuration"); 1709 "Invalid proxy configuration $configuration");
1597 } 1710 }
1598 // Skip the "PROXY " prefix. 1711 String host = proxy.substring(0, colon).trim();
1599 String host = proxy.substring(PROXY_PREFIX.length, colon).trim();
1600 String portString = proxy.substring(colon + 1).trim(); 1712 String portString = proxy.substring(colon + 1).trim();
1601 int port; 1713 int port;
1602 try { 1714 try {
1603 port = int.parse(portString); 1715 port = int.parse(portString);
1604 } on FormatException catch (e) { 1716 } on FormatException catch (e) {
1605 throw new HttpException( 1717 throw new HttpException(
1606 "Invalid proxy configuration $configuration, " 1718 "Invalid proxy configuration $configuration, "
1607 "invalid port '$portString'"); 1719 "invalid port '$portString'");
1608 } 1720 }
1609 proxies.add(new _Proxy(host, port)); 1721 proxies.add(new _Proxy(host, port, username, password));
1610 } else if (proxy.trim() == DIRECT_PREFIX) { 1722 } else if (proxy.trim() == DIRECT_PREFIX) {
1611 proxies.add(new _Proxy.direct()); 1723 proxies.add(new _Proxy.direct());
1612 } else { 1724 } else {
1613 throw new HttpException("Invalid proxy configuration $configuration"); 1725 throw new HttpException("Invalid proxy configuration $configuration");
1614 } 1726 }
1615 } 1727 }
1616 }); 1728 });
1617 } 1729 }
1618 1730
1619 const _ProxyConfiguration.direct() 1731 const _ProxyConfiguration.direct()
1620 : proxies = const [const _Proxy.direct()]; 1732 : proxies = const [const _Proxy.direct()];
1621 1733
1622 final List<_Proxy> proxies; 1734 final List<_Proxy> proxies;
1623 } 1735 }
1624 1736
1625 1737
1626 class _Proxy { 1738 class _Proxy {
1627 const _Proxy(this.host, this.port) : isDirect = false; 1739 const _Proxy(
1628 const _Proxy.direct() : host = null, port = null, isDirect = true; 1740 this.host, this.port, this.username, this.password) : isDirect = false;
1741 const _Proxy.direct() : host = null, port = null,
1742 username = null, password = null, isDirect = true;
1743
1744 bool get isAuthenticated => username != null;
1629 1745
1630 final String host; 1746 final String host;
1631 final int port; 1747 final int port;
1748 final String username;
1749 final String password;
1632 final bool isDirect; 1750 final bool isDirect;
1633 } 1751 }
1634 1752
1635 1753
1636 class _HttpConnectionInfo implements HttpConnectionInfo { 1754 class _HttpConnectionInfo implements HttpConnectionInfo {
1637 static _HttpConnectionInfo create(Socket socket) { 1755 static _HttpConnectionInfo create(Socket socket) {
1638 if (socket == null) return null; 1756 if (socket == null) return null;
1639 try { 1757 try {
1640 _HttpConnectionInfo info = new _HttpConnectionInfo._(); 1758 _HttpConnectionInfo info = new _HttpConnectionInfo._();
1641 info.remoteHost = socket.remoteHost; 1759 info.remoteHost = socket.remoteHost;
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
1768 String realm; 1886 String realm;
1769 _HttpClientCredentials credentials; 1887 _HttpClientCredentials credentials;
1770 1888
1771 // Digest specific fields. 1889 // Digest specific fields.
1772 String nonce; 1890 String nonce;
1773 String algorithm; 1891 String algorithm;
1774 String qop; 1892 String qop;
1775 } 1893 }
1776 1894
1777 1895
1896 class _ProxyCredentials {
1897 _ProxyCredentials(this.host, this.port, this.realm, this.credentials);
1898
1899 _AuthenticationScheme get scheme => credentials.scheme;
1900
1901 bool applies(_Proxy proxy, _AuthenticationScheme scheme) {
1902 return proxy.host == host && proxy.port == port;
1903 }
1904
1905 void authorize(HttpClientRequest request) {
1906 credentials.authorizeProxy(this, request);
1907 }
1908
1909 String host;
1910 int port;
1911 String realm;
1912 _HttpClientCredentials credentials;
1913 }
1914
1915
1778 abstract class _HttpClientCredentials implements HttpClientCredentials { 1916 abstract class _HttpClientCredentials implements HttpClientCredentials {
1779 _AuthenticationScheme get scheme; 1917 _AuthenticationScheme get scheme;
1780 void authorize(_Credentials credentials, HttpClientRequest request); 1918 void authorize(_Credentials credentials, HttpClientRequest request);
1781 } 1919 }
1782 1920
1783 1921
1784 class _HttpClientBasicCredentials 1922 class _HttpClientBasicCredentials
1785 extends _HttpClientCredentials 1923 extends _HttpClientCredentials
1786 implements HttpClientBasicCredentials { 1924 implements HttpClientBasicCredentials {
1787 _HttpClientBasicCredentials(this.username, 1925 _HttpClientBasicCredentials(this.username,
1788 this.password); 1926 this.password);
1789 1927
1790 _AuthenticationScheme get scheme => _AuthenticationScheme.BASIC; 1928 _AuthenticationScheme get scheme => _AuthenticationScheme.BASIC;
1791 1929
1792 void authorize(_Credentials _, HttpClientRequest request) { 1930 String authorization() {
1793 // There is no mentioning of username/password encoding in RFC 1931 // There is no mentioning of username/password encoding in RFC
1794 // 2617. However there is an open draft for adding an additional 1932 // 2617. However there is an open draft for adding an additional
1795 // accept-charset parameter to the WWW-Authenticate and 1933 // accept-charset parameter to the WWW-Authenticate and
1796 // Proxy-Authenticate headers, see 1934 // Proxy-Authenticate headers, see
1797 // http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For 1935 // http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For
1798 // now always use UTF-8 encoding. 1936 // now always use UTF-8 encoding.
1799 String auth = 1937 String auth =
1800 CryptoUtils.bytesToBase64(_encodeString("$username:$password")); 1938 CryptoUtils.bytesToBase64(_encodeString("$username:$password"));
1801 request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth"); 1939 return "Basic $auth";
1940 }
1941
1942 void authorize(_Credentials _, HttpClientRequest request) {
1943 request.headers.set(HttpHeaders.AUTHORIZATION, authorization());
1944 }
1945
1946 void authorizeProxy(_ProxyCredentials _, HttpClientRequest request) {
1947 request.headers.set(HttpHeaders.PROXY_AUTHORIZATION, authorization());
1802 } 1948 }
1803 1949
1804 String username; 1950 String username;
1805 String password; 1951 String password;
1806 } 1952 }
1807 1953
1808 1954
1809 class _HttpClientDigestCredentials 1955 class _HttpClientDigestCredentials
1810 extends _HttpClientCredentials 1956 extends _HttpClientCredentials
1811 implements HttpClientDigestCredentials { 1957 implements HttpClientDigestCredentials {
1812 _HttpClientDigestCredentials(this.username, 1958 _HttpClientDigestCredentials(this.username,
1813 this.password); 1959 this.password);
1814 1960
1815 _AuthenticationScheme get scheme => _AuthenticationScheme.DIGEST; 1961 _AuthenticationScheme get scheme => _AuthenticationScheme.DIGEST;
1816 1962
1817 void authorize(_Credentials credentials, HttpClientRequest request) { 1963 void authorize(_Credentials credentials, HttpClientRequest request) {
1818 // TODO(sgjesse): Implement!!! 1964 // TODO(sgjesse): Implement!!!
1819 throw new UnsupportedError("Digest authentication not yet supported"); 1965 throw new UnsupportedError("Digest authentication not yet supported");
1820 } 1966 }
1821 1967
1968 void authorizeProxy(_Credentials credentials, HttpClientRequest request) {
1969 // TODO(sgjesse): Implement!!!
1970 throw new UnsupportedError("Digest authentication not yet supported");
1971 }
1972
1822 String username; 1973 String username;
1823 String password; 1974 String password;
1824 } 1975 }
1825 1976
1826 1977
1827 class _RedirectInfo implements RedirectInfo { 1978 class _RedirectInfo implements RedirectInfo {
1828 const _RedirectInfo(int this.statusCode, 1979 const _RedirectInfo(int this.statusCode,
1829 String this.method, 1980 String this.method,
1830 Uri this.location); 1981 Uri this.location);
1831 final int statusCode; 1982 final int statusCode;
1832 final String method; 1983 final String method;
1833 final Uri location; 1984 final Uri location;
1834 } 1985 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698