Проблемы с отправкой HTTP-запросов на API-диск Discord с использованием Winsock2.h C ++ - PullRequest
0 голосов
/ 11 февраля 2020

Я копал некоторое время, чтобы посмотреть, смогу ли я найти какие-то исправления для этого, но я, кажется, врезался в стену. На данный момент, я не уверен, в чем проблема. Все остальные хосты, которые я пробовал, работали, за исключением разногласий.

WSADATA wsaData;

if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
    cout << "WSAStartup failed.\n";
    system("pause");
    return 1;
}

SOCKET Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

struct hostent* host;
host = gethostbyname("discordapp.com");

SOCKADDR_IN SockAddr;
SockAddr.sin_port = htons(80);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);

cout << "Connecting...\n"; 
if (connect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr)) != 0) {
    cout << "Could not connect";
    system("pause");
    return 1;
}
cout << "Connected.\n";

send(Socket, "GET /api/ HTTP/1.1\r\nHost: discordapp.com\r\nConnection: close\r\n\r\n", strlen("GET /api/ HTTP/1.1\r\nHost: discordapp.com\r\nConnection: close\r\n\r\n"), 0);
char buffer[10000];

int nDataLength;
while ((nDataLength = recv(Socket, buffer, 10000, 0)) > 0) {
    int i = 0;
    while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
        cout << buffer[i];
        i += 1;
    }
}

closesocket(Socket);
WSACleanup();

system("pause");
return 0;

Я продолжаю получать этот ответ, независимо от того, что я пытаюсь:

HTTP/1.1 301 Moved Permanently
Date: Mon, 10 Feb 2020 21:16:57 GMT
Transfer-Encoding: chunked
Connection: close
Cache-Control: max-age=3600
Expires: Mon, 10 Feb 2020 22:16:57 GMT
Location: https://discordapp.com/api/
Set-Cookie: __cfruid=17e1ccd526aa851f5d5563850c5793a999f859c0-1581369417; path=/; domain=.discordapp.com; HttpOnly
Server: cloudflare
CF-RAY: 56311b6b0baba67b-DUB`

Есть ли что-то, что мне не хватает? Конечная цель - иметь возможность отправлять сообщения в webhook с помощью API.

1 Ответ

1 голос
/ 11 февраля 2020

Вы подключаетесь к порту 80, делая простой (незашифрованный) HTTP-запрос GET.

Сервер отвечает HTTP-перенаправлением на https://discordapp.com/api/, т. Е. Переключает протоколы на защищенный HTTP (HTTPS).

Судя по всему, сервер не разрешает незашифрованный трафик c. Вы можете попытаться установить безопасное соединение HTTP, подключившись к порту 443 и выполнив квитирование TLS и проверив сертификат сервера (например, используя schannel ), но это не будет продуктивным. Даже в случае успеха вам придется дополнительно реализовать частичное кодирование передачи HTTP 1.1 и другие особенности протокола (большинство из которых можно пропустить, отправив запрос HTTP / 1.0, но это не главное).

Дело в том, чтобы использовать HTTP-клиентскую библиотеку для выполнения HTTP-вызовов. Windows имеет встроенный Win Inet.

Например, вот так

#include <windows.h>
#include <wininet.h>
#include <iostream>
#pragma comment(lib, "wininet.lib")
int fail(const char* fmt, ...);

int main() {
    HANDLE ih = InternetOpenA("Mozilla/4.0 (compatible)", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    if (!ih) return fail("InternetOpen failed");

    HINTERNET ch = InternetConnectA(ih, "discordapp.com", 443, NULL, NULL,
                                    INTERNET_SERVICE_HTTP, 0, 0);
    if (!ch) return fail("InternetConnect failed");

    const char* acceptTypes[] = { "*/*", NULL };
    HINTERNET req = HttpOpenRequestA(ch, NULL, "/api/", NULL, NULL, acceptTypes,
                                     INTERNET_FLAG_SECURE | INTERNET_FLAG_NO_UI, 0);
    if (!req) return fail("HttpOpenRequest failed");

    if (!HttpSendRequestA(req, NULL, 0, NULL, 0)) return fail("HttpSendRequest failed");

    char buffer[4096];
    DWORD n;
    while (InternetReadFile(req, &buffer, 1, &n)) {
        if (n == 0)
            break;
        std::cout.write(buffer, n);
    }
    std::cout << std::endl;

    InternetCloseHandle(ch);
    InternetCloseHandle(req);
    InternetCloseHandle(ih);
    return 0;
}

// helper function for printing the error message
int fail(const char* fmt, ...) {
    DWORD lastError = GetLastError();
    LPSTR lpMsgBuf = nullptr;
    if (lastError)
        FormatMessageA(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS |
            FORMAT_MESSAGE_FROM_HMODULE,
            GetModuleHandle("wininet.dll"), lastError,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPSTR)&lpMsgBuf, 0, NULL);
    va_list va;
    va_start(va, fmt);
    char buf[1024];
    _vsnprintf(buf, sizeof(buf), fmt, va);
    va_end(va);
    buf[1023] = 0;
    std::string msg = buf;
    if (lpMsgBuf) {
        msg += ": ";
        auto len = strlen(lpMsgBuf);
        while (len && (lpMsgBuf[len - 1] == '\r' || lpMsgBuf[len - 1] == '\n'))
            lpMsgBuf[--len] = 0;
        msg += lpMsgBuf;
        LocalFree(lpMsgBuf);
    }
    std::cerr << msg << std::endl;
    return 1;
}
...