Mercurial > hg > orthanc-dicomweb
changeset 276:14419134e05e
cont
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 03 Jun 2019 17:30:44 +0200 |
parents | 0d1815ffe865 |
children | d5c223df16c8 |
files | UnitTestsSources/UnitTestsMain.cpp |
diffstat | 1 files changed, 98 insertions(+), 65 deletions(-) [+] |
line wrap: on
line diff
--- a/UnitTestsSources/UnitTestsMain.cpp Mon Jun 03 14:33:58 2019 +0200 +++ b/UnitTestsSources/UnitTestsMain.cpp Mon Jun 03 17:30:44 2019 +0200 @@ -161,12 +161,12 @@ } } - const void* GetPointerBegin() const + const char* GetPointerBegin() const { return &GetMatchBegin()[0]; } - const void* GetPointerEnd() const + const char* GetPointerEnd() const { return &GetMatchEnd()[0]; } @@ -213,6 +213,7 @@ //std::auto_ptr<Search> boundaryMatcher_; ChunkedBuffer buffer_; size_t blockSize_; + std::string contentType_; static void ParseHeaders(Dictionary& headers, @@ -276,24 +277,33 @@ } - static bool ParseHeaderValues(Dictionary& values, + static bool ParseHeaderValues(std::string& main, + Dictionary& parameters, const Dictionary& headers, const std::string& key) { Dictionary::const_iterator it = headers.find(key); + main.clear(); + parameters.clear(); + if (it == headers.end()) { return false; } else { - values.clear(); - std::vector<std::string> tokens; Toolbox::TokenizeString(tokens, it->second, ';'); - for (size_t i = 0; i < tokens.size(); i++) + if (tokens.empty()) + { + return false; + } + + main = tokens[0]; + + for (size_t i = 1; i < tokens.size(); i++) { size_t separator = tokens[i].find('='); if (separator != std::string::npos) @@ -304,7 +314,7 @@ if (!key.empty()) { Toolbox::ToLowerCase(key); - values[key] = value; + parameters[key] = value; } } } @@ -316,15 +326,15 @@ void InitializeMultipart(const Dictionary& headers) { - Dictionary values; - if (!ParseHeaderValues(values, headers, "content-type")) + Dictionary parameters; + if (!ParseHeaderValues(contentType_, parameters, headers, "content-type")) { throw OrthancException(ErrorCode_NetworkProtocol, "Multipart stream without a Content-Type"); - } + } - Dictionary::const_iterator boundary = values.find("boundary"); - if (boundary == values.end()) + Dictionary::const_iterator boundary = parameters.find("boundary"); + if (boundary == parameters.end()) { throw OrthancException(ErrorCode_NetworkProtocol, "Missing boundary in the Content-Type of a multipart stream"); @@ -362,7 +372,8 @@ void ParseStream() { printf("."); fflush(stdout); - if (handler_ == NULL) + if (handler_ == NULL || + state_ == State_Done) { return; } @@ -390,6 +401,8 @@ } } + //printf("PATTERN: [%s]\n", boundaryMatcher_->GetPattern().c_str()); + assert(boundaryMatcher_.get() != NULL); // This is initialized at (*) if (state_ == State_UnusedArea) @@ -409,12 +422,12 @@ else { // We have not seen the end of the unused area yet + std::string reminder(current, corpusEnd); + buffer_.AddChunkDestructive(reminder); return; } - } - - StringMatcher::Iterator processed = current; - + } + for (;;) { size_t patternSize = boundaryMatcher_->GetPattern().size(); @@ -437,7 +450,7 @@ "Garbage between two items in a multipart stream"); } - StringMatcher::Iterator start = processed + patternSize + 2; + StringMatcher::Iterator start = current + patternSize + 2; if (!headersMatcher_.Apply(start, corpusEnd)) { @@ -448,44 +461,46 @@ ParseHeaders(headers, start, headersMatcher_.GetMatchBegin()); size_t contentLength; - if (LookupHeaderSizeValue(contentLength, headers, "content-length")) + if (!LookupHeaderSizeValue(contentLength, headers, "content-length")) { - if (headersMatcher_.GetMatchEnd() + contentLength <= corpusEnd) + if (boundaryMatcher_->Apply(headersMatcher_.GetMatchEnd(), corpusEnd)) { - printf("-"); - handler_->Apply(headers, headersMatcher_.GetPointerEnd(), contentLength); - processed = headersMatcher_.GetMatchEnd() + contentLength; + size_t d = std::distance(headersMatcher_.GetMatchEnd(), boundaryMatcher_->GetMatchBegin()); + if (d <= 1) + { + throw OrthancException(ErrorCode_NetworkProtocol); + } + else + { + contentLength = d - 2; + } } else { - break; // Not enough data available + break; // Not enough data available to have a full part } } - else + + if (headersMatcher_.GetMatchEnd() + contentLength + 2 > corpusEnd) { - // No "Content-Length" header: Search for the next boundary in the stream - if (boundaryMatcher_->Apply(headersMatcher_.GetMatchEnd(), corpusEnd)) - { - printf("+"); - handler_->Apply(headers, headersMatcher_.GetPointerEnd(), - std::distance(headersMatcher_.GetMatchEnd(), boundaryMatcher_->GetMatchBegin())); - processed = boundaryMatcher_->GetMatchBegin(); - } - else - { - break; // Not enough data available - } + break; // Not enough data available to have a full part } + + const char* p = headersMatcher_.GetPointerEnd() + contentLength; + if (p[0] != '\r' || + p[1] != '\n') + { + throw OrthancException(ErrorCode_NetworkProtocol, + "No endline at the end of a part"); + } + + handler_->Apply(headers, headersMatcher_.GetPointerEnd(), contentLength); + current = headersMatcher_.GetMatchEnd() + contentLength + 2; } - if (processed == corpusEnd) + if (current != corpusEnd) { - // No part found, recycle the entire corpus for next iteration - buffer_.AddChunkDestructive(corpus); - } - else - { - std::string reminder(processed, corpusEnd); + std::string reminder(current, corpusEnd); buffer_.AddChunkDestructive(reminder); } } @@ -557,6 +572,11 @@ buffer_.Flatten(tmp); printf("Reminder: [%s]\n", tmp.c_str()); } + + const std::string& GetContentType() const + { + return contentType_; + } }; @@ -722,14 +742,32 @@ TEST(Multipart, Optimization2) { - std::string boundary = "123456789123456789"; + std::string stream; + + { + std::string boundary = "123456789123456789"; + + stream += "Coucou: a\r\n"; + stream += "Hello: b\r\n"; + stream += "Content-Type: multipart/mixed; boundary=" + boundary + "\r\n"; + stream += "World: c\r\n"; - std::string f; - /*f.resize(512*512*2); - for (size_t i = 0; i < f.size(); i++) - f[i] = i % 256;*/ - f = "hello"; - + for (size_t i = 0; i < 10; i++) + { + std::string f = "<hello " + boost::lexical_cast<std::string>(i) + ">"; + + stream += "\r\n--" + boundary + "\r\n"; + if (i % 2 == 0) + stream += "Content-Length: " + boost::lexical_cast<std::string>(f.size()) + "\r\n"; + stream += "Content-Type: toto\r\n\r\n"; + stream += f; + } + + stream += "\r\n--" + boundary + "--"; + + printf("[%s]\n", stream.c_str()); + } + boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time(); @@ -738,26 +776,21 @@ Orthanc::MultipartStreamParser parser; - //parser.SetBlockSize(127); - //parser.SetBoundary(boundary); + parser.SetBlockSize(1); parser.SetHandler(toto); - parser.AddChunk("Coucou: a\r\n"); - parser.AddChunk("Hello: b\r\n"); - parser.AddChunk("Content-Type: multipart/mixed; boundary=" + boundary + "\r\n"); - parser.AddChunk("World: c\r\n\r\n"); - - for (size_t i = 0; i < 10; i++) +#if 0 + for (size_t i = 0; i < stream.size(); i++) { - parser.AddChunk("--" + boundary + "\r\n"); - if (i % 2 == 0) - parser.AddChunk("Content-Length: " + boost::lexical_cast<std::string>(f.size()) + "\r\n"); - parser.AddChunk("Content-Type: toto\r\n\r\n"); - parser.AddChunk(f); + parser.AddChunk(&stream[i], 1); } +#else + parser.AddChunk(stream); +#endif - parser.AddChunk("--" + boundary + "--"); parser.CloseStream(); + + ASSERT_EQ("multipart/mixed", parser.GetContentType()); printf("%d\n", toto.GetCount()); }