Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(322)

Side by Side Diff: net/url_request/url_request_ftp_job.cc

Issue 12582012: Implement FTP auth through proxy (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: tests Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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();
238
239 if (response_info_->headers->response_code() == 401 ||
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 if (http_transaction_) {
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 ftp_auth_cache_->Add(request_->url().GetOrigin(),
340 auth_data_->credentials);
344 341
345 RestartTransactionWithAuth(); 342 RestartTransactionWithAuth();
346 } 343 }
347 344
348 void URLRequestFtpJob::CancelAuth() { 345 void URLRequestFtpJob::CancelAuth() {
349 DCHECK(ftp_transaction_); 346 DCHECK(ftp_transaction_ || http_transaction_);
350 DCHECK(NeedsAuth()); 347 DCHECK(NeedsAuth());
351 server_auth_->state = AUTH_STATE_CANCELED; 348
349 auth_data_->state = AUTH_STATE_CANCELED;
352 350
353 // Once the auth is cancelled, we proceed with the request as though 351 // 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 352 // 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. 353 // any recursing into the caller as a result of this call.
356 OnStartCompletedAsync(OK); 354 OnStartCompletedAsync(OK);
357 } 355 }
358 356
359 UploadProgress URLRequestFtpJob::GetUploadProgress() const { 357 UploadProgress URLRequestFtpJob::GetUploadProgress() const {
360 return UploadProgress(); 358 return UploadProgress();
361 } 359 }
(...skipping 23 matching lines...) Expand all
385 383
386 if (rv == ERR_IO_PENDING) { 384 if (rv == ERR_IO_PENDING) {
387 read_in_progress_ = true; 385 read_in_progress_ = true;
388 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); 386 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
389 } else { 387 } else {
390 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv)); 388 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
391 } 389 }
392 return false; 390 return false;
393 } 391 }
394 392
393 void URLRequestFtpJob::HandleAuthNeededResponse() {
394 GURL origin = request_->url().GetOrigin();
395
396 if (auth_data_) {
397 if (auth_data_->state == AUTH_STATE_CANCELED) {
398 NotifyHeadersComplete();
399 return;
400 }
401
402 if (auth_data_->state == AUTH_STATE_HAVE_AUTH)
403 ftp_auth_cache_->Remove(origin, auth_data_->credentials);
404 } else {
405 auth_data_ = new AuthData;
406 }
407 auth_data_->state = AUTH_STATE_NEED_AUTH;
408
409 FtpAuthCache::Entry* cached_auth = ftp_auth_cache_->Lookup(origin);
mmenke 2013/03/28 18:34:52 This seems wrong for proxy auth. Looks like if a
410 if (cached_auth) {
411 // Retry using cached auth data.
412 SetAuth(cached_auth->credentials);
413 } else {
414 // Prompt for a username/password.
415 NotifyHeadersComplete();
416 }
417 }
418
395 } // namespace net 419 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698