From 9f2bd01c1968bbe79a2693afe6bf7a5cda5c3777 Mon Sep 17 00:00:00 2001
From: lux <luxko@qq.com>
Date: Fri, 9 Aug 2024 21:02:48 +0800
Subject: [PATCH 1/2] case-insensitive headers

---
 linux.jai   | 10 ++++++----
 windows.jai |  9 ++++++---
 2 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/linux.jai b/linux.jai
index 9bf46fc..074e46d 100644
--- a/linux.jai
+++ b/linux.jai
@@ -257,10 +257,12 @@ read_http_request :: (socket: Socket) -> *Request {
         kv := split(line, ": ");
         #if parseheaders table_add(*request.headers, kv[0], kv[1]);
 
-        if kv[0] == {
-          case "Content-Length";    request.content_length   = xx to_integer(kv[1]);
-          case "Sec-WebSocket-Key"; request.websocket_key    = kv[1];
-          case "Accept-Encoding";   request.accept_encoding  = kv[1];
+        if compare_nocase(kv[0], "Content-Length") == 0 {
+          request.content_length = xx to_integer(kv[1]);
+        } else if compare_nocase(kv[0], "Sec-WebSocket-Key") == 0 {
+          request.websocket_key = kv[1];
+        } else if compare_nocase(kv[0], "Accept-Encoding") == 0 {
+          request.accept_encoding = kv[1];
         }
 
         if request.raw[request.buffercursor+2] == #char "\r" && request.raw[request.buffercursor+2 + 1] == #char "\n" {
diff --git a/windows.jai b/windows.jai
index 89be49f..137578e 100644
--- a/windows.jai
+++ b/windows.jai
@@ -224,9 +224,12 @@ recv_http_request :: (socket: MySocket) -> Request {
         kv := split(line, ": ");
         #if parseheaders table_add(*request.headers, kv[0], kv[1]);
 
-        if kv[0] == {
-          case "Content-Length";    request.content_length = xx to_integer(kv[1]);
-          case "Sec-WebSocket-Key"; request.websocket_key  = kv[1];
+        if compare_nocase(kv[0], "Content-Length") == 0 {
+          request.content_length = xx to_integer(kv[1]);
+        } else if compare_nocase(kv[0], "Sec-WebSocket-Key") == 0 {
+          request.websocket_key = kv[1];
+        } else if compare_nocase(kv[0], "Accept-Encoding") == 0 {
+          request.accept_encoding = kv[1];
         }
 
         if request.raw[buffercursor+2] == #char "\r" && request.raw[buffercursor+2 + 1] == #char "\n" {

From 896b7d0164d175c367b11fadb5118f0175d6b013 Mon Sep 17 00:00:00 2001
From: lux <luxko@qq.com>
Date: Tue, 13 Aug 2024 20:32:32 +0800
Subject: [PATCH 2/2] fix data race

---
 linux.jai | 27 +++++++++++----------------
 1 file changed, 11 insertions(+), 16 deletions(-)

diff --git a/linux.jai b/linux.jai
index 074e46d..81124fc 100644
--- a/linux.jai
+++ b/linux.jai
@@ -26,7 +26,7 @@ thread_pool           : [THREAD_POOL_COUNT] Thread;
 epoll_fd_pool         : [THREAD_POOL_COUNT] s32;
 epoll_events_pool     : [THREAD_POOL_COUNT] [MAX_EVENTS] epoll_event;
 
-request_pool          : Table(Socket, Request);
+request_pool          : [THREAD_POOL_COUNT]Table(Socket, Request);
 
 
 listen_socket: Socket;
@@ -38,12 +38,6 @@ http_listen :: (port: u16 = 80, ip: string = "0.0.0.0") {
   listen_socket = create_listen_socket(port, ip);
   log("HTTP Server listening on %:%", ip, port);
 
-  // request_pool init
-  // without this our code actually crashes when there's high concurrency!
-  // Array bounds check failed
-  // i think while this table is expanding in 1 thread it's being accessed out of bounds in another thread?
-  init(*request_pool, BACKLOG+3); // why +3?
-
   // spin up the thread pool
   for * thread, i: thread_pool {
     epoll_fd_pool[i] = epoll_create1(0);
@@ -51,6 +45,7 @@ http_listen :: (port: u16 = 80, ip: string = "0.0.0.0") {
     add_to_epoll_fd_list(epoll_fd_pool[i], listen_socket, null, EPOLLIN | EPOLLET /*| EPOLLONESHOT*/);
 
     thread.data = xx i;
+    init(*request_pool[i], BACKLOG+3); // why +3?
     thread_init(thread, thread_pool_proc);
     thread_start(thread);
   }
@@ -127,8 +122,8 @@ 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);
-          handle_client_socket_accepted_or_read_ready(client_socket);
+          new_request_from_pool(client_socket, thread_id);
+          handle_client_socket_accepted_or_read_ready(client_socket, thread_id);
         }
 
         continue;
@@ -155,8 +150,8 @@ make_mysocket :: (socket: Socket) -> MySocket {
   return mysocket;
 }
 
-new_request_from_pool :: (client_socket: Socket) -> *Request {
-  request: *Request = find_or_add(*request_pool, client_socket);
+new_request_from_pool :: (client_socket: Socket, thread_id: s32) -> *Request {
+  request: *Request = find_or_add(*request_pool[thread_id], client_socket);
   request.content_length = 0;
   request.body.data      = null;
   request.response_sent  = false;
@@ -180,7 +175,7 @@ new_request_from_pool :: (client_socket: Socket) -> *Request {
   return request;
 }
 
-handle_client_socket_accepted_or_read_ready :: (client_socket: Socket) {
+handle_client_socket_accepted_or_read_ready :: (client_socket: Socket, thread_id: s32) {
   while 1 {
 
     // if this socket is a websocket, not a request
@@ -191,7 +186,7 @@ handle_client_socket_accepted_or_read_ready :: (client_socket: Socket) {
     }
 
 
-    request := read_http_request(client_socket);
+    request := read_http_request(client_socket, thread_id);
     if request == null  return; // we're waiting to read, need to come back later
     if request.err {
       // ssl has a massive memory leak when run with high concurrency... this doesn't fix it...
@@ -203,14 +198,14 @@ handle_client_socket_accepted_or_read_ready :: (client_socket: Socket) {
 
     handle_request(request);
 
-    new_request_from_pool(client_socket); // reset this requests data when we're done with it
+    new_request_from_pool(client_socket, thread_id); // reset this requests data when we're done with it
   }
 }
 
 
 // todo: i think i have to rewrite this to handle read() not giving us a full line
-read_http_request :: (socket: Socket) -> *Request {
-  request: *Request = table_find_pointer(*request_pool, socket);
+read_http_request :: (socket: Socket, thread_id: s32) -> *Request {
+  request: *Request = table_find_pointer(*request_pool[thread_id], socket);
   if request == null then die("no request for socket", socket);
   // assert(request != null);