parsec_interface/requests/request/
mod.rs

1// Copyright 2019 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3//! # Request definition
4//!
5//! A `Request` is to the service to execute one operation.
6use super::common::wire_header_1_0::WireHeader as Raw;
7use super::response::ResponseHeader;
8use crate::requests::{ResponseStatus, Result};
9use crate::secrecy::ExposeSecret;
10use derivative::Derivative;
11use log::error;
12use std::convert::{TryFrom, TryInto};
13use std::io::{Read, Write};
14
15mod request_auth;
16mod request_body;
17mod request_header;
18
19pub use request_auth::RequestAuth;
20pub use request_body::RequestBody;
21pub use request_header::RequestHeader;
22
23#[cfg(feature = "testing")]
24pub use super::common::wire_header_1_0::WireHeader as RawHeader;
25
26/// Representation of the request wire format.
27#[derive(Derivative)]
28#[derivative(Debug)]
29pub struct Request {
30    /// Request header
31    pub header: RequestHeader,
32    /// Request body consists of `RequestBody` object holding a collection of bytes.
33    /// Interpretation of said bytes is deferred to the a converter which can handle the
34    /// `content_type` defined in the header.
35    pub body: RequestBody,
36    /// Auth field is stored as a `RequestAuth` object. A parser that can handle the `auth_type`
37    /// specified in the header is needed to authenticate the request.
38    #[derivative(Debug = "ignore")]
39    pub auth: RequestAuth,
40}
41
42impl Request {
43    /// Create a request with "default" header and empty body.
44    /// Available for testing purposes only.
45    #[cfg(feature = "testing")]
46    pub fn new() -> Request {
47        Request {
48            header: RequestHeader::new(),
49            body: RequestBody::new(),
50            auth: RequestAuth::new(Vec::new()),
51        }
52    }
53
54    /// Serialise request and write it to given stream.
55    ///
56    /// Request header is first converted to its raw format before serialization.
57    ///
58    /// # Errors
59    /// - if an IO operation fails while writing any of the subfields of the request,
60    /// `ResponseStatus::ConnectionError` is returned.
61    /// - if encoding any of the fields in the header fails, `ResponseStatus::InvalidEncoding`
62    /// is returned.
63    pub fn write_to_stream(self, stream: &mut impl Write) -> Result<()> {
64        let mut raw_header: Raw = self.header.into();
65        raw_header.body_len = u32::try_from(self.body.len())?;
66        raw_header.auth_len = u16::try_from(self.auth.buffer.expose_secret().len())?;
67        raw_header.write_to_stream(stream)?;
68
69        self.body.write_to_stream(stream)?;
70        self.auth.write_to_stream(stream)?;
71
72        Ok(())
73    }
74
75    /// Deserialise request from given stream.
76    ///
77    /// Request header is parsed from its raw form, ensuring that all fields are valid.
78    /// The `body_len_limit` parameter allows the interface client to reject requests that are
79    /// longer than a predefined limit. The length limit is in bytes.
80    ///
81    /// # Errors
82    /// - if reading any of the subfields (header, body or auth) fails, the corresponding
83    /// `ResponseStatus` will be returned.
84    /// - if the request body size specified in the header is larger than the limit passed as
85    /// a parameter, `BodySizeExceedsLimit` will be returned.
86    pub fn read_from_stream(stream: &mut impl Read, body_len_limit: usize) -> Result<Request> {
87        let raw_header = Raw::read_from_stream(stream)?;
88        let body_len = usize::try_from(raw_header.body_len)?;
89        if body_len > body_len_limit {
90            error!(
91                "Request body length ({}) bigger than the limit given ({}).",
92                body_len, body_len_limit
93            );
94            return Err(ResponseStatus::BodySizeExceedsLimit);
95        }
96        let body = RequestBody::read_from_stream(stream, body_len)?;
97        let auth = RequestAuth::read_from_stream(stream, usize::try_from(raw_header.auth_len)?)?;
98
99        Ok(Request {
100            header: raw_header.try_into()?,
101            body,
102            auth,
103        })
104    }
105}
106
107#[cfg(feature = "testing")]
108impl Default for Request {
109    fn default() -> Request {
110        Request::new()
111    }
112}
113
114/// Conversion from `RequestHeader` to `ResponseHeader` is useful for
115/// when reversing data flow, from handling a request to handling a response.
116impl From<RequestHeader> for ResponseHeader {
117    fn from(req_hdr: RequestHeader) -> ResponseHeader {
118        ResponseHeader {
119            provider: req_hdr.provider,
120            session: req_hdr.session,
121            content_type: req_hdr.accept_type,
122            opcode: req_hdr.opcode,
123            status: ResponseStatus::Success,
124        }
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use super::super::utils::tests as test_utils;
131    use super::super::{AuthType, BodyType, Opcode, ProviderId, ResponseStatus};
132    use super::*;
133
134    #[test]
135    fn request_1_to_stream() {
136        let mut mock = test_utils::MockReadWrite { buffer: Vec::new() };
137        let request = get_request_1();
138
139        request
140            .write_to_stream(&mut mock)
141            .expect("Failed to write request");
142
143        assert_eq!(mock.buffer, get_request_1_bytes());
144    }
145
146    #[test]
147    fn request_2_to_stream() {
148        let mut mock = test_utils::MockReadWrite { buffer: Vec::new() };
149        let request = get_request_2();
150
151        request
152            .write_to_stream(&mut mock)
153            .expect("Failed to write request");
154
155        assert_eq!(mock.buffer, get_request_2_bytes());
156    }
157
158    #[test]
159    fn stream_to_request_1() {
160        let mut mock = test_utils::MockReadWrite {
161            buffer: get_request_1_bytes(),
162        };
163
164        let request = Request::read_from_stream(&mut mock, 1000).expect("Failed to read request");
165        let exp_req = get_request_1();
166
167        assert_eq!(request.header, exp_req.header);
168        assert_eq!(request.body, exp_req.body);
169        assert_eq!(
170            request.auth.buffer.expose_secret(),
171            exp_req.auth.buffer.expose_secret()
172        );
173    }
174
175    #[test]
176    fn stream_to_request_2() {
177        let mut mock = test_utils::MockReadWrite {
178            buffer: get_request_2_bytes(),
179        };
180
181        let request = Request::read_from_stream(&mut mock, 1000).expect("Failed to read request");
182        let exp_req = get_request_2();
183
184        assert_eq!(request.header, exp_req.header);
185        assert_eq!(request.body, exp_req.body);
186        assert_eq!(
187            request.auth.buffer.expose_secret(),
188            exp_req.auth.buffer.expose_secret()
189        );
190    }
191
192    #[test]
193    fn stream_to_fail_request_1() {
194        let mut mock = test_utils::MockReadWrite {
195            buffer: get_request_bytes_reserved_fields_both_not_zero(),
196        };
197
198        assert_eq!(
199            Request::read_from_stream(&mut mock, 1000).unwrap_err(),
200            ResponseStatus::InvalidHeader
201        );
202    }
203
204    #[test]
205    fn stream_to_fail_request_2() {
206        let mut mock = test_utils::MockReadWrite {
207            buffer: get_request_bytes_reserved_fields_first_not_zero(),
208        };
209
210        assert_eq!(
211            Request::read_from_stream(&mut mock, 1000).unwrap_err(),
212            ResponseStatus::InvalidHeader
213        );
214    }
215
216    #[test]
217    fn stream_to_fail_request_3() {
218        let mut mock = test_utils::MockReadWrite {
219            buffer: get_request_bytes_reserved_fields_second_not_zero(),
220        };
221
222        assert_eq!(
223            Request::read_from_stream(&mut mock, 1000).unwrap_err(),
224            ResponseStatus::InvalidHeader
225        );
226    }
227
228    #[test]
229    fn stream_to_fail_request_wrong_endians() {
230        let mut mock = test_utils::MockReadWrite {
231            buffer: get_request_bytes_big_endian_fixint_encoding(),
232        };
233        let response_status =
234            Request::read_from_stream(&mut mock, 1000).expect_err("Should have failed.");
235        assert_eq!(response_status, ResponseStatus::InvalidHeader);
236
237        let mut mock = test_utils::MockReadWrite {
238            buffer: get_request_bytes_big_endian_varint_encoding(),
239        };
240        let response_status =
241            Request::read_from_stream(&mut mock, 1000).expect_err("Should have failed.");
242        assert_eq!(response_status, ResponseStatus::InvalidHeader);
243    }
244    #[test]
245    fn stream_to_fail_request_wrong_int_encoding() {
246        let mut mock = test_utils::MockReadWrite {
247            buffer: get_request_bytes_little_endian_varint_encoding(),
248        };
249        let response_status =
250            Request::read_from_stream(&mut mock, 1000).expect_err("Should have failed.");
251        assert_eq!(response_status, ResponseStatus::InvalidHeader);
252    }
253
254    #[test]
255    #[should_panic(expected = "Failed to read request")]
256    fn failed_read() {
257        let mut fail_mock = test_utils::MockFailReadWrite;
258
259        let _ = Request::read_from_stream(&mut fail_mock, 1000).expect("Failed to read request");
260    }
261
262    #[test]
263    #[should_panic(expected = "Request body too large")]
264    fn body_too_large() {
265        let mut mock = test_utils::MockReadWrite {
266            buffer: get_request_1_bytes(),
267        };
268
269        let _ = Request::read_from_stream(&mut mock, 0).expect("Request body too large");
270    }
271
272    #[test]
273    #[should_panic(expected = "Failed to write request")]
274    fn failed_write() {
275        let request: Request = get_request_1();
276        let mut fail_mock = test_utils::MockFailReadWrite;
277
278        request
279            .write_to_stream(&mut fail_mock)
280            .expect("Failed to write request");
281    }
282
283    #[test]
284    fn req_hdr_to_resp_hdr() {
285        let req_hdr = get_request_1().header;
286        let resp_hdr: ResponseHeader = req_hdr.into();
287
288        let mut resp_hdr_exp = ResponseHeader::new();
289        resp_hdr_exp.provider = ProviderId::Core;
290        resp_hdr_exp.session = 0x11_22_33_44_55_66_77_88;
291        resp_hdr_exp.content_type = BodyType::Protobuf;
292        resp_hdr_exp.opcode = Opcode::Ping;
293        resp_hdr_exp.status = ResponseStatus::Success;
294
295        assert_eq!(resp_hdr, resp_hdr_exp);
296    }
297
298    #[test]
299    fn wrong_version() {
300        let mut mock = test_utils::MockReadWrite {
301            buffer: get_request_1_bytes(),
302        };
303        // Put an invalid version major field.
304        mock.buffer[6] = 0xFF;
305        // Put an invalid version minor field.
306        mock.buffer[7] = 0xFF;
307
308        let response_status =
309            Request::read_from_stream(&mut mock, 1000).expect_err("Should have failed.");
310
311        assert_eq!(
312            response_status,
313            ResponseStatus::WireProtocolVersionNotSupported
314        );
315    }
316
317    fn get_request_1() -> Request {
318        let body = RequestBody::from_bytes(vec![0x70, 0x80, 0x90]);
319        let auth = RequestAuth::new(vec![0xa0, 0xb0, 0xc0]);
320        let header = RequestHeader {
321            provider: ProviderId::Core,
322            session: 0x11_22_33_44_55_66_77_88,
323            content_type: BodyType::Protobuf,
324            accept_type: BodyType::Protobuf,
325            auth_type: AuthType::Direct,
326            opcode: Opcode::Ping,
327        };
328        Request { header, body, auth }
329    }
330
331    fn get_request_2() -> Request {
332        let body = RequestBody::from_bytes(vec![0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5]);
333        let auth = RequestAuth::new(vec![0xA0, 0xA1, 0xA2, 0xA3, 0xA4]);
334        let header = RequestHeader {
335            provider: ProviderId::Core,
336            session: 0x88_99_AA_BB_CC_DD_EE_FF,
337            content_type: BodyType::Protobuf,
338            accept_type: BodyType::Protobuf,
339            auth_type: AuthType::Direct,
340            opcode: Opcode::Ping,
341        };
342        Request { header, body, auth }
343    }
344
345    fn get_request_1_bytes() -> Vec<u8> {
346        vec![
347            0x10, 0xA7, 0xC0, 0x5E, // MAGIC_NUMBER
348            0x1E, 0x00, // REQUEST_HDR_SIZE
349            0x01, // WIRE_PROTOCOL_VERSION_MAJ
350            0x00, // WIRE_PROTOCOL_VERSION_MIN
351            0x00, 0x00, // WireHeader::flags
352            0x00, // WireHeader::provider
353            0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, // WireHeader::session
354            0x00, // WireHeader::content_type
355            0x00, // WireHeader::accept_type
356            0x01, // WireHeader::auth_type
357            0x03, 0x00, 0x00, 0x00, // WireHeader::body_len
358            0x03, 0x00, // WireHeader::auth_len
359            0x01, 0x00, 0x00, 0x00, // WireHeader::opcode
360            0x00, 0x00, // WireHeader::status
361            0x00, // WireHeader::reserved1
362            0x00, // WireHeader::reserved2
363            0x70, 0x80, 0x90, // RequestBody
364            0xA0, 0xB0, 0xC0, // RequestAuth
365        ]
366    }
367
368    fn get_request_2_bytes() -> Vec<u8> {
369        vec![
370            0x10, 0xA7, 0xC0, 0x5E, // MAGIC_NUMBER
371            0x1E, 0x00, // REQUEST_HDR_SIZE
372            0x01, // WIRE_PROTOCOL_VERSION_MAJ
373            0x00, // WIRE_PROTOCOL_VERSION_MIN
374            0x00, 0x00, // WireHeader::flags
375            0x00, // WireHeader::provider
376            0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, // WireHeader::session
377            0x00, // WireHeader::content_type
378            0x00, // WireHeader::accept_type
379            0x01, // WireHeader::auth_type
380            0x06, 0x00, 0x00, 0x00, // WireHeader::body_len
381            0x05, 0x00, // WireHeader::auth_len
382            0x01, 0x00, 0x00, 0x00, // WireHeader::opcode
383            0x00, 0x00, // WireHeader::status
384            0x00, // WireHeader::reserved1
385            0x00, // WireHeader::reserved2
386            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, // RequestBody
387            0xA0, 0xA1, 0xA2, 0xA3, 0xA4, // RequestAuth
388        ]
389    }
390
391    fn get_request_bytes_reserved_fields_both_not_zero() -> Vec<u8> {
392        // reserved fields set to 0xDEAD
393        vec![
394            0x10, 0xA7, 0xC0, 0x5E, // MAGIC_NUMBER
395            0x1E, 0x00, // REQUEST_HDR_SIZE
396            0x01, // WIRE_PROTOCOL_VERSION_MAJ
397            0x00, // WIRE_PROTOCOL_VERSION_MIN
398            0x00, 0x00, // WireHeader::flags
399            0x00, // WireHeader::provider
400            0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, // WireHeader::session
401            0x00, // WireHeader::content_type
402            0x00, // WireHeader::accept_type
403            0x01, // WireHeader::auth_type
404            0x06, 0x00, 0x00, 0x00, // WireHeader::body_len
405            0x05, 0x00, // WireHeader::auth_len
406            0x01, 0x00, 0x00, 0x00, // WireHeader::opcode
407            0x00, 0x00, // WireHeader::status
408            0xDE, // WireHeader::reserved1
409            0xAD, // WireHeader::reserved2
410            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, // RequestBody
411            0xA0, 0xA1, 0xA2, 0xA3, 0xA4, // RequestAuth
412        ]
413    }
414
415    fn get_request_bytes_reserved_fields_first_not_zero() -> Vec<u8> {
416        vec![
417            0x10, 0xA7, 0xC0, 0x5E, // MAGIC_NUMBER
418            0x1E, 0x00, // REQUEST_HDR_SIZE
419            0x01, // WIRE_PROTOCOL_VERSION_MAJ
420            0x00, // WIRE_PROTOCOL_VERSION_MIN
421            0x00, 0x00, // WireHeader::flags
422            0x00, // WireHeader::provider
423            0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, // WireHeader::session
424            0x00, // WireHeader::content_type
425            0x00, // WireHeader::accept_type
426            0x01, // WireHeader::auth_type
427            0x06, 0x00, 0x00, 0x00, // WireHeader::body_len
428            0x05, 0x00, // WireHeader::auth_len
429            0x01, 0x00, 0x00, 0x00, // WireHeader::opcode
430            0x00, 0x00, // WireHeader::status
431            0xDE, // WireHeader::reserved1
432            0x00, // WireHeader::reserved2
433            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, // RequestBody
434            0xA0, 0xA1, 0xA2, 0xA3, 0xA4, // RequestAuth
435        ]
436    }
437    fn get_request_bytes_reserved_fields_second_not_zero() -> Vec<u8> {
438        vec![
439            0x10, 0xA7, 0xC0, 0x5E, // MAGIC_NUMBER
440            0x1E, 0x00, // REQUEST_HDR_SIZE
441            0x01, // WIRE_PROTOCOL_VERSION_MAJ
442            0x00, // WIRE_PROTOCOL_VERSION_MIN
443            0x00, 0x00, // WireHeader::flags
444            0x00, // WireHeader::provider
445            0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, // WireHeader::session
446            0x00, // WireHeader::content_type
447            0x00, // WireHeader::accept_type
448            0x01, // WireHeader::auth_type
449            0x06, 0x00, 0x00, 0x00, // WireHeader::body_len
450            0x05, 0x00, // WireHeader::auth_len
451            0x01, 0x00, 0x00, 0x00, // WireHeader::opcode
452            0x00, 0x00, // WireHeader::status
453            0x00, // WireHeader::reserved1
454            0xAD, // WireHeader::reserved2
455            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, // RequestBody
456            0xA0, 0xA1, 0xA2, 0xA3, 0xA4, // RequestAuth
457        ]
458    }
459    fn get_request_bytes_big_endian_fixint_encoding() -> Vec<u8> {
460        vec![
461            0x5E, 0xC0, 0xA7, 0x10, // MAGIC_NUMBER
462            0x00, 0x1E, // REQUEST_HDR_SIZE
463            0x01, // WIRE_PROTOCOL_VERSION_MAJ
464            0x00, // WIRE_PROTOCOL_VERSION_MIN
465            0x00, 0x00, // WireHeader::flags
466            0x00, // WireHeader::provider
467            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // WireHeader::session
468            0x00, // WireHeader::content_type
469            0x00, // WireHeader::accept_type
470            0x01, // WireHeader::auth_type
471            0x00, 0x00, 0x00, 0x03, // WireHeader::body_len
472            0x00, 0x03, // WireHeader::auth_len
473            0x00, 0x00, 0x00, 0x01, // WireHeader::opcode
474            0x00, 0x00, // WireHeader::status
475            0x00, // WireHeader::reserved1
476            0x00, // WireHeader::reserved2
477            0x70, 0x80, 0x90, // RequestBody
478            0xa0, 0xb0, 0xc0, // RequestAuth
479        ]
480    }
481    fn get_request_bytes_little_endian_varint_encoding() -> Vec<u8> {
482        vec![
483            0xFC, // Encoding byte indicates that the following 4 bytes make a u32 int
484            //https://docs.rs/bincode/1.3.3/bincode/config/struct.VarintEncoding.html
485            0x5E, 0xC0, 0xA7, 0x10, // MAGIC_NUMBER
486            0x1E, // REQUEST_HDR_SIZE
487            0x01, // WIRE_PROTOCOL_VERSION_MAJ
488            0x00, // WIRE_PROTOCOL_VERSION_MIN
489            0x00, // WireHeader::flags
490            0x00, // WireHeader::provider
491            0xFD, // Encoding byte indicates that the following 8 bytes make a u64 int
492            //https://docs.rs/bincode/1.3.3/bincode/config/struct.VarintEncoding.html
493            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // WireHeader::session
494            0x00, // WireHeader::content_type
495            0x00, // WireHeader::accept_type
496            0x01, // WireHeader::auth_type
497            0x03, // WireHeader::body_len
498            0x03, // WireHeader::auth_len
499            0x01, // WireHeader::opcode
500            0x00, // WireHeader::status
501            0x00, // WireHeader::reserved1
502            0x00, // WireHeader::reserved2
503            0x70, 0x80, 0x90, // RequestBody
504            0xA0, 0xB0, 0xC0, // RequestAuth
505        ]
506    }
507    fn get_request_bytes_big_endian_varint_encoding() -> Vec<u8> {
508        vec![
509            0xFC, // Encoding byte indicates that the following 4 bytes make a u32 int
510            //https://docs.rs/bincode/1.3.3/bincode/config/struct.VarintEncoding.html
511            0x10, 0xA7, 0xC0, 0x5E, // MAGIC_NUMBER
512            0x1E, // REQUEST_HDR_SIZE
513            0x01, // WIRE_PROTOCOL_VERSION_MAJ
514            0x00, // WIRE_PROTOCOL_VERSION_MIN
515            0x00, // WireHeader::flags
516            0x00, // WireHeader::provider
517            0xFD, // Encoding byte indicates that the following 8 bytes make a u64 int
518            //https://docs.rs/bincode/1.3.3/bincode/config/struct.VarintEncoding.html
519            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // WireHeader::session
520            0x00, // WireHeader::content_type
521            0x00, // WireHeader::accept_type
522            0x01, // WireHeader::auth_type
523            0x03, // WireHeader::body_len
524            0x03, // WireHeader::auth_len
525            0x01, // WireHeader::opcode
526            0x00, // WireHeader::status
527            0x00, // WireHeader::reserved1
528            0x00, // WireHeader::reserved2
529            0x70, 0x80, 0x90, // RequestBody
530            0xA0, 0xB0, 0xC0, // RequestAuth
531        ]
532    }
533}