1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use ReferrerPolicy;
6 use hyper::header::Headers;
7 use hyper::method::Method;
8 use msg::constellation_msg::PipelineId;
9 use servo_url::{ImmutableOrigin, ServoUrl};
10 use std::default::Default;
11 
12 /// An [initiator](https://fetch.spec.whatwg.org/#concept-request-initiator)
13 #[derive(Clone, Copy, MallocSizeOf, PartialEq)]
14 pub enum Initiator {
15     None,
16     Download,
17     ImageSet,
18     Manifest,
19     XSLT,
20 }
21 
22 /// A request [destination](https://fetch.spec.whatwg.org/#concept-request-destination)
23 #[derive(Clone, Copy, Deserialize, MallocSizeOf, PartialEq, Serialize)]
24 pub enum Destination {
25     None,
26     Audio,
27     Document,
28     Embed,
29     Font,
30     Image,
31     Manifest,
32     Object,
33     Report,
34     Script,
35     ServiceWorker,
36     SharedWorker,
37     Style,
38     Track,
39     Video,
40     Worker,
41     Xslt,
42 }
43 
44 impl Destination {
45     /// https://fetch.spec.whatwg.org/#request-destination-script-like
46     #[inline]
is_script_like(&self) -> bool47     pub fn is_script_like(&self) -> bool {
48         *self == Destination::Script ||
49         *self == Destination::ServiceWorker ||
50         *self == Destination::SharedWorker ||
51         *self == Destination::Worker
52     }
53 }
54 
55 /// A request [origin](https://fetch.spec.whatwg.org/#concept-request-origin)
56 #[derive(Clone, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
57 pub enum Origin {
58     Client,
59     Origin(ImmutableOrigin),
60 }
61 
62 /// A [referer](https://fetch.spec.whatwg.org/#concept-request-referrer)
63 #[derive(Clone, Deserialize, MallocSizeOf, PartialEq, Serialize)]
64 pub enum Referrer {
65     NoReferrer,
66     /// Default referrer if nothing is specified
67     Client,
68     ReferrerUrl(ServoUrl),
69 }
70 
71 /// A [request mode](https://fetch.spec.whatwg.org/#concept-request-mode)
72 #[derive(Clone, Deserialize, MallocSizeOf, PartialEq, Serialize)]
73 pub enum RequestMode {
74     Navigate,
75     SameOrigin,
76     NoCors,
77     CorsMode,
78     WebSocket { protocols: Vec<String> }
79 }
80 
81 /// Request [credentials mode](https://fetch.spec.whatwg.org/#concept-request-credentials-mode)
82 #[derive(Clone, Copy, Deserialize, MallocSizeOf, PartialEq, Serialize)]
83 pub enum CredentialsMode {
84     Omit,
85     CredentialsSameOrigin,
86     Include,
87 }
88 
89 /// [Cache mode](https://fetch.spec.whatwg.org/#concept-request-cache-mode)
90 #[derive(Clone, Copy, Deserialize, MallocSizeOf, PartialEq, Serialize)]
91 pub enum CacheMode {
92     Default,
93     NoStore,
94     Reload,
95     NoCache,
96     ForceCache,
97     OnlyIfCached,
98 }
99 
100 /// [Service-workers mode](https://fetch.spec.whatwg.org/#request-service-workers-mode)
101 #[derive(Clone, Copy, Deserialize, MallocSizeOf, PartialEq, Serialize)]
102 pub enum ServiceWorkersMode {
103     All,
104     Foreign,
105     None,
106 }
107 
108 /// [Redirect mode](https://fetch.spec.whatwg.org/#concept-request-redirect-mode)
109 #[derive(Clone, Copy, Deserialize, MallocSizeOf, PartialEq, Serialize)]
110 pub enum RedirectMode {
111     Follow,
112     Error,
113     Manual,
114 }
115 
116 /// [Response tainting](https://fetch.spec.whatwg.org/#concept-request-response-tainting)
117 #[derive(Clone, Copy, MallocSizeOf, PartialEq)]
118 pub enum ResponseTainting {
119     Basic,
120     CorsTainting,
121     Opaque,
122 }
123 
124 /// [Window](https://fetch.spec.whatwg.org/#concept-request-window)
125 #[derive(Clone, Copy, MallocSizeOf, PartialEq)]
126 pub enum Window {
127     NoWindow,
128     Client, // TODO: Environmental settings object
129 }
130 
131 /// [CORS settings attribute](https://html.spec.whatwg.org/multipage/#attr-crossorigin-anonymous)
132 #[derive(Clone, Copy, Deserialize, PartialEq, Serialize)]
133 pub enum CorsSettings {
134     Anonymous,
135     UseCredentials,
136 }
137 
138 #[derive(Clone, Deserialize, MallocSizeOf, Serialize)]
139 pub struct RequestInit {
140     #[serde(deserialize_with = "::hyper_serde::deserialize",
141             serialize_with = "::hyper_serde::serialize")]
142     #[ignore_malloc_size_of = "Defined in hyper"]
143     pub method: Method,
144     pub url: ServoUrl,
145     #[serde(deserialize_with = "::hyper_serde::deserialize",
146             serialize_with = "::hyper_serde::serialize")]
147     #[ignore_malloc_size_of = "Defined in hyper"]
148     pub headers: Headers,
149     pub unsafe_request: bool,
150     pub body: Option<Vec<u8>>,
151     pub service_workers_mode: ServiceWorkersMode,
152     // TODO: client object
153     pub destination: Destination,
154     pub synchronous: bool,
155     pub mode: RequestMode,
156     pub cache_mode: CacheMode,
157     pub use_cors_preflight: bool,
158     pub credentials_mode: CredentialsMode,
159     pub use_url_credentials: bool,
160     pub origin: ImmutableOrigin,
161     // XXXManishearth these should be part of the client object
162     pub referrer_url: Option<ServoUrl>,
163     pub referrer_policy: Option<ReferrerPolicy>,
164     pub pipeline_id: Option<PipelineId>,
165     pub redirect_mode: RedirectMode,
166     pub integrity_metadata: String,
167     // to keep track of redirects
168     pub url_list: Vec<ServoUrl>,
169 }
170 
171 impl Default for RequestInit {
default() -> RequestInit172     fn default() -> RequestInit {
173         RequestInit {
174             method: Method::Get,
175             url: ServoUrl::parse("about:blank").unwrap(),
176             headers: Headers::new(),
177             unsafe_request: false,
178             body: None,
179             service_workers_mode: ServiceWorkersMode::All,
180             destination: Destination::None,
181             synchronous: false,
182             mode: RequestMode::NoCors,
183             cache_mode: CacheMode::Default,
184             use_cors_preflight: false,
185             credentials_mode: CredentialsMode::Omit,
186             use_url_credentials: false,
187             origin: ImmutableOrigin::new_opaque(),
188             referrer_url: None,
189             referrer_policy: None,
190             pipeline_id: None,
191             redirect_mode: RedirectMode::Follow,
192             integrity_metadata: "".to_owned(),
193             url_list: vec![],
194         }
195     }
196 }
197 
198 /// A [Request](https://fetch.spec.whatwg.org/#concept-request) as defined by
199 /// the Fetch spec.
200 #[derive(Clone, MallocSizeOf)]
201 pub struct Request {
202     /// <https://fetch.spec.whatwg.org/#concept-request-method>
203     #[ignore_malloc_size_of = "Defined in hyper"]
204     pub method: Method,
205     /// <https://fetch.spec.whatwg.org/#local-urls-only-flag>
206     pub local_urls_only: bool,
207     /// <https://fetch.spec.whatwg.org/#sandboxed-storage-area-urls-flag>
208     pub sandboxed_storage_area_urls: bool,
209     /// <https://fetch.spec.whatwg.org/#concept-request-header-list>
210     #[ignore_malloc_size_of = "Defined in hyper"]
211     pub headers: Headers,
212     /// <https://fetch.spec.whatwg.org/#unsafe-request-flag>
213     pub unsafe_request: bool,
214     /// <https://fetch.spec.whatwg.org/#concept-request-body>
215     pub body: Option<Vec<u8>>,
216     // TODO: client object
217     pub window: Window,
218     // TODO: target browsing context
219     /// <https://fetch.spec.whatwg.org/#request-keepalive-flag>
220     pub keep_alive: bool,
221     /// <https://fetch.spec.whatwg.org/#request-service-workers-mode>
222     pub service_workers_mode: ServiceWorkersMode,
223     /// <https://fetch.spec.whatwg.org/#concept-request-initiator>
224     pub initiator: Initiator,
225     /// <https://fetch.spec.whatwg.org/#concept-request-destination>
226     pub destination: Destination,
227     // TODO: priority object
228     /// <https://fetch.spec.whatwg.org/#concept-request-origin>
229     pub origin: Origin,
230     /// <https://fetch.spec.whatwg.org/#concept-request-referrer>
231     pub referrer: Referrer,
232     /// <https://fetch.spec.whatwg.org/#concept-request-referrer-policy>
233     pub referrer_policy: Option<ReferrerPolicy>,
234     pub pipeline_id: Option<PipelineId>,
235     /// <https://fetch.spec.whatwg.org/#synchronous-flag>
236     pub synchronous: bool,
237     /// <https://fetch.spec.whatwg.org/#concept-request-mode>
238     pub mode: RequestMode,
239     /// <https://fetch.spec.whatwg.org/#use-cors-preflight-flag>
240     pub use_cors_preflight: bool,
241     /// <https://fetch.spec.whatwg.org/#concept-request-credentials-mode>
242     pub credentials_mode: CredentialsMode,
243     /// <https://fetch.spec.whatwg.org/#concept-request-use-url-credentials-flag>
244     pub use_url_credentials: bool,
245     /// <https://fetch.spec.whatwg.org/#concept-request-cache-mode>
246     pub cache_mode: CacheMode,
247     /// <https://fetch.spec.whatwg.org/#concept-request-redirect-mode>
248     pub redirect_mode: RedirectMode,
249     /// <https://fetch.spec.whatwg.org/#concept-request-integrity-metadata>
250     pub integrity_metadata: String,
251     // Use the last method on url_list to act as spec current url field, and
252     // first method to act as spec url field
253     /// <https://fetch.spec.whatwg.org/#concept-request-url-list>
254     pub url_list: Vec<ServoUrl>,
255     /// <https://fetch.spec.whatwg.org/#concept-request-redirect-count>
256     pub redirect_count: u32,
257     /// <https://fetch.spec.whatwg.org/#concept-request-response-tainting>
258     pub response_tainting: ResponseTainting,
259 }
260 
261 impl Request {
new(url: ServoUrl, origin: Option<Origin>, pipeline_id: Option<PipelineId>) -> Request262     pub fn new(url: ServoUrl,
263                origin: Option<Origin>,
264                pipeline_id: Option<PipelineId>)
265                -> Request {
266         Request {
267             method: Method::Get,
268             local_urls_only: false,
269             sandboxed_storage_area_urls: false,
270             headers: Headers::new(),
271             unsafe_request: false,
272             body: None,
273             window: Window::Client,
274             keep_alive: false,
275             service_workers_mode: ServiceWorkersMode::All,
276             initiator: Initiator::None,
277             destination: Destination::None,
278             origin: origin.unwrap_or(Origin::Client),
279             referrer: Referrer::Client,
280             referrer_policy: None,
281             pipeline_id: pipeline_id,
282             synchronous: false,
283             mode: RequestMode::NoCors,
284             use_cors_preflight: false,
285             credentials_mode: CredentialsMode::Omit,
286             use_url_credentials: false,
287             cache_mode: CacheMode::Default,
288             redirect_mode: RedirectMode::Follow,
289             integrity_metadata: String::new(),
290             url_list: vec![url],
291             redirect_count: 0,
292             response_tainting: ResponseTainting::Basic,
293         }
294     }
295 
from_init(init: RequestInit) -> Request296     pub fn from_init(init: RequestInit) -> Request {
297         let mut req = Request::new(init.url.clone(),
298                                    Some(Origin::Origin(init.origin)),
299                                    init.pipeline_id);
300         req.method = init.method;
301         req.headers = init.headers;
302         req.unsafe_request = init.unsafe_request;
303         req.body = init.body;
304         req.service_workers_mode = init.service_workers_mode;
305         req.destination = init.destination;
306         req.synchronous = init.synchronous;
307         req.mode = init.mode;
308         req.use_cors_preflight = init.use_cors_preflight;
309         req.credentials_mode = init.credentials_mode;
310         req.use_url_credentials = init.use_url_credentials;
311         req.cache_mode = init.cache_mode;
312         req.referrer = if let Some(url) = init.referrer_url {
313             Referrer::ReferrerUrl(url)
314         } else {
315             Referrer::NoReferrer
316         };
317         req.referrer_policy = init.referrer_policy;
318         req.pipeline_id = init.pipeline_id;
319         req.redirect_mode = init.redirect_mode;
320         let mut url_list = init.url_list;
321         if url_list.is_empty() {
322             url_list.push(init.url);
323         }
324         req.redirect_count = url_list.len() as u32 - 1;
325         req.url_list = url_list;
326         req.integrity_metadata = init.integrity_metadata;
327         req
328     }
329 
330     /// <https://fetch.spec.whatwg.org/#concept-request-url>
url(&self) -> ServoUrl331     pub fn url(&self) -> ServoUrl {
332         self.url_list.first().unwrap().clone()
333     }
334 
335     /// <https://fetch.spec.whatwg.org/#concept-request-current-url>
current_url(&self) -> ServoUrl336     pub fn current_url(&self) -> ServoUrl {
337         self.url_list.last().unwrap().clone()
338     }
339 
340     /// <https://fetch.spec.whatwg.org/#concept-request-current-url>
current_url_mut(&mut self) -> &mut ServoUrl341     pub fn current_url_mut(&mut self) -> &mut ServoUrl {
342         self.url_list.last_mut().unwrap()
343     }
344 
345     /// <https://fetch.spec.whatwg.org/#navigation-request>
is_navigation_request(&self) -> bool346     pub fn is_navigation_request(&self) -> bool {
347         self.destination == Destination::Document
348     }
349 
350     /// <https://fetch.spec.whatwg.org/#subresource-request>
is_subresource_request(&self) -> bool351     pub fn is_subresource_request(&self) -> bool {
352         match self.destination {
353             Destination::Audio | Destination::Font | Destination::Image | Destination::Manifest |
354             Destination::Script | Destination::Style | Destination::Track | Destination::Video |
355             Destination::Xslt | Destination::None => true,
356             _ => false,
357         }
358     }
359 }
360 
361 impl Referrer {
to_url(&self) -> Option<&ServoUrl>362     pub fn to_url(&self) -> Option<&ServoUrl> {
363         match *self {
364             Referrer::NoReferrer | Referrer::Client => None,
365             Referrer::ReferrerUrl(ref url) => Some(url),
366         }
367     }
368 }
369