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