parsec_interface/requests/response/
mod.rs

1// Copyright 2019 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3//! Response definition
4
5use super::common::wire_header_1_0::WireHeader as Raw;
6use super::request::RequestHeader;
7use super::ResponseStatus;
8use super::Result;
9use log::error;
10use std::convert::{TryFrom, TryInto};
11use std::io::{Read, Write};
12
13mod response_body;
14mod response_header;
15
16pub use response_body::ResponseBody;
17pub use response_header::ResponseHeader;
18
19#[cfg(feature = "testing")]
20pub use super::common::wire_header_1_0::WireHeader as RawHeader;
21
22/// Native representation of the response wire format.
23#[derive(PartialEq, Eq, Debug)]
24pub struct Response {
25    /// Header of the response, containing the response status.
26    pub header: ResponseHeader,
27    /// Response body consists of an opaque vector of bytes. Interpretation of said bytes
28    /// is deferred to the a converter which can handle the `content_type` defined in the
29    /// header.
30    pub body: ResponseBody,
31}
32
33impl Response {
34    /// Create a response with empty header and empty body.
35    fn new() -> Response {
36        Response {
37            header: ResponseHeader::new(),
38            body: ResponseBody::new(),
39        }
40    }
41
42    /// Convert request into an error response with a given `ResponseStatus`.
43    ///
44    /// The relevant fields in the header are preserved and an empty body is provided
45    /// by default.
46    pub fn from_request_header(header: RequestHeader, status: ResponseStatus) -> Response {
47        let mut response = Response::new();
48        response.header = header.into();
49        response.header.status = status;
50
51        response
52    }
53
54    /// Create an empty response with a specific status.
55    pub fn from_status(status: ResponseStatus) -> Response {
56        let mut response = Response::new();
57        response.header.status = status;
58
59        response
60    }
61
62    /// Serialise response and write it to given stream.
63    ///
64    /// Header is converted to a raw format before serializing.
65    ///
66    /// # Errors
67    /// - if writing any of the subfields (header or body) fails, then
68    /// `ResponseStatus::ConnectionError` is returned.
69    /// - if encoding any of the fields in the header fails, then
70    /// `ResponseStatus::InvalidEncoding` is returned.
71    pub fn write_to_stream(self, stream: &mut impl Write) -> Result<()> {
72        let mut raw_header: Raw = self.header.into();
73        raw_header.body_len = u32::try_from(self.body.len())?;
74
75        raw_header.write_to_stream(stream)?;
76        self.body.write_to_stream(stream)?;
77
78        Ok(())
79    }
80
81    /// Deserialise response from given stream.
82    ///
83    /// The `body_len_limit` parameter allows the interface client to reject requests that are
84    /// longer than a predefined limit. The length limit is in bytes.
85    ///
86    /// # Errors
87    /// - if reading any of the subfields (header or body) fails, the
88    /// corresponding `ResponseStatus` will be returned.
89    /// - if the request body size specified in the header is larger than the limit passed as
90    /// a parameter, `BodySizeExceedsLimit` will be returned.
91    pub fn read_from_stream(stream: &mut impl Read, body_len_limit: usize) -> Result<Response> {
92        let raw_header = Raw::read_from_stream(stream)?;
93        let body_len = usize::try_from(raw_header.body_len)?;
94        if body_len > body_len_limit {
95            error!(
96                "Request body length ({}) bigger than the limit given ({}).",
97                body_len, body_len_limit
98            );
99            return Err(ResponseStatus::BodySizeExceedsLimit);
100        }
101        let body = ResponseBody::read_from_stream(stream, body_len)?;
102
103        Ok(Response {
104            header: raw_header.try_into()?,
105            body,
106        })
107    }
108}
109
110#[cfg(test)]
111mod tests {
112    use super::super::utils::tests as test_utils;
113    use super::super::{BodyType, Opcode, ProviderId, ResponseStatus};
114    use super::*;
115
116    #[test]
117    fn response_1_to_stream() {
118        let mut mock = test_utils::MockReadWrite { buffer: Vec::new() };
119        let response = get_response_1();
120
121        response
122            .write_to_stream(&mut mock)
123            .expect("Failed to write response");
124
125        assert_eq!(mock.buffer, get_response_1_bytes());
126    }
127
128    #[test]
129    fn response_2_to_stream() {
130        let mut mock = test_utils::MockReadWrite { buffer: Vec::new() };
131        let response = get_response_2();
132
133        response
134            .write_to_stream(&mut mock)
135            .expect("Failed to write response");
136
137        assert_eq!(mock.buffer, get_response_2_bytes());
138    }
139
140    #[test]
141    fn stream_to_response_1() {
142        let mut mock = test_utils::MockReadWrite {
143            buffer: get_response_1_bytes(),
144        };
145
146        let response =
147            Response::read_from_stream(&mut mock, 1000).expect("Failed to read response");
148
149        assert_eq!(response, get_response_1());
150    }
151
152    #[test]
153    fn stream_to_response_2() {
154        let mut mock = test_utils::MockReadWrite {
155            buffer: get_response_2_bytes(),
156        };
157
158        let response =
159            Response::read_from_stream(&mut mock, 1000).expect("Failed to read response");
160
161        assert_eq!(response, get_response_2());
162    }
163
164    #[test]
165    fn stream_to_fail_response_wrong_endians() {
166        let mut mock = test_utils::MockReadWrite {
167            buffer: get_response_bytes_big_endian_fixint_encoding(),
168        };
169        let response_status =
170            Response::read_from_stream(&mut mock, 1000).expect_err("Should have failed.");
171        assert_eq!(response_status, ResponseStatus::InvalidHeader);
172
173        let mut mock = test_utils::MockReadWrite {
174            buffer: get_response_bytes_big_endian_varint_encoding(),
175        };
176        let response_status =
177            Response::read_from_stream(&mut mock, 1000).expect_err("Should have failed.");
178        assert_eq!(response_status, ResponseStatus::InvalidHeader);
179    }
180    #[test]
181    fn stream_to_fail_response_wrong_int_encoding() {
182        let mut mock = test_utils::MockReadWrite {
183            buffer: get_response_bytes_little_endian_varint_encoding(),
184        };
185        let response_status =
186            Response::read_from_stream(&mut mock, 1000).expect_err("Should have failed.");
187        assert_eq!(response_status, ResponseStatus::InvalidHeader);
188    }
189
190    #[test]
191    #[should_panic(expected = "Failed to read response")]
192    fn failed_read() {
193        let mut fail_mock = test_utils::MockFailReadWrite;
194
195        let _ = Response::read_from_stream(&mut fail_mock, 1000).expect("Failed to read response");
196    }
197
198    #[test]
199    #[should_panic(expected = "Response body too large")]
200    fn body_too_large() {
201        let mut mock = test_utils::MockReadWrite {
202            buffer: get_response_1_bytes(),
203        };
204
205        let _ = Response::read_from_stream(&mut mock, 0).expect("Response body too large");
206    }
207
208    #[test]
209    #[should_panic(expected = "Failed to write response")]
210    fn failed_write() {
211        let response: Response = get_response_1();
212        let mut fail_mock = test_utils::MockFailReadWrite;
213
214        response
215            .write_to_stream(&mut fail_mock)
216            .expect("Failed to write response");
217    }
218
219    #[test]
220    fn wrong_version() {
221        let mut mock = test_utils::MockReadWrite {
222            buffer: get_response_1_bytes(),
223        };
224        // Put an invalid version major field.
225        mock.buffer[6] = 0xFF;
226        // Put an invalid version minor field.
227        mock.buffer[7] = 0xFF;
228
229        let response_status =
230            Response::read_from_stream(&mut mock, 1000).expect_err("Should have failed.");
231
232        assert_eq!(
233            response_status,
234            ResponseStatus::WireProtocolVersionNotSupported
235        );
236    }
237
238    fn get_response_1() -> Response {
239        let body = ResponseBody::from_bytes(vec![0x70, 0x80, 0x90]);
240        let header = ResponseHeader {
241            provider: ProviderId::Core,
242            session: 0x11_22_33_44_55_66_77_88,
243            content_type: BodyType::Protobuf,
244            opcode: Opcode::Ping,
245            status: ResponseStatus::Success,
246        };
247        Response { header, body }
248    }
249
250    fn get_response_2() -> Response {
251        let body = ResponseBody::from_bytes(vec![0xB0, 0xB1, 0xB2, 0xB3]);
252        let header = ResponseHeader {
253            provider: ProviderId::Core,
254            session: 0x88_99_AA_BB_CC_DD_EE_FF,
255            content_type: BodyType::Protobuf,
256            opcode: Opcode::Ping,
257            status: ResponseStatus::Success,
258        };
259        Response { header, body }
260    }
261
262    fn get_response_1_bytes() -> Vec<u8> {
263        vec![
264            0x10, 0xA7, 0xC0, 0x5E, // MAGIC_NUMBER
265            0x1E, 0x00, // REQUEST_HDR_SIZE
266            0x01, // WIRE_PROTOCOL_VERSION_MAJ
267            0x00, // WIRE_PROTOCOL_VERSION_MIN
268            0x00, 0x00, // WireHeader::flags
269            0x00, // WireHeader::provider
270            0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, // WireHeader::session
271            0x00, // WireHeader::content_type
272            0x00, // WireHeader::accept_type
273            0x00, // WireHeader::auth_type
274            0x03, 0x00, 0x00, 0x00, // WireHeader::body_len
275            0x00, 0x00, // WireHeader::auth_len
276            0x01, 0x00, 0x00, 0x00, // WireHeader::opcode
277            0x00, 0x00, // WireHeader::status
278            0x00, // WireHeader::reserved1
279            0x00, // WireHeader::reserved2
280            0x70, 0x80, 0x90, // ResponseBody
281        ]
282    }
283
284    fn get_response_2_bytes() -> Vec<u8> {
285        vec![
286            0x10, 0xA7, 0xC0, 0x5E, // MAGIC_NUMBER
287            0x1E, 0x00, // REQUEST_HDR_SIZE
288            0x01, // WIRE_PROTOCOL_VERSION_MAJ
289            0x00, // WIRE_PROTOCOL_VERSION_MIN
290            0x00, 0x00, // WireHeader::flags
291            0x00, // WireHeader::provider
292            0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, // WireHeader::session
293            0x00, // WireHeader::content_type
294            0x00, // WireHeader::accept_type
295            0x00, // WireHeader::auth_type
296            0x04, 0x00, 0x00, 0x00, // WireHeader::body_len
297            0x00, 0x00, // WireHeader::auth_len
298            0x01, 0x00, 0x00, 0x00, // WireHeader::opcode
299            0x00, 0x00, // WireHeader::status
300            0x00, // WireHeader::reserved1
301            0x00, // WireHeader::reserved2
302            0xB0, 0xB1, 0xB2, 0xB3, // ResponseBody
303        ]
304    }
305    fn get_response_bytes_big_endian_fixint_encoding() -> Vec<u8> {
306        vec![
307            0x5E, 0xC0, 0xA7, 0x10, // MAGIC_NUMBER
308            0x00, 0x1E, // REQUEST_HDR_SIZE
309            0x01, // WIRE_PROTOCOL_VERSION_MAJ
310            0x00, // WIRE_PROTOCOL_VERSION_MIN
311            0x00, 0x00, // WireHeader::flags
312            0x00, // WireHeader::provider
313            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // WireHeader::session
314            0x00, // WireHeader::content_type
315            0x00, // WireHeader::accept_type
316            0x00, // WireHeader::auth_type
317            0x00, 0x00, 0x00, 0x03, // WireHeader::body_len
318            0x00, 0x00, // WireHeader::auth_len
319            0x00, 0x00, 0x00, 0x01, // WireHeader::opcode
320            0x00, 0x00, // WireHeader::status
321            0x00, // WireHeader::reserved1
322            0x00, // WireHeader::reserved2
323            0x70, 0x80, 0x90, // RequestBody
324        ]
325    }
326    fn get_response_bytes_little_endian_varint_encoding() -> Vec<u8> {
327        vec![
328            0xFC, // Encoding byte indicates that the following 4 bytes make a u32 int
329            //https://docs.rs/bincode/1.3.3/bincode/config/struct.VarintEncoding.html
330            0x5E, 0xC0, 0xA7, 0x10, // MAGIC_NUMBER
331            0x1E, // REQUEST_HDR_SIZE
332            0x01, // WIRE_PROTOCOL_VERSION_MAJ
333            0x00, // WIRE_PROTOCOL_VERSION_MIN
334            0x00, // WireHeader::flags
335            0x00, // WireHeader::provider
336            0xFD, // Encoding byte indicates that the following 8 bytes make a u64 int
337            //https://docs.rs/bincode/1.3.3/bincode/config/struct.VarintEncoding.html
338            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // WireHeader::session
339            0x00, // WireHeader::content_type
340            0x00, // WireHeader::accept_type
341            0x00, // WireHeader::auth_type
342            0x03, // WireHeader::body_len
343            0x00, // WireHeader::auth_len
344            0x01, // WireHeader::opcode
345            0x00, // WireHeader::status
346            0x00, // WireHeader::reserved1
347            0x00, // WireHeader::reserved2
348            0x70, 0x80, 0x90, // RequestBody
349        ]
350    }
351    fn get_response_bytes_big_endian_varint_encoding() -> Vec<u8> {
352        vec![
353            0xFC, // Encoding byte indicates that the following 4 bytes make a u32 int
354            //https://docs.rs/bincode/1.3.3/bincode/config/struct.VarintEncoding.html
355            0x10, 0xA7, 0xC0, 0x5E, // MAGIC_NUMBER
356            0x1E, // REQUEST_HDR_SIZE
357            0x01, // WIRE_PROTOCOL_VERSION_MAJ
358            0x00, // WIRE_PROTOCOL_VERSION_MIN
359            0x00, // WireHeader::flags
360            0x00, // WireHeader::provider
361            0xFD, // Encoding byte indicates that the following 8 bytes make a u64 int
362            //https://docs.rs/bincode/1.3.3/bincode/config/struct.VarintEncoding.html
363            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // WireHeader::session
364            0x00, // WireHeader::content_type
365            0x00, // WireHeader::accept_type
366            0x00, // WireHeader::auth_type
367            0x03, // WireHeader::body_len
368            0x00, // WireHeader::auth_len
369            0x01, // WireHeader::opcode
370            0x00, // WireHeader::status
371            0x00, // WireHeader::reserved1
372            0x00, // WireHeader::reserved2
373            0x70, 0x80, 0x90, // RequestBody
374        ]
375    }
376}