1#[cfg(feature = "timezone")]
2use crate::Result;
3
4use serde::de::DeserializeOwned;
5use wasm_bindgen::JsCast;
6
7#[derive(Debug, Clone)]
11pub struct Cf {
12 inner: worker_sys::IncomingRequestCfProperties,
13}
14
15unsafe impl Send for Cf {}
16unsafe impl Sync for Cf {}
17
18impl Cf {
19 #[cfg(feature = "http")]
20 pub(crate) fn new(inner: worker_sys::IncomingRequestCfProperties) -> Self {
21 Self { inner }
22 }
23
24 #[cfg(feature = "http")]
25 pub(crate) fn inner(&self) -> &worker_sys::IncomingRequestCfProperties {
26 &self.inner
27 }
28
29 pub fn colo(&self) -> String {
32 self.inner.colo().unwrap()
33 }
34
35 pub fn asn(&self) -> Option<u32> {
37 self.inner.asn().unwrap()
38 }
39
40 pub fn as_organization(&self) -> Option<String> {
42 self.inner.as_organization().unwrap()
43 }
44
45 pub fn country(&self) -> Option<String> {
48 self.inner.country().unwrap()
49 }
50
51 pub fn http_protocol(&self) -> String {
53 self.inner.http_protocol().unwrap()
54 }
55
56 pub fn request_priority(&self) -> Option<RequestPriority> {
60 if let Some(priority) = self.inner.request_priority().unwrap() {
61 let mut weight = 1;
62 let mut exclusive = false;
63 let mut group = 0;
64 let mut group_weight = 0;
65
66 priority
67 .as_str()
68 .split(';')
69 .map(|key_value_pair| {
70 let mut iter = key_value_pair.split('=');
71
72 let key = iter.next().unwrap(); let value = iter.next().unwrap(); (key, value)
77 })
78 .for_each(|(key, value)| match key {
79 "weight" => weight = value.parse().unwrap(),
80 "exclusive" => exclusive = value == "1",
81 "group" => group = value.parse().unwrap(),
82 "group-weight" => group_weight = value.parse().unwrap(),
83 _ => unreachable!(),
84 });
85
86 Some(RequestPriority {
87 weight,
88 exclusive,
89 group,
90 group_weight,
91 })
92 } else {
93 None
94 }
95 }
96
97 pub fn tls_cipher(&self) -> String {
99 self.inner.tls_cipher().unwrap()
100 }
101
102 pub fn tls_client_auth(&self) -> Option<TlsClientAuth> {
105 self.inner.tls_client_auth().unwrap().map(Into::into)
106 }
107
108 pub fn tls_version(&self) -> String {
110 self.inner.tls_version().unwrap()
112 }
113
114 pub fn city(&self) -> Option<String> {
116 self.inner.city().unwrap()
117 }
118
119 pub fn continent(&self) -> Option<String> {
121 self.inner.continent().unwrap()
122 }
123
124 pub fn coordinates(&self) -> Option<(f32, f32)> {
126 let lat_opt = self.inner.latitude().unwrap();
127 let lon_opt = self.inner.longitude().unwrap();
128 match (lat_opt, lon_opt) {
129 (Some(lat_str), Some(lon_str)) => {
130 let lat = lat_str.parse().unwrap();
132 let lon = lon_str.parse().unwrap();
133 Some((lat, lon))
134 }
135 _ => None,
136 }
137 }
138
139 pub fn postal_code(&self) -> Option<String> {
141 self.inner.postal_code().unwrap()
142 }
143
144 pub fn metro_code(&self) -> Option<String> {
146 self.inner.metro_code().unwrap()
147 }
148
149 pub fn region(&self) -> Option<String> {
151 self.inner.region().unwrap()
152 }
153
154 pub fn region_code(&self) -> Option<String> {
156 self.inner.region_code().unwrap()
157 }
158
159 #[cfg(feature = "timezone")]
161 pub fn timezone(&self) -> Result<impl chrono::TimeZone> {
162 let tz = self.inner.timezone()?;
163 Ok(tz.parse::<chrono_tz::Tz>()?)
164 }
165
166 pub fn timezone_name(&self) -> String {
168 self.inner.timezone().unwrap()
169 }
170
171 pub fn is_eu_country(&self) -> bool {
173 self.inner.is_eu_country().unwrap() == Some("1".to_string())
174 }
175
176 pub fn host_metadata<T: serde::de::DeserializeOwned>(&self) -> crate::Result<Option<T>> {
177 let host_metadata = self.inner.host_metadata()?;
178 if host_metadata.is_undefined() {
179 Ok(None)
180 } else {
181 serde_wasm_bindgen::from_value(host_metadata)
182 .map(Some)
183 .map_err(|e| wasm_bindgen::JsValue::from(e.to_string()))
184 }
185 .map_err(crate::Error::from)
186 }
187}
188
189#[derive(Debug, Clone, Copy)]
191pub struct RequestPriority {
192 pub weight: usize,
194
195 pub exclusive: bool,
197
198 pub group: usize,
200
201 pub group_weight: usize,
203}
204
205impl From<worker_sys::IncomingRequestCfProperties> for Cf {
206 fn from(inner: worker_sys::IncomingRequestCfProperties) -> Self {
207 Self { inner }
208 }
209}
210
211#[derive(Debug)]
213pub struct TlsClientAuth {
214 inner: worker_sys::TlsClientAuth,
215}
216
217impl TlsClientAuth {
218 pub fn cert_issuer_dn_legacy(&self) -> String {
219 self.inner.cert_issuer_dn_legacy().unwrap()
220 }
221
222 pub fn cert_issuer_dn(&self) -> String {
223 self.inner.cert_issuer_dn().unwrap()
224 }
225
226 pub fn cert_issuer_dn_rfc2253(&self) -> String {
227 self.inner.cert_issuer_dn_rfc2253().unwrap()
228 }
229
230 pub fn cert_subject_dn_legacy(&self) -> String {
231 self.inner.cert_subject_dn_legacy().unwrap()
232 }
233
234 pub fn cert_verified(&self) -> String {
235 self.inner.cert_verified().unwrap()
236 }
237
238 pub fn cert_not_after(&self) -> String {
239 self.inner.cert_not_after().unwrap()
240 }
241
242 pub fn cert_subject_dn(&self) -> String {
243 self.inner.cert_subject_dn().unwrap()
244 }
245
246 pub fn cert_fingerprint_sha1(&self) -> String {
247 self.inner.cert_fingerprint_sha1().unwrap()
248 }
249
250 pub fn cert_fingerprint_sha256(&self) -> String {
251 self.inner.cert_fingerprint_sha256().unwrap()
252 }
253
254 pub fn cert_not_before(&self) -> String {
255 self.inner.cert_not_before().unwrap()
256 }
257
258 pub fn cert_serial(&self) -> String {
259 self.inner.cert_serial().unwrap()
260 }
261
262 pub fn cert_presented(&self) -> String {
263 self.inner.cert_presented().unwrap()
264 }
265
266 pub fn cert_subject_dn_rfc2253(&self) -> String {
267 self.inner.cert_subject_dn_rfc2253().unwrap()
268 }
269}
270
271impl From<worker_sys::TlsClientAuth> for TlsClientAuth {
272 fn from(inner: worker_sys::TlsClientAuth) -> Self {
273 Self { inner }
274 }
275}
276
277#[derive(Clone, Debug)]
278pub struct CfResponseProperties(pub(crate) js_sys::Object);
279
280impl CfResponseProperties {
281 pub fn into_raw(self) -> js_sys::Object {
282 self.0
283 }
284
285 pub fn try_into<T: DeserializeOwned>(self) -> crate::Result<T> {
286 Ok(serde_wasm_bindgen::from_value(self.0.unchecked_into())?)
287 }
288}
289
290unsafe impl Send for CfResponseProperties {}
291unsafe impl Sync for CfResponseProperties {}