Sfoglia il codice sorgente

Merge pull request #535 from oatpp/#534

Added support for multiple parts with same name in oatpp::web::mime::multipart::PartList
Leonid Stryzhevskyi 2 anni fa
parent
commit
e91cb4079c

+ 15 - 7
src/oatpp/web/mime/multipart/PartList.cpp

@@ -6,7 +6,8 @@
  *                (_____)(__)(__)(__)  |_|    |_|
  *
  *
- * Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
+ * Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>,
+ * Matthias Haselmaier <mhaselmaier@gmail.com>
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -59,11 +60,7 @@ std::shared_ptr<Part> PartList::readNextPart(async::Action& action) {
 void PartList::writeNextPart(const std::shared_ptr<Part>& part, async::Action& action) {
 
   if(part->getName()) {
-    auto it = m_namedParts.find(part->getName());
-    if(it != m_namedParts.end()) {
-      throw std::runtime_error("[oatpp::web::mime::multipart::Multipart::addPart()]: Error. Part with such name already exists.");
-    }
-    m_namedParts.insert({part->getName(), part});
+    m_namedParts[part->getName()].push_back(part);
   }
 
   m_parts.push_back(part);
@@ -74,13 +71,24 @@ std::shared_ptr<Part> PartList::getNamedPart(const oatpp::String& name) {
 
   auto it = m_namedParts.find(name);
   if(it != m_namedParts.end()) {
-    return it->second;
+    return it->second.front();
   }
 
   return nullptr;
 
 }
 
+std::list<std::shared_ptr<Part>> PartList::getNamedParts(const oatpp::String& name) {
+
+  auto it = m_namedParts.find(name);
+  if(it != m_namedParts.end()) {
+    return it->second;
+  }
+
+  return std::list<std::shared_ptr<Part>>{};
+
+}
+
 const std::list<std::shared_ptr<Part>>& PartList::getAllParts() {
   return m_parts;
 }

+ 13 - 3
src/oatpp/web/mime/multipart/PartList.hpp

@@ -6,7 +6,8 @@
  *                (_____)(__)(__)(__)  |_|    |_|
  *
  *
- * Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
+ * Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>,
+ * Matthias Haselmaier <mhaselmaier@gmail.com>
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -34,7 +35,7 @@ namespace oatpp { namespace web { namespace mime { namespace multipart {
  */
 class PartList : public Multipart {
 private:
-  std::unordered_map<oatpp::String, std::shared_ptr<Part>> m_namedParts;
+  std::unordered_map<oatpp::String, std::list<std::shared_ptr<Part>>> m_namedParts;
   bool m_readIteratorInitialized;
   std::list<std::shared_ptr<Part>> m_parts;
   std::list<std::shared_ptr<Part>>::const_iterator m_iterator;
@@ -74,12 +75,21 @@ public:
 
   /**
    * Get part by name <br>
+   * Returns the first part if multiple parts with same name exist.
    * Applicable to named parts only.
    * @param name - &id:oatpp::String;.
-   * @return - &id:oatpp::web::mime::multipart::Part;.
+   * @return - `std::shared_ptr` to &id:oatpp::web::mime::multipart::Part;.
    */
   std::shared_ptr<Part> getNamedPart(const oatpp::String& name);
 
+  /**
+   * Get all parts by name <br>
+   * Applicable to named parts only.
+   * @param name - &id:oatpp::String;.
+   * @return - `std::list` of `std::shared_ptr` to &id:oatpp::web::mime::multipart::Part;.
+   */
+  std::list<std::shared_ptr<Part>> getNamedParts(const oatpp::String& name);
+
   /**
    * Get list of all parts.
    * @return - `std::list` of `std::shared_ptr` to &id:oatpp::web::mime::multipart::Part;.

+ 20 - 3
test/oatpp/web/mime/multipart/StatefulParserTest.cpp

@@ -6,7 +6,8 @@
  *                (_____)(__)(__)(__)  |_|    |_|
  *
  *
- * Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
+ * Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>,
+ * Matthias Haselmaier <mhaselmaier@gmail.com>
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -52,6 +53,14 @@ namespace {
     "Content-Disposition: form-data; name=part3 filename=\"filename.jpg\"\r\n"
     "\r\n"
     "part3-file-binary-data\r\n"
+    "--12345\r\n"
+    "Content-Disposition: form-data; name=\"part4\"\r\n"
+    "\r\n"
+    "part4-first-value\r\n"
+    "--12345\r\n"
+    "Content-Disposition: form-data; name=\"part4\"\r\n"
+    "\r\n"
+    "part4-second-value\r\n"
     "--12345--\r\n"
     ;
 
@@ -112,19 +121,25 @@ void StatefulParserTest::onRun() {
 
     parseStepByStep(text, "12345", listener, i);
 
-    if(multipart.count() != 3) {
+    if(multipart.count() != 5) {
       OATPP_LOGD(TAG, "TEST_DATA_1 itearation %d", i);
     }
 
-    OATPP_ASSERT(multipart.count() == 3);
+    OATPP_ASSERT(multipart.count() == 5);
 
     auto part1 = multipart.getNamedPart("part1");
     auto part2 = multipart.getNamedPart("part2");
     auto part3 = multipart.getNamedPart("part3");
 
+    auto part4 = multipart.getNamedPart("part4");
+    auto part4List = multipart.getNamedParts("part4");
+
     OATPP_ASSERT(part1);
     OATPP_ASSERT(part2);
     OATPP_ASSERT(part3);
+    OATPP_ASSERT(part4);
+    OATPP_ASSERT(part4List.size() == 2);
+    OATPP_ASSERT(part4List.front().get() == part4.get());
 
     OATPP_ASSERT(part1->getFilename().get() == nullptr);
     OATPP_ASSERT(part2->getFilename() == "filename.txt");
@@ -133,6 +148,8 @@ void StatefulParserTest::onRun() {
     assertPartData(part1, "part1-value");
     assertPartData(part2, "--part2-file-content-line1\r\n--1234part2-file-content-line2");
     assertPartData(part3, "part3-file-binary-data");
+    assertPartData(part4List.front(), "part4-first-value");
+    assertPartData(part4List.back(), "part4-second-value");
 
   }