wasm_framework/
request.rs1use crate::js_values;
2use crate::{Error, Method};
3use serde::de::DeserializeOwned;
4use std::borrow::Cow;
5use url::Url;
6use wasm_bindgen::JsValue;
7
8#[derive(Debug, Clone)]
10pub struct Request {
11 method: Method,
12 url: Url,
13 headers: web_sys::Headers,
14 body: Option<Vec<u8>>,
15}
16unsafe impl Sync for Request {}
17
18impl Request {
19 pub fn new(
21 method: Method,
22 url: Url,
23 headers: web_sys::Headers,
24 body: Option<Vec<u8>>,
25 ) -> Request {
26 Request {
27 method,
28 url,
29 headers,
30 body,
31 }
32 }
33
34 pub(crate) fn from_js(map: &js_sys::Map) -> Result<Self, JsValue> {
36 Ok(Request::new(
37 Method::from(
38 &js_values::get_map_str(&map, "method")
39 .ok_or_else(|| JsValue::from_str("invalid_req.method"))?,
40 )?,
41 Url::parse(
42 &js_values::get_map_str(&map, "url")
43 .ok_or_else(|| JsValue::from_str("invalid_req.url"))?,
44 )
45 .map_err(|e| JsValue::from_str(&format!("invalid req.url:{}", e.to_string())))?,
46 js_values::get_map_headers(&map, "headers")
47 .ok_or_else(|| JsValue::from_str("invalid_req"))?,
48 js_values::get_map_bytes(&map, "body"),
49 ))
50 }
51
52 pub fn method(&self) -> Method {
54 self.method
55 }
56
57 pub fn url(&self) -> &Url {
59 &self.url
60 }
61
62 pub fn headers(&self) -> &web_sys::Headers {
64 &self.headers
65 }
66
67 pub fn get_header(&self, name: &str) -> Option<String> {
70 match self.headers.get(name) {
71 Ok(v) => v,
72 Err(_) => None,
73 }
74 }
75
76 pub fn has_header(&self, name: &str) -> bool {
78 self.headers.has(name).unwrap_or(false)
79 }
80
81 pub fn is_empty(&self) -> bool {
83 self.body.is_none() || self.body.as_ref().unwrap().is_empty()
84 }
85
86 pub fn body(&self) -> Option<&Vec<u8>> {
88 self.body.as_ref()
89 }
90
91 pub fn json<T: DeserializeOwned>(&self) -> Result<T, Error> {
93 if let Some(vec) = self.body.as_ref() {
94 Ok(serde_json::from_slice(vec)?)
95 } else {
96 Err(Error::Other("body is empty".to_string()))
97 }
98 }
99
100 pub fn get_cookie_value(&self, cookie_name: &str) -> Option<String> {
102 self.get_header("cookie")
103 .map(|cookie| {
104 (&cookie)
105 .split(';')
106 .map(|s| s.trim())
108 .find_map(|part| cookie_value(part, cookie_name))
110 .map(|v| v.to_string())
111 })
112 .unwrap_or_default()
113 }
114
115 pub fn get_query_value<'req>(&'req self, key: &'_ str) -> Option<Cow<'req, str>> {
117 self.url()
118 .query_pairs()
119 .find(|(k, _)| k == key)
120 .map(|(_, v)| v)
121 }
122}
123
124fn cookie_value<'cookie>(part: &'cookie str, name: &str) -> Option<&'cookie str> {
126 if part.len() > name.len() {
127 let (left, right) = part.split_at(name.len());
128 if left == name && right.starts_with('=') {
129 return Some(&right[1..]);
130 }
131 }
132 None
133}
134
135#[test]
136fn test_cookie_value() {
138 assert_eq!(cookie_value("x=y", "x"), Some("y"));
140
141 assert_eq!(cookie_value("foo=bar", "foo"), Some("bar"));
143
144 assert_eq!(cookie_value("x=y", "z"), None);
146
147 assert_eq!(cookie_value("foo=", "foo"), Some(""));
149}