changeset 4453:4f8e77c650e8

new function MultipartStreamReader::ParseHeaderArguments()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 19 Jan 2021 10:02:46 +0100
parents a86fd55c4df0
children f20a7655fb1c
files NEWS OrthancFramework/Sources/HttpServer/MultipartStreamReader.cpp OrthancFramework/Sources/HttpServer/MultipartStreamReader.h OrthancFramework/UnitTestsSources/RestApiTests.cpp
diffstat 4 files changed, 126 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Mon Jan 18 15:04:36 2021 +0100
+++ b/NEWS	Tue Jan 19 10:02:46 2021 +0100
@@ -24,6 +24,7 @@
 Maintenance
 -----------
 
+* Partial fix of issue #48 (Windows service not stopped properly), cf. comment 4
 * Upgraded dependencies for static builds (notably on Windows):
   - jsoncpp 1.9.4
 
--- a/OrthancFramework/Sources/HttpServer/MultipartStreamReader.cpp	Mon Jan 18 15:04:36 2021 +0100
+++ b/OrthancFramework/Sources/HttpServer/MultipartStreamReader.cpp	Tue Jan 19 10:02:46 2021 +0100
@@ -23,6 +23,7 @@
 #include "../PrecompiledHeaders.h"
 #include "MultipartStreamReader.h"
 
+#include "../Logging.h"
 #include "../OrthancException.h"
 #include "../Toolbox.h"
 
@@ -332,7 +333,7 @@
     bool valid = false;
     subType.clear();
 
-    for (size_t i = 0; i < tokens.size(); i++)
+    for (size_t i = 1; i < tokens.size(); i++)
     {
       std::vector<std::string> items;
       Toolbox::TokenizeString(items, tokens[i], '=');
@@ -362,4 +363,66 @@
 
     return valid;
   }
+
+  
+  bool MultipartStreamReader::ParseHeaderArguments(std::string& main,
+                                                   std::map<std::string, std::string>& arguments,
+                                                   const std::string& header)
+  {
+    std::vector<std::string> tokens;
+    Toolbox::TokenizeString(tokens, header, ';');
+
+    if (tokens.empty())
+    {
+      return false;
+    }
+
+    main = Toolbox::StripSpaces(tokens[0]);
+    Toolbox::ToLowerCase(main);
+    if (main.empty())
+    {
+      return false;
+    }
+
+    arguments.clear();
+    
+    for (size_t i = 1; i < tokens.size(); i++)
+    {
+      std::vector<std::string> items;
+      Toolbox::TokenizeString(items, tokens[i], '=');
+
+      if (items.size() > 2)
+      {
+        return false;
+      }
+      else if (!items.empty())
+      {
+        std::string key = Toolbox::StripSpaces(items[0]);
+        Toolbox::ToLowerCase(key);
+        
+        if (arguments.find(key) != arguments.end())
+        {
+          LOG(ERROR) << "The same argument was provided twice in an HTTP header: \""
+                     << key << "\" in \"" << header << "\"";
+          return false;
+        }
+        else if (!key.empty())
+        {
+          if (items.size() == 1)
+          {
+            arguments[key] = "";
+          }
+          else
+          {
+            assert(items.size() == 2);
+            std::string value = Toolbox::StripSpaces(items[1]);
+            RemoveSurroundingQuotes(value);
+            arguments[key] = value;
+          }
+        }
+      }
+    }
+
+    return true;
+  }
 }
--- a/OrthancFramework/Sources/HttpServer/MultipartStreamReader.h	Mon Jan 18 15:04:36 2021 +0100
+++ b/OrthancFramework/Sources/HttpServer/MultipartStreamReader.h	Tue Jan 19 10:02:46 2021 +0100
@@ -86,5 +86,9 @@
                                           std::string& subType,  // Possibly empty
                                           std::string& boundary,
                                           const std::string& contentTypeHeader);
+
+    static bool ParseHeaderArguments(std::string& main,
+                                     std::map<std::string, std::string>& arguments,
+                                     const std::string& header);
   };
 }
--- a/OrthancFramework/UnitTestsSources/RestApiTests.cpp	Mon Jan 18 15:04:36 2021 +0100
+++ b/OrthancFramework/UnitTestsSources/RestApiTests.cpp	Tue Jan 19 10:02:46 2021 +0100
@@ -836,6 +836,63 @@
 }
 
 
+TEST(MultipartStreamReader, ParseHeaders2)
+{
+  std::string main;
+  std::map<std::string, std::string> args;
+  
+  ASSERT_FALSE(MultipartStreamReader::ParseHeaderArguments(main, args, ""));
+  ASSERT_FALSE(MultipartStreamReader::ParseHeaderArguments(main, args, "     "));
+  ASSERT_FALSE(MultipartStreamReader::ParseHeaderArguments(main, args, "  ;   "));
+
+  ASSERT_TRUE(MultipartStreamReader::ParseHeaderArguments(main, args, "hello"));
+  ASSERT_EQ("hello", main);
+  ASSERT_TRUE(args.empty());
+
+  ASSERT_TRUE(MultipartStreamReader::ParseHeaderArguments(main, args, "hello  ;  a  = \"  b  \";c=d  ;  e=f;"));
+  ASSERT_EQ("hello", main);
+  ASSERT_EQ(3u, args.size());
+  ASSERT_EQ("  b  ", args["a"]);
+  ASSERT_EQ("d", args["c"]);
+  ASSERT_EQ("f", args["e"]);
+
+  ASSERT_TRUE(MultipartStreamReader::ParseHeaderArguments(main, args, "    hello  ;;;;  ;  "));
+  ASSERT_EQ("hello", main);
+  ASSERT_TRUE(args.empty());
+
+  ASSERT_FALSE(MultipartStreamReader::ParseHeaderArguments(main, args, "hello;a=b;c=d;a=f"));
+
+  ASSERT_TRUE(MultipartStreamReader::ParseHeaderArguments(main, args, "multipart/related; dummy=value; boundary=1234; hello=world"));
+  ASSERT_EQ("multipart/related", main);
+  ASSERT_EQ(3u, args.size());
+  ASSERT_EQ("value", args["dummy"]);
+  ASSERT_EQ("1234", args["boundary"]);
+  ASSERT_EQ("world", args["hello"]);
+
+  ASSERT_TRUE(MultipartStreamReader::ParseHeaderArguments(main, args, "multipart/related; boundary="));
+  ASSERT_EQ("multipart/related", main);
+  ASSERT_EQ(1u, args.size());
+  ASSERT_EQ("", args["boundary"]);
+
+  ASSERT_TRUE(MultipartStreamReader::ParseHeaderArguments(main, args, "multipart/related; boundary"));
+  ASSERT_EQ("multipart/related", main);
+  ASSERT_EQ(1u, args.size());
+  ASSERT_EQ("", args["boundary"]);
+
+  ASSERT_TRUE(MultipartStreamReader::ParseHeaderArguments(main, args, "Multipart/Related; TYPE=Application/Dicom; Boundary=heLLO"));
+  ASSERT_EQ("multipart/related", main);
+  ASSERT_EQ(2u, args.size());
+  ASSERT_EQ("Application/Dicom", args["type"]);
+  ASSERT_EQ("heLLO", args["boundary"]);
+
+  ASSERT_TRUE(MultipartStreamReader::ParseHeaderArguments(main, args, "Multipart/Related; type=\"application/DICOM\"; Boundary=a"));
+  ASSERT_EQ("multipart/related", main);
+  ASSERT_EQ(2u, args.size());
+  ASSERT_EQ("application/DICOM", args["type"]);
+  ASSERT_EQ("a", args["boundary"]);
+}
+
+
 TEST(MultipartStreamReader, BytePerByte)
 {
   std::string stream = "GARBAGE";