Skip to content

Commit 3f4fd90

Browse files
committed
Encode and decode errors
1 parent 1f58568 commit 3f4fd90

File tree

6 files changed

+46
-9
lines changed

6 files changed

+46
-9
lines changed

README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,11 @@ Please see _'Development Status'_ for a listing of all crates and their capabili
9494
some sort of reactor which feeds the client/server respectively with deserialized lines. This enables us to
9595
start out with a sync implementation, and later add an async one that reuses all the protocol code.
9696
* [ ] [PKT-Line](https://github.com/git/git/blob/master/Documentation/technical/protocol-common.txt#L52:L52)
97-
* [ ] encode
98-
* [ ] decode (zero-copy)
99-
* [ ] [error line](https://github.com/git/git/blob/master/Documentation/technical/pack-protocol.txt#L28:L28)
97+
* [x] encode
98+
* [x] decode (zero-copy)
99+
* [x] [error line](https://github.com/git/git/blob/master/Documentation/technical/pack-protocol.txt#L28:L28)
100100
* [ ] [V2 additions](https://github.com/git/git/blob/master/Documentation/technical/protocol-v2.txt#L35:L36)
101-
* [ ]
101+
* [ ] [side-band mode](https://github.com/git/git/blob/master/Documentation/technical/pack-protocol.txt#L467:L467)
102102
* [ ] `Iterator` for multi-plexed pack lines from `Read`
103103
* [ ] parse and serialize [capabilities](https://github.com/git/git/blob/master/Documentation/technical/protocol-capabilities.txt#L1:L1)
104104
* [ ] **Version 1**
@@ -111,7 +111,6 @@ Please see _'Development Status'_ for a listing of all crates and their capabili
111111
* [ ] multi-ack
112112
* [ ] multi-ack detailed
113113
* [ ] [server-response (pack)](https://github.com/git/git/blob/master/Documentation/technical/pack-protocol.txt#L404:L404)
114-
* [ ] [side-band mode](https://github.com/git/git/blob/master/Documentation/technical/pack-protocol.txt#L467:L467)
115114
* [ ] push
116115
* [ ] [Version 2](https://github.com/git/git/blob/master/Documentation/technical/protocol-v2.txt)
117116

git-protocol/src/packet_line/encode.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::packet_line::{FLUSH_LINE, MAX_DATA_LEN};
1+
use crate::packet_line::{ERR_PREFIX, FLUSH_LINE, MAX_DATA_LEN};
22
use quick_error::quick_error;
33
use std::io;
44

@@ -18,10 +18,23 @@ quick_error! {
1818
}
1919
}
2020
}
21+
2122
pub fn flush_to_write(mut out: impl io::Write) -> io::Result<usize> {
2223
out.write_all(FLUSH_LINE).map(|_| 4)
2324
}
2425

26+
pub fn error_to_write(data: &[u8], out: impl io::Write) -> Result<usize, Error> {
27+
let data_with_prefix_end = data.len() + ERR_PREFIX.len();
28+
if data_with_prefix_end > MAX_DATA_LEN {
29+
return Err(Error::DataLengthLimitExceeded(data.len() - ERR_PREFIX.len()));
30+
}
31+
// This is a big buffer, but it's only used on error, so the program is on the way out
32+
let mut buf = [0u8; MAX_DATA_LEN];
33+
buf[..ERR_PREFIX.len()].copy_from_slice(ERR_PREFIX);
34+
buf[ERR_PREFIX.len()..data_with_prefix_end].copy_from_slice(data);
35+
data_to_write(&buf[..data_with_prefix_end], out)
36+
}
37+
2538
pub fn data_to_write(data: &[u8], mut out: impl io::Write) -> Result<usize, Error> {
2639
if data.len() > MAX_DATA_LEN {
2740
return Err(Error::DataLengthLimitExceeded(data.len()));

git-protocol/src/packet_line/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ impl<'a> Borrowed<'a> {
3131
pub fn as_bstr(&self) -> &BStr {
3232
self.as_slice().into()
3333
}
34+
pub fn to_error(&self) -> Error {
35+
Error(self.as_slice())
36+
}
37+
}
38+
39+
pub struct Error<'a>(&'a [u8]);
40+
41+
impl<'a> Error<'a> {
42+
pub fn to_write(&self, out: impl io::Write) -> Result<usize, encode::Error> {
43+
encode::error_to_write(self.0, out)
44+
}
3445
}
3546

3647
pub mod decode;

git-protocol/tests/packet_line/decode.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@ mod streaming {
7474
Ok(())
7575
}
7676

77+
#[test]
78+
fn roundtrip_error_line() -> crate::Result {
79+
let mut out = Vec::new();
80+
PacketLine::Data(b"the error").to_error().to_write(&mut out)?;
81+
assert_err_display(streaming(&out), "the error");
82+
Ok(())
83+
}
84+
7785
mod incomplete {
7886
use git_protocol::packet_line::decode::{self, streaming, Stream};
7987

git-protocol/tests/packet_line/encode.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
mod data_to_write {
22
use crate::packet_line::assert_err_display;
33
use bstr::ByteSlice;
4-
use git_protocol::packet_line::encode::{data_to_write, flush_to_write};
4+
use git_protocol::packet_line::encode::{data_to_write, error_to_write, flush_to_write};
55
use std::io;
66

77
fn vec_sized(size: usize) -> Vec<u8> {
@@ -30,6 +30,14 @@ mod data_to_write {
3030
Ok(())
3131
}
3232

33+
#[test]
34+
fn successful_write_of_error_line() -> crate::Result {
35+
let mut out = Vec::new();
36+
assert_eq!(error_to_write(b"hello error", &mut out)?, 19);
37+
assert_eq!(out.as_bstr(), b"0013ERR hello error".as_bstr());
38+
Ok(())
39+
}
40+
3341
#[test]
3442
fn error_if_data_exceeds_limit() {
3543
assert_err_display(

tasks.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
* to be used to obtain more real-world samples of typical git interactions for use in the test-suite
77
* **git-protocol**
88
* [ ] pkt-lines support
9-
* [x] encoding including flush lines
10-
* [ ] decoding
119
* [ ] basic V1 parsing to understand data frames to allow placing them into individual files
1210
* **a way to intercept git-http communication**
1311
* Maybe with a custom proxy as well, can't hurt to try APIs in real-world programs

0 commit comments

Comments
 (0)