Meta: Add files to repository
This commit is contained in:
parent
6d27d43268
commit
52cb92f587
120 changed files with 71820 additions and 0 deletions
88
System/Libraries/Base64.HC
Normal file
88
System/Libraries/Base64.HC
Normal file
|
@ -0,0 +1,88 @@
|
|||
|
||||
U8* @base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
U8* @base64_decode(U8* input, I64* output_length)
|
||||
{
|
||||
I64 input_length = StrLen(input);
|
||||
if (input_length % 4 != 0) {
|
||||
return NULL; // Invalid Base64 input length
|
||||
}
|
||||
|
||||
// Calculate the expected output length
|
||||
*output_length = (3 * input_length) / 4;
|
||||
if (input[input_length - 1] == '=') {
|
||||
(*output_length)--;
|
||||
}
|
||||
if (input[input_length - 2] == '=') {
|
||||
(*output_length)--;
|
||||
}
|
||||
|
||||
// Allocate memory for the decoded data
|
||||
U8* decoded_data = CAlloc(*output_length, adam_task);
|
||||
if (decoded_data == NULL) {
|
||||
return NULL; // Memory allocation failed
|
||||
}
|
||||
|
||||
// Initialize variables for decoding process
|
||||
I32 i, j = 0;
|
||||
U32 sextet_bits = 0;
|
||||
I64 sextet_count = 0;
|
||||
U32 base64_value;
|
||||
U8* char_pointer;
|
||||
U8 input_find_buf[2];
|
||||
input_find_buf[1] = NULL;
|
||||
|
||||
// Loop through the Base64 input and decode it
|
||||
for (i = 0; i < input_length; i++) {
|
||||
// Convert Base64 character to a 6-bit value
|
||||
base64_value = 0;
|
||||
if (input[i] == '=') {
|
||||
base64_value = 0;
|
||||
} else {
|
||||
input_find_buf[0] = input[i];
|
||||
char_pointer = StrFirstOcc(@base64_chars, input_find_buf);
|
||||
if (char_pointer == NULL) {
|
||||
Free(decoded_data);
|
||||
return NULL; // Invalid Base64 character
|
||||
}
|
||||
base64_value = char_pointer - @base64_chars;
|
||||
}
|
||||
|
||||
// Combine 6-bit values into a 24-bit sextet
|
||||
sextet_bits = (sextet_bits << 6) | base64_value;
|
||||
sextet_count++;
|
||||
|
||||
// When a sextet is complete, decode it into three bytes
|
||||
if (sextet_count == 4) {
|
||||
decoded_data[j++] = (sextet_bits >> 16) & 0xFF;
|
||||
decoded_data[j++] = (sextet_bits >> 8) & 0xFF;
|
||||
decoded_data[j++] = sextet_bits & 0xFF;
|
||||
sextet_bits = 0;
|
||||
sextet_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return decoded_data;
|
||||
}
|
||||
|
||||
U8* @base64_encode(U8* input, I64 input_length)
|
||||
{
|
||||
I64 i;
|
||||
U8 buf[3];
|
||||
I64 c = 0;
|
||||
U8* output = CAlloc(input_length * 2, adam_task);
|
||||
|
||||
for (i = 0; i < input_length; i += 3) {
|
||||
buf[0] = input[i];
|
||||
buf[1] = @t((i + 1 < input_length), input[i + 1], 0);
|
||||
buf[2] = @t((i + 2 < input_length), input[i + 2], 0);
|
||||
|
||||
output[c++] = @base64_chars[(buf[0] & 0xfc) >> 2];
|
||||
output[c++] = @base64_chars[((buf[0] & 0x03) << 4) + ((buf[1] & 0xf0) >> 4)];
|
||||
output[c++] = @t((i + 1 < input_length), @base64_chars[((buf[1] & 0x0f) << 2) + ((buf[2] & 0xc0) >> 6)], '=');
|
||||
output[c++] = @t((i + 2 < input_length), @base64_chars[buf[2] & 0x3f], '=');
|
||||
}
|
||||
|
||||
output[c] = '\0';
|
||||
return output;
|
||||
}
|
628
System/Libraries/Http.HC
Normal file
628
System/Libraries/Http.HC
Normal file
|
@ -0,0 +1,628 @@
|
|||
#define HTTP_TMP_DIRECTORY "B:/Tmp"
|
||||
#define HTTP_CACHE_DIRECTORY "B:/Tmp/Cache"
|
||||
#define HTTP_FETCH_BUFFER_SIZE 1024 << 15
|
||||
|
||||
#define SEDECIM_USER_AGENT_STRING "Mozilla/5.0 (compatible; Sedecim/1.0; TempleOS) (KHTML, like Gecko)"
|
||||
|
||||
class @http_buffer
|
||||
{
|
||||
I64 length;
|
||||
U8* data;
|
||||
};
|
||||
|
||||
class @http_status
|
||||
{
|
||||
U8* protocol;
|
||||
I64 code;
|
||||
U8* text;
|
||||
};
|
||||
|
||||
class @http_response
|
||||
{
|
||||
I64 state;
|
||||
TlsSocket* s;
|
||||
@http_status status;
|
||||
JsonObject* headers;
|
||||
@http_buffer body;
|
||||
Bool headers_parsed;
|
||||
};
|
||||
|
||||
class @http_url
|
||||
{
|
||||
U8* scheme;
|
||||
U8* host;
|
||||
I64 port;
|
||||
U8* path;
|
||||
U8* query;
|
||||
U8* fragment;
|
||||
};
|
||||
|
||||
class @http_request
|
||||
{
|
||||
@http_url* url;
|
||||
U8* buf;
|
||||
U8* data;
|
||||
I64 type;
|
||||
JsonObject* headers;
|
||||
@http_response* response;
|
||||
};
|
||||
|
||||
#define HttpResponse @http_response
|
||||
#define HttpUrl @http_url
|
||||
|
||||
#define HTTP_FETCH_BUFFER_SIZE 16777216
|
||||
|
||||
#define HTTP_PARSE_SCHEME 0
|
||||
#define HTTP_PARSE_SCHEME_FS 1
|
||||
#define HTTP_PARSE_HOST 2
|
||||
#define HTTP_PARSE_PORT 3
|
||||
#define HTTP_PARSE_PATH 4
|
||||
#define HTTP_PARSE_QUERY 5
|
||||
#define HTTP_PARSE_FRAGMENT 6
|
||||
|
||||
#define HTTP_MIN_REQUEST_BUFFER_SIZE 16384
|
||||
#define HTTP_PARSE_URL_FIFO_SIZE 1024
|
||||
|
||||
#define HTTP_REQ_GET 0
|
||||
#define HTTP_REQ_HEAD 1
|
||||
#define HTTP_REQ_POST 2
|
||||
#define HTTP_REQ_PUT 3
|
||||
|
||||
#define HTTP_STATE_UNSENT 0
|
||||
#define HTTP_STATE_OPENED 1
|
||||
#define HTTP_STATE_HEADERS_RECEIVED 2
|
||||
#define HTTP_STATE_LOADING 3
|
||||
#define HTTP_STATE_DONE 4
|
||||
|
||||
U8* @http_string_from_fifo(CFifoU8* f)
|
||||
{
|
||||
U8 ch;
|
||||
I64 i = 0;
|
||||
U8* str = CAlloc(FifoU8Cnt(f) + 1, adam_task);
|
||||
while (FifoU8Cnt(f)) {
|
||||
FifoU8Rem(f, &ch);
|
||||
str[i] = ch;
|
||||
i++;
|
||||
}
|
||||
FifoU8Flush(f);
|
||||
return str;
|
||||
}
|
||||
|
||||
U0 @http_free_url(@http_url* url)
|
||||
{
|
||||
if (!url)
|
||||
return;
|
||||
if (url->scheme)
|
||||
Free(url->scheme);
|
||||
if (url->host)
|
||||
Free(url->host);
|
||||
if (url->path)
|
||||
Free(url->path);
|
||||
if (url->query)
|
||||
Free(url->query);
|
||||
if (url->fragment)
|
||||
Free(url->fragment);
|
||||
Free(url);
|
||||
}
|
||||
|
||||
U0 @http_free_response(@http_response* resp)
|
||||
{
|
||||
if (!resp)
|
||||
return;
|
||||
// FIXME: Free response headers JSON object
|
||||
Free(resp);
|
||||
}
|
||||
|
||||
@http_url* @http_parse_url(U8* str)
|
||||
{
|
||||
if (!str)
|
||||
return NULL;
|
||||
U8* buf = NULL;
|
||||
U8 hex[3];
|
||||
I64 i = 0;
|
||||
I64 state = HTTP_PARSE_SCHEME;
|
||||
CFifoU8* consume_fifo = FifoU8New(HTTP_PARSE_URL_FIFO_SIZE, adam_task);
|
||||
@http_url* url = CAlloc(sizeof(@http_url), adam_task);
|
||||
while (1) {
|
||||
switch (str[i]) {
|
||||
case 0:
|
||||
switch (state) {
|
||||
case HTTP_PARSE_HOST:
|
||||
url->host = @http_string_from_fifo(consume_fifo);
|
||||
url->path = StrNew("/", adam_task);
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
case HTTP_PARSE_PORT:
|
||||
buf = @http_string_from_fifo(consume_fifo);
|
||||
url->port = Str2I64(buf);
|
||||
Free(buf);
|
||||
url->path = StrNew("/", adam_task);
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
case HTTP_PARSE_PATH:
|
||||
url->path = @http_string_from_fifo(consume_fifo);
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
case HTTP_PARSE_QUERY:
|
||||
url->query = @http_string_from_fifo(consume_fifo);
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
case HTTP_PARSE_FRAGMENT:
|
||||
url->fragment = @http_string_from_fifo(consume_fifo);
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
default:
|
||||
goto done_parsing_url;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '#':
|
||||
switch (state) {
|
||||
case HTTP_PARSE_PATH:
|
||||
url->path = @http_string_from_fifo(consume_fifo);
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
state = HTTP_PARSE_FRAGMENT;
|
||||
break;
|
||||
case HTTP_PARSE_QUERY:
|
||||
url->query = @http_string_from_fifo(consume_fifo);
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
state = HTTP_PARSE_FRAGMENT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
switch (state) {
|
||||
case HTTP_PARSE_PATH:
|
||||
url->path = @http_string_from_fifo(consume_fifo);
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
state = HTTP_PARSE_QUERY;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
switch (state) {
|
||||
case HTTP_PARSE_SCHEME:
|
||||
state = HTTP_PARSE_SCHEME_FS;
|
||||
goto keep_consuming_url_chars;
|
||||
break;
|
||||
case HTTP_PARSE_SCHEME_FS:
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
url->scheme = @http_string_from_fifo(consume_fifo);
|
||||
if (!StrCmp(url->scheme, "http://"))
|
||||
url->port = 80;
|
||||
if (!StrCmp(url->scheme, "https://"))
|
||||
url->port = 443;
|
||||
state = HTTP_PARSE_HOST;
|
||||
break;
|
||||
case HTTP_PARSE_HOST:
|
||||
url->host = @http_string_from_fifo(consume_fifo);
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
state = HTTP_PARSE_PATH;
|
||||
break;
|
||||
case HTTP_PARSE_PORT:
|
||||
buf = @http_string_from_fifo(consume_fifo);
|
||||
url->port = Str2I64(buf);
|
||||
Free(buf);
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
state = HTTP_PARSE_PATH;
|
||||
break;
|
||||
case HTTP_PARSE_PATH:
|
||||
goto keep_consuming_url_chars;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ':':
|
||||
switch (state) {
|
||||
case HTTP_PARSE_SCHEME:
|
||||
case HTTP_PARSE_PATH:
|
||||
case HTTP_PARSE_QUERY:
|
||||
case HTTP_PARSE_FRAGMENT:
|
||||
goto keep_consuming_url_chars;
|
||||
break;
|
||||
case HTTP_PARSE_HOST:
|
||||
url->host = @http_string_from_fifo(consume_fifo);
|
||||
state = HTTP_PARSE_PORT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
keep_consuming_url_chars:
|
||||
switch (state) {
|
||||
case HTTP_PARSE_PATH:
|
||||
case HTTP_PARSE_QUERY:
|
||||
switch (str[i]) {
|
||||
case '0' ... '9':
|
||||
case 'A' ... 'Z':
|
||||
case 'a' ... 'z':
|
||||
case '?':
|
||||
case '&':
|
||||
case '/':
|
||||
case '=':
|
||||
// !'()*-._~
|
||||
case '!':
|
||||
case '\'':
|
||||
case '(':
|
||||
case ')':
|
||||
case '*':
|
||||
case '-':
|
||||
case '.':
|
||||
case '_':
|
||||
case '~':
|
||||
case '%':
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
break;
|
||||
default:
|
||||
FifoU8Ins(consume_fifo, '%');
|
||||
StrPrint(hex, "%02X", str[i]);
|
||||
FifoU8Ins(consume_fifo, hex[0]);
|
||||
FifoU8Ins(consume_fifo, hex[1]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
FifoU8Ins(consume_fifo, str[i]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
done_parsing_url:
|
||||
FifoU8Flush(consume_fifo);
|
||||
FifoU8Del(consume_fifo);
|
||||
return url;
|
||||
}
|
||||
|
||||
U0 @http_parse_response_headers(@http_response* resp, U8* buffer, I64 length)
|
||||
{
|
||||
if (!resp || !buffer || !length)
|
||||
return;
|
||||
U64 response_data_ptr = StrFind("\r\n\r\n", buffer);
|
||||
if (!response_data_ptr)
|
||||
return;
|
||||
resp->body.data = response_data_ptr + 4;
|
||||
resp->body.data[-4] = NULL;
|
||||
JsonObject* headers = Json.CreateObject();
|
||||
U8** lines = NULL;
|
||||
I64 lines_count = 0;
|
||||
I64 i;
|
||||
I64 j;
|
||||
U8* key_ptr = NULL;
|
||||
U8* value_ptr = NULL;
|
||||
lines = String.Split(buffer, '\n', &lines_count);
|
||||
|
||||
U8* resp_protocol = lines[0];
|
||||
U8* resp_status_code = StrFind(" ", resp_protocol) + 1;
|
||||
U8* resp_text = StrFind(" ", resp_status_code + 1);
|
||||
(*StrFind(" ", resp_protocol)) = NULL;
|
||||
(*StrFind(" ", resp_status_code)) = NULL;
|
||||
|
||||
resp->status.protocol = StrNew(resp_protocol, adam_task);
|
||||
resp->status.code = Str2I64(resp_status_code);
|
||||
resp->status.text = StrNew(resp_text, adam_task);
|
||||
|
||||
for (i = 1; i < lines_count; i++) {
|
||||
for (j = 0; j < StrLen(lines[i]); j++) {
|
||||
if (lines[i][j] == ':' && lines[i][j + 1] == ' ') {
|
||||
lines[i][j] = NULL;
|
||||
key_ptr = lines[i];
|
||||
value_ptr = lines[i] + j + 2;
|
||||
(*StrFind("\r", value_ptr)) = NULL;
|
||||
Json.Set(headers, key_ptr, StrNew(value_ptr, adam_task), JSON_STRING);
|
||||
goto @http_next_header_line;
|
||||
}
|
||||
}
|
||||
@http_next_header_line:
|
||||
}
|
||||
resp->headers = headers;
|
||||
resp->headers_parsed = TRUE;
|
||||
}
|
||||
|
||||
Bool @http_detect_response_headers(U8* buf, I64 len)
|
||||
{
|
||||
if (len < 4)
|
||||
return FALSE;
|
||||
I64 i;
|
||||
for (i = 0; i < len - 4; i++) {
|
||||
if (!MemCmp(buf + i, "\r\n\r\n", 4))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I64 @http_req(@http_request* req)
|
||||
{
|
||||
if (!req)
|
||||
return NULL;
|
||||
if (!req->url || !req->buf || !req->response)
|
||||
return NULL;
|
||||
if (!req->url->scheme || !req->url->host || !req->url->path)
|
||||
return NULL;
|
||||
if (req->type == HTTP_REQ_POST && !req->data)
|
||||
return NULL;
|
||||
if (req->type == HTTP_REQ_PUT && !req->data)
|
||||
return NULL;
|
||||
|
||||
@http_response* resp = req->response;
|
||||
|
||||
U8* buf = NULL;
|
||||
U8* headers_buf = "";
|
||||
I64 cnt = 1;
|
||||
I64 len = NULL;
|
||||
|
||||
buf = CAlloc(HTTP_MIN_REQUEST_BUFFER_SIZE, adam_task);
|
||||
if (req->headers) {
|
||||
headers_buf = CAlloc(HTTP_MIN_REQUEST_BUFFER_SIZE, adam_task);
|
||||
JsonKey* key = req->headers->keys;
|
||||
while (key) {
|
||||
StrPrint(headers_buf + StrLen(headers_buf), "%s: %s\r\n", key->name, key->value);
|
||||
key = key->next;
|
||||
}
|
||||
}
|
||||
|
||||
switch (req->type) {
|
||||
case HTTP_REQ_GET:
|
||||
StrPrint(buf,
|
||||
"GET %s%s HTTP/1.0\r\n"
|
||||
"Host: %s\r\n"
|
||||
"%s"
|
||||
"User-Agent: " SEDECIM_USER_AGENT_STRING
|
||||
"\r\n\r\n",
|
||||
req->url->path, req->url->query, req->url->host, headers_buf);
|
||||
break;
|
||||
case HTTP_REQ_HEAD:
|
||||
StrPrint(buf,
|
||||
"HEAD %s%s HTTP/1.0\r\n"
|
||||
"Host: %s\r\n"
|
||||
"%s"
|
||||
"User-Agent: " SEDECIM_USER_AGENT_STRING
|
||||
"\r\n\r\n",
|
||||
req->url->path, req->url->query, req->url->host, headers_buf);
|
||||
break;
|
||||
case HTTP_REQ_POST:
|
||||
StrPrint(buf,
|
||||
"POST %s%s HTTP/1.0\r\n"
|
||||
"Host: %s\r\n"
|
||||
"%s"
|
||||
"User-Agent: " SEDECIM_USER_AGENT_STRING
|
||||
"\r\n"
|
||||
"Content-Length: %d\r\n\r\n",
|
||||
req->url->path, req->url->query, req->url->host, headers_buf,
|
||||
StrLen(req->data));
|
||||
StrPrint(buf + StrLen(buf), req->data);
|
||||
break;
|
||||
case HTTP_REQ_PUT:
|
||||
StrPrint(buf,
|
||||
"PUT %s%s HTTP/1.0\r\n"
|
||||
"Host: %s\r\n"
|
||||
"%s"
|
||||
"User-Agent: " SEDECIM_USER_AGENT_STRING
|
||||
"\r\n"
|
||||
"Content-Length: %d\r\n\r\n",
|
||||
req->url->path, req->url->query, req->url->host, headers_buf,
|
||||
StrLen(req->data));
|
||||
StrPrint(buf + StrLen(buf), req->data);
|
||||
break;
|
||||
}
|
||||
|
||||
TlsSocket* s = NULL;
|
||||
resp->s = NULL;
|
||||
|
||||
if (!StrCmp(req->url->scheme, "http://")) {
|
||||
s = @tcp_socket_create(req->url->host, req->url->port);
|
||||
resp->s = s;
|
||||
while (s->state != TCP_SOCKET_STATE_ESTABLISHED)
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
if (!StrCmp(req->url->scheme, "https://")) {
|
||||
s = @tls_socket_create(req->url->host, req->url->port);
|
||||
resp->s = s;
|
||||
while (!@tls_established(s->ctx))
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
resp->state = HTTP_STATE_OPENED;
|
||||
s->send(buf, StrLen(buf));
|
||||
while (cnt || s->state != TCP_SOCKET_STATE_CLOSED) {
|
||||
cnt = s->receive(req->buf + len, 1024);
|
||||
len += cnt;
|
||||
switch (resp->state) {
|
||||
case HTTP_STATE_LOADING:
|
||||
resp->body.length += cnt;
|
||||
break;
|
||||
case HTTP_STATE_HEADERS_RECEIVED:
|
||||
resp->body.length = (req->buf + len) - resp->body.data;
|
||||
resp->state = HTTP_STATE_LOADING;
|
||||
break;
|
||||
case HTTP_STATE_OPENED:
|
||||
if (@http_detect_response_headers(req->buf, len)) {
|
||||
@http_parse_response_headers(resp, req->buf, len);
|
||||
resp->state = HTTP_STATE_HEADERS_RECEIVED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
if (!resp->headers_parsed)
|
||||
@http_parse_response_headers(resp, req->buf, len);
|
||||
resp->state = HTTP_STATE_DONE;
|
||||
req->buf[len] = NULL;
|
||||
Free(buf);
|
||||
if (StrLen(headers_buf) > 0) {
|
||||
Free(headers_buf);
|
||||
}
|
||||
s->close();
|
||||
resp->s = NULL;
|
||||
Free(req);
|
||||
return len;
|
||||
}
|
||||
|
||||
Bool @http_scheme_is_https(@http_url* url)
|
||||
{
|
||||
if (!url || !url->scheme)
|
||||
return FALSE;
|
||||
return !MemCmp(url->scheme, "https", 5);
|
||||
}
|
||||
|
||||
@http_response* @http_get(@http_url* url, U8* buf, U64 return_req = NULL, JsonObject* headers = NULL)
|
||||
{
|
||||
@http_response* resp = CAlloc(sizeof(@http_response), adam_task);
|
||||
@http_request* req = CAlloc(sizeof(@http_request), adam_task);
|
||||
if (return_req)
|
||||
MemCpy(return_req, &req, sizeof(U64));
|
||||
req->url = url;
|
||||
req->buf = buf;
|
||||
req->type = HTTP_REQ_GET;
|
||||
req->headers = headers;
|
||||
req->response = resp;
|
||||
Spawn(&@http_req, req, "HTTPGetRequest");
|
||||
return resp;
|
||||
}
|
||||
|
||||
@http_response* @http_head(@http_url* url, U8* buf, JsonObject* headers = NULL)
|
||||
{
|
||||
@http_response* resp = CAlloc(sizeof(@http_response), adam_task);
|
||||
@http_request* req = CAlloc(sizeof(@http_request), adam_task);
|
||||
req->url = url;
|
||||
req->buf = buf;
|
||||
req->type = HTTP_REQ_HEAD;
|
||||
req->headers = headers;
|
||||
req->response = resp;
|
||||
Spawn(&@http_req, req, "HTTPHeadRequest");
|
||||
return resp;
|
||||
}
|
||||
|
||||
@http_response* @http_post(@http_url* url, U8* buf, U8* data, JsonObject* headers = NULL)
|
||||
{
|
||||
@http_response* resp = CAlloc(sizeof(@http_response), adam_task);
|
||||
@http_request* req = CAlloc(sizeof(@http_request), adam_task);
|
||||
req->url = url;
|
||||
req->buf = buf;
|
||||
req->type = HTTP_REQ_POST;
|
||||
req->headers = headers;
|
||||
req->data = data;
|
||||
req->response = resp;
|
||||
Spawn(&@http_req, req, "HTTPPostRequest");
|
||||
return resp;
|
||||
}
|
||||
|
||||
@http_response* @http_put(@http_url* url, U8* buf, U8* data, JsonObject* headers = NULL)
|
||||
{
|
||||
@http_response* resp = CAlloc(sizeof(@http_response), adam_task);
|
||||
@http_request* req = CAlloc(sizeof(@http_request), adam_task);
|
||||
req->url = url;
|
||||
req->buf = buf;
|
||||
req->type = HTTP_REQ_PUT;
|
||||
req->headers = headers;
|
||||
req->data = data;
|
||||
req->response = resp;
|
||||
Spawn(&@http_req, req, "HTTPPutRequest");
|
||||
return resp;
|
||||
}
|
||||
|
||||
class @http
|
||||
{
|
||||
@http_response* (*Get)(@http_url* url, U8* buf, U64* req = NULL, JsonObject* headers = NULL);
|
||||
@http_response* (*Head)(@http_url* url, U8* buf, JsonObject* headers = NULL);
|
||||
@http_response* (*Post)(@http_url* url, U8* buf, U8* data, JsonObject* headers = NULL);
|
||||
@http_response* (*Put)(@http_url* url, U8* buf, U8* data, JsonObject* headers = NULL);
|
||||
};
|
||||
|
||||
@http Http;
|
||||
|
||||
Http.Get = &@http_get;
|
||||
Http.Head = &@http_head;
|
||||
Http.Post = &@http_post;
|
||||
Http.Put = &@http_put;
|
||||
|
||||
Bool @http_is_resource_cached(U8* src, U8* cache_directory = HTTP_CACHE_DIRECTORY)
|
||||
{
|
||||
U8 buf[512];
|
||||
U8* src_md5 = md5_string(src, StrLen(src));
|
||||
StrCpy(buf, cache_directory);
|
||||
StrPrint(buf + StrLen(buf), "/%s", src_md5);
|
||||
Free(src_md5);
|
||||
return FileFind(buf);
|
||||
}
|
||||
|
||||
U0 @http_cache_resource(U8* src, U8* data, I64 size, U8* cache_directory = HTTP_CACHE_DIRECTORY)
|
||||
{
|
||||
U8 buf[512];
|
||||
U8* src_md5 = md5_string(src, StrLen(src));
|
||||
StrCpy(buf, cache_directory);
|
||||
StrPrint(buf + StrLen(buf), "/%s", src_md5);
|
||||
Free(src_md5);
|
||||
FileWrite(buf, data, size);
|
||||
}
|
||||
|
||||
U8* @http_get_cached_resource_filename(U8* src, U8* cache_directory = HTTP_CACHE_DIRECTORY)
|
||||
{
|
||||
U8* buf = CAlloc(512, adam_task);
|
||||
U8* src_md5 = md5_string(src, StrLen(src));
|
||||
StrCpy(buf, cache_directory);
|
||||
StrPrint(buf + StrLen(buf), "/%s", src_md5);
|
||||
Free(src_md5);
|
||||
return buf;
|
||||
}
|
||||
|
||||
U0 @http_init_tmp_and_cache_directories()
|
||||
{
|
||||
if (!FileFind(HTTP_TMP_DIRECTORY))
|
||||
DirMk(HTTP_TMP_DIRECTORY);
|
||||
if (!FileFind(HTTP_CACHE_DIRECTORY))
|
||||
DirMk(HTTP_CACHE_DIRECTORY);
|
||||
}
|
||||
|
||||
@http_response* fetch(U8* url_string, U8* fetch_buffer)
|
||||
{
|
||||
if (!url_string || !fetch_buffer)
|
||||
return NULL;
|
||||
HttpUrl* url = @http_parse_url(url_string);
|
||||
if (!url)
|
||||
return NULL;
|
||||
@http_response* resp = Http.Get(url, fetch_buffer);
|
||||
while (resp->state != HTTP_STATE_DONE)
|
||||
Sleep(1);
|
||||
return resp;
|
||||
}
|
||||
|
||||
I64 curl(U8* url_string)
|
||||
{
|
||||
if (!url_string)
|
||||
return 0;
|
||||
U8* fetch_buffer = CAlloc(HTTP_FETCH_BUFFER_SIZE, adam_task);
|
||||
@http_response* resp = fetch(url_string, fetch_buffer);
|
||||
if (!resp)
|
||||
return 0;
|
||||
if (resp->body.length) {
|
||||
U8* buf = resp->body.data;
|
||||
while (*buf) {
|
||||
if (*buf == '\d')
|
||||
"\d\d";
|
||||
else
|
||||
"%c", *buf;
|
||||
++buf;
|
||||
}
|
||||
"\n";
|
||||
}
|
||||
Free(fetch_buffer);
|
||||
return resp->body.length;
|
||||
}
|
||||
|
||||
I64 download(U8* path, U8* url_string)
|
||||
{
|
||||
if (!path || !url_string)
|
||||
return 0;
|
||||
U8* fetch_buffer = CAlloc(HTTP_FETCH_BUFFER_SIZE, adam_task);
|
||||
@http_response* resp = fetch(url_string, fetch_buffer);
|
||||
if (!resp)
|
||||
return 0;
|
||||
if (resp->body.length) {
|
||||
FileWrite(path, resp->body.data, resp->body.length);
|
||||
}
|
||||
Free(fetch_buffer);
|
||||
return resp->body.length;
|
||||
}
|
||||
|
||||
@http_init_tmp_and_cache_directories;
|
1354
System/Libraries/Json.HC
Normal file
1354
System/Libraries/Json.HC
Normal file
File diff suppressed because it is too large
Load diff
44
System/Libraries/Rsa.HC
Normal file
44
System/Libraries/Rsa.HC
Normal file
|
@ -0,0 +1,44 @@
|
|||
Silent(1); // This is needed to suppress "Function should return val" warnings for wrappers to non-HolyC functions
|
||||
|
||||
I64 @rsa_import(U8* der_bytes, I64 der_len, U64 key)
|
||||
{
|
||||
U64 reg RDI rdi = der_bytes;
|
||||
U64 reg RSI rsi = der_len;
|
||||
U64 reg RDX rdx = key;
|
||||
no_warn rdi, rsi, rdx;
|
||||
asm {
|
||||
MOV RAX, RSA_IMPORT
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I64 @rsa_create_signature(U8* sig, I64* siglen, U8* hash, I64 hashlen, U64 key)
|
||||
{
|
||||
U64 reg RDI rdi = sig;
|
||||
U64 reg RSI rsi = siglen;
|
||||
U64 reg RDX rdx = hash;
|
||||
U64 reg RCX rcx = hashlen;
|
||||
U64 reg R8 r8 = key;
|
||||
no_warn rdi, rsi, rdx, rcx, r8;
|
||||
asm {
|
||||
MOV RAX, RSA_CREATE_SIGNATURE
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I64 @rsa_verify_signature(U8* sig, I64 siglen, U8* hash, I64 hashlen, I32* stat, U64 key)
|
||||
{
|
||||
U64 reg RDI rdi = sig;
|
||||
U64 reg RSI rsi = siglen;
|
||||
U64 reg RDX rdx = hash;
|
||||
U64 reg RCX rcx = hashlen;
|
||||
U64 reg R8 r8 = stat;
|
||||
U64 reg R9 r9 = key;
|
||||
no_warn rdi, rsi, rdx, rcx, r8, r9;
|
||||
asm {
|
||||
MOV RAX, RSA_VERIFY_SIGNATURE
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
Silent(0);
|
233
System/Libraries/Sha256.HC
Normal file
233
System/Libraries/Sha256.HC
Normal file
|
@ -0,0 +1,233 @@
|
|||
#define CHUNK_SIZE 64
|
||||
#define TOTAL_LEN_LEN 8
|
||||
|
||||
/*
|
||||
* ABOUT bool: this file does not use bool in order to be as pre-C99 compatible
|
||||
* as possible.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Comments from pseudo-code at https://en.wikipedia.org/wiki/SHA-2 are
|
||||
* reproduced here. When useful for clarification, portions of the pseudo-code
|
||||
* are reproduced here too.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initialize array of round constants:
|
||||
* (first 32 bits of the fractional parts of the cube roots of the first 64
|
||||
* primes 2..311):
|
||||
*/
|
||||
U32 k[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
||||
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
||||
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
||||
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
U32 _h[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
|
||||
|
||||
class buffer_state {
|
||||
U8* p;
|
||||
I32 len;
|
||||
I32 total_len;
|
||||
I32 single_one_delivered; /* bool */
|
||||
I32 total_len_delivered; /* bool */
|
||||
};
|
||||
|
||||
U32 right_rot(U32 value, U32 count)
|
||||
{
|
||||
/*
|
||||
* Defined behaviour in standard C for all count where 0 < count < 32,
|
||||
* which is what we need here.
|
||||
*/
|
||||
return value >> count | value << (32 - count);
|
||||
}
|
||||
|
||||
U0 init_buf_state(buffer_state* state, U8* input, I32 len)
|
||||
{
|
||||
state->p = input;
|
||||
state->len = len;
|
||||
state->total_len = len;
|
||||
state->single_one_delivered = 0;
|
||||
state->total_len_delivered = 0;
|
||||
}
|
||||
|
||||
/* Return value: bool */
|
||||
I32 calc_chunk(U8* chunk, buffer_state* state)
|
||||
{
|
||||
I32 space_in_chunk;
|
||||
|
||||
if (state->total_len_delivered) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (state->len >= CHUNK_SIZE) {
|
||||
MemCpy(chunk, state->p, CHUNK_SIZE);
|
||||
state->p += CHUNK_SIZE;
|
||||
state->len -= CHUNK_SIZE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
MemCpy(chunk, state->p, state->len);
|
||||
chunk += state->len;
|
||||
space_in_chunk = CHUNK_SIZE - state->len;
|
||||
state->p += state->len;
|
||||
state->len = 0;
|
||||
|
||||
/* If we are here, space_in_chunk is one at minimum. */
|
||||
if (!state->single_one_delivered) {
|
||||
*chunk++ = 0x80;
|
||||
space_in_chunk -= 1;
|
||||
state->single_one_delivered = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now:
|
||||
* - either there is enough space left for the total length, and we can
|
||||
* conclude,
|
||||
* - or there is too little space left, and we have to pad the rest of this
|
||||
* chunk with zeroes. In the latter case, we will conclude at the next
|
||||
* invokation of this function.
|
||||
*/
|
||||
if (space_in_chunk >= TOTAL_LEN_LEN) {
|
||||
I32 left = space_in_chunk - TOTAL_LEN_LEN;
|
||||
I32 len = state->total_len;
|
||||
I32 i;
|
||||
MemSet(chunk, 0x00, left);
|
||||
chunk += left;
|
||||
|
||||
/* Storing of len * 8 as a big endian 64-bit without overflow. */
|
||||
chunk[7] = (len << 3);
|
||||
len >>= 5;
|
||||
for (i = 6; i >= 0; i--) {
|
||||
chunk[i] = len;
|
||||
len >>= 8;
|
||||
}
|
||||
state->total_len_delivered = 1;
|
||||
} else {
|
||||
MemSet(chunk, 0x00, space_in_chunk);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Limitations:
|
||||
* - Since input is a pointer in RAM, the data to hash should be in RAM, which
|
||||
* could be a problem for large data sizes.
|
||||
* - SHA algorithms theoretically operate on bit strings. However, this
|
||||
* implementation has no support for bit string lengths that are not multiples
|
||||
* of eight, and it really operates on arrays of bytes. In particular, the len
|
||||
* parameter is a number of bytes.
|
||||
*/
|
||||
U0 calc_sha_256(U8* hash, U8* input, I32 len)
|
||||
{
|
||||
/*
|
||||
* Note 1: All integers (expect indexes) are 32-bit U32 integers and addition
|
||||
* is calculated modulo 2^32. Note 2: For each round, there is one round
|
||||
* constant k[i] and one entry in the message schedule array w[i], 0 = i = 63
|
||||
* Note 3: The compression function uses 8 working variables, a through h
|
||||
* Note 4: Big-endian convention is used when expressing the constants in this
|
||||
* pseudocode, and when parsing message block data from bytes to words, for
|
||||
* example, the first word of the input message "abc" after padding is
|
||||
* 0x61626380
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initialize hash values:
|
||||
* (first 32 bits of the fractional parts of the square roots of the first 8
|
||||
* primes 2..19):
|
||||
*/
|
||||
|
||||
U32 h[8];
|
||||
U32 i, j;
|
||||
MemCpy(h, _h, sizeof(U32) * 8);
|
||||
|
||||
/* 512-bit chunks is what we will operate on. */
|
||||
U8 chunk[64];
|
||||
|
||||
buffer_state state;
|
||||
|
||||
init_buf_state(&state, input, len);
|
||||
|
||||
while (calc_chunk(chunk, &state)) {
|
||||
U32 ah[8];
|
||||
|
||||
U8* p = chunk;
|
||||
|
||||
/* Initialize working variables to current hash value: */
|
||||
for (i = 0; i < 8; i++)
|
||||
ah[i] = h[i];
|
||||
|
||||
/* Compression function main loop: */
|
||||
for (i = 0; i < 4; i++) {
|
||||
/*
|
||||
* The w-array is really w[64], but since we only need
|
||||
* 16 of them at a time, we save stack by calculating
|
||||
* 16 at a time.
|
||||
*
|
||||
* This optimization was not there initially and the
|
||||
* rest of the comments about w[64] are kept in their
|
||||
* initial state.
|
||||
*/
|
||||
|
||||
/*
|
||||
* create a 64-entry message schedule array w[0..63] of 32-bit words
|
||||
* (The initial values in w[0..63] don't matter, so many implementations
|
||||
* zero them here) copy chunk into first 16 words w[0..15] of the message
|
||||
* schedule array
|
||||
*/
|
||||
U32 w[16];
|
||||
|
||||
U32 s0, s1;
|
||||
|
||||
for (j = 0; j < 16; j++) {
|
||||
if (i == 0) {
|
||||
w[j] = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
|
||||
p += 4;
|
||||
} else {
|
||||
/* Extend the first 16 words into the remaining 48 words w[16..63] of
|
||||
* the message schedule array: */
|
||||
s0 = right_rot(w[(j + 1) & 0xf], 7) ^ right_rot(w[(j + 1) & 0xf], 18) ^ (w[(j + 1) & 0xf] >> 3);
|
||||
s1 = right_rot(w[(j + 14) & 0xf], 17) ^ right_rot(w[(j + 14) & 0xf], 19) ^ (w[(j + 14) & 0xf] >> 10);
|
||||
w[j] = w[j] + s0 + w[(j + 9) & 0xf] + s1;
|
||||
}
|
||||
s1 = right_rot(ah[4], 6) ^ right_rot(ah[4], 11) ^ right_rot(ah[4], 25);
|
||||
U32 ch = (ah[4] & ah[5]) ^ (~ah[4] & ah[6]);
|
||||
U32 temp1 = ah[7] + s1 + ch + k[i << 4 | j] + w[j];
|
||||
s0 = right_rot(ah[0], 2) ^ right_rot(ah[0], 13) ^ right_rot(ah[0], 22);
|
||||
U32 maj = (ah[0] & ah[1]) ^ (ah[0] & ah[2]) ^ (ah[1] & ah[2]);
|
||||
U32 temp2 = s0 + maj;
|
||||
|
||||
ah[7] = ah[6];
|
||||
ah[6] = ah[5];
|
||||
ah[5] = ah[4];
|
||||
ah[4] = ah[3] + temp1;
|
||||
ah[3] = ah[2];
|
||||
ah[2] = ah[1];
|
||||
ah[1] = ah[0];
|
||||
ah[0] = temp1 + temp2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the compressed chunk to the current hash value: */
|
||||
for (i = 0; i < 8; i++)
|
||||
h[i] += ah[i];
|
||||
}
|
||||
|
||||
/* Produce the final hash value (big-endian): */
|
||||
for (i = 0, j = 0; i < 8; i++) {
|
||||
hash[j++] = (h[i] >> 24);
|
||||
hash[j++] = (h[i] >> 16);
|
||||
hash[j++] = (h[i] >> 8);
|
||||
hash[j++] = h[i];
|
||||
}
|
||||
}
|
133
System/Libraries/String.HC
Normal file
133
System/Libraries/String.HC
Normal file
|
@ -0,0 +1,133 @@
|
|||
U0 @string_append(U8* dst, U8* fmt, ...)
|
||||
{
|
||||
U8* buf;
|
||||
if (argc) {
|
||||
buf = StrPrintJoin(NULL, fmt, argc, argv);
|
||||
} else {
|
||||
buf = StrNew(fmt, adam_task);
|
||||
}
|
||||
U8* src = buf;
|
||||
StrCpy(dst + StrLen(dst), src);
|
||||
Free(buf);
|
||||
}
|
||||
|
||||
Bool @string_is_number(U8* s)
|
||||
{
|
||||
while (*s) {
|
||||
switch (*s) {
|
||||
case '-':
|
||||
case '.':
|
||||
case '0' ... '9':
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Bool @string_begins_with(U8* fragment, U8* str)
|
||||
{
|
||||
if (!fragment || !str)
|
||||
return FALSE;
|
||||
if (StrLen(fragment) > StrLen(str))
|
||||
return FALSE;
|
||||
return !MemCmp(fragment, str, StrLen(fragment));
|
||||
}
|
||||
|
||||
Bool @string_ends_with(U8* fragment, U8* str)
|
||||
{
|
||||
if (!fragment || !str)
|
||||
return FALSE;
|
||||
if (StrLen(fragment) > StrLen(str))
|
||||
return FALSE;
|
||||
return !MemCmp(fragment, str + StrLen(str) - StrLen(fragment), StrLen(fragment));
|
||||
}
|
||||
|
||||
U8* @string_replace(U8* s, U8* oldW, U8* newW)
|
||||
{
|
||||
if (!StrFind(oldW, s)) {
|
||||
return StrNew(s, adam_task);
|
||||
}
|
||||
U8* result;
|
||||
I64 i, cnt = 0;
|
||||
I64 newWlen = StrLen(newW);
|
||||
I64 oldWlen = StrLen(oldW);
|
||||
for (i = 0; s[i] != NULL; i++) {
|
||||
if (StrFind(oldW, &s[i]) == &s[i]) {
|
||||
cnt++;
|
||||
|
||||
i += oldWlen - 1;
|
||||
}
|
||||
}
|
||||
result = MAlloc(i + cnt * (newWlen - oldWlen) + 1, adam_task);
|
||||
i = 0;
|
||||
while (*s) {
|
||||
if (StrFind(oldW, s) == s) {
|
||||
StrCpy(&result[i], newW);
|
||||
i += newWlen;
|
||||
s += oldWlen;
|
||||
} else
|
||||
result[i++] = *s++;
|
||||
}
|
||||
result[i] = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
U8** @string_split(U8* s, U8 ch = '\n', I64* cnt)
|
||||
{
|
||||
U8 check_buf[4];
|
||||
StrPrint(check_buf, "%c", ch);
|
||||
if (!StrFind(check_buf, s)) {
|
||||
U8** same_arr = CAlloc(sizeof(U8*) * 1, adam_task);
|
||||
same_arr[0] = s;
|
||||
*cnt = 1;
|
||||
return same_arr;
|
||||
}
|
||||
U8* p = s;
|
||||
cnt[0] = 0;
|
||||
while (*p) {
|
||||
if (*p == ch)
|
||||
cnt[0]++;
|
||||
p++;
|
||||
}
|
||||
if (!(cnt[0]))
|
||||
return NULL;
|
||||
cnt[0]++;
|
||||
I64 i = -1;
|
||||
U8** arr = CAlloc(sizeof(U8*) * cnt[0], adam_task);
|
||||
p = s;
|
||||
while (*p) {
|
||||
if (*p == ch || i < 0) {
|
||||
i++;
|
||||
arr[i] = p;
|
||||
if (*p == ch) {
|
||||
arr[i]++;
|
||||
*p = NULL;
|
||||
}
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
class @string
|
||||
{
|
||||
U0(*Append)
|
||||
(U8 * dst, U8 * fmt, ...);
|
||||
Bool (*BeginsWith)(U8* fragment, U8* str);
|
||||
Bool (*EndsWith)(U8* fragment, U8* str);
|
||||
Bool (*IsNumber)(U8* s);
|
||||
U8* (*Replace)(U8* s, U8* oldW, U8* newW);
|
||||
U8** (*Split)(U8* s, U8 ch = '\n', I64 * cnt);
|
||||
};
|
||||
|
||||
@string String;
|
||||
String.Append = &@string_append;
|
||||
String.BeginsWith = &@string_begins_with;
|
||||
String.EndsWith = &@string_ends_with;
|
||||
String.IsNumber = &@string_is_number;
|
||||
String.Replace = &@string_replace;
|
||||
String.Split = &@string_split;
|
115
System/Libraries/Tlse.HC
Normal file
115
System/Libraries/Tlse.HC
Normal file
|
@ -0,0 +1,115 @@
|
|||
#define TLS_V12 0x0303
|
||||
|
||||
Silent(1); // This is needed to suppress "Function should return val" warnings for wrappers to non-HolyC functions
|
||||
|
||||
U64 @tls_create_context(U8 is_server, U16 version)
|
||||
{
|
||||
U64 reg RDI rdi = is_server;
|
||||
U64 reg RSI rsi = version;
|
||||
no_warn rdi, rsi;
|
||||
asm {
|
||||
MOV RAX, TLS_CREATE_CONTEXT
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_sni_set(U64 context, U8* sni)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
U64 reg RSI rsi = sni;
|
||||
no_warn rdi, rsi;
|
||||
asm {
|
||||
MOV RAX, TLS_SNI_SET
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_client_connect(U64 context)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
no_warn rdi;
|
||||
asm {
|
||||
MOV RAX, TLS_CLIENT_CONNECT
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
U8* @tls_get_write_buffer(U64 context, U32* outlen)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
U64 reg RSI rsi = outlen;
|
||||
no_warn rdi, rsi;
|
||||
asm {
|
||||
MOV RAX, TLS_GET_WRITE_BUFFER
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
U0 @tls_buffer_clear(U64 context)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
no_warn rdi;
|
||||
asm {
|
||||
MOV RAX, TLS_BUFFER_CLEAR
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_connection_status(U64 context)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
no_warn rdi;
|
||||
asm {
|
||||
MOV RAX, TLS_CONNECTION_STATUS
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
U0 @tls_consume_stream(U64 context, U8* buf, I32 buf_len, U64 certificate_verify)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
U64 reg RSI rsi = buf;
|
||||
U64 reg RDX rdx = buf_len;
|
||||
U64 reg RCX rcx = certificate_verify;
|
||||
no_warn rdi, rsi, rdx, rcx;
|
||||
asm {
|
||||
MOV RAX, TLS_CONSUME_STREAM
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_read(U64 context, U8* buf, U32 size)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
U64 reg RSI rsi = buf;
|
||||
U64 reg RDX rdx = size;
|
||||
no_warn rdi, rsi, rdx;
|
||||
asm {
|
||||
MOV RAX, TLS_READ
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_write(U64 context, U8* data, U32 len)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
U64 reg RSI rsi = data;
|
||||
U64 reg RDX rdx = len;
|
||||
no_warn rdi, rsi, rdx;
|
||||
asm {
|
||||
MOV RAX, TLS_WRITE
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
I32 @tls_established(U64 context)
|
||||
{
|
||||
U64 reg RDI rdi = context;
|
||||
no_warn rdi;
|
||||
asm {
|
||||
MOV RAX, TLS_ESTABLISHED
|
||||
CALL RAX
|
||||
}
|
||||
}
|
||||
|
||||
Silent(0);
|
Loading…
Add table
Add a link
Reference in a new issue