diff options
| -rw-r--r-- | src/request/response.rs | 58 |
1 files changed, 31 insertions, 27 deletions
diff --git a/src/request/response.rs b/src/request/response.rs index ef4b515..d38e0bd 100644 --- a/src/request/response.rs +++ b/src/request/response.rs @@ -16,46 +16,38 @@ // Copyright (C) 2022-2025 Fuwn <[email protected]> // SPDX-License-Identifier: GPL-3.0-only -use { - crate::request::Status, - rustls::SupportedCipherSuite, - std::{borrow::Cow, fmt::Write}, -}; +use {crate::request::Status, rustls::SupportedCipherSuite, std::borrow::Cow}; #[derive(Debug, Clone, PartialEq)] pub struct Response { status: Status, meta: String, - content: Option<String>, + content: Option<Vec<u8>>, size: usize, suite: Option<SupportedCipherSuite>, } impl Response { pub(crate) fn new(data: &[u8], suite: Option<SupportedCipherSuite>) -> Self { - let string_form = String::from_utf8_lossy(data).to_string(); - let mut content = None; - let header; - - if string_form.ends_with("\r\n") { - header = string_form; + let delimiter = b"\r\n"; + let header_end = data + .windows(delimiter.len()) + .position(|window| window == delimiter) + .map_or(data.len(), |pos| pos + delimiter.len()); + let header_bytes = &data[..header_end]; + let header = String::from_utf8_lossy(header_bytes).trim_end().to_string(); + let content_bytes = if header_end < data.len() { + Some(data[header_end..].to_vec()) } else { - let mut string_split = string_form.split("\r\n"); - - header = string_split.next().unwrap_or("").to_string(); - content = Some(string_split.fold(String::new(), |mut output, s| { - let _ = write!(output, "{s}\r\n"); - - output - })); - } - - let header_split = header.split_at(2); + None + }; + let (status_string, meta_string) = header.split_at(2); + let status_code = status_string.parse::<i32>().unwrap_or(0); Self { - status: Status::from(header_split.0.parse::<i32>().unwrap_or(0)), - meta: header_split.1.trim_start().to_string(), - content, + status: Status::from(status_code), + meta: meta_string.trim_start().to_string(), + content: content_bytes, size: data.len(), suite, } @@ -68,8 +60,20 @@ impl Response { #[must_use] pub fn meta(&self) -> Cow<'_, str> { Cow::Borrowed(&self.meta) } + /// This associated function assumes that the content is valid UTF-8. + /// + /// If you want to handle data bytes directly, use + /// [`Response::content_bytes`]. + #[must_use] + pub fn content(&self) -> Option<String> { + self + .content + .as_ref() + .map(|content| String::from_utf8_lossy(content).to_string()) + } + #[must_use] - pub const fn content(&self) -> &Option<String> { &self.content } + pub fn content_bytes(&self) -> Option<&[u8]> { self.content.as_deref() } #[must_use] pub const fn size(&self) -> &usize { &self.size } |