changeset 1514:d73a2178b319

support of deflate and gzip content-types
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 10 Aug 2015 16:43:59 +0200
parents fe07f82d83d3
children c94353fbd4e9
files Core/Enumerations.h Core/FileStorage/CompressedFileStorageAccessor.cpp Core/HttpServer/HttpOutput.cpp Core/RestApi/RestApi.cpp Core/RestApi/RestApiOutput.cpp Core/RestApi/RestApiOutput.h NEWS OrthancServer/ServerContext.cpp UnitTestsSources/FileStorageTests.cpp UnitTestsSources/ServerIndexTests.cpp
diffstat 10 files changed, 79 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/Core/Enumerations.h	Mon Aug 10 16:01:37 2015 +0200
+++ b/Core/Enumerations.h	Mon Aug 10 16:43:59 2015 +0200
@@ -325,7 +325,7 @@
      * buffer is non-empty, the buffer is compatible with the
      * "deflate" HTTP compression.
      **/
-    CompressionType_Zlib = 2
+    CompressionType_ZlibWithSize = 2
   };
 
   enum FileContentType
--- a/Core/FileStorage/CompressedFileStorageAccessor.cpp	Mon Aug 10 16:01:37 2015 +0200
+++ b/Core/FileStorage/CompressedFileStorageAccessor.cpp	Mon Aug 10 16:43:59 2015 +0200
@@ -64,7 +64,7 @@
       return FileInfo(uuid, type, size, md5);
     }
 
-    case CompressionType_Zlib:
+    case CompressionType_ZlibWithSize:
     {
       std::string compressed;
       zlib_.Compress(compressed, data, size);
@@ -86,7 +86,7 @@
       }
 
       return FileInfo(uuid, type, size, md5,
-                      CompressionType_Zlib, compressed.size(), compressedMD5);
+                      CompressionType_ZlibWithSize, compressed.size(), compressedMD5);
     }
 
     default:
@@ -131,7 +131,7 @@
       GetStorageArea().Read(content, uuid, type);
       break;
 
-    case CompressionType_Zlib:
+    case CompressionType_ZlibWithSize:
     {
       std::string compressed;
       GetStorageArea().Read(compressed, uuid, type);
@@ -155,7 +155,7 @@
       return uncompressedAccessor.ConstructHttpFileSender(uuid, type);
     }
 
-    case CompressionType_Zlib:
+    case CompressionType_ZlibWithSize:
     {
       std::string compressed;
       GetStorageArea().Read(compressed, uuid, type);
--- a/Core/HttpServer/HttpOutput.cpp	Mon Aug 10 16:01:37 2015 +0200
+++ b/Core/HttpServer/HttpOutput.cpp	Mon Aug 10 16:43:59 2015 +0200
@@ -36,6 +36,7 @@
 #include "../Logging.h"
 #include "../OrthancException.h"
 #include "../Toolbox.h"
+#include "../Compression/GzipCompressor.h"
 #include "../Compression/ZlibCompressor.h"
 
 #include <iostream>
@@ -275,16 +276,27 @@
           break;
         }
 
+        case HttpCompression_Gzip:
         case HttpCompression_Deflate:
         {
-          LOG(TRACE) << "Compressing a HTTP answer using Deflate";
-          ZlibCompressor compressor;
+          std::string compressed, encoding;
 
-          // Do not prefix the buffer with its uncompressed size, to be compatible with "deflate"
-          compressor.SetPrefixWithUncompressedSize(false);  
+          if (compression == HttpCompression_Deflate)
+          {
+            encoding = "deflate";
+            ZlibCompressor compressor;
+            // Do not prefix the buffer with its uncompressed size, to be compatible with "deflate"
+            compressor.SetPrefixWithUncompressedSize(false);  
+            compressor.Compress(compressed, buffer, length);
+          }
+          else
+          {
+            encoding = "gzip";
+            GzipCompressor compressor;
+            compressor.Compress(compressed, buffer, length);
+          }
 
-          std::string compressed;
-          compressor.Compress(compressed, buffer, length);
+          LOG(TRACE) << "Compressing a HTTP answer using " << encoding;
 
           // The body is empty, do not use Deflate compression
           if (compressed.size() == 0)
@@ -293,7 +305,7 @@
           }
           else
           {
-            stateMachine_.AddHeader("Content-Encoding", "deflate");
+            stateMachine_.AddHeader("Content-Encoding", encoding);
             stateMachine_.SendBody(compressed.c_str(), compressed.size());
           }
 
--- a/Core/RestApi/RestApi.cpp	Mon Aug 10 16:01:37 2015 +0200
+++ b/Core/RestApi/RestApi.cpp	Mon Aug 10 16:43:59 2015 +0200
@@ -205,12 +205,15 @@
         for (size_t i = 0; i < encodings.size(); i++)
         {
           std::string s = Toolbox::StripSpaces(encodings[i]);
+
           if (s == "deflate")
           {
-            wrappedOutput.SetHttpCompression(HttpCompression_Deflate);
+            wrappedOutput.AllowDeflateCompression(true);
           }
-
-          // TODO HttpCompression_Gzip ?
+          else if (s == "gzip")
+          {
+            wrappedOutput.AllowGzipCompression(true);
+          }
         }
       }
     }
--- a/Core/RestApi/RestApiOutput.cpp	Mon Aug 10 16:01:37 2015 +0200
+++ b/Core/RestApi/RestApiOutput.cpp	Mon Aug 10 16:43:59 2015 +0200
@@ -45,7 +45,8 @@
                                HttpMethod method) : 
     output_(output),
     method_(method),
-    compression_(HttpCompression_None),
+    allowDeflateCompression_(false),
+    allowGzipCompression_(false),
     convertJsonToXml_(false)
   {
     alreadySent_ = false;
@@ -78,6 +79,24 @@
     }
   }
 
+
+  HttpCompression  RestApiOutput::GetPreferredCompression() const
+  {
+    if (allowGzipCompression_)
+    {
+      return HttpCompression_Gzip;
+    }
+    else if (allowDeflateCompression_)
+    {
+      return HttpCompression_Deflate;
+    }
+    else
+    {
+      return HttpCompression_None;
+    }
+  }
+
+
   void RestApiOutput::AnswerFile(HttpFileSender& sender)
   {
     CheckStatus();
@@ -95,7 +114,7 @@
       std::string s;
       Toolbox::JsonToXml(s, value);
       output_.SetContentType("application/xml");
-      output_.SendBody(s, compression_);
+      output_.SendBody(s, GetPreferredCompression());
 #else
       LOG(ERROR) << "Orthanc was compiled without XML support";
       throw OrthancException(ErrorCode_InternalError);
@@ -105,7 +124,7 @@
     {
       Json::StyledWriter writer;
       output_.SetContentType("application/json");
-      output_.SendBody(writer.write(value), compression_);
+      output_.SendBody(writer.write(value), GetPreferredCompression());
     }
 
     alreadySent_ = true;
@@ -114,10 +133,8 @@
   void RestApiOutput::AnswerBuffer(const std::string& buffer,
                                    const std::string& contentType)
   {
-    CheckStatus();
-    output_.SetContentType(contentType.c_str());
-    output_.SendBody(buffer, compression_);
-    alreadySent_ = true;
+    AnswerBuffer(buffer.size() == 0 ? NULL : buffer.c_str(),
+                 buffer.size(), contentType);
   }
 
   void RestApiOutput::AnswerBuffer(const void* buffer,
@@ -126,7 +143,7 @@
   {
     CheckStatus();
     output_.SetContentType(contentType.c_str());
-    output_.SendBody(buffer, length, compression_);
+    output_.SendBody(buffer, length, GetPreferredCompression());
     alreadySent_ = true;
   }
 
--- a/Core/RestApi/RestApiOutput.h	Mon Aug 10 16:01:37 2015 +0200
+++ b/Core/RestApi/RestApiOutput.h	Mon Aug 10 16:43:59 2015 +0200
@@ -42,14 +42,17 @@
   class RestApiOutput
   {
   private:
-    HttpOutput&      output_;
-    HttpMethod       method_;
-    HttpCompression  compression_;
-    bool             alreadySent_;
-    bool             convertJsonToXml_;
+    HttpOutput&  output_;
+    HttpMethod   method_;
+    bool         allowDeflateCompression_;
+    bool         allowGzipCompression_;
+    bool         alreadySent_;
+    bool         convertJsonToXml_;
 
     void CheckStatus();
 
+    HttpCompression  GetPreferredCompression() const;
+
   public:
     RestApiOutput(HttpOutput& output,
                   HttpMethod method);
@@ -76,14 +79,14 @@
       return convertJsonToXml_;
     }
 
-    void SetHttpCompression(HttpCompression compression)
+    void AllowDeflateCompression(bool allow)
     {
-      compression_ = compression;
+      allowDeflateCompression_ = allow;
     }
 
-    HttpCompression GetHttpCompression() const
+    void AllowGzipCompression(bool allow)
     {
-      return compression_;
+      allowGzipCompression_ = allow;
     }
 
     void AnswerFile(HttpFileSender& sender);
--- a/NEWS	Mon Aug 10 16:01:37 2015 +0200
+++ b/NEWS	Mon Aug 10 16:43:59 2015 +0200
@@ -2,6 +2,7 @@
 ===============================
 
 * "limit" and "since" arguments while retrieving DICOM resources in the REST API
+* Support of "deflate" and "gzip" content-types in HTTP requests
 
 
 Version 0.9.3 (2015/08/07)
--- a/OrthancServer/ServerContext.cpp	Mon Aug 10 16:01:37 2015 +0200
+++ b/OrthancServer/ServerContext.cpp	Mon Aug 10 16:43:59 2015 +0200
@@ -214,7 +214,8 @@
 
       if (compressionEnabled_)
       {
-        accessor_.SetCompressionForNextOperations(CompressionType_Zlib);
+        // TODO Should we use "gzip" instead?
+        accessor_.SetCompressionForNextOperations(CompressionType_ZlibWithSize);
       }
       else
       {
@@ -403,7 +404,8 @@
     
     if (compressionEnabled_)
     {
-      accessor_.SetCompressionForNextOperations(CompressionType_Zlib);
+      // TODO Should we use "gzip" instead?
+      accessor_.SetCompressionForNextOperations(CompressionType_ZlibWithSize);
     }
     else
     {
--- a/UnitTestsSources/FileStorageTests.cpp	Mon Aug 10 16:01:37 2015 +0200
+++ b/UnitTestsSources/FileStorageTests.cpp	Mon Aug 10 16:43:59 2015 +0200
@@ -188,7 +188,7 @@
   FilesystemStorage s("UnitTestsStorage");
   CompressedFileStorageAccessor accessor(s);
 
-  accessor.SetCompressionForNextOperations(CompressionType_Zlib);
+  accessor.SetCompressionForNextOperations(CompressionType_ZlibWithSize);
   std::string data = "Hello world";
   FileInfo info = accessor.Write(data, FileContentType_Dicom);
   
@@ -196,7 +196,7 @@
   accessor.Read(r, info.GetUuid(), FileContentType_Unknown);
 
   ASSERT_EQ(data, r);
-  ASSERT_EQ(CompressionType_Zlib, info.GetCompressionType());
+  ASSERT_EQ(CompressionType_ZlibWithSize, info.GetCompressionType());
   ASSERT_EQ(11u, info.GetUncompressedSize());
   ASSERT_EQ(FileContentType_Dicom, info.GetContentType());
 }
@@ -211,13 +211,13 @@
   std::string compressedData = "Hello";
   std::string uncompressedData = "HelloWorld";
 
-  accessor.SetCompressionForNextOperations(CompressionType_Zlib);
+  accessor.SetCompressionForNextOperations(CompressionType_ZlibWithSize);
   FileInfo compressedInfo = accessor.Write(compressedData, FileContentType_Dicom);
   
   accessor.SetCompressionForNextOperations(CompressionType_None);
   FileInfo uncompressedInfo = accessor.Write(uncompressedData, FileContentType_Dicom);
   
-  accessor.SetCompressionForNextOperations(CompressionType_Zlib);
+  accessor.SetCompressionForNextOperations(CompressionType_ZlibWithSize);
   accessor.Read(r, compressedInfo.GetUuid(), FileContentType_Unknown);
   ASSERT_EQ(compressedData, r);
 
@@ -227,7 +227,7 @@
 
   /*
   // This test is too slow on Windows
-  accessor.SetCompressionForNextOperations(CompressionType_Zlib);
+  accessor.SetCompressionForNextOperations(CompressionType_ZlibWithSize);
   ASSERT_THROW(accessor.Read(r, uncompressedInfo.GetUuid(), FileContentType_Unknown), OrthancException);
   */
 }
--- a/UnitTestsSources/ServerIndexTests.cpp	Mon Aug 10 16:01:37 2015 +0200
+++ b/UnitTestsSources/ServerIndexTests.cpp	Mon Aug 10 16:43:59 2015 +0200
@@ -350,7 +350,7 @@
   ASSERT_EQ(0u, md.size());
 
   index_->AddAttachment(a[4], FileInfo("my json file", FileContentType_DicomAsJson, 42, "md5", 
-                                       CompressionType_Zlib, 21, "compressedMD5"));
+                                       CompressionType_ZlibWithSize, 21, "compressedMD5"));
   index_->AddAttachment(a[4], FileInfo("my dicom file", FileContentType_Dicom, 42, "md5"));
   index_->AddAttachment(a[6], FileInfo("world", FileContentType_Dicom, 44, "md5"));
   index_->SetMetadata(a[4], MetadataType_Instance_RemoteAet, "PINNACLE");
@@ -409,7 +409,7 @@
   ASSERT_EQ("md5", att.GetUncompressedMD5());
   ASSERT_EQ("compressedMD5", att.GetCompressedMD5());
   ASSERT_EQ(42u, att.GetUncompressedSize());
-  ASSERT_EQ(CompressionType_Zlib, att.GetCompressionType());
+  ASSERT_EQ(CompressionType_ZlibWithSize, att.GetCompressionType());
 
   ASSERT_TRUE(index_->LookupAttachment(att, a[6], FileContentType_Dicom));
   ASSERT_EQ("world", att.GetUuid());