• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 //! HTTP [`Response`].
15 
16 pub mod status;
17 use status::StatusCode;
18 
19 use crate::headers::Headers;
20 use crate::version::Version;
21 
22 // TODO: `ResponseBuilder` implementation.
23 
24 /// HTTP `Response` Implementation.
25 ///
26 /// The status-line and field-line of a response-message are stored in
27 /// `Response`.
28 ///
29 /// The body can be saved in the user-defined type.
30 ///
31 /// According to the [`RFC9112`], the origin reason-phrase of status-line is not
32 /// saved, the unified reason in `StatusCode` is used to indicate the status
33 /// code reason.
34 ///
35 /// [`RFC9112`]: https://httpwg.org/specs/rfc9112.html
36 /// [`Response`]: https://httpwg.org/specs/rfc9112.html#status.line
37 pub struct Response<T> {
38     part: ResponsePart,
39     body: T,
40 }
41 
42 impl<T> Response<T> {
43     /// Gets an immutable reference to the `Version`.
version(&self) -> &Version44     pub fn version(&self) -> &Version {
45         &self.part.version
46     }
47 
48     /// Gets the `StatusCode`.
status(&self) -> StatusCode49     pub fn status(&self) -> StatusCode {
50         self.part.status
51     }
52 
53     /// Gets an immutable reference to the `Headers`.
headers(&self) -> &Headers54     pub fn headers(&self) -> &Headers {
55         &self.part.headers
56     }
57 
58     /// Gets an immutable reference to the `Body`.
body(&self) -> &T59     pub fn body(&self) -> &T {
60         &self.body
61     }
62 
63     /// Gets a mutable reference to the `Body`.
body_mut(&mut self) -> &mut T64     pub fn body_mut(&mut self) -> &mut T {
65         &mut self.body
66     }
67 
68     /// Splits `Response` into `ResponsePart` and `Body`.
into_parts(self) -> (ResponsePart, T)69     pub fn into_parts(self) -> (ResponsePart, T) {
70         (self.part, self.body)
71     }
72 
73     /// Response construction method with parameters
from_raw_parts(part: ResponsePart, body: T) -> Response<T>74     pub fn from_raw_parts(part: ResponsePart, body: T) -> Response<T> {
75         Self { part, body }
76     }
77 }
78 
79 impl<T: Clone> Clone for Response<T> {
clone(&self) -> Self80     fn clone(&self) -> Self {
81         Self::from_raw_parts(self.part.clone(), self.body.clone())
82     }
83 }
84 
85 /// `ResponsePart`, which is called [`Status Line`] in [`RFC9112`].
86 ///
87 /// A request-line begins with a method token, followed by a single space (SP),
88 /// the request-target, and another single space (SP), and ends with the
89 /// protocol version.
90 ///
91 /// [`RFC9112`]: https://httpwg.org/specs/rfc9112.html
92 /// [`Status Line`]: https://httpwg.org/specs/rfc9112.html#status.line
93 #[derive(Debug, Clone, Eq, PartialEq)]
94 pub struct ResponsePart {
95     /// HTTP Version implementation.
96     pub version: Version,
97     /// HTTP Status Codes implementation.
98     pub status: StatusCode,
99     /// HTTP Headers, which is called Fields in RFC9110.
100     pub headers: Headers,
101 }
102 
103 #[cfg(test)]
104 #[cfg(feature = "http1_1")]
105 mod ut_response {
106     use crate::h1::ResponseDecoder;
107     use crate::headers::Headers;
108     use crate::response::Response;
109 
110     const ERROR_HEADER: &str = "header append failed";
111 
112     /// UT test cases for `Response::version`.
113     ///
114     /// # Brief
115     /// 1. Creates a `ResponsePart` by calling `ResponseDecoder::decode`.
116     /// 2. Gets the reference of a `Version` by calling `Response::version`.
117     /// 3. Checks if the test result is correct.
118     #[test]
ut_response_version()119     fn ut_response_version() {
120         let response_str = "HTTP/1.1 304 \r\nAge: \t 270646 \t \t\r\nDate: \t Mon, 19 Dec 2022 01:46:59 GMT \t \t\r\nEtag:\t \"3147526947+gzip\" \t \t\r\n\r\n".as_bytes();
121         let mut decoder = ResponseDecoder::new();
122         let result = decoder.decode(response_str).unwrap().unwrap();
123         let response = Response {
124             part: result.0,
125             body: result.1,
126         };
127         assert_eq!(response.version().as_str(), "HTTP/1.1")
128     }
129 
130     /// UT test cases for `Response::status_code`.
131     ///
132     /// # Brief
133     /// 1. Creates a `ResponsePart` by calling `ResponseDecoder::decode`.
134     /// 2. Gets the reference of a `StatusCode` by calling
135     ///    `Response::status_code`.
136     /// 3. Checks if the test result is correct.
137     #[test]
ut_response_status_code()138     fn ut_response_status_code() {
139         let response_str = "HTTP/1.1 304 \r\nAge: \t 270646 \t \t\r\nDate: \t Mon, 19 Dec 2022 01:46:59 GMT \t \t\r\nEtag:\t \"3147526947+gzip\" \t \t\r\n\r\n".as_bytes();
140         let mut decoder = ResponseDecoder::new();
141         let result = decoder.decode(response_str).unwrap().unwrap();
142         let response = Response {
143             part: result.0,
144             body: result.1,
145         };
146         assert_eq!(response.status().as_u16(), 304)
147     }
148 
149     /// UT test cases for `Response::headers`.
150     ///
151     /// # Brief
152     /// 1. Creates a `ResponsePart` by calling `ResponseDecoder::decode`.
153     /// 2. Gets the reference of a `Headers` by calling `Response::headers`.
154     /// 3. Checks if the test result is correct.
155     #[test]
ut_response_headers()156     fn ut_response_headers() {
157         let response_str = "HTTP/1.1 304 \r\nAge: \t 270646 \t \t\r\nDate: \t Mon, 19 Dec 2022 01:46:59 GMT \t \t\r\nEtag:\t \"3147526947+gzip\" \t \t\r\n\r\n".as_bytes();
158         let mut decoder = ResponseDecoder::new();
159         let result = decoder.decode(response_str).unwrap().unwrap();
160         let response = Response {
161             part: result.0,
162             body: result.1,
163         };
164         let mut headers = Headers::new();
165         headers.insert("age", "270646").expect(ERROR_HEADER);
166         headers
167             .insert("Date", "Mon, 19 Dec 2022 01:46:59 GMT")
168             .expect(ERROR_HEADER);
169         headers
170             .insert("Etag", "\"3147526947+gzip\"")
171             .expect(ERROR_HEADER);
172         assert_eq!(response.headers(), &headers)
173     }
174 
175     /// UT test cases for `Response::body`.
176     ///
177     /// # Brief
178     /// 1. Creates a body by calling `ResponseDecoder::decode`.
179     /// 2. Gets the reference of a `&[u8]` body by calling `Response::body`.
180     /// 3. Checks if the test result is correct.
181     #[test]
ut_response_body()182     fn ut_response_body() {
183         let response_str = "HTTP/1.1 304 \r\nAge: \t 270646 \t \t\r\nDate: \t Mon, 19 Dec 2022 01:46:59 GMT \t \t\r\nEtag:\t \"3147526947+gzip\" \t \t\r\n\r\nbody part".as_bytes();
184         let mut decoder = ResponseDecoder::new();
185         let result = decoder.decode(response_str).unwrap().unwrap();
186         let response = Response {
187             part: result.0,
188             body: result.1,
189         };
190         assert_eq!(*response.body(), "body part".as_bytes())
191     }
192 
193     /// UT test cases for `Response::body_mut`.
194     ///
195     /// # Brief
196     /// 1. Creates a body by calling `ResponseDecoder::decode`.
197     /// 2. Gets the reference of a `&[u8]` body by calling `Response::body_mut`.
198     /// 3. Checks if the test result is correct.
199     #[test]
ut_response_body_mut()200     fn ut_response_body_mut() {
201         let response_str = "HTTP/1.1 304 \r\nAge: \t 270646 \t \t\r\nDate: \t Mon, 19 Dec 2022 01:46:59 GMT \t \t\r\nEtag:\t \"3147526947+gzip\" \t \t\r\n\r\nbody part".as_bytes();
202         let mut decoder = ResponseDecoder::new();
203         let result = decoder.decode(response_str).unwrap().unwrap();
204         let mut response = Response {
205             part: result.0,
206             body: result.1,
207         };
208         assert_eq!(*response.body_mut(), "body part".as_bytes())
209     }
210 
211     /// UT test cases for `Response::into_parts`.
212     ///
213     /// # Brief
214     /// 1. Creates a body by calling `ResponseDecoder::into_parts`.
215     /// 2. Checks if the test result is correct.
216     #[test]
ut_response_into_parts()217     fn ut_response_into_parts() {
218         let response_str = "HTTP/1.1 304 \r\nAge: \t 270646 \t \t\r\nDate: \t Mon, 19 Dec 2022 01:46:59 GMT \t \t\r\nEtag:\t \"3147526947+gzip\" \t \t\r\n\r\n".as_bytes();
219         let mut decoder = ResponseDecoder::new();
220         let result = decoder.decode(response_str).unwrap().unwrap();
221         let response = Response {
222             part: result.0,
223             body: result.1,
224         };
225         let (part, body) = response.into_parts();
226         assert!(body.is_empty());
227         assert_eq!(part.version.as_str(), "HTTP/1.1");
228     }
229 
230     /// UT test cases for `Response::from_raw_parts`.
231     ///
232     /// # Brief
233     /// 1. Creates a body and a part by calling `ResponseDecoder::decode`.
234     /// 2. Creates a `Response` by calling `Response::from_raw_parts`.
235     /// 3. Creates a `Response` by calling `Response::clone`.
236     /// 3. Checks if the test result is correct.
237     #[test]
ut_response_from_raw_parts()238     fn ut_response_from_raw_parts() {
239         let response_str = "HTTP/1.1 304 \r\nAge: \t 270646 \t \t\r\nDate: \t Mon, 19 Dec 2022 01:46:59 GMT \t \t\r\nEtag:\t \"3147526947+gzip\" \t \t\r\n\r\nbody part".as_bytes();
240         let mut decoder = ResponseDecoder::new();
241         let result = decoder.decode(response_str).unwrap().unwrap();
242         let response = Response::<&[u8]>::from_raw_parts(result.0, result.1);
243         assert_eq!(response.version().as_str(), "HTTP/1.1");
244         assert_eq!(response.status().as_u16(), 304);
245         let mut headers = Headers::new();
246         headers.insert("age", "270646").expect(ERROR_HEADER);
247         headers
248             .insert("Date", "Mon, 19 Dec 2022 01:46:59 GMT")
249             .expect(ERROR_HEADER);
250         headers
251             .insert("Etag", "\"3147526947+gzip\"")
252             .expect(ERROR_HEADER);
253         assert_eq!(response.headers(), &headers);
254         assert_eq!(*response.body(), "body part".as_bytes())
255     }
256 }
257