changeset 1526:096a8af528c9

fix streams, initialization/finalization of libcurl and openssl
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 12 Aug 2015 10:43:10 +0200
parents f9b0169eb6bb
children 7b58e0048874
files Core/HttpServer/HttpStreamTranscoder.cpp Core/HttpServer/HttpStreamTranscoder.h OrthancServer/OrthancInitialization.cpp UnitTestsSources/StreamTests.cpp
diffstat 4 files changed, 128 insertions(+), 74 deletions(-) [+]
line wrap: on
line diff
--- a/Core/HttpServer/HttpStreamTranscoder.cpp	Tue Aug 11 17:50:38 2015 +0200
+++ b/Core/HttpServer/HttpStreamTranscoder.cpp	Wed Aug 12 10:43:10 2015 +0200
@@ -39,8 +39,6 @@
 #include <string.h>   // For memcpy()
 #include <cassert>
 
-#include <stdio.h>
-
 namespace Orthanc
 {
   void HttpStreamTranscoder::ReadSource(std::string& buffer)
@@ -73,50 +71,59 @@
   }
 
 
+  HttpCompression HttpStreamTranscoder::SetupZlibCompression(bool deflateAllowed)
+  {
+    uint64_t size = source_.GetContentLength();
+
+    if (size == 0)
+    {
+      return HttpCompression_None;
+    }
+
+    if (size < sizeof(uint64_t))
+    {
+      throw OrthancException(ErrorCode_CorruptedFile);
+    }
+
+    if (deflateAllowed)
+    {
+      bytesToSkip_ = sizeof(uint64_t);
+
+      return HttpCompression_Deflate;
+    }
+    else
+    {
+      // TODO Use stream-based zlib decoding to reduce memory usage
+      std::string compressed;
+      ReadSource(compressed);
+
+      uncompressed_.reset(new BufferHttpSender);
+
+      ZlibCompressor compressor;
+      IBufferCompressor::Uncompress(uncompressed_->GetBuffer(), compressor, compressed);
+
+      return HttpCompression_None;
+    }
+  }
+
+
   HttpCompression HttpStreamTranscoder::SetupHttpCompression(bool gzipAllowed,
                                                              bool deflateAllowed)
   {
+    if (ready_)
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+
+    ready_ = true;
+
     switch (sourceCompression_)
     {
       case CompressionType_None:
-      {
         return HttpCompression_None;
-      }
 
       case CompressionType_ZlibWithSize:
-      {
-        uint64_t size = source_.GetContentLength();
-
-        if (size == 0)
-        {
-          return HttpCompression_None;
-        }
-
-        if (size < sizeof(uint64_t))
-        {
-          throw OrthancException(ErrorCode_CorruptedFile);
-        }
-
-        if (deflateAllowed)
-        {
-          bytesToSkip_ = sizeof(uint64_t);
-          return HttpCompression_Deflate;
-        }
-        else
-        {
-          std::string compressed;
-          ReadSource(compressed);
-
-          uncompressed_.reset(new BufferHttpSender);
-
-          ZlibCompressor compressor;
-          IBufferCompressor::Uncompress(uncompressed_->GetBuffer(), compressor, compressed);
-
-          return HttpCompression_None;
-        }
-
-        break;
-      }
+        return SetupZlibCompression(deflateAllowed);
 
       default:
         throw OrthancException(ErrorCode_NotImplemented);
@@ -126,6 +133,11 @@
 
   uint64_t HttpStreamTranscoder::GetContentLength()
   {
+    if (!ready_)
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+
     if (uncompressed_.get() != NULL)
     {
       return uncompressed_->GetContentLength();
@@ -145,6 +157,11 @@
 
   bool HttpStreamTranscoder::ReadNextChunk()
   {
+    if (!ready_)
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+
     if (uncompressed_.get() != NULL)
     {
       return uncompressed_->ReadNextChunk();
@@ -162,7 +179,6 @@
     for (;;)
     {
       assert(skipped_ < bytesToSkip_);
-      printf("[%d %d]  ", skipped_, bytesToSkip_); fflush(stdout);
 
       bool ok = source_.ReadNextChunk();
       if (!ok)
@@ -182,14 +198,13 @@
         // We have skipped enough bytes, but we must read a new chunk
         currentChunkOffset_ = 0;            
         skipped_ = bytesToSkip_;
-        return source_.GetChunkSize();
+        return source_.ReadNextChunk();
       }
       else
       {
+        // We have skipped enough bytes, and we have enough data in the current chunk
         assert(s > remaining);
-            
-        // We have skipped enough bytes, and we have enough data in the current chunk
-        currentChunkOffset_ = s - remaining;
+        currentChunkOffset_ = remaining;
         skipped_ = bytesToSkip_;
         return true;
       }
@@ -199,6 +214,11 @@
 
   const char* HttpStreamTranscoder::GetChunkContent()
   {
+    if (!ready_)
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+
     if (uncompressed_.get() != NULL)
     {
       return uncompressed_->GetChunkContent();
@@ -211,6 +231,11 @@
 
   size_t HttpStreamTranscoder::GetChunkSize()
   {
+    if (!ready_)
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+
     if (uncompressed_.get() != NULL)
     {
       return uncompressed_->GetChunkSize();
--- a/Core/HttpServer/HttpStreamTranscoder.h	Tue Aug 11 17:50:38 2015 +0200
+++ b/Core/HttpServer/HttpStreamTranscoder.h	Wed Aug 12 10:43:10 2015 +0200
@@ -46,18 +46,22 @@
     uint64_t           bytesToSkip_;
     uint64_t           skipped_;
     uint64_t           currentChunkOffset_;
+    bool               ready_;
 
     std::auto_ptr<BufferHttpSender>  uncompressed_;
 
     void ReadSource(std::string& buffer);
 
+    HttpCompression SetupZlibCompression(bool deflateAllowed);
+
   public:
     HttpStreamTranscoder(IHttpStreamAnswer& source,
                          CompressionType compression) : 
       source_(source),
       sourceCompression_(compression),
       bytesToSkip_(0),
-      skipped_(0)
+      skipped_(0),
+      ready_(false)
     {
     }
 
--- a/OrthancServer/OrthancInitialization.cpp	Tue Aug 11 17:50:38 2015 +0200
+++ b/OrthancServer/OrthancInitialization.cpp	Wed Aug 12 10:43:10 2015 +0200
@@ -49,6 +49,16 @@
 #include <boost/thread.hpp>
 
 
+#if ORTHANC_SSL_ENABLED == 1
+// For OpenSSL initialization and finalization
+#include <openssl/conf.h>
+#include <openssl/engine.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/ssl.h>
+#endif
+
+
 #if ORTHANC_JPEG_ENABLED == 1
 #include <dcmtk/dcmjpeg/djdecode.h>
 #endif
@@ -259,6 +269,18 @@
   {
     boost::mutex::scoped_lock lock(globalMutex_);
 
+#if ORTHANC_SSL_ENABLED == 1
+    // https://wiki.openssl.org/index.php/Library_Initialization
+    SSL_library_init();
+    SSL_load_error_strings();
+    OpenSSL_add_all_algorithms();
+    ERR_load_crypto_strings();
+
+    curl_global_init(CURL_GLOBAL_ALL);
+#else
+    curl_global_init(CURL_GLOBAL_ALL & ~CURL_GLOBAL_SSL);
+#endif
+
     InitializeServerEnumerations();
 
     // Read the user-provided configuration
@@ -298,6 +320,20 @@
     // Unregister JPEG codecs
     DJDecoderRegistration::cleanup();
 #endif
+
+    curl_global_cleanup();
+
+#if ORTHANC_SSL_ENABLED == 1
+    // Finalize OpenSSL
+    // https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
+    FIPS_mode_set(0);
+    ENGINE_cleanup();
+    CONF_modules_unload(1);
+    EVP_cleanup();
+    CRYPTO_cleanup_all_ex_data();
+    ERR_remove_state(0);
+    ERR_free_strings();
+#endif
   }
 
 
--- a/UnitTestsSources/StreamTests.cpp	Tue Aug 11 17:50:38 2015 +0200
+++ b/UnitTestsSources/StreamTests.cpp	Wed Aug 12 10:43:10 2015 +0200
@@ -181,9 +181,9 @@
                           bool allowGzip = false,
                           bool allowDeflate = false)
 {
-  result.resize(stream.GetContentLength());
+  stream.SetupHttpCompression(allowGzip, allowDeflate);
 
-  stream.SetupHttpCompression(allowGzip, allowDeflate);
+  result.resize(stream.GetContentLength());
 
   size_t pos = 0;
   while (stream.ReadNextChunk())
@@ -209,38 +209,15 @@
 
   {
     BufferHttpSender sender;
-    sender.SetChunkSize(0);
-    sender.GetBuffer() = s;
-    ASSERT_TRUE(ReadAllStream(t, sender));
-    ASSERT_EQ(s, t);
-  }
-
-  {
-    BufferHttpSender sender;
-    sender.SetChunkSize(1);
-    sender.GetBuffer() = s;
-    ASSERT_TRUE(ReadAllStream(t, sender));
-    ASSERT_EQ(s, t);
-  }
-
-  {
-    BufferHttpSender sender;
     sender.SetChunkSize(1);
     ASSERT_TRUE(ReadAllStream(t, sender));
     ASSERT_EQ(0u, t.size());
   }
 
+  for (int cs = 0; cs < 5; cs++)
   {
     BufferHttpSender sender;
-    sender.SetChunkSize(3);
-    sender.GetBuffer() = s;
-    ASSERT_TRUE(ReadAllStream(t, sender));
-    ASSERT_EQ(s, t);
-  }
-
-  {
-    BufferHttpSender sender;
-    sender.SetChunkSize(300);
+    sender.SetChunkSize(cs);
     sender.GetBuffer() = s;
     ASSERT_TRUE(ReadAllStream(t, sender));
     ASSERT_EQ(s, t);
@@ -279,7 +256,7 @@
   std::string t;
   IBufferCompressor::Compress(t, compressor, s);
 
-  for (int cs = 0; cs < 3; cs++)
+  for (int cs = 0; cs < 5; cs++)
   {
     BufferHttpSender sender;
     sender.SetChunkSize(cs);
@@ -293,7 +270,7 @@
   }
 
   // Pass-through test, no decompression occurs
-  for (int cs = 0; cs < 3; cs++)
+  for (int cs = 0; cs < 5; cs++)
   {
     BufferHttpSender sender;
     sender.SetChunkSize(cs);
@@ -308,7 +285,7 @@
   }
 
   // Pass-through test, decompression occurs
-  for (int cs = 0; cs < 3; cs++)
+  for (int cs = 0; cs < 5; cs++)
   {
     BufferHttpSender sender;
     sender.SetChunkSize(cs);
@@ -323,7 +300,7 @@
   }
 
   // Pass-through test with zlib, no decompression occurs but deflate is sent
-  for (int cs = 0; cs < 3; cs++)
+  for (int cs = 0; cs < 16; cs++)
   {
     BufferHttpSender sender;
     sender.SetChunkSize(cs);
@@ -337,4 +314,16 @@
     ASSERT_EQ(t.size() - sizeof(uint64_t), u.size());
     ASSERT_EQ(t.substr(sizeof(uint64_t)), u);
   }
+
+  for (int cs = 0; cs < 3; cs++)
+  {
+    BufferHttpSender sender;
+    sender.SetChunkSize(cs);
+
+    HttpStreamTranscoder transcode(sender, CompressionType_ZlibWithSize);
+    std::string u;
+    ASSERT_TRUE(ReadAllStream(u, transcode, false, true));
+    
+    ASSERT_EQ(0u, u.size());
+  }
 }