node: Use `gix_packetline`
`gix-packetline` already is in the dependency closure of `radicle-node`. Use the well-tested and -used reader instead of ours.
This commit is contained in:
parent
c96aea0699
commit
5fa68ed814
|
|
@ -3133,6 +3133,7 @@ dependencies = [
|
|||
"crossbeam-channel",
|
||||
"cyphernet",
|
||||
"fastrand",
|
||||
"gix-packetline",
|
||||
"lexopt",
|
||||
"log",
|
||||
"mio 1.0.4",
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ dunce = "1.0.5"
|
|||
fastrand = { version = "2.0.0", default-features = false }
|
||||
git2 = { version = "0.19.0", default-features = false, features = ["vendored-libgit2"] }
|
||||
gix-hash = { version = "0.22.1", default-features = false, features = ["sha1"] }
|
||||
gix-packetline = { version = "0.21.1", default-features = false }
|
||||
human-panic = "2.0.6"
|
||||
itertools = "0.14"
|
||||
lexopt = "0.3.0"
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ colored = { workspace = true }
|
|||
crossbeam-channel = { workspace = true }
|
||||
cyphernet = { workspace = true, features = ["tor", "dns", "ed25519", "p2p-ed25519", "noise-framework", "noise_sha2"] }
|
||||
fastrand = { workspace = true }
|
||||
gix-packetline = { workspace = true, features = ["blocking-io"] }
|
||||
lexopt = { workspace = true }
|
||||
log = { workspace = true, features = ["kv", "std"] }
|
||||
mio = { version = "1", features = ["net", "os-poll"] }
|
||||
|
|
|
|||
|
|
@ -141,15 +141,51 @@ impl Worker {
|
|||
|
||||
let timeout = channels.timeout();
|
||||
let (mut stream_r, stream_w) = channels.split();
|
||||
let header = match upload_pack::pktline::git_request(&mut stream_r) {
|
||||
Ok(header) => header,
|
||||
Err(e) => {
|
||||
|
||||
let mut iter = gix_packetline::blocking_io::StreamingPeekableIter::new(
|
||||
&mut stream_r,
|
||||
&[gix_packetline::PacketLineRef::Flush],
|
||||
false, /* packet tracing */
|
||||
);
|
||||
|
||||
let header = match iter.read_line() {
|
||||
None => {
|
||||
return FetchResult::Responder {
|
||||
rid: None,
|
||||
result: Err(UploadError::PacketLine(std::io::Error::new(
|
||||
std::io::ErrorKind::UnexpectedEof,
|
||||
"unexpected end of stream while reading upload-pack header",
|
||||
))),
|
||||
}
|
||||
}
|
||||
Some(Err(e)) => {
|
||||
return FetchResult::Responder {
|
||||
rid: None,
|
||||
result: Err(UploadError::PacketLine(e)),
|
||||
}
|
||||
}
|
||||
Some(Ok(Err(e))) => {
|
||||
return FetchResult::Responder {
|
||||
rid: None,
|
||||
result: Err(UploadError::PacketLine(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
format!("invalid upload-pack header: {e}"),
|
||||
))),
|
||||
}
|
||||
}
|
||||
Some(Ok(Ok(header))) => header,
|
||||
};
|
||||
|
||||
let Some(header) = upload_pack::GitRequest::from_packetline(header) else {
|
||||
return FetchResult::Responder {
|
||||
rid: None,
|
||||
result: Err(UploadError::PacketLine(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"failed to parse upload-pack header",
|
||||
))),
|
||||
};
|
||||
};
|
||||
|
||||
log::debug!(target: "worker", "Spawning upload-pack process for {} on stream {stream}..", header.repo);
|
||||
|
||||
if let Err(e) = self.is_authorized(remote, header.repo) {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ pub fn upload_pack<R, W>(
|
|||
remote: NodeId,
|
||||
storage: &Storage,
|
||||
emitter: &Emitter<Event>,
|
||||
header: &pktline::GitRequest,
|
||||
header: &GitRequest,
|
||||
mut recv: R,
|
||||
send: W,
|
||||
timeout: Duration,
|
||||
|
|
@ -239,70 +239,9 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) mod pktline {
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::str;
|
||||
|
||||
use radicle::prelude::RepoId;
|
||||
|
||||
pub const HEADER_LEN: usize = 4;
|
||||
|
||||
/// Read and parse the `GitRequest` data from the client side.
|
||||
pub fn git_request<R>(reader: &mut R) -> io::Result<GitRequest>
|
||||
where
|
||||
R: io::Read,
|
||||
{
|
||||
let mut reader = Reader::new(reader);
|
||||
let (header, _) = reader.read_request_pktline()?;
|
||||
Ok(header)
|
||||
}
|
||||
|
||||
struct Reader<'a, R> {
|
||||
stream: &'a mut R,
|
||||
}
|
||||
|
||||
impl<'a, R: io::Read> Reader<'a, R> {
|
||||
/// Create a new packet-line reader.
|
||||
pub fn new(stream: &'a mut R) -> Self {
|
||||
Self { stream }
|
||||
}
|
||||
|
||||
/// Parse a Git request packet-line.
|
||||
/// The Git request packet-line for a repository.
|
||||
///
|
||||
/// Example: `0032git-upload-pack /project.git\0host=myserver.com\0`
|
||||
///
|
||||
fn read_request_pktline(&mut self) -> io::Result<(GitRequest, Vec<u8>)> {
|
||||
let mut pktline = [0u8; 1024];
|
||||
let length = self.read_pktline(&mut pktline)?;
|
||||
let Some(cmd) = GitRequest::parse(&pktline[4..length]) else {
|
||||
return Err(io::ErrorKind::InvalidInput.into());
|
||||
};
|
||||
Ok((cmd, Vec::from(&pktline[..length])))
|
||||
}
|
||||
|
||||
/// Parse a Git packet-line.
|
||||
fn read_pktline(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.read_exact(&mut buf[..HEADER_LEN])?;
|
||||
|
||||
let length = str::from_utf8(&buf[..HEADER_LEN])
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e.to_string()))?;
|
||||
let length = usize::from_str_radix(length, 16)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e.to_string()))?;
|
||||
|
||||
self.read_exact(&mut buf[HEADER_LEN..length])?;
|
||||
|
||||
Ok(length)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: io::Read> io::Read for Reader<'_, R> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.stream.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
/// The Git request packet-line for a Heartwood repository.
|
||||
/// See <https://git-scm.com/docs/pack-protocol.html#_git_transport>.
|
||||
///
|
||||
/// Example: `0032git-upload-pack /rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5.git\0host=myserver.com\0`
|
||||
#[derive(Debug)]
|
||||
|
|
@ -316,9 +255,15 @@ pub(super) mod pktline {
|
|||
}
|
||||
|
||||
impl GitRequest {
|
||||
pub(super) fn from_packetline(
|
||||
packet_line: gix_packetline::PacketLineRef<'_>,
|
||||
) -> Option<GitRequest> {
|
||||
packet_line.as_slice().and_then(Self::parse)
|
||||
}
|
||||
|
||||
/// Parse a Git command from a packet-line.
|
||||
fn parse(input: &[u8]) -> Option<Self> {
|
||||
let input = str::from_utf8(input).ok()?;
|
||||
let input = std::str::from_utf8(input).ok()?;
|
||||
let mut parts = input
|
||||
.strip_prefix("git-upload-pack ")?
|
||||
.split_terminator('\0');
|
||||
|
|
@ -354,4 +299,3 @@ pub(super) mod pktline {
|
|||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue