diff options
author | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-05 02:14:16 +0000 |
---|---|---|
committer | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-05 02:14:16 +0000 |
commit | 4c62d8c3a0ad1c141976135d7622516eb02e46c5 (patch) | |
tree | 70c80e26965149f7afeeeea97e94837df4744f3b /net | |
parent | b170d9cd4f96b4c16880b2a188a1aa9b442b9aa6 (diff) | |
download | chromium_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.cc | 5 | ||||
-rw-r--r-- | net/ftp/ftp_directory_parser.h | 16 | ||||
-rw-r--r-- | net/ftp/ftp_network_transaction.cc | 225 | ||||
-rw-r--r-- | net/ftp/ftp_network_transaction.h | 11 | ||||
-rw-r--r-- | net/url_request/url_request_new_ftp_job.cc | 129 | ||||
-rw-r--r-- | net/url_request/url_request_new_ftp_job.h | 7 |
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_; |