[4.0] Removed CURLOPT_FAILONERROR
[platform/core/uifw/dali-adaptor.git] / platform-abstractions / tizen / resource-loader / network / file-download.cpp
index ad50249..b276678 100755 (executable)
 
 // EXTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
+#include <pthread.h>
 #include <curl/curl.h>
+#include <openssl/crypto.h>
 #include <cstring>
 
 // INTERNAL INCLUDES
-#include "portable/file-closer.h"
+#include "portable/file-writer.h"
 
 #ifdef TPK_CURL_ENABLED
 #include <tpkp_curl.h>
@@ -55,14 +57,13 @@ const long EXCLUDE_BODY = 1L;
  */
 static Dali::TizenPlatform::Network::CurlEnvironment gCurlEnvironment;
 
-
 void ConfigureCurlOptions( CURL* curlHandle, const std::string& url )
 {
   curl_easy_setopt( curlHandle, CURLOPT_URL, url.c_str() );
   curl_easy_setopt( curlHandle, CURLOPT_VERBOSE, VERBOSE_MODE );
 
   // CURLOPT_FAILONERROR is not fail-safe especially when authentication is involved ( see manual )
-  curl_easy_setopt( curlHandle, CURLOPT_FAILONERROR, CLOSE_CONNECTION_ON_ERROR );
+  // Removed CURLOPT_FAILONERROR option
   curl_easy_setopt( curlHandle, CURLOPT_CONNECTTIMEOUT, CONNECTION_TIMEOUT_SECONDS );
   curl_easy_setopt( curlHandle, CURLOPT_HEADER, INCLUDE_HEADER );
   curl_easy_setopt( curlHandle, CURLOPT_NOBODY, EXCLUDE_BODY );
@@ -100,11 +101,10 @@ size_t ChunkLoader(char *ptr, size_t size, size_t nmemb, void *userdata)
 CURLcode DownloadFileDataWithSize( CURL* curlHandle, Dali::Vector<uint8_t>& dataBuffer, size_t dataSize )
 {
   CURLcode result( CURLE_OK );
-  dataBuffer.Resize( dataSize );
 
   // create
-  Dali::Internal::Platform::FileCloser fileCloser( static_cast<void*>(&dataBuffer[0]), dataSize, "wb" );
-  FILE* dataBufferFilePointer = fileCloser.GetFile();
+  Dali::Internal::Platform::FileWriter fileWriter( dataBuffer, dataSize );
+  FILE* dataBufferFilePointer = fileWriter.GetFile();
   if( NULL != dataBufferFilePointer )
   {
     // we only want the body which contains the file data
@@ -189,6 +189,7 @@ bool DownloadFile( CURL* curlHandle,
   }
   else if( size > 0 )
   {
+    // If we know the size up front, allocate once and avoid chunk copies.
     dataSize = static_cast<size_t>( size );
     result = DownloadFileDataWithSize( curlHandle, dataBuffer, dataSize );
   }
@@ -212,18 +213,74 @@ bool DownloadFile( CURL* curlHandle,
 namespace Network
 {
 
+std::mutex* CurlEnvironment::mMutexs = NULL;
+
 CurlEnvironment::CurlEnvironment()
 {
   // Must be called before we attempt any loads. e.g. by using curl_easy_init()
   // and before we start any threads.
   curl_global_init(CURL_GLOBAL_ALL);
+
+ // libcurl with openssl needs locking_function and thread id for threadsafe
+ // https://curl.haxx.se/libcurl/c/threadsafe.html
+ // https://www.openssl.org/docs/man1.0.2/crypto/threads.html#DESCRIPTION
+ // SetLockingFunction sets locking_function and get thread id by the guide.
+  SetLockingFunction();
 }
 
 CurlEnvironment::~CurlEnvironment()
 {
+  UnsetLockingFunction();
+
   curl_global_cleanup();
 }
 
+// libcurl with openssl needs locking_function and thread id for threadsafe
+// https://curl.haxx.se/libcurl/c/threadsafe.html
+// https://www.openssl.org/docs/man1.0.2/crypto/threads.html#DESCRIPTION
+void CurlEnvironment::OnOpenSSLLocking( int mode, int n, const char* file, int line )
+{
+  if( mode & CRYPTO_LOCK )
+  {
+    mMutexs[n].lock();
+  }
+  else
+  {
+    mMutexs[n].unlock();
+  }
+}
+
+unsigned long CurlEnvironment::GetThreadId()
+{
+  // If dali uses c++ thread, we may replace pthread_self() to this_thread::get_id()
+  return static_cast< unsigned long >( pthread_self() );
+}
+
+void CurlEnvironment::SetLockingFunction()
+{
+  if( mMutexs != NULL )
+  {
+    return;
+  }
+
+  mMutexs = new std::mutex[ CRYPTO_num_locks() ];
+
+  CRYPTO_set_id_callback( &CurlEnvironment::GetThreadId );
+  CRYPTO_set_locking_callback( &CurlEnvironment::OnOpenSSLLocking );
+}
+
+void CurlEnvironment::UnsetLockingFunction()
+{
+  if( mMutexs == NULL )
+  {
+    return;
+  }
+
+  CRYPTO_set_id_callback( NULL );
+  CRYPTO_set_locking_callback( NULL );
+  delete [] mMutexs;
+  mMutexs = NULL;
+}
 
 bool DownloadRemoteFileIntoMemory( const std::string& url,
                                    Dali::Vector<uint8_t>& dataBuffer,