playwright_cdp/
response.rs1use crate::cdp::session::CdpSession;
4use crate::error::{Error, Result};
5use crate::network::{NetworkStore, SecurityDetails, ServerAddr, Sizes, Timing};
6use crate::request::Request;
7use crate::types::Headers;
8use base64::Engine;
9use parking_lot::Mutex;
10use serde_json::{json, Value};
11use std::sync::Arc;
12
13#[derive(Clone)]
15pub struct Response {
16 inner: Arc<ResponseInner>,
17}
18
19struct ResponseInner {
20 url: String,
21 status: u16,
22 status_text: String,
23 headers: Headers,
24 request_id: String,
25 from_cache: bool,
26 from_service_worker: bool,
27 session: Arc<CdpSession>,
28 body: Mutex<Option<Arc<[u8]>>>,
29 request: Request,
30}
31
32impl Response {
33 #[allow(clippy::too_many_arguments)]
34 pub(crate) fn new(
35 url: String,
36 status: u16,
37 status_text: String,
38 headers: Headers,
39 request_id: String,
40 from_cache: bool,
41 from_service_worker: bool,
42 session: Arc<CdpSession>,
43 request: Request,
44 ) -> Self {
45 Self {
46 inner: Arc::new(ResponseInner {
47 url,
48 status,
49 status_text,
50 headers,
51 request_id,
52 from_cache,
53 from_service_worker,
54 session,
55 body: Mutex::new(None),
56 request,
57 }),
58 }
59 }
60
61 pub fn url(&self) -> &str {
62 &self.inner.url
63 }
64
65 pub fn status(&self) -> u16 {
66 self.inner.status
67 }
68
69 pub fn status_text(&self) -> &str {
70 &self.inner.status_text
71 }
72
73 pub fn ok(&self) -> bool {
74 (200..300).contains(&self.inner.status)
75 }
76
77 pub fn headers(&self) -> &Headers {
78 &self.inner.headers
79 }
80
81 pub fn from_cache(&self) -> bool {
82 self.inner.from_cache
83 }
84
85 pub fn from_service_worker(&self) -> bool {
86 self.inner.from_service_worker
87 }
88
89 pub fn request(&self) -> Request {
90 self.inner.request.clone()
91 }
92
93 pub fn http_version(&self) -> String {
97 self.store()
98 .and_then(|s| s.http_version(&self.inner.request_id))
99 .unwrap_or_default()
100 }
101
102 pub fn security_details(&self) -> Option<SecurityDetails> {
104 self.store()
105 .and_then(|s| s.security_details(&self.inner.request_id))
106 }
107
108 pub fn server_addr(&self) -> Option<ServerAddr> {
110 self.store()
111 .and_then(|s| s.server_addr(&self.inner.request_id))
112 }
113
114 pub fn sizes(&self) -> Option<Sizes> {
116 self.store()
117 .and_then(|s| s.sizes(&self.inner.request_id))
118 }
119
120 pub fn timing(&self) -> Option<Timing> {
122 self.store()
123 .and_then(|s| s.timing(&self.inner.request_id))
124 }
125
126 pub fn all_headers(&self) -> Headers {
129 self.store()
130 .and_then(|s| s.raw_response_headers(&self.inner.request_id))
131 .unwrap_or_else(|| self.inner.headers.clone())
132 }
133
134 pub fn finished(&self) -> Result<()> {
137 if let Some(store) = self.store() {
138 if store.finished(&self.inner.request_id) {
139 return Ok(());
140 }
141 if let Some(text) = store.failure(&self.inner.request_id) {
143 return Err(Error::ProtocolError(format!(
144 "request failed: {text}"
145 )));
146 }
147 }
148 Err(Error::ProtocolError(
149 "request has not finished loading".to_string(),
150 ))
151 }
152
153 fn store(&self) -> Option<Arc<NetworkStore>> {
154 self.inner.request.store_weak()
155 }
156
157 pub async fn body(&self) -> Result<Vec<u8>> {
159 if let Some(b) = self.inner.body.lock().clone() {
160 return Ok(b.to_vec());
161 }
162 let v = self
163 .inner
164 .session
165 .send(
166 "Network.getResponseBody",
167 json!({ "requestId": self.inner.request_id }),
168 )
169 .await?;
170 let body_str = v.get("body").and_then(|x| x.as_str()).unwrap_or("");
171 let encoded = v.get("base64Encoded").and_then(|x| x.as_bool()).unwrap_or(false);
172 let bytes = if encoded {
173 base64::engine::general_purpose::STANDARD
174 .decode(body_str)
175 .map_err(|e| Error::ProtocolError(format!("response body base64 decode: {e}")))?
176 } else {
177 body_str.as_bytes().to_vec()
178 };
179 *self.inner.body.lock() = Some(Arc::from(bytes.as_slice()));
180 Ok(bytes)
181 }
182
183 pub async fn text(&self) -> Result<String> {
184 let bytes = self.body().await?;
185 Ok(String::from_utf8_lossy(&bytes).into_owned())
186 }
187
188 pub async fn json(&self) -> Result<Value> {
189 let text = self.text().await?;
190 serde_json::from_str(&text).map_err(Error::from)
191 }
192}