2 * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include "download-agent-dl-info.h"
24 #include "download-agent-http-msg-handler.h"
25 #include "download-agent-plugin-libcurl.h"
27 int __translate_error_code(int curl_error)
30 case CURLE_OPERATION_TIMEDOUT:
31 return DA_ERR_HTTP_TIMEOUT;
32 case CURLE_SSL_CONNECT_ERROR:
33 case CURLE_SSL_ENGINE_NOTFOUND:
34 case CURLE_SSL_ENGINE_SETFAILED:
35 case CURLE_SSL_CERTPROBLEM:
36 case CURLE_SSL_CIPHER:
37 case CURLE_SSL_CACERT:
38 case CURLE_SSL_ENGINE_INITFAILED:
39 case CURLE_SSL_CACERT_BADFILE:
41 case CURLE_SSL_SHUTDOWN_FAILED:
42 case CURLE_SSL_CRL_BADFILE:
43 case CURLE_SSL_ISSUER_ERROR:
44 return DA_ERR_SSL_FAIL;
45 case CURLE_TOO_MANY_REDIRECTS:
46 return DA_ERR_TOO_MANY_REDIRECTS;
47 case CURLE_OUT_OF_MEMORY:
48 return DA_ERR_FAIL_TO_MEMALLOC;
49 case CURLE_UNSUPPORTED_PROTOCOL:
50 case CURLE_URL_MALFORMAT:
51 case CURLE_COULDNT_RESOLVE_PROXY:
52 case CURLE_COULDNT_RESOLVE_HOST:
53 case CURLE_COULDNT_CONNECT:
54 case CURLE_REMOTE_ACCESS_DENIED:
55 case CURLE_HTTP_POST_ERROR:
56 case CURLE_BAD_DOWNLOAD_RESUME:
57 return DA_ERR_CONNECTION_FAIL;
58 case CURLE_ABORTED_BY_CALLBACK:
59 return DA_RESULT_USER_CANCELED;
61 return DA_ERR_NETWORK_FAIL;
65 int my_trace(CURL *handle, curl_infotype type, char *data, size_t size, void *user)
70 DA_SECURE_LOGI("[curl] Info:%s", data);
72 case CURLINFO_HEADER_OUT:
73 DA_LOGD("[curl] Send header");
75 DA_SECURE_LOGI("[curl] %s", data);
77 case CURLINFO_DATA_OUT:
78 DA_LOGD("[curl] Send data");
80 DA_SECURE_LOGI("[curl] %s", data);
82 case CURLINFO_SSL_DATA_OUT:
83 DA_LOGD("[curl] Send SSL data");
85 case CURLINFO_HEADER_IN:
86 DA_LOGD("[curl] Recv header");
88 DA_SECURE_LOGI("[curl] %s", data);
90 case CURLINFO_SSL_DATA_IN:
91 DA_SECURE_LOGI("[curl] Recv SSL data");
99 void __parse_raw_header(const char *raw_data, http_info_t *http_info)
102 char *ptr2 = DA_NULL;
104 char *field = DA_NULL;
105 char *value = DA_NULL;
106 http_msg_response_t *http_msg_response = NULL;
108 if (!raw_data || !http_info) {
109 DA_LOGE("NULL Check!: raw_data or http_info");
113 if (!http_info->http_msg_response) {
114 http_info->http_msg_response = (http_msg_response_t *)calloc(1,
115 sizeof(http_msg_response_t));
116 if (!http_info->http_msg_response) {
117 DA_LOGE("Fail to calloc");
120 http_info->http_msg_response->head = DA_NULL;
122 http_msg_response = http_info->http_msg_response;
124 ptr = strchr(raw_data, ':');
127 len = ptr - (char *)raw_data;
128 field = (char *)calloc(len + 1, sizeof(char));
130 DA_LOGE("Fail to calloc");
133 memcpy(field, raw_data, len);
142 ptr2 = strchr(raw_data, '\n');
147 value = (char *)calloc(len + 1, sizeof(char));
149 DA_LOGE("Fail to calloc");
153 memcpy(value, ptr, len);
155 http_msg_response_add_field(http_msg_response, field, value);
160 void __store_header(void *msg, da_info_t *da_info, size_t header_size,
161 const char *sniffed_type)
163 http_info_t *http_info = DA_NULL;
165 if (!da_info || !msg) {
166 DA_LOGE("NULL Check!: da_info or msg");
169 http_info = da_info->http_info;
171 DA_LOGE("NULL Check!: http_info");
175 // FIXME later : check status code and redirection case check.
176 if (strcmp(msg, HTTP_FIELD_END_OF_FIELD) == 0) {
180 http_raw_data_t *raw_data = DA_NULL;
181 curl = http_info->http_msg->curl;
182 if (http_info->proxy_info) {
183 DA_LOGI("Proxy is set.");
184 res = curl_easy_getinfo(curl, CURLINFO_HTTP_CONNECTCODE, &status);
186 res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
188 if (res != CURLE_OK) {
189 DA_LOGE("Fail to get response status code");
192 DA_LOGI("status code[%d]", (int)status);
193 if (http_info->http_msg_response)
194 http_info->http_msg_response->status_code = (int)status;
195 raw_data = (http_raw_data_t *)calloc(1, sizeof(http_raw_data_t));
197 DA_LOGE("Fail to calloc");
201 raw_data->status_code = (int)status;
202 raw_data->type = HTTP_EVENT_GOT_HEADER;
204 if (http_info->update_cb)
205 http_info->update_cb(raw_data, da_info);
210 DA_LOGI("%s", (char *)msg);
211 __parse_raw_header((const char *)msg, http_info);
214 size_t __http_gotheaders_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
216 da_info_t *da_info = DA_NULL;
217 if (!ptr || !userdata) {
218 DA_LOGE("Check NULL!: ptr, userdata");
221 da_info = (da_info_t *)userdata;
222 if (da_info->http_info && da_info->http_info->http_msg
223 && da_info->http_info->http_msg->is_cancel_reqeusted) {
224 DA_LOGI("Cancel requested");
228 __store_header(ptr, da_info, (size * nmemb), DA_NULL);
231 DA_LOGI("[RAF] __http_gotheaders_cb done");
234 return (size * nmemb);
238 da_ret_t PI_http_set_file_name_to_curl(http_msg_t *http_msg, char *file_path)
240 NULL_CHECK_RET(http_msg);
241 NULL_CHECK_RET(file_path);
242 DA_LOGI("[RAF]set file_path[%s]", file_path);
243 curl_easy_setopt(http_msg->curl, CURLOPT_BOOSTER_RAF_FILE, file_path);
248 size_t __http_gotchunk_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
250 http_info_t *http_info = DA_NULL;
251 da_info_t *da_info = DA_NULL;
252 http_raw_data_t *raw_data = DA_NULL;
253 if (!ptr || !userdata) {
254 DA_LOGE("Check NULL!: ptr, stream");
257 da_info = (da_info_t *)userdata;
258 NULL_CHECK_RET_OPT(da_info, 0);
259 http_info = da_info->http_info;
260 NULL_CHECK_RET_OPT(http_info, 0);
261 NULL_CHECK_RET_OPT(http_info->http_msg, 0);
262 if (da_info->http_info->http_msg->is_cancel_reqeusted) {
263 DA_LOGI("Cancel requested");
266 //DA_LOGV("size=%ld, nmemb=%ld, datalen=%ld", size, nmemb, strlen((const char *)ptr));
268 //DA_LOGI("size=%ld, nmemb=%ld, datalen=%ld", size, nmemb, strlen((const char *)ptr));
269 if (http_info->is_raf_mode_confirmed) {
270 DA_LOGI("[RAF] return chunked callback");
271 return (size * nmemb);
275 if (ptr && size * nmemb > 0) {
276 if (http_info->update_cb) {
277 raw_data = (http_raw_data_t *)calloc(1, sizeof(http_raw_data_t));
279 DA_LOGE("Fail to calloc");
282 raw_data->body = (char *)calloc(size, nmemb);
283 if (!(raw_data->body)) {
284 DA_LOGE("Fail to calloc");
288 memcpy(raw_data->body, ptr, size * nmemb);
289 raw_data->body_len = size*nmemb;
290 raw_data->type = HTTP_EVENT_GOT_PACKET;
291 http_info->update_cb(raw_data, da_info);
294 return (size * nmemb);
297 long __http_finished_cb(void *ptr)
300 DA_LOGE("Check NULL!: ptr");
301 return CURL_CHUNK_END_FUNC_FAIL;
304 return CURL_CHUNK_END_FUNC_OK;
308 da_ret_t __set_proxy_on_soup_session(proxy_info_t *proxy_info, CURL *curl)
310 da_ret_t ret = DA_RESULT_OK;
312 if (proxy_info && strlen(proxy_info->addr) > 0) {
313 if (!strstr(proxy_info->addr, "0.0.0.0")) {
314 curl_easy_setopt(curl, CURLOPT_PROXY, proxy_info->addr);
315 DA_LOGI("proxy[%s] is used.", proxy_info->addr);
316 if (proxy_info->user_name)
317 curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, proxy_info->user_name);
318 if (proxy_info->password)
319 curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, proxy_info->password);
326 struct curl_slist *__fill_soup_msg_header(CURL *curl, http_info_t *info)
328 http_msg_request_t *input_http_msg_request;
329 struct curl_slist *headers = DA_NULL;
332 DA_LOGE("NULL Check!: curl");
335 input_http_msg_request = info->http_msg_request;
337 if (input_http_msg_request) {
338 char *field = DA_NULL;
339 char *value = DA_NULL;
340 char *buff = DA_NULL;
342 http_header_t *cur = DA_NULL;
343 cur = input_http_msg_request->head;
347 if (field && value) {
348 len = strlen(field) + strlen(value) + 1;
349 buff = (char *)calloc(len + 1, sizeof(char));
351 DA_LOGE("Fail to memalloc");
354 // DA_SECURE_LOGI("[%s] %s", field, value);
355 snprintf(buff, len + 1, "%s:%s", field, value);
356 headers = curl_slist_append(headers, (const char *)buff);
363 DA_LOGE("NULL Check!: input_http_msg_request");
366 if (input_http_msg_request->http_body) {
367 char buff[256] = {0,};
368 int body_len = strlen(input_http_msg_request->http_body);
369 snprintf(buff, sizeof(buff), "%s:%d", HTTP_FIELD_CONTENT_LENGTH,
371 headers = curl_slist_append(headers, buff);
372 memset(buff, 0x00, 256);
373 snprintf(buff, sizeof(buff), "%s:text/plain", HTTP_FIELD_CONTENT_TYPE);
374 headers = curl_slist_append(headers, buff);
375 headers = curl_slist_append(headers, input_http_msg_request->http_body);
377 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
382 int __http_progress_cb(void *clientp, double dltotal, double dlnow,
383 double ultotal, double ulnow)
385 da_info_t *da_info = DA_NULL;
386 http_info_t *http_info = DA_NULL;
387 http_raw_data_t *raw_data = DA_NULL;
389 if (dlnow > 0 || ulnow > 0)
390 DA_LOGI("[RAF]dlnow/ulnow[%llu/%llu][%llu,%llu]", (da_size_t)dlnow, (da_size_t)ulnow, (da_size_t)dltotal, (da_size_t)ultotal);
395 DA_LOGI("[RAF]dlnow is zero. Why is this callback called although there is zero size?");
398 NULL_CHECK_RET_OPT(clientp, -1);
399 da_info = (da_info_t *)clientp;
400 http_info = da_info->http_info;
401 NULL_CHECK_RET_OPT(http_info, -1);
402 NULL_CHECK_RET_OPT(http_info->http_msg, -1);
404 if (http_info->http_msg->is_cancel_reqeusted) {
405 DA_LOGI("Cancel requested");
410 if (http_info->update_cb) {
411 raw_data = (http_raw_data_t *)calloc(1, sizeof(http_raw_data_t));
413 DA_LOGE("Fail to calloc");
416 raw_data->received_len = (da_size_t)dlnow;
417 raw_data->type = HTTP_EVENT_GOT_PACKET;
418 http_info->update_cb(raw_data, da_info);
425 da_ret_t PI_http_start(da_info_t *da_info)
427 da_ret_t ret = DA_RESULT_OK;
428 http_method_t http_method;
429 CURL *curl = DA_NULL;
431 http_msg_t *http_msg = DA_NULL;
433 http_info_t *http_info = DA_NULL;
434 long http_status = 0;
435 struct curl_httppost* post = NULL;
436 struct curl_slist *headers = DA_NULL;
437 char err_buffer[CURL_ERROR_SIZE] = {0,};
438 int disable_verify_host = 0;
443 get_smart_bonding_vconf();
445 NULL_CHECK_GOTO(da_info);
446 NULL_CHECK_GOTO(da_info->req_info);
447 url = da_info->req_info->url;
448 NULL_CHECK_GOTO(url);
449 http_info = da_info->http_info;
450 NULL_CHECK_GOTO(http_info);
452 disable_verify_host = da_info->req_info->disable_verify_host;
454 http_method = http_info->http_method;
455 ret = init_http_msg_t(&http_msg);
456 if (ret != DA_RESULT_OK)
458 http_info->http_msg = http_msg;
460 curl_global_init(CURL_GLOBAL_ALL);
461 curl = curl_easy_init();
464 DA_LOGE("Fail to create curl");
465 return DA_ERR_FAIL_TO_MEMALLOC;
467 DA_LOGI("curl[%p]", curl);
469 curl_easy_setopt(curl, CURLOPT_MAXCONNECTS, MAX_SESSION_COUNT);
470 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, MAX_TIMEOUT);
472 curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, LOW_SPEED_TIME);
473 curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1L);
475 __set_proxy_on_soup_session(http_info->proxy_info, curl);
477 curl_easy_setopt(curl, CURLOPT_URL, url);
478 switch (http_method) {
479 case HTTP_METHOD_GET:
480 curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
482 case HTTP_METHOD_POST:
483 // FIXME later : If the post method is supprot, the post data should be set with curl_fromadd
484 curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
485 DA_LOGI("Need more information for post filed");
487 case HTTP_METHOD_HEAD:
488 DA_LOGI("Donnot implement yet");
491 DA_LOGE("Cannot enter here");
495 headers = __fill_soup_msg_header(curl, http_info);
497 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, __http_gotheaders_cb); // can replace to started_cb
498 curl_easy_setopt(curl, CURLOPT_HEADERDATA, da_info); // param .. same with CURLOPT_WRITEHEADER
499 curl_easy_setopt(curl, CURLOPT_HEADER, 0L); // does not include header to body
500 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, __http_gotchunk_cb); // can replace to progress_
501 curl_easy_setopt(curl, CURLOPT_WRITEDATA, da_info); // param .. same with CURLOPT_WRITEHEADERcb
502 curl_easy_setopt(curl, CURLOPT_CHUNK_END_FUNCTION, __http_finished_cb);
503 curl_easy_setopt(curl, CURLOPT_CHUNK_DATA, da_info);
504 #if _ENABLE_LIBCURL_LOG_VERBOSE
505 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
507 curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);
509 // curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace);
510 curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, err_buffer);
511 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
512 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
513 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, disable_verify_host ? 0L : 2L);
515 curl_easy_setopt(curl, CURLOPT_CAINFO, _CA_CERT);
518 curl_easy_setopt(curl, CURLOPT_CAPATH, _CA_PATH);
521 curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, __http_progress_cb);
522 curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, da_info);
523 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
526 if (da_info->req_info->network_bonding) {
527 #ifdef _DOWNLOAD_BOOSTER_SUPPORT
528 DA_LOGI("network bonding enable");
529 curl_easy_setopt(curl, CURLOPT_MULTIRAT_NEEDED, 1L);
532 curl_easy_setopt(curl, CURLOPT_BOOSTER_RAF_MODE, 1L);
535 http_msg->curl = curl;
536 res = curl_easy_perform(curl);
537 DA_LOGD("perform done! res[%d]", res);
538 if (res != CURLE_OK) {
539 //DA_LOGE("Fail to send data :%d[%s]", res, curl_easy_strerror(res));
540 DA_LOGE("Fail to send data :%d[%s]", res, curl_easy_strerror(res));
541 if (strlen(err_buffer) > 1)
542 DA_LOGE("Fail to error buffer[%s]", err_buffer);
544 res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_status);
545 if (res != CURLE_OK) {
546 //DA_LOGE("Fail to get response code:%d[%s]", res, curl_easy_strerror(res));
547 DA_LOGE("Fail to get response code:%d[%s]", res, curl_easy_strerror(res));
548 ret = DA_ERR_FAIL_TO_MEMALLOC;;
551 DA_LOGD("Response Http Status code[%d]", (int)http_status);
554 if (http_info->update_cb) {
555 http_raw_data_t *raw_data = DA_NULL;
556 raw_data = (http_raw_data_t *)calloc(1, sizeof(http_raw_data_t));
558 DA_LOGE("Fail to calloc");
559 ret = DA_ERR_FAIL_TO_MEMALLOC;
562 if (http_msg->is_cancel_reqeusted ||
563 res == CURLE_ABORTED_BY_CALLBACK) {
564 DA_LOGI("canceled exit. Err[%d]", http_info->error_code);
565 if (http_info->error_code < 0)
566 ret = http_info->error_code;
568 ret = DA_RESULT_USER_CANCELED;
569 } else if ((http_status > 0 && http_status < 100)) {
570 raw_data->error = __translate_error_code(res);
571 ret = DA_ERR_NETWORK_FAIL;
572 } else if (res != CURLE_OK) {
573 raw_data->error = __translate_error_code(res);
574 ret = DA_ERR_NETWORK_FAIL;
576 raw_data->status_code = (int)http_status;
578 raw_data->type = HTTP_EVENT_FINAL;
579 http_info->update_cb(raw_data, da_info);
581 if (DA_NULL != headers)
582 curl_slist_free_all(headers);
583 curl_easy_cleanup(curl);
584 http_msg->curl = DA_NULL;
585 DA_MUTEX_INIT(&(http_msg->mutex), DA_NULL);
592 da_ret_t PI_http_disconnect(http_info_t *info)
594 da_ret_t ret = DA_RESULT_OK;
595 http_msg_t *http_msg = DA_NULL;
598 NULL_CHECK_RET(info);
599 http_msg = info->http_msg;
600 NULL_CHECK_RET(http_msg);
601 DA_LOGV("session [%p]", http_msg->curl);
602 DA_MUTEX_LOCK(&(http_msg->mutex));
603 if (http_msg->is_paused)
604 PI_http_unpause(info);
606 curl_easy_cleanup(http_msg->curl);
608 http_msg->curl = DA_NULL;
609 http_msg->is_paused = DA_FALSE;
610 http_msg->is_cancel_reqeusted = DA_FALSE;
611 DA_MUTEX_UNLOCK(&(http_msg->mutex));
612 DA_MUTEX_DESTROY(&(http_msg->mutex));
613 destroy_http_msg_t(http_msg);
614 info->http_msg = DA_NULL;
618 da_ret_t PI_http_cancel(http_info_t *info)
620 da_ret_t ret = DA_RESULT_OK;
621 http_msg_t *http_msg = DA_NULL;
625 NULL_CHECK_RET(info);
626 http_msg = info->http_msg;
627 NULL_CHECK_RET(http_msg);
628 NULL_CHECK_RET(http_msg->curl);
629 DA_MUTEX_LOCK(&(http_msg->mutex));
630 DA_LOGI("curl[%p]", http_msg->curl);
631 http_msg->is_cancel_reqeusted = DA_TRUE;
632 DA_MUTEX_UNLOCK(&(http_msg->mutex));
633 DA_LOGD("Done - soup cancel");
637 da_ret_t PI_http_pause(http_info_t *info)
639 da_ret_t ret = DA_RESULT_OK;
640 http_msg_t *http_msg = DA_NULL;
641 CURLcode res = CURLE_OK;
644 NULL_CHECK_RET(info);
645 http_msg = info->http_msg;
646 NULL_CHECK_RET(http_msg);
647 DA_LOGD("curl [%p]", http_msg->curl);
648 NULL_CHECK_RET(http_msg->curl);
649 DA_MUTEX_LOCK(&(http_msg->mutex));
650 DA_LOGE("curl_easy_pause call");
651 res = curl_easy_pause(http_msg->curl, CURLPAUSE_ALL);
652 DA_LOGE("curl_easy_pause:%d", res);
654 http_msg->is_paused = DA_TRUE;
656 ret = DA_ERR_CANNOT_SUSPEND;
658 DA_MUTEX_UNLOCK(&(http_msg->mutex));
662 da_ret_t PI_http_unpause(http_info_t *info)
664 da_ret_t ret = DA_RESULT_OK;
665 http_msg_t *http_msg = DA_NULL;
666 CURLcode res = CURLE_OK;
669 NULL_CHECK_RET(info);
670 http_msg = info->http_msg;
671 NULL_CHECK_RET(http_msg);
672 DA_LOGD("curl [%p]", http_msg->curl);
673 NULL_CHECK_RET(http_msg->curl);
674 DA_MUTEX_LOCK(&(http_msg->mutex));
675 res = curl_easy_pause(http_msg->curl, CURLPAUSE_CONT);
676 if (res == CURLE_OK) {
677 http_msg->is_paused = DA_FALSE;
679 DA_LOGE("resume is failed: [%d]", res);
680 ret = DA_ERR_CANNOT_RESUME;
682 DA_MUTEX_UNLOCK(&(http_msg->mutex));