| @@ -5,6 +5,7 @@ use std::{ · 4 unmodified lines |
| 5 | 5 | io, |
| 6 | 6 | io::Read, |
| 7 | 7 | sync::mpsc::{sync_channel, Receiver, SyncSender, TrySendError}, |
| 8 | + thread, |
| 8 | 9 | }; |
| 9 | 10 | |
| 10 | 11 | #[derive(Default)] |
| @@ -17,7 +18,35 @@ struct Handler { · 6 unmodified lines |
| 17 | 18 | impl curl::easy::Handler for Handler {} |
| 18 | 19 | |
| 19 | 20 | pub struct Curl { |
| 20 | | − handle: Easy2<Handler>, |
| 21 | + req: SyncSender<Request>, |
| 22 | + res: Receiver<Response>, |
| 23 | + handle: Option<thread::JoinHandle<Result<(), curl::Error>>>, |
| 24 | +} |
| 25 | + |
| 26 | +impl Curl { |
| 27 | + pub fn new() -> Self { |
| 28 | + let (handle, req, res) = new_remote_curl(); |
| 29 | + Curl { |
| 30 | + handle: Some(handle), |
| 31 | + req, |
| 32 | + res, |
| 33 | + } |
| 34 | + } |
| 35 | + |
| 36 | + fn restore_thread_after_failure(&mut self) -> http::Error { |
| 37 | + let err_that_brought_thread_down = self |
| 38 | + .handle |
| 39 | + .take() |
| 40 | + .expect("thread present") |
| 41 | + .join() |
| 42 | + .expect("handler thread should never panic") |
| 43 | + .expect_err("something should have gone wrong with curl"); |
| 44 | + let (handle, req, res) = new_remote_curl(); |
| 45 | + self.handle = Some(handle); |
| 46 | + self.req = req; |
| 47 | + self.res = res; |
| 48 | + return err_that_brought_thread_down.into(); |
| 49 | + } |
| 21 | 50 | } |
| 22 | 51 | |
| 23 | 52 | struct Request { |
| @@ -28,11 +57,11 @@ struct Request { · 4 unmodified lines |
| 28 | 57 | struct Response { |
| 29 | 58 | headers: pipe::Reader, |
| 30 | 59 | body: pipe::Reader, |
| 31 | | − upload_body: pipe::Writer, |
| 60 | + _upload_body: pipe::Writer, |
| 32 | 61 | } |
| 33 | 62 | |
| 34 | 63 | fn new_remote_curl() -> ( |
| 35 | | − std::thread::JoinHandle<Result<(), curl::Error>>, |
| 64 | + thread::JoinHandle<Result<(), curl::Error>>, |
| 36 | 65 | SyncSender<Request>, |
| 37 | 66 | Receiver<Response>, |
| 38 | 67 | ) { |
| @@ -85,7 +114,7 @@ fn new_remote_curl() -> ( · 46 unmodified lines |
| 85 | 114 | .send(Response { |
| 86 | 115 | headers: receive_headers, |
| 87 | 116 | body: receive_data, |
| 88 | | − upload_body: send_body, |
| 117 | + _upload_body: send_body, |
| 89 | 118 | }) |
| 90 | 119 | .is_err() |
| 91 | 120 | { |
| @@ -97,14 +126,6 @@ fn new_remote_curl() -> ( · 5 unmodified lines |
| 97 | 126 | (handle, req_send, res_recv) |
| 98 | 127 | } |
| 99 | 128 | |
| 100 | | −impl Curl { |
| 101 | | − pub fn new() -> Self { |
| 102 | | − Curl { |
| 103 | | − handle: Easy2::new(Handler::default()), |
| 104 | | − } |
| 105 | | − } |
| 106 | | −} |
| 107 | | − |
| 108 | 129 | impl From<curl::Error> for http::Error { |
| 109 | 130 | fn from(err: curl::Error) -> Self { |
| 110 | 131 | http::Error::Detail(err.to_string()) |
| @@ -120,19 +141,30 @@ impl crate::client::http::Http for Curl { · 9 unmodified lines |
| 120 | 141 | url: &str, |
| 121 | 142 | headers: impl IntoIterator<Item = impl AsRef<str>>, |
| 122 | 143 | ) -> Result<(Self::Headers, Self::ResponseBody), http::Error> { |
| 123 | | − self.handle.url(url)?; |
| 124 | 144 | let mut list = curl::easy::List::new(); |
| 125 | 145 | for header in headers { |
| 126 | 146 | list.append(header.as_ref())?; |
| 127 | 147 | } |
| 128 | | − self.handle.http_headers(list)?; |
| 129 | | − |
| 130 | | − let (send, receive_data) = pipe::unidirectional(1); |
| 131 | | − self.handle.get_mut().send_data = Some(send); |
| 132 | | − let (send, receive_headers) = pipe::unidirectional(1); |
| 133 | | − self.handle.get_mut().send_header = Some(send); |
| 134 | | − |
| 135 | | − Ok((receive_headers, receive_data)) |
| 148 | + if self |
| 149 | + .req |
| 150 | + .send(Request { |
| 151 | + url: url.to_owned(), |
| 152 | + headers: list, |
| 153 | + }) |
| 154 | + .is_err() |
| 155 | + { |
| 156 | + return Err(self.restore_thread_after_failure()); |
| 157 | + } |
| 158 | + let Response { |
| 159 | + headers, |
| 160 | + body, |
| 161 | + _upload_body: _, |
| 162 | + } = match self.res.recv() { |
| 163 | + Ok(res) => res, |
| 164 | + Err(_) => return Err(self.restore_thread_after_failure()), |
| 165 | + }; |
| 166 | + |
| 167 | + Ok((headers, body)) |
| 136 | 168 | } |
| 137 | 169 | |
| 138 | 170 | fn post( |