Revert manifest to default one
[profile/ivi/download-provider.git] / src / agent / download-agent-plugin-libsoup.c
1 /*
2  * Download Agent
3  *
4  * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jungki Kwak <jungki.kwak@samsung.com>, Keunsoon Lee <keunsoon.lee@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  * @file                download-agent-plugin-libsoup.c
21  * @brief               Platform dependent functions for interface of libsoup http module
22  * @author              Keunsoon Lee (keunsoon.lee@samsung.com)
23  * @author              Jungki Kwak (jungki.kwak@samsung.com)
24  ***/
25
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "download-agent-debug.h"
30 #include "download-agent-plugin-libsoup.h"
31 #include "download-agent-http-misc.h"
32 #include "download-agent-utils.h"
33 #include "download-agent-pthread.h"
34
35 pthread_mutex_t mutex_for_session_table = PTHREAD_MUTEX_INITIALIZER;
36
37 pi_session_table_t pi_session_table[MAX_SESSION_COUNT] = { { 0, }, };
38 da_bool_t using_content_sniffing;
39
40 da_bool_t _pi_http_is_this_session_table_entry_using(
41                 const int in_session_table_entry);
42
43 da_result_t PI_http_init(void)
44 {
45         DA_LOG_FUNC_START(HTTPManager);
46
47         using_content_sniffing = DA_TRUE;
48
49         return DA_RESULT_OK;
50 }
51
52 void PI_http_deinit(void)
53 {
54         DA_LOG_FUNC_START(HTTPManager);
55
56         return;
57 }
58
59 da_result_t _set_proxy_on_soup_session(SoupSession *session, char *proxy_addr)
60 {
61         da_result_t ret = DA_RESULT_OK;
62
63
64         if (proxy_addr && strlen(proxy_addr) > 0) {
65                 DA_LOG_CRITICAL(HTTPManager,"received proxy = %s \n", proxy_addr);
66                 if (!strstr(proxy_addr, "0.0.0.0")) {
67                         if (strstr((const char *)proxy_addr, "http") == DA_NULL) {
68                                 /* DA_LOG(Default,"There is no \"http://\" on received uri, so, add it."); */
69
70                                 char *tmp_str = DA_NULL;
71                                 int needed_len = 0;
72
73                                 needed_len = strlen(proxy_addr) + strlen(
74                                                 SCHEME_HTTP) + 1;
75                                 tmp_str = (char *) calloc(1, needed_len);
76                                 if (!tmp_str) {
77                                         DA_LOG_ERR(HTTPManager,"DA_ERR_FAIL_TO_MEMALLOC");
78                                         ret = DA_ERR_FAIL_TO_MEMALLOC;
79                                         goto ERR;
80                                 }
81                                 snprintf(tmp_str, needed_len, "%s%s",
82                                                 SCHEME_HTTP, proxy_addr);
83
84                                 g_object_set(session, SOUP_SESSION_PROXY_URI,
85                                                 soup_uri_new(tmp_str), NULL);
86
87                                 free(tmp_str);
88                         } else {
89                                 DA_LOG(HTTPManager,"There is \"http\" on uri, so, push this address to soup directly.");
90                                 g_object_set(session, SOUP_SESSION_PROXY_URI,
91                                                 soup_uri_new(proxy_addr), NULL);
92                         }
93                 }
94         } else {
95                 DA_LOG(HTTPManager,"There is no proxy value");
96         }
97 ERR:
98         return ret;
99 }
100
101 void _fill_soup_msg_header(SoupMessage *msg,
102                 const input_for_tranx_t *input_for_tranx)
103 {
104         SoupMessageHeaders *headers = msg->request_headers;
105
106         http_msg_request_t *input_http_msg_request;
107         http_msg_iter_t http_msg_iter;
108         http_msg_iter_t http_msg_iter_pre;
109
110         char *field;
111         char *value;
112
113         input_http_msg_request = input_for_tranx->http_msg_request;
114
115         http_msg_request_get_iter(input_http_msg_request, &http_msg_iter);
116         http_msg_iter_pre = http_msg_iter;
117         while (http_msg_get_field_with_iter(&http_msg_iter, &field, &value)) {
118                 if ((field != DA_NULL) && (value != DA_NULL)) {
119                         DA_LOG(HTTPManager,"[%s] %s", field, value);
120                         soup_message_headers_append(headers, field, value);
121                 }
122                 http_msg_iter_pre = http_msg_iter;
123         }
124
125         if (input_http_msg_request->http_body) {
126                 char body_len_str[16] = { 0, };
127                 int body_len = strlen(input_http_msg_request->http_body);
128
129                 snprintf(body_len_str, sizeof(body_len_str), "%d", body_len);
130
131                 soup_message_headers_append(headers, "Content-Length",
132                                 body_len_str);
133                 soup_message_headers_append(headers, "Content-Type",
134                                 "text/plain");
135                 soup_message_body_append(msg->request_body, SOUP_MEMORY_COPY,
136                                 input_http_msg_request->http_body, body_len);
137         }
138 }
139
140 da_result_t PI_http_start_transaction(const input_for_tranx_t *input_for_tranx,
141                 int *out_tranx_id)
142 {
143         da_result_t ret = DA_RESULT_OK;
144
145         int session_table_entry = -1;
146         pi_http_method_t pi_http_method = PI_HTTP_METHOD_GET;
147
148         queue_t *queue = DA_NULL;
149
150         char *url = DA_NULL;
151
152         SoupSession *session = DA_NULL;
153         SoupMessage *msg = DA_NULL;
154
155         DA_LOG_FUNC_START(HTTPManager);
156
157         if (DA_FALSE == _pi_http_is_valid_input_for_tranx(input_for_tranx)) {
158                 DA_LOG_ERR(HTTPManager,"input_for_tranx is invalid");
159                 ret = DA_ERR_INVALID_ARGUMENT;
160                 goto ERR;
161         } else {
162                 queue = input_for_tranx->queue;
163                 pi_http_method = input_for_tranx->http_method;
164                 url = input_for_tranx->http_msg_request->url;
165         }
166
167         session_table_entry = _pi_http_get_avaiable_session_table_entry();
168         if (session_table_entry == -1) {
169                 ret = DA_ERR_ALREADY_MAX_DOWNLOAD;
170                 goto ERR;
171         }
172         DA_LOG(HTTPManager,"session_table_entry = %d", session_table_entry);
173
174         if (DA_FALSE == _pi_http_register_queue_to_session_table(
175                         session_table_entry, queue)) {
176                 _pi_http_destroy_session_table_entry(session_table_entry);
177                 ret = DA_ERR_ALREADY_MAX_DOWNLOAD;
178                 goto ERR;
179         }
180
181         /* modified by keunsoon.lee 2010-09-20 use sync_new() instead of async_new() for make different soup thread from UI main thread*/
182         session = soup_session_sync_new();
183         /* session=soup_session_async_new(); */
184         if (!session) {
185                 DA_LOG_ERR(HTTPManager,"Fail to create session");
186                 return DA_ERR_INVALID_URL;
187         }
188         DA_LOG(HTTPManager,"session[%p]", session);
189 /*
190         SoupLogger* logger = soup_logger_new(SOUP_LOGGER_LOG_BODY, -1);
191         soup_logger_attach(logger, session);
192         g_object_unref(logger);
193 */
194         if (DA_FALSE == _pi_http_register_session_to_session_table(
195                         session_table_entry, session)) {
196                 _pi_http_init_session_table_entry(session_table_entry);
197                 ret = DA_ERR_ALREADY_MAX_DOWNLOAD;
198                 goto ERR;
199         }
200
201         g_object_set(session, SOUP_SESSION_MAX_CONNS, MAX_SESSION_COUNT, NULL);
202         /* Set timeout unlimited time to resume a download which has ETag when the network is re-connected
203          * => This is changed to 180 seconds due to limitation of max downloading items.
204          */
205         g_object_set(session, SOUP_SESSION_TIMEOUT, MAX_TIMEOUT, NULL);
206
207         _set_proxy_on_soup_session(session, input_for_tranx->proxy_addr);
208
209         switch (pi_http_method) {
210         case PI_HTTP_METHOD_GET:
211                 msg = soup_message_new(METHOD_GET, url);
212                 break;
213         case PI_HTTP_METHOD_POST:
214                 msg = soup_message_new(METHOD_POST, url);
215                 break;
216         case PI_HTTP_METHOD_HEAD:
217                 msg = soup_message_new(METHOD_HEAD, url);
218                 break;
219         default:
220                 DA_LOG_ERR(HTTPManager,"Cannot enter here");
221                 break;
222         }
223         DA_LOG(HTTPManager,"msg[%p]", msg);
224         /* if it is failed to create a msg, the url can be invalid, becasue of the input argument of soup_message_new API */
225         if (msg == NULL) {
226                 DA_LOG_ERR(HTTPManager,"Fail to create message");
227                 ret = DA_ERR_INVALID_URL;
228                 goto ERR;
229         }
230
231         _fill_soup_msg_header(msg, input_for_tranx);
232
233         g_signal_connect(msg, "restarted", G_CALLBACK(_pi_http_restarted_cb),
234                         NULL); /* for redirection case */
235         g_signal_connect(msg, "got-headers",
236                         G_CALLBACK(_pi_http_gotheaders_cb), NULL);
237         g_signal_connect(msg, "got-chunk", G_CALLBACK(_pi_http_gotchunk_cb),
238                         NULL);
239
240         if (using_content_sniffing) {
241                 soup_session_add_feature_by_type(session, SOUP_TYPE_CONTENT_SNIFFER);
242                 g_signal_connect(msg, "content-sniffed",
243                                 G_CALLBACK(_pi_http_contentsniffed_cb), NULL);
244         } else {
245                 soup_message_disable_feature(msg, SOUP_TYPE_CONTENT_SNIFFER);
246         }
247
248         soup_session_queue_message(session, msg, _pi_http_finished_cb, NULL);
249 //      g_signal_connect(msg, "finished", G_CALLBACK(_pi_http_finished_cb),     NULL);
250
251         if (DA_FALSE == _pi_http_register_msg_to_session_table(
252                         session_table_entry, msg)) {
253                 _pi_http_destroy_session_table_entry(session_table_entry);
254                 ret = DA_ERR_ALREADY_MAX_DOWNLOAD;
255                 goto ERR;
256         }
257
258         *out_tranx_id = session_table_entry;
259         DA_LOG(HTTPManager,"*out_tranx_id = %d", *out_tranx_id);
260
261 ERR:
262         return ret;
263 }
264
265 da_result_t PI_http_disconnect_transaction(int in_tranx_id)
266 {
267         da_result_t ret = DA_RESULT_OK;
268         int session_table_entry = -1;
269
270         DA_LOG_FUNC_START(HTTPManager);
271
272         DA_LOG(HTTPManager,"in_tranx_id = %d", in_tranx_id);
273
274         session_table_entry = in_tranx_id;
275
276         _pi_http_destroy_session_table_entry(session_table_entry);
277
278         return ret;
279 }
280
281 da_result_t PI_http_cancel_transaction(int in_tranx_id, da_bool_t abort_option)
282 {
283         da_result_t ret = DA_RESULT_OK;
284         SoupSession *session;
285         SoupMessage *msg;
286         int session_table_entry = -1;
287
288         DA_LOG_FUNC_START(HTTPManager);
289
290         DA_LOG(HTTPManager,"in_tranx_id = %d", in_tranx_id);
291
292         session_table_entry = in_tranx_id;
293         if (!_pi_http_is_this_session_table_entry_using(session_table_entry)) {
294                 DA_LOG_CRITICAL(HTTPManager,"not using session");
295                 return ret;
296         }
297         session = GET_SESSION_FROM_TABLE_ENTRY(session_table_entry);
298         msg = GET_MSG_FROM_TABLE_ENTRY(session_table_entry);
299
300         if (DA_NULL == session) {
301                 DA_LOG_ERR(HTTPManager,"invalid session = %p", session);
302                 goto ERR;
303         }
304
305         if (DA_NULL == msg) {
306                 DA_LOG_ERR(HTTPManager,"invalid message = %p", msg);
307                 goto ERR;
308         }
309         DA_LOG(HTTPManager,"Call soup cancel API : abort option[%d]",abort_option);
310         if (abort_option)
311                 soup_session_abort(session);
312         else
313                 soup_session_cancel_message(session, msg, SOUP_STATUS_CANCELLED);
314         DA_LOG(HTTPManager,"Call soup cancel API-Done");
315 ERR:
316         return ret;
317 }
318
319 void PI_http_pause_transaction(int transaction_id)
320 {
321         int session_table_entry = -1;
322         pthread_mutex_t *mutex;
323         pthread_cond_t *cond;
324
325         DA_LOG_FUNC_START(HTTPManager);
326
327         DA_LOG(HTTPManager,"in_tranx_id = %d", transaction_id);
328
329         session_table_entry = transaction_id;
330
331         if (!_pi_http_is_this_session_table_entry_using(session_table_entry))
332                 return;
333
334         mutex = &(pi_session_table[session_table_entry].mutex);
335         cond = &(pi_session_table[session_table_entry].cond);
336
337         _da_thread_mutex_lock (mutex);
338
339         if (pi_session_table[session_table_entry].is_paused == DA_FALSE) {
340                 DA_LOG_CRITICAL(HTTPManager,"paused!");
341                 pi_session_table[session_table_entry].is_paused = DA_TRUE;
342                 _da_thread_cond_wait(cond, mutex);
343         } else {
344                 DA_LOG_CRITICAL(HTTPManager,"NOT paused!");
345         }
346
347         _da_thread_mutex_unlock (mutex);
348
349 }
350
351 void PI_http_unpause_transaction(int transaction_id)
352 {
353         int session_table_entry = -1;
354         pthread_mutex_t* mutex;
355         pthread_cond_t* cond;
356
357         /*      DA_LOG_FUNC_START(Default); */
358
359         session_table_entry = transaction_id;
360
361         if (!_pi_http_is_this_session_table_entry_using(session_table_entry))
362                 return;
363
364         mutex = &(pi_session_table[session_table_entry].mutex);
365         cond = &(pi_session_table[session_table_entry].cond);
366
367         _da_thread_mutex_lock (mutex);
368
369         if (pi_session_table[session_table_entry].is_paused == DA_TRUE) {
370                 DA_LOG_CRITICAL(HTTPManager,"wake up!");
371                 pi_session_table[session_table_entry].is_paused = DA_FALSE;
372                 _da_thread_cond_signal(cond);
373         }
374
375         _da_thread_mutex_unlock (mutex);
376
377 }
378
379 da_bool_t _pi_http_is_valid_input_for_tranx(
380                 const input_for_tranx_t *input_for_tranx)
381 {
382         if (!(input_for_tranx->http_msg_request)) {
383                 DA_LOG_ERR(HTTPManager,"http_msg_request is NULL");
384                 return DA_FALSE;
385         }
386
387         if (!((input_for_tranx->http_method == PI_HTTP_METHOD_GET) ||
388                         (input_for_tranx->http_method == PI_HTTP_METHOD_POST) ||
389                         (input_for_tranx->http_method == PI_HTTP_METHOD_HEAD))) {
390                 DA_LOG_ERR(HTTPManager,"http_method is neither GET or POST or HEAD");
391                 return DA_FALSE;
392         }
393
394         return DA_TRUE;
395 }
396
397 da_bool_t _pi_http_is_this_session_table_entry_using(
398                 const int in_session_table_entry)
399 {
400         da_bool_t is_using = DA_FALSE;
401
402         if (DA_FALSE == IS_VALID_SESSION_TABLE_ENTRY(in_session_table_entry))
403                 return DA_FALSE;
404
405         _da_thread_mutex_lock (&mutex_for_session_table);
406
407         is_using = pi_session_table[in_session_table_entry].is_using;
408
409         _da_thread_mutex_unlock (&mutex_for_session_table);
410
411         return is_using;
412 }
413
414 void _pi_http_init_session_table_entry(const int in_session_table_entry)
415 {
416         int entry = in_session_table_entry;
417
418         if (DA_FALSE == IS_VALID_SESSION_TABLE_ENTRY(entry))
419                 return;
420
421 //      _da_thread_mutex_lock (&mutex_for_session_table);
422
423         pi_session_table[entry].is_using = DA_TRUE;
424         pi_session_table[entry].msg = NULL;
425         pi_session_table[entry].session = NULL;
426         pi_session_table[entry].queue = NULL;
427
428         _da_thread_mutex_init(&(pi_session_table[entry].mutex), DA_NULL);
429         _da_thread_cond_init(&(pi_session_table[entry].cond), NULL);
430         pi_session_table[entry].is_paused = DA_FALSE;
431
432 //      _da_thread_mutex_unlock (&mutex_for_session_table);
433
434         return;
435 }
436
437 void _pi_http_destroy_session_table_entry(const int in_session_table_entry)
438 {
439         int entry = in_session_table_entry;
440
441         if (DA_FALSE == IS_VALID_SESSION_TABLE_ENTRY(entry))
442                 return;
443
444         _da_thread_mutex_lock (&mutex_for_session_table);
445
446         if (pi_session_table[entry].is_paused == DA_TRUE)
447                 PI_http_unpause_transaction(entry);
448
449         /* Warning! Do not g_object_unref(msg) here!
450          * soup_session_queue_message() steals msg's reference count,
451          * so, we don't need to do anything for memory management.
452          *
453          * But, if using soup_session_send_message(), MUST call g_object_unref(msg). */
454         /* if (pi_session_table[entry].msg)
455                 g_object_unref(pi_session_table[entry].msg); */
456
457         pi_session_table[entry].msg = NULL;
458
459         /* FIXME Cannot g_object_unref(session) here,
460          * because msg inside this session is not destoryed yet.
461          * The msg's reference count is stealed by soup_session_queue_message(),
462          * and it will be destroyed when _pi_http_finished_cb() is returned.
463          * For now, this _pi_http_destroy_session_table_entry() is called inside
464          * _pi_http_finished_cb(), so, g_object_unref(session) is not working.
465          * Should find out call this function after _pi_http_finished_cb(). */
466         if (pi_session_table[entry].session)
467                 g_object_unref(pi_session_table[entry].session);
468         else
469                 DA_LOG_ERR(HTTPManager,"session is NULL. Cannot unref this.");
470         DA_LOG(HTTPManager,"unref session [%p]",pi_session_table[entry].session);
471
472         pi_session_table[entry].session = NULL;
473
474         pi_session_table[entry].queue = NULL;
475         pi_session_table[entry].is_paused = DA_FALSE;
476         pi_session_table[entry].is_using = DA_FALSE;
477
478         _da_thread_mutex_destroy(&(pi_session_table[entry].mutex));
479         _da_thread_cond_destroy(&(pi_session_table[entry].cond));
480
481         _da_thread_mutex_unlock (&mutex_for_session_table);
482
483         return;
484 }
485
486 int _pi_http_get_avaiable_session_table_entry(void)
487 {
488         int i;
489         int avaiable_entry = -1;
490
491         _da_thread_mutex_lock (&mutex_for_session_table);
492
493         for (i = 0; i < MAX_SESSION_COUNT; i++) {
494                 if (pi_session_table[i].is_using == DA_FALSE) {
495                         /*      pi_session_table[i].is_using = DA_TRUE; */
496                         DA_LOG(HTTPManager,"available entry = %d", i);
497
498                         avaiable_entry = i;
499
500                         break;
501                 }
502         }
503         _pi_http_init_session_table_entry(avaiable_entry);
504         _da_thread_mutex_unlock (&mutex_for_session_table);
505
506         return avaiable_entry;
507 }
508
509 da_bool_t _pi_http_register_queue_to_session_table(
510                 const int in_session_table_entry, const queue_t *in_queue)
511 {
512         int entry = in_session_table_entry;
513         queue_t *queue = (queue_t *) in_queue;
514         da_bool_t ret = DA_FALSE;
515
516         if (DA_FALSE == IS_VALID_SESSION_TABLE_ENTRY(entry)) {
517                 DA_LOG_ERR(HTTPManager,"invalid entry = %d", entry);
518                 return DA_FALSE;
519         }
520
521         _da_thread_mutex_lock (&mutex_for_session_table);
522
523         if (pi_session_table[entry].is_using == DA_FALSE) {
524                 DA_LOG_ERR(HTTPManager,"this entry [%d] is not using", entry);
525                 ret = DA_FALSE;
526         } else {
527                 pi_session_table[entry].queue = queue;
528                 DA_LOG(HTTPManager,"queue = %p", pi_session_table[entry].queue);
529                 ret = DA_TRUE;
530         }
531
532         _da_thread_mutex_unlock (&mutex_for_session_table);
533
534         return ret;
535 }
536
537 da_bool_t _pi_http_register_session_to_session_table(
538                 const int in_session_table_entry, SoupSession *session)
539 {
540         int entry = in_session_table_entry;
541         da_bool_t ret = DA_FALSE;
542
543         if (DA_FALSE == IS_VALID_SESSION_TABLE_ENTRY(entry)) {
544                 DA_LOG_ERR(HTTPManager,"invalid entry = %d", entry);
545                 return DA_FALSE;
546         }
547
548         if (DA_NULL == session) {
549                 DA_LOG_ERR(HTTPManager,"invalid session = %p",session);
550                 return DA_FALSE;
551         }
552
553         _da_thread_mutex_lock (&mutex_for_session_table);
554
555         if (pi_session_table[entry].is_using == DA_FALSE) {
556                 ret = DA_FALSE;
557         } else {
558                 pi_session_table[entry].session = session;
559                 ret = DA_TRUE;
560         }
561
562         _da_thread_mutex_unlock (&mutex_for_session_table);
563
564         return ret;
565 }
566
567 da_bool_t _pi_http_register_msg_to_session_table(
568                 const int in_session_table_entry, SoupMessage *msg)
569 {
570         int entry = in_session_table_entry;
571         da_bool_t ret = DA_FALSE;
572
573         if (DA_FALSE == IS_VALID_SESSION_TABLE_ENTRY(entry)) {
574                 DA_LOG_ERR(HTTPManager,"invalid entry = %d", entry);
575                 return DA_FALSE;
576         }
577
578         if (DA_NULL == msg) {
579                 DA_LOG_ERR(HTTPManager,"invalid msg = %p",msg);
580                 return DA_FALSE;
581         }
582
583         _da_thread_mutex_lock (&mutex_for_session_table);
584
585         if (pi_session_table[entry].is_using == DA_FALSE) {
586                 ret = DA_FALSE;
587         } else {
588                 pi_session_table[entry].msg = msg;
589                 ret = DA_TRUE;
590         }
591
592         _da_thread_mutex_unlock (&mutex_for_session_table);
593
594         return ret;
595 }
596
597 queue_t *_pi_http_get_queue_from_session_table_entry(
598                 const int in_session_table_entry)
599 {
600         int entry = in_session_table_entry;
601         queue_t *out_queue = NULL;
602
603         if (DA_FALSE == IS_VALID_SESSION_TABLE_ENTRY(entry)) {
604                 DA_LOG_ERR(HTTPManager,"invalid entry = %d", entry);
605                 return out_queue;
606         }
607
608         _da_thread_mutex_lock (&mutex_for_session_table);
609
610         out_queue = pi_session_table[entry].queue;
611         _da_thread_mutex_unlock (&mutex_for_session_table);
612
613         return out_queue;
614 }
615
616 void _pi_http_store_read_header_to_queue(SoupMessage *msg, const char *sniffedType)
617 {
618         da_result_t ret = DA_RESULT_OK;
619
620         queue_t *da_queue = NULL;
621         q_event_t *da_event = NULL;
622         q_event_type_data da_event_type_data;
623
624         int session_table_entry = -1;
625         SoupMessageHeadersIter headers_iter;
626
627         const char *header_name;
628         const char *header_value;
629
630         http_msg_response_t *http_msg_response = NULL;
631
632         /*      DA_LOG_FUNC_START(Default); */
633
634         if (msg->response_headers) {
635                 ret = http_msg_response_create(&http_msg_response);
636                 if (ret != DA_RESULT_OK)
637                         return;
638
639                 http_msg_response_set_status_code(http_msg_response,
640                                 msg->status_code);
641
642                 DA_LOG(HTTPManager,"\n----raw header---------------------------------------------");
643                 DA_LOG_CRITICAL(HTTPManager,"status code = %d", msg->status_code);
644                 soup_message_headers_iter_init(&headers_iter,
645                                 msg->response_headers);
646                 while (soup_message_headers_iter_next(&headers_iter,
647                                 &header_name, &header_value)) {
648                         if ((header_name != DA_NULL) && (header_value
649                                         != DA_NULL)) {
650                                 http_msg_response_add_field(http_msg_response,
651                                                 header_name, header_value);
652                         }
653                 }
654                 DA_LOG(HTTPManager,"\n-------------------------------------------------------------\n");
655
656         }
657
658         if (using_content_sniffing && sniffedType)
659                 http_msg_response_set_content_type(http_msg_response, sniffedType);
660
661         session_table_entry
662                         = _pi_http_get_session_table_entry_from_message(msg);
663         if (session_table_entry == -1) {
664                 DA_LOG_ERR(HTTPManager,"Fail to find matched session table entry..");
665                 ret = DA_ERR_INVALID_ARGUMENT;
666                 goto ERR;
667         }
668
669         da_event_type_data = Q_EVENT_TYPE_DATA_PACKET;
670
671         da_queue = _pi_http_get_queue_from_session_table_entry(
672                         session_table_entry);
673
674         ret = Q_make_http_data_event(da_event_type_data, &da_event);
675         if (ret != DA_RESULT_OK) {
676                 DA_LOG_ERR(HTTPManager,"fail to make da_event");
677                 goto ERR;
678         } else {
679                 Q_set_status_code_on_http_data_event(da_event, msg->status_code);
680                 da_event->type.q_event_data_http.http_response_msg
681                                 = http_msg_response;
682
683                 Q_push_event(da_queue, da_event);
684         }
685         return;
686
687 ERR:
688         if (DA_RESULT_OK != ret)
689                 http_msg_response_destroy(&http_msg_response);
690
691         return;
692 }
693
694 void _pi_http_store_read_data_to_queue(SoupMessage *msg, const char* body_data,
695                 int received_body_len)
696 {
697         da_result_t ret = DA_RESULT_OK;
698         da_bool_t b_ret = DA_FALSE;
699
700         char *body_buffer = NULL;
701         queue_t *da_queue = NULL;
702         q_event_t *da_event = NULL;
703         q_event_type_data da_event_type_data;
704         int session_table_entry = -1;
705         int http_status = -1;
706
707         /*      DA_LOG_FUNC_START(Default); */
708
709         http_status = msg->status_code;
710
711         session_table_entry
712                         = _pi_http_get_session_table_entry_from_message(msg);
713         if (session_table_entry == -1) {
714                 DA_LOG_ERR(HTTPManager,"Fail to find matched session table entry..");
715                 ret = DA_ERR_INVALID_ARGUMENT;
716                 goto ERR;
717         }
718
719         if (received_body_len == 0) {
720                 DA_LOG(HTTPManager,"Q_EVENT_TYPE_DATA_FINAL");
721                 da_event_type_data = Q_EVENT_TYPE_DATA_FINAL;
722         } else {
723                 da_event_type_data = Q_EVENT_TYPE_DATA_PACKET;
724                 if (received_body_len > 0) {
725                         body_buffer = (char*) calloc(1, received_body_len);
726                         DA_LOG(HTTPManager,"body_buffer[%p]msg[%p]",body_buffer,msg);
727                         if (body_buffer == DA_NULL) {
728                                 DA_LOG_ERR(HTTPManager,"DA_ERR_FAIL_TO_MEMALLOC");
729                                 goto ERR;
730                         }
731                         memcpy(body_buffer, body_data, received_body_len);
732                 }
733         }
734
735         da_queue = _pi_http_get_queue_from_session_table_entry(
736                         session_table_entry);
737
738         ret = Q_make_http_data_event(da_event_type_data, &da_event);
739         if (ret != DA_RESULT_OK) {
740                 DA_LOG_ERR(HTTPManager,"fail to make da_event");
741                 goto ERR;
742         } else {
743                 Q_set_status_code_on_http_data_event(da_event, http_status);
744                 Q_set_http_body_on_http_data_event(da_event, received_body_len,
745                                 body_buffer);
746
747                 _da_thread_mutex_lock (&(da_queue->mutex_queue));
748                 b_ret = Q_push_event_without_lock(da_queue, da_event);
749                 if (b_ret == DA_FALSE) {
750                         DA_LOG_CRITICAL(HTTPManager,"----------------------------------------fail to push!");
751
752                         pthread_mutex_t *session_mutex = NULL;
753                         pthread_cond_t *session_cond = NULL;
754
755                         session_mutex
756                                         = &(pi_session_table[session_table_entry].mutex);
757                         session_cond
758                                         = &(pi_session_table[session_table_entry].cond);
759
760                         /*  MUST keep this order for these mutexes */
761                         _da_thread_mutex_lock (session_mutex);
762                         _da_thread_mutex_unlock (&(da_queue->mutex_queue));
763
764                         if (pi_session_table[session_table_entry].is_paused
765                                         == DA_FALSE) {
766                                 DA_LOG_CRITICAL(HTTPManager,"paused!");
767                                 pi_session_table[session_table_entry].is_paused
768                                                 = DA_TRUE;
769                                 _da_thread_cond_wait(session_cond, session_mutex);
770                         } else {
771                                 DA_LOG_CRITICAL(HTTPManager,"NOT paused!");
772                         }
773
774                         _da_thread_mutex_unlock (session_mutex);
775
776                         DA_LOG_CRITICAL(HTTPManager,"wake up! push again");
777                         Q_push_event(da_queue, da_event);
778                 } else {
779                         _da_thread_mutex_unlock (&(da_queue->mutex_queue));
780                 }
781
782         }
783
784         return;
785
786 ERR:
787         if (DA_RESULT_OK != ret) {
788                 if (DA_NULL != body_buffer) {
789                         free(body_buffer);
790                 }
791         }
792
793         return;
794 }
795
796 int _translate_error_code(int soup_error)
797 {
798         switch (soup_error) {
799         case SOUP_STATUS_CANT_RESOLVE:
800         case SOUP_STATUS_CANT_RESOLVE_PROXY:
801         case SOUP_STATUS_CANT_CONNECT:
802         case SOUP_STATUS_CANT_CONNECT_PROXY:
803         case SOUP_STATUS_IO_ERROR:
804         case SOUP_STATUS_MALFORMED:
805         case SOUP_STATUS_TRY_AGAIN:
806         case SOUP_STATUS_TOO_MANY_REDIRECTS:
807                 return DA_ERR_NETWORK_FAIL;
808
809         case SOUP_STATUS_SSL_FAILED:
810                 return DA_ERR_SSL_FAIL;
811
812         default:
813                 return DA_RESULT_OK;
814         }
815 }
816
817 void _pi_http_store_neterr_to_queue(SoupMessage *msg)
818 {
819         da_result_t ret = DA_RESULT_OK;
820         int error_type = -1;
821         queue_t *da_queue = NULL;
822         q_event_t *da_event = NULL;
823         int session_table_entry = -1;
824
825         DA_LOG_FUNC_START(HTTPManager);
826
827         error_type = _translate_error_code(msg->status_code);
828
829         session_table_entry
830                         = _pi_http_get_session_table_entry_from_message(msg);
831         if (session_table_entry == -1) {
832                 DA_LOG_ERR(HTTPManager,"Fail to find matched session table entry..");
833                 ret = DA_ERR_INVALID_ARGUMENT;
834                 goto ERR;
835         }
836
837         da_queue = _pi_http_get_queue_from_session_table_entry(
838                         session_table_entry);
839
840         DA_LOG_CRITICAL(HTTPManager,"Q_EVENT_TYPE_DATA_ABORT");
841         ret = Q_make_http_data_event(Q_EVENT_TYPE_DATA_ABORT, &da_event);
842         if (ret != DA_RESULT_OK) {
843                 DA_LOG_ERR(HTTPManager,"fail to make da_event");
844                 goto ERR;
845         } else {
846                 Q_set_error_type_on_http_data_event(da_event, error_type);
847
848                 Q_push_event(da_queue, da_event);
849         }
850
851 ERR:
852         return;
853 }
854
855 int _pi_http_get_session_table_entry_from_message(SoupMessage *msg)
856 {
857
858         int out_entry = -1;
859         int i;
860
861         if (DA_NULL == msg) {
862                 DA_LOG_ERR(HTTPManager,"invalid message = %p", msg);
863                 return out_entry;
864         }
865
866         _da_thread_mutex_lock (&mutex_for_session_table);
867
868         for (i = 0; i < MAX_SESSION_COUNT; i++) {
869                 if (pi_session_table[i].is_using == DA_TRUE) {
870                         if (pi_session_table[i].msg == msg) {
871                                 out_entry = i;
872                                 break;
873                         }
874                 }
875         }
876
877         _da_thread_mutex_unlock (&mutex_for_session_table);
878
879         if (i == MAX_SESSION_COUNT) {
880                 DA_LOG_ERR(HTTPManager,"fail to find message = %p", msg);
881         }
882
883         return out_entry;
884
885 }
886
887 void _pi_http_finished_cb(SoupSession *session, SoupMessage *msg, gpointer data)
888 {
889         char *url = NULL;
890
891         DA_LOG_FUNC_START(HTTPManager);
892
893         url = soup_uri_to_string(soup_message_get_uri(msg), DA_FALSE);
894
895         DA_LOG(HTTPManager,"status_code[%d], reason[%s], url[%s]",msg->status_code,msg->reason_phrase,url);
896
897         if (url) {
898                 free(url);
899                 url = NULL;
900         }
901
902         if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)) {
903                 if (msg->status_code == SOUP_STATUS_CANCELLED) {
904                         _pi_http_store_read_data_to_queue(msg, DA_NULL, 0);
905                 } else {
906                         _pi_http_store_neterr_to_queue(msg);
907                 }
908         } else {
909                 _pi_http_store_read_data_to_queue(msg, DA_NULL, 0);
910         }
911
912 }
913
914 /* this callback is called in case of redirection */
915 void _pi_http_restarted_cb(SoupMessage *msg, gpointer data)
916 {
917         DA_LOG_FUNC_START(HTTPManager);
918         /* Location URL is needed when extracting the file name from url.
919          * So, the response header should be handled by http mgr.*/
920         _pi_http_store_read_header_to_queue(msg, NULL);
921 }
922
923 void _pi_http_gotheaders_cb(SoupMessage *msg, gpointer data)
924 {
925         DA_LOG_FUNC_START(HTTPManager);
926
927         if (SOUP_STATUS_IS_REDIRECTION(msg->status_code)) {
928                 DA_LOG(HTTPManager,"Redirection !!");
929                 if (SOUP_STATUS_NOT_MODIFIED != msg->status_code)
930                         return;
931         }
932
933         soup_message_body_set_accumulate(msg->response_body, FALSE);
934
935         if (!using_content_sniffing)
936                 _pi_http_store_read_header_to_queue(msg, NULL);
937         else
938                 DA_LOG(HTTPManager,"ignore because content sniffing is turned on");
939 }
940
941 void _pi_http_contentsniffed_cb(SoupMessage *msg, const char *sniffedType,
942                 GHashTable *params, gpointer data)
943 {
944         DA_LOG_FUNC_START(HTTPManager);
945
946         if (SOUP_STATUS_IS_REDIRECTION(msg->status_code)) {
947                 DA_LOG(HTTPManager,"Redirection !!");
948                 if (SOUP_STATUS_NOT_MODIFIED != msg->status_code)
949                         return;
950         }
951
952         if (using_content_sniffing)
953                 _pi_http_store_read_header_to_queue(msg, sniffedType);
954 }
955
956 void _pi_http_gotchunk_cb(SoupMessage *msg, SoupBuffer *chunk, gpointer data)
957 {
958         DA_LOG_FUNC_START(HTTPManager);
959
960         if (SOUP_STATUS_IS_REDIRECTION(msg->status_code))
961                 return;
962
963         if (chunk->data && chunk->length > 0) {
964                 _pi_http_store_read_data_to_queue(msg, chunk->data,
965                                 chunk->length);
966         }
967 }
968