History

[clone] first sketch of remote-curl, a way to transform curl into Read/Write

Sebastian Thiel committed 6 years ago

Commit 22b4b391 parent afe29961 file · +80 −1Browse files

Unified · Split

git-transport/src/client/http/curl.rs+80−1
@@ -1,12 +1,17 @@
11 use crate::client::http;
22 use curl::easy::Easy2;
33 use git_features::pipe;
4−use std::io::Read;
4+use std::{
5+ io,
6+ io::Read,
7+ sync::mpsc::{sync_channel, Receiver, SyncSender, TrySendError},
8+};
59
610 #[derive(Default)]
711 struct Handler {
812 send_header: Option<pipe::Writer>,
913 send_data: Option<pipe::Writer>,
14+ receive_body: Option<pipe::Reader>,
1015 }
1116
1217 impl curl::easy::Handler for Handler {}
@@ -15,6 +20,80 @@ pub struct Curl { · 2 unmodified lines
1520 handle: Easy2<Handler>,
1621 }
1722
23+struct Request {
24+ url: String,
25+ headers: curl::easy::List,
26+}
27+
28+struct Response {
29+ headers: pipe::Reader,
30+ body: pipe::Reader,
31+ upload_body: pipe::Writer,
32+}
33+
34+fn new_remote_curl() -> (
35+ std::thread::JoinHandle<Result<(), curl::Error>>,
36+ SyncSender<Request>,
37+ Receiver<Response>,
38+) {
39+ let (req_send, req_recv) = sync_channel(0);
40+ let (res_send, res_recv) = sync_channel(0);
41+ let handle = std::thread::spawn(move || -> Result<(), curl::Error> {
42+ let mut handle = Easy2::new(Handler::default());
43+ for Request { url, headers } in req_recv {
44+ handle.url(&url)?;
45+ handle.http_headers(headers)?;
46+
47+ let (receive_data, receive_headers, send_body) = {
48+ let handler = handle.get_mut();
49+ let (send, receive_data) = pipe::unidirectional(1);
50+ handler.send_data = Some(send);
51+ let (send, receive_headers) = pipe::unidirectional(1);
52+ handler.send_header = Some(send);
53+ let (send_body, receive_body) = pipe::unidirectional(None);
54+ handler.receive_body = Some(receive_body);
55+ (receive_data, receive_headers, send_body)
56+ };
57+
58+ if let Err(err) = handle.perform() {
59+ let handler = handle.get_mut();
60+ let err = Err(io::Error::new(io::ErrorKind::Other, err));
61+ handler.receive_body.take();
62+ if let Some(header) = handler.send_header.take() {
63+ match header.channel.try_send(err) {
64+ Ok(_) => {
65+ handler.send_data.take();
66+ }
67+ Err(TrySendError::Disconnected(err)) | Err(TrySendError::Full(err)) => {
68+ if let Some(body) = handler.send_data.take() {
69+ body.channel.try_send(err).ok();
70+ }
71+ }
72+ }
73+ }
74+ } else {
75+ let handler = handle.get_mut();
76+ handler.receive_body.take();
77+ handler.send_header.take();
78+ handler.send_data.take();
79+ }
80+
81+ if res_send
82+ .send(Response {
83+ headers: receive_headers,
84+ body: receive_data,
85+ upload_body: send_body,
86+ })
87+ .is_err()
88+ {
89+ break;
90+ }
91+ }
92+ Ok(())
93+ });
94+ (handle, req_send, res_recv)
95+}
96+
1897 impl Curl {
1998 pub fn new() -> Self {
2099 Curl {