2017-03-20 12:14:49 +00:00
|
|
|
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<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 {
|
2017-03-20 15:20:37 +00:00
|
|
|
fn from(_: HttpError) -> Self {
|
2017-03-20 12:14:49 +00:00
|
|
|
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 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(())
|
|
|
|
}
|
|
|
|
}
|