diff options
-rw-r--r-- | net/ftp/ftp_network_transaction.cc | 8 | ||||
-rw-r--r-- | net/ftp/ftp_network_transaction.h | 1 | ||||
-rw-r--r-- | net/ftp/ftp_network_transaction_unittest.cc | 43 | ||||
-rw-r--r-- | net/ftp/ftp_response_info.h | 9 | ||||
-rw-r--r-- | net/url_request/url_request_new_ftp_job.cc | 6 |
5 files changed, 60 insertions, 7 deletions
diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc index 06c9c25..a463de8 100644 --- a/net/ftp/ftp_network_transaction.cc +++ b/net/ftp/ftp_network_transaction.cc @@ -59,7 +59,6 @@ FtpNetworkTransaction::FtpNetworkTransaction( read_ctrl_buf_(new IOBuffer(kCtrlBufLen)), ctrl_response_buffer_(new FtpCtrlResponseBuffer()), read_data_buf_len_(0), - file_data_len_(0), last_error_(OK), system_type_(SYSTEM_TYPE_UNKNOWN), retr_failed_(false), @@ -308,7 +307,6 @@ void FtpNetworkTransaction::ResetStateForRestart() { ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer()); read_data_buf_ = NULL; read_data_buf_len_ = 0; - file_data_len_ = 0; if (write_buf_) write_buf_->SetOffset(0); last_error_ = OK; @@ -889,10 +887,12 @@ int FtpNetworkTransaction::ProcessResponseSIZE( case ERROR_CLASS_OK: if (response.lines.size() != 1) return Stop(ERR_INVALID_RESPONSE); - if (!StringToInt(response.lines[0], &file_data_len_)) + int64 size; + if (!StringToInt64(response.lines[0], &size)) return Stop(ERR_INVALID_RESPONSE); - if (file_data_len_ < 0) + if (size < 0) return Stop(ERR_INVALID_RESPONSE); + response_.expected_content_size = size; break; case ERROR_CLASS_INFO_NEEDED: break; diff --git a/net/ftp/ftp_network_transaction.h b/net/ftp/ftp_network_transaction.h index e8140f4..e1dcef6 100644 --- a/net/ftp/ftp_network_transaction.h +++ b/net/ftp/ftp_network_transaction.h @@ -190,7 +190,6 @@ class FtpNetworkTransaction : public FtpTransaction { scoped_refptr<IOBuffer> read_data_buf_; int read_data_buf_len_; - int file_data_len_; // Buffer holding the command line to be written to the control socket. scoped_refptr<IOBufferWithSize> write_command_buf_; diff --git a/net/ftp/ftp_network_transaction_unittest.cc b/net/ftp/ftp_network_transaction_unittest.cc index e46e1ba..0c3e72c 100644 --- a/net/ftp/ftp_network_transaction_unittest.cc +++ b/net/ftp/ftp_network_transaction_unittest.cc @@ -499,7 +499,33 @@ class FtpSocketDataProviderEvilPasv : public FtpSocketDataProviderFileDownload { DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderEvilPasv); }; -class FtpSocketDataProviderEvilLogin : public FtpSocketDataProviderFileDownload { +class FtpSocketDataProviderEvilSize : public FtpSocketDataProviderFileDownload { + public: + FtpSocketDataProviderEvilSize(const char* size_response, State expected_state) + : size_response_(size_response), + expected_state_(expected_state) { + } + + virtual MockWriteResult OnWrite(const std::string& data) { + if (InjectFault()) + return MockWriteResult(true, data.length()); + switch (state()) { + case PRE_SIZE: + return Verify("SIZE /file\r\n", data, expected_state_, size_response_); + default: + return FtpSocketDataProviderFileDownload::OnWrite(data); + } + } + + private: + const char* size_response_; + const State expected_state_; + + DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderEvilSize); +}; + +class FtpSocketDataProviderEvilLogin + : public FtpSocketDataProviderFileDownload { public: FtpSocketDataProviderEvilLogin(const char* expected_user, const char* expected_password) @@ -594,6 +620,12 @@ class FtpNetworkTransactionTest : public PlatformTest { EXPECT_EQ(static_cast<int>(mock_data.length()), callback_.WaitForResult()); EXPECT_EQ(mock_data, std::string(io_buffer->data(), mock_data.length())); + if (transaction_.GetResponseInfo()->is_directory_listing) { + EXPECT_EQ(-1, transaction_.GetResponseInfo()->expected_content_size); + } else { + // We pass an artificial value of 18 as a response to the SIZE command. + EXPECT_EQ(18, transaction_.GetResponseInfo()->expected_content_size); + } } EXPECT_EQ(LOAD_STATE_IDLE, transaction_.GetLoadState()); } @@ -906,6 +938,15 @@ TEST_F(FtpNetworkTransactionTest, Escaping) { OK); } +// Test for http://crbug.com/23794. +TEST_F(FtpNetworkTransactionTest, DownloadTransactionEvilSize) { + // Try to overflow int64 in the response. + FtpSocketDataProviderEvilSize ctrl_socket( + "213 99999999999999999999999999999999\r\n", + FtpSocketDataProvider::PRE_QUIT); + ExecuteTransaction(&ctrl_socket, "ftp://host/file", ERR_INVALID_RESPONSE); +} + // Regression test for http://crbug.com/25023. TEST_F(FtpNetworkTransactionTest, CloseConnection) { FtpSocketDataProviderCloseConnection ctrl_socket; diff --git a/net/ftp/ftp_response_info.h b/net/ftp/ftp_response_info.h index 9c94064..daec6c2 100644 --- a/net/ftp/ftp_response_info.h +++ b/net/ftp/ftp_response_info.h @@ -11,7 +11,10 @@ namespace net { class FtpResponseInfo { public: - FtpResponseInfo() : needs_auth(false), is_directory_listing(false) { + FtpResponseInfo() + : needs_auth(false), + expected_content_size(-1), + is_directory_listing(false) { } // True if authentication failed and valid authentication credentials are @@ -26,6 +29,10 @@ class FtpResponseInfo { // responses, this time could be "far" in the past. base::Time response_time; + // Expected content size, in bytes, as reported by SIZE command. Only valid + // for file downloads. -1 means unknown size. + int64 expected_content_size; + // True if the response data is of a directory listing. bool is_directory_listing; }; diff --git a/net/url_request/url_request_new_ftp_job.cc b/net/url_request/url_request_new_ftp_job.cc index c4c3782..171eed9 100644 --- a/net/url_request/url_request_new_ftp_job.cc +++ b/net/url_request/url_request_new_ftp_job.cc @@ -146,6 +146,12 @@ void URLRequestNewFtpJob::OnStartCompleted(int result) { return; // Clear the IO_PENDING status SetStatus(URLRequestStatus()); + + // FTP obviously doesn't have HTTP Content-Length header. We have to pass + // the content size information manually. + set_expected_content_size( + transaction_->GetResponseInfo()->expected_content_size); + if (result == net::OK) { NotifyHeadersComplete(); } else if (transaction_->GetResponseInfo()->needs_auth) { |