#include "../oshttpreq.inl"
#include <core/arrst.h>
#include <core/heap.h>
#include <core/stream.h>
#include <core/strings.h>
#include <sewer/bstd.h>
#include <sewer/cassert.h>
#include <sewer/ptr.h>
#include <sewer/unicode.h>
#if !defined(__WINDOWS__)
#error This file is for Windows system
#endif
#include <sewer/nowarn.hxx>
#include <Windows.h>
#include <WinInet.h>
#include <sewer/warn.hxx>
struct _oshttp_t
{
HINTERNET hInternet;
HINTERNET hConnect;
HINTERNET hRequest;
ierror_t error;
bool_t secure;
Stream *headers;
};
void oshttp_init(void)
{
}
void oshttp_finish(void)
{
}
OSHttp *oshttp_create(const char_t *host, const uint16_t port, const bool_t secure)
{
OSHttp *http = heap_new0(OSHttp);
http->secure = secure;
http->error = ekIOK;
http->hInternet = InternetOpen(L"nappgui", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
http->headers = stm_memory(1024);
stm_set_write_utf(http->headers, ekUTF16);
if (http->hInternet != NULL)
{
WCHAR whost[128];
unicode_convers(host, cast(whost, char_t), ekUTF8, ekUTF16, sizeof(whost));
http->hConnect = InternetConnect(http->hInternet, whost, (INTERNET_PORT)port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (http->hConnect == NULL)
http->error = ekINOHOST;
}
else
{
http->error = ekINONET;
}
return http;
}
void oshttp_destroy(OSHttp **http)
{
cassert_no_null(http);
cassert_no_null(*http);
if ((*http)->hRequest != NULL)
InternetCloseHandle((*http)->hRequest);
if ((*http)->hConnect != NULL)
InternetCloseHandle((*http)->hConnect);
if ((*http)->hInternet != NULL)
InternetCloseHandle((*http)->hInternet);
stm_close(&(*http)->headers);
heap_delete(http, OSHttp);
}
void oshttp_clear_headers(OSHttp *http)
{
cassert_no_null(http);
stm_close(&http->headers);
http->headers = stm_memory(1024);
stm_set_write_utf(http->headers, ekUTF16);
}
void oshttp_add_header(OSHttp *http, const char_t *name, const char_t *value)
{
cassert_no_null(http);
if (stm_bytes_written(http->headers) > 0)
stm_writef(http->headers, "\n");
stm_writef(http->headers, name);
stm_writef(http->headers, ": ");
stm_writef(http->headers, value);
}
static void i_request(OSHttp *http, const WCHAR *verb, const char_t *path, const byte_t *data, const uint32_t size, const bool_t auto_redirect, ierror_t *error)
{
WCHAR wpath[1024];
uint64_t hsize = 0;
BOOL status = FALSE;
DWORD flags = 0;
cassert_no_null(http);
if (http->error != ekIOK)
{
ptr_assign(error, http->error);
return;
}
unicode_convers(path, cast(wpath, char_t), ekUTF8, ekUTF16, sizeof(wpath));
if (http->hRequest != NULL)
{
InternetCloseHandle(http->hRequest);
http->hRequest = NULL;
}
flags |= http->secure ? INTERNET_FLAG_SECURE : 0;
flags |= auto_redirect ? 0 : INTERNET_FLAG_NO_AUTO_REDIRECT;
http->hRequest = HttpOpenRequest(http->hConnect, verb, wpath, L"HTTP/1.1", NULL, NULL, flags, 0);
if (http->hRequest == NULL)
{
ptr_assign(error, ekISERVER);
return;
}
hsize = stm_bytes_written(http->headers);
if (hsize > 0)
{
WCHAR *lpszHeaders = cast(stm_buffer(http->headers), WCHAR);
status = HttpSendRequest(http->hRequest, lpszHeaders, (DWORD)hsize / sizeof(WCHAR), (LPVOID)data, (DWORD)size);
}
else
{
status = HttpSendRequest(http->hRequest, NULL, (DWORD)-1, (LPVOID)data, (DWORD)size);
}
if (status == TRUE)
{
ptr_assign(error, ekIOK);
}
else
{
ptr_assign(error, ekISERVER);
InternetCloseHandle(http->hRequest);
http->hRequest = NULL;
}
}
void oshttp_get(OSHttp *http, const char_t *path, const byte_t *data, const uint32_t size, const bool_t auto_redirect, ierror_t *error)
{
i_request(http, L"GET", path, data, size, auto_redirect, error);
}
void oshttp_post(OSHttp *http, const char_t *path, const byte_t *data, const uint32_t size, const bool_t auto_redirect, ierror_t *error)
{
i_request(http, L"POST", path, data, size, auto_redirect, error);
}
Stream *oshttp_response(OSHttp *http)
{
cassert_no_null(http);
if (http->hRequest != NULL)
{
uint32_t i = 0;
DWORD asize = 512;
DWORD size = 512;
for (i = 0; i < 2; ++i)
{
WCHAR *data = cast(heap_malloc((uint32_t)asize, "http_headers"), WCHAR);
if (HttpQueryInfo(http->hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, (LPVOID)data, &size, NULL) == TRUE)
{
Stream *stm_src = stm_from_block(cast_const(data, byte_t), (uint32_t)size);
Stream *stm_dest = stm_memory(size + 10);
stm_set_read_utf(stm_src, ekUTF16);
stm_set_write_utf(stm_dest, ekUTF8);
stm_lines(line, stm_src)
stm_writef(stm_dest, line);
stm_write_char(stm_dest, 13);
stm_write_char(stm_dest, 10);
stm_next(line, stm_src)
heap_free(dcast(&data, byte_t), (uint32_t)asize, "http_headers");
stm_close(&stm_src);
return stm_dest;
}
else
{
heap_free(dcast(&data, byte_t), (uint32_t)asize, "http_headers");
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
asize = size;
}
else
{
cassert(FALSE);
}
}
}
}
return NULL;
}
void oshttp_response_body(OSHttp *http, Stream *body, ierror_t *error)
{
cassert_no_null(http);
if (http->hRequest != NULL)
{
char szBuffer[1024];
DWORD dwByteRead = 0;
do
{
if (InternetReadFile(http->hRequest, szBuffer, sizeof(szBuffer), &dwByteRead) == TRUE)
{
stm_write(body, cast_const(szBuffer, byte_t), (uint32_t)dwByteRead);
}
else
{
ptr_assign(error, ekISTREAM);
return;
}
} while (dwByteRead);
}
ptr_assign(error, ekIOK);
}