From 05731070a5cfb403bb82d8d8baa360ffe8cc45a9 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 16 Nov 2022 08:43:44 +0100 Subject: [PATCH 1/3] Add simple push request/response as obtained through HTTP proxying The payload is exactly the same as through the git daemon, or other means, which makes it easiest to intercept via `git -c http.proxy=localhost:9090 push` and a proxy running at localhost:9090 (like Proxyman on macOS). --- git-transport/tests/fixtures/v1/push.request | Bin 0 -> 1395 bytes git-transport/tests/fixtures/v1/push.response | 8 ++++++++ 2 files changed, 8 insertions(+) create mode 100644 git-transport/tests/fixtures/v1/push.request create mode 100644 git-transport/tests/fixtures/v1/push.response diff --git a/git-transport/tests/fixtures/v1/push.request b/git-transport/tests/fixtures/v1/push.request new file mode 100644 index 0000000000000000000000000000000000000000..20808368a49141542388c878e12e8bfdd3776b82 GIT binary patch literal 1395 zcmV-(1&sPIFk)giV=y^lVK8GfV>325FkxmhHaTKsVKioAIAt?qH8^B5W@BSyV>dP+ zGcq#-21&Zc)NR04N^fO=z79v)F3@cDY zhA>Y-gkix@*_ZJMijpK}kY@G!VS(Utu3-MH9@l%+-k0*Q;2yj|zHnbSbrRdLdp~2@o;sP3L)M zPw9oW&_cV2$wFQY@W^gX9Bkaix=p^DtQ4aa!I*og+v_O3^3X||t|fqE-}ENc1m7c9 z^R0?o*m}_=tM6o4r~0$JFlUN2tPfj5?r|7~o{Af7r7YQZ6)i0i0-UD&VF$V0mwM~j z{z$3rsq_^ImdoVNhnqCsqsctbloM(Pa=cEXY?0C%SBP|dyXgt=7>|x??uN;QBK_&G zW#D6L#%*9HVHVmt%yOf7b1Y@m>M5JBu^AycFpq^yV`41=BDCg!I%G2}EWaq(>?3ryO4LDs3a|P)j_SwgmvDM$QKHZn4({_t(O3^Qh z%!zi>_m!|TEmJ-pro8s0_&Wi<-_*n*esxB7wf|}ikr!jp=S83GU>S2b7sNkI(_YX2 z0h46a#;Dq3FJ<*JY*fMZ3(r|a*m#@)9{}M0nFN^xklPekuoA7ZrFV7G0s8Y=&tuO0 ziVr8T?p= zDXiVuo&9T!7M6lwCD`oj?0}$xq)1^S-axkqp1@Yw1E^qQl~bg$5l^7+0PlOfIglg%4ir5_@qJs zmkmM@<`Rt{2W?6Sh^QkK_I29rwEMS<`5z5YSO-`%kX%8U;D-fO1jVRt@O}w=a Bm+Alj literal 0 HcmV?d00001 diff --git a/git-transport/tests/fixtures/v1/push.response b/git-transport/tests/fixtures/v1/push.response new file mode 100644 index 00000000000..3a156d3f84e --- /dev/null +++ b/git-transport/tests/fixtures/v1/push.response @@ -0,0 +1,8 @@ +0022Resolving deltas: 0% (0/2) 0022Resolving deltas: 50% (1/2) 0022Resolving deltas: 100% (2/2) 0043Resolving deltas: 100% (2/2), completed with 2 local objects. +0013000eunpack ok +001c0017ok refs/heads/main +00b5 +GitHub found 1 vulnerability on the-lean-crate/criner's default branch (1 high). To find out more, visit: + https://github.com/the-lean-crate/criner/security/dependabot/1 + +000900000000 \ No newline at end of file From 42acc88bbc63850c0d38db70bc46b1058875e2a0 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 16 Nov 2022 09:04:28 +0100 Subject: [PATCH 2/3] feat: `client::RequestWriter::into_parts()` to obtain a bare write handled along with a buf reader with packetline capabilties. That way it's possible to perform interactions akin to a V1 puash. --- DEVELOPMENT.md | 2 ++ git-transport/src/client/async_io/request.rs | 8 +++++ .../src/client/blocking_io/request.rs | 8 +++++ git-transport/tests/client/git.rs | 30 +++++++++++++++++++ 4 files changed, 48 insertions(+) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index d3fbb7622ed..dd7801ec3d5 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -213,6 +213,8 @@ This also means that CI may fail despite everything being alright locally, and t ## How to update fixtures +### For object data + Fixtures are created by using a line like this which produces a line we ignore via `tail +1` followed by the un-prettified object payload trailed by a newline. ```sh diff --git a/git-transport/src/client/async_io/request.rs b/git-transport/src/client/async_io/request.rs index 9328bed7452..f2380f1cdfd 100644 --- a/git-transport/src/client/async_io/request.rs +++ b/git-transport/src/client/async_io/request.rs @@ -84,4 +84,12 @@ impl<'a> RequestWriter<'a> { self.write_message(self.on_into_read).await?; Ok(self.reader) } + + /// Dissolve this instance into its write and read handles without any side-effect. + /// + /// This is useful to take more over when to write with packetline or not, which is why the writer doesn't write + /// packetlines but verbatim. + pub fn into_parts(self) -> (Box, Box) { + (self.writer.into_inner(), self.reader) + } } diff --git a/git-transport/src/client/blocking_io/request.rs b/git-transport/src/client/blocking_io/request.rs index 75339e789b0..b40ae0feeed 100644 --- a/git-transport/src/client/blocking_io/request.rs +++ b/git-transport/src/client/blocking_io/request.rs @@ -60,4 +60,12 @@ impl<'a> RequestWriter<'a> { self.write_message(self.on_into_read)?; Ok(self.reader) } + + /// Dissolve this instance into its write and read handles without any side-effect. + /// + /// This is useful to take more over when to write with packetline or not, which is why the writer doesn't write + /// packetlines but verbatim. + pub fn into_parts(self) -> (Box, Box) { + (self.writer.into_inner(), self.reader) + } } diff --git a/git-transport/tests/client/git.rs b/git-transport/tests/client/git.rs index 10e4ebbd005..35ddbfa9227 100644 --- a/git-transport/tests/client/git.rs +++ b/git-transport/tests/client/git.rs @@ -145,6 +145,36 @@ async fn handshake_v1_and_request() -> crate::Result { Ok(()) } +#[maybe_async::test(feature = "blocking-client", async(feature = "async-client", async_std::test))] +async fn push_v1_simulated() -> crate::Result { + let mut out = Vec::new(); + let server_response = fixture_bytes("v1/push.response"); + let mut c = git::Connection::new( + server_response.as_slice(), + &mut out, + Protocol::V1, + "/foo.git", + Some(("example.org", None)), + git::ConnectMode::Process, + ); + + let mut writer = c.request(client::WriteMode::Binary, client::MessageKind::Flush)?; + let expected = fixture_bytes("v1/push.request"); + writer.write_all(b"7c09ba0c4c3680af369bda4fc8e3c58d3fccdc76 32690d87d3943c7c0dda81246d0cde344ca7e633 refs/heads/main\0 report-status-v2 side-band-64k object-format=sha1 agent=git/2.37.1.(Apple.Git-137.1)").await?; + writer.write_message(client::MessageKind::Flush).await?; + { + let (mut write, _read) = writer.into_parts(); + write.write_all(&expected[191..]).await?; + } + + assert_eq!( + out.as_slice().as_bstr(), + expected.as_bstr(), + "we are able to reproduce a typical push request by hand with a little bit of juggling" + ); + Ok(()) +} + #[maybe_async::test(feature = "blocking-client", async(feature = "async-client", async_std::test))] async fn handshake_v1_process_mode() -> crate::Result { let mut out = Vec::new(); From 4d84a208e4d0a8bf3dbcfa6912b92ec1bdf4ec05 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 16 Nov 2022 09:36:35 +0100 Subject: [PATCH 3/3] Add test to see if we can correctly read the server response. And we can, even though the data lines are double-encoded. --- git-transport/tests/client/git.rs | 36 ++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/git-transport/tests/client/git.rs b/git-transport/tests/client/git.rs index 35ddbfa9227..b8d2d10e0b0 100644 --- a/git-transport/tests/client/git.rs +++ b/git-transport/tests/client/git.rs @@ -163,8 +163,42 @@ async fn push_v1_simulated() -> crate::Result { writer.write_all(b"7c09ba0c4c3680af369bda4fc8e3c58d3fccdc76 32690d87d3943c7c0dda81246d0cde344ca7e633 refs/heads/main\0 report-status-v2 side-band-64k object-format=sha1 agent=git/2.37.1.(Apple.Git-137.1)").await?; writer.write_message(client::MessageKind::Flush).await?; { - let (mut write, _read) = writer.into_parts(); + let (mut write, mut read) = writer.into_parts(); write.write_all(&expected[191..]).await?; + + let messages = Arc::new(Mutex::new(Vec::::new())); + read.set_progress_handler(Some(Box::new({ + let sb = messages.clone(); + move |is_err, data| { + assert!(!is_err); + sb.deref() + .lock() + .expect("no panic in other threads") + .push(std::str::from_utf8(data).expect("valid utf8").to_owned()) + } + }))); + let mut lines = read.lines(); + let mut info = Vec::new(); + #[allow(clippy::while_let_on_iterator)] // needed in async version of test + while let Some(line) = lines.next().await { + info.push(line?) + } + assert_eq!( + info, + &["000eunpack ok", "0017ok refs/heads/main", "0000"], + "this seems to be a packetline encoding within a packetline encoding! Including a flush package. Strange, but it's the real deal." + ); + let expected_progress = &["Resolving deltas: 0% (0/2)\r", + "Resolving deltas: 50% (1/2)\r", + "Resolving deltas: 100% (2/2)\r", + "Resolving deltas: 100% (2/2), completed with 2 local objects.", + "\nGitHub found 1 vulnerability on the-lean-crate/criner's default branch (1 high). To find out more, visit:\n https://github.com/the-lean-crate/criner/security/dependabot/1\n" + ]; + assert_eq!( + messages.lock().expect("no poison").as_slice(), + expected_progress, + "these look like they are created once the whole pack has been received" + ); } assert_eq!(