X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Fimaging%2Fcommon%2Ffile-download.cpp;h=cee5ba2e18bbd6e08616c1122d59d1ae7837b403;hb=4e39a7a1d48fbfc9b2cc00ed4adec47f421339be;hp=b4d3f4fb87a8e93fc068356852cc520a02285c89;hpb=065bbce24dc290218352636ffbe1ee716de185e6;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git diff --git a/dali/internal/imaging/common/file-download.cpp b/dali/internal/imaging/common/file-download.cpp old mode 100755 new mode 100644 index b4d3f4f..cee5ba2 --- a/dali/internal/imaging/common/file-download.cpp +++ b/dali/internal/imaging/common/file-download.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,36 +19,31 @@ #include // EXTERNAL INCLUDES +#include #include #include -#include +#include #include // INTERNAL INCLUDES #include -#ifdef TPK_CURL_ENABLED -#include -#endif // TPK_CURL_ENABLED - using namespace Dali::Integration; namespace Dali { - namespace TizenPlatform { - namespace // unnamed namespace { - -const int CONNECTION_TIMEOUT_SECONDS( 30L ); -const long VERBOSE_MODE = 0L; // 0 == off, 1 == on -const long CLOSE_CONNECTION_ON_ERROR = 1L; // 0 == off, 1 == on -const long EXCLUDE_HEADER = 0L; -const long INCLUDE_HEADER = 1L; -const long INCLUDE_BODY = 0L; -const long EXCLUDE_BODY = 1L; +const int CONNECTION_TIMEOUT_SECONDS(30L); +const int TIMEOUT_SECONDS(120L); +const long VERBOSE_MODE = 0L; // 0 == off, 1 == on +const long CLOSE_CONNECTION_ON_ERROR = 1L; // 0 == off, 1 == on +const long EXCLUDE_HEADER = 0L; +const long INCLUDE_HEADER = 1L; +const long INCLUDE_BODY = 0L; +const long EXCLUDE_BODY = 1L; /** * Curl library environment. Direct initialize ensures it's constructed before adaptor @@ -56,237 +51,202 @@ const long EXCLUDE_BODY = 1L; */ static Dali::TizenPlatform::Network::CurlEnvironment gCurlEnvironment; -void ConfigureCurlOptions( CURL* curlHandle, const std::string& url ) +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 ); + 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 ) // 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 ); - -#ifdef TPK_CURL_ENABLED - // Apply certificate pinning on Tizen - curl_easy_setopt( curlHandle, CURLOPT_SSL_CTX_FUNCTION, tpkp_curl_ssl_ctx_callback ); -#endif // TPK_CURL_ENABLED + curl_easy_setopt(curlHandle, CURLOPT_CONNECTTIMEOUT, CONNECTION_TIMEOUT_SECONDS); + curl_easy_setopt(curlHandle, CURLOPT_TIMEOUT, TIMEOUT_SECONDS); + curl_easy_setopt(curlHandle, CURLOPT_HEADER, INCLUDE_HEADER); + curl_easy_setopt(curlHandle, CURLOPT_NOBODY, EXCLUDE_BODY); + curl_easy_setopt(curlHandle, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curlHandle, CURLOPT_MAXREDIRS, 5L); + + // If the proxy variable is set, ensure it's also used. + // In theory, this variable should be used by the curl library; however, something + // is overriding it. + char* proxy = std::getenv("http_proxy"); + if(proxy != nullptr) + { + curl_easy_setopt(curlHandle, CURLOPT_PROXY, proxy); + } } // Without a write function or a buffer (file descriptor) to write to, curl will pump out // header/body contents to stdout -size_t DummyWrite(char *ptr, size_t size, size_t nmemb, void *userdata) +size_t DummyWrite(char* ptr, size_t size, size_t nmemb, void* userdata) { return size * nmemb; } struct ChunkData { - std::vector< uint8_t > data; + std::vector data; }; -size_t ChunkLoader(char *ptr, size_t size, size_t nmemb, void *userdata) +size_t ChunkLoader(char* ptr, size_t size, size_t nmemb, void* userdata) { - std::vector* chunks = static_cast*>( userdata ); - int numBytes = size*nmemb; - chunks->push_back( ChunkData() ); - ChunkData& chunkData = (*chunks)[chunks->size()-1]; - chunkData.data.reserve( numBytes ); - memcpy( &chunkData.data[0], ptr, numBytes ); + std::vector* chunks = static_cast*>(userdata); + int numBytes = size * nmemb; + chunks->push_back(ChunkData()); + ChunkData& chunkData = (*chunks)[chunks->size() - 1]; + chunkData.data.reserve(numBytes); + memcpy(&chunkData.data[0], ptr, numBytes); return numBytes; } - -CURLcode DownloadFileDataWithSize( CURL* curlHandle, Dali::Vector& dataBuffer, size_t dataSize ) +CURLcode DownloadFileDataWithSize(CURL* curlHandle, Dali::Vector& dataBuffer, size_t dataSize) { - CURLcode result( CURLE_OK ); + CURLcode result(CURLE_OK); // create - Dali::Internal::Platform::FileWriter fileWriter( dataBuffer, dataSize ); - FILE* dataBufferFilePointer = fileWriter.GetFile(); - if( NULL != dataBufferFilePointer ) + Dali::Internal::Platform::FileWriter fileWriter(dataBuffer, dataSize); + FILE* dataBufferFilePointer = fileWriter.GetFile(); + if(NULL != dataBufferFilePointer) { // we only want the body which contains the file data - curl_easy_setopt( curlHandle, CURLOPT_HEADER, EXCLUDE_HEADER ); - curl_easy_setopt( curlHandle, CURLOPT_NOBODY, INCLUDE_BODY ); + curl_easy_setopt(curlHandle, CURLOPT_HEADER, EXCLUDE_HEADER); + curl_easy_setopt(curlHandle, CURLOPT_NOBODY, INCLUDE_BODY); // disable the write callback, and get curl to write directly into our data buffer - curl_easy_setopt( curlHandle, CURLOPT_WRITEFUNCTION, NULL ); - curl_easy_setopt( curlHandle, CURLOPT_WRITEDATA, dataBufferFilePointer ); + curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, NULL); + curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, dataBufferFilePointer); // synchronous request of the body data - result = curl_easy_perform( curlHandle ); + result = curl_easy_perform(curlHandle); } return result; } -CURLcode DownloadFileDataByChunk( CURL* curlHandle, Dali::Vector& dataBuffer, size_t& dataSize ) +CURLcode DownloadFileDataByChunk(CURL* curlHandle, Dali::Vector& dataBuffer, size_t& dataSize) { // create - std::vector< ChunkData > chunks; + std::vector chunks; // we only want the body which contains the file data - curl_easy_setopt( curlHandle, CURLOPT_HEADER, EXCLUDE_HEADER ); - curl_easy_setopt( curlHandle, CURLOPT_NOBODY, INCLUDE_BODY ); + curl_easy_setopt(curlHandle, CURLOPT_HEADER, EXCLUDE_HEADER); + curl_easy_setopt(curlHandle, CURLOPT_NOBODY, INCLUDE_BODY); // Enable the write callback. - curl_easy_setopt( curlHandle, CURLOPT_WRITEFUNCTION, ChunkLoader ); - curl_easy_setopt( curlHandle, CURLOPT_WRITEDATA, &chunks ); + curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, ChunkLoader); + curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, &chunks); // synchronous request of the body data - CURLcode result = curl_easy_perform( curlHandle ); + CURLcode result = curl_easy_perform(curlHandle); // chunks should now contain all of the chunked data. Reassemble into a single vector dataSize = 0; - for( size_t i=0; i& dataBuffer, - size_t& dataSize, - size_t maximumAllowedSizeBytes ) +bool DownloadFile(CURL* curlHandle, + const std::string& url, + Dali::Vector& dataBuffer, + size_t& dataSize, + size_t maximumAllowedSizeBytes, + char* errorBuffer) { - CURLcode result( CURLE_OK ); - double size(0); + CURLcode result(CURLE_OK); + double size(0); // setup curl to download just the header so we can extract the content length - ConfigureCurlOptions( curlHandle, url ); - - curl_easy_setopt( curlHandle, CURLOPT_WRITEFUNCTION, DummyWrite); + ConfigureCurlOptions(curlHandle, url); + curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, DummyWrite); + if(errorBuffer != nullptr) + { + errorBuffer[0] = 0; + } // perform the request to get the header - result = curl_easy_perform( curlHandle ); + result = curl_easy_perform(curlHandle); - if( result != CURLE_OK) + if(result != CURLE_OK) { - DALI_LOG_ERROR( "Failed to download http header for \"%s\" with error code %d\n", url.c_str(), result ); + if(errorBuffer != nullptr) + { + DALI_LOG_ERROR("Failed to download http header for \"%s\" with error code %d (%s)\n", url.c_str(), result, &errorBuffer[0]); + } + else + { + DALI_LOG_ERROR("Failed to download http header for \"%s\" with error code %d\n", url.c_str(), result); + } return false; } // get the content length, -1 == size is not known - curl_easy_getinfo( curlHandle,CURLINFO_CONTENT_LENGTH_DOWNLOAD , &size ); + curl_easy_getinfo(curlHandle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &size); - - if( size >= maximumAllowedSizeBytes ) + if(size >= maximumAllowedSizeBytes) { - DALI_LOG_ERROR( "File content length %f > max allowed %zu \"%s\" \n", size, maximumAllowedSizeBytes, url.c_str() ); + DALI_LOG_ERROR("File content length %f > max allowed %zu \"%s\" \n", size, maximumAllowedSizeBytes, url.c_str()); return false; } - else if( size > 0 ) + else if(size > 0) { // If we know the size up front, allocate once and avoid chunk copies. - dataSize = static_cast( size ); - result = DownloadFileDataWithSize( curlHandle, dataBuffer, dataSize ); + dataSize = static_cast(size); + result = DownloadFileDataWithSize(curlHandle, dataBuffer, dataSize); } else { - result = DownloadFileDataByChunk( curlHandle, dataBuffer, dataSize ); + result = DownloadFileDataByChunk(curlHandle, dataBuffer, dataSize); } - if( result != CURLE_OK ) + if(result != CURLE_OK) { - DALI_LOG_ERROR( "Failed to download image file \"%s\" with error code %d\n", url.c_str(), result ); + if(errorBuffer != nullptr) + { + DALI_LOG_ERROR("Failed to download image file \"%s\" with error code %d\n", url.c_str(), result); + } + else + { + DALI_LOG_ERROR("Failed to download image file \"%s\" with error code %d (%s)\n", url.c_str(), result, errorBuffer); + } return false; } return true; } - } // unnamed namespace - 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 ) +bool DownloadRemoteFileIntoMemory(const std::string& url, + Dali::Vector& dataBuffer, + size_t& dataSize, + size_t maximumAllowedSizeBytes) { - if( mode & CRYPTO_LOCK ) - { - mMutexs[n].lock(); - } - else - { - mMutexs[n].unlock(); - } -} - -void CurlEnvironment::GetThreadId( CRYPTO_THREADID* tid ) -{ - // If dali uses c++ thread, we may replace pthread_self() to this_thread::get_id() - CRYPTO_THREADID_set_numeric( tid, static_cast< unsigned long > ( pthread_self() ) ); -} - -void CurlEnvironment::SetLockingFunction() -{ - if( mMutexs != NULL ) - { - return; - } - - mMutexs = new std::mutex[ CRYPTO_num_locks() ]; + bool result = false; - CRYPTO_THREADID_set_callback( &CurlEnvironment::GetThreadId ); - CRYPTO_set_locking_callback( &CurlEnvironment::OnOpenSSLLocking ); -} - -void CurlEnvironment::UnsetLockingFunction() -{ - if( mMutexs == NULL ) - { - return; - } - - CRYPTO_THREADID_set_callback( NULL ); - CRYPTO_set_locking_callback( NULL ); - delete [] mMutexs; - mMutexs = NULL; -} - -bool DownloadRemoteFileIntoMemory( const std::string& url, - Dali::Vector& dataBuffer, - size_t& dataSize, - size_t maximumAllowedSizeBytes ) -{ - if( url.empty() ) + if(url.empty()) { DALI_LOG_WARNING("empty url requested \n"); return false; @@ -296,17 +256,15 @@ bool DownloadRemoteFileIntoMemory( const std::string& url, // thread we need to explicity call curl_global_init() on startup from a single thread. CURL* curlHandle = curl_easy_init(); + if(curlHandle) + { + std::vector errorBuffer(CURL_ERROR_SIZE); + curl_easy_setopt(curlHandle, CURLOPT_ERRORBUFFER, &errorBuffer[0]); + result = DownloadFile(curlHandle, url, dataBuffer, dataSize, maximumAllowedSizeBytes, &errorBuffer[0]); - bool result = DownloadFile( curlHandle, url, dataBuffer, dataSize, maximumAllowedSizeBytes); - - // clean up session - curl_easy_cleanup( curlHandle ); - -#ifdef TPK_CURL_ENABLED - // Clean up tpkp(the module for certificate pinning) resources on Tizen - tpkp_curl_cleanup(); -#endif // TPK_CURL_ENABLED - + // clean up session + curl_easy_cleanup(curlHandle); + } return result; }