summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2024-01-04 13:38:02 +0300
committerGeorge Hazan <george.hazan@gmail.com>2024-01-04 13:38:02 +0300
commit94667140aeb3886d22e4c1301423fe99aaf3fba4 (patch)
tree88bc46dfa6a3dba117905f7994b5e5f6ae09fa2a
parente63471b9885d040b9e6db3255432f6cea36144e9 (diff)
Netlib: pascal code is completely isolated from C++ core using helpers
-rw-r--r--include/delphi/m_netlib.inc8
-rw-r--r--include/m_netlib.h4
-rw-r--r--libs/win32/mir_app.libbin277222 -> 278210 bytes
-rw-r--r--libs/win64/mir_app.libbin276512 -> 277538 bytes
-rw-r--r--plugins/Utils.pas/mirutils.pas55
-rw-r--r--plugins/Watrack/myshows/i_cookies.inc51
-rw-r--r--plugins/Watrack/myshows/i_myshows_api.inc1
-rw-r--r--protocols/Discord/src/gateway.cpp7
-rw-r--r--protocols/Discord/src/server.cpp13
-rw-r--r--protocols/ICQ-WIM/src/mra.cpp13
-rw-r--r--protocols/Tox/src/http_request.h1
-rw-r--r--src/mir_app/src/mir_app.def7
-rw-r--r--src/mir_app/src/mir_app64.def7
-rw-r--r--src/mir_app/src/netlib.h1
-rw-r--r--src/mir_app/src/netlib_http.cpp525
15 files changed, 349 insertions, 344 deletions
diff --git a/include/delphi/m_netlib.inc b/include/delphi/m_netlib.inc
index 253c836a4d..d5c553817e 100644
--- a/include/delphi/m_netlib.inc
+++ b/include/delphi/m_netlib.inc
@@ -200,7 +200,7 @@ function Netlib_CloseHandle(pHandle:THANDLE) : int; stdcall; external AppDll;
}
-function Netlib_FreeHttpRequest(param:PNETLIBHTTPREQUEST) : bytebool; stdcall; external AppDll;
+function Netlib_FreeHttpRequest(param:THANDLE) : bytebool; stdcall; external AppDll;
{
wParam : HANDLE
@@ -239,7 +239,11 @@ function Netlib_FreeHttpRequest(param:PNETLIBHTTPREQUEST) : bytebool; stdcall; e
Errors returned by the aforementioned internally used functions
}
-function Netlib_HttpTransaction(nlu:THANDLE; param:PNETLIBHTTPREQUEST) : PNETLIBHTTPREQUEST; stdcall; external AppDll;
+function Netlib_HttpTransaction(nlu:THANDLE; param:PNETLIBHTTPREQUEST) : THANDLE; stdcall; external AppDll;
+
+function Netlib_HttpResult(http:THANDLE) : int; stdcall; external AppDll;
+function Netlib_HttpBuffer(http:THANDLE; var cbLen:int) : PAnsiChar; stdcall; external AppDll;
+function Netlib_HttpCookies(http:THANDLE) : PAnsiChar; stdcall; external AppDll;
{
Affect : Send data over an open connection see notes
diff --git a/include/m_netlib.h b/include/m_netlib.h
index 149b025f8e..0f8cdc2015 100644
--- a/include/m_netlib.h
+++ b/include/m_netlib.h
@@ -434,7 +434,7 @@ EXTERN_C MIR_APP_DLL(char*) Netlib_GetHeader(const NETLIBHTTPREQUEST *pRec, cons
#define NLHRF_DUMPASTEXT 0x00080000 // dump posted and reply data as text. Headers are always dumped as text.
#define NLHRF_NODUMPSEND 0x00100000 // do not dump sent message.
-struct NETLIBHTTPREQUEST
+struct MIR_APP_EXPORT NETLIBHTTPREQUEST
{
int requestType; // a REQUEST_
uint32_t flags;
@@ -448,6 +448,8 @@ struct NETLIBHTTPREQUEST
HNETLIBCONN nlc;
int timeout;
+ CMStringA GetCookies() const;
+
__forceinline const char *operator[](const char *pszName) {
return Netlib_GetHeader(this, pszName);
}
diff --git a/libs/win32/mir_app.lib b/libs/win32/mir_app.lib
index 90c5625b72..0adef99d45 100644
--- a/libs/win32/mir_app.lib
+++ b/libs/win32/mir_app.lib
Binary files differ
diff --git a/libs/win64/mir_app.lib b/libs/win64/mir_app.lib
index d8752d5f06..5ed62c15f7 100644
--- a/libs/win64/mir_app.lib
+++ b/libs/win64/mir_app.lib
Binary files differ
diff --git a/plugins/Utils.pas/mirutils.pas b/plugins/Utils.pas/mirutils.pas
index c6066c8ee9..fb07550f08 100644
--- a/plugins/Utils.pas/mirutils.pas
+++ b/plugins/Utils.pas/mirutils.pas
@@ -404,7 +404,9 @@ function SendRequest(url:PAnsiChar;rtype:int;args:PAnsiChar=nil;hNetLib:THANDLE=
var
nlu:TNETLIBUSER;
req :TNETLIBHTTPREQUEST;
- resp:PNETLIBHTTPREQUEST;
+ resp:THANDLE;
+ bufLen:int;
+ pBuf:PAnsiChar;
hTmpNetLib:THANDLE;
nlh:array [0..1] of TNETLIBHTTPHEADER;
buf:array [0..31] of AnsiChar;
@@ -438,15 +440,16 @@ begin
hTmpNetLib:=hNetLib;
resp:=Netlib_HttpTransaction(hTmpNetLib,@req);
- if resp<>nil then
+ if resp<>0 then
begin
- if resp^.resultCode=200 then
+ if Netlib_HttpResult(resp)=200 then
begin
- StrDup(result,resp.pData,resp.dataLength);
+ pBuf := Netlib_HttpBuffer(resp,bufLen);
+ StrDup(result,pBuf,bufLen);
end
else
begin
- result:=PAnsiChar(int_ptr(resp^.resultCode and $0FFF));
+ result:=PAnsiChar(int_ptr(Netlib_HttpResult(resp) and $0FFF));
end;
Netlib_FreeHttpRequest(resp);
end;
@@ -464,9 +467,10 @@ function GetFile(url:PAnsiChar; save_file:PAnsiChar; hNetLib:THANDLE=0; recurse_
var
nlu:TNETLIBUSER;
req :TNETLIBHTTPREQUEST;
- resp:PNETLIBHTTPREQUEST;
+ resp:THANDLE;
hSaveFile:THANDLE;
- i:integer;
+ retCode, bufLen:integer;
+ pBuf:PAnsiChar;
begin
result:=false;
if recurse_count>MAX_REDIRECT_RECURSE then
@@ -477,8 +481,7 @@ begin
FillChar(req,SizeOf(req),0);
req.requestType:=REQUEST_GET;
req.szUrl :=url;
- req.flags :=NLHRF_NODUMP;
-
+ req.flags :=NLHRF_NODUMP or NLHRF_REDIRECT;
FillChar(nlu,SizeOf(nlu),0);
if hNetLib=0 then
@@ -489,29 +492,19 @@ begin
end;
resp:=Netlib_HttpTransaction(hNetLib,@req);
- if resp<>nil then
+ if resp<>0 then
begin
- if resp^.resultCode=200 then
+ retCode:=Netlib_HttpResult(resp);
+ if retCode=200 then
begin
hSaveFile:=Rewrite(save_file);
if hSaveFile<>THANDLE(INVALID_HANDLE_VALUE) then
begin
- BlockWrite(hSaveFile,resp^.pData^,resp^.dataLength);
+ pBuf := Netlib_HttpBuffer(resp,bufLen);
+ BlockWrite(hSaveFile,pBuf^,bufLen);
CloseHandle(hSaveFile);
result:=true;
end
- end
- else if (resp.resultCode>=300) and (resp.resultCode<400) then
- begin
- // get new location
- for i:=0 to resp^.headersCount-1 do
- begin
- if StrCmp(resp^.headers^[i].szName,'Location')=0 then
- begin
- result:=GetFile(resp^.headers^[i].szValue,save_file,hNetLib,recurse_count+1);
- break;
- end
- end;
end;
Netlib_FreeHttpRequest(resp);
@@ -583,8 +576,9 @@ function LoadImageURL(url:PAnsiChar;size:integer=0):HBITMAP;
var
nlu:TNETLIBUSER;
req :TNETLIBHTTPREQUEST;
- resp:PNETLIBHTTPREQUEST;
- hNetLib:THANDLE;
+ resp,hNetLib:THANDLE;
+ bufLen:integer;
+ pBuf:PAnsiChar;
begin
result:=0;
if (url=nil) or (url^=#0) then
@@ -601,10 +595,13 @@ begin
hNetLib:=Netlib_RegisterUser(@nlu);
resp:=Netlib_HttpTransaction(hNetLib,@req);
- if resp<>nil then
+ if resp<>0 then
begin
- if resp^.resultCode=200 then
- result := Image_LoadFromMem(resp.pData, resp.dataLength, FIF_JPEG);
+ if Netlib_HttpResult(resp)=200 then
+ begin
+ pBuf := Netlib_HttpBuffer(resp,bufLen);
+ result := Image_LoadFromMem(pBuf, bufLen, FIF_JPEG);
+ end;
Netlib_FreeHttpRequest(resp);
end;
diff --git a/plugins/Watrack/myshows/i_cookies.inc b/plugins/Watrack/myshows/i_cookies.inc
index cd01ef6621..82c12f3b3d 100644
--- a/plugins/Watrack/myshows/i_cookies.inc
+++ b/plugins/Watrack/myshows/i_cookies.inc
@@ -2,46 +2,14 @@
const
cookies:pAnsiChar=nil;
-function ExtractCookies(resp:PNETLIBHTTPREQUEST):integer;
-var
- cnt,len:integer;
- p,pc:pAnsiChar;
-begin
- result:=0;
-
- mFreeMem(cookies);
- mGetMem(cookies,1024);
-
- pc:=cookies;
- for cnt:=0 to resp^.headersCount-1 do
- begin
- with resp^.headers[cnt] do
- if StrCmp(szName,'Set-Cookie')=0 then
- begin
- len:=0;
- p:=szValue;
- while (p^<>#0) and (p^<>';') do
- begin
- inc(p);
- inc(len);
- end;
- if pc<>cookies then
- begin
- pc^:=';'; inc(pc);
- pc^:=' '; inc(pc);
- end;
- pc:=StrCopyE(pc,szValue,len);
- inc(result);
- end;
- end;
-end;
-
function SendRequestCookies(url:PAnsiChar;useCookies:boolean):pAnsiChar;
var
nlu:TNETLIBUSER;
req :TNETLIBHTTPREQUEST;
- resp:PNETLIBHTTPREQUEST;
+ resp:THANDLE;
hTmpNetLib:THANDLE;
+ bufLen:int;
+ pBuf:PAnsiChar;
nlh:array [0..10] of TNETLIBHTTPHEADER;
begin
result:=nil;
@@ -66,20 +34,21 @@ begin
hTmpNetLib:=Netlib_RegisterUser(@nlu);
resp:=Netlib_HttpTransaction(hTmpNetLib,@req);
- if resp<>nil then
+ if resp<>0 then
begin
- if resp^.resultCode=200 then
+ if Netlib_HttpResult(resp)=200 then
begin
- if resp.pData<>nil then
- StrDup(result,resp.pData,resp.dataLength)
+ pBuf := Netlib_HttpBuffer(resp,bufLen);
+ if pBuf<>nil then
+ StrDup(result,pBuf,bufLen)
else
result:=PAnsiChar(200);
if not useCookies then
- ExtractCookies(resp);
+ cookies := Netlib_HttpCookies(resp);
end
else
begin
- result:=pAnsiChar(int_ptr(resp^.resultCode and $0FFF));
+ result:=pAnsiChar(int_ptr(Netlib_HttpResult(resp) and $0FFF));
end;
Netlib_FreeHttpRequest(resp);
end;
diff --git a/plugins/Watrack/myshows/i_myshows_api.inc b/plugins/Watrack/myshows/i_myshows_api.inc
index f92df86b50..828fb5c650 100644
--- a/plugins/Watrack/myshows/i_myshows_api.inc
+++ b/plugins/Watrack/myshows/i_myshows_api.inc
@@ -88,7 +88,6 @@ begin
StrReplace(request,'<password>',buf);
res:=SendRequestCookies(request,false);
-// res:=SendRequest(request,REQUEST_GET);
if res<>nil then
begin
if uint_ptr(res)<$0FFF then
diff --git a/protocols/Discord/src/gateway.cpp b/protocols/Discord/src/gateway.cpp
index 543020f105..e76de2848a 100644
--- a/protocols/Discord/src/gateway.cpp
+++ b/protocols/Discord/src/gateway.cpp
@@ -61,12 +61,7 @@ bool CDiscordProto::GatewayThreadWorker()
return false;
}
- if (auto *pszNewCookie = Netlib_GetHeader(pReply, "Set-Cookie")) {
- char *p = strchr(pszNewCookie, ';');
- if (p) *p = 0;
-
- m_szWSCookie = pszNewCookie;
- }
+ m_szWSCookie = pReply->GetCookies();
if (pReply->resultCode != 101) {
// if there's no cookie & Miranda is bounced with error 404, simply apply the cookie and try again
diff --git a/protocols/Discord/src/server.cpp b/protocols/Discord/src/server.cpp
index 243e80d2b2..1ef3517822 100644
--- a/protocols/Discord/src/server.cpp
+++ b/protocols/Discord/src/server.cpp
@@ -165,18 +165,7 @@ void CDiscordProto::OnReceiveMyInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*
m_wszEmail = data["email"].as_mstring();
m_ownId = id;
-
- m_szCookie.Empty();
- for (int i=0; i < pReply->headersCount; i++) {
- if (!mir_strcmpi(pReply->headers[i].szName, "Set-Cookie")) {
- char *p = strchr(pReply->headers[i].szValue, ';');
- if (p) *p = 0;
- if (!m_szCookie.IsEmpty())
- m_szCookie.Append("; ");
-
- m_szCookie.Append(pReply->headers[i].szValue);
- }
- }
+ m_szCookie = pReply->GetCookies();
// launch gateway thread
if (m_szGateway.IsEmpty())
diff --git a/protocols/ICQ-WIM/src/mra.cpp b/protocols/ICQ-WIM/src/mra.cpp
index cfe427a136..b65ae238dc 100644
--- a/protocols/ICQ-WIM/src/mra.cpp
+++ b/protocols/ICQ-WIM/src/mra.cpp
@@ -19,18 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
void CIcqProto::SendMrimLogin(NETLIBHTTPREQUEST *pReply)
{
- if (pReply) {
- for (int i=0; i < pReply->headersCount; i++) {
- if (!mir_strcmpi(pReply->headers[i].szName, "Set-Cookie")) {
- char *p = strchr(pReply->headers[i].szValue, ';');
- if (p) *p = 0;
- if (!m_szMraCookie.IsEmpty())
- m_szMraCookie.Append("; ");
-
- m_szMraCookie.Append(pReply->headers[i].szValue);
- }
- }
- }
+ m_szMraCookie = pReply->GetCookies();
auto *pReq = new AsyncHttpRequest(CONN_NONE, REQUEST_POST, "https://icqapilogin.mail.ru/auth/mrimLogin", &CIcqProto::OnCheckMrimLogin);
pReq->AddHeader("User-Agent", NETLIB_USER_AGENT);
diff --git a/protocols/Tox/src/http_request.h b/protocols/Tox/src/http_request.h
index d51aab289f..bba9f0591c 100644
--- a/protocols/Tox/src/http_request.h
+++ b/protocols/Tox/src/http_request.h
@@ -24,7 +24,6 @@ private:
void Init(int type)
{
- cbSize = sizeof(NETLIBHTTPREQUEST);
requestType = type;
flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMPSEND | NLHRF_DUMPASTEXT;
szUrl = nullptr;
diff --git a/src/mir_app/src/mir_app.def b/src/mir_app/src/mir_app.def
index 68914f96b2..bb3a1dec8e 100644
--- a/src/mir_app/src/mir_app.def
+++ b/src/mir_app/src/mir_app.def
@@ -919,3 +919,10 @@ _CallContactService@20 @1048 NONAME
??0MDatabaseExport@@QAE@XZ @1049 NONAME
??1MDatabaseExport@@UAE@XZ @1050 NONAME
??_7MDatabaseExport@@6B@ @1051 NONAME
+??4NETLIBHTTPREQUEST@@QAEAAU0@$$QAU0@@Z @1052 NONAME
+??4NETLIBHTTPREQUEST@@QAEAAU0@ABU0@@Z @1053 NONAME
+??ANETLIBHTTPREQUEST@@QAEPBDPBD@Z @1054 NONAME
+?GetCookies@NETLIBHTTPREQUEST@@QBE?AV?$CMStringT@DV?$ChTraitsCRT@D@@@@XZ @1055 NONAME
+Netlib_HttpBuffer @1056
+Netlib_HttpCookies @1057
+Netlib_HttpResult @1058
diff --git a/src/mir_app/src/mir_app64.def b/src/mir_app/src/mir_app64.def
index b3aa1095b9..26f860b889 100644
--- a/src/mir_app/src/mir_app64.def
+++ b/src/mir_app/src/mir_app64.def
@@ -919,3 +919,10 @@ CallContactService @1042 NONAME
??0MDatabaseExport@@QEAA@XZ @1043 NONAME
??1MDatabaseExport@@UEAA@XZ @1044 NONAME
??_7MDatabaseExport@@6B@ @1045 NONAME
+??4NETLIBHTTPREQUEST@@QEAAAEAU0@$$QEAU0@@Z @1046 NONAME
+??4NETLIBHTTPREQUEST@@QEAAAEAU0@AEBU0@@Z @1047 NONAME
+??ANETLIBHTTPREQUEST@@QEAAPEBDPEBD@Z @1048 NONAME
+?GetCookies@NETLIBHTTPREQUEST@@QEBA?AV?$CMStringT@DV?$ChTraitsCRT@D@@@@XZ @1049 NONAME
+Netlib_HttpBuffer @1050
+Netlib_HttpCookies @1051
+Netlib_HttpResult @1052
diff --git a/src/mir_app/src/netlib.h b/src/mir_app/src/netlib.h
index d5ddb6687b..1ce7394cfb 100644
--- a/src/mir_app/src/netlib.h
+++ b/src/mir_app/src/netlib.h
@@ -166,7 +166,6 @@ bool BindSocketToPort(const char *szPorts, SOCKET s, SOCKET s6, int* portn);
void NetlibHttpSetLastErrorUsingHttpResult(int result);
int Netlib_SendHttpRequest(HNETLIBCONN hConnection, NETLIBHTTPREQUEST *pRec);
-NETLIBHTTPREQUEST* Netlib_RecvHttpHeaders(NetlibConnection *hConnection, int flags = 0);
NETLIBHTTPREQUEST* NetlibHttpRecv(NetlibConnection *nlc, uint32_t hflags, uint32_t dflags, bool isConnect = false);
// netliblog.cpp
diff --git a/src/mir_app/src/netlib_http.cpp b/src/mir_app/src/netlib_http.cpp
index 6845435d34..9e8e6759cb 100644
--- a/src/mir_app/src/netlib_http.cpp
+++ b/src/mir_app/src/netlib_http.cpp
@@ -79,6 +79,66 @@ struct ProxyAuthList : OBJLIST<ProxyAuth>
ProxyAuthList proxyAuthList;
+/////////////////////////////////////////////////////////////////////////////////////////
+// Module exports
+
+MIR_APP_DLL(bool) Netlib_FreeHttpRequest(NETLIBHTTPREQUEST *nlhr)
+{
+ if (nlhr == nullptr || nlhr->requestType != REQUEST_RESPONSE) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+
+ if (nlhr->headers) {
+ for (int i = 0; i < nlhr->headersCount; i++) {
+ NETLIBHTTPHEADER &p = nlhr->headers[i];
+ mir_free(p.szName);
+ mir_free(p.szValue);
+ }
+ mir_free(nlhr->headers);
+ }
+ mir_free(nlhr->pData);
+ mir_free(nlhr->szResultDescr);
+ mir_free(nlhr->szUrl);
+ mir_free(nlhr);
+ return true;
+}
+
+MIR_APP_DLL(char*) Netlib_GetHeader(const NETLIBHTTPREQUEST *nlhr, const char *hdr)
+{
+ if (nlhr == nullptr || hdr == nullptr)
+ return nullptr;
+
+ for (int i = 0; i < nlhr->headersCount; i++) {
+ NETLIBHTTPHEADER &p = nlhr->headers[i];
+ if (_stricmp(p.szName, hdr) == 0)
+ return p.szValue;
+ }
+
+ return nullptr;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CMStringA NETLIBHTTPREQUEST::GetCookies() const
+{
+ CMStringA ret;
+
+ for (int i = 0; i < headersCount; i++) {
+ if (!mir_strcmpi(headers[i].szName, "Set-Cookie")) {
+ char *p = strchr(headers[i].szValue, ';');
+ if (p) *p = 0;
+ if (!ret.IsEmpty())
+ ret.Append("; ");
+
+ ret.Append(headers[i].szValue);
+ }
+ }
+ return ret;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
static int RecvWithTimeoutTime(NetlibConnection *nlc, int dwTimeoutTime, char *buf, int len, int flags)
{
int dwTimeNow;
@@ -105,20 +165,6 @@ static int RecvWithTimeoutTime(NetlibConnection *nlc, int dwTimeoutTime, char *b
return Netlib_Recv(nlc, buf, len, flags);
}
-MIR_APP_DLL(char *) Netlib_GetHeader(const NETLIBHTTPREQUEST *nlhr, const char *hdr)
-{
- if (nlhr == nullptr || hdr == nullptr)
- return nullptr;
-
- for (int i=0; i < nlhr->headersCount; i++) {
- NETLIBHTTPHEADER &p = nlhr->headers[i];
- if (_stricmp(p.szName, hdr) == 0)
- return p.szValue;
- }
-
- return nullptr;
-}
-
static char* NetlibHttpFindAuthHeader(NETLIBHTTPREQUEST *nlhrReply, const char *hdr, const char *szProvider)
{
char *szBasicHdr = nullptr;
@@ -145,7 +191,7 @@ static char* NetlibHttpFindAuthHeader(NETLIBHTTPREQUEST *nlhrReply, const char *
/////////////////////////////////////////////////////////////////////////////////////////
-void NetlibConnFromUrl(const char *szUrl, bool secur, NetlibUrl &url)
+static void NetlibConnFromUrl(const char *szUrl, bool secur, NetlibUrl &url)
{
secur = secur || _strnicmp(szUrl, "https", 5) == 0;
@@ -369,6 +415,120 @@ static int SendHttpRequestAndData(NetlibConnection *nlc, CMStringA &httpRequest,
}
/////////////////////////////////////////////////////////////////////////////////////////
+// Receives HTTP headers
+//
+// Returns a pointer to a NETLIBHTTPREQUEST structure on success, NULL on failure.
+// Call Netlib_FreeHttpRequest() to free this.
+// hConnection must have been returned by MS_NETLIB_OPENCONNECTION
+// nlhr->pData = NULL and nlhr->dataLength = 0 always. The requested data should
+// be retrieved using MS_NETLIB_RECV once the header has been parsed.
+// If the headers haven't finished within 60 seconds the function returns NULL
+// and ERROR_TIMEOUT.
+// Errors: ERROR_INVALID_PARAMETER, any from MS_NETLIB_RECV or select()
+// ERROR_HANDLE_EOF (connection closed before headers complete)
+// ERROR_TIMEOUT (headers still not complete after 60 seconds)
+// ERROR_BAD_FORMAT (invalid character or line ending in headers, or first line is blank)
+// ERROR_BUFFER_OVERFLOW (each header line must be less than 4096 chars long)
+// ERROR_INVALID_DATA (first header line is malformed ("http/[01].[0-9] [0-9]+ .*", or no colon in subsequent line)
+
+#define NHRV_BUF_SIZE 8192
+
+static NETLIBHTTPREQUEST* Netlib_RecvHttpHeaders(HNETLIBCONN hConnection, int flags)
+{
+ NetlibConnection *nlc = (NetlibConnection *)hConnection;
+ if (!NetlibEnterNestedCS(nlc, NLNCS_RECV))
+ return nullptr;
+
+ uint32_t dwRequestTimeoutTime = GetTickCount() + HTTPRECVDATATIMEOUT;
+ NETLIBHTTPREQUEST *nlhr = (NETLIBHTTPREQUEST *)mir_calloc(sizeof(NETLIBHTTPREQUEST));
+ nlhr->nlc = nlc; // Needed to id connection in the protocol HTTP gateway wrapper functions
+ nlhr->requestType = REQUEST_RESPONSE;
+
+ int firstLineLength = 0;
+ if (!HttpPeekFirstResponseLine(nlc, dwRequestTimeoutTime, flags | MSG_PEEK, &nlhr->resultCode, &nlhr->szResultDescr, &firstLineLength)) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ Netlib_FreeHttpRequest(nlhr);
+ return nullptr;
+ }
+
+ char *buffer = (char *)_alloca(NHRV_BUF_SIZE + 1);
+ int bytesPeeked = Netlib_Recv(nlc, buffer, min(firstLineLength, NHRV_BUF_SIZE), flags | MSG_DUMPASTEXT);
+ if (bytesPeeked != firstLineLength) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ Netlib_FreeHttpRequest(nlhr);
+ if (bytesPeeked != SOCKET_ERROR)
+ SetLastError(ERROR_HANDLE_EOF);
+ return nullptr;
+ }
+
+ // Make sure all headers arrived
+ MBinBuffer buf;
+ int headersCount = 0;
+ bytesPeeked = 0;
+ for (bool headersCompleted = false; !headersCompleted;) {
+ bytesPeeked = RecvWithTimeoutTime(nlc, dwRequestTimeoutTime, buffer, NHRV_BUF_SIZE, flags | MSG_DUMPASTEXT | MSG_NOTITLE);
+ if (bytesPeeked == 0)
+ break;
+
+ if (bytesPeeked == SOCKET_ERROR) {
+ bytesPeeked = 0;
+ break;
+ }
+
+ buf.append(buffer, bytesPeeked);
+
+ headersCount = 0;
+ for (char *pbuffer = (char *)buf.data();; headersCount++) {
+ char *peol = strchr(pbuffer, '\n');
+ if (peol == nullptr) break;
+ if (peol == pbuffer || (peol == (pbuffer + 1) && *pbuffer == '\r')) {
+ bytesPeeked = peol - (char *)buf.data() + 1;
+ headersCompleted = true;
+ break;
+ }
+ pbuffer = peol + 1;
+ }
+ }
+
+ if (bytesPeeked <= 0) {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ Netlib_FreeHttpRequest(nlhr);
+ return nullptr;
+ }
+
+ // Receive headers
+ nlhr->headersCount = headersCount;
+ nlhr->headers = (NETLIBHTTPHEADER *)mir_calloc(sizeof(NETLIBHTTPHEADER) * headersCount);
+
+ headersCount = 0;
+ for (char *pbuffer = (char *)buf.data();; headersCount++) {
+ char *peol = strchr(pbuffer, '\n');
+ if (peol == nullptr || peol == pbuffer || (peol == (pbuffer + 1) && *pbuffer == '\r'))
+ break;
+ *peol = 0;
+
+ char *pColon = strchr(pbuffer, ':');
+ if (pColon == nullptr) {
+ Netlib_FreeHttpRequest(nlhr); nlhr = nullptr;
+ SetLastError(ERROR_INVALID_DATA);
+ break;
+ }
+
+ *pColon = 0;
+ nlhr->headers[headersCount].szName = mir_strdup(rtrim(pbuffer));
+ nlhr->headers[headersCount].szValue = mir_strdup(lrtrimp(pColon + 1));
+ pbuffer = peol + 1;
+ }
+
+ // remove processed data
+ buf.remove(bytesPeeked);
+ nlc->foreBuf.appendBefore(buf.data(), buf.length());
+
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ return nlhr;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
// Sends a HTTP request over a connection
//
// Returns number of bytes sent on success, SOCKET_ERROR on failure
@@ -699,228 +859,6 @@ int Netlib_SendHttpRequest(HNETLIBCONN nlc, NETLIBHTTPREQUEST *nlhr)
return bytesSent;
}
-MIR_APP_DLL(bool) Netlib_FreeHttpRequest(NETLIBHTTPREQUEST *nlhr)
-{
- if (nlhr == nullptr || nlhr->requestType != REQUEST_RESPONSE) {
- SetLastError(ERROR_INVALID_PARAMETER);
- return false;
- }
-
- if (nlhr->headers) {
- for (int i = 0; i < nlhr->headersCount; i++) {
- NETLIBHTTPHEADER &p = nlhr->headers[i];
- mir_free(p.szName);
- mir_free(p.szValue);
- }
- mir_free(nlhr->headers);
- }
- mir_free(nlhr->pData);
- mir_free(nlhr->szResultDescr);
- mir_free(nlhr->szUrl);
- mir_free(nlhr);
- return true;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Receives HTTP headers
-//
-// Returns a pointer to a NETLIBHTTPREQUEST structure on success, NULL on failure.
-// Call Netlib_FreeHttpRequest() to free this.
-// hConnection must have been returned by MS_NETLIB_OPENCONNECTION
-// nlhr->pData = NULL and nlhr->dataLength = 0 always. The requested data should
-// be retrieved using MS_NETLIB_RECV once the header has been parsed.
-// If the headers haven't finished within 60 seconds the function returns NULL
-// and ERROR_TIMEOUT.
-// Errors: ERROR_INVALID_PARAMETER, any from MS_NETLIB_RECV or select()
-// ERROR_HANDLE_EOF (connection closed before headers complete)
-// ERROR_TIMEOUT (headers still not complete after 60 seconds)
-// ERROR_BAD_FORMAT (invalid character or line ending in headers, or first line is blank)
-// ERROR_BUFFER_OVERFLOW (each header line must be less than 4096 chars long)
-// ERROR_INVALID_DATA (first header line is malformed ("http/[01].[0-9] [0-9]+ .*", or no colon in subsequent line)
-
-#define NHRV_BUF_SIZE 8192
-
-NETLIBHTTPREQUEST* Netlib_RecvHttpHeaders(HNETLIBCONN hConnection, int flags)
-{
- NetlibConnection *nlc = (NetlibConnection*)hConnection;
- if (!NetlibEnterNestedCS(nlc, NLNCS_RECV))
- return nullptr;
-
- uint32_t dwRequestTimeoutTime = GetTickCount() + HTTPRECVDATATIMEOUT;
- NETLIBHTTPREQUEST *nlhr = (NETLIBHTTPREQUEST*)mir_calloc(sizeof(NETLIBHTTPREQUEST));
- nlhr->nlc = nlc; // Needed to id connection in the protocol HTTP gateway wrapper functions
- nlhr->requestType = REQUEST_RESPONSE;
-
- int firstLineLength = 0;
- if (!HttpPeekFirstResponseLine(nlc, dwRequestTimeoutTime, flags | MSG_PEEK, &nlhr->resultCode, &nlhr->szResultDescr, &firstLineLength)) {
- NetlibLeaveNestedCS(&nlc->ncsRecv);
- Netlib_FreeHttpRequest(nlhr);
- return nullptr;
- }
-
- char *buffer = (char*)_alloca(NHRV_BUF_SIZE + 1);
- int bytesPeeked = Netlib_Recv(nlc, buffer, min(firstLineLength, NHRV_BUF_SIZE), flags | MSG_DUMPASTEXT);
- if (bytesPeeked != firstLineLength) {
- NetlibLeaveNestedCS(&nlc->ncsRecv);
- Netlib_FreeHttpRequest(nlhr);
- if (bytesPeeked != SOCKET_ERROR)
- SetLastError(ERROR_HANDLE_EOF);
- return nullptr;
- }
-
- // Make sure all headers arrived
- MBinBuffer buf;
- int headersCount = 0;
- bytesPeeked = 0;
- for (bool headersCompleted = false; !headersCompleted;) {
- bytesPeeked = RecvWithTimeoutTime(nlc, dwRequestTimeoutTime, buffer, NHRV_BUF_SIZE, flags | MSG_DUMPASTEXT | MSG_NOTITLE);
- if (bytesPeeked == 0)
- break;
-
- if (bytesPeeked == SOCKET_ERROR) {
- bytesPeeked = 0;
- break;
- }
-
- buf.append(buffer, bytesPeeked);
-
- headersCount = 0;
- for (char *pbuffer = (char*)buf.data();; headersCount++) {
- char *peol = strchr(pbuffer, '\n');
- if (peol == nullptr) break;
- if (peol == pbuffer || (peol == (pbuffer + 1) && *pbuffer == '\r')) {
- bytesPeeked = peol - (char*)buf.data() + 1;
- headersCompleted = true;
- break;
- }
- pbuffer = peol + 1;
- }
- }
-
- if (bytesPeeked <= 0) {
- NetlibLeaveNestedCS(&nlc->ncsRecv);
- Netlib_FreeHttpRequest(nlhr);
- return nullptr;
- }
-
- // Receive headers
- nlhr->headersCount = headersCount;
- nlhr->headers = (NETLIBHTTPHEADER*)mir_calloc(sizeof(NETLIBHTTPHEADER) * headersCount);
-
- headersCount = 0;
- for (char *pbuffer = (char*)buf.data();; headersCount++) {
- char *peol = strchr(pbuffer, '\n');
- if (peol == nullptr || peol == pbuffer || (peol == (pbuffer+1) && *pbuffer == '\r'))
- break;
- *peol = 0;
-
- char *pColon = strchr(pbuffer, ':');
- if (pColon == nullptr) {
- Netlib_FreeHttpRequest(nlhr); nlhr = nullptr;
- SetLastError(ERROR_INVALID_DATA);
- break;
- }
-
- *pColon = 0;
- nlhr->headers[headersCount].szName = mir_strdup(rtrim(pbuffer));
- nlhr->headers[headersCount].szValue = mir_strdup(lrtrimp(pColon+1));
- pbuffer = peol + 1;
- }
-
- // remove processed data
- buf.remove(bytesPeeked);
- nlc->foreBuf.appendBefore(buf.data(), buf.length());
-
- NetlibLeaveNestedCS(&nlc->ncsRecv);
- return nlhr;
-}
-
-MIR_APP_DLL(NETLIBHTTPREQUEST*) Netlib_HttpTransaction(HNETLIBUSER nlu, NETLIBHTTPREQUEST *nlhr)
-{
- if (GetNetlibHandleType(nlu) != NLH_USER || !(nlu->user.flags & NUF_OUTGOING) || !nlhr || !nlhr->szUrl || nlhr->szUrl[0] == 0) {
- SetLastError(ERROR_INVALID_PARAMETER);
- return nullptr;
- }
-
- if (nlhr->nlc != nullptr && GetNetlibHandleType(nlhr->nlc) != NLH_CONNECTION)
- nlhr->nlc = nullptr;
-
- NetlibConnection *nlc = NetlibHttpProcessUrl(nlhr, nlu, (NetlibConnection*)nlhr->nlc);
- if (nlc == nullptr)
- return nullptr;
-
- NETLIBHTTPREQUEST nlhrSend = *nlhr;
- nlhrSend.flags |= NLHRF_SMARTREMOVEHOST;
-
- bool doneUserAgentHeader = Netlib_GetHeader(nlhr, "User-Agent") != nullptr;
- bool doneAcceptEncoding = Netlib_GetHeader(nlhr, "Accept-Encoding") != nullptr;
- if (!doneUserAgentHeader || !doneAcceptEncoding) {
- nlhrSend.headers = (NETLIBHTTPHEADER*)mir_alloc(sizeof(NETLIBHTTPHEADER) * (nlhrSend.headersCount + 2));
- memcpy(nlhrSend.headers, nlhr->headers, sizeof(NETLIBHTTPHEADER) * nlhr->headersCount);
- }
-
- char szUserAgent[64];
- if (!doneUserAgentHeader) {
- nlhrSend.headers[nlhrSend.headersCount].szName = "User-Agent";
- nlhrSend.headers[nlhrSend.headersCount].szValue = szUserAgent;
- ++nlhrSend.headersCount;
-
- char szMirandaVer[64];
- strncpy_s(szMirandaVer, MIRANDA_VERSION_STRING, _TRUNCATE);
- #if defined(_WIN64)
- strncat_s(szMirandaVer, " x64", _TRUNCATE);
- #endif
-
- char *pspace = strchr(szMirandaVer, ' ');
- if (pspace) {
- *pspace++ = '\0';
- mir_snprintf(szUserAgent, "Miranda/%s (%s)", szMirandaVer, pspace);
- }
- else mir_snprintf(szUserAgent, "Miranda/%s", szMirandaVer);
- }
- if (!doneAcceptEncoding) {
- nlhrSend.headers[nlhrSend.headersCount].szName = "Accept-Encoding";
- nlhrSend.headers[nlhrSend.headersCount].szValue = "deflate, gzip";
- ++nlhrSend.headersCount;
- }
- if (Netlib_SendHttpRequest(nlc, &nlhrSend) == SOCKET_ERROR) {
- if (!doneUserAgentHeader || !doneAcceptEncoding) mir_free(nlhrSend.headers);
- nlhr->resultCode = nlhrSend.resultCode;
- Netlib_CloseHandle(nlc);
- return nullptr;
- }
- if (!doneUserAgentHeader || !doneAcceptEncoding)
- mir_free(nlhrSend.headers);
-
- uint32_t dflags = (nlhr->flags & NLHRF_DUMPASTEXT ? MSG_DUMPASTEXT : 0) |
- (nlhr->flags & NLHRF_NODUMP ? MSG_NODUMP : (nlhr->flags & NLHRF_DUMPPROXY ? MSG_DUMPPROXY : 0)) |
- (nlhr->flags & NLHRF_NOPROXY ? MSG_RAW : 0);
-
- uint32_t hflags =
- (nlhr->flags & NLHRF_NODUMP ? MSG_NODUMP : (nlhr->flags & NLHRF_DUMPPROXY ? MSG_DUMPPROXY : 0)) |
- (nlhr->flags & NLHRF_NOPROXY ? MSG_RAW : 0);
-
- NETLIBHTTPREQUEST *nlhrReply;
- if (nlhr->requestType == REQUEST_HEAD)
- nlhrReply = Netlib_RecvHttpHeaders(nlc);
- else
- nlhrReply = NetlibHttpRecv(nlc, hflags, dflags);
-
- if (nlhrReply) {
- nlhrReply->szUrl = nlc->szNewUrl;
- nlc->szNewUrl = nullptr;
- }
-
- if ((nlhr->flags & NLHRF_PERSISTENT) == 0 || nlhrReply == nullptr) {
- Netlib_CloseHandle(nlc);
- if (nlhrReply)
- nlhrReply->nlc = nullptr;
- }
- else nlhrReply->nlc = nlc;
-
- return nlhrReply;
-}
-
void NetlibHttpSetLastErrorUsingHttpResult(int result)
{
if (result >= 200 && result < 300) {
@@ -941,7 +879,7 @@ void NetlibHttpSetLastErrorUsingHttpResult(int result)
}
}
-char* gzip_decode(char *gzip_data, int *len_ptr, int window)
+static char* gzip_decode(char *gzip_data, int *len_ptr, int window)
{
if (*len_ptr == 0) return nullptr;
@@ -1176,3 +1114,114 @@ next:
return nlhrReply;
}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Module entry point
+
+MIR_APP_DLL(NETLIBHTTPREQUEST *) Netlib_HttpTransaction(HNETLIBUSER nlu, NETLIBHTTPREQUEST *nlhr)
+{
+ if (GetNetlibHandleType(nlu) != NLH_USER || !(nlu->user.flags & NUF_OUTGOING) || !nlhr || !nlhr->szUrl || nlhr->szUrl[0] == 0) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return nullptr;
+ }
+
+ if (nlhr->nlc != nullptr && GetNetlibHandleType(nlhr->nlc) != NLH_CONNECTION)
+ nlhr->nlc = nullptr;
+
+ NetlibConnection *nlc = NetlibHttpProcessUrl(nlhr, nlu, (NetlibConnection *)nlhr->nlc);
+ if (nlc == nullptr)
+ return nullptr;
+
+ NETLIBHTTPREQUEST nlhrSend = *nlhr;
+ nlhrSend.flags |= NLHRF_SMARTREMOVEHOST;
+
+ bool doneUserAgentHeader = Netlib_GetHeader(nlhr, "User-Agent") != nullptr;
+ bool doneAcceptEncoding = Netlib_GetHeader(nlhr, "Accept-Encoding") != nullptr;
+ if (!doneUserAgentHeader || !doneAcceptEncoding) {
+ nlhrSend.headers = (NETLIBHTTPHEADER *)mir_alloc(sizeof(NETLIBHTTPHEADER) * (nlhrSend.headersCount + 2));
+ memcpy(nlhrSend.headers, nlhr->headers, sizeof(NETLIBHTTPHEADER) * nlhr->headersCount);
+ }
+
+ char szUserAgent[64];
+ if (!doneUserAgentHeader) {
+ nlhrSend.headers[nlhrSend.headersCount].szName = "User-Agent";
+ nlhrSend.headers[nlhrSend.headersCount].szValue = szUserAgent;
+ ++nlhrSend.headersCount;
+
+ char szMirandaVer[64];
+ strncpy_s(szMirandaVer, MIRANDA_VERSION_STRING, _TRUNCATE);
+ #if defined(_WIN64)
+ strncat_s(szMirandaVer, " x64", _TRUNCATE);
+ #endif
+
+ char *pspace = strchr(szMirandaVer, ' ');
+ if (pspace) {
+ *pspace++ = '\0';
+ mir_snprintf(szUserAgent, "Miranda/%s (%s)", szMirandaVer, pspace);
+ }
+ else mir_snprintf(szUserAgent, "Miranda/%s", szMirandaVer);
+ }
+ if (!doneAcceptEncoding) {
+ nlhrSend.headers[nlhrSend.headersCount].szName = "Accept-Encoding";
+ nlhrSend.headers[nlhrSend.headersCount].szValue = "deflate, gzip";
+ ++nlhrSend.headersCount;
+ }
+ if (Netlib_SendHttpRequest(nlc, &nlhrSend) == SOCKET_ERROR) {
+ if (!doneUserAgentHeader || !doneAcceptEncoding) mir_free(nlhrSend.headers);
+ nlhr->resultCode = nlhrSend.resultCode;
+ Netlib_CloseHandle(nlc);
+ return nullptr;
+ }
+ if (!doneUserAgentHeader || !doneAcceptEncoding)
+ mir_free(nlhrSend.headers);
+
+ uint32_t dflags = (nlhr->flags & NLHRF_DUMPASTEXT ? MSG_DUMPASTEXT : 0) |
+ (nlhr->flags & NLHRF_NODUMP ? MSG_NODUMP : (nlhr->flags & NLHRF_DUMPPROXY ? MSG_DUMPPROXY : 0)) |
+ (nlhr->flags & NLHRF_NOPROXY ? MSG_RAW : 0);
+
+ uint32_t hflags =
+ (nlhr->flags & NLHRF_NODUMP ? MSG_NODUMP : (nlhr->flags & NLHRF_DUMPPROXY ? MSG_DUMPPROXY : 0)) |
+ (nlhr->flags & NLHRF_NOPROXY ? MSG_RAW : 0);
+
+ NETLIBHTTPREQUEST *nlhrReply;
+ if (nlhr->requestType == REQUEST_HEAD)
+ nlhrReply = Netlib_RecvHttpHeaders(nlc, 0);
+ else
+ nlhrReply = NetlibHttpRecv(nlc, hflags, dflags);
+
+ if (nlhrReply) {
+ nlhrReply->szUrl = nlc->szNewUrl;
+ nlc->szNewUrl = nullptr;
+ }
+
+ if ((nlhr->flags & NLHRF_PERSISTENT) == 0 || nlhrReply == nullptr) {
+ Netlib_CloseHandle(nlc);
+ if (nlhrReply)
+ nlhrReply->nlc = nullptr;
+ }
+ else nlhrReply->nlc = nlc;
+
+ return nlhrReply;
+}
+
+EXTERN_C MIR_APP_DLL(int) Netlib_HttpResult(NETLIBHTTPREQUEST *nlhr)
+{
+ return (nlhr) ? nlhr->resultCode : 500;
+}
+
+EXTERN_C MIR_APP_DLL(char *) Netlib_HttpBuffer(NETLIBHTTPREQUEST *nlhr, int &cbLen)
+{
+ if (!nlhr)
+ return nullptr;
+
+ cbLen = nlhr->dataLength;
+ return nlhr->pData;
+}
+
+EXTERN_C MIR_APP_DLL(char *) Netlib_HttpCookies(NETLIBHTTPREQUEST *nlhr)
+{
+ if (!nlhr)
+ return nullptr;
+
+ return nlhr->GetCookies().Detach();
+}