1use std::sync::atomic::AtomicBool;
8
9use http::HeaderMap;
10use hyper_serde::Serde;
11use malloc_size_of_derive::MallocSizeOf;
12use parking_lot::Mutex;
13use serde::{Deserialize, Serialize};
14use servo_arc::Arc;
15use servo_url::ServoUrl;
16
17use crate::fetch::headers::extract_mime_type_as_mime;
18use crate::http_status::HttpStatus;
19use crate::resource_fetch_timing::{ResourceFetchTimingContainer, ResourceTimingType};
20use crate::{
21 FetchMetadata, FilteredMetadata, Metadata, NetworkError, ReferrerPolicy, ResourceFetchTiming,
22 TlsSecurityInfo,
23};
24
25#[derive(Clone, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
27pub enum ResponseType {
28 Basic,
29 Cors,
30 Default,
31 Error(NetworkError),
32 Opaque,
33 OpaqueRedirect,
34}
35
36#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)]
38pub enum TerminationReason {
39 EndUserAbort,
40 Fatal,
41 Timeout,
42}
43
44#[derive(Clone, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
47pub enum ResponseBody {
48 Empty, Receiving(Vec<u8>),
50 Done(Vec<u8>),
51}
52
53impl ResponseBody {
54 pub fn is_done(&self) -> bool {
55 match *self {
56 ResponseBody::Done(..) => true,
57 ResponseBody::Empty | ResponseBody::Receiving(..) => false,
58 }
59 }
60}
61
62#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize)]
64pub enum RedirectTaint {
65 #[default]
66 SameOrigin,
67 SameSite,
68 CrossSite,
69}
70
71#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)]
73pub enum CacheState {
74 None,
75 Local,
76 Validated,
77 Partial,
78}
79
80#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
82pub enum HttpsState {
83 None,
84 Deprecated,
85 Modern,
86}
87
88#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
89pub struct ResponseInit {
90 pub url: ServoUrl,
91 #[serde(
92 deserialize_with = "::hyper_serde::deserialize",
93 serialize_with = "::hyper_serde::serialize"
94 )]
95 pub headers: HeaderMap,
96 pub status_code: u16,
97 pub referrer: Option<ServoUrl>,
98 pub location_url: Option<Result<ServoUrl, String>>,
99}
100
101#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
103pub struct Response {
104 pub response_type: ResponseType,
105 pub termination_reason: Option<TerminationReason>,
106 url: Option<ServoUrl>,
107 pub url_list: Vec<ServoUrl>,
108 pub status: HttpStatus,
109 #[serde(
110 deserialize_with = "::hyper_serde::deserialize",
111 serialize_with = "::hyper_serde::serialize"
112 )]
113 pub headers: HeaderMap,
114 #[conditional_malloc_size_of]
115 pub body: Arc<Mutex<ResponseBody>>,
116 pub cache_state: CacheState,
117 pub https_state: HttpsState,
118 pub tls_security_info: Option<TlsSecurityInfo>,
119 pub referrer: Option<ServoUrl>,
120 pub redirect_taint: RedirectTaint,
122 pub referrer_policy: ReferrerPolicy,
123 pub cors_exposed_header_name_list: Vec<String>,
125 pub location_url: Option<Result<ServoUrl, String>>,
127 pub internal_response: Option<Box<Response>>,
130 pub return_internal: bool,
132 #[conditional_malloc_size_of]
134 pub aborted: Arc<AtomicBool>,
135 pub resource_timing: ResourceFetchTimingContainer,
137
138 pub range_requested: bool,
140
141 pub request_includes_credentials: bool,
144}
145
146impl Response {
147 pub fn new(url: ServoUrl, resource_timing: ResourceFetchTiming) -> Response {
148 Response {
149 response_type: ResponseType::Default,
150 termination_reason: None,
151 url: Some(url),
152 url_list: vec![],
153 status: HttpStatus::default(),
154 headers: HeaderMap::new(),
155 body: Arc::new(Mutex::new(ResponseBody::Empty)),
156 cache_state: CacheState::None,
157 https_state: HttpsState::None,
158 tls_security_info: None,
159 referrer: None,
160 referrer_policy: ReferrerPolicy::EmptyString,
161 cors_exposed_header_name_list: vec![],
162 location_url: None,
163 internal_response: None,
164 return_internal: true,
165 aborted: Arc::new(AtomicBool::new(false)),
166 resource_timing: resource_timing.into(),
167 range_requested: false,
168 request_includes_credentials: true,
169 redirect_taint: Default::default(),
170 }
171 }
172
173 pub fn from_init(init: ResponseInit, resource_timing_type: ResourceTimingType) -> Response {
174 let mut res = Response::new(init.url, ResourceFetchTiming::new(resource_timing_type));
175 res.location_url = init.location_url;
176 res.headers = init.headers;
177 res.referrer = init.referrer;
178 res.status = HttpStatus::new_raw(init.status_code, vec![]);
179 res
180 }
181
182 pub fn network_error(e: NetworkError) -> Response {
183 Response {
184 response_type: ResponseType::Error(e),
185 termination_reason: None,
186 url: None,
187 url_list: vec![],
188 status: HttpStatus::new_error(),
189 headers: HeaderMap::new(),
190 body: Arc::new(Mutex::new(ResponseBody::Empty)),
191 cache_state: CacheState::None,
192 https_state: HttpsState::None,
193 tls_security_info: None,
194 referrer: None,
195 referrer_policy: ReferrerPolicy::EmptyString,
196 cors_exposed_header_name_list: vec![],
197 location_url: None,
198 internal_response: None,
199 return_internal: true,
200 aborted: Arc::new(AtomicBool::new(false)),
201 resource_timing: ResourceFetchTiming::new(ResourceTimingType::Error).into(),
202 range_requested: false,
203 request_includes_credentials: true,
204 redirect_taint: Default::default(),
205 }
206 }
207
208 pub fn url(&self) -> Option<&ServoUrl> {
209 self.url.as_ref()
210 }
211
212 pub fn is_network_error(&self) -> bool {
213 matches!(self.response_type, ResponseType::Error(..))
214 }
215
216 pub fn get_network_error(&self) -> Option<&NetworkError> {
217 match self.response_type {
218 ResponseType::Error(ref e) => Some(e),
219 _ => None,
220 }
221 }
222
223 pub fn set_network_error(&mut self, network_error: NetworkError) {
224 self.response_type = ResponseType::Error(network_error);
225 }
226
227 pub fn actual_response(&self) -> &Response {
228 if self.return_internal && self.internal_response.is_some() {
229 self.internal_response.as_ref().unwrap()
230 } else {
231 self
232 }
233 }
234
235 pub fn actual_response_mut(&mut self) -> &mut Response {
236 if self.return_internal && self.internal_response.is_some() {
237 self.internal_response.as_mut().unwrap()
238 } else {
239 self
240 }
241 }
242
243 pub fn to_actual(self) -> Response {
244 if self.return_internal && self.internal_response.is_some() {
245 *self.internal_response.unwrap()
246 } else {
247 self
248 }
249 }
250
251 pub fn get_resource_timing(&self) -> &ResourceFetchTimingContainer {
252 &self.resource_timing
253 }
254
255 #[rustfmt::skip]
258 pub fn to_filtered(self, filter_type: ResponseType) -> Response {
259 match filter_type {
260 ResponseType::Default |
261 ResponseType::Error(..) => panic!(),
262 _ => (),
263 }
264
265 let old_response = self.to_actual();
266
267 if let ResponseType::Error(e) = old_response.response_type {
268 return Response::network_error(e);
269 }
270
271 let old_headers = old_response.headers.clone();
272 let exposed_headers = old_response.cors_exposed_header_name_list.clone();
273 let mut response = old_response.clone();
274 response.internal_response = Some(Box::new(old_response));
275 response.response_type = filter_type;
276
277 match response.response_type {
278 ResponseType::Default |
279 ResponseType::Error(..) => unreachable!(),
280
281 ResponseType::Basic => {
282 let headers = old_headers.iter().filter(|(name, _)| {
283 !matches!(&*name.as_str().to_ascii_lowercase(), "set-cookie" | "set-cookie2")
284 }).map(|(n, v)| (n.clone(), v.clone())).collect();
285 response.headers = headers;
286 },
287
288 ResponseType::Cors => {
289 let headers = old_headers.iter().filter(|(name, _)| {
290 match &*name.as_str().to_ascii_lowercase() {
291 "cache-control" | "content-language" | "content-length" | "content-type" |
292 "expires" | "last-modified" | "pragma" => true,
293 "set-cookie" | "set-cookie2" => false,
294 header => {
295 exposed_headers.iter().any(|h| *header == h.as_str().to_ascii_lowercase())
296 }
297 }
298 }).map(|(n, v)| (n.clone(), v.clone())).collect();
299 response.headers = headers;
300 },
301
302 ResponseType::Opaque => {
303 response.url_list = vec![];
304 response.url = None;
305 response.headers = HeaderMap::new();
306 response.status = HttpStatus::new_error();
307 response.body = Arc::new(Mutex::new(ResponseBody::Empty));
308 response.cache_state = CacheState::None;
309 },
310
311 ResponseType::OpaqueRedirect => {
312 response.headers = HeaderMap::new();
313 response.status = HttpStatus::new_error();
314 response.body = Arc::new(Mutex::new(ResponseBody::Empty));
315 response.cache_state = CacheState::None;
316 },
317 }
318
319 response
320 }
321
322 pub fn metadata(&self) -> Result<FetchMetadata, NetworkError> {
323 fn init_metadata(response: &Response, url: &ServoUrl) -> Metadata {
324 let mut metadata = Metadata::default(url.clone());
325 metadata.set_content_type(extract_mime_type_as_mime(&response.headers).as_ref());
326 metadata.location_url.clone_from(&response.location_url);
327 metadata.headers = Some(Serde(response.headers.clone()));
328 metadata.status.clone_from(&response.status);
329 metadata.https_state = response.https_state;
330 metadata.referrer.clone_from(&response.referrer);
331 metadata.referrer_policy = response.referrer_policy;
332 metadata.redirected = response.actual_response().url_list.len() > 1;
333 metadata
334 .tls_security_info
335 .clone_from(&response.tls_security_info);
336 metadata
337 }
338
339 if let Some(error) = self.get_network_error() {
340 return Err(error.clone());
341 }
342
343 let metadata = self.url.as_ref().map(|url| init_metadata(self, url));
344
345 if let Some(ref response) = self.internal_response {
346 match response.url {
347 Some(ref url) => {
348 let unsafe_metadata = init_metadata(response, url);
349
350 match self.response_type {
351 ResponseType::Basic => Ok(FetchMetadata::Filtered {
352 filtered: FilteredMetadata::Basic(metadata.unwrap()),
353 unsafe_: unsafe_metadata,
354 }),
355 ResponseType::Cors => Ok(FetchMetadata::Filtered {
356 filtered: FilteredMetadata::Cors(metadata.unwrap()),
357 unsafe_: unsafe_metadata,
358 }),
359 ResponseType::Default => unreachable!(),
360 ResponseType::Error(ref network_err) => Err(network_err.clone()),
361 ResponseType::Opaque => Ok(FetchMetadata::Filtered {
362 filtered: FilteredMetadata::Opaque,
363 unsafe_: unsafe_metadata,
364 }),
365 ResponseType::OpaqueRedirect => Ok(FetchMetadata::Filtered {
366 filtered: FilteredMetadata::OpaqueRedirect(url.clone()),
367 unsafe_: unsafe_metadata,
368 }),
369 }
370 },
371 None => Err(NetworkError::ResourceLoadError(
372 "No url found in unsafe response".to_owned(),
373 )),
374 }
375 } else {
376 assert_eq!(self.response_type, ResponseType::Default);
377 Ok(FetchMetadata::Unfiltered(metadata.unwrap()))
378 }
379 }
380}