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 867 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 878 _responseCompleter.completeError(e); | 878 _responseCompleter.completeError(e); |
| 879 }); | 879 }); |
| 880 } | 880 } |
| 881 | 881 |
| 882 void _onError(error) { | 882 void _onError(error) { |
| 883 _responseCompleter.completeError(error); | 883 _responseCompleter.completeError(error); |
| 884 } | 884 } |
| 885 | 885 |
| 886 void _writeHeader() { | 886 void _writeHeader() { |
| 887 var buffer = new _BufferList(); | 887 var buffer = new _BufferList(); |
| 888 | |
| 888 writeSP() => buffer.add(const [_CharCode.SP]); | 889 writeSP() => buffer.add(const [_CharCode.SP]); |
| 890 | |
| 889 writeCRLF() => buffer.add(const [_CharCode.CR, _CharCode.LF]); | 891 writeCRLF() => buffer.add(const [_CharCode.CR, _CharCode.LF]); |
| 890 | 892 |
| 891 buffer.add(method.codeUnits); | 893 void writePath() { |
| 892 writeSP(); | |
| 893 // Send the path for direct connections and the whole URL for | |
| 894 // proxy connections. | |
| 895 if (_proxy.isDirect) { | |
| 896 String path = uri.path; | 894 String path = uri.path; |
| 897 if (path.length == 0) path = "/"; | 895 if (path.length == 0) path = "/"; |
| 898 if (uri.query != "") { | 896 if (uri.query != "") { |
| 899 if (uri.fragment != "") { | 897 if (uri.fragment != "") { |
| 900 path = "${path}?${uri.query}#${uri.fragment}"; | 898 path = "${path}?${uri.query}#${uri.fragment}"; |
| 901 } else { | 899 } else { |
| 902 path = "${path}?${uri.query}"; | 900 path = "${path}?${uri.query}"; |
| 903 } | 901 } |
| 904 } | 902 } |
| 905 buffer.add(path.codeUnits); | 903 buffer.add(path.codeUnits); |
| 904 } | |
| 905 | |
| 906 // Write the request method. | |
| 907 buffer.add(method.codeUnits); | |
| 908 writeSP(); | |
| 909 // Write the request URI. | |
| 910 if (_proxy.isDirect) { | |
| 911 writePath(); | |
| 906 } else { | 912 } else { |
| 907 buffer.add(uri.toString().codeUnits); | 913 if (method == "CONNECT") { |
| 914 // For the connect method the request URI is the host:port of | |
| 915 // the requested destination of the tunnel (see RFC 2817 | |
| 916 // section 5.2) | |
| 917 buffer.add(uri.domain.codeUnits); | |
| 918 buffer.add(const [_CharCode.COLON]); | |
| 919 buffer.add(uri.port.toString().codeUnits); | |
| 920 } else { | |
| 921 if (_httpClientConnection._proxyTunnel) { | |
| 922 writePath(); | |
| 923 } else { | |
| 924 buffer.add(uri.toString().codeUnits); | |
| 925 } | |
| 926 } | |
| 908 } | 927 } |
| 909 writeSP(); | 928 writeSP(); |
| 910 buffer.add(_Const.HTTP11); | 929 buffer.add(_Const.HTTP11); |
| 911 writeCRLF(); | 930 writeCRLF(); |
| 912 | 931 |
| 913 // Add the cookies to the headers. | 932 // Add the cookies to the headers. |
| 914 if (!cookies.isEmpty) { | 933 if (!cookies.isEmpty) { |
| 915 StringBuffer sb = new StringBuffer(); | 934 StringBuffer sb = new StringBuffer(); |
| 916 for (int i = 0; i < cookies.length; i++) { | 935 for (int i = 0; i < cookies.length; i++) { |
| 917 if (i > 0) sb.write("; "); | 936 if (i > 0) sb.write("; "); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1017 } | 1036 } |
| 1018 | 1037 |
| 1019 Future close() { | 1038 Future close() { |
| 1020 _doneCompleter.complete(_consumer); | 1039 _doneCompleter.complete(_consumer); |
| 1021 return new Future.value(); | 1040 return new Future.value(); |
| 1022 } | 1041 } |
| 1023 | 1042 |
| 1024 Future get done => _doneCompleter.future; | 1043 Future get done => _doneCompleter.future; |
| 1025 } | 1044 } |
| 1026 | 1045 |
| 1027 | |
| 1028 class _HttpClientConnection { | 1046 class _HttpClientConnection { |
| 1029 final String key; | 1047 final String key; |
| 1030 final Socket _socket; | 1048 final Socket _socket; |
| 1049 final bool _proxyTunnel; | |
| 1031 final _HttpParser _httpParser; | 1050 final _HttpParser _httpParser; |
| 1032 StreamSubscription _subscription; | 1051 StreamSubscription _subscription; |
| 1033 final _HttpClient _httpClient; | 1052 final _HttpClient _httpClient; |
| 1053 bool _dispose = false; | |
| 1034 | 1054 |
| 1035 Completer<_HttpIncoming> _nextResponseCompleter; | 1055 Completer<_HttpIncoming> _nextResponseCompleter; |
| 1036 Future _streamFuture; | 1056 Future _streamFuture; |
| 1037 | 1057 |
| 1038 _HttpClientConnection(String this.key, | 1058 _HttpClientConnection(String this.key, |
| 1039 Socket this._socket, | 1059 Socket this._socket, |
| 1040 _HttpClient this._httpClient) | 1060 _HttpClient this._httpClient, |
| 1061 [this._proxyTunnel = false]) | |
| 1041 : _httpParser = new _HttpParser.responseParser() { | 1062 : _httpParser = new _HttpParser.responseParser() { |
| 1042 _socket.pipe(_httpParser); | 1063 _socket.pipe(_httpParser); |
| 1043 | 1064 |
| 1044 // Set up handlers on the parser here, so we are sure to get 'onDone' from | 1065 // Set up handlers on the parser here, so we are sure to get 'onDone' from |
| 1045 // the parser. | 1066 // the parser. |
| 1046 _subscription = _httpParser.listen( | 1067 _subscription = _httpParser.listen( |
| 1047 (incoming) { | 1068 (incoming) { |
| 1048 // Only handle one incoming response at the time. Keep the | 1069 // Only handle one incoming response at the time. Keep the |
| 1049 // stream paused until the response have been processed. | 1070 // stream paused until the response have been processed. |
| 1050 _subscription.pause(); | 1071 _subscription.pause(); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1109 _httpParser.responseToMethod = method; | 1130 _httpParser.responseToMethod = method; |
| 1110 _streamFuture = outgoing.done | 1131 _streamFuture = outgoing.done |
| 1111 .then((s) { | 1132 .then((s) { |
| 1112 // Request sent, set up response completer. | 1133 // Request sent, set up response completer. |
| 1113 _nextResponseCompleter = new Completer(); | 1134 _nextResponseCompleter = new Completer(); |
| 1114 | 1135 |
| 1115 // Listen for response. | 1136 // Listen for response. |
| 1116 _nextResponseCompleter.future | 1137 _nextResponseCompleter.future |
| 1117 .then((incoming) { | 1138 .then((incoming) { |
| 1118 incoming.dataDone.then((_) { | 1139 incoming.dataDone.then((_) { |
| 1119 if (incoming.headers.persistentConnection && | 1140 if (!_dispose && |
| 1141 incoming.headers.persistentConnection && | |
| 1120 request.persistentConnection) { | 1142 request.persistentConnection) { |
| 1121 // Return connection, now we are done. | 1143 // Return connection, now we are done. |
| 1122 _httpClient._returnConnection(this); | 1144 _httpClient._returnConnection(this); |
| 1123 _subscription.resume(); | 1145 _subscription.resume(); |
| 1124 } else { | 1146 } else { |
| 1125 destroy(); | 1147 destroy(); |
| 1126 } | 1148 } |
| 1127 }); | 1149 }); |
| 1128 request._onIncoming(incoming); | 1150 request._onIncoming(incoming); |
| 1129 }) | 1151 }) |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 1160 _socket.destroy(); | 1182 _socket.destroy(); |
| 1161 } | 1183 } |
| 1162 | 1184 |
| 1163 void close() { | 1185 void close() { |
| 1164 _httpClient._connectionClosed(this); | 1186 _httpClient._connectionClosed(this); |
| 1165 _streamFuture | 1187 _streamFuture |
| 1166 // TODO(ajohnsen): Add timeout. | 1188 // TODO(ajohnsen): Add timeout. |
| 1167 .then((_) => _socket.destroy()); | 1189 .then((_) => _socket.destroy()); |
| 1168 } | 1190 } |
| 1169 | 1191 |
| 1192 Future<_HttpClientConnection> createProxyTunnel(host, port, proxy) { | |
| 1193 _HttpClientRequest request = | |
| 1194 send(new Uri.fromComponents(domain: host, port: port), | |
| 1195 port, | |
| 1196 "CONNECT", | |
| 1197 proxy); | |
| 1198 if (proxy.isAuthenticated) { | |
| 1199 // If the proxy configuration contains user information use that | |
| 1200 // for proxy basic authorization. | |
| 1201 String auth = CryptoUtils.bytesToBase64( | |
| 1202 _encodeString("${proxy.username}:${proxy.password}")); | |
| 1203 request.headers.set(HttpHeaders.PROXY_AUTHORIZATION, "Basic $auth"); | |
| 1204 } | |
| 1205 return request.close() | |
| 1206 .then((response) { | |
| 1207 if (response.statusCode != HttpStatus.OK) { | |
| 1208 throw "Proxy failed to establish tunnel " | |
| 1209 "(${response.statusCode} ${response.reasonPhrase})"; | |
| 1210 } | |
| 1211 var socket = response._httpRequest._httpClientConnection._socket; | |
| 1212 return SecureSocket.secure(socket, host: host); | |
| 1213 }) | |
| 1214 .then((secureSocket) { | |
| 1215 String key = _HttpClientConnection.makeKey(true, host, port); | |
| 1216 return new _HttpClientConnection( | |
| 1217 key, secureSocket, request._httpClient, true); | |
| 1218 }); | |
| 1219 } | |
| 1220 | |
| 1170 HttpConnectionInfo get connectionInfo => _HttpConnectionInfo.create(_socket); | 1221 HttpConnectionInfo get connectionInfo => _HttpConnectionInfo.create(_socket); |
| 1222 | |
| 1223 static makeKey(bool isSecure, String host, int port) { | |
| 1224 return isSecure ? "ssh:$host:$port" : "$host:$port"; | |
| 1225 } | |
| 1226 | |
| 1171 } | 1227 } |
| 1172 | 1228 |
| 1173 class _ConnnectionInfo { | 1229 class _ConnnectionInfo { |
| 1174 _ConnnectionInfo(_HttpClientConnection this.connection, _Proxy this.proxy); | 1230 _ConnnectionInfo(_HttpClientConnection this.connection, _Proxy this.proxy); |
| 1175 final _HttpClientConnection connection; | 1231 final _HttpClientConnection connection; |
| 1176 final _Proxy proxy; | 1232 final _Proxy proxy; |
| 1177 } | 1233 } |
| 1178 | 1234 |
| 1179 | 1235 |
| 1180 class _HttpClient implements HttpClient { | 1236 class _HttpClient implements HttpClient { |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1268 HttpClientCredentials cr) { | 1324 HttpClientCredentials cr) { |
| 1269 _proxyCredentials.add(new _ProxyCredentials(host, port, realm, cr)); | 1325 _proxyCredentials.add(new _ProxyCredentials(host, port, realm, cr)); |
| 1270 } | 1326 } |
| 1271 | 1327 |
| 1272 set findProxy(String f(Uri uri)) => _findProxy = f; | 1328 set findProxy(String f(Uri uri)) => _findProxy = f; |
| 1273 | 1329 |
| 1274 Future<HttpClientRequest> _openUrl(String method, Uri uri) { | 1330 Future<HttpClientRequest> _openUrl(String method, Uri uri) { |
| 1275 if (method == null) { | 1331 if (method == null) { |
| 1276 throw new ArgumentError(method); | 1332 throw new ArgumentError(method); |
| 1277 } | 1333 } |
| 1278 if (uri.domain.isEmpty || (uri.scheme != "http" && uri.scheme != "https")) { | 1334 if (method != "CONNECT") { |
| 1279 throw new ArgumentError("Unsupported scheme '${uri.scheme}' in $uri"); | 1335 if (uri.domain.isEmpty || (uri.scheme != "http" && uri.scheme != "https")) { |
|
Mads Ager (google)
2013/04/29 10:05:01
long line
| |
| 1336 throw new ArgumentError("Unsupported scheme '${uri.scheme}' in $uri"); | |
| 1337 } | |
| 1280 } | 1338 } |
| 1281 | 1339 |
| 1282 bool isSecure = (uri.scheme == "https"); | 1340 bool isSecure = (uri.scheme == "https"); |
| 1283 int port = uri.port; | 1341 int port = uri.port; |
| 1284 if (port == 0) { | 1342 if (port == 0) { |
| 1285 port = isSecure ? | 1343 port = isSecure ? |
| 1286 HttpClient.DEFAULT_HTTPS_PORT : | 1344 HttpClient.DEFAULT_HTTPS_PORT : |
| 1287 HttpClient.DEFAULT_HTTP_PORT; | 1345 HttpClient.DEFAULT_HTTP_PORT; |
| 1288 } | 1346 } |
| 1289 // Check to see if a proxy server should be used for this connection. | 1347 // Check to see if a proxy server should be used for this connection. |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1357 int uriPort, | 1415 int uriPort, |
| 1358 _ProxyConfiguration proxyConf, | 1416 _ProxyConfiguration proxyConf, |
| 1359 bool isSecure) { | 1417 bool isSecure) { |
| 1360 Iterator<_Proxy> proxies = proxyConf.proxies.iterator; | 1418 Iterator<_Proxy> proxies = proxyConf.proxies.iterator; |
| 1361 | 1419 |
| 1362 Future<_ConnnectionInfo> connect(error) { | 1420 Future<_ConnnectionInfo> connect(error) { |
| 1363 if (!proxies.moveNext()) return new Future.error(error); | 1421 if (!proxies.moveNext()) return new Future.error(error); |
| 1364 _Proxy proxy = proxies.current; | 1422 _Proxy proxy = proxies.current; |
| 1365 String host = proxy.isDirect ? uriHost: proxy.host; | 1423 String host = proxy.isDirect ? uriHost: proxy.host; |
| 1366 int port = proxy.isDirect ? uriPort: proxy.port; | 1424 int port = proxy.isDirect ? uriPort: proxy.port; |
| 1367 String key = isSecure ? "ssh:$host:$port" : "$host:$port"; | 1425 String key = _HttpClientConnection.makeKey(isSecure, host, port); |
| 1368 if (_idleConnections.containsKey(key)) { | 1426 if (_idleConnections.containsKey(key)) { |
| 1369 var connection = _idleConnections[key].first; | 1427 var connection = _idleConnections[key].first; |
| 1370 _idleConnections[key].remove(connection); | 1428 _idleConnections[key].remove(connection); |
| 1371 if (_idleConnections[key].isEmpty) { | 1429 if (_idleConnections[key].isEmpty) { |
| 1372 _idleConnections.remove(key); | 1430 _idleConnections.remove(key); |
| 1373 } | 1431 } |
| 1374 _activeConnections.add(connection); | 1432 _activeConnections.add(connection); |
| 1375 return new Future.value(new _ConnnectionInfo(connection, proxy)); | 1433 return new Future.value(new _ConnnectionInfo(connection, proxy)); |
| 1376 } | 1434 } |
| 1377 return (isSecure && proxy.isDirect | 1435 return (isSecure && proxy.isDirect |
| 1378 ? SecureSocket.connect(host, | 1436 ? SecureSocket.connect(host, |
| 1379 port, | 1437 port, |
| 1380 sendClientCertificate: true) | 1438 sendClientCertificate: true) |
| 1381 : Socket.connect(host, port)) | 1439 : Socket.connect(host, port)) |
| 1382 .then((socket) { | 1440 .then((socket) { |
| 1383 socket.setOption(SocketOption.TCP_NODELAY, true); | 1441 socket.setOption(SocketOption.TCP_NODELAY, true); |
| 1384 var connection = new _HttpClientConnection(key, socket, this); | 1442 var connection = new _HttpClientConnection(key, socket, this); |
| 1385 _activeConnections.add(connection); | 1443 if (isSecure && !proxy.isDirect) { |
| 1386 return new _ConnnectionInfo(connection, proxy); | 1444 connection._dispose = true; |
| 1445 return connection.createProxyTunnel(uriHost, uriPort, proxy) | |
| 1446 .then((tunnel) { | |
| 1447 _activeConnections.add(tunnel); | |
| 1448 return new _ConnnectionInfo(tunnel, proxy); | |
| 1449 }); | |
| 1450 } else { | |
| 1451 _activeConnections.add(connection); | |
| 1452 return new _ConnnectionInfo(connection, proxy); | |
| 1453 } | |
| 1387 }, onError: (error) { | 1454 }, onError: (error) { |
| 1388 // Continue with next proxy. | 1455 // Continue with next proxy. |
| 1389 return connect(error); | 1456 return connect(error); |
| 1390 }); | 1457 }); |
| 1391 } | 1458 } |
| 1392 return connect(new HttpException("No proxies given")); | 1459 return connect(new HttpException("No proxies given")); |
| 1393 } | 1460 } |
| 1394 | 1461 |
| 1395 _Credentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) { | 1462 _Credentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) { |
| 1396 // Look for credentials. | 1463 // Look for credentials. |
| (...skipping 593 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1990 | 2057 |
| 1991 | 2058 |
| 1992 class _RedirectInfo implements RedirectInfo { | 2059 class _RedirectInfo implements RedirectInfo { |
| 1993 const _RedirectInfo(int this.statusCode, | 2060 const _RedirectInfo(int this.statusCode, |
| 1994 String this.method, | 2061 String this.method, |
| 1995 Uri this.location); | 2062 Uri this.location); |
| 1996 final int statusCode; | 2063 final int statusCode; |
| 1997 final String method; | 2064 final String method; |
| 1998 final Uri location; | 2065 final Uri location; |
| 1999 } | 2066 } |
| OLD | NEW |