wayver's git archive


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

src/handlers/git.rs@71b17dd92232913d023854951d629e9876076719

raw
Date Commit Message Author Files + -
2026-02-20 20:25 remove unneeded result type alias wayverd 13 27 31
...

1use axum::{
2    extract::State,
3    http::{HeaderValue, StatusCode, Uri, header},
4    response::{IntoResponse as _, Response},
5};
6
7use crate::{
8    BileState,
9    error::{Context as _, Result},
10    git::Repository,
11    http::{extractor::RepoName, path::Path, response::ErrorPage},
12};
13
14#[tracing::instrument(skip_all)]
15pub(crate) async fn get_1(
16    state: State<BileState>,
17    uri: Uri,
18    Path(repo_name): Path<RepoName>,
19) -> Response {
20    state
21        .spawn(move |state| inner(&state, &uri, &repo_name))
22        .await
23}
24
25#[tracing::instrument(skip_all)]
26pub(crate) async fn get_2(
27    state: State<BileState>,
28    uri: Uri,
29    Path((repo_name, _)): Path<(RepoName, String)>,
30) -> Response {
31    state
32        .spawn(move |state| inner(&state, &uri, &repo_name))
33        .await
34}
35
36fn inner(state: &BileState, uri: &Uri, repo_name: &RepoName) -> Result<Response> {
37    let Some(repo) = Repository::open(&state.config, repo_name).context("opening repository")?
38    else {
39        return Ok(ErrorPage::from(state)
40            .with_status(StatusCode::NOT_FOUND)
41            .into_response());
42    };
43
44    let path = uri
45        .path()
46        .strip_prefix(&format!("/{repo_name}/"))
47        .unwrap_or_default();
48
49    let path = repo.path().join(path);
50
51    // cant canonicalize if it doesnt exist
52    if !path.exists() {
53        return Ok(ErrorPage::from(state)
54            .with_status(StatusCode::NOT_FOUND)
55            .into_response());
56    }
57
58    let path = path.canonicalize().context("canonicalize new path")?;
59
60    // that path got us outside of the repository structure somehow
61    if !path.starts_with(repo.path()) {
62        tracing::warn!("Attempt to acces file outside of repo dir: {:?}", path);
63        return Ok(ErrorPage::from(state)
64            .with_status(StatusCode::FORBIDDEN)
65            .into_response());
66    }
67
68    // Either the requested resource does not exist or it is not
69    // a file, i.e. a directory.
70    if !path.is_file() {
71        return Ok(ErrorPage::from(state)
72            .with_status(StatusCode::NOT_FOUND)
73            .into_response());
74    }
75
76    let body = std::fs::read(&path).context("reading file")?;
77
78    Ok((
79        StatusCode::OK,
80        [(
81            header::CONTENT_TYPE,
82            HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()),
83        )],
84        body,
85    )
86        .into_response())
87}
88