Jovana
Jovana

Reputation: 1

Issues sending HTTP requests to the discord api using Winsock2.h C++

I have been digging for a while to see if I can find any fixes for this but I have seemed to hit a wall. At this point, I am not sure what the issue is. Every other host I have tried has worked except for discord.

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;

I keep getting this response no matter what I try:

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`

Is there something I am missing? The ultimate goal is to be able to post to a webhook using the api.

Upvotes: 0

Views: 1244

Answers (1)

rustyx
rustyx

Reputation: 85541

You are connecting to port 80 making a plain (unencrypted) HTTP GET request.

The server replies with an HTTP redirect to https://discordapp.com/api/ i.e. switching protocols to secure HTTP (HTTPS).

Apparently the server is not allowing unencrypted traffic. You could try establishing a secure HTTP connection by connecting to port 443 and performing a TLS handshake and validating the server certificate (e.g. using schannel), but that wouldn't be productive. Even if successful, you'll have to additionally implement HTTP 1.1 chunked transfer-encoding and other protocol specifics (most of which you could skip by sending an HTTP/1.0 request, by that's not the point).

The point is, use a proper HTTP client library for making HTTP calls. Windows has a built-in one called WinInet.

For example, like this

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

Upvotes: 1

Related Questions