Chromium Code Reviews| 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 176 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 response_info_ = http_transaction_->GetResponseInfo(); |
|
asanka
2013/04/02 17:11:48
Minor nit: something like http_response_info_ migh
Paweł Hajdan Jr.
2013/04/05 00:03:19
Done.
| |
| 238 | |
| 239 if (response_info_->headers->response_code() == 401 || | |
|
asanka
2013/04/02 17:11:48
Under which circumstances would you need to handle
Paweł Hajdan Jr.
2013/04/05 00:03:19
When FTP server requires auth, the proxy will issu
| |
| 240 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 (response_info_) { | |
| 319 *result = 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 |