c - 如何在 C 中使用 wininet api 将文件上传到 anonfile?
问题描述
我正在尝试使用 wininet 库将文件上传到 C 中的 anonfile。
根据他们的 API,我们需要向以下 URL 发送一个指定文件的 POST HTTP 请求:
https://api.anonfile.com/upload
此外,我上传了一个带有 CURL 的文件以查看生成的标题:https ://pastebin.com/VZfhaxEy
因此,我的函数看起来像这个(基于这篇文章)。请注意,它仍然不处理服务器响应,只是发送:
#include <windows.h>
#include <wininet.h>
#include <stdio.h>
#pragma comment(lib,"Wininet.lib") //Library
#define ERROR_OPEN_FILE 10
#define ERROR_MEMORY 11
#define ERROR_SIZE 12
#define ERROR_INTERNET_OPEN 13
#define ERROR_INTERNET_CONN 14
#define ERROR_INTERNET_REQ 15
#define ERROR_INTERNET_SEND 16
int main(int argc, char* argv[])
{
// Local variables
char* filename = "C:\\test.zip"; //Filename to be loaded
char* type = "binary";
char boundary[] = "pippo"; //Header boundary
char nameForm[] = "upload"; //Input form name
char iaddr[] = "api.anonfile.com"; //IP address
char url[] = "upload"; //URL
char hdrs[1024]; //Headers
char* buffer; //Buffer containing file + headers
char* content; //Buffer containing file
FILE* pFile; //File pointer
long lSize; //File size
HRESULT result;
// Open file
fopen_s(&pFile, filename, "rb");
if (pFile == NULL) return ERROR_OPEN_FILE;
// obtain file size:
fseek(pFile, 0, SEEK_END);
lSize = ftell(pFile);
rewind(pFile);
// allocate memory to contain the whole file:
content = (char*)malloc(sizeof(char) * lSize);
if (content == NULL) return ERROR_MEMORY;
// copy the file into the buffer:
result = fread(content, 1, lSize, pFile);
if (result != lSize) return ERROR_SIZE;
// terminate
fclose(pFile);
//allocate memory to contain the whole file + HEADER
buffer = (char*)malloc(sizeof(char) * lSize + 2048);
//print header
sprintf_s(hdrs,
1024,
"POST /upload HTTP/2\r\n"
"Host: api.anonfile.com\r\n"
"User-Agent: curl/7.60.0"
"cache-control: no-cache\r\n"
"content-type: multipart/form-data\r\n"
"name=\"%s\"; filename=\"%s\"\r\n"
"Content-Length: %i\r\n"
"Accept: */*\r\n"
"\n", nameForm, filename, lSize);
//Open internet connection
HINTERNET hSession = InternetOpen("WinSock", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (hSession == NULL) return ERROR_INTERNET_OPEN;
HINTERNET hConnect = InternetConnect(hSession, iaddr, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
if (hConnect == NULL) {
printf("%d", GetLastError());
return ERROR_INTERNET_CONN;
}
HINTERNET hRequest = HttpOpenRequest(hConnect, (const char*)"POST", url, NULL, NULL, (const char**)"*/*\0", 0, 1);
if (hRequest == NULL) {
printf("%d", GetLastError());
return ERROR_INTERNET_REQ;
}
BOOL sent = HttpSendRequest(hRequest, hdrs, strlen(hdrs), buffer, strlen(buffer));
if (!sent) {
printf("%d", GetLastError());
return ERROR_INTERNET_SEND;
}
//close any valid internet-handles
InternetCloseHandle(hSession);
InternetCloseHandle(hConnect);
InternetCloseHandle(hRequest);
return 0;
}
但不知何故,它无法执行连接:
123
(process 7652) exited with code 14. (ERROR_INTERNET_CONN).
我错过了什么?
这是我发现的唯一一个匿名文件上传示例,但它使用 curl 并且使用 C++。
解决方案
访问安全站点时,请更改INTERNET_DEFAULT_HTTPS_PORT
为 RemyLebeau 提到的。
也INTERNET_FLAG_SECURE
用于HttpOpenRequest
用 上传数据"content-type: multipart/form-data"
,需要用str_open
和包裹数据,str_close
如下代码所示:
注意,"$$ABCXYZ$$"
是一些随机文本。将其更改为不会在目标文件中退出的更随机的内容。
int main()
{
const char* str_header = "Content-Type: multipart/form-data; boundary=----$$ABCXYZ$$";
const char* str_open = "------$$ABCXYZ$$\r\n"
"Content-Disposition: form-data; name=\"file\"; filename=\"filename.txt\"\r\n"
"Content-Type: application/octet-stream\r\n"
"\r\n";
const char *str_close = "\r\n------$$ABCXYZ$$--\r\n";
FILE *fp = NULL;
fopen_s(&fp, "filename.txt", "rb");
if(!fp)
return 0;
fseek(fp, 0, SEEK_END);
long filesize = ftell(fp);
rewind(fp);
int datalen = filesize + strlen(str_open) + strlen(str_close);
char *data = malloc(datalen);
strcpy_s(data, datalen, str_open);
fread(data + strlen(str_open), 1, filesize, fp);
memcpy(data + strlen(str_open) + filesize, str_close, strlen(str_close));
HINTERNET hsession = NULL, hconnect = NULL, hrequest = NULL;
hsession = InternetOpenA("myname", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if(!hsession)
goto cleanup;
hconnect = InternetConnectA(hsession, "api.anonfile.com",
INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if(!hconnect)
goto cleanup;
hrequest = HttpOpenRequestA(hconnect, "POST", "/upload",
NULL, NULL, NULL, INTERNET_FLAG_SECURE, 0);
if(!hrequest)
goto cleanup;
if(!HttpSendRequestA(hrequest, str_header, (DWORD)-1, data, datalen))
goto cleanup;
DWORD received;
BYTE buf[1024];
while(InternetReadFile(hrequest, buf, sizeof(buf), &received) && received)
{
buf[received] = 0;
printf("%s\n", buf);
}
cleanup:
fclose(fp);
if(hsession)InternetCloseHandle(hsession);
if(hconnect)InternetCloseHandle(hconnect);
if(hrequest)InternetCloseHandle(hrequest);
return 0;
}
编辑:更改datalen
,更改strlen(data)
为datalen
二进制文件兼容性
推荐阅读
- css - angularjs + css - 显示悬停 div 然后单击悬停按钮将显示另一个 div
- ios - 错误:使用 xib 文件快速注册自定义 tableView 单元格
- c++ - 计算(64 位无符号整数)*(64 位无符号整数)除以 2^64 的商
- c - size_t 的可变迭代规模
- macos - Strange gcc Initialization crash on old macs
- javascript - 将函数添加到队列中以供稍后执行。还原
- javascript - JS/CSS Transform 属性未被修改
- azure - 使用 portal.azure 更改应用程序设置无法创建帖子
- python - 断点没有在工厂模式 VSCode 中的 Flask 应用程序中命中
- c - 用C逐位读取整个磁盘的内容