changeset 1589:334d3a92ed83

improvements to the ServeFolders plugin
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 26 Aug 2015 17:43:00 +0200
parents b5bc87a7212d
children ba0226474e22
files CMakeLists.txt Core/Toolbox.cpp Plugins/Samples/ServeFolders/Plugin.cpp Resources/ErrorCodes.json
diffstat 4 files changed, 146 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Wed Aug 26 16:49:46 2015 +0200
+++ b/CMakeLists.txt	Wed Aug 26 17:43:00 2015 +0200
@@ -29,6 +29,7 @@
 SET(ENABLE_JPEG ON CACHE BOOL "Enable JPEG decompression")
 SET(ENABLE_JPEG_LOSSLESS ON CACHE BOOL "Enable JPEG-LS (Lossless) decompression")
 SET(ENABLE_PLUGINS ON CACHE BOOL "Enable plugins")
+SET(BUILD_SERVE_FOLDERS ON CACHE BOOL "Build the ServeFolders plugin")
 
 # Advanced parameters to fine-tune linking against system libraries
 SET(USE_SYSTEM_JSONCPP ON CACHE BOOL "Use the system version of JsonCpp")
@@ -221,10 +222,6 @@
   list(APPEND ORTHANC_UNIT_TESTS_SOURCES
     UnitTestsSources/PluginsTests.cpp
     )
-
-  set(SERVE_FOLDERS_SOURCES
-    Plugins/Samples/ServeFolders/Plugin.cpp
-    )
 endif()
 
 
@@ -328,20 +325,7 @@
     message(FATAL_ERROR "Error while computing the version information: ${Failure}")
   endif()
 
-  execute_process(
-    COMMAND 
-    ${PYTHON_EXECUTABLE} ${ORTHANC_ROOT}/Resources/WindowsResources.py
-    ${ORTHANC_VERSION} ServeFolders ServeFolders.dll "Orthanc plugin to serve additional folders"
-    ERROR_VARIABLE Failure
-    OUTPUT_FILE ${AUTOGENERATED_DIR}/ServeFolders.rc
-    )
-
-  if (Failure)
-    message(FATAL_ERROR "Error while computing the version information: ${Failure}")
-  endif()
-
   list(APPEND ORTHANC_RESOURCES ${AUTOGENERATED_DIR}/Orthanc.rc)
-  list(APPEND SERVE_FOLDERS_SOURCES ${AUTOGENERATED_DIR}/ServeFolders.rc)
 endif()
 
 
@@ -464,15 +448,28 @@
 ## Build the "ServeFolders" plugin
 #####################################################################
 
-if (ENABLE_PLUGINS)
+if (ENABLE_PLUGINS AND BUILD_SERVE_FOLDERS)
+  execute_process(
+    COMMAND 
+    ${PYTHON_EXECUTABLE} ${ORTHANC_ROOT}/Resources/WindowsResources.py
+    ${ORTHANC_VERSION} ServeFolders ServeFolders.dll "Orthanc plugin to serve additional folders"
+    ERROR_VARIABLE Failure
+    OUTPUT_FILE ${AUTOGENERATED_DIR}/ServeFolders.rc
+    )
+
+  if (Failure)
+    message(FATAL_ERROR "Error while computing the version information: ${Failure}")
+  endif()
+
   add_definitions(-DSERVE_FOLDERS_VERSION="${ORTHANC_VERSION}")
 
   include_directories(${CMAKE_SOURCE_DIR}/Plugins/Include)
 
-  add_library(
-    ServeFolders SHARED 
-    ${SERVE_FOLDERS_SOURCES}
+  add_library(ServeFolders SHARED 
+    ${BOOST_SOURCES}
     ${JSONCPP_SOURCES}
+    Plugins/Samples/ServeFolders/Plugin.cpp
+    ${AUTOGENERATED_DIR}/ServeFolders.rc
     )
 
   set_target_properties(
--- a/Core/Toolbox.cpp	Wed Aug 26 16:49:46 2015 +0200
+++ b/Core/Toolbox.cpp	Wed Aug 26 17:43:00 2015 +0200
@@ -208,6 +208,12 @@
   void Toolbox::ReadFile(std::string& content,
                          const std::string& path) 
   {
+    if (!boost::filesystem::is_regular_file(path))
+    {
+      LOG(ERROR) << "The path does not point to a regular file: " << path;
+      throw OrthancException(ErrorCode_RegularFileExpected);
+    }
+
     boost::filesystem::ifstream f;
     f.open(path, std::ifstream::in | std::ifstream::binary);
     if (!f.good())
--- a/Plugins/Samples/ServeFolders/Plugin.cpp	Wed Aug 26 16:49:46 2015 +0200
+++ b/Plugins/Samples/ServeFolders/Plugin.cpp	Wed Aug 26 17:43:00 2015 +0200
@@ -22,11 +22,8 @@
 
 #include <json/reader.h>
 #include <json/value.h>
-#include <string.h>
-#include <stdio.h>
-#include <fstream>
-#include <algorithm>
-#include <sys/stat.h>
+#include <boost/filesystem.hpp>
+
 
 static OrthancPluginContext* context_ = NULL;
 static std::map<std::string, std::string> folders_;
@@ -136,6 +133,80 @@
 }
 
 
+
+static bool LookupFolder(std::string& folder,
+                         OrthancPluginRestOutput* output,
+                         const OrthancPluginHttpRequest* request)
+{
+  const std::string uri = request->groups[0];
+
+  std::map<std::string, std::string>::const_iterator found = folders_.find(uri);
+  if (found == folders_.end())
+  {
+    std::string s = "Unknown URI in plugin server-folders: " + uri;
+    OrthancPluginLogError(context_, s.c_str());
+    OrthancPluginSendHttpStatusCode(context_, output, 404);
+    return false;
+  }
+  else
+  {
+    folder = found->second;
+    return true;
+  }
+}
+
+
+static int32_t IndexCallback(OrthancPluginRestOutput* output,
+                             const char* url,
+                             const OrthancPluginHttpRequest* request)
+{
+  namespace fs = boost::filesystem;
+
+  if (request->method != OrthancPluginHttpMethod_Get)
+  {
+    OrthancPluginSendMethodNotAllowed(context_, output, "GET");
+    return 0;
+  }
+
+  std::string folder;
+  if (LookupFolder(folder, output, request))
+  {
+    std::string baseUri = "/" + std::string(request->groups[0]);
+
+    if (fs::is_regular_file(fs::path(folder) / "index.html"))
+    {
+      std::string s = baseUri + "/index.html";
+      OrthancPluginRedirect(context_, output, s.c_str());
+    }
+    else
+    {
+      std::string s;
+      s += "<html>\n";
+      s += "  <body>\n";
+      s += "    <ul>\n";
+
+      fs::directory_iterator end;
+      for (fs::directory_iterator it(folder) ; it != end; ++it)
+      {
+        if (fs::is_regular_file(it->status()))
+        {
+          std::string f = it->path().filename().string();
+          s += "      <li><a href=\"" + baseUri + "/" + f + "\">" + f + "</a></li>";
+        }
+      }
+
+      s += "    </ul>\n";
+      s += "  </body>\n";
+      s += "</html>\n";
+
+      OrthancPluginAnswerBuffer(context_, output, s.c_str(), s.size(), "text/html");
+    }
+  }
+
+  return 0;
+}
+
+
 static int32_t FolderCallback(OrthancPluginRestOutput* output,
                               const char* url,
                               const OrthancPluginHttpRequest* request)
@@ -146,32 +217,27 @@
     return 0;
   }
 
-  const std::string uri = request->groups[0];
-  const std::string item = request->groups[1];
+  std::string folder;
 
-  std::map<std::string, std::string>::const_iterator found = folders_.find(uri);
-  if (found == folders_.end())
+  if (LookupFolder(folder, output, request))
   {
-    std::string s = "Unknown URI in plugin server-folders: " + uri;
-    OrthancPluginLogError(context_, s.c_str());
-    OrthancPluginSendHttpStatusCode(context_, output, 404);
-    return 0;
-  }
+    const std::string item = request->groups[1];
+
+    std::string path = folder + "/" + item;
+    const char* mime = GetMimeType(path);
 
-  std::string path = found->second + "/" + item;
-  const char* mime = GetMimeType(path);
-
-  std::string s;
-  if (ReadFile(s, path))
-  {
-    const char* resource = s.size() ? s.c_str() : NULL;
-    OrthancPluginAnswerBuffer(context_, output, resource, s.size(), mime);
-  }
-  else
-  {
-    std::string s = "Inexistent file in served folder: " + path;
-    OrthancPluginLogError(context_, s.c_str());
-    OrthancPluginSendHttpStatusCode(context_, output, 404);
+    std::string s;
+    if (ReadFile(s, path))
+    {
+      const char* resource = s.size() ? s.c_str() : NULL;
+      OrthancPluginAnswerBuffer(context_, output, resource, s.size(), mime);
+    }
+    else
+    {
+      std::string s = "Inexistent file in served folder: " + path;
+      OrthancPluginLogError(context_, s.c_str());
+      OrthancPluginSendHttpStatusCode(context_, output, 404);
+    }
   }
 
   return 0;
@@ -200,7 +266,7 @@
     for (std::map<std::string, std::string>::const_iterator
            it = folders_.begin(); it != folders_.end(); ++it)
     {
-      s += "<li><a href=\"" + it->first + "/index.html\">" + it->first + "</li>\n";
+      s += "<li><a href=\"/" + it->first + "\">" + it->first + "</li>\n";
     }
     
     s += "</ul>\n";
@@ -214,7 +280,6 @@
 }
 
 
-
 extern "C"
 {
   ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context)
@@ -266,7 +331,7 @@
     {
       std::string baseUri = *it;
 
-      // Remove the heading and trailing slashes if any
+      // Remove the heading and trailing slashes in the root URI, if any
       while (!baseUri.empty() &&
              *baseUri.begin() == '/')
       {
@@ -285,11 +350,28 @@
         return -1;
       }
 
-      const std::string path = configuration["ServeFolders"][*it].asString();
-      const std::string regex = "/(" + baseUri + ")/(.*)";
+      // Check whether the source folder exists and is indeed a directory
+      const std::string folder = configuration["ServeFolders"][*it].asString();
+      if (!boost::filesystem::is_directory(folder))
+      {
+        std::string msg = "Trying and serve an inexistent folder: " + folder;
+        OrthancPluginLogError(context_, msg.c_str());
+        return -1;
+      }
+
+      folders_[baseUri] = folder;
 
-      OrthancPluginRegisterRestCallback(context, regex.c_str(), FolderCallback);
-      folders_[baseUri] = path;
+      // Register the callback to serve the index of the folder
+      {
+        const std::string regex = "/(" + baseUri + ")";
+        OrthancPluginRegisterRestCallback(context, regex.c_str(), IndexCallback);
+      }
+
+      // Register the callback to serve the folder
+      {
+        const std::string regex = "/(" + baseUri + ")/(.*)";
+        OrthancPluginRegisterRestCallback(context, regex.c_str(), FolderCallback);
+      }
     }
 
     OrthancPluginRegisterRestCallback(context, INDEX_URI, ListServedFolders);
--- a/Resources/ErrorCodes.json	Wed Aug 26 16:49:46 2015 +0200
+++ b/Resources/ErrorCodes.json	Wed Aug 26 17:43:00 2015 +0200
@@ -157,6 +157,11 @@
     "Code": 27, 
     "Name": "UnknownDicomTag", 
     "Description": "Unknown DICOM tag"
+  }, 
+  {
+    "Code": 28, 
+    "Name": "RegularFileExpected", 
+    "Description": "The path does not point to a regular file"
   },