sciter/
request.rs

1/*! Sciter Request API.
2
3Handling all attributes of requests (GET/POST/PUT/DELETE) sent by
4[`Element.request()`](https://sciter.com/docs/content/sciter/Element.htm) and
5[`View.request()`](https://sciter.com/docs/content/sciter/View.htm)
6functions and other load requests.
7
8*/
9pub use capi::screquest::{HREQUEST, REQUEST_RESULT};
10pub use capi::screquest::{REQUEST_METHOD, REQUEST_STATE, REQUEST_TYPE, RESOURCE_TYPE};
11
12use capi::sctypes::{LPVOID, UINT};
13use capi::scdef::{LPCWSTR_RECEIVER};
14
15use utf::{store_astr, store_wstr, store_bstr};
16
17use _RAPI;
18
19
20
21macro_rules! ok_or {
22	($ok:ident) => {
23		ok_or!((), $ok)
24	};
25
26  ($rv:expr, $ok:ident) => {
27    if $ok == REQUEST_RESULT::OK {
28      Ok($rv)
29    } else {
30      Err($ok)
31    }
32  };
33}
34
35/// A specialized `Result` type for request operations.
36pub type Result<T> = ::std::result::Result<T, REQUEST_RESULT>;
37
38type GetCountFn = extern "system" fn (rq: HREQUEST, pNumber: &mut UINT) -> REQUEST_RESULT;
39type GetNameFn = extern "system" fn (rq: HREQUEST, n: UINT, rcv: LPCWSTR_RECEIVER, rcv_param: LPVOID) -> REQUEST_RESULT;
40type GetValueFn = extern "system" fn (rq: HREQUEST, n: UINT, rcv: LPCWSTR_RECEIVER, rcv_param: LPVOID) -> REQUEST_RESULT;
41
42/// Request object.
43///
44/// Can be constructed from a `HREQUEST` handle only:
45///
46/// ```rust,no_run
47/// # use sciter::request::Request;
48/// # use sciter::host::{SCN_LOAD_DATA, LOAD_RESULT};
49/// fn on_data_load(pnm: &mut SCN_LOAD_DATA) -> Option<LOAD_RESULT> {
50///   let mut rq = Request::from(pnm.request_id);
51///   // ...
52///   # None
53/// }
54/// ```
55pub struct Request(HREQUEST);
56
57/// Destroy the object.
58impl Drop for Request {
59	fn drop(&mut self) {
60		(_RAPI.RequestUnUse)(self.0);
61	}
62}
63
64/// Copies the object.
65///
66/// All allocated objects are reference counted so copying is just a matter of increasing reference counts.
67impl Clone for Request {
68	fn clone(&self) -> Self {
69		let dst = Request(self.0);
70		(_RAPI.RequestUse)(dst.0);
71		dst
72	}
73}
74
75/// Construct a Request object from `HREQUEST` handle.
76impl From<HREQUEST> for Request {
77	fn from(hrq: HREQUEST) -> Request {
78		assert!(!hrq.is_null());
79  	(_RAPI.RequestUse)(hrq);
80		Request(hrq)
81	}
82}
83
84impl Request {
85	/// Mark the request as complete with status and optional data.
86	pub fn succeeded(&mut self, status: u32, data: Option<&[u8]>) -> Result<()> {
87		let (ptr, size) = if let Some(data) = data {
88			(data.as_ptr(), data.len() as u32)
89		} else {
90			(std::ptr::null(), 0_u32)
91		};
92		let ok = (_RAPI.RequestSetSucceeded)(self.0, status, ptr, size);
93		ok_or!(ok)
94	}
95
96	/// Mark the request as complete with failure.
97	pub fn failed(&mut self, status: u32, data: Option<&[u8]>) -> Result<()> {
98		let (ptr, size) = if let Some(data) = data {
99			(data.as_ptr(), data.len() as u32)
100		} else {
101			(std::ptr::null(), 0_u32)
102		};
103		let ok = (_RAPI.RequestSetSucceeded)(self.0, status, ptr, size);
104		ok_or!(ok)
105	}
106
107	/// Append a data chunk to the received data.
108	pub fn append_received_data(&mut self, data: &[u8]) -> Result<()> {
109		let (ptr, size) = (data.as_ptr(), data.len() as u32);
110		let ok = (_RAPI.RequestAppendDataChunk)(self.0, ptr, size);
111		ok_or!(ok)
112	}
113
114	/// Get received (so far) data.
115	pub fn get_received_data(&self) -> Result<Vec<u8>> {
116		let mut data = Vec::new();
117		let ok = (_RAPI.RequestGetData)(self.0, store_bstr, &mut data as *mut _ as LPVOID);
118		ok_or!(data, ok)
119	}
120
121	/// Get the URL of the request.
122	pub fn url(&self) -> Result<String> {
123		let mut s = String::new();
124		let ok = (_RAPI.RequestUrl)(self.0, store_astr, &mut s as *mut _ as LPVOID);
125		ok_or!(s, ok)
126	}
127
128	/// Get a real URL of the content (e.g., after possible redirection).
129	pub fn content_url(&self) -> Result<String> {
130		let mut s = String::new();
131		let ok = (_RAPI.RequestContentUrl)(self.0, store_astr, &mut s as *mut _ as LPVOID);
132		ok_or!(s, ok)
133	}
134
135	/// Get the data type of the request.
136	pub fn method(&self) -> Result<REQUEST_METHOD> {
137		let mut t = REQUEST_METHOD::GET;
138		let ok = (_RAPI.RequestGetRequestType)(self.0, &mut t);
139		ok_or!(t, ok)
140	}
141
142	/// Get the resource data type of the request.
143	pub fn request_type(&self) -> Result<RESOURCE_TYPE> {
144		let mut t = RESOURCE_TYPE::RAW;
145		let ok = (_RAPI.RequestGetRequestedDataType)(self.0, &mut t);
146		ok_or!(t, ok)
147	}
148
149	/// Get the MIME type of the received data.
150	pub fn response_type(&self) -> Result<String> {
151		let mut s = String::new();
152		let ok = (_RAPI.RequestGetReceivedDataType)(self.0, store_astr, &mut s as *mut _ as LPVOID);
153		ok_or!(s, ok)
154	}
155
156	/// Set the MIME type of the received data.
157	pub fn set_response_type(&mut self, mime_type: &str) -> Result<()> {
158		let text = s2u!(mime_type);
159		let ok = (_RAPI.RequestSetReceivedDataType)(self.0, text.as_ptr());
160		ok_or!(ok)
161	}
162
163	/// Set the data encoding for the received data.
164	pub fn set_response_encoding(&mut self, encoding_type: &str) -> Result<()> {
165		let text = s2u!(encoding_type);
166		let ok = (_RAPI.RequestSetReceivedDataEncoding)(self.0, text.as_ptr());
167		ok_or!(ok)
168	}
169
170	fn get_collection_impl(&self, get_count: GetCountFn, get_name: GetNameFn, get_value: GetValueFn) -> Result<std::collections::HashMap<String, String>>	{
171		let mut count = 0;
172		let ok = get_count(self.0, &mut count);
173		if ok != REQUEST_RESULT::OK {
174			return Err(ok);
175		}
176
177		let mut args = std::collections::HashMap::with_capacity(count as usize);
178		for i in 0..count {
179			let mut name = String::new();
180			let mut ok = get_name(self.0, i, store_wstr, &mut name as *mut _ as LPVOID);
181			if ok == REQUEST_RESULT::OK {
182				let mut value = String::new();
183				ok = get_value(self.0, i, store_wstr, &mut value as *mut _ as LPVOID);
184				if ok == REQUEST_RESULT::OK {
185					args.insert(name, value);
186				}
187			}
188			if ok != REQUEST_RESULT::OK {
189				return Err(ok);
190			}
191		}
192
193		Ok(args)
194	}
195
196	/// Get the parameters of the request.
197	pub fn parameters(&self) -> Result<std::collections::HashMap<String, String>> {
198		self.get_collection_impl(_RAPI.RequestGetNumberOfParameters, _RAPI.RequestGetNthParameterName, _RAPI.RequestGetNthParameterValue)
199	}
200
201	/// Get the headers of the request.
202	pub fn request_headers(&self) -> Result<std::collections::HashMap<String, String>> {
203		self.get_collection_impl(_RAPI.RequestGetNumberOfRqHeaders, _RAPI.RequestGetNthRqHeaderName, _RAPI.RequestGetNthRqHeaderValue)
204	}
205
206	/// Set request header (a single item).
207	pub fn set_request_header(&mut self, name: &str, value: &str) -> Result<()> {
208		let wname = s2w!(name);
209		let wtext = s2w!(value);
210		let ok = (_RAPI.RequestSetRqHeader)(self.0, wname.as_ptr(), wtext.as_ptr());
211		ok_or!(ok)
212	}
213
214	/// Get the headers of the response.
215	pub fn response_headers(&self) -> Result<std::collections::HashMap<String, String>> {
216		self.get_collection_impl(_RAPI.RequestGetNumberOfRspHeaders, _RAPI.RequestGetNthRspHeaderName, _RAPI.RequestGetNthRspHeaderValue)
217	}
218
219	/// Set respone header (a single item).
220	pub fn set_response_header(&mut self, name: &str, value: &str) -> Result<()> {
221		let wname = s2w!(name);
222		let wtext = s2w!(value);
223		let ok = (_RAPI.RequestSetRspHeader)(self.0, wname.as_ptr(), wtext.as_ptr());
224		ok_or!(ok)
225	}
226
227	/// Get proxy host and port (if any).
228	pub fn proxy(&self) -> Result<(String, u16)> {
229		let mut s = String::new();
230		let mut ok = (_RAPI.RequestGetProxyHost)(self.0, store_astr, &mut s as *mut _ as LPVOID);
231		if ok == REQUEST_RESULT::OK {
232			let mut n = 0_u32;
233			ok = (_RAPI.RequestGetProxyPort)(self.0, &mut n);
234			if ok == REQUEST_RESULT::OK {
235				return Ok((s, n as u16));
236			}
237		}
238		Err(ok)
239	}
240
241	/// Get the current completion status of the request.
242	///
243	/// Returns current state and HTTP response code.
244	pub fn completion_status(&self) -> Result<(REQUEST_STATE, u32)> {
245		let mut state = REQUEST_STATE::SUCCESS;
246		let mut code = 0_u32;
247		let ok = (_RAPI.RequestGetCompletionStatus)(self.0, &mut state, &mut code);
248		ok_or!((state, code), ok)
249	}
250
251	/// Get the execution duratiom of the request.
252	pub fn request_duration(&self) -> Result<std::time::Duration> {
253		let mut started = 0;
254		let mut ended = 0;
255		let ok = (_RAPI.RequestGetTimes)(self.0, &mut started, &mut ended);
256		if ok == REQUEST_RESULT::OK && ended > started {
257			let d = std::time::Duration::from_millis(ended as u64 - started as u64);
258			Ok(d)
259		} else {
260			Err(ok)
261		}
262	}
263
264	/// Get the execution `started` and `ended` time of the request, in milliseconds.
265	pub fn request_time(&self) -> Result<(std::time::Duration, std::time::Duration)> {
266		let mut started = 0;
267		let mut ended = 0;
268		let ok = (_RAPI.RequestGetTimes)(self.0, &mut started, &mut ended);
269		if ok == REQUEST_RESULT::OK {
270			use std::time::Duration;
271			let s = Duration::from_millis(started as u64);
272			let e = Duration::from_millis(ended as u64);
273			Ok((s, e))
274		} else {
275			Err(ok)
276		}
277	}
278
279}