wayver's git archive


a simple self-hosted git server
git clone https://git.wayver.dev/bile

src/handlers/repo_file_raw.rs@7e0330303eec590c92eb6194f83f04d0e8fb2ea0

raw
Date Commit Message Author Files + -
2026-02-19 17:51 large refactoring wayverd 53 2153 1683
...

1use std::path;
2
3use axum::{
4    extract::{Path, State},
5    http::{StatusCode, header},
6    response::{IntoResponse as _, Response},
7};
8
9use crate::{
10    BileState,
11    error::Context as _,
12    git::Repository,
13    http::{
14        extractor::{ObjectName, Ref, RepoName},
15        response::{ErrorPage, Result},
16    },
17    utils::blob_mime,
18};
19
20#[tracing::instrument(skip_all)]
21pub(crate) async fn get(
22    state: State<BileState>,
23    Path((repo_name, r#ref, object_name)): Path<(RepoName, Ref, ObjectName)>,
24) -> Response {
25    state
26        .spawn(move |state| inner(&state, &repo_name, &r#ref, &object_name))
27        .await
28}
29
30#[tracing::instrument(skip_all)]
31fn inner(
32    state: &BileState,
33    repo_name: &RepoName,
34    r#ref: &Ref,
35    object_name: &ObjectName,
36) -> Result<Response> {
37    let repo = match Repository::open(&state.config, repo_name).context("opening repository") {
38        Ok(Some(repo)) => repo,
39        Ok(None) => {
40            return Ok(ErrorPage::new(&state.config)
41                .with_status(StatusCode::NOT_FOUND)
42                .into_response());
43        }
44        Err(err) => {
45            tracing::error!(err=?err, "failed to open repository");
46
47            return Ok(ErrorPage::new(&state.config)
48                .with_status(StatusCode::NOT_FOUND)
49                .into_response());
50        }
51    };
52
53    let path = path::Path::new(&object_name.0);
54
55    let Some((_, tree)) = repo
56        .commit_tree(&r#ref.0)
57        .context("failed to get commit tree")?
58    else {
59        return Ok(ErrorPage::new(&state.config)
60            .with_status(StatusCode::NOT_FOUND)
61            .into_response());
62    };
63
64    let Some(blob) = repo.tree_blob(&tree, path)? else {
65        return Ok(ErrorPage::new(&state.config)
66            .with_status(StatusCode::NOT_FOUND)
67            .into_response());
68    };
69
70    let extension = path
71        .extension()
72        .and_then(std::ffi::OsStr::to_str)
73        .unwrap_or_default();
74
75    let mime = blob_mime(&blob, extension);
76
77    Ok((
78        StatusCode::OK,
79        [(header::CONTENT_TYPE, mime.as_ref())],
80        blob.content().to_vec(),
81    )
82        .into_response())
83}
84