From 5fd3d1dfe2c1c5294c74fb350b810a360e668213 Mon Sep 17 00:00:00 2001 From: lganzzzo Date: Wed, 31 Jul 2019 01:59:46 +0400 Subject: [PATCH] Multipart. Some convenienve API for InMemoryPartReader. --- .../web/mime/multipart/InMemoryPartReader.cpp | 12 +++++ .../web/mime/multipart/InMemoryPartReader.hpp | 14 ++++++ test/oatpp/AllTestsMain.cpp | 4 +- test/oatpp/web/app/Controller.hpp | 36 ++++++++++++-- test/oatpp/web/app/ControllerAsync.hpp | 47 +++++++++++++++---- 5 files changed, 96 insertions(+), 17 deletions(-) diff --git a/src/oatpp/web/mime/multipart/InMemoryPartReader.cpp b/src/oatpp/web/mime/multipart/InMemoryPartReader.cpp index 71d41b55..aac47965 100644 --- a/src/oatpp/web/mime/multipart/InMemoryPartReader.cpp +++ b/src/oatpp/web/mime/multipart/InMemoryPartReader.cpp @@ -136,4 +136,16 @@ async::CoroutineStarter AsyncInMemoryPartReader::onPartDataAsync(const std::shar return nullptr; } +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Other functions + +std::shared_ptr createInMemoryPartReader(data::v_io_size maxDataSize) { + return std::make_shared(maxDataSize); +} + + +std::shared_ptr createAsyncInMemoryPartReader(data::v_io_size maxDataSize) { + return std::make_shared(maxDataSize); +} + }}}} diff --git a/src/oatpp/web/mime/multipart/InMemoryPartReader.hpp b/src/oatpp/web/mime/multipart/InMemoryPartReader.hpp index 34500144..048d4838 100644 --- a/src/oatpp/web/mime/multipart/InMemoryPartReader.hpp +++ b/src/oatpp/web/mime/multipart/InMemoryPartReader.hpp @@ -97,6 +97,20 @@ public: }; +/** + * Create in-memory part reader.
+ * @param maxDataSize - max size of the received data. + * @return - `std::shared_ptr` to &id:oatpp::web::mime::multipart::PartReader;. + */ +std::shared_ptr createInMemoryPartReader(data::v_io_size maxDataSize = 64 * 1024); + +/** + * Create in-memory part reader.
+ * @param maxDataSize - max size of the received data. + * @return - `std::shared_ptr` to &id:oatpp::web::mime::multipart::AsyncPartReader;. + */ +std::shared_ptr createAsyncInMemoryPartReader(data::v_io_size maxDataSize = 64 * 1024); + }}}} #endif // oatpp_web_mime_multipart_InMemoryPartReader_hpp diff --git a/test/oatpp/AllTestsMain.cpp b/test/oatpp/AllTestsMain.cpp index 75f4c712..b94c193a 100644 --- a/test/oatpp/AllTestsMain.cpp +++ b/test/oatpp/AllTestsMain.cpp @@ -46,7 +46,7 @@ namespace { void runTests() { oatpp::base::Environment::printCompilationConfig(); -/* + OATPP_RUN_TEST(oatpp::test::base::RegRuleTest); OATPP_RUN_TEST(oatpp::test::base::CommandLineArgumentsTest); @@ -76,7 +76,7 @@ void runTests() { OATPP_RUN_TEST(oatpp::test::web::mime::multipart::StatefulParserTest); OATPP_RUN_TEST(oatpp::test::web::server::api::ApiControllerTest); -*/ + { oatpp::test::web::FullTest test_virtual(0, 1000); diff --git a/test/oatpp/web/app/Controller.hpp b/test/oatpp/web/app/Controller.hpp index a23b64b0..63eba8e9 100644 --- a/test/oatpp/web/app/Controller.hpp +++ b/test/oatpp/web/app/Controller.hpp @@ -185,22 +185,48 @@ public: } - ENDPOINT("POST", "test/multipart/file/{chunk-size}", multipartFileTest, - PATH(Int32, chunkSize, "chunk-size"), + ENDPOINT("POST", "test/multipart-all", multipartFileTest, REQUEST(std::shared_ptr, request)) { + /* Prepare multipart container. */ auto multipart = std::make_shared(request->getHeaders()); + /* Create multipart reader. */ multipart::Reader multipartReader(multipart.get()); - multipartReader.setPartReader("part1", multipart::createFilePartReader("/Users/leonid/Documents/test/my-text-file.tf", -1)); + /* Configure to read part with name "part1" into memory */ + multipartReader.setPartReader("part1", multipart::createInMemoryPartReader(256 /* max-data-size */)); + /* Configure to stream part with name "part2" to file */ + multipartReader.setPartReader("part2", multipart::createFilePartReader("/Users/leonid/Documents/test/my-text-file.tf")); + + /* Configure to read all other parts into memory */ + multipartReader.setDefaultPartReader(multipart::createInMemoryPartReader(16 * 1024 /* max-data-size */)); + + /* Read multipart body */ request->transferBody(&multipartReader); - auto responseBody = std::make_shared(multipart, chunkSize->getValue()); + /* Print number of uploaded parts */ + OATPP_LOGD("Multipart", "parts_count=%d", multipart->count()); - return OutgoingResponse::createShared(Status::CODE_200, responseBody); + /* Print value of "part1" */ + auto part1 = multipart->getNamedPart("part1"); + + OATPP_ASSERT_HTTP(part1, Status::CODE_400, "part1 is empty"); + + OATPP_LOGD("Multipart", "part1='%s'", part1->getInMemoryData()->c_str()); + + /* Get part by name "part2"*/ + auto filePart = multipart->getNamedPart("part2"); + + OATPP_ASSERT_HTTP(filePart, Status::CODE_400, "part2 is empty"); + + auto inputStream = filePart->getInputStream(); + + // TODO - process file stream. + + return createResponse(Status::CODE_200, "OK"); } diff --git a/test/oatpp/web/app/ControllerAsync.hpp b/test/oatpp/web/app/ControllerAsync.hpp index 2806915d..08ecd172 100644 --- a/test/oatpp/web/app/ControllerAsync.hpp +++ b/test/oatpp/web/app/ControllerAsync.hpp @@ -205,30 +205,57 @@ public: }; - ENDPOINT_ASYNC("POST", "test/multipart/file/{chunk-size}", MultipartFileTest) { + ENDPOINT_ASYNC("POST", "test/multipart-all", MultipartUpload) { - ENDPOINT_ASYNC_INIT(MultipartFileTest) + ENDPOINT_ASYNC_INIT(MultipartUpload) - v_int32 m_chunkSize; + /* Coroutine State */ std::shared_ptr m_multipart; Action act() override { - m_chunkSize = oatpp::utils::conversion::strToInt32(request->getPathVariable("chunk-size")->c_str()); - m_multipart = std::make_shared(request->getHeaders()); auto multipartReader = std::make_shared(m_multipart); - multipartReader->setPartReader("part1", multipart::createAsyncFilePartReader("/Users/leonid/Documents/test/my-text-file-async.tf", 16)); + /* Configure to read part with name "part1" into memory */ + multipartReader->setPartReader("part1", multipart::createAsyncInMemoryPartReader(256 /* max-data-size */)); - return request->transferBodyAsync(multipartReader).next(yieldTo(&MultipartFileTest::respond)); + /* Configure to stream part with name "part2" to file */ + multipartReader->setPartReader("part2", multipart::createAsyncFilePartReader("/Users/leonid/Documents/test/my-text-file.tf")); + + /* Configure to read all other parts into memory */ + multipartReader->setDefaultPartReader(multipart::createAsyncInMemoryPartReader(16 * 1024 /* max-data-size */)); + + /* Read multipart body */ + return request->transferBodyAsync(multipartReader).next(yieldTo(&MultipartUpload::onUploaded)); } - Action respond() { + Action onUploaded() { - auto responseBody = std::make_shared(m_multipart, m_chunkSize); - return _return(OutgoingResponse::createShared(Status::CODE_200, responseBody)); + /* Print number of uploaded parts */ + OATPP_LOGD("Multipart", "parts_count=%d", m_multipart->count()); + + /* Get multipart by name */ + auto part1 = m_multipart->getNamedPart("part1"); + + /* Asser part not-null */ + OATPP_ASSERT_HTTP(part1, Status::CODE_400, "part1 is empty"); + + /* Print value of "part1" */ + OATPP_LOGD("Multipart", "part1='%s'", part1->getInMemoryData()->c_str()); + + /* Get multipart by name */ + auto filePart = m_multipart->getNamedPart("part2"); + + /* Asser part not-null */ + OATPP_ASSERT_HTTP(filePart, Status::CODE_400, "part2 is empty"); + + auto inputStream = filePart->getInputStream(); + + // TODO - process file stream. + + return _return(controller->createResponse(Status::CODE_200, "OK")); }