ripht_php_sapi/execution/
result.rs1use super::header::ResponseHeader;
2use super::message::{ExecutionMessage, SyslogLevel};
3
4#[must_use]
9#[derive(Debug, Clone)]
10pub struct ExecutionResult {
11 status: u16,
12 body: Vec<u8>,
13 headers: Vec<ResponseHeader>,
14 messages: Vec<ExecutionMessage>,
15}
16
17impl ExecutionResult {
18 pub fn new(
19 status: u16,
20 body: Vec<u8>,
21 headers: Vec<ResponseHeader>,
22 messages: Vec<ExecutionMessage>,
23 ) -> Self {
24 Self {
25 status,
26 body,
27 headers,
28 messages,
29 }
30 }
31
32 pub fn body(&self) -> Vec<u8> {
33 self.body.to_owned()
34 }
35
36 pub fn take_body(&mut self) -> Vec<u8> {
37 std::mem::take(&mut self.body)
38 }
39
40 pub fn body_string(&self) -> String {
41 if self.body.is_empty() {
42 return String::default();
43 }
44
45 String::from_utf8_lossy(&self.body).into_owned()
46 }
47
48 pub fn body_str(&self) -> Result<&str, std::str::Utf8Error> {
49 std::str::from_utf8(&self.body)
50 }
51
52 pub fn status_code(&self) -> u16 {
53 self.status
54 }
55
56 pub fn has_errors(&self) -> bool {
57 self.messages
58 .iter()
59 .any(|m| m.is_error())
60 }
61
62 pub fn has_message_level(&self, level: SyslogLevel) -> bool {
63 self.messages
64 .iter()
65 .any(|m| m.level == level)
66 }
67
68 pub fn errors(&self) -> impl Iterator<Item = &ExecutionMessage> {
69 self.messages
70 .iter()
71 .filter(|m| m.is_error())
72 }
73
74 pub fn all_messages(&self) -> impl Iterator<Item = &ExecutionMessage> {
75 self.messages.iter()
76 }
77
78 pub fn all_headers(&self) -> impl Iterator<Item = &ResponseHeader> {
79 self.headers.iter()
80 }
81
82 pub fn header_val(&self, name: &str) -> Option<&str> {
84 self.headers
85 .iter()
86 .find(|h| {
87 h.name()
88 .eq_ignore_ascii_case(name)
89 })
90 .map(|h| h.value())
91 }
92
93 pub fn header_vals(&self, name: &str) -> Vec<&str> {
96 self.headers
97 .iter()
98 .filter(|h| {
99 h.name()
100 .eq_ignore_ascii_case(name)
101 })
102 .map(|h| h.value())
103 .collect()
104 }
105
106 pub fn is_success(&self) -> bool {
107 (200..300).contains(&self.status)
108 }
109
110 pub fn is_redirect(&self) -> bool {
111 (300..400).contains(&self.status)
112 }
113
114 pub fn is_client_error(&self) -> bool {
115 (400..500).contains(&self.status)
116 }
117
118 pub fn is_server_error(&self) -> bool {
119 (500..600).contains(&self.status)
120 }
121}
122
123impl Default for ExecutionResult {
124 fn default() -> Self {
125 Self {
126 status: 200,
127 body: Vec::new(),
128 headers: Vec::new(),
129 messages: Vec::new(),
130 }
131 }
132}
133
134#[cfg(feature = "http")]
135impl ExecutionResult {
136 pub fn into_http_response(self) -> http::Response<Vec<u8>> {
137 let mut builder = http::Response::builder().status(self.status);
138
139 for h in &self.headers {
140 builder = builder.header(h.name(), h.value());
141 }
142
143 builder
144 .body(self.body)
145 .unwrap_or_else(|_| http::Response::new(Vec::new()))
146 }
147}
148
149#[cfg(feature = "http")]
150impl From<ExecutionResult> for http::Response<Vec<u8>> {
151 fn from(res: ExecutionResult) -> Self {
152 res.into_http_response()
153 }
154}