| @@ -5,6 +5,7 @@ use std::{ · 4 unmodified lines |
| 5 | io, | 5 | io, |
| 6 | io::Read, | 6 | io::Read, |
| 7 | sync::mpsc::{sync_channel, Receiver, SyncSender, TrySendError}, | 7 | sync::mpsc::{sync_channel, Receiver, SyncSender, TrySendError}, |
| | 8 | thread, |
| 8 | }; | 9 | }; |
| 9 | | 10 | |
| 10 | #[derive(Default)] | 11 | #[derive(Default)] |
| @@ -17,7 +18,35 @@ struct Handler { · 6 unmodified lines |
| 17 | impl curl::easy::Handler for Handler {} | 18 | impl curl::easy::Handler for Handler {} |
| 18 | | 19 | |
| 19 | pub struct Curl { | 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 | struct Request { | 52 | struct Request { |
| @@ -28,11 +57,11 @@ struct Request { · 4 unmodified lines |
| 28 | struct Response { | 57 | struct Response { |
| 29 | headers: pipe::Reader, | 58 | headers: pipe::Reader, |
| 30 | body: pipe::Reader, | 59 | body: pipe::Reader, |
| 31 | upload_body: pipe::Writer, | 60 | _upload_body: pipe::Writer, |
| 32 | } | 61 | } |
| 33 | | 62 | |
| 34 | fn new_remote_curl() -> ( | 63 | fn new_remote_curl() -> ( |
| 35 | std::thread::JoinHandle<Result<(), curl::Error>>, | 64 | thread::JoinHandle<Result<(), curl::Error>>, |
| 36 | SyncSender<Request>, | 65 | SyncSender<Request>, |
| 37 | Receiver<Response>, | 66 | Receiver<Response>, |
| 38 | ) { | 67 | ) { |
| @@ -85,7 +114,7 @@ fn new_remote_curl() -> ( · 46 unmodified lines |
| 85 | .send(Response { | 114 | .send(Response { |
| 86 | headers: receive_headers, | 115 | headers: receive_headers, |
| 87 | body: receive_data, | 116 | body: receive_data, |
| 88 | upload_body: send_body, | 117 | _upload_body: send_body, |
| 89 | }) | 118 | }) |
| 90 | .is_err() | 119 | .is_err() |
| 91 | { | 120 | { |
| @@ -97,14 +126,6 @@ fn new_remote_curl() -> ( · 5 unmodified lines |
| 97 | (handle, req_send, res_recv) | 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 | impl From<curl::Error> for http::Error { | 129 | impl From<curl::Error> for http::Error { |
| 109 | fn from(err: curl::Error) -> Self { | 130 | fn from(err: curl::Error) -> Self { |
| 110 | http::Error::Detail(err.to_string()) | 131 | http::Error::Detail(err.to_string()) |
| @@ -120,19 +141,30 @@ impl crate::client::http::Http for Curl { · 9 unmodified lines |
| 120 | url: &str, | 141 | url: &str, |
| 121 | headers: impl IntoIterator<Item = impl AsRef<str>>, | 142 | headers: impl IntoIterator<Item = impl AsRef<str>>, |
| 122 | ) -> Result<(Self::Headers, Self::ResponseBody), http::Error> { | 143 | ) -> Result<(Self::Headers, Self::ResponseBody), http::Error> { |
| 123 | self.handle.url(url)?; | | |
| 124 | let mut list = curl::easy::List::new(); | 144 | let mut list = curl::easy::List::new(); |
| 125 | for header in headers { | 145 | for header in headers { |
| 126 | list.append(header.as_ref())?; | 146 | list.append(header.as_ref())?; |
| 127 | } | 147 | } |
| 128 | self.handle.http_headers(list)?; | 148 | if self |
| 129 | | 149 | .req |
| 130 | let (send, receive_data) = pipe::unidirectional(1); | 150 | .send(Request { |
| 131 | self.handle.get_mut().send_data = Some(send); | 151 | url: url.to_owned(), |
| 132 | let (send, receive_headers) = pipe::unidirectional(1); | 152 | headers: list, |
| 133 | self.handle.get_mut().send_header = Some(send); | 153 | }) |
| 134 | | 154 | .is_err() |
| 135 | Ok((receive_headers, receive_data)) | 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 | fn post( | 170 | fn post( |