use curl;
use curl::easy::{Easy, List, WriteError};
use std::fmt;
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 fmt::Display for HttpError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
HttpError::Error(ref err) => fmt::Display::fmt(err, f),
HttpError::CurlError(ref err) => fmt::Display::fmt(err, f),
HttpError::Utf8Error(ref err) => fmt::Display::fmt(err, f),
HttpError::IOError(ref err) => fmt::Display::fmt(err, f),
HttpError::UrlParseError(ref err) => fmt::Display::fmt(err, f),
}
}
}
impl From<curl::Error> for HttpError {
fn from(e: curl::Error) -> Self {
HttpError::CurlError(e)
}
}
impl From<Utf8Error> for HttpError {
fn from(e: Utf8Error) -> Self {
HttpError::Utf8Error(e)
}
}
impl From<io::Error> for HttpError {
fn from(e: io::Error) -> Self {
HttpError::IOError(e)
}
}
impl From<url::ParseError> for HttpError {
fn from(e: url::ParseError) -> Self {
HttpError::UrlParseError(e)
}
}
impl From<HttpError> for WriteError {
fn from(_: 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<String, HttpError> {
let mut data = Vec::new();
self.curl.url(uri)?;
{
let mut transfer = self.curl.transfer();
transfer
.write_function(|new_data| {
data.extend_from_slice(new_data);
Ok(new_data.len())
})?;
transfer.perform()?;
}
match str::from_utf8(data.as_slice()) {
Ok(value) => Ok(value.to_owned()),
Err(error) => Err(HttpError::Utf8Error(error)),
}
}
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 get_filename(&mut self, download_uri: &str) -> Result<String, HttpError> {
self.curl.url(download_uri)?;
self.curl.nobody(true)?;
self.curl.perform()?;
self.curl.nobody(false)?;
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.")),
};
Ok(file_name.to_owned())
}
pub fn download(&mut self,
download_uri: &str,
download_dir: &PathBuf)
-> Result<String, 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(file_name.to_owned())
}
}