大家好,欢迎来到IT知识分享网。
代码都在下面了,目前这个版本实现的功能还非常的少,能实现的有:
1. GET方法。给定一个URL(可以带中文),返回http的响应数据,包括文本和二进制数据
2. 支持代理服务器,需要用户预先设定好proxy server ip, port, username, password.
不支持的有:
1. POST
2. 查询http响应的header。
3. 将返回的文本数据重新编码,变成UTF-16。这需要首先从header取出http server响应的数据是什么编码的,然后就可以使用windows的MultiByteToWideChar来进行转换。
这里总结几点开发过程中的注意点:
1. MSDN上的资料不是非常的全,所以有些参考了google得来的内容。
2. WinHttpOpen的时候,如果用AUTO PROXY,也就是让winhttp从注册表读取proxy设置的话(这个注册表的设置是proxycfg.exe生成的,和IE中的那个proxy设置是两码事)。
3. proxy的用户名和密码需要用WinHttpSetOption来进行设置, timeout设定用WinHttpSetTimeouts
4. 使用WinHttpCrackUrl可以将一个给定的url(必须以http://, https://打头)分解,设置到URL_COMPONENTS这个structure中。在这里其实就可以做url encoding(也就是将url不支持的字符转换成%xxx这样的东西),但是这样做的话需要手动给URL_COMPONENETS中的member分 配内存,比较麻烦,所以没做。
5. 使用WinHttpCreateUrl可以根据URL_COMPONENETS重新生成一个string的URL,但是这里没用到。
6. 使用WinHttpConnect的时候,一定要注意要给出hostname,不是url,所以要手动分解,只取出http server的那个部分,比如http://www.google.com/sfsdfdsf?id=xxx& user=xxxx,hostname就是www.google.com
7. 然后使用WinHttpOpenRequest的时候,就可以给出去掉了http://之后的后面所有内容了,也就是www.google.com /sfsdfdsf?id=xxx&user=xxxx这样的东西。注意最后的flag设 置:WINHTTP_FLAG_ESCAPE_PERCENT | WINHTTP_FLAG_REFRESH,这两个很有用,WINHTTP_FLAG_ESCAPE_PERCENT就是将url中不合法的内容转 成%xxx,WINHTTP_FLAG_REFRESH就是跳过proxy的cache,每次都请求全新的数据。还有需要注意的 是,WinHttpOpenRequest中,要求给出我们能接受的mimetype,这里可以参考代码,如果要文本,就给text/*,如果要二进制数 据,就可以像这里给出application/*, image/*, audio/*……
8. 最后WinHttpSendRequest的时候,也可以设定additional header和optional数据。这里的optional数据一般是用于POST的,也就是将需要post到server的数据填充在这个地方。 WinHttpSendRequest将header都发送出去之后,紧接着就会发送这个optional数据。
9. WinHttpQueryDataAvailable可以check是否还有数据需要接收。WinHttpReadData用来读取数据,注意读出来的数 据就是字节流,像前面所说,如果是文本,那么要根据response header,首先知道是什么编码和字符集,然后再用MultiByteToWideChar来转换。也要注意WinHttpReadData的最后一个 参数,给出了实际读取到的字节数,也可以根据这个信息来判断是否已经接收完了。此外特别需要注意的是,如果用的是一个固定的buffer循环接收,就像这 里一样,那么不要忘记接收完成的时候,要在尾部加上\0,分配buffer的时候也要留出\0的位置。
1. GET方法。给定一个URL(可以带中文),返回http的响应数据,包括文本和二进制数据
2. 支持代理服务器,需要用户预先设定好proxy server ip, port, username, password.
不支持的有:
1. POST
2. 查询http响应的header。
3. 将返回的文本数据重新编码,变成UTF-16。这需要首先从header取出http server响应的数据是什么编码的,然后就可以使用windows的MultiByteToWideChar来进行转换。
这里总结几点开发过程中的注意点:
1. MSDN上的资料不是非常的全,所以有些参考了google得来的内容。
2. WinHttpOpen的时候,如果用AUTO PROXY,也就是让winhttp从注册表读取proxy设置的话(这个注册表的设置是proxycfg.exe生成的,和IE中的那个proxy设置是两码事)。
3. proxy的用户名和密码需要用WinHttpSetOption来进行设置, timeout设定用WinHttpSetTimeouts
4. 使用WinHttpCrackUrl可以将一个给定的url(必须以http://, https://打头)分解,设置到URL_COMPONENTS这个structure中。在这里其实就可以做url encoding(也就是将url不支持的字符转换成%xxx这样的东西),但是这样做的话需要手动给URL_COMPONENETS中的member分 配内存,比较麻烦,所以没做。
5. 使用WinHttpCreateUrl可以根据URL_COMPONENETS重新生成一个string的URL,但是这里没用到。
6. 使用WinHttpConnect的时候,一定要注意要给出hostname,不是url,所以要手动分解,只取出http server的那个部分,比如http://www.google.com/sfsdfdsf?id=xxx& user=xxxx,hostname就是www.google.com
7. 然后使用WinHttpOpenRequest的时候,就可以给出去掉了http://之后的后面所有内容了,也就是www.google.com /sfsdfdsf?id=xxx&user=xxxx这样的东西。注意最后的flag设 置:WINHTTP_FLAG_ESCAPE_PERCENT | WINHTTP_FLAG_REFRESH,这两个很有用,WINHTTP_FLAG_ESCAPE_PERCENT就是将url中不合法的内容转 成%xxx,WINHTTP_FLAG_REFRESH就是跳过proxy的cache,每次都请求全新的数据。还有需要注意的 是,WinHttpOpenRequest中,要求给出我们能接受的mimetype,这里可以参考代码,如果要文本,就给text/*,如果要二进制数 据,就可以像这里给出application/*, image/*, audio/*……
8. 最后WinHttpSendRequest的时候,也可以设定additional header和optional数据。这里的optional数据一般是用于POST的,也就是将需要post到server的数据填充在这个地方。 WinHttpSendRequest将header都发送出去之后,紧接着就会发送这个optional数据。
9. WinHttpQueryDataAvailable可以check是否还有数据需要接收。WinHttpReadData用来读取数据,注意读出来的数 据就是字节流,像前面所说,如果是文本,那么要根据response header,首先知道是什么编码和字符集,然后再用MultiByteToWideChar来转换。也要注意WinHttpReadData的最后一个 参数,给出了实际读取到的字节数,也可以根据这个信息来判断是否已经接收完了。此外特别需要注意的是,如果用的是一个固定的buffer循环接收,就像这 里一样,那么不要忘记接收完成的时候,要在尾部加上\0,分配buffer的时候也要留出\0的位置。
/*
* Schedule Download Http utilities, based on winhttp
* Written by Eric Zhang <nicolas.m.zhang@gmail.com>
*/
#include
“
..\include\http.h
“
#include
“
..\include\logger.h
“
#include
“
..\include\utils.h
“
#include
“
..\include\defs.h
“
#include
“
..\include\macros.h
“
#include
<
strsafe.h
>
//
http server’s hostname length
#define
HTTP_HOST_NAME_MAX 255
#define
HTTP_TEXT_MIMETYPE 1
#define
HTTP_BIN_MIMETYPE 2
//
mimetypes for WinHttpOpenRequest
LPCWSTR text_mimetype[]
=
{ L
“
text/*
“
, L
“
\0
“
};
LPCWSTR bin_mimetype[]
=
{ L
“
application/*
“
, L
“
audio/*
“
, L
“
image/*
“
, L
“
video/*
“
, L
“
\0
“
};
/*
* This function used internally. It checks the proxy settings and apply
* to the WinHttp. Return winhttp session handle if succeeded, otherwise
* return NULL.
*/
static
HINTERNET open_winhttp()
{
HINTERNET session
=
NULL;
TCHAR proxy_enabled[REGISTRY_VALUE_SIZE];
TCHAR proxy_server[REGISTRY_VALUE_SIZE];
TCHAR proxy_port[REGISTRY_VALUE_SIZE];
TCHAR proxy_username[REGISTRY_VALUE_SIZE];
TCHAR proxy_password[REGISTRY_VALUE_SIZE];
DWORD errcode;
size_t proxy_username_len
=
0
;
size_t proxy_password_len
=
0
;
//
Check whether the proxy has enabled
SecureZeroMemory(proxy_enabled,
sizeof
(proxy_enabled));
utils_get_registry_value(SD_REGISTRY_KEY, HTTP_PROXY_ENABLED_ENTRY, proxy_enabled,
sizeof
(proxy_enabled));
if
(utils_is_string_empty(proxy_enabled)
||
_tcscmp(proxy_enabled, TEXT(
“
Y
“
))
!=
0
) {
//
proxy isn’t enabled, direct connect
session
=
WinHttpOpen(HTTP_AGENT_NAME, WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS,
0
);
if
(session
==
NULL) {
GET_ERROR_CODE(errcode);
M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_NO_PROXY_OPEN_FAILED, utils_format_error_string(errcode));
}
}
else
{
//
proxy enabled, read server/port/user/pass next
SecureZeroMemory(proxy_server,
sizeof
(proxy_server));
SecureZeroMemory(proxy_port,
sizeof
(proxy_port));
SecureZeroMemory(proxy_username,
sizeof
(proxy_username));
SecureZeroMemory(proxy_password,
sizeof
(proxy_password));
utils_get_registry_value(SD_REGISTRY_KEY, HTTP_PROXY_SERVER_ENTRY, proxy_server,
sizeof
(proxy_server));
utils_get_registry_value(SD_REGISTRY_KEY, HTTP_PROXY_PORT_ENTRY, proxy_port,
sizeof
(proxy_port));
utils_get_registry_value(SD_REGISTRY_KEY, HTTP_PROXY_USER_ENTRY, proxy_username,
sizeof
(proxy_username));
utils_get_registry_value(SD_REGISTRY_KEY, HTTP_PROXY_PASS_ENTRY, proxy_password,
sizeof
(proxy_password));
M_GTIF_WITH_LOG(
!
utils_is_string_empty(proxy_server), failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_PROXY_SERVER_ABSENT);
M_GTIF_WITH_LOG(
!
utils_is_string_empty(proxy_port), failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_PROXY_PORT_ABSENT);
M_GTIF_WITH_LOG(utils_is_string_int(proxy_port), failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_PROXY_PORT_ILLEGAL);
//
add port into server string
M_GTIF_WITH_LOG(SUCCEEDED(StringCchPrintf(proxy_server, _countof(proxy_server), TEXT(
“
%s:%s
“
), proxy_server, proxy_port)), failed,
LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_STRING_OPERATION_FAILED);
//
open
session
=
WinHttpOpen(HTTP_AGENT_NAME, WINHTTP_ACCESS_TYPE_NAMED_PROXY, proxy_server, WINHTTP_NO_PROXY_BYPASS,
0
);
if
(session
==
NULL) {
GET_ERROR_CODE(errcode);
M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_OPEN_WITH_PROXY_FAILED, utils_format_error_string(errcode));
}
//
set proxy username & password
if
(
!
utils_is_string_empty(proxy_username)
&&
!
utils_is_string_empty(proxy_password)) {
M_GTIF_WITH_LOG(SUCCEEDED(StringCchLength(proxy_username, _countof(proxy_username),
&
proxy_username_len)), failed,
LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_STRING_OPERATION_FAILED);
M_GTIF_WITH_LOG(SUCCEEDED(StringCchLength(proxy_password, _countof(proxy_password),
&
proxy_password_len)), failed,
LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_STRING_OPERATION_FAILED);
if
(
!
WinHttpSetOption(session, WINHTTP_OPTION_PROXY_USERNAME, proxy_username, proxy_username_len)) {
GET_ERROR_CODE(errcode);
M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_SET_PROXY_USER_FAILED, utils_format_error_string(errcode));
}
if
(
!
WinHttpSetOption(session, WINHTTP_OPTION_PROXY_PASSWORD, proxy_password, proxy_password_len)) {
GET_ERROR_CODE(errcode);
M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_SET_PROXY_PASS_FAILED, utils_format_error_string(errcode));
}
}
}
//
set timeouts
if
(
!
WinHttpSetTimeouts(session, HTTP_RESOLVE_TO, HTTP_CONNECT_TO, HTTP_SEND_TO, HTTP_RECV_TO)) {
GET_ERROR_CODE(errcode);
M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_SET_TIMEOUTS_FAILED, utils_format_error_string(errcode));
}
return
session;
failed:
if
(session
!=
NULL) WinHttpCloseHandle(session);
return
NULL;
}
static
BOOL http_get(PCTSTR url, HINTERNET
*
sess, HINTERNET
*
conn, HINTERNET
*
req, DWORD mimetype)
{
HINTERNET session
=
NULL, connect
=
NULL, request
=
NULL;
BOOL result
=
FALSE;
DWORD errcode;
URL_COMPONENTS url_comp;
size_t url_len_input;
TCHAR http_host_name[HTTP_HOST_NAME_MAX];
int
hostname_index;
M_RETURN_VAL_IF_FAIL(url
!=
NULL, FALSE);
M_RETURN_VAL_IF_FAIL(sess
!=
NULL, FALSE);
M_RETURN_VAL_IF_FAIL(conn
!=
NULL, FALSE);
M_RETURN_VAL_IF_FAIL(req
!=
NULL, FALSE);
M_RETURN_VAL_IF_FAIL(logger_is_enabled(), FALSE);
session
=
open_winhttp();
M_RETURN_VAL_IF_FAIL(session
!=
NULL, FALSE);
//
log has been done in open_winhttp function
//
crack url input
//
Initialize the URL_COMPONENTS structure.
SecureZeroMemory(
&
url_comp,
sizeof
(url_comp));
url_comp.dwStructSize
=
sizeof
(url_comp);
//
Set required component lengths to non-zero
//
so that they are cracked.
url_comp.dwSchemeLength
=
–
1
;
url_comp.dwHostNameLength
=
–
1
;
url_comp.dwUrlPathLength
=
–
1
;
url_comp.dwExtraInfoLength
=
–
1
;
M_GTIF_WITH_LOG(SUCCEEDED(StringCchLength(url, STRSAFE_MAX_CCH,
&
url_len_input)), failed, LOG_LEVEL_ERROR,
__SDFILE__, __LINE__, HTTP_STRING_OPERATION_FAILED);
result
=
WinHttpCrackUrl(url, url_len_input,
0
,
&
url_comp);
if
(
!
result) {
GET_ERROR_CODE(errcode);
M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_CRACK_URL_FAILED, utils_format_error_string(errcode));
}
/*
No need to create url because No winhttp functions accept a whole escaped url
// get new url length, allocate it
WinHttpCreateUrl(&url_comp, 0, NULL, &url_len_cracked);
M_GTIF_WITH_LOG(url_len_cracked > 0, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_CREATE_URL_GET_LEN_FAILED);
// the length WinHttpCreateUrl generated is wide character numbers
url_cracked = (TCHAR *)HeapAlloc(sdc_heap, HEAP_ZERO_MEMORY, url_len_cracked * sizeof(WCHAR));
M_GTIF_WITH_LOG(url_cracked != NULL, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_HEAP_ALLOC_FAILED);
// call create url again, this time get result url
result = WinHttpCreateUrl(&url_comp, 0, url_cracked, &url_len_cracked);
if (!result) {
GET_ERROR_CODE(errcode);
M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_CREATE_URL_FAILED, utils_format_error_string(errcode));
}
*/
//
url OK, connect. Notice here WinHttpConnect needs Host/Server name, not the whole URL
//
Request file and parameters should be set in WinHttpOpenRequest function
//
get hostname
hostname_index
=
utils_find_char(url_comp.lpszHostName, (TCHAR)
‘
/
‘
);
if
(hostname_index
<
0
) {
//
not found or error occurs, use the original hostname
connect
=
WinHttpConnect(session, url_comp.lpszHostName, INTERNET_DEFAULT_HTTP_PORT,
0
);
}
else
{
//
found “/”
memcpy_s(http_host_name,
sizeof
(http_host_name), url_comp.lpszHostName, hostname_index
*
sizeof
(TCHAR));
http_host_name[hostname_index]
=
(TCHAR)
‘
\0
‘
;
connect
=
WinHttpConnect(session, http_host_name, INTERNET_DEFAULT_HTTP_PORT,
0
);
}
if
(connect
==
NULL) {
GET_ERROR_CODE(errcode);
M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_CONNECT_FAILED, utils_format_error_string(errcode));
}
if
(mimetype
==
HTTP_TEXT_MIMETYPE) {
request
=
WinHttpOpenRequest(connect, TEXT(
“
GET
“
), url_comp.lpszUrlPath, NULL, WINHTTP_NO_REFERER,
text_mimetype, WINHTTP_FLAG_ESCAPE_PERCENT
|
WINHTTP_FLAG_REFRESH);
}
else
{
request
=
WinHttpOpenRequest(connect, TEXT(
“
GET
“
), url_comp.lpszUrlPath, NULL, WINHTTP_NO_REFERER,
bin_mimetype, WINHTTP_FLAG_ESCAPE_PERCENT
|
WINHTTP_FLAG_REFRESH);
}
if
(request
==
NULL) {
GET_ERROR_CODE(errcode);
M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_OPEN_REQUEST_FAILED, utils_format_error_string(errcode));
}
//
Send the request
result
=
WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS,
0
, WINHTTP_NO_REQUEST_DATA,
0
,
0
,
0
);
if
(
!
result) {
GET_ERROR_CODE(errcode);
M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_SEND_REQUEST_FAILED, utils_format_error_string(errcode));
}
//
Start receiving
result
=
WinHttpReceiveResponse(request, NULL);
if
(
!
result) {
GET_ERROR_CODE(errcode);
M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_RECV_RESPONSE_FAILED, utils_format_error_string(errcode));
}
//
OK, return
*
sess
=
session;
*
conn
=
connect;
*
req
=
request;
return
TRUE;
failed:
//
Close any open handles
if
(request) WinHttpCloseHandle(request);
if
(connect) WinHttpCloseHandle(connect);
if
(session) WinHttpCloseHandle(session);
return
FALSE;
}
BOOL http_get_text(PCTSTR url, HINTERNET
*
sess, HINTERNET
*
conn, HINTERNET
*
req)
{
return
http_get(url, sess, conn, req, HTTP_TEXT_MIMETYPE);
}
BOOL http_get_bin(PCTSTR url, HINTERNET
*
sess, HINTERNET
*
conn, HINTERNET
*
req)
{
return
http_get(url, sess, conn, req, HTTP_BIN_MIMETYPE);
}
BOOL http_check_data_len(HINTERNET request, DWORD
*
len)
{
DWORD data_size
=
0
;
BOOL result
=
FALSE;
DWORD errcode;
M_RETURN_VAL_IF_FAIL(request
!=
NULL, FALSE);
M_RETURN_VAL_IF_FAIL(len
!=
NULL, FALSE);
M_RETURN_VAL_IF_FAIL(logger_is_enabled(), FALSE);
//
Check the data length
result
=
WinHttpQueryDataAvailable(request,
&
data_size);
if
(
!
result) {
GET_ERROR_CODE(errcode);
M_RVIF_WITH_LOG(FALSE, FALSE, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_QUERY_DATA_FAILED, utils_format_error_string(errcode));
}
M_RVIF_WITH_LOG(data_size
>
0
, FALSE, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_DATA_LENGTH_ILLEGAL, data_size);
*
len
=
data_size;
return
TRUE;
}
BOOL http_recv(HINTERNET request, LPVOID buffer, DWORD buffer_len, DWORD
*
bytes_read)
{
BOOL result
=
FALSE;
DWORD errcode;
M_RETURN_VAL_IF_FAIL(request
!=
NULL, FALSE);
M_RETURN_VAL_IF_FAIL(buffer
!=
NULL, FALSE);
M_RETURN_VAL_IF_FAIL(buffer_len
>
0
, FALSE);
M_RETURN_VAL_IF_FAIL(bytes_read
!=
NULL, FALSE);
M_RETURN_VAL_IF_FAIL(logger_is_enabled(), FALSE);
//
Read the Data.
SecureZeroMemory(buffer, buffer_len);
result
=
WinHttpReadData(request, buffer, buffer_len, bytes_read);
if
(
!
result) {
GET_ERROR_CODE(errcode);
M_RVIF_WITH_LOG(FALSE, FALSE, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_READ_DATA_FAILED, utils_format_error_string(errcode));
}
return
TRUE;
}
void
http_close(HINTERNET
*
session, HINTERNET
*
connect, HINTERNET
*
request)
{
if
(
*
request) WinHttpCloseHandle(
*
request);
if
(
*
connect) WinHttpCloseHandle(
*
connect);
if
(
*
session) WinHttpCloseHandle(
*
session);
*
session
=
NULL;
*
connect
=
NULL;
*
request
=
NULL;
return
;
}
BOOL http_check_internet(PCTSTR url)
{
HINTERNET session
=
NULL, connect
=
NULL, request
=
NULL;
BOOL result
=
FALSE;
DWORD data_len
=
0
;
M_RETURN_VAL_IF_FAIL(url
!=
NULL, FALSE);
M_RETURN_VAL_IF_FAIL(logger_is_enabled(), FALSE);
result
=
http_get_text(url,
&
session,
&
connect,
&
request);
M_RETURN_VAL_IF_FAIL(result, FALSE);
//
logger has been done in http_send
result
=
http_check_data_len(request,
&
data_len);
M_RETURN_VAL_IF_FAIL(result, FALSE);
//
internet is OK, no need to receive actual data
http_close(
&
session,
&
connect,
&
request);
return
TRUE;
}
原帖链接: http://www.cnblogs.com/super119/archive/2011/04/10/2011350.html
ps: 这个帖子帮了我大忙, 感谢原作者!
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/13597.html