1use std::collections::VecDeque;
22use std::io::Read;
23use std::sync::Arc;
24
25use axum::extract::ws::{Message, WebSocket, WebSocketUpgrade};
26use axum::extract::State;
27use axum::response::Response;
28use bytes::Bytes;
29use futures::SinkExt;
30use libfw_core::auth::{Action, AuthError};
31use libfw_core::claims::TokenClaims;
32use libfw_core::compress::{
33 CompressionFormat, MAX_FRAME_OUTPUT, compressor, decompressor_with_limit,
34};
35use libfw_core::storage::WriteMode;
36use libfw_core::ws::*;
37use libfw_core::{RangeSpec, protocol_compatible};
38
39use crate::{ServerState, validate_rel_path};
40
41const DEFAULT_DOWNLOAD_BLOCK: u64 = 256 * 1024;
44const SENDER_WINDOW: usize = 16;
48const MIN_BLOCK_SIZE: u64 = 1024;
53const MAX_BLOCK_SIZE: u64 = 16 * 1024 * 1024;
56const MAX_WINDOW: usize = 64;
59const MAX_BLOCKS: u64 = 1 << 24;
64
65pub async fn ws_handler(
71 ws: WebSocketUpgrade,
72 State(state): State<Arc<ServerState>>,
73) -> Response {
74 ws.on_upgrade(move |socket| run_socket(socket, state))
75}
76
77async fn run_socket(mut socket: WebSocket, state: Arc<ServerState>) {
82 let claims = match handshake(&mut socket, &state).await {
84 Ok(claims) => claims,
85 Err(err) => {
86 let _ = send_frame(&mut socket, error_frame("handshake", &err)).await;
87 let _ = socket.close().await;
88 return;
89 }
90 };
91
92 loop {
95 let msg = match socket.recv().await {
96 Some(Ok(msg)) => msg,
97 _ => break,
98 };
99 let frame: Vec<u8> = match msg {
100 Message::Binary(data) => data.to_vec(),
101 Message::Text(text) => text.as_bytes().to_vec(),
102 Message::Close(_) => break,
103 _ => continue,
104 };
105 match frame_type(&frame) {
106 Some(FRAME_LIST_REQ) => {
107 let reply = list_reply(&state, &claims, &frame).await;
108 if send_frame(&mut socket, reply).await.is_err() {
109 break;
110 }
111 }
112 Some(FRAME_META_REQ) => {
113 let reply = meta_reply(&state, &claims, &frame).await;
114 if send_frame(&mut socket, reply).await.is_err() {
115 break;
116 }
117 }
118 Some(FRAME_START) => {
119 let start: StartRequest = match parse_control(&frame, FRAME_START) {
120 Some(s) => s,
121 None => {
122 let _ = send_frame(
123 &mut socket,
124 error_frame("protocol", "malformed START"),
125 )
126 .await;
127 break;
128 }
129 };
130 match start.kind {
131 TransferKind::Download => {
132 run_download(&mut socket, &state, &claims, start).await;
133 }
134 TransferKind::Upload => {
135 run_upload(&mut socket, &state, &claims, start).await;
136 }
137 }
138 }
140 Some(FRAME_COMPLETE) => {
141 break;
143 }
144 _ => {}
146 }
147 }
148}
149
150async fn handshake(socket: &mut WebSocket, state: &ServerState) -> Result<TokenClaims, String> {
152 let msg = match socket.recv().await {
153 Some(Ok(Message::Binary(data))) => data.to_vec(),
154 Some(Ok(Message::Text(text))) => text.as_bytes().to_vec(),
155 _ => return Err("expected FRAME_HELLO".into()),
156 };
157 let hello: Hello = parse_control(&msg, FRAME_HELLO).ok_or("expected FRAME_HELLO")?;
158 if !protocol_compatible(&hello.protocol) {
159 return Err(format!("unsupported protocol `{}`", hello.protocol));
160 }
161 let claims = state
162 .verifier
163 .verify(&hello.token)
164 .map_err(|e| format!("authentication failed: {e}"))?;
165 let ok = control_frame(FRAME_HELLO_OK, &serde_json::json!({ "ok": true }));
166 send_frame(socket, ok).await.map_err(|_| "send failed".to_string())?;
167 Ok(claims)
168}
169
170async fn send_frame(socket: &mut WebSocket, frame: Vec<u8>) -> Result<(), ()> {
172 socket
173 .send(Message::Binary(Bytes::from(frame)))
174 .await
175 .map_err(|_| ())
176}
177
178async fn send_complete(socket: &mut WebSocket, ok: bool, size: u64, err: Option<&str>) {
180 let msg = CompleteMessage {
181 ok,
182 size,
183 error: err.map(str::to_string),
184 };
185 let _ = send_frame(socket, control_frame(FRAME_COMPLETE, &msg)).await;
186}
187
188fn error_frame(code: &str, message: &str) -> Vec<u8> {
190 control_frame(
191 FRAME_ERROR,
192 &ErrorMessage {
193 code: code.to_string(),
194 message: message.to_string(),
195 },
196 )
197}
198
199fn authorize(
200 state: &ServerState,
201 claims: &TokenClaims,
202 path: &str,
203 action: Action,
204) -> Result<(), String> {
205 state.authorize(claims, path, action).map_err(|err| match err {
206 AuthError::Forbidden { path, action } => {
207 format!("permission denied: {action} on `{path}`")
208 }
209 other => format!("unauthorized: {other}"),
210 })
211}
212
213async fn list_reply(state: &ServerState, claims: &TokenClaims, frame: &[u8]) -> Vec<u8> {
218 #[derive(serde::Deserialize)]
219 struct ListReq {
220 #[serde(default)]
221 path: String,
222 }
223 let req: ListReq = match serde_json::from_slice(frame_payload(frame)) {
224 Ok(r) => r,
225 Err(_) => return error_frame("protocol", "malformed LIST_REQ"),
226 };
227 let path = match validate_rel_path(&req.path) {
228 Ok(p) => p,
229 Err(e) => return error_frame("path", e),
230 };
231 if let Err(e) = authorize(state, claims, &path, Action::Read) {
232 return error_frame("auth", &e);
233 }
234 match state.storage.list_dir(&path).await {
235 Ok(entries) => control_frame(
236 FRAME_LIST_REPLY,
237 &serde_json::json!({ "path": req.path, "entries": entries }),
238 ),
239 Err(e) => error_frame("storage", &e.to_string()),
240 }
241}
242
243async fn meta_reply(state: &ServerState, claims: &TokenClaims, frame: &[u8]) -> Vec<u8> {
244 #[derive(serde::Deserialize)]
245 struct MetaReq {
246 #[serde(default)]
247 path: String,
248 }
249 let req: MetaReq = match serde_json::from_slice(frame_payload(frame)) {
250 Ok(r) => r,
251 Err(_) => return error_frame("protocol", "malformed META_REQ"),
252 };
253 let path = match validate_rel_path(&req.path) {
254 Ok(p) => p,
255 Err(e) => return error_frame("path", e),
256 };
257 if let Err(e) = authorize(state, claims, &path, Action::Read) {
258 return error_frame("auth", &e);
259 }
260 match state.storage.file_meta(&path).await {
261 Ok(Some(meta)) => control_frame(
262 FRAME_META_REPLY,
263 &serde_json::json!({
264 "path": meta.path,
265 "size": meta.size,
266 "mtime": meta.mtime,
267 "etag": meta.etag,
268 }),
269 ),
270 Ok(None) => error_frame("not_found", &format!("file not found: {path}")),
271 Err(e) => error_frame("storage", &e.to_string()),
272 }
273}
274
275async fn run_download(
282 socket: &mut WebSocket,
283 state: &ServerState,
284 claims: &TokenClaims,
285 start: StartRequest,
286) {
287 let path = match validate_rel_path(&start.path) {
288 Ok(p) => p,
289 Err(e) => {
290 let _ = send_frame(socket, error_frame("path", e)).await;
291 return;
292 }
293 };
294 if let Err(e) = authorize(state, claims, &path, Action::Read) {
295 let _ = send_frame(socket, error_frame("auth", &e)).await;
296 return;
297 }
298 let meta = match state.storage.file_meta(&path).await {
299 Ok(Some(m)) => m,
300 Ok(None) => {
301 let _ = send_frame(socket, error_frame("not_found", &path)).await;
302 return;
303 }
304 Err(e) => {
305 let _ = send_frame(socket, error_frame("storage", &e.to_string())).await;
306 return;
307 }
308 };
309
310 let block_size = if (MIN_BLOCK_SIZE..=MAX_BLOCK_SIZE).contains(&start.block_size) {
315 start.block_size
316 } else {
317 DEFAULT_DOWNLOAD_BLOCK
318 };
319 let window = if start.window > 0 {
320 (start.window as usize).clamp(1, MAX_WINDOW)
321 } else {
322 SENDER_WINDOW
323 };
324 let compress = start.compress && state.compression == CompressionFormat::Zrip;
327 let start_off = start.offset.min(meta.size);
328 let total = meta.size - start_off;
329 let total_blocks = block_count(total, block_size);
330 if total_blocks as u64 > MAX_BLOCKS {
334 let _ = send_frame(socket, error_frame("too_large", "transfer too large")).await;
335 return;
336 }
337
338 let ready = ReadyReply {
339 kind: TransferKind::Download,
340 path: path.clone(),
341 size: meta.size,
342 mtime: meta.mtime,
343 etag: meta.etag.clone(),
344 compress,
345 block_size,
346 total_blocks,
347 offset: start_off,
348 received: Vec::new(),
349 };
350 if send_frame(socket, control_frame(FRAME_READY, &ready)).await.is_err() {
351 return;
352 }
353
354 let mut queue: VecDeque<u32> = (0..total_blocks).collect();
356
357 loop {
358 let mut wave: Vec<(u32, Vec<u8>, u32, u32)> = Vec::new();
366 let mut sent = 0usize;
367 while sent < window {
368 let Some(idx) = queue.pop_front() else {
369 break;
370 };
371 let (start, end) = block_bounds(idx, block_size, total);
372 let abs = block_offset(idx, block_size, start_off);
373 let mut data = vec![0u8; (end - start) as usize];
374 let mut reader = match state
375 .storage
376 .read_stream(&path, RangeSpec { start: abs, end: abs + (end - start) })
377 .await
378 {
379 Ok(r) => r,
380 Err(e) => {
381 let _ = send_frame(socket, error_frame("storage", &e.to_string())).await;
382 return;
383 }
384 };
385 if read_exact(&mut reader, &mut data).is_err() {
386 let _ = send_frame(socket, error_frame("io", "read failed")).await;
387 return;
388 }
389 let raw_len = data.len() as u32;
390 let payload: Vec<u8> = if compress {
391 match compress_frame(&data) {
392 Some(p) => p,
393 None => {
394 let _ =
395 send_frame(socket, error_frame("compress", "compress failed")).await;
396 return;
397 }
398 }
399 } else {
400 data
401 };
402 let crc = crc32(&payload);
403 wave.push((idx, payload, crc, raw_len));
404 sent += 1;
405 }
406
407 for (idx, payload, crc, raw_len) in wave {
409 let frame = block_frame(idx, crc, raw_len, &payload);
410 if send_frame(socket, frame).await.is_err() {
411 return;
412 }
413 }
414
415 if send_frame(socket, wave_done_frame()).await.is_err() {
417 return;
418 }
419
420 loop {
423 let msg = match socket.recv().await {
424 Some(Ok(msg)) => msg,
425 _ => return, };
427 let frame: Vec<u8> = match msg {
428 Message::Binary(data) => data.to_vec(),
429 Message::Text(text) => text.as_bytes().to_vec(),
430 Message::Close(_) => return,
431 _ => continue,
432 };
433 match frame_type(&frame) {
434 Some(FRAME_NAK) => {
435 if let Some(index) = parse_nak(&frame) {
436 if index < total_blocks {
440 queue.push_back(index);
441 }
442 }
443 }
444 Some(FRAME_REQ) => {
445 if let Some(indices) = parse_req(&frame) {
446 queue.extend(indices.into_iter().filter(|&i| i < total_blocks));
447 }
448 break; }
450 Some(FRAME_COMPLETE) => return, _ => {}
452 }
453 }
454 }
455}
456
457async fn run_upload(
465 socket: &mut WebSocket,
466 state: &ServerState,
467 claims: &TokenClaims,
468 start: StartRequest,
469) {
470 let path = match validate_rel_path(&start.path) {
471 Ok(p) => p,
472 Err(e) => {
473 let _ = send_frame(socket, error_frame("path", e)).await;
474 return;
475 }
476 };
477 if let Err(e) = authorize(state, claims, &path, Action::Write) {
478 let _ = send_frame(socket, error_frame("auth", &e)).await;
479 return;
480 }
481 if start.size > state.max_upload_size {
482 let _ = send_frame(
483 socket,
484 error_frame(
485 "too_large",
486 &format!("upload exceeds limit of {} bytes", state.max_upload_size),
487 ),
488 )
489 .await;
490 return;
491 }
492
493 let block_size = if (MIN_BLOCK_SIZE..=MAX_BLOCK_SIZE).contains(&start.block_size) {
494 start.block_size
495 } else {
496 libfw_core::CHUNK_SIZE
497 };
498 let total_blocks = block_count(start.size, block_size);
499 if total_blocks as u64 > MAX_BLOCKS {
501 let _ = send_frame(socket, error_frame("too_large", "transfer too large")).await;
502 return;
503 }
504 let mode = if start.mode.eq_ignore_ascii_case("create") {
505 WriteMode::Create
506 } else {
507 WriteMode::Overwrite
508 };
509 let session = start.etag.trim_matches('"');
512
513 let mut sink = match state.storage.write_stream_session(&path, session, mode).await {
514 Ok(s) => s,
515 Err(e) => {
516 let _ = send_frame(socket, error_frame("storage", &e.to_string())).await;
517 return;
518 }
519 };
520
521 let received = sink.received_ranges().await.unwrap_or_default();
524 let received_pairs: Vec<[u64; 2]> = received.iter().map(|r| [r.start, r.end]).collect();
525 let received_slices: Vec<(u64, u64)> = received.iter().map(|r| (r.start, r.end)).collect();
526 let mut verified = BlockSet::new(total_blocks);
527 verified.seed_from_ranges(block_size, &received_slices);
528
529 let ready = ReadyReply {
530 kind: TransferKind::Upload,
531 path: path.clone(),
532 size: start.size,
533 mtime: start.mtime,
534 etag: start.etag.clone(),
535 compress: start.compress,
536 block_size,
537 total_blocks,
538 offset: 0,
539 received: received_pairs,
540 };
541 if send_frame(socket, control_frame(FRAME_READY, &ready)).await.is_err() {
542 return; }
544
545 let compress = start.compress;
546 loop {
547 let msg = match socket.recv().await {
548 Some(Ok(msg)) => msg,
549 _ => {
550 return;
553 }
554 };
555 let frame: Vec<u8> = match msg {
556 Message::Binary(data) => data.to_vec(),
557 Message::Text(text) => text.as_bytes().to_vec(),
558 Message::Close(_) => {
559 return;
561 }
562 _ => continue,
563 };
564 match frame_type(&frame) {
565 Some(FRAME_BLOCK) => {
566 let Some(block) = parse_block(&frame) else {
567 continue;
568 };
569 if block.index >= total_blocks || verified.contains(block.index) {
572 continue;
573 }
574 let crc_ok = crc32(&block.data) == block.crc;
576 let raw: Vec<u8> = if compress {
577 match decompress_frame(&block.data) {
578 Ok(d) => d,
579 Err(_) => {
580 let _ = send_frame(socket, nak_frame(block.index)).await;
581 continue;
582 }
583 }
584 } else {
585 block.data
586 };
587 let len_ok = !compress || raw.len() as u32 == block.raw_len;
588 let abs = block_offset(block.index, block_size, 0);
589 let end = abs.saturating_add(raw.len() as u64);
590 let in_bounds = end <= start.size && end <= state.max_upload_size;
591 if !(crc_ok && len_ok && in_bounds) {
592 let _ = send_frame(socket, nak_frame(block.index)).await;
594 continue;
595 }
596 if let Err(e) = sink.write_at(abs, &raw).await {
597 let _ = send_frame(
598 socket,
599 control_frame(
600 FRAME_COMPLETE,
601 &CompleteMessage::err(format!("write failed: {e}")),
602 ),
603 )
604 .await;
605 let _ = sink.abort().await;
606 return;
607 }
608 verified.insert(block.index);
609 }
610 Some(FRAME_WAVE_DONE) => {
611 let missing = verified.missing();
614 if missing.is_empty() {
615 let len = match sink.len().await {
616 Ok(l) => l,
617 Err(e) => {
618 let _ = send_complete(
619 socket,
620 false,
621 0,
622 Some(&format!("len failed: {e}")),
623 )
624 .await;
625 let _ = sink.abort().await;
626 return;
627 }
628 };
629 if len != start.size {
630 let _ = send_complete(socket, false, 0, Some("commit size mismatch")).await;
631 let _ = sink.abort().await;
632 return;
633 }
634 match sink.commit().await {
637 Ok(_) => {
638 let _ = send_complete(socket, true, start.size, None).await;
639 return;
640 }
641 Err(e) => {
642 let _ = send_complete(
643 socket,
644 false,
645 0,
646 Some(&format!("commit failed: {e}")),
647 )
648 .await;
649 return;
650 }
651 }
652 } else {
653 let _ = send_frame(socket, req_frame(&missing)).await;
654 }
655 }
656 Some(FRAME_COMPLETE) => {
657 return;
659 }
660 _ => {}
661 }
662 }
663}
664
665fn read_exact(reader: &mut Box<dyn Read + Send>, buf: &mut [u8]) -> Result<(), ()> {
671 let mut filled = 0usize;
672 while filled < buf.len() {
673 match reader.read(&mut buf[filled..]) {
674 Ok(0) => return Err(()),
675 Ok(n) => filled += n,
676 Err(_) => return Err(()),
677 }
678 }
679 Ok(())
680}
681
682fn compress_frame(data: &[u8]) -> Option<Vec<u8>> {
684 let mut enc = compressor(CompressionFormat::Zrip).ok()?;
685 let mut out = Vec::with_capacity(data.len());
686 enc.compress(data, &mut out).ok()?;
687 enc.finish(&mut out).ok()?;
688 Some(out)
689}
690
691fn decompress_frame(data: &[u8]) -> Result<Vec<u8>, libfw_core::StorageError> {
693 let mut dec = decompressor_with_limit(CompressionFormat::Zrip, MAX_FRAME_OUTPUT);
694 let mut out: Vec<u8> = Vec::new();
695 dec.decompress(data, &mut out)
696 .map_err(|e| libfw_core::StorageError::Other(std::io::Error::other(format!("{e}"))))?;
697 dec.finish(&mut out)
698 .map_err(|e| libfw_core::StorageError::Other(std::io::Error::other(format!("{e}"))))?;
699 Ok(out)
700}