…it's much easier for callers to get a write handle to write into from their own code instead of passing a Read that captures everything they care about. This just requires them to signal that they are done writing by dropping the writer. Fair enough, that's all done in our custom transport code who knows the system. Thinking about it, it will probably yield that handle to code in git-protocol, which then also needs to know about that.
Unified · Split
| @@ -3,7 +3,6 @@ use curl::easy::Easy2; · 2 unmodified lines | |||
| 3 | use git_features::pipe; | 3 | use git_features::pipe; |
| 4 | use std::{ | 4 | use std::{ |
| 5 | io, | 5 | io, |
| 6 | io::Read, | ||
| 7 | sync::mpsc::{sync_channel, Receiver, SyncSender, TrySendError}, | 6 | sync::mpsc::{sync_channel, Receiver, SyncSender, TrySendError}, |
| 8 | thread, | 7 | thread, |
| 9 | }; | 8 | }; |
| @@ -37,8 +36,7 @@ impl Curl { · 27 unmodified lines | |||
| 37 | &mut self, | 36 | &mut self, |
| 38 | url: &str, | 37 | url: &str, |
| 39 | headers: impl IntoIterator<Item = impl AsRef<str>>, | 38 | headers: impl IntoIterator<Item = impl AsRef<str>>, |
| 40 | post_body: Option<impl Read>, | 39 | ) -> Result<http::PostResponse<pipe::Reader, pipe::Reader, pipe::Writer>, http::Error> { |
| 41 | ) -> Result<(pipe::Reader, pipe::Reader), http::Error> { | ||
| 42 | let mut list = curl::easy::List::new(); | 40 | let mut list = curl::easy::List::new(); |
| 43 | for header in headers { | 41 | for header in headers { |
| 44 | list.append(header.as_ref())?; | 42 | list.append(header.as_ref())?; |
| @@ -56,16 +54,16 @@ impl Curl { · 11 unmodified lines | |||
| 56 | let Response { | 54 | let Response { |
| 57 | headers, | 55 | headers, |
| 58 | body, | 56 | body, |
| 59 | mut upload_body, | 57 | upload_body, |
| 60 | } = match self.res.recv() { | 58 | } = match self.res.recv() { |
| 61 | Ok(res) => res, | 59 | Ok(res) => res, |
| 62 | Err(_) => return Err(self.restore_thread_after_failure()), | 60 | Err(_) => return Err(self.restore_thread_after_failure()), |
| 63 | }; | 61 | }; |
| 64 | if let Some(mut body) = post_body { | 62 | Ok(http::PostResponse { |
| 65 | io::copy(&mut body, &mut upload_body)?; | 63 | post_body: upload_body, |
| 66 | } | 64 | headers, |
| 67 | 65 | body, | |
| 68 | Ok((headers, body)) | 66 | }) |
| 69 | } | 67 | } |
| 70 | 68 | ||
| 71 | fn restore_thread_after_failure(&mut self) -> http::Error { | 69 | fn restore_thread_after_failure(&mut self) -> http::Error { |
| @@ -170,21 +168,21 @@ impl From<curl::Error> for http::Error { · 98 unmodified lines | |||
| 170 | impl crate::client::http::Http for Curl { | 168 | impl crate::client::http::Http for Curl { |
| 171 | type Headers = pipe::Reader; | 169 | type Headers = pipe::Reader; |
| 172 | type ResponseBody = pipe::Reader; | 170 | type ResponseBody = pipe::Reader; |
| 171 | type PostBody = pipe::Writer; | ||
| 173 | 172 | ||
| 174 | fn get( | 173 | fn get( |
| 175 | &mut self, | 174 | &mut self, |
| 176 | url: &str, | 175 | url: &str, |
| 177 | headers: impl IntoIterator<Item = impl AsRef<str>>, | 176 | headers: impl IntoIterator<Item = impl AsRef<str>>, |
| 178 | ) -> Result<(Self::Headers, Self::ResponseBody), http::Error> { | 177 | ) -> Result<http::GetResponse<Self::Headers, Self::ResponseBody>, http::Error> { |
| 179 | self.make_request(url, headers, None::<std::fs::File>) | 178 | self.make_request(url, headers).map(Into::into) |
| 180 | } | 179 | } |
| 181 | 180 | ||
| 182 | fn post( | 181 | fn post( |
| 183 | &mut self, | 182 | &mut self, |
| 184 | _url: &str, | 183 | url: &str, |
| 185 | _headers: impl IntoIterator<Item = impl AsRef<str>>, | 184 | headers: impl IntoIterator<Item = impl AsRef<str>>, |
| 186 | _body: impl Read, | 185 | ) -> Result<http::PostResponse<Self::Headers, Self::ResponseBody, Self::PostBody>, http::Error> { |
| 187 | ) -> Result<(Self::Headers, Self::ResponseBody), http::Error> { | 186 | self.make_request(url, headers) |
| 188 | unimplemented!() | ||
| 189 | } | 187 | } |
| 190 | } | 188 | } |
| @@ -20,21 +20,42 @@ quick_error! { · 19 unmodified lines | |||
| 20 | #[cfg(feature = "http-client-curl")] | 20 | #[cfg(feature = "http-client-curl")] |
| 21 | pub(crate) mod curl; | 21 | pub(crate) mod curl; |
| 22 | 22 | ||
| 23 | pub struct GetResponse<H, B> { | ||
| 24 | headers: H, | ||
| 25 | body: B, | ||
| 26 | } | ||
| 27 | |||
| 28 | pub struct PostResponse<H, B, PB> { | ||
| 29 | /// **Note**: Implementations should drop the handle to avoid deadlocks | ||
| 30 | post_body: PB, | ||
| 31 | headers: H, | ||
| 32 | body: B, | ||
| 33 | } | ||
| 34 | |||
| 35 | impl<A, B, C> From<PostResponse<A, B, C>> for GetResponse<A, B> { | ||
| 36 | fn from(v: PostResponse<A, B, C>) -> Self { | ||
| 37 | GetResponse { | ||
| 38 | headers: v.headers, | ||
| 39 | body: v.body, | ||
| 40 | } | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 23 | trait Http { | 44 | trait Http { |
| 24 | type Headers: io::BufRead; | 45 | type Headers: io::BufRead; |
| 25 | type ResponseBody: io::BufRead; | 46 | type ResponseBody: io::BufRead; |
| 47 | type PostBody: io::Write; | ||
| 26 | 48 | ||
| 27 | fn get( | 49 | fn get( |
| 28 | &mut self, | 50 | &mut self, |
| 29 | url: &str, | 51 | url: &str, |
| 30 | headers: impl IntoIterator<Item = impl AsRef<str>>, | 52 | headers: impl IntoIterator<Item = impl AsRef<str>>, |
| 31 | ) -> Result<(Self::Headers, Self::ResponseBody), Error>; | 53 | ) -> Result<GetResponse<Self::Headers, Self::ResponseBody>, Error>; |
| 32 | fn post( | 54 | fn post( |
| 33 | &mut self, | 55 | &mut self, |
| 34 | url: &str, | 56 | url: &str, |
| 35 | headers: impl IntoIterator<Item = impl AsRef<str>>, | 57 | headers: impl IntoIterator<Item = impl AsRef<str>>, |
| 36 | body: impl io::Read, | 58 | ) -> Result<PostResponse<Self::Headers, Self::ResponseBody, Self::PostBody>, Error>; |
| 37 | ) -> Result<(Self::Headers, Self::ResponseBody), Error>; | ||
| 38 | } | 59 | } |
| 39 | 60 | ||
| 40 | #[cfg(feature = "http-client-curl")] | 61 | #[cfg(feature = "http-client-curl")] |