Próbuję przesłać plik do AnonFile w C, używając bibliotek Wininet.

Według Ich API, musimy wysłać żądanie żądania Post HTTP określając plik do następnego adresu URL:

https://api.anonfile.com/upload

Dodatkowo przesłałem jeden plik z Curl, aby zobaczyć generowane nagłówki: https://pastebin.com/vzfhaxeya .

Tak więc moja funkcja wygląda taka ( na podstawie tego posta). Zauważ, że nadal nie obsługuje odpowiedź serwera, tylko wysyłanie:

#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;
}

Ale jakoś nie jest w stanie wykonać połączenia:

123 
(process 7652) exited with code 14. (ERROR_INTERNET_CONN).

Czego mi brakuje?

Oto Jedynym przykładem przesyłania plików anonfile Znalazłem, ale używa curl i jest w C ++.

1
mllamazares 7 marzec 2020, 20:02

2 odpowiedzi

Najlepsza odpowiedź

Podczas uzyskania dostępu do bezpiecznej witryny, zmień INTERNET_DEFAULT_HTTPS_PORT, jak wspomniano przez Remyleleau.

Użyj również INTERNET_FLAG_SECURE w HttpOpenRequest}

Aby przesłać dane za pomocą "content-type: multipart/form-data", jest to wymagane, aby owinąć dane za pomocą str_open i str_close, jak pokazano w poniższym kodzie:

Uwaga, "$$ABCXYZ$$" to jakiś przypadkowy tekst. Zmień go na coś bardziej losowego, co nie wyjdzie w pliku docelowym.

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;
}

Edytuj: Zmieniono datalen, zmieniono strlen(data) do datalen dla kompatybilności z plikami binarnymi

2
Barmak Shemirani 8 marzec 2020, 12:22

Twój komunikat o błędzie oznacza, że kod jest zawiesi na InternetConnect().

Kod błędu 123 to ERROR_INVALID_NAME: " nazwa pliku, nazwa katalogu lub składnia etykiety głośności jest nieprawidłowa ".

API wymaga wysyłania przez HTTPS, ale próbujesz połączyć się z portem HTTP 80, a nie HTTPS Port 443.

Musisz zmienić INTERNET_DEFAULT_HTTP_PORT do INTERNET_DEFAULT_HTTPS_PORT.

1
Remy Lebeau 7 marzec 2020, 19:06