# HG changeset patch # User Sebastien Jodogne # Date 1611046966 -3600 # Node ID 4f8e77c650e8862ec86fa2f6d5f725077fa7a75d # Parent a86fd55c4df008a74ff72814913373ca7d807535 new function MultipartStreamReader::ParseHeaderArguments() diff -r a86fd55c4df0 -r 4f8e77c650e8 NEWS --- 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 diff -r a86fd55c4df0 -r 4f8e77c650e8 OrthancFramework/Sources/HttpServer/MultipartStreamReader.cpp --- 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 items; Toolbox::TokenizeString(items, tokens[i], '='); @@ -362,4 +363,66 @@ return valid; } + + + bool MultipartStreamReader::ParseHeaderArguments(std::string& main, + std::map& arguments, + const std::string& header) + { + std::vector 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 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; + } } diff -r a86fd55c4df0 -r 4f8e77c650e8 OrthancFramework/Sources/HttpServer/MultipartStreamReader.h --- 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& arguments, + const std::string& header); }; } diff -r a86fd55c4df0 -r 4f8e77c650e8 OrthancFramework/UnitTestsSources/RestApiTests.cpp --- 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 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";