Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
DaseinPhaos committed Aug 14, 2024
2 parents 3668947 + b0c87ec commit 90d236f
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 65 deletions.
2 changes: 1 addition & 1 deletion examples/bench/first.jai
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ main :: () {

http_listen(port=80);

get("/", (request: *Request) {; send_html(request, "Hello World"); });
get("/", (request: *Request) {; send_text(request, "Hello World"); });

while 1 sleep_milliseconds(60_000); // uhh, the program just exits instantly without this xxx
}
Expand Down
2 changes: 1 addition & 1 deletion examples/hello/first.jai
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ main :: () {

get("/hello/:name", (request: *Request) {;
// send_html(request, tprint("Hello %!", request.params["name"])); // this syntax broken in beta .66
send_html(request, tprint("Hello %!", request.get_param(request, "name")), content_type="text/plain");
send_text(request, tprint("Hello %!", request.get_param(request, "name")));
});


Expand Down
52 changes: 35 additions & 17 deletions linux.jai
Original file line number Diff line number Diff line change
Expand Up @@ -123,19 +123,27 @@ thread_pool_proc :: (thread: *Thread) -> s64 {
if event.data.fd == listen_socket_ssl then ssl_make_socket_ssl(client_socket);

new_request_from_pool(client_socket, thread_id);
handle_client_socket_accepted_or_read_ready(client_socket, thread_id);
handle_client_socket_accepted_or_read_ready(client_socket, epoll_fd, thread_id);
}

continue;
}

// not the listen socket, must be a client_socket ready to read ... right?
// not the listen socket, must be a client_socket ready to read or write ... right?
if event.events & EPOLLIN {
client_socket := event.data.fd;
handle_client_socket_accepted_or_read_ready(client_socket);
handle_client_socket_accepted_or_read_ready(client_socket, epoll_fd, thread_id);
// add_to_epoll_fd_list(epoll_fd, client_socket, null, EPOLLIN | EPOLLET | EPOLLONESHOT, mod=true);
continue;
}

if event.events & EPOLLOUT {
client_socket := event.data.fd;
request := table_find_pointer(*request_pool, client_socket);
if !request || !request.write_data continue;
continue_write(request);
continue;
}
}

tfree();
Expand Down Expand Up @@ -168,14 +176,12 @@ new_request_from_pool :: (client_socket: Socket, thread_id: s32) -> *Request {
}
request.raw.count = 0;

// #if parseheaders uninit(*request.headers);
// #if parseheaders init(*request.headers);
#if parseheaders table_reset(*request.headers);

return request;
}

handle_client_socket_accepted_or_read_ready :: (client_socket: Socket, thread_id: s32) {
handle_client_socket_accepted_or_read_ready :: (client_socket: Socket, epoll_fd: s32, thread_id: s32) {
while 1 {

// if this socket is a websocket, not a request
Expand All @@ -196,6 +202,7 @@ handle_client_socket_accepted_or_read_ready :: (client_socket: Socket, thread_id
return;
}

request.epoll_fd = epoll_fd;
handle_request(request);

new_request_from_pool(client_socket, thread_id); // reset this requests data when we're done with it
Expand All @@ -205,6 +212,7 @@ handle_client_socket_accepted_or_read_ready :: (client_socket: Socket, thread_id

// todo: i think i have to rewrite this to handle read() not giving us a full line
read_http_request :: (socket: Socket, thread_id: s32) -> *Request {
// this is slowwwwww. maybe i should use faster string compares
request: *Request = table_find_pointer(*request_pool[thread_id], socket);
if request == null then die("no request for socket", socket);
// assert(request != null);
Expand All @@ -216,7 +224,7 @@ read_http_request :: (socket: Socket, thread_id: s32) -> *Request {
if bytes_received == 0 {
if request.raw.count == REQUEST_BUFFER_LEN {
mylog("pretty sure this means we ran out of buffer space for this request so we had to drop it!");
send_html(request, tprint("Request too large. Max request size is % bytes.", REQUEST_BUFFER_LEN), status_code=413);
send_text(request, tprint("Request too large. Max request size is % bytes.", REQUEST_BUFFER_LEN), status_code=413);
}
request.err = true;
break;
Expand Down Expand Up @@ -276,18 +284,27 @@ read_http_request :: (socket: Socket, thread_id: s32) -> *Request {
}


continue_write :: (request: *Request) {
while request.write_bytes_sent < request.write_data.count {
remaining_bytes_to_write := substr(request.write_data, request.write_bytes_sent);
bytes_written := mysocket_write(request.socket, remaining_bytes_to_write);

if bytes_written < 0 {
if errno() == EWOULDBLOCK {
add_to_epoll_fd_list(request.epoll_fd, request.socket.socket, null, EPOLLOUT, mod=true);
return;
}
mylog("well, this is really bad: Error writing to socket: %", errno());
return;
}

request.write_bytes_sent += bytes_written;
}

// send_file :: (request: *Request, filename: string) {
// file_cache_record, success := file_cache_get_or_create(filename);
// if !success return;
free(request.write_data.data); request.write_data.data = null;
add_to_epoll_fd_list(request.epoll_fd, request.socket.socket, null, EPOLLIN, mod=true); // Reset the socket to listen for reads
}

// content_type := extension2contenttype(filename);
// content := ifx does_request_accept_encoding(request, "br") then file_cache_record.brotli else file_cache_record.rawcontent;
// content_encoding := ifx does_request_accept_encoding(request, "br") then "br" else "";
// send_html(request, content, content_type=content_type, content_encoding=content_encoding);
// }

// // todo: async? caching?
// send_file :: (request: *Request, filename: string) {
Expand Down Expand Up @@ -340,8 +357,8 @@ add_to_epoll_fd_list :: (epoll_fd: s32, fd: s32, ptr: *void, ep_events: u32, $mo
else event.data.fd = fd;
event.events = ep_events;

#if !mod if epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, *event) die("add epoll_ctl() ADD");
#if mod if epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, *event) die("add epoll_ctl() MOD");
#if !mod if epoll_ctl(epoll_fd, .ADD, fd, *event) die("add epoll_ctl() ADD");
#if mod if epoll_ctl(epoll_fd, .MOD, fd, *event) die("add epoll_ctl() MOD");
}
// remove_from_epoll_fd_list :: (fd: s32) {
// if epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, null) die("remove epoll_ctl()");
Expand Down Expand Up @@ -374,6 +391,7 @@ get_ip_string_from_socket :: (socket: s32) -> string {
#import,dir "modules/mysocket";

#import "POSIX";
#import "Linux";
#import "File";
#import "Thread";

Expand Down
57 changes: 37 additions & 20 deletions module.jai
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,39 @@ Middleware :: struct {
cb: (*Request)->();
}

get :: (path: string, cb: (*Request)->()) {array_add(*middlewares, .{method=.GET , cb=cb, path=normalize_path(path)}); }
post :: (path: string, cb: (*Request)->()) {array_add(*middlewares, .{method=.POST, cb=cb, path=normalize_path(path)}); }
any :: (path: string, cb: (*Request)->()) {array_add(*middlewares, .{method=.ANY , cb=cb, path=normalize_path(path)}); }
get :: (path: string, cb: (*Request)->()) {array_add(*middlewares, .{method=.GET, cb=cb, path=normalize_path(path)}); }
post :: (path: string, cb: (*Request)->()) {array_add(*middlewares, .{method=.POST, cb=cb, path=normalize_path(path)}); }
put :: (path: string, cb: (*Request)->()) {array_add(*middlewares, .{method=.PUT, cb=cb, path=normalize_path(path)}); }
delete :: (path: string, cb: (*Request)->()) {array_add(*middlewares, .{method=.DELETE, cb=cb, path=normalize_path(path)}); }
any :: (path: string, cb: (*Request)->()) {array_add(*middlewares, .{method=.ANY, cb=cb, path=normalize_path(path)}); }






send_html :: (request: *Request, html: string, status_code: u16 = 200, content_type: string = "text/html", content_encoding: string = "") {
// todo: status_code 404 is responding with 404 OK; lol
send_html :: #bake_arguments send_response(content_type="text/html");
send_text :: #bake_arguments send_response(content_type="text/plain");
send_json :: #bake_arguments send_response(content_type="application/json");
send_response :: (request: *Request, content: string, status_code: u16 = 200, content_type: string = "text/plain", content_encoding: string = "") {
// todo: status_code 404 is responding with "404 OK" lol
content_encoding_header := ifx content_encoding then tprint("\r\nContent-Encoding: %", content_encoding) else "";
http_response := tprint("HTTP/1.1 % OK\r\nContent-Length: %\r\nContent-Type: %; charset=UTF-8%\r\n\r\n%", status_code, html.count, content_type, content_encoding_header, html);
http_response := tprint("HTTP/1.1 % OK\r\nContent-Length: %\r\nContent-Type: %; charset=UTF-8%\r\n\r\n%", status_code, content.count, content_type, content_encoding_header, content);

mysocket_write(request.socket, http_response);
request.response_sent = true;
}

send_json :: (request: *Request, json: string) {
http_response := tprint("HTTP/1.1 200 OK\r\nContent-Length: %\r\nContent-Type: application/json\r\n\r\n%", json.count, json);
mysocket_write(request.socket, http_response);
request.response_sent = true;
#if OS == .WINDOWS {
mysocket_write(request.socket, http_response);
} else {
bytes_sent := mysocket_write(request.socket, http_response);
if bytes_sent < http_response.count {
write_data := alloc_string(http_response.count - bytes_sent);
memcpy(write_data.data, http_response.data + bytes_sent, write_data.count);
request.write_data = write_data;
request.write_bytes_sent = 0;
continue_write(request);
}
}
}

send_file :: (request: *Request, raw_filename: string) {
Expand All @@ -57,7 +68,7 @@ send_file :: (request: *Request, raw_filename: string) {
content := ifx are_we_returning_br then file_cache_record.brotli else file_cache_record.rawcontent;
content_encoding := ifx are_we_returning_br then "br" else "";
content_type := extension2contenttype(filename);
send_html(request, content, content_type=content_type, content_encoding=content_encoding);
send_response(request, content, content_type=content_type, content_encoding=content_encoding);
}


Expand All @@ -83,8 +94,13 @@ Request :: struct {
err : bool;

#if OS == .LINUX {
buffercursor : u32;
startofline : u32;
buffercursor : u32;
startofline : u32;

write_data : string;
write_bytes_sent : int;

epoll_fd : s32;
}

get_param :: (request: *Request, name: string) -> string {
Expand Down Expand Up @@ -138,6 +154,7 @@ handle_request :: (request: *Request) {
}

// let the user's middleware handle the request!
// use tries instead of a for loop ... @perf
for middleware: middlewares {

if request.response_sent then break; // once a middleware handles the request, we stop. this is first because webhook could've handled it already
Expand Down Expand Up @@ -167,7 +184,7 @@ handle_request :: (request: *Request) {
}

// if none of the middleware responded to this request, 404
if !request.response_sent then send_html(request, tprint("<pre>Cannot % %</pre>", request.method, request.path), status_code=404);
if !request.response_sent then send_text(request, tprint("Cannot % %", request.method, request.path), status_code=404);
}


Expand Down Expand Up @@ -245,14 +262,12 @@ to_METHOD :: (str: string) -> METHOD {
}



// Content-Type aka MIME type
extension2contenttype :: (filename: string) -> string {
index_of_dot := find_index_from_right(filename, ".");
if index_of_dot == -1 return "text/html";

extension: string;
extension.data = filename.data + index_of_dot;
extension.count = filename.count - index_of_dot;
extension := substr(filename, index_of_dot, filename.count-index_of_dot);

if extension == {
case ".css"; return "text/css";
Expand All @@ -265,8 +280,10 @@ extension2contenttype :: (filename: string) -> string {
case ".ico"; return "image/x-icon";
case ".jpg"; return "image/jpeg";
case ".jpeg"; return "image/jpeg";
case ".svg"; return "image/svg+xml";
case ".ini"; return "text/plain";
case ".txt"; return "text/plain";
case ".exe"; return "application/octet-stream";
}

return "text/html";
Expand Down
1 change: 1 addition & 0 deletions modules/brotli/module.jai
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ using BrotliEncoderMode :: enum s32 {BROTLI_MODE_GENERIC :: 0; BROTLI_MODE_TEXT
#scope_file

brotli :: #library,no_dll "linux/libbrotli";
libm :: #system_library,link_always "libm";
#import "POSIX";


Expand Down
Binary file removed modules/openssl/linux/libcrypto.so
Binary file not shown.
Binary file removed modules/openssl/linux/libssl.so
Binary file not shown.
9 changes: 2 additions & 7 deletions modules/openssl/module.jai
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,5 @@ SSL_get_error :: (s: *SSL, ret_code: s32) -> s32 #foreign libssl;
ERR_get_error :: () -> u64 #foreign libssl;
ERR_error_string :: (e: u64, buf: *u8) -> *u8 #foreign libssl;


// libssl :: #library,no_dll "linux/libssl";
// libcrypto :: #library,no_dll "linux/libcrypto";
// libdl :: #library,no_dll "linux/libdl";
libssl :: #library "linux/libssl";
libcrypto :: #library "linux/libcrypto";

libssl :: #system_library "libssl";
libcrypto :: #system_library,link_always "libcrypto";
24 changes: 5 additions & 19 deletions windows.jai
Original file line number Diff line number Diff line change
Expand Up @@ -112,34 +112,20 @@ thread_pool_proc :: (thread: *Thread) -> s64 {
ts: Temporary_Storage; context.temporary_storage = *ts;

while 1 {
auto_release_temp();

wait_for(*connection_queue_sema);
client_socket := work_get();
defer closesocket(client_socket);

if client_socket.socket == 0 mylog("wut? socket 0"); // i don't think this has ever happened

while 1 {
auto_release_temp();

request := recv_http_request(client_socket);
if request.err then break;

path_normal := trim(request.path, "/");

// let the user's middleware handle the request!
for middleware: middlewares {
if middleware.method != .ANY && middleware.method != request.method then continue;
if middleware.path != "*" && middleware.path != path_normal then continue;

middleware.cb(*request);
if request.response_sent then break; // once a middleware handles the request, we stop
}

// if none of the middleware responded to this request, 404
if !request.response_sent then send_html(*request, tprint("<pre>Cannot % %</pre>", request.method, request.path), status_code=404);

tfree();
handle_request(*request);
}

tfree();
}

return 0;
Expand Down

0 comments on commit 90d236f

Please sign in to comment.