Mercurial
comparison seobeo/s_web.c @ 186:8cf4ec5e2191 hg-web
Fixed merge conflict.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Fri, 23 Jan 2026 22:38:59 -0800 |
| parents | 71ad34a8bc9a 8c74204fd362 |
| children | a69485d9f2e1 |
comparison
equal
deleted
inserted
replaced
| 176:fed99fc04e12 | 186:8cf4ec5e2191 |
|---|---|
| 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" |
| 146 | |
| 147 void *p_ver_kv = Dowa_HashMap_Get_Ptr(p_req_map, "Version"); | |
| 148 const char *http_version = p_ver_kv ? ((Seobeo_Request_Entry*)p_ver_kv)->value : "HTTP/1.0"; | |
| 149 boolean is_http11 = (strstr(http_version, "1.1") != NULL); | |
| 150 | |
| 151 void *p_conn_kv = Dowa_HashMap_Get_Ptr(p_req_map, "Connection"); | |
| 152 const char *conn_header = p_conn_kv ? ((Seobeo_Request_Entry*)p_conn_kv)->value : NULL; | |
| 153 | |
| 97 void *p_real_ip_kv = Dowa_HashMap_Get_Ptr(p_req_map, "X-Real-IP"); | 154 void *p_real_ip_kv = Dowa_HashMap_Get_Ptr(p_req_map, "X-Real-IP"); |
| 98 const char *real_ip = p_real_ip_kv ? ((Seobeo_Request_Entry*)p_real_ip_kv)->value : NULL; | 155 const char *real_ip = p_real_ip_kv ? ((Seobeo_Request_Entry*)p_real_ip_kv)->value : NULL; |
| 99 | |
| 100 // Fallback | |
| 101 if (!real_ip) | |
| 102 { | |
| 103 void *p_forwarded_kv = Dowa_HashMap_Get_Ptr(p_req_map, "X-Forwarded-For"); | |
| 104 real_ip = p_forwarded_kv ? ((Seobeo_Request_Entry*)p_forwarded_kv)->value : NULL; | |
| 105 } | |
| 106 | |
| 107 if (!real_ip) | 156 if (!real_ip) |
| 108 real_ip = p_cli_handle->host; | 157 real_ip = p_cli_handle->host; |
| 109 | 158 |
| 159 if (conn_header) | |
| 160 { | |
| 161 if (connection_header_contains(conn_header, "close")) | |
| 162 should_keep_alive = FALSE; | |
| 163 else if (connection_header_contains(conn_header, "keep-alive")) | |
| 164 should_keep_alive = use_keep_alive; | |
| 165 else | |
| 166 should_keep_alive = is_http11 && use_keep_alive; // Unknown value, use version default | |
| 167 } | |
| 168 else | |
| 169 should_keep_alive = is_http11 && use_keep_alive; | |
| 170 | |
| 110 void *p_method_kv = Dowa_HashMap_Get_Ptr(p_req_map, "HTTP_Method"); | 171 void *p_method_kv = Dowa_HashMap_Get_Ptr(p_req_map, "HTTP_Method"); |
| 111 const char *method = p_method_kv ? ((Seobeo_Request_Entry*)p_method_kv)->value : NULL; | 172 const char *method = p_method_kv ? ((Seobeo_Request_Entry*)p_method_kv)->value : NULL; |
| 112 | 173 |
| 113 void *p_path_kv_log = Dowa_HashMap_Get_Ptr(p_req_map, "Path"); | 174 void *p_path_kv = Dowa_HashMap_Get_Ptr(p_req_map, "Path"); |
| 114 const char *path_log = p_path_kv_log ? ((Seobeo_Request_Entry*)p_path_kv_log)->value : "/"; | 175 const char *path = p_path_kv ? ((Seobeo_Request_Entry*)p_path_kv)->value : "/"; |
| 115 | |
| 116 Seobeo_Log(SEOBEO_INFO, "%s - %s %s\n", | |
| 117 real_ip ? real_ip : "unknown", | |
| 118 method ? method : "UNKNOWN", | |
| 119 path_log); | |
| 120 | |
| 121 Seobeo_Log(SEOBEO_DEBUG, "Parsed request, method=%s\n", method ? method : "NULL"); | |
| 122 | 176 |
| 123 if (!method) | 177 if (!method) |
| 124 { | 178 { |
| 125 Seobeo_Log(SEOBEO_ERROR, "No HTTP method found in request\n"); | 179 Seobeo_Log(SEOBEO_DEBUG, "No HTTP method found in request\n"); |
| 126 Seobeo_Web_Header_Generate(p_response_header, | 180 Seobeo_Web_Header_Generate(p_response_header, |
| 127 HTTP_BAD_REQUEST, | 181 HTTP_BAD_REQUEST, |
| 128 "text/plain", 0); | 182 "text/plain", 0); |
| 129 Seobeo_Handle_Queue(p_cli_handle, | 183 Seobeo_Handle_Queue(p_cli_handle, |
| 130 (const uint8*)p_response_header, | 184 (const uint8*)p_response_header, |
| 131 (uint32)strlen(p_response_header)); | 185 (uint32)strlen(p_response_header)); |
| 132 Seobeo_Handle_Flush(p_cli_handle); | 186 Seobeo_Handle_Flush(p_cli_handle); |
| 133 goto clean_up; | 187 should_keep_alive = FALSE; |
| 134 } | 188 goto clean_up_arenas; |
| 135 | 189 } |
| 136 void *p_path_kv = Dowa_HashMap_Get_Ptr(p_req_map, "Path"); | |
| 137 const char *path = p_path_kv ? ((Seobeo_Request_Entry*)p_path_kv)->value : "/"; | |
| 138 | 190 |
| 139 // --- Check for WebSocket upgrade request --- | 191 // --- Check for WebSocket upgrade request --- |
| 140 #ifdef SEOBEO_WEBSOCKET_SERVER | 192 #ifdef SEOBEO_WEBSOCKET_SERVER |
| 141 Seobeo_Log(SEOBEO_DEBUG, "Web socket path \n"); | 193 Seobeo_Log(SEOBEO_DEBUG, "Web socket path \n"); |
| 142 if (Seobeo_WebSocket_Server_Handle_Upgrade(p_cli_handle, p_req_map, path)) | 194 if (Seobeo_WebSocket_Server_Handle_Upgrade(p_cli_handle, p_req_map, path)) |
| 143 { | 195 { |
| 144 Seobeo_Log(SEOBEO_INFO, "WebSocket connection established\n"); | 196 Seobeo_Log(SEOBEO_INFO, "WebSocket connection established\n"); |
| 145 if (p_request_arena) | 197 Dowa_Arena_Free(p_request_arena); |
| 146 Dowa_Arena_Free(p_request_arena); | 198 Dowa_Arena_Free(p_response_arena); |
| 147 if (p_response_arena) | 199 return FALSE; // WebSocket takes over, don't keep-alive in HTTP sense |
| 148 Dowa_Arena_Free(p_response_arena); | |
| 149 return; | |
| 150 } | 200 } |
| 151 #endif | 201 #endif |
| 152 | 202 |
| 153 // --- Try to match streaming route first --- | 203 // --- Try to match streaming route first --- |
| 154 Seobeo_Stream_Handler stream_handler = Seobeo_Router_Find_Stream_Handler(method, path, &p_req_map, p_request_arena); | 204 Seobeo_Stream_Handler stream_handler = Seobeo_Router_Find_Stream_Handler(method, path, &p_req_map, p_request_arena); |
| 161 // --- Try to match API route --- | 211 // --- Try to match API route --- |
| 162 Seobeo_Route_Handler handler = Seobeo_Router_Find_Handler(method, path, &p_req_map, p_request_arena); | 212 Seobeo_Route_Handler handler = Seobeo_Router_Find_Handler(method, path, &p_req_map, p_request_arena); |
| 163 if (handler != NULL) | 213 if (handler != NULL) |
| 164 { | 214 { |
| 165 Seobeo_Request_Entry *p_response_map = handler(p_req_map, p_response_arena); | 215 Seobeo_Request_Entry *p_response_map = handler(p_req_map, p_response_arena); |
| 166 Seobeo_Router_Send_Response(p_cli_handle, p_response_map, p_response_arena); | 216 Seobeo_Router_Send_Response_KeepAlive(p_cli_handle, p_response_map, p_response_arena, should_keep_alive); |
| 167 goto clean_up; | 217 goto clean_up_arenas; |
| 168 } | 218 } |
| 169 | 219 |
| 170 // --- Static files fallback for GET --- | 220 // --- Static files fallback for GET (use original large arena logic) --- |
| 171 if (strcmp(method, "GET") == 0) | 221 if (strcmp(method, "GET") == 0) |
| 172 { | 222 { |
| 173 void *p_kv = Dowa_HashMap_Get_Ptr(p_req_map, "Path"); | 223 char *file_path = Dowa_Arena_Allocate(p_response_arena, (size_t)5 * 1024); |
| 174 const char *path = p_kv ? ((Seobeo_Request_Entry*)p_kv)->value : NULL; | |
| 175 char *file_path = Dowa_Arena_Allocate(p_response_arena, (size_t)5 * 1024); // 5Kb only for path | |
| 176 | 224 |
| 177 if (!path || strcmp(path, "/") == 0) | 225 if (!path || strcmp(path, "/") == 0) |
| 178 { | 226 { |
| 179 strcpy(file_path, "index.html"); | 227 strcpy(file_path, "index.html"); |
| 180 } | 228 } |
| 190 } | 238 } |
| 191 else | 239 else |
| 192 strcpy(file_path, path); | 240 strcpy(file_path, path); |
| 193 } | 241 } |
| 194 | 242 |
| 195 // Check if file is in cache, load if not | |
| 196 void *p_file_kv = Dowa_HashMap_Get_Ptr(p_html_cache, file_path); | 243 void *p_file_kv = Dowa_HashMap_Get_Ptr(p_html_cache, file_path); |
| 197 const char *file_content = NULL; | 244 const char *file_content = NULL; |
| 198 size_t body_size = 0; | 245 size_t body_size = 0; |
| 199 | 246 |
| 200 if (p_file_kv) | 247 if (p_file_kv) |
| 201 { | 248 { |
| 202 // File is cached - use stored size for binary file support | |
| 203 Seobeo_Cached_File *cached = ((Seobeo_Cache_Entry*)p_file_kv)->value; | 249 Seobeo_Cached_File *cached = ((Seobeo_Cache_Entry*)p_file_kv)->value; |
| 204 file_content = cached->content; | 250 file_content = cached->content; |
| 205 body_size = cached->size; | 251 body_size = cached->size; |
| 206 } | 252 } |
| 207 else | 253 else |
| 216 } | 262 } |
| 217 } | 263 } |
| 218 | 264 |
| 219 if (!file_content) | 265 if (!file_content) |
| 220 { | 266 { |
| 221 Seobeo_Web_Header_Generate(p_response_header, | 267 Seobeo_Web_Header_Generate_KeepAlive(p_response_header, |
| 222 HTTP_NOT_FOUND, | 268 HTTP_NOT_FOUND, |
| 223 "text/html", 0); | 269 "text/html", 0, should_keep_alive); |
| 224 Seobeo_Handle_Queue(p_cli_handle, | 270 Seobeo_Handle_Queue(p_cli_handle, |
| 225 (const uint8*)p_response_header, | 271 (const uint8*)p_response_header, |
| 226 (uint32)strlen(p_response_header)); | 272 (uint32)strlen(p_response_header)); |
| 227 Seobeo_Handle_Flush(p_cli_handle); | 273 Seobeo_Handle_Flush(p_cli_handle); |
| 228 goto clean_up; | 274 goto clean_up_arenas; |
| 229 } | 275 } |
| 230 | 276 |
| 231 Seobeo_Log(SEOBEO_DEBUG, "Serving Static Files\n"); | |
| 232 // Serve static file | |
| 233 const char *mime = "application/octet-stream"; | 277 const char *mime = "application/octet-stream"; |
| 234 if (strstr(file_path, ".html")) mime = "text/html; charset=utf-8"; | 278 if (strstr(file_path, ".html")) mime = "text/html; charset=utf-8"; |
| 235 else if (strstr(file_path, ".css")) mime = "text/css"; | 279 else if (strstr(file_path, ".css")) mime = "text/css"; |
| 236 else if (strstr(file_path, ".js")) mime = "application/javascript"; | 280 else if (strstr(file_path, ".js")) mime = "application/javascript"; |
| 237 else if (strstr(file_path, ".png")) mime = "image/png"; | 281 else if (strstr(file_path, ".png")) mime = "image/png"; |
| 238 else if (strstr(file_path, ".jpg") || strstr(file_path, ".jpeg")) mime = "image/jpeg"; | 282 else if (strstr(file_path, ".jpg") || strstr(file_path, ".jpeg")) mime = "image/jpeg"; |
| 239 else if (strstr(file_path, ".webp")) mime = "image/webp"; | |
| 240 else if (strstr(file_path, ".gif")) mime = "image/gif"; | 283 else if (strstr(file_path, ".gif")) mime = "image/gif"; |
| 241 else if (strstr(file_path, ".svg")) mime = "image/svg+xml"; | 284 else if (strstr(file_path, ".svg")) mime = "image/svg+xml"; |
| 242 else if (strstr(file_path, ".ico")) mime = "image/x-icon"; | 285 else if (strstr(file_path, ".ico")) mime = "image/x-icon"; |
| 286 else if (strstr(file_path, ".webp")) mime = "image/webp"; | |
| 243 else if (strstr(file_path, ".json")) mime = "application/json"; | 287 else if (strstr(file_path, ".json")) mime = "application/json"; |
| 244 else if (strstr(file_path, ".wasm")) mime = "application/wasm"; | 288 else if (strstr(file_path, ".wasm")) mime = "application/wasm"; |
| 289 else if (strstr(file_path, ".xml")) mime = "application/xml"; | |
| 290 else if (strstr(file_path, ".pdf")) mime = "application/pdf"; | |
| 291 else if (strstr(file_path, ".txt")) mime = "text/plain"; | |
| 245 else if (strstr(file_path, ".mp4")) mime = "video/mp4"; | 292 else if (strstr(file_path, ".mp4")) mime = "video/mp4"; |
| 246 else if (strstr(file_path, ".webm")) mime = "video/webm"; | 293 else if (strstr(file_path, ".webm")) mime = "video/webm"; |
| 294 else if (strstr(file_path, ".mp3")) mime = "audio/mpeg"; | |
| 295 else if (strstr(file_path, ".woff2")) mime = "font/woff2"; | |
| 296 else if (strstr(file_path, ".woff")) mime = "font/woff"; | |
| 297 else if (strstr(file_path, ".ttf")) mime = "font/ttf"; | |
| 298 else if (strstr(file_path, ".webp")) mime = "image/webp"; | |
| 247 else if (strstr(file_path, ".glb")) mime = "model/gltf-binary"; | 299 else if (strstr(file_path, ".glb")) mime = "model/gltf-binary"; |
| 248 else if (strstr(file_path, ".gltf")) mime = "model/gltf+json"; | 300 else if (strstr(file_path, ".gltf")) mime = "model/gltf+json"; |
| 249 | 301 |
| 250 Seobeo_Log(SEOBEO_DEBUG, "File path: %s\nBody Size: %zu\n", file_path, body_size); | 302 |
| 251 | 303 Seobeo_Web_Header_Generate_KeepAlive(p_response_header, |
| 252 Seobeo_Web_Header_Generate(p_response_header, | |
| 253 HTTP_OK, | 304 HTTP_OK, |
| 254 mime, | 305 mime, |
| 255 body_size); | 306 body_size, should_keep_alive); |
| 256 | 307 |
| 257 Seobeo_Handle_Queue(p_cli_handle, | 308 Seobeo_Handle_Queue(p_cli_handle, |
| 258 (const uint8*)p_response_header, | 309 (const uint8*)p_response_header, |
| 259 (uint32)strlen(p_response_header)); | 310 (uint32)strlen(p_response_header)); |
| 260 Seobeo_Handle_Queue(p_cli_handle, | 311 Seobeo_Handle_Queue(p_cli_handle, |
| 261 (const uint8*)file_content, | 312 (const uint8*)file_content, |
| 262 (uint32)body_size); | 313 (uint32)body_size); |
| 263 Seobeo_Handle_Flush(p_cli_handle); | 314 Seobeo_Handle_Flush(p_cli_handle); |
| 264 Seobeo_Log(SEOBEO_DEBUG, "Request handled successfully\n"); | |
| 265 } | 315 } |
| 266 else | 316 else |
| 267 { | 317 { |
| 268 Seobeo_Web_Header_Generate(p_response_header, | 318 Seobeo_Web_Header_Generate_KeepAlive(p_response_header, |
| 269 HTTP_FORBIDDEN, | 319 HTTP_NOT_FOUND, |
| 270 "text/plain", 0); | 320 "text/plain", 0, should_keep_alive); |
| 271 Seobeo_Handle_Queue(p_cli_handle, | 321 Seobeo_Handle_Queue(p_cli_handle, |
| 272 (const uint8*)p_response_header, | 322 (const uint8*)p_response_header, |
| 273 (uint32)strlen(p_response_header)); | 323 (uint32)strlen(p_response_header)); |
| 274 Seobeo_Handle_Flush(p_cli_handle); | 324 Seobeo_Handle_Flush(p_cli_handle); |
| 275 } | 325 } |
| 276 goto clean_up; | 326 |
| 277 | 327 clean_up_arenas: |
| 278 clean_up: | |
| 279 Seobeo_Log(SEOBEO_INFO, "Clean up all Arenas\n"); | |
| 280 if (p_cli_handle) | |
| 281 Seobeo_Handle_Destroy(p_cli_handle); | |
| 282 if (p_request_arena) | 328 if (p_request_arena) |
| 283 Dowa_Arena_Free(p_request_arena); | 329 Dowa_Arena_Free(p_request_arena); |
| 284 if (p_response_arena) | 330 if (p_response_arena) |
| 285 Dowa_Arena_Free(p_response_arena); | 331 Dowa_Arena_Free(p_response_arena); |
| 286 return; | 332 return should_keep_alive; |
| 287 } | 333 } |
| 288 | |
| 289 | 334 |
| 290 int Seobeo_Web_Header_Parse(Seobeo_Handle *p_handle, Seobeo_Request_Entry **pp_map, Dowa_Arena *p_arena) | 335 int Seobeo_Web_Header_Parse(Seobeo_Handle *p_handle, Seobeo_Request_Entry **pp_map, Dowa_Arena *p_arena) |
| 291 { | 336 { |
| 292 while (1) | 337 while (1) |
| 293 { | 338 { |
| 553 Seobeo_Stream_Handle_Server_Accept(p_server_handle); | 598 Seobeo_Stream_Handle_Server_Accept(p_server_handle); |
| 554 if (!p_cli_handle) continue; | 599 if (!p_cli_handle) continue; |
| 555 | 600 |
| 556 if (fork() == 0) | 601 if (fork() == 0) |
| 557 { | 602 { |
| 558 Seobeo_Web_HandleClientRequest(p_cli_handle, | 603 Seobeo_Web_ClientHandle_Request(p_cli_handle, p_html_cache, FALSE); |
| 559 p_html_cache); | |
| 560 _exit(0); | 604 _exit(0); |
| 561 } | 605 } |
| 562 } | 606 } |
| 563 } | 607 } |
| 564 | 608 |
| 725 void Seobeo_Router_Send_Response( | 769 void Seobeo_Router_Send_Response( |
| 726 Seobeo_Handle *p_handle, | 770 Seobeo_Handle *p_handle, |
| 727 Seobeo_Request_Entry *p_response_map, | 771 Seobeo_Request_Entry *p_response_map, |
| 728 Dowa_Arena *p_arena) | 772 Dowa_Arena *p_arena) |
| 729 { | 773 { |
| 774 Seobeo_Router_Send_Response_KeepAlive(p_handle, p_response_map, p_arena, FALSE); | |
| 775 } | |
| 776 | |
| 777 void Seobeo_Router_Send_Response_KeepAlive( | |
| 778 Seobeo_Handle *p_handle, | |
| 779 Seobeo_Request_Entry *p_response_map, | |
| 780 Dowa_Arena *p_arena, | |
| 781 boolean keep_alive) | |
| 782 { | |
| 730 if (p_response_map == NULL) | 783 if (p_response_map == NULL) |
| 731 { | 784 { |
| 732 char *header = Dowa_Arena_Allocate(p_arena, 1024); | 785 char *header = Dowa_Arena_Allocate(p_arena, 1024); |
| 733 Seobeo_Web_Header_Generate(header, HTTP_INTERNAL_ERROR, "text/plain", 21); | 786 Seobeo_Web_Header_Generate_KeepAlive(header, HTTP_INTERNAL_ERROR, "text/plain", 21, keep_alive); |
| 734 Seobeo_Handle_Queue(p_handle, (uint8_t*)header, strlen(header)); | 787 Seobeo_Handle_Queue(p_handle, (uint8_t*)header, strlen(header)); |
| 735 Seobeo_Handle_Queue(p_handle, (uint8_t*)"Internal Server Error", 21); | 788 Seobeo_Handle_Queue(p_handle, (uint8_t*)"Internal Server Error", 21); |
| 736 Seobeo_Handle_Flush(p_handle); | 789 Seobeo_Handle_Flush(p_handle); |
| 737 return; | 790 return; |
| 738 } | 791 } |
| 765 } | 818 } |
| 766 else | 819 else |
| 767 body_length = strlen(body); | 820 body_length = strlen(body); |
| 768 | 821 |
| 769 char *header = Dowa_Arena_Allocate(p_arena, 4096); | 822 char *header = Dowa_Arena_Allocate(p_arena, 4096); |
| 770 Seobeo_Web_Header_Generate(header, status, content_type, body_length); | 823 Seobeo_Web_Header_Generate_KeepAlive(header, status, content_type, body_length, keep_alive); |
| 771 for (int i = 0; i < Dowa_Array_Length(p_response_map); i++) | 824 for (int i = 0; i < Dowa_Array_Length(p_response_map); i++) |
| 772 { | 825 { |
| 773 if ( | 826 if ( |
| 774 strstr(p_response_map[i].key, "status") || | 827 strstr(p_response_map[i].key, "status") || |
| 775 strstr(p_response_map[i].key, "body") || | 828 strstr(p_response_map[i].key, "body") || |
| 776 strstr(p_response_map[i].key, "content-type") || | 829 strstr(p_response_map[i].key, "content-type") || |
| 777 strstr(p_response_map[i].key, "content-length") | 830 strstr(p_response_map[i].key, "content-length") |
| 778 ) | 831 ) |
| 779 continue; | 832 continue; |
| 780 | 833 |
| 781 int32 current_header_len = strlen(header); | 834 int32 current_header_len = strlen(header); |
| 782 char *temp = malloc(sizeof(char) * 1024); | 835 char *temp = malloc(sizeof(char) * 1024); |
| 786 } | 839 } |
| 787 | 840 |
| 788 printf("hEADER %s\n", header); | 841 printf("hEADER %s\n", header); |
| 789 | 842 |
| 790 Seobeo_Handle_Queue(p_handle, (uint8_t*)header, strlen(header)); | 843 Seobeo_Handle_Queue(p_handle, (uint8_t*)header, strlen(header)); |
| 791 Seobeo_Handle_Queue(p_handle, (uint8_t*)body, body_length); | 844 Seobeo_Handle_Queue(p_handle, (uint8_t*)body, body_length); |
| 792 Seobeo_Handle_Flush(p_handle); | 845 Seobeo_Handle_Flush(p_handle); |
| 793 } | 846 } |
| 794 | 847 |
| 795 void Seobeo_Router_Destroy() | 848 void Seobeo_Router_Destroy() |
| 796 { | 849 { |