diff --git a/Cargo.lock b/Cargo.lock index 08a0762..45de387 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,7 +104,7 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "http-request" -version = "5.3.0" +version = "6.0.0" dependencies = [ "color-output", "hex", diff --git a/Cargo.toml b/Cargo.toml index b8edfdf..767d100 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "http-request" -version = "5.3.0" +version = "6.0.0" edition = "2021" authors = ["ltpp-universe "] license = "MIT" diff --git a/src/request/http_request/impl.rs b/src/request/http_request/impl.rs index 3b96382..77e9169 100644 --- a/src/request/http_request/impl.rs +++ b/src/request/http_request/impl.rs @@ -14,7 +14,10 @@ use crate::{ request::{ config::r#type::Config, error::Error, request_url::r#type::RequestUrl, tmp::r#type::Tmp, }, - response::{http_response_binary::r#type::HttpResponseBinary, r#trait::HttpResponse}, + response::{ + http_response_binary::r#type::HttpResponseBinary, r#trait::HttpResponse, + r#type::BoxHttpResponse, + }, utils::vec::case_insensitive_match, }; use crate::{ @@ -225,7 +228,7 @@ impl HttpRequest { fn send_get_request( &mut self, stream: &mut Box, - ) -> Result { + ) -> Result { let mut request: Vec = Vec::new(); let path: String = self.get_path(); let request_line_string: String = @@ -256,7 +259,7 @@ impl HttpRequest { fn send_post_request( &mut self, stream: &mut Box, - ) -> Result { + ) -> Result { let mut request: Vec = Vec::new(); let path: String = self.get_path(); let request_line_string: String = @@ -287,10 +290,7 @@ impl HttpRequest { /// Returns a `Result`, where: /// - `Ok(HttpResponseBinary)` contains the complete HTTP response after processing headers and body. /// - `Err(Error)` indicates that an error occurred while reading the response. - fn read_response( - &mut self, - stream: &mut Box, - ) -> Result { + fn read_response(&mut self, stream: &mut Box) -> Result { let buffer_size: usize = self.config.buffer; let mut buffer: Vec = vec![0; buffer_size]; let mut response_bytes: Vec = Vec::new(); @@ -344,7 +344,7 @@ impl HttpRequest { } self.response = ::from(&response_bytes); if !self.config.redirect || redirect_url.is_none() { - return Ok(self.response.clone()); + return Ok(Box::new(self.response.clone())); } let url: String = String::from_utf8(redirect_url.unwrap()).map_err(|_| Error::InvalidUrl)?; @@ -438,7 +438,7 @@ impl HttpRequest { /// - `url`: The redirection URL to follow. /// /// Returns `Ok(HttpResponseBinary)` if the redirection is successful, or `Err(Error)` otherwise. - fn handle_redirect(&mut self, url: String) -> Result { + fn handle_redirect(&mut self, url: String) -> Result { if self.tmp.visit_url.contains(&url) { return Err(Error::RedirectUrlDeadLoop); } @@ -529,7 +529,7 @@ impl HttpRequest { /// Determines the HTTP method and constructs the appropriate request (GET or POST). /// /// Returns `Ok(HttpResponseBinary)` if the request is successful, or `Err(Error)` otherwise. - pub fn send(&mut self) -> Result { + pub fn send(&mut self) -> Result { self.config.url_obj = self.parse_url().map_err(|_| Error::InvalidUrl)?; let methods: Methods = self.get_methods(); let host: String = self.config.url_obj.host.clone().unwrap_or_default(); @@ -537,7 +537,7 @@ impl HttpRequest { let mut stream: Box = self .get_connection_stream(host, port) .map_err(|_| Error::TcpStreamConnectError)?; - let res: Result = match methods { + let res: Result = match methods { m if m.is_get() => self.send_get_request(&mut stream), m if m.is_post() => self.send_post_request(&mut stream), _ => Err(Error::RequestError), diff --git a/src/response/http_response_binary/impl.rs b/src/response/http_response_binary/impl.rs index 7dcdd0f..9ebd244 100644 --- a/src/response/http_response_binary/impl.rs +++ b/src/response/http_response_binary/impl.rs @@ -11,35 +11,37 @@ use crate::{ }; use std::{collections::HashMap, vec::IntoIter}; -/// Provides functionality for parsing and working with HTTP responses. +/// Implements the `HttpResponse` trait for `HttpResponseBinary`. /// -/// This implementation contains methods for extracting specific information from HTTP response -/// strings, such as content length, and parsing the entire response into an `HttpResponseBinary` object. +/// This implementation specifies the associated types for binary and text representations +/// of HTTP responses, enabling seamless conversion and handling of HTTP response data. /// -/// # Methods -/// - `get_content_length`: Extracts the `Content-Length` value from the HTTP response string. -/// - `from`: Parses a raw HTTP response string into an `HttpResponseBinary` struct, including the -/// status line, headers, and body. +/// # Associated Types +/// - `OutputText`: Specifies the text representation of an HTTP response (`HttpResponseText`). +/// - `OutputBinary`: Specifies the binary representation of an HTTP response (`HttpResponseBinary`). impl HttpResponse for HttpResponseBinary { type OutputText = HttpResponseText; type OutputBinary = HttpResponseBinary; - /// Parses an HTTP response from a byte slice and returns an `HttpResponseBinary` object. + + /// Parses a raw HTTP response from a byte slice and constructs an `HttpResponseBinary` instance. /// - /// This function processes the raw HTTP response in byte form. It splits the response into - /// the status line, headers, and body, parsing each part accordingly. The status line is parsed - /// to extract the HTTP version, status code, and status text. Headers are split and stored in - /// a `HashMap`. The body is collected into a byte vector. + /// This method processes the raw HTTP response into its constituent parts: status line, headers, and body. + /// Each part is parsed and stored in the resulting `HttpResponseBinary` object. /// /// # Parameters /// - `response`: A byte slice representing the raw HTTP response. /// /// # Returns - /// Returns an `HttpResponseBinary` object containing the parsed HTTP version, status code, status text, - /// headers, and body. If parsing any part fails, defaults are used (e.g., `HTTP/1.1`, status code `200`). + /// - `HttpResponseBinary`: A structured representation of the parsed HTTP response, including + /// the HTTP version, status code, status text, headers, and body. /// /// # Panics - /// This method will panic if the HTTP response is malformed in ways that the unwrap operations cannot handle. - fn from(response: &[u8]) -> Self { + /// - This method will panic if the HTTP response format is malformed and required components + /// such as the status line cannot be parsed. + fn from(response: &[u8]) -> Self + where + Self: Sized, + { let split_lines: Vec<&[u8]> = split_multi_byte(response, HTTP_BR_BYTES); let mut lines: IntoIter<&[u8]> = split_lines.into_iter(); let status_line: &[u8] = lines.next().unwrap_or(&[]); @@ -82,23 +84,34 @@ impl HttpResponse for HttpResponseBinary { } } - /// Converts the response body to text format. + /// Returns a clone of the binary representation of the HTTP response. /// - /// This function takes the current response and creates a new `HttpResponseBinary` - /// instance with the body converted to a text representation. The `body` is - /// extracted as text from the original response body and stored in the new - /// response as a `ResponseBody::Text` variant. + /// This method is part of the `HttpResponse` trait implementation, allowing for retrieval + /// of the current binary HTTP response without modification. /// /// # Returns + /// - `Self::OutputBinary`: A binary representation of the HTTP response, cloned from the current instance. + fn binary(&self) -> Self::OutputBinary { + self.clone() + } + + /// Converts the binary HTTP response to its text representation. /// - /// - `Self` - A new `HttpResponseBinary` instance with the body converted to text. - fn text(self) -> HttpResponseText { - let body: String = String::from_utf8_lossy(&self.body).to_string(); + /// This method processes the current instance of `HttpResponseBinary` by interpreting the + /// response body as UTF-8 encoded text, preserving other components such as HTTP version, + /// status code, status text, and headers unchanged. + /// + /// # Returns + /// - `HttpResponseText`: A structured representation of the HTTP response with the body + /// converted to text. + fn text(&self) -> HttpResponseText { + let http_response: HttpResponseBinary = self.clone(); + let body: String = String::from_utf8_lossy(&http_response.body).to_string(); HttpResponseText { - http_version: self.http_version, - status_code: self.status_code, - status_text: self.status_text, - headers: self.headers, + http_version: http_response.http_version, + status_code: http_response.status_code, + status_text: http_response.status_text, + headers: http_response.headers, body, } } diff --git a/src/response/http_response_text/impl.rs b/src/response/http_response_text/impl.rs new file mode 100644 index 0000000..9452b30 --- /dev/null +++ b/src/response/http_response_text/impl.rs @@ -0,0 +1,64 @@ +use super::r#type::HttpResponseText; +use crate::response::{http_response_binary::r#type::HttpResponseBinary, r#trait::HttpResponse}; + +/// Implements the `HttpResponse` trait for `HttpResponseText`. +/// +/// This implementation allows `HttpResponseText` to convert between text and binary +/// representations of HTTP responses. It provides methods for parsing raw responses, as well +/// as accessing text and binary formats. +/// +/// # Associated Types +/// - `OutputText`: Specifies the text representation of an HTTP response (`HttpResponseText`). +/// - `OutputBinary`: Specifies the binary representation of an HTTP response (`HttpResponseBinary`). +impl HttpResponse for HttpResponseText { + type OutputText = HttpResponseText; + type OutputBinary = HttpResponseBinary; + + /// Parses a raw HTTP response from a byte slice and converts it to a `HttpResponseText` instance. + /// + /// This method utilizes the `from` implementation of `HttpResponseBinary` to parse the binary + /// response and then converts it to a text representation. + /// + /// # Parameters + /// - `response`: A byte slice representing the raw HTTP response. + /// + /// # Returns + /// - `Self::OutputText`: A `HttpResponseText` instance with the parsed response. + /// + /// # Panics + /// - This method will panic if the binary parsing or text conversion fails unexpectedly. + fn from(response: &[u8]) -> Self::OutputText + where + Self: Sized, + { + ::from(response).text() + } + + /// Returns a clone of the current text representation of the HTTP response. + /// + /// This method allows for retrieving the current instance as the text representation without + /// modification. + /// + /// # Returns + /// - `Self::OutputText`: A clone of the current instance. + fn text(&self) -> Self::OutputText { + self.clone() + } + + /// Converts the text representation to a binary representation of the HTTP response. + /// + /// This method constructs a new `HttpResponseBinary` instance, copying all fields and + /// converting the body from a string to a byte vector. + /// + /// # Returns + /// - `HttpResponseBinary`: The binary representation of the HTTP response. + fn binary(&self) -> HttpResponseBinary { + HttpResponseBinary { + http_version: self.http_version.clone(), + status_code: self.status_code, + status_text: self.status_text.clone(), + headers: self.headers.clone(), + body: self.body.clone().into_bytes(), + } + } +} diff --git a/src/response/http_response_text/mod.rs b/src/response/http_response_text/mod.rs index 6e146ba..6297e83 100644 --- a/src/response/http_response_text/mod.rs +++ b/src/response/http_response_text/mod.rs @@ -1 +1,2 @@ +pub mod r#impl; pub mod r#type; diff --git a/src/response/mod.rs b/src/response/mod.rs index b04bfcd..db5bf49 100644 --- a/src/response/mod.rs +++ b/src/response/mod.rs @@ -1,3 +1,4 @@ pub mod http_response_binary; pub mod http_response_text; pub mod r#trait; +pub mod r#type; diff --git a/src/response/trait.rs b/src/response/trait.rs index f0072c3..ba694d6 100644 --- a/src/response/trait.rs +++ b/src/response/trait.rs @@ -1,26 +1,45 @@ /// A trait representing common behaviors for HTTP response types. /// -/// This trait provides a generic `text` method and a `from` method for -/// parsing and transforming HTTP responses. +/// This trait provides methods for transforming an HTTP response into +/// different formats (text and binary) and parsing raw HTTP response data. +/// Implementing types should define how to convert the response into text +/// and binary formats, as well as how to parse raw response data into a +/// structured representation. /// /// # Associated Types -/// - `Output`: The type returned by the `from` method. +/// - `OutputText`: The type returned by the `text` method, typically a text-based HTTP response. +/// - `OutputBinary`: The type returned by the `binary` method, typically a binary-based HTTP response. pub trait HttpResponse { type OutputText; type OutputBinary; /// Transforms the HTTP response into a text representation. /// + /// This method converts the body of the HTTP response into a string format. + /// + /// # Returns + /// - `Self::OutputText`: The text representation of the HTTP response, typically a string. + fn text(&self) -> Self::OutputText; + + /// Transforms the HTTP response into a binary representation. + /// + /// This method converts the body of the HTTP response into a byte-based format. + /// /// # Returns - /// Returns the body of the HTTP response as a string. - fn text(self) -> Self::OutputText; + /// - `Self::OutputBinary`: The binary representation of the HTTP response, typically a byte vector. + fn binary(&self) -> Self::OutputBinary; /// Parses a raw HTTP response into the associated type `Output`. /// + /// This method is responsible for parsing a byte slice representing a raw HTTP response + /// and transforming it into a structured HTTP response object. + /// /// # Parameters /// - `response`: A byte slice representing the raw HTTP response. /// /// # Returns - /// Returns an instance of the implementing type. - fn from(response: &[u8]) -> Self::OutputBinary; + /// - `Self`: An instance of the implementing type, populated with parsed data. + fn from(response: &[u8]) -> Self + where + Self: Sized; } diff --git a/src/response/type.rs b/src/response/type.rs new file mode 100644 index 0000000..3cdae23 --- /dev/null +++ b/src/response/type.rs @@ -0,0 +1,13 @@ +use super::{ + http_response_binary::r#type::HttpResponseBinary, http_response_text::r#type::HttpResponseText, +}; +use crate::HttpResponse; + +/// A type alias for a boxed dynamic trait object implementing the `HttpResponse` trait. +/// +/// This alias defines a `Response` as a `Box` containing any type that implements the +/// `HttpResponse` trait, with associated types `OutputText` set to `HttpResponseText` +/// and `OutputBinary` set to `HttpResponseBinary`. It allows for flexible handling of +/// HTTP responses that can be either in text or binary format. +pub type BoxHttpResponse = + Box>;