首页 > 解决方案 > 如何在 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++。

标签: cwinapihttp-post

解决方案


访问安全站点时,请更改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二进制文件兼容性


推荐阅读