changeset 216:e5d5d4a9a326

refactored upload of dicom through http
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 29 Nov 2012 11:57:35 +0100
parents c07170f3f4f7
children 1ac3aacd10a5
files Core/RestApi/RestApi.h Core/RestApi/RestApiOutput.cpp Core/RestApi/RestApiOutput.h OrthancServer/OrthancRestApi.cpp OrthancServer/OrthancRestApi2.cpp OrthancServer/ServerEnumerations.cpp OrthancServer/ServerEnumerations.h
diffstat 7 files changed, 99 insertions(+), 94 deletions(-) [+]
line wrap: on
line diff
--- a/Core/RestApi/RestApi.h	Thu Nov 29 11:25:29 2012 +0100
+++ b/Core/RestApi/RestApi.h	Thu Nov 29 11:57:35 2012 +0100
@@ -107,7 +107,7 @@
       const std::string* data_;
 
     public:
-      const std::string& GetData()
+      const std::string& GetPutBody()
       {
         return *data_;
       }
@@ -121,7 +121,7 @@
       const std::string* data_;
 
     public:
-      const std::string& GetData()
+      const std::string& GetPostBody()
       {
         return *data_;
       }
--- a/Core/RestApi/RestApiOutput.cpp	Thu Nov 29 11:25:29 2012 +0100
+++ b/Core/RestApi/RestApiOutput.cpp	Thu Nov 29 11:57:35 2012 +0100
@@ -39,12 +39,12 @@
   RestApiOutput::RestApiOutput(HttpOutput& output) : 
     output_(output)
   {
-    existingResource_ = false;
+    alreadySent_ = false;
   }
 
   RestApiOutput::~RestApiOutput()
   {
-    if (!existingResource_)
+    if (!alreadySent_)
     {
       output_.SendHeader(Orthanc_HttpStatus_400_BadRequest);
     }
@@ -52,7 +52,7 @@
   
   void RestApiOutput::CheckStatus()
   {
-    if (existingResource_)
+    if (alreadySent_)
     {
       throw OrthancException(ErrorCode_BadSequenceOfCalls);
     }
@@ -62,7 +62,7 @@
   {
     CheckStatus();
     sender.Send(output_);
-    existingResource_ = true;
+    alreadySent_ = true;
   }
 
   void RestApiOutput::AnswerJson(const Json::Value& value)
@@ -71,7 +71,7 @@
     Json::StyledWriter writer;
     std::string s = writer.write(value);
     output_.AnswerBufferWithContentType(s, "application/json");
-    existingResource_ = true;
+    alreadySent_ = true;
   }
 
   void RestApiOutput::AnswerBuffer(const std::string& buffer,
@@ -79,13 +79,25 @@
   {
     CheckStatus();
     output_.AnswerBufferWithContentType(buffer, contentType);
-    existingResource_ = true;
+    alreadySent_ = true;
   }
 
   void RestApiOutput::Redirect(const std::string& path)
   {
     CheckStatus();
     output_.Redirect(path);
-    existingResource_ = true;
+    alreadySent_ = true;
+  }
+
+  void RestApiOutput::SignalError(Orthanc_HttpStatus status)
+  {
+    if (status != Orthanc_HttpStatus_415_UnsupportedMediaType)
+    {
+      throw OrthancException("This HTTP status is not allowed in a REST API");
+    }
+
+    CheckStatus();
+    output_.SendHeader(status);
+    alreadySent_ = true;    
   }
 }
--- a/Core/RestApi/RestApiOutput.h	Thu Nov 29 11:25:29 2012 +0100
+++ b/Core/RestApi/RestApiOutput.h	Thu Nov 29 11:57:35 2012 +0100
@@ -43,7 +43,7 @@
   {
   private:
     HttpOutput& output_;
-    bool existingResource_;
+    bool alreadySent_;
 
     void CheckStatus();
 
@@ -59,6 +59,8 @@
     void AnswerBuffer(const std::string& buffer,
                       const std::string& contentType);
 
+    void SignalError(Orthanc_HttpStatus status);
+
     void Redirect(const std::string& path);
   };
 }
--- a/OrthancServer/OrthancRestApi.cpp	Thu Nov 29 11:25:29 2012 +0100
+++ b/OrthancServer/OrthancRestApi.cpp	Thu Nov 29 11:57:35 2012 +0100
@@ -52,59 +52,6 @@
     output.AnswerBufferWithContentType(s, "application/json");
   }
 
-  bool OrthancRestApi::Store(Json::Value& result,
-                               const std::string& postData)
-  {
-    // Prepare an input stream for the memory buffer
-    DcmInputBufferStream is;
-    if (postData.size() > 0)
-    {
-      is.setBuffer(&postData[0], postData.size());
-    }
-    is.setEos();
-
-    //printf("[%d]\n", postData.size());
-
-    DcmFileFormat dicomFile;
-    if (dicomFile.read(is).good())
-    {
-      DicomMap dicomSummary;
-      FromDcmtkBridge::Convert(dicomSummary, *dicomFile.getDataset());
-
-      DicomInstanceHasher hasher(dicomSummary);
-
-      Json::Value dicomJson;
-      FromDcmtkBridge::ToJson(dicomJson, *dicomFile.getDataset());
-      
-      StoreStatus status = StoreStatus_Failure;
-      if (postData.size() > 0)
-      {
-        status = index_.Store
-          (storage_, reinterpret_cast<const char*>(&postData[0]),
-           postData.size(), dicomSummary, dicomJson, "");
-      }
-
-      result["ID"] = hasher.HashInstance();
-      result["Path"] = "/instances/" + hasher.HashInstance();
-
-      switch (status)
-      {
-      case StoreStatus_Success:
-        result["Status"] = "Success";
-        return true;
-      
-      case StoreStatus_AlreadyStored:
-        result["Status"] = "AlreadyStored";
-        return true;
-
-      default:
-        return false;
-      }
-    }
-
-    return false;
-  }
-
   void OrthancRestApi::ConnectToModality(DicomUserConnection& c,
                                            const std::string& name)
   {
@@ -341,37 +288,6 @@
     Json::Value result(Json::objectValue);
 
 
-    // List all the instances ---------------------------------------------------
- 
-    if (uri.size() == 1 && uri[0] == "instances")
-    {
-      if (method == "GET")
-      {
-        result = Json::Value(Json::arrayValue);
-        index_.GetAllUuids(result, ResourceType_Instance);
-        existingResource = true;
-      }
-      else if (method == "POST")
-      {
-        // Add a new instance to the storage
-        if (Store(result, postData))
-        {
-          SendJson(output, result);
-          return;
-        }
-        else
-        {
-          output.SendHeader(Orthanc_HttpStatus_415_UnsupportedMediaType);
-          return;
-        }
-      }
-      else
-      {
-        output.SendMethodNotAllowedError("GET,POST");
-        return;
-      }
-    }
-
     // DICOM bridge -------------------------------------------------------------
 
     if ((uri.size() == 2 ||
--- a/OrthancServer/OrthancRestApi2.cpp	Thu Nov 29 11:25:29 2012 +0100
+++ b/OrthancServer/OrthancRestApi2.cpp	Thu Nov 29 11:57:35 2012 +0100
@@ -41,6 +41,7 @@
 #include <dcmtk/dcmdata/dcistrmb.h>
 #include <dcmtk/dcmdata/dcfilefo.h>
 #include <boost/lexical_cast.hpp>
+#include <glog/logging.h>
 
 
 #define RETRIEVE_CONTEXT(call)                                          \
@@ -269,6 +270,58 @@
   }
 
 
+  // Upload of DICOM files through HTTP ---------------------------------------
+
+  static void UploadDicomFile(RestApi::PostCall& call)
+  {
+    RETRIEVE_CONTEXT(call);
+
+    const std::string& postData = call.GetPostBody();
+
+    LOG(INFO) << "Receiving a DICOM file of " << postData.size() << " bytes through HTTP";
+
+    // Prepare an input stream for the memory buffer
+    DcmInputBufferStream is;
+    if (postData.size() > 0)
+    {
+      is.setBuffer(&postData[0], postData.size());
+    }
+    is.setEos();
+
+    DcmFileFormat dicomFile;
+    if (!dicomFile.read(is).good())
+    {
+      call.GetOutput().SignalError(Orthanc_HttpStatus_415_UnsupportedMediaType);
+      return;
+    }
+
+    DicomMap dicomSummary;
+    FromDcmtkBridge::Convert(dicomSummary, *dicomFile.getDataset());
+
+    DicomInstanceHasher hasher(dicomSummary);
+
+    Json::Value dicomJson;
+    FromDcmtkBridge::ToJson(dicomJson, *dicomFile.getDataset());
+      
+    StoreStatus status = StoreStatus_Failure;
+    if (postData.size() > 0)
+    {
+      status = context.GetIndex().Store
+        (context.GetFileStorage(), reinterpret_cast<const char*>(&postData[0]),
+         postData.size(), dicomSummary, dicomJson, "");
+    }
+
+    Json::Value result = Json::objectValue;
+
+    if (status != StoreStatus_Failure)
+    {
+      result["ID"] = hasher.HashInstance();
+      result["Path"] = GetBasePath(ResourceType_Instance, hasher.HashInstance());
+    }
+
+    result["Status"] = ToString(status);
+    call.GetOutput().AnswerJson(result);
+  }
 
 
   // DICOM bridge -------------------------------------------------------------
@@ -305,6 +358,7 @@
     Register("/changes", GetChanges);
     Register("/modalities", ListModalities);
 
+    Register("/instances", UploadDicomFile);
     Register("/instances", ListResources<ResourceType_Instance>);
     Register("/patients", ListResources<ResourceType_Patient>);
     Register("/series", ListResources<ResourceType_Series>);
--- a/OrthancServer/ServerEnumerations.cpp	Thu Nov 29 11:25:29 2012 +0100
+++ b/OrthancServer/ServerEnumerations.cpp	Thu Nov 29 11:57:35 2012 +0100
@@ -99,6 +99,25 @@
     }
   }
 
+  const char* ToString(StoreStatus status)
+  {
+    switch (status)
+    {
+    case StoreStatus_Success:
+      return "Success";
+
+    case StoreStatus_AlreadyStored:
+      return "AlreadyStored";
+
+    case StoreStatus_Failure:
+      return "Failure";
+
+    default:
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
   const char* ToString(ChangeType type)
   {
     switch (type)
--- a/OrthancServer/ServerEnumerations.h	Thu Nov 29 11:25:29 2012 +0100
+++ b/OrthancServer/ServerEnumerations.h	Thu Nov 29 11:57:35 2012 +0100
@@ -99,5 +99,7 @@
 
   const char* ToString(SeriesStatus status);
 
+  const char* ToString(StoreStatus status);
+
   const char* ToString(ChangeType type);
 }