diff options
-rw-r--r-- | net/base/io_buffer.cc | 2 | ||||
-rw-r--r-- | net/ftp/ftp_network_transaction.cc | 245 | ||||
-rw-r--r-- | net/ftp/ftp_network_transaction.h | 59 | ||||
-rw-r--r-- | net/ftp/ftp_network_transaction_unittest.cc | 101 |
4 files changed, 247 insertions, 160 deletions
diff --git a/net/base/io_buffer.cc b/net/base/io_buffer.cc index db2bffb..eb7094b 100644 --- a/net/base/io_buffer.cc +++ b/net/base/io_buffer.cc @@ -13,7 +13,7 @@ IOBuffer::IOBuffer(int buffer_size) { data_ = new char[buffer_size]; } void ReusedIOBuffer::SetOffset(int offset) { - DCHECK(offset > 0 && offset < size_); + DCHECK(offset >= 0 && offset < size_); data_ = base_->data() + offset; } diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc index 248b716..5b3ff67 100644 --- a/net/ftp/ftp_network_transaction.cc +++ b/net/ftp/ftp_network_transaction.cc @@ -34,8 +34,10 @@ FtpNetworkTransaction::FtpNetworkTransaction( session_(session), request_(NULL), resolver_(session->host_resolver()), - read_ctrl_buf_size_(kCtrlBufLen), + response_message_buf_(new IOBufferWithSize(kCtrlBufLen)), response_message_buf_len_(0), + read_ctrl_buf_(new ReusedIOBuffer(response_message_buf_, + response_message_buf_->size())), read_data_buf_len_(0), file_data_len_(0), last_error_(OK), @@ -44,8 +46,6 @@ FtpNetworkTransaction::FtpNetworkTransaction( data_connection_port_(0), socket_factory_(socket_factory), next_state_(STATE_NONE) { - read_ctrl_buf_ = new IOBuffer(kCtrlBufLen); - response_message_buf_ = new IOBuffer(kCtrlBufLen); } FtpNetworkTransaction::~FtpNetworkTransaction() { @@ -119,6 +119,56 @@ uint64 FtpNetworkTransaction::GetUploadProgress() const { return 0; } +int FtpNetworkTransaction::ParseCtrlResponse(int* cut_pos) { + enum { + CODE, // Three-digit status code. + TEXT, // The text after code, not including the space after code. + ENDLINE, // We expect a CRLF at end of each line. + } scan_state = CODE; + + *cut_pos = 0; // Index of first unparsed character. + + // Store parsed code and text for current line. + int status_code = 0; + std::string status_text; + + const char* data = response_message_buf_->data(); + for (int i = 0; i < response_message_buf_len_; i++) { + switch (scan_state) { + case CODE: + if (data[i] == ' ' || data[i] == '\t') { + if (status_code < 100 || status_code > 599) + return ERR_INVALID_RESPONSE; + scan_state = TEXT; + break; + } + if (data[i] < '0' || data[i] > '9') + return ERR_INVALID_RESPONSE; + status_code = 10 * status_code + (data[i] - '0'); + break; + case TEXT: + if (data[i] == '\r') { + scan_state = ENDLINE; + break; + } + status_text.push_back(data[i]); + break; + case ENDLINE: + if (data[i] != '\n') + return ERR_INVALID_RESPONSE; + ctrl_responses_.push(ResponseLine(status_code, status_text)); + *cut_pos = i + 1; + scan_state = CODE; + break; + default: + NOTREACHED(); + return ERR_UNEXPECTED; + } + } + + return OK; +} + // Used to prepare and send FTP commad. int FtpNetworkTransaction::SendFtpCommand(const std::string& command, Command cmd) { @@ -136,60 +186,72 @@ int FtpNetworkTransaction::SendFtpCommand(const std::string& command, return ctrl_socket_->Write(write_buf_, buf_len, &io_callback_); } -int FtpNetworkTransaction::GetRespnseCode() { - std::string str(response_message_buf_->data(), 3); - return StringToInt(str); -} - -int FtpNetworkTransaction::ProcessResponse(int response_code) { +int FtpNetworkTransaction::ProcessCtrlResponses() { int rv = OK; + if (command_sent_ == COMMAND_NONE) { + while (!ctrl_responses_.empty()) { + ResponseLine line = ctrl_responses_.front(); + ctrl_responses_.pop(); + if (GetErrorClass(line.code) != ERROR_CLASS_OK) + return Stop(ERR_FAILED); + } + next_state_ = STATE_CTRL_WRITE_USER; + return rv; + } + + // TODO(phajdan.jr): Correctly handle multiple code 230 response lines after + // PASS command. + if (ctrl_responses_.size() != 1) + return Stop(ERR_INVALID_RESPONSE); + + ResponseLine response_line = ctrl_responses_.front(); + ctrl_responses_.pop(); + switch (command_sent_) { - case COMMAND_NONE: - next_state_ = STATE_CTRL_WRITE_USER; - break; case COMMAND_USER: - rv = ProcessResponseUSER(response_code); + rv = ProcessResponseUSER(response_line); break; case COMMAND_PASS: - rv = ProcessResponsePASS(response_code); + rv = ProcessResponsePASS(response_line); break; case COMMAND_ACCT: - rv = ProcessResponseACCT(response_code); + rv = ProcessResponseACCT(response_line); break; case COMMAND_SYST: - rv = ProcessResponseSYST(response_code); + rv = ProcessResponseSYST(response_line); break; case COMMAND_PWD: - rv = ProcessResponsePWD(response_code); + rv = ProcessResponsePWD(response_line); break; case COMMAND_TYPE: - rv = ProcessResponseTYPE(response_code); + rv = ProcessResponseTYPE(response_line); break; case COMMAND_PASV: - rv = ProcessResponsePASV(response_code); + rv = ProcessResponsePASV(response_line); break; case COMMAND_SIZE: - rv = ProcessResponseSIZE(response_code); + rv = ProcessResponseSIZE(response_line); break; case COMMAND_RETR: - rv = ProcessResponseRETR(response_code); + rv = ProcessResponseRETR(response_line); break; case COMMAND_CWD: - rv = ProcessResponseCWD(response_code); + rv = ProcessResponseCWD(response_line); break; case COMMAND_LIST: - rv = ProcessResponseLIST(response_code); + rv = ProcessResponseLIST(response_line); break; case COMMAND_MDTM: - rv = ProcessResponseMDTM(response_code); + rv = ProcessResponseMDTM(response_line); break; case COMMAND_QUIT: - rv = ProcessResponseQUIT(response_code); + rv = ProcessResponseQUIT(response_line); break; default: DLOG(INFO) << "Missing Command response handling!"; return ERR_FAILED; } + DCHECK(ctrl_responses_.empty()); return rv; } @@ -380,38 +442,41 @@ int FtpNetworkTransaction::DoCtrlRead() { next_state_ = STATE_CTRL_READ_COMPLETE; read_ctrl_buf_->data()[0] = 0; - return ctrl_socket_->Read(read_ctrl_buf_, read_ctrl_buf_size_ - 1, - &io_callback_); + return ctrl_socket_->Read( + read_ctrl_buf_, + response_message_buf_->size() - response_message_buf_len_, + &io_callback_); } int FtpNetworkTransaction::DoCtrlReadComplete(int result) { if (result < 0) return Stop(ERR_FAILED); - int response_code; - // Null termination added, now we can treat this as string. - read_ctrl_buf_->data()[result] = 0; - memcpy(response_message_buf_->data() + response_message_buf_len_, - read_ctrl_buf_->data(), result); - response_message_buf_len_ = response_message_buf_len_ + result; - for (int i = 0; i < response_message_buf_len_; i++) { - if (response_message_buf_->data()[i] == '\r' && - response_message_buf_->data()[i + 1] == '\n') { - if (response_message_buf_len_ > 3 && - response_message_buf_->data()[3] == ' ') { - response_message_buf_->data()[response_message_buf_len_ - 2] = 0; - response_code = GetRespnseCode(); - return ProcessResponse(response_code); - } - response_message_buf_len_ -= (i + 2); - memcpy(response_message_buf_->data(), - response_message_buf_->data() + i + 2, - response_message_buf_len_); - i = 0; - } + response_message_buf_len_ += result; + + int cut_pos; + int rv = ParseCtrlResponse(&cut_pos); + + if (rv != OK) + return Stop(rv); + + if (cut_pos > 0) { + // Parsed at least one response line. + DCHECK_GE(response_message_buf_len_, cut_pos); + memmove(response_message_buf_->data(), + response_message_buf_->data() + cut_pos, + response_message_buf_len_ - cut_pos); + response_message_buf_len_ -= cut_pos; + + rv = ProcessCtrlResponses(); + } else { + // Incomplete response line. Read more. + next_state_ = STATE_CTRL_READ; } - next_state_ = STATE_CTRL_READ; - return OK; + + read_ctrl_buf_->SetOffset(response_message_buf_len_); + + return rv; } // FTP Commands and responses @@ -430,8 +495,8 @@ int FtpNetworkTransaction::DoCtrlWriteUSER() { return SendFtpCommand(command, COMMAND_USER); } -int FtpNetworkTransaction::ProcessResponseUSER(int response_code) { - switch (GetErrorClass(response_code)) { +int FtpNetworkTransaction::ProcessResponseUSER(const ResponseLine& response) { + switch (GetErrorClass(response.code)) { case ERROR_CLASS_OK: next_state_ = STATE_CTRL_WRITE_SYST; break; @@ -439,7 +504,7 @@ int FtpNetworkTransaction::ProcessResponseUSER(int response_code) { next_state_ = STATE_CTRL_WRITE_PASS; break; case ERROR_CLASS_ERROR_RETRY: - if (response_code == 421) + if (response.code == 421) return Stop(ERR_FAILED); break; case ERROR_CLASS_ERROR: @@ -464,8 +529,8 @@ int FtpNetworkTransaction::DoCtrlWritePASS() { return SendFtpCommand(command, COMMAND_PASS); } -int FtpNetworkTransaction::ProcessResponsePASS(int response_code) { - switch (GetErrorClass(response_code)) { +int FtpNetworkTransaction::ProcessResponsePASS(const ResponseLine& response) { + switch (GetErrorClass(response.code)) { case ERROR_CLASS_OK: next_state_ = STATE_CTRL_WRITE_SYST; break; @@ -473,12 +538,12 @@ int FtpNetworkTransaction::ProcessResponsePASS(int response_code) { next_state_ = STATE_CTRL_WRITE_ACCT; break; case ERROR_CLASS_ERROR_RETRY: - if (response_code == 421) { + if (response.code == 421) { // TODO(ibrar): Retry here. } return Stop(ERR_FAILED); case ERROR_CLASS_ERROR: - if (response_code == 503) { + if (response.code == 503) { next_state_ = STATE_CTRL_WRITE_USER; } else { // TODO(ibrar): Retry here. @@ -498,8 +563,8 @@ int FtpNetworkTransaction::DoCtrlWriteSYST() { return SendFtpCommand(command, COMMAND_SYST); } -int FtpNetworkTransaction::ProcessResponseSYST(int response_code) { - switch (GetErrorClass(response_code)) { +int FtpNetworkTransaction::ProcessResponseSYST(const ResponseLine& response) { + switch (GetErrorClass(response.code)) { case ERROR_CLASS_INITIATED: return Stop(ERR_FAILED); case ERROR_CLASS_OK: @@ -527,8 +592,8 @@ int FtpNetworkTransaction::DoCtrlWritePWD() { return SendFtpCommand(command, COMMAND_PWD); } -int FtpNetworkTransaction::ProcessResponsePWD(int response_code) { - switch (GetErrorClass(response_code)) { +int FtpNetworkTransaction::ProcessResponsePWD(const ResponseLine& response) { + switch (GetErrorClass(response.code)) { case ERROR_CLASS_INITIATED: return Stop(ERR_FAILED); case ERROR_CLASS_OK: @@ -553,8 +618,8 @@ int FtpNetworkTransaction::DoCtrlWriteTYPE() { return SendFtpCommand(command, COMMAND_TYPE); } -int FtpNetworkTransaction::ProcessResponseTYPE(int response_code) { - switch (GetErrorClass(response_code)) { +int FtpNetworkTransaction::ProcessResponseTYPE(const ResponseLine& response) { + switch (GetErrorClass(response.code)) { case ERROR_CLASS_INITIATED: return Stop(ERR_FAILED); case ERROR_CLASS_OK: @@ -579,8 +644,8 @@ int FtpNetworkTransaction::DoCtrlWriteACCT() { return SendFtpCommand(command, COMMAND_ACCT); } -int FtpNetworkTransaction::ProcessResponseACCT(int response_code) { - switch (GetErrorClass(response_code)) { +int FtpNetworkTransaction::ProcessResponseACCT(const ResponseLine& response) { + switch (GetErrorClass(response.code)) { case ERROR_CLASS_INITIATED: return Stop(ERR_FAILED); case ERROR_CLASS_OK: @@ -608,20 +673,20 @@ int FtpNetworkTransaction::DoCtrlWritePASV() { // There are two way we can receive IP address and port. // (127,0,0,1,23,21) IP address and port encapsulate in (). // 127,0,0,1,23,21 IP address and port without (). -int FtpNetworkTransaction::ProcessResponsePASV(int response_code) { - switch (GetErrorClass(response_code)) { +int FtpNetworkTransaction::ProcessResponsePASV(const ResponseLine& response) { + switch (GetErrorClass(response.code)) { case ERROR_CLASS_INITIATED: return Stop(ERR_FAILED); case ERROR_CLASS_OK: - char* ptr; + const char* ptr; int i0, i1, i2, i3, p0, p1; - ptr = read_ctrl_buf_->data(); // Try with bracket. + ptr = response.text.c_str(); // Try with bracket. while (*ptr && *ptr != '(') ++ptr; if (*ptr) { ++ptr; } else { - ptr = read_ctrl_buf_->data(); // Try without bracket. + ptr = response.text.c_str(); // Try without bracket. while (*ptr && *ptr != ',') ++ptr; while (*ptr && *ptr != ' ') @@ -659,21 +724,15 @@ int FtpNetworkTransaction::DoCtrlWriteSIZE() { return SendFtpCommand(command, COMMAND_SIZE); } -int FtpNetworkTransaction::ProcessResponseSIZE(int response_code) { - switch (GetErrorClass(response_code)) { +int FtpNetworkTransaction::ProcessResponseSIZE(const ResponseLine& response) { + switch (GetErrorClass(response.code)) { case ERROR_CLASS_INITIATED: break; case ERROR_CLASS_OK: - // 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); + if (!StringToInt(response.text, &file_data_len_)) + return Stop(ERR_INVALID_RESPONSE); + if (file_data_len_ < 0) + return Stop(ERR_INVALID_RESPONSE); break; case ERROR_CLASS_PENDING: break; @@ -701,8 +760,8 @@ int FtpNetworkTransaction::DoCtrlWriteRETR() { return SendFtpCommand(command, COMMAND_RETR); } -int FtpNetworkTransaction::ProcessResponseRETR(int response_code) { - switch (GetErrorClass(response_code)) { +int FtpNetworkTransaction::ProcessResponseRETR(const ResponseLine& response) { + switch (GetErrorClass(response.code)) { case ERROR_CLASS_INITIATED: break; case ERROR_CLASS_OK: @@ -712,7 +771,7 @@ int FtpNetworkTransaction::ProcessResponseRETR(int response_code) { next_state_ = STATE_CTRL_WRITE_PASV; break; case ERROR_CLASS_ERROR_RETRY: - if (response_code == 421 || response_code == 425 || response_code == 426) + if (response.code == 421 || response.code == 425 || response.code == 426) return Stop(ERR_FAILED); return ERR_FAILED; // TODO(ibrar): Retry here. case ERROR_CLASS_ERROR: @@ -740,8 +799,8 @@ int FtpNetworkTransaction::DoCtrlWriteMDTM() { return SendFtpCommand(command, COMMAND_MDTM); } -int FtpNetworkTransaction::ProcessResponseMDTM(int response_code) { - switch (GetErrorClass(response_code)) { +int FtpNetworkTransaction::ProcessResponseMDTM(const ResponseLine& response) { + switch (GetErrorClass(response.code)) { case ERROR_CLASS_INITIATED: return Stop(ERR_FAILED); case ERROR_CLASS_OK: @@ -774,8 +833,8 @@ int FtpNetworkTransaction::DoCtrlWriteCWD() { return SendFtpCommand(command, COMMAND_CWD); } -int FtpNetworkTransaction::ProcessResponseCWD(int response_code) { - switch (GetErrorClass(response_code)) { +int FtpNetworkTransaction::ProcessResponseCWD(const ResponseLine& response) { + switch (GetErrorClass(response.code)) { case ERROR_CLASS_INITIATED: return Stop(ERR_FAILED); case ERROR_CLASS_OK: @@ -800,10 +859,10 @@ int FtpNetworkTransaction::DoCtrlWriteLIST() { return SendFtpCommand(command, COMMAND_LIST); } -int FtpNetworkTransaction::ProcessResponseLIST(int response_code) { - switch (GetErrorClass(response_code)) { +int FtpNetworkTransaction::ProcessResponseLIST(const ResponseLine& response) { + switch (GetErrorClass(response.code)) { case ERROR_CLASS_INITIATED: - response_message_buf_len_ = 0; // Clear the responce buffer. + response_message_buf_len_ = 0; // Clear the response buffer. next_state_ = STATE_CTRL_READ; break; case ERROR_CLASS_OK: @@ -829,7 +888,7 @@ int FtpNetworkTransaction::DoCtrlWriteQUIT() { return SendFtpCommand(command, COMMAND_QUIT); } -int FtpNetworkTransaction::ProcessResponseQUIT(int response_code) { +int FtpNetworkTransaction::ProcessResponseQUIT(const ResponseLine& response) { ctrl_socket_->Disconnect(); return last_error_; } diff --git a/net/ftp/ftp_network_transaction.h b/net/ftp/ftp_network_transaction.h index 53f0b29..90c53e4 100644 --- a/net/ftp/ftp_network_transaction.h +++ b/net/ftp/ftp_network_transaction.h @@ -6,6 +6,8 @@ #define NET_FTP_FTP_NETWORK_TRANSACTION_H_ #include <string> +#include <queue> +#include <utility> #include "base/ref_counted.h" #include "base/scoped_ptr.h" @@ -70,11 +72,24 @@ class FtpNetworkTransaction : public FtpTransaction { // the requested action did not take place. }; + struct ResponseLine { + ResponseLine(int code, const std::string& text) : code(code), text(text) { + } + + int code; // Three-digit status code. + std::string text; // Text after the code, without ending CRLF. + }; + void DoCallback(int result); void OnIOComplete(int result); - int GetRespnseCode(); - int ProcessResponse(int response_code); - int ParsePasvResponse(); + + // Executes correct ProcessResponse + command_name function based on last + // issued command. Returns error code. + int ProcessCtrlResponses(); + + // Parses as much as possible from response_message_buf_. Puts index of the + // first unparsed character in cut_pos. Returns error code. + int ParseCtrlResponse(int* cut_pos); int SendFtpCommand(const std::string& command, Command cmd); @@ -99,31 +114,31 @@ class FtpNetworkTransaction : public FtpTransaction { int DoCtrlRead(); int DoCtrlReadComplete(int result); int DoCtrlWriteUSER(); - int ProcessResponseUSER(int response_code); + int ProcessResponseUSER(const ResponseLine& response); int DoCtrlWritePASS(); - int ProcessResponsePASS(int response_code); + int ProcessResponsePASS(const ResponseLine& response); int DoCtrlWriteACCT(); - int ProcessResponseACCT(int response_code); + int ProcessResponseACCT(const ResponseLine& response); int DoCtrlWriteSYST(); - int ProcessResponseSYST(int response_code); + int ProcessResponseSYST(const ResponseLine& response); int DoCtrlWritePWD(); - int ProcessResponsePWD(int response_code); + int ProcessResponsePWD(const ResponseLine& response); int DoCtrlWriteTYPE(); - int ProcessResponseTYPE(int response_code); + int ProcessResponseTYPE(const ResponseLine& response); int DoCtrlWritePASV(); - int ProcessResponsePASV(int response_code); + int ProcessResponsePASV(const ResponseLine& response); int DoCtrlWriteRETR(); - int ProcessResponseRETR(int response_code); + int ProcessResponseRETR(const ResponseLine& response); int DoCtrlWriteSIZE(); - int ProcessResponseSIZE(int response_code); + int ProcessResponseSIZE(const ResponseLine& response); int DoCtrlWriteCWD(); - int ProcessResponseCWD(int response_code); + int ProcessResponseCWD(const ResponseLine& response); int DoCtrlWriteLIST(); - int ProcessResponseLIST(int response_code); + int ProcessResponseLIST(const ResponseLine& response); int DoCtrlWriteMDTM(); - int ProcessResponseMDTM(int response_code); + int ProcessResponseMDTM(const ResponseLine& response); int DoCtrlWriteQUIT(); - int ProcessResponseQUIT(int response_code); + int ProcessResponseQUIT(const ResponseLine& response); int DoDataResolveHost(); int DoDataResolveHostComplete(int result); @@ -146,13 +161,17 @@ class FtpNetworkTransaction : public FtpTransaction { SingleRequestHostResolver resolver_; AddressList addresses_; - // User buffer and length passed to the Read method. - scoped_refptr<IOBuffer> read_ctrl_buf_; - int read_ctrl_buf_size_; + // As we read full response lines, we parse them and add to the queue. + std::queue<ResponseLine> ctrl_responses_; - scoped_refptr<IOBuffer> response_message_buf_; + // Buffer holding not-yet-parsed control socket responses. + scoped_refptr<IOBufferWithSize> response_message_buf_; int response_message_buf_len_; + // User buffer passed to the Read method. It actually writes to the + // response_message_buf_ at correct offset. + scoped_refptr<ReusedIOBuffer> read_ctrl_buf_; + scoped_refptr<IOBuffer> read_data_buf_; int read_data_buf_len_; int file_data_len_; diff --git a/net/ftp/ftp_network_transaction_unittest.cc b/net/ftp/ftp_network_transaction_unittest.cc index d381b0b..51cf77b 100644 --- a/net/ftp/ftp_network_transaction_unittest.cc +++ b/net/ftp/ftp_network_transaction_unittest.cc @@ -235,15 +235,16 @@ class FtpNetworkTransactionTest : public PlatformTest { return info; } - void TransactionFailHelper(FtpMockControlSocket* ctrl_socket, - const char* request, - FtpMockControlSocket::State state, - FtpMockControlSocket::State next_state, - const char* response, - int expected_result) { - ctrl_socket->InjectFailure(state, next_state, response); - StaticMockSocket data_socket1; - StaticMockSocket data_socket2; + void ExecuteTransaction(FtpMockControlSocket* ctrl_socket, + const char* request, + int expected_result) { + std::string mock_data("mock-data"); + MockRead data_reads[] = { + MockRead(mock_data.c_str()), + }; + // TODO(phajdan.jr): FTP transaction should not open two data sockets. + StaticMockSocket data_socket1(data_reads, NULL); + StaticMockSocket data_socket2(data_reads, NULL); mock_socket_factory_.AddMockSocket(ctrl_socket); mock_socket_factory_.AddMockSocket(&data_socket1); mock_socket_factory_.AddMockSocket(&data_socket2); @@ -251,6 +252,25 @@ class FtpNetworkTransactionTest : public PlatformTest { ASSERT_EQ(ERR_IO_PENDING, transaction_.Start(&request_info, &callback_)); EXPECT_EQ(expected_result, callback_.WaitForResult()); EXPECT_EQ(FtpMockControlSocket::QUIT, ctrl_socket->state()); + if (expected_result == OK) { + scoped_refptr<IOBuffer> io_buffer(new IOBuffer(kBufferSize)); + memset(io_buffer->data(), 0, kBufferSize); + ASSERT_EQ(ERR_IO_PENDING, + transaction_.Read(io_buffer.get(), kBufferSize, &callback_)); + EXPECT_EQ(static_cast<int>(mock_data.length()), + callback_.WaitForResult()); + EXPECT_EQ(mock_data, std::string(io_buffer->data(), mock_data.length())); + } + } + + void TransactionFailHelper(FtpMockControlSocket* ctrl_socket, + const char* request, + FtpMockControlSocket::State state, + FtpMockControlSocket::State next_state, + const char* response, + int expected_result) { + ctrl_socket->InjectFailure(state, next_state, response); + ExecuteTransaction(ctrl_socket, request, expected_result); } scoped_refptr<FtpNetworkSession> session_; @@ -270,47 +290,36 @@ TEST_F(FtpNetworkTransactionTest, FailedLookup) { TEST_F(FtpNetworkTransactionTest, DirectoryTransaction) { FtpMockControlSocketDirectoryListing ctrl_socket; - std::string test_string("mock-directory-listing"); - MockRead data_reads[] = { - MockRead(test_string.c_str()), - }; - // TODO(phajdan.jr): FTP transaction should not open two data sockets. - StaticMockSocket data_socket1; - StaticMockSocket data_socket2(data_reads, NULL); - mock_socket_factory_.AddMockSocket(&ctrl_socket); - mock_socket_factory_.AddMockSocket(&data_socket1); - mock_socket_factory_.AddMockSocket(&data_socket2); - FtpRequestInfo request_info = GetRequestInfo("ftp://host"); - ASSERT_EQ(ERR_IO_PENDING, transaction_.Start(&request_info, &callback_)); - EXPECT_EQ(OK, callback_.WaitForResult()); - EXPECT_EQ(FtpMockControlSocket::QUIT, ctrl_socket.state()); - scoped_refptr<IOBuffer> io_buffer(new IOBuffer(kBufferSize)); - memset(io_buffer->data(), 0, kBufferSize); - EXPECT_EQ(ERR_IO_PENDING, - transaction_.Read(io_buffer.get(), kBufferSize, &callback_)); - EXPECT_EQ(static_cast<int>(test_string.length()), callback_.WaitForResult()); - EXPECT_EQ(test_string, std::string(io_buffer->data(), test_string.length())); + ExecuteTransaction(&ctrl_socket, "ftp://host", OK); +} + +TEST_F(FtpNetworkTransactionTest, DirectoryTransactionShortReads2) { + FtpMockControlSocketDirectoryListing ctrl_socket; + ctrl_socket.set_short_read_limit(2); + ExecuteTransaction(&ctrl_socket, "ftp://host", OK); +} + +TEST_F(FtpNetworkTransactionTest, DirectoryTransactionShortReads5) { + FtpMockControlSocketDirectoryListing ctrl_socket; + ctrl_socket.set_short_read_limit(5); + ExecuteTransaction(&ctrl_socket, "ftp://host", OK); } TEST_F(FtpNetworkTransactionTest, DownloadTransaction) { FtpMockControlSocketFileDownload ctrl_socket; - std::string test_string("mock-file-contents"); - MockRead data_reads[] = { - MockRead(test_string.c_str()), - }; - StaticMockSocket data_socket(data_reads, NULL); - mock_socket_factory_.AddMockSocket(&ctrl_socket); - mock_socket_factory_.AddMockSocket(&data_socket); - FtpRequestInfo request_info = GetRequestInfo("ftp://host/file"); - ASSERT_EQ(ERR_IO_PENDING, transaction_.Start(&request_info, &callback_)); - EXPECT_EQ(OK, callback_.WaitForResult()); - EXPECT_EQ(FtpMockControlSocket::QUIT, ctrl_socket.state()); - scoped_refptr<IOBuffer> io_buffer(new IOBuffer(kBufferSize)); - memset(io_buffer->data(), 0, kBufferSize); - EXPECT_EQ(ERR_IO_PENDING, - transaction_.Read(io_buffer.get(), kBufferSize, &callback_)); - EXPECT_EQ(static_cast<int>(test_string.length()), callback_.WaitForResult()); - EXPECT_EQ(test_string, std::string(io_buffer->data(), test_string.length())); + ExecuteTransaction(&ctrl_socket, "ftp://host/file", OK); +} + +TEST_F(FtpNetworkTransactionTest, DownloadTransactionShortReads2) { + FtpMockControlSocketFileDownload ctrl_socket; + ctrl_socket.set_short_read_limit(2); + ExecuteTransaction(&ctrl_socket, "ftp://host/file", OK); +} + +TEST_F(FtpNetworkTransactionTest, DownloadTransactionShortReads5) { + FtpMockControlSocketFileDownload ctrl_socket; + ctrl_socket.set_short_read_limit(5); + ExecuteTransaction(&ctrl_socket, "ftp://host/file", OK); } TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailUser) { |