如何在 C 中使用 wininet api 将文件上传到 anonfile?
How to upload a file to anonfile using wininet api in C?
我正在尝试使用 wininet 库将文件上传到 C 中的 anonfile。
根据their API,我们需要发送一个POST指定文件的HTTP请求到以下URL:
https://api.anonfile.com/upload
另外,我上传了一个带有 CURL 的文件来查看生成的 headers:https://pastebin.com/VZfhaxEy
因此,我的函数看起来像这个 (based on this post)。请注意,它仍然不处理服务器响应,只是发送:
#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**)"*/*[=12=]", 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).
我错过了什么?
这里是 the only anonfile file uploading example I've found,但它使用 curl 并且是在 C++ 中。
您的错误消息暗示代码在 InternetConnect()
.
上失败
错误代码 123 是 ERROR_INVALID_NAME
:“文件名、目录名或卷标语法不正确”。
API 要求您 post 通过 HTTPS,但您尝试连接到 HTTP 端口 80 而不是 HTTPS 端口 443。
您需要将 INTERNET_DEFAULT_HTTP_PORT
更改为 INTERNET_DEFAULT_HTTPS_PORT
。
访问安全站点时,更改为 RemyLebeau 提到的 INTERNET_DEFAULT_HTTPS_PORT
。
在HttpOpenRequest
中也使用INTERNET_FLAG_SECURE
要用"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
以实现二进制文件兼容性
我正在尝试使用 wininet 库将文件上传到 C 中的 anonfile。
根据their API,我们需要发送一个POST指定文件的HTTP请求到以下URL:
https://api.anonfile.com/upload
另外,我上传了一个带有 CURL 的文件来查看生成的 headers:https://pastebin.com/VZfhaxEy
因此,我的函数看起来像这个 (based on this post)。请注意,它仍然不处理服务器响应,只是发送:
#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**)"*/*[=12=]", 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).
我错过了什么?
这里是 the only anonfile file uploading example I've found,但它使用 curl 并且是在 C++ 中。
您的错误消息暗示代码在 InternetConnect()
.
错误代码 123 是 ERROR_INVALID_NAME
:“文件名、目录名或卷标语法不正确”。
API 要求您 post 通过 HTTPS,但您尝试连接到 HTTP 端口 80 而不是 HTTPS 端口 443。
您需要将 INTERNET_DEFAULT_HTTP_PORT
更改为 INTERNET_DEFAULT_HTTPS_PORT
。
访问安全站点时,更改为 RemyLebeau 提到的 INTERNET_DEFAULT_HTTPS_PORT
。
在HttpOpenRequest
INTERNET_FLAG_SECURE
要用"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
以实现二进制文件兼容性