Skip to main content

lanflare_core/server/
router.rs

1//! Hyper router dispatching incoming HTTP requests to LocalSend v2.2 handlers.
2
3use std::net::IpAddr;
4use bytes::Bytes;
5use http_body_util::Full;
6use hyper::body::Incoming;
7use hyper::{Method, Request, Response, StatusCode};
8
9use crate::server::handlers::{
10    empty_response, handle_cancel, handle_download, handle_info, handle_prepare_download,
11    handle_prepare_upload, handle_register, handle_upload, handle_web_portal, ServerState,
12};
13
14/// Client connection metadata extracted from the underlying TLS / TCP stream.
15#[derive(Clone, Debug)]
16pub struct ClientConnectionInfo {
17    /// Remote IP address.
18    pub remote_ip: IpAddr,
19    /// Client certificate SHA-256 fingerprint (if presented in mTLS).
20    pub cert_fingerprint: Option<String>,
21}
22
23/// Routes incoming HTTP requests to the appropriate handler according to LocalSend v2.2 specification.
24pub async fn route_request(
25    req: Request<Incoming>,
26    client: ClientConnectionInfo,
27    state: &ServerState,
28) -> Result<Response<Full<Bytes>>, hyper::Error> {
29    let method = req.method();
30    let path = req.uri().path();
31
32    let response = match (method, path) {
33        // Web portal for browser download (Share via link)
34        (&Method::GET, "/") | (&Method::GET, "/index.html") => {
35            handle_web_portal(&req, state).await
36        }
37
38        // v1/v2 Device Information: GET /api/localsend/v2/info or GET /api/localsend/v1/info
39        (&Method::GET, "/api/localsend/v2/info") | (&Method::GET, "/api/localsend/v1/info") => {
40            handle_info(state).await
41        }
42
43        // Two-way discovery registration: POST /api/localsend/v2/register
44        (&Method::POST, "/api/localsend/v2/register") => {
45            handle_register(req, client.remote_ip, client.cert_fingerprint, state).await
46        }
47
48        // Transfer session preparation: POST /api/localsend/v2/prepare-upload
49        (&Method::POST, "/api/localsend/v2/prepare-upload") => {
50            handle_prepare_upload(req, client.remote_ip, client.cert_fingerprint, state).await
51        }
52
53        // Binary file upload stream: POST /api/localsend/v2/upload
54        (&Method::POST, "/api/localsend/v2/upload") => {
55            handle_upload(req, client.remote_ip, state).await
56        }
57
58        // Reverse file transfer (Browser download metadata): POST /api/localsend/v2/prepare-download
59        (&Method::POST, "/api/localsend/v2/prepare-download") => {
60            handle_prepare_download(req, client.remote_ip, state).await
61        }
62
63        // Reverse file transfer binary stream: GET /api/localsend/v2/download or GET /download
64        (&Method::GET, "/api/localsend/v2/download") | (&Method::GET, "/download") => {
65            handle_download(req, client.remote_ip, state).await
66        }
67
68        // Transfer cancellation: POST /api/localsend/v2/cancel
69        (&Method::POST, "/api/localsend/v2/cancel") => {
70            handle_cancel(req, client.remote_ip, state).await
71        }
72
73        // Fallback: 404 Not Found
74        _ => empty_response(StatusCode::NOT_FOUND),
75    };
76
77    Ok(response)
78}