mirror of
https://github.com/YGGverse/titanit.git
synced 2026-03-31 17:15:30 +00:00
update main handler, add comments
This commit is contained in:
parent
156a2c40dc
commit
31e33bca28
1 changed files with 59 additions and 35 deletions
86
src/main.rs
86
src/main.rs
|
|
@ -59,45 +59,69 @@ fn handle(
|
||||||
match connection {
|
match connection {
|
||||||
Ok(mut stream) => {
|
Ok(mut stream) => {
|
||||||
// server should work with large files without memory overload,
|
// server should work with large files without memory overload,
|
||||||
// because of that incoming data read partially, using chunks;
|
// because of that, incoming data read partially, using chunks;
|
||||||
// collect header bytes first to route the request
|
// collect header bytes first to route the request by its type.
|
||||||
let mut header = Vec::with_capacity(HEADER_MAX_LEN);
|
let mut header_buffer = Vec::with_capacity(HEADER_MAX_LEN);
|
||||||
loop {
|
loop {
|
||||||
let mut buffer = vec![0];
|
let mut header_chunk = vec![0];
|
||||||
match stream.read(&mut buffer) {
|
match stream.read(&mut header_chunk) {
|
||||||
Ok(0) => println!("[{}] [warning] [{peer}] Peer closed connection.", now()),
|
Ok(0) => println!("[{}] [warning] [{peer}] Peer closed connection.", now()),
|
||||||
Ok(_) => {
|
Ok(l) => {
|
||||||
header.push(buffer[0]);
|
// validate header buffer, break on its length reached protocol limits
|
||||||
// header bytes collected
|
if header_buffer.len() + l > HEADER_MAX_LEN {
|
||||||
if header.len() > HEADER_MAX_LEN || buffer[0] == b'\n' {
|
return send(
|
||||||
// detect controller for the request by parse its header bytes
|
|
||||||
return match Request::from_bytes(&header) {
|
|
||||||
Ok(request) => match request {
|
|
||||||
Request::Gemini(this) => {
|
|
||||||
gemini(this, &argument, &peer, &mut stream)
|
|
||||||
}
|
|
||||||
Request::Titan(this) => {
|
|
||||||
titan(this, &argument, &peer, &mut stream)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => send(
|
|
||||||
&response::failure::permanent::BadRequest {
|
&response::failure::permanent::BadRequest {
|
||||||
message: Some("Invalid request".to_string()),
|
message: Some("Bad request".to_string()),
|
||||||
}
|
}
|
||||||
.into_bytes(),
|
.into_bytes(),
|
||||||
&mut stream,
|
&mut stream,
|
||||||
|result| match result {
|
|result| match result {
|
||||||
Ok(()) => println!("[{}] [warning] [{peer}] {e}", now()),
|
Ok(()) => {
|
||||||
|
println!("[{}] [warning] [{peer}] Bad request", now())
|
||||||
|
}
|
||||||
Err(e) => println!("[{}] [error] [{peer}] {e}", now()),
|
Err(e) => println!("[{}] [error] [{peer}] {e}", now()),
|
||||||
},
|
},
|
||||||
),
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
// take chunk bytes at this point
|
||||||
|
header_buffer.extend(header_chunk);
|
||||||
|
|
||||||
|
// ending header byte received
|
||||||
|
if header_buffer.last().is_some_and(|&b| b == b'\n') {
|
||||||
|
// header bytes contain valid Gemini **request**
|
||||||
|
if let Ok(request) = request::Gemini::from_bytes(&header_buffer) {
|
||||||
|
return gemini(request, &argument, &peer, &mut stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// header bytes contain valid Titan **meta**
|
||||||
|
// * yet, no data has been received to parse the entire Titan request,
|
||||||
|
// the data will be handled separately upon success, in chunks.
|
||||||
|
if let Ok(meta) = request::titan::Meta::from_bytes(&header_buffer) {
|
||||||
|
return titan(meta, &argument, &peer, &mut stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// header bytes received but yet could not be parsed,
|
||||||
|
// complete with request failure
|
||||||
|
return send(
|
||||||
|
&response::failure::permanent::BadRequest {
|
||||||
|
message: Some("Bad request".to_string()),
|
||||||
|
}
|
||||||
|
.into_bytes(),
|
||||||
|
&mut stream,
|
||||||
|
|result| match result {
|
||||||
|
Ok(()) => {
|
||||||
|
println!("[{}] [warning] [{peer}] Bad request", now())
|
||||||
|
}
|
||||||
|
Err(e) => println!("[{}] [error] [{peer}] {e}", now()),
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return send(
|
return send(
|
||||||
&response::failure::permanent::BadRequest {
|
&response::failure::permanent::BadRequest {
|
||||||
message: Some("Invalid request".to_string()),
|
message: Some("Bad request".to_string()),
|
||||||
}
|
}
|
||||||
.into_bytes(),
|
.into_bytes(),
|
||||||
&mut stream,
|
&mut stream,
|
||||||
|
|
@ -174,16 +198,16 @@ fn gemini(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn titan(
|
fn titan(
|
||||||
titan: titanite::request::Titan,
|
meta: titanite::request::titan::Meta,
|
||||||
argument: &Argument,
|
argument: &Argument,
|
||||||
peer: &SocketAddr,
|
peer: &SocketAddr,
|
||||||
stream: &mut TlsStream<TcpStream>,
|
stream: &mut TlsStream<TcpStream>,
|
||||||
) {
|
) {
|
||||||
use titanite::*;
|
use titanite::*;
|
||||||
println!("[{}] [info] [{peer}] Request: {}", now(), titan.meta.url);
|
println!("[{}] [info] [{peer}] Request: {}", now(), meta.url);
|
||||||
// require content type for application,
|
// require content type for application,
|
||||||
// even MIME value is optional by Titan specification
|
// even MIME value is optional by Titan specification
|
||||||
let mime = match titan.meta.mime {
|
let mime = match meta.mime {
|
||||||
Some(mime) => mime,
|
Some(mime) => mime,
|
||||||
None => {
|
None => {
|
||||||
const MESSAGE: &str = "Content type is required";
|
const MESSAGE: &str = "Content type is required";
|
||||||
|
|
@ -236,7 +260,7 @@ fn titan(
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate client-side limits (from header)
|
// validate client-side limits (from header)
|
||||||
if total > titan.meta.size {
|
if total > meta.size {
|
||||||
if let Err(e) = tmp.delete() {
|
if let Err(e) = tmp.delete() {
|
||||||
println!("[{}] [error] [{peer}] {e}", now());
|
println!("[{}] [error] [{peer}] {e}", now());
|
||||||
}
|
}
|
||||||
|
|
@ -278,12 +302,12 @@ fn titan(
|
||||||
}
|
}
|
||||||
|
|
||||||
// just to make sure
|
// just to make sure
|
||||||
if total > titan.meta.size {
|
if total > meta.size {
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
|
|
||||||
// all data received
|
// all data received
|
||||||
if titan.meta.size == total {
|
if meta.size == total {
|
||||||
return match tmp.commit() {
|
return match tmp.commit() {
|
||||||
Ok(pmt) => send(
|
Ok(pmt) => send(
|
||||||
&response::redirect::Permanent {
|
&response::redirect::Permanent {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue