@@ -69,8 +69,8 @@ pub const Bridge = struct {
6969 }
7070
7171 fn handleRequest (self : * Bridge , stream : std.net.Stream ) ! void {
72- // Read HTTP request (up to 4KB header )
73- var buf : [4096 ]u8 = undefined ;
72+ // Read HTTP request headers (up to 8KB )
73+ var buf : [8192 ]u8 = undefined ;
7474 const n = stream .read (& buf ) catch return ;
7575 if (n == 0 ) return ;
7676 const request = buf [0.. n ];
@@ -105,13 +105,48 @@ pub const Bridge = struct {
105105
106106 std .debug .print ("[px-bridge] {s} {s}\n " , .{if (is_get ) "GET" else "POST" , path });
107107
108- // Extract POST body if present
108+ // Extract POST body — read full body based on Content-Length
109109 var post_body : ? []const u8 = null ;
110+ var body_alloc : ? []u8 = null ;
111+ defer if (body_alloc ) | b | self .allocator .free (b );
112+
110113 if (is_post ) {
111- // Find end of headers
112114 if (std .mem .indexOf (u8 , request , "\r \n \r \n " )) | hdr_end | {
113115 const body_start = hdr_end + 4 ;
114- if (body_start < n ) {
116+ const headers = request [0.. hdr_end ];
117+
118+ // Parse Content-Length
119+ var content_length : usize = 0 ;
120+ var hdr_iter = std .mem .splitSequence (u8 , headers , "\r \n " );
121+ while (hdr_iter .next ()) | line | {
122+ if (std .ascii .startsWithIgnoreCase (line , "content-length:" )) {
123+ const val = std .mem .trim (u8 , line ["content-length:" .len .. ], & std .ascii .whitespace );
124+ content_length = std .fmt .parseInt (usize , val , 10 ) catch 0 ;
125+ break ;
126+ }
127+ }
128+
129+ if (content_length > max_body ) content_length = max_body ;
130+
131+ if (content_length > 0 ) {
132+ // Allocate buffer for full body
133+ body_alloc = self .allocator .alloc (u8 , content_length ) catch null ;
134+ if (body_alloc ) | full_body | {
135+ // Copy what we already have
136+ const already_read = @min (n - body_start , content_length );
137+ @memcpy (full_body [0.. already_read ], request [body_start .. body_start + already_read ]);
138+
139+ // Read remaining body from stream
140+ var total : usize = already_read ;
141+ while (total < content_length ) {
142+ const r = stream .read (full_body [total .. content_length ]) catch break ;
143+ if (r == 0 ) break ;
144+ total += r ;
145+ }
146+ post_body = full_body [0.. total ];
147+ }
148+ } else if (body_start < n ) {
149+ // No Content-Length, use what's in buffer
115150 post_body = request [body_start .. n ];
116151 }
117152 }
@@ -358,14 +393,7 @@ pub const Bridge = struct {
358393 }
359394
360395 fn handleDone (self : * Bridge , stream : std.net.Stream , id : []const u8 , result : []const u8 , exit_code : i32 ) ! void {
361- // URL-decode '+' as spaces in result
362- const decoded_result = try self .allocator .alloc (u8 , result .len );
363- defer self .allocator .free (decoded_result );
364- for (result , 0.. ) | c , i | {
365- decoded_result [i ] = if (c == '+' ) ' ' else c ;
366- }
367-
368- self .updateJob (id , "done" , decoded_result , exit_code ) catch {
396+ self .updateJob (id , "done" , result , exit_code ) catch {
369397 try writeResponse (stream , "404" , "{\" error\" :\" job not found\" }" );
370398 return ;
371399 };
0 commit comments