summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-26 15:57:58 +0000
committerphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-26 15:57:58 +0000
commit8b8a197df55d54f6bde86858b7a820e12473f304 (patch)
treeaba47fac644c3ca721e4a489bfba616556c09a1a /net
parentbee16aabebd2b0415acb9680d2e1b90ce9c1fd60 (diff)
downloadchromium_src-8b8a197df55d54f6bde86858b7a820e12473f304.zip
chromium_src-8b8a197df55d54f6bde86858b7a820e12473f304.tar.gz
chromium_src-8b8a197df55d54f6bde86858b7a820e12473f304.tar.bz2
Implement RestartWithAuth for NewFtpTransaction.
TEST=Covered by net_unittests. http://crbug.com/20112 Review URL: http://codereview.chromium.org/173270 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@24449 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/ftp/ftp_network_transaction.cc72
-rw-r--r--net/ftp/ftp_network_transaction.h11
-rw-r--r--net/ftp/ftp_response_info.h9
-rw-r--r--net/ftp/ftp_transaction.h2
-rw-r--r--net/url_request/url_request_new_ftp_job.cc67
-rw-r--r--net/url_request/url_request_new_ftp_job.h12
-rw-r--r--net/url_request/url_request_unittest.cc60
7 files changed, 198 insertions, 35 deletions
diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc
index ef896b8..6b6b8c4 100644
--- a/net/ftp/ftp_network_transaction.cc
+++ b/net/ftp/ftp_network_transaction.cc
@@ -36,11 +36,11 @@ FtpNetworkTransaction::FtpNetworkTransaction(
request_(NULL),
resolver_(session->host_resolver()),
read_ctrl_buf_(new IOBuffer(kCtrlBufLen)),
+ ctrl_response_buffer_(new FtpCtrlResponseBuffer()),
read_data_buf_len_(0),
file_data_len_(0),
write_command_buf_written_(0),
last_error_(OK),
- is_anonymous_(false),
retr_failed_(false),
data_connection_port_(0),
socket_factory_(socket_factory),
@@ -56,6 +56,15 @@ int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info,
load_log_ = load_log;
request_ = request_info;
+ if (request_->url.has_username()) {
+ username_ = UTF8ToWide(request_->url.username());
+ if (request_->url.has_password())
+ password_ = UTF8ToWide(request_->url.password());
+ } else {
+ username_ = L"anonymous";
+ password_ = L"chrome@example.com";
+ }
+
next_state_ = STATE_CTRL_INIT;
int rv = DoLoop(OK);
if (rv == ERR_IO_PENDING)
@@ -75,7 +84,16 @@ int FtpNetworkTransaction::Stop(int error) {
int FtpNetworkTransaction::RestartWithAuth(const std::wstring& username,
const std::wstring& password,
CompletionCallback* callback) {
- return ERR_FAILED;
+ ResetStateForRestart();
+
+ username_ = username;
+ password_ = password;
+
+ next_state_ = STATE_CTRL_INIT;
+ int rv = DoLoop(OK);
+ if (rv == ERR_IO_PENDING)
+ user_callback_ = callback;
+ return rv;
}
int FtpNetworkTransaction::RestartIgnoringLastError(
@@ -134,7 +152,7 @@ int FtpNetworkTransaction::SendFtpCommand(const std::string& command,
// If we send a new command when we still have unprocessed responses
// for previous commands, the response receiving code will have no way to know
// which responses are for which command.
- DCHECK(!ctrl_response_buffer_.ResponseAvailable());
+ DCHECK(!ctrl_response_buffer_->ResponseAvailable());
DCHECK(!write_command_buf_);
DCHECK(!write_buf_);
@@ -176,7 +194,7 @@ FtpNetworkTransaction::ErrorClass FtpNetworkTransaction::GetErrorClass(
}
int FtpNetworkTransaction::ProcessCtrlResponse() {
- FtpCtrlResponse response = ctrl_response_buffer_.PopResponse();
+ FtpCtrlResponse response = ctrl_response_buffer_->PopResponse();
int rv = OK;
switch (command_sent_) {
@@ -230,8 +248,8 @@ int FtpNetworkTransaction::ProcessCtrlResponse() {
// We may get multiple responses for some commands,
// see http://crbug.com/18036.
- while (ctrl_response_buffer_.ResponseAvailable() && rv == OK) {
- response = ctrl_response_buffer_.PopResponse();
+ while (ctrl_response_buffer_->ResponseAvailable() && rv == OK) {
+ response = ctrl_response_buffer_->PopResponse();
switch (command_sent_) {
case COMMAND_RETR:
@@ -246,6 +264,24 @@ int FtpNetworkTransaction::ProcessCtrlResponse() {
return rv;
}
+void FtpNetworkTransaction::ResetStateForRestart() {
+ command_sent_ = COMMAND_NONE;
+ user_callback_ = NULL;
+ response_ = FtpResponseInfo();
+ read_ctrl_buf_ = new IOBuffer(kCtrlBufLen);
+ ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer());
+ read_data_buf_ = NULL;
+ read_data_buf_len_ = 0;
+ file_data_len_ = 0;
+ write_command_buf_written_ = 0;
+ last_error_ = OK;
+ retr_failed_ = false;
+ data_connection_port_ = 0;
+ ctrl_socket_.reset();
+ data_socket_.reset();
+ next_state_ = STATE_NONE;
+}
+
void FtpNetworkTransaction::DoCallback(int rv) {
DCHECK(rv != ERR_IO_PENDING);
DCHECK(user_callback_);
@@ -443,9 +479,9 @@ int FtpNetworkTransaction::DoCtrlReadComplete(int result) {
if (result < 0)
return Stop(result);
- ctrl_response_buffer_.ConsumeData(read_ctrl_buf_->data(), result);
+ ctrl_response_buffer_->ConsumeData(read_ctrl_buf_->data(), result);
- if (!ctrl_response_buffer_.ResponseAvailable()) {
+ if (!ctrl_response_buffer_->ResponseAvailable()) {
// Read more data from the control socket.
next_state_ = STATE_CTRL_READ;
return OK;
@@ -486,14 +522,7 @@ int FtpNetworkTransaction::DoCtrlWriteComplete(int result) {
// USER Command.
int FtpNetworkTransaction::DoCtrlWriteUSER() {
- std::string command = "USER";
- if (request_->url.has_username()) {
- command.append(" ");
- command.append(request_->url.username());
- } else {
- is_anonymous_ = true;
- command.append(" anonymous");
- }
+ std::string command = "USER " + WideToUTF8(username_);
next_state_ = STATE_CTRL_READ;
return SendFtpCommand(command, COMMAND_USER);
}
@@ -522,14 +551,7 @@ int FtpNetworkTransaction::ProcessResponseUSER(
// PASS command.
int FtpNetworkTransaction::DoCtrlWritePASS() {
- std::string command = "PASS";
- if (request_->url.has_password()) {
- command.append(" ");
- command.append(request_->url.password());
- } else {
- command.append(" ");
- command.append("chrome@example.com");
- }
+ std::string command = "PASS " + WideToUTF8(password_);
next_state_ = STATE_CTRL_READ;
return SendFtpCommand(command, COMMAND_PASS);
}
@@ -552,7 +574,7 @@ int FtpNetworkTransaction::ProcessResponsePASS(
if (response.status_code == 503) {
next_state_ = STATE_CTRL_WRITE_USER;
} else {
- // TODO(ibrar): Retry here.
+ response_.needs_auth = true;
return Stop(ERR_FAILED);
}
break;
diff --git a/net/ftp/ftp_network_transaction.h b/net/ftp/ftp_network_transaction.h
index 447d271..4dbf6f4 100644
--- a/net/ftp/ftp_network_transaction.h
+++ b/net/ftp/ftp_network_transaction.h
@@ -85,6 +85,9 @@ class FtpNetworkTransaction : public FtpTransaction {
ERROR_CLASS_PERMANENT_ERROR,
};
+ // Resets the members of the transaction so it can be restarted.
+ void ResetStateForRestart();
+
void DoCallback(int result);
void OnIOComplete(int result);
@@ -167,7 +170,7 @@ class FtpNetworkTransaction : public FtpTransaction {
// User buffer passed to the Read method for control socket.
scoped_refptr<IOBuffer> read_ctrl_buf_;
- FtpCtrlResponseBuffer ctrl_response_buffer_;
+ scoped_ptr<FtpCtrlResponseBuffer> ctrl_response_buffer_;
scoped_refptr<IOBuffer> read_data_buf_;
int read_data_buf_len_;
@@ -186,7 +189,11 @@ class FtpNetworkTransaction : public FtpTransaction {
int last_error_;
- bool is_anonymous_;
+ // We get username and password as wstrings in RestartWithAuth, so they are
+ // also kept as wstrings here.
+ std::wstring username_;
+ std::wstring password_;
+
bool retr_failed_;
std::string data_connection_ip_;
diff --git a/net/ftp/ftp_response_info.h b/net/ftp/ftp_response_info.h
index b3c3361..9c94064 100644
--- a/net/ftp/ftp_response_info.h
+++ b/net/ftp/ftp_response_info.h
@@ -5,17 +5,18 @@
#ifndef NET_FTP_FTP_RESPONSE_INFO_H_
#define NET_FTP_FTP_RESPONSE_INFO_H_
-#include "net/base/auth.h"
+#include "base/time.h"
namespace net {
class FtpResponseInfo {
public:
- FtpResponseInfo() : is_directory_listing(false) {
+ FtpResponseInfo() : needs_auth(false), is_directory_listing(false) {
}
- // Non-null when authentication is required.
- scoped_refptr<AuthChallengeInfo> auth_challenge;
+ // True if authentication failed and valid authentication credentials are
+ // needed.
+ bool needs_auth;
// The time at which the request was made that resulted in this response.
// For cached responses, this time could be "far" in the past.
diff --git a/net/ftp/ftp_transaction.h b/net/ftp/ftp_transaction.h
index 3d629746..da7f73e 100644
--- a/net/ftp/ftp_transaction.h
+++ b/net/ftp/ftp_transaction.h
@@ -11,8 +11,8 @@
namespace net {
-class FtpRequestInfo;
class FtpResponseInfo;
+class FtpRequestInfo;
class LoadLog;
// Represents a single FTP transaction.
diff --git a/net/url_request/url_request_new_ftp_job.cc b/net/url_request/url_request_new_ftp_job.cc
index f467357..16865a1 100644
--- a/net/url_request/url_request_new_ftp_job.cc
+++ b/net/url_request/url_request_new_ftp_job.cc
@@ -8,6 +8,7 @@
#include "base/file_version_info.h"
#include "base/message_loop.h"
#include "base/sys_string_conversions.h"
+#include "net/base/auth.h"
#include "net/base/escape.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
@@ -60,7 +61,6 @@ string16 RawByteSequenceToFilename(const char* raw_filename,
URLRequestNewFtpJob::URLRequestNewFtpJob(URLRequest* request)
: URLRequestJob(request),
- server_auth_state_(net::AUTH_STATE_DONT_NEED_AUTH),
response_info_(NULL),
dir_listing_buf_size_(0),
ALLOW_THIS_IN_INITIALIZER_LIST(
@@ -106,6 +106,48 @@ net::LoadState URLRequestNewFtpJob::GetLoadState() const {
transaction_->GetLoadState() : net::LOAD_STATE_IDLE;
}
+bool URLRequestNewFtpJob::NeedsAuth() {
+ // Note that we only have to worry about cases where an actual FTP server
+ // requires auth (and not a proxy), because connecting to FTP via proxy
+ // effectively means the browser communicates via HTTP, and uses HTTP's
+ // Proxy-Authenticate protocol when proxy servers require auth.
+ return server_auth_ && server_auth_->state == net::AUTH_STATE_NEED_AUTH;
+}
+
+void URLRequestNewFtpJob::GetAuthChallengeInfo(
+ scoped_refptr<net::AuthChallengeInfo>* result) {
+ DCHECK((server_auth_ != NULL) &&
+ (server_auth_->state == net::AUTH_STATE_NEED_AUTH));
+ scoped_refptr<net::AuthChallengeInfo> auth_info = new net::AuthChallengeInfo;
+ auth_info->is_proxy = false;
+ auth_info->host_and_port = ASCIIToWide(
+ net::GetHostAndPort(request_->url()));
+ auth_info->scheme = L"";
+ auth_info->realm = L"";
+ result->swap(auth_info);
+}
+
+void URLRequestNewFtpJob::SetAuth(const std::wstring& username,
+ const std::wstring& password) {
+ DCHECK(NeedsAuth());
+ server_auth_->state = net::AUTH_STATE_HAVE_AUTH;
+ server_auth_->username = username;
+ server_auth_->password = password;
+
+ RestartTransactionWithAuth();
+}
+
+void URLRequestNewFtpJob::CancelAuth() {
+ DCHECK(NeedsAuth());
+ server_auth_->state = net::AUTH_STATE_CANCELED;
+
+ // Once the auth is cancelled, we proceed with the request as though
+ // there were no auth. Schedule this for later so that we don't cause
+ // any recursing into the caller as a result of this call.
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &URLRequestNewFtpJob::OnStartCompleted, net::OK));
+}
+
bool URLRequestNewFtpJob::ReadRawData(net::IOBuffer* buf,
int buf_size,
int *bytes_read) {
@@ -250,6 +292,10 @@ void URLRequestNewFtpJob::OnStartCompleted(int result) {
SetStatus(URLRequestStatus());
if (result == net::OK) {
NotifyHeadersComplete();
+ } else if (transaction_->GetResponseInfo()->needs_auth) {
+ server_auth_ = new net::AuthData();
+ server_auth_->state = net::AUTH_STATE_NEED_AUTH;
+ NotifyHeadersComplete();
} else {
NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result));
}
@@ -273,6 +319,25 @@ void URLRequestNewFtpJob::OnReadCompleted(int result) {
NotifyReadComplete(result);
}
+void URLRequestNewFtpJob::RestartTransactionWithAuth() {
+ DCHECK(server_auth_ && server_auth_->state == net::AUTH_STATE_HAVE_AUTH);
+
+ response_info_ = NULL;
+
+ // No matter what, we want to report our status as IO pending since we will
+ // be notifying our consumer asynchronously via OnStartCompleted.
+ SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
+
+ int rv = transaction_->RestartWithAuth(server_auth_->username,
+ server_auth_->password,
+ &start_callback_);
+ if (rv == net::ERR_IO_PENDING)
+ return;
+
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &URLRequestNewFtpJob::OnStartCompleted, rv));
+}
+
void URLRequestNewFtpJob::StartTransaction() {
// Create a transaction.
DCHECK(!transaction_.get());
diff --git a/net/url_request/url_request_new_ftp_job.h b/net/url_request/url_request_new_ftp_job.h
index ebdb0e4..d7a9b25 100644
--- a/net/url_request/url_request_new_ftp_job.h
+++ b/net/url_request/url_request_new_ftp_job.h
@@ -31,6 +31,12 @@ class URLRequestNewFtpJob : public URLRequestJob {
virtual void Start();
virtual void Kill();
virtual net::LoadState GetLoadState() const;
+ virtual bool NeedsAuth();
+ virtual void GetAuthChallengeInfo(
+ scoped_refptr<net::AuthChallengeInfo>* auth_info);
+ virtual void SetAuth(const std::wstring& username,
+ const std::wstring& password);
+ virtual void CancelAuth();
// TODO(ibrar): Yet to give another look at this function.
virtual uint64 GetUploadProgress() const { return 0; }
@@ -42,9 +48,9 @@ class URLRequestNewFtpJob : public URLRequestJob {
void OnStartCompleted(int result);
void OnReadCompleted(int result);
- int ProcessFtpDir(net::IOBuffer *buf, int buf_size, int bytes_read);
+ void RestartTransactionWithAuth();
- net::AuthState server_auth_state_;
+ int ProcessFtpDir(net::IOBuffer *buf, int buf_size, int bytes_read);
net::FtpRequestInfo request_info_;
scoped_ptr<net::FtpTransaction> transaction_;
@@ -60,6 +66,8 @@ class URLRequestNewFtpJob : public URLRequestJob {
bool read_in_progress_;
std::string encoding_;
+ scoped_refptr<net::AuthData> server_auth_;
+
// Keep a reference to the url request context to be sure it's not deleted
// before us.
scoped_refptr<URLRequestContext> context_;
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index b224c2e..49f01a2 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -1972,6 +1972,36 @@ TEST_F(URLRequestTest, FTPCheckWrongPassword) {
}
}
+TEST_F(URLRequestTest, FTPCheckWrongPasswordRestart) {
+ // Pass wrong login credentials in the request URL.
+ scoped_refptr<FTPTestServer> server =
+ FTPTestServer::CreateServer(L"", "chrome", "wrong_password");
+ ASSERT_TRUE(NULL != server.get());
+ FilePath app_path;
+ PathService::Get(base::DIR_SOURCE_ROOT, &app_path);
+ app_path = app_path.AppendASCII("LICENSE");
+ TestDelegate d;
+ // Set correct login credentials. The delegate will be asked for them when
+ // the initial login with wrong credentials will fail.
+ d.set_username(L"chrome");
+ d.set_password(L"chrome");
+ {
+ TestURLRequest r(server->TestServerPage("/LICENSE"), &d);
+ r.Start();
+ EXPECT_TRUE(r.is_pending());
+
+ MessageLoop::current()->Run();
+
+ int64 file_size = 0;
+ file_util::GetFileSize(app_path, &file_size);
+
+ EXPECT_FALSE(r.is_pending());
+ EXPECT_EQ(1, d.response_started_count());
+ EXPECT_FALSE(d.received_data_before_response());
+ EXPECT_EQ(d.bytes_received(), static_cast<int>(file_size));
+ }
+}
+
TEST_F(URLRequestTest, FTPCheckWrongUser) {
scoped_refptr<FTPTestServer> server =
FTPTestServer::CreateServer(L"", "wrong_user", "chrome");
@@ -1996,3 +2026,33 @@ TEST_F(URLRequestTest, FTPCheckWrongUser) {
EXPECT_EQ(d.bytes_received(), 0);
}
}
+
+TEST_F(URLRequestTest, FTPCheckWrongUserRestart) {
+ // Pass wrong login credentials in the request URL.
+ scoped_refptr<FTPTestServer> server =
+ FTPTestServer::CreateServer(L"", "wrong_user", "chrome");
+ ASSERT_TRUE(NULL != server.get());
+ FilePath app_path;
+ PathService::Get(base::DIR_SOURCE_ROOT, &app_path);
+ app_path = app_path.AppendASCII("LICENSE");
+ TestDelegate d;
+ // Set correct login credentials. The delegate will be asked for them when
+ // the initial login with wrong credentials will fail.
+ d.set_username(L"chrome");
+ d.set_password(L"chrome");
+ {
+ TestURLRequest r(server->TestServerPage("/LICENSE"), &d);
+ r.Start();
+ EXPECT_TRUE(r.is_pending());
+
+ MessageLoop::current()->Run();
+
+ int64 file_size = 0;
+ file_util::GetFileSize(app_path, &file_size);
+
+ EXPECT_FALSE(r.is_pending());
+ EXPECT_EQ(1, d.response_started_count());
+ EXPECT_FALSE(d.received_data_before_response());
+ EXPECT_EQ(d.bytes_received(), static_cast<int>(file_size));
+ }
+}