Unified · Split
| @@ -1,12 +1,17 @@ | ||
| 1 | 1 | use crate::client::http; |
| 2 | 2 | use curl::easy::Easy2; |
| 3 | 3 | 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 | +}; | |
| 5 | 9 | |
| 6 | 10 | #[derive(Default)] |
| 7 | 11 | struct Handler { |
| 8 | 12 | send_header: Option<pipe::Writer>, |
| 9 | 13 | send_data: Option<pipe::Writer>, |
| 14 | + receive_body: Option<pipe::Reader>, | |
| 10 | 15 | } |
| 11 | 16 | |
| 12 | 17 | impl curl::easy::Handler for Handler {} |
| @@ -15,6 +20,80 @@ pub struct Curl { · 2 unmodified lines | ||
| 15 | 20 | handle: Easy2<Handler>, |
| 16 | 21 | } |
| 17 | 22 | |
| 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 | + | |
| 18 | 97 | impl Curl { |
| 19 | 98 | pub fn new() -> Self { |
| 20 | 99 | Curl { |