2 // Open Service Platform
3 // Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
19 * @file FNetHttp_HttpMultipleConnectionInfo.cpp
20 * @brief This is the implementation file for _HttpMultipleConnectionInfo class.
23 #include <FBaseString.h>
24 #include <FBaseSysLog.h>
26 #include <FBase_StringConverter.h>
27 #include <FBaseRt_EventDispatcher.h>
28 #include "FNetHttp_HttpCommon.h"
29 #include "FNetHttp_HttpMultipleConnectionInfo.h"
30 #include "FNetHttp_HttpTransactionImpl.h"
31 #include "FNetHttp_HttpTransactionUserData.h"
32 #include "FNetHttp_HttpCurl.h"
33 #include "FNetHttp_HttpSocketInfo.h"
34 #include "FNetHttp_HttpRequestImpl.h"
35 #include "FNetHttp_HttpResponseImpl.h"
36 #include "FNetHttp_HttpHeaderImpl.h"
37 #include "FNetHttp_HttpTransactionEventArg.h"
38 #include "FNetHttp_HttpTransactionEvent.h"
40 using namespace Tizen::Base;
41 using namespace Tizen::Base::Runtime;
42 using namespace Tizen::Base::Collection;
44 namespace Tizen { namespace Net { namespace Http
47 _HttpMultipleConnectionInfo::_HttpMultipleConnectionInfo()
51 , __pGMainContext(null)
52 , __remainsConnection(-1)
53 , __isAlreadyClosedSession(false)
54 , __pTimerSource(null)
55 , __cookieFlag(NET_HTTP_COOKIE_FLAG_ALWAYS_MANUAL)
59 _HttpMultipleConnectionInfo::~_HttpMultipleConnectionInfo(void)
61 if (__pTimerSource != null)
63 int timerId = g_source_get_id(__pTimerSource);
64 g_source_set_callback(__pTimerSource, null, null, null);
65 SysLog(NID_NET_HTTP, "Deleted g_source_destroy(%d)", timerId);
66 g_source_destroy(__pTimerSource);
67 g_source_unref(__pTimerSource);
68 __pTimerSource = null;
69 SysLog(NID_NET_HTTP, "Cancelled the TimerSource[%d] of HttpSession[%d].", timerId, __sessionId);
74 SysLog(NID_NET_HTTP, "Deleted the __pCurlM(%x).", __pCurlM);
75 curl_multi_cleanup(__pCurlM);
78 __pGMainContext = null;
80 SysLog(NID_NET_HTTP, "Deleted the HttpMultipleConnectionInfo of HttpSession[%d]", __sessionId);
84 _HttpMultipleConnectionInfo::Construct(CURLM* pCurlM, int sessionId, NetHttpCookieFlag cookieFlag)
87 SysTryReturnResult(NID_NET_HTTP, pCurlM != null,
88 E_INVALID_ARG, "pCurlM is null.");
90 _EventDispatcher* pEventDispatcher = _EventDispatcher::GetCurrentEventDispatcher();
91 SysTryReturnResult(NID_NET_HTTP, pEventDispatcher != null,
92 E_SYSTEM, "GetCurrentEventDispatcher() is null.");
95 SysLog(NID_NET_HTTP, "Created the __pCurlM(%x).", __pCurlM);
96 __pGMainContext = pEventDispatcher->GetGMainContext();
97 __sessionId = sessionId;
98 __cookieFlag = cookieFlag;
106 _HttpMultipleConnectionInfo::AddRef(void)
109 SysLog(NID_NET_HTTP, "The reference count is %d. HttpSession[%d]", __refCount, __sessionId);
113 _HttpMultipleConnectionInfo::Release(void)
116 SysLog(NID_NET_HTTP, "The reference count is %d. HttpSession[%d]", __refCount, __sessionId);
120 SysLog(NID_NET_HTTP, "The reference count is 0. HttpSession[%d]", __sessionId);
126 _HttpMultipleConnectionInfo::SetTimerEvent(int timeout_ms)
128 result r = E_SUCCESS;
132 if (__pTimerSource != null)
134 timerId = g_source_get_id(__pTimerSource);
135 g_source_set_callback(__pTimerSource, null, null, null);
136 SysLog(NID_NET_HTTP, "Deleted g_source_destroy(%d)", timerId);
137 g_source_destroy(__pTimerSource);
138 g_source_unref(__pTimerSource);
139 __pTimerSource = null;
140 SysLog(NID_NET_HTTP, "Cancelled the TimerSource[%d] of HttpSession[%d].", timerId, __sessionId);
145 __pTimerSource = g_timeout_source_new(timeout_ms);
146 g_source_set_callback(__pTimerSource, _HttpMultipleConnectionInfo::OnCurlTimerExpiredEvent, this, null);
147 g_source_attach(__pTimerSource, __pGMainContext);
149 timerId = g_source_get_id(__pTimerSource);
150 SysLog(NID_NET_HTTP, "Created the TimerSource[%d] of HttpSession[%d], timeout[%d].", timerId, __sessionId, timeout_ms);
154 SysLog(NID_NET_HTTP, "The value of timeout_ms is less than 0.");
161 _HttpMultipleConnectionInfo::OnCurlMultiSocketUpdated(CURL* pCurl, curl_socket_t socketFd, int curlAction, void* pUserData,
162 void* pCurlMAssigned)
164 static const char* pCurlSocketActionMessages[] = { "NONE", "IN", "OUT", "INOUT", "REMOVE" };
165 SysLog(NID_NET_HTTP, "Updated Socket(%d), Action(%s).", socketFd, pCurlSocketActionMessages[curlAction]);
167 _HttpMultipleConnectionInfo* pHttpMultipleConnectionInfo = static_cast< _HttpMultipleConnectionInfo* >(pUserData);
168 _HttpSocketInfo* pHttpSocketInfo = static_cast< _HttpSocketInfo* >(pCurlMAssigned);
170 if (curlAction == CURL_POLL_REMOVE)
172 SysLog(NID_NET_HTTP, "Removed the Socket(%d).", socketFd);
173 delete pHttpSocketInfo;
177 if (pHttpSocketInfo == null)
179 SysLog(NID_NET_HTTP, "Adding the Socket(%d).", socketFd);
180 pHttpSocketInfo = new (std::nothrow) _HttpSocketInfo();
181 pHttpSocketInfo->SetSocketEvent(pHttpMultipleConnectionInfo, socketFd, curlAction, false);
185 SysLog(NID_NET_HTTP, "Changing the Socket(%d). Action %s => %s", socketFd,
186 pCurlSocketActionMessages[pHttpSocketInfo->GetSocketAction()], pCurlSocketActionMessages[curlAction]);
187 pHttpSocketInfo->SetSocketEvent(pHttpMultipleConnectionInfo, socketFd, curlAction, true);
195 _HttpMultipleConnectionInfo::OnCurlMultiTimerChanged(CURLM* pCurlM, long timeout_ms, void* pUserData)
197 result r = E_SUCCESS;
198 SysLog(NID_NET_HTTP, "The timer(%d) of curlM was changed.", timeout_ms);
200 _HttpMultipleConnectionInfo* pHttpMultipleConnectionInfo = static_cast< _HttpMultipleConnectionInfo* >(pUserData);
202 r = pHttpMultipleConnectionInfo->SetTimerEvent(timeout_ms);
205 SysLog(NID_NET_HTTP, "Failed to Set the timer.");
212 _HttpMultipleConnectionInfo::OnCurlTimerExpiredEvent(gpointer pUserData)
217 _HttpMultipleConnectionInfo* pHttpMultipleConnectionInfo = static_cast< _HttpMultipleConnectionInfo* >(pUserData);
219 if (pHttpMultipleConnectionInfo->__pTimerSource != null)
221 timerId = g_source_get_id(pHttpMultipleConnectionInfo->__pTimerSource);
222 g_source_set_callback(pHttpMultipleConnectionInfo->__pTimerSource, null, null, null);
223 SysLog(NID_NET_HTTP, "Deleted g_source_destroy(%d).", timerId);
224 g_source_destroy(pHttpMultipleConnectionInfo->__pTimerSource);
225 g_source_unref(pHttpMultipleConnectionInfo->__pTimerSource);
226 pHttpMultipleConnectionInfo->__pTimerSource = null;
227 SysLog(NID_NET_HTTP, "Expired the TimerSource[%d] of HttpSession[%d].", timerId,
228 pHttpMultipleConnectionInfo->__sessionId);
231 rc = curl_multi_socket_action(pHttpMultipleConnectionInfo->__pCurlM, CURL_SOCKET_TIMEOUT, 0,
232 &(pHttpMultipleConnectionInfo->__remainsConnection));
235 SysLog(NID_NET_HTTP, "CURLM_OK - Called curl_multi_socket_action(), HttpSession[%d]",
236 pHttpMultipleConnectionInfo->__sessionId);
240 _HttpUtility::PrintCurlMultiErrorCode(rc);
244 pHttpMultipleConnectionInfo->CheckCurlMultiStatus();
250 _HttpMultipleConnectionInfo::CheckCurlMultiStatus(void)
252 result r = E_SUCCESS;
253 CURLMsg* pMessage = null;
254 int messageCount = 0;
257 CURLcode curlCode = CURLE_OK;
258 _HttpTransactionImpl* pHttpTransactionImpl = null;
259 _HttpTransactionUserData* pHttpTransactionUserData = null;
261 SysLog(NID_NET_HTTP, "The remains of connection is %d.", __remainsConnection);
262 pMessage = curl_multi_info_read(__pCurlM, &messageCount);
263 while (pMessage != null)
265 SysLog(NID_NET_HTTP, "The count of message left is %d.", messageCount);
266 if (pMessage->msg == CURLMSG_DONE)
268 pCurl = pMessage->easy_handle;
269 curlCode = pMessage->data.result;
270 curl_easy_getinfo(pCurl, CURLINFO_PRIVATE, &pHttpTransactionUserData);
271 curl_easy_getinfo(pCurl, CURLINFO_EFFECTIVE_URL, &pUrl);
273 if (pHttpTransactionUserData != null)
275 _HttpCurl* pHttpCurl = null;
276 SysLog(NID_NET_HTTP, "Completed - HttpSession[%d], HttpTransaction[%d], %s: result(%d) - %s", __sessionId, pHttpTransactionUserData->GetTransactionId(), pUrl, curlCode, pHttpTransactionUserData->GetErrorMessage());
278 if (pHttpTransactionUserData->IsClosedTransaction() == true)
280 SysLog(NID_NET_HTTP, "The HttpTransaction[%d] is already closed.",
281 pHttpTransactionUserData->GetTransactionId());
285 pHttpTransactionImpl = pHttpTransactionUserData->GetHttpTransactionImpl();
286 SysAssertf(pHttpTransactionImpl != null, "The pHttpTransactionImpl must not be null.");
288 _HttpTransactionEvent* pHttpTransactionEvent = pHttpTransactionImpl->GetHttpTransactionEvent();
289 SysAssertf(pHttpTransactionEvent != null, "The pHttpTransactionEvent must not be null.");
291 if (__isAlreadyClosedSession == true)
293 //Fire the event(_HTTP_TRANSACTION_EVENT_TYPE_ABORTED)
294 pHttpTransactionEvent->FireTransactionAbortedEvent(E_NETWORK_UNAVAILABLE);
298 //Check if the curlCode is CURLE_OK
299 if (curlCode == CURLE_OK)
301 int readBodySize = 0;
303 if (!pHttpTransactionImpl->IsHeaderEventFired())
305 _HttpResponseImpl* pHttpResponseImpl = pHttpTransactionImpl->GetHttpResponseImpl();
306 pCurl = pHttpTransactionImpl->GetHttpCurl()->GetCurl();
308 SysLog(NID_NET_HTTP, "The header event will be fired in CheckCurlMStatus()");
310 r = pHttpResponseImpl->AddRawHeader(null, 0, true);
314 SysLogException(NID_NET_HTTP, r, "[%s] Propagated.", GetErrorMessage(r));
317 long httpAuth = _CURL_HTTP_AUTH_NONE;
318 long proxyAuth = _CURL_HTTP_AUTH_NONE;
319 curl_easy_getinfo(pCurl, CURLINFO_HTTPAUTH_AVAIL, &httpAuth);
320 curl_easy_getinfo(pCurl, CURLINFO_PROXYAUTH_AVAIL, &proxyAuth);
322 //Fire the event(_HTTP_TRANSACTION_EVENT_TYPE_HEADER_COMPLETED)
323 pHttpTransactionEvent->FireTransactionHeaderCompletedEvent(pHttpResponseImpl->GetHeaderLength(), proxyAuth, httpAuth);
325 if (pHttpTransactionUserData->IsClosedTransaction() == true)
327 SysLog(NID_NET_HTTP, "The HttpTransaction is already closed.");
332 _HttpResponseImpl* pHttpResponseImpl = pHttpTransactionImpl->GetHttpResponseImpl();
333 SysTryReturnVoidResult(NID_NET_HTTP, pHttpResponseImpl != null, E_SYSTEM,
334 "[E_SYSTEM] An internal error has occurred.");
336 r = pHttpResponseImpl->AddLastBody(readBodySize);
338 if (readBodySize != 0)
340 pHttpResponseImpl->SetCurrentBodyLength(readBodySize);
342 //Fire the event(_HTTP_TRANSACTION_EVENT_TYPE_READY_TO_READ)
343 pHttpTransactionEvent->FireTransactionReadyToReadEvent(readBodySize);
345 if (pHttpTransactionUserData->IsClosedTransaction() == true)
347 SysLog(NID_NET_HTTP, "The HttpTransaction[%d] is already closed.", pHttpTransactionUserData->GetTransactionId());
351 if (pHttpTransactionImpl->GetHttpProgressEventListener() != null)
353 //Fire the event(_HTTP_TRANSACTION_EVENT_TYPE_DOWNLOAD_PROGRESS)
354 pHttpTransactionEvent->FireHttpDownloadInProgressEvent(pHttpResponseImpl->GetCurrentBodyLength(), pHttpResponseImpl->GetTotalBodyLength());
356 if (pHttpTransactionUserData->IsClosedTransaction() == true)
358 SysLog(NID_NET_HTTP, "The HttpTransaction[%d] is already closed.", pHttpTransactionUserData->GetTransactionId());
364 //Fire the event(_HTTP_TRANSACTION_EVENT_TYPE_COMPLETD)
365 pHttpTransactionEvent->FireTransactionCompletedEvent();
369 SysLog(NID_NET_HTTP, "Exceptional Case");
371 //Convert the error code from CURLCode
372 r = _HttpUtility::ConvertErrorCode(curlCode);
373 if (r != E_OPERATION_CANCELED)
375 if (_HttpUtility::IsSslError(curlCode))
377 _HttpSslInfo* pSSLInfo = _HttpUtility::GetSslCertInfo(pHttpTransactionUserData->GetSocketFd());
379 if (pSSLInfo == null)
381 if (curlCode == CURLE_SSL_CACERT || curlCode == CURLE_SSL_ISSUER_ERROR || curlCode == CURLE_SSL_CRL_BADFILE || curlCode == CURLE_SSL_CACERT_BADFILE)
383 pHttpTransactionEvent->FireTransactionAbortedEvent(E_SYSTEM);
386 //Fire the event(_HTTP_TRANSACTION_EVENT_TYPE_ABORTED) - E_NO_CERTIFICATE
387 pHttpTransactionEvent->FireTransactionAbortedEvent(E_NO_CERTIFICATE);
392 if (pSSLInfo->GetCertificateVerificationFlag() == HTTP_CV_FLAG_MANUAL)
394 r = _HttpUtility::RemoveSslCertInfo(*pSSLInfo);
397 SysLogException(NID_NET_HTTP, E_SYSTEM, "[E_SYSTEM] Failed to remove the server cert.");
400 SysLog(NID_NET_HTTP, "The server certificate verification is failed by user.");
402 //Fire the event(_HTTP_TRANSACTION_EVENT_TYPE_ABORTED)
403 pHttpTransactionEvent->FireTransactionAbortedEvent(E_HTTP_USER);
408 SysLog(NID_NET_HTTP, "The value of _HttpSslInfo is depth(%d), Subject(%ls).", pSSLInfo->GetDepth(), pSSLInfo->GetServerCert().GetPointer());
410 SysLog(NID_NET_HTTP, "SERVER CERT FAIL(Reason: %ls)", pSSLInfo->GetErrorMessage().GetPointer());
411 String* pServerCert = new (std::nothrow) String(pSSLInfo->GetServerCert());
413 r = _HttpUtility::RemoveSslCertInfo(*pSSLInfo);
416 SysLogException(NID_NET_HTTP, E_SYSTEM, "[E_SYSTEM] Failed to remove the server cert.");
419 //Fire the event(_HTTP_TRANSACTION_EVENT_TYPE_CERT_VERIFICATION_REQUIRED)
420 pHttpTransactionEvent->FireTransactionCertVerificationRequiredNEvent(pServerCert);
422 if (pHttpTransactionUserData->IsClosedTransaction() == false && pHttpTransactionImpl->IsAlreadyResumed() == false)
424 SysLog(NID_NET_HTTP, "The HttpTransaction[%d] action(resume or pause) does not set.", pHttpTransactionUserData->GetTransactionId());
426 //Start the timer. (30s)
427 pHttpTransactionImpl->SetTimer();
428 SysLog(NID_NET_HTTP, "The timer will be expired if the user does not call the API for resume or pause the transaction.");
435 //Fire the event(_HTTP_TRANSACTION_EVENT_TYPE_ABORTED)
436 pHttpTransactionEvent->FireTransactionAbortedEvent(r);
441 SysLog(NID_NET_HTTP, "Ignored to fire the event(_HTTP_TRANSACTION_EVENT_TYPE_ABORTED), the result is E_OPERATION_CANCELED.");
447 curl_multi_remove_handle(__pCurlM, pCurl);
449 if (__cookieFlag == NET_HTTP_COOKIE_FLAG_ALWAYS_AUTOMATIC)
451 curl_easy_setopt(pCurl, CURLOPT_COOKIELIST, "FLUSH");
452 SysLog(NID_NET_HTTP, "Flush the cookie data to the file.");
455 pHttpCurl = pHttpTransactionUserData->GetHttpCurl();
456 pHttpCurl->Release();
458 pHttpTransactionUserData->Release();
463 SysLog(NID_NET_HTTP, "The _HttpMultipleConnectionInfo instance was deleted.");
473 SysAssertf(false, "The pHttpTransactionUserData must not be null.");
477 pMessage = curl_multi_info_read(__pCurlM, &messageCount);
482 _HttpMultipleConnectionInfo::SetRemainsConnection(int remainsConnection)
484 __remainsConnection = remainsConnection;
488 _HttpMultipleConnectionInfo::GetRemainsConnection(void) const
490 return __remainsConnection;
494 _HttpMultipleConnectionInfo::Close(void)
496 __isAlreadyClosedSession = true;
500 _HttpMultipleConnectionInfo::GetCurlM(void) const
506 _HttpMultipleConnectionInfo::GetGMainContext(void) const
508 return __pGMainContext;
511 } } } // Tizen::Net::Http