summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-05 02:14:16 +0000
committerwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-05 02:14:16 +0000
commit4c62d8c3a0ad1c141976135d7622516eb02e46c5 (patch)
tree70c80e26965149f7afeeeea97e94837df4744f3b /net
parentb170d9cd4f96b4c16880b2a188a1aa9b442b9aa6 (diff)
downloadchromium_src-4c62d8c3a0ad1c141976135d7622516eb02e46c5.zip
chromium_src-4c62d8c3a0ad1c141976135d7622516eb02e46c5.tar.gz
chromium_src-4c62d8c3a0ad1c141976135d7622516eb02e46c5.tar.bz2
Check in the fourth Portable FTP CL from Ibrar Ahmed
<ibrar.ahmad@gmail.com>. Now we can browse some ftp sites and can download files. There are some TODO yet to be fixed. Original review: http://codereview.chromium.org/115291 R=wtc BUG=http://crbug.com/4965 TEST=none Review URL: http://codereview.chromium.org/118274 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17703 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/ftp/ftp_directory_parser.cc5
-rw-r--r--net/ftp/ftp_directory_parser.h16
-rw-r--r--net/ftp/ftp_network_transaction.cc225
-rw-r--r--net/ftp/ftp_network_transaction.h11
-rw-r--r--net/url_request/url_request_new_ftp_job.cc129
-rw-r--r--net/url_request/url_request_new_ftp_job.h7
6 files changed, 285 insertions, 108 deletions
diff --git a/net/ftp/ftp_directory_parser.cc b/net/ftp/ftp_directory_parser.cc
index 7e3c86d..cb89e9f 100644
--- a/net/ftp/ftp_directory_parser.cc
+++ b/net/ftp/ftp_directory_parser.cc
@@ -84,7 +84,10 @@ LineType ParseFTPLine(const char *line,
return FTP_TYPE_JUNK;
memset(result, 0, sizeof(*result));
-
+ if (state->magic != ((void *)ParseFTPLine)) {
+ memset(state, 0, sizeof(*state));
+ state->magic = ((void *)ParseFTPLine);
+ }
state->numlines++;
// Carry buffer is only valid from one line to the next.
diff --git a/net/ftp/ftp_directory_parser.h b/net/ftp/ftp_directory_parser.h
index df0d540..83b1982 100644
--- a/net/ftp/ftp_directory_parser.h
+++ b/net/ftp/ftp_directory_parser.h
@@ -48,13 +48,14 @@
namespace net {
struct ListState {
- int64 now_time; // needed for year determination.
- struct tm now_tm; // needed for year determination.
- int lstyle; // LISTing style.
- int parsed_one; // returned anything yet?
- char carry_buf[84]; // for VMS multiline.
- unsigned int carry_buf_len; // length of name in carry_buf.
- unsigned int numlines; // number of lines seen.
+ void* magic; // to determine if previously initialized
+ int64 now_time; // needed for year determination.
+ struct tm now_tm; // needed for year determination.
+ int lstyle; // LISTing style.
+ int parsed_one; // returned anything yet?
+ char carry_buf[84]; // for VMS multiline.
+ unsigned int carry_buf_len; // length of name in carry_buf.
+ unsigned int numlines; // number of lines seen.
};
enum LineType {
@@ -73,6 +74,7 @@ struct ListResult {
unsigned int fe_lnlen; // length of symlink name
char fe_size[40]; // size of file in bytes (<= (2^128 - 1))
int fe_cinfs; // file system is definitely case insensitive
+ // TODO(ibrar): We should use "base::Time::Exploded" instead of "tm"
struct tm fe_time; // last-modified time
};
diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc
index d8e5a82..c314764 100644
--- a/net/ftp/ftp_network_transaction.cc
+++ b/net/ftp/ftp_network_transaction.cc
@@ -39,6 +39,8 @@ FtpNetworkTransaction::FtpNetworkTransaction(
read_data_buf_len_(0),
file_data_len_(0),
last_error_(OK),
+ is_anonymous_(false),
+ retr_failed_(false),
data_connection_port_(0),
socket_factory_(socket_factory),
next_state_(STATE_NONE) {
@@ -126,8 +128,8 @@ int FtpNetworkTransaction::SendFtpCommand(const std::string& command,
write_buf_ = new IOBuffer(buf_len + 2);
memcpy(write_buf_->data(), buf, buf_len);
memcpy(write_buf_->data() + buf_len, kCRLF, 2);
+ buf_len += 2;
- // TODO(ibrar): Handle the completion of Write and release write_buf_.
return ctrl_socket_->Write(write_buf_, buf_len, &io_callback_);
}
@@ -175,6 +177,9 @@ int FtpNetworkTransaction::ProcessResponse(int response_code) {
case COMMAND_LIST:
rv = ProcessResponseLIST(response_code);
break;
+ case COMMAND_MDTM:
+ rv = ProcessResponseMDTM(response_code);
+ break;
case COMMAND_QUIT:
rv = ProcessResponseQUIT(response_code);
break;
@@ -278,10 +283,19 @@ int FtpNetworkTransaction::DoLoop(int result) {
case STATE_CTRL_WRITE_LIST:
rv = DoCtrlWriteLIST();
break;
+ case STATE_CTRL_WRITE_MDTM:
+ rv = DoCtrlWriteMDTM();
+ break;
case STATE_CTRL_WRITE_QUIT:
rv = DoCtrlWriteQUIT();
break;
+ case STATE_DATA_RESOLVE_HOST:
+ rv = DoDataResolveHost();
+ break;
+ case STATE_DATA_RESOLVE_HOST_COMPLETE:
+ rv = DoDataResolveHostComplete(rv);
+ break;
case STATE_DATA_CONNECT:
DCHECK(rv == OK);
rv = DoDataConnect();
@@ -350,6 +364,9 @@ int FtpNetworkTransaction::DoCtrlConnectComplete(int result) {
}
int FtpNetworkTransaction::DoCtrlRead() {
+ if (write_buf_) // Clear the write buffer
+ write_buf_ = NULL;
+
next_state_ = STATE_CTRL_READ_COMPLETE;
read_ctrl_buf_->data()[0] = 0;
return ctrl_socket_->Read(read_ctrl_buf_, read_ctrl_buf_size_ - 1,
@@ -390,11 +407,13 @@ int FtpNetworkTransaction::DoCtrlReadComplete(int result) {
// USER Command.
int FtpNetworkTransaction::DoCtrlWriteUSER() {
- std::string command = "USER ";
+ std::string command = "USER";
if (request_->url.has_username()) {
+ command.append(" ");
command.append(request_->url.username());
} else {
- command.append("anonymous");
+ is_anonymous_ = true;
+ command.append(" anonymous");
}
next_state_ = STATE_CTRL_READ;
return SendFtpCommand(command, COMMAND_USER);
@@ -402,9 +421,8 @@ int FtpNetworkTransaction::DoCtrlWriteUSER() {
int FtpNetworkTransaction::ProcessResponseUSER(int response_code) {
switch (GetErrorClass(response_code)) {
- case ERROR_CLASS_INITIATED:
case ERROR_CLASS_OK:
- next_state_ = STATE_CTRL_WRITE_USER;
+ next_state_ = STATE_CTRL_WRITE_SYST;
break;
case ERROR_CLASS_PENDING:
next_state_ = STATE_CTRL_WRITE_PASS;
@@ -423,11 +441,13 @@ int FtpNetworkTransaction::ProcessResponseUSER(int response_code) {
// PASS command.
int FtpNetworkTransaction::DoCtrlWritePASS() {
- std::string command = "PASS ";
+ std::string command = "PASS";
if (request_->url.has_password()) {
+ command.append(" ");
command.append(request_->url.password());
} else {
- command.append("IEUser@");
+ command.append(" ");
+ command.append("chrome@example.com");
}
next_state_ = STATE_CTRL_READ;
return SendFtpCommand(command, COMMAND_PASS);
@@ -435,7 +455,6 @@ int FtpNetworkTransaction::DoCtrlWritePASS() {
int FtpNetworkTransaction::ProcessResponsePASS(int response_code) {
switch (GetErrorClass(response_code)) {
- case ERROR_CLASS_INITIATED:
case ERROR_CLASS_OK:
next_state_ = STATE_CTRL_WRITE_SYST;
break;
@@ -443,11 +462,15 @@ int FtpNetworkTransaction::ProcessResponsePASS(int response_code) {
next_state_ = STATE_CTRL_WRITE_ACCT;
break;
case ERROR_CLASS_ERROR_RETRY:
+ if (response_code == 421) {
+ // TODO(ibrar): Retry here.
+ }
return Stop(ERR_FAILED);
case ERROR_CLASS_ERROR:
if (response_code == 503) {
- next_state_ = STATE_CTRL_WRITE_PASS;
+ next_state_ = STATE_CTRL_WRITE_USER;
} else {
+ // TODO(ibrar): Retry here.
return Stop(ERR_FAILED);
}
break;
@@ -457,44 +480,35 @@ int FtpNetworkTransaction::ProcessResponsePASS(int response_code) {
return OK;
}
-// ACCT command.
-int FtpNetworkTransaction::DoCtrlWriteACCT() {
- std::string command = "ACCT noaccount";
+// SYST command.
+int FtpNetworkTransaction::DoCtrlWriteSYST() {
+ std::string command = "SYST";
next_state_ = STATE_CTRL_READ;
- return SendFtpCommand(command, COMMAND_ACCT);
+ return SendFtpCommand(command, COMMAND_SYST);
}
-int FtpNetworkTransaction::ProcessResponseACCT(int response_code) {
+int FtpNetworkTransaction::ProcessResponseSYST(int response_code) {
switch (GetErrorClass(response_code)) {
case ERROR_CLASS_INITIATED:
return Stop(ERR_FAILED);
case ERROR_CLASS_OK:
- next_state_ = STATE_CTRL_WRITE_SYST;
+ // TODO(ibrar): Process SYST response properly.
+ next_state_ = STATE_CTRL_WRITE_PWD;
break;
case ERROR_CLASS_PENDING:
return Stop(ERR_FAILED);
case ERROR_CLASS_ERROR_RETRY:
return Stop(ERR_FAILED);
case ERROR_CLASS_ERROR:
- return Stop(ERR_FAILED);
+ // Server does not recognize the SYST command so proceed.
+ next_state_ = STATE_CTRL_WRITE_PWD;
+ break;
default:
return Stop(ERR_FAILED);
}
return OK;
}
-// SYST command.
-int FtpNetworkTransaction::DoCtrlWriteSYST() {
- std::string command = "SYST";
- next_state_ = STATE_CTRL_READ;
- return SendFtpCommand(command, COMMAND_SYST);
-}
-
-int FtpNetworkTransaction::ProcessResponseSYST(int response_code) {
- next_state_ = STATE_CTRL_WRITE_PWD;
- return OK;
-}
-
// PWD command.
int FtpNetworkTransaction::DoCtrlWritePWD() {
std::string command = "PWD";
@@ -547,9 +561,35 @@ int FtpNetworkTransaction::ProcessResponseTYPE(int response_code) {
return OK;
}
+// ACCT command.
+int FtpNetworkTransaction::DoCtrlWriteACCT() {
+ std::string command = "ACCT noaccount";
+ next_state_ = STATE_CTRL_READ;
+ return SendFtpCommand(command, COMMAND_ACCT);
+}
+
+int FtpNetworkTransaction::ProcessResponseACCT(int response_code) {
+ switch (GetErrorClass(response_code)) {
+ case ERROR_CLASS_INITIATED:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_OK:
+ next_state_ = STATE_CTRL_WRITE_SYST;
+ break;
+ case ERROR_CLASS_PENDING:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_ERROR_RETRY:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_ERROR:
+ return Stop(ERR_FAILED);
+ default:
+ return Stop(ERR_FAILED);
+ }
+ return OK;
+}
+
// PASV command
int FtpNetworkTransaction::DoCtrlWritePASV() {
- std::string command = "PASV ";
+ std::string command = "PASV";
next_state_ = STATE_CTRL_READ;
return SendFtpCommand(command, COMMAND_PASV);
}
@@ -580,7 +620,7 @@ int FtpNetworkTransaction::ProcessResponsePASV(int response_code) {
&i0, &i1, &i2, &i3, &p0, &p1) == 6) {
data_connection_ip_ = StringPrintf("%d.%d.%d.%d", i0, i1, i2, i3);
data_connection_port_ = (p0 << 8) + p1;
- next_state_ = STATE_DATA_CONNECT;
+ next_state_ = STATE_DATA_RESOLVE_HOST;
} else {
return Stop(ERR_FAILED);
}
@@ -599,9 +639,11 @@ int FtpNetworkTransaction::ProcessResponsePASV(int response_code) {
// SIZE command
int FtpNetworkTransaction::DoCtrlWriteSIZE() {
- std::string command = "SIZE ";
- if (request_->url.has_path())
+ std::string command = "SIZE";
+ if (request_->url.has_path()) {
+ command.append(" ");
command.append(request_->url.path());
+ }
next_state_ = STATE_CTRL_READ;
return SendFtpCommand(command, COMMAND_SIZE);
}
@@ -609,33 +651,41 @@ int FtpNetworkTransaction::DoCtrlWriteSIZE() {
int FtpNetworkTransaction::ProcessResponseSIZE(int response_code) {
switch (GetErrorClass(response_code)) {
case ERROR_CLASS_INITIATED:
- next_state_ = STATE_CTRL_WRITE_LIST;
break;
case ERROR_CLASS_OK:
- next_state_ = STATE_CTRL_WRITE_RETR;
+ // Remove CR, CRLF from read_ctrl_buf_.
+ for (char* ptr = read_ctrl_buf_->data(); *ptr != '\0'; ptr++) {
+ if ((*ptr == '\r') || (*ptr == '\n')) {
+ // Stop if '\n' or '\r' detected.
+ *ptr = '\0';
+ break;
+ }
+ }
if (!StringToInt(read_ctrl_buf_->data() + 4, &file_data_len_))
return Stop(ERR_FAILED);
break;
case ERROR_CLASS_PENDING:
- next_state_ = STATE_CTRL_WRITE_LIST;
break;
case ERROR_CLASS_ERROR_RETRY:
- next_state_ = STATE_CTRL_WRITE_LIST;
break;
case ERROR_CLASS_ERROR:
- next_state_ = STATE_CTRL_WRITE_LIST;
break;
default:
return Stop(ERR_FAILED);
}
+ next_state_ = STATE_CTRL_WRITE_MDTM;
return OK;
}
// RETR command
int FtpNetworkTransaction::DoCtrlWriteRETR() {
- std::string command = "RETR ";
- if (request_->url.has_path())
+ std::string command = "RETR";
+ if (request_->url.has_path()) {
+ command.append(" ");
command.append(request_->url.path());
+ } else {
+ command.append(" /");
+ }
next_state_ = STATE_CTRL_READ;
return SendFtpCommand(command, COMMAND_RETR);
}
@@ -644,10 +694,10 @@ int FtpNetworkTransaction::ProcessResponseRETR(int response_code) {
switch (GetErrorClass(response_code)) {
case ERROR_CLASS_INITIATED:
next_state_ = STATE_CTRL_WRITE_QUIT;
- ctrl_socket_->Disconnect();
break;
case ERROR_CLASS_OK:
- break; // FTP Done
+ next_state_ = STATE_DATA_RESOLVE_HOST;
+ break;
case ERROR_CLASS_PENDING:
next_state_ = STATE_CTRL_WRITE_PASV;
break;
@@ -656,7 +706,41 @@ int FtpNetworkTransaction::ProcessResponseRETR(int response_code) {
return Stop(ERR_FAILED);
return ERR_FAILED; // TODO(ibrar): Retry here.
case ERROR_CLASS_ERROR:
- next_state_ = STATE_CTRL_WRITE_CWD;
+ retr_failed_ = true;
+ next_state_ = STATE_CTRL_WRITE_PASV;
+ break;
+ default:
+ return Stop(ERR_FAILED);
+ }
+ return OK;
+}
+
+// MDMT command
+int FtpNetworkTransaction::DoCtrlWriteMDTM() {
+ std::string command = "MDTM";
+ if (request_->url.has_path()) {
+ command.append(" ");
+ command.append(request_->url.path());
+ } else {
+ command.append(" /");
+ }
+ next_state_ = STATE_CTRL_READ;
+ return SendFtpCommand(command, COMMAND_MDTM);
+}
+
+int FtpNetworkTransaction::ProcessResponseMDTM(int response_code) {
+ switch (GetErrorClass(response_code)) {
+ case ERROR_CLASS_INITIATED:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_OK:
+ next_state_ = STATE_CTRL_WRITE_RETR;
+ break;
+ case ERROR_CLASS_PENDING:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_ERROR_RETRY:
+ return Stop(ERR_FAILED);
+ case ERROR_CLASS_ERROR:
+ next_state_ = STATE_CTRL_WRITE_RETR;
break;
default:
return Stop(ERR_FAILED);
@@ -664,9 +748,16 @@ int FtpNetworkTransaction::ProcessResponseRETR(int response_code) {
return OK;
}
+
// CWD command
int FtpNetworkTransaction::DoCtrlWriteCWD() {
std::string command = "CWD";
+ if (request_->url.has_path()) {
+ command.append(" ");
+ command.append(request_->url.path());
+ } else {
+ command.append(" /");
+ }
next_state_ = STATE_CTRL_READ;
return SendFtpCommand(command, COMMAND_CWD);
}
@@ -677,6 +768,7 @@ int FtpNetworkTransaction::ProcessResponseCWD(int response_code) {
return Stop(ERR_FAILED);
case ERROR_CLASS_OK:
next_state_ = STATE_CTRL_WRITE_LIST;
+ break;
case ERROR_CLASS_PENDING:
return Stop(ERR_FAILED);
case ERROR_CLASS_ERROR_RETRY:
@@ -691,9 +783,7 @@ int FtpNetworkTransaction::ProcessResponseCWD(int response_code) {
// LIST command
int FtpNetworkTransaction::DoCtrlWriteLIST() {
- std::string command = "LIST ";
- if (request_->url.has_path())
- command.append(request_->url.path());
+ std::string command = "LIST";
next_state_ = STATE_CTRL_READ;
return SendFtpCommand(command, COMMAND_LIST);
}
@@ -701,12 +791,12 @@ int FtpNetworkTransaction::DoCtrlWriteLIST() {
int FtpNetworkTransaction::ProcessResponseLIST(int response_code) {
switch (GetErrorClass(response_code)) {
case ERROR_CLASS_INITIATED:
- next_state_ = STATE_CTRL_WRITE_QUIT;
- response_.is_directory_listing = true;
+ response_message_buf_len_ = 0; // Clear the responce buffer.
+ next_state_ = STATE_CTRL_READ;
break;
case ERROR_CLASS_OK:
- next_state_ = STATE_CTRL_WRITE_QUIT;
response_.is_directory_listing = true;
+ next_state_ = STATE_CTRL_WRITE_QUIT;
break;
case ERROR_CLASS_PENDING:
return Stop(ERR_FAILED);
@@ -733,22 +823,41 @@ int FtpNetworkTransaction::ProcessResponseQUIT(int response_code) {
}
// Data Connection
+
+int FtpNetworkTransaction::DoDataResolveHost() {
+ next_state_ = STATE_DATA_RESOLVE_HOST_COMPLETE;
+
+ DidStartDnsResolution(data_connection_ip_, this);
+ return resolver_.Resolve(data_connection_ip_, data_connection_port_,
+ &addresses_, &io_callback_);
+}
+
+int FtpNetworkTransaction::DoDataResolveHostComplete(int result) {
+ bool ok = (result == OK);
+ DidFinishDnsResolutionWithStatus(ok, GURL(), this);
+ if (ok) {
+ next_state_ = STATE_DATA_CONNECT;
+ return result;
+ }
+ return ERR_FAILED;
+}
+
int FtpNetworkTransaction::DoDataConnect() {
+ if (data_socket_ != NULL && data_socket_->IsConnected())
+ data_socket_->Disconnect();
+
next_state_ = STATE_DATA_CONNECT_COMPLETE;
- AddressList adr;
- // TODO(ibrar): Call resolver_.Resolve in asynchronous mode, with a non-null
- // callback.
- int err = resolver_.Resolve(data_connection_ip_,
- data_connection_port_, &adr, NULL);
- if (err != OK)
- return err;
- data_socket_.reset(socket_factory_->CreateTCPClientSocket(adr));
+ data_socket_.reset(socket_factory_->CreateTCPClientSocket(addresses_));
return data_socket_->Connect(&io_callback_);
}
int FtpNetworkTransaction::DoDataConnectComplete(int result) {
- next_state_ = STATE_CTRL_WRITE_SIZE;
- return result;
+ if (retr_failed_) {
+ next_state_ = STATE_CTRL_WRITE_CWD;
+ } else {
+ next_state_ = STATE_CTRL_WRITE_SIZE;
+ }
+ return OK;
}
int FtpNetworkTransaction::DoDataRead() {
diff --git a/net/ftp/ftp_network_transaction.h b/net/ftp/ftp_network_transaction.h
index 67ddaeb..0bb67e5 100644
--- a/net/ftp/ftp_network_transaction.h
+++ b/net/ftp/ftp_network_transaction.h
@@ -53,6 +53,7 @@ class FtpNetworkTransaction : public FtpTransaction {
COMMAND_RETR,
COMMAND_CWD,
COMMAND_LIST,
+ COMMAND_MDTM,
COMMAND_QUIT
};
@@ -119,9 +120,13 @@ class FtpNetworkTransaction : public FtpTransaction {
int ProcessResponseCWD(int response_code);
int DoCtrlWriteLIST();
int ProcessResponseLIST(int response_code);
+ int DoCtrlWriteMDTM();
+ int ProcessResponseMDTM(int response_code);
int DoCtrlWriteQUIT();
int ProcessResponseQUIT(int response_code);
+ int DoDataResolveHost();
+ int DoDataResolveHostComplete(int result);
int DoDataConnect();
int DoDataConnectComplete(int result);
int DoDataRead();
@@ -155,6 +160,9 @@ class FtpNetworkTransaction : public FtpTransaction {
int last_error_;
+ bool is_anonymous_;
+ bool retr_failed_;
+
std::string data_connection_ip_;
int data_connection_port_;
@@ -184,8 +192,11 @@ class FtpNetworkTransaction : public FtpTransaction {
STATE_CTRL_WRITE_SIZE,
STATE_CTRL_WRITE_CWD,
STATE_CTRL_WRITE_LIST,
+ STATE_CTRL_WRITE_MDTM,
STATE_CTRL_WRITE_QUIT,
// Data connection states:
+ STATE_DATA_RESOLVE_HOST,
+ STATE_DATA_RESOLVE_HOST_COMPLETE,
STATE_DATA_CONNECT,
STATE_DATA_CONNECT_COMPLETE,
STATE_DATA_READ,
diff --git a/net/url_request/url_request_new_ftp_job.cc b/net/url_request/url_request_new_ftp_job.cc
index 257d1dc..d3a0c3e 100644
--- a/net/url_request/url_request_new_ftp_job.cc
+++ b/net/url_request/url_request_new_ftp_job.cc
@@ -20,6 +20,8 @@
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(
start_callback_(this, &URLRequestNewFtpJob::OnStartCompleted)),
ALLOW_THIS_IN_INITIALIZER_LIST(
@@ -88,51 +90,22 @@ bool URLRequestNewFtpJob::ReadRawData(net::IOBuffer* buf,
directory_html_.erase(0, bytes_to_copy);
return true;
}
+
int rv = transaction_->Read(buf, buf_size, &read_callback_);
- if (response_info_->is_directory_listing) {
- std::string file_entry;
- if (rv > 0) {
- std::string line;
- buf->data()[rv] = 0;
- std::istringstream iss(buf->data());
- while (getline(iss, line)) {
- struct net::ListState state;
- struct net::ListResult result;
- // TODO(ibrar): Use a more descriptive variable name than 'lt', which
- // looks like 'it'.
- net::LineType lt = ParseFTPLine(line.c_str(), &state, &result);
- switch (lt) {
- case net::FTP_TYPE_DIRECTORY:
- file_entry.append(net::GetDirectoryListingEntry(result.fe_fname,
- true,
- rv,
- base::Time()));
- break;
- case net::FTP_TYPE_FILE:
- file_entry.append(net::GetDirectoryListingEntry(result.fe_fname,
- false,
- rv,
- base::Time()));
- break;
- case net::FTP_TYPE_SYMLINK:
- case net::FTP_TYPE_JUNK:
- case net::FTP_TYPE_COMMENT:
- break;
- default:
- break;
- }
- }
- memcpy(buf->data(), file_entry.c_str(), file_entry.length());
- *bytes_read = file_entry.length();
- return true;
- }
- } else {
- rv = transaction_->Read(buf, buf_size, &read_callback_);
- }
if (rv >= 0) {
- *bytes_read = rv;
+ if (response_info_->is_directory_listing) {
+ *bytes_read = ProcessFtpDir(buf, buf_size, rv);
+ } else {
+ *bytes_read = rv;
+ }
return true;
}
+
+ if (response_info_->is_directory_listing) {
+ dir_listing_buf_ = buf;
+ dir_listing_buf_size_ = buf_size;
+ }
+
if (rv == net::ERR_IO_PENDING) {
read_in_progress_ = true;
SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
@@ -142,6 +115,75 @@ bool URLRequestNewFtpJob::ReadRawData(net::IOBuffer* buf,
return false;
}
+int URLRequestNewFtpJob::ProcessFtpDir(net::IOBuffer *buf,
+ int buf_size,
+ int bytes_read) {
+ std::string file_entry;
+ std::string line;
+ buf->data()[bytes_read] = 0;
+ int64 file_size;
+ std::istringstream iss(buf->data());
+ while (getline(iss, line)) {
+ struct net::ListState state;
+ struct net::ListResult result;
+ base::Time::Exploded et;
+ std::replace(line.begin(), line.end(), '\r', '\0');
+ net::LineType line_type = ParseFTPLine(line.c_str(), &state, &result);
+ switch (line_type) {
+ case net::FTP_TYPE_DIRECTORY:
+ // TODO(ibrar): There is some problem in ParseFTPLine function or
+ // in conversion between tm and base::Time::Exploded.
+ // It returns wrong date/time (Differnce is 1 day and 17 Hours).
+ memset(&et, 0, sizeof(base::Time::Exploded));
+ et.second = result.fe_time.tm_sec;
+ et.minute = result.fe_time.tm_min;
+ et.hour = result.fe_time.tm_hour;
+ et.day_of_month = result.fe_time.tm_mday;
+ et.month = result.fe_time.tm_mon + 1;
+ et.year = result.fe_time.tm_year + 1900;
+ et.day_of_week = result.fe_time.tm_wday;
+
+ file_entry.append(net::GetDirectoryListingEntry(
+ result.fe_fname, true, 0, base::Time::FromLocalExploded(et)));
+ break;
+ case net::FTP_TYPE_FILE:
+ // TODO(ibrar): There should be a way to create a Time object based
+ // on "tm" structure. This will remove bunch of line of code to convert
+ // tm to Time object.
+ memset(&et, 0, sizeof(base::Time::Exploded));
+ et.second = result.fe_time.tm_sec;
+ et.minute = result.fe_time.tm_min;
+ et.hour = result.fe_time.tm_hour;
+ et.day_of_month = result.fe_time.tm_mday;
+ et.month = result.fe_time.tm_mon + 1;
+ et.year = result.fe_time.tm_year + 1900;
+ et.day_of_week = result.fe_time.tm_wday;
+ // TODO(ibrar): There is some problem in ParseFTPLine function or
+ // in conversion between tm and base::Time::Exploded.
+ // It returns wrong date/time (Differnce is 1 day and 17 Hours).
+ if (StringToInt64(result.fe_size, &file_size))
+ file_entry.append(net::GetDirectoryListingEntry(
+ result.fe_fname, false, file_size,
+ base::Time::FromLocalExploded(et)));
+ break;
+ case net::FTP_TYPE_SYMLINK:
+ case net::FTP_TYPE_JUNK:
+ case net::FTP_TYPE_COMMENT:
+ break;
+ default:
+ break;
+ }
+ }
+ directory_html_.append(file_entry);
+ size_t bytes_to_copy = std::min(static_cast<size_t>(buf_size),
+ directory_html_.length());
+ if (bytes_to_copy) {
+ memcpy(buf->data(), directory_html_.c_str(), bytes_to_copy);
+ directory_html_.erase(0, bytes_to_copy);
+ }
+ return bytes_to_copy;
+}
+
void URLRequestNewFtpJob::OnStartCompleted(int result) {
// If the request was destroyed, then there is no more work to do.
if (!request_ || !request_->delegate())
@@ -166,6 +208,11 @@ void URLRequestNewFtpJob::OnReadCompleted(int result) {
} else if (result < 0) {
NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result));
} else {
+ // TODO(ibrar): find the best place to delete dir_listing_buf_
+ // Filter for Directory listing.
+ if (response_info_->is_directory_listing)
+ result = ProcessFtpDir(dir_listing_buf_, dir_listing_buf_size_, result);
+
// Clear the IO_PENDING status
SetStatus(URLRequestStatus());
}
diff --git a/net/url_request/url_request_new_ftp_job.h b/net/url_request/url_request_new_ftp_job.h
index 1a90a5e..a74a265 100644
--- a/net/url_request/url_request_new_ftp_job.h
+++ b/net/url_request/url_request_new_ftp_job.h
@@ -43,11 +43,16 @@ class URLRequestNewFtpJob : public URLRequestJob {
void OnStartCompleted(int result);
void OnReadCompleted(int result);
+ int ProcessFtpDir(net::IOBuffer *buf, int buf_size, int bytes_read);
+
+ net::AuthState server_auth_state_;
+
net::FtpRequestInfo request_info_;
scoped_ptr<net::FtpTransaction> transaction_;
const net::FtpResponseInfo* response_info_;
- net::AuthState server_auth_state_;
+ scoped_refptr<net::IOBuffer> dir_listing_buf_;
+ int dir_listing_buf_size_;
net::CompletionCallbackImpl<URLRequestNewFtpJob> start_callback_;
net::CompletionCallbackImpl<URLRequestNewFtpJob> read_callback_;