forked from
me.webbeef.org/browser.html
Rewild Your Web
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+}