From d30afe819abb03b139190c020db271888fab5eb1 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Fri, 21 Dec 2018 15:59:56 +0300 Subject: attempt to unify AsyncHttpRequest in various protocols --- include/m_netlib.h | 29 ++++++++++ libs/win32/mir_app.lib | Bin 186428 -> 189168 bytes libs/win64/mir_app.lib | Bin 181650 -> 184494 bytes protocols/Discord/src/connection.cpp | 4 +- protocols/Discord/src/http.cpp | 68 +---------------------- protocols/Discord/src/proto.h | 17 +----- protocols/VKontakte/src/vk_chats.cpp | 5 +- protocols/VKontakte/src/vk_files.cpp | 25 ++++----- protocols/VKontakte/src/vk_messages.cpp | 5 +- protocols/VKontakte/src/vk_proto.h | 2 +- protocols/VKontakte/src/vk_queue.cpp | 37 ++----------- protocols/VKontakte/src/vk_search.cpp | 21 +++----- protocols/VKontakte/src/vk_struct.cpp | 23 +------- protocols/VKontakte/src/vk_struct.h | 18 +------ protocols/VKontakte/src/vk_wallpost.cpp | 5 +- src/mir_app/src/MHttpRequest.cpp | 93 ++++++++++++++++++++++++++++++++ src/mir_app/src/mir_app.def | 9 ++++ src/mir_app/src/mir_app64.def | 9 ++++ src/mir_core/src/http.cpp | 25 ++++++--- 19 files changed, 196 insertions(+), 199 deletions(-) create mode 100644 src/mir_app/src/MHttpRequest.cpp diff --git a/include/m_netlib.h b/include/m_netlib.h index c23d0fddc1..6c504e2702 100644 --- a/include/m_netlib.h +++ b/include/m_netlib.h @@ -550,6 +550,35 @@ public: Netlib_FreeHttpRequest(_p); } }; + +struct MIR_APP_EXPORT MHttpRequest : public NETLIBHTTPREQUEST, public MZeroedObject +{ + MHttpRequest(); + ~MHttpRequest(); + + CMStringA m_szUrl; + CMStringA m_szParam; + void *pUserInfo; + + void AddHeader(const char *szName, const char *szValue); +}; + +template +class MTHttpRequest : public MHttpRequest +{ +public: + __inline MTHttpRequest() + {} + + typedef void (T::*MTHttpRequestHandler)(NETLIBHTTPREQUEST*, struct AsyncHttpRequest*); + MTHttpRequestHandler m_pFunc = nullptr; +}; + +MIR_APP_DLL(MHttpRequest*) operator<<(MHttpRequest*, const INT_PARAM&); +MIR_APP_DLL(MHttpRequest*) operator<<(MHttpRequest*, const INT64_PARAM&); +MIR_APP_DLL(MHttpRequest*) operator<<(MHttpRequest*, const CHAR_PARAM&); +MIR_APP_DLL(MHttpRequest*) operator<<(MHttpRequest*, const WCHAR_PARAM&); + #endif ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/libs/win32/mir_app.lib b/libs/win32/mir_app.lib index 0b3694c692..7d1f32b898 100644 Binary files a/libs/win32/mir_app.lib and b/libs/win32/mir_app.lib differ diff --git a/libs/win64/mir_app.lib b/libs/win64/mir_app.lib index c03d0b753b..50cddcd753 100644 Binary files a/libs/win64/mir_app.lib and b/libs/win64/mir_app.lib differ diff --git a/protocols/Discord/src/connection.cpp b/protocols/Discord/src/connection.cpp index 80ec0c172a..b986921046 100644 --- a/protocols/Discord/src/connection.cpp +++ b/protocols/Discord/src/connection.cpp @@ -43,8 +43,8 @@ void CDiscordProto::ExecuteRequest(AsyncHttpRequest *pReq) debugLogA("Executing request #%d:\n%s", pReq->m_iReqNum, pReq->szUrl); NETLIBHTTPREQUEST *reply = Netlib_HttpTransaction(m_hNetlibUser, pReq); if (reply != nullptr) { - if (pReq->m_pCallback != nullptr) - (this->*(pReq->m_pCallback))(reply, pReq); + if (pReq->m_pFunc != nullptr) + (this->*(pReq->m_pFunc))(reply, pReq); if (pReq->m_bMainSite) m_hAPIConnection = reply->nlc; diff --git a/protocols/Discord/src/http.cpp b/protocols/Discord/src/http.cpp index 743c615605..cf368a5270 100644 --- a/protocols/Discord/src/http.cpp +++ b/protocols/Discord/src/http.cpp @@ -38,7 +38,7 @@ AsyncHttpRequest::AsyncHttpRequest() m_iReqNum = ::InterlockedIncrement(&g_reqNum); } -AsyncHttpRequest::AsyncHttpRequest(CDiscordProto *ppro, int iRequestType, LPCSTR _url, HttpCallback pFunc, JSONNode *pRoot) +AsyncHttpRequest::AsyncHttpRequest(CDiscordProto *ppro, int iRequestType, LPCSTR _url, MTHttpRequestHandler pFunc, JSONNode *pRoot) { cbSize = sizeof(NETLIBHTTPREQUEST); @@ -66,72 +66,8 @@ AsyncHttpRequest::AsyncHttpRequest(CDiscordProto *ppro, int iRequestType, LPCSTR } AddHeader("Content-Type", "application/json"); + m_pFunc = pFunc; requestType = iRequestType; - m_pCallback = pFunc; - pUserInfo = nullptr; m_iErrorCode = 0; m_iReqNum = ::InterlockedIncrement(&g_reqNum); } - -AsyncHttpRequest::~AsyncHttpRequest() -{ - for (int i = 0; i < headersCount; i++) { - mir_free(headers[i].szName); - mir_free(headers[i].szValue); - } - mir_free(headers); - mir_free(pData); -} - -void AsyncHttpRequest::AddHeader(LPCSTR szName, LPCSTR szValue) -{ - for (int i = 0; i < headersCount; i++) - if (!mir_strcmp(headers[i].szName, szName)) { - replaceStr(headers[i].szValue, szValue); - return; - } - - headers = (NETLIBHTTPHEADER*)mir_realloc(headers, sizeof(NETLIBHTTPHEADER)*(headersCount + 1)); - headers[headersCount].szName = mir_strdup(szName); - headers[headersCount].szValue = mir_strdup(szValue); - headersCount++; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -AsyncHttpRequest* operator<<(AsyncHttpRequest *pReq, const INT_PARAM ¶m) -{ - CMStringA &s = pReq->m_szParam; - if (!s.IsEmpty()) - s.AppendChar('&'); - s.AppendFormat("%s=%i", param.szName, param.iValue); - return pReq; -} - -AsyncHttpRequest* operator<<(AsyncHttpRequest *pReq, const INT64_PARAM ¶m) -{ - CMStringA &s = pReq->m_szParam; - if (!s.IsEmpty()) - s.AppendChar('&'); - s.AppendFormat("%s=%lld", param.szName, param.iValue); - return pReq; -} - -AsyncHttpRequest* operator<<(AsyncHttpRequest *pReq, const CHAR_PARAM ¶m) -{ - CMStringA &s = pReq->m_szParam; - if (!s.IsEmpty()) - s.AppendChar('&'); - s.AppendFormat("%s=%s", param.szName, ptrA(mir_urlEncode(param.szValue))); - return pReq; -} - -AsyncHttpRequest* operator<<(AsyncHttpRequest *pReq, const WCHAR_PARAM ¶m) -{ - T2Utf szValue(param.wszValue); - CMStringA &s = pReq->m_szParam; - if (!s.IsEmpty()) - s.AppendChar('&'); - s.AppendFormat("%s=%s", param.szName, ptrA(mir_urlEncode(szValue))); - return pReq; -} diff --git a/protocols/Discord/src/proto.h b/protocols/Discord/src/proto.h index fd9bc8d632..7321e9efa2 100644 --- a/protocols/Discord/src/proto.h +++ b/protocols/Discord/src/proto.h @@ -8,30 +8,17 @@ __forceinline int compareInt64(const SnowFlake i1, const SnowFlake i2) } class CDiscordProto; -typedef void (CDiscordProto::*HttpCallback)(NETLIBHTTPREQUEST*, struct AsyncHttpRequest*); typedef void (CDiscordProto::*GatewayHandlerFunc)(const JSONNode&); -struct AsyncHttpRequest : public NETLIBHTTPREQUEST, public MZeroedObject +struct AsyncHttpRequest : public MTHttpRequest { AsyncHttpRequest(); - AsyncHttpRequest(CDiscordProto*, int iRequestType, LPCSTR szUrl, HttpCallback pFunc, JSONNode *pNode = nullptr); - ~AsyncHttpRequest(); + AsyncHttpRequest(CDiscordProto*, int iRequestType, LPCSTR szUrl, MTHttpRequestHandler pFunc, JSONNode *pNode = nullptr); - void AddHeader(LPCSTR, LPCSTR); - - CMStringA m_szUrl; - CMStringA m_szParam; - HttpCallback m_pCallback; int m_iErrorCode, m_iReqNum; bool m_bMainSite; - void *pUserInfo; }; -AsyncHttpRequest* operator<<(AsyncHttpRequest*, const INT_PARAM&); -AsyncHttpRequest* operator<<(AsyncHttpRequest*, const INT64_PARAM&); -AsyncHttpRequest* operator<<(AsyncHttpRequest*, const CHAR_PARAM&); -AsyncHttpRequest* operator<<(AsyncHttpRequest*, const WCHAR_PARAM&); - ///////////////////////////////////////////////////////////////////////////////////////// struct CDiscordRole : public MZeroedObject diff --git a/protocols/VKontakte/src/vk_chats.cpp b/protocols/VKontakte/src/vk_chats.cpp index 46c990b205..a6f6d4cfd6 100644 --- a/protocols/VKontakte/src/vk_chats.cpp +++ b/protocols/VKontakte/src/vk_chats.cpp @@ -565,9 +565,8 @@ INT_PTR __cdecl CVkProto::OnJoinChat(WPARAM hContact, LPARAM) if (chat_id == VK_INVALID_USER) return 1; - AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_POST, "/method/messages.send.json", true, &CVkProto::OnSendChatMsg, AsyncHttpRequest::rpHigh) - << INT_PARAM("chat_id", chat_id) - << WCHAR_PARAM("message", m_vkOptions.pwszReturnChatMessage); + AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_POST, "/method/messages.send.json", true, &CVkProto::OnSendChatMsg, AsyncHttpRequest::rpHigh); + pReq << INT_PARAM("chat_id", chat_id) << WCHAR_PARAM("message", m_vkOptions.pwszReturnChatMessage); pReq->AddHeader("Content-Type", "application/x-www-form-urlencoded"); Push(pReq); db_unset(hContact, m_szModuleName, "off"); diff --git a/protocols/VKontakte/src/vk_files.cpp b/protocols/VKontakte/src/vk_files.cpp index 68fbe7da09..717ba18dcf 100644 --- a/protocols/VKontakte/src/vk_files.cpp +++ b/protocols/VKontakte/src/vk_files.cpp @@ -263,10 +263,8 @@ void CVkProto::OnReciveUpload(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) SendFileFiled(fup, VKERR_INVALID_PARAMETERS); return; } - pUploadReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/photos.saveMessagesPhoto.json", true, &CVkProto::OnReciveUploadFile) - << WCHAR_PARAM("server", server) - << WCHAR_PARAM("photo", upload) - << WCHAR_PARAM("hash", hash); + pUploadReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/photos.saveMessagesPhoto.json", true, &CVkProto::OnReciveUploadFile); + pUploadReq << WCHAR_PARAM("server", server) << WCHAR_PARAM("photo", upload) << WCHAR_PARAM("hash", hash); break; case CVkFileUploadParam::typeAudio: upload = jnRoot["audio"].as_mstring(); @@ -274,10 +272,8 @@ void CVkProto::OnReciveUpload(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) SendFileFiled(fup, VKERR_INVALID_PARAMETERS); return; } - pUploadReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/audio.save.json", true, &CVkProto::OnReciveUploadFile) - << WCHAR_PARAM("server", server) - << WCHAR_PARAM("audio", upload) - << WCHAR_PARAM("hash", hash); + pUploadReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/audio.save.json", true, &CVkProto::OnReciveUploadFile); + pUploadReq << WCHAR_PARAM("server", server) << WCHAR_PARAM("audio", upload) << WCHAR_PARAM("hash", hash); break; case CVkFileUploadParam::typeDoc: upload = jnRoot["file"].as_mstring(); @@ -285,9 +281,8 @@ void CVkProto::OnReciveUpload(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) SendFileFiled(fup, VKERR_INVALID_PARAMETERS); return; } - pUploadReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/docs.save.json", true, &CVkProto::OnReciveUploadFile) - << CHAR_PARAM("title", fup->fileName()) - << WCHAR_PARAM("file", upload); + pUploadReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/docs.save.json", true, &CVkProto::OnReciveUploadFile); + pUploadReq << CHAR_PARAM("title", fup->fileName()) << WCHAR_PARAM("file", upload); break; default: SendFileFiled(fup, VKERR_FTYPE_NOT_SUPPORTED); @@ -359,8 +354,8 @@ void CVkProto::OnReciveUploadFile(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pR return; } - pMsgReq = new AsyncHttpRequest(this, REQUEST_POST, "/method/messages.send.json", true, &CVkProto::OnSendChatMsg, AsyncHttpRequest::rpHigh) - << INT_PARAM("chat_id", cc->m_chatid); + pMsgReq = new AsyncHttpRequest(this, REQUEST_POST, "/method/messages.send.json", true, &CVkProto::OnSendChatMsg, AsyncHttpRequest::rpHigh); + pMsgReq << INT_PARAM("chat_id", cc->m_chatid); pMsgReq->pUserInfo = pReq->pUserInfo; } @@ -371,8 +366,8 @@ void CVkProto::OnReciveUploadFile(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pR return; } - pMsgReq = new AsyncHttpRequest(this, REQUEST_POST, "/method/messages.send.json", true, &CVkProto::OnSendMessage, AsyncHttpRequest::rpHigh) - << INT_PARAM("user_id", userID); + pMsgReq = new AsyncHttpRequest(this, REQUEST_POST, "/method/messages.send.json", true, &CVkProto::OnSendMessage, AsyncHttpRequest::rpHigh); + pMsgReq << INT_PARAM("user_id", userID); pMsgReq->pUserInfo = new CVkSendMsgParam(fup->hContact, fup); } diff --git a/protocols/VKontakte/src/vk_messages.cpp b/protocols/VKontakte/src/vk_messages.cpp index f6cdbf0fc1..63d5ce317b 100644 --- a/protocols/VKontakte/src/vk_messages.cpp +++ b/protocols/VKontakte/src/vk_messages.cpp @@ -47,9 +47,8 @@ int CVkProto::SendMsg(MCONTACT hContact, int, const char *szMsg) ULONG uMsgId = ::InterlockedIncrement(&m_msgId); AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_POST, "/method/messages.send.json", true, - bIsChat ? &CVkProto::OnSendChatMsg : &CVkProto::OnSendMessage, AsyncHttpRequest::rpHigh) - << INT_PARAM(bIsChat ? "chat_id" : "peer_id", iUserID) - << INT_PARAM("random_id", ((LONG)time(0)) * 100 + uMsgId % 100); + bIsChat ? &CVkProto::OnSendChatMsg : &CVkProto::OnSendMessage, AsyncHttpRequest::rpHigh); + pReq << INT_PARAM(bIsChat ? "chat_id" : "peer_id", iUserID) << INT_PARAM("random_id", ((LONG)time(0)) * 100 + uMsgId % 100); pReq->AddHeader("Content-Type", "application/x-www-form-urlencoded"); if (StickerId) diff --git a/protocols/VKontakte/src/vk_proto.h b/protocols/VKontakte/src/vk_proto.h index 6c3d632715..e77bea8472 100644 --- a/protocols/VKontakte/src/vk_proto.h +++ b/protocols/VKontakte/src/vk_proto.h @@ -361,7 +361,7 @@ private: void UninitQueue(); void ExecuteRequest(AsyncHttpRequest*); void __cdecl WorkerThread(void*); - AsyncHttpRequest* Push(AsyncHttpRequest *pReq, int iTimeout = 10000); + AsyncHttpRequest* Push(MHttpRequest *pReq, int iTimeout = 10000); bool RunCaptchaForm(LPCSTR szUrl, CMStringA&); bool ApplyCaptcha(AsyncHttpRequest *pReq, const JSONNode&); void ConnectionFailed(int iReason); diff --git a/protocols/VKontakte/src/vk_queue.cpp b/protocols/VKontakte/src/vk_queue.cpp index ff6b62b9ab..c4ef960cc0 100644 --- a/protocols/VKontakte/src/vk_queue.cpp +++ b/protocols/VKontakte/src/vk_queue.cpp @@ -90,8 +90,10 @@ void CVkProto::ExecuteRequest(AsyncHttpRequest *pReq) ///////////////////////////////////////////////////////////////////////////////////////// -AsyncHttpRequest* CVkProto::Push(AsyncHttpRequest *pReq, int iTimeout) +AsyncHttpRequest* CVkProto::Push(MHttpRequest *p, int iTimeout) { + AsyncHttpRequest *pReq = (AsyncHttpRequest*)p; + debugLogA("CVkProto::Push"); pReq->timeout = iTimeout; if (pReq->m_bApiReq) { @@ -131,7 +133,8 @@ void CVkProto::WorkerThread(void*) else { // Initialize new OAuth session extern char szBlankUrl[]; - AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_GET, "https://oauth.vk.com/authorize", false, &CVkProto::OnOAuthAuthorize) + AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_GET, "https://oauth.vk.com/authorize", false, &CVkProto::OnOAuthAuthorize); + pReq << INT_PARAM("client_id", VK_APP_ID) << CHAR_PARAM("scope", Score) << CHAR_PARAM("redirect_uri", szBlankUrl) @@ -203,33 +206,3 @@ void CVkProto::WorkerThread(void*) m_hWorkerThread = nullptr; } } - -///////////////////////////////////////////////////////////////////////////////////////// - -AsyncHttpRequest* operator<<(AsyncHttpRequest *pReq, const INT_PARAM ¶m) -{ - CMStringA &s = pReq->m_szParam; - if (!s.IsEmpty()) - s.AppendChar('&'); - s.AppendFormat("%s=%ld", param.szName, param.iValue); - return pReq; -} - -AsyncHttpRequest* operator<<(AsyncHttpRequest *pReq, const CHAR_PARAM ¶m) -{ - CMStringA &s = pReq->m_szParam; - if (!s.IsEmpty()) - s.AppendChar('&'); - s.AppendFormat("%s=%s", param.szName, ptrA(pReq->bExpUrlEncode ? ExpUrlEncode(param.szValue) : mir_urlEncode(param.szValue))); - return pReq; -} - -AsyncHttpRequest* operator<<(AsyncHttpRequest *pReq, const WCHAR_PARAM ¶m) -{ - T2Utf szValue(param.wszValue); - CMStringA &s = pReq->m_szParam; - if (!s.IsEmpty()) - s.AppendChar('&'); - s.AppendFormat("%s=%s", param.szName, ptrA(pReq->bExpUrlEncode ? ExpUrlEncode(szValue) : mir_urlEncode(szValue))); - return pReq; -} \ No newline at end of file diff --git a/protocols/VKontakte/src/vk_search.cpp b/protocols/VKontakte/src/vk_search.cpp index 3796fbb530..9cba181b6f 100644 --- a/protocols/VKontakte/src/vk_search.cpp +++ b/protocols/VKontakte/src/vk_search.cpp @@ -46,11 +46,9 @@ void CVkProto::SearchBasicThread(void *id) debugLogA("CVkProto::OnSearchBasicThread"); if (!IsOnline()) return; - AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/users.get.json", true, &CVkProto::OnSearch) - << WCHAR_PARAM("user_ids", (wchar_t *)id) - << CHAR_PARAM("fields", "nickname, domain"); - pReq->pUserInfo = nullptr; - Push(pReq); + + Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/users.get.json", true, &CVkProto::OnSearch) + << WCHAR_PARAM("user_ids", (wchar_t *)id) << CHAR_PARAM("fields", "nickname, domain")); } void CVkProto::SearchByMailThread(void *email) @@ -58,10 +56,9 @@ void CVkProto::SearchByMailThread(void *email) debugLogA("CVkProto::OnSearchBasicThread"); if (!IsOnline()) return; - AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/account.lookupContacts.json", true, &CVkProto::OnSearchByMail) - << WCHAR_PARAM("contacts", (wchar_t *)email) - << CHAR_PARAM("service", "email"); - Push(pReq); + + Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/account.lookupContacts.json", true, &CVkProto::OnSearchByMail) + << WCHAR_PARAM("contacts", (wchar_t *)email) << CHAR_PARAM("service", "email")); } void __cdecl CVkProto::SearchThread(void *p) @@ -74,12 +71,10 @@ void __cdecl CVkProto::SearchThread(void *p) if (!IsOnline()) return; - AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/users.search.json", true, &CVkProto::OnSearch) + Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/users.search.json", true, &CVkProto::OnSearch) << WCHAR_PARAM("q", (wchar_t *)arg) << CHAR_PARAM("fields", "nickname, domain") - << INT_PARAM("count", 200); - pReq->pUserInfo = p; - Push(pReq); + << INT_PARAM("count", 200))->pUserInfo = p; } void CVkProto::FreeProtoShearchStruct(PROTOSEARCHBYNAME *pParam) diff --git a/protocols/VKontakte/src/vk_struct.cpp b/protocols/VKontakte/src/vk_struct.cpp index 4f7a58001a..e02430914b 100644 --- a/protocols/VKontakte/src/vk_struct.cpp +++ b/protocols/VKontakte/src/vk_struct.cpp @@ -32,17 +32,15 @@ AsyncHttpRequest::AsyncHttpRequest() bNeedsRestart = false; bIsMainConn = false; m_pFunc = nullptr; - bExpUrlEncode = true; m_reqNum = ::InterlockedIncrement(&m_reqCount); m_priority = rpLow; } -AsyncHttpRequest::AsyncHttpRequest(CVkProto *ppro, int iRequestType, LPCSTR _url, bool bSecure, VK_REQUEST_HANDLER pFunc, RequestPriority rpPriority) +AsyncHttpRequest::AsyncHttpRequest(CVkProto *ppro, int iRequestType, LPCSTR _url, bool bSecure, MTHttpRequestHandler pFunc, RequestPriority rpPriority) { cbSize = sizeof(NETLIBHTTPREQUEST); m_bApiReq = true; bIsMainConn = false; - bExpUrlEncode = (BYTE)ppro->m_vkOptions.bUseStandardUrlEncode == 0; AddHeader("Connection", "keep-alive"); if (*_url == '/') { // relative url leads to a site @@ -69,24 +67,6 @@ AsyncHttpRequest::AsyncHttpRequest(CVkProto *ppro, int iRequestType, LPCSTR _url m_priority = rpPriority; } -AsyncHttpRequest::~AsyncHttpRequest() -{ - for (int i = 0; i < headersCount; i++) { - mir_free(headers[i].szName); - mir_free(headers[i].szValue); - } - mir_free(headers); - mir_free(pData); -} - -void AsyncHttpRequest::AddHeader(LPCSTR szName, LPCSTR szValue) -{ - headers = (NETLIBHTTPHEADER*)mir_realloc(headers, sizeof(NETLIBHTTPHEADER)*(headersCount + 1)); - headers[headersCount].szName = mir_strdup(szName); - headers[headersCount].szValue = mir_strdup(szValue); - headersCount++; -} - void AsyncHttpRequest::Redirect(NETLIBHTTPREQUEST *nhr) { for (int i = 0; i < nhr->headersCount; i++) { @@ -208,7 +188,6 @@ CVKOptions::CVKOptions(PROTO_INTERFACE *proto) : bSendVKLinksAsAttachments(proto, "SendVKLinksAsAttachments", true), bLoadSentAttachments(proto, "LoadSentAttachments", bSendVKLinksAsAttachments), bUseNonStandardNotifications(proto, "UseNonStandardNotifications", false), - bUseStandardUrlEncode(proto, "UseStandardUrlEncode", false), bShortenLinksForAudio(proto, "ShortenLinksForAudio", true), bAddMessageLinkToMesWAtt(proto, "AddMessageLinkToMesWAtt", true), bSplitFormatFwdMsg(proto, "SplitFormatFwdMsg", true), diff --git a/protocols/VKontakte/src/vk_struct.h b/protocols/VKontakte/src/vk_struct.h index 00e24f5b90..96916c6fd3 100644 --- a/protocols/VKontakte/src/vk_struct.h +++ b/protocols/VKontakte/src/vk_struct.h @@ -18,37 +18,24 @@ along with this program. If not, see . #include "stdafx.h" #pragma once -typedef void (CVkProto::*VK_REQUEST_HANDLER)(NETLIBHTTPREQUEST*, struct AsyncHttpRequest*); - -struct AsyncHttpRequest : public NETLIBHTTPREQUEST, public MZeroedObject +struct AsyncHttpRequest : public MTHttpRequest { enum RequestPriority { rpLow, rpMedium, rpHigh }; AsyncHttpRequest(); - AsyncHttpRequest(CVkProto*, int iRequestType, LPCSTR szUrl, bool bSecure, VK_REQUEST_HANDLER pFunc, RequestPriority rpPriority = rpMedium); - ~AsyncHttpRequest(); + AsyncHttpRequest(CVkProto*, int iRequestType, LPCSTR szUrl, bool bSecure, MTHttpRequestHandler pFunc, RequestPriority rpPriority = rpMedium); - void AddHeader(LPCSTR, LPCSTR); void Redirect(NETLIBHTTPREQUEST*); - CMStringA m_szUrl; - CMStringA m_szParam; - VK_REQUEST_HANDLER m_pFunc; - void *pUserInfo; int m_iRetry; int m_iErrorCode; RequestPriority m_priority; static ULONG m_reqCount; ULONG m_reqNum; bool m_bApiReq; - bool bExpUrlEncode; bool bNeedsRestart, bIsMainConn; }; -AsyncHttpRequest* operator<<(AsyncHttpRequest*, const INT_PARAM&); -AsyncHttpRequest* operator<<(AsyncHttpRequest*, const CHAR_PARAM&); -AsyncHttpRequest* operator<<(AsyncHttpRequest*, const WCHAR_PARAM&); - struct CVkFileUploadParam : public MZeroedObject { enum VKFileType { typeInvalid, typeImg, typeAudio, typeDoc, typeNotSupported }; wchar_t *FileName; @@ -301,7 +288,6 @@ struct CVKOptions { CMOption bNotificationFilterInvites; CMOption bNotificationFilterAcceptedFriends; CMOption bUseNonStandardNotifications; - CMOption bUseStandardUrlEncode; CMOption bShortenLinksForAudio; CMOption bAddMessageLinkToMesWAtt; CMOption bSplitFormatFwdMsg; diff --git a/protocols/VKontakte/src/vk_wallpost.cpp b/protocols/VKontakte/src/vk_wallpost.cpp index e90296b151..aa41fcec2a 100644 --- a/protocols/VKontakte/src/vk_wallpost.cpp +++ b/protocols/VKontakte/src/vk_wallpost.cpp @@ -40,9 +40,8 @@ void CVkProto::WallPost(MCONTACT hContact, wchar_t *pwszMsg, wchar_t *pwszUrl, b if (userID == VK_INVALID_USER || userID == VK_FEED_USER) return; - AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_POST, "/method/wall.post.json", true, &CVkProto::OnReceiveSmth) - << INT_PARAM("owner_id", userID) - << INT_PARAM("friends_only", bFriendsOnly ? 1 : 0); + AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_POST, "/method/wall.post.json", true, &CVkProto::OnReceiveSmth); + pReq << INT_PARAM("owner_id", userID) << INT_PARAM("friends_only", bFriendsOnly ? 1 : 0); if (!IsEmpty(pwszMsg)) pReq << WCHAR_PARAM("message", pwszMsg); diff --git a/src/mir_app/src/MHttpRequest.cpp b/src/mir_app/src/MHttpRequest.cpp new file mode 100644 index 0000000000..ce511f8e4b --- /dev/null +++ b/src/mir_app/src/MHttpRequest.cpp @@ -0,0 +1,93 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-18 Miranda NG team, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "stdafx.h" + +MHttpRequest::MHttpRequest() +{ + cbSize = sizeof(NETLIBHTTPREQUEST); + requestType = REQUEST_GET; +} + +MHttpRequest::~MHttpRequest() +{ + for (int i = 0; i < headersCount; i++) { + mir_free(headers[i].szName); + mir_free(headers[i].szValue); + } + mir_free(headers); + mir_free(pData); +} + +void MHttpRequest::AddHeader(LPCSTR szName, LPCSTR szValue) +{ + for (int i = 0; i < headersCount; i++) + if (!mir_strcmp(headers[i].szName, szName)) { + replaceStr(headers[i].szValue, szValue); + return; + } + + headers = (NETLIBHTTPHEADER*)mir_realloc(headers, sizeof(NETLIBHTTPHEADER)*(headersCount + 1)); + headers[headersCount].szName = mir_strdup(szName); + headers[headersCount].szValue = mir_strdup(szValue); + headersCount++; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(MHttpRequest*) operator<<(MHttpRequest *pReq, const INT_PARAM ¶m) +{ + CMStringA &s = pReq->m_szParam; + if (!s.IsEmpty()) + s.AppendChar('&'); + s.AppendFormat("%s=%ld", param.szName, param.iValue); + return pReq; +} + +MIR_APP_DLL(MHttpRequest*) operator<<(MHttpRequest *pReq, const INT64_PARAM ¶m) +{ + CMStringA &s = pReq->m_szParam; + if (!s.IsEmpty()) + s.AppendChar('&'); + s.AppendFormat("%s=%lld", param.szName, param.iValue); + return pReq; +} + +MIR_APP_DLL(MHttpRequest*) operator<<(MHttpRequest *pReq, const CHAR_PARAM ¶m) +{ + CMStringA &s = pReq->m_szParam; + if (!s.IsEmpty()) + s.AppendChar('&'); + s.AppendFormat("%s=%s", param.szName, ptrA(mir_urlEncode(param.szValue))); + return pReq; +} + +MIR_APP_DLL(MHttpRequest*) operator<<(MHttpRequest *pReq, const WCHAR_PARAM ¶m) +{ + T2Utf szValue(param.wszValue); + CMStringA &s = pReq->m_szParam; + if (!s.IsEmpty()) + s.AppendChar('&'); + s.AppendFormat("%s=%s", param.szName, ptrA(mir_urlEncode(szValue))); + return pReq; +} diff --git a/src/mir_app/src/mir_app.def b/src/mir_app/src/mir_app.def index e3be5f3916..673016746d 100644 --- a/src/mir_app/src/mir_app.def +++ b/src/mir_app/src/mir_app.def @@ -671,3 +671,12 @@ g_hevSettingChanged @696 NONAME ?MetaRemoveSubHistory@MDatabaseReadonly@@UAGHPAUDBCachedContact@@@Z @704 NONAME Chat_GetGroup @705 Chat_SetGroup @706 +??0MHttpRequest@@QAE@ABU0@@Z @707 NONAME +??0MHttpRequest@@QAE@XZ @708 NONAME +??1MHttpRequest@@QAE@XZ @709 NONAME +??4MHttpRequest@@QAEAAU0@ABU0@@Z @710 NONAME +??6@YGPAUMHttpRequest@@PAU0@ABUCHAR_PARAM@@@Z @711 NONAME +??6@YGPAUMHttpRequest@@PAU0@ABUINT_PARAM@@@Z @712 NONAME +??6@YGPAUMHttpRequest@@PAU0@ABUWCHAR_PARAM@@@Z @713 NONAME +??6@YGPAUMHttpRequest@@PAU0@ABUINT64_PARAM@@@Z @714 NONAME +?AddHeader@MHttpRequest@@QAEXPBD0@Z @715 NONAME diff --git a/src/mir_app/src/mir_app64.def b/src/mir_app/src/mir_app64.def index bb0746bc4e..513a79e71c 100644 --- a/src/mir_app/src/mir_app64.def +++ b/src/mir_app/src/mir_app64.def @@ -671,3 +671,12 @@ g_hevSettingChanged @696 NONAME ?MetaRemoveSubHistory@MDatabaseReadonly@@UEAAHPEAUDBCachedContact@@@Z @704 NONAME Chat_GetGroup @705 Chat_SetGroup @706 +??0MHttpRequest@@QEAA@AEBU0@@Z @707 NONAME +??0MHttpRequest@@QEAA@XZ @708 NONAME +??1MHttpRequest@@QEAA@XZ @709 NONAME +??4MHttpRequest@@QEAAAEAU0@AEBU0@@Z @710 NONAME +??6@YAPEAUMHttpRequest@@PEAU0@AEBUCHAR_PARAM@@@Z @711 NONAME +??6@YAPEAUMHttpRequest@@PEAU0@AEBUINT_PARAM@@@Z @712 NONAME +??6@YAPEAUMHttpRequest@@PEAU0@AEBUWCHAR_PARAM@@@Z @713 NONAME +??6@YAPEAUMHttpRequest@@PEAU0@AEBUINT64_PARAM@@@Z @714 NONAME +?AddHeader@MHttpRequest@@QEAAXPEBD0@Z @715 NONAME diff --git a/src/mir_core/src/http.cpp b/src/mir_core/src/http.cpp index ae5a9f3ff4..fad969c680 100755 --- a/src/mir_core/src/http.cpp +++ b/src/mir_core/src/http.cpp @@ -29,11 +29,14 @@ MIR_CORE_DLL(char*) mir_urlEncode(const char *szUrl) const BYTE *s; int outputLen; for (outputLen = 0, s = (const BYTE*)szUrl; *s; s++) { - if (('0' <= *s && *s <= '9') || //0-9 + if ((*s & 0x80) || + ('0' <= *s && *s <= '9') || //0-9 ('A' <= *s && *s <= 'Z') || //ABC...XYZ ('a' <= *s && *s <= 'z') || //abc...xyz - *s == '-' || *s == '_' || *s == '.' || *s == ' ' || *s == '~') outputLen++; - else outputLen += 3; + *s == '-' || *s == '_' || *s == '.' || *s == ' ' || *s == '~') + outputLen++; + else + outputLen += 3; } char *szOutput = (char*)mir_alloc(outputLen+1); @@ -42,11 +45,17 @@ MIR_CORE_DLL(char*) mir_urlEncode(const char *szUrl) char *d = szOutput; for (s = (const BYTE*)szUrl; *s; s++) { - if (('0' <= *s && *s <= '9') || //0-9 - ('A' <= *s && *s <= 'Z') || //ABC...XYZ - ('a' <= *s && *s <= 'z') || //abc...xyz - *s == '-' || *s == '_' || *s == '.' || *s == '~') *d++ = *s; - else if (*s == ' ') *d++='+'; + if ((*s & 0x80) || + ('0' <= *s && *s <= '9') || //0-9 + ('A' <= *s && *s <= 'Z') || //ABC...XYZ + ('a' <= *s && *s <= 'z') || //abc...xyz + *s == '-' || *s == '_' || *s == '.' || *s == '~') + { + *d++ = *s; + } + else if (*s == ' ') { + *d++ = '+'; + } else { *d++ = '%'; *d++ = szHexDigits[*s >> 4]; -- cgit v1.2.3