我花了好几天撞到墙上,我以为我会问这里。
以下代码的问题是我基本上在迭代目录,在那里上传文件。所有文件都很小,大小约为1KB,因此这不是大小问题。第一次上传就像一个魅力,所有后续调用都被winhttp打破,只发送标题。
以下是代码:
BOOL NetworkManager::UploadFileToServer(wchar_t *pszURL, wchar_t *pszFilePath, wchar_t *_pszProxyAddress, wchar_t *pszServerAddress)
{
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
BOOL bResults;
DWORD dwSize = 0;
DWORD dwContentLength = 0;
LPCWSTR pszProxyAddress = 0;
wchar_t wszContentLength[256] = { 0 };
pszProxyAddress = _pszProxyAddress;
printf("Trying to send %S\r\n", pszFilePath);
if(pszProxyAddress != NULL && wcslen(pszProxyAddress) < 4)
{
pszProxyAddress = NULL;
}
HANDLE hFile = CreateFile(pszFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
printf("UM: Unable to open the file for sending, aborting...\r\n");
return FALSE;
}
DWORD dwFileSize = GetFileSize(hFile, NULL);
// Use WinHttpOpen to obtain a session handle.
if(pszProxyAddress == NULL)
{
hSession = WinHttpOpen( L"Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
NULL,
WINHTTP_NO_PROXY_BYPASS, 0);
}
else
{
hSession = WinHttpOpen( L"Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko",
WINHTTP_ACCESS_TYPE_NAMED_PROXY,
pszProxyAddress,
WINHTTP_NO_PROXY_BYPASS, 0);
}
// Specify an HTTP server.
if (hSession)
{
hConnect = WinHttpConnect( hSession, _pszServerAddress,
INTERNET_DEFAULT_HTTPS_PORT, 0);
}
else
{
printf("hSession failed, errorcode 0x%08x\r\n", GetLastError());
return FALSE;
}
// Create an HTTP request handle.
if (hConnect)
{
hRequest = WinHttpOpenRequest( hConnect, L"POST", L"upload.php",
NULL, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
WINHTTP_FLAG_SECURE);
}
else
{
printf("hConnect failed, errorcode 0x%08x\r\n", GetLastError());
WinHttpCloseHandle(hSession);
return FALSE;
}
PHEAP_BUFFER pBuf = NULL;
DWORD dwBytesWritten = 0;
// Send a request.
if (hRequest)
{
DWORD options = SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | SECURITY_FLAG_IGNORE_UNKNOWN_CA ;
bResults = WinHttpSetOption( hRequest, WINHTTP_OPTION_SECURITY_FLAGS , (LPVOID)&options, sizeof (DWORD) );
WinHttpAddRequestHeaders(hRequest, L"Content-Type: multipart/form-data; boundary=----BoundaryXu02", (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD);
dwContentLength = strlen(pszFormHeader) + dwFileSize + strlen(pszFinalBoundary);
DWORD dwTotalSent = 0;
pBuf = MemoryManager::AllocateHeapMemory(dwContentLength, 1);
DWORD dwBytesRead = 0;
strcat_s((PCHAR)pBuf->pBuffer, pBuf->dwBufferSize, pszFormHeader);
ReadFile(hFile, &pBuf->pBuffer[strlen(pszFormHeader)], dwFileSize, &dwBytesRead, NULL);
memcpy(&pBuf->pBuffer[strlen(pszFormHeader) + dwFileSize], pszFinalBoundary, strlen(pszFinalBoundary));
wsprintf(wszContentLength, L"Content-Length: %d", dwContentLength);
bResults = WinHttpSendRequest( hRequest, wszContentLength, -1, 0, 0, dwContentLength, 0);
printf("Sending out the request\r\n");
WinHttpWriteData(hRequest, pBuf->pBuffer, pBuf->dwBufferSize, &dwBytesWritten);
}
else
{
printf("hRequest failed, errorcode 0x%08x\r\n", GetLastError());
WinHttpCloseHandle(hSession);
WinHttpCloseHandle(hConnect);
return FALSE;
}
//WinHttpWriteData(hRequest, pBuf->pBuffer, pBuf->dwBufferSize, &dwBytesWritten);
// End the request.
if (bResults)
{
bResults = WinHttpReceiveResponse( hRequest, NULL);
}
else
{
printf("hResults failed, errorcode 0x%08x\r\n");
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
MemoryManager::FreeHeapMemory(pBuf);
return FALSE;
}
WinHttpQueryDataAvailable(hRequest, &dwBytesWritten);
// Close any open handles.
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
MemoryManager::FreeHeapMemory(pBuf);
CloseHandle(hFile);
DeleteFile(pszFilePath);
return TRUE;
}
这是来自服务器access_log:
xxx.xxx.xxx.244 - - [09/Jan/2014:16:39:33 +0200] "POST /upload.php HTTP/1.1" 200 1811 "-" "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
xxx.xxx.xxx.244 - - [09/Jan/2014:16:39:33 +0200] "POST /upload.php HTTP/1.1" 200 295 "-" "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
xxx.xxx.xxx.244 - - [09/Jan/2014:16:39:33 +0200] "POST /upload.php HTTP/1.1" 200 295 "-" "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
xxx.xxx.xxx.244 - - [09/Jan/2014:16:39:33 +0200] "POST /upload.php HTTP/1.1" 200 295 "-" "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
xxx.xxx.xxx.244 - - [09/Jan/2014:16:39:33 +0200] "POST /upload.php HTTP/1.1" 200 295 "-" "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
xxx.xxx.xxx.244 - - [09/Jan/2014:16:39:34 +0200] "POST /upload.php HTTP/1.1" 200 295 "-" "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
xxx.xxx.xxx.244 - - [09/Jan/2014:16:39:34 +0200] "POST /upload.php HTTP/1.1" 200 295 "-" "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
xxx.xxx.xxx.244 - - [09/Jan/2014:16:39:34 +0200] "POST /upload.php HTTP/1.1" 200 295 "-" "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
xxx.xxx.xxx.244 - - [09/Jan/2014:16:39:34 +0200] "POST /upload.php HTTP/1.1" 200 295 "-" "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
xxx.xxx.xxx.244 - - [09/Jan/2014:16:39:34 +0200] "POST /upload.php HTTP/1.1" 200 295 "-" "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
xxx.xxx.xxx.244 - - [09/Jan/2014:16:39:34 +0200] "POST /upload.php HTTP/1.1" 200 295 "-" "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
xxx.xxx.xxx.244 - - [09/Jan/2014:16:39:34 +0200] "POST /upload.php HTTP/1.1" 200 295 "-" "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
xxx.xxx.xxx.244 - - [09/Jan/2014:16:39:34 +0200] "POST /upload.php HTTP/1.1" 200 295 "-" "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
xxx.xxx.xxx.244 - - [09/Jan/2014:16:39:34 +0200] "POST /upload.php HTTP/1.1" 200 295 "-" "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
我完全迷失了为什么世界上第一个POST成功但剩下的就是sh * t :(
编辑:
忘记添加标题声明:
char *pszFormHeader = "------BoundaryXu02\r\nContent-Disposition: form-data; name=\"uploaded\"; filename=\"aviconv.dat\"\r\nContent-Type: application/octet-stream\r\n\r\n";
char *pszFinalBoundary = "\r\n------BoundaryXu02--\r\n";
char *pwzContentHeader = "Content-Type: multipart/form-data; boundary=----BoundaryXu02";
wchar_t wszContentLength[256] = { 0 };
答案 0 :(得分:3)
好的,所以最终找出了代码所带来的问题。
1)为了防止潜在的代理干扰上传,在调用WinHttpOpenRequest时使用WINHTTP_FLAG_REFRESH
2)因为在这段代码中,你为每次上传创建了新的连接,似乎有些服务器感到困惑,因为WinHTTP的默认值是在头文件中使用“Connection:keep-alive”。添加“Connection:close”解决了这个问题。
3)似乎调用WinHttpReceiveResponse和WinHttpQueryDataAvailable是不够的。在最后添加WinHttpReadData调用后,事情开始正常。
4)每次添加CurrentTickCount调用时,确保上传使用不同的边界。只是为了确保一路上一个愚蠢的代理不会想到“我之前已经看过这个”
以下是通过SSL(HTTPS)将文件上传到php脚本的功能代码。我已经删除了引用项目中其他组件的调用,并用普通的C等值替换它们。
我希望这对那些与WinHTTP搏斗的人有所帮助:)
另外,请注意该功能在发送后删除文件,所以不要只复制/粘贴并测试c:\ windows \ system32 \ kernel32.dll ......
免责声明:我知道代码仍然有改进的余地,特别是在一些不太好的函数调用上,加上如果文件大小大于DWORD,你会遇到问题。再说一次,另一方面,如果你试图像这样发送它们,WinHTTP会对上传大量的barf。
#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#include <string.h>
#include <winhttp.h>
char *pszFormHeader = "------Boundary%08X\r\nContent-Disposition: form-data; name=\"uploaded\"; filename=\"%08x.dat\"\r\nContent-Type: application/octet-stream\r\n\r\n";
char *pszFinalBoundary = "\r\n------Boundary%08X--\r\n";
wchar_t *wszContentHeader = L"Content-Type: multipart/form-data; boundary=----Boundary%08X";
wchar_t wszContentLength[256] = { 0 };
#define BUFFER_SIZE_1KB 1024
BOOL UploadFileToServer(wchar_t *wszURL, wchar_t *wszFilePath, wchar_t *_wszProxyAddress, wchar_t *_wszServerAddress);
int main(int argc, char **argv)
{
UploadFileToServer(L"upload.php", L"c:\\sample1.txt", NULL, L"www.example.com");
UploadFileToServer(L"upload.php", L"c:\\sample2.txt", NULL, L"www.example.com");
}
BOOL UploadFileToServer(wchar_t *wszURL, wchar_t *wszFilePath, wchar_t *_wszProxyAddress, wchar_t *_wszServerAddress)
{
/*
* Declarations and initializations
*/
HINTERNET hSession = NULL, hConnect = NULL, hRequest = NULL;
BOOL bResults;
DWORD dwSize = 0;
DWORD dwContentLength = 0;
DWORD dwBytesToRead = 0;
DWORD dwBytesRead = 0;
DWORD dwBytesWritten = 0;
DWORD dwBoundaryValue = 0;
DWORD dwFileSize = 0;
DWORD options = SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | SECURITY_FLAG_IGNORE_UNKNOWN_CA ;
LPCWSTR wszProxyAddress = 0;
wchar_t wszContentLength[256] = { 0 };
PUCHAR pResponse = 0;
PCHAR pFormHeader = 0;
PCHAR pFinalBoundary = 0;
PUCHAR pBuf = 0;
wchar_t *pContentHeader = 0;
/*
* Preparations, set up the content headers
*/
pFormHeader = (PCHAR) calloc(BUFFER_SIZE_1KB, 1);
pFinalBoundary = (PCHAR) calloc(BUFFER_SIZE_1KB, 1);
pContentHeader = (wchar_t *) calloc(BUFFER_SIZE_1KB, 1);
dwBoundaryValue = GetTickCount();
wszProxyAddress = _wszProxyAddress;
sprintf_s(pFormHeader, BUFFER_SIZE_1KB, pszFormHeader, dwBoundaryValue, dwBoundaryValue);
sprintf_s(pFinalBoundary, BUFFER_SIZE_1KB, pszFinalBoundary, dwBoundaryValue);
wsprintf(pContentHeader, wszContentHeader, dwBoundaryValue);
if(wszProxyAddress != NULL && wcslen(wszProxyAddress) < 4)
{
wszProxyAddress = NULL;
}
HANDLE hFile = CreateFile(wszFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
free(pFormHeader);
free(pFinalBoundary);
free(pContentHeader);
printf("Unable to open the file for sending, aborting...\r\n");
return FALSE;
}
dwFileSize = GetFileSize(hFile, NULL);
if(dwFileSize == 0)
{
free(pFormHeader);
free(pFinalBoundary);
free(pContentHeader);
printf("The file is 0 bytes in size, cannot send it\r\n");
return FALSE;
}
if(wszProxyAddress == NULL)
{
hSession = WinHttpOpen( L"Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
NULL,
WINHTTP_NO_PROXY_BYPASS, 0);
}
else
{
hSession = WinHttpOpen( L"Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko",
WINHTTP_ACCESS_TYPE_NAMED_PROXY,
wszProxyAddress,
WINHTTP_NO_PROXY_BYPASS, 0);
}
if (hSession)
{
hConnect = WinHttpConnect( hSession, _wszServerAddress,
INTERNET_DEFAULT_HTTPS_PORT, 0);
}
else
{
free(pFormHeader);
free(pFinalBoundary);
free(pContentHeader);
printf("hSession failed, errorcode 0x%08x\r\n", GetLastError());
return FALSE;
}
if (hConnect)
{
hRequest = WinHttpOpenRequest( hConnect, L"POST", wszURL,
NULL, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
WINHTTP_FLAG_SECURE | WINHTTP_FLAG_REFRESH);
}
else
{
free(pFormHeader);
free(pFinalBoundary);
free(pContentHeader);
printf("hConnect failed, errorcode 0x%08x\r\n", GetLastError());
WinHttpCloseHandle(hSession);
return FALSE;
}
if (hRequest)
{
bResults = WinHttpSetOption( hRequest, WINHTTP_OPTION_SECURITY_FLAGS , (LPVOID)&options, sizeof (DWORD) );
WinHttpAddRequestHeaders(hRequest, pContentHeader, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD);
WinHttpAddRequestHeaders(hRequest, L"Connection: close", (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE);
dwContentLength = strlen(pFormHeader) + dwFileSize + strlen(pFinalBoundary);
pBuf = (PUCHAR)calloc(dwContentLength, 1);
strcat_s((PCHAR)pBuf, dwContentLength, pFormHeader);
ReadFile(hFile, &pBuf[strlen(pFormHeader)], dwFileSize, &dwBytesRead, NULL);
memcpy(&pBuf[strlen(pFormHeader) + dwFileSize], pFinalBoundary, strlen(pFinalBoundary));
wsprintf(wszContentLength, L"Content-Length: %d", dwContentLength);
bResults = WinHttpSendRequest( hRequest,
wszContentLength,
-1, pBuf, dwContentLength,
dwContentLength, 0);
}
else
{
free(pFormHeader);
free(pFinalBoundary);
free(pContentHeader);
printf("hRequest failed, errorcode 0x%08x\r\n", GetLastError());
WinHttpCloseHandle(hSession);
WinHttpCloseHandle(hConnect);
return FALSE;
}
if (bResults)
{
bResults = WinHttpReceiveResponse( hRequest, NULL);
}
else
{
printf("hResults failed, errorcode 0x%08x\r\n");
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
free(pBuf);
free(pFormHeader);
free(pFinalBoundary);
free(pContentHeader);
return FALSE;
}
WinHttpQueryDataAvailable(hRequest, &dwBytesToRead);
pResponse = (PUCHAR)calloc(dwBytesToRead, 1);
WinHttpReadData(hRequest, pResponse, dwBytesToRead, &dwBytesRead);
free(pResponse);
free(pFormHeader);
free(pFinalBoundary);
free(pContentHeader);
// Close any open handles.
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
free(pBuf);
CloseHandle(hFile);
DeleteFile(wszFilePath);
return TRUE;
}
答案 1 :(得分:0)
以下代码对我有用,可将文本图块上载至状态为200的HTTP侦听器。
#include <Windows.h>
#include <winhttp.h>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;
std::wstring ErrorMessage(DWORD dwMessageId)
{
HMODULE h = GetModuleHandle(L"Winhttp");
constexpr DWORD dwSize = 512;
HANDLE hHeap = GetProcessHeap();
LPWSTR lpwszBuffer = static_cast<LPWSTR>(HeapAlloc(hHeap, 0, dwSize * sizeof(WCHAR)));
if (lpwszBuffer) {
if (0 == FormatMessageW(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, h, dwMessageId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), lpwszBuffer, dwSize, nullptr))
_ltow_s(dwMessageId, lpwszBuffer, dwSize, 16);
else {
for (WCHAR* p; (p = wcschr(lpwszBuffer, L'\r')) != nullptr; *p = L' ') {}
for (WCHAR* p; (p = wcschr(lpwszBuffer, L'\n')) != nullptr; *p = L' ') {}
}
std::wstring wsError = lpwszBuffer;
HeapFree(hHeap, 0, lpwszBuffer);
return wsError;
}
return std::wstring{};
}
int main()
{
DWORD dwSize = 0;
LPVOID lpOutBuffer = NULL;
BOOL bResults = FALSE;
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
// Use WinHttpOpen to obtain a session handle.
hSession = WinHttpOpen(L"A WinHTTP Example Program/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
std::wstring url{ L"http://app.pomdit.com:3010/uploadfile" };
URL_COMPONENTS components{};
components.dwStructSize = sizeof(components);
components.dwHostNameLength = (DWORD)-1;
components.dwUrlPathLength = (DWORD)-1;
if (!WinHttpCrackUrl(url.c_str(), static_cast<DWORD>(url.length()), 0, &components)) {
wprintf((L"WinHttpCrackUrl(): " + ErrorMessage(GetLastError())).c_str());
}
std::wstring hostName(components.lpszHostName ? std::wstring{ components.lpszHostName, components.dwHostNameLength } : L"localhost");
// Specify an HTTP server.
if (hSession)
hConnect = WinHttpConnect(hSession, hostName.c_str(),
components.nPort, 0);
// Create an HTTP request handle.
if (hConnect)
hRequest = WinHttpOpenRequest(hConnect, L"POST", components.lpszUrlPath,
NULL, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
0);
const WCHAR* ContentType =
L"Content-Type: multipart/form-data;boundary = 19024605111143684786787635207";
std::ifstream in("LogFile.txt");
std::stringstream buffer;
buffer << in.rdbuf();
std::string contents(buffer.str());
std::string MultipartRequestBody =
"--19024605111143684786787635207\r\n"
"Content-Disposition: form-data; name=\"file\"; filename=\"Logfile\"\r\n"
"Content-Type: application/octet-stream\r\n"
"\r\n";
std::string finalBody = "--19024605111143684786787635207--\r\n";
MultipartRequestBody += contents + "\r\n" + finalBody;
bResults = WinHttpAddRequestHeaders(
hRequest,
ContentType,
-1L,
WINHTTP_ADDREQ_FLAG_ADD
);
bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA,
0,
MultipartRequestBody.length(),
NULL);
DWORD dwBytesWritten = 0;
if (bResults)
bResults = WinHttpWriteData(hRequest, MultipartRequestBody.c_str(),
MultipartRequestBody.length(),
&dwBytesWritten);
// End the request.
if (bResults)
bResults = WinHttpReceiveResponse(hRequest, NULL);
if (bResults)
{
DWORD status{}, len = sizeof(status);
bResults = WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &len, NULL);
printf("Status code = %d.\n", status);
}
else
{
wprintf(L"WinHttpReceiveResponse(): %s\n", ErrorMessage(GetLastError()).c_str());
}
// Close any open handles.
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
}