mirror of
https://github.com/estkme-group/lpac
synced 2025-10-06 01:50:31 +02:00
Added http backend winhttp, Win32 no longer relies on the libcurl dynamic library. Co-authored-by: septs <github@septs.pw> Co-authored-by: Coelacanthus <uwu@coelacanthus.name>
169 lines
5.2 KiB
C
169 lines
5.2 KiB
C
#include "winhttp.h"
|
|
|
|
#include <inttypes.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <windows.h>
|
|
#include <winhttp.h>
|
|
|
|
#include <euicc/interface.h>
|
|
#include <lpac/utils.h>
|
|
|
|
DEFINE_TRIVIAL_CLEANUP_FUNC(HINTERNET, WinHttpCloseHandle);
|
|
|
|
static wchar_t *utf8_to_wide(const char *input) {
|
|
if (input == NULL)
|
|
return NULL;
|
|
const int n = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0);
|
|
if (n < 0)
|
|
return NULL;
|
|
wchar_t *output = calloc(n, sizeof(wchar_t));
|
|
if (output == NULL)
|
|
return NULL;
|
|
if (MultiByteToWideChar(CP_UTF8, 0, input, -1, output, n) > 0)
|
|
return output;
|
|
free(output);
|
|
return NULL;
|
|
}
|
|
|
|
static int http_interface_transmit(struct euicc_ctx *ctx, const char *url, uint32_t *rcode, uint8_t **rx,
|
|
uint32_t *rx_len, const uint8_t *tx, uint32_t tx_len, const char **h) {
|
|
int fret = 0;
|
|
_cleanup_(WinHttpCloseHandlep) HINTERNET hSession = NULL;
|
|
_cleanup_(WinHttpCloseHandlep) HINTERNET hConnect = NULL;
|
|
_cleanup_(WinHttpCloseHandlep) HINTERNET hRequest = NULL;
|
|
wchar_t hostname[256];
|
|
wchar_t pathname[128];
|
|
BOOL bResults = FALSE;
|
|
|
|
*rx = NULL;
|
|
*rx_len = 0;
|
|
*rcode = 0;
|
|
|
|
URL_COMPONENTS urlComp = {
|
|
.dwStructSize = sizeof(urlComp),
|
|
.dwHostNameLength = sizeof(hostname),
|
|
.lpszHostName = hostname,
|
|
.dwUrlPathLength = sizeof(pathname),
|
|
.lpszUrlPath = pathname,
|
|
.nPort = INTERNET_DEFAULT_HTTPS_PORT,
|
|
};
|
|
_cleanup_free_ const wchar_t *wUrl = utf8_to_wide(url);
|
|
if (wUrl == NULL)
|
|
goto error;
|
|
if (!WinHttpCrackUrl(wUrl, wcslen(wUrl), 0, &urlComp))
|
|
goto error;
|
|
|
|
hSession =
|
|
WinHttpOpen(NULL, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
|
|
if (hSession == NULL)
|
|
goto error;
|
|
|
|
hConnect = WinHttpConnect(hSession, hostname, urlComp.nPort, 0);
|
|
if (hConnect == NULL)
|
|
goto error;
|
|
|
|
hRequest = WinHttpOpenRequest(hConnect, L"POST", pathname, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES,
|
|
WINHTTP_FLAG_SECURE);
|
|
if (!hRequest)
|
|
goto error;
|
|
WinHttpSetOption(hRequest, WINHTTP_OPTION_SECURITY_FLAGS, &(DWORD){SECURITY_FLAG_IGNORE_UNKNOWN_CA}, sizeof(DWORD));
|
|
WinHttpSetOption(hRequest, WINHTTP_OPTION_REDIRECT_POLICY, &(DWORD){WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS},
|
|
sizeof(DWORD));
|
|
WinHttpSetOption(hRequest, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0);
|
|
|
|
for (int i = 0; h[i] != NULL; i++) {
|
|
_cleanup_free_ const wchar_t *wHeader = utf8_to_wide(h[i]);
|
|
if (wHeader == NULL)
|
|
goto error;
|
|
if (!WinHttpAddRequestHeaders(hRequest, wHeader, (ULONG)-1L, WINHTTP_ADDREQ_FLAG_ADD))
|
|
goto error;
|
|
}
|
|
|
|
bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, (LPVOID)tx, tx_len, tx_len, 0);
|
|
if (!bResults)
|
|
goto error;
|
|
|
|
bResults = WinHttpReceiveResponse(hRequest, NULL);
|
|
if (!bResults)
|
|
goto error;
|
|
|
|
DWORD dwStatusCode = 0;
|
|
DWORD dwSize = sizeof(dwStatusCode);
|
|
bResults = WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
|
|
WINHTTP_HEADER_NAME_BY_INDEX, &dwStatusCode, &dwSize, WINHTTP_NO_HEADER_INDEX);
|
|
if (!bResults)
|
|
goto error;
|
|
*rcode = dwStatusCode;
|
|
|
|
DWORD dwDataSize = 0, dwDownloaded = 0;
|
|
uint8_t *response_buffer = NULL;
|
|
uint32_t total_size = 0;
|
|
|
|
do {
|
|
if (!WinHttpQueryDataAvailable(hRequest, &dwDataSize)) {
|
|
fprintf(stderr, "WinHttpQueryDataAvailable error: %d\n", (int)GetLastError());
|
|
free(response_buffer);
|
|
goto error;
|
|
}
|
|
if (dwDataSize == 0)
|
|
break;
|
|
|
|
uint8_t *new_buffer = realloc(response_buffer, total_size + dwDataSize);
|
|
if (new_buffer == NULL) {
|
|
free(response_buffer);
|
|
fret = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto exit;
|
|
}
|
|
response_buffer = new_buffer;
|
|
|
|
if (!WinHttpReadData(hRequest, response_buffer + total_size, dwDataSize, &dwDownloaded)) {
|
|
fret = (int)GetLastError();
|
|
fprintf(stderr, "WinHttpReadData error: %d\n", fret);
|
|
free(response_buffer);
|
|
goto exit;
|
|
}
|
|
total_size += dwDownloaded;
|
|
} while (dwDataSize > 0);
|
|
|
|
uint8_t *final_buf = realloc(response_buffer, total_size + 1);
|
|
if (!final_buf && total_size != 0) {
|
|
free(response_buffer);
|
|
goto error;
|
|
}
|
|
if (final_buf != NULL)
|
|
final_buf[total_size] = 0;
|
|
|
|
*rx = final_buf;
|
|
*rx_len = total_size;
|
|
|
|
fret = 0;
|
|
goto exit;
|
|
|
|
error:
|
|
fret = -1;
|
|
fprintf(stderr, "WinHTTP error: %d\n", (int)GetLastError());
|
|
exit:
|
|
return fret;
|
|
}
|
|
|
|
static int libhttpinterface_init(struct euicc_http_interface *ifstruct) {
|
|
if (WinHttpCheckPlatform() == FALSE) {
|
|
return -1;
|
|
}
|
|
|
|
memset(ifstruct, 0, sizeof(struct euicc_http_interface));
|
|
ifstruct->transmit = http_interface_transmit;
|
|
|
|
return 0;
|
|
}
|
|
|
|
const struct euicc_driver driver_http_winhttp = {
|
|
.type = DRIVER_HTTP,
|
|
.name = "winhttp",
|
|
.init = (int (*)(void *))libhttpinterface_init,
|
|
.main = NULL,
|
|
.fini = NULL,
|
|
};
|