Files
common/Global/HttpThread.cpp
T
2026-06-12 23:18:12 +08:00

589 lines
15 KiB
C++

//---------------------------------------------------------------------------
#include <vcl.h>
#include <Wininet.h>
#include <tchar.h>
#include <stdio.h>
#include <vector>
//#include <System.DateUtils.hpp>
#pragma hdrstop
#include "HttpThread.h"
#include "GlobalUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma comment(lib, "wininet")
//---------------------------------------------------------------------------
DWORD WINAPI HttpProc(LPVOID args)
{
THttpParam* param = (THttpParam*)args;
TCHAR hdrsStream[] = _T("Content-Type: application/octet-stream\r\n"),
hdrsXForm[] = _T("Content-Type: application/x-www-form-urlencoded\r\n"),
*hdrs = param->iMode==0 ? hdrsStream : hdrsXForm;
LPCTSTR lpszAccept[] = { _T("text/html"), NULL };//{ _T("application/json"), NULL };//
char szBuffer[1024];
DWORD dwFlags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE,
dwByteRead = 0,
dwAllBytes = 0,
dwSize = 4;
int pos = 0;
bool bSent = false;
// char srvAddr[256];
//Open internet connection
param->hSession = InternetOpen( L"HttpPost/1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
if( !param->hSession ){
param->errCode = ERROR_INTERNET_OPEN;
return 0;
}
char addr[80];
int port = 80;
char* p = strstr( param->server, ":" );
if( p ){
memcpy( addr, param->server, p - param->server );
addr[p - param->server] = 0;
sscanf( p+1, "%d", &port );
}
else
strcpy( addr, param->server );
param->hConnect = InternetConnect(param->hSession,
(String(addr)).w_str(),
port,//INTERNET_DEFAULT_HTTP_PORT,
NULL,
NULL,
INTERNET_SERVICE_HTTP,
0,
1);
if( param->hConnect ){
if( port==INTERNET_DEFAULT_HTTPS_PORT )
dwFlags |= INTERNET_FLAG_SECURE;
param->hRequest = HttpOpenRequest(param->hConnect,
_T("POST"),
((String)param->api).c_str(),
NULL,
NULL,
NULL,//lpszAccept,//
dwFlags,
1);
if( param->hRequest ){
if( port==INTERNET_DEFAULT_HTTPS_PORT ){
DWORD flags = 0;
DWORD bufflen = sizeof(flags);
InternetQueryOption(param->hRequest, INTERNET_OPTION_SECURITY_FLAGS,
(LPVOID)&flags, &bufflen);
flags |= SECURITY_FLAG_IGNORE_REVOCATION;
InternetSetOption(param->hRequest, INTERNET_OPTION_SECURITY_FLAGS,
(LPVOID)&flags, sizeof(flags));
}
if( HttpSendRequest( param->hRequest, hdrs, wcslen(hdrs),
param->dataIn, param->sizeIn) ){
bSent = true;
}
else{
param->errCode = GetLastError();
}
}
else{
param->errCode = GetLastError();
}
}
else{
param->errCode = GetLastError();
}
if( !param->hConnect ){
param->errCode = ERROR_INTERNET_CONN;
return 0;
}
if( !param->hRequest ){
param->errCode = ERROR_INTERNET_REQ;
return 0;
}
if( !bSent ){
param->errCode = ERROR_INTERNET_SEND;
return 0;
}
// if( param->bGetDT ){
// SYSTEMTIME sysTime;
// SecureZeroMemory(&sysTime, sizeof(SYSTEMTIME));
// DWORD dwSize = sizeof(SYSTEMTIME);
// if( HttpQueryInfo( param->hRequest, HTTP_QUERY_DATE|HTTP_QUERY_FLAG_SYSTEMTIME,
// &sysTime, &dwSize, NULL ) ){
// TDateTime dt = SystemTimeToDateTime(sysTime);
// param->dwDateTime = DateTimeToUnix(dt);
// }
// else
// param->dwDateTime = 0;
// }
if( !HttpQueryInfo( param->hRequest, HTTP_QUERY_CONTENT_LENGTH|HTTP_QUERY_FLAG_NUMBER,
&dwAllBytes, &dwSize, NULL ) ){
dwAllBytes = 0;
}
// 防止乱码的方法就是建立完变量立即清空
ZeroMemory(szBuffer, sizeof(szBuffer));
ZeroMemory(param->dataOut, param->sizeOut);
// 循环读取缓冲区内容直到结束
while( param->hRequest && InternetReadFile(param->hRequest, szBuffer, sizeof(szBuffer),
&dwByteRead) && dwByteRead > 0 ){
if( pos + dwByteRead > param->sizeOut ){
param->errCode = ERROR_SIZE;
return 0;
}
// 复制输出数据
memcpy( param->dataOut+pos, szBuffer, dwByteRead );
pos += dwByteRead;
// 清空缓冲区以备下一次读取
ZeroMemory(szBuffer, sizeof(szBuffer));
}
if( !param->hRequest ){
param->errCode = ERROR_INTERNET_REQ;
}
else if( dwAllBytes>0 && pos!=dwAllBytes ){
param->errCode = ERROR_SIZE;
}
else{
param->dataOut[pos] = 0;
param->sizeOut = pos;
}
return 0;
}
//---------------------------------------------------------------------------
DWORD WINAPI VeloProc(LPVOID args)
{
TVeloParam* param = (TVeloParam*)args;
TCHAR hdrs[] = _T("Content-Type: application/x-www-form-urlencoded\r\n");
// TCHAR hdrs[] = _T("Content-Type: text/html\r\n");
LPCTSTR lpszAccept[] = { _T("*/*"), NULL };
// char srvAddr[256];
//Open internet connection
param->hSession = InternetOpen(L"Velocity",INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if( !param->hSession ){
param->errCode = ERROR_INTERNET_OPEN;
return 0;
}
param->hConnect = InternetConnect(param->hSession,
(String(param->addr)).w_str(),
param->port,
NULL,
NULL,
INTERNET_SERVICE_HTTP,
0,
0);
if( !param->hConnect ){
param->errCode = ERROR_INTERNET_CONN;
return 0;
}
param->hRequest = HttpOpenRequest(param->hConnect,
_T("GET"),
((String)param->api).c_str(),
_T("HTTP/1.1"),
NULL,
NULL,//lpszAccept,
param->flag,
0);
if( !param->hRequest ){
//param->errCode = ERROR_INTERNET_REQ;
return 0;
}
if( param->port==INTERNET_DEFAULT_HTTPS_PORT ){
DWORD flags = 0;
DWORD bufflen = sizeof(flags);
InternetQueryOption(param->hRequest, INTERNET_OPTION_SECURITY_FLAGS,
(LPVOID)&flags, &bufflen);
flags |= SECURITY_FLAG_IGNORE_REVOCATION | SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
InternetSetOption(param->hRequest, INTERNET_OPTION_SECURITY_FLAGS,
(LPVOID)&flags, sizeof(flags));
}
if( !HttpSendRequest( param->hRequest, hdrs, wcslen(hdrs), NULL, 0) ){
//param->errCode = ERROR_INTERNET_SEND;
int err = GetLastError();
return 0;
}
DWORD dwCode = 0,
dwSize = sizeof(DWORD);
if( HttpQueryInfo( param->hRequest, HTTP_QUERY_STATUS_CODE |HTTP_QUERY_FLAG_NUMBER,
&dwCode, &dwSize, NULL ) ){
if( dwCode<HTTP_STATUS_SERVER_ERROR ){
param->errCode = 1;
ReleaseSemaphore( param->hSema, 1, NULL );
}
}
return 0;
}
//---------------------------------------------------------------------------
DWORD WINAPI ProbProc(LPVOID args)
{
TProbParam* param = (TProbParam*)args;
param->hSession = InternetOpen( L"RookIE/1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
if( param->hSession ){
String api = L"http://" + (String)param->server + L"/Api/chkServer";
param->hRequest = InternetOpenUrl( param->hSession, api.c_str(), NULL, 0,
INTERNET_FLAG_DONT_CACHE|INTERNET_FLAG_RELOAD|INTERNET_FLAG_PRAGMA_NOCACHE, 0 );
if( param->hRequest ){
DWORD dwByteRead = 0;
char szBuffer[1024];
ZeroMemory(szBuffer, sizeof(szBuffer));
InternetReadFile(param->hRequest, szBuffer, sizeof(szBuffer), &dwByteRead);
if( dwByteRead==2 && szBuffer[0]=='o' && szBuffer[1]=='k' ){
param->errCode = 1;
ReleaseSemaphore( param->hSema, 1, NULL );
}
}
else
param->errCode = ERROR_INTERNET_REQ;
}
else
param->errCode = ERROR_INTERNET_OPEN;
return 0;
}
//---------------------------------------------------------------------------
DWORD WINAPI UrlProc(LPVOID args)
{
TUrlParam* param = (TUrlParam*)args;
param->hSession = InternetOpen( L"RookIE/1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
if( param->hSession ){
param->hRequest = InternetOpenUrl( param->hSession, param->url.c_str(), param->header.c_str(), 0,
INTERNET_FLAG_DONT_CACHE|INTERNET_FLAG_RELOAD|INTERNET_FLAG_PRAGMA_NOCACHE, 0 );
if( param->hRequest ){
int pos = 0;
DWORD dwByteRead = 0;
char szBuffer[10240];
ZeroMemory(szBuffer, sizeof(szBuffer));
ZeroMemory(param->dataOut, param->sizeOut);
// 循环读取缓冲区内容直到结束
while( param->hRequest && InternetReadFile(param->hRequest, szBuffer, 10240, &dwByteRead)
&& dwByteRead > 0){
if( pos + dwByteRead > param->sizeOut ){
param->errCode = ERROR_SIZE;
break;
}
// 复制输出数据
memcpy( param->dataOut+pos, szBuffer, dwByteRead );
pos += dwByteRead;
// 清空缓冲区以备下一次读取
ZeroMemory(szBuffer, 10240);
}
param->dataOut[pos] = 0;
param->sizeOut = pos;
if( param->hRequest )
return 0;
}
param->errCode = ERROR_INTERNET_REQ;
}
else
param->errCode = ERROR_INTERNET_OPEN;
return 0;
}
//---------------------------------------------------------------------------
bool IsPureUrl(String url)
{
bool bPure = false;
int num = 0;
int len = url.Length();
for( int i=1; i<=len && num<5; i++ ){
if( url[i]=='/' ){
num++;
}
}
if( num<3 )
bPure = true;
else if( num==3 && url[len]=='/' )
bPure = true;
return bPure;
}
/////////////////////////////////////////////////////////////////////////////
// TBaseWebThread
__fastcall TBaseWebThread::TBaseWebThread( HWND handle )
: TThread(true)
{
m_hWnd = handle;
m_hSema = CreateSemaphore( NULL, 0, 1, NULL );
}
//---------------------------------------------------------------------------
__fastcall TBaseWebThread::~TBaseWebThread()
{
if( m_hSema )
CloseHandle( m_hSema );
}
//---------------------------------------------------------------------------
void __fastcall TBaseWebThread::Cancel()
{
Terminate();
ReleaseSemaphore( m_hSema, 1, NULL );
}
//---------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////////////
// TAsynHttpThread
__fastcall TAsynHttpThread::TAsynHttpThread( HWND handle, char* server, String api,
char* dataIn, int sizeIn, int op, int mode )
: TBaseWebThread( handle )
{
memcpy( m_dataIn, dataIn, sizeIn );
m_dataIn[sizeIn] = 0;
m_sizeIn = sizeIn;
memset( m_dataOut, 0, sizeof(m_dataOut) );
m_sizeOut = 0;
strcpy( m_server, server );
m_api = api;
m_iOp = op;
m_iMode = mode;
}
//---------------------------------------------------------------------------
void __fastcall TAsynHttpThread::Execute()
{
char szReturn[10240];
int errCode = 0;
THttpParam param;
param.iMode = m_iMode;
param.sizeIn = m_sizeIn;
param.dataIn = m_dataIn;
param.sizeOut = 10240;
param.dataOut = szReturn;
strcpy( param.server, m_server );
strcpy( param.api, ((AnsiString)m_api).c_str() );
DWORD id;
HANDLE hThread = CreateThread( NULL, 0, HttpProc, &param, 0, &id );
if( hThread ){
HANDLE aHandle[2] = { m_hSema, hThread };
DWORD dwRet = WaitForMultipleObjects( 2, aHandle, FALSE, 15000 );
if( param.hRequest )
InternetCloseHandle( param.hRequest );
if( param.hConnect )
InternetCloseHandle( param.hConnect );
if( param.hSession )
InternetCloseHandle( param.hSession );
param.hSession = param.hConnect = param.hRequest = NULL;
WaitForSingleObject( hThread, 200 );
CloseHandle( hThread );
if( dwRet==WAIT_OBJECT_0 ){ //用户退出
return;//errCode = ERROR_INTERNET_CANCEL;
}
else if( dwRet==WAIT_OBJECT_0+1 && param.errCode==0 ){ //线程正常退出
m_sizeOut = param.sizeOut;
memcpy( m_dataOut, szReturn, m_sizeOut );
m_dataOut[m_sizeOut] = 0;
}
else if( dwRet==WAIT_TIMEOUT ) //超时
errCode = ERROR_INTERNET_TMOUT;
else if( param.errCode==0 )//出错了
errCode = ERROR_INTERNET_UNKNOWN;
}
else
errCode = ERROR_INTERNET_UNKNOWN;
if( m_hWnd )
PostMessage( m_hWnd, UM_HTTPRETURN, errCode, m_iOp );
}
//---------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////////////
// TAsynUrlThread
__fastcall TAsynUrlThread::TAsynUrlThread( HWND handle, String api, char* pzOut, int& szOut, int op, String header )
: TBaseWebThread( handle ), m_szOut(szOut)
{
m_url = api;
m_pzOut = pzOut;
m_iOp = op;
m_header = header;
}
//---------------------------------------------------------------------------
void __fastcall TAsynUrlThread::Execute()
{
int errCode = 0;
TUrlParam param;
param.url = m_url;
param.header = m_header;
param.dataOut = m_pzOut;
param.sizeOut = m_szOut;
DWORD id;
HANDLE hThread = CreateThread( NULL, 0, UrlProc, &param, 0, &id );
if( hThread ){
HANDLE aHandle[2] = { m_hSema, hThread };
DWORD dwRet = WaitForMultipleObjects( 2, aHandle, FALSE, 15000 );
if( param.hRequest )
InternetCloseHandle( param.hRequest );
if( param.hSession )
InternetCloseHandle( param.hSession );
param.hSession = param.hRequest = NULL;
WaitForSingleObject( hThread, 200 );
CloseHandle( hThread );
if( dwRet==WAIT_OBJECT_0 ){ //用户退出
return;
}
else if( dwRet==WAIT_OBJECT_0+1 ){ //线程正常退出
m_szOut = param.sizeOut;
errCode = param.errCode;
}
else if( dwRet==WAIT_TIMEOUT ) //超时
errCode = ERROR_INTERNET_TMOUT;
else if( param.errCode==0 )//出错了
errCode = ERROR_INTERNET_UNKNOWN;
}
else
errCode = ERROR_INTERNET_UNKNOWN;
if( m_hWnd )
PostMessage( m_hWnd, UM_URLRETURN, errCode, m_iOp );
}
//---------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////////////
// TVeloThread
__fastcall TVeloThread::TVeloThread( HWND handle, int nWS, char* websites[],
int ports[], char* api, int msWait )
: TBaseWebThread( handle )
{
m_nWS = nWS;
m_websites = websites;
m_ports = ports;
m_msWait = msWait;
strcpy(m_sApi, api);
}
//---------------------------------------------------------------------------
void __fastcall TVeloThread::Execute()
{
HANDLE *aHandle = new HANDLE[m_nWS];
TVeloParam* aParam = new TVeloParam[m_nWS];
HANDLE hWaitSema = CreateSemaphore( NULL, 0, m_nWS>1 ? 2 : 1, NULL );
DWORD id;
for( int i=0; i<m_nWS; i++ ){
if(m_sWebsite.Length()>0 && m_sWebsite.Pos(m_websites[i])){
aHandle[i] = NULL;
}
else{
aParam[i].hSema = hWaitSema;
aParam[i].port = m_ports ? m_ports[i] : INTERNET_DEFAULT_HTTPS_PORT;
aParam[i].flag = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE;
if( aParam[i].port==INTERNET_DEFAULT_HTTPS_PORT )
aParam[i].flag |= INTERNET_FLAG_SECURE;
strcpy( aParam[i].addr, m_websites[i] );
strcpy( aParam[i].api, m_sApi );
//aParam[i].api[0] = 0;
aHandle[i] = CreateThread( NULL, 0, VeloProc, &aParam[i], CREATE_SUSPENDED, &id );
ResumeThread(aHandle[i]);
}
}
DWORD dwRet = WaitForSingleObject( hWaitSema, m_msWait );
int sel = -1;
for( int i=0; i<m_nWS; i++ ){
if( aHandle[i] ){
if( aParam[i].hRequest )
InternetCloseHandle( aParam[i].hRequest );
if( aParam[i].hConnect )
InternetCloseHandle( aParam[i].hConnect );
if( aParam[i].hSession )
InternetCloseHandle( aParam[i].hSession );
aParam[i].hSession = aParam[i].hConnect = aParam[i].hRequest = NULL;
WaitForSingleObject( aHandle[i], 800 );
CloseHandle( aHandle[i] );
if( aParam[i].errCode==1 && sel<0 )
sel = i;
}
}
if( sel<0 ){ //线程非正常退出
sel = GetTickCount() % m_nWS;
if( m_sWebsite.Pos( m_websites[sel] ) )
sel = (sel+1) % m_nWS;
}
if( !m_ports || m_ports[sel]==INTERNET_DEFAULT_HTTPS_PORT )
m_sWebsite = Format( "https://%s", ARRAYOFCONST((m_websites[sel])) );
else if( m_ports[sel]==INTERNET_DEFAULT_HTTP_PORT )
m_sWebsite = Format( "http://%s", ARRAYOFCONST((m_websites[sel])) );
else
m_sWebsite = Format( "http://%s:%d", ARRAYOFCONST((m_websites[sel], m_ports[sel])) );
CloseHandle( hWaitSema );
delete[] aHandle;
delete[] aParam;
if( !Terminated )
PostMessage( m_hWnd, UM_VELOCITY, sel, (LPARAM)this );
}
//---------------------------------------------------------------------------