viceroy_lib/wiggle_abi/
resp_impl.rs

1//! fastly_resp` hostcall implementations.
2
3use {
4    crate::{
5        error::Error,
6        session::{Session, ViceroyResponseMetadata},
7        upstream,
8        wiggle_abi::{
9            fastly_http_resp::FastlyHttpResp,
10            headers::HttpHeaders,
11            types::{
12                BodyHandle, FramingHeadersMode, HttpKeepaliveMode, HttpStatus, HttpVersion,
13                MultiValueCursor, MultiValueCursorResult, ResponseHandle,
14            },
15        },
16    },
17    cfg_if::cfg_if,
18    hyper::http::response::Response,
19    std::net::IpAddr,
20    wiggle::{GuestMemory, GuestPtr},
21};
22
23impl FastlyHttpResp for Session {
24    fn new(&mut self, _memory: &mut GuestMemory<'_>) -> Result<ResponseHandle, Error> {
25        // KTM: Unfortunately `response::Parts` doesn't expose a constructor. This is a workaround.
26        let (parts, _) = Response::new(()).into_parts();
27        Ok(self.insert_response_parts(parts))
28    }
29
30    fn header_names_get(
31        &mut self,
32        memory: &mut GuestMemory<'_>,
33        resp_handle: ResponseHandle,
34        buf: GuestPtr<u8>,
35        buf_len: u32,
36        cursor: MultiValueCursor,
37        ending_cursor_out: GuestPtr<MultiValueCursorResult>,
38        nwritten_out: GuestPtr<u32>,
39    ) -> Result<(), Error> {
40        let headers = &self.response_parts(resp_handle)?.headers;
41        multi_value_result!(
42            memory,
43            headers.names_get(memory, buf, buf_len, cursor, nwritten_out),
44            ending_cursor_out
45        )
46    }
47
48    fn header_value_get(
49        &mut self,
50        memory: &mut GuestMemory<'_>,
51        resp_handle: ResponseHandle,
52        name: GuestPtr<[u8]>,
53        value: GuestPtr<u8>,
54        value_max_len: u32,
55        nwritten_out: GuestPtr<u32>,
56    ) -> Result<(), Error> {
57        let headers = &self.response_parts(resp_handle)?.headers;
58        headers.value_get(memory, name, value, value_max_len, nwritten_out)
59    }
60
61    fn header_values_get(
62        &mut self,
63        memory: &mut GuestMemory<'_>,
64        resp_handle: ResponseHandle,
65        name: GuestPtr<[u8]>,
66        buf: GuestPtr<u8>,
67        buf_len: u32,
68        cursor: MultiValueCursor,
69        ending_cursor_out: GuestPtr<MultiValueCursorResult>,
70        nwritten_out: GuestPtr<u32>,
71    ) -> Result<(), Error> {
72        cfg_if! {
73            if #[cfg(feature = "test-fatalerror-config")] {
74                // Avoid warnings:
75                let _ = (memory, resp_handle, name, buf, buf_len, cursor, ending_cursor_out, nwritten_out);
76                return Err(Error::FatalError("A fatal error occurred in the test-only implementation of header_values_get".to_string()));
77            } else {
78                let headers = &self.response_parts(resp_handle)?.headers;
79                multi_value_result!(
80                    memory,
81                    headers.values_get(memory, name, buf, buf_len, cursor, nwritten_out),
82                    ending_cursor_out
83                )
84            }
85        }
86    }
87
88    fn header_values_set(
89        &mut self,
90        memory: &mut GuestMemory<'_>,
91        resp_handle: ResponseHandle,
92        name: GuestPtr<[u8]>,
93        values: GuestPtr<[u8]>,
94    ) -> Result<(), Error> {
95        let headers = &mut self.response_parts_mut(resp_handle)?.headers;
96        headers.values_set(memory, name, values)
97    }
98
99    fn header_insert(
100        &mut self,
101        memory: &mut GuestMemory<'_>,
102        resp_handle: ResponseHandle,
103        name: GuestPtr<[u8]>,
104        value: GuestPtr<[u8]>,
105    ) -> Result<(), Error> {
106        let headers = &mut self.response_parts_mut(resp_handle)?.headers;
107        HttpHeaders::insert(headers, memory, name, value)
108    }
109
110    fn header_append<'a>(
111        &mut self,
112        memory: &mut GuestMemory<'_>,
113        resp_handle: ResponseHandle,
114        name: GuestPtr<[u8]>,
115        value: GuestPtr<[u8]>,
116    ) -> Result<(), Error> {
117        let headers = &mut self.response_parts_mut(resp_handle)?.headers;
118        HttpHeaders::append(headers, memory, name, value)
119    }
120
121    fn header_remove<'a>(
122        &mut self,
123        memory: &mut GuestMemory<'_>,
124        resp_handle: ResponseHandle,
125        name: GuestPtr<[u8]>,
126    ) -> Result<(), Error> {
127        let headers = &mut self.response_parts_mut(resp_handle)?.headers;
128        HttpHeaders::remove(headers, memory, name)
129    }
130
131    fn version_get(
132        &mut self,
133        _memory: &mut GuestMemory<'_>,
134        resp_handle: ResponseHandle,
135    ) -> Result<HttpVersion, Error> {
136        let resp = self.response_parts(resp_handle)?;
137        HttpVersion::try_from(resp.version).map_err(|msg| Error::Unsupported { msg })
138    }
139
140    fn version_set(
141        &mut self,
142        _memory: &mut GuestMemory<'_>,
143        resp_handle: ResponseHandle,
144        version: HttpVersion,
145    ) -> Result<(), Error> {
146        let resp = self.response_parts_mut(resp_handle)?;
147
148        let version = hyper::Version::try_from(version)?;
149        resp.version = version;
150        Ok(())
151    }
152
153    fn send_downstream(
154        &mut self,
155        _memory: &mut GuestMemory<'_>,
156        resp_handle: ResponseHandle,
157        body_handle: BodyHandle,
158        streaming: u32,
159    ) -> Result<(), Error> {
160        let resp = {
161            // Take the response parts and body from the session, and use them to build a response.
162            // Return an `FastlyStatus::Badf` error code if either of the given handles are invalid.
163            let resp_parts = self.take_response_parts(resp_handle)?;
164            let body = if streaming == 1 {
165                self.begin_streaming(body_handle)?
166            } else {
167                self.take_body(body_handle)?
168            };
169            Response::from_parts(resp_parts, body)
170        }; // Set the downstream response, and return.
171        self.send_downstream_response(resp)
172    }
173
174    fn status_get(
175        &mut self,
176        _memory: &mut GuestMemory<'_>,
177        resp_handle: ResponseHandle,
178    ) -> Result<HttpStatus, Error> {
179        Ok(self.response_parts(resp_handle)?.status.as_u16())
180    }
181
182    fn status_set(
183        &mut self,
184        _memory: &mut GuestMemory<'_>,
185        resp_handle: ResponseHandle,
186        status: HttpStatus,
187    ) -> Result<(), Error> {
188        let resp = self.response_parts_mut(resp_handle)?;
189        let status = hyper::StatusCode::from_u16(status)?;
190        resp.status = status;
191        Ok(())
192    }
193
194    fn framing_headers_mode_set(
195        &mut self,
196        _memory: &mut GuestMemory<'_>,
197        resp_handle: ResponseHandle,
198        mode: FramingHeadersMode,
199    ) -> Result<(), Error> {
200        let extensions = &mut self.response_parts_mut(resp_handle)?.extensions;
201
202        match extensions.get_mut::<ViceroyResponseMetadata>() {
203            None => {
204                extensions.insert(ViceroyResponseMetadata {
205                    framing_headers_mode: mode,
206                    // future note: at time of writing, this is the only field of
207                    // this structure, but there is an intention to add more fields.
208                    // When we do, and if/when an error appears, what you're looking
209                    // for is:
210                    // ..Default::default()
211                });
212            }
213            Some(vrm) => {
214                vrm.framing_headers_mode = mode;
215            }
216        }
217
218        Ok(())
219    }
220
221    fn close(
222        &mut self,
223        _memory: &mut GuestMemory<'_>,
224        resp_handle: ResponseHandle,
225    ) -> Result<(), Error> {
226        // We don't do anything with the parts, but we do pass the error up if
227        // the handle given doesn't exist
228        self.take_response_parts(resp_handle)?;
229        Ok(())
230    }
231
232    fn http_keepalive_mode_set(
233        &mut self,
234        _memory: &mut GuestMemory<'_>,
235        _h: ResponseHandle,
236        mode: HttpKeepaliveMode,
237    ) -> Result<(), Error> {
238        match mode {
239            HttpKeepaliveMode::NoKeepalive => Err(Error::NotAvailable("No Keepalive")),
240            HttpKeepaliveMode::Automatic => Ok(()),
241        }
242    }
243
244    fn get_addr_dest_ip(
245        &mut self,
246        memory: &mut GuestMemory<'_>,
247        resp_handle: ResponseHandle,
248        addr_octets_ptr: GuestPtr<u8>,
249    ) -> Result<u32, Error> {
250        let resp = self.response_parts(resp_handle)?;
251        let md = resp
252            .extensions
253            .get::<upstream::ConnMetadata>()
254            .ok_or(Error::ValueAbsent)?;
255
256        if !md.direct_pass {
257            // Compute currently only returns this value when we are doing
258            // direct pass, so we skip returning a value here for now, even
259            // if we have one, so that guest code doesn't come to expect it
260            // during local testing.
261            return Err(Error::ValueAbsent);
262        }
263
264        match md.remote_addr.ip() {
265            IpAddr::V4(addr) => {
266                let octets = addr.octets();
267                let octets_bytes = octets.len() as u32;
268                debug_assert_eq!(octets_bytes, 4);
269                memory.copy_from_slice(&octets, addr_octets_ptr.as_array(octets_bytes))?;
270                Ok(octets_bytes)
271            }
272            IpAddr::V6(addr) => {
273                let octets = addr.octets();
274                let octets_bytes = octets.len() as u32;
275                debug_assert_eq!(octets_bytes, 16);
276                memory.copy_from_slice(&octets, addr_octets_ptr.as_array(octets_bytes))?;
277                Ok(octets_bytes)
278            }
279        }
280    }
281
282    fn get_addr_dest_port(
283        &mut self,
284        _memory: &mut GuestMemory<'_>,
285        resp_handle: ResponseHandle,
286    ) -> Result<u16, Error> {
287        let resp = self.response_parts(resp_handle)?;
288        let md = resp
289            .extensions
290            .get::<upstream::ConnMetadata>()
291            .ok_or(Error::ValueAbsent)?;
292
293        if !md.direct_pass {
294            // Compute currently only returns this value when we are doing
295            // direct pass, so we skip returning a value here for now, even
296            // if we have one, so that guest code doesn't come to expect it
297            // during local testing.
298            return Err(Error::ValueAbsent);
299        }
300
301        let port = md.remote_addr.port();
302        Ok(port)
303    }
304}