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