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