comparison Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.h @ 1:fef9a239df5c

adding auto-generated files
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 26 Mar 2020 18:50:10 +0100
parents
children 952e969a2240
comparison
equal deleted inserted replaced
0:7ed502b17b8f 1:fef9a239df5c
1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * In addition, as a special exception, the copyright holders of this
13 * program give permission to link the code of its release with the
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it
15 * that use the same license as the "OpenSSL" library), and distribute
16 * the linked executables. You must obey the GNU General Public License
17 * in all respects for all of the code used other than "OpenSSL". If you
18 * modify file(s) with this exception, you may extend this exception to
19 * your version of the file(s), but you are not obligated to do so. If
20 * you do not wish to do so, delete this exception statement from your
21 * version. If you delete this exception statement from all source files
22 * in the program, then also delete it here.
23 *
24 * This program is distributed in the hope that it will be useful, but
25 * WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 **/
32
33
34 #pragma once
35
36 #include "OrthancPluginException.h"
37
38 #include <orthanc/OrthancCPlugin.h>
39 #include <boost/noncopyable.hpp>
40 #include <boost/lexical_cast.hpp>
41 #include <boost/date_time/posix_time/posix_time.hpp>
42 #include <json/value.h>
43 #include <vector>
44 #include <list>
45 #include <set>
46 #include <map>
47
48
49
50 #if !defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)
51 #define ORTHANC_PLUGINS_VERSION_IS_ABOVE(major, minor, revision) \
52 (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER > major || \
53 (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER == major && \
54 (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER > minor || \
55 (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER == minor && \
56 ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER >= revision))))
57 #endif
58
59
60 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 2, 0)
61 // The "OrthancPluginFindMatcher()" primitive was introduced in Orthanc 1.2.0
62 # define HAS_ORTHANC_PLUGIN_FIND_MATCHER 1
63 #else
64 # define HAS_ORTHANC_PLUGIN_FIND_MATCHER 0
65 #endif
66
67
68 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 4, 2)
69 # define HAS_ORTHANC_PLUGIN_PEERS 1
70 # define HAS_ORTHANC_PLUGIN_JOB 1
71 #else
72 # define HAS_ORTHANC_PLUGIN_PEERS 0
73 # define HAS_ORTHANC_PLUGIN_JOB 0
74 #endif
75
76 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 0)
77 # define HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS 1
78 #else
79 # define HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS 0
80 #endif
81
82 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4)
83 # define HAS_ORTHANC_PLUGIN_METRICS 1
84 #else
85 # define HAS_ORTHANC_PLUGIN_METRICS 0
86 #endif
87
88 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 1, 0)
89 # define HAS_ORTHANC_PLUGIN_HTTP_CLIENT 1
90 #else
91 # define HAS_ORTHANC_PLUGIN_HTTP_CLIENT 0
92 #endif
93
94 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 7)
95 # define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT 1
96 #else
97 # define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT 0
98 #endif
99
100 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 7)
101 # define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER 1
102 #else
103 # define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER 0
104 #endif
105
106 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 0)
107 # define HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP 1
108 #else
109 # define HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP 0
110 #endif
111
112
113
114 namespace OrthancPlugins
115 {
116 typedef void (*RestCallback) (OrthancPluginRestOutput* output,
117 const char* url,
118 const OrthancPluginHttpRequest* request);
119
120 void SetGlobalContext(OrthancPluginContext* context);
121
122 bool HasGlobalContext();
123
124 OrthancPluginContext* GetGlobalContext();
125
126
127 class OrthancImage;
128
129
130 class MemoryBuffer : public boost::noncopyable
131 {
132 private:
133 OrthancPluginMemoryBuffer buffer_;
134
135 void Check(OrthancPluginErrorCode code);
136
137 bool CheckHttp(OrthancPluginErrorCode code);
138
139 public:
140 MemoryBuffer();
141
142 ~MemoryBuffer()
143 {
144 Clear();
145 }
146
147 OrthancPluginMemoryBuffer* operator*()
148 {
149 return &buffer_;
150 }
151
152 // This transfers ownership from "other" to "this"
153 void Assign(OrthancPluginMemoryBuffer& other);
154
155 void Swap(MemoryBuffer& other);
156
157 OrthancPluginMemoryBuffer Release();
158
159 const char* GetData() const
160 {
161 if (buffer_.size > 0)
162 {
163 return reinterpret_cast<const char*>(buffer_.data);
164 }
165 else
166 {
167 return NULL;
168 }
169 }
170
171 size_t GetSize() const
172 {
173 return buffer_.size;
174 }
175
176 bool IsEmpty() const
177 {
178 return GetSize() == 0 || GetData() == NULL;
179 }
180
181 void Clear();
182
183 void ToString(std::string& target) const;
184
185 void ToJson(Json::Value& target) const;
186
187 bool RestApiGet(const std::string& uri,
188 bool applyPlugins);
189
190 bool RestApiGet(const std::string& uri,
191 const std::map<std::string, std::string>& httpHeaders,
192 bool applyPlugins);
193
194 bool RestApiPost(const std::string& uri,
195 const void* body,
196 size_t bodySize,
197 bool applyPlugins);
198
199 bool RestApiPut(const std::string& uri,
200 const void* body,
201 size_t bodySize,
202 bool applyPlugins);
203
204 bool RestApiPost(const std::string& uri,
205 const Json::Value& body,
206 bool applyPlugins);
207
208 bool RestApiPut(const std::string& uri,
209 const Json::Value& body,
210 bool applyPlugins);
211
212 bool RestApiPost(const std::string& uri,
213 const std::string& body,
214 bool applyPlugins)
215 {
216 return RestApiPost(uri, body.empty() ? NULL : body.c_str(), body.size(), applyPlugins);
217 }
218
219 bool RestApiPut(const std::string& uri,
220 const std::string& body,
221 bool applyPlugins)
222 {
223 return RestApiPut(uri, body.empty() ? NULL : body.c_str(), body.size(), applyPlugins);
224 }
225
226 void CreateDicom(const Json::Value& tags,
227 OrthancPluginCreateDicomFlags flags);
228
229 void CreateDicom(const Json::Value& tags,
230 const OrthancImage& pixelData,
231 OrthancPluginCreateDicomFlags flags);
232
233 void ReadFile(const std::string& path);
234
235 void GetDicomQuery(const OrthancPluginWorklistQuery* query);
236
237 void DicomToJson(Json::Value& target,
238 OrthancPluginDicomToJsonFormat format,
239 OrthancPluginDicomToJsonFlags flags,
240 uint32_t maxStringLength);
241
242 bool HttpGet(const std::string& url,
243 const std::string& username,
244 const std::string& password);
245
246 bool HttpPost(const std::string& url,
247 const std::string& body,
248 const std::string& username,
249 const std::string& password);
250
251 bool HttpPut(const std::string& url,
252 const std::string& body,
253 const std::string& username,
254 const std::string& password);
255
256 void GetDicomInstance(const std::string& instanceId);
257 };
258
259
260 class OrthancString : public boost::noncopyable
261 {
262 private:
263 char* str_;
264
265 void Clear();
266
267 public:
268 OrthancString() :
269 str_(NULL)
270 {
271 }
272
273 ~OrthancString()
274 {
275 Clear();
276 }
277
278 // This transfers ownership, warning: The string must have been
279 // allocated by the Orthanc core
280 void Assign(char* str);
281
282 const char* GetContent() const
283 {
284 return str_;
285 }
286
287 void ToString(std::string& target) const;
288
289 void ToJson(Json::Value& target) const;
290 };
291
292
293 class OrthancConfiguration : public boost::noncopyable
294 {
295 private:
296 Json::Value configuration_; // Necessarily a Json::objectValue
297 std::string path_;
298
299 std::string GetPath(const std::string& key) const;
300
301 void LoadConfiguration();
302
303 public:
304 OrthancConfiguration();
305
306 OrthancConfiguration(bool load);
307
308 const Json::Value& GetJson() const
309 {
310 return configuration_;
311 }
312
313 bool IsSection(const std::string& key) const;
314
315 void GetSection(OrthancConfiguration& target,
316 const std::string& key) const;
317
318 bool LookupStringValue(std::string& target,
319 const std::string& key) const;
320
321 bool LookupIntegerValue(int& target,
322 const std::string& key) const;
323
324 bool LookupUnsignedIntegerValue(unsigned int& target,
325 const std::string& key) const;
326
327 bool LookupBooleanValue(bool& target,
328 const std::string& key) const;
329
330 bool LookupFloatValue(float& target,
331 const std::string& key) const;
332
333 bool LookupListOfStrings(std::list<std::string>& target,
334 const std::string& key,
335 bool allowSingleString) const;
336
337 bool LookupSetOfStrings(std::set<std::string>& target,
338 const std::string& key,
339 bool allowSingleString) const;
340
341 std::string GetStringValue(const std::string& key,
342 const std::string& defaultValue) const;
343
344 int GetIntegerValue(const std::string& key,
345 int defaultValue) const;
346
347 unsigned int GetUnsignedIntegerValue(const std::string& key,
348 unsigned int defaultValue) const;
349
350 bool GetBooleanValue(const std::string& key,
351 bool defaultValue) const;
352
353 float GetFloatValue(const std::string& key,
354 float defaultValue) const;
355
356 void GetDictionary(std::map<std::string, std::string>& target,
357 const std::string& key) const;
358 };
359
360 class OrthancImage : public boost::noncopyable
361 {
362 private:
363 OrthancPluginImage* image_;
364
365 void Clear();
366
367 void CheckImageAvailable() const;
368
369 public:
370 OrthancImage();
371
372 OrthancImage(OrthancPluginImage* image);
373
374 OrthancImage(OrthancPluginPixelFormat format,
375 uint32_t width,
376 uint32_t height);
377
378 OrthancImage(OrthancPluginPixelFormat format,
379 uint32_t width,
380 uint32_t height,
381 uint32_t pitch,
382 void* buffer
383 );
384
385 ~OrthancImage()
386 {
387 Clear();
388 }
389
390 void UncompressPngImage(const void* data,
391 size_t size);
392
393 void UncompressJpegImage(const void* data,
394 size_t size);
395
396 void DecodeDicomImage(const void* data,
397 size_t size,
398 unsigned int frame);
399
400 OrthancPluginPixelFormat GetPixelFormat() const;
401
402 unsigned int GetWidth() const;
403
404 unsigned int GetHeight() const;
405
406 unsigned int GetPitch() const;
407
408 const void* GetBuffer() const;
409
410 const OrthancPluginImage* GetObject() const
411 {
412 return image_;
413 }
414
415 void CompressPngImage(MemoryBuffer& target) const;
416
417 void CompressJpegImage(MemoryBuffer& target,
418 uint8_t quality) const;
419
420 void AnswerPngImage(OrthancPluginRestOutput* output) const;
421
422 void AnswerJpegImage(OrthancPluginRestOutput* output,
423 uint8_t quality) const;
424 };
425
426
427 #if HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1
428 class FindMatcher : public boost::noncopyable
429 {
430 private:
431 OrthancPluginFindMatcher* matcher_;
432 const OrthancPluginWorklistQuery* worklist_;
433
434 void SetupDicom(const void* query,
435 uint32_t size);
436
437 public:
438 FindMatcher(const OrthancPluginWorklistQuery* worklist);
439
440 FindMatcher(const void* query,
441 uint32_t size)
442 {
443 SetupDicom(query, size);
444 }
445
446 FindMatcher(const MemoryBuffer& dicom)
447 {
448 SetupDicom(dicom.GetData(), dicom.GetSize());
449 }
450
451 ~FindMatcher();
452
453 bool IsMatch(const void* dicom,
454 uint32_t size) const;
455
456 bool IsMatch(const MemoryBuffer& dicom) const
457 {
458 return IsMatch(dicom.GetData(), dicom.GetSize());
459 }
460 };
461 #endif
462
463
464 bool RestApiGet(Json::Value& result,
465 const std::string& uri,
466 bool applyPlugins);
467
468 bool RestApiGetString(std::string& result,
469 const std::string& uri,
470 bool applyPlugins);
471
472 bool RestApiGetString(std::string& result,
473 const std::string& uri,
474 const std::map<std::string, std::string>& httpHeaders,
475 bool applyPlugins);
476
477 bool RestApiPost(std::string& result,
478 const std::string& uri,
479 const void* body,
480 size_t bodySize,
481 bool applyPlugins);
482
483 bool RestApiPost(Json::Value& result,
484 const std::string& uri,
485 const void* body,
486 size_t bodySize,
487 bool applyPlugins);
488
489 bool RestApiPost(Json::Value& result,
490 const std::string& uri,
491 const Json::Value& body,
492 bool applyPlugins);
493
494 inline bool RestApiPost(Json::Value& result,
495 const std::string& uri,
496 const std::string& body,
497 bool applyPlugins)
498 {
499 return RestApiPost(result, uri, body.empty() ? NULL : body.c_str(),
500 body.size(), applyPlugins);
501 }
502
503 inline bool RestApiPost(Json::Value& result,
504 const std::string& uri,
505 const MemoryBuffer& body,
506 bool applyPlugins)
507 {
508 return RestApiPost(result, uri, body.GetData(),
509 body.GetSize(), applyPlugins);
510 }
511
512 bool RestApiPut(Json::Value& result,
513 const std::string& uri,
514 const void* body,
515 size_t bodySize,
516 bool applyPlugins);
517
518 bool RestApiPut(Json::Value& result,
519 const std::string& uri,
520 const Json::Value& body,
521 bool applyPlugins);
522
523 inline bool RestApiPut(Json::Value& result,
524 const std::string& uri,
525 const std::string& body,
526 bool applyPlugins)
527 {
528 return RestApiPut(result, uri, body.empty() ? NULL : body.c_str(),
529 body.size(), applyPlugins);
530 }
531
532 bool RestApiDelete(const std::string& uri,
533 bool applyPlugins);
534
535 bool HttpDelete(const std::string& url,
536 const std::string& username,
537 const std::string& password);
538
539 void AnswerJson(const Json::Value& value,
540 OrthancPluginRestOutput* output);
541
542 void AnswerString(const std::string& answer,
543 const char* mimeType,
544 OrthancPluginRestOutput* output);
545
546 void AnswerHttpError(uint16_t httpError,
547 OrthancPluginRestOutput* output);
548
549 void AnswerMethodNotAllowed(OrthancPluginRestOutput* output, const char* allowedMethods);
550
551 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 0)
552 const char* AutodetectMimeType(const std::string& path);
553 #endif
554
555 void LogError(const std::string& message);
556
557 void LogWarning(const std::string& message);
558
559 void LogInfo(const std::string& message);
560
561 void ReportMinimalOrthancVersion(unsigned int major,
562 unsigned int minor,
563 unsigned int revision);
564
565 bool CheckMinimalOrthancVersion(unsigned int major,
566 unsigned int minor,
567 unsigned int revision);
568
569
570 namespace Internals
571 {
572 template <RestCallback Callback>
573 static OrthancPluginErrorCode Protect(OrthancPluginRestOutput* output,
574 const char* url,
575 const OrthancPluginHttpRequest* request)
576 {
577 try
578 {
579 Callback(output, url, request);
580 return OrthancPluginErrorCode_Success;
581 }
582 catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
583 {
584 #if HAS_ORTHANC_EXCEPTION == 1 && HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS == 1
585 if (HasGlobalContext() &&
586 e.HasDetails())
587 {
588 // The "false" instructs Orthanc not to log the detailed
589 // error message. This is to avoid duplicating the details,
590 // because "OrthancException" already does it on construction.
591 OrthancPluginSetHttpErrorDetails
592 (GetGlobalContext(), output, e.GetDetails(), false);
593 }
594 #endif
595
596 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
597 }
598 catch (boost::bad_lexical_cast&)
599 {
600 return OrthancPluginErrorCode_BadFileFormat;
601 }
602 catch (...)
603 {
604 return OrthancPluginErrorCode_Plugin;
605 }
606 }
607 }
608
609
610 template <RestCallback Callback>
611 void RegisterRestCallback(const std::string& uri,
612 bool isThreadSafe)
613 {
614 if (isThreadSafe)
615 {
616 OrthancPluginRegisterRestCallbackNoLock
617 (GetGlobalContext(), uri.c_str(), Internals::Protect<Callback>);
618 }
619 else
620 {
621 OrthancPluginRegisterRestCallback
622 (GetGlobalContext(), uri.c_str(), Internals::Protect<Callback>);
623 }
624 }
625
626
627 #if HAS_ORTHANC_PLUGIN_PEERS == 1
628 class OrthancPeers : public boost::noncopyable
629 {
630 private:
631 typedef std::map<std::string, uint32_t> Index;
632
633 OrthancPluginPeers *peers_;
634 Index index_;
635 uint32_t timeout_;
636
637 size_t GetPeerIndex(const std::string& name) const;
638
639 public:
640 OrthancPeers();
641
642 ~OrthancPeers();
643
644 uint32_t GetTimeout() const
645 {
646 return timeout_;
647 }
648
649 void SetTimeout(uint32_t timeout)
650 {
651 timeout_ = timeout;
652 }
653
654 bool LookupName(size_t& target,
655 const std::string& name) const;
656
657 std::string GetPeerName(size_t index) const;
658
659 std::string GetPeerUrl(size_t index) const;
660
661 std::string GetPeerUrl(const std::string& name) const;
662
663 size_t GetPeersCount() const
664 {
665 return index_.size();
666 }
667
668 bool LookupUserProperty(std::string& value,
669 size_t index,
670 const std::string& key) const;
671
672 bool LookupUserProperty(std::string& value,
673 const std::string& peer,
674 const std::string& key) const;
675
676 bool DoGet(MemoryBuffer& target,
677 size_t index,
678 const std::string& uri) const;
679
680 bool DoGet(MemoryBuffer& target,
681 const std::string& name,
682 const std::string& uri) const;
683
684 bool DoGet(Json::Value& target,
685 size_t index,
686 const std::string& uri) const;
687
688 bool DoGet(Json::Value& target,
689 const std::string& name,
690 const std::string& uri) const;
691
692 bool DoPost(MemoryBuffer& target,
693 size_t index,
694 const std::string& uri,
695 const std::string& body) const;
696
697 bool DoPost(MemoryBuffer& target,
698 const std::string& name,
699 const std::string& uri,
700 const std::string& body) const;
701
702 bool DoPost(Json::Value& target,
703 size_t index,
704 const std::string& uri,
705 const std::string& body) const;
706
707 bool DoPost(Json::Value& target,
708 const std::string& name,
709 const std::string& uri,
710 const std::string& body) const;
711
712 bool DoPut(size_t index,
713 const std::string& uri,
714 const std::string& body) const;
715
716 bool DoPut(const std::string& name,
717 const std::string& uri,
718 const std::string& body) const;
719
720 bool DoDelete(size_t index,
721 const std::string& uri) const;
722
723 bool DoDelete(const std::string& name,
724 const std::string& uri) const;
725 };
726 #endif
727
728
729
730 #if HAS_ORTHANC_PLUGIN_JOB == 1
731 class OrthancJob : public boost::noncopyable
732 {
733 private:
734 std::string jobType_;
735 std::string content_;
736 bool hasSerialized_;
737 std::string serialized_;
738 float progress_;
739
740 static void CallbackFinalize(void* job);
741
742 static float CallbackGetProgress(void* job);
743
744 static const char* CallbackGetContent(void* job);
745
746 static const char* CallbackGetSerialized(void* job);
747
748 static OrthancPluginJobStepStatus CallbackStep(void* job);
749
750 static OrthancPluginErrorCode CallbackStop(void* job,
751 OrthancPluginJobStopReason reason);
752
753 static OrthancPluginErrorCode CallbackReset(void* job);
754
755 protected:
756 void ClearContent();
757
758 void UpdateContent(const Json::Value& content);
759
760 void ClearSerialized();
761
762 void UpdateSerialized(const Json::Value& serialized);
763
764 void UpdateProgress(float progress);
765
766 public:
767 OrthancJob(const std::string& jobType);
768
769 virtual ~OrthancJob()
770 {
771 }
772
773 virtual OrthancPluginJobStepStatus Step() = 0;
774
775 virtual void Stop(OrthancPluginJobStopReason reason) = 0;
776
777 virtual void Reset() = 0;
778
779 static OrthancPluginJob* Create(OrthancJob* job /* takes ownership */);
780
781 static std::string Submit(OrthancJob* job /* takes ownership */,
782 int priority);
783
784 static void SubmitAndWait(Json::Value& result,
785 OrthancJob* job /* takes ownership */,
786 int priority);
787
788 // Submit a job from a POST on the REST API with the same
789 // conventions as in the Orthanc core (according to the
790 // "Synchronous" and "Priority" options)
791 static void SubmitFromRestApiPost(OrthancPluginRestOutput* output,
792 const Json::Value& body,
793 OrthancJob* job);
794 };
795 #endif
796
797
798 #if HAS_ORTHANC_PLUGIN_METRICS == 1
799 inline void SetMetricsValue(char* name,
800 float value)
801 {
802 OrthancPluginSetMetricsValue(GetGlobalContext(), name,
803 value, OrthancPluginMetricsType_Default);
804 }
805
806 class MetricsTimer : public boost::noncopyable
807 {
808 private:
809 std::string name_;
810 boost::posix_time::ptime start_;
811
812 public:
813 MetricsTimer(const char* name);
814
815 ~MetricsTimer();
816 };
817 #endif
818
819
820 #if HAS_ORTHANC_PLUGIN_HTTP_CLIENT == 1
821 class HttpClient : public boost::noncopyable
822 {
823 public:
824 typedef std::map<std::string, std::string> HttpHeaders;
825
826 class IRequestBody : public boost::noncopyable
827 {
828 public:
829 virtual ~IRequestBody()
830 {
831 }
832
833 virtual bool ReadNextChunk(std::string& chunk) = 0;
834 };
835
836
837 class IAnswer : public boost::noncopyable
838 {
839 public:
840 virtual ~IAnswer()
841 {
842 }
843
844 virtual void AddHeader(const std::string& key,
845 const std::string& value) = 0;
846
847 virtual void AddChunk(const void* data,
848 size_t size) = 0;
849 };
850
851
852 private:
853 class RequestBodyWrapper;
854
855 uint16_t httpStatus_;
856 OrthancPluginHttpMethod method_;
857 std::string url_;
858 HttpHeaders headers_;
859 std::string username_;
860 std::string password_;
861 uint32_t timeout_;
862 std::string certificateFile_;
863 std::string certificateKeyFile_;
864 std::string certificateKeyPassword_;
865 bool pkcs11_;
866 std::string fullBody_;
867 IRequestBody* chunkedBody_;
868 bool allowChunkedTransfers_;
869
870 #if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1
871 void ExecuteWithStream(uint16_t& httpStatus, // out
872 IAnswer& answer, // out
873 IRequestBody& body) const;
874 #endif
875
876 void ExecuteWithoutStream(uint16_t& httpStatus, // out
877 HttpHeaders& answerHeaders, // out
878 std::string& answerBody, // out
879 const std::string& body) const;
880
881 public:
882 HttpClient();
883
884 uint16_t GetHttpStatus() const
885 {
886 return httpStatus_;
887 }
888
889 void SetMethod(OrthancPluginHttpMethod method)
890 {
891 method_ = method;
892 }
893
894 const std::string& GetUrl() const
895 {
896 return url_;
897 }
898
899 void SetUrl(const std::string& url)
900 {
901 url_ = url;
902 }
903
904 void SetHeaders(const HttpHeaders& headers)
905 {
906 headers_ = headers;
907 }
908
909 void AddHeader(const std::string& key,
910 const std::string& value)
911 {
912 headers_[key] = value;
913 }
914
915 void AddHeaders(const HttpHeaders& headers);
916
917 void SetCredentials(const std::string& username,
918 const std::string& password);
919
920 void ClearCredentials();
921
922 void SetTimeout(unsigned int timeout) // 0 for default timeout
923 {
924 timeout_ = timeout;
925 }
926
927 void SetCertificate(const std::string& certificateFile,
928 const std::string& keyFile,
929 const std::string& keyPassword);
930
931 void ClearCertificate();
932
933 void SetPkcs11(bool pkcs11)
934 {
935 pkcs11_ = pkcs11;
936 }
937
938 void ClearBody();
939
940 void SwapBody(std::string& body);
941
942 void SetBody(const std::string& body);
943
944 void SetBody(IRequestBody& body);
945
946 // This function can be used to disable chunked transfers if the
947 // remote server is Orthanc with a version <= 1.5.6.
948 void SetChunkedTransfersAllowed(bool allow)
949 {
950 allowChunkedTransfers_ = allow;
951 }
952
953 bool IsChunkedTransfersAllowed() const
954 {
955 return allowChunkedTransfers_;
956 }
957
958 void Execute(IAnswer& answer);
959
960 void Execute(HttpHeaders& answerHeaders /* out */,
961 std::string& answerBody /* out */);
962
963 void Execute(HttpHeaders& answerHeaders /* out */,
964 Json::Value& answerBody /* out */);
965
966 void Execute();
967 };
968 #endif
969
970
971
972 class IChunkedRequestReader : public boost::noncopyable
973 {
974 public:
975 virtual ~IChunkedRequestReader()
976 {
977 }
978
979 virtual void AddChunk(const void* data,
980 size_t size) = 0;
981
982 virtual void Execute(OrthancPluginRestOutput* output) = 0;
983 };
984
985
986 typedef IChunkedRequestReader* (*ChunkedRestCallback) (const char* url,
987 const OrthancPluginHttpRequest* request);
988
989
990 namespace Internals
991 {
992 void NullRestCallback(OrthancPluginRestOutput* output,
993 const char* url,
994 const OrthancPluginHttpRequest* request);
995
996 IChunkedRequestReader *NullChunkedRestCallback(const char* url,
997 const OrthancPluginHttpRequest* request);
998
999
1000 #if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1
1001 template <ChunkedRestCallback Callback>
1002 static OrthancPluginErrorCode ChunkedProtect(OrthancPluginServerChunkedRequestReader** reader,
1003 const char* url,
1004 const OrthancPluginHttpRequest* request)
1005 {
1006 try
1007 {
1008 if (reader == NULL)
1009 {
1010 return OrthancPluginErrorCode_InternalError;
1011 }
1012 else
1013 {
1014 *reader = reinterpret_cast<OrthancPluginServerChunkedRequestReader*>(Callback(url, request));
1015 if (*reader == NULL)
1016 {
1017 return OrthancPluginErrorCode_Plugin;
1018 }
1019 else
1020 {
1021 return OrthancPluginErrorCode_Success;
1022 }
1023 }
1024 }
1025 catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
1026 {
1027 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
1028 }
1029 catch (boost::bad_lexical_cast&)
1030 {
1031 return OrthancPluginErrorCode_BadFileFormat;
1032 }
1033 catch (...)
1034 {
1035 return OrthancPluginErrorCode_Plugin;
1036 }
1037 }
1038
1039 OrthancPluginErrorCode ChunkedRequestReaderAddChunk(
1040 OrthancPluginServerChunkedRequestReader* reader,
1041 const void* data,
1042 uint32_t size);
1043
1044 OrthancPluginErrorCode ChunkedRequestReaderExecute(
1045 OrthancPluginServerChunkedRequestReader* reader,
1046 OrthancPluginRestOutput* output);
1047
1048 void ChunkedRequestReaderFinalize(
1049 OrthancPluginServerChunkedRequestReader* reader);
1050
1051 #else
1052
1053 OrthancPluginErrorCode ChunkedRestCompatibility(OrthancPluginRestOutput* output,
1054 const char* url,
1055 const OrthancPluginHttpRequest* request,
1056 RestCallback GetHandler,
1057 ChunkedRestCallback PostHandler,
1058 RestCallback DeleteHandler,
1059 ChunkedRestCallback PutHandler);
1060
1061 template<
1062 RestCallback GetHandler,
1063 ChunkedRestCallback PostHandler,
1064 RestCallback DeleteHandler,
1065 ChunkedRestCallback PutHandler
1066 >
1067 inline OrthancPluginErrorCode ChunkedRestCompatibility(OrthancPluginRestOutput* output,
1068 const char* url,
1069 const OrthancPluginHttpRequest* request)
1070 {
1071 return ChunkedRestCompatibility(output, url, request, GetHandler,
1072 PostHandler, DeleteHandler, PutHandler);
1073 }
1074 #endif
1075 }
1076
1077
1078
1079 // NB: We use a templated class instead of a templated function, because
1080 // default values are only available in functions since C++11
1081 template<
1082 RestCallback GetHandler = Internals::NullRestCallback,
1083 ChunkedRestCallback PostHandler = Internals::NullChunkedRestCallback,
1084 RestCallback DeleteHandler = Internals::NullRestCallback,
1085 ChunkedRestCallback PutHandler = Internals::NullChunkedRestCallback
1086 >
1087 class ChunkedRestRegistration : public boost::noncopyable
1088 {
1089 public:
1090 static void Apply(const std::string& uri)
1091 {
1092 #if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1
1093 OrthancPluginRegisterChunkedRestCallback(
1094 GetGlobalContext(), uri.c_str(),
1095 GetHandler == Internals::NullRestCallback ? NULL : Internals::Protect<GetHandler>,
1096 PostHandler == Internals::NullChunkedRestCallback ? NULL : Internals::ChunkedProtect<PostHandler>,
1097 DeleteHandler == Internals::NullRestCallback ? NULL : Internals::Protect<DeleteHandler>,
1098 PutHandler == Internals::NullChunkedRestCallback ? NULL : Internals::ChunkedProtect<PutHandler>,
1099 Internals::ChunkedRequestReaderAddChunk,
1100 Internals::ChunkedRequestReaderExecute,
1101 Internals::ChunkedRequestReaderFinalize);
1102 #else
1103 OrthancPluginRegisterRestCallbackNoLock(
1104 GetGlobalContext(), uri.c_str(),
1105 Internals::ChunkedRestCompatibility<GetHandler, PostHandler, DeleteHandler, PutHandler>);
1106 #endif
1107 }
1108 };
1109
1110
1111
1112 #if HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP == 1
1113 class IStorageCommitmentScpHandler : public boost::noncopyable
1114 {
1115 public:
1116 virtual ~IStorageCommitmentScpHandler()
1117 {
1118 }
1119
1120 virtual OrthancPluginStorageCommitmentFailureReason Lookup(const std::string& sopClassUid,
1121 const std::string& sopInstanceUid) = 0;
1122
1123 static OrthancPluginErrorCode Lookup(OrthancPluginStorageCommitmentFailureReason* target,
1124 void* rawHandler,
1125 const char* sopClassUid,
1126 const char* sopInstanceUid);
1127
1128 static void Destructor(void* rawHandler);
1129 };
1130 #endif
1131 }