use crate::action_factory::{ActionTrait, ActionData};
use std::error::Error;
use log::*;
use simple_error::*;
use crate::action_do::{executor_fail, executor_recover};
use curl::easy::{Easy, List};
use std::time::Duration;
use std::sync::{Arc,Mutex};
use isahc::config::{Configurable, SslOption, RedirectPolicy};
use isahc::http::header::USER_AGENT;
use crate::config::ActionConf;
pub struct ActionHttp {
task:ActionData
}
impl ActionHttp {
fn executor_isahc(&mut self) {
let task_conf = &self.task.task_action;
let req = isahc::HttpClientBuilder::new()
.timeout(Duration::from_millis(task_conf.timeout as u64))
.default_header(USER_AGENT.as_str(),
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) \
AppleWebKit/537.36 (KHTML, like Gecko) \
Chrome/88.0.4324.150 Safari/537.36 \
TickChecker/1.0.0")
.redirect_policy(RedirectPolicy::Limit(2))
.auto_referer()
.ssl_options(if task_conf.skip_tls_check { SslOption::DANGER_ACCEPT_REVOKED_CERTS } else { SslOption::NONE })
.build().unwrap();
let r = req.head(task_conf.target.as_str());
match r {
Ok(resp) => {
let status_code = resp.status().as_u16();
if (status_code >= 200 && status_code <= 220) || (status_code >= 300 && status_code <= 305) {
if task_conf.output_result {
info!("http status:{}\n\theaders:{:?}",status_code,resp.headers());
}
self.task.do_recover();
}else {
warn!("http error status code:{}",status_code);
self.task.do_failed();
}
},
Err(e) => {
warn!("http error:{}",e);
self.task.do_failed();
}
}
}
fn executor_curl(&mut self) {
let task_conf = &self.task.task_action;
let mut easy = Easy::new();
easy.max_redirections(1);
easy.follow_location(true);
if task_conf.skip_tls_check {
easy.ssl_verify_peer(false);
easy.ssl_verify_host(false);
}
let mut headers = List::new();
headers.append("User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36 TickChecker/1.0.0");
easy.http_headers(headers);
easy.timeout(Duration::from_millis(task_conf.timeout as u64));
let mut header_data = Arc::new(Mutex::new(String::new()));
let mut hd = header_data.clone();
easy.header_function(move |header| {
let mut v = hd.lock().unwrap();
v.push_str(format!("{}", std::str::from_utf8(header).unwrap()).as_str());
true
}).unwrap();
easy.url(task_conf.target.as_str()).unwrap();
let r = easy.perform();
match r {
Ok(_) => {
if task_conf.output_result {
info!("connect timd:{:?},total time:{:?}",
easy.connect_time().unwrap(),
easy.total_time().unwrap());
info!("write header:{}",header_data.lock().unwrap().as_str());
}
self.task.do_recover();
}
Err(e) => {
error!("http error:{}",e);
self.task.do_failed();
}
}
}
}
impl ActionTrait for ActionHttp {
fn id(&self) -> i32 {
self.task.id
}
fn name(&self) -> &str {
self.task.name.as_str()
}
fn append_data(&mut self, data: ActionData) {
self.task = data;
}
fn executor(&mut self) {
info!("start http action:{} id:{}...",self.task.id,self.task.name);
self.executor_curl(); }
}
pub fn new_http(data: ActionData) -> ActionHttp {
ActionHttp { task:data }
}