• 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 an immutable reference to the `StatusCode`.
49     // TODO: change this to `status_code`?
status(&self) -> &StatusCode50     pub fn status(&self) -> &StatusCode {
51         &self.part.status
52     }
53 
54     /// Gets an immutable reference to the `Headers`.
headers(&self) -> &Headers55     pub fn headers(&self) -> &Headers {
56         &self.part.headers
57     }
58 
59     /// Gets an immutable reference to the `Body`.
body(&self) -> &T60     pub fn body(&self) -> &T {
61         &self.body
62     }
63 
64     /// Gets a mutable reference to the `Body`.
body_mut(&mut self) -> &mut T65     pub fn body_mut(&mut self) -> &mut T {
66         &mut self.body
67     }
68 
69     /// Splits `Response` into `ResponsePart` and `Body`.
into_parts(self) -> (ResponsePart, T)70     pub fn into_parts(self) -> (ResponsePart, T) {
71         (self.part, self.body)
72     }
73 
74     /// Response construction method with parameters
from_raw_parts(part: ResponsePart, body: T) -> Response<T>75     pub fn from_raw_parts(part: ResponsePart, body: T) -> Response<T> {
76         Self { part, body }
77     }
78 }
79 
80 impl<T: Clone> Clone for Response<T> {
clone(&self) -> Self81     fn clone(&self) -> Self {
82         Self::from_raw_parts(self.part.clone(), self.body.clone())
83     }
84 }
85 
86 /// `ResponsePart`, which is called [`Status Line`] in [`RFC9112`].
87 ///
88 /// A request-line begins with a method token, followed by a single space (SP),
89 /// the request-target, and another single space (SP), and ends with the
90 /// protocol version.
91 ///
92 /// [`RFC9112`]: https://httpwg.org/specs/rfc9112.html
93 /// [`Status Line`]: https://httpwg.org/specs/rfc9112.html#status.line
94 #[derive(Debug, Clone, Eq, PartialEq)]
95 pub struct ResponsePart {
96     /// HTTP Version implementation.
97     pub version: Version,
98     /// HTTP Status Codes implementation.
99     pub status: StatusCode,
100     /// HTTP Headers, which is called Fields in RFC9110.
101     pub headers: Headers,
102 }
103 
104 #[cfg(test)]
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