torrust_index_backend/web/api/v1/contexts/proxy/
handlers.rs

1//! API handlers for the the [`proxy`](crate::web::api::v1::contexts::proxy) API
2//! context.
3use std::sync::Arc;
4
5use axum::extract::{Path, State};
6use axum::response::Response;
7
8use super::responses::png_image;
9use crate::cache::image::manager::Error;
10use crate::common::AppData;
11use crate::ui::proxy::map_error_to_image;
12use crate::web::api::v1::extractors::bearer_token::Extract;
13
14/// Get the remote image. It uses the cached image if available.
15#[allow(clippy::unused_async)]
16pub async fn get_proxy_image_handler(
17    State(app_data): State<Arc<AppData>>,
18    Extract(maybe_bearer_token): Extract,
19    Path(url): Path<String>,
20) -> Response {
21    if maybe_bearer_token.is_none() {
22        return png_image(map_error_to_image(&Error::Unauthenticated));
23    }
24
25    let Ok(user_id) = app_data.auth.get_user_id_from_bearer_token(&maybe_bearer_token).await else {
26        return png_image(map_error_to_image(&Error::Unauthenticated));
27    };
28
29    // code-review: Handling status codes in the frontend other tan OK is quite a pain.
30    // Return OK for now.
31
32    // todo: it also work for other image types but we are always returning the
33    // same content type: `image/png`. If we only support PNG images we should
34    // change the documentation and return an error for other image types.
35
36    // Get image URL from URL path parameter.
37    let image_url = urlencoding::decode(&url).unwrap_or_default().into_owned();
38
39    match app_data.proxy_service.get_image_by_url(&image_url, &user_id).await {
40        Ok(image_bytes) => {
41            // Returns the cached image.
42            png_image(image_bytes)
43        }
44        Err(e) => {
45            // Returns an error image.
46            png_image(map_error_to_image(&e))
47        }
48    }
49}