diff --git a/common/cpp/include/system_wrappers/io.h b/common/cpp/include/system_wrappers/io.h index ebb62dfa58b63d52335ea8518ef6656a8e6f2c8a..c10e3591d52eef0f26b9ef42c9d9255cbd9fb69f 100644 --- a/common/cpp/include/system_wrappers/io.h +++ b/common/cpp/include/system_wrappers/io.h @@ -218,6 +218,8 @@ class IO { virtual size_t Read (FileDescriptor fd, void* buf, size_t length, Error* err) const = 0; virtual size_t Write (FileDescriptor fd, const void* buf, size_t length, Error* err) const = 0; + virtual Error WriteDataToFile (const std::string& fname, const FileData& data, size_t length) const = 0; + virtual void CreateNewDirectory (const std::string& directory_name, Error* err) const = 0; virtual FileData GetDataFromFile (const std::string& fname, uint64_t fsize, Error* err) const = 0; virtual void CollectFileInformationRecursively(const std::string& path, std::vector<FileInfo>* files, diff --git a/common/cpp/include/system_wrappers/system_io.h b/common/cpp/include/system_wrappers/system_io.h index 52b7332bb16c6c0c90707041a3f7a273498ec4da..2a1703d7f4823a4ac53911a32fb217088888c191 100644 --- a/common/cpp/include/system_wrappers/system_io.h +++ b/common/cpp/include/system_wrappers/system_io.h @@ -101,6 +101,7 @@ class SystemIO final : public IO { size_t Write(FileDescriptor fd, const void* buf, size_t length, Error* err) const; void CreateNewDirectory(const std::string& directory_name, Error* err) const; FileData GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const; + Error WriteDataToFile (const std::string& fname, const FileData& data, size_t length) const; void CollectFileInformationRecursively(const std::string& path, std::vector<FileInfo>* files, Error* err) const; std::string ReadFileToString(const std::string& fname, Error* err) const; diff --git a/common/cpp/include/unittests/MockIO.h b/common/cpp/include/unittests/MockIO.h index 1ce54ffed75c4ccec1d666eb76642759c76a2ace..262245a8b77c1708c454b99f35be7ef0652e8f1b 100644 --- a/common/cpp/include/unittests/MockIO.h +++ b/common/cpp/include/unittests/MockIO.h @@ -170,8 +170,16 @@ class MockIO : public IO { err->reset(error); return FileData(data); } + MOCK_CONST_METHOD3(GetDataFromFile_t, uint8_t* (const std::string& fname, uint64_t fsize, ErrorInterface** err)); + Error WriteDataToFile(const std::string& fname, const FileData& data, size_t length) const override { + return Error{WriteDataToFile_t(fname, data.get(), length)}; + + } + + MOCK_CONST_METHOD3(WriteDataToFile_t, ErrorInterface * (const std::string& fname, uint8_t* data, size_t fsize)); + void CollectFileInformationRecursively(const std::string& path, std::vector<FileInfo>* files, Error* err) const override { ErrorInterface* error = nullptr; diff --git a/common/cpp/src/system_io/system_io.cpp b/common/cpp/src/system_io/system_io.cpp index 5b023f3ec637cb3635028ed7cf8c17903504aea8..d91eda9a4c508c78cd88f5ce69d7482853291946 100644 --- a/common/cpp/src/system_io/system_io.cpp +++ b/common/cpp/src/system_io/system_io.cpp @@ -121,6 +121,23 @@ void hidra2::SystemIO::CreateNewDirectory(const std::string& directory_name, Err } } +Error SystemIO::WriteDataToFile(const std::string& fname, const FileData& data, size_t length) const { + Error err; + auto fd = Open(fname, IO_OPEN_MODE_CREATE_AND_FAIL_IF_EXISTS | IO_OPEN_MODE_RW, &err); + if (err) { + return err; + } + + Write(fd, data.get(), length, &err); + if (err) { + return err; + } + + Close(fd, &err); + return err; +} + + std::string SystemIO::ReadFileToString(const std::string& fname, Error* err) const { auto info = GetFileInfo(fname, err); if (*err != nullptr) { diff --git a/receiver/src/receiver_error.h b/receiver/src/receiver_error.h index b82705288067bfcc6ee8df54d7384dc6c6e66fd0..63da34f6fe47518ca7d55278a47e82b0f302d7ed 100644 --- a/receiver/src/receiver_error.h +++ b/receiver/src/receiver_error.h @@ -7,6 +7,7 @@ namespace hidra2 { enum class ReceiverErrorType { kInvalidOpCode, + kBadRequest }; //TODO Make a marco to create error class and error template class @@ -51,6 +52,10 @@ namespace ReceiverErrorTemplates { auto const kInvalidOpCode = ReceiverErrorTemplate { "Invalid Opcode", ReceiverErrorType::kInvalidOpCode }; +auto const kBadRequest = ReceiverErrorTemplate { + "Bad request", ReceiverErrorType::kBadRequest + }; + }; } diff --git a/receiver/src/request.cpp b/receiver/src/request.cpp index 48d85e9dec781eeab7e0316d3a36818cd6c9026c..ef2794098cae92b3fa9a7840a2e25ff132e5f2de 100644 --- a/receiver/src/request.cpp +++ b/receiver/src/request.cpp @@ -4,7 +4,7 @@ namespace hidra2 { Request::Request(const GenericNetworkRequestHeader& header, - SocketDescriptor socket_fd) : io__{new SystemIO}, request_header_{header}, socket_fd_{socket_fd} { + SocketDescriptor socket_fd) : io__{new SystemIO}, request_header_(header), socket_fd_{socket_fd} { } Error Request::AllocateDataBuffer() { @@ -55,6 +55,19 @@ void Request::AddHandler(const RequestHandler* handler) { } +uint64_t Request::GetDataSize() const { + return request_header_.data_size; +} + +const FileData& Request::GetData() const { + return data_buffer_; +} + +std::string Request::GetFileName() const { + return std::to_string(request_header_.data_id) + ".bin"; +} + + std::unique_ptr<Request> RequestFactory::GenerateRequest(const GenericNetworkRequestHeader& request_header, SocketDescriptor socket_fd, Error* err) const noexcept { diff --git a/receiver/src/request.h b/receiver/src/request.h index 8efcaf784c5476ed2c48e1009b626f44cf9507a7..dd45a8c7446057dbfe60a7e95a0ae045425adeef 100644 --- a/receiver/src/request.h +++ b/receiver/src/request.h @@ -18,6 +18,10 @@ class Request { Request(const GenericNetworkRequestHeader& request_header, SocketDescriptor socket_fd); void AddHandler(const RequestHandler*); const RequestHandlerList& GetListHandlers() const; + virtual uint64_t GetDataSize() const; + virtual std::string GetFileName() const; + + virtual const FileData& GetData() const; std::unique_ptr<IO> io__; private: Error AllocateDataBuffer(); diff --git a/receiver/src/request_handler_file_write.cpp b/receiver/src/request_handler_file_write.cpp index 6b509495df142cafd696a8e99f441d5f48b5b366..2796f6321f0f4561f35fab2ccdad7382eed52d23 100644 --- a/receiver/src/request_handler_file_write.cpp +++ b/receiver/src/request_handler_file_write.cpp @@ -1,10 +1,20 @@ #include "request_handler_file_write.h" #include "system_wrappers/system_io.h" - +#include "request.h" namespace hidra2 { Error RequestHandlerFileWrite::ProcessRequest(const Request& request) const { - return nullptr; + auto fsize = request.GetDataSize(); + if (fsize <= 0 || fsize > kMaxFileSize) { + return ReceiverErrorTemplates::kBadRequest.Generate(); + } + + const FileData& data = request.GetData(); + + auto fname = request.GetFileName(); + + return io__->WriteDataToFile("files/" + fname, data, fsize); + } RequestHandlerFileWrite::RequestHandlerFileWrite() : io__{new SystemIO} { diff --git a/receiver/src/request_handler_file_write.h b/receiver/src/request_handler_file_write.h index bbffa8d3fb1dfb0960a4b53f9cbdde6040021764..fb56d4e25c5a3e313de22cab655e2d9e72b9aed8 100644 --- a/receiver/src/request_handler_file_write.h +++ b/receiver/src/request_handler_file_write.h @@ -7,6 +7,8 @@ namespace hidra2 { +const uint64_t kMaxFileSize = uint64_t(1024) * 1024 * 1024 * 2; //2GB + class RequestHandlerFileWrite final: public RequestHandler { public: RequestHandlerFileWrite(); diff --git a/receiver/unittests/test_request_handler_file_write.cpp b/receiver/unittests/test_request_handler_file_write.cpp index 2996f715912743876df9a39d6a469056db2431f4..d330b855c31be28bbf9bbe787ce27241309e47e3 100644 --- a/receiver/unittests/test_request_handler_file_write.cpp +++ b/receiver/unittests/test_request_handler_file_write.cpp @@ -9,6 +9,7 @@ using ::testing::Test; using ::testing::Return; +using ::testing::ReturnRef; using ::testing::_; using ::testing::DoAll; using ::testing::SetArgReferee; @@ -44,7 +45,11 @@ class FileWriteHandlerTests : public Test { public: RequestHandlerFileWrite handler; NiceMock<MockIO> mock_io; + std::unique_ptr<MockRequest> mock_request; void SetUp() override { + GenericNetworkRequestHeader request_header; + request_header.data_id = 2; + mock_request.reset(new MockRequest{request_header, 1}); handler.io__ = std::unique_ptr<hidra2::IO> {&mock_io}; /* ON_CALL(mock_io, Receive_t(socket_fd_, _, data_size_, _)).WillByDefault( DoAll(SetArgPointee<3>(nullptr), @@ -57,4 +62,53 @@ class FileWriteHandlerTests : public Test { }; +TEST_F(FileWriteHandlerTests, ErrorWhenZeroFileSize) { + EXPECT_CALL(*mock_request, GetDataSize()) + .WillOnce(Return(0)) + ; + + auto err = handler.ProcessRequest(*mock_request); + + ASSERT_THAT(err, Eq(hidra2::ReceiverErrorTemplates::kBadRequest)); +} + +TEST_F(FileWriteHandlerTests, ErrorWhenTooBigFileSize) { + EXPECT_CALL(*mock_request, GetDataSize()) + .WillOnce(Return(hidra2::kMaxFileSize + 1)) + ; + + auto err = handler.ProcessRequest(*mock_request); + + ASSERT_THAT(err, Eq(hidra2::ReceiverErrorTemplates::kBadRequest)); +} + +TEST_F(FileWriteHandlerTests, CallsWriteFile) { + std::string expected_file_name = "2.bin"; + uint64_t expected_file_size = 10; + EXPECT_CALL(*mock_request, GetDataSize()) + .WillOnce(Return(expected_file_size)) + ; + + hidra2::FileData data; + EXPECT_CALL(*mock_request, GetData()) + .WillOnce(ReturnRef(data)) + ; + + EXPECT_CALL(*mock_request, GetFileName()) + .WillOnce(Return(expected_file_name)) + ; + + + EXPECT_CALL(mock_io, WriteDataToFile_t("files/"+expected_file_name, _, expected_file_size)) + .WillOnce( + //Return(hidra2::IOErrorTemplates::kUnknownIOError.Generate().release()) + Return(nullptr) + ); + + auto err = handler.ProcessRequest(*mock_request); + + ASSERT_THAT(err, Eq(nullptr)); +} + + } \ No newline at end of file diff --git a/tests/producer_receiver/transfer_single_file/check_linux.sh b/tests/producer_receiver/transfer_single_file/check_linux.sh index ae45360ab56d92b1ae1e92d5a6726b78138d56b5..163d4ab08b8144ea133ca0f6f48899b304234e63 100644 --- a/tests/producer_receiver/transfer_single_file/check_linux.sh +++ b/tests/producer_receiver/transfer_single_file/check_linux.sh @@ -14,6 +14,8 @@ nohup $2 &>/dev/null & sleep 0.3 receiverid=`echo $!` +mkdir files + $1 localhost:4200 100 1 -du -b files/0.bin | cut -f1 | grep 100 +ls -ln files/0.bin | awk '{ print $5 }'| grep 100 diff --git a/tests/producer_receiver/transfer_single_file/check_windows.bat b/tests/producer_receiver/transfer_single_file/check_windows.bat index a6076b28b2a8f4e96c8c3a1ca59b435842500cda..9413a82a228200e5a50ed87135e10450ab471714 100644 --- a/tests/producer_receiver/transfer_single_file/check_windows.bat +++ b/tests/producer_receiver/transfer_single_file/check_windows.bat @@ -5,6 +5,8 @@ start /B "" "%full_recv_name%" ping 1.0.0.0 -n 1 -w 100 > nul +mkdir files + %1 localhost:4200 100 1 ping 1.0.0.0 -n 1 -w 100 > nul