use async_foundation::net::tcp_stream::TcpStream;
use futures::executor::block_on;
use futures::io::BufReader;
use httpio::enums::http_body::HttpBody;
use httpio::enums::http_request_method::HttpRequestMethod;
use httpio::enums::http_version::HttpVersion;
use httpio::structures::connection::http_connection::HttpConnection;
use httpio::structures::header::header_list::HttpHeaderList;
use httpio::{enums::char_set::CharSet, utils::url::Url};
use log::{LogLevel, Logger};
use tls12::structs::tls_stream::TLSStream;
use httpio::compression::set_compression_provider;
#[path = "../shared/mod.rs"]
mod shared;
use shared::Flate2Decoder;
const TARGET: &str = "https://www.example.com";
const USER_AGENT: &str = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.5 Safari/605.1.15";
const ACCEPT: &str = "text/html, application/json, */*;q=0.8";
const ACCEPT_LANGUAGE: &str =
"en,es-ES;q=0.9,es;q=0.8,it;q=0.7,de;q=0.6,cs;q=0.5,ru;q=0.4,ja;q=0.3,uk;q=0.2";
const LOG_TLS_PREFIX: &str = "TLS";
const LOG_TLS_HANDSHAKE_PREFIX: &str = "TLS Handshake";
fn main() -> Result<(), Box<dyn std::error::Error>> {
set_compression_provider(Box::new(Flate2Decoder))
.map_err(|e| format!("Failed to set compression provider: {}", e))?;
block_on(main_async())
}
async fn main_async() -> Result<(), Box<dyn std::error::Error>> {
let url: Url = TARGET.into();
let addr = url.socket_address()?;
let host_name = url.domain.to_string();
let (reader, writer) = TcpStream::connect(addr)?.split();
let (reader, writer) = TLSStream::connect_with_logger(
reader,
writer,
Some(host_name.clone()),
logger(format!(
"{{time}} [{{level}}][{}] {{message}}",
LOG_TLS_PREFIX
)),
logger(format!(
"{{time}} [{{level}}][{}] {{message}}",
LOG_TLS_HANDSHAKE_PREFIX
)),
)
.await?
.split();
let reader = BufReader::new(reader);
let mut connection = HttpConnection::new(
reader,
writer,
HttpVersion::Http11,
&host_name,
request_headers().into(),
logger("{time} [{level}][HTTP] {message}".to_string()),
)?;
connection
.send_request(
HttpRequestMethod::Get,
&url.path_query(),
HttpHeaderList::default(),
HttpBody::None,
)
.await?;
let message = connection.read_response().await?;
let charset = message.headers.get_charset(CharSet::Iso88591);
let _message: String = message.body.to_string(charset)?;
Ok(())
}
fn request_headers() -> Vec<httpio::enums::header::http_header::HttpHeader> {
use httpio::enums::header::http_header::HttpHeader;
use httpio::utils::http_header_field_name;
vec![
HttpHeader::new(http_header_field_name::USER_AGENT, USER_AGENT),
HttpHeader::new(http_header_field_name::ACCEPT, ACCEPT),
HttpHeader::Generic {
key: "Cache-Control".to_string(),
value: "no-cache".to_string(),
},
HttpHeader::Generic {
key: "Accept-Language".to_string(),
value: ACCEPT_LANGUAGE.to_string(),
},
]
}
fn logger(format: String) -> Logger {
Logger::with_level(LogLevel::Info)
.stdout()
.time_format("%H:%M:%S%.3f")
.format(format)
}