2 // Tizen Web Device API
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
23 #include <FilesystemUtils.h>
25 #include "DownloadState.h"
26 #include "DownloadNetworkType.h"
27 #include "DownloadManager.h"
32 static std::string _get_download_error(int err)
38 case DOWNLOAD_ERROR_INVALID_PARAMETER:
39 msg = "Invalid parameter";
41 case DOWNLOAD_ERROR_OUT_OF_MEMORY:
42 msg = "Out of memory";
44 case DOWNLOAD_ERROR_NETWORK_UNREACHABLE:
45 msg = "Network is unreachable";
47 case DOWNLOAD_ERROR_CONNECTION_TIMED_OUT:
48 msg = "Http session time-out";
50 case DOWNLOAD_ERROR_NO_SPACE:
51 msg = "No space left on device";
53 case DOWNLOAD_ERROR_FIELD_NOT_FOUND:
54 msg = "Specified field not found";
56 case DOWNLOAD_ERROR_INVALID_STATE:
57 msg = "Invalid state";
59 case DOWNLOAD_ERROR_CONNECTION_FAILED:
60 msg = "Connection failed";
62 case DOWNLOAD_ERROR_INVALID_URL:
65 case DOWNLOAD_ERROR_INVALID_DESTINATION:
66 msg = "Invalid destination";
68 case DOWNLOAD_ERROR_TOO_MANY_DOWNLOADS:
69 msg = "Full of available simultaneous downloads";
71 case DOWNLOAD_ERROR_QUEUE_FULL:
72 msg = "Full of available downloading items from server";
74 case DOWNLOAD_ERROR_ALREADY_COMPLETED:
75 msg = "The download is already completed";
77 case DOWNLOAD_ERROR_FILE_ALREADY_EXISTS:
78 msg = "It is failed to rename the downloaded file";
80 case DOWNLOAD_ERROR_CANNOT_RESUME:
81 msg = "It cannot resume";
83 case DOWNLOAD_ERROR_TOO_MANY_REDIRECTS:
84 msg = "In case of too may redirects from http response header";
86 case DOWNLOAD_ERROR_UNHANDLED_HTTP_CODE:
87 msg = "The download cannot handle the http status value";
89 case DOWNLOAD_ERROR_REQUEST_TIMEOUT:
90 msg = "There are no action after client create a download id";
92 case DOWNLOAD_ERROR_RESPONSE_TIMEOUT:
93 msg = "It does not call start API in some time although the download is created";
95 case DOWNLOAD_ERROR_SYSTEM_DOWN:
96 msg = "There are no response from client after rebooting download daemon";
98 case DOWNLOAD_ERROR_ID_NOT_FOUND:
99 msg = "The download id is not existed in download service module";
101 case DOWNLOAD_ERROR_NO_DATA:
102 msg = "No data because the set API is not called";
104 case DOWNLOAD_ERROR_IO_ERROR:
105 msg = "Internal I/O error";
107 case DOWNLOAD_ERROR_NONE:
111 msg = "Unknown error";
115 LoggerE("Platform error %d <%s>", err, msg.c_str());
123 download_state_e state;
124 unsigned long long received;
126 } DOWNLOAD_EVENT_DATA_T;
128 static gboolean downloadEventCB(void *data) {
131 DOWNLOAD_EVENT_DATA_T *fnData = static_cast<DOWNLOAD_EVENT_DATA_T*>(data);
134 long downloadId = (long)fnData->downloadId;
136 DownloadManager *thisObj = (DownloadManager*)fnData->user_data;
138 throw UnknownException("UserData is NULL.");
141 DownloadCallback *callback = thisObj->getCallbackFromMap(downloadId);
143 throw UnknownException("Callback could not found.");
146 switch(fnData->state) {
147 case DOWNLOAD_STATE_QUEUED:
149 callback->onprogress(downloadId, 0, 0);
152 case DOWNLOAD_STATE_PAUSED:
154 callback->onpaused(downloadId);
157 case DOWNLOAD_STATE_DOWNLOADING:
159 unsigned long long totalSize = 0;
160 ret = download_get_content_size(downloadId, &totalSize);
161 if (ret != DOWNLOAD_ERROR_NONE) {
162 throw UnknownException(("Platform error while getting total file size. " + _get_download_error(ret)).c_str());
165 callback->onprogress(downloadId, fnData->received, totalSize);
168 case DOWNLOAD_STATE_COMPLETED:
170 ret = download_unset_state_changed_cb(downloadId);
171 if (ret != DOWNLOAD_ERROR_NONE) {
172 throw UnknownException(("Platform error while unsetting state changed callback. " + _get_download_error(ret)).c_str());
175 ret = download_unset_progress_cb(downloadId);
176 if (ret != DOWNLOAD_ERROR_NONE) {
177 throw UnknownException(("Platform error while unsetting progress callback. " + _get_download_error(ret)).c_str());
180 char *fullPath = NULL;
181 ret = download_get_downloaded_file_path(downloadId, &fullPath);
182 if (ret != DOWNLOAD_ERROR_NONE || !fullPath) {
183 throw UnknownException(("Platform error while getting downloaded full path. " + _get_download_error(ret)).c_str());
186 ret = download_destroy(downloadId);
187 if (ret != DOWNLOAD_ERROR_NONE) {
188 LoggerW("Platform error while destroying download handle. downloadId=" << downloadId);
191 std::string virtualPath;
193 virtualPath = DeviceAPI::Filesystem::Utils::toVirtualPath(NULL, fullPath);
195 LoggerW("Platform error while converting fullPath.");
196 virtualPath = fullPath;
199 callback->oncompleted(downloadId, virtualPath);
202 thisObj->removeCallbackFromMap(downloadId);
205 case DOWNLOAD_STATE_FAILED:
207 ret = download_unset_state_changed_cb(downloadId);
208 if (ret != DOWNLOAD_ERROR_NONE) {
209 throw UnknownException(("Platform error while unsetting state changed callback. " + _get_download_error(ret)).c_str());
212 ret = download_unset_progress_cb(downloadId);
213 if (ret != DOWNLOAD_ERROR_NONE) {
214 throw UnknownException(("Platform error while unsetting progress callback. " + _get_download_error(ret)).c_str());
217 int err = DOWNLOAD_ERROR_NONE;
218 std::string errMessage;
219 ret = download_get_error(downloadId, (download_error_e*)&err);
220 if (ret != DOWNLOAD_ERROR_NONE) {
221 LoggerW("Platform error while getting download error. ");
223 errMessage = _get_download_error(err);
226 ret = download_destroy(downloadId);
227 if (ret != DOWNLOAD_ERROR_NONE) {
228 LoggerW("Platform error while destroying download handle. downloadId=" << downloadId);
231 UnknownException error(errMessage.c_str());
232 callback->onfailed(downloadId, error);
233 thisObj->removeCallbackFromMap(downloadId);
236 case DOWNLOAD_STATE_CANCELED:
238 ret = download_unset_state_changed_cb(downloadId);
239 if (ret != DOWNLOAD_ERROR_NONE) {
240 throw UnknownException(("Platform error while unsetting state changed callback. " + _get_download_error(ret)).c_str());
243 ret = download_unset_progress_cb(downloadId);
244 if (ret != DOWNLOAD_ERROR_NONE) {
245 throw UnknownException(("Platform error while unsetting progress callback. " + _get_download_error(ret)).c_str());
248 ret = download_destroy(downloadId);
249 if (ret != DOWNLOAD_ERROR_NONE) {
250 LoggerW("Platform error while destroying download handle. downloadId=" << downloadId);
253 callback->oncanceled(downloadId);
254 thisObj->removeCallbackFromMap(downloadId);
258 LoggerW("State changed is ignored.");
261 } catch (const BasePlatformException &err) {
262 LoggerE("download_state_changed_cb: %s", err.getMessage().c_str());
269 static void download_state_changed_cb(int downloadId, download_state_e state, void *user_data)
271 LoggerD("download_state_changed_cb, downloadId=%d, state=%d", downloadId, (int)state);
272 DOWNLOAD_EVENT_DATA_T *data = new DOWNLOAD_EVENT_DATA_T;
273 data->downloadId = downloadId;
276 data->user_data = user_data;
278 // download core f/w calls this callback function in another thread.
279 // so we should use g_idle_add() to switch context to main thread.
280 g_idle_add(downloadEventCB, static_cast<void*>(data));
283 static void download_progress_cb(int downloadId, unsigned long long received, void *user_data)
285 LoggerD("download_progress_cb, downloadId=%d, received=%ld", downloadId, received);
286 DOWNLOAD_EVENT_DATA_T *data = new DOWNLOAD_EVENT_DATA_T;
287 data->downloadId = downloadId;
288 data->state = DOWNLOAD_STATE_DOWNLOADING;
289 data->received = received;
290 data->user_data = user_data;
292 // download core f/w calls this callback function in another thread.
293 // so we should use g_idle_add() to switch context to main thread.
294 g_idle_add(downloadEventCB, static_cast<void*>(data));
297 DownloadManager::DownloadManager()
301 DownloadManager::~DownloadManager()
305 void DownloadManager::setCallbackToMap(long downloadId, DownloadCallback *callback)
307 DownloadCallback *value = mDownloadCallbacks[downloadId];
311 mDownloadCallbacks[downloadId] = callback;
314 DownloadCallback* DownloadManager::getCallbackFromMap(long downloadId)
316 return mDownloadCallbacks[downloadId];
319 void DownloadManager::removeCallbackFromMap(long downloadId) {
320 DownloadCallback *value = mDownloadCallbacks[downloadId];
321 mDownloadCallbacks.erase(downloadId);
327 long DownloadManager::start(DownloadRequest *request, DownloadCallback *downloadCallback)
336 throw TypeMismatchException("request is NULL.");
339 std::string url = request->getUrl();
340 std::string destination = request->getDestination();
341 std::string fileName = request->getFileName();
342 std::string networkType = request->getNetworkType();
343 std::map<std::string, std::string> httpHeader = request->getHttpHeader();
345 LoggerD("url <%s>, destination <%s>, fileName <%s>", url.c_str(), destination.c_str(), fileName.c_str());
348 throw InvalidValuesException("Invalid DownloadRequest.url.");
351 ret = download_create(&downloadId);
352 if (ret != DOWNLOAD_ERROR_NONE) {
353 throw UnknownException(("Platform error while creating download. " + _get_download_error(ret)).c_str());
356 ret = download_set_url(downloadId, url.c_str());
357 if (ret != DOWNLOAD_ERROR_NONE) {
358 throw UnknownException(("Platform error while setting url. " + _get_download_error(ret)).c_str());
361 if (!destination.empty()) {
362 std::string fullPath;
364 DeviceAPI::Filesystem::IPathPtr path = DeviceAPI::Filesystem::Utils::fromVirtualPath(NULL, destination);
365 fullPath = path->getFullPath();
367 LoggerW("Converting virtual path is failed. [%s]", destination.c_str());
368 fullPath = destination;
370 LoggerD("Converted FullPath = <%s>", fullPath.c_str());
371 ret = download_set_destination(downloadId, fullPath.c_str());
372 if (ret != DOWNLOAD_ERROR_NONE) {
373 throw UnknownException(("Platform error while setting destination. " + _get_download_error(ret)).c_str());
377 if (!fileName.empty()) {
378 ret = download_set_file_name(downloadId, fileName.c_str());
379 if (ret != DOWNLOAD_ERROR_NONE) {
380 throw UnknownException(("Platform error while setting fileName. " + _get_download_error(ret)).c_str());
384 ret = download_set_state_changed_cb(downloadId, download_state_changed_cb, this);
385 if (ret != DOWNLOAD_ERROR_NONE) {
386 throw UnknownException(("Platform error while setting state changed callback. " + _get_download_error(ret)).c_str());
389 ret = download_set_progress_cb(downloadId, download_progress_cb, this);
390 if (ret != DOWNLOAD_ERROR_NONE) {
391 throw UnknownException(("Platform error while setting progress callback. " + _get_download_error(ret)).c_str());
394 if (!networkType.empty()) {
395 ret = DOWNLOAD_ERROR_NONE;
396 if (networkType == TIZEN_ENUM_DOWNLOAD_NETWORK_TYPE_CELLULAR) {
397 ret = download_set_network_type(downloadId, DOWNLOAD_NETWORK_DATA_NETWORK);
398 } else if (networkType == TIZEN_ENUM_DOWNLOAD_NETWORK_TYPE_WIFI) {
399 ret = download_set_network_type(downloadId, DOWNLOAD_NETWORK_WIFI);
400 } else if (networkType == TIZEN_ENUM_DOWNLOAD_NETWORK_TYPE_ALL) {
401 ret = download_set_network_type(downloadId, DOWNLOAD_NETWORK_ALL);
403 throw TypeMismatchException("Wrong DownloadNetworkType.");
405 if (ret != DOWNLOAD_ERROR_NONE) {
406 throw UnknownException(("Platform error while setting network type. " + _get_download_error(ret)).c_str());
410 std::map<std::string, std::string>::const_iterator iter;
411 for (iter = httpHeader.begin(); iter != httpHeader.end(); ++iter) {
412 ret = download_add_http_header_field(downloadId, iter->first.c_str(), iter->second.c_str());
413 if (ret != DOWNLOAD_ERROR_NONE) {
414 throw UnknownException(("Platform error while setting http header fields. " + _get_download_error(ret)).c_str());
418 ret = download_start(downloadId);
419 if (ret != DOWNLOAD_ERROR_NONE) {
420 throw UnknownException(("Platform error while starting download. " + _get_download_error(ret)).c_str());
423 LoggerD("downloadId: %d", downloadId);
425 setCallbackToMap(downloadId, downloadCallback);
430 void DownloadManager::cancel(long downloadId)
434 LoggerD("entered. downloadId = %d", downloadId);
436 ret = download_cancel(downloadId);
437 if (ret != DOWNLOAD_ERROR_NONE) {
438 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
439 throw NotFoundException("download id could not found.");
440 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
441 throw InvalidValuesException("download id is not valid.");
443 throw UnknownException(("Platform error while canceling download. " + _get_download_error(ret)).c_str());
447 void DownloadManager::pause(long downloadId)
451 LoggerD("entered. downloadId = %d", downloadId);
453 ret = download_pause(downloadId);
454 if (ret != DOWNLOAD_ERROR_NONE) {
455 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
456 throw NotFoundException("download id could not found.");
457 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
458 throw InvalidValuesException("download id is not valid.");
460 throw UnknownException(("Platform error while pausing download. " + _get_download_error(ret)).c_str());
464 void DownloadManager::resume(long downloadId)
468 LoggerD("entered. downloadId = %d", downloadId);
470 ret = download_start(downloadId);
471 if (ret != DOWNLOAD_ERROR_NONE) {
472 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
473 throw NotFoundException("download id could not found.");
474 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
475 throw InvalidValuesException("download id is not valid.");
477 throw UnknownException(("Platform error while resuming download. " + _get_download_error(ret)).c_str());
481 std::string DownloadManager::getState(long downloadId)
484 download_state_e state;
487 LoggerD("entered. downloadId = %d", downloadId);
489 ret = download_get_state(downloadId, &state);
490 if (ret != DOWNLOAD_ERROR_NONE) {
491 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
492 throw NotFoundException("download id could not found.");
493 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
494 throw InvalidValuesException("download id is not valid.");
496 throw UnknownException(("Platform error while getting state. " + _get_download_error(ret)).c_str());
500 case DOWNLOAD_STATE_READY:
501 case DOWNLOAD_STATE_QUEUED:
502 result = TIZEN_ENUM_DOWNLOAD_STATE_QUEUED;
504 case DOWNLOAD_STATE_DOWNLOADING:
505 result = TIZEN_ENUM_DOWNLOAD_STATE_DOWNLOADING;
507 case DOWNLOAD_STATE_PAUSED:
508 result = TIZEN_ENUM_DOWNLOAD_STATE_PAUSED;
510 case DOWNLOAD_STATE_COMPLETED:
511 result = TIZEN_ENUM_DOWNLOAD_STATE_COMPLETED;
513 case DOWNLOAD_STATE_FAILED:
514 result = TIZEN_ENUM_DOWNLOAD_STATE_FAILED;
516 case DOWNLOAD_STATE_CANCELED:
517 result = TIZEN_ENUM_DOWNLOAD_STATE_CANCELED;
520 result = "undefined";
521 LoggerW("Unknown DownloadState was returned.");
528 DownloadRequest* DownloadManager::getDownloadRequest(long downloadId)
534 char *destination = NULL;
535 char *fileName = NULL;
536 download_network_type_e networkTypeValue = DOWNLOAD_NETWORK_ALL;
537 char **fieldNames = NULL;
538 char *fieldValue = NULL;
541 LoggerD("entered. downloadId = %d", downloadId);
543 ret = download_get_url(downloadId, &url);
544 if (ret != DOWNLOAD_ERROR_NONE) {
545 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
546 throw NotFoundException("download id could not found.");
547 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
548 throw InvalidValuesException("download id is not valid.");
550 throw UnknownException(("Platform error while getting url. " + _get_download_error(ret)).c_str());
553 ret = download_get_destination(downloadId, &destination);
554 if (ret != DOWNLOAD_ERROR_NONE && ret != DOWNLOAD_ERROR_NO_DATA) {
555 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
556 throw NotFoundException("download id could not found.");
557 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
558 throw InvalidValuesException("download id is not valid.");
560 throw UnknownException(("Platform error while getting destination. " + _get_download_error(ret)).c_str());
563 ret = download_get_file_name(downloadId, &fileName);
564 if (ret != DOWNLOAD_ERROR_NONE && ret != DOWNLOAD_ERROR_NO_DATA) {
565 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
566 throw NotFoundException("download id could not found.");
567 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
568 throw InvalidValuesException("download id is not valid.");
570 throw UnknownException(("Platform error while getting fileName. " + _get_download_error(ret)).c_str());
573 ret = download_get_network_type(downloadId, &networkTypeValue);
574 if (ret != DOWNLOAD_ERROR_NONE && ret != DOWNLOAD_ERROR_NO_DATA) {
575 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
576 throw NotFoundException("download id could not found.");
577 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
578 throw InvalidValuesException("download id is not valid.");
580 throw UnknownException(("Platform error while getting network type. " + _get_download_error(ret)).c_str());
583 ret = download_get_http_header_field_list(downloadId, &fieldNames, &fieldLength);
584 if (ret != DOWNLOAD_ERROR_NONE && ret != DOWNLOAD_ERROR_NO_DATA) {
585 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
586 throw NotFoundException("download id could not found.");
587 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
588 throw InvalidValuesException("download id is not valid.");
590 throw UnknownException(("Platform error while getting http header fields. " + _get_download_error(ret)).c_str());
593 std::map<std::string, std::string> httpHeader;
594 for (i = 0; i < fieldLength; i++) {
595 ret = download_get_http_header_field(downloadId, fieldNames[i], &fieldValue);
596 if (ret != DOWNLOAD_ERROR_NONE) {
597 LoggerW("Platform error while getting http header field. " << _get_download_error(ret));
599 httpHeader.insert(make_pair(std::string(fieldNames[i]), std::string(fieldValue)));
605 DownloadRequest *request = new DownloadRequest();
608 request->setUrl(url);
613 std::string virtualPath;
615 virtualPath = DeviceAPI::Filesystem::Utils::toVirtualPath(NULL, destination);
617 LoggerW("Platform error while converting destination path.");
618 virtualPath = destination;
620 request->setDestination(virtualPath);
625 request->setFileName(fileName);
629 switch(networkTypeValue) {
630 case DOWNLOAD_NETWORK_DATA_NETWORK:
631 request->setNetworkType(TIZEN_ENUM_DOWNLOAD_NETWORK_TYPE_CELLULAR);
633 case DOWNLOAD_NETWORK_WIFI:
634 request->setNetworkType(TIZEN_ENUM_DOWNLOAD_NETWORK_TYPE_WIFI);
637 request->setNetworkType(TIZEN_ENUM_DOWNLOAD_NETWORK_TYPE_ALL);
642 request->setHttpHeader(httpHeader);
649 std::string DownloadManager::getMIMEType(long downloadId)
652 char *mimeType = NULL;
653 std::string result("");
655 LoggerD("entered. downloadId = %d", downloadId);
657 ret = download_get_mime_type(downloadId, &mimeType);
658 if (ret != DOWNLOAD_ERROR_NONE) {
659 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
660 throw NotFoundException("download id could not found.");
661 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
662 throw InvalidValuesException("download id is not valid.");
663 } else if (ret == DOWNLOAD_ERROR_NO_DATA) {
666 throw UnknownException(("Platform error while getting MIME type. " + _get_download_error(ret)).c_str());
679 void DownloadManager::setListener(long downloadId, DownloadCallback *downloadCallback)
683 LoggerD("entered. downloadId = %d", downloadId);
685 ret = download_set_state_changed_cb(downloadId, download_state_changed_cb, this);
686 if (ret != DOWNLOAD_ERROR_NONE) {
687 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
688 throw NotFoundException("download id could not found.");
689 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
690 throw InvalidValuesException("download id is not valid.");
692 throw UnknownException(("Platform error while setting state changed callback. " + _get_download_error(ret)).c_str());
695 ret = download_set_progress_cb(downloadId, download_progress_cb, this);
696 if (ret != DOWNLOAD_ERROR_NONE) {
697 if (ret == DOWNLOAD_ERROR_ID_NOT_FOUND) {
698 throw NotFoundException("download id could not found.");
699 } else if (ret == DOWNLOAD_ERROR_INVALID_PARAMETER) {
700 throw InvalidValuesException("download id is not valid.");
702 throw UnknownException(("Platform error while setting progress callback. " + _get_download_error(ret)).c_str());
705 setCallbackToMap(downloadId, downloadCallback);