playwright_rs/protocol/
response.rs1use crate::error::Result;
8use crate::server::channel_owner::{ChannelOwner, ChannelOwnerImpl, ParentOrConnection};
9use serde_json::Value;
10use std::any::Any;
11use std::sync::Arc;
12
13#[derive(Debug, Clone)]
19#[non_exhaustive]
20pub struct SecurityDetails {
21 pub issuer: Option<String>,
23 pub protocol: Option<String>,
25 pub subject_name: Option<String>,
27 pub valid_from: Option<f64>,
29 pub valid_to: Option<f64>,
31}
32
33#[derive(Debug, Clone)]
37#[non_exhaustive]
38pub struct RemoteAddr {
39 pub ip_address: String,
41 pub port: u16,
43}
44
45#[derive(Debug, Clone)]
49#[non_exhaustive]
50pub struct RequestSizes {
51 pub request_body_size: i64,
53 pub request_headers_size: i64,
56 pub response_body_size: i64,
58 pub response_headers_size: i64,
61}
62
63#[derive(Debug, Clone)]
69#[non_exhaustive]
70pub struct HeaderEntry {
71 pub name: String,
73 pub value: String,
75}
76
77#[derive(Clone)]
84pub struct ResponseObject {
85 base: ChannelOwnerImpl,
86}
87
88impl ResponseObject {
89 pub fn new(
94 parent: Arc<dyn ChannelOwner>,
95 type_name: String,
96 guid: Arc<str>,
97 initializer: Value,
98 ) -> Result<Self> {
99 let base = ChannelOwnerImpl::new(
100 ParentOrConnection::Parent(parent),
101 type_name,
102 guid,
103 initializer,
104 );
105
106 Ok(Self { base })
107 }
108
109 pub fn status(&self) -> u16 {
113 self.initializer()
114 .get("status")
115 .and_then(|v| v.as_u64())
116 .unwrap_or(0) as u16
117 }
118
119 pub fn status_text(&self) -> &str {
123 self.initializer()
124 .get("statusText")
125 .and_then(|v| v.as_str())
126 .unwrap_or("")
127 }
128
129 pub fn url(&self) -> &str {
133 self.initializer()
134 .get("url")
135 .and_then(|v| v.as_str())
136 .unwrap_or("")
137 }
138
139 #[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid(), bytes_len = tracing::field::Empty))]
146 pub async fn body(&self) -> Result<Vec<u8>> {
147 use serde::Deserialize;
148
149 #[derive(Deserialize)]
150 struct BodyResponse {
151 binary: String,
152 }
153
154 let result: BodyResponse = self.channel().send("body", serde_json::json!({})).await?;
155
156 use base64::Engine;
157 let bytes = base64::engine::general_purpose::STANDARD
158 .decode(&result.binary)
159 .map_err(|e| {
160 crate::error::Error::ProtocolError(format!(
161 "Failed to decode response body from base64: {}",
162 e
163 ))
164 })?;
165 Ok(bytes)
166 }
167
168 #[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid()))]
172 pub async fn security_details(&self) -> Result<Option<SecurityDetails>> {
173 let result: serde_json::Value = self
174 .channel()
175 .send("securityDetails", serde_json::json!({}))
176 .await?;
177
178 let value = result.get("value");
179 match value {
180 Some(v) if v.as_object().is_some_and(|obj| !obj.is_empty()) => {
181 Ok(Some(SecurityDetails {
182 issuer: v.get("issuer").and_then(|v| v.as_str()).map(String::from),
183 protocol: v.get("protocol").and_then(|v| v.as_str()).map(String::from),
184 subject_name: v
185 .get("subjectName")
186 .and_then(|v| v.as_str())
187 .map(String::from),
188 valid_from: v.get("validFrom").and_then(|v| v.as_f64()),
189 valid_to: v.get("validTo").and_then(|v| v.as_f64()),
190 }))
191 }
192 _ => Ok(None),
193 }
194 }
195
196 #[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid()))]
200 pub async fn server_addr(&self) -> Result<Option<RemoteAddr>> {
201 let result: serde_json::Value = self
202 .channel()
203 .send("serverAddr", serde_json::json!({}))
204 .await?;
205
206 let value = result.get("value");
207 match value {
208 Some(v) if !v.is_null() => {
209 let ip_address = v
210 .get("ipAddress")
211 .and_then(|v| v.as_str())
212 .unwrap_or("")
213 .to_string();
214 let port = v.get("port").and_then(|v| v.as_u64()).unwrap_or(0) as u16;
215 Ok(Some(RemoteAddr { ip_address, port }))
216 }
217 _ => Ok(None),
218 }
219 }
220
221 #[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid()))]
225 pub async fn sizes(&self) -> Result<RequestSizes> {
226 use serde::Deserialize;
227
228 #[derive(Deserialize)]
229 #[serde(rename_all = "camelCase")]
230 struct SizesRaw {
231 request_body_size: i64,
232 request_headers_size: i64,
233 response_body_size: i64,
234 response_headers_size: i64,
235 }
236
237 #[derive(Deserialize)]
238 struct RpcResult {
239 sizes: SizesRaw,
240 }
241
242 let result: RpcResult = self.channel().send("sizes", serde_json::json!({})).await?;
243
244 Ok(RequestSizes {
245 request_body_size: result.sizes.request_body_size,
246 request_headers_size: result.sizes.request_headers_size,
247 response_body_size: result.sizes.response_body_size,
248 response_headers_size: result.sizes.response_headers_size,
249 })
250 }
251
252 #[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid(), version = tracing::field::Empty))]
258 pub async fn http_version(&self) -> Result<String> {
259 use serde::Deserialize;
260
261 #[derive(Deserialize)]
262 struct HttpVersionResponse {
263 value: String,
264 }
265
266 let result: HttpVersionResponse = self
267 .channel()
268 .send("httpVersion", serde_json::json!({}))
269 .await?;
270 Ok(result.value)
271 }
272
273 #[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid()))]
279 pub async fn raw_headers(&self) -> Result<Vec<HeaderEntry>> {
280 use serde::Deserialize;
281
282 #[derive(Deserialize)]
283 struct RawHeadersResponse {
284 headers: Vec<HeaderEntryRaw>,
285 }
286
287 #[derive(Deserialize)]
288 struct HeaderEntryRaw {
289 name: String,
290 value: String,
291 }
292
293 let result: RawHeadersResponse = self
294 .channel()
295 .send("rawResponseHeaders", serde_json::json!({}))
296 .await?;
297
298 Ok(result
299 .headers
300 .into_iter()
301 .map(|h| HeaderEntry {
302 name: h.name,
303 value: h.value,
304 })
305 .collect())
306 }
307}
308
309impl ChannelOwner for ResponseObject {
310 fn guid(&self) -> &str {
311 self.base.guid()
312 }
313
314 fn type_name(&self) -> &str {
315 self.base.type_name()
316 }
317
318 fn parent(&self) -> Option<Arc<dyn ChannelOwner>> {
319 self.base.parent()
320 }
321
322 fn connection(&self) -> Arc<dyn crate::server::connection::ConnectionLike> {
323 self.base.connection()
324 }
325
326 fn initializer(&self) -> &Value {
327 self.base.initializer()
328 }
329
330 fn channel(&self) -> &crate::server::channel::Channel {
331 self.base.channel()
332 }
333
334 fn dispose(&self, reason: crate::server::channel_owner::DisposeReason) {
335 self.base.dispose(reason)
336 }
337
338 fn adopt(&self, child: Arc<dyn ChannelOwner>) {
339 self.base.adopt(child)
340 }
341
342 fn add_child(&self, guid: Arc<str>, child: Arc<dyn ChannelOwner>) {
343 self.base.add_child(guid, child)
344 }
345
346 fn remove_child(&self, guid: &str) {
347 self.base.remove_child(guid)
348 }
349
350 fn on_event(&self, _method: &str, _params: Value) {
351 }
353
354 fn was_collected(&self) -> bool {
355 self.base.was_collected()
356 }
357
358 fn as_any(&self) -> &dyn Any {
359 self
360 }
361}
362
363impl std::fmt::Debug for ResponseObject {
364 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
365 f.debug_struct("ResponseObject")
366 .field("guid", &self.guid())
367 .finish()
368 }
369}