Skip to main content

bt_obex/client/
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 futures::SinkExt;
6use log::trace;
7
8use crate::client::SrmOperation;
9use crate::error::Error;
10use crate::header::{HeaderSet, SingleResponseMode};
11use crate::operation::{OpCode, RequestPacket, ResponseCode, ResponsePacket};
12use crate::transport::ObexTransport;
13
14/// Represents an in-progress GET Operation.
15///
16/// Example Usage:
17/// ```
18/// let obex_client = ObexClient::new(..);
19/// let get_operation = obex_client.get()?;
20/// // Optionally make request for information about the payload.
21/// let initial_headers: HeaderSet = ...;
22/// let received_headers = get_operation.get_information(initial_headers).await?;
23/// // Process `received_headers` and make a subsequent request for more information.
24/// let additional_headers: HeaderSet = ...;
25/// let additional_received_headers = get_operation.get_information(additional_headers).await?;
26/// // Make the "final" request to get data.
27/// let body = get_operation.get_data(HeaderSet::new()).await?;
28/// // Process `body` - `get_operation` is consumed and the operation is assumed to be complete.
29/// ```
30#[must_use]
31#[derive(Debug)]
32pub struct GetOperation<'a> {
33    /// The L2CAP or RFCOMM connection to the remote peer.
34    transport: ObexTransport<'a>,
35    /// The initial set of headers used in the GET operation. This is Some<T> when `is_started` is
36    /// false, and None when `is_started` is true.
37    headers: Option<HeaderSet>,
38    /// Whether the operation is in-progress or not - one or more GET requests have been made.
39    is_started: bool,
40    /// The status of SRM for this operation. By default, SRM will be enabled if the transport
41    /// supports it. However, it may be disabled if the peer requests to disable it.
42    srm: SingleResponseMode,
43}
44
45impl<'a> GetOperation<'a> {
46    pub fn new(headers: HeaderSet, transport: ObexTransport<'a>) -> Self {
47        let srm = transport.srm_supported().into();
48        Self { transport, headers: Some(headers), is_started: false, srm }
49    }
50
51    fn set_started(&mut self) {
52        let _ = self.headers.take().unwrap();
53        self.is_started = true;
54    }
55
56    /// Attempts to update the `application_headers` if the operation hasn't started.
57    /// Returns Ok on a successful update or if the operation has already started, Error otherwise.
58    fn update_headers_before_start(
59        &mut self,
60        application_headers: &mut HeaderSet,
61    ) -> Result<(), Error> {
62        if self.is_started {
63            return Ok(());
64        }
65        // Combine the set of application headers with any initial headers.
66        let initial = self.headers.replace(HeaderSet::new()).unwrap();
67        application_headers.try_append(initial)?;
68        // Try to enable SRM since this is the first packet of the operation.
69        self.try_enable_srm(application_headers)?;
70        Ok(())
71    }
72
73    /// Processes the `response` to a GET request and returns the set of headers on success, Error
74    /// otherwise.
75    fn handle_get_response(response: ResponsePacket) -> Result<HeaderSet, Error> {
76        response.expect_code(OpCode::Get, ResponseCode::Continue).map(Into::into)
77    }
78
79    /// Processes the `response` to a GETFINAL request and returns a flag indicating the
80    /// terminal user data payload, responder headers, and the user data payload.
81    fn handle_get_final_response(
82        response: ResponsePacket,
83    ) -> Result<(bool, HeaderSet, Vec<u8>), Error> {
84        // If the response code is OK then this is the final body packet of the GET request.
85        if *response.code() == ResponseCode::Ok {
86            // The EndOfBody Header contains the user data.
87            let mut headers = HeaderSet::from(response);
88            return headers.remove_body(true).map(|eob| (true, headers, eob));
89        }
90
91        // Otherwise, a Continue means there are more body packets left.
92        let mut headers =
93            response.expect_code(OpCode::GetFinal, ResponseCode::Continue).map(HeaderSet::from)?;
94        // The Body Header contains the user data.
95        headers.remove_body(false).map(|b| (false, headers, b))
96    }
97
98    /// Request information about the payload.
99    /// Returns the informational headers from the peer response on success, Error otherwise.
100    ///
101    /// Only one such request can be outstanding at a time. `headers` must be nonempty. If no
102    /// additional information is needed, use `GetOperation::get_data` instead.
103    pub async fn get_information(&mut self, mut headers: HeaderSet) -> Result<HeaderSet, Error> {
104        // Potentially add initial headers if this is the first request in the operation.
105        self.update_headers_before_start(&mut headers)?;
106
107        // For non-final requests, we expect at least one informational header to be sent.
108        if headers.is_empty() {
109            return Err(Error::operation(OpCode::Get, "missing headers"));
110        }
111
112        // SRM is considered active if this is a subsequent GET request & the transport supports it.
113        let srm_active = self.is_started && self.get_srm() == SingleResponseMode::Enable;
114
115        let request = RequestPacket::new_get(headers);
116        trace!(request:?; "Making outgoing GET request");
117        self.transport.send(request).await?;
118        trace!("Successfully made GET request");
119
120        // Only expect a response if SRM is inactive.
121        let response_headers = if !srm_active {
122            let response = self.transport.receive_response(OpCode::Get).await?;
123            Self::handle_get_response(response)?
124        } else {
125            HeaderSet::new()
126        };
127        if !self.is_started {
128            self.check_response_for_srm(&response_headers);
129            self.set_started();
130        }
131        Ok(response_headers)
132    }
133
134    /// Request the user data payload from the remote OBEX server.
135    /// Returns the byte payload on success, Error otherwise.
136    ///
137    /// The GET operation is considered complete after this.
138    pub async fn get_data(mut self, mut headers: HeaderSet) -> Result<Vec<u8>, Error> {
139        // Potentially add initial headers if this is the first request in the operation.
140        self.update_headers_before_start(&mut headers)?;
141
142        let mut request = RequestPacket::new_get_final(headers);
143        let mut first_request = true;
144        let mut body = vec![];
145        loop {
146            // We always make an initial `GetFinal` request. Subsequent requests are only made if
147            // SRM is disabled.
148            if first_request || self.srm != SingleResponseMode::Enable {
149                trace!(request:?; "Making outgoing GET final request");
150                self.transport.send(request.clone()).await?;
151                trace!("Successfully made GET final request");
152                // All subsequent GetFinal requests will not contain any headers.
153                request = RequestPacket::new_get_final(HeaderSet::new());
154                first_request = false;
155            }
156            let response = self.transport.receive_response(OpCode::GetFinal).await?;
157            let (final_packet, response_headers, mut response_body) =
158                Self::handle_get_final_response(response)?;
159            body.append(&mut response_body);
160
161            // Check to see if peer wants SRM for this single-packet request.
162            if !self.is_started {
163                self.check_response_for_srm(&response_headers);
164                self.set_started();
165            }
166
167            if final_packet {
168                trace!("Found terminal GET final packet");
169                break;
170            }
171        }
172        Ok(body)
173    }
174
175    /// Request to terminate a multi-packet GET request early.
176    /// Returns the informational headers from the peer response on success, Error otherwise.
177    /// If Error is returned, there are no guarantees about the synchronization between the local
178    /// OBEX client and remote OBEX server.
179    pub async fn terminate(mut self, headers: HeaderSet) -> Result<HeaderSet, Error> {
180        let opcode = OpCode::Abort;
181        if !self.is_started {
182            return Err(Error::operation(opcode, "can't abort when not started"));
183        }
184
185        let request = RequestPacket::new_abort(headers);
186        trace!(request:?; "Making outgoing {opcode:?} request");
187        self.transport.send(request).await?;
188        trace!("Successfully made {opcode:?} request");
189        let response = self.transport.receive_response(opcode).await?;
190        response.expect_code(opcode, ResponseCode::Ok).map(Into::into)
191    }
192}
193
194impl SrmOperation for GetOperation<'_> {
195    const OPERATION_TYPE: OpCode = OpCode::Get;
196
197    fn get_srm(&self) -> SingleResponseMode {
198        self.srm
199    }
200
201    fn set_srm(&mut self, mode: SingleResponseMode) {
202        self.srm = mode;
203    }
204}
205
206#[cfg(test)]
207mod tests {
208    use super::*;
209    use bt_channel_test_support::Transport;
210    use test_case::test_case;
211
212    use assert_matches::assert_matches;
213    use async_test_helpers::expect_stream_pending;
214    use async_utils::PollExt;
215    use fuchsia_async as fasync;
216    use std::pin::pin;
217
218    use crate::error::PacketError;
219    use crate::header::{Header, HeaderIdentifier};
220    use crate::transport::ObexTransportManager;
221    use crate::transport::test_utils::{
222        expect_code, expect_request, expect_request_and_reply, new_manager, reply,
223    };
224
225    fn setup_get_operation(mgr: &ObexTransportManager, initial: HeaderSet) -> GetOperation<'_> {
226        let transport = mgr.try_new_operation().expect("can start operation");
227        GetOperation::new(initial, transport)
228    }
229
230    #[test_case(Transport::Socket ; "socket")]
231    #[test_case(Transport::Fidl ; "fidl")]
232    #[fuchsia::test]
233    fn get_operation(transport: Transport) {
234        let mut exec = fasync::TestExecutor::new();
235        let (manager, mut remote) = new_manager(transport, /* srm_supported */ false);
236        let mut operation = setup_get_operation(&manager, HeaderSet::new());
237        assert!(!operation.is_started);
238
239        // The initial GET request should succeed and return the set of Headers specified by the
240        // peer.
241        {
242            let info_headers = HeaderSet::from_header(Header::name("text"));
243            let info_fut = operation.get_information(info_headers);
244            let mut info_fut = pin!(info_fut);
245            exec.run_until_stalled(&mut info_fut).expect_pending("waiting for peer response");
246            let response_headers = HeaderSet::from_header(Header::name("bar"));
247            let response = ResponsePacket::new_no_data(ResponseCode::Continue, response_headers);
248            let expectation = |request: RequestPacket| {
249                assert_eq!(*request.code(), OpCode::Get);
250                let headers = HeaderSet::from(request);
251                assert!(headers.contains_header(&HeaderIdentifier::Name));
252            };
253            expect_request_and_reply(&mut exec, &mut remote, expectation, response);
254            let received_headers = exec
255                .run_until_stalled(&mut info_fut)
256                .expect("response received")
257                .expect("valid response");
258            assert!(received_headers.contains_header(&HeaderIdentifier::Name));
259        }
260        assert!(operation.is_started);
261
262        // A subsequent request for more information should return the set of additional Headers
263        // specified by the peer.
264        {
265            let info_headers = HeaderSet::from_header(Header::Type("file".into()));
266            let info_fut = operation.get_information(info_headers);
267            let mut info_fut = pin!(info_fut);
268            exec.run_until_stalled(&mut info_fut).expect_pending("waiting for peer response");
269            let response_headers = HeaderSet::from_header(Header::Description("big file".into()));
270            let response = ResponsePacket::new_no_data(ResponseCode::Continue, response_headers);
271            expect_request_and_reply(&mut exec, &mut remote, expect_code(OpCode::Get), response);
272            let received_headers = exec
273                .run_until_stalled(&mut info_fut)
274                .expect("response received")
275                .expect("valid response");
276            assert!(received_headers.contains_header(&HeaderIdentifier::Description));
277        }
278
279        // The multi-packet user payload should be returned at the end of the operation. Because
280        // the operation is taken by value, it is considered complete after this step and resources
281        // are freed.
282        let data_fut = operation.get_data(HeaderSet::new());
283        let mut data_fut = pin!(data_fut);
284        exec.run_until_stalled(&mut data_fut).expect_pending("waiting for peer response");
285        let response_headers1 = HeaderSet::from_header(Header::Body(vec![1, 2, 3]));
286        let response1 = ResponsePacket::new_no_data(ResponseCode::Continue, response_headers1);
287        expect_request_and_reply(&mut exec, &mut remote, expect_code(OpCode::GetFinal), response1);
288        exec.run_until_stalled(&mut data_fut)
289            .expect_pending("waiting for additional peer responses");
290        // The OK response code indicates the last user data packet.
291        let response_headers2 = HeaderSet::from_header(Header::EndOfBody(vec![4, 5, 6]));
292        let response2 = ResponsePacket::new_no_data(ResponseCode::Ok, response_headers2);
293        expect_request_and_reply(&mut exec, &mut remote, expect_code(OpCode::GetFinal), response2);
294        // All user data packets are received and the concatenated data object is returned.
295        let user_data = exec
296            .run_until_stalled(&mut data_fut)
297            .expect("received all responses")
298            .expect("valid user data");
299        assert_eq!(user_data, vec![1, 2, 3, 4, 5, 6]);
300    }
301
302    #[fuchsia::test]
303    fn get_operation_terminate_success() {
304        let mut exec = fasync::TestExecutor::new();
305        let (manager, mut remote) = new_manager(Transport::Socket, /* srm_supported */ false);
306        let initial = HeaderSet::from_header(Header::name("foo"));
307        let mut operation = setup_get_operation(&manager, initial);
308
309        // Start the GET operation.
310        operation.set_started();
311
312        // Terminating early is OK. It should consume the operation and be considered complete.
313        let headers = HeaderSet::from_header(Header::name("terminated"));
314        let terminate_fut = operation.terminate(headers);
315        let mut terminate_fut = pin!(terminate_fut);
316        let _ =
317            exec.run_until_stalled(&mut terminate_fut).expect_pending("waiting for peer response");
318        let response = ResponsePacket::new_no_data(ResponseCode::Ok, HeaderSet::new());
319        expect_request_and_reply(&mut exec, &mut remote, expect_code(OpCode::Abort), response);
320    }
321
322    #[fuchsia::test]
323    fn get_operation_srm() {
324        let mut exec = fasync::TestExecutor::new();
325        let (manager, mut remote) = new_manager(Transport::Socket, /* srm_supported */ true);
326        let mut operation = setup_get_operation(&manager, HeaderSet::new());
327
328        // Making the initial GET request should automatically try to include SRM. Peer responds
329        // positively to SRM, so it is enabled hereafter.
330        {
331            let info_headers = HeaderSet::from_header(Header::name("foo"));
332            let info_fut = operation.get_information(info_headers);
333            let mut info_fut = pin!(info_fut);
334            exec.run_until_stalled(&mut info_fut).expect_pending("waiting for peer response");
335            let response_headers = HeaderSet::from_headers(vec![
336                Header::name("bar"),
337                SingleResponseMode::Enable.into(),
338            ])
339            .unwrap();
340            let response = ResponsePacket::new_no_data(ResponseCode::Continue, response_headers);
341            let expectation = |request: RequestPacket| {
342                assert_eq!(*request.code(), OpCode::Get);
343                let headers = HeaderSet::from(request);
344                assert!(headers.contains_header(&HeaderIdentifier::Name));
345                assert!(headers.contains_header(&HeaderIdentifier::SingleResponseMode));
346            };
347            expect_request_and_reply(&mut exec, &mut remote, expectation, response);
348            let _received_headers = exec
349                .run_until_stalled(&mut info_fut)
350                .expect("response received")
351                .expect("valid response");
352        }
353        assert!(operation.is_started);
354        assert_eq!(operation.srm, SingleResponseMode::Enable);
355
356        // A subsequent request with additional headers should resolve immediately as SRM is
357        // enabled.
358        // Any peer response headers will only be returned after the GetFinal request.
359        {
360            let info_headers = HeaderSet::from_header(Header::Type("file".into()));
361            let info_fut = operation.get_information(info_headers);
362            let mut info_fut = pin!(info_fut);
363            let received_headers = exec
364                .run_until_stalled(&mut info_fut)
365                .expect("ready without peer response")
366                .expect("successful request");
367            assert_eq!(received_headers, HeaderSet::new());
368            let expectation = |request: RequestPacket| {
369                assert_eq!(*request.code(), OpCode::Get);
370                let headers = HeaderSet::from(request);
371                assert!(headers.contains_header(&HeaderIdentifier::Type));
372                assert!(!headers.contains_header(&HeaderIdentifier::SingleResponseMode));
373            };
374            expect_request(&mut exec, &mut remote, expectation);
375        }
376
377        // The 3-packet user payload should be returned at the end of the operation. Because
378        // SRM is enabled, only one GetFinal request is issued.
379        let data_fut = operation.get_data(HeaderSet::new());
380        let mut data_fut = pin!(data_fut);
381        exec.run_until_stalled(&mut data_fut).expect_pending("waiting for peer response");
382        let response_headers1 = HeaderSet::from_header(Header::Body(vec![1, 2, 3]));
383        let response1 = ResponsePacket::new_no_data(ResponseCode::Continue, response_headers1);
384        expect_request_and_reply(&mut exec, &mut remote, expect_code(OpCode::GetFinal), response1);
385        exec.run_until_stalled(&mut data_fut)
386            .expect_pending("waiting for additional peer responses");
387        // The peer will keep sending responses until the user payload has been completely sent.
388        let response_headers2 = HeaderSet::from_header(Header::Body(vec![4, 5, 6]));
389        let response2 = ResponsePacket::new_no_data(ResponseCode::Continue, response_headers2);
390        expect_stream_pending(&mut exec, &mut remote);
391        reply(&mut exec, &mut remote, response2);
392        // Final user data packet.
393        let response_headers3 = HeaderSet::from_header(Header::EndOfBody(vec![7, 8, 9]));
394        let response3 = ResponsePacket::new_no_data(ResponseCode::Ok, response_headers3);
395        expect_stream_pending(&mut exec, &mut remote);
396        reply(&mut exec, &mut remote, response3);
397        // All user data packets are received and the concatenated data object is returned.
398        let user_data = exec
399            .run_until_stalled(&mut data_fut)
400            .expect("received all responses")
401            .expect("valid user data");
402        assert_eq!(user_data, vec![1, 2, 3, 4, 5, 6, 7, 8, 9]);
403    }
404
405    #[fuchsia::test]
406    fn client_disable_srm_mid_get_is_ignored() {
407        let mut exec = fasync::TestExecutor::new();
408        let (manager, mut remote) = new_manager(Transport::Socket, /* srm_supported */ true);
409        let transport = manager.try_new_operation().expect("can start operation");
410        let mut operation = GetOperation::new(HeaderSet::new(), transport);
411        // Bypass start and enable SRM.
412        operation.set_started();
413        assert_eq!(operation.srm, SingleResponseMode::Enable);
414
415        // A subsequent request with additional headers disabling SRM should not result in SRM
416        // being disabled.
417        {
418            let info_headers = HeaderSet::from_header(SingleResponseMode::Disable.into());
419            let info_fut = operation.get_information(info_headers);
420            let mut info_fut = pin!(info_fut);
421            let received_headers = exec
422                .run_until_stalled(&mut info_fut)
423                .expect("ready without peer response")
424                .expect("successful request");
425            assert_eq!(received_headers, HeaderSet::new());
426            expect_request(&mut exec, &mut remote, expect_code(OpCode::Get));
427        }
428        assert_eq!(operation.srm, SingleResponseMode::Enable);
429    }
430
431    #[fuchsia::test]
432    fn get_operation_information_error() {
433        let mut exec = fasync::TestExecutor::new();
434        let (manager, _remote) = new_manager(Transport::Socket, /* srm_supported */ false);
435        let initial = HeaderSet::from_header(Header::name("foo"));
436        let mut operation = setup_get_operation(&manager, initial);
437
438        // Set started.
439        operation.set_started();
440
441        // Trying to get additional information without providing any headers is an Error.
442        let get_info_fut = operation.get_information(HeaderSet::new());
443        let mut get_info_fut = pin!(get_info_fut);
444        let get_info_result =
445            exec.run_until_stalled(&mut get_info_fut).expect("resolves with error");
446        assert_matches!(get_info_result, Err(Error::OperationError { .. }));
447    }
448
449    #[fuchsia::test]
450    fn get_operation_data_before_start_is_ok() {
451        let mut exec = fasync::TestExecutor::new();
452        let (manager, mut remote) = new_manager(Transport::Socket, /* srm_supported */ false);
453        let initial = HeaderSet::from_header(Header::name("foo"));
454        let operation = setup_get_operation(&manager, initial);
455
456        // Trying to get the user data directly is OK.
457        let get_data_fut = operation.get_data(HeaderSet::new());
458        let mut get_data_fut = pin!(get_data_fut);
459        exec.run_until_stalled(&mut get_data_fut).expect_pending("waiting for peer response");
460        let response_headers = HeaderSet::from_header(Header::EndOfBody(vec![1, 2, 3]));
461        let response = ResponsePacket::new_no_data(ResponseCode::Ok, response_headers);
462        let expectation = |request: RequestPacket| {
463            assert_eq!(*request.code(), OpCode::GetFinal);
464            let headers = HeaderSet::from(request);
465            assert!(headers.contains_header(&HeaderIdentifier::Name));
466        };
467        expect_request_and_reply(&mut exec, &mut remote, expectation, response);
468        let user_data = exec
469            .run_until_stalled(&mut get_data_fut)
470            .expect("received all responses")
471            .expect("valid user data");
472        assert_eq!(user_data, vec![1, 2, 3]);
473    }
474
475    #[fuchsia::test]
476    fn get_operation_data_before_start_with_srm_is_ok() {
477        let mut exec = fasync::TestExecutor::new();
478        let (manager, mut remote) = new_manager(Transport::Socket, /* srm_supported */ true);
479        let operation = setup_get_operation(&manager, HeaderSet::new());
480
481        // Trying to get the user data directly is OK.
482        let get_data_fut = operation.get_data(HeaderSet::new());
483        let mut get_data_fut = pin!(get_data_fut);
484        exec.run_until_stalled(&mut get_data_fut).expect_pending("waiting for peer response");
485        let response_headers1 = HeaderSet::from_headers(vec![
486            Header::Body(vec![1, 1]),
487            Header::SingleResponseMode(SingleResponseMode::Enable.into()),
488        ])
489        .unwrap();
490        let response1 = ResponsePacket::new_no_data(ResponseCode::Continue, response_headers1);
491        let expectation = |request: RequestPacket| {
492            assert_eq!(*request.code(), OpCode::GetFinal);
493            let headers = HeaderSet::from(request);
494            assert!(headers.contains_header(&HeaderIdentifier::SingleResponseMode));
495        };
496        expect_request_and_reply(&mut exec, &mut remote, expectation, response1);
497        exec.run_until_stalled(&mut get_data_fut)
498            .expect_pending("waiting for additional peer responses");
499
500        // The peer will keep sending responses until the user payload has been completely sent.
501        let response_headers2 = HeaderSet::from_header(Header::Body(vec![2, 2]));
502        let response2 = ResponsePacket::new_no_data(ResponseCode::Continue, response_headers2);
503        expect_stream_pending(&mut exec, &mut remote);
504        reply(&mut exec, &mut remote, response2);
505
506        // Final user data packet.
507        let response_headers3 = HeaderSet::from_header(Header::EndOfBody(vec![3, 3]));
508        let response3 = ResponsePacket::new_no_data(ResponseCode::Ok, response_headers3);
509        expect_stream_pending(&mut exec, &mut remote);
510        reply(&mut exec, &mut remote, response3);
511        // All user data packets are received and the concatenated data object is returned.
512        let user_data = exec
513            .run_until_stalled(&mut get_data_fut)
514            .expect("received all responses")
515            .expect("valid user data");
516        assert_eq!(user_data, vec![1, 1, 2, 2, 3, 3]);
517    }
518
519    #[fuchsia::test]
520    fn get_operation_data_peer_disconnect_is_error() {
521        let mut exec = fasync::TestExecutor::new();
522        let (manager, remote) = new_manager(Transport::Socket, /* srm_supported */ false);
523        let initial = HeaderSet::from_header(Header::name("foo"));
524        let mut operation = setup_get_operation(&manager, initial);
525        // Bypass initial SRM setup by marking this operation as started.
526        operation.set_started();
527
528        // Before the client can get the user data, the peer disconnects.
529        drop(remote);
530        let get_data_fut = operation.get_data(HeaderSet::new());
531        let mut get_data_fut = pin!(get_data_fut);
532        let get_data_result =
533            exec.run_until_stalled(&mut get_data_fut).expect("resolves with error");
534        assert_matches!(get_data_result, Err(Error::IOError(_)));
535    }
536
537    #[fuchsia::test]
538    async fn get_operation_terminate_before_start_error() {
539        let (manager, _remote) = new_manager(Transport::Socket, /* srm_supported */ false);
540        let initial = HeaderSet::from_header(Header::name("bar"));
541        let operation = setup_get_operation(&manager, initial);
542
543        // The GET operation is not in progress yet so trying to terminate will fail.
544        let terminate_result = operation.terminate(HeaderSet::new()).await;
545        assert_matches!(terminate_result, Err(Error::OperationError { .. }));
546    }
547
548    #[fuchsia::test]
549    fn handle_get_response_success() {
550        let headers = HeaderSet::from_header(Header::name("foo"));
551        let response = ResponsePacket::new_no_data(ResponseCode::Continue, headers.clone());
552        let result = GetOperation::handle_get_response(response).expect("valid response");
553        assert_eq!(result, headers);
554    }
555
556    #[fuchsia::test]
557    fn handle_get_response_error() {
558        let headers = HeaderSet::from_header(Header::name("foo"));
559        // Expect the Continue, not Ok.
560        let response1 = ResponsePacket::new_no_data(ResponseCode::Ok, headers.clone());
561        assert_matches!(
562            GetOperation::handle_get_response(response1),
563            Err(Error::PeerRejected { .. })
564        );
565
566        // Expect the Continue, not anything else.
567        let response1 = ResponsePacket::new_no_data(ResponseCode::NotFound, headers);
568        assert_matches!(
569            GetOperation::handle_get_response(response1),
570            Err(Error::PeerRejected { .. })
571        );
572    }
573
574    #[fuchsia::test]
575    fn handle_get_final_response_success() {
576        let headers = HeaderSet::from_header(Header::EndOfBody(vec![1, 2]));
577        let response1 = ResponsePacket::new_no_data(ResponseCode::Ok, headers);
578        let result1 = GetOperation::handle_get_final_response(response1).expect("valid response");
579        assert_eq!(result1, (true, HeaderSet::new(), vec![1, 2]));
580
581        let headers = HeaderSet::from_header(Header::Body(vec![1, 3, 5]));
582        let response2 = ResponsePacket::new_no_data(ResponseCode::Continue, headers);
583        let result2 = GetOperation::handle_get_final_response(response2).expect("valid response");
584        assert_eq!(result2, (false, HeaderSet::new(), vec![1, 3, 5]));
585    }
586
587    #[fuchsia::test]
588    fn get_final_response_error() {
589        // A non-success error code is an Error.
590        let headers = HeaderSet::from_header(Header::EndOfBody(vec![1, 2]));
591        let response1 = ResponsePacket::new_no_data(ResponseCode::Forbidden, headers);
592        assert_matches!(
593            GetOperation::handle_get_final_response(response1),
594            Err(Error::PeerRejected { .. })
595        );
596
597        // A final packet with no EndOfBody payload is an Error.
598        let response2 = ResponsePacket::new_no_data(ResponseCode::Ok, HeaderSet::new());
599        assert_matches!(
600            GetOperation::handle_get_final_response(response2),
601            Err(Error::Packet(PacketError::Data(_)))
602        );
603
604        // A non-final packet with no Body payload is an Error.
605        let response3 = ResponsePacket::new_no_data(ResponseCode::Continue, HeaderSet::new());
606        assert_matches!(
607            GetOperation::handle_get_final_response(response3),
608            Err(Error::Packet(PacketError::Data(_)))
609        );
610    }
611}