cfg_if::cfg_if! {
if #[cfg(feature = "std_web")] {
mod std_web;
pub use std_web::*;
} else if #[cfg(feature = "web_sys")] {
mod web_sys;
pub use self::web_sys::*;
}
}
#[derive(Debug)]
pub enum Referrer {
SameOriginUrl(String),
AboutClient,
Empty,
}
#[cfg(test)]
#[cfg(all(feature = "wasm_test", feature = "httpbin_test"))]
mod tests {
use super::*;
use crate::callback::{test_util::CallbackFuture, Callback};
use crate::format::{Json, Nothing};
use crate::utils;
#[cfg(feature = "web_sys")]
use ::web_sys::ReferrerPolicy;
use serde::Deserialize;
use ssri::Integrity;
use std::collections::HashMap;
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
wasm_bindgen_test_configure!(run_in_browser);
const fn httpbin_base_url() -> &'static str {
env!("HTTPBIN_URL")
}
#[derive(Deserialize, Debug)]
struct HttpBin {
headers: HashMap<String, String>,
origin: String,
url: String,
}
#[derive(Deserialize, Debug)]
struct HttpBinHeaders {
headers: HashMap<String, String>,
}
#[test]
async fn fetch_referrer_default() {
let request = Request::get(format!("{}/get", httpbin_base_url()))
.body(Nothing)
.unwrap();
let options = FetchOptions::default();
let cb_future = CallbackFuture::<Response<Json<Result<HttpBin, anyhow::Error>>>>::default();
let callback: Callback<_> = cb_future.clone().into();
let _task = FetchService::fetch_with_options(request, options, callback);
let resp = cb_future.await;
assert_eq!(resp.status(), StatusCode::OK);
if let Json(Ok(http_bin)) = resp.body() {
assert!(http_bin.headers.get("Referer").is_some());
} else {
assert!(false, "unexpected resp: {:#?}", resp);
}
}
#[test]
async fn fetch_referrer_same_origin_url() {
let request = Request::get(format!("{}/get", httpbin_base_url()))
.body(Nothing)
.unwrap();
let options = FetchOptions {
referrer: Some(Referrer::SameOriginUrl(String::from("same-origin"))),
referrer_policy: Some(ReferrerPolicy::NoReferrerWhenDowngrade),
..FetchOptions::default()
};
let cb_future = CallbackFuture::<Response<Json<Result<HttpBin, anyhow::Error>>>>::default();
let callback: Callback<_> = cb_future.clone().into();
let _task = FetchService::fetch_with_options(request, options, callback);
let resp = cb_future.await;
assert_eq!(resp.status(), StatusCode::OK);
if let Json(Ok(http_bin)) = resp.body() {
let referrer = http_bin.headers.get("Referer").expect("no referer set");
assert!(referrer.ends_with("/same-origin"));
} else {
assert!(false, "unexpected resp: {:#?}", resp);
}
}
#[test]
async fn fetch_referrer_about_client() {
let request = Request::get(format!("{}/get", httpbin_base_url()))
.body(Nothing)
.unwrap();
let options = FetchOptions {
referrer: Some(Referrer::AboutClient),
..FetchOptions::default()
};
let cb_future = CallbackFuture::<Response<Json<Result<HttpBin, anyhow::Error>>>>::default();
let callback: Callback<_> = cb_future.clone().into();
let _task = FetchService::fetch_with_options(request, options, callback);
let resp = cb_future.await;
assert_eq!(resp.status(), StatusCode::OK);
if let Json(Ok(http_bin)) = resp.body() {
assert!(http_bin.headers.get("Referer").is_some());
} else {
assert!(false, "unexpected resp: {:#?}", resp);
}
}
#[test]
async fn fetch_referrer_empty() {
let request = Request::get(format!("{}/get", httpbin_base_url()))
.body(Nothing)
.unwrap();
let options = FetchOptions {
referrer: Some(Referrer::Empty),
..FetchOptions::default()
};
let cb_future = CallbackFuture::<Response<Json<Result<HttpBin, anyhow::Error>>>>::default();
let callback: Callback<_> = cb_future.clone().into();
let _task = FetchService::fetch_with_options(request, options, callback);
let resp = cb_future.await;
assert_eq!(resp.status(), StatusCode::OK);
if let Json(Ok(http_bin)) = resp.body() {
assert!(http_bin.headers.get("Referer").is_none());
} else {
assert!(false, "unexpected resp: {:#?}", resp);
}
}
#[test]
async fn fetch_redirect_default() {
let request = Request::get(format!("{}/relative-redirect/1", httpbin_base_url()))
.body(Nothing)
.unwrap();
let options = FetchOptions::default();
let cb_future = CallbackFuture::<Response<Json<Result<HttpBin, anyhow::Error>>>>::default();
let callback: Callback<_> = cb_future.clone().into();
let _task = FetchService::fetch_with_options(request, options, callback);
let resp = cb_future.await;
assert_eq!(resp.status(), StatusCode::OK);
if let Json(Ok(http_bin)) = resp.body() {
assert_eq!(http_bin.url, format!("{}/get", httpbin_base_url()));
} else {
assert!(false, "unexpected resp: {:#?}", resp);
}
}
#[test]
async fn fetch_redirect_follow() {
let request = Request::get(format!("{}/relative-redirect/1", httpbin_base_url()))
.body(Nothing)
.unwrap();
let options = FetchOptions {
redirect: Some(Redirect::Follow),
..FetchOptions::default()
};
let cb_future = CallbackFuture::<Response<Json<Result<HttpBin, anyhow::Error>>>>::default();
let callback: Callback<_> = cb_future.clone().into();
let _task = FetchService::fetch_with_options(request, options, callback);
let resp = cb_future.await;
assert_eq!(resp.status(), StatusCode::OK);
if let Json(Ok(http_bin)) = resp.body() {
assert_eq!(http_bin.url, format!("{}/get", httpbin_base_url()));
} else {
assert!(false, "unexpected resp: {:#?}", resp);
}
}
#[test]
async fn fetch_redirect_error() {
let request = Request::get(format!("{}/relative-redirect/1", httpbin_base_url()))
.body(Nothing)
.unwrap();
let options = FetchOptions {
redirect: Some(Redirect::Error),
..FetchOptions::default()
};
let cb_future = CallbackFuture::<Response<Result<String, anyhow::Error>>>::default();
let callback: Callback<_> = cb_future.clone().into();
let _task = FetchService::fetch_with_options(request, options, callback);
let resp = cb_future.await;
assert_eq!(resp.status(), StatusCode::REQUEST_TIMEOUT);
}
#[test]
async fn fetch_redirect_manual() {
let request = Request::get(format!("{}/relative-redirect/1", httpbin_base_url()))
.body(Nothing)
.unwrap();
let options = FetchOptions {
redirect: Some(Redirect::Manual),
..FetchOptions::default()
};
let cb_future = CallbackFuture::<Response<Result<String, anyhow::Error>>>::default();
let callback: Callback<_> = cb_future.clone().into();
let _task = FetchService::fetch_with_options(request, options, callback);
let resp = cb_future.await;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(resp.body().as_ref().unwrap(), &String::from(""));
}
#[test]
async fn fetch_integrity() {
let resource = "Yew SRI Test";
let request = Request::get(format!(
"{}/base64/{}",
httpbin_base_url(),
base64::encode_config(resource, base64::URL_SAFE)
))
.body(Nothing)
.unwrap();
let options = FetchOptions {
integrity: Some(Integrity::from(resource).to_string()),
..FetchOptions::default()
};
let cb_future = CallbackFuture::<Response<Result<String, anyhow::Error>>>::default();
let callback: Callback<_> = cb_future.clone().into();
let _task = FetchService::fetch_with_options(request, options, callback);
let resp = cb_future.await;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(resp.body().as_ref().unwrap(), resource);
}
#[test]
async fn fetch_integrity_fail() {
let resource = "Yew SRI Test";
let request = Request::get(format!(
"{}/base64/{}",
httpbin_base_url(),
base64::encode_config(resource, base64::URL_SAFE)
))
.body(Nothing)
.unwrap();
let options = FetchOptions {
integrity: Some(Integrity::from("Yew SRI Test fail").to_string()),
..FetchOptions::default()
};
let cb_future = CallbackFuture::<Response<Result<String, anyhow::Error>>>::default();
let callback: Callback<_> = cb_future.clone().into();
let _task = FetchService::fetch_with_options(request, options, callback);
let resp = cb_future.await;
assert!(resp.body().is_err());
}
#[test]
async fn fetch_fail() {
let request = Request::get("https://fetch.fail").body(Nothing).unwrap();
let cb_future = CallbackFuture::<Response<Result<String, anyhow::Error>>>::default();
let callback: Callback<_> = cb_future.clone().into();
let _task = FetchService::fetch(request, callback);
let resp = cb_future.await;
#[cfg(feature = "std_web")]
assert!(resp.body().is_err());
#[cfg(feature = "web_sys")]
assert!(resp
.body()
.as_ref()
.unwrap_err()
.to_string()
.starts_with("TypeError:"));
}
#[test]
async fn fetch_referrer_policy_no_referrer() {
let request = Request::get(format!("{}/headers", httpbin_base_url()))
.body(Nothing)
.unwrap();
let options = FetchOptions {
referrer_policy: Some(ReferrerPolicy::NoReferrer),
..FetchOptions::default()
};
let cb_future =
CallbackFuture::<Response<Json<Result<HttpBinHeaders, anyhow::Error>>>>::default();
let callback: Callback<_> = cb_future.clone().into();
let _task = FetchService::fetch_with_options(request, options, callback);
let resp = cb_future.await;
assert_eq!(resp.status(), StatusCode::OK);
if let Json(Ok(httpbin_headers)) = resp.body() {
assert_eq!(httpbin_headers.headers.get("Referer"), None);
} else {
assert!(false, "unexpected resp: {:#?}", resp);
}
}
#[test]
async fn fetch_referrer_policy_origin() {
let request = Request::get(format!("{}/headers", httpbin_base_url()))
.body(Nothing)
.unwrap();
let options = FetchOptions {
referrer_policy: Some(ReferrerPolicy::Origin),
..FetchOptions::default()
};
let cb_future =
CallbackFuture::<Response<Json<Result<HttpBinHeaders, anyhow::Error>>>>::default();
let callback: Callback<_> = cb_future.clone().into();
let _task = FetchService::fetch_with_options(request, options, callback);
let resp = cb_future.await;
assert_eq!(resp.status(), StatusCode::OK);
if let Json(Ok(httpbin_headers)) = resp.body() {
assert!(httpbin_headers
.headers
.get("Referer")
.unwrap()
.starts_with(&utils::origin().unwrap()));
} else {
assert!(false, "unexpected resp: {:#?}", resp);
}
}
}