changeset 6:1e61008b9980

[Seobeo] Updated seobeo so that API is more opinionated. Added my webpage./build.sh
author June Park <parkjune1995@gmail.com>
date Mon, 29 Sep 2025 16:00:44 -0700
parents 3e12bf044589
children 114cad94008f
files dowa/d_memory.c seobeo/BUILD seobeo/main.c seobeo/pages/index.html seobeo/s_linux_network.c seobeo/seobeo.h
diffstat 6 files changed, 133 insertions(+), 166 deletions(-) [+]
line wrap: on
line diff
--- a/dowa/d_memory.c	Sat Sep 27 16:23:04 2025 -0700
+++ b/dowa/d_memory.c	Mon Sep 29 16:00:44 2025 -0700
@@ -265,13 +265,12 @@
         perror("Dowa_HashMap_Cache_Folder");
         return -1;
       }
-      void *value = Dowa_HashMap_Get(p_child_map, "bar.txt");
 
-      // Should not copy as we malloced alredy.
+      // Should not copy as we malloced already.
       if (Dowa_HashMap_PushValueWithTypeNoCopy(map, entry->d_name, p_child_map,
                                          sizeof(p_child_map), DOWA_HASH_MAP_TYPE_HASHMAP) == -1)
       {
-        Dowa_HashMap_Free(map);
+        Dowa_HashMap_Free(p_child_map);
         return -1;
       }
     }
--- a/seobeo/BUILD	Sat Sep 27 16:23:04 2025 -0700
+++ b/seobeo/BUILD	Mon Sep 29 16:00:44 2025 -0700
@@ -5,25 +5,40 @@
   name = "seobeo",
   actual = select({
     "@platforms//os:osx": ":seobeo_example_mac",
-  })
+  }),
+  visibility = ["//visibility:public"],
+)
+
+filegroup(
+  name = "pages_files",
+  srcs = glob(["pages/**"]),
+)
+
+filegroup(
+  name = "seobeo_headers",
+  srcs = [
+    "seobeo.h",
+    "seobeo_internal.h"
+  ],
+  visibility = ["//visibility:public"],
 )
 
 cc_binary(
   name = "seobeo_example_mac",
   srcs = ["main.c"],
   deps = [":seobeo_non_window"],
-  data = [
-    "pages/index.html"
-  ],
+  data = glob(["pages/**"]),
   target_compatible_with = [
       "@platforms//os:osx",
   ],
+  visibility = ["//visibility:public"],
 )
 
 cc_library(
   name = "seobeo_non_window",
   srcs = [
     "s_linux_network.c",
+    "s_web.c",
   ],
   deps = ["//dowa:dowa"],
   hdrs = [
@@ -33,4 +48,5 @@
   target_compatible_with = [
       "@platforms//os:osx",
   ],
+  visibility = ["//visibility:public"],
 )
--- a/seobeo/main.c	Sat Sep 27 16:23:04 2025 -0700
+++ b/seobeo/main.c	Mon Sep 29 16:00:44 2025 -0700
@@ -4,122 +4,8 @@
 
 #include "seobeo/seobeo.h"
 
-Dowa_PHashMap cache;
-
-void SigchildHandler(int s)
-{
-  (void)s; // quiet unused variable warning
-
-  // waitpid() might overwrite errno, so we save and restore it:
-  int saved_errno = errno;
-
-  while(waitpid(-1, NULL, WNOHANG) > 0);
-
-  errno = saved_errno;
-}
-
-void HandleClientRequest(Seobeo_PHandle cli)
-{
-  Dowa_PArena response_arena = Dowa_Arena_Create(8192);
-  if (!response_arena)
-  {
-    perror("Dowa_Arena_Initialize");
-    goto clean_up;
-  }
-
-  size_t idx = Dowa_HashMap_GetPosition(cache, "index.html");
-  Dowa_PHashEntry entry = cache->entries[idx]; 
-  if (!entry)
-  {
-    // 404 response if missing
-    const char *not_found =
-      "HTTP/2.0 404 Not Found\r\n"
-      "Content-Length: 0\r\n"
-      "Connection: close\r\n"
-      "\r\n";
-    send(cli->socket, not_found, strlen(not_found), 0);
-    goto clean_up;
-  }
-
-  // 3) Prepare header with the correct content‐length
-  size_t body_size = entry->capacity;
-  const char *template =
-    "HTTP/2.0 200 OK\r\n"
-    "Content-Type: text/html\r\n"
-    "Content-Length: %zu\r\n"
-    "Connection: close\r\n"
-    "\r\n";
-
-  // Compute how large the header is and allocate just enough space
-  int header_len = snprintf(NULL, 0, template, body_size);
-  void *header = Dowa_Arena_Allocate(response_arena, (size_t)(header_len+1));
-  if (header == NULL)
-  {
-    perror("Dowa_Arena_Allocate");
-    goto clean_up;
-  }
-
-  snprintf((char *)header, header_len + 1, template, body_size);
-  Seobeo_Handle_QueueData(cli,
-              (const uint8*)header,
-              (uint32)(header_len + 1));
-  Seobeo_Handle_QueueData(cli,
-              (const uint8*)entry->buffer,
-              (uint32)body_size);
-  Seobeo_Handle_Flush(cli);
-  goto clean_up;
-
-clean_up:
-  Seobeo_Handle_Destroy(cli);
-  Dowa_Arena_Free(response_arena);
-  return ;
-}
 
 int main(void)
 {
-  struct sigaction sa;
-
-  cache = Dowa_HashMap_Create(1024);
-  if (Dowa_Cache_Folder(cache, "seobeo/pages") != 0)
-  {
-    perror("Dowa_Cache_Folder");
-    return -1;
-  }
-
-  Seobeo_PHandle srv = Seobeo_Stream_Handle_Create(NULL, "8080");
-
-  if (srv->socket < 0) return 1;
-  printf("Listening on port 8080\n");
-
-  // TODO: Use epoll or something else.
-  // Code from Beej's book
-  // Handling child processes
-  sa.sa_handler = SigchildHandler;
-  sigemptyset(&sa.sa_mask);
-  sa.sa_flags = SA_RESTART;
-  if (sigaction(SIGCHLD, &sa, NULL) == -1)
-  {
-    perror("sigaction");
-    exit(1);
-  }
-
-  while (1)
-  {
-    Seobeo_PHandle cli = Seobeo_Stream_Handle_Accept(srv);
-    if (cli == NULL)
-    {
-      continue; 
-    }
-    printf("client connected from %s\n", cli->host);
-
-    if (!fork())
-    {
-      HandleClientRequest(cli);
-      exit(0);
-    }
-    Seobeo_Handle_Destroy(cli);
-  }
-
-  Seobeo_Handle_Destroy(srv);
-  return 0;
+  Seobeo_Web_StartBasicHTTPServer("seobeo/pages", "8080");
 }
--- a/seobeo/pages/index.html	Sat Sep 27 16:23:04 2025 -0700
+++ b/seobeo/pages/index.html	Mon Sep 29 16:00:44 2025 -0700
@@ -2,6 +2,7 @@
   <head>
   </head>
   <body>
-    <h1> June </h1>
+    <h1> This is June park xd </h1>
   </body>
+  <script src="index.js"></script>
 </HTML>
--- a/seobeo/s_linux_network.c	Sat Sep 27 16:23:04 2025 -0700
+++ b/seobeo/s_linux_network.c	Mon Sep 29 16:00:44 2025 -0700
@@ -110,12 +110,12 @@
   return p_handle;
 }
 
-Seobeo_PHandle Seobeo_Stream_Handle_Accept(Seobeo_PHandle server_h)
+Seobeo_PHandle Seobeo_Stream_Handle_Accept(Seobeo_PHandle p_server_handle)
 {
   struct sockaddr_storage addr;
   socklen_t addrlen = sizeof addr;
   char client_inet_addr[INET6_ADDRSTRLEN];
-  int client_fd = accept(server_h->socket,
+  int client_fd = accept(p_server_handle->socket,
                          (struct sockaddr*)&addr,
                          &addrlen);
   inet_ntop(
@@ -128,45 +128,46 @@
     return NULL;
   }
 
-  Seobeo_PHandle h = malloc(sizeof *h);
+  Seobeo_PHandle p_client_handle = malloc(sizeof *p_client_handle);
 
-  h->socket               = client_fd;
-  h->host                 = strdup(client_inet_addr);
-  h->port                 = NULL;
+  p_client_handle->socket               = client_fd;
+  p_client_handle->host                 = strdup(client_inet_addr);
+  p_client_handle->port                 = NULL;
 
-  h->read_buffer_capacity = server_h->read_buffer_capacity;
-  h->read_buffer_len      = 0;
-  h->read_buffer          = malloc(h->read_buffer_capacity);
+  p_client_handle->read_buffer_capacity = p_server_handle->read_buffer_capacity;
+  p_client_handle->read_buffer_len      = 0;
+  p_client_handle->read_buffer          = malloc(p_client_handle->read_buffer_capacity);
 
-  h->write_buffer_capacity = server_h->write_buffer_capacity;
-  h->write_buffer_len      = 0;
-  h->write_buffer          = malloc(h->write_buffer_capacity);
+  p_client_handle->write_buffer_capacity = p_server_handle->write_buffer_capacity;
+  p_client_handle->write_buffer_len      = 0;
+  p_client_handle->write_buffer          = malloc(p_client_handle->write_buffer_capacity);
 
-  return h;
+  return p_client_handle;
 }
 
-void Seobeo_Handle_Destroy(Seobeo_PHandle h)
+void Seobeo_Handle_Destroy(Seobeo_PHandle p_handle)
 {
-  close(h->socket);
-  free(h->host);
-  free(h->port);
-  free(h->read_buffer);
-  free(h->write_buffer);
-  free(h->file);
-  free(h->text_copy);
-  free(h->file_name);
-  free(h);
+  close(p_handle->socket);
+  free(p_handle->host);
+  free(p_handle->port);
+  free(p_handle->read_buffer);
+  free(p_handle->write_buffer);
+  free(p_handle->file);
+  free(p_handle->text_copy);
+  free(p_handle->file_name);
+  free(p_handle);
 }
 
-int Seobeo_Handle_Flush(Seobeo_PHandle h)
+int Seobeo_Handle_Flush(Seobeo_PHandle p_handle)
 {
-  uint32 total = h->write_buffer_len;
+  uint32 total = p_handle->write_buffer_len;
   uint32 sent  = 0;
 
-  while (sent < total) {
+  while (sent < total)
+  {
     ssize_t n = write(
-      h->socket,
-      h->write_buffer + sent,
+      p_handle->socket,
+      p_handle->write_buffer + sent,
       total - sent
     );
     if (n < 0) {
@@ -177,28 +178,29 @@
     sent += (uint32)n;
   }
 
-  h->write_buffer_len = 0;
+  p_handle->write_buffer_len = 0;
   return 0;
 }
 
-
-int Seobeo_Handle_QueueData(Seobeo_PHandle h, const uint8_t *data, uint32_t data_size)
+int Seobeo_Handle_Queue(Seobeo_PHandle p_handle, const uint8_t *data, uint32_t data_size)
 {
-  if (h->write_buffer_len + data_size > h->write_buffer_capacity) {
-    int rc = Seobeo_Handle_Flush(h);
+  if (p_handle->write_buffer_len + data_size > p_handle->write_buffer_capacity)
+  {
+    int rc = Seobeo_Handle_Flush(p_handle);
     if (rc < 0) return -1;
     if (rc > 0) return 1;
   }
 
-  if (data_size > h->write_buffer_capacity)
+  if (data_size > p_handle->write_buffer_capacity)
   {
     uint32_t offset = 0;
     while (offset < data_size)
     {
-      ssize_t n = write(h->socket,
+      ssize_t n = write(p_handle->socket,
                 data + offset,
                 data_size - offset);
-      if (n < 0) {
+      if (n < 0)
+      {
         if (errno == EINTR)  continue;
         if (errno == EAGAIN) return 1;
         return -1;
@@ -208,13 +210,55 @@
     return 0;
   }
 
-  memcpy(h->write_buffer + h->write_buffer_len,
+  memcpy(p_handle->write_buffer + p_handle->write_buffer_len,
          data,
          data_size);
-  h->write_buffer_len += data_size;
+  p_handle->write_buffer_len += data_size;
   return 0;
 }
 
+int Seobeo_Handle_Read(Seobeo_PHandle p_handle)
+{
+  // How many bytes we can still read into the buffer
+  uint32 free_space = p_handle->read_buffer_capacity - p_handle->read_buffer_len;
+  if (free_space == 0)
+    return -1;
+
+  ssize_t n = read(
+    p_handle->socket,
+    p_handle->read_buffer + p_handle->read_buffer_len,
+    free_space
+  );
+  if (n < 0) {
+    if (errno == EINTR)    return Seobeo_Handle_Read(p_handle);
+    if (errno == EAGAIN)   return 0;   // no data available right now
+    return -1;                        // fatal error
+  }
+  if (n == 0) {
+    return -2;   // peer closed the connection
+  }
+
+  p_handle->read_buffer_len += (uint32)n;
+  return (int)n;  // number of bytes read
+}
+
+void Seobeo_Handle_Consume(Seobeo_PHandle p_handle, uint32 consumed)
+{
+  if (consumed >= p_handle->read_buffer_len)
+  {
+    p_handle->read_buffer_len = 0;
+    return;
+  }
+
+  // Slide remaining bytes to the front
+  memmove(
+    p_handle->read_buffer,
+    p_handle->read_buffer + consumed,
+    p_handle->read_buffer_len - consumed
+  );
+  p_handle->read_buffer_len -= consumed;
+}
+
 void *Seobeo_GetIP4OrIP6(struct sockaddr *sa)
 {
   if (sa->sa_family == AF_INET) 
--- a/seobeo/seobeo.h	Sat Sep 27 16:23:04 2025 -0700
+++ b/seobeo/seobeo.h	Mon Sep 29 16:00:44 2025 -0700
@@ -23,6 +23,17 @@
 
 #define INITIAL_BUFFER_CAPACITY 4096
 
+// HTTP STATUS CODE
+#define HTTP_OK 200
+#define HTTP_CREATED 201
+#define HTTP_MOVED_PERMANENTLY 301
+#define HTTP_FOUND 302
+#define HTTP_BAD_REQUEST 400
+#define HTTP_UNAUTHORIZED 401
+#define HTTP_FORBIDDEN 403
+#define HTTP_NOT_FOUND 404
+#define HTTP_INTERNAL_ERROR 500
+
 typedef struct {
   int     socket; 
   char    *host;
@@ -31,7 +42,7 @@
   uint8   *read_buffer;
   uint32  read_buffer_capacity;
   uint32  read_buffer_len; // current size
-  uint32  read_buffer_pos; // TODO: Implement this for client 
+  uint32  read_buffer_used; // TODO: Implement this for client 
 
   uint8   *write_buffer;
   uint32  write_buffer_capacity;
@@ -49,11 +60,21 @@
 
 // --- TCP --- //
 extern Seobeo_PHandle Seobeo_Stream_Handle_Create(const char *host,  const char* port);
-extern Seobeo_PHandle Seobeo_Stream_Handle_Accept(Seobeo_PHandle server_h);
+extern Seobeo_PHandle Seobeo_Stream_Handle_Accept(Seobeo_PHandle p_server_handle);
+extern int            Seobeo_Stream_Handle_Read(Seobeo_PHandle p_handle);
+
+// --- Web --- //
+extern void           Seobeo_Web_GenerateResponseHeader(void *buffer, int status, const char *content_type, const int content_length);
+extern void           Seobeo_Web_HandleClientRequest(Seobeo_PHandle cli, Dowa_PHashMap p_html_cache);
+extern int            Seobeo_Web_ParseClientHeader(Seobeo_PHandle p_handle, Dowa_PHashMap map);
+extern int            Seobeo_Web_StartBasicHTTPServer(const char *folder_path, const char *port);
 
 // --- Helper functions --- //
-extern void           Seobeo_Handle_Destroy(Seobeo_PHandle h);
-extern int            Seobeo_Handle_Flush(Seobeo_PHandle h);
-extern int            Seobeo_Handle_QueueData(Seobeo_PHandle h, const uint8_t *data, uint32_t data_size);
+extern void           Seobeo_Handle_Destroy(Seobeo_PHandle p_handle);
+extern int            Seobeo_Handle_Flush(Seobeo_PHandle p_handle);
+extern int            Seobeo_Handle_Queue(Seobeo_PHandle p_handle, const uint8_t *data, uint32_t data_size);
+extern int            Seobeo_Handle_Read(Seobeo_PHandle p_handle);
+extern void           Seobeo_Handle_Consume(Seobeo_PHandle p_handle, uint32 consumed);
+
 
 #endif