use std::sync::Arc;
use super::{FileType, InputContent, ResolvedInputSource};
use crate::ratelimit::HostPool;
use crate::utils::request;
use crate::{BasicAuthExtractor, Result, Uri};
use http::HeaderMap;
use reqwest::{Request, Url};
#[derive(Debug, Clone)]
pub struct UrlContentResolver {
pub basic_auth_extractor: Option<BasicAuthExtractor>,
pub headers: HeaderMap,
pub host_pool: Arc<HostPool>,
}
impl Default for UrlContentResolver {
fn default() -> Self {
Self {
basic_auth_extractor: None,
headers: HeaderMap::new(),
host_pool: Arc::new(HostPool::default()),
}
}
}
impl UrlContentResolver {
pub async fn url_contents(&self, url: Url) -> Result<InputContent> {
let file_type = match url.path() {
path if path.is_empty() || path == "/" => FileType::Html,
_ => FileType::from(url.as_str()),
};
let credentials = request::extract_credentials(
self.basic_auth_extractor.as_ref(),
&Uri { url: url.clone() },
);
let request = self.build_request(&url, credentials)?;
let response = self.host_pool.execute_request(request, true).await?;
if !response.status.is_success() {
return Err(crate::ErrorKind::ReadInputUrlStatusCode(response.status));
}
let content = response.text.unwrap_or_else(|| {
unreachable!("execute_request with needs_body=true always returns text")
});
Ok(InputContent {
source: ResolvedInputSource::RemoteUrl(Box::new(url)),
file_type,
content,
})
}
fn build_request(
&self,
url: &Url,
credentials: Option<super::BasicAuthCredentials>,
) -> Result<Request> {
let mut request = self
.host_pool
.build_request(reqwest::Method::GET, &url.clone().into())?;
request.headers_mut().extend(self.headers.clone());
if let Some(credentials) = credentials {
credentials.append_to_request(&mut request);
}
Ok(request)
}
}