1use crate::error::{Error, Result};
4use crate::headers::Headers;
5use bytes::Bytes;
6use http::StatusCode;
7use std::io::Read;
8use url::Url;
9
10#[derive(Debug, Clone)]
12pub struct Response {
13 pub(crate) status: u16,
14 headers: Headers,
15 body: Bytes,
16 http_version: String,
17 effective_url: Option<Url>,
18}
19
20impl Response {
21 pub fn new(status: u16, headers: Headers, body: Bytes, http_version: String) -> Self {
22 Self {
23 status,
24 headers,
25 body,
26 http_version,
27 effective_url: None,
28 }
29 }
30
31 pub fn with_url(mut self, url: Url) -> Self {
34 self.effective_url = Some(url);
35 self
36 }
37
38 pub fn http_version(&self) -> &str {
39 &self.http_version
40 }
41
42 pub fn status(&self) -> StatusCode {
43 StatusCode::from_u16(self.status).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)
44 }
45
46 pub fn status_code(&self) -> u16 {
47 self.status
48 }
49
50 pub fn headers(&self) -> &Headers {
51 &self.headers
52 }
53
54 pub fn url(&self) -> Option<&Url> {
55 self.effective_url.as_ref()
56 }
57
58 pub fn body(&self) -> &Bytes {
59 &self.body
60 }
61
62 pub fn bytes_raw(&self) -> Bytes {
63 self.body.clone()
64 }
65
66 pub fn into_body(self) -> Bytes {
67 self.body
68 }
69
70 pub fn bytes(&self) -> Result<Bytes> {
71 self.decoded_body()
72 }
73
74 pub fn is_success(&self) -> bool {
75 (200..300).contains(&self.status)
76 }
77 pub fn is_redirect(&self) -> bool {
78 (300..400).contains(&self.status)
79 }
80 pub fn redirect_url(&self) -> Option<&str> {
81 self.get_header("Location")
82 }
83
84 pub fn get_header(&self, name: &str) -> Option<&str> {
85 self.headers.get(name)
86 }
87
88 pub fn get_headers(&self, name: &str) -> Vec<&str> {
89 self.headers.get_all(name)
90 }
91
92 pub fn content_type(&self) -> Option<&str> {
93 self.get_header("Content-Type")
94 }
95 pub fn content_encoding(&self) -> Option<&str> {
96 self.get_header("Content-Encoding")
97 }
98
99 pub fn decoded_body(&self) -> Result<Bytes> {
102 let encodings: Vec<&str> = self
103 .content_encoding()
104 .map(|s| s.split(',').map(str::trim).collect())
105 .unwrap_or_default();
106
107 if !encodings.is_empty() {
110 let mut data = self.body.clone();
111 for encoding in encodings.iter().rev() {
112 data = match encoding.to_lowercase().as_str() {
113 "gzip" | "x-gzip" => decode_gzip(&data)?,
114 "deflate" => decode_deflate(&data)?,
115 "br" => decode_brotli(&data)?,
116 "zstd" => decode_zstd(&data)?,
117 "identity" => data,
118 _ => {
119 data
121 }
122 };
123 }
124 return Ok(data);
125 }
126
127 if self.body.len() >= 4 {
129 if self.body[0] == 0x28
131 && self.body[1] == 0xB5
132 && self.body[2] == 0x2F
133 && self.body[3] == 0xFD
134 {
135 return decode_zstd(&self.body);
136 }
137 }
138 if self.body.len() >= 2 {
139 if self.body[0] == 0x1f && self.body[1] == 0x8b {
141 return decode_gzip(&self.body);
142 }
143 }
144
145 Ok(self.body.clone())
146 }
147
148 pub fn text(&self) -> Result<String> {
149 let decoded = self.decoded_body()?;
150 String::from_utf8(decoded.to_vec())
151 .map_err(|e| Error::Decompression(format!("UTF-8 decode error: {}", e)))
152 }
153
154 pub fn json<T: serde::de::DeserializeOwned>(&self) -> Result<T> {
155 let text = self.text()?;
156 serde_json::from_str(&text).map_err(Error::from)
157 }
158
159 pub fn error_for_status(self) -> Result<Self> {
160 if self.status().is_client_error() || self.status().is_server_error() {
161 let message = self
162 .status()
163 .canonical_reason()
164 .unwrap_or("HTTP error")
165 .to_string();
166 Err(Error::http_status(self.status, message))
167 } else {
168 Ok(self)
169 }
170 }
171
172 pub fn error_for_status_ref(&self) -> Result<&Self> {
173 if self.status().is_client_error() || self.status().is_server_error() {
174 let message = self
175 .status()
176 .canonical_reason()
177 .unwrap_or("HTTP error")
178 .to_string();
179 Err(Error::http_status(self.status, message))
180 } else {
181 Ok(self)
182 }
183 }
184}
185
186fn decode_gzip(data: &[u8]) -> Result<Bytes> {
187 let mut decoder = flate2::read::GzDecoder::new(data);
188 let mut decoded = Vec::new();
189 decoder
190 .read_to_end(&mut decoded)
191 .map_err(|e| Error::Decompression(format!("gzip: {}", e)))?;
192 Ok(Bytes::from(decoded))
193}
194
195fn decode_deflate(data: &[u8]) -> Result<Bytes> {
196 let mut decoded = Vec::new();
197 if flate2::read::ZlibDecoder::new(data)
198 .read_to_end(&mut decoded)
199 .is_ok()
200 {
201 return Ok(Bytes::from(decoded));
202 }
203 decoded.clear();
204 flate2::read::DeflateDecoder::new(data)
205 .read_to_end(&mut decoded)
206 .map_err(|e| Error::Decompression(format!("deflate: {}", e)))?;
207 Ok(Bytes::from(decoded))
208}
209
210fn decode_brotli(data: &[u8]) -> Result<Bytes> {
211 let mut decoder = brotli::Decompressor::new(data, 4096);
212 let mut decoded = Vec::new();
213 decoder
214 .read_to_end(&mut decoded)
215 .map_err(|e| Error::Decompression(format!("brotli: {}", e)))?;
216 Ok(Bytes::from(decoded))
217}
218
219fn decode_zstd(data: &[u8]) -> Result<Bytes> {
220 zstd::stream::decode_all(data)
221 .map(Bytes::from)
222 .map_err(|e| Error::Decompression(format!("zstd: {}", e)))
223}