Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |