OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/url_request/url_request_ftp_job.h" | 5 #include "net/url_request/url_request_ftp_job.h" |
6 | 6 |
7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
9 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
10 #include "net/base/auth.h" | 10 #include "net/base/auth.h" |
(...skipping 12 matching lines...) Expand all Loading... |
23 namespace net { | 23 namespace net { |
24 | 24 |
25 URLRequestFtpJob::URLRequestFtpJob( | 25 URLRequestFtpJob::URLRequestFtpJob( |
26 URLRequest* request, | 26 URLRequest* request, |
27 NetworkDelegate* network_delegate, | 27 NetworkDelegate* network_delegate, |
28 FtpTransactionFactory* ftp_transaction_factory, | 28 FtpTransactionFactory* ftp_transaction_factory, |
29 FtpAuthCache* ftp_auth_cache) | 29 FtpAuthCache* ftp_auth_cache) |
30 : URLRequestJob(request, network_delegate), | 30 : URLRequestJob(request, network_delegate), |
31 priority_(DEFAULT_PRIORITY), | 31 priority_(DEFAULT_PRIORITY), |
32 pac_request_(NULL), | 32 pac_request_(NULL), |
33 response_info_(NULL), | 33 http_response_info_(NULL), |
34 read_in_progress_(false), | 34 read_in_progress_(false), |
35 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), | 35 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), |
36 ftp_transaction_factory_(ftp_transaction_factory), | 36 ftp_transaction_factory_(ftp_transaction_factory), |
37 ftp_auth_cache_(ftp_auth_cache) { | 37 ftp_auth_cache_(ftp_auth_cache) { |
38 DCHECK(ftp_transaction_factory); | 38 DCHECK(ftp_transaction_factory); |
39 DCHECK(ftp_auth_cache); | 39 DCHECK(ftp_auth_cache); |
40 } | 40 } |
41 | 41 |
42 URLRequestFtpJob::~URLRequestFtpJob() { | 42 URLRequestFtpJob::~URLRequestFtpJob() { |
43 if (pac_request_) | 43 if (pac_request_) |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 } else { | 78 } else { |
79 // No special handling of MIME type is needed. As opposed to direct FTP | 79 // No special handling of MIME type is needed. As opposed to direct FTP |
80 // transaction, we do not get a raw directory listing to parse. | 80 // transaction, we do not get a raw directory listing to parse. |
81 return http_transaction_->GetResponseInfo()-> | 81 return http_transaction_->GetResponseInfo()-> |
82 headers->GetMimeType(mime_type); | 82 headers->GetMimeType(mime_type); |
83 } | 83 } |
84 return false; | 84 return false; |
85 } | 85 } |
86 | 86 |
87 void URLRequestFtpJob::GetResponseInfo(HttpResponseInfo* info) { | 87 void URLRequestFtpJob::GetResponseInfo(HttpResponseInfo* info) { |
88 if (response_info_) | 88 if (http_response_info_) |
89 *info = *response_info_; | 89 *info = *http_response_info_; |
90 } | 90 } |
91 | 91 |
92 HostPortPair URLRequestFtpJob::GetSocketAddress() const { | 92 HostPortPair URLRequestFtpJob::GetSocketAddress() const { |
93 if (proxy_info_.is_direct()) { | 93 if (proxy_info_.is_direct()) { |
94 if (!ftp_transaction_) | 94 if (!ftp_transaction_) |
95 return HostPortPair(); | 95 return HostPortPair(); |
96 return ftp_transaction_->GetResponseInfo()->socket_address; | 96 return ftp_transaction_->GetResponseInfo()->socket_address; |
97 } else { | 97 } else { |
98 if (!http_transaction_) | 98 if (!http_transaction_) |
99 return HostPortPair(); | 99 return HostPortPair(); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 // The transaction started synchronously, but we need to notify the | 187 // The transaction started synchronously, but we need to notify the |
188 // URLRequest delegate via the message loop. | 188 // URLRequest delegate via the message loop. |
189 OnStartCompletedAsync(rv); | 189 OnStartCompletedAsync(rv); |
190 } | 190 } |
191 | 191 |
192 void URLRequestFtpJob::StartHttpTransaction() { | 192 void URLRequestFtpJob::StartHttpTransaction() { |
193 // Create a transaction. | 193 // Create a transaction. |
194 DCHECK(!http_transaction_); | 194 DCHECK(!http_transaction_); |
195 | 195 |
196 // Do not cache FTP responses sent through HTTP proxy. | 196 // Do not cache FTP responses sent through HTTP proxy. |
197 // Do not send HTTP auth data because this is really FTP. | |
198 request_->set_load_flags(request_->load_flags() | | 197 request_->set_load_flags(request_->load_flags() | |
199 LOAD_DISABLE_CACHE | | 198 LOAD_DISABLE_CACHE | |
200 LOAD_DO_NOT_SAVE_COOKIES | | 199 LOAD_DO_NOT_SAVE_COOKIES | |
201 LOAD_DO_NOT_SEND_AUTH_DATA | | |
202 LOAD_DO_NOT_SEND_COOKIES); | 200 LOAD_DO_NOT_SEND_COOKIES); |
203 | 201 |
204 http_request_info_.url = request_->url(); | 202 http_request_info_.url = request_->url(); |
205 http_request_info_.method = request_->method(); | 203 http_request_info_.method = request_->method(); |
206 http_request_info_.load_flags = request_->load_flags(); | 204 http_request_info_.load_flags = request_->load_flags(); |
207 http_request_info_.request_id = request_->identifier(); | 205 http_request_info_.request_id = request_->identifier(); |
208 | 206 |
209 int rv = request_->context()->http_transaction_factory()->CreateTransaction( | 207 int rv = request_->context()->http_transaction_factory()->CreateTransaction( |
210 priority_, &http_transaction_, NULL); | 208 priority_, &http_transaction_, NULL); |
211 if (rv == OK) { | 209 if (rv == OK) { |
(...skipping 16 matching lines...) Expand all Loading... |
228 | 226 |
229 // Note that ftp_transaction_ may be NULL due to a creation failure. | 227 // Note that ftp_transaction_ may be NULL due to a creation failure. |
230 if (ftp_transaction_) { | 228 if (ftp_transaction_) { |
231 // FTP obviously doesn't have HTTP Content-Length header. We have to pass | 229 // FTP obviously doesn't have HTTP Content-Length header. We have to pass |
232 // the content size information manually. | 230 // the content size information manually. |
233 set_expected_content_size( | 231 set_expected_content_size( |
234 ftp_transaction_->GetResponseInfo()->expected_content_size); | 232 ftp_transaction_->GetResponseInfo()->expected_content_size); |
235 } | 233 } |
236 | 234 |
237 if (result == OK) { | 235 if (result == OK) { |
238 if (http_transaction_) | 236 if (http_transaction_) { |
239 response_info_ = http_transaction_->GetResponseInfo(); | 237 http_response_info_ = http_transaction_->GetResponseInfo(); |
| 238 |
| 239 if (http_response_info_->headers->response_code() == 401 || |
| 240 http_response_info_->headers->response_code() == 407) { |
| 241 HandleAuthNeededResponse(); |
| 242 return; |
| 243 } |
| 244 } |
240 NotifyHeadersComplete(); | 245 NotifyHeadersComplete(); |
241 } else if (ftp_transaction_ && | 246 } else if (ftp_transaction_ && |
242 ftp_transaction_->GetResponseInfo()->needs_auth) { | 247 ftp_transaction_->GetResponseInfo()->needs_auth) { |
243 GURL origin = request_->url().GetOrigin(); | 248 HandleAuthNeededResponse(); |
244 if (server_auth_ && server_auth_->state == AUTH_STATE_HAVE_AUTH) { | 249 return; |
245 ftp_auth_cache_->Remove(origin, server_auth_->credentials); | |
246 } else if (!server_auth_) { | |
247 server_auth_ = new AuthData(); | |
248 } | |
249 server_auth_->state = AUTH_STATE_NEED_AUTH; | |
250 | |
251 FtpAuthCache::Entry* cached_auth = ftp_auth_cache_->Lookup(origin); | |
252 if (cached_auth) { | |
253 // Retry using cached auth data. | |
254 SetAuth(cached_auth->credentials); | |
255 } else { | |
256 // Prompt for a username/password. | |
257 NotifyHeadersComplete(); | |
258 } | |
259 } else { | 250 } else { |
260 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result)); | 251 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result)); |
261 } | 252 } |
262 } | 253 } |
263 | 254 |
264 void URLRequestFtpJob::OnStartCompletedAsync(int result) { | 255 void URLRequestFtpJob::OnStartCompletedAsync(int result) { |
265 MessageLoop::current()->PostTask( | 256 MessageLoop::current()->PostTask( |
266 FROM_HERE, | 257 FROM_HERE, |
267 base::Bind(&URLRequestFtpJob::OnStartCompleted, | 258 base::Bind(&URLRequestFtpJob::OnStartCompleted, |
268 weak_factory_.GetWeakPtr(), result)); | 259 weak_factory_.GetWeakPtr(), result)); |
269 } | 260 } |
270 | 261 |
271 void URLRequestFtpJob::OnReadCompleted(int result) { | 262 void URLRequestFtpJob::OnReadCompleted(int result) { |
272 read_in_progress_ = false; | 263 read_in_progress_ = false; |
273 if (result == 0) { | 264 if (result == 0) { |
274 NotifyDone(URLRequestStatus()); | 265 NotifyDone(URLRequestStatus()); |
275 } else if (result < 0) { | 266 } else if (result < 0) { |
276 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result)); | 267 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result)); |
277 } else { | 268 } else { |
278 // Clear the IO_PENDING status | 269 // Clear the IO_PENDING status |
279 SetStatus(URLRequestStatus()); | 270 SetStatus(URLRequestStatus()); |
280 } | 271 } |
281 NotifyReadComplete(result); | 272 NotifyReadComplete(result); |
282 } | 273 } |
283 | 274 |
284 void URLRequestFtpJob::RestartTransactionWithAuth() { | 275 void URLRequestFtpJob::RestartTransactionWithAuth() { |
285 DCHECK(ftp_transaction_); | 276 DCHECK(auth_data_ && auth_data_->state == AUTH_STATE_HAVE_AUTH); |
286 DCHECK(server_auth_ && server_auth_->state == AUTH_STATE_HAVE_AUTH); | |
287 | 277 |
288 // No matter what, we want to report our status as IO pending since we will | 278 // No matter what, we want to report our status as IO pending since we will |
289 // be notifying our consumer asynchronously via OnStartCompleted. | 279 // be notifying our consumer asynchronously via OnStartCompleted. |
290 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); | 280 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); |
291 | 281 |
292 int rv = ftp_transaction_->RestartWithAuth( | 282 int rv; |
293 server_auth_->credentials, | 283 if (proxy_info_.is_direct()) { |
294 base::Bind(&URLRequestFtpJob::OnStartCompleted, | 284 rv = ftp_transaction_->RestartWithAuth( |
295 base::Unretained(this))); | 285 auth_data_->credentials, |
| 286 base::Bind(&URLRequestFtpJob::OnStartCompleted, |
| 287 base::Unretained(this))); |
| 288 } else { |
| 289 rv = http_transaction_->RestartWithAuth( |
| 290 auth_data_->credentials, |
| 291 base::Bind(&URLRequestFtpJob::OnStartCompleted, |
| 292 base::Unretained(this))); |
| 293 } |
296 if (rv == ERR_IO_PENDING) | 294 if (rv == ERR_IO_PENDING) |
297 return; | 295 return; |
298 | 296 |
299 OnStartCompletedAsync(rv); | 297 OnStartCompletedAsync(rv); |
300 } | 298 } |
301 | 299 |
302 LoadState URLRequestFtpJob::GetLoadState() const { | 300 LoadState URLRequestFtpJob::GetLoadState() const { |
303 if (proxy_info_.is_direct()) { | 301 if (proxy_info_.is_direct()) { |
304 return ftp_transaction_ ? | 302 return ftp_transaction_ ? |
305 ftp_transaction_->GetLoadState() : LOAD_STATE_IDLE; | 303 ftp_transaction_->GetLoadState() : LOAD_STATE_IDLE; |
306 } else { | 304 } else { |
307 return http_transaction_ ? | 305 return http_transaction_ ? |
308 http_transaction_->GetLoadState() : LOAD_STATE_IDLE; | 306 http_transaction_->GetLoadState() : LOAD_STATE_IDLE; |
309 } | 307 } |
310 } | 308 } |
311 | 309 |
312 bool URLRequestFtpJob::NeedsAuth() { | 310 bool URLRequestFtpJob::NeedsAuth() { |
313 // TODO(phajdan.jr): Implement proxy auth, http://crbug.com/171497 . | 311 return auth_data_ && auth_data_->state == AUTH_STATE_NEED_AUTH; |
314 if (!ftp_transaction_) | |
315 return false; | |
316 | |
317 // Note that we only have to worry about cases where an actual FTP server | |
318 // requires auth (and not a proxy), because connecting to FTP via proxy | |
319 // effectively means the browser communicates via HTTP, and uses HTTP's | |
320 // Proxy-Authenticate protocol when proxy servers require auth. | |
321 return server_auth_ && server_auth_->state == AUTH_STATE_NEED_AUTH; | |
322 } | 312 } |
323 | 313 |
324 void URLRequestFtpJob::GetAuthChallengeInfo( | 314 void URLRequestFtpJob::GetAuthChallengeInfo( |
325 scoped_refptr<AuthChallengeInfo>* result) { | 315 scoped_refptr<AuthChallengeInfo>* result) { |
326 DCHECK((server_auth_ != NULL) && | 316 DCHECK(NeedsAuth()); |
327 (server_auth_->state == AUTH_STATE_NEED_AUTH)); | 317 |
| 318 if (http_response_info_) { |
| 319 *result = http_response_info_->auth_challenge; |
| 320 return; |
| 321 } |
| 322 |
328 scoped_refptr<AuthChallengeInfo> auth_info(new AuthChallengeInfo); | 323 scoped_refptr<AuthChallengeInfo> auth_info(new AuthChallengeInfo); |
329 auth_info->is_proxy = false; | 324 auth_info->is_proxy = false; |
330 auth_info->challenger = HostPortPair::FromURL(request_->url()); | 325 auth_info->challenger = HostPortPair::FromURL(request_->url()); |
331 // scheme and realm are kept empty. | 326 // scheme and realm are kept empty. |
332 DCHECK(auth_info->scheme.empty()); | 327 DCHECK(auth_info->scheme.empty()); |
333 DCHECK(auth_info->realm.empty()); | 328 DCHECK(auth_info->realm.empty()); |
334 result->swap(auth_info); | 329 result->swap(auth_info); |
335 } | 330 } |
336 | 331 |
337 void URLRequestFtpJob::SetAuth(const AuthCredentials& credentials) { | 332 void URLRequestFtpJob::SetAuth(const AuthCredentials& credentials) { |
338 DCHECK(ftp_transaction_); | 333 DCHECK(ftp_transaction_ || http_transaction_); |
339 DCHECK(NeedsAuth()); | 334 DCHECK(NeedsAuth()); |
340 server_auth_->state = AUTH_STATE_HAVE_AUTH; | |
341 server_auth_->credentials = credentials; | |
342 | 335 |
343 ftp_auth_cache_->Add(request_->url().GetOrigin(), server_auth_->credentials); | 336 auth_data_->state = AUTH_STATE_HAVE_AUTH; |
| 337 auth_data_->credentials = credentials; |
| 338 |
| 339 if (ftp_transaction_) { |
| 340 ftp_auth_cache_->Add(request_->url().GetOrigin(), |
| 341 auth_data_->credentials); |
| 342 } |
344 | 343 |
345 RestartTransactionWithAuth(); | 344 RestartTransactionWithAuth(); |
346 } | 345 } |
347 | 346 |
348 void URLRequestFtpJob::CancelAuth() { | 347 void URLRequestFtpJob::CancelAuth() { |
349 DCHECK(ftp_transaction_); | 348 DCHECK(ftp_transaction_ || http_transaction_); |
350 DCHECK(NeedsAuth()); | 349 DCHECK(NeedsAuth()); |
351 server_auth_->state = AUTH_STATE_CANCELED; | 350 |
| 351 auth_data_->state = AUTH_STATE_CANCELED; |
352 | 352 |
353 // Once the auth is cancelled, we proceed with the request as though | 353 // Once the auth is cancelled, we proceed with the request as though |
354 // there were no auth. Schedule this for later so that we don't cause | 354 // there were no auth. Schedule this for later so that we don't cause |
355 // any recursing into the caller as a result of this call. | 355 // any recursing into the caller as a result of this call. |
356 OnStartCompletedAsync(OK); | 356 OnStartCompletedAsync(OK); |
357 } | 357 } |
358 | 358 |
359 UploadProgress URLRequestFtpJob::GetUploadProgress() const { | 359 UploadProgress URLRequestFtpJob::GetUploadProgress() const { |
360 return UploadProgress(); | 360 return UploadProgress(); |
361 } | 361 } |
(...skipping 23 matching lines...) Expand all Loading... |
385 | 385 |
386 if (rv == ERR_IO_PENDING) { | 386 if (rv == ERR_IO_PENDING) { |
387 read_in_progress_ = true; | 387 read_in_progress_ = true; |
388 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); | 388 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); |
389 } else { | 389 } else { |
390 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv)); | 390 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv)); |
391 } | 391 } |
392 return false; | 392 return false; |
393 } | 393 } |
394 | 394 |
| 395 void URLRequestFtpJob::HandleAuthNeededResponse() { |
| 396 GURL origin = request_->url().GetOrigin(); |
| 397 |
| 398 if (auth_data_) { |
| 399 if (auth_data_->state == AUTH_STATE_CANCELED) { |
| 400 NotifyHeadersComplete(); |
| 401 return; |
| 402 } |
| 403 |
| 404 if (ftp_transaction_ && auth_data_->state == AUTH_STATE_HAVE_AUTH) |
| 405 ftp_auth_cache_->Remove(origin, auth_data_->credentials); |
| 406 } else { |
| 407 auth_data_ = new AuthData; |
| 408 } |
| 409 auth_data_->state = AUTH_STATE_NEED_AUTH; |
| 410 |
| 411 FtpAuthCache::Entry* cached_auth = NULL; |
| 412 if (ftp_transaction_ && ftp_transaction_->GetResponseInfo()->needs_auth) |
| 413 cached_auth = ftp_auth_cache_->Lookup(origin); |
| 414 if (cached_auth) { |
| 415 // Retry using cached auth data. |
| 416 SetAuth(cached_auth->credentials); |
| 417 } else { |
| 418 // Prompt for a username/password. |
| 419 NotifyHeadersComplete(); |
| 420 } |
| 421 } |
| 422 |
395 } // namespace net | 423 } // namespace net |
OLD | NEW |