playwright_cdp/
response.rs1use crate::cdp::session::CdpSession;
4use crate::error::{Error, Result};
5use crate::request::Request;
6use crate::types::Headers;
7use base64::Engine;
8use parking_lot::Mutex;
9use serde_json::{json, Value};
10use std::sync::Arc;
11
12#[derive(Clone)]
14pub struct Response {
15 inner: Arc<ResponseInner>,
16}
17
18struct ResponseInner {
19 url: String,
20 status: u16,
21 status_text: String,
22 headers: Headers,
23 request_id: String,
24 from_cache: bool,
25 from_service_worker: bool,
26 session: Arc<CdpSession>,
27 body: Mutex<Option<Arc<[u8]>>>,
28 request: Request,
29}
30
31impl Response {
32 #[allow(clippy::too_many_arguments)]
33 pub(crate) fn new(
34 url: String,
35 status: u16,
36 status_text: String,
37 headers: Headers,
38 request_id: String,
39 from_cache: bool,
40 from_service_worker: bool,
41 session: Arc<CdpSession>,
42 request: Request,
43 ) -> Self {
44 Self {
45 inner: Arc::new(ResponseInner {
46 url,
47 status,
48 status_text,
49 headers,
50 request_id,
51 from_cache,
52 from_service_worker,
53 session,
54 body: Mutex::new(None),
55 request,
56 }),
57 }
58 }
59
60 pub fn url(&self) -> &str {
61 &self.inner.url
62 }
63
64 pub fn status(&self) -> u16 {
65 self.inner.status
66 }
67
68 pub fn status_text(&self) -> &str {
69 &self.inner.status_text
70 }
71
72 pub fn ok(&self) -> bool {
73 (200..300).contains(&self.inner.status)
74 }
75
76 pub fn headers(&self) -> &Headers {
77 &self.inner.headers
78 }
79
80 pub fn from_cache(&self) -> bool {
81 self.inner.from_cache
82 }
83
84 pub fn from_service_worker(&self) -> bool {
85 self.inner.from_service_worker
86 }
87
88 pub fn request(&self) -> Request {
89 self.inner.request.clone()
90 }
91
92 pub async fn body(&self) -> Result<Vec<u8>> {
94 if let Some(b) = self.inner.body.lock().clone() {
95 return Ok(b.to_vec());
96 }
97 let v = self
98 .inner
99 .session
100 .send(
101 "Network.getResponseBody",
102 json!({ "requestId": self.inner.request_id }),
103 )
104 .await?;
105 let body_str = v.get("body").and_then(|x| x.as_str()).unwrap_or("");
106 let encoded = v.get("base64Encoded").and_then(|x| x.as_bool()).unwrap_or(false);
107 let bytes = if encoded {
108 base64::engine::general_purpose::STANDARD
109 .decode(body_str)
110 .map_err(|e| Error::ProtocolError(format!("response body base64 decode: {e}")))?
111 } else {
112 body_str.as_bytes().to_vec()
113 };
114 *self.inner.body.lock() = Some(Arc::from(bytes.as_slice()));
115 Ok(bytes)
116 }
117
118 pub async fn text(&self) -> Result<String> {
119 let bytes = self.body().await?;
120 Ok(String::from_utf8_lossy(&bytes).into_owned())
121 }
122
123 pub async fn json(&self) -> Result<Value> {
124 let text = self.text().await?;
125 serde_json::from_str(&text).map_err(Error::from)
126 }
127}