1use std::io::{self, Read};
17use std::sync::{Arc, Mutex};
18use std::time::Duration;
19
20use go_lib::chan::{chan, Sender};
21use go_lib::net::{TcpListener, TcpStream};
22use rustls::ServerConnection;
23use url::Url;
24
25use crate::error::HttpError;
26use crate::handler::{default_serve_mux, Handler};
27use crate::parse::request::{read_request, DEFAULT_MAX_HEADER_BYTES};
28use crate::parse::transfer::Body;
29use crate::request::Request;
30use crate::response::{ConnResponseWriter, ResponseWriter};
31
32pub struct Server {
38 pub addr: String,
40 pub handler: Option<Arc<dyn Handler>>,
42 pub read_timeout: Option<Duration>,
43 pub write_timeout: Option<Duration>,
44 pub idle_timeout: Option<Duration>,
45 pub max_header_bytes: usize,
47 shutdown_tx: Mutex<Option<Sender<()>>>,
49}
50
51impl Server {
52 pub fn new(addr: impl Into<String>) -> Self {
53 Self {
54 addr: addr.into(),
55 handler: None,
56 read_timeout: None,
57 write_timeout: None,
58 idle_timeout: None,
59 max_header_bytes: DEFAULT_MAX_HEADER_BYTES,
60 shutdown_tx: Mutex::new(None),
61 }
62 }
63
64 pub fn listen_and_serve(&self) -> Result<(), HttpError> {
71 let listener = TcpListener::bind(&self.addr as &str).map_err(HttpError::Io)?;
72
73 let handler: Arc<dyn Handler> = match &self.handler {
74 Some(h) => Arc::clone(h),
75 None => default_serve_mux(),
76 };
77 let max_header_bytes = self.max_header_bytes;
78
79 let (shutdown_tx, shutdown_rx) = chan::<()>(1);
81 *self.shutdown_tx.lock().unwrap() = Some(shutdown_tx);
82
83 let (conn_tx, conn_rx) = chan::<TcpStream>(8);
85
86 go_lib::go!(move || {
92 loop {
93 match listener.accept() {
94 Err(_) => break,
95 Ok(stream) => {
96 let _ = std::panic::catch_unwind(
97 std::panic::AssertUnwindSafe(|| conn_tx.send(stream))
98 );
99 }
100 }
101 }
102 });
103
104 loop {
106 go_lib::select! {
107 recv(shutdown_rx) -> _sig => { break }
108 recv(conn_rx) -> conn => {
109 match conn {
110 None => break,
111 Some(stream) => {
112 let h = Arc::clone(&handler);
113 go_lib::go!(move || {
114 serve_conn(stream, h, max_header_bytes);
115 });
116 }
117 }
118 }
119 }
120 }
121
122 Ok(())
123 }
124
125 pub fn listen_and_serve_tls(
134 &self,
135 cert_file: &str,
136 key_file: &str,
137 ) -> Result<(), HttpError> {
138 let tls_config = crate::tls::server_config(cert_file, key_file)?;
139 let listener = TcpListener::bind(&self.addr as &str).map_err(HttpError::Io)?;
140
141 let handler: Arc<dyn Handler> = match &self.handler {
142 Some(h) => Arc::clone(h),
143 None => default_serve_mux(),
144 };
145 let max_header_bytes = self.max_header_bytes;
146
147 let (shutdown_tx, shutdown_rx) = chan::<()>(1);
148 *self.shutdown_tx.lock().unwrap() = Some(shutdown_tx);
149
150 let (conn_tx, conn_rx) = chan::<TcpStream>(8);
151
152 go_lib::go!(move || {
153 loop {
154 match listener.accept() {
155 Err(_) => break,
156 Ok(stream) => {
157 let _ = std::panic::catch_unwind(
158 std::panic::AssertUnwindSafe(|| conn_tx.send(stream))
159 );
160 }
161 }
162 }
163 });
164
165 loop {
166 go_lib::select! {
167 recv(shutdown_rx) -> _sig => { break }
168 recv(conn_rx) -> conn => {
169 match conn {
170 None => break,
171 Some(stream) => {
172 let h = Arc::clone(&handler);
173 let cfg = Arc::clone(&tls_config);
174 go_lib::go!(move || {
175 serve_conn_tls(stream, cfg, h, max_header_bytes);
176 });
177 }
178 }
179 }
180 }
181 }
182
183 Ok(())
184 }
185
186 pub fn shutdown(&self) {
189 if let Some(tx) = self.shutdown_tx.lock().unwrap().take() {
190 let _ = std::panic::catch_unwind(
191 std::panic::AssertUnwindSafe(|| tx.send(()))
192 );
193 }
194 }
195}
196
197fn serve_conn(
209 stream: TcpStream,
210 handler: Arc<dyn Handler>,
211 max_header_bytes: usize,
212) {
213 let remote_addr = stream.peer_addr()
214 .map(|a| a.to_string())
215 .unwrap_or_default();
216
217 let mut write_half = match stream.try_clone() {
219 Ok(s) => s,
220 Err(_) => return,
221 };
222
223 loop {
224 let read_half = match stream.try_clone() {
231 Ok(s) => s,
232 Err(_) => break,
233 };
234
235 let parsed = match read_request(read_half, max_header_bytes) {
236 Ok(p) => p,
237 Err(_) => break,
238 };
239
240 let connection_close = {
241 let hdr = parsed.header.get("Connection").unwrap_or("").to_ascii_lowercase();
242 hdr.contains("close") || parsed.proto_minor == 0
243 };
244
245 let req = match build_request(parsed, remote_addr.clone()) {
247 Ok(r) => r,
248 Err(_) => break,
249 };
250
251 let mut w = ConnResponseWriter::new(&mut write_half);
253 w.header().set("Server", "go-http/0.1");
254 if connection_close {
255 w.header().set("Connection", "close");
256 }
257
258 handler.serve_http(&mut w, &req);
259
260 if w.finish().is_err() {
261 break;
262 }
263
264 if connection_close {
265 break;
266 }
267 }
268}
269
270struct RawTlsRead(*mut dyn Read);
285unsafe impl Send for RawTlsRead {}
286impl Read for RawTlsRead {
287 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
288 unsafe { (*self.0).read(buf) }
289 }
290}
291
292fn serve_conn_tls(
300 stream: TcpStream,
301 tls_config: Arc<rustls::ServerConfig>,
302 handler: Arc<dyn Handler>,
303 max_header_bytes: usize,
304) {
305 let remote_addr = stream.peer_addr()
306 .map(|a| a.to_string())
307 .unwrap_or_default();
308
309 let server_conn = match ServerConnection::new(tls_config) {
310 Ok(c) => c,
311 Err(_) => return,
312 };
313 let mut tls = rustls::StreamOwned::new(server_conn, stream);
314
315 loop {
316 let read_ptr: *mut dyn Read = &mut tls as &mut dyn Read as *mut dyn Read;
319 let parsed = match read_request(RawTlsRead(read_ptr), max_header_bytes) {
320 Ok(p) => p,
321 Err(_) => break,
322 };
323
324 let connection_close = {
325 let hdr = parsed.header.get("Connection").unwrap_or("").to_ascii_lowercase();
326 hdr.contains("close") || parsed.proto_minor == 0
327 };
328
329 let req = match build_request_scheme(parsed, remote_addr.clone(), "https") {
332 Ok(r) => r,
333 Err(_) => break,
334 };
335
336 let mut w = ConnResponseWriter::new(&mut tls);
339 w.header().set("Server", "go-http/0.1");
340 if connection_close {
341 w.header().set("Connection", "close");
342 }
343
344 handler.serve_http(&mut w, &req);
345
346 if w.finish().is_err() {
347 break;
348 }
349
350 if connection_close {
351 break;
352 }
353 }
354}
355
356fn build_request(
361 parsed: crate::parse::request::ParsedRequest,
362 remote_addr: String,
363) -> Result<Request, HttpError> {
364 build_request_scheme(parsed, remote_addr, "http")
365}
366
367fn build_request_scheme(
368 parsed: crate::parse::request::ParsedRequest,
369 remote_addr: String,
370 scheme: &str,
371) -> Result<Request, HttpError> {
372 let host = if parsed.host.is_empty() { "localhost".to_owned() } else { parsed.host.clone() };
373
374 let url_str = if parsed.request_uri.starts_with("http://")
375 || parsed.request_uri.starts_with("https://")
376 {
377 parsed.request_uri.clone()
378 } else {
379 format!("{scheme}://{host}{}", parsed.request_uri)
380 };
381
382 let url = Url::parse(&url_str).map_err(|e| HttpError::InvalidUrl(e.to_string()))?;
383 let ctx = go_lib::context::background();
384 let body = match parsed.body {
385 Body::Empty => None,
386 other => Some(other),
387 };
388
389 let mut req = Request::new_with_context(&parsed.method, url.as_str(), body, ctx)?;
390 req.proto = parsed.proto;
391 req.proto_major = parsed.proto_major;
392 req.proto_minor = parsed.proto_minor;
393 req.header = parsed.header;
394 req.host = parsed.host;
395 req.content_length = parsed.content_length;
396 req.transfer_encoding = parsed.transfer_encoding;
397 req.remote_addr = remote_addr;
398 Ok(req)
399}
400
401pub fn listen_and_serve(
410 addr: &str,
411 handler: Option<Arc<dyn Handler>>,
412) -> Result<(), HttpError> {
413 let mut srv = Server::new(addr);
414 srv.handler = handler;
415 srv.listen_and_serve()
416}
417
418pub fn listen_and_serve_tls(
423 addr: &str,
424 cert_file: &str,
425 key_file: &str,
426 handler: Option<Arc<dyn Handler>>,
427) -> Result<(), HttpError> {
428 let mut srv = Server::new(addr);
429 srv.handler = handler;
430 srv.listen_and_serve_tls(cert_file, key_file)
431}
432
433pub use crate::handler::handle;
434pub use crate::handler::handle_func;
435
436#[cfg(test)]
441mod tests {
442 use super::*;
443
444 #[test]
445 fn build_request_basic() {
446 use crate::parse::request::ParsedRequest;
447 use crate::parse::transfer::Body;
448
449 let mut hdr = crate::header::Header::new();
450 hdr.set("Host", "example.com");
451
452 let pr = ParsedRequest {
453 method: "GET".into(),
454 request_uri: "/hello?q=1".into(),
455 proto: "HTTP/1.1".into(),
456 proto_major: 1,
457 proto_minor: 1,
458 header: hdr,
459 body: Body::Empty,
460 content_length: -1,
461 transfer_encoding: vec![],
462 host: "example.com".into(),
463 };
464
465 let req = build_request(pr, "10.0.0.1:42".into()).unwrap();
466 assert_eq!(req.method, "GET");
467 assert_eq!(req.host, "example.com");
468 assert_eq!(req.url.path(), "/hello");
469 assert_eq!(req.url.query(), Some("q=1"));
470 assert_eq!(req.remote_addr, "10.0.0.1:42");
471 }
472
473 #[test]
474 fn response_writer_output() {
475 let mut buf = Vec::<u8>::new();
476 let mut w = ConnResponseWriter::new(&mut buf);
477 w.header().set("Content-Type", "text/plain");
478 w.write_header(200);
479 w.write(b"Hello!").unwrap();
480 w.finish().unwrap();
481
482 let s = String::from_utf8(buf).unwrap();
483 assert!(s.starts_with("HTTP/1.1 200 OK\r\n"), "bad status: {s:?}");
484 assert!(s.contains("Content-Type: text/plain\r\n"));
485 assert!(s.contains("Hello!"));
486 assert!(s.contains("0\r\n\r\n"), "missing chunked terminal: {s:?}");
487 }
488
489}