1use std::io::{Read, Write};
4use std::convert::TryInto;
5
6pub(crate) fn take_sized<R: Read>(reader: &mut R, len: usize) -> std::io::Result<(Vec<u8>, u64)> {
7 let mut r = Vec::with_capacity(len);
8 let got = std::io::copy(&mut reader.take(len as u64), &mut r)?;
9 Ok((r, got))
10}
11
12pub(crate) fn token<R: Read>(reader: &mut R, token: &[u8]) -> std::io::Result<()> {
13 use std::io::{Error, ErrorKind};
14 let (got, read) = take_sized(reader, token.len())?;
15 if read != token.len() as u64 {
16 Err(Error::new(ErrorKind::InvalidInput, "more data needed"))
17 } else if got[..] == token[..] {
18 Ok(())
19 } else {
20 Err(Error::new(ErrorKind::InvalidData, "token mismatch"))
21 }
22}
23
24#[inline]
25pub(crate) fn u8<R: Read>(reader: &mut R) -> std::io::Result<u8> {
26 let mut buf = [0; 1];
27 reader.read_exact(&mut buf)?;
28 Ok(buf[0])
29}
30
31#[inline]
32pub(crate) fn u32_be<R: Read>(reader: &mut R) -> std::io::Result<u32> {
33 let mut buf = [0; 4];
34 reader.read_exact(&mut buf)?;
35 Ok(u32::from_be_bytes(buf[..].try_into().unwrap()))
36}
37
38fn read_len<R: Read>(reader: &mut R) -> std::io::Result<usize> {
39 let (next, got) = take_sized(reader, 4)?;
40 if got != 4 {
41 Ok(0x10000)
43 } else {
44 let str = String::from_utf8_lossy(&next);
45 let len = usize::from_str_radix(str.as_ref(), 16).unwrap();
46 Ok(len)
47 }
48}
49
50pub fn read_pktline<R: Read>(reader: &mut R) -> std::io::Result<(Vec<u8>, usize)> {
52 let mut len = read_len(reader)?;
53 let data = if len == 0x10000 {
54 len = 0;
55 Vec::new()
56 } else if len >= 4 {
57 let (data, _) = take_sized(reader, len - 4)?;
58 data
59 } else {
60 format!("{:04x}", len).as_bytes().to_vec()
61 };
62 Ok((data, len))
63}
64
65pub fn write_pktline<W: Write>(writer: &mut W, data: &str) -> std::io::Result<()> {
68 writer.write(format!("{:04x}", data.len() + 1 + 4).as_bytes())?;
69 writer.write(data.as_bytes())?;
70 writer.write(b"\n")?;
71 Ok(())
72}
73
74pub fn write_pktline_nolf<W: Write>(writer: &mut W, data: &str) -> std::io::Result<()> {
76 writer.write(format!("{:04x}", data.len() + 4).as_bytes())?;
77 writer.write(data.as_bytes())?;
78 Ok(())
79}
80
81pub(crate) fn write_packet<W: Write>(writer: &mut W, data: u8) -> std::io::Result<()> {
85 writer.write(format!("{:04x}", data).as_bytes())?;
86 Ok(())
87}
88
89#[cfg(test)]
90mod tests {
91 use crate::io::{write_pktline, read_pktline, take_sized, token, u8, u32_be, read_len, write_pktline_nolf, write_packet};
92 use std::io::{Read, Cursor};
93
94 #[test]
95 fn test_take_sized() {
96 let v = [1, 2, 3];
97 let mut c = Cursor::new(v);
98 let (v, got) = take_sized(&mut c, 2).unwrap();
99 assert_eq!(v, vec![1, 2]);
100 assert_eq!(got, 2);
101
102 let (v, got) = take_sized(&mut c, 2).unwrap();
103 assert_eq!(v, vec![3]);
104 assert_eq!(got, 1);
105 }
106
107 #[test]
108 fn test_token() {
109 let t = b"fLaCtest";
110 let mut c = Cursor::new(t);
111 token(&mut c, b"fLaC").expect("fLaC token error");
112 token(&mut c, b"2333").expect_err("token not match");
113 }
114
115 #[test]
116 fn test_u8() {
117 let v = [1, 2, 3];
118 let mut c = Cursor::new(v);
119 assert_eq!(u8(&mut c).unwrap(), 1);
120 assert_eq!(u8(&mut c).unwrap(), 2);
121 assert_eq!(u8(&mut c).unwrap(), 3);
122 u8(&mut c).expect_err("fn should have no byte to read");
123 }
124
125 #[test]
126 fn test_u32_be() {
127 let v = [0xaa, 0xbb, 0xcc, 0xdd];
128 let mut c = Cursor::new(v);
129 assert_eq!(u32_be(&mut c).unwrap(), 0xaabbccdd);
130 }
131
132 #[test]
133 fn test_read_len() {
134 let v = b"00100000";
135 let mut c = Cursor::new(v);
136 assert_eq!(read_len(&mut c).unwrap(), 0x10);
137 assert_eq!(read_len(&mut c).unwrap(), 0);
138 assert_eq!(read_len(&mut c).unwrap(), 0x10000);
139 }
140
141 #[test]
142 fn test_pktline_read() {
143 let data = [
144 0x30, 0x30, 0x31, 0x65, 0x23, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x3d, 0x67, 0x69,
145 0x74, 0x2d, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x2d, 0x70, 0x61, 0x63, 0x6b, 0x0a, 0x30, 0x30,
146 0x30, 0x30, 0x30, 0x30, 0x30, 0x65, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x0a,
147 0x30, 0x30, 0x32, 0x33, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x3d, 0x67, 0x69, 0x74, 0x2f, 0x67, 0x69,
148 0x74, 0x68, 0x75, 0x62, 0x2d, 0x67, 0x31, 0x38, 0x63, 0x33, 0x31, 0x39, 0x39, 0x33, 0x39, 0x34,
149 0x61, 0x63, 0x0a, 0x30, 0x30, 0x30, 0x63, 0x6c, 0x73, 0x2d, 0x72, 0x65, 0x66, 0x73, 0x0a, 0x30,
150 0x30, 0x31, 0x39, 0x66, 0x65, 0x74, 0x63, 0x68, 0x3d, 0x73, 0x68, 0x61, 0x6c, 0x6c, 0x6f, 0x77,
151 0x20, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x0a, 0x30, 0x30, 0x31, 0x32, 0x73, 0x65, 0x72, 0x76,
152 0x65, 0x72, 0x2d, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x30, 0x30, 0x31, 0x37, 0x6f, 0x62,
153 0x6a, 0x65, 0x63, 0x74, 0x2d, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x3d, 0x73, 0x68, 0x61, 0x31,
154 0x0a, 0x30, 0x30, 0x30, 0x30,
155 ];
156 let mut cursor = std::io::Cursor::new(data);
157 let (r, s) = read_pktline(&mut cursor).expect("failed to read");
158 assert_eq!(r, b"# service=git-upload-pack\n");
159 assert_eq!(s, 0x001e);
160
161 let (r, s) = read_pktline(&mut cursor).expect("failed to read");
162 assert_eq!(r, b"0000");
163 assert_eq!(s, 0x0000);
164
165 let (r, s) = read_pktline(&mut cursor).expect("failed to read");
166 assert_eq!(r, b"version 2\n");
167 assert_eq!(s, 0x000e);
168
169 let (r, s) = read_pktline(&mut cursor).expect("failed to read");
170 assert_eq!(r, b"agent=git/github-g18c3199394ac\n");
171 assert_eq!(s, 0x0023);
172
173 let (r, s) = read_pktline(&mut cursor).expect("failed to read");
174 assert_eq!(r, b"ls-refs\n");
175 assert_eq!(s, 0x000c);
176
177 let (r, s) = read_pktline(&mut cursor).expect("failed to read");
178 assert_eq!(r, b"fetch=shallow filter\n");
179 assert_eq!(s, 0x0019);
180
181 let (r, s) = read_pktline(&mut cursor).expect("failed to read");
182 assert_eq!(r, b"server-option\n");
183 assert_eq!(s, 0x0012);
184
185 let (r, s) = read_pktline(&mut cursor).expect("failed to read");
186 assert_eq!(r, b"object-format=sha1\n");
187 assert_eq!(s, 0x0017);
188
189 let (r, s) = read_pktline(&mut cursor).expect("failed to read");
190 assert_eq!(r, b"0000");
191 assert_eq!(s, 0x0000);
192
193 let mut r = [0; 0];
194 let r = cursor.read(&mut r).expect("failed to read");
195 assert_eq!(r, 0);
196 }
197
198 #[test]
199 fn test_pktline_write() {
200 let out = Vec::with_capacity(100);
201 let mut cursor = std::io::Cursor::new(out);
202 write_pktline(&mut cursor, "test").expect("failed to write pktline");
203 write_pktline_nolf(&mut cursor, "another_test").expect("failed to write pktline");
204 write_packet(&mut cursor, 0).expect("failed to write packet");
205 assert_eq!(cursor.into_inner(), b"0009test\n0010another_test0000")
206 }
207}