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