Windows平台利用wininet做的HTTP的GET和POST,支持HTTPS

论坛 期权论坛 脚本     
匿名技术用户   2020-12-27 08:22   11   0

By Fanxiushu 2014 转载或引用请注明原作者 。

C++开发中,实现HTTP的代码总是比其他开发语言麻烦,现提供 Windows平台下,利用wininet实现的HTTP,支持HTTPS。

希望对还在坚持使用C++开发HTTP通讯的朋友有一小点帮助.


///头文件

///// By Fanxiushu 2014-04-27
#pragma once
///////////////////////////////////////////////////////////GET
struct http_get_param
{
const char* url;
const char* option_hdr;
int trans_timeout;
//////////////

const char* file_path;

};

int http_downfile(http_get_param * hgp);

///////////////////////////////////////////////////////// POST
struct http_post_part
{
/////
const char* name;
const char* filename;

char* data;
int data_len;
};

struct http_post_param
{
const char* url;
const char* option_hdr;
int trans_timeout;
////
http_post_part* parts;
int parts_count;

char* res_buf;
int res_len;
};

int http_postdata(http_post_param* hpp);

///实现文件, 实现文件的底部是调用实例。

/// By Fanxiushu 2014-04-27

#include <WinInet.h>
#pragma comment(lib,"wininet.lib")
#include "httpclient.h"

struct __http_data_t
{
HANDLE hEvt;
HINTERNET hUrl;
};

static void CALLBACK InternetStatusCallback(
_In_ HINTERNET hInternet,
_In_ DWORD_PTR dwContext,
_In_ DWORD dwInternetStatus,
_In_ LPVOID lpvStatusInformation,
_In_ DWORD dwStatusInformationLength
)
{
__http_data_t* data = (__http_data_t*)dwContext;
////
// printf("**dwInternetStatus=%d\n", dwInternetStatus);
if (dwInternetStatus == INTERNET_STATUS_REQUEST_COMPLETE){
INTERNET_ASYNC_RESULT* res = (INTERNET_ASYNC_RESULT*)lpvStatusInformation;
data->hUrl = (HINTERNET)res->dwResult;
SetEvent(data->hEvt);
}
else if (dwInternetStatus == INTERNET_STATUS_HANDLE_CREATED){
INTERNET_ASYNC_RESULT* res = (INTERNET_ASYNC_RESULT*)lpvStatusInformation;
data->hUrl = (HINTERNET)res->dwResult;
}
}

int http_downfile( http_get_param * hgp )
{
if (!hgp || !hgp->url || !hgp->file_path) return -1;

///
DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE;

char dns[512] = "";
char uri_path[8192] = "";
URL_COMPONENTS uc;
memset(&uc, 0, sizeof(uc));
uc.dwStructSize = sizeof(uc);
uc.lpszHostName = dns;
uc.dwHostNameLength = 512;
uc.dwUrlPathLength = 8192;
uc.lpszUrlPath = uri_path;
InternetCrackUrl(hgp->url, 0, 0, &uc);

if (uc.nScheme == INTERNET_SCHEME_HTTPS)
flags |= (SECURITY_IGNORE_ERROR_MASK |
SECURITY_INTERNET_MASK | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP |
INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP |
INTERNET_FLAG_RELOAD);

/////
HINTERNET hSession = NULL;
hSession = InternetOpen("HTTP.GetData-UserAgent", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, INTERNET_FLAG_ASYNC);
if (!hSession){
log_printf("http_downfile: InternetOpen Error <%d>\n", GetLastError());
return -1;
}
InternetSetStatusCallback(hSession, InternetStatusCallback);
/////
HANDLE hEvt = CreateEvent(NULL, FALSE, FALSE, NULL);
__http_data_t data; data.hEvt = hEvt; data.hUrl = NULL;

HINTERNET hConnect = InternetConnect(hSession, dns, uc.nPort, "", "", INTERNET_SERVICE_HTTP, 0, (DWORD_PTR)&data );
if (!hConnect && GetLastError() == ERROR_IO_PENDING){
DWORD ret = ::WaitForSingleObject(hEvt, hgp->trans_timeout * 1000);
hConnect = data.hUrl;
}
if (!hConnect){
log_printf("http_downfile: Connect [%s:%d] Err<%d>\n", dns, uc.nPort, GetLastError());
InternetCloseHandle(hSession);
CloseHandle(hEvt);
return -1;
}

HINTERNET hRequest = HttpOpenRequest(hConnect, "GET", uri_path, HTTP_VERSION, NULL, NULL, flags, (DWORD_PTR)&data);
if (!hRequest && GetLastError() == ERROR_IO_PENDING ){
DWORD ret = ::WaitForSingleObject(hEvt, hgp->trans_timeout * 1000);
hRequest = data.hUrl;
}
if (!hRequest){
InternetCloseHandle(hConnect);
InternetCloseHandle(hSession);
CloseHandle(hEvt);
log_printf("http_downfile: Open URL [%s] err=%d.\n", hgp->url, GetLastError());
return -1;
}

//////
if (uc.nScheme == INTERNET_SCHEME_HTTPS){// 忽略证书错误
BOOL f;
DWORD flags = 0; DWORD len = sizeof(flags);
f = InternetQueryOption(hRequest, INTERNET_OPTION_SECURITY_FLAGS, &flags, &len);
flags |= (SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_WRONG_USAGE);
f = InternetSetOption(hRequest, INTERNET_OPTION_SECURITY_FLAGS, &flags, sizeof(flags));
if (!f){
log_printf("Warning: Set HTTPS Flags Error err=%d\n", GetLastError());
}
}
//////////
BOOL ff = HttpSendRequest(hRequest, hgp->option_hdr, hgp->option_hdr?strlen(hgp->option_hdr):0, NULL, 0 );
if (!ff && GetLastError() == ERROR_IO_PENDING){
if (::WaitForSingleObject(hEvt, hgp->trans_timeout * 1000) == WAIT_OBJECT_0) ff = TRUE;
}
if (!ff){
log_printf("http_downfile: HttpSendRequest Err=%d\n",GetLastError() );
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hSession);
CloseHandle(hEvt);
return -1;
}

/////////////
FILE* fp = fopen(hgp->file_path, "wb");
if (!fp){
log_printf("http_downfile: Can not Create Local File [%s]\n", hgp->file_path );
InternetCloseHandle(hRequest); InternetCloseHandle(hConnect); InternetCloseHandle(hSession);
CloseHandle(hEvt); return -1;
}

DWORD total_len = 0; DWORD _sz_len = sizeof(DWORD);
HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &total_len, &_sz_len, NULL);

int ret = 0; DWORD cur_len = 0;
///
while (true){
char buf[16 * 1024];
DWORD bytes = 0;
data.hUrl = 0;
INTERNET_BUFFERS ib; memset(&ib, 0, sizeof(ib));
ib.dwStructSize = sizeof(INTERNET_BUFFERS);
ib.dwBufferLength = sizeof(buf)-1;
ib.lpvBuffer = buf;

BOOL ff = InternetReadFileEx(hRequest, &ib, IRF_ASYNC, (DWORD_PTR)&data);
if (!ff){
if (GetLastError() == ERROR_IO_PENDING){
if (::WaitForSingleObject(data.hEvt, hgp->trans_timeout * 1000) != WAIT_OBJECT_0){
ret = -1; break;
}
////
}
else{
ret = -1; break;
}
}
bytes = ib.dwBufferLength;
if (bytes == 0)break;
////
if (fwrite(buf, 1, bytes, fp) != bytes){
log_printf("http_downfile: Local Disk Error Can not Write Data.\n");
ret = -1;
break;
}
cur_len += bytes; ////
///////progress
if (total_len > 0){

}
/////
// buf[bytes]=0; printf( "%s",buf );
}

InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hSession);
CloseHandle(hEvt);

////
::fclose(fp);
if (ret < 0){
remove(hgp->file_path);
}
////
return ret;
}

int http_postdata( http_post_param* hpp )
{
const char* url = hpp->url;
const char* option_hdr = hpp->option_hdr;
hpp->res_buf = NULL;
hpp->res_len = 0;
/////
DWORD flags = INTERNET_FLAG_KEEP_CONNECTION| INTERNET_FLAG_NO_CACHE_WRITE;
int i;

char dns[512] = "";
char uri_path[8192] = "";
URL_COMPONENTS uc;
memset(&uc, 0, sizeof(uc));
uc.dwStructSize = sizeof(uc);
uc.lpszHostName = dns;
uc.dwHostNameLength = 512;
uc.dwUrlPathLength = 8192;
uc.lpszUrlPath = uri_path;
InternetCrackUrl(url, 0, 0, &uc);
// printf("%s -> %d -> %s\n", dns, uc.nPort, uri_path);

if (uc.nScheme == INTERNET_SCHEME_HTTPS)
flags |= (SECURITY_IGNORE_ERROR_MASK |
SECURITY_INTERNET_MASK | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP |
INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP |
INTERNET_FLAG_RELOAD);
//////////////////////////

HINTERNET hSession = NULL;
HINTERNET hConnect = NULL;
HINTERNET hRequest = NULL;
hSession = InternetOpen("HTTP.PostData-UserAgent", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, INTERNET_FLAG_ASYNC);
if (!hSession){
log_printf("http_postdata: InternetOpen Error <%d>\n", GetLastError());
return -1;
}
InternetSetStatusCallback(hSession, InternetStatusCallback);
/////
HANDLE hEvt = CreateEvent(NULL, FALSE, FALSE, NULL);
__http_data_t hd; hd.hEvt = hEvt; hd.hUrl = NULL;
hConnect = InternetConnect(hSession, dns, uc.nPort, "", "", INTERNET_SERVICE_HTTP, 0, (DWORD_PTR)&hd);
if (!hConnect && GetLastError() == ERROR_IO_PENDING){
DWORD ret = ::WaitForSingleObject(hEvt, hpp->trans_timeout * 1000);
hConnect = hd.hUrl;
}
if (!hConnect){
log_printf("http_postdata: Connect [%s:%d] Err<%d>\n", dns, uc.nPort, GetLastError());
InternetCloseHandle(hSession);
CloseHandle(hEvt);
return -1;
}

hRequest = HttpOpenRequest(hConnect, "POST", uri_path, HTTP_VERSION, NULL, NULL, flags, (DWORD_PTR)&hd );
if (!hRequest && GetLastError() == ERROR_IO_PENDING){
DWORD ret = ::WaitForSingleObject(hEvt, hpp->trans_timeout * 1000);
hRequest = hd.hUrl;
}
if (!hRequest){
log_printf("http_postdata: HttpOpenRequest [%s:%d] Err<%d>\n", dns, uc.nPort, GetLastError());
InternetCloseHandle(hConnect);
InternetCloseHandle(hSession);
CloseHandle(hEvt);
return -1;
}
//////
if (uc.nScheme == INTERNET_SCHEME_HTTPS){// 忽略证书错误
BOOL f;
DWORD flags = 0; DWORD len = sizeof(flags);
f = InternetQueryOption(hRequest, INTERNET_OPTION_SECURITY_FLAGS, &flags, &len);
flags |= (SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_WRONG_USAGE );
f = InternetSetOption(hRequest, INTERNET_OPTION_SECURITY_FLAGS, &flags, sizeof(flags));
if (!f){
log_printf("Warning: Set HTTPS Flags Error err=%d\n", GetLastError() );
}
}
//////////

LPSTR boundary = "$$$-----------------------------xiuxiu2014.03-13%%$$$$----()***kk===";
///
LPSTR accept = "Accept: text/html,application/xhtml+xml,application/xml,text/plain;q=0.9,*/*;q=0.8";
LPSTR accept_lan = "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3";
// LPSTR accept_encoding = "Accept-Encoding: gzip, deflate";
char content_type[256];
sprintf(content_type, "Content-Type: multipart/form-data; boundary=%s", boundary);

HttpAddRequestHeaders(hRequest, content_type, -1, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE);
HttpAddRequestHeaders(hRequest, accept, -1, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE);
HttpAddRequestHeaders(hRequest, accept_lan, -1, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE);
//
// HttpAddRequestHeaders(hRequest, accept_encoding, -1, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); //不接受编码

//添加附加头
if (option_hdr){
HttpAddRequestHeaders(hRequest, option_hdr, -1, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE);
}
//////
char first_boundary[256];
char end_boundary[256];
char delimiter[256];
sprintf_s(first_boundary, "--%s\r\n", boundary); int fb_len = strlen(first_boundary);
sprintf_s(delimiter, "\r\n--%s\r\n", boundary); int del_len = strlen(delimiter);
sprintf_s(end_boundary, "\r\n--%s--\r\n", boundary); int eb_len = strlen(end_boundary);

struct arr_data{
const char* data;
int data_len;
string str;
arr_data(const char* d, int l) :data(d), data_len(l){}
arr_data(const string& o) { str = o; data = str.c_str(); data_len = str.length(); }
arr_data(const arr_data& o){ data = o.data; data_len = o.data_len; str = o.str; if (!str.empty()){ data = str.c_str(); data_len = str.length(); } }
};
list<arr_data> data_array;
unsigned int id_idx = 0;

///
char* content_subtype = "Content-Type: application/octet-stream\r\n\r\n";
int subtype_len = strlen(content_subtype);

data_array.push_back(arr_data(first_boundary, fb_len )); // first boundary

DWORD upLen = fb_len + eb_len;

for (i = 0; i < hpp->parts_count && hpp->parts ; ++i ){
http_post_part* ps = &(hpp->parts[i]);
char name[1024]; char filename[1024];
if (ps->name)sprintf(name, "; name=\"%s\"", ps->name);
else { sprintf(name, "; name=\"NAME%d\"", id_idx++); }
if (ps->filename)sprintf(filename, "; filename=\"%s\"", ps->filename);
else strcpy(filename, "");
string ctx = string("Content-Disposition: form-data") + name + filename + "\r\n";
////
if ( i != 0 ){ //不是第一个段,多个段之间的分割

data_array.push_back( arr_data(delimiter, del_len) ); upLen += del_len;
}

data_array.push_back( arr_data(ctx) ); upLen += ctx.length(); //content_dispos
data_array.push_back(arr_data(content_subtype, subtype_len)); upLen += subtype_len; // content_subtype
if (ps->data && ps->data_len > 0){
data_array.push_back(arr_data(ps->data, ps->data_len)); upLen += ps->data_len; // DATA
}
//////
}

data_array.push_back(arr_data(end_boundary, eb_len)); // end boundary

INTERNET_BUFFERS bufIn;
memset(&bufIn, 0, sizeof(bufIn));
bufIn.dwStructSize = sizeof(bufIn);
bufIn.dwBufferTotal = upLen;
BOOL ret = HttpSendRequestEx(hRequest, &bufIn, NULL, 0, (DWORD_PTR)&hd);
if (!ret && GetLastError() == ERROR_IO_PENDING){
if (::WaitForSingleObject(hEvt, hpp->trans_timeout * 1000) == WAIT_OBJECT_0) ret = TRUE;
}
if (!ret){
log_printf("http_postdata: HttpSendRequestEx [%s:%d] Err<%d>\n", dns, uc.nPort, GetLastError());
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hSession);
CloseHandle(hEvt);
return -1;
}

//////
list<arr_data>::iterator yy;
for (yy = data_array.begin(); yy != data_array.end(); ++yy ){
DWORD bytes = 0;
arr_data* d = &(*yy);
ret = InternetWriteFile(hRequest, d->data,d->data_len, &bytes);
if (!ret && GetLastError() == ERROR_IO_PENDING){
if (::WaitForSingleObject(hEvt, hpp->trans_timeout * 1000) == WAIT_OBJECT_0) ret = TRUE;
}
if (!ret){
log_printf("http_postdata: InternetWriteFile [%s:%d] Err<%d>\n", dns, uc.nPort, GetLastError());
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hSession);
CloseHandle(hEvt);
return -1;
}
}

///
ret = HttpEndRequest(hRequest, 0, 0, (DWORD_PTR)&hd);
if (!ret && GetLastError() == ERROR_IO_PENDING){
if (::WaitForSingleObject(hEvt, hpp->trans_timeout * 1000) == WAIT_OBJECT_0) ret = TRUE;
}
if (!ret){
log_printf("http_postdata: HttpEndRequest err\n");
}
//// read response
DWORD size = 4096;
char* pbuf = (char*)malloc(size);

DWORD total_len = 0; DWORD _sz_len = sizeof(DWORD);

HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &total_len, &_sz_len, NULL);

ret = 0; DWORD cur_len = 0;
if (!pbuf){
ret = -1; goto L;
}
///
while (true){
char buf[8 * 1024];
DWORD bytes = 0;
hd.hUrl = 0;
INTERNET_BUFFERS ib; memset(&ib, 0, sizeof(ib));
ib.dwStructSize = sizeof(INTERNET_BUFFERS);
ib.dwBufferLength = sizeof(buf)-1;
ib.lpvBuffer = buf;

BOOL ff = InternetReadFileEx(hRequest, &ib, IRF_ASYNC, (DWORD_PTR)&hd);
if (!ff){
if (GetLastError() == ERROR_IO_PENDING){
if (::WaitForSingleObject(hd.hEvt, hpp->trans_timeout * 1000) != WAIT_OBJECT_0){
ret = -1;
goto L;
}
////
}
else{
ret = -1;
goto L;
}
}
bytes = ib.dwBufferLength;
if (bytes == 0)break;
////
if (bytes + cur_len >= size-1 ){
size = cur_len + bytes + 1024 * 8 + 10;
char* vpp = (char*)realloc(pbuf, size);
if (!vpp){
ret = -1;
goto L;
}
pbuf = vpp;
}

memcpy(pbuf + cur_len, buf, bytes);

cur_len += bytes; ////

///////progress, 进度
if (total_len > 0){
///
}
/////
// buf[bytes]=0; printf( "%s",buf );
}

//////
pbuf[cur_len] = '\0';
hpp->res_buf = pbuf;
pbuf = NULL;
hpp->res_len = cur_len;

L:

InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hSession);
CloseHandle(hEvt);
if (pbuf)free(pbuf);
////
return ret;
}

#if 1

int main(int argc, char** argv)
{
#if 1 // POST
http_post_param hp; memset(&hp, 0, sizeof(hp));
hp.trans_timeout = 20;

hp.url = "https://passport.csdn.net/account/login?ref=toolbar"; // "https://www.google.com.hk/"; "http://192.168.0.120/tmp_dir";

http_post_part sc[5]; memset(&sc, 0, sizeof(sc));
sc[0].name = "Client-UniqueID"; sc[0].data = "ID00001"; sc[0].data_len = 8; //sc.filename = "filename.txt";

sc[1].name = "DATA";
sc[1].data = "DATA001"; sc[1].data_len = 7;

sc[2].name = "ScreenSize";
sc[2].data = "1366,768"; sc[2].data_len = strlen(sc[2].data);

/////
hp.parts = sc;
hp.parts_count = 3; ///
///////////////////////////////////


http_postdata(&hp); printf("DATA_LEN=%d\n%s\n", hp.res_len, hp.res_buf);
// getchar();

if (hp.res_buf)free(hp.res_buf);

#endif

#if 1 /// GET
http_get_param hgp; memset(&hgp, 0, sizeof(hgp));

hgp.url = "https://www.google.com.hk/";
hgp.trans_timeout = 15;
hgp.file_path = "test.htm";

http_downfile(&hgp);

#endif


return 0;
}

#endif


分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP