Merge branch 'tizen_3.0' into tizen_4.0
[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   }
322
323   out["downloadId"] = picojson::value(static_cast<double>(download_id));
324
325   out["fullPath"] = picojson::value(common::FilesystemProvider::Create().GetVirtualPath(fullPath));
326   out["listenerId"] = picojson::value(kDownloadManagerListenerId);
327
328   Instance::PostMessage(down_cb_ptr->instance, picojson::value(out).serialize().c_str());
329   // down_cb_ptr is freed in destructor, it prevent from crash if OnFinished state
330   // was called after OnCanceled or OnFailed
331   free(fullPath);
332
333   return FALSE;
334 }
335
336 gboolean DownloadInstance::OnPaused(void* user_data) {
337   ScopeLogger();
338   CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
339   std::lock_guard<std::mutex> lock(instances_mutex_);
340   if (!CheckInstance(down_cb_ptr->instance)) {
341     return FALSE;
342   }
343
344   int download_id = down_cb_ptr->download_id;
345   DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[download_id];
346   if (!di_ptr) {
347     LoggerW("Download handle does not exist for callback id %d", down_cb_ptr->download_id);
348     return FALSE;
349   }
350
351   LoggerD("OnPaused for callbackID %d Called", download_id);
352
353   picojson::value::object out;
354   out["status"] = picojson::value("paused");
355   out["downloadId"] = picojson::value(static_cast<double>(download_id));
356   out["listenerId"] = picojson::value(kDownloadManagerListenerId);
357
358   Instance::PostMessage(down_cb_ptr->instance, picojson::value(out).serialize().c_str());
359   return FALSE;
360 }
361
362 gboolean DownloadInstance::OnCanceled(void* user_data) {
363   ScopeLogger();
364   CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
365   std::lock_guard<std::mutex> lock(instances_mutex_);
366   if (!CheckInstance(down_cb_ptr->instance)) {
367     return FALSE;
368   }
369
370   int download_id = down_cb_ptr->download_id;
371   DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[download_id];
372   if (!di_ptr) {
373     LoggerW("Download handle does not exist for callback id %d", download_id);
374     return FALSE;
375   }
376
377   LoggerD("OnCanceled for callbackID %d Called", download_id);
378
379   int ret = download_unset_state_changed_cb(di_ptr->native_download_id);
380   if (ret != DOWNLOAD_ERROR_NONE) {
381     LoggerE("%s", get_error_message(ret));
382   }
383
384   ret = download_unset_progress_cb(di_ptr->native_download_id);
385   if (ret != DOWNLOAD_ERROR_NONE) {
386     LoggerE("%s", get_error_message(ret));
387   }
388
389   ret = download_destroy(di_ptr->native_download_id);
390   if (ret != DOWNLOAD_ERROR_NONE) {
391     LoggerE("%s", get_error_message(ret));
392   }
393
394   picojson::value::object out;
395   out["status"] = picojson::value("canceled");
396   out["downloadId"] = picojson::value(static_cast<double>(download_id));
397   out["listenerId"] = picojson::value(kDownloadManagerListenerId);
398
399   Instance::PostMessage(down_cb_ptr->instance, picojson::value(out).serialize().c_str());
400   // down_cb_ptr is freed in destructor, it prevent from crash if OnFinished state
401   // was called after OnFinished or OnFailed
402   return FALSE;
403 }
404
405 gboolean DownloadInstance::OnFailed(void* user_data) {
406   ScopeLogger();
407   download_error_e error;
408   picojson::object out;
409
410   CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
411   std::lock_guard<std::mutex> lock(instances_mutex_);
412   if (!CheckInstance(down_cb_ptr->instance)) {
413     return FALSE;
414   }
415
416   int download_id = down_cb_ptr->download_id;
417   DownloadInfoPtr di_ptr = down_cb_ptr->instance->di_map[download_id];
418   if (!di_ptr) {
419     LoggerW("Download handle does not exist for callback id %d", download_id);
420     return FALSE;
421   }
422
423   LoggerD("OnFailed for callbackID %d called", download_id);
424
425   download_get_error(down_cb_ptr->native_download_id, &error);
426   if (DOWNLOAD_ERROR_NONE != error) {
427     int http_status = 0;
428     int ret = download_get_http_status(down_cb_ptr->native_download_id, &http_status);
429     std::string error_message;
430     if (DOWNLOAD_ERROR_NONE != ret) {
431       LoggerE("Gathering HTTP status failed, default error message will be used");
432     } else {
433       LoggerD("HTTP status is: %d", http_status);
434       error_message = "Error with HTTP status: " + std::to_string(http_status);
435     }
436     LogAndReportError(convertError(error, error_message), &out,
437                       ("download_get_error error: %d (%s)", error, get_error_message(error)));
438   }
439
440   int ret = download_unset_state_changed_cb(di_ptr->native_download_id);
441   if (ret != DOWNLOAD_ERROR_NONE) {
442     LoggerE("%s", get_error_message(ret));
443   }
444
445   ret = download_unset_progress_cb(di_ptr->native_download_id);
446   if (ret != DOWNLOAD_ERROR_NONE) {
447     LoggerE("%s", get_error_message(ret));
448   }
449
450   ret = download_destroy(di_ptr->native_download_id);
451   if (DOWNLOAD_ERROR_NONE != ret) {
452     LoggerE("%s", get_error_message(ret));
453   }
454
455   out["downloadId"] = picojson::value(static_cast<double>(down_cb_ptr->download_id));
456   out["listenerId"] = picojson::value(kDownloadManagerListenerId);
457
458   Instance::PostMessage(down_cb_ptr->instance, picojson::value(out).serialize().c_str());
459   // down_cb_ptr is freed in destructor, it prevent from crash if OnFinished state
460   // was called after OnFinished or OnCanceled
461   return FALSE;
462 }
463
464 void DownloadInstance::progress_changed_cb(int download_id, long long unsigned received,
465                                            void* user_data) {
466   ScopeLogger();
467   CallbackPtr down_cb_ptr = static_cast<CallbackPtr>(user_data);
468   down_cb_ptr->received = received;
469   down_cb_ptr->native_download_id = download_id;
470
471   g_idle_add(OnProgressChanged, down_cb_ptr);
472 }
473
474 void DownloadInstance::DownloadManagerStart(const picojson::value& args, picojson::object& out) {
475   ScopeLogger();
476   CHECK_PRIVILEGE_ACCESS(kPrivilegeDownload, &out);
477   CHECK_EXIST(args, "downloadId", out)
478   CHECK_EXIST(args, "url", out)
479
480   int ret;
481   std::string networkType;
482
483   DownloadInfoPtr di_ptr(new DownloadInfo);
484
485   di_ptr->download_id = static_cast<int>(args.get("downloadId").get<double>());
486   di_ptr->url = args.get("url").is<std::string>() ? args.get("url").get<std::string>() : "";
487
488   if (!args.get("destination").is<picojson::null>()) {
489     if (args.get("destination").is<std::string>() &&
490         args.get("destination").get<std::string>() != "") {
491       di_ptr->destination = args.get("destination").get<std::string>();
492       di_ptr->destination = common::FilesystemProvider::Create().GetRealPath(di_ptr->destination);
493     }
494   }
495
496   if (!args.get("fileName").is<picojson::null>()) {
497     if (args.get("fileName").is<std::string>() && args.get("fileName").get<std::string>() != "") {
498       di_ptr->file_name = args.get("fileName").get<std::string>();
499     }
500   }
501
502   if (!args.get("networkType").is<picojson::null>()) {
503     networkType = args.get("networkType").is<std::string>()
504                       ? args.get("networkType").get<std::string>()
505                       : "ALL";
506   }
507
508   bool network_support = false;
509   bool cell_support = false;
510   bool wifi_support = false;
511
512   system_info_get_platform_bool("http://tizen.org/feature/network.telephony", &cell_support);
513   system_info_get_platform_bool("http://tizen.org/feature/network.wifi", &wifi_support);
514
515   connection_h connection = nullptr;
516   connection_create(&connection);
517   SCOPE_EXIT {
518     connection_destroy(connection);
519   };
520
521   connection_cellular_state_e cell_state = CONNECTION_CELLULAR_STATE_OUT_OF_SERVICE;
522   connection_wifi_state_e wifi_state = CONNECTION_WIFI_STATE_DEACTIVATED;
523
524   connection_get_cellular_state(connection, &cell_state);
525   connection_get_wifi_state(connection, &wifi_state);
526
527   connection_type_e connection_type = CONNECTION_TYPE_DISCONNECTED;
528   connection_get_type(connection, &connection_type);
529
530   if (CONNECTION_TYPE_DISCONNECTED == connection_type) {
531     LogAndReportError(
532         common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, "Connection problem occured"), &out,
533         ("Connection type is disconnected"));
534     return;
535   }
536
537   bool network_available = false;
538   bool cell_available = (CONNECTION_CELLULAR_STATE_CONNECTED == cell_state);
539   bool wifi_available = (CONNECTION_WIFI_STATE_CONNECTED == wifi_state);
540
541   if ("CELLULAR" == networkType) {
542     network_support = cell_support;
543     network_available = cell_available;
544     di_ptr->network_type = DOWNLOAD_NETWORK_DATA_NETWORK;
545   } else if ("WIFI" == networkType) {
546     network_support = wifi_support;
547     network_available = wifi_available;
548     di_ptr->network_type = DOWNLOAD_NETWORK_WIFI;
549   } else if (("ALL" == networkType) && (CONNECTION_TYPE_DISCONNECTED != connection_type)) {
550     network_support = true;
551     network_available = true;
552     di_ptr->network_type = DOWNLOAD_NETWORK_ALL;
553   } else {
554     LogAndReportError(
555         common::PlatformResult(common::ErrorCode::INVALID_VALUES_ERR,
556                                "The input parameter contains an invalid network type."),
557         &out, ("The input parameter contains an invalid network type: %s", networkType.c_str()));
558     return;
559   }
560
561   /*
562    * There is no relevant feature for networkType == "ALL".
563    */
564   if (!network_support && ("ALL" != networkType)) {
565     LogAndReportError(common::PlatformResult(common::ErrorCode::NOT_SUPPORTED_ERR,
566                                              "The networkType of the given DownloadRequest "
567                                              "is not supported on this device."),
568                       &out, ("Requested network type (%s) is not supported.", networkType.c_str()));
569     return;
570   }
571
572   if (!network_available) {
573     LogAndReportError(common::PlatformResult(common::ErrorCode::NETWORK_ERR,
574                                              "The networkType of the given DownloadRequest "
575                                              "is currently not available on this device."),
576                       &out, ("Requested network type (%s) is not available.", networkType.c_str()));
577     return;
578   }
579
580   CallbackPtr down_cb_ptr(new DownloadCallback);
581
582   down_cb_ptr->download_id = di_ptr->download_id;
583   down_cb_ptr->instance = this;
584
585   download_callbacks[down_cb_ptr->download_id] = down_cb_ptr;
586
587   ret = download_create(&di_ptr->native_download_id);
588   if (ret != DOWNLOAD_ERROR_NONE) {
589     LogAndReportError(convertError(ret), &out,
590                       ("download_create error: %d (%s)", ret, get_error_message(ret)));
591     return;
592   }
593
594   ret = download_set_state_changed_cb(di_ptr->native_download_id, OnStateChanged,
595                                       static_cast<void*>(down_cb_ptr));
596   if (ret != DOWNLOAD_ERROR_NONE) {
597     LogAndReportError(convertError(ret), &out, ("download_set_state_changed_cb error: %d (%s)", ret,
598                                                 get_error_message(ret)));
599     return;
600   }
601
602   ret = download_set_progress_cb(di_ptr->native_download_id, progress_changed_cb,
603                                  static_cast<void*>(down_cb_ptr));
604   if (ret != DOWNLOAD_ERROR_NONE) {
605     LogAndReportError(convertError(ret), &out,
606                       ("download_set_progress_cb error: %d (%s)", ret, get_error_message(ret)));
607     return;
608   }
609
610   ret = download_set_url(di_ptr->native_download_id, di_ptr->url.c_str());
611   if (ret != DOWNLOAD_ERROR_NONE) {
612     LogAndReportError(convertError(ret), &out,
613                       ("download_set_url error: %d (%s)", ret, get_error_message(ret)));
614     return;
615   }
616
617   if (di_ptr->destination.size() != 0) {
618     ret = download_set_destination(di_ptr->native_download_id, di_ptr->destination.c_str());
619     if (ret != DOWNLOAD_ERROR_NONE) {
620       LogAndReportError(convertError(ret), &out,
621                         ("download_set_destination error: %d (%s)", ret, get_error_message(ret)));
622       return;
623     }
624   }
625
626   if (!di_ptr->file_name.empty()) {
627     ret = download_set_file_name(di_ptr->native_download_id, di_ptr->file_name.c_str());
628     if (ret != DOWNLOAD_ERROR_NONE) {
629       LogAndReportError(convertError(ret), &out,
630                         ("download_set_file_name error: %d (%s)", ret, get_error_message(ret)));
631       return;
632     }
633   }
634
635   ret = download_set_network_type(di_ptr->native_download_id, di_ptr->network_type);
636
637   if (args.get("httpHeader").is<picojson::object>()) {
638     picojson::object obj = args.get("httpHeader").get<picojson::object>();
639     for (picojson::object::const_iterator it = obj.begin(); it != obj.end(); ++it) {
640       download_add_http_header_field(di_ptr->native_download_id, it->first.c_str(),
641                                      it->second.to_str().c_str());
642     }
643   }
644
645   di_map[down_cb_ptr->download_id] = di_ptr;
646
647   ret = download_start(di_ptr->native_download_id);
648
649   if (ret == DOWNLOAD_ERROR_NONE) {
650     ReportSuccess(out);
651   } else {
652     LogAndReportError(convertError(ret), &out,
653                       ("download_start error: %d (%s)", ret, get_error_message(ret)));
654   }
655 }
656
657 void DownloadInstance::DownloadManagerCancel(const picojson::value& args, picojson::object& out) {
658   ScopeLogger();
659   CHECK_EXIST(args, "downloadId", out)
660   int downloadId, ret;
661
662   int callbackId = static_cast<int>(args.get("downloadId").get<double>());
663
664   if (!GetDownloadID(callbackId, downloadId)) {
665     LogAndReportError(
666         common::PlatformResult(common::ErrorCode::NOT_FOUND_ERR,
667                                "The identifier does not match any download operation in progress"),
668         &out, ("The identifier %d does not match any download operation in progress", downloadId));
669     return;
670   }
671
672   ret = download_cancel(downloadId);
673
674   if (ret == DOWNLOAD_ERROR_NONE) {
675     ReportSuccess(out);
676   } else {
677     LogAndReportError(convertError(ret), &out,
678                       ("download_cancel error: %d (%s)", ret, get_error_message(ret)));
679   }
680 }
681
682 void DownloadInstance::DownloadManagerPause(const picojson::value& args, picojson::object& out) {
683   ScopeLogger();
684   CHECK_EXIST(args, "downloadId", out)
685   int downloadId, ret;
686
687   int callbackId = static_cast<int>(args.get("downloadId").get<double>());
688
689   if (!GetDownloadID(callbackId, downloadId)) {
690     LogAndReportError(
691         common::PlatformResult(common::ErrorCode::NOT_FOUND_ERR,
692                                "The identifier does not match any download operation in progress"),
693         &out, ("The identifier %d does not match any download operation in progress", downloadId));
694     return;
695   }
696
697   ret = download_pause(downloadId);
698
699   if (ret == DOWNLOAD_ERROR_NONE) {
700     ReportSuccess(out);
701   } else {
702     LogAndReportError(convertError(ret), &out,
703                       ("download_pause error: %d (%s)", ret, get_error_message(ret)));
704   }
705 }
706
707 void DownloadInstance::DownloadManagerResume(const picojson::value& args, picojson::object& out) {
708   ScopeLogger();
709   CHECK_EXIST(args, "downloadId", out)
710   int downloadId, ret;
711
712   int callbackId = static_cast<int>(args.get("downloadId").get<double>());
713
714   if (!GetDownloadID(callbackId, downloadId)) {
715     LogAndReportError(
716         common::PlatformResult(common::ErrorCode::NOT_FOUND_ERR,
717                                "The identifier does not match any download operation in progress"),
718         &out, ("The identifier %d does not match any download operation in progress", downloadId));
719     return;
720   }
721
722   ret = download_start(downloadId);
723
724   if (ret == DOWNLOAD_ERROR_NONE) {
725     ReportSuccess(out);
726   } else {
727     LogAndReportError(convertError(ret), &out,
728                       ("download_start error: %d (%s)", ret, get_error_message(ret)));
729   }
730 }
731
732 void DownloadInstance::DownloadManagerGetstate(const picojson::value& args, picojson::object& out) {
733   ScopeLogger();
734   CHECK_EXIST(args, "downloadId", out)
735   int downloadId, ret;
736   std::string stateValue;
737   download_state_e state;
738
739   int callbackId = static_cast<int>(args.get("downloadId").get<double>());
740
741   if (!GetDownloadID(callbackId, downloadId)) {
742     LogAndReportError(
743         common::PlatformResult(common::ErrorCode::NOT_FOUND_ERR,
744                                "The identifier does not match any download operation in progress"),
745         &out, ("The identifier %d does not match any download operation in progress", downloadId));
746     return;
747   }
748
749   ret = download_get_state(downloadId, &state);
750
751   if (ret == DOWNLOAD_ERROR_NONE) {
752     switch (state) {
753       case DOWNLOAD_STATE_NONE:
754         break;
755       case DOWNLOAD_STATE_QUEUED:
756         stateValue = "QUEUED";
757         break;
758       case DOWNLOAD_STATE_DOWNLOADING:
759         stateValue = "DOWNLOADING";
760         break;
761       case DOWNLOAD_STATE_PAUSED:
762         stateValue = "PAUSED";
763         break;
764       case DOWNLOAD_STATE_COMPLETED:
765         stateValue = "COMPLETED";
766         break;
767       case DOWNLOAD_STATE_FAILED:
768         stateValue = "FAILED";
769         break;
770       case DOWNLOAD_STATE_CANCELED:
771         stateValue = "CANCELED";
772         break;
773       default:
774         LoggerD("Unexpected download state: %d", state);
775         break;
776     }
777
778     ReportSuccess(picojson::value(stateValue), out);
779   } else {
780     LogAndReportError(convertError(ret), &out,
781                       ("download_get_state error: %d (%s)", ret, get_error_message(ret)));
782   }
783 }
784
785 void DownloadInstance::DownloadManagerGetmimetype(const picojson::value& args,
786                                                   picojson::object& out) {
787   ScopeLogger();
788   CHECK_EXIST(args, "downloadId", out)
789
790   int downloadId, ret;
791   char* mimetype = NULL;
792
793   int callbackId = static_cast<int>(args.get("downloadId").get<double>());
794
795   if (!GetDownloadID(callbackId, downloadId)) {
796     LogAndReportError(
797         common::PlatformResult(common::ErrorCode::NOT_FOUND_ERR,
798                                "The identifier does not match any download operation in progress"),
799         &out, ("The identifier %d does not match any download operation in progress", downloadId));
800     return;
801   }
802
803   ret = download_get_mime_type(downloadId, &mimetype);
804
805   if (ret == DOWNLOAD_ERROR_NONE) {
806     ReportSuccess(picojson::value(mimetype), out);
807   } else {
808     LogAndReportError(convertError(ret), &out,
809                       ("download_get_mime_type error: %d (%s)", ret, get_error_message(ret)));
810   }
811   free(mimetype);
812 }
813
814 bool DownloadInstance::GetDownloadID(const int download_id, int& native_download_id) {
815   ScopeLogger();
816   if (di_map.find(download_id) != di_map.end()) {
817     native_download_id = di_map.find(download_id)->second->native_download_id;
818   } else {
819     return false;
820   }
821   return true;
822 }
823
824 #undef CHECK_EXIST
825
826 }  // namespace download
827 }  // namespace extension