wayver's git archive


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

src/handlers/git.rs@6e060abc1f25c2e1b79fe06bfa8b72cd26952ee1

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

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