📄 httprequest.c
字号:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 预处理。
#include <WinSock2.h>
#include "HttpRequest.h"
#ifdef UNICODE
#undef UNICODE
#endif // UNICODE
#define __TRY
#define __LEAVE(vResult) hrError = vResult; goto __Finally
#define __FINALLY __Finally:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 发送通知消息
__inline BOOL WINAPI SendHRNotify(HWND hNotify, WPARAM wParam, LPARAM lParam)
{
if (hNotify)
{
return (BOOL) SendMessage(hNotify, UM_HRNOTIFY, wParam, lParam);
//if (IsWindow(hNotify))
//{
// return (BOOL) SendMessage(hNotify, UM_HRNOTIFY, wParam, lParam);
//}
//else
//{
// return (BOOL) ((WNDPROC) hNotify)(NULL, UM_HRNOTIFY, wParam, lParam);
//}
}
return FALSE;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 发送 HTTP/1.1 请求,并接收返回数据。
HRERROR WINAPI HttpRequest(LPSTR pszServer, USHORT uPort, LPCSTR pszUri,
LPSTR pszHost, LPCSTR pszRefer, LPCSTR pszCookie,
LPCBYTE pbPost, UINT uPost, LPBYTE pbReceive, LPUINT puReceive,
LPSTR pszProxy, USHORT uProxy, BOOL bResolve, HWND hNotify)
{
PBYTE p;
int iSize;
BOOL bProxy;
UINT uHeader;
UINT uReceive;
SOCKET sSocket;
HRERROR hrError;
HOSTENT *pHostent;
char szRequest[2048];
SOCKADDR_IN saiAddress;
__TRY
{
// 检查参数。
if ((pszServer == NULL) || (pszUri == NULL) || (pszHost == NULL))
{
__LEAVE(HRERROR_ARGUMENT);
}
// 判断是否使用了代理服务器。
bProxy = pszProxy && pszProxy[0];
// 创建 Socket。
sSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sSocket == INVALID_SOCKET)
{
__LEAVE(HRERROR_SOCKET);
}
// 填写 SOCKADDR_IN 结构。
saiAddress.sin_family = AF_INET;
saiAddress.sin_port = htons(bProxy ? uProxy : uPort);
saiAddress.sin_addr.s_addr = inet_addr((bProxy ? pszProxy : pszServer));
if (saiAddress.sin_addr.s_addr == INADDR_NONE)
{
// 如果输入的不是 IP 地址,尝试进行域名转换。
if (SendHRNotify(hNotify, HRNOTIFY_CONNECT, (LPARAM) (bProxy ? pszProxy : pszServer)))
{
__LEAVE(HRERROR_CANCELED);
}
pHostent = gethostbyname((bProxy ? pszProxy : pszServer));
if (pHostent == NULL)
{
// 解析域名失败。
__LEAVE(HRERROR_RESOLVEDNS);
}
// 解析域名成功,修改服务器地址。
if (bResolve)
{
wsprintf((bProxy ? pszProxy : pszServer), "%d.%d.%d.%d",
(BYTE) pHostent->h_addr[0],
(BYTE) pHostent->h_addr[1],
(BYTE) pHostent->h_addr[2],
(BYTE) pHostent->h_addr[3]);
}
// 设置 SOCKADDR_IN 地址值。
saiAddress.sin_addr.s_addr = *((PULONG) pHostent->h_addr);
}
// 连接服务器。
if (SendHRNotify(hNotify, HRNOTIFY_CONNECT, (LPARAM) (bProxy ? pszProxy : pszServer)))
{
__LEAVE(HRERROR_CANCELED);
}
if (connect(sSocket, (PSOCKADDR) &saiAddress, sizeof(saiAddress)) == SOCKET_ERROR)
{
__LEAVE(HRERROR_CONNECT);
}
// 构造 HTTP/1.1 请求。
lstrcpy(szRequest, (pbPost ? "POST " : "GET "));
if (bProxy)
{
wsprintf(szRequest + lstrlen(szRequest), "http://%s:%d", pszHost, uPort);
}
wsprintf(szRequest + lstrlen(szRequest), "%s HTTP/1.1\r\n", pszUri);
if (pszRefer)
{
wsprintf(szRequest + lstrlen(szRequest), "Refer: %s\r\n", pszRefer);
}
if (pbPost)
{
wsprintf(szRequest + lstrlen(szRequest), "Content-Length: %d\r\n", uPost);
}
if (pszCookie)
{
wsprintf(szRequest + lstrlen(szRequest), "Cookie: %s\r\n", pszCookie);
}
wsprintf(szRequest + lstrlen(szRequest),
"Accept: */*\r\n"
"Accept-Language: zh-cn\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"Accept-Encoding: gzip, deflate\r\n"
"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2)\r\n"
"Host: %s\r\n\r\n", pszHost);
// 发送请求。
iSize = lstrlen(szRequest);
if (SendHRNotify(hNotify, HRNOTIFY_SEND, iSize))
{
__LEAVE(HRERROR_CANCELED);
}
if (send(sSocket, szRequest, iSize, 0) == SOCKET_ERROR)
{
__LEAVE(HRERROR_SEND);
}
// 发送 POST 数据。
if (pbPost)
{
if (SendHRNotify(hNotify, HRNOTIFY_SEND, uPost))
{
__LEAVE(HRERROR_CANCELED);
}
if (send(sSocket, pbPost, uPost, 0) == SOCKET_ERROR)
{
__LEAVE(HRERROR_SEND);
}
}
// 如果要接收数据。
if ((pbReceive) && (puReceive) && (*puReceive > HRNOTIFY_DISCONNECT))
{
// 接收返回数据。
for(uReceive = 0, uHeader = 0; uReceive < *puReceive; uReceive += iSize)
{
// 接收数据。
if (SendHRNotify(hNotify, *puReceive, uReceive))
{
__LEAVE(HRERROR_CANCELED);
}
iSize = recv(sSocket, pbReceive + uReceive, min(2048, *puReceive - uReceive), 0);
if (iSize < 1)
{
break;
}
if ((strcmpi(pszUri, "/image.jsp") == 0) && (uReceive + iSize > 1300))
{
uReceive += iSize;
break;
}
if (uHeader == 0)
{
// 分析接收到的数据是否包含完整的 HTTP 头部。
p = strstr(pbReceive, "\r\n\r\n");
if (p)
{
// 取得 HTTP 头的大小。
uHeader = (UINT) (p - pbReceive + 4); // sizeof("\r\n\r\n")
// 分析接收到的数据是否指定了 Content-Length 值。
p = strstr(pbReceive, "Content-Length: ");
if (p)
{
if (*puReceive > (uHeader + atoi(p + 16)))
{
// 修正要接收的数据字节数。
*puReceive = uHeader + atoi(p + 16);
}
}
}
}
}
// 设置接收数据总字节数。
*puReceive = uReceive;
if (uReceive < 1)
{
__LEAVE(HRERROR_RECEIVE);
}
}
// 设置成功返回值。
hrError = HRERROR_SUCCESS;
}
__FINALLY
{
// 关闭 Socket
if (sSocket != INVALID_SOCKET)
{
closesocket(sSocket);
}
SendHRNotify(hNotify, HRNOTIFY_DISCONNECT, hrError);
// 返回结果
return hrError;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -