| 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 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 304 // this authenticate response. | 304 // this authenticate response. |
| 305 if (cr.scheme == _AuthenticationScheme.BASIC && !cr.used) { | 305 if (cr.scheme == _AuthenticationScheme.BASIC && !cr.used) { |
| 306 // Credentials where found, prepare for retrying the request. | 306 // Credentials where found, prepare for retrying the request. |
| 307 return retryWithCredentials(cr); | 307 return retryWithCredentials(cr); |
| 308 } | 308 } |
| 309 | 309 |
| 310 // Digest authentication only supports the MD5 algorithm. | 310 // Digest authentication only supports the MD5 algorithm. |
| 311 if (cr.scheme == _AuthenticationScheme.DIGEST && | 311 if (cr.scheme == _AuthenticationScheme.DIGEST && |
| 312 (header.parameters["algorithm"] == null || | 312 (header.parameters["algorithm"] == null || |
| 313 header.parameters["algorithm"].toLowerCase() == "md5")) { | 313 header.parameters["algorithm"].toLowerCase() == "md5")) { |
| 314 // If the nonce is not set then this is the first authenticate | 314 if (cr.nonce == null || cr.nonce == header.parameters["nonce"]) { |
| 315 // response for these credentials. | 315 // If the nonce is not set then this is the first authenticate |
| 316 // TODO(sgjesse): Check for changed nonce. | 316 // response for these credentials. Set up authentication state. |
| 317 if (cr.nonce == null) { | 317 if (cr.nonce == null) { |
| 318 // Set up authentication state. | 318 cr.nonce = header.parameters["nonce"]; |
| 319 cr.algorithm = "MD5"; |
| 320 cr.qop = header.parameters["qop"]; |
| 321 cr.nonceCount = 0; |
| 322 } |
| 323 // Credentials where found, prepare for retrying the request. |
| 324 return retryWithCredentials(cr); |
| 325 } else if (header.parameters["stale"] != null && |
| 326 header.parameters["stale"].toLowerCase() == "true") { |
| 327 // If stale is true retry with new nonce. |
| 319 cr.nonce = header.parameters["nonce"]; | 328 cr.nonce = header.parameters["nonce"]; |
| 320 cr.algorithm = "MD5"; | 329 // Credentials where found, prepare for retrying the request. |
| 321 cr.qop = header.parameters["qop"]; | 330 return retryWithCredentials(cr); |
| 322 cr.nonceCount = 0; | |
| 323 } | 331 } |
| 324 // Credentials where found, prepare for retrying the request. | |
| 325 return retryWithCredentials(cr); | |
| 326 } | 332 } |
| 327 } | 333 } |
| 328 | 334 |
| 329 // Ask for more credentials if none found or the one found has | 335 // Ask for more credentials if none found or the one found has |
| 330 // already been used. If it has already been used it must now be | 336 // already been used. If it has already been used it must now be |
| 331 // invalid and is removed. | 337 // invalid and is removed. |
| 332 if (cr != null) { | 338 if (cr != null) { |
| 333 _httpClient._removeCredentials(cr); | 339 _httpClient._removeCredentials(cr); |
| 334 cr = null; | 340 cr = null; |
| 335 } | 341 } |
| (...skipping 771 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1107 } | 1113 } |
| 1108 }, | 1114 }, |
| 1109 onDone: () { | 1115 onDone: () { |
| 1110 close(); | 1116 close(); |
| 1111 }); | 1117 }); |
| 1112 } | 1118 } |
| 1113 | 1119 |
| 1114 _HttpClientRequest send(Uri uri, int port, String method, _Proxy proxy) { | 1120 _HttpClientRequest send(Uri uri, int port, String method, _Proxy proxy) { |
| 1115 // Start with pausing the parser. | 1121 // Start with pausing the parser. |
| 1116 _subscription.pause(); | 1122 _subscription.pause(); |
| 1123 _Credentials cr; // Credentials used to authorize this request. |
| 1117 var outgoing = new _HttpOutgoing(_socket); | 1124 var outgoing = new _HttpOutgoing(_socket); |
| 1118 // Create new request object, wrapping the outgoing connection. | 1125 // Create new request object, wrapping the outgoing connection. |
| 1119 var request = new _HttpClientRequest(outgoing, | 1126 var request = new _HttpClientRequest(outgoing, |
| 1120 uri, | 1127 uri, |
| 1121 method, | 1128 method, |
| 1122 proxy, | 1129 proxy, |
| 1123 _httpClient, | 1130 _httpClient, |
| 1124 this); | 1131 this); |
| 1125 request.headers.host = uri.domain; | 1132 request.headers.host = uri.domain; |
| 1126 request.headers.port = port; | 1133 request.headers.port = port; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1138 } | 1145 } |
| 1139 } | 1146 } |
| 1140 if (uri.userInfo != null && !uri.userInfo.isEmpty) { | 1147 if (uri.userInfo != null && !uri.userInfo.isEmpty) { |
| 1141 // If the URL contains user information use that for basic | 1148 // If the URL contains user information use that for basic |
| 1142 // authorization. | 1149 // authorization. |
| 1143 String auth = | 1150 String auth = |
| 1144 CryptoUtils.bytesToBase64(_encodeString(uri.userInfo)); | 1151 CryptoUtils.bytesToBase64(_encodeString(uri.userInfo)); |
| 1145 request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth"); | 1152 request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth"); |
| 1146 } else { | 1153 } else { |
| 1147 // Look for credentials. | 1154 // Look for credentials. |
| 1148 _Credentials cr = _httpClient._findCredentials(uri); | 1155 cr = _httpClient._findCredentials(uri); |
| 1149 if (cr != null) { | 1156 if (cr != null) { |
| 1150 cr.authorize(request); | 1157 cr.authorize(request); |
| 1151 } | 1158 } |
| 1152 } | 1159 } |
| 1153 // Start sending the request (lazy, delayed until the user provides | 1160 // Start sending the request (lazy, delayed until the user provides |
| 1154 // data). | 1161 // data). |
| 1155 _httpParser.responseToMethod = method; | 1162 _httpParser.responseToMethod = method; |
| 1156 _streamFuture = outgoing.done | 1163 _streamFuture = outgoing.done |
| 1157 .then((s) { | 1164 .then((s) { |
| 1158 // Request sent, set up response completer. | 1165 // Request sent, set up response completer. |
| 1159 _nextResponseCompleter = new Completer(); | 1166 _nextResponseCompleter = new Completer(); |
| 1160 | 1167 |
| 1161 // Listen for response. | 1168 // Listen for response. |
| 1162 _nextResponseCompleter.future | 1169 _nextResponseCompleter.future |
| 1163 .then((incoming) { | 1170 .then((incoming) { |
| 1164 incoming.dataDone.then((_) { | 1171 incoming.dataDone.then((_) { |
| 1165 if (!_dispose && | 1172 if (!_dispose && |
| 1166 incoming.headers.persistentConnection && | 1173 incoming.headers.persistentConnection && |
| 1167 request.persistentConnection) { | 1174 request.persistentConnection) { |
| 1168 // Return connection, now we are done. | 1175 // Return connection, now we are done. |
| 1169 _httpClient._returnConnection(this); | 1176 _httpClient._returnConnection(this); |
| 1170 _subscription.resume(); | 1177 _subscription.resume(); |
| 1171 } else { | 1178 } else { |
| 1172 destroy(); | 1179 destroy(); |
| 1173 } | 1180 } |
| 1174 }); | 1181 }); |
| 1182 // For digest authentication check if the server |
| 1183 // requests the client to start using a new nonce. |
| 1184 if (cr != null && cr.scheme == _AuthenticationScheme.DIGEST) { |
| 1185 var authInfo = incoming.headers["authentication-info"]; |
| 1186 if (authInfo != null && authInfo.length == 1) { |
| 1187 var header = |
| 1188 new _HeaderValue.fromString( |
| 1189 authInfo[0], parameterSeparator: ','); |
| 1190 var nextnonce = header.parameters["nextnonce"]; |
| 1191 if (nextnonce != null) cr.nonce = nextnonce; |
| 1192 } |
| 1193 } |
| 1175 request._onIncoming(incoming); | 1194 request._onIncoming(incoming); |
| 1176 }) | 1195 }) |
| 1177 // If we see a state error, we failed to get the 'first' | 1196 // If we see a state error, we failed to get the 'first' |
| 1178 // element. | 1197 // element. |
| 1179 // Transform the error to a HttpParserException, for | 1198 // Transform the error to a HttpParserException, for |
| 1180 // consistency. | 1199 // consistency. |
| 1181 .catchError((error) { | 1200 .catchError((error) { |
| 1182 throw new HttpParserException( | 1201 throw new HttpParserException( |
| 1183 "Connection closed before data was received"); | 1202 "Connection closed before data was received"); |
| 1184 }, test: (error) => error is StateError) | 1203 }, test: (error) => error is StateError) |
| (...skipping 974 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2159 | 2178 |
| 2160 | 2179 |
| 2161 class _RedirectInfo implements RedirectInfo { | 2180 class _RedirectInfo implements RedirectInfo { |
| 2162 const _RedirectInfo(int this.statusCode, | 2181 const _RedirectInfo(int this.statusCode, |
| 2163 String this.method, | 2182 String this.method, |
| 2164 Uri this.location); | 2183 Uri this.location); |
| 2165 final int statusCode; | 2184 final int statusCode; |
| 2166 final String method; | 2185 final String method; |
| 2167 final Uri location; | 2186 final Uri location; |
| 2168 } | 2187 } |
| OLD | NEW |