$(tizen_platform_abstraction_src_dir)/resource-loader/resource-thread-image.cpp \
$(tizen_platform_abstraction_src_dir)/resource-loader/resource-thread-shader.cpp \
\
+ $(tizen_platform_abstraction_src_dir)/resource-loader/network/file-download.cpp \
+ $(tizen_platform_abstraction_src_dir)/resource-loader/network/http-utils.cpp \
\
$(tizen_platform_abstraction_src_dir)/resource-loader/debug/resource-loader-debug.cpp \
\
--- /dev/null
+/*
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// HEADER
+#include "file-download.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <curl/curl.h>
+
+// INTERNAL INCLUDES
+#include "portable/file-closer.h"
+
+
+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;
+
+void ConfigureCurlOptions( CURL* curl_handle, const std::string& url )
+{
+ curl_easy_setopt( curl_handle, CURLOPT_URL, url.c_str() );
+ curl_easy_setopt( curl_handle, CURLOPT_VERBOSE, VERBOSE_MODE );
+
+ // CURLOPT_FAILONERROR is not fail-safe especially when authentication is involved ( see manual )
+ curl_easy_setopt( curl_handle, CURLOPT_FAILONERROR, CLOSE_CONNECTION_ON_ERROR );
+ curl_easy_setopt( curl_handle, CURLOPT_CONNECTTIMEOUT, CONNECTION_TIMEOUT_SECONDS );
+ curl_easy_setopt( curl_handle, CURLOPT_HEADER, INCLUDE_HEADER );
+ curl_easy_setopt( curl_handle, CURLOPT_NOBODY, EXCLUDE_BODY );
+}
+
+// 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)
+{
+ return size * nmemb;
+}
+
+
+bool DownloadFile( CURL* curl_handle,
+ const std::string& url,
+ Dali::Vector<uint8_t>& dataBuffer,
+ size_t& dataSize,
+ size_t maximumAllowedSizeBytes )
+{
+ CURLcode res( CURLE_OK );
+ double size(0);
+
+ // setup curl to download just the header so we can extract the content length
+ ConfigureCurlOptions( curl_handle, url );
+
+ curl_easy_setopt( curl_handle, CURLOPT_WRITEFUNCTION, DummyWrite);
+
+ // perform the request to get the header
+ res = curl_easy_perform( curl_handle );
+
+ if( res != CURLE_OK)
+ {
+ DALI_LOG_WARNING( "Failed to download http header for \"%s\" with error code %d\n", url.c_str(), res );
+ return false;
+ }
+
+ // get the content length, -1 == size is not known
+ curl_easy_getinfo( curl_handle,CURLINFO_CONTENT_LENGTH_DOWNLOAD , &size );
+
+ if( size < 1 )
+ {
+ DALI_LOG_WARNING( "Header missing content length \"%s\" \n", url.c_str() );
+ return false;
+ }
+ if( size >= maximumAllowedSizeBytes )
+ {
+ DALI_LOG_WARNING( "File content length %f > max allowed %zu \"%s\" \n", size, maximumAllowedSizeBytes, url.c_str() );
+ return false;
+ }
+
+ dataSize = static_cast<size_t>( size );
+
+ dataBuffer.Resize( dataSize );
+
+ // create
+ Dali::Internal::Platform::FileCloser fileCloser( static_cast<void*>(&dataBuffer[0]), dataSize, "wb" );
+ FILE* dataBufferFilePointer = fileCloser.GetFile();
+ if( NULL != dataBufferFilePointer )
+ {
+ // we only want the body which contains the file data
+ curl_easy_setopt( curl_handle, CURLOPT_HEADER, EXCLUDE_HEADER );
+ curl_easy_setopt( curl_handle, CURLOPT_NOBODY, INCLUDE_BODY );
+
+ // disable the write callback, and get curl to write directly into our data buffer
+ curl_easy_setopt( curl_handle, CURLOPT_WRITEFUNCTION, NULL );
+ curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA, dataBufferFilePointer );
+
+ // synchronous request of the body data
+ res = curl_easy_perform( curl_handle );
+
+ if( CURLE_OK != res )
+ {
+ DALI_LOG_WARNING( "Failed to download image file \"%s\" with error code %d\n", url.c_str(), res );
+ return false;
+ }
+ }
+ return true;
+}
+} // unnamed namespace
+
+
+
+bool Network::DownloadRemoteFileIntoMemory( const std::string& url,
+ Dali::Vector<uint8_t>& dataBuffer,
+ size_t& dataSize,
+ size_t maximumAllowedSizeBytes )
+{
+ if( url.empty() )
+ {
+ DALI_LOG_WARNING("empty url requested \n");
+ return false;
+ }
+
+ // start a libcurl easy session, this internally calls curl_global_init, if we ever have more than one download
+ // thread we need to explicity call curl_global_init() on startup from a single thread.
+
+ CURL* curl_handle = curl_easy_init();
+
+ bool result = DownloadFile( curl_handle, url, dataBuffer, dataSize, maximumAllowedSizeBytes);
+
+ // clean up session
+ curl_easy_cleanup( curl_handle );
+
+ return result;
+}
+
+
+} // namespace TizenPlatform
+
+} // namespace Dali
--- /dev/null
+#ifndef __DALI_TIZEN_PLATFORM_NETWORK_FILE_DOWNLOAD_H__
+#define __DALI_TIZEN_PLATFORM_NETWORK_FILE_DOWNLOAD_H__
+
+/*
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <string>
+#include <stdint.h> // uint8
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace Network
+{
+
+/**
+ * Download a requested file into a memory buffer.
+ * Threading notes: This function can be called from multiple threads, however l
+ * we must explicitly call curl_global_init() from a single thread before using curl
+ * as the global function calls are not thread safe.
+ *
+ * @param[in] url The requested file url
+ * @param[out] dataBuffer A memory buffer object to be written with downloaded file data.
+ * @param[out] dataSize The size of the memory buffer.
+ * @param[in] maximumAllowedSize The maxmimum allowed file size in bytes to download. E.g. for an Image file this may be 50 MB
+ * @return true on success, false on failure
+ *
+ */
+bool DownloadRemoteFileIntoMemory( const std::string& url,
+ Dali::Vector<uint8_t>& dataBuffer,
+ size_t& dataSize,
+ size_t maximumAllowedSizeBytes );
+
+} // namespace Network
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // __DALI_TIZEN_PLATFORM_RESOURCE_THREAD_IMAGE_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "http-utils.h"
+
+// EXTERNAL INCLUDES
+#include <cstring>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace
+{
+const unsigned int MIN_HTTP_URL_LENGTH = 12; // assume we have a least http://xx/yy
+const char HTTP_URL[] = "http://";
+const char HTTPS_URL[] = "https://";
+}
+
+bool Network::IsHttpUrl( const std::string& path )
+{
+ if( path.size() <= MIN_HTTP_URL_LENGTH )
+ {
+ return false;
+ }
+
+ if( ( strncasecmp( path.c_str(), HTTP_URL, sizeof(HTTP_URL) -1 ) == 0 ) ||
+ ( strncasecmp( path.c_str(), HTTPS_URL, sizeof(HTTPS_URL) -1 ) == 0 ) )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+} // TizenPlatform
+
+} // Dali
--- /dev/null
+#ifndef __DALI_TIZEN_PLATFORM_NETWORK_UTILS_H__
+#define __DALI_TIZEN_PLATFORM_NETWORK_UTILS_H__
+
+/*
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <string>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace Network
+{
+
+/**
+ * @brief Tests if a string starts with either http:// or https://
+ * @param[in] path string
+ * @return true if the path is a http url
+ */
+bool IsHttpUrl( const std::string& path );
+
+} // Network
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // __DALI_TIZEN_PLATFORM_NETWORK_UTILS_H__
*
*/
+// CLASS HEADER
#include "resource-bitmap-requester.h"
+
+// EXTERNAL INCLUDES
#include <dali/integration-api/resource-cache.h>
+// INTERNAL INCLUDES
+#include "network/file-download.h"
+#include "network/http-utils.h"
+
using namespace Dali::Integration;
namespace Dali
{
namespace TizenPlatform
{
+namespace
+{
+enum ResourceScheme
+{
+ FILE_SYSTEM_RESOURCE,
+ NETWORK_RESOURCE
+};
+}// unnamed namespace
ResourceBitmapRequester::ResourceBitmapRequester( ResourceLoader& resourceLoader )
-: ResourceRequesterBase( resourceLoader )
+: ResourceRequesterBase( resourceLoader ),
+ mThreadImageLocal( NULL ),
+ mThreadImageRemote( NULL )
{
- mThreadImageLocal = new ResourceThreadImage( resourceLoader, false );
- mThreadImageRemote = new ResourceThreadImage( resourceLoader, true );
}
ResourceBitmapRequester::~ResourceBitmapRequester()
void ResourceBitmapRequester::Pause()
{
- mThreadImageLocal->Pause();
- mThreadImageRemote->Pause();
+ if( mThreadImageLocal )
+ {
+ mThreadImageLocal->Pause();
+ }
+ if( mThreadImageRemote )
+ {
+ mThreadImageRemote->Pause();
+ }
}
void ResourceBitmapRequester::Resume()
{
- mThreadImageLocal->Resume();
- mThreadImageRemote->Resume();
+ if( mThreadImageLocal )
+ {
+ mThreadImageLocal->Resume();
+ }
+ if( mThreadImageRemote )
+ {
+ mThreadImageRemote->Resume();
+ }
}
void ResourceBitmapRequester::LoadResource( Integration::ResourceRequest& request )
{
DALI_ASSERT_DEBUG( (0 != dynamic_cast<BitmapResourceType*>(request.GetType())) && "Only requsts for bitmap resources can ever be routed to ResourceBitmapRequester.\n");
BitmapResourceType* resType = static_cast<BitmapResourceType*>(request.GetType());
- if( resType )
+ if( !resType )
{
- // Work out what thread to decode / load the image on:
- ResourceThreadBase* const localImageThread = mThreadImageLocal;
- ResourceThreadBase* const remoteImageThread = mThreadImageRemote;
- ResourceThreadBase* workerThread;
-
- // Work out if the resource is in memory, a file, or in a remote server:
- ResourceThreadBase::RequestType requestType;
- if( request.GetResource().Get() )
+ return;
+ }
+
+ // Work out what thread to decode / load the image on:
+ ResourceScheme scheme( FILE_SYSTEM_RESOURCE );
+
+ // Work out if the resource is in memory, a file, or in a remote server:
+ ResourceThreadBase::RequestType requestType;
+
+ // if resource exists already, then it just needs decoding
+ if( request.GetResource().Get() )
+ {
+ requestType = ResourceThreadBase::RequestDecode;
+ }
+ else
+ {
+ const std::string& resourcePath = request.GetPath();
+ if( Network::IsHttpUrl( resourcePath) )
{
- requestType = ResourceThreadBase::RequestDecode;
- workerThread = localImageThread;
+ requestType = ResourceThreadBase::RequestDownload;
+ scheme = NETWORK_RESOURCE;
}
else
{
- const std::string& resourcePath = request.GetPath();
- if( strncasecmp( resourcePath.c_str(), "http", 4 ) == 0 )
- {
- if( resourcePath.size() > 4 &&
- ( strncasecmp( &resourcePath.c_str()[4], "://", 3 ) == 0 ||
- strncasecmp( &resourcePath.c_str()[4], "s://", 4) == 0 ) )
- {
- requestType = ResourceThreadBase::RequestDownload;
- workerThread = remoteImageThread;
- }
- else
- {
- requestType = ResourceThreadBase::RequestLoad;
- workerThread = localImageThread;
- }
- }
- else
- {
- requestType = ResourceThreadBase::RequestLoad;
- workerThread = localImageThread;
- }
+ requestType = ResourceThreadBase::RequestLoad;
}
+ }
- // Dispatch the job to the right thread:
- workerThread->AddRequest( request, requestType );
+ // Dispatch the job to the right thread
+ // lazily create the thread
+ if( scheme == FILE_SYSTEM_RESOURCE )
+ {
+ if( !mThreadImageLocal )
+ {
+ mThreadImageLocal = new ResourceThreadImage( mResourceLoader );
+ }
+ mThreadImageLocal->AddRequest( request, requestType );
+ }
+ else
+ {
+ if( !mThreadImageRemote )
+ {
+ mThreadImageRemote = new ResourceThreadImage( mResourceLoader );
+ }
+ mThreadImageRemote->AddRequest( request, requestType );
}
}
void ResourceBitmapRequester::CancelLoad(Integration::ResourceId id, Integration::ResourceTypeId typeId)
{
- mThreadImageLocal->CancelRequest(id);
- mThreadImageRemote->CancelRequest(id);
+ if( mThreadImageLocal )
+ {
+ mThreadImageLocal->CancelRequest(id);
+ }
+ if( mThreadImageRemote )
+ {
+ mThreadImageRemote->CancelRequest(id);
+ }
}
} // TizenPlatform
*/
virtual void CancelLoad(Integration::ResourceId id, Integration::ResourceTypeId typeId);
-protected:
+private:
ResourceThreadImage* mThreadImageLocal; ///< Image loader thread object to load images in local machine
ResourceThreadImage* mThreadImageRemote; ///< Image loader thread object to download images in remote http server
};
{
/** Pull a resource out of the platform's file system. */
RequestLoad,
- /** Pull a resource over http protocol. */
+ /** Pull a resource from the network. */
RequestDownload,
/** Pull a resource out of a memory buffer. */
RequestDecode,
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2015 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.
*
*/
+// CLASS HEADER
#include "resource-thread-image.h"
+
+// EXTERNAL INCLUDES
#include <dali/devel-api/common/ref-counted-dali-vector.h>
#include <dali/integration-api/bitmap.h>
#include <dali/integration-api/debug.h>
#include <dali/integration-api/resource-cache.h>
#include <dali/integration-api/resource-types.h>
-#include <curl/curl.h>
+
+// INTERNAL INCLUDES
#include "portable/file-closer.h"
#include "image-loaders/image-loader.h"
+#include "network/file-download.h"
using namespace Dali::Integration;
-namespace
-{
-const int CONNECTION_TIMEOUT( 30 );
-}
-
namespace Dali
{
namespace TizenPlatform
{
-ResourceThreadImage::ResourceThreadImage(ResourceLoader& resourceLoader, bool forRemoteImage)
+namespace
+{
+
+// limit maximum image down load size to 50 MB
+const size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE = 50 * 1024 * 1024 ;
+}
+
+ResourceThreadImage::ResourceThreadImage(ResourceLoader& resourceLoader)
: ResourceThreadBase(resourceLoader)
{
}
bool ResourceThreadImage::DownloadRemoteImageIntoMemory(const Integration::ResourceRequest& request, Dali::Vector<uint8_t>& dataBuffer, size_t& dataSize)
{
- bool succeeded = true;
- CURLcode cresult;
-
- CURL* curl_handle = curl_easy_init();
- curl_easy_setopt( curl_handle, CURLOPT_VERBOSE, 0 );
- curl_easy_setopt( curl_handle, CURLOPT_URL, request.GetPath().c_str() );
- curl_easy_setopt( curl_handle, CURLOPT_FAILONERROR, 1 );
- curl_easy_setopt( curl_handle, CURLOPT_CONNECTTIMEOUT, CONNECTION_TIMEOUT );
-
- // Download header first to get data size
- char* headerBytes = NULL;
- size_t headerSize = 0;
- FILE* header_fp = open_memstream( &headerBytes, &headerSize );
- double size;
-
- if( NULL != header_fp)
- {
- curl_easy_setopt( curl_handle, CURLOPT_HEADER, 1 );
- curl_easy_setopt( curl_handle, CURLOPT_NOBODY, 1 );
- curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA, header_fp );
-
- cresult = curl_easy_perform( curl_handle );
- if( cresult == CURLE_OK )
- {
- curl_easy_getinfo( curl_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &size );
- }
- else
- {
- DALI_LOG_WARNING( "Failed to download http header for \"%s\" with error code %d\n", request.GetPath().c_str(), cresult );
- succeeded = false;
- }
-
- fclose( header_fp );
- }
- else
- {
- succeeded = false;
- }
-
- if( NULL != headerBytes )
- {
- free( headerBytes );
- }
-
- if( succeeded )
- {
- // Download file data
- dataSize = static_cast<size_t>( size );
- dataBuffer.Reserve( dataSize );
- dataBuffer.Resize( dataSize );
-
- Dali::Internal::Platform::FileCloser fileCloser( static_cast<void*>(&dataBuffer[0]), dataSize, "wb" );
- FILE* data_fp = fileCloser.GetFile();
- if( NULL != data_fp )
- {
- curl_easy_setopt( curl_handle, CURLOPT_HEADER, 0 );
- curl_easy_setopt( curl_handle, CURLOPT_NOBODY, 0 );
- curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA, data_fp );
-
- cresult = curl_easy_perform( curl_handle );
- if( CURLE_OK != cresult )
- {
- DALI_LOG_WARNING( "Failed to download image file \"%s\" with error code %d\n", request.GetPath().c_str(), cresult );
- succeeded = false;
- }
- }
- else
- {
- succeeded = false;
- }
- }
-
- curl_easy_cleanup( curl_handle );
-
- if( !succeeded )
+ bool ok = Network::DownloadRemoteFileIntoMemory( request.GetPath(), dataBuffer, dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE );
+ if( !ok )
{
FailedResource resource(request.GetId(), FailureUnknown);
mResourceLoader.AddFailedLoad(resource);
}
-
- return succeeded;
+ return ok;
}
void ResourceThreadImage::LoadImageFromLocalFile(const Integration::ResourceRequest& request)
#define __DALI_TIZEN_PLATFORM_RESOURCE_THREAD_IMAGE_H__
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2015 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.
* limitations under the License.
*
*/
-
+// EXTERNAL INCLUDES
#include <dali/integration-api/resource-cache.h>
#include <dali/integration-api/resource-types.h>
+
+// INTERNAL INCLUDES
#include "resource-thread-base.h"
namespace Dali
* Constructor
* @param[in] resourceLoader A reference to the ResourceLoader
*/
- ResourceThreadImage(ResourceLoader& resourceLoader, bool forRemoteImage);
+ ResourceThreadImage( ResourceLoader& resourceLoader );
/**
* Destructor