summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ftp/ftp_network_transaction.cc8
-rw-r--r--net/ftp/ftp_network_transaction.h1
-rw-r--r--net/ftp/ftp_network_transaction_unittest.cc43
-rw-r--r--net/ftp/ftp_response_info.h9
-rw-r--r--net/url_request/url_request_new_ftp_job.cc6
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) {