# HG changeset patch # User Sebastien Jodogne # Date 1367315451 -7200 # Node ID d2c69150a979d0767ae0802edb26d2bebd797707 # Parent 5962898fb7c8d7c3a1c12b688fe1ef98568067cc bulk storescu diff -r 5962898fb7c8 -r d2c69150a979 Core/Toolbox.cpp --- a/Core/Toolbox.cpp Tue Apr 30 10:57:00 2013 +0200 +++ b/Core/Toolbox.cpp Tue Apr 30 11:50:51 2013 +0200 @@ -565,6 +565,33 @@ } } + bool Toolbox::IsSHA1(const std::string& str) + { + if (str.size() != 44) + { + return false; + } + + for (unsigned int i = 0; i < 44; i++) + { + if (i == 8 || + i == 17 || + i == 26 || + i == 35) + { + if (str[i] != '-') + return false; + } + else + { + if (!isalnum(str[i])) + return false; + } + } + + return true; + } + std::string Toolbox::GetNowIsoString() { boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); diff -r 5962898fb7c8 -r d2c69150a979 Core/Toolbox.h --- a/Core/Toolbox.h Tue Apr 30 10:57:00 2013 +0200 +++ b/Core/Toolbox.h Tue Apr 30 11:50:51 2013 +0200 @@ -80,6 +80,8 @@ void ComputeSHA1(std::string& result, const std::string& data); + bool IsSHA1(const std::string& str); + std::string DecodeBase64(const std::string& data); std::string EncodeBase64(const std::string& data); diff -r 5962898fb7c8 -r d2c69150a979 Core/Uuid.cpp --- a/Core/Uuid.cpp Tue Apr 30 10:57:00 2013 +0200 +++ b/Core/Uuid.cpp Tue Apr 30 11:50:51 2013 +0200 @@ -96,6 +96,28 @@ } + bool StartsWithUuid(const std::string& str) + { + if (str.size() < 36) + { + return false; + } + + if (str.size() == 36) + { + return IsUuid(str); + } + + assert(str.size() > 36); + if (!isspace(str[36])) + { + return false; + } + + return IsUuid(str.substr(0, 36)); + } + + static std::string CreateTemporaryPath(const char* extension) { #if BOOST_HAS_FILESYSTEM_V3 == 1 diff -r 5962898fb7c8 -r d2c69150a979 Core/Uuid.h --- a/Core/Uuid.h Tue Apr 30 10:57:00 2013 +0200 +++ b/Core/Uuid.h Tue Apr 30 11:50:51 2013 +0200 @@ -51,6 +51,8 @@ bool IsUuid(const std::string& str); + bool StartsWithUuid(const std::string& str); + class TemporaryFile { private: diff -r 5962898fb7c8 -r d2c69150a979 OrthancServer/OrthancRestApi.cpp --- a/OrthancServer/OrthancRestApi.cpp Tue Apr 30 10:57:00 2013 +0200 +++ b/OrthancServer/OrthancRestApi.cpp Tue Apr 30 11:50:51 2013 +0200 @@ -249,45 +249,67 @@ RETRIEVE_CONTEXT(call); std::string remote = call.GetUriComponent("id", ""); + std::string stripped = Toolbox::StripSpaces(call.GetPostBody()); + + Json::Value request; + if (Toolbox::IsSHA1(stripped)) + { + // This is for compatibility with Orthanc <= 0.5.1. + request = stripped; + } + else if (!call.ParseJsonRequest(request)) + { + // Bad JSON request + return; + } + + std::list instances; + if (request.isString()) + { + context.GetIndex().LogExportedResource(request.asString(), remote); + context.GetIndex().GetChildInstances(instances, request.asString()); + } + else if (request.isArray()) + { + for (Json::Value::ArrayIndex i = 0; i < request.size(); i++) + { + if (!request[i].isString()) + { + return; + } + + std::string stripped = Toolbox::StripSpaces(request[i].asString()); + if (!Toolbox::IsSHA1(stripped)) + { + return; + } + + context.GetIndex().LogExportedResource(stripped, remote); + + std::list tmp; + context.GetIndex().GetChildInstances(tmp, stripped); + instances.merge(tmp); + assert(tmp.size() == 0); + } + } + else + { + // Neither a string, nor a list of strings. Bad request. + return; + } + DicomUserConnection connection; ConnectToModality(connection, remote); - const std::string& resourceId = call.GetPostBody(); - - Json::Value found; - if (context.GetIndex().LookupResource(found, resourceId, ResourceType_Series)) + for (std::list::const_iterator + it = instances.begin(); it != instances.end(); it++) { - // The UUID corresponds to a series - context.GetIndex().LogExportedResource(resourceId, remote); - - for (Json::Value::ArrayIndex i = 0; i < found["Instances"].size(); i++) - { - std::string instanceId = found["Instances"][i].asString(); - std::string dicom; - context.ReadFile(dicom, instanceId, FileContentType_Dicom); - connection.Store(dicom); - } - - call.GetOutput().AnswerBuffer("{}", "application/json"); + std::string dicom; + context.ReadFile(dicom, *it, FileContentType_Dicom); + connection.Store(dicom); } - else if (context.GetIndex().LookupResource(found, resourceId, ResourceType_Instance)) - { - // The UUID corresponds to an instance - context.GetIndex().LogExportedResource(resourceId, remote); - std::string dicom; - context.ReadFile(dicom, resourceId, FileContentType_Dicom); - connection.Store(dicom); - - call.GetOutput().AnswerBuffer("{}", "application/json"); - } - else - { - // The POST body is not a known resource, assume that it - // contains a raw DICOM instance - connection.Store(resourceId); - call.GetOutput().AnswerBuffer("{}", "application/json"); - } + call.GetOutput().AnswerBuffer("{}", "application/json"); } diff -r 5962898fb7c8 -r d2c69150a979 UnitTests/main.cpp --- a/UnitTests/main.cpp Tue Apr 30 10:57:00 2013 +0200 +++ b/UnitTests/main.cpp Tue Apr 30 11:50:51 2013 +0200 @@ -29,6 +29,23 @@ ASSERT_FALSE(Toolbox::IsUuid("")); ASSERT_FALSE(Toolbox::IsUuid("012345678901234567890123456789012345")); ASSERT_TRUE(Toolbox::IsUuid("550e8400-e29b-41d4-a716-446655440000")); + ASSERT_FALSE(Toolbox::StartsWithUuid("550e8400-e29b-41d4-a716-44665544000")); + ASSERT_TRUE(Toolbox::StartsWithUuid("550e8400-e29b-41d4-a716-446655440000")); + ASSERT_TRUE(Toolbox::StartsWithUuid("550e8400-e29b-41d4-a716-446655440000 ok")); + ASSERT_FALSE(Toolbox::StartsWithUuid("550e8400-e29b-41d4-a716-446655440000ok")); +} + +TEST(Toolbox, IsSHA1) +{ + ASSERT_FALSE(Toolbox::IsSHA1("")); + ASSERT_FALSE(Toolbox::IsSHA1("01234567890123456789012345678901234567890123")); + ASSERT_FALSE(Toolbox::IsSHA1("012345678901234567890123456789012345678901234")); + ASSERT_TRUE(Toolbox::IsSHA1("b5ed549f-956400ce-69a8c063-bf5b78be-2732a4b9")); + + std::string s; + Toolbox::ComputeSHA1(s, "The quick brown fox jumps over the lazy dog"); + ASSERT_TRUE(Toolbox::IsSHA1(s)); + ASSERT_EQ("2fd4e1c6-7a2d28fc-ed849ee1-bb76e739-1b93eb12", s); } TEST(Zlib, Basic)