use curl; use curl::easy::{Easy, List, WriteError}; use std::fs; use std::fs::File; use std::io; use std::io::Write; use std::path::Path; use std::path::PathBuf; use std::str; use std::str::Utf8Error; use url; use url::Url; #[derive(Debug)] pub enum HttpError { Error(&'static str), CurlError(curl::Error), Utf8Error(Utf8Error), IOError(io::Error), UrlParseError(url::ParseError), } impl From for HttpError { fn from(e: curl::Error) -> Self { HttpError::CurlError(e) } } impl From for HttpError { fn from(e: Utf8Error) -> Self { HttpError::Utf8Error(e) } } impl From for HttpError { fn from(e: io::Error) -> Self { HttpError::IOError(e) } } impl From for HttpError { fn from(e: url::ParseError) -> Self { HttpError::UrlParseError(e) } } impl From for WriteError { fn from(e: HttpError) -> Self { WriteError::__Nonexhaustive } } pub struct Http { curl: Easy, } impl Http { pub fn new() -> Http { let mut curl = Easy::new(); curl.follow_location(true).unwrap(); Http { curl: curl } } pub fn get(&mut self, uri: &str) -> Result { let mut response_body = String::new(); self.curl.url(uri)?; { let mut transfer = self.curl.transfer(); transfer.write_function(|data| { response_body = String::from(str::from_utf8(data).unwrap()); Ok(data.len()) })?; transfer.perform()?; } Ok(response_body) } pub fn add_header(&mut self, header: &str) -> Result<(), HttpError> { let mut list = List::new(); list.append(header)?; match self.curl.http_headers(list) { Ok(_) => Ok(()), Err(error) => Err(HttpError::CurlError(error)), } } pub fn download(&mut self, download_uri: &str, download_dir: &PathBuf) -> Result<(), HttpError> { let download_path_tmp = Path::new(download_dir.as_os_str()).join(".progress"); let mut file_download = File::create(&download_path_tmp)?; self.curl.url(download_uri)?; { let mut transfer = self.curl.transfer(); transfer.write_function(|data| { match file_download.write(data) { Ok(_) => Ok(()), Err(error) => Err(HttpError::IOError(error)), }?; Ok(data.len()) })?; transfer.perform()?; } let download_url_string = match self.curl.effective_url()? { Some(value) => value, None => return Err(HttpError::Error("Can't get effective download url.")), }; let download_url = Url::parse(download_url_string)?; let download_url_segments = match download_url.path_segments() { Some(value) => value, None => return Err(HttpError::Error("Can't parse download segments.")), }; let file_name = match download_url_segments.last() { Some(value) => value, None => return Err(HttpError::Error("No segments in download url.")), }; let download_path = Path::new(download_dir.as_os_str()).join(file_name); match fs::rename(download_path_tmp, download_path) { Ok(_) => Ok(()), Err(error) => Err(HttpError::IOError(error)), }?; Ok(()) } }