Mercurial
comparison seobeo/s_web.c @ 185:dfdd66825396
Merged in keep alive changes and mrjunejune changes.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Fri, 23 Jan 2026 22:22:30 -0800 |
| parents | 8c74204fd362 |
| children | 8cf4ec5e2191 |
comparison
equal
deleted
inserted
replaced
| 182:d6ab5921fedc | 185:dfdd66825396 |
|---|---|
| 1 #include "seobeo/seobeo.h" | 1 #include "seobeo/seobeo.h" |
| 2 #include <strings.h> | |
| 3 #include <time.h> | |
| 2 | 4 |
| 3 static char g_folder_path[512] = "."; | 5 static char g_folder_path[512] = "."; |
| 4 | 6 |
| 5 char* Seobeo_Web_LoadFile(const char *file_path, size_t *p_file_size) | 7 char* Seobeo_Web_LoadFile(const char *file_path, size_t *p_file_size) |
| 6 { | 8 { |
| 33 } | 35 } |
| 34 | 36 |
| 35 void Seobeo_Web_Header_Generate( | 37 void Seobeo_Web_Header_Generate( |
| 36 void *buffer, int status, | 38 void *buffer, int status, |
| 37 const char *content_type, const int content_length) | 39 const char *content_type, const int content_length) |
| 40 { | |
| 41 Seobeo_Web_Header_Generate_KeepAlive(buffer, status, content_type, content_length, FALSE); | |
| 42 } | |
| 43 | |
| 44 void Seobeo_Web_Header_Generate_KeepAlive( | |
| 45 void *buffer, int status, | |
| 46 const char *content_type, const int content_length, | |
| 47 boolean keep_alive) | |
| 38 { | 48 { |
| 39 const char *status_text; | 49 const char *status_text; |
| 40 switch(status) | 50 switch(status) |
| 41 { | 51 { |
| 42 case HTTP_OK: status_text = "OK"; break; | 52 case HTTP_OK: status_text = "OK"; break; |
| 48 case HTTP_FORBIDDEN: status_text = "Forbidden"; break; | 58 case HTTP_FORBIDDEN: status_text = "Forbidden"; break; |
| 49 case HTTP_NOT_FOUND: status_text = "Not Found"; break; | 59 case HTTP_NOT_FOUND: status_text = "Not Found"; break; |
| 50 case HTTP_INTERNAL_ERROR: status_text = "Internal Server Error"; break; | 60 case HTTP_INTERNAL_ERROR: status_text = "Internal Server Error"; break; |
| 51 default: status_text = "Unknown"; break; | 61 default: status_text = "Unknown"; break; |
| 52 } | 62 } |
| 53 | 63 |
| 54 sprintf( | 64 sprintf( |
| 55 buffer, | 65 buffer, |
| 56 "HTTP/1.1 %d %s\r\n" | 66 "HTTP/1.1 %d %s\r\n" |
| 57 "Content-Type: %s\r\n" | 67 "Content-Type: %s\r\n" |
| 58 "Content-Length: %d\r\n" | 68 "Content-Length: %d\r\n" |
| 59 "Connection: close\r\n" | 69 "Connection: %s\r\n" |
| 60 "\r\n", | 70 "\r\n", |
| 61 status, status_text, content_type, content_length | 71 status, status_text, content_type, content_length, |
| 72 keep_alive ? "keep-alive" : "close" | |
| 62 ); | 73 ); |
| 63 } | 74 } |
| 64 | 75 |
| 65 void Seobeo_Web_HandleClientRequest(Seobeo_Handle *p_cli_handle, | 76 // Default arena size (5MB) - will allocate more if Content-Length requires it |
| 66 Seobeo_Cache_Entry *p_html_cache) | 77 #define DEFAULT_ARENA_SIZE (5 * 1024 * 1024) |
| 67 { | 78 |
| 68 // TODO: This should be splitted up instead of handling up to 50 MB as it will fail more often... | 79 // Helper to check if Connection header contains a specific value (case-insensitive) |
| 69 Dowa_Arena *p_request_arena = Dowa_Arena_Create(50*1024*1024); // 50 MB because of files... | 80 static boolean connection_header_contains(const char *header_value, const char *target) |
| 70 if (!p_request_arena) { perror("Dowa_Arena_Create request"); goto clean_up; } | 81 { |
| 71 | 82 if (!header_value || !target) return FALSE; |
| 72 Dowa_Arena *p_response_arena = Dowa_Arena_Create(50*1024*1024); // 50 MB for response | 83 |
| 73 if (!p_response_arena) { perror("Dowa_Arena_Create response"); goto clean_up; } | 84 // Make a copy to tokenize |
| 85 char *copy = strdup(header_value); | |
| 86 if (!copy) return FALSE; | |
| 87 | |
| 88 boolean found = FALSE; | |
| 89 char *token = strtok(copy, ", \t"); | |
| 90 while (token) { | |
| 91 if (strcasecmp(token, target) == 0) { | |
| 92 found = TRUE; | |
| 93 break; | |
| 94 } | |
| 95 token = strtok(NULL, ", \t"); | |
| 96 } | |
| 97 free(copy); | |
| 98 return found; | |
| 99 } | |
| 100 | |
| 101 // Returns TRUE if connection should be kept alive, FALSE if it should be closed | |
| 102 boolean Seobeo_Web_ClientHandle_Request(Seobeo_Handle *p_cli_handle, | |
| 103 Seobeo_Cache_Entry *p_html_cache, | |
| 104 boolean use_keep_alive) | |
| 105 { | |
| 106 boolean should_keep_alive = FALSE; | |
| 107 | |
| 108 // Start with default arena size (5MB) | |
| 109 size_t arena_size = DEFAULT_ARENA_SIZE; | |
| 110 | |
| 111 // We'll peek at Content-Length to potentially allocate larger arena | |
| 112 // For now, start with default and handle body reading separately | |
| 113 Dowa_Arena *p_request_arena = Dowa_Arena_Create(arena_size); | |
| 114 if (!p_request_arena) { perror("Dowa_Arena_Create request"); return FALSE; } | |
| 115 | |
| 116 Dowa_Arena *p_response_arena = Dowa_Arena_Create(arena_size); | |
| 117 if (!p_response_arena) { perror("Dowa_Arena_Create response"); Dowa_Arena_Free(p_request_arena); return FALSE; } | |
| 74 | 118 |
| 75 void *p_response_header = Dowa_Arena_Allocate(p_response_arena, 1024*5); // 5Kb | 119 void *p_response_header = Dowa_Arena_Allocate(p_response_arena, 1024*5); // 5Kb |
| 76 if (!p_response_header) { perror("Dowa_Arena_Allocate"); goto clean_up; } | 120 if (!p_response_header) { perror("Dowa_Arena_Allocate"); goto clean_up_arenas; } |
| 77 | 121 |
| 78 Seobeo_Request_Entry *p_req_map = NULL; | 122 Seobeo_Request_Entry *p_req_map = NULL; |
| 79 int parse_result = Seobeo_Web_Header_Parse(p_cli_handle, &p_req_map, p_request_arena); | 123 int parse_result = Seobeo_Web_Header_Parse(p_cli_handle, &p_req_map, p_request_arena); |
| 80 | 124 |
| 81 if (parse_result != 0 && parse_result != 1) | 125 // Handle parse errors |
| 82 { | 126 if (parse_result < 0) { |
| 83 Seobeo_Log(SEOBEO_ERROR, "Seobeo_Web_Header_Parse failed with code %d\n", parse_result); | 127 // Fatal error or connection closed |
| 128 Seobeo_Log(SEOBEO_DEBUG, "Seobeo_Web_Header_Parse failed with code %d\n", parse_result); | |
| 129 if (parse_result == -2) { | |
| 130 // Connection closed by client - don't send error response | |
| 131 goto clean_up_arenas; | |
| 132 } | |
| 84 Seobeo_Web_Header_Generate(p_response_header, | 133 Seobeo_Web_Header_Generate(p_response_header, |
| 85 HTTP_BAD_REQUEST, | 134 HTTP_BAD_REQUEST, |
| 86 "text/plain", 0); | 135 "text/plain", 0); |
| 87 Seobeo_Handle_Queue(p_cli_handle, | 136 Seobeo_Handle_Queue(p_cli_handle, |
| 88 (const uint8*)p_response_header, | 137 (const uint8*)p_response_header, |
| 89 (uint32)strlen(p_response_header)); | 138 (uint32)strlen(p_response_header)); |
| 90 Seobeo_Handle_Flush(p_cli_handle); | 139 Seobeo_Handle_Flush(p_cli_handle); |
| 91 goto clean_up; | 140 goto clean_up_arenas; |
| 92 } | 141 } |
| 93 | 142 |
| 94 Seobeo_Log(SEOBEO_DEBUG, "Parse completed with code %d\n", parse_result); | 143 // Determine keep-alive based on HTTP version and Connection header |
| 95 | 144 // HTTP/1.1: keep-alive by default unless "Connection: close" |
| 96 // Recording IP to see who is ddosing or any web scrappers... | 145 // HTTP/1.0: close by default unless "Connection: keep-alive" |
| 97 void *p_real_ip_kv = Dowa_HashMap_Get_Ptr(p_req_map, "X-Real-IP"); | 146 |
| 98 const char *real_ip = p_real_ip_kv ? ((Seobeo_Request_Entry*)p_real_ip_kv)->value : NULL; | 147 void *p_ver_kv = Dowa_HashMap_Get_Ptr(p_req_map, "Version"); |
| 99 // Fallback | 148 const char *http_version = p_ver_kv ? ((Seobeo_Request_Entry*)p_ver_kv)->value : "HTTP/1.0"; |
| 100 if (!real_ip) | 149 boolean is_http11 = (strstr(http_version, "1.1") != NULL); |
| 101 { | 150 |
| 102 void *p_forwarded_kv = Dowa_HashMap_Get_Ptr(p_req_map, "X-Forwarded-For"); | 151 void *p_conn_kv = Dowa_HashMap_Get_Ptr(p_req_map, "Connection"); |
| 103 real_ip = p_forwarded_kv ? ((Seobeo_Request_Entry*)p_forwarded_kv)->value : NULL; | 152 const char *conn_header = p_conn_kv ? ((Seobeo_Request_Entry*)p_conn_kv)->value : NULL; |
| 104 } | 153 |
| 105 // Fallback | 154 if (conn_header) |
| 106 if (!real_ip) | 155 { |
| 107 real_ip = p_cli_handle->host; | 156 if (connection_header_contains(conn_header, "close")) |
| 157 should_keep_alive = FALSE; | |
| 158 else if (connection_header_contains(conn_header, "keep-alive")) | |
| 159 should_keep_alive = use_keep_alive; | |
| 160 else | |
| 161 should_keep_alive = is_http11 && use_keep_alive; // Unknown value, use version default | |
| 162 } | |
| 163 else | |
| 164 should_keep_alive = is_http11 && use_keep_alive; | |
| 108 | 165 |
| 109 void *p_method_kv = Dowa_HashMap_Get_Ptr(p_req_map, "HTTP_Method"); | 166 void *p_method_kv = Dowa_HashMap_Get_Ptr(p_req_map, "HTTP_Method"); |
| 110 const char *method = p_method_kv ? ((Seobeo_Request_Entry*)p_method_kv)->value : NULL; | 167 const char *method = p_method_kv ? ((Seobeo_Request_Entry*)p_method_kv)->value : NULL; |
| 111 | 168 |
| 112 void *p_path_kv_log = Dowa_HashMap_Get_Ptr(p_req_map, "Path"); | 169 void *p_path_kv = Dowa_HashMap_Get_Ptr(p_req_map, "Path"); |
| 113 const char *path_log = p_path_kv_log ? ((Seobeo_Request_Entry*)p_path_kv_log)->value : "/"; | 170 const char *path = p_path_kv ? ((Seobeo_Request_Entry*)p_path_kv)->value : "/"; |
| 114 | |
| 115 Seobeo_Log(SEOBEO_INFO, "%s - %s %s\n", | |
| 116 real_ip ? real_ip : "unknown", | |
| 117 method ? method : "UNKNOWN", | |
| 118 path_log); | |
| 119 | |
| 120 Seobeo_Log(SEOBEO_DEBUG, "Parsed request, method=%s\n", method ? method : "NULL"); | |
| 121 | 171 |
| 122 if (!method) | 172 if (!method) |
| 123 { | 173 { |
| 124 Seobeo_Log(SEOBEO_ERROR, "No HTTP method found in request\n"); | 174 Seobeo_Log(SEOBEO_DEBUG, "No HTTP method found in request\n"); |
| 125 Seobeo_Web_Header_Generate(p_response_header, | 175 Seobeo_Web_Header_Generate(p_response_header, |
| 126 HTTP_BAD_REQUEST, | 176 HTTP_BAD_REQUEST, |
| 127 "text/plain", 0); | 177 "text/plain", 0); |
| 128 Seobeo_Handle_Queue(p_cli_handle, | 178 Seobeo_Handle_Queue(p_cli_handle, |
| 129 (const uint8*)p_response_header, | 179 (const uint8*)p_response_header, |
| 130 (uint32)strlen(p_response_header)); | 180 (uint32)strlen(p_response_header)); |
| 131 Seobeo_Handle_Flush(p_cli_handle); | 181 Seobeo_Handle_Flush(p_cli_handle); |
| 132 goto clean_up; | 182 should_keep_alive = FALSE; |
| 133 } | 183 goto clean_up_arenas; |
| 134 | 184 } |
| 135 void *p_path_kv = Dowa_HashMap_Get_Ptr(p_req_map, "Path"); | |
| 136 const char *path = p_path_kv ? ((Seobeo_Request_Entry*)p_path_kv)->value : "/"; | |
| 137 | 185 |
| 138 // --- Check for WebSocket upgrade request --- | 186 // --- Check for WebSocket upgrade request --- |
| 139 #ifdef SEOBEO_WEBSOCKET_SERVER | 187 #ifdef SEOBEO_WEBSOCKET_SERVER |
| 140 Seobeo_Log(SEOBEO_DEBUG, "Web soceket path \n"); | |
| 141 if (Seobeo_WebSocket_Server_Handle_Upgrade(p_cli_handle, p_req_map, path)) | 188 if (Seobeo_WebSocket_Server_Handle_Upgrade(p_cli_handle, p_req_map, path)) |
| 142 { | 189 { |
| 143 Seobeo_Log(SEOBEO_INFO, "WebSocket connection established\n"); | 190 Seobeo_Log(SEOBEO_INFO, "WebSocket connection established\n"); |
| 144 if (p_request_arena) | 191 Dowa_Arena_Free(p_request_arena); |
| 145 Dowa_Arena_Free(p_request_arena); | 192 Dowa_Arena_Free(p_response_arena); |
| 146 if (p_response_arena) | 193 return FALSE; // WebSocket takes over, don't keep-alive in HTTP sense |
| 147 Dowa_Arena_Free(p_response_arena); | |
| 148 return; | |
| 149 } | 194 } |
| 150 #endif | 195 #endif |
| 151 | 196 |
| 152 // --- Try to match API route first --- | 197 // --- Try to match API route first --- |
| 153 Seobeo_Route_Handler handler = Seobeo_Router_Find_Handler(method, path, &p_req_map, p_request_arena); | 198 Seobeo_Route_Handler handler = Seobeo_Router_Find_Handler(method, path, &p_req_map, p_request_arena); |
| 154 if (handler != NULL) | 199 if (handler != NULL) |
| 155 { | 200 { |
| 156 Seobeo_Request_Entry *p_response_map = handler(p_req_map, p_response_arena); | 201 Seobeo_Request_Entry *p_response_map = handler(p_req_map, p_response_arena); |
| 157 Seobeo_Router_Send_Response(p_cli_handle, p_response_map, p_response_arena); | 202 Seobeo_Router_Send_Response_KeepAlive(p_cli_handle, p_response_map, p_response_arena, should_keep_alive); |
| 158 goto clean_up; | 203 goto clean_up_arenas; |
| 159 } | 204 } |
| 160 | 205 |
| 161 // --- Static files fallback for GET --- | 206 // --- Static files fallback for GET (use original large arena logic) --- |
| 162 if (strcmp(method, "GET") == 0) | 207 if (strcmp(method, "GET") == 0) |
| 163 { | 208 { |
| 164 void *p_kv = Dowa_HashMap_Get_Ptr(p_req_map, "Path"); | 209 char *file_path = Dowa_Arena_Allocate(p_response_arena, (size_t)5 * 1024); |
| 165 const char *path = p_kv ? ((Seobeo_Request_Entry*)p_kv)->value : NULL; | |
| 166 char *file_path = Dowa_Arena_Allocate(p_response_arena, (size_t)5 * 1024); // 5Kb only for path | |
| 167 | 210 |
| 168 if (!path || strcmp(path, "/") == 0) | 211 if (!path || strcmp(path, "/") == 0) |
| 169 { | 212 { |
| 170 strcpy(file_path, "index.html"); | 213 strcpy(file_path, "index.html"); |
| 171 } | 214 } |
| 181 } | 224 } |
| 182 else | 225 else |
| 183 strcpy(file_path, path); | 226 strcpy(file_path, path); |
| 184 } | 227 } |
| 185 | 228 |
| 186 // Check if file is in cache, load if not | |
| 187 void *p_file_kv = Dowa_HashMap_Get_Ptr(p_html_cache, file_path); | 229 void *p_file_kv = Dowa_HashMap_Get_Ptr(p_html_cache, file_path); |
| 188 const char *file_content = NULL; | 230 const char *file_content = NULL; |
| 189 size_t body_size = 0; | 231 size_t body_size = 0; |
| 190 | 232 |
| 191 if (p_file_kv) | 233 if (p_file_kv) |
| 192 { | 234 { |
| 193 // File is cached - use stored size for binary file support | |
| 194 Seobeo_Cached_File *cached = ((Seobeo_Cache_Entry*)p_file_kv)->value; | 235 Seobeo_Cached_File *cached = ((Seobeo_Cache_Entry*)p_file_kv)->value; |
| 195 file_content = cached->content; | 236 file_content = cached->content; |
| 196 body_size = cached->size; | 237 body_size = cached->size; |
| 197 } | 238 } |
| 198 else | 239 else |
| 207 } | 248 } |
| 208 } | 249 } |
| 209 | 250 |
| 210 if (!file_content) | 251 if (!file_content) |
| 211 { | 252 { |
| 212 Seobeo_Web_Header_Generate(p_response_header, | 253 Seobeo_Web_Header_Generate_KeepAlive(p_response_header, |
| 213 HTTP_NOT_FOUND, | 254 HTTP_NOT_FOUND, |
| 214 "text/html", 0); | 255 "text/html", 0, should_keep_alive); |
| 215 Seobeo_Handle_Queue(p_cli_handle, | 256 Seobeo_Handle_Queue(p_cli_handle, |
| 216 (const uint8*)p_response_header, | 257 (const uint8*)p_response_header, |
| 217 (uint32)strlen(p_response_header)); | 258 (uint32)strlen(p_response_header)); |
| 218 Seobeo_Handle_Flush(p_cli_handle); | 259 Seobeo_Handle_Flush(p_cli_handle); |
| 219 goto clean_up; | 260 goto clean_up_arenas; |
| 220 } | 261 } |
| 221 | 262 |
| 222 Seobeo_Log(SEOBEO_DEBUG, "Serving Static Files\n"); | |
| 223 // Serve static file | |
| 224 const char *mime = "application/octet-stream"; | 263 const char *mime = "application/octet-stream"; |
| 225 if (strstr(file_path, ".html")) mime = "text/html; charset=utf-8"; | 264 if (strstr(file_path, ".html")) mime = "text/html; charset=utf-8"; |
| 226 else if (strstr(file_path, ".css")) mime = "text/css"; | 265 else if (strstr(file_path, ".css")) mime = "text/css"; |
| 227 else if (strstr(file_path, ".js")) mime = "application/javascript"; | 266 else if (strstr(file_path, ".js")) mime = "application/javascript"; |
| 228 else if (strstr(file_path, ".png")) mime = "image/png"; | 267 else if (strstr(file_path, ".png")) mime = "image/png"; |
| 229 else if (strstr(file_path, ".jpg") || strstr(file_path, ".jpeg")) mime = "image/jpeg"; | 268 else if (strstr(file_path, ".jpg") || strstr(file_path, ".jpeg")) mime = "image/jpeg"; |
| 230 else if (strstr(file_path, ".webp")) mime = "image/webp"; | |
| 231 else if (strstr(file_path, ".gif")) mime = "image/gif"; | 269 else if (strstr(file_path, ".gif")) mime = "image/gif"; |
| 232 else if (strstr(file_path, ".svg")) mime = "image/svg+xml"; | 270 else if (strstr(file_path, ".svg")) mime = "image/svg+xml"; |
| 233 else if (strstr(file_path, ".ico")) mime = "image/x-icon"; | 271 else if (strstr(file_path, ".ico")) mime = "image/x-icon"; |
| 272 else if (strstr(file_path, ".webp")) mime = "image/webp"; | |
| 234 else if (strstr(file_path, ".json")) mime = "application/json"; | 273 else if (strstr(file_path, ".json")) mime = "application/json"; |
| 235 else if (strstr(file_path, ".wasm")) mime = "application/wasm"; | 274 else if (strstr(file_path, ".wasm")) mime = "application/wasm"; |
| 275 else if (strstr(file_path, ".xml")) mime = "application/xml"; | |
| 276 else if (strstr(file_path, ".pdf")) mime = "application/pdf"; | |
| 277 else if (strstr(file_path, ".txt")) mime = "text/plain"; | |
| 236 else if (strstr(file_path, ".mp4")) mime = "video/mp4"; | 278 else if (strstr(file_path, ".mp4")) mime = "video/mp4"; |
| 237 else if (strstr(file_path, ".webm")) mime = "video/webm"; | 279 else if (strstr(file_path, ".webm")) mime = "video/webm"; |
| 280 else if (strstr(file_path, ".mp3")) mime = "audio/mpeg"; | |
| 281 else if (strstr(file_path, ".woff2")) mime = "font/woff2"; | |
| 282 else if (strstr(file_path, ".woff")) mime = "font/woff"; | |
| 283 else if (strstr(file_path, ".ttf")) mime = "font/ttf"; | |
| 284 else if (strstr(file_path, ".webp")) mime = "image/webp"; | |
| 238 else if (strstr(file_path, ".glb")) mime = "model/gltf-binary"; | 285 else if (strstr(file_path, ".glb")) mime = "model/gltf-binary"; |
| 239 else if (strstr(file_path, ".gltf")) mime = "model/gltf+json"; | 286 else if (strstr(file_path, ".gltf")) mime = "model/gltf+json"; |
| 240 | 287 |
| 241 Seobeo_Log(SEOBEO_DEBUG, "File path: %s\nBody Size: %zu\n", file_path, body_size); | 288 |
| 242 | 289 Seobeo_Web_Header_Generate_KeepAlive(p_response_header, |
| 243 Seobeo_Web_Header_Generate(p_response_header, | |
| 244 HTTP_OK, | 290 HTTP_OK, |
| 245 mime, | 291 mime, |
| 246 body_size); | 292 body_size, should_keep_alive); |
| 247 | 293 |
| 248 Seobeo_Handle_Queue(p_cli_handle, | 294 Seobeo_Handle_Queue(p_cli_handle, |
| 249 (const uint8*)p_response_header, | 295 (const uint8*)p_response_header, |
| 250 (uint32)strlen(p_response_header)); | 296 (uint32)strlen(p_response_header)); |
| 251 Seobeo_Handle_Queue(p_cli_handle, | 297 Seobeo_Handle_Queue(p_cli_handle, |
| 252 (const uint8*)file_content, | 298 (const uint8*)file_content, |
| 253 (uint32)body_size); | 299 (uint32)body_size); |
| 254 Seobeo_Handle_Flush(p_cli_handle); | 300 Seobeo_Handle_Flush(p_cli_handle); |
| 255 Seobeo_Log(SEOBEO_DEBUG, "Request handled successfully\n"); | |
| 256 } | 301 } |
| 257 else | 302 else |
| 258 { | 303 { |
| 259 Seobeo_Web_Header_Generate(p_response_header, | 304 Seobeo_Web_Header_Generate_KeepAlive(p_response_header, |
| 260 HTTP_FORBIDDEN, | 305 HTTP_NOT_FOUND, |
| 261 "text/plain", 0); | 306 "text/plain", 0, should_keep_alive); |
| 262 Seobeo_Handle_Queue(p_cli_handle, | 307 Seobeo_Handle_Queue(p_cli_handle, |
| 263 (const uint8*)p_response_header, | 308 (const uint8*)p_response_header, |
| 264 (uint32)strlen(p_response_header)); | 309 (uint32)strlen(p_response_header)); |
| 265 Seobeo_Handle_Flush(p_cli_handle); | 310 Seobeo_Handle_Flush(p_cli_handle); |
| 266 } | 311 } |
| 267 goto clean_up; | 312 |
| 268 | 313 clean_up_arenas: |
| 269 clean_up: | |
| 270 Seobeo_Log(SEOBEO_INFO, "Clean up all Arenas\n"); | |
| 271 if (p_cli_handle) | |
| 272 Seobeo_Handle_Destroy(p_cli_handle); | |
| 273 if (p_request_arena) | 314 if (p_request_arena) |
| 274 Dowa_Arena_Free(p_request_arena); | 315 Dowa_Arena_Free(p_request_arena); |
| 275 if (p_response_arena) | 316 if (p_response_arena) |
| 276 Dowa_Arena_Free(p_response_arena); | 317 Dowa_Arena_Free(p_response_arena); |
| 277 return; | 318 return should_keep_alive; |
| 278 } | 319 } |
| 279 | |
| 280 | 320 |
| 281 int Seobeo_Web_Header_Parse(Seobeo_Handle *p_handle, Seobeo_Request_Entry **pp_map, Dowa_Arena *p_arena) | 321 int Seobeo_Web_Header_Parse(Seobeo_Handle *p_handle, Seobeo_Request_Entry **pp_map, Dowa_Arena *p_arena) |
| 282 { | 322 { |
| 283 while (1) | 323 while (1) |
| 284 { | 324 { |
| 544 Seobeo_Stream_Handle_Server_Accept(p_server_handle); | 584 Seobeo_Stream_Handle_Server_Accept(p_server_handle); |
| 545 if (!p_cli_handle) continue; | 585 if (!p_cli_handle) continue; |
| 546 | 586 |
| 547 if (fork() == 0) | 587 if (fork() == 0) |
| 548 { | 588 { |
| 549 Seobeo_Web_HandleClientRequest(p_cli_handle, | 589 Seobeo_Web_ClientHandle_Request(p_cli_handle, p_html_cache, FALSE); |
| 550 p_html_cache); | |
| 551 _exit(0); | 590 _exit(0); |
| 552 } | 591 } |
| 553 } | 592 } |
| 554 } | 593 } |
| 555 | 594 |
| 673 void Seobeo_Router_Send_Response( | 712 void Seobeo_Router_Send_Response( |
| 674 Seobeo_Handle *p_handle, | 713 Seobeo_Handle *p_handle, |
| 675 Seobeo_Request_Entry *p_response_map, | 714 Seobeo_Request_Entry *p_response_map, |
| 676 Dowa_Arena *p_arena) | 715 Dowa_Arena *p_arena) |
| 677 { | 716 { |
| 717 Seobeo_Router_Send_Response_KeepAlive(p_handle, p_response_map, p_arena, FALSE); | |
| 718 } | |
| 719 | |
| 720 void Seobeo_Router_Send_Response_KeepAlive( | |
| 721 Seobeo_Handle *p_handle, | |
| 722 Seobeo_Request_Entry *p_response_map, | |
| 723 Dowa_Arena *p_arena, | |
| 724 boolean keep_alive) | |
| 725 { | |
| 678 if (p_response_map == NULL) | 726 if (p_response_map == NULL) |
| 679 { | 727 { |
| 680 char *header = Dowa_Arena_Allocate(p_arena, 1024); | 728 char *header = Dowa_Arena_Allocate(p_arena, 1024); |
| 681 Seobeo_Web_Header_Generate(header, HTTP_INTERNAL_ERROR, "text/plain", 21); | 729 Seobeo_Web_Header_Generate_KeepAlive(header, HTTP_INTERNAL_ERROR, "text/plain", 21, keep_alive); |
| 682 Seobeo_Handle_Queue(p_handle, (uint8_t*)header, strlen(header)); | 730 Seobeo_Handle_Queue(p_handle, (uint8_t*)header, strlen(header)); |
| 683 Seobeo_Handle_Queue(p_handle, (uint8_t*)"Internal Server Error", 21); | 731 Seobeo_Handle_Queue(p_handle, (uint8_t*)"Internal Server Error", 21); |
| 684 Seobeo_Handle_Flush(p_handle); | 732 Seobeo_Handle_Flush(p_handle); |
| 685 return; | 733 return; |
| 686 } | 734 } |
| 714 const char *content_length_str = ((Seobeo_Request_Entry*)p_content_length_kv)->value; | 762 const char *content_length_str = ((Seobeo_Request_Entry*)p_content_length_kv)->value; |
| 715 body_length = atoi(content_length_str); | 763 body_length = atoi(content_length_str); |
| 716 } | 764 } |
| 717 | 765 |
| 718 char *header = Dowa_Arena_Allocate(p_arena, 4096); | 766 char *header = Dowa_Arena_Allocate(p_arena, 4096); |
| 719 Seobeo_Web_Header_Generate(header, status, content_type, body_length); | 767 Seobeo_Web_Header_Generate_KeepAlive(header, status, content_type, body_length, keep_alive); |
| 720 for (int i = 0; i < Dowa_Array_Length(p_response_map); i++) | 768 for (int i = 0; i < Dowa_Array_Length(p_response_map); i++) |
| 721 { | 769 { |
| 722 if ( | 770 if ( |
| 723 strstr(p_response_map[i].key, "status") || | 771 strstr(p_response_map[i].key, "status") || |
| 724 strstr(p_response_map[i].key, "body") || | 772 strstr(p_response_map[i].key, "body") || |
| 725 strstr(p_response_map[i].key, "content-type") || | 773 strstr(p_response_map[i].key, "content-type") || |
| 726 strstr(p_response_map[i].key, "content-length") | 774 strstr(p_response_map[i].key, "content-length") |
| 727 ) | 775 ) |
| 728 continue; | 776 continue; |
| 729 | 777 |
| 730 int32 current_header_len = strlen(header); | 778 int32 current_header_len = strlen(header); |
| 731 char *temp = malloc(sizeof(char) * 1024); | 779 char *temp = malloc(sizeof(char) * 1024); |
| 733 memcpy(&header[current_header_len - 2 /* \r\n */], temp, strlen(temp)); | 781 memcpy(&header[current_header_len - 2 /* \r\n */], temp, strlen(temp)); |
| 734 free(temp); | 782 free(temp); |
| 735 } | 783 } |
| 736 | 784 |
| 737 Seobeo_Handle_Queue(p_handle, (uint8_t*)header, strlen(header)); | 785 Seobeo_Handle_Queue(p_handle, (uint8_t*)header, strlen(header)); |
| 738 Seobeo_Handle_Queue(p_handle, (uint8_t*)body, body_length); | 786 Seobeo_Handle_Queue(p_handle, (uint8_t*)body, body_length); |
| 739 Seobeo_Handle_Flush(p_handle); | 787 Seobeo_Handle_Flush(p_handle); |
| 740 } | 788 } |
| 741 | 789 |
| 742 void Seobeo_Router_Destroy() | 790 void Seobeo_Router_Destroy() |
| 743 { | 791 { |
| 754 if (route->is_param) free(route->is_param); | 802 if (route->is_param) free(route->is_param); |
| 755 } | 803 } |
| 756 Dowa_Array_Free(g_routes); | 804 Dowa_Array_Free(g_routes); |
| 757 g_routes = NULL; | 805 g_routes = NULL; |
| 758 } | 806 } |
| 759 | |
| 760 // Logging functions moved to s_logging.c | |
| 761 |