windjammer_runtime/platform/native/
http.rs1use std::io::{Read, Write};
3use std::net::{TcpListener, TcpStream};
4
5pub type HttpResult<T> = Result<T, String>;
6
7pub use super::net::{get, post, Request, Response};
12
13pub fn put(url: String, body: String) -> HttpResult<Response> {
15 Request {
16 url,
17 method: "PUT".to_string(),
18 headers: Vec::new(),
19 body: Some(body),
20 timeout: None,
21 }
22 .send()
23}
24
25pub fn delete(url: String) -> HttpResult<Response> {
26 Request {
27 url,
28 method: "DELETE".to_string(),
29 headers: Vec::new(),
30 body: None,
31 timeout: None,
32 }
33 .send()
34}
35
36#[derive(Debug, Clone)]
42pub struct ServerRequest {
43 pub method: String,
44 pub path: String,
45 pub headers: Vec<(String, String)>,
46 pub body: String,
47}
48
49#[derive(Debug, Clone)]
51pub struct ServerResponse {
52 pub status: i32,
53 pub headers: Vec<(String, String)>,
54 pub body: String,
55 pub binary_body: Option<Vec<u8>>,
56}
57
58impl ServerResponse {
59 pub fn new(status: i32, body: String) -> Self {
60 Self {
61 status,
62 headers: Vec::new(),
63 body,
64 binary_body: None,
65 }
66 }
67
68 pub fn binary(status: i32, data: Vec<u8>) -> Self {
69 Self {
70 status,
71 headers: Vec::new(),
72 body: String::new(),
73 binary_body: Some(data),
74 }
75 }
76
77 pub fn html(body: String) -> Self {
78 Self {
79 status: 200,
80 headers: vec![("Content-Type".to_string(), "text/html".to_string())],
81 body,
82 binary_body: None,
83 }
84 }
85
86 pub fn json(body: String) -> Self {
87 Self {
88 status: 200,
89 headers: vec![("Content-Type".to_string(), "application/json".to_string())],
90 body,
91 binary_body: None,
92 }
93 }
94
95 pub fn error(status: i32, message: String) -> Self {
96 Self {
97 status,
98 headers: vec![("Content-Type".to_string(), "text/plain".to_string())],
99 body: message,
100 binary_body: None,
101 }
102 }
103
104 pub fn header(mut self, key: String, value: String) -> Self {
105 self.headers.push((key, value));
106 self
107 }
108}
109
110#[derive(Debug, Clone)]
112pub struct Server {
113 pub address: String,
114 pub port: i32,
115}
116
117impl Server {
118 pub fn new(address: String, port: i32) -> Self {
119 Self { address, port }
120 }
121
122 pub fn serve<F>(self, handler: F) -> HttpResult<()>
123 where
124 F: Fn(ServerRequest) -> ServerResponse + Send + Sync + 'static,
125 {
126 let addr = format!("{}:{}", self.address, self.port);
127 let listener =
128 TcpListener::bind(&addr).map_err(|e| format!("Failed to bind to {}: {}", addr, e))?;
129
130 println!("🚀 Server listening on http://{}", addr);
131
132 for stream in listener.incoming() {
133 match stream {
134 Ok(stream) => {
135 if let Err(e) = handle_connection(stream, &handler) {
136 eprintln!("❌ Error handling connection: {}", e);
137 }
138 }
139 Err(e) => {
140 eprintln!("❌ Error accepting connection: {}", e);
141 }
142 }
143 }
144
145 Ok(())
146 }
147}
148
149fn handle_connection<F>(mut stream: TcpStream, handler: &F) -> HttpResult<()>
150where
151 F: Fn(ServerRequest) -> ServerResponse,
152{
153 let mut buffer = [0; 4096];
154 let size = stream
155 .read(&mut buffer)
156 .map_err(|e| format!("Failed to read from stream: {}", e))?;
157
158 let request_str = String::from_utf8_lossy(&buffer[..size]);
159
160 let request = parse_request(&request_str)?;
162
163 println!("📄 {} {}", request.method, request.path);
164
165 let response = handler(request);
167
168 send_response(&mut stream, response)?;
170
171 Ok(())
172}
173
174fn parse_request(request_str: &str) -> HttpResult<ServerRequest> {
175 let mut lines = request_str.lines();
176
177 let first_line = lines.next().ok_or("Empty request")?;
179 let parts: Vec<&str> = first_line.split_whitespace().collect();
180
181 if parts.len() < 2 {
182 return Err("Invalid request line".to_string());
183 }
184
185 let method = parts[0].to_string();
186 let path = parts[1].to_string();
187
188 let mut headers = Vec::new();
190 for line in lines {
191 if line.is_empty() {
192 break;
193 }
194 if let Some((key, value)) = line.split_once(':') {
195 headers.push((key.trim().to_string(), value.trim().to_string()));
196 }
197 }
198
199 Ok(ServerRequest {
200 method,
201 path,
202 headers,
203 body: String::new(),
204 })
205}
206
207fn send_response(stream: &mut TcpStream, response: ServerResponse) -> HttpResult<()> {
208 let status_text = match response.status {
209 200 => "OK",
210 404 => "Not Found",
211 500 => "Internal Server Error",
212 _ => "Unknown",
213 };
214
215 let mut response_str = format!("HTTP/1.1 {} {}\r\n", response.status, status_text);
216
217 for (key, value) in &response.headers {
219 response_str.push_str(&format!("{}: {}\r\n", key, value));
220 }
221
222 if let Some(binary_data) = &response.binary_body {
224 response_str.push_str(&format!("Content-Length: {}\r\n", binary_data.len()));
226 response_str.push_str("Access-Control-Allow-Origin: *\r\n");
227 response_str.push_str("\r\n");
228
229 stream
231 .write_all(response_str.as_bytes())
232 .map_err(|e| format!("Failed to write response headers: {}", e))?;
233
234 stream
236 .write_all(binary_data)
237 .map_err(|e| format!("Failed to write binary body: {}", e))?;
238 } else {
239 response_str.push_str(&format!("Content-Length: {}\r\n", response.body.len()));
241 response_str.push_str("Access-Control-Allow-Origin: *\r\n");
242 response_str.push_str("\r\n");
243 response_str.push_str(&response.body);
244
245 stream
246 .write_all(response_str.as_bytes())
247 .map_err(|e| format!("Failed to write response: {}", e))?;
248 }
249
250 stream
251 .flush()
252 .map_err(|e| format!("Failed to flush stream: {}", e))?;
253
254 Ok(())
255}