Skip to content

Instantly share code, notes, and snippets.

@henkman
Last active June 10, 2018 12:53
Show Gist options
  • Save henkman/db26187c8ccf306f7e06ca5f7fcc7d12 to your computer and use it in GitHub Desktop.
Save henkman/db26187c8ccf306f7e06ca5f7fcc7d12 to your computer and use it in GitHub Desktop.
single header C api for http request
typedef struct
{
size_t size, cap;
char *data;
} Buffer;
static size_t next_power_of_two(size_t v)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
static void buffer_init(Buffer *b, size_t initial)
{
b->size = 0;
b->cap = initial;
b->data = malloc(sizeof(char) * initial);
}
static void buffer_grow(Buffer *b, size_t size)
{
size_t n = b->size + size;
if (n >= b->cap)
{
b->cap = next_power_of_two(n);
b->data = realloc(b->data, b->cap);
}
}
static void buffer_write(Buffer *b, char *data, size_t size)
{
buffer_grow(b, size);
memcpy(&b->data[b->size], data, size);
b->size += size;
}
static void buffer_reset(Buffer *b)
{
b->size = 0;
}
static void buffer_free(Buffer *b)
{
free(b->data);
}
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winhttp.h>
static int http(wchar_t *method, wchar_t *host, short port, wchar_t *path,
wchar_t *headers, unsigned char *data, size_t size,
Buffer *response)
{
int code = 0;
HINTERNET hConnect = NULL, hRequest = NULL;
HINTERNET hSession = WinHttpOpen(NULL,
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession)
{
code = 1;
goto end;
}
hConnect = WinHttpConnect(hSession, host, port, 0);
if (!hConnect)
{
code = 2;
goto end;
}
hRequest = WinHttpOpenRequest(hConnect, method, path,
NULL, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
WINHTTP_FLAG_SECURE);
if (!hRequest)
{
code = 3;
goto end;
}
DWORD dwFlags =
SECURITY_FLAG_IGNORE_UNKNOWN_CA |
SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE |
SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
if (!WinHttpSetOption(
hRequest,
WINHTTP_OPTION_SECURITY_FLAGS,
&dwFlags,
sizeof(dwFlags)))
{
code = 4;
goto end;
}
if (!WinHttpSendRequest(hRequest, headers, headers != NULL ? -1L : 0,
WINHTTP_NO_REQUEST_DATA, 0,
size, 0))
{
code = 5;
goto end;
}
if (size > 0)
{
DWORD dwBytesWritten;
if (!WinHttpWriteData(hRequest, data, size, &dwBytesWritten))
{
code = 6;
goto end;
}
}
if (!WinHttpReceiveResponse(hRequest, NULL))
{
code = 7;
goto end;
}
if (response != NULL)
{
DWORD dwDownloaded, dwSize;
do
{
if (!WinHttpQueryDataAvailable(hRequest, &dwSize) && dwSize)
break;
buffer_growby(response, dwSize);
WinHttpReadData(hRequest, (LPVOID)&response->data[response->size], dwSize, &dwDownloaded);
response->size += dwSize;
if (!dwDownloaded)
break;
} while (dwSize > 0);
}
end:
if (hRequest)
WinHttpCloseHandle(hRequest);
if (hConnect)
WinHttpCloseHandle(hConnect);
if (hSession)
WinHttpCloseHandle(hSession);
return code;
}
#else
#error "not supported"
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment