Merge branch 'main' of https://git.meex.lol/MeexReay/flowgate
This commit is contained in:
commit
e39c5152fd
0
Cargo.lock
generated
Normal file → Executable file
0
Cargo.lock
generated
Normal file → Executable file
18
README.md
18
README.md
@ -3,22 +3,32 @@ HTTP requests redirection system
|
||||
|
||||
Features:
|
||||
- Request redirection
|
||||
- TLS support
|
||||
- TLS support (via Rustls!)
|
||||
- Keep-alive connections
|
||||
- Sending IP in header (X-Real-IP)
|
||||
- Multiple ip forwarding methods
|
||||
- Accepts incoming ip forwarding
|
||||
|
||||
TODO:
|
||||
- Remove panics
|
||||
- Creating trees of flowgate
|
||||
- Filter by headers
|
||||
- Modify response headers
|
||||
- HTTP/3 full support
|
||||
- HTTP/3 full support (quic/udp)
|
||||
|
||||
## How to use
|
||||
|
||||
Firstly, download it from releases. or build from sources (read BUILD.md) \
|
||||
Just run it and configure in `conf.yml` file.
|
||||
|
||||
### Logging
|
||||
|
||||
To get all logs (with debug ones), set this env var:
|
||||
|
||||
```
|
||||
RUST_LOG=debug
|
||||
```
|
||||
|
||||
Read more: [env_logger](https://docs.rs/env_logger/latest/env_logger/#enabling-logging)
|
||||
|
||||
## Configuration
|
||||
|
||||
### IP forwarding methods
|
||||
|
5
conf.yml
5
conf.yml
@ -1,8 +1,9 @@
|
||||
http_host: localhost:80 # Http server host
|
||||
https_host: localhost:443 # Https server host
|
||||
http_host: localhost:80 # Http server host (optional)
|
||||
https_host: localhost:443 # Https server host (optional)
|
||||
|
||||
connection_timeout: 10 # Read and write timeout of connections in seconds (optional, default - 10)
|
||||
incoming_ip_forwarding: none # Read IP forwarding on incoming connections (optional, default - none)
|
||||
threadpool_size: 10 # Size of the global threadpool (optional, default - 10)
|
||||
|
||||
sites:
|
||||
- domain: localhost # Site domain (use wildcard matching)
|
||||
|
@ -51,10 +51,11 @@ impl IpForwarding {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Config {
|
||||
pub sites: Vec<SiteConfig>,
|
||||
pub http_host: String,
|
||||
pub https_host: String,
|
||||
pub http_host: Option<String>,
|
||||
pub https_host: Option<String>,
|
||||
pub connection_timeout: Duration,
|
||||
pub incoming_ip_forwarding: IpForwarding
|
||||
pub incoming_ip_forwarding: IpForwarding,
|
||||
pub threadpool_size: usize
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@ -62,8 +63,10 @@ impl Config {
|
||||
let file_content = fs::read_to_string(filename).ok()?;
|
||||
let doc = serde_yml::from_str::<Value>(file_content.as_str()).ok()?;
|
||||
|
||||
let http_host = doc["http_host"].as_str()?.to_string();
|
||||
let https_host = doc["https_host"].as_str()?.to_string();
|
||||
let http_host = doc.get("http_host").and_then(|o| Some(o.as_str()?.to_string()));
|
||||
let https_host = doc.get("https_host").and_then(|o| Some(o.as_str()?.to_string()));
|
||||
|
||||
let threadpool_size = doc.get("threadpool_size").and_then(|o| Some(o.as_u64()? as usize + 2)).unwrap_or(12);
|
||||
|
||||
let connection_timeout = Duration::from_secs(doc.get("connection_timeout")
|
||||
.unwrap_or(&Value::Number(Number::from(10))).as_u64()?);
|
||||
@ -115,7 +118,8 @@ impl Config {
|
||||
http_host,
|
||||
https_host,
|
||||
connection_timeout,
|
||||
incoming_ip_forwarding
|
||||
incoming_ip_forwarding,
|
||||
threadpool_size
|
||||
}.clone())
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ impl FlowgateServer {
|
||||
pub fn start(self) -> ThreadPool {
|
||||
let local_self = Arc::new(self);
|
||||
|
||||
let threadpool = ThreadPool::new(10);
|
||||
let threadpool = ThreadPool::new(local_self.config.threadpool_size);
|
||||
|
||||
let mut handles = Vec::new();
|
||||
|
||||
@ -68,9 +68,10 @@ impl FlowgateServer {
|
||||
}
|
||||
|
||||
pub fn run_http(self: Arc<Self>, threadpool: &ThreadPool) -> Result<(), Box<dyn Error>> {
|
||||
let listener = TcpListener::bind(&self.config.http_host)?;
|
||||
if let Some(host) = self.config.http_host.clone() {
|
||||
let listener = TcpListener::bind(&host)?;
|
||||
|
||||
info!("HTTP server runned on {}", &self.config.http_host);
|
||||
info!("HTTP server runned on {}", &host);
|
||||
|
||||
for stream in listener.incoming() {
|
||||
if let Ok(mut stream) = stream {
|
||||
@ -86,17 +87,21 @@ impl FlowgateServer {
|
||||
addr,
|
||||
false
|
||||
);
|
||||
|
||||
debug!("{} close connection", addr);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_https(self: Arc<Self>, threadpool: &ThreadPool) -> Result<(), Box<dyn Error>> {
|
||||
let listener = TcpListener::bind(&self.config.https_host)?;
|
||||
if let Some(host) = self.config.https_host.clone() {
|
||||
let listener = TcpListener::bind(&host)?;
|
||||
|
||||
info!("HTTPS server runned on {}", &self.config.https_host);
|
||||
info!("HTTPS server runned on {}", &host);
|
||||
|
||||
let config = Arc::new(create_server_config(self.config.clone()));
|
||||
|
||||
@ -120,10 +125,11 @@ impl FlowgateServer {
|
||||
&mut stream,
|
||||
addr,
|
||||
true
|
||||
).map(|_| {
|
||||
);
|
||||
|
||||
debug!("{} close connection", addr);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -362,6 +368,11 @@ impl FlowgateServer {
|
||||
}
|
||||
} else if is_chunked {
|
||||
transfer_chunked(&mut stream, conn.stream.get_mut())?;
|
||||
} else {
|
||||
let buffer = stream.buffer().to_vec();
|
||||
|
||||
conn.stream.get_mut().write_all(&buffer).ok()?;
|
||||
stream.consume(buffer.len());
|
||||
}
|
||||
|
||||
debug!("{} {} send body to server", addr, status[1]);
|
||||
@ -432,6 +443,11 @@ impl FlowgateServer {
|
||||
}
|
||||
} else if is_chunked {
|
||||
transfer_chunked(&mut conn.stream, stream.get_mut())?;
|
||||
} else {
|
||||
let buffer = conn.stream.buffer().to_vec();
|
||||
|
||||
stream.get_mut().write_all(&buffer).ok()?;
|
||||
conn.stream.consume(buffer.len());
|
||||
}
|
||||
|
||||
debug!("{} {} send response body to clientr", addr, status[1]);
|
||||
|
32
tests/half_request.py
Executable file
32
tests/half_request.py
Executable file
@ -0,0 +1,32 @@
|
||||
import socket
|
||||
|
||||
HOST = '172.16.1.32'
|
||||
PORT = 80
|
||||
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.connect((HOST, PORT))
|
||||
|
||||
s.send(b"""GET / HTTP/1.1\r
|
||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r
|
||||
Accept-Encoding: gzip, deflate, br, zstd\r
|
||||
Accept-Language: en-US,en;q=0.9\r
|
||||
Cache-Control: no-cache\r
|
||||
Connection: keep-alive\r
|
||||
Host: git.meex.lol\r
|
||||
Pragma: no-cache\r
|
||||
Sec-Fetch-Dest: document\r
|
||||
Sec-Fetch-Mode: navigate\r
|
||||
Sec-Fetch-Site: none\r
|
||||
Sec-Fetch-User: ?1\r
|
||||
Upgrade-Insecure-Requests: 1\r
|
||||
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36\r
|
||||
sec-ch-ua: \"Chromium\";v=\"135\", \"Not-A.Brand\";v=\"8\"\r
|
||||
sec-ch-ua-mobile: ?0\r
|
||||
sec-ch-ua-platform: \"Linux\"\r
|
||||
\r
|
||||
""")
|
||||
|
||||
content_length = 0
|
||||
while True:
|
||||
data = s.recv(1024)
|
||||
print(data)
|
0
tests/http_client.py
Normal file → Executable file
0
tests/http_client.py
Normal file → Executable file
Loading…
x
Reference in New Issue
Block a user