10a4398e81
- Remove unnecessary sorting in advertise_refs for deterministic output - Add path traversal detection and validation in bare_dir construction - Implement symlink resolution checks to prevent security vulnerabilities - Refactor cache system with CRC validation and improved metrics - Integrate repo-specific cache invalidation using indexed keys - Add comprehensive unit tests for commit operations and diff functionality - Move configuration constants to centralized config module - Optimize string operations in disk cache random value generation - Enhance license detection algorithm with cleaner matching logic - Streamline argument processing in various git operations - Update dependencies including crc32fast and flate2 for performance - Add signal handling capability to tokio runtime configuration
113 lines
3.6 KiB
Rust
113 lines
3.6 KiB
Rust
use crate::bare::GitBare;
|
|
use crate::error::{GitError, GitResult};
|
|
use crate::pb::{AdvertiseRefsRequest, AdvertiseRefsResponse, ReferenceAdvertisement};
|
|
|
|
impl GitBare {
|
|
pub fn advertise_refs(
|
|
&self,
|
|
request: AdvertiseRefsRequest,
|
|
) -> GitResult<AdvertiseRefsResponse> {
|
|
if request.raw {
|
|
return self.advertise_refs_raw(&request);
|
|
}
|
|
let repo = self.gix_repo()?;
|
|
let mut references = Vec::new();
|
|
for r in repo.references()?.all()? {
|
|
let mut r = match r {
|
|
Ok(r) => r,
|
|
Err(_) => continue,
|
|
};
|
|
let name = r.name().to_string();
|
|
let target_oid = r.peel_to_id().ok().map(|id| self.oid_to_pb(id.to_string()));
|
|
let is_symbolic = r.target().try_id().is_none();
|
|
let symbolic_target = if is_symbolic {
|
|
match r.target() {
|
|
gix::refs::TargetRef::Symbolic(name) => name.to_string(),
|
|
_ => String::new(),
|
|
}
|
|
} else {
|
|
String::new()
|
|
};
|
|
// Peel past tags to get the commit OID if this is a tag ref
|
|
let peeled_oid = if name.starts_with("refs/tags/") {
|
|
r.peel_to_id().ok().map(|id| self.oid_to_pb(id.to_string()))
|
|
} else {
|
|
None
|
|
};
|
|
references.push(ReferenceAdvertisement {
|
|
name,
|
|
target_oid,
|
|
peeled_oid,
|
|
symbolic: is_symbolic,
|
|
symbolic_target,
|
|
});
|
|
}
|
|
references.sort_by(|a, b| a.name.cmp(&b.name));
|
|
Ok(AdvertiseRefsResponse {
|
|
references,
|
|
capabilities: vec![
|
|
"report-status".into(),
|
|
"delete-refs".into(),
|
|
"side-band-64k".into(),
|
|
"ofs-delta".into(),
|
|
"multi_ack_detailed".into(),
|
|
"multi_ack".into(),
|
|
"symref=HEAD".into(),
|
|
],
|
|
raw_data: Vec::new(),
|
|
})
|
|
}
|
|
|
|
/// Return raw pkt-line output from git upload-pack/receive-pack --advertise-refs.
|
|
/// Used by transparent proxies (gitshell) that forward bytes verbatim to git clients.
|
|
fn advertise_refs_raw(
|
|
&self,
|
|
request: &AdvertiseRefsRequest,
|
|
) -> GitResult<AdvertiseRefsResponse> {
|
|
let bare_dir_str = self.bare_dir.to_string_lossy().into_owned();
|
|
let stateless = request.protocol.as_ref().is_some_and(|p| p.stateless);
|
|
|
|
let subcommand = if request.service == "git-receive-pack" {
|
|
"receive-pack"
|
|
} else {
|
|
"upload-pack"
|
|
};
|
|
|
|
let mut args: Vec<String> = vec![
|
|
"--git-dir".into(),
|
|
bare_dir_str,
|
|
subcommand.into(),
|
|
"--advertise-refs".into(),
|
|
];
|
|
if stateless {
|
|
args.push("--stateless-rpc".into());
|
|
}
|
|
|
|
let result = duct::cmd("git", &args)
|
|
.stdout_capture()
|
|
.stderr_capture()
|
|
.unchecked()
|
|
.run()?;
|
|
|
|
if !result.status.success() {
|
|
return Err(GitError::CommandFailed {
|
|
status_code: result.status.code(),
|
|
stderr: String::from_utf8_lossy(&result.stderr).into_owned(),
|
|
});
|
|
}
|
|
|
|
tracing::debug!(
|
|
raw_len = result.stdout.len(),
|
|
service = %request.service,
|
|
stateless = stateless,
|
|
"advertise_refs raw output"
|
|
);
|
|
|
|
Ok(AdvertiseRefsResponse {
|
|
references: Vec::new(),
|
|
capabilities: Vec::new(),
|
|
raw_data: result.stdout,
|
|
})
|
|
}
|
|
}
|