@@ -31,6 +31,12 @@ pub const Server = struct {
3131 const MAX_BODY_SIZE = 100 * 1024 * 1024 ; // Increase limit but enforce streaming
3232 const NUM_WORKERS = 4 ;
3333
34+ const ReadState = enum {
35+ reading_headers ,
36+ reading_body ,
37+ ready_to_process ,
38+ };
39+
3440 const ConnectionState = struct {
3541 fd : i32 ,
3642 stream : net.Stream ,
@@ -39,6 +45,9 @@ pub const Server = struct {
3945 write_buffer : std .ArrayList (u8 ),
4046 keep_alive : bool ,
4147 allocator : mem.Allocator ,
48+ read_state : ReadState ,
49+ headers_end_pos : ? usize ,
50+ expected_body_length : ? usize ,
4251
4352 fn init (allocator : mem.Allocator , fd : i32 , stream : net.Stream , address : net.Address ) ! * ConnectionState {
4453 const state = try allocator .create (ConnectionState );
@@ -50,6 +59,9 @@ pub const Server = struct {
5059 .write_buffer = .{},
5160 .keep_alive = true ,
5261 .allocator = allocator ,
62+ .read_state = .reading_headers ,
63+ .headers_end_pos = null ,
64+ .expected_body_length = null ,
5365 };
5466 return state ;
5567 }
@@ -60,6 +72,14 @@ pub const Server = struct {
6072 self .stream .close ();
6173 allocator .destroy (self );
6274 }
75+
76+ fn reset (self : * ConnectionState ) void {
77+ self .read_buffer .clearRetainingCapacity ();
78+ self .write_buffer .clearRetainingCapacity ();
79+ self .read_state = .reading_headers ;
80+ self .headers_end_pos = null ;
81+ self .expected_body_length = null ;
82+ }
6383 };
6484
6585 pub fn listen (self : * Server ) ! void {
@@ -262,11 +282,78 @@ pub const Server = struct {
262282
263283 try connection .read_buffer .appendSlice (connection .allocator , buffer [0.. bytes_read ]);
264284
265- if (mem .indexOf (u8 , connection .read_buffer .items , "\r \n \r \n " )) | _ | {
266- try processRequest (ctx , fd );
267- break ;
285+ // State machine for reading headers then body
286+ switch (connection .read_state ) {
287+ .reading_headers = > {
288+ // Look for end of headers
289+ if (mem .indexOf (u8 , connection .read_buffer .items , "\r \n \r \n " )) | headers_end | {
290+ connection .headers_end_pos = headers_end + 4 ;
291+
292+ // Parse headers to check for Content-Length
293+ const headers_section = connection .read_buffer .items [0.. headers_end ];
294+ connection .expected_body_length = parseContentLength (headers_section );
295+
296+ if (connection .expected_body_length ) | body_len | {
297+ if (body_len > MAX_BODY_SIZE ) {
298+ std .log .err ("Request body too large: {d} bytes (max: {d})" , .{ body_len , MAX_BODY_SIZE });
299+ closeConnection (ctx , fd );
300+ return ;
301+ }
302+
303+ // Transition to reading body
304+ connection .read_state = .reading_body ;
305+
306+ // Check if we already have the full body
307+ const current_body_len = connection .read_buffer .items .len - connection .headers_end_pos .? ;
308+ if (current_body_len >= body_len ) {
309+ connection .read_state = .ready_to_process ;
310+ try processRequest (ctx , fd );
311+ break ;
312+ }
313+ } else {
314+ // No body expected, ready to process
315+ connection .read_state = .ready_to_process ;
316+ try processRequest (ctx , fd );
317+ break ;
318+ }
319+ }
320+
321+ // Check if headers are getting too large
322+ if (connection .read_buffer .items .len > MAX_HEADERS_SIZE ) {
323+ std .log .err ("Request headers too large" , .{});
324+ closeConnection (ctx , fd );
325+ return ;
326+ }
327+ },
328+ .reading_body = > {
329+ const headers_end = connection .headers_end_pos .? ;
330+ const expected_len = connection .expected_body_length .? ;
331+ const current_body_len = connection .read_buffer .items .len - headers_end ;
332+
333+ if (current_body_len >= expected_len ) {
334+ connection .read_state = .ready_to_process ;
335+ try processRequest (ctx , fd );
336+ break ;
337+ }
338+ },
339+ .ready_to_process = > {
340+ // Already processing, shouldn't get more reads
341+ break ;
342+ },
343+ }
344+ }
345+ }
346+
347+ fn parseContentLength (headers : []const u8 ) ? usize {
348+ var lines = mem .splitSequence (u8 , headers , "\r \n " );
349+ while (lines .next ()) | line | {
350+ if (std .ascii .startsWithIgnoreCase (line , "content-length:" )) {
351+ const value_start = mem .indexOfScalar (u8 , line , ':' ) orelse continue ;
352+ const value = mem .trim (u8 , line [value_start + 1 .. ], " \t " );
353+ return std .fmt .parseInt (usize , value , 10 ) catch null ;
268354 }
269355 }
356+ return null ;
270357 }
271358
272359 fn processRequest (ctx : WorkerContext , fd : i32 ) ! void {
@@ -325,10 +412,9 @@ pub const Server = struct {
325412 return ;
326413 };
327414
328- var raw_reader_storage : ? @TypeOf (raw_request .readerExpectNone (tmp_buf )) = null ;
329415 if (method == .POST or method == .PUT or method == .PATCH ) {
330- raw_reader_storage = raw_request .readerExpectNone (tmp_buf );
331- body_reader = http_types .BodyReader .initFromReader ( raw_reader_storage .? . any () , MAX_BODY_SIZE );
416+ const raw_reader_ptr = raw_request .readerExpectNone (tmp_buf );
417+ body_reader = http_types .BodyReader .init ( raw_reader_ptr , MAX_BODY_SIZE );
332418 } else {
333419 _ = raw_request .readerExpectNone (tmp_buf );
334420 }
@@ -457,7 +543,8 @@ pub const Server = struct {
457543
458544 if (connection .write_buffer .items .len == 0 ) {
459545 if (connection .keep_alive ) {
460- connection .read_buffer .clearRetainingCapacity ();
546+ // Reset connection state for next request
547+ connection .reset ();
461548
462549 var event = std.os.linux.epoll_event {
463550 .events = std .os .linux .EPOLL .IN | std .os .linux .EPOLL .ET ,
@@ -494,7 +581,7 @@ pub const Server = struct {
494581
495582 var in_reader = conn .stream .reader (& read_buffer );
496583 var out_writer = conn .stream .writer (& write_buffer );
497- var server = http .Server .init (in_reader . any (), & out_writer . any ( ));
584+ var server = http .Server .init (@as ( * std . io . Reader , @ptrCast ( & in_reader )), @as ( * std . io . Writer , @ptrCast ( & out_writer ) ));
498585
499586 var raw_request = server .receiveHead () catch | err | {
500587 std .log .err ("Failed to parse request: {any}" , .{err });
@@ -535,10 +622,9 @@ pub const Server = struct {
535622 return ;
536623 };
537624
538- var raw_reader_storage : ? @TypeOf (raw_request .readerExpectNone (tmp_buf )) = null ;
539625 if (method == .POST or method == .PUT or method == .PATCH ) {
540- raw_reader_storage = raw_request .readerExpectNone (tmp_buf );
541- body_reader = http_types .BodyReader .initFromReader ( raw_reader_storage .? . any () , MAX_BODY_SIZE );
626+ const raw_reader_ptr = raw_request .readerExpectNone (tmp_buf );
627+ body_reader = http_types .BodyReader .init ( raw_reader_ptr , MAX_BODY_SIZE );
542628 } else {
543629 _ = raw_request .readerExpectNone (tmp_buf );
544630 }
0 commit comments