[Download][TDAF-1353] Exception fix for 'start' function
[platform/core/api/webapi-plugins.git] / src / download / download_instance.cc
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 #include "download/download_instance.h"
18
19 #include <functional>
20
21 #include <net_connection.h>
22
23 #include "common/filesystem/filesystem_provider.h"
24 #include "common/logger.h"
25 #include "common/picojson.h"
26 #include "common/scope_exit.h"
27 #include "common/tools.h"
28 #include "common/typeutil.h"
29
30 namespace extension {
31 namespace download {
32
33 std::vector<DownloadInstance*> DownloadInstance::instances_;
34 std::mutex DownloadInstance::instances_mutex_;
35
36 namespace {
37 // The privileges that required in Download API
38 const std::string kPrivilegeDownload = "http://tizen.org/privilege/download";
39 const std::string kDownloadManagerListenerId = "DownloadManagerListener";
40
41 }  // namespace
42
43 DownloadInstance::DownloadInstance() {
44   ScopeLogger();
45   using std::placeholders::_1;
46   using std::placeholders::_2;
47 #define REGISTER_SYNC(c, x) RegisterSyncHandler(c, std::bind(&DownloadInstance::x, this, _1, _2));
48   REGISTER_SYNC("DownloadManager_pause", DownloadManagerPause);
49   REGISTER_SYNC("DownloadManager_getMIMEType", DownloadManagerGetmimetype);
50   REGISTER_SYNC("DownloadManager_start", DownloadManagerStart);
51   REGISTER_SYNC("DownloadManager_cancel", DownloadManagerCancel);
52   REGISTER_SYNC("DownloadManager_resume", DownloadManagerResume);
53   REGISTER_SYNC("DownloadManager_getState", DownloadManagerGetstate);
54 #undef REGISTER_SYNC
55
56   std::lock_guard<std::mutex> lock(instances_mutex_);
57   instances_.push_back(this);
58 }
59
60 DownloadInstance::~DownloadInstance() {
61   ScopeLogger();
62   int ret;
63
64   std::lock_guard<std::mutex> lock(instances_mutex_);
65
66   for (DownloadCallbackMap::iterator it = download_callbacks.begin();
67        it != download_callbacks.end(); ++it) {
68     DownloadInfoPtr di_ptr = it->second->instance->di_map[it->second->download_id];
69     SLoggerD("~DownloadInstance() for callbackID %d Called", it->second->download_id);
70
71     if (di_ptr) {
72       ret = download_unset_state_changed_cb(di_ptr->native_download_id);
73       if (ret != DOWNLOAD_ERROR_NONE)
74         LoggerE("download_unset_state_changed_cb() is failed. (%s)", get_error_message(ret));
75
76       ret = download_unset_progress_cb(di_ptr->native_download_id);
77       if (ret != DOWNLOAD_ERROR_NONE)
78         LoggerE("download_unset_progress_cb() is failed. (%s)", get_error_message(ret));
79
80       ret = download_cancel(di_ptr->native_download_id);
81       if (ret != DOWNLOAD_ERROR_NONE)
82         LoggerE("download_cancel() is failed. (%s)", get_error_message(ret));
83
84       ret = download_destroy(di_ptr->native_download_id);
85       if (ret != DOWNLOAD_ERROR_NONE)
86         LoggerE("download_destroy() is failed. (%s)", get_error_message(ret));
87     } else {
88       LoggerD("di_ptr is nullptr");
89     }
90
91     delete (it->second);
92   }
93
94   for (auto it = instances_.begin(); it != instances_.end(); it++) {
95     if (*it == this) {
96       instances_.erase(it);
97       break;
98     }
99   }
100 }
101
102 bool DownloadInstance::CheckInstance(DownloadInstance* instance) {
103   ScopeLogger();
104   for (auto vec_instance : instances_) {
105     if (vec_instance == instance) {
106       return true;
107     }
108   }
109
110   return false;
111 }
112
113 common::PlatformResult DownloadInstance::convertError(int err, const std::string& message) {
114   char* error = nullptr;
115   if (message.empty()) {
116     error = get_error_message(err);
117   } else {
118     error = (char*)message.c_str();
119   }
120
121   switch (err) {
122     case DOWNLOAD_ERROR_INVALID_PARAMETER:
123       return common::PlatformResult(common::ErrorCode::INVALID_VALUES_ERR, error);
124     case DOWNLOAD_ERROR_OUT_OF_MEMORY:
125       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
126     case DOWNLOAD_ERROR_NETWORK_UNREACHABLE:
127       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
128     case DOWNLOAD_ERROR_CONNECTION_TIMED_OUT:
129       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
130     case DOWNLOAD_ERROR_NO_SPACE:
131       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
132     case DOWNLOAD_ERROR_PERMISSION_DENIED:
133       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
134     case DOWNLOAD_ERROR_NOT_SUPPORTED:
135       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
136     case DOWNLOAD_ERROR_INVALID_STATE:
137       return common::PlatformResult(common::ErrorCode::INVALID_VALUES_ERR, error);
138     case DOWNLOAD_ERROR_CONNECTION_FAILED:
139       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
140     case DOWNLOAD_ERROR_INVALID_URL:
141       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
142     case DOWNLOAD_ERROR_INVALID_DESTINATION:
143       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
144     case DOWNLOAD_ERROR_TOO_MANY_DOWNLOADS:
145       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
146     case DOWNLOAD_ERROR_QUEUE_FULL:
147       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
148     case DOWNLOAD_ERROR_ALREADY_COMPLETED:
149       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
150     case DOWNLOAD_ERROR_FILE_ALREADY_EXISTS:
151       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
152     case DOWNLOAD_ERROR_CANNOT_RESUME:
153       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
154     case DOWNLOAD_ERROR_FIELD_NOT_FOUND:
155       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
156     case DOWNLOAD_ERROR_TOO_MANY_REDIRECTS:
157       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
158     case DOWNLOAD_ERROR_UNHANDLED_HTTP_CODE:
159       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
160     case DOWNLOAD_ERROR_REQUEST_TIMEOUT:
161       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
162     case DOWNLOAD_ERROR_RESPONSE_TIMEOUT:
163       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
164     case DOWNLOAD_ERROR_SYSTEM_DOWN:
165       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
166     case DOWNLOAD_ERROR_ID_NOT_FOUND:
167       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
168     case DOWNLOAD_ERROR_INVALID_NETWORK_TYPE:
169       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
170     case DOWNLOAD_ERROR_NO_DATA:
171       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
172     case DOWNLOAD_ERROR_IO_ERROR:
173       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, error);
174     default:
175       return common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, "Unknown error.");
176   }
177 }
178
179 #define CHECK_EXIST(args, name, out)                                               \
180   if (!args.contains(name)) {                                                      \
181     LogAndReportError(common::PlatformResult(common::ErrorCode::TYPE_MISMATCH_ERR, \
182                                              name " is required argument"),        \
183                       &out);                                                       \
184     return;                                                                        \
185   }
186
187 void DownloadInstance::OnStateChanged(int download_id, download_state_e state, void* user_data) {
188   ScopeLogger();
189   CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
190
191   // Prevent to call finished, cancelled or failed function more than once
192   if (DOWNLOAD_STATE_COMPLETED == down_cb_ptr->state ||
193       DOWNLOAD_STATE_CANCELED == down_cb_ptr->state ||
194       DOWNLOAD_STATE_FAILED == down_cb_ptr->state) {
195     LoggerD("Already finished job, not calling callback for %d state", down_cb_ptr->state);
196     return;
197   }
198
199   down_cb_ptr->state = state;
200   down_cb_ptr->native_download_id = download_id;
201
202   SLoggerD("State for callbackId %d changed to %d", down_cb_ptr->download_id,
203            static_cast<int>(state));
204
205   switch (state) {
206     case DOWNLOAD_STATE_NONE:
207       break;
208     case DOWNLOAD_STATE_DOWNLOADING:
209       OnStart(download_id, user_data);
210       break;
211     case DOWNLOAD_STATE_PAUSED:
212       g_idle_add(OnPaused, down_cb_ptr);
213       break;
214     case DOWNLOAD_STATE_COMPLETED:
215       g_idle_add(OnFinished, down_cb_ptr);
216       break;
217     case DOWNLOAD_STATE_CANCELED:
218       g_idle_add(OnCanceled, down_cb_ptr);
219       break;
220     case DOWNLOAD_STATE_FAILED:
221       g_idle_add(OnFailed, down_cb_ptr);
222       break;
223     default:
224       LoggerD("Unexpected download state: %d", state);
225       break;
226   }
227 }
228
229 gboolean DownloadInstance::OnProgressChanged(void* user_data) {
230   ScopeLogger();
231   CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
232   std::lock_guard<std::mutex> lock(instances_mutex_);
233   if (!CheckInstance(down_cb_ptr->instance)) {
234     return FALSE;
235   }
236
237   DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[down_cb_ptr->download_id];
238   if (!di_ptr) {
239     LoggerW("Download handle does not exist for callback id %d", down_cb_ptr->download_id);
240     return FALSE;
241   }
242
243   picojson::value::object out;
244   out["status"] = picojson::value("progress");
245   out["downloadId"] = picojson::value(static_cast<double>(down_cb_ptr->download_id));
246   out["receivedSize"] = picojson::value(static_cast<double>(down_cb_ptr->received));
247   out["totalSize"] = picojson::value(static_cast<double>(di_ptr->file_size));
248   out["listenerId"] = picojson::value(kDownloadManagerListenerId);
249
250   LoggerD("OnProgressChanged for callbackId %d Called: Received: %llu", down_cb_ptr->download_id,
251           down_cb_ptr->received);
252
253   picojson::value v = picojson::value(out);
254   Instance::PostMessage(down_cb_ptr->instance, v.serialize().c_str());
255
256   return FALSE;
257 }
258
259 void DownloadInstance::OnStart(int download_id, void* user_data) {
260   ScopeLogger();
261   unsigned long long totalSize;
262
263   CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
264   std::lock_guard<std::mutex> lock(instances_mutex_);
265   if (!CheckInstance(down_cb_ptr->instance)) {
266     return;
267   }
268
269   SLoggerD("OnStart for callbackId %d Called", down_cb_ptr->download_id);
270
271   DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[down_cb_ptr->download_id];
272   if (!di_ptr) {
273     LoggerW("Download handle does not exist for callback id %d", down_cb_ptr->download_id);
274     return;
275   }
276
277   download_get_content_size(download_id, &totalSize);
278
279   di_ptr->file_size = totalSize;
280 }
281
282 gboolean DownloadInstance::OnFinished(void* user_data) {
283   ScopeLogger();
284   char* fullPath = NULL;
285
286   CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
287   std::lock_guard<std::mutex> lock(instances_mutex_);
288   if (!CheckInstance(down_cb_ptr->instance)) {
289     return FALSE;
290   }
291
292   int download_id = down_cb_ptr->download_id;
293   DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[download_id];
294   if (!di_ptr) {
295     LoggerW("Download handle does not exist for callback id %d", down_cb_ptr->download_id);
296     return FALSE;
297   }
298
299   LoggerD("OnFinished for callbackID %d Called", download_id);
300
301   picojson::value::object out;
302
303   int ret = download_get_downloaded_file_path(down_cb_ptr->native_download_id, &fullPath);
304   if (ret != DOWNLOAD_ERROR_NONE) {
305     LogAndReportError(convertError(ret), &out, ("download_get_downloaded_file_path error: %d (%s)",
306                                                 ret, get_error_message(ret)));
307   } else {
308     ret = download_unset_state_changed_cb(di_ptr->native_download_id);
309     if (ret != DOWNLOAD_ERROR_NONE) {
310       LoggerW("%s", get_error_message(ret));
311     }
312     ret = download_unset_progress_cb(di_ptr->native_download_id);
313     if (ret != DOWNLOAD_ERROR_NONE) {
314       LoggerW("%s", get_error_message(ret));
315     }
316     ret = download_destroy(di_ptr->native_download_id);
317     if (ret != DOWNLOAD_ERROR_NONE) {
318       LoggerW("%s", get_error_message(ret));
319     }
320     out["status"] = picojson::value("completed");
321     out["fullPath"] =
322         picojson::value(common::FilesystemProvider::Create().GetVirtualPath(fullPath));
323   }
324   out["downloadId"] = picojson::value(static_cast<double>(download_id));
325
326   out["listenerId"] = picojson::value(kDownloadManagerListenerId);
327   Instance::PostMessage(down_cb_ptr->instance, picojson::value(out).serialize().c_str());
328   // down_cb_ptr is freed in destructor, it prevent from crash if OnFinished state
329   // was called after OnCanceled or OnFailed
330   free(fullPath);
331
332   return FALSE;
333 }
334
335 gboolean DownloadInstance::OnPaused(void* user_data) {
336   ScopeLogger();
337   CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
338   std::lock_guard<std::mutex> lock(instances_mutex_);
339   if (!CheckInstance(down_cb_ptr->instance)) {
340     return FALSE;
341   }
342
343   int download_id = down_cb_ptr->download_id;
344   DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[download_id];
345   if (!di_ptr) {
346     LoggerW("Download handle does not exist for callback id %d", down_cb_ptr->download_id);
347     return FALSE;
348   }
349
350   LoggerD("OnPaused for callbackID %d Called", download_id);
351
352   picojson::value::object out;
353   out["status"] = picojson::value("paused");
354   out["downloadId"] = picojson::value(static_cast<double>(download_id));
355   out["listenerId"] = picojson::value(kDownloadManagerListenerId);
356
357   Instance::PostMessage(down_cb_ptr->instance, picojson::value(out).serialize().c_str());
358   return FALSE;
359 }
360
361 gboolean DownloadInstance::OnCanceled(void* user_data) {
362   ScopeLogger();
363   CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
364   std::lock_guard<std::mutex> lock(instances_mutex_);
365   if (!CheckInstance(down_cb_ptr->instance)) {
366     return FALSE;
367   }
368
369   int download_id = down_cb_ptr->download_id;
370   DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[download_id];
371   if (!di_ptr) {
372     LoggerW("Download handle does not exist for callback id %d", download_id);
373     return FALSE;
374   }
375
376   LoggerD("OnCanceled for callbackID %d Called", download_id);
377
378   int ret = download_unset_state_changed_cb(di_ptr->native_download_id);
379   if (ret != DOWNLOAD_ERROR_NONE) {
380     LoggerE("%s", get_error_message(ret));
381   }
382
383   ret = download_unset_progress_cb(di_ptr->native_download_id);
384   if (ret != DOWNLOAD_ERROR_NONE) {
385     LoggerE("%s", get_error_message(ret));
386   }
387
388   ret = download_destroy(di_ptr->native_download_id);
389   if (ret != DOWNLOAD_ERROR_NONE) {
390     LoggerE("%s", get_error_message(ret));
391   }
392
393   picojson::value::object out;
394   out["status"] = picojson::value("canceled");
395   out["downloadId"] = picojson::value(static_cast<double>(download_id));
396   out["listenerId"] = picojson::value(kDownloadManagerListenerId);
397
398   Instance::PostMessage(down_cb_ptr->instance, picojson::value(out).serialize().c_str());
399   // down_cb_ptr is freed in destructor, it prevent from crash if OnFinished state
400   // was called after OnFinished or OnFailed
401   return FALSE;
402 }
403
404 gboolean DownloadInstance::OnFailed(void* user_data) {
405   ScopeLogger();
406   download_error_e error;
407   picojson::object out;
408
409   CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
410   std::lock_guard<std::mutex> lock(instances_mutex_);
411   if (!CheckInstance(down_cb_ptr->instance)) {
412     return FALSE;
413   }
414
415   int download_id = down_cb_ptr->download_id;
416   DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[download_id];
417   if (!di_ptr) {
418     LoggerW("Download handle does not exist for callback id %d", download_id);
419     return FALSE;
420   }
421
422   LoggerD("OnFailed for callbackID %d called", download_id);
423
424   download_get_error(down_cb_ptr->native_download_id, &error);
425   if (DOWNLOAD_ERROR_NONE != error) {
426     int http_status = 0;
427     int ret = download_get_http_status(down_cb_ptr->native_download_id, &http_status);
428     std::string error_message;
429     if (DOWNLOAD_ERROR_NONE != ret) {
430       LoggerE("Gathering HTTP status failed, default error message will be used");
431     } else {
432       LoggerD("HTTP status is: %d", http_status);
433       error_message = "Error with HTTP status: " + std::to_string(http_status);
434     }
435     LogAndReportError(convertError(error, error_message), &out,
436                       ("download_get_error error: %d (%s)", error, get_error_message(error)));
437   }
438
439   int ret = download_unset_state_changed_cb(di_ptr->native_download_id);
440   if (ret != DOWNLOAD_ERROR_NONE) {
441     LoggerE("%s", get_error_message(ret));
442   }
443
444   ret = download_unset_progress_cb(di_ptr->native_download_id);
445   if (ret != DOWNLOAD_ERROR_NONE) {
446     LoggerE("%s", get_error_message(ret));
447   }
448
449   ret = download_destroy(di_ptr->native_download_id);
450   if (DOWNLOAD_ERROR_NONE != ret) {
451     LoggerE("%s", get_error_message(ret));
452   }
453
454   out["downloadId"] = picojson::value(static_cast<double>(down_cb_ptr->download_id));
455   out["listenerId"] = picojson::value(kDownloadManagerListenerId);
456
457   Instance::PostMessage(down_cb_ptr->instance, picojson::value(out).serialize().c_str());
458   // down_cb_ptr is freed in destructor, it prevent from crash if OnFinished state
459   // was called after OnFinished or OnCanceled
460   return FALSE;
461 }
462
463 void DownloadInstance::progress_changed_cb(int download_id, long long unsigned received,
464                                            void* user_data) {
465   ScopeLogger();
466   CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
467   down_cb_ptr->received = received;
468   down_cb_ptr->native_download_id = download_id;
469
470   g_idle_add(OnProgressChanged, down_cb_ptr);
471 }
472
473 #define CHECK_CONNECTION_ERROR(ret)                                                            \
474   switch (ret) {                                                                               \
475     case CONNECTION_ERROR_NONE:                                                                \
476       break;                                                                                   \
477     case CONNECTION_ERROR_NOT_SUPPORTED:                                                       \
478       return LogAndCreateResult(                                                               \
479           common::ErrorCode::NOT_SUPPORTED_ERR,                                                \
480           "The networkType of the given DownloadRequest is not supported",                     \
481           ("The networkType of the given DownloadRequest is not supported"));                  \
482     default:                                                                                   \
483       return LogAndCreateResult(common::ErrorCode::UNKNOWN_ERR, "Connection problem occurred", \
484                                 ("Connection problem occurred"));                              \
485   }
486
487 common::PlatformResult DownloadInstance::CheckNetworkConnection(const std::string& network_type,
488                                                                 bool& network_support,
489                                                                 bool& network_available,
490                                                                 DownloadInfoPtr di_ptr) {
491   ScopeLogger("network_type: %s", network_type.c_str());
492
493   connection_h connection = nullptr;
494   int ret = connection_create(&connection);
495   CHECK_CONNECTION_ERROR(ret)
496   SCOPE_EXIT {
497     connection_destroy(connection);
498   };
499
500   connection_type_e connection_type = CONNECTION_TYPE_DISCONNECTED;
501   ret = connection_get_type(connection, &connection_type);
502   CHECK_CONNECTION_ERROR(ret)
503
504   if ("CELLULAR" == network_type) {
505     // check if connection type is supported
506     bool cell_support = false;
507     system_info_get_platform_bool("http://tizen.org/feature/network.telephony", &cell_support);
508
509     // check if connection is available
510     connection_cellular_state_e cell_state = CONNECTION_CELLULAR_STATE_OUT_OF_SERVICE;
511     ret = connection_get_cellular_state(connection, &cell_state);
512     CHECK_CONNECTION_ERROR(ret)
513     bool cell_available = (CONNECTION_CELLULAR_STATE_CONNECTED == cell_state);
514
515     // setup download parameters using cellular network
516     network_support = cell_support;
517     network_available = cell_available;
518     di_ptr->network_type = DOWNLOAD_NETWORK_DATA_NETWORK;
519   } else if ("WIFI" == network_type) {
520     // check if connection type is supported
521     bool wifi_support = false;
522     system_info_get_platform_bool("http://tizen.org/feature/network.wifi", &wifi_support);
523
524     // check if connection is available
525     connection_wifi_state_e wifi_state = CONNECTION_WIFI_STATE_DEACTIVATED;
526     ret = connection_get_wifi_state(connection, &wifi_state);
527     CHECK_CONNECTION_ERROR(ret)
528     bool wifi_available = (CONNECTION_WIFI_STATE_CONNECTED == wifi_state);
529
530     // setup download parameters using wifi network
531     network_support = wifi_support;
532     network_available = wifi_available;
533     di_ptr->network_type = DOWNLOAD_NETWORK_WIFI;
534   } else if (("ALL" == network_type) && (CONNECTION_TYPE_DISCONNECTED != connection_type)) {
535     // setup download parameters using 'all' network
536     network_support = true;
537     network_available = true;
538     di_ptr->network_type = DOWNLOAD_NETWORK_ALL;
539   } else {
540     return LogAndCreateResult(
541         common::ErrorCode::INVALID_VALUES_ERR,
542         "The input parameter contains an invalid network type.",
543         ("The input parameter contains an invalid network type: %s", network_type.c_str()));
544   }
545   if (CONNECTION_TYPE_DISCONNECTED == connection_type) {
546     return LogAndCreateResult(common::ErrorCode::UNKNOWN_ERR, "Connection problem occurred",
547                               ("Connection type is disconnected"));
548   }
549   return common::PlatformResult(common::ErrorCode::NO_ERROR);
550 }
551 #undef CHECK_CONNECTION_ERROR
552
553 void DownloadInstance::DownloadManagerStart(const picojson::value& args, picojson::object& out) {
554   ScopeLogger();
555   CHECK_PRIVILEGE_ACCESS(kPrivilegeDownload, &out);
556   CHECK_EXIST(args, "downloadId", out)
557   CHECK_EXIST(args, "url", out)
558
559   int ret;
560   std::string network_type;
561
562   DownloadInfoPtr di_ptr(new DownloadInfo);
563
564   di_ptr->download_id = static_cast<int>(args.get("downloadId").get<double>());
565   di_ptr->url = args.get("url").is<std::string>() ? args.get("url").get<std::string>() : "";
566
567   if (!args.get("destination").is<picojson::null>()) {
568     if (args.get("destination").is<std::string>() &&
569         args.get("destination").get<std::string>() != "") {
570       di_ptr->destination = args.get("destination").get<std::string>();
571       di_ptr->destination = common::FilesystemProvider::Create().GetRealPath(di_ptr->destination);
572     }
573   }
574
575   CHECK_STORAGE_ACCESS(di_ptr->destination.empty()
576                            ? common::FilesystemProvider::Create().GetRealPath("downloads")
577                            : di_ptr->destination,
578                        &out);
579
580   if (!args.get("fileName").is<picojson::null>()) {
581     if (args.get("fileName").is<std::string>() && args.get("fileName").get<std::string>() != "") {
582       di_ptr->file_name = args.get("fileName").get<std::string>();
583     }
584   }
585
586   if (!args.get("networkType").is<picojson::null>()) {
587     network_type = args.get("networkType").is<std::string>()
588                        ? args.get("networkType").get<std::string>()
589                        : "ALL";
590   }
591
592   bool network_support = false;
593   bool network_available = false;
594
595   common::PlatformResult result =
596       CheckNetworkConnection(network_type, network_support, network_available, di_ptr);
597   if (!result) {
598     LogAndReportError(result, &out);
599     return;
600   }
601
602   /*
603    * There is no relevant feature for network_type == "ALL".
604    */
605   if (!network_support && ("ALL" != network_type)) {
606     LogAndReportError(common::PlatformResult(common::ErrorCode::NOT_SUPPORTED_ERR,
607                                              "The networkType of the given DownloadRequest "
608                                              "is not supported on this device."),
609                       &out,
610                       ("Requested network type (%s) is not supported.", network_type.c_str()));
611     return;
612   }
613
614   if (!network_available) {
615     LogAndReportError(common::PlatformResult(common::ErrorCode::NETWORK_ERR,
616                                              "The networkType of the given DownloadRequest "
617                                              "is currently not available on this device."),
618                       &out,
619                       ("Requested network type (%s) is not available.", network_type.c_str()));
620     return;
621   }
622
623   CallbackPtr down_cb_ptr(new DownloadCallback);
624
625   down_cb_ptr->download_id = di_ptr->download_id;
626   down_cb_ptr->instance = this;
627
628   download_callbacks[down_cb_ptr->download_id] = down_cb_ptr;
629
630   ret = download_create(&di_ptr->native_download_id);
631   if (ret != DOWNLOAD_ERROR_NONE) {
632     LogAndReportError(convertError(ret), &out,
633                       ("download_create error: %d (%s)", ret, get_error_message(ret)));
634     return;
635   }
636
637   ret = download_set_state_changed_cb(di_ptr->native_download_id, OnStateChanged,
638                                       static_cast<void*>(down_cb_ptr));
639   if (ret != DOWNLOAD_ERROR_NONE) {
640     LogAndReportError(convertError(ret), &out, ("download_set_state_changed_cb error: %d (%s)", ret,
641                                                 get_error_message(ret)));
642     return;
643   }
644
645   ret = download_set_progress_cb(di_ptr->native_download_id, progress_changed_cb,
646                                  static_cast<void*>(down_cb_ptr));
647   if (ret != DOWNLOAD_ERROR_NONE) {
648     LogAndReportError(convertError(ret), &out,
649                       ("download_set_progress_cb error: %d (%s)", ret, get_error_message(ret)));
650     return;
651   }
652
653   ret = download_set_url(di_ptr->native_download_id, di_ptr->url.c_str());
654   if (ret != DOWNLOAD_ERROR_NONE) {
655     LogAndReportError(convertError(ret), &out,
656                       ("download_set_url error: %d (%s)", ret, get_error_message(ret)));
657     return;
658   }
659
660   if (di_ptr->destination.size() != 0) {
661     ret = download_set_destination(di_ptr->native_download_id, di_ptr->destination.c_str());
662     if (ret != DOWNLOAD_ERROR_NONE) {
663       LogAndReportError(convertError(ret), &out,
664                         ("download_set_destination error: %d (%s)", ret, get_error_message(ret)));
665       return;
666     }
667   }
668
669   if (!di_ptr->file_name.empty()) {
670     ret = download_set_file_name(di_ptr->native_download_id, di_ptr->file_name.c_str());
671     if (ret != DOWNLOAD_ERROR_NONE) {
672       LogAndReportError(convertError(ret), &out,
673                         ("download_set_file_name error: %d (%s)", ret, get_error_message(ret)));
674       return;
675     }
676   }
677
678   ret = download_set_network_type(di_ptr->native_download_id, di_ptr->network_type);
679
680   if (args.get("httpHeader").is<picojson::object>()) {
681     picojson::object obj = args.get("httpHeader").get<picojson::object>();
682     for (picojson::object::const_iterator it = obj.begin(); it != obj.end(); ++it) {
683       download_add_http_header_field(di_ptr->native_download_id, it->first.c_str(),
684                                      it->second.to_str().c_str());
685     }
686   }
687
688   di_map[down_cb_ptr->download_id] = di_ptr;
689
690   ret = download_start(di_ptr->native_download_id);
691
692   if (ret == DOWNLOAD_ERROR_NONE) {
693     ReportSuccess(out);
694   } else {
695     LogAndReportError(convertError(ret), &out,
696                       ("download_start error: %d (%s)", ret, get_error_message(ret)));
697   }
698 }
699
700 void DownloadInstance::DownloadManagerCancel(const picojson::value& args, picojson::object& out) {
701   ScopeLogger();
702   CHECK_EXIST(args, "downloadId", out)
703   int downloadId, ret;
704
705   int callbackId = static_cast<int>(args.get("downloadId").get<double>());
706
707   if (!GetDownloadID(callbackId, downloadId)) {
708     LogAndReportError(
709         common::PlatformResult(common::ErrorCode::NOT_FOUND_ERR,
710                                "The identifier does not match any download operation in progress"),
711         &out, ("The identifier %d does not match any download operation in progress", downloadId));
712     return;
713   }
714
715   ret = download_cancel(downloadId);
716
717   if (ret == DOWNLOAD_ERROR_NONE) {
718     ReportSuccess(out);
719   } else {
720     LogAndReportError(convertError(ret), &out,
721                       ("download_cancel error: %d (%s)", ret, get_error_message(ret)));
722   }
723 }
724
725 void DownloadInstance::DownloadManagerPause(const picojson::value& args, picojson::object& out) {
726   ScopeLogger();
727   CHECK_EXIST(args, "downloadId", out)
728   int downloadId, ret;
729
730   int callbackId = static_cast<int>(args.get("downloadId").get<double>());
731
732   if (!GetDownloadID(callbackId, downloadId)) {
733     LogAndReportError(
734         common::PlatformResult(common::ErrorCode::NOT_FOUND_ERR,
735                                "The identifier does not match any download operation in progress"),
736         &out, ("The identifier %d does not match any download operation in progress", downloadId));
737     return;
738   }
739
740   ret = download_pause(downloadId);
741
742   if (ret == DOWNLOAD_ERROR_NONE) {
743     ReportSuccess(out);
744   } else {
745     LogAndReportError(convertError(ret), &out,
746                       ("download_pause error: %d (%s)", ret, get_error_message(ret)));
747   }
748 }
749
750 void DownloadInstance::DownloadManagerResume(const picojson::value& args, picojson::object& out) {
751   ScopeLogger();
752   CHECK_EXIST(args, "downloadId", out)
753   int downloadId, ret;
754
755   int callbackId = static_cast<int>(args.get("downloadId").get<double>());
756
757   if (!GetDownloadID(callbackId, downloadId)) {
758     LogAndReportError(
759         common::PlatformResult(common::ErrorCode::NOT_FOUND_ERR,
760                                "The identifier does not match any download operation in progress"),
761         &out, ("The identifier %d does not match any download operation in progress", downloadId));
762     return;
763   }
764
765   ret = download_start(downloadId);
766
767   if (ret == DOWNLOAD_ERROR_NONE) {
768     ReportSuccess(out);
769   } else {
770     LogAndReportError(convertError(ret), &out,
771                       ("download_start error: %d (%s)", ret, get_error_message(ret)));
772   }
773 }
774
775 void DownloadInstance::DownloadManagerGetstate(const picojson::value& args, picojson::object& out) {
776   ScopeLogger();
777   CHECK_EXIST(args, "downloadId", out)
778   int downloadId, ret;
779   std::string stateValue;
780   download_state_e state;
781
782   int callbackId = static_cast<int>(args.get("downloadId").get<double>());
783
784   if (!GetDownloadID(callbackId, downloadId)) {
785     LogAndReportError(
786         common::PlatformResult(common::ErrorCode::NOT_FOUND_ERR,
787                                "The identifier does not match any download operation in progress"),
788         &out, ("The identifier %d does not match any download operation in progress", downloadId));
789     return;
790   }
791
792   ret = download_get_state(downloadId, &state);
793
794   if (ret == DOWNLOAD_ERROR_NONE) {
795     switch (state) {
796       case DOWNLOAD_STATE_NONE:
797         break;
798       case DOWNLOAD_STATE_QUEUED:
799         stateValue = "QUEUED";
800         break;
801       case DOWNLOAD_STATE_DOWNLOADING:
802         stateValue = "DOWNLOADING";
803         break;
804       case DOWNLOAD_STATE_PAUSED:
805         stateValue = "PAUSED";
806         break;
807       case DOWNLOAD_STATE_COMPLETED:
808         stateValue = "COMPLETED";
809         break;
810       case DOWNLOAD_STATE_FAILED:
811         stateValue = "FAILED";
812         break;
813       case DOWNLOAD_STATE_CANCELED:
814         stateValue = "CANCELED";
815         break;
816       default:
817         LoggerD("Unexpected download state: %d", state);
818         break;
819     }
820
821     ReportSuccess(picojson::value(stateValue), out);
822   } else {
823     LogAndReportError(convertError(ret), &out,
824                       ("download_get_state error: %d (%s)", ret, get_error_message(ret)));
825   }
826 }
827
828 void DownloadInstance::DownloadManagerGetmimetype(const picojson::value& args,
829                                                   picojson::object& out) {
830   ScopeLogger();
831   CHECK_EXIST(args, "downloadId", out)
832
833   int downloadId, ret;
834   char* mimetype = NULL;
835
836   int callbackId = static_cast<int>(args.get("downloadId").get<double>());
837
838   if (!GetDownloadID(callbackId, downloadId)) {
839     LogAndReportError(
840         common::PlatformResult(common::ErrorCode::NOT_FOUND_ERR,
841                                "The identifier does not match any download operation in progress"),
842         &out, ("The identifier %d does not match any download operation in progress", downloadId));
843     return;
844   }
845
846   ret = download_get_mime_type(downloadId, &mimetype);
847
848   if (ret == DOWNLOAD_ERROR_NONE) {
849     ReportSuccess(picojson::value(mimetype), out);
850   } else {
851     LogAndReportError(convertError(ret), &out,
852                       ("download_get_mime_type error: %d (%s)", ret, get_error_message(ret)));
853   }
854   free(mimetype);
855 }
856
857 bool DownloadInstance::GetDownloadID(const int download_id, int& native_download_id) {
858   ScopeLogger();
859   if (di_map.find(download_id) != di_map.end()) {
860     native_download_id = di_map.find(download_id)->second->native_download_id;
861   } else {
862     return false;
863   }
864   return true;
865 }
866
867 #undef CHECK_EXIST
868
869 }  // namespace download
870 }  // namespace extension