Rewild Your Web
at main 243 lines 8.3 kB view raw
1--- original 2+++ modified 3@@ -0,0 +1,240 @@ 4+// SPDX-License-Identifier: AGPL-3.0-or-later 5+ 6+use std::fmt::Debug; 7+ 8+use content_security_policy::{self as csp}; 9+use http::{Method, StatusCode}; 10+use parking_lot::Mutex; 11+use serde::de::DeserializeOwned; 12+use serde_json::json; 13+use servo_arc::Arc; 14+use servo_url::ServoUrl; 15+use sync_wrapper::SyncWrapper; 16+ 17+use crate::header::CONTENT_TYPE; 18+use crate::http_status::HttpStatus; 19+use crate::request::{CredentialsMode, Referrer, Request, create_request_body_with_content}; 20+use crate::response::{Response, ResponseBody}; 21+use crate::{ 22+ CoreResourceThread, FetchMetadata, FetchResponseMsg, FetchTaskTarget, HeaderMap, HeaderValue, 23+ RequestBuilder, ResourceFetchTiming, ResourceTimingType, fetch_async, 24+}; 25+ 26+/// A FetchTaskTarget that doesn't do anything. 27+#[derive(Default)] 28+pub struct SimpleFetchTarget { 29+ pub body: Vec<u8>, 30+} 31+ 32+impl FetchTaskTarget for SimpleFetchTarget { 33+ fn process_request_body(&mut self, _: &Request) {} 34+ fn process_response(&mut self, _: &Request, _: &Response) {} 35+ fn process_response_chunk(&mut self, _: &Request, payload: Vec<u8>) { 36+ self.body.extend(payload); 37+ } 38+ fn process_response_eof(&mut self, _: &Request, response: &Response) { 39+ // TODO: figure out a way to not clone. 40+ *response.body.lock() = ResponseBody::Done(self.body.clone()); 41+ } 42+ fn process_csp_violations(&mut self, _: &Request, _: Vec<csp::Violation>) {} 43+} 44+ 45+/// Rewrites a response to replace the url. 46+pub fn rewrite_response_url(url: ServoUrl, inner_url: ServoUrl, fetched: Response) -> Response { 47+ let mut response = Response::new( 48+ url.clone(), 49+ ResourceFetchTiming::new(ResourceTimingType::Resource), 50+ ); 51+ response.response_type = fetched.response_type; 52+ response.termination_reason = fetched.termination_reason; 53+ response.url_list = fetched 54+ .url_list 55+ .into_iter() 56+ .map(|list_url| { 57+ if list_url == inner_url { 58+ url.clone() 59+ } else { 60+ list_url.clone() 61+ } 62+ }) 63+ .collect(); 64+ response.status = fetched.status; 65+ response.headers = fetched.headers; 66+ response.body = fetched.body; 67+ response.cache_state = fetched.cache_state; 68+ response.https_state = fetched.https_state; 69+ response.referrer = fetched.referrer; 70+ response.referrer_policy = fetched.referrer_policy; 71+ response.cors_exposed_header_name_list = fetched.cors_exposed_header_name_list; 72+ response.location_url = fetched.location_url; 73+ response.internal_response = fetched.internal_response.map(|internal_response| { 74+ Box::new(rewrite_response_url(url, inner_url, *internal_response)) 75+ }); 76+ response.return_internal = fetched.return_internal; 77+ response.aborted = fetched.aborted; 78+ response.resource_timing = fetched.resource_timing; 79+ response.range_requested = fetched.range_requested; 80+ response 81+} 82+ 83+/// Creates a http response with the given status code and the message as the body. 84+pub fn http_response(url: ServoUrl, status: StatusCode, message: &str) -> Response { 85+ let mut response = Response::new(url, ResourceFetchTiming::new(ResourceTimingType::Resource)); 86+ 87+ response.status = HttpStatus::new(status, vec![]); 88+ let body = ResponseBody::Done(message.as_bytes().to_vec()); 89+ response.body = Arc::new(Mutex::new(body)); 90+ 91+ response 92+} 93+ 94+// A simple fetch response. 95+#[derive(Default, Clone)] 96+pub struct FetchResponse { 97+ pub metadata: Option<FetchMetadata>, 98+ pub data: Arc<Vec<u8>>, 99+} 100+ 101+// pub type BoxedResponseCallback = Box<dyn FnMut(FetchResponse) + Send + 'static>; 102+ 103+// pub fn fetch_url( 104+// url: ServoUrl, 105+// params: &[(&str, &str)], 106+// resource_thread: &CoreResourceThread, 107+// mut callback: BoxedResponseCallback, 108+// ) { 109+// let mut full_url = url.clone(); 110+// { 111+// let mut url_params = full_url.as_mut_url().query_pairs_mut(); 112+// for param in params { 113+// url_params.append_pair(param.0, param.1); 114+// } 115+// } 116+ 117+// let request = RequestBuilder::new(None, full_url, Referrer::NoReferrer); 118+ 119+// let mut state: FetchResponse = Default::default(); 120+ 121+// fetch_async( 122+// resource_thread, 123+// request, 124+// None, 125+// Box::new(move |response_message| match response_message { 126+// FetchResponseMsg::ProcessResponseChunk(_id, chunk) => { 127+// Arc::get_mut(&mut state.data).unwrap().extend(chunk); 128+// }, 129+// FetchResponseMsg::ProcessResponse(_id, Ok(metadata)) => state.metadata = Some(metadata), 130+// FetchResponseMsg::ProcessResponseEOF(_id, _timing) => { 131+// callback(state.clone()); 132+// }, 133+// _ => {}, 134+// }), 135+// ); 136+// } 137+ 138+#[derive(Debug)] 139+pub enum FetchJsonError<T: DeserializeOwned + Debug> { 140+ Json(String), 141+ NoMetadata, 142+ NoContent, 143+ Other(T), 144+ Network, 145+} 146+ 147+pub async fn fetch_json<S: DeserializeOwned, E: DeserializeOwned + Debug>( 148+ url: ServoUrl, 149+ params: &[(&str, &str)], 150+ resource_thread: SyncWrapper<CoreResourceThread>, 151+ method: Method, 152+ headers: Option<HeaderMap>, 153+ requires_auth: bool, 154+) -> Result<S, FetchJsonError<E>> { 155+ let mut full_url = url.clone(); 156+ 157+ if method == Method::GET && !params.is_empty() { 158+ let mut url_params = full_url.as_mut_url().query_pairs_mut(); 159+ for param in params { 160+ url_params.append_pair(param.0, param.1); 161+ } 162+ } 163+ 164+ let mut headers = headers.unwrap_or_default(); 165+ 166+ let body = if method == Method::POST && !params.is_empty() { 167+ headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json")); 168+ // Create a JSON encoded body. 169+ let mut object = serde_json::Map::new(); 170+ for param in params { 171+ object.insert(param.0.into(), json!(param.1)); 172+ } 173+ let value = serde_json::Value::Object(object); 174+ Some(create_request_body_with_content( 175+ &serde_json::to_string(&value).unwrap_or("{}".to_owned()), 176+ )) 177+ } else { 178+ None 179+ }; 180+ 181+ let mut builder = RequestBuilder::new(None, full_url.clone(), Referrer::NoReferrer) 182+ .method(method) 183+ .headers(headers) 184+ .origin(full_url.origin()) 185+ .body(body); 186+ 187+ if requires_auth { 188+ builder = builder.credentials_mode(CredentialsMode::Include); 189+ } 190+ 191+ let mut state: FetchResponse = Default::default(); 192+ 193+ let (tx, rx) = tokio::sync::oneshot::channel(); 194+ 195+ let mut tx = Some(tx); 196+ 197+ fetch_async( 198+ &resource_thread.into_inner(), 199+ builder, 200+ None, 201+ Box::new(move |response_message| match response_message { 202+ FetchResponseMsg::ProcessResponseChunk(_id, chunk) => { 203+ Arc::get_mut(&mut state.data).unwrap().extend(chunk.0) 204+ }, 205+ FetchResponseMsg::ProcessResponse(_id, Ok(metadata)) => state.metadata = Some(metadata), 206+ FetchResponseMsg::ProcessResponseEOF(_id, _result, _timing) => { 207+ let _ = tx.take().unwrap().send(state.clone()); 208+ }, 209+ _ => {}, 210+ }), 211+ ); 212+ 213+ let response = rx.await.unwrap(); 214+ 215+ let Some(metadata) = response.metadata else { 216+ return Err(FetchJsonError::NoMetadata); 217+ }; 218+ 219+ let status = &metadata.metadata().status; 220+ 221+ if status.is_success() { 222+ if response.data.is_empty() { 223+ Err(FetchJsonError::NoContent) 224+ } else { 225+ serde_json::from_slice::<S>(&response.data) 226+ .map_err(|err| FetchJsonError::Json(err.to_string())) 227+ } 228+ } else { 229+ log::error!( 230+ "Fetch Error {}: {}", 231+ status.raw_code(), 232+ String::from_utf8_lossy(&response.data) 233+ ); 234+ if status.raw_code() == 400 { 235+ match serde_json::from_slice::<E>(&response.data) { 236+ Ok(err) => Err(FetchJsonError::Other(err)), 237+ Err(err) => Err(FetchJsonError::Json(err.to_string())), 238+ } 239+ } else { 240+ Err(FetchJsonError::Network) 241+ } 242+ } 243+}