comparison OrthancServer/Sources/OrthancRestApi/OrthancRestApi.cpp @ 4357:886bc367aeb2

"/instances" can be used to import ZIP archives provided in the POST body
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 08 Dec 2020 13:17:40 +0100
parents a01b1c9cbef4
children 79ef2b6d8e76
comparison
equal deleted inserted replaced
4356:18c94a82f3d4 4357:886bc367aeb2
33 33
34 #include "../PrecompiledHeadersServer.h" 34 #include "../PrecompiledHeadersServer.h"
35 #include "OrthancRestApi.h" 35 #include "OrthancRestApi.h"
36 36
37 #include "../../../OrthancFramework/Sources/Compression/GzipCompressor.h" 37 #include "../../../OrthancFramework/Sources/Compression/GzipCompressor.h"
38 #include "../../../OrthancFramework/Sources/Compression/ZipReader.h"
38 #include "../../../OrthancFramework/Sources/Logging.h" 39 #include "../../../OrthancFramework/Sources/Logging.h"
39 #include "../../../OrthancFramework/Sources/MetricsRegistry.h" 40 #include "../../../OrthancFramework/Sources/MetricsRegistry.h"
40 #include "../../../OrthancFramework/Sources/SerializationToolbox.h" 41 #include "../../../OrthancFramework/Sources/SerializationToolbox.h"
41 #include "../ServerContext.h" 42 #include "../ServerContext.h"
42 43
59 60
60 result["Status"] = EnumerationToString(status); 61 result["Status"] = EnumerationToString(status);
61 } 62 }
62 63
63 64
65 static void SetupResourceAnswer(Json::Value& result,
66 DicomInstanceToStore& instance,
67 StoreStatus status,
68 const std::string& instanceId)
69 {
70 SetupResourceAnswer(result, instanceId, ResourceType_Instance, status);
71
72 result["ParentPatient"] = instance.GetHasher().HashPatient();
73 result["ParentStudy"] = instance.GetHasher().HashStudy();
74 result["ParentSeries"] = instance.GetHasher().HashSeries();
75 }
76
77
64 void OrthancRestApi::AnswerStoredInstance(RestApiPostCall& call, 78 void OrthancRestApi::AnswerStoredInstance(RestApiPostCall& call,
65 DicomInstanceToStore& instance, 79 DicomInstanceToStore& instance,
66 StoreStatus status, 80 StoreStatus status,
67 const std::string& instanceId) const 81 const std::string& instanceId) const
68 { 82 {
69 Json::Value result; 83 Json::Value result;
70 SetupResourceAnswer(result, instanceId, ResourceType_Instance, status); 84 SetupResourceAnswer(result, instance, status, instanceId);
71
72 result["ParentPatient"] = instance.GetHasher().HashPatient();
73 result["ParentStudy"] = instance.GetHasher().HashStudy();
74 result["ParentSeries"] = instance.GetHasher().HashSeries();
75
76 call.GetOutput().AnswerJson(result); 85 call.GetOutput().AnswerJson(result);
77 } 86 }
78 87
79 88
80 void OrthancRestApi::AnswerStoredResource(RestApiPostCall& call, 89 void OrthancRestApi::AnswerStoredResource(RestApiPostCall& call,
119 { 128 {
120 throw OrthancException(ErrorCode_BadFileFormat, 129 throw OrthancException(ErrorCode_BadFileFormat,
121 "Received an empty DICOM file"); 130 "Received an empty DICOM file");
122 } 131 }
123 132
124 // The lifetime of "dicom" must be longer than "toStore", as the 133 if (ZipReader::IsZipMemoryBuffer(call.GetBodyData(), call.GetBodySize()))
125 // latter can possibly store a reference to the former (*) 134 {
126 std::string dicom; 135 // New in Orthanc 1.9.0
127 136 std::unique_ptr<ZipReader> reader(ZipReader::CreateFromMemory(call.GetBodyData(), call.GetBodySize()));
128 DicomInstanceToStore toStore; 137
129 toStore.SetOrigin(DicomInstanceOrigin::FromRest(call)); 138 Json::Value answer = Json::arrayValue;
130 139
131 if (boost::iequals(call.GetHttpHeader("content-encoding", ""), "gzip")) 140 std::string filename, content;
132 { 141 while (reader->ReadNextFile(filename, content))
133 GzipCompressor compressor; 142 {
134 compressor.Uncompress(dicom, call.GetBodyData(), call.GetBodySize()); 143 if (!content.empty())
135 toStore.SetBuffer(dicom.c_str(), dicom.size()); // (*) 144 {
145 LOG(INFO) << "Uploading DICOM file from ZIP archive: " << filename;
146
147 DicomInstanceToStore toStore;
148 toStore.SetOrigin(DicomInstanceOrigin::FromRest(call));
149 toStore.SetBuffer(content.c_str(), content.size());
150
151 std::string publicId;
152
153 try
154 {
155 StoreStatus status = context.Store(publicId, toStore, StoreInstanceMode_Default);
156
157 Json::Value info;
158 SetupResourceAnswer(info, toStore, status, publicId);
159 answer.append(info);
160 }
161 catch (OrthancException& e)
162 {
163 if (e.GetErrorCode() == ErrorCode_BadFileFormat)
164 {
165 LOG(ERROR) << "Cannot import non-DICOM file from ZIP archive: " << filename;
166 }
167 else
168 {
169 throw;
170 }
171 }
172 }
173 }
174
175 call.GetOutput().AnswerJson(answer);
136 } 176 }
137 else 177 else
138 { 178 {
139 toStore.SetBuffer(call.GetBodyData(), call.GetBodySize()); 179 // The lifetime of "dicom" must be longer than "toStore", as the
140 } 180 // latter can possibly store a reference to the former (*)
141 181 std::string dicom;
142 std::string publicId; 182
143 StoreStatus status = context.Store(publicId, toStore, StoreInstanceMode_Default); 183 DicomInstanceToStore toStore;
144 184 toStore.SetOrigin(DicomInstanceOrigin::FromRest(call));
145 OrthancRestApi::GetApi(call).AnswerStoredInstance(call, toStore, status, publicId); 185
186 if (boost::iequals(call.GetHttpHeader("content-encoding", ""), "gzip"))
187 {
188 GzipCompressor compressor;
189 compressor.Uncompress(dicom, call.GetBodyData(), call.GetBodySize());
190 toStore.SetBuffer(dicom.c_str(), dicom.size()); // (*)
191 }
192 else
193 {
194 toStore.SetBuffer(call.GetBodyData(), call.GetBodySize());
195 }
196
197 std::string publicId;
198 StoreStatus status = context.Store(publicId, toStore, StoreInstanceMode_Default);
199
200 OrthancRestApi::GetApi(call).AnswerStoredInstance(call, toStore, status, publicId);
201 }
146 } 202 }
147 203
148 204
149 205
150 // Registration of the various REST handlers -------------------------------- 206 // Registration of the various REST handlers --------------------------------