bt_obex/server/
get.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use log::{trace, warn};
6use packet_encoding::Encodable;
7use std::collections::VecDeque;
8
9use crate::error::Error;
10use crate::header::{Header, HeaderSet, SingleResponseMode};
11use crate::operation::{OpCode, RequestPacket, ResponseCode, ResponsePacket};
12use crate::server::handler::ObexOperationError;
13use crate::server::{ApplicationResponse, OperationRequest, ServerOperation};
14
15/// All Body & EndOfBody headers have 3 bytes (1 byte HI, 2 bytes Length) preceding the payload.
16const BODY_HEADER_PREFIX_LENGTH_BYTES: usize = 3;
17
18/// A collection that maintains the staged data during a GET operation.
19#[derive(Debug, PartialEq)]
20struct StagedData {
21    /// The first chunk of user data.
22    /// This is Some<T> when the first chunk is available and can be taken with `next_response`
23    /// and None otherwise.
24    /// In some cases, no user data can fit in the first chunk and so this will be Some<None>.
25    first: Option<Option<Vec<u8>>>,
26    /// The remaining chunks of user data to be sent.
27    /// The `StagedData` is considered exhausted and complete when both `first` and `rest` are
28    /// empty.
29    rest: VecDeque<Vec<u8>>,
30}
31
32impl StagedData {
33    fn new(first: Option<Vec<u8>>, rest: VecDeque<Vec<u8>>) -> Self {
34        Self { first: Some(first), rest }
35    }
36
37    fn empty() -> Self {
38        Self { first: None, rest: VecDeque::new() }
39    }
40
41    /// Builds and stages the `data` into chunks of Headers (Body/EndOfBody) that conform to the
42    /// provided `max_headers_size`.
43    /// `header_size` is the size (in bytes) of the informational headers describing the `data`.
44    /// Returns Ok if the data was successfully divided, Error if the data could not be chunked or
45    /// if the provided `max_headers_size` or `headers_size` is invalid.
46    fn from_data(
47        mut data: Vec<u8>,
48        max_headers_size: u16,
49        headers_size: usize,
50    ) -> Result<Self, Error> {
51        let max_headers_size = max_headers_size as usize;
52        // To many headers provided.
53        if headers_size > max_headers_size {
54            warn!("Too many headers in GET");
55            // TODO(https://fxbug.dev/42082648): It's probably reasonable to support this case by splitting
56            // the headers across multiple responses.
57            return Err(Error::operation(OpCode::Get, "too many headers"));
58        }
59
60        // The maximum header size must be able to fit at least a Body/EndOfBody Header with one
61        // byte of data. In practice, this max is in the range of [255, u16::MAX], but this
62        // function is resilient to smaller values.
63        if max_headers_size <= BODY_HEADER_PREFIX_LENGTH_BYTES {
64            return Err(Error::operation(OpCode::Get, "max_headers_size too small"));
65        }
66
67        // The maximum size of the first packet is special as it may contain non-Body/EndOfBody
68        // `headers` and a chunk of user data in the Body/EndOfBody.
69        let max_first_data_packet_size = max_headers_size - headers_size;
70
71        // Check if the entire payload can fit in a single packet.
72        let data_encoded_len = data.len() + BODY_HEADER_PREFIX_LENGTH_BYTES;
73        if data_encoded_len <= max_first_data_packet_size {
74            return Ok(Self::new(Some(data), VecDeque::new()));
75        }
76
77        // Otherwise, we'll need more than one packet. Chunk the special first packet.
78        let first_chunk_size =
79            max_first_data_packet_size.checked_sub(BODY_HEADER_PREFIX_LENGTH_BYTES);
80        let (first, remaining) = if let Some(max) = first_chunk_size {
81            let remaining = data.split_off(max);
82            (Some(data), remaining)
83        } else {
84            // No space in first packet for any user data.
85            (None, data)
86        };
87
88        // The maximum size of all other packets where only data is present.
89        let max_data_packet_size = max_headers_size - BODY_HEADER_PREFIX_LENGTH_BYTES;
90        // Chunk up the rest.
91        let mut chunks = VecDeque::new();
92        for chunk in remaining.chunks(max_data_packet_size as usize) {
93            chunks.push_back(chunk.to_vec());
94        }
95        Ok(Self::new(first, chunks))
96    }
97
98    /// Returns true if the first response exists and can be taken.
99    #[cfg(test)]
100    fn is_first_response(&self) -> bool {
101        self.first.is_some()
102    }
103
104    /// Returns true if the first response and all staged data has been taken.
105    fn is_complete(&self) -> bool {
106        self.first.is_none() && self.rest.is_empty()
107    }
108
109    /// Returns the response packet for the next chunk of data in the staged payload.
110    /// Returns Error if all the data has already been returned - namely, `Self::is_complete` is
111    /// true or if the response packet couldn't be built with the provided `headers`.
112    fn next_response(&mut self, mut headers: HeaderSet) -> Result<ResponsePacket, Error> {
113        if self.is_complete() {
114            return Err(Error::operation(OpCode::Get, "staged data is already complete"));
115        }
116
117        let chunk = if let Some(first_packet) = self.first.take() {
118            // First chunk, which may be None if no user data can fit in the first packet.
119            first_packet
120        } else {
121            // Otherwise, subsequent chunk. This must always be populated, even if empty.
122            Some(self.rest.pop_front().unwrap_or(vec![]))
123        };
124
125        // If `self.rest` is empty after grabbing the next chunk, then this is the final chunk of
126        // the payload. An EndOfBody header is used instead of Body for the chunk.
127        let (code, h) = if self.rest.is_empty() {
128            (ResponseCode::Ok, chunk.map(|p| Header::EndOfBody(p)))
129        } else {
130            (ResponseCode::Continue, chunk.map(|p| Header::Body(p)))
131        };
132
133        if let Some(header) = h {
134            headers.add(header)?;
135        }
136        Ok(ResponsePacket::new_get(code, headers))
137    }
138
139    /// Returns response packets for all of the staged data.
140    /// Returns Error if all of the data has already been returned.
141    fn all_responses(
142        &mut self,
143        mut initial_headers: HeaderSet,
144    ) -> Result<Vec<ResponsePacket>, Error> {
145        let mut responses = Vec::new();
146        while !self.is_complete() {
147            // Only the first packet will contain the `initial_headers`. Subsequent responses will
148            // not have any informational headers.
149            let headers = std::mem::replace(&mut initial_headers, HeaderSet::new());
150            let response = self.next_response(headers)?;
151            responses.push(response);
152        }
153        Ok(responses)
154    }
155}
156
157/// The current state of the GET operation.
158#[derive(Debug)]
159enum State {
160    /// The request phase of the operation in which the remote OBEX client sends informational
161    /// headers describing the payload. This can be spread out over multiple packets.
162    /// `headers` contain staged informational headers to be relayed to the upper application
163    /// profile.
164    Request { headers: HeaderSet },
165    /// The request phase of the operation is complete (GET_FINAL has been received) and we are
166    /// waiting for the profile application.
167    /// The response phase is started by calling `GetOperation::handle_application_response` with
168    /// the profile application's accepting or rejecting of the request.
169    RequestPhaseComplete,
170    /// The profile application has accepted the GET request.
171    /// The response phase of the operation in which the local OBEX server sends the payload over
172    /// potentially multiple packets.
173    Response { staged_data: StagedData },
174    /// The response phase of the operation is complete (all data packets have been relayed). The
175    /// entire GET operation is considered complete.
176    Complete,
177}
178
179/// The current SRM status for the GET operation.
180enum SrmState {
181    /// SRM has not been negotiated yet.
182    /// `srm_supported` is true if SRM is supported locally.
183    NotNegotiated { srm_supported: bool },
184    /// SRM is currently negotiating and therefore we need to send a SRM response to the peer.
185    /// `negotiated_srm` is the negotiated SRM value that will be sent to the peer.
186    Negotiating { negotiated_srm: SingleResponseMode },
187    /// SRM has been negotiated. If `srm` is `SingleResponseMode::Enable`, then SRM is considered
188    /// active for the duration of this GET operation.
189    Negotiated { srm: SingleResponseMode },
190}
191
192/// Represents an in-progress GET operation.
193pub struct GetOperation {
194    /// The maximum number of bytes that can be allocated to headers in the GetOperation. This
195    /// includes informational headers and data headers.
196    max_headers_size: u16,
197    /// The current SRM status for this operation.
198    /// SRM may not necessarily be negotiated during a GET operation in which case is defaulted
199    /// to disabled.
200    srm_state: SrmState,
201    /// Current state of the GET operation.
202    state: State,
203}
204
205impl GetOperation {
206    /// `max_packet_size` is the max number of bytes that can fit in a single packet.
207    pub fn new(max_packet_size: u16, srm_supported: bool) -> Self {
208        let max_headers_size = max_packet_size - ResponsePacket::MIN_PACKET_SIZE as u16;
209        Self {
210            max_headers_size,
211            srm_state: SrmState::NotNegotiated { srm_supported },
212            state: State::Request { headers: HeaderSet::new() },
213        }
214    }
215
216    #[cfg(test)]
217    fn new_at_state(max_packet_size: u16, state: State) -> Self {
218        let max_headers_size = max_packet_size - ResponsePacket::MIN_PACKET_SIZE as u16;
219        Self {
220            max_headers_size,
221            srm_state: SrmState::NotNegotiated { srm_supported: false },
222            state,
223        }
224    }
225
226    /// Checks if the operation is complete and updates the state.
227    fn check_complete_and_update_state(&mut self) {
228        let State::Response { ref staged_data } = &self.state else { return };
229
230        if staged_data.is_complete() {
231            self.state = State::Complete;
232        }
233    }
234
235    /// Attempts to add the SRM response to the provided `headers`.
236    /// Returns Ok(true) if SRM is negotiating and the header was added.
237    /// Returns Ok(false) if SRM is not negotiating and the header wasn't added.
238    /// Returns Error if the SRM response couldn't be added to `headers`.
239    fn maybe_add_srm_header(&mut self, headers: &mut HeaderSet) -> Result<bool, Error> {
240        if let SrmState::Negotiating { negotiated_srm } = self.srm_state {
241            headers.add(negotiated_srm.into())?;
242            self.srm_state = SrmState::Negotiated { srm: negotiated_srm };
243            return Ok(true);
244        }
245        Ok(false)
246    }
247}
248
249impl ServerOperation for GetOperation {
250    fn srm_status(&self) -> SingleResponseMode {
251        // Defaults to disabled if SRM has not been negotiated.
252        match self.srm_state {
253            SrmState::NotNegotiated { .. } | SrmState::Negotiating { .. } => {
254                SingleResponseMode::Disable
255            }
256            SrmState::Negotiated { srm } => srm,
257        }
258    }
259
260    fn is_complete(&self) -> bool {
261        matches!(self.state, State::Complete)
262    }
263
264    fn handle_peer_request(&mut self, request: RequestPacket) -> Result<OperationRequest, Error> {
265        let code = *request.code();
266        // The current SRM mode before processing the peer's `request`, which can contain a SRM
267        // request. If SRM is not negotiated, or negotiation is in progress, this will default to
268        // `Disable` since SRM is not considered active.
269        let current_srm_mode = self.srm_status();
270        match &mut self.state {
271            State::Request { ref mut headers } if code == OpCode::Get => {
272                let request_headers = HeaderSet::from(request);
273                // The response to the `request` depends on the current SRM status.
274                // If SRM is enabled, then no response is needed.
275                // If SRM is disabled or is being negotiated, then we expect to reply with the
276                // application's response headers.
277                // If SRM hasn't been negotiated yet, we check to see if the peer requests it
278                // and include the negotiated SRM header in the next response.
279                match self.srm_state {
280                    SrmState::Negotiated { srm: SingleResponseMode::Enable } => {
281                        // Stage the request headers to be given to the application.
282                        headers.try_append(request_headers)?;
283                        return Ok(OperationRequest::None);
284                    }
285                    SrmState::Negotiated { srm: SingleResponseMode::Disable }
286                    | SrmState::Negotiating { .. } => {}
287                    SrmState::NotNegotiated { srm_supported } => {
288                        // SRM hasn't been negotiated. Check if the peer is requesting it.
289                        if let Some(negotiated_srm) =
290                            Self::check_headers_for_srm(srm_supported, &request_headers)
291                        {
292                            // The peer is requesting to update the SRM status. We need to
293                            // include it in the next response packet.
294                            self.srm_state = SrmState::Negotiating { negotiated_srm };
295                        }
296                    }
297                };
298                Ok(OperationRequest::GetApplicationInfo(request_headers))
299            }
300            State::Request { ref mut headers } if code == OpCode::GetFinal => {
301                headers.try_append(HeaderSet::from(request))?;
302                // Update the current SRM status if it hasn't been negotiated yet.
303                if let SrmState::NotNegotiated { srm_supported } = self.srm_state {
304                    if let Some(negotiated_srm) =
305                        Self::check_headers_for_srm(srm_supported, &headers)
306                    {
307                        // The peer is requesting to update the SRM status. We need to
308                        // include it in the next response packet.
309                        self.srm_state = SrmState::Negotiating { negotiated_srm };
310                    }
311                }
312
313                let request_headers = std::mem::replace(headers, HeaderSet::new());
314                // This is the final request packet. All request headers have been received and we
315                // are ready to get the payload from the application.
316                self.state = State::RequestPhaseComplete;
317                Ok(OperationRequest::GetApplicationData(request_headers))
318            }
319            State::Response { ref mut staged_data } if code == OpCode::GetFinal => {
320                let responses = if current_srm_mode == SingleResponseMode::Enable {
321                    staged_data.all_responses(HeaderSet::new())?
322                } else {
323                    vec![staged_data.next_response(HeaderSet::new())?]
324                };
325                self.check_complete_and_update_state();
326                Ok(OperationRequest::SendPackets(responses))
327            }
328            _ => Err(Error::operation(OpCode::Get, "received invalid request")),
329        }
330    }
331
332    fn handle_application_response(
333        &mut self,
334        response: Result<ApplicationResponse, ObexOperationError>,
335    ) -> Result<Vec<ResponsePacket>, Error> {
336        let response = match response {
337            Ok(response) => response,
338            Err((code, response_headers)) => {
339                trace!("Application rejected GET request: {code:?}");
340                self.state = State::Response { staged_data: StagedData::empty() };
341                self.check_complete_and_update_state();
342                return Ok(vec![ResponsePacket::new_get(code, response_headers)]);
343            }
344        };
345
346        match response {
347            ApplicationResponse::GetInfo(mut response_headers) => {
348                if !matches!(self.state, State::Request { .. }) {
349                    return Err(Error::operation(OpCode::Get, "GetInfo response in invalid state"));
350                }
351                let _ = self.maybe_add_srm_header(&mut response_headers)?;
352                Ok(vec![ResponsePacket::new_get(ResponseCode::Continue, response_headers)])
353            }
354            ApplicationResponse::GetData((data, response_headers)) => {
355                if !matches!(self.state, State::RequestPhaseComplete) {
356                    return Err(Error::operation(
357                        OpCode::Get,
358                        "Get response before request phase complete",
359                    ));
360                }
361
362                let mut srm_headers = HeaderSet::new();
363                let srm_packet = if self.maybe_add_srm_header(&mut srm_headers)? {
364                    Some(ResponsePacket::new_get(ResponseCode::Continue, srm_headers))
365                } else {
366                    None
367                };
368
369                // Potentially split the user data payload into chunks to be sent over multiple
370                // response packets.
371                let mut staged_data = StagedData::from_data(
372                    data,
373                    self.max_headers_size,
374                    response_headers.encoded_len(),
375                )?;
376
377                let responses = match (self.srm_status(), srm_packet) {
378                    (SingleResponseMode::Enable, Some(packet)) => {
379                        // If SRM was just enabled, then the first packet will only be the SRM
380                        // response. The remaining packets will contain the data & informational
381                        // headers.
382                        let mut packets = vec![packet];
383                        packets.append(&mut staged_data.all_responses(response_headers)?);
384                        packets
385                    }
386                    (SingleResponseMode::Disable, Some(packet)) => {
387                        // If SRM was just disabled, then the first packet will only be the SRM
388                        // response. The peer will make subsequent requests to get the data.
389                        vec![packet]
390                    }
391                    (SingleResponseMode::Enable, None) => {
392                        // SRM is enabled so all packets will be returned.
393                        staged_data.all_responses(response_headers)?
394                    }
395                    (SingleResponseMode::Disable, None) => {
396                        // SRM is disabled, so only the next packet will be returned.
397                        vec![staged_data.next_response(response_headers)?]
398                    }
399                };
400                self.state = State::Response { staged_data };
401                self.check_complete_and_update_state();
402                Ok(responses)
403            }
404            ApplicationResponse::Put => {
405                Err(Error::operation(OpCode::Get, "invalid application response to GET request"))
406            }
407        }
408    }
409}
410
411#[cfg(test)]
412mod tests {
413    use super::*;
414
415    use assert_matches::assert_matches;
416
417    use crate::header::header_set::{expect_body, expect_end_of_body};
418    use crate::header::HeaderIdentifier;
419    use crate::server::test_utils::expect_single_packet;
420
421    fn bytes(start_idx: usize, end_idx: usize) -> Vec<u8> {
422        // NOTE: In practice this can result in unexpected behavior if `start_idx` and `end_idx`
423        // are too large.
424        let s = start_idx as u8;
425        let e = end_idx as u8;
426        (s..e).collect::<Vec<u8>>()
427    }
428
429    /// Expects a single outgoing response packet with the `expected_code` and `expected_body`.
430    #[track_caller]
431    fn expect_packet_with_body(
432        operation_request: OperationRequest,
433        expected_code: ResponseCode,
434        expected_body: Vec<u8>,
435    ) {
436        let packet = expect_single_packet(operation_request);
437        assert_eq!(*packet.code(), expected_code);
438        if expected_code == ResponseCode::Ok {
439            expect_end_of_body(packet.headers(), expected_body);
440        } else {
441            expect_body(packet.headers(), expected_body);
442        }
443    }
444
445    #[fuchsia::test]
446    fn single_packet_get_operation() {
447        let max_packet_size = 50;
448        let mut operation = GetOperation::new(max_packet_size, false);
449        assert!(!operation.is_complete());
450
451        // First (and final) request with informational headers.
452        let headers = HeaderSet::from_header(Header::name("default"));
453        let request = RequestPacket::new_get_final(headers);
454        let response1 = operation.handle_peer_request(request).expect("valid request");
455        assert_matches!(response1,
456            OperationRequest::GetApplicationData(headers)
457            if headers.contains_header(&HeaderIdentifier::Name)
458        );
459
460        // Application provides the payload. Since the entire payload can fit in a single packet,
461        // we expect the operation to be complete after it is returned.
462        let payload = bytes(0, 25);
463        let mut responses2 = operation
464            .handle_application_response(ApplicationResponse::accept_get(payload, HeaderSet::new()))
465            .expect("valid response");
466        let response2 = responses2.pop().expect("one response");
467        assert_eq!(*response2.code(), ResponseCode::Ok);
468        expect_end_of_body(response2.headers(), bytes(0, 25));
469        assert!(operation.is_complete());
470    }
471
472    #[fuchsia::test]
473    fn multi_packet_get_operation() {
474        let max_packet_size = 50;
475        let mut operation = GetOperation::new(max_packet_size, false);
476        assert!(!operation.is_complete());
477
478        // First request provides informational headers. Expect to ask the application for a
479        // response.
480        let headers1 = HeaderSet::from_header(Header::name("foo".into()));
481        let request1 = RequestPacket::new_get(headers1);
482        let response1 = operation.handle_peer_request(request1).expect("valid request");
483        assert_matches!(response1, OperationRequest::GetApplicationInfo(headers) if headers.contains_header(&HeaderIdentifier::Name));
484
485        // Application responds with a header - expect to handle it and return a single outgoing
486        // packet to be sent to the peer.
487        let info_headers = HeaderSet::from_header(Header::Description("ok".into()));
488        let response2 = operation
489            .handle_application_response(ApplicationResponse::accept_get_info(info_headers))
490            .expect("valid request");
491        assert_eq!(response2.len(), 1);
492        assert_eq!(*response2[0].code(), ResponseCode::Continue);
493        assert!(response2[0].headers().contains_header(&HeaderIdentifier::Description));
494
495        // Peer sends a final request with more informational headers. Expect to ask the profile
496        // application for the user data payload. The received informational headers should also be
497        // relayed.
498        let headers3 = HeaderSet::from_header(Header::Type("text/x-vCard".into()));
499        let request3 = RequestPacket::new_get_final(headers3);
500        let response3 = operation.handle_peer_request(request3).expect("valid request");
501        assert_matches!(response3,
502            OperationRequest::GetApplicationData(headers)
503            if headers.contains_header(&HeaderIdentifier::Type)
504        );
505
506        // After providing the payload, we expect the first response packet to contain the
507        // response headers and the first chunk of the payload since it cannot entirely fit in
508        // `max_packet_size`.
509        // The `response_headers` has an encoded size of 33 bytes. This leaves 17 bytes for the
510        // first chunk of user data, of which 6 bytes are allocated to the prefix.
511        let payload = bytes(0, 200);
512        let response_headers = HeaderSet::from_header(Header::Description("random payload".into()));
513        let response_packets4 = operation
514            .handle_application_response(ApplicationResponse::accept_get(payload, response_headers))
515            .expect("valid response");
516        assert_eq!(response_packets4.len(), 1);
517        assert_eq!(*response_packets4[0].code(), ResponseCode::Continue);
518        expect_body(response_packets4[0].headers(), bytes(0, 11));
519
520        // Peer will keep asking for payload until finished.
521        // Each data chunk will be 44 bytes long (max 50 - 6 byte prefix)
522        let expected_bytes =
523            vec![bytes(11, 55), bytes(55, 99), bytes(99, 143), bytes(143, 187), bytes(187, 200)];
524        for (i, expected) in expected_bytes.into_iter().enumerate() {
525            let expected_code = if i == 4 { ResponseCode::Ok } else { ResponseCode::Continue };
526            let request = RequestPacket::new_get_final(HeaderSet::new());
527            let response = operation.handle_peer_request(request).expect("valid request");
528            expect_packet_with_body(response, expected_code, expected);
529        }
530        assert!(operation.is_complete());
531    }
532
533    #[fuchsia::test]
534    fn multi_packet_get_operation_srm_enabled() {
535        let max_packet_size = 50;
536        let mut operation = GetOperation::new(max_packet_size, true);
537        assert!(!operation.is_complete());
538        assert_eq!(operation.srm_status(), SingleResponseMode::Disable);
539
540        // First request provides a Name and SRM enable request. Expect to ask application and
541        // eventually reply positively to negotiate SRM.
542        let headers1 = HeaderSet::from_headers(vec![
543            Header::name("foo".into()),
544            SingleResponseMode::Enable.into(),
545        ])
546        .unwrap();
547        let request1 = RequestPacket::new_get(headers1);
548        let response1 = operation.handle_peer_request(request1).expect("valid request");
549        assert_matches!(response1, OperationRequest::GetApplicationInfo(headers) if headers.contains_header(&HeaderIdentifier::Name));
550
551        // Application responds with a header - expect to return a single outgoing packet to be sent
552        // to the peer which contains the SRM header.
553        let info_headers = HeaderSet::from_header(Header::Description("ok".into()));
554        let response2 = operation
555            .handle_application_response(ApplicationResponse::accept_get_info(info_headers))
556            .expect("valid request");
557        assert_eq!(response2.len(), 1);
558        assert_eq!(*response2[0].code(), ResponseCode::Continue);
559        assert!(response2[0].headers().contains_header(&HeaderIdentifier::Description));
560        assert!(response2[0].headers().contains_header(&HeaderIdentifier::SingleResponseMode));
561        // SRM should be enabled now.
562        assert_eq!(operation.srm_status(), SingleResponseMode::Enable);
563
564        // Second (non-final) request from the peer. Don't expect an immediate response since SRM is
565        // active.
566        let headers3 = HeaderSet::from_header(Header::Description("random payload".into()));
567        let request3 = RequestPacket::new_get(headers3);
568        let response3 = operation.handle_peer_request(request3).expect("valid request");
569        assert_matches!(response3, OperationRequest::None);
570
571        // Third and final request provides a Type header - the request phase is considered complete
572        // Expect to ask the profile application for the user data payload with the previous two
573        // headers.
574        let headers4 = HeaderSet::from_header(Header::Type("text/x-vCard".into()));
575        let request4 = RequestPacket::new_get_final(headers4);
576        let response4 = operation.handle_peer_request(request4).expect("valid request");
577        assert_matches!(response4,
578            OperationRequest::GetApplicationData(headers)
579            if
580             headers.contains_header(&HeaderIdentifier::Type)
581            && headers.contains_header(&HeaderIdentifier::Description)
582        );
583
584        // After getting the payload from the application, we expect to send _all_ of the packets
585        // subsequently, since SRM is enabled. We expect 4 packets in total due to `max_packet_size`
586        // limitations.
587        let payload = bytes(0, 100);
588        let response_headers = HeaderSet::from_header(Header::Description("random payload".into()));
589        let response_packets = operation
590            .handle_application_response(ApplicationResponse::accept_get(payload, response_headers))
591            .expect("valid response");
592        assert_eq!(response_packets.len(), 4);
593        // First packet is special as it contains informational headers & data. `response_headers`
594        // takes up 39 bytes when encoded, so only 11 bytes of user data can fit in the packet.
595        assert_eq!(*response_packets[0].code(), ResponseCode::Continue);
596        expect_body(response_packets[0].headers(), bytes(0, 11));
597
598        // Each subsequent data chunk will be 44 bytes long (max 50 - 3 bytes for response prefix
599        // - 3 bytes for header prefix).
600        let expected_bytes = [bytes(11, 55), bytes(55, 99), bytes(99, 100)];
601        for (i, expected) in expected_bytes.into_iter().enumerate() {
602            // Skip the first packet since it's validated outside of the loop.
603            let idx = i + 1;
604            // Last packet has a code of `Ok`.
605            let expected_code = if idx == 3 { ResponseCode::Ok } else { ResponseCode::Continue };
606            assert_eq!(*response_packets[idx].code(), expected_code);
607            if expected_code == ResponseCode::Ok {
608                expect_end_of_body(response_packets[idx].headers(), expected);
609            } else {
610                expect_body(response_packets[idx].headers(), expected);
611            }
612        }
613
614        // The operation is considered complete after this.
615        assert!(operation.is_complete());
616    }
617
618    // While unusual, it's valid for the peer to request SRM on the GetFinal packet. We should
619    // handle this and send the remaining data chunks after the first response.
620    #[fuchsia::test]
621    fn srm_enable_request_during_get_final_success() {
622        let max_packet_size = 50;
623        let mut operation = GetOperation::new(max_packet_size, true);
624
625        // First (and final) request contains a SRM enable request. Expect to get the data from
626        // the application and respond.
627        let headers1 = HeaderSet::from_header(SingleResponseMode::Enable.into());
628        let request1 = RequestPacket::new_get_final(headers1);
629        let response1 = operation.handle_peer_request(request1).expect("valid request");
630        assert_matches!(response1, OperationRequest::GetApplicationData(_));
631        assert!(!operation.is_complete());
632
633        // Because SRM was just requested, the first response packet should contain the SRM accept
634        // response. Subsequent packets will contain the data.
635        let payload = bytes(0, 90);
636        let response_headers = HeaderSet::from_header(Header::Description("random payload".into()));
637        let response_packets = operation
638            .handle_application_response(ApplicationResponse::accept_get(payload, response_headers))
639            .expect("valid response");
640        assert_eq!(response_packets.len(), 4);
641        assert_eq!(*response_packets[0].code(), ResponseCode::Continue);
642        assert!(response_packets[0]
643            .headers()
644            .contains_header(&HeaderIdentifier::SingleResponseMode));
645        // Shouldn't contain the Body or Description, yet.
646        assert!(!response_packets[0].headers().contains_header(&HeaderIdentifier::Description));
647        assert!(!response_packets[0].headers().contains_header(&HeaderIdentifier::Body));
648        assert_eq!(operation.srm_status(), SingleResponseMode::Enable);
649
650        // Each chunk can hold max (50) - 6 bytes (prefix) = 44 bytes of user data.
651        // The first chunk of data also contains the Description header (39 bytes), so there is only
652        // 12 bytes of data.
653        assert!(response_packets[1].headers().contains_header(&HeaderIdentifier::Description));
654        expect_body(response_packets[1].headers(), bytes(0, 11));
655        expect_body(response_packets[2].headers(), bytes(11, 55));
656        expect_end_of_body(response_packets[3].headers(), bytes(55, 90));
657        assert!(operation.is_complete());
658    }
659
660    #[fuchsia::test]
661    fn srm_disable_request_during_get_final_success() {
662        let max_packet_size = 50;
663        let mut operation = GetOperation::new(max_packet_size, false);
664
665        // First (and final) request contains a SRM enable request. Expect to get the data from
666        // the application and respond.
667        let headers1 = HeaderSet::from_header(SingleResponseMode::Enable.into());
668        let request1 = RequestPacket::new_get_final(headers1);
669        let response1 = operation.handle_peer_request(request1).expect("valid request");
670        assert_matches!(response1, OperationRequest::GetApplicationData(_));
671        assert!(!operation.is_complete());
672
673        // Because SRM was just requested and we don't support it, the first packet should only
674        // contain the negative response - SRM should be disabled for this operation.
675        let payload = bytes(0, 90);
676        let response_packets = operation
677            .handle_application_response(ApplicationResponse::accept_get(payload, HeaderSet::new()))
678            .expect("valid response");
679        assert_eq!(response_packets.len(), 1);
680        assert_eq!(*response_packets[0].code(), ResponseCode::Continue);
681        let received_srm = response_packets[0]
682            .headers()
683            .get(&HeaderIdentifier::SingleResponseMode)
684            .expect("contains SRM");
685        assert_eq!(*received_srm, Header::SingleResponseMode(SingleResponseMode::Disable));
686        // Shouldn't contain the Body in the first packet.
687        assert!(!response_packets[0].headers().contains_header(&HeaderIdentifier::Body));
688        assert_eq!(operation.srm_status(), SingleResponseMode::Disable);
689
690        // Because SRM is disabled, the peeer should issue GETFINAL requests for each data chunk.
691        let expected_bytes = vec![bytes(0, 44), bytes(44, 88), bytes(88, 90)];
692        for (i, expected) in expected_bytes.into_iter().enumerate() {
693            let expected_code = if i == 2 { ResponseCode::Ok } else { ResponseCode::Continue };
694            let request2 = RequestPacket::new_get_final(HeaderSet::new());
695            let response2 = operation.handle_peer_request(request2).expect("valid request");
696            expect_packet_with_body(response2, expected_code, expected);
697        }
698        assert!(operation.is_complete());
699    }
700
701    #[fuchsia::test]
702    fn application_rejects_request_success() {
703        let mut operation = GetOperation::new_at_state(10, State::RequestPhaseComplete);
704        let headers = HeaderSet::from_header(Header::Description("not allowed today".into()));
705        let response_packets = operation
706            .handle_application_response(Err((ResponseCode::Forbidden, headers)))
707            .expect("rejection is ok");
708        assert_eq!(*response_packets[0].code(), ResponseCode::Forbidden);
709        assert!(response_packets[0].headers().contains_header(&HeaderIdentifier::Description));
710        assert!(operation.is_complete());
711    }
712
713    #[fuchsia::test]
714    fn handle_application_response_error() {
715        let max_packet_size = 15;
716        // Receiving the application data response before the request phase is complete is an Error.
717        let mut operation = GetOperation::new(max_packet_size, false);
718        let data = vec![1, 2, 3];
719        assert_matches!(
720            operation.handle_application_response(ApplicationResponse::accept_get(
721                data,
722                HeaderSet::new()
723            )),
724            Err(Error::OperationError { .. })
725        );
726
727        // Receiving the application info response after the request phase is complete is an Error.
728        let mut operation = GetOperation::new_at_state(10, State::RequestPhaseComplete);
729        assert_matches!(
730            operation.handle_application_response(ApplicationResponse::accept_get_info(
731                HeaderSet::new()
732            )),
733            Err(Error::OperationError { .. })
734        );
735    }
736
737    #[fuchsia::test]
738    fn non_get_request_is_error() {
739        let mut operation = GetOperation::new(50, false);
740        let random_request1 = RequestPacket::new_put(HeaderSet::new());
741        assert_matches!(
742            operation.handle_peer_request(random_request1),
743            Err(Error::OperationError { .. })
744        );
745
746        let random_request2 = RequestPacket::new_disconnect(HeaderSet::new());
747        assert_matches!(
748            operation.handle_peer_request(random_request2),
749            Err(Error::OperationError { .. })
750        );
751    }
752
753    #[fuchsia::test]
754    fn get_request_invalid_state_is_error() {
755        let random_headers = HeaderSet::from_header(Header::name("foo".into()));
756
757        // Receiving another GET request while we are waiting for the application to accept is an
758        // Error.
759        let mut operation1 = GetOperation::new_at_state(10, State::RequestPhaseComplete);
760        let request1 = RequestPacket::new_get(random_headers.clone());
761        let response1 = operation1.handle_peer_request(request1);
762        assert_matches!(response1, Err(Error::OperationError { .. }));
763
764        // Receiving a GET request when the operation is complete is an Error.
765        let mut operation2 = GetOperation::new_at_state(10, State::Complete);
766        let request2 = RequestPacket::new_get(random_headers.clone());
767        let response2 = operation2.handle_peer_request(request2);
768        assert_matches!(response2, Err(Error::OperationError { .. }));
769
770        // Receiving a non-GETFINAL request in the response phase is an Error.
771        let staged_data = StagedData { first: None, rest: VecDeque::from(vec![vec![1, 2, 3]]) };
772        let mut operation3 = GetOperation::new_at_state(10, State::Response { staged_data });
773        let request3 = RequestPacket::new_get(random_headers);
774        let response3 = operation3.handle_peer_request(request3);
775        assert_matches!(response3, Err(Error::OperationError { .. }));
776    }
777
778    #[fuchsia::test]
779    fn build_staged_data_success() {
780        // An empty data payload is fine. Should be chunked as a single packet.
781        let empty_data = Vec::new();
782        let empty_headers = HeaderSet::new();
783        let result = StagedData::from_data(empty_data, 50, empty_headers.encoded_len())
784            .expect("can divide data");
785        let expected = StagedData { first: Some(Some(vec![])), rest: VecDeque::new() };
786        assert_eq!(result, expected);
787
788        // A data payload that can fit in a single packet.
789        let headers = HeaderSet::from_header(Header::name("foo".into()));
790        let data = vec![1, 2, 3];
791        let result =
792            StagedData::from_data(data, 50, headers.encoded_len()).expect("can divide data");
793        let expected = StagedData { first: Some(Some(vec![1, 2, 3])), rest: VecDeque::new() };
794        assert_eq!(result, expected);
795
796        // A data payload with headers that is split into multiple packets. The first chunk is
797        // smaller since there must be room for the provided headers.
798        let headers = HeaderSet::from_header(Header::Http(vec![5, 5, 5]));
799        let max = 10;
800        let large_data = (0..50).collect::<Vec<u8>>();
801        let result =
802            StagedData::from_data(large_data, max, headers.encoded_len()).expect("can divide data");
803        let first = Some(vec![0]);
804        let rest = VecDeque::from(vec![
805            bytes(1, 8),
806            bytes(8, 15),
807            bytes(15, 22),
808            bytes(22, 29),
809            bytes(29, 36),
810            bytes(36, 43),
811            bytes(43, 50),
812        ]);
813        let expected = StagedData { first: Some(first), rest };
814        assert_eq!(result, expected);
815    }
816
817    #[fuchsia::test]
818    fn build_staged_data_error() {
819        let random_data = bytes(0, 50);
820
821        // Cannot build and stage data if the overall max packet size is too small.
822        let too_small_max = 2;
823        assert_matches!(
824            StagedData::from_data(random_data.clone(), too_small_max, 0),
825            Err(Error::OperationError { .. })
826        );
827        assert_matches!(
828            StagedData::from_data(random_data.clone(), 0, 0),
829            Err(Error::OperationError { .. })
830        );
831
832        // Cannot build and stage data if the header size is larger than the max.
833        // TODO(https://fxbug.dev/42082648): Delete this case when headers can be split across packets.
834        let small_max = 10;
835        let large_header_size = 20;
836        assert_matches!(
837            StagedData::from_data(random_data, small_max, large_header_size),
838            Err(Error::OperationError { .. })
839        );
840    }
841
842    #[fuchsia::test]
843    fn empty_staged_data_success() {
844        let empty = Vec::new();
845        let empty_headers = HeaderSet::new();
846        let mut staged = StagedData::from_data(empty.clone(), 50, empty_headers.encoded_len())
847            .expect("can construct");
848        assert!(staged.is_first_response());
849        assert!(!staged.is_complete());
850        let response = staged.next_response(empty_headers).expect("has first response");
851        assert_eq!(*response.code(), ResponseCode::Ok);
852        expect_end_of_body(response.headers(), vec![]);
853        assert!(!staged.is_first_response());
854        assert!(staged.is_complete());
855    }
856
857    #[fuchsia::test]
858    fn single_packet_staged_data_success() {
859        let single = vec![1, 2, 3];
860        let empty_headers = HeaderSet::new();
861        let mut staged = StagedData::from_data(single.clone(), 50, empty_headers.encoded_len())
862            .expect("can construct");
863        let response = staged.next_response(empty_headers).expect("has first response");
864        assert_eq!(*response.code(), ResponseCode::Ok);
865        expect_end_of_body(response.headers(), single);
866        assert!(staged.is_complete());
867    }
868
869    #[fuchsia::test]
870    fn multi_packet_staged_data_success() {
871        let max_packet_size = 10;
872        let large_data = (0..30).collect::<Vec<u8>>();
873        let headers = HeaderSet::from_header(Header::Who(vec![1, 2, 3, 4, 5]));
874        let mut staged = StagedData::from_data(large_data, max_packet_size, headers.encoded_len())
875            .expect("can construct");
876        let response1 = staged.next_response(headers).expect("has first response");
877        assert_eq!(*response1.code(), ResponseCode::Continue);
878        // First buffer has no user data since it can't fit with headers.
879        assert!(response1.headers().contains_header(&HeaderIdentifier::Who));
880        assert!(!response1.headers().contains_header(&HeaderIdentifier::Body));
881        assert!(!staged.is_complete());
882
883        // Each next chunk should contain 7 bytes each since the max is 10 and 3 bytes are
884        // reserved for the header prefix.
885        let expected_bytes = vec![bytes(0, 7), bytes(7, 14), bytes(14, 21), bytes(21, 28)];
886        for expected in expected_bytes {
887            let r = staged.next_response(HeaderSet::new()).expect("has next response");
888            assert_eq!(*r.code(), ResponseCode::Continue);
889            expect_body(r.headers(), expected);
890        }
891
892        // Final chunk has the remaining bits and an Ok response code to signal completion.
893        let final_response = staged.next_response(HeaderSet::new()).expect("has next response");
894        assert_eq!(*final_response.code(), ResponseCode::Ok);
895        let expected = bytes(28, 30);
896        expect_end_of_body(final_response.headers(), expected);
897        assert!(staged.is_complete());
898    }
899
900    #[fuchsia::test]
901    fn staged_data_response_error() {
902        // Calling `next_response` when complete is Error.
903        let mut staged = StagedData::new(None, VecDeque::new());
904        let _ = staged.next_response(HeaderSet::new()).expect("has first response");
905        assert!(staged.is_complete());
906        assert_matches!(staged.next_response(HeaderSet::new()), Err(Error::OperationError { .. }));
907    }
908}