use std::cell::RefCell;
use std::future::{poll_fn, Future};
use std::io;
use std::mem;
use std::net::Shutdown;
use std::ops::Deref;
use std::pin::pin;
use std::rc::Rc;
use std::task::Poll;
use std::time::{Duration, Instant};
use giong::net::{TcpListener, TcpStream, UnixListener, UnixStream};
use giong::time::{sleep, timeout};
use crate::chunked::{Decoder, Progress};
use crate::parse::{find_head_end, parse_head};
use crate::request::{BodyBytes, Request};
use crate::response::Response;
const FLUSH_AT: usize = 64 * 1024;
const ERROR_LINGER: Duration = Duration::from_secs(1);
thread_local! {
static BUFFERS: RefCell<Vec<Vec<u8>>> = const { RefCell::new(Vec::new()) };
}
fn take_buffer() -> Vec<u8> {
BUFFERS
.with(|pool| pool.borrow_mut().pop())
.unwrap_or_else(|| Vec::with_capacity(4 * 1024))
}
fn give_buffer(mut buf: Vec<u8>) {
buf.clear();
if buf.capacity() == 0 || buf.capacity() > 256 * 1024 {
return;
}
BUFFERS.with(|pool| {
let mut pool = pool.borrow_mut();
if pool.len() < 1024 {
pool.push(buf);
}
});
}
pub trait Transport: 'static {
type Chunk: Deref<Target = [u8]>;
fn recv(&self) -> impl Future<Output = io::Result<Self::Chunk>>;
fn write_all(&self, buf: Vec<u8>) -> impl Future<Output = (io::Result<()>, Vec<u8>)>;
fn close_write(&self) -> impl Future<Output = ()>;
}
impl Transport for TcpStream {
type Chunk = giong::RecvBuf;
fn recv(&self) -> impl Future<Output = io::Result<Self::Chunk>> {
TcpStream::recv(self)
}
fn write_all(&self, buf: Vec<u8>) -> impl Future<Output = (io::Result<()>, Vec<u8>)> {
TcpStream::write_all(self, buf)
}
async fn close_write(&self) {
let _ = self.shutdown(Shutdown::Write);
}
}
impl Transport for UnixStream {
type Chunk = giong::RecvBuf;
fn recv(&self) -> impl Future<Output = io::Result<Self::Chunk>> {
UnixStream::recv(self)
}
fn write_all(&self, buf: Vec<u8>) -> impl Future<Output = (io::Result<()>, Vec<u8>)> {
UnixStream::write_all(self, buf)
}
async fn close_write(&self) {
let _ = self.shutdown(Shutdown::Write);
}
}
#[cfg(feature = "tls")]
impl Transport for giong_tls::TlsStream {
type Chunk = Vec<u8>;
fn recv(&self) -> impl Future<Output = io::Result<Self::Chunk>> {
giong_tls::TlsStream::recv(self)
}
fn write_all(&self, buf: Vec<u8>) -> impl Future<Output = (io::Result<()>, Vec<u8>)> {
giong_tls::TlsStream::write_all(self, buf)
}
async fn close_write(&self) {
let _ = self.shutdown().await;
}
}
#[derive(Clone, Copy, Debug)]
struct Config {
idle_timeout: Duration,
request_timeout: Duration,
write_timeout: Duration,
max_head_size: usize,
max_body_size: usize,
shutdown_linger: Duration,
}
#[derive(Clone, Debug)]
pub struct Server {
cfg: Config,
}
impl Default for Server {
fn default() -> Self {
Self::new()
}
}
impl Server {
pub fn new() -> Self {
Self {
cfg: Config {
idle_timeout: Duration::from_secs(60),
request_timeout: Duration::from_secs(30),
write_timeout: Duration::from_secs(30),
max_head_size: 64 * 1024,
max_body_size: 1024 * 1024,
shutdown_linger: Duration::from_millis(100),
},
}
}
pub fn idle_timeout(mut self, timeout: Duration) -> Self {
self.cfg.idle_timeout = timeout;
self
}
pub fn request_timeout(mut self, timeout: Duration) -> Self {
self.cfg.request_timeout = timeout;
self
}
pub fn write_timeout(mut self, timeout: Duration) -> Self {
self.cfg.write_timeout = timeout;
self
}
pub fn max_head_size(mut self, bytes: usize) -> Self {
self.cfg.max_head_size = bytes.max(64);
self
}
pub fn max_body_size(mut self, bytes: usize) -> Self {
self.cfg.max_body_size = bytes;
self
}
pub fn shutdown_linger(mut self, linger: Duration) -> Self {
self.cfg.shutdown_linger = linger;
self
}
pub async fn serve<H, Fut>(&self, listener: TcpListener, handler: H)
where
H: Fn(Request) -> Fut + 'static,
Fut: Future<Output = Response> + 'static,
{
let handler = Rc::new(handler);
let cfg = self.cfg;
let accept = || listener.accept();
self.accept_loop(accept, |stream: TcpStream| {
let _ = stream.set_nodelay(true);
drop(giong::spawn(Conn::new(stream, cfg).run(handler.clone())));
})
.await;
}
pub async fn serve_unix<H, Fut>(&self, listener: UnixListener, handler: H)
where
H: Fn(Request) -> Fut + 'static,
Fut: Future<Output = Response> + 'static,
{
let handler = Rc::new(handler);
let cfg = self.cfg;
let accept = || listener.accept();
self.accept_loop(accept, |stream: UnixStream| {
drop(giong::spawn(Conn::new(stream, cfg).run(handler.clone())));
})
.await;
}
#[cfg(feature = "tls")]
pub async fn serve_tls<H, Fut>(
&self,
listener: TcpListener,
acceptor: giong_tls::TlsAcceptor,
handler: H,
) where
H: Fn(Request) -> Fut + 'static,
Fut: Future<Output = Response> + 'static,
{
let handler = Rc::new(handler);
let cfg = self.cfg;
let accept = || listener.accept();
self.accept_loop(accept, |stream: TcpStream| {
let _ = stream.set_nodelay(true);
let (acceptor, handler) = (acceptor.clone(), handler.clone());
drop(giong::spawn(async move {
if let Ok(tls) = acceptor.accept(stream).await {
Conn::new(tls, cfg).run(handler).await;
}
}));
})
.await;
}
async fn accept_loop<S, A>(&self, accept: impl Fn() -> A, spawn: impl Fn(S))
where
A: Future<Output = io::Result<S>>,
{
while let Some(accepted) = giong::until_shutdown(accept()).await {
match accepted {
Ok(stream) => spawn(stream),
Err(_) => sleep(Duration::from_millis(50)).await,
}
}
let deadline = Instant::now() + self.cfg.shutdown_linger;
loop {
let left = deadline.saturating_duration_since(Instant::now());
match timeout(left, accept()).await {
Ok(Ok(stream)) => spawn(stream),
_ => break,
}
}
}
pub async fn serve_connection<T, H, Fut>(&self, stream: T, handler: Rc<H>)
where
T: Transport,
H: Fn(Request) -> Fut + 'static,
Fut: Future<Output = Response> + 'static,
{
Conn::new(stream, self.cfg).run(handler).await;
}
}
enum End {
Close,
Status(u16),
}
struct Conn<T> {
stream: T,
cfg: Config,
buf: Rc<Vec<u8>>,
pos: usize,
scanned: usize,
out: Vec<u8>,
closing: bool,
deadline: Option<Instant>,
}
impl<T: Transport> Conn<T> {
fn new(stream: T, cfg: Config) -> Self {
Self {
stream,
cfg,
buf: Rc::new(Vec::new()),
pos: 0,
scanned: 0,
out: Vec::new(),
closing: false,
deadline: None,
}
}
async fn run<H, Fut>(mut self, handler: Rc<H>)
where
H: Fn(Request) -> Fut + 'static,
Fut: Future<Output = Response> + 'static,
{
loop {
let req = match self.next_request().await {
Ok(req) => req,
Err(End::Close) => break,
Err(End::Status(status)) => {
self.reserve_out();
Response::new(status).write_to(&mut self.out, 1, false, false);
if self.flush().await.is_ok() {
self.lingering_close().await;
}
return;
}
};
let minor = req.head.minor;
let head_only = req.method() == "HEAD";
let wants_keep_alive = !req.head.close && (minor == 1 || req.head.keep_alive);
let mut fut = pin!(handler(req));
let first = poll_fn(|cx| Poll::Ready(fut.as_mut().poll(cx))).await;
let resp = match first {
Poll::Ready(resp) => resp,
Poll::Pending => {
if self.flush().await.is_err() {
return;
}
fut.await
}
};
self.closing |= giong::is_shutting_down();
let keep_alive = wants_keep_alive && !self.closing;
self.reserve_out();
resp.write_to(&mut self.out, minor, keep_alive, head_only);
if !keep_alive {
break;
}
if self.out.len() >= FLUSH_AT && self.flush().await.is_err() {
return;
}
}
if self.flush().await.is_ok() {
self.close_write().await;
}
}
async fn next_request(&mut self) -> Result<Request, End> {
let head = loop {
while self.buf[self.pos..].starts_with(b"\r\n") {
self.pos += 2;
self.scanned = 0;
}
let data = &self.buf[self.pos..];
if let Some(end) = find_head_end(data, self.scanned) {
if end > self.cfg.max_head_size {
return Err(End::Status(431));
}
break parse_head(&data[..end]).map_err(End::Status)?;
}
if data.len() > self.cfg.max_head_size {
return Err(End::Status(431));
}
self.scanned = data.len().saturating_sub(3);
let idle = data.is_empty();
self.read_more(idle).await?;
};
let mut interim_sent = false;
let (body, total) = if head.chunked {
let mut decoder = Decoder::new(self.cfg.max_body_size);
loop {
let data = &self.buf[self.pos + head.len..];
match decoder.feed(data).map_err(End::Status)? {
Progress::Done(used) => {
break (
BodyBytes::Decoded(mem::take(&mut decoder.body)),
head.len + used,
)
}
Progress::NeedMore => {
self.send_continue(&head, &mut interim_sent);
self.read_more(false).await?;
}
}
}
} else {
let len = head.content_length.unwrap_or(0);
if len > self.cfg.max_body_size as u64 {
return Err(End::Status(413));
}
let len = len as usize;
while self.buf.len() - self.pos - head.len < len {
self.send_continue(&head, &mut interim_sent);
self.read_more(false).await?;
}
let start = self.pos + head.len;
(BodyBytes::InBuffer(start..start + len), head.len + len)
};
let req = Request {
buf: self.buf.clone(),
start: self.pos,
head,
body,
};
self.pos += total;
self.scanned = 0;
self.deadline = None;
Ok(req)
}
fn send_continue(&mut self, head: &crate::parse::Head, sent: &mut bool) {
if head.expect_continue && head.minor == 1 && !*sent {
*sent = true;
self.reserve_out();
self.out.extend_from_slice(b"HTTP/1.1 100 Continue\r\n\r\n");
}
}
async fn read_more(&mut self, idle: bool) -> Result<(), End> {
self.flush().await?;
let received = if idle {
if self.closing {
return Err(End::Close);
}
self.release_buffers();
let recv = timeout(self.cfg.idle_timeout, self.stream.recv());
match giong::until_shutdown(recv).await {
Some(received) => received,
None => {
self.closing = true;
timeout(self.cfg.shutdown_linger, self.stream.recv()).await
}
}
} else {
let request_timeout = self.cfg.request_timeout;
let deadline = *self
.deadline
.get_or_insert_with(|| Instant::now() + request_timeout);
let left = deadline.saturating_duration_since(Instant::now());
match timeout(left, self.stream.recv()).await {
Ok(received) => Ok(received),
Err(_) => return Err(End::Status(408)),
}
};
match received {
Ok(Ok(chunk)) if !chunk.is_empty() => {
self.append(&chunk);
Ok(())
}
_ => Err(End::Close),
}
}
fn append(&mut self, chunk: &[u8]) {
match Rc::get_mut(&mut self.buf) {
Some(buf) => {
if self.pos > 0 {
buf.drain(..self.pos);
self.pos = 0;
}
if buf.capacity() == 0 {
*buf = take_buffer();
}
buf.extend_from_slice(chunk);
}
None => {
let mut fresh = take_buffer();
fresh.extend_from_slice(&self.buf[self.pos..]);
fresh.extend_from_slice(chunk);
self.buf = Rc::new(fresh);
self.pos = 0;
}
}
}
fn reserve_out(&mut self) {
if self.out.capacity() == 0 {
self.out = take_buffer();
}
}
fn release_buffers(&mut self) {
if self.pos == self.buf.len() {
match Rc::get_mut(&mut self.buf) {
Some(buf) => give_buffer(mem::take(buf)),
None => self.buf = Rc::new(Vec::new()),
}
self.pos = 0;
}
give_buffer(mem::take(&mut self.out));
}
async fn flush(&mut self) -> Result<(), End> {
if self.out.is_empty() {
return Ok(());
}
let out = mem::take(&mut self.out);
match timeout(self.cfg.write_timeout, self.stream.write_all(out)).await {
Ok((Ok(()), mut out)) => {
out.clear();
self.out = out;
Ok(())
}
_ => Err(End::Close),
}
}
async fn close_write(&mut self) {
let _ = timeout(self.cfg.write_timeout, self.stream.close_write()).await;
}
async fn lingering_close(&mut self) {
self.close_write().await;
let deadline = Instant::now() + ERROR_LINGER;
loop {
let left = deadline.saturating_duration_since(Instant::now());
match timeout(left, self.stream.recv()).await {
Ok(Ok(chunk)) if !chunk.is_empty() => {}
_ => return,
}
}
}
}