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 {