@@ -3,13 +3,21 @@ module fasthttp
33import net
44
55#include <sys/event.h>
6+ #include <sys/stat.h>
7+ #include <sys/types.h>
8+ #include <sys/socket.h>
9+ #include <sys/uio.h>
610
711const buf_size = max_connection_size
812const kqueue_max_events = 128
913const backlog = max_connection_size
1014
1115fn C.kevent (kq int , changelist & C.kevent, nchanges int , eventlist & C.kevent, nevents int , timeout & C.timespec) int
1216fn C.kqueue () int
17+ fn C.fstat (fd int , buf & C.stat) int
18+
19+ // int sendfile(int fd, int s, off_t offset, off_t *len, struct sf_hdtr *hdtr, int flags);
20+ fn C.sendfile (fd int , s int , offset i64 , len & i64 , hdtr voidptr , flags int ) int
1321
1422struct C.kevent {
1523 ident u64
3846 read_len int
3947 write_buf []u8
4048 write_pos int
49+
50+ // Sendfile state
51+ file_fd int = - 1
52+ file_len i64
53+ file_pos i64
4154}
4255
4356pub struct Server {
@@ -46,7 +59,7 @@ pub mut:
4659 socket_fd int
4760 poll_fd int // kqueue fd
4861 user_data voidptr
49- request_handler fn (HttpRequest) ! [] u8 @[required]
62+ request_handler fn (HttpRequest) ! HttpResponse @[required]
5063}
5164
5265// new_server creates and initializes a new Server instance.
@@ -87,27 +100,67 @@ fn close_conn(kq int, c_ptr voidptr) {
87100 if c.write_buf.len > 0 {
88101 c.write_buf.clear ()
89102 }
103+ if c.file_fd != - 1 {
104+ C.close (c.file_fd)
105+ c.file_fd = - 1
106+ }
90107 unsafe { free (c_ptr) }
91108}
92109
93110fn send_pending (c_ptr voidptr ) bool {
94111 mut c := unsafe { & Conn (c_ptr) }
95- if c.write_buf.len == 0 {
96- return false
97- }
98- remaining := c.write_buf.len - c.write_pos
99- if remaining < = 0 {
100- return false
112+
113+ // 1. Send memory buffer (headers or small response)
114+ if c.write_pos < c.write_buf.len {
115+ remaining := c.write_buf.len - c.write_pos
116+ write_ptr := unsafe { & c.write_buf[0 ] + c.write_pos }
117+ sent := C.send (c.fd, write_ptr, remaining, 0 )
118+ if sent > 0 {
119+ c.write_pos + = int (sent)
120+ }
121+ if sent < 0 {
122+ if C.errno == C.EAGAIN || C.errno == C.EWOULDBLOCK {
123+ return true
124+ }
125+ return false // Error
126+ }
101127 }
102- write_ptr := unsafe { & c.write_buf[0 ] + c.write_pos }
103- sent := C.send (c.fd, write_ptr, remaining, 0 )
104- if sent > 0 {
105- c.write_pos + = int (sent)
128+
129+ // 2. Send file if buffer is fully sent
130+ if c.write_pos > = c.write_buf.len && c.file_fd != - 1 {
131+ mut len := i64 (0 ) // Input 0 means send until EOF
132+ ret := C.sendfile (c.file_fd, c.fd, c.file_pos, & len, unsafe { nil }, 0 )
133+
134+ if len > 0 {
135+ c.file_pos + = len
136+ }
137+
138+ if ret == - 1 {
139+ if C.errno == C.EAGAIN || C.errno == C.EWOULDBLOCK {
140+ return true
141+ }
142+ // Error sending file
143+ C.close (c.file_fd)
144+ c.file_fd = - 1
145+ return false
146+ }
147+
148+ if c.file_pos > = c.file_len {
149+ // Done sending file
150+ C.close (c.file_fd)
151+ c.file_fd = - 1
152+ } else {
153+ // Not done yet
154+ return true
155+ }
106156 }
107- if sent < 0 && (C.errno == C.EAGAIN || C.errno == C.EWOULDBLOCK) {
108- return true
157+
158+ // Check if completely done (both buffer and file)
159+ if c.write_pos > = c.write_buf.len && c.file_fd == - 1 {
160+ return false // Done
109161 }
110- return c.write_pos < c.write_buf.len
162+
163+ return true // Still pending (partial buffer write or file not done)
111164}
112165
113166fn send_bad_request (fd int ) {
@@ -169,7 +222,21 @@ fn handle_read(mut s Server, kq int, c_ptr voidptr) {
169222 return
170223 }
171224
172- c.write_buf = resp.clone ()
225+ c.write_buf = resp.content.clone ()
226+ if resp.file_path != '' {
227+ fd := C.open (resp.file_path.str, C.O_RDONLY)
228+ if fd != - 1 {
229+ mut st := C.stat{}
230+ if C.fstat (fd, & st) == 0 {
231+ c.file_fd = fd
232+ c.file_len = st.st_size
233+ c.file_pos = 0
234+ } else {
235+ C.close (fd)
236+ }
237+ }
238+ }
239+
173240 c.write_pos = 0
174241 c.read_len = 0
175242
@@ -196,6 +263,7 @@ fn accept_clients(kq int, listen_fd int) {
196263 mut c := & Conn{
197264 fd: client_fd
198265 user_data: unsafe { nil }
266+ file_fd: - 1
199267 }
200268 add_event (kq, u64 (client_fd), i16 (C.EVFILT_READ), u16 (C.EV_ADD | C.EV_ENABLE | C.EV_CLEAR),
201269 c)
0 commit comments