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 |