diff --git a/crates/shadowsocks-service/src/local/http/server.rs b/crates/shadowsocks-service/src/local/http/server.rs index eee5a7d65476..c3919b04e9b3 100644 --- a/crates/shadowsocks-service/src/local/http/server.rs +++ b/crates/shadowsocks-service/src/local/http/server.rs @@ -119,7 +119,12 @@ impl Http { }; trace!("HTTP accepted client from {}", peer_addr); - tokio::spawn(handler.clone().serve_connection(stream, peer_addr)); + let handler = handler.clone(); + tokio::spawn(async move { + if let Err(err) = handler.serve_connection(stream, peer_addr).await { + error!("HTTP connection {} handler failed with error: {}", peer_addr, err); + } + }); } } } @@ -145,7 +150,7 @@ impl HttpConnectionHandler { } /// Handle a TCP HTTP connection - pub async fn serve_connection(self, stream: S, peer_addr: SocketAddr) + pub async fn serve_connection(self, stream: S, peer_addr: SocketAddr) -> hyper::Result<()> where S: AsyncRead + AsyncWrite + Unpin + Send + 'static, { @@ -159,7 +164,7 @@ impl HttpConnectionHandler { // NOTE: Some stupid clients requires HTTP header keys to be case-sensitive. // For example: Nintendo Switch - if let Err(err) = http1::Builder::new() + http1::Builder::new() .keep_alive(true) .title_case_headers(true) .preserve_header_case(true) @@ -172,8 +177,5 @@ impl HttpConnectionHandler { ) .with_upgrades() .await - { - error!("failed to serve HTTP connection, error: {}", err); - } } } diff --git a/crates/shadowsocks-service/src/local/socks/server/server.rs b/crates/shadowsocks-service/src/local/socks/server/server.rs index 70614fa8895f..2afd6e327528 100644 --- a/crates/shadowsocks-service/src/local/socks/server/server.rs +++ b/crates/shadowsocks-service/src/local/socks/server/server.rs @@ -4,10 +4,10 @@ use log::{error, info}; use shadowsocks::{config::Mode, net::TcpListener as ShadowTcpListener, ServerAddr}; use tokio::{net::TcpStream, time}; +#[cfg(feature = "local-http")] +use crate::local::http::HttpConnectionHandler; use crate::local::{ - context::ServiceContext, - loadbalancing::PingBalancer, - net::tcp::listener::create_standard_tcp_listener, + context::ServiceContext, loadbalancing::PingBalancer, net::tcp::listener::create_standard_tcp_listener, socks::config::Socks5AuthConfig, }; @@ -104,6 +104,8 @@ impl SocksTcpServer { // If UDP is enabled, SOCK5 UDP_ASSOCIATE command will let client to send requests to this address let udp_bind_addr = Arc::new(self.udp_bind_addr); + #[cfg(feature = "local-http")] + let http_handler = HttpConnectionHandler::new(self.context.clone(), self.balancer.clone()); loop { let (stream, peer_addr) = match self.listener.accept().await { @@ -115,57 +117,90 @@ impl SocksTcpServer { } }; - let balancer = self.balancer.clone(); - let context = self.context.clone(); - let udp_bind_addr = udp_bind_addr.clone(); - let socks5_auth = self.socks5_auth.clone(); - let mode = self.mode; + let handler = SocksTcpHandler { + context: self.context.clone(), + udp_bind_addr: udp_bind_addr.clone(), + stream, + balancer: self.balancer.clone(), + peer_addr, + mode: self.mode, + socks5_auth: self.socks5_auth.clone(), + #[cfg(feature = "local-http")] + http_handler: http_handler.clone(), + }; tokio::spawn(async move { - if let Err(err) = SocksTcpServer::handle_tcp_client( - context, - udp_bind_addr, - stream, - balancer, - peer_addr, - mode, - socks5_auth, - ) - .await - { + if let Err(err) = handler.handle_tcp_client().await { error!("socks5 tcp client handler error: {}", err); } }); } } +} - #[cfg(feature = "local-socks4")] - async fn handle_tcp_client( - context: Arc, - udp_bind_addr: Arc, - stream: TcpStream, - balancer: PingBalancer, - peer_addr: SocketAddr, - mode: Mode, - socks5_auth: Arc, - ) -> io::Result<()> { +struct SocksTcpHandler { + context: Arc, + udp_bind_addr: Arc, + stream: TcpStream, + balancer: PingBalancer, + peer_addr: SocketAddr, + mode: Mode, + socks5_auth: Arc, + #[cfg(feature = "local-http")] + http_handler: HttpConnectionHandler, +} + +impl SocksTcpHandler { + #[cfg(not(any(feature = "local-socks4", feature = "local-http")))] + async fn handle_tcp_client(self) -> io::Result<()> { + let handler = Socks5TcpHandler::new( + self.context, + self.udp_bind_addr, + self.balancer, + self.mode, + self.socks5_auth, + ); + handler.handle_socks5_client(self.stream, self.peer_addr).await + } + + #[cfg(any(feature = "local-socks4", feature = "local-http"))] + async fn handle_tcp_client(self) -> io::Result<()> { use std::io::ErrorKind; let mut version_buffer = [0u8; 1]; - let n = stream.peek(&mut version_buffer).await?; + let n = self.stream.peek(&mut version_buffer).await?; if n == 0 { return Err(ErrorKind::UnexpectedEof.into()); } match version_buffer[0] { + #[cfg(feature = "local-socks4")] 0x04 => { - let handler = Socks4TcpHandler::new(context, balancer, mode); - handler.handle_socks4_client(stream, peer_addr).await + let handler = Socks4TcpHandler::new(self.context, self.balancer, self.mode); + handler.handle_socks4_client(self.stream, self.peer_addr).await } 0x05 => { - let handler = Socks5TcpHandler::new(context, udp_bind_addr, balancer, mode, socks5_auth); - handler.handle_socks5_client(stream, peer_addr).await + let handler = Socks5TcpHandler::new( + self.context, + self.udp_bind_addr, + self.balancer, + self.mode, + self.socks5_auth, + ); + handler.handle_socks5_client(self.stream, self.peer_addr).await + } + + #[cfg(feature = "local-http")] + b'G' | b'g' | b'H' | b'h' | b'P' | b'p' | b'D' | b'd' | b'C' | b'c' | b'O' | b'o' | b'T' | b't' => { + // GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH + match self.http_handler.serve_connection(self.stream, self.peer_addr).await { + Ok(..) => Ok(()), + Err(err) => { + error!("HTTP connection {} handler failed with error: {}", self.peer_addr, err); + Err(io::Error::new(ErrorKind::Other, err)) + } + } } version => { @@ -175,20 +210,6 @@ impl SocksTcpServer { } } } - - #[cfg(not(feature = "local-socks4"))] - async fn handle_tcp_client( - context: Arc, - udp_bind_addr: Arc, - stream: TcpStream, - balancer: PingBalancer, - peer_addr: SocketAddr, - mode: Mode, - socks5_auth: Arc, - ) -> io::Result<()> { - let handler = Socks5TcpHandler::new(context, udp_bind_addr, balancer, mode, socks5_auth); - handler.handle_socks5_client(stream, peer_addr).await - } } /// SOCKS UDP server