stop storage reader on chunk sending error

This commit is contained in:
yggverse 2025-06-29 12:44:44 +03:00
parent 2003cefb67
commit 9a40d2a7a5
2 changed files with 75 additions and 47 deletions

View file

@ -37,35 +37,79 @@ impl Connection {
Ok(q) => { Ok(q) => {
if self.session.is_debug { if self.session.is_debug {
println!( println!(
"[{}] < [{}] request `{q}`...", "[{}] < [{}] incoming request: `{q}`",
self.address.server, self.address.client self.address.server, self.address.client
) )
} }
if let Some(ref i) = self.session.request { if let Some(ref r) = self.session.request {
i.add(&self.address.client, &q) r.add(&self.address.client, &q)
} }
self.session if self
.session
.clone() .clone()
.public .public
.request(&q, |r| t += self.response(r)); // chunk loop .request(&q, |r| match self.response(r) {
self.session Ok(sent) => {
.access_log t += sent;
.clf(&self.address.client, Some(&q), 0, t); if self.session.is_debug {
println!(
"[{}] > [{}] sent {sent} ({t} total) bytes response.",
self.address.server, self.address.client
)
};
true
}
Err(e) => {
eprintln!(
"[{}] > [{}] `{q}`: error sending response: `{e}`",
self.address.server, self.address.client
);
false
}
})
{
self.session
.access_log
.clf(&self.address.client, Some(&q), 0, t);
self.shutdown()
} else {
self.session
.access_log
.clf(&self.address.client, Some(&q), 1, t);
}
} }
Err(e) => { Err(e) => match self.response(Response::InternalServerError(
t += self.response(Response::InternalServerError( "",
"", format!(
format!( "[{}] < [{}] failed to handle incoming request: `{e}`",
"[{}] < [{}] failed to handle incoming request: `{e}`", self.address.server, self.address.client
),
)) {
Ok(sent) => {
t += sent;
if self.session.is_debug {
println!(
"[{}] > [{}] sent {sent} ({t} total) bytes response.",
self.address.server, self.address.client
)
};
self.session
.access_log
.clf(&self.address.client, None, 2, t);
self.shutdown()
}
Err(e) => {
eprintln!(
"[{}] > [{}] handle request error: `{e}`",
self.address.server, self.address.client self.address.server, self.address.client
), );
)); self.session
self.session .access_log
.access_log .clf(&self.address.client, None, 1, t);
.clf(&self.address.client, None, 1, t); self.shutdown()
} }
},
} }
self.shutdown()
} }
fn request(&mut self) -> Result<String> { fn request(&mut self) -> Result<String> {
@ -74,7 +118,7 @@ impl Connection {
Ok(urlencoding::decode(std::str::from_utf8(&b[..n])?.trim())?.to_string()) Ok(urlencoding::decode(std::str::from_utf8(&b[..n])?.trim())?.to_string())
} }
fn response(&mut self, response: Response) -> usize { fn response(&mut self, response: Response) -> Result<usize> {
let bytes = match response { let bytes = match response {
Response::File(b) => b, Response::File(b) => b,
Response::Directory(q, ref s, is_root) => { Response::Directory(q, ref s, is_root) => {
@ -114,29 +158,9 @@ impl Connection {
self.session.template.not_found() self.session.template.not_found()
} }
}; };
match self.stream.write_all(bytes) { self.stream.write_all(bytes)?;
Ok(()) => { self.stream.flush()?;
if self.session.is_debug { Ok(bytes.len())
println!(
"[{}] > [{}] sent {} bytes response.",
self.address.server,
self.address.client,
bytes.len()
)
}
if let Err(e) = self.stream.flush() {
eprintln!(
"[{}] ! [{}] failed to flush the stream: `{e}`",
self.address.server, self.address.client,
)
}
}
Err(e) => eprintln!(
"[{}] ! [{}] failed to response: `{e}`",
self.address.server, self.address.client,
),
};
bytes.len()
} }
fn shutdown(self) { fn shutdown(self) {

View file

@ -42,7 +42,7 @@ impl Public {
}) })
} }
pub fn request(&self, query: &str, mut callback: impl FnMut(Response)) { pub fn request(&self, query: &str, mut callback: impl FnMut(Response) -> bool) -> bool {
let p = { let p = {
// access restriction zone, change carefully! // access restriction zone, change carefully!
let mut p = PathBuf::from(&self.public_dir); let mut p = PathBuf::from(&self.public_dir);
@ -67,8 +67,12 @@ impl Public {
Ok(mut f) => loop { Ok(mut f) => loop {
let mut b = vec![0; self.read_chunk]; let mut b = vec![0; self.read_chunk];
match f.read(&mut b) { match f.read(&mut b) {
Ok(0) => break, Ok(0) => return true,
Ok(n) => callback(Response::File(&b[..n])), Ok(n) => {
if !callback(Response::File(&b[..n])) {
return false; // break reader on callback failure
}
}
Err(e) => { Err(e) => {
return callback(Response::InternalServerError( return callback(Response::InternalServerError(
query, query,