1cfg_if::cfg_if! {
4 if #[cfg(feature = "std_web")] {
5 mod std_web;
6 pub use std_web::*;
7 } else if #[cfg(feature = "web_sys")] {
8 mod web_sys;
9 pub use self::web_sys::*;
10 }
11}
12
13#[derive(Debug)]
15pub enum Referrer {
16 SameOriginUrl(String),
18 AboutClient,
20 Empty,
22}
23
24#[cfg(test)]
25#[cfg(all(feature = "wasm_test", feature = "httpbin_test"))]
26mod tests {
27 use super::*;
28 use crate::callback::{test_util::CallbackFuture, Callback};
29 use crate::format::{Json, Nothing};
30 use crate::utils;
31 #[cfg(feature = "web_sys")]
32 use ::web_sys::ReferrerPolicy;
33 use serde::Deserialize;
34 use ssri::Integrity;
35 use std::collections::HashMap;
36 use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
37
38 wasm_bindgen_test_configure!(run_in_browser);
39
40 const fn httpbin_base_url() -> &'static str {
41 env!("HTTPBIN_URL")
43 }
44
45 #[derive(Deserialize, Debug)]
46 struct HttpBin {
47 headers: HashMap<String, String>,
48 origin: String,
49 url: String,
50 }
51
52 #[derive(Deserialize, Debug)]
53 struct HttpBinHeaders {
54 headers: HashMap<String, String>,
55 }
56
57 #[test]
58 async fn fetch_referrer_default() {
59 let request = Request::get(format!("{}/get", httpbin_base_url()))
60 .body(Nothing)
61 .unwrap();
62 let options = FetchOptions::default();
63 let cb_future = CallbackFuture::<Response<Json<Result<HttpBin, anyhow::Error>>>>::default();
64 let callback: Callback<_> = cb_future.clone().into();
65 let _task = FetchService::fetch_with_options(request, options, callback);
66 let resp = cb_future.await;
67 assert_eq!(resp.status(), StatusCode::OK);
68 if let Json(Ok(http_bin)) = resp.body() {
69 assert!(http_bin.headers.get("Referer").is_some());
70 } else {
71 assert!(false, "unexpected resp: {:#?}", resp);
72 }
73 }
74
75 #[test]
76 async fn fetch_referrer_same_origin_url() {
77 let request = Request::get(format!("{}/get", httpbin_base_url()))
78 .body(Nothing)
79 .unwrap();
80 let options = FetchOptions {
81 referrer: Some(Referrer::SameOriginUrl(String::from("same-origin"))),
82 referrer_policy: Some(ReferrerPolicy::NoReferrerWhenDowngrade),
83 ..FetchOptions::default()
84 };
85 let cb_future = CallbackFuture::<Response<Json<Result<HttpBin, anyhow::Error>>>>::default();
86 let callback: Callback<_> = cb_future.clone().into();
87 let _task = FetchService::fetch_with_options(request, options, callback);
88 let resp = cb_future.await;
89 assert_eq!(resp.status(), StatusCode::OK);
90 if let Json(Ok(http_bin)) = resp.body() {
91 let referrer = http_bin.headers.get("Referer").expect("no referer set");
92 assert!(referrer.ends_with("/same-origin"));
93 } else {
94 assert!(false, "unexpected resp: {:#?}", resp);
95 }
96 }
97
98 #[test]
99 async fn fetch_referrer_about_client() {
100 let request = Request::get(format!("{}/get", httpbin_base_url()))
101 .body(Nothing)
102 .unwrap();
103 let options = FetchOptions {
104 referrer: Some(Referrer::AboutClient),
105 ..FetchOptions::default()
106 };
107 let cb_future = CallbackFuture::<Response<Json<Result<HttpBin, anyhow::Error>>>>::default();
108 let callback: Callback<_> = cb_future.clone().into();
109 let _task = FetchService::fetch_with_options(request, options, callback);
110 let resp = cb_future.await;
111 assert_eq!(resp.status(), StatusCode::OK);
112 if let Json(Ok(http_bin)) = resp.body() {
113 assert!(http_bin.headers.get("Referer").is_some());
114 } else {
115 assert!(false, "unexpected resp: {:#?}", resp);
116 }
117 }
118
119 #[test]
120 async fn fetch_referrer_empty() {
121 let request = Request::get(format!("{}/get", httpbin_base_url()))
122 .body(Nothing)
123 .unwrap();
124 let options = FetchOptions {
125 referrer: Some(Referrer::Empty),
126 ..FetchOptions::default()
127 };
128 let cb_future = CallbackFuture::<Response<Json<Result<HttpBin, anyhow::Error>>>>::default();
129 let callback: Callback<_> = cb_future.clone().into();
130 let _task = FetchService::fetch_with_options(request, options, callback);
131 let resp = cb_future.await;
132 assert_eq!(resp.status(), StatusCode::OK);
133 if let Json(Ok(http_bin)) = resp.body() {
134 assert!(http_bin.headers.get("Referer").is_none());
135 } else {
136 assert!(false, "unexpected resp: {:#?}", resp);
137 }
138 }
139
140 #[test]
141 async fn fetch_redirect_default() {
142 let request = Request::get(format!("{}/relative-redirect/1", httpbin_base_url()))
143 .body(Nothing)
144 .unwrap();
145 let options = FetchOptions::default();
146 let cb_future = CallbackFuture::<Response<Json<Result<HttpBin, anyhow::Error>>>>::default();
147 let callback: Callback<_> = cb_future.clone().into();
148 let _task = FetchService::fetch_with_options(request, options, callback);
149 let resp = cb_future.await;
150 assert_eq!(resp.status(), StatusCode::OK);
151 if let Json(Ok(http_bin)) = resp.body() {
152 assert_eq!(http_bin.url, format!("{}/get", httpbin_base_url()));
153 } else {
154 assert!(false, "unexpected resp: {:#?}", resp);
155 }
156 }
157
158 #[test]
159 async fn fetch_redirect_follow() {
160 let request = Request::get(format!("{}/relative-redirect/1", httpbin_base_url()))
161 .body(Nothing)
162 .unwrap();
163 let options = FetchOptions {
164 redirect: Some(Redirect::Follow),
165 ..FetchOptions::default()
166 };
167 let cb_future = CallbackFuture::<Response<Json<Result<HttpBin, anyhow::Error>>>>::default();
168 let callback: Callback<_> = cb_future.clone().into();
169 let _task = FetchService::fetch_with_options(request, options, callback);
170 let resp = cb_future.await;
171 assert_eq!(resp.status(), StatusCode::OK);
172 if let Json(Ok(http_bin)) = resp.body() {
173 assert_eq!(http_bin.url, format!("{}/get", httpbin_base_url()));
174 } else {
175 assert!(false, "unexpected resp: {:#?}", resp);
176 }
177 }
178
179 #[test]
180 async fn fetch_redirect_error() {
181 let request = Request::get(format!("{}/relative-redirect/1", httpbin_base_url()))
182 .body(Nothing)
183 .unwrap();
184 let options = FetchOptions {
185 redirect: Some(Redirect::Error),
186 ..FetchOptions::default()
187 };
188 let cb_future = CallbackFuture::<Response<Result<String, anyhow::Error>>>::default();
189 let callback: Callback<_> = cb_future.clone().into();
190 let _task = FetchService::fetch_with_options(request, options, callback);
191 let resp = cb_future.await;
192 assert_eq!(resp.status(), StatusCode::REQUEST_TIMEOUT);
193 }
194
195 #[test]
196 async fn fetch_redirect_manual() {
197 let request = Request::get(format!("{}/relative-redirect/1", httpbin_base_url()))
198 .body(Nothing)
199 .unwrap();
200 let options = FetchOptions {
201 redirect: Some(Redirect::Manual),
202 ..FetchOptions::default()
203 };
204 let cb_future = CallbackFuture::<Response<Result<String, anyhow::Error>>>::default();
205 let callback: Callback<_> = cb_future.clone().into();
206 let _task = FetchService::fetch_with_options(request, options, callback);
207 let resp = cb_future.await;
208 assert_eq!(resp.status(), StatusCode::OK);
209 assert_eq!(resp.body().as_ref().unwrap(), &String::from(""));
211 }
212
213 #[test]
214 async fn fetch_integrity() {
215 let resource = "Yew SRI Test";
216 let request = Request::get(format!(
217 "{}/base64/{}",
218 httpbin_base_url(),
219 base64::encode_config(resource, base64::URL_SAFE)
220 ))
221 .body(Nothing)
222 .unwrap();
223 let options = FetchOptions {
224 integrity: Some(Integrity::from(resource).to_string()),
225 ..FetchOptions::default()
226 };
227 let cb_future = CallbackFuture::<Response<Result<String, anyhow::Error>>>::default();
228 let callback: Callback<_> = cb_future.clone().into();
229 let _task = FetchService::fetch_with_options(request, options, callback);
230 let resp = cb_future.await;
231 assert_eq!(resp.status(), StatusCode::OK);
232 assert_eq!(resp.body().as_ref().unwrap(), resource);
233 }
234
235 #[test]
236 async fn fetch_integrity_fail() {
237 let resource = "Yew SRI Test";
238 let request = Request::get(format!(
239 "{}/base64/{}",
240 httpbin_base_url(),
241 base64::encode_config(resource, base64::URL_SAFE)
242 ))
243 .body(Nothing)
244 .unwrap();
245 let options = FetchOptions {
246 integrity: Some(Integrity::from("Yew SRI Test fail").to_string()),
247 ..FetchOptions::default()
248 };
249 let cb_future = CallbackFuture::<Response<Result<String, anyhow::Error>>>::default();
250 let callback: Callback<_> = cb_future.clone().into();
251 let _task = FetchService::fetch_with_options(request, options, callback);
252 let resp = cb_future.await;
253 assert!(resp.body().is_err());
254 }
255
256 #[test]
257 async fn fetch_fail() {
258 let request = Request::get("https://fetch.fail").body(Nothing).unwrap();
259 let cb_future = CallbackFuture::<Response<Result<String, anyhow::Error>>>::default();
260 let callback: Callback<_> = cb_future.clone().into();
261 let _task = FetchService::fetch(request, callback);
262 let resp = cb_future.await;
263 #[cfg(feature = "std_web")]
264 assert!(resp.body().is_err());
265 #[cfg(feature = "web_sys")]
266 assert!(resp
267 .body()
268 .as_ref()
269 .unwrap_err()
270 .to_string()
271 .starts_with("TypeError:"));
272 }
273
274 #[test]
275 async fn fetch_referrer_policy_no_referrer() {
276 let request = Request::get(format!("{}/headers", httpbin_base_url()))
277 .body(Nothing)
278 .unwrap();
279 let options = FetchOptions {
280 referrer_policy: Some(ReferrerPolicy::NoReferrer),
281 ..FetchOptions::default()
282 };
283 let cb_future =
284 CallbackFuture::<Response<Json<Result<HttpBinHeaders, anyhow::Error>>>>::default();
285 let callback: Callback<_> = cb_future.clone().into();
286 let _task = FetchService::fetch_with_options(request, options, callback);
287 let resp = cb_future.await;
288 assert_eq!(resp.status(), StatusCode::OK);
289 if let Json(Ok(httpbin_headers)) = resp.body() {
290 assert_eq!(httpbin_headers.headers.get("Referer"), None);
291 } else {
292 assert!(false, "unexpected resp: {:#?}", resp);
293 }
294 }
295
296 #[test]
297 async fn fetch_referrer_policy_origin() {
298 let request = Request::get(format!("{}/headers", httpbin_base_url()))
299 .body(Nothing)
300 .unwrap();
301 let options = FetchOptions {
302 referrer_policy: Some(ReferrerPolicy::Origin),
303 ..FetchOptions::default()
304 };
305 let cb_future =
306 CallbackFuture::<Response<Json<Result<HttpBinHeaders, anyhow::Error>>>>::default();
307 let callback: Callback<_> = cb_future.clone().into();
308 let _task = FetchService::fetch_with_options(request, options, callback);
309 let resp = cb_future.await;
310 assert_eq!(resp.status(), StatusCode::OK);
311 if let Json(Ok(httpbin_headers)) = resp.body() {
312 assert!(httpbin_headers
313 .headers
314 .get("Referer")
315 .unwrap()
316 .starts_with(&utils::origin().unwrap()));
317 } else {
318 assert!(false, "unexpected resp: {:#?}", resp);
319 }
320 }
321}