use async_http_range_reader::AsyncHttpRangeReaderError;
use rattler_conda_types::package::PackageFile;
use reqwest_middleware::ClientWithMiddleware;
use tracing::debug;
use url::Url;
pub use super::full_download::{
fetch_file_from_remote_full_download, fetch_package_file_full_download,
};
use super::sparse::fetch_package_file_sparse;
use crate::ExtractError;
use crate::reqwest::sparse::fetch_file_from_remote_sparse;
pub async fn fetch_package_file_from_remote_url<P: PackageFile>(
client: ClientWithMiddleware,
url: Url,
) -> Result<P, ExtractError> {
match fetch_package_file_sparse::<P>(client.clone(), url.clone()).await {
Ok(result) => return Ok(result),
Err(ExtractError::UnsupportedArchiveType) => {
debug!("archive type not supported for range requests, falling back to full download");
}
Err(ExtractError::AsyncHttpRangeReaderError(
AsyncHttpRangeReaderError::HttpRangeRequestUnsupported,
)) => {
debug!("server does not support range requests, falling back to full download");
}
Err(ExtractError::AsyncHttpRangeReaderError(AsyncHttpRangeReaderError::HttpError(err)))
if err.status() == Some(reqwest::StatusCode::RANGE_NOT_SATISFIABLE) =>
{
debug!("server returned range not satisfiable, falling back to full download");
}
Err(e) => return Err(e),
}
fetch_package_file_full_download::<P>(&client, &url).await
}
pub async fn fetch_file_from_remote_url(
client: ClientWithMiddleware,
url: Url,
target_path: &std::path::Path,
) -> Result<Option<Vec<u8>>, ExtractError> {
match fetch_file_from_remote_sparse(client.clone(), url.clone(), target_path).await {
Ok(result) => return Ok(result),
Err(ExtractError::UnsupportedArchiveType) => {
debug!("archive type not supported for range requests, falling back to full download");
}
Err(ExtractError::AsyncHttpRangeReaderError(
AsyncHttpRangeReaderError::HttpRangeRequestUnsupported,
)) => {
debug!("server does not support range requests, falling back to full download");
}
Err(ExtractError::AsyncHttpRangeReaderError(AsyncHttpRangeReaderError::HttpError(err)))
if err.status() == Some(reqwest::StatusCode::RANGE_NOT_SATISFIABLE) =>
{
debug!("server returned range not satisfiable, falling back to full download");
}
Err(e) => return Err(e),
}
fetch_file_from_remote_full_download(&client, &url, target_path).await
}
#[cfg(test)]
mod tests {
use super::*;
use crate::reqwest::test_server;
fn test_file() -> std::path::PathBuf {
std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../../test-data/clobber/clobber-fd-1-0.1.0-h4616a5c_0.conda")
}
#[tokio::test]
async fn test_fetch_index_json() {
use rattler_conda_types::package::IndexJson;
let url = test_server::serve_file(test_file()).await;
let client = reqwest_middleware::ClientWithMiddleware::from(reqwest::Client::new());
let index_json: IndexJson = fetch_package_file_from_remote_url(client, url)
.await
.unwrap();
insta::assert_yaml_snapshot!(index_json);
}
#[tokio::test]
async fn test_fetch_about_json() {
use rattler_conda_types::package::AboutJson;
let url = test_server::serve_file(test_file()).await;
let client = reqwest_middleware::ClientWithMiddleware::from(reqwest::Client::new());
let about_json: AboutJson = fetch_package_file_from_remote_url(client, url)
.await
.unwrap();
insta::assert_yaml_snapshot!(about_json);
}
#[tokio::test]
async fn test_fetch_full_download_tar_bz2() {
use rattler_conda_types::package::IndexJson;
let tar_bz2 = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../../test-data/clobber/clobber-1-0.1.0-h4616a5c_0.tar.bz2");
let url = test_server::serve_file(tar_bz2).await;
let client = reqwest_middleware::ClientWithMiddleware::from(reqwest::Client::new());
let index_json: IndexJson = fetch_package_file_from_remote_url(client, url)
.await
.unwrap();
insta::assert_yaml_snapshot!(index_json);
}
#[tokio::test]
async fn test_fetch_full_download_conda() {
use rattler_conda_types::package::IndexJson;
let url = test_server::serve_file(test_file()).await;
let client = reqwest_middleware::ClientWithMiddleware::from(reqwest::Client::new());
let index_json: IndexJson = fetch_package_file_full_download(&client, &url)
.await
.unwrap();
insta::assert_yaml_snapshot!(index_json);
}
#[tokio::test]
async fn test_fetch_file_from_remote() {
let url = test_server::serve_file(test_file()).await;
let client = reqwest_middleware::ClientWithMiddleware::from(reqwest::Client::new());
let raw = fetch_file_from_remote_url(client, url, std::path::Path::new("info/index.json"))
.await
.unwrap()
.expect("file should exist in archive");
assert!(!raw.is_empty());
}
#[tokio::test]
async fn test_fetch_file_from_remote_tar_bz2_fallback() {
let tar_bz2 = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../../test-data/clobber/clobber-1-0.1.0-h4616a5c_0.tar.bz2");
let url = test_server::serve_file(tar_bz2).await;
let client = reqwest_middleware::ClientWithMiddleware::from(reqwest::Client::new());
let raw = fetch_file_from_remote_url(client, url, std::path::Path::new("info/index.json"))
.await
.unwrap()
.expect("file should exist in archive");
assert!(!raw.is_empty());
}
}