From e9ddabb388417f654f8b4365f8c276d142acc9ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=A4=E9=9B=A8=E4=B8=9C?= Date: Tue, 3 Dec 2024 23:21:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:7.0.0=20struct=20update=1B[D=1B[D=1B[D=1B[?= =?UTF-8?q?D=1B[D=1B[D=1B[C=1B[C=1B[C=1B[C=1B[C=1B[C=1B[C=1B[C=1B[Cand=20a?= =?UTF-8?q?dd=20decode=20response?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 74 ++++++++++- Cargo.toml | 6 +- readme.md | 23 ++-- src/body/impl.rs | 54 ++------ src/body/type.rs | 2 +- src/{request => }/cfg.rs | 82 +++++++++++- src/compress/brotli/decode.rs | 23 ++++ src/compress/brotli/helper.rs | 1 + src/compress/brotli/mod.rs | 2 + src/compress/constant.rs | 14 ++ src/compress/deflate/decode.rs | 21 +++ src/compress/deflate/helper.rs | 1 + src/compress/deflate/mod.rs | 2 + src/compress/gzip/decode.rs | 28 ++++ src/compress/gzip/helper.rs | 1 + src/compress/gzip/mod.rs | 2 + src/compress/impl.rs | 73 +++++++++++ src/compress/mod.rs | 6 + src/compress/type.rs | 7 + src/constant/mod.rs | 1 - src/content_type/impl.rs | 44 ++----- src/content_type/type.rs | 2 +- src/http_url/impl.rs | 40 +++--- src/http_url/type.rs | 2 +- src/http_version/impl.rs | 31 +---- src/http_version/type.rs | 8 +- src/lib.rs | 9 +- src/methods/constant.rs | 2 + src/methods/impl.rs | 23 ++-- src/methods/mod.rs | 1 + src/methods/type.rs | 6 +- src/protocol/impl.rs | 65 ++++------ src/protocol/type.rs | 7 +- src/request/config/impl.rs | 19 +-- src/request/config/type.rs | 7 +- src/{constant/http.rs => request/constant.rs} | 9 ++ src/request/error.rs | 69 ---------- src/request/error/impl.rs | 28 ++++ src/request/{http_request => error}/mod.rs | 0 src/request/error/type.rs | 34 +++++ src/{ => request}/header/mod.rs | 0 src/{ => request}/header/type.rs | 0 src/request/http_request_builder/type.rs | 27 ---- src/request/mod.rs | 8 +- src/request/{http_request => request}/impl.rs | 48 ++++--- .../{http_request_builder => request}/mod.rs | 0 src/request/{http_request => request}/type.rs | 9 +- .../impl.rs | 94 +++++++------- .../request_builder}/mod.rs | 0 src/request/request_builder/type.rs | 22 ++++ src/request/tmp/impl.rs | 12 +- src/request/tmp/type.rs | 7 +- src/response/http_response_text/impl.rs | 64 --------- src/response/mod.rs | 5 +- .../impl.rs | 63 +++------ .../mod.rs | 0 .../type.rs | 2 +- src/response/response_header/mod.rs | 1 + src/response/response_header/type.rs | 6 + src/response/response_text/impl.rs | 69 ++++++++++ src/response/response_text/mod.rs | 2 + .../type.rs | 2 +- src/response/trait.rs | 14 +- src/response/type.rs | 12 +- src/status_code/impl.rs | 122 +++++++----------- 65 files changed, 784 insertions(+), 634 deletions(-) rename src/{request => }/cfg.rs (70%) create mode 100644 src/compress/brotli/decode.rs create mode 100644 src/compress/brotli/helper.rs create mode 100644 src/compress/brotli/mod.rs create mode 100644 src/compress/constant.rs create mode 100644 src/compress/deflate/decode.rs create mode 100644 src/compress/deflate/helper.rs create mode 100644 src/compress/deflate/mod.rs create mode 100644 src/compress/gzip/decode.rs create mode 100644 src/compress/gzip/helper.rs create mode 100644 src/compress/gzip/mod.rs create mode 100644 src/compress/impl.rs create mode 100644 src/compress/mod.rs create mode 100644 src/compress/type.rs create mode 100644 src/methods/constant.rs rename src/{constant/http.rs => request/constant.rs} (90%) delete mode 100644 src/request/error.rs create mode 100644 src/request/error/impl.rs rename src/request/{http_request => error}/mod.rs (100%) create mode 100644 src/request/error/type.rs rename src/{ => request}/header/mod.rs (100%) rename src/{ => request}/header/type.rs (100%) delete mode 100644 src/request/http_request_builder/type.rs rename src/request/{http_request => request}/impl.rs (96%) rename src/request/{http_request_builder => request}/mod.rs (100%) rename src/request/{http_request => request}/type.rs (80%) rename src/request/{http_request_builder => request_builder}/impl.rs (75%) rename src/{response/http_response_binary => request/request_builder}/mod.rs (100%) create mode 100644 src/request/request_builder/type.rs delete mode 100644 src/response/http_response_text/impl.rs rename src/response/{http_response_binary => response_binary}/impl.rs (60%) rename src/response/{http_response_text => response_binary}/mod.rs (100%) rename src/response/{http_response_binary => response_binary}/type.rs (97%) create mode 100644 src/response/response_header/mod.rs create mode 100644 src/response/response_header/type.rs create mode 100644 src/response/response_text/impl.rs create mode 100644 src/response/response_text/mod.rs rename src/response/{http_response_text => response_text}/type.rs (97%) diff --git a/Cargo.lock b/Cargo.lock index 534f068..2d9ad12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,54 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "brotli" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "cc" version = "1.2.2" @@ -45,6 +87,15 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -72,6 +123,16 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +[[package]] +name = "flate2" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "foreign-types" version = "0.3.2" @@ -104,9 +165,11 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "http-request" -version = "6.0.2" +version = "7.0.0" dependencies = [ + "brotli", "color-output", + "flate2", "hex", "native-tls", "serde", @@ -293,6 +356,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "native-tls" version = "0.2.12" diff --git a/Cargo.toml b/Cargo.toml index 051c643..9d0cf9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,16 @@ [package] name = "http-request" -version = "6.0.2" +version = "7.0.0" edition = "2021" authors = ["ltpp-universe "] license = "MIT" -description = """http_request is a lightweight, efficient library for building, sending, and handling HTTP/HTTPS requests in Rust applications. It provides a simple and intuitive API, allowing developers to easily interact with web services, whether they use the "HTTP" or "HTTPS" protocol. The library supports various HTTP methods, custom headers, request bodies, and automatic handling of redirects (including detecting redirect loops), enabling fast and secure communication. Whether working with secure "HTTPS" connections or standard "HTTP" requests, the library is optimized for performance, minimal resource usage, and easy integration into Rust projects.""" +description = """http-request is a lightweight, efficient library for building, sending, and handling HTTP/HTTPS requests in Rust applications. It provides a simple and intuitive API, allowing developers to easily interact with web services, whether they use the "HTTP" or "HTTPS" protocol. The library supports various HTTP methods, custom headers, request bodies, timeout, automatic handling of redirects (including detecting redirect loops), and enhanced response body decoding (both automatic and manual), enabling fast and secure communication. Whether working with secure "HTTPS" connections or standard "HTTP" requests, the library is optimized for performance, minimal resource usage, and easy integration into Rust projects.""" keywords = ["http", "request", "response", "tcp", "redirect"] repository = "https://github.com/ltpp-universe/http-request.git" [dependencies] +brotli = "7.0.0" +flate2 = "1.0.35" hex = "0.4.3" native-tls = "0.2.12" serde = { version = "1.0", features = ["derive"] } diff --git a/readme.md b/readme.md index 0cf133f..aea7572 100644 --- a/readme.md +++ b/readme.md @@ -7,20 +7,23 @@ [Official Documentation](https://docs.ltpp.vip/HTTP-REQUEST/) -> http-request is a lightweight, efficient library for building, sending, and handling HTTP/HTTPS requests in Rust applications. It provides a simple and intuitive API, allowing developers to easily interact with web services, whether they use the "HTTP" or "HTTPS" protocol. The library supports various HTTP methods, custom headers, request bodies, timeout, and automatic handling of redirects (including detecting redirect loops), enabling fast and secure communication. Whether working with secure "HTTPS" connections or standard "HTTP" requests, the library is optimized for performance, minimal resource usage, and easy integration into Rust projects. +[Api Docs](https://docs.rs/http-request/latest/http_request/) + +> http-request is a lightweight, efficient library for building, sending, and handling HTTP/HTTPS requests in Rust applications. It provides a simple and intuitive API, allowing developers to easily interact with web services, whether they use the "HTTP" or "HTTPS" protocol. The library supports various HTTP methods, custom headers, request bodies, timeout, automatic handling of redirects (including detecting redirect loops), and enhanced response body decoding (both automatic and manual), enabling fast and secure communication. Whether working with secure "HTTPS" connections or standard "HTTP" requests, the library is optimized for performance, minimal resource usage, and easy integration into Rust projects.http-request is a lightweight, efficient library for building, sending, and handling HTTP/HTTPS requests in Rust applications. It provides a simple and intuitive API, allowing developers to easily interact with web services, whether they use the "HTTP" or "HTTPS" protocol. The library supports various HTTP methods, custom headers, request bodies, timeout, automatic handling of redirects (including detecting redirect loops), and enhanced response body decoding (both automatic and manual), enabling fast and secure communication. Whether working with secure "HTTPS" connections or standard "HTTP" requests, the library is optimized for performance, minimal resource usage, and easy integration into Rust projects. ## Features - **Support for HTTP/HTTPS**: Supports both HTTP and HTTPS protocols. - **Lightweight Design**: The `http_request` crate provides a simple and efficient API for building, sending, and handling HTTP requests while minimizing resource consumption. - **Supports Common HTTP Methods**: Supports common HTTP methods such as GET and POST. -- **Flexible Request Building**: Offers rich configuration options through `HttpRequestBuilder` to set request headers, bodies, and URLs. +- **Flexible Request Building**: Offers rich configuration options through `RequestBuilder` to set request headers, bodies, and URLs. - **Simple Error Handling**: Utilizes the `Result` type to handle errors in requests and responses, making error handling straightforward. - **Custom Headers and Request Bodies**: Easily add custom headers and request bodies. - **Response Handling**: Provides a simple wrapper around HTTP responses, making it easy to access and process response data. - **Optimized Memory Management**: Implements efficient memory management to minimize unnecessary memory allocations and improve performance. - **Redirect Handling**: Supports redirect handling, allows setting the maximum number of redirects, and includes redirect loop detection. -- **timeout**: Supports timeout +- **timeout**: Supports timeout. +- **Automatic and Manual Response Body Decoding**: Supports both automatic and manual decoding of response bodies, allowing for seamless interaction with different content types (e.g., JSON, XML, etc.). ## Installation @@ -39,7 +42,7 @@ use http_request::*; use std::collections::HashMap; let mut header: HashMap<&str, &str> = HashMap::new(); header.insert("header-key", "header-value"); -let mut _request_builder = HttpRequestBuilder::new() +let mut _request_builder = RequestBuilder::new() .get("https://ltpp.vip/") .headers(header) .timeout(6000) @@ -47,6 +50,7 @@ let mut _request_builder = HttpRequestBuilder::new() .max_redirect_times(8) .http1_1_only() .buffer(4096) + .decode() .builder(); _request_builder .send() @@ -68,7 +72,7 @@ let mut header: HashMap<&str, &str> = HashMap::new(); header.insert("header-key", "header-value"); let mut body: HashMap<&str, &str> = HashMap::new(); body.insert("body-key", "body-value"); -let mut _request_builder = HttpRequestBuilder::new() +let mut _request_builder = RequestBuilder::new() .post("http://localhost:80") .json(body) .headers(header) @@ -81,7 +85,7 @@ let mut _request_builder = HttpRequestBuilder::new() _request_builder .send() .and_then(|response| { - println!("{:?}", response.text()); + println!("{:?}", response.decode().text()); Ok(()) }) .unwrap_or_else(|e| println!("Error => {}", e)); @@ -94,7 +98,7 @@ use http_request::*; use std::collections::HashMap; let mut header: HashMap<&str, &str> = HashMap::new(); header.insert("header-key", "header-value"); -let mut _request_builder = HttpRequestBuilder::new() +let mut _request_builder = RequestBuilder::new() .post("http://localhost") .text("hello") .headers(header) @@ -103,6 +107,7 @@ let mut _request_builder = HttpRequestBuilder::new() .max_redirect_times(8) .http1_1_only() .buffer(4096) + .decode() .builder(); _request_builder .send() @@ -120,7 +125,7 @@ use http_request::*; use std::collections::HashMap; let mut header: HashMap<&str, &str> = HashMap::new(); header.insert("header-key", "header-value"); -let mut _request_builder = HttpRequestBuilder::new() +let mut _request_builder = RequestBuilder::new() .post("http://localhost") .body("hello".as_bytes()) .headers(header) @@ -133,7 +138,7 @@ let mut _request_builder = HttpRequestBuilder::new() _request_builder .send() .and_then(|response| { - println!("{:?}", response.text()); + println!("{:?}", response.decode(4096).text()); Ok(()) }) .unwrap_or_else(|e| println!("Error => {}", e)); diff --git a/src/body/impl.rs b/src/body/impl.rs index 170b402..c11a4c8 100644 --- a/src/body/impl.rs +++ b/src/body/impl.rs @@ -1,74 +1,36 @@ use super::r#type::Body; use serde::{Serialize, Serializer}; -use std::fmt::{self}; +use std::fmt::{self, Display}; -/// Represents the body of a request or response, which can be either plain text, JSON, or binary data. impl Default for Body { - /// Provides a default implementation for the `Body` enum. - /// - /// Returns a `Body::Text` variant with an empty string as the default body. fn default() -> Self { Self::Text("") } } -/// Implements the `fmt::Display` trait for the `Body` enum. -/// -/// This trait is responsible for providing a human-readable representation of the body: -/// - For the `Text` variant, the contained text is displayed. -/// - For the `Json` variant, the JSON is serialized to a string. If serialization fails, -/// an empty JSON object (`{}`) is displayed. -/// - For the `Binary` variant, the binary data is displayed in a debug format. -impl fmt::Display for Body { - /// Formats the `Body` instance for user-friendly display. - /// - /// # Parameters - /// - `f`: A mutable reference to the formatter. - /// - /// # Returns - /// A `Result` indicating whether the formatting was successful. The result is - /// `fmt::Result` which is either `Ok` or an error. +impl Display for Body { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Body::Text(text) => write!(f, "{}", text.to_string()), - Body::Json(json) => write!( + Self::Text(text) => write!(f, "{}", text.to_string()), + Self::Json(json) => write!( f, "{:?}", serde_json::to_string(json).unwrap_or_else(|_| String::from("{}")) ), - Body::Binary(binary) => write!(f, "{:?}", binary), + Self::Binary(binary) => write!(f, "{:?}", binary), } } } -/// Implements the `Serialize` trait for the `Body` enum. -/// -/// This trait enables the serialization of the `Body` enum into different formats using -/// the `serde` framework: -/// - The `Text` variant is serialized as a plain string. -/// - The `Json` variant is serialized using the provided `serde` serializer. -/// - The `Binary` variant is serialized as binary data. impl Serialize for Body { - /// Serializes the `Body` instance into the given serializer. - /// - /// # Type Parameters - /// - `S`: The serializer type implementing the `Serializer` trait. - /// - /// # Parameters - /// - `serializer`: The serializer used for serialization, which will handle - /// the transformation of the `Body` into the target format. - /// - /// # Returns - /// A `Result` containing either the successfully serialized output or an error. - /// If successful, it returns `S::Ok`; if an error occurs, it returns `S::Error`. fn serialize(&self, serializer: S) -> Result where S: Serializer, { match self { - Body::Text(text) => text.serialize(serializer), - Body::Json(json) => json.serialize(serializer), - Body::Binary(binary) => binary.serialize(serializer), + Self::Text(text) => text.serialize(serializer), + Self::Json(json) => json.serialize(serializer), + Self::Binary(binary) => binary.serialize(serializer), } } } diff --git a/src/body/type.rs b/src/body/type.rs index f7e9d05..4953c15 100644 --- a/src/body/type.rs +++ b/src/body/type.rs @@ -14,7 +14,7 @@ pub type BodyBinary = &'static [u8]; /// Represents the body of an HTTP request, which can be either plain text, JSON, or binary data. /// This enum allows different types of content to be used in the body of the request, supporting /// both structured and unstructured data formats. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum Body { /// The text variant of the body, containing plain string content. /// diff --git a/src/request/cfg.rs b/src/cfg.rs similarity index 70% rename from src/request/cfg.rs rename to src/cfg.rs index 2b1f354..aa059c0 100644 --- a/src/request/cfg.rs +++ b/src/cfg.rs @@ -30,7 +30,7 @@ fn test_http_post_request() { body.insert("code", "hello"); body.insert("language", "rust"); body.insert("testin", ""); - let mut _request_builder: HttpRequest = HttpRequestBuilder::new() + let mut _request_builder: Request = RequestBuilder::new() .post("http://localhost:80/rust?hello=rust") .json(body) .headers(header) @@ -59,7 +59,7 @@ fn test_http_get_request() { header.insert("header-key", "header-value"); let mut body: HashMap<&str, &str> = HashMap::new(); body.insert("body-key", "body-value"); - let mut _request_builder: HttpRequest = HttpRequestBuilder::new() + let mut _request_builder: Request = RequestBuilder::new() .get("http://localhost:80") .headers(header) .timeout(6000) @@ -92,7 +92,7 @@ fn test_https_post_request() { body.insert("code", "fn main() {\r\n println!(\"hello world\");\r\n}"); body.insert("language", "rust"); body.insert("testin", ""); - let mut _request_builder: HttpRequest = HttpRequestBuilder::new() + let mut _request_builder: Request = RequestBuilder::new() .post("https://code.ltpp.vip/") .json(body) .headers(header) @@ -121,7 +121,7 @@ fn test_https_get_request() { header.insert("header-key", "header-value"); let mut body: HashMap<&str, &str> = HashMap::new(); body.insert("body-key", "body-value"); - let mut _request_builder: HttpRequest = HttpRequestBuilder::new() + let mut _request_builder: Request = RequestBuilder::new() .get("https://code.ltpp.vip/") .headers(header) .timeout(10000) @@ -148,7 +148,7 @@ fn test_http_post_text_request() { let mut header: HashMap<&str, &str> = HashMap::new(); header.insert("Accept", "*/*"); header.insert("Content-Type", "application/json"); - let mut _request_builder: HttpRequest = HttpRequestBuilder::new() + let mut _request_builder: Request = RequestBuilder::new() .post("http://localhost:80") .text("hello") .headers(header) @@ -176,7 +176,7 @@ fn test_http_post_binary_request() { let mut header: HashMap<&str, &str> = HashMap::new(); header.insert("Accept", "*/*"); header.insert("Content-Type", "application/json"); - let mut _request_builder: HttpRequest = HttpRequestBuilder::new() + let mut _request_builder: Request = RequestBuilder::new() .post("http://localhost:80") .body("hello".as_bytes()) .headers(header) @@ -198,3 +198,73 @@ fn test_http_post_binary_request() { }) .unwrap_or_else(|e| output("Error => ", &format!("{:?}", e), Color::Red)); } + +#[test] +fn test_auto_gzip_get() { + let mut _request_builder: Request = RequestBuilder::new() + .get("https://proxy.ltpp.vip/visit/add?origin=https://docs.ltpp.vip/") + .timeout(10000) + .redirect() + .max_redirect_times(8) + .decode() + .buffer(4096) + .http1_1_only() + .builder(); + _request_builder + .send() + .and_then(|response| { + output( + "Response => ", + &format!("{:?}", response.text()), + Color::Green, + ); + Ok(()) + }) + .unwrap_or_else(|e| output("Error => ", &format!("{:?}", e), Color::Red)); +} + +#[test] +fn test_gzip_get() { + let mut _request_builder: Request = RequestBuilder::new() + .get("https://proxy.ltpp.vip/visit/add?origin=https://docs.ltpp.vip/") + .timeout(10000) + .redirect() + .max_redirect_times(8) + .buffer(4096) + .http1_1_only() + .builder(); + _request_builder + .send() + .and_then(|response| { + output( + "Response => ", + &format!("{:?}", response.decode(4096).text()), + Color::Green, + ); + Ok(()) + }) + .unwrap_or_else(|e| output("Error => ", &format!("{:?}", e), Color::Red)); +} + +#[test] +fn test_unredirect_get() { + let mut _request_builder: Request = RequestBuilder::new() + .post("https://proxy.ltpp.vip/visit/add?origin=https://docs.ltpp.vip/") + .timeout(10000) + .max_redirect_times(8) + .buffer(4096) + .unredirect() + .http1_1_only() + .builder(); + _request_builder + .send() + .and_then(|response| { + output( + "Response => ", + &format!("{:?}", response.decode(4096).text()), + Color::Green, + ); + Ok(()) + }) + .unwrap_or_else(|e| output("Error => ", &format!("{:?}", e), Color::Red)); +} diff --git a/src/compress/brotli/decode.rs b/src/compress/brotli/decode.rs new file mode 100644 index 0000000..0e753f4 --- /dev/null +++ b/src/compress/brotli/decode.rs @@ -0,0 +1,23 @@ +use brotli::Decompressor; +use std::io::Read; + +/// Decodes compressed data using a specified decompressor +/// +/// This function takes a reference to a `Vec` containing compressed data and a buffer size. +/// It uses the `Decompressor` to decompress the data and returns the decompressed result as a `Vec`. +/// If decompression fails, it returns an empty `Vec`. +/// +/// # Parameters +/// - `data`: A reference to a `Vec` containing the compressed data. +/// - `buffer_size`: The buffer size to use for the decompressor. +/// +/// # Returns +/// A `Vec` containing the decompressed data, or an empty `Vec` if decompression fails. +pub fn decode(data: &Vec, buffer_size: usize) -> Vec { + let mut decompressor: Decompressor<&[u8]> = Decompressor::new(data.as_slice(), buffer_size); + let mut decompressed_data: Vec = Vec::new(); + match decompressor.read_to_end(&mut decompressed_data) { + Ok(_) => decompressed_data, + _ => Vec::new(), + } +} diff --git a/src/compress/brotli/helper.rs b/src/compress/brotli/helper.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/compress/brotli/helper.rs @@ -0,0 +1 @@ + diff --git a/src/compress/brotli/mod.rs b/src/compress/brotli/mod.rs new file mode 100644 index 0000000..f83214d --- /dev/null +++ b/src/compress/brotli/mod.rs @@ -0,0 +1,2 @@ +pub mod decode; +pub mod helper; diff --git a/src/compress/constant.rs b/src/compress/constant.rs new file mode 100644 index 0000000..96b91a8 --- /dev/null +++ b/src/compress/constant.rs @@ -0,0 +1,14 @@ +/// A constant representing the "gzip" compression algorithm. +/// +/// This constant holds the string value `"gzip"`, which is commonly used to refer to the GZIP compression format. +pub static GZIP: &str = "gzip"; + +/// A constant representing the "deflate" compression algorithm. +/// +/// This constant holds the string value `"deflate"`, which is commonly used to refer to the DEFLATE compression format. +pub static DEFLATE: &str = "deflate"; + +/// A constant representing the "br" compression algorithm (Brotli). +/// +/// This constant holds the string value `"br"`, which is commonly used to refer to the Brotli compression format. +pub static BR: &str = "br"; diff --git a/src/compress/deflate/decode.rs b/src/compress/deflate/decode.rs new file mode 100644 index 0000000..bf36482 --- /dev/null +++ b/src/compress/deflate/decode.rs @@ -0,0 +1,21 @@ +use flate2::read::DeflateDecoder; +use std::io::{BufReader, Read}; + +/// Decodes deflate compressed data +/// +/// # Parameters +/// - `data`: A reference to a `Vec` containing the compressed data. +/// - `buffer_size`: The buffer size to use for the buffered reader. +/// +/// # Returns +/// A `Vec` containing the decompressed data, or an empty `Vec` in case of error. +pub fn decode(data: &Vec, buffer_size: usize) -> Vec { + let decoder: DeflateDecoder<&[u8]> = DeflateDecoder::new(data.as_slice()); + let mut buffered_reader: BufReader> = + BufReader::with_capacity(buffer_size, decoder); + let mut decompressed_data: Vec = Vec::new(); + match buffered_reader.read_to_end(&mut decompressed_data) { + Ok(_) => decompressed_data, + _ => Vec::new(), + } +} diff --git a/src/compress/deflate/helper.rs b/src/compress/deflate/helper.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/compress/deflate/helper.rs @@ -0,0 +1 @@ + diff --git a/src/compress/deflate/mod.rs b/src/compress/deflate/mod.rs new file mode 100644 index 0000000..f83214d --- /dev/null +++ b/src/compress/deflate/mod.rs @@ -0,0 +1,2 @@ +pub mod decode; +pub mod helper; diff --git a/src/compress/gzip/decode.rs b/src/compress/gzip/decode.rs new file mode 100644 index 0000000..ea90213 --- /dev/null +++ b/src/compress/gzip/decode.rs @@ -0,0 +1,28 @@ +use flate2::read::GzDecoder; +use std::io::BufReader; +use std::io::Read; + +/// Decodes Gzip compressed data. +/// +/// This function takes a Gzip compressed byte vector and decompresses it using the +/// `flate2` crate's `GzDecoder`. It buffers the decompressed data and returns the +/// result as a vector of bytes. +/// +/// # Arguments +/// - `data` - A reference to a `Vec` containing the compressed Gzip data. +/// - `buffer_size` - The buffer size to use for reading the compressed data. A larger +/// buffer size can improve performance for larger datasets. +/// +/// # Returns +/// - `Vec` - The decompressed data as a vector of bytes. If decompression fails, +/// an empty `Vec` is returned. +pub fn decode(data: &Vec, buffer_size: usize) -> Vec { + let decoder: GzDecoder<&[u8]> = GzDecoder::new(data.as_slice()); + let mut buffered_reader: BufReader> = + BufReader::with_capacity(buffer_size, decoder); + let mut decompressed_data: Vec = Vec::new(); + match buffered_reader.read_to_end(&mut decompressed_data) { + Ok(_) => decompressed_data, + _ => Vec::new(), + } +} diff --git a/src/compress/gzip/helper.rs b/src/compress/gzip/helper.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/compress/gzip/helper.rs @@ -0,0 +1 @@ + diff --git a/src/compress/gzip/mod.rs b/src/compress/gzip/mod.rs new file mode 100644 index 0000000..f83214d --- /dev/null +++ b/src/compress/gzip/mod.rs @@ -0,0 +1,2 @@ +pub mod decode; +pub mod helper; diff --git a/src/compress/impl.rs b/src/compress/impl.rs new file mode 100644 index 0000000..f54c171 --- /dev/null +++ b/src/compress/impl.rs @@ -0,0 +1,73 @@ +use std::str::FromStr; + +use super::{ + brotli, + constant::{BR, DEFLATE, GZIP}, + deflate, gzip, + r#type::Compress, +}; +use crate::{request::constant::CONTENT_ENCODING, response::response_header::r#type::Header}; + +impl Default for Compress { + fn default() -> Self { + Self::Unknown + } +} + +impl FromStr for Compress { + type Err = (); + + fn from_str(data: &str) -> Result { + match data.to_lowercase().as_str() { + _data if _data == GZIP => Ok(Self::Gzip), + _data if _data == DEFLATE => Ok(Self::Deflate), + _data if _data == BR => Ok(Self::Br), + _ => Ok(Self::Unknown), + } + } +} + +impl Compress { + /// Extracts the compression type from an HTTP header. + /// + /// This function looks for the `Content-Encoding` header in the provided `Header` and attempts + /// to parse it into a `Compress` enum value. + /// + /// # Arguments + /// - `header` - The HTTP header from which the compression type is to be extracted. + /// + /// # Returns + /// - The `Compress` value corresponding to the `Content-Encoding` header, or `Compress::Unknown` + /// if the header does not match any known compression types. + pub fn from(header: &Header) -> Self { + let content_encoding_key: String = CONTENT_ENCODING.to_lowercase(); + let mut compress: Compress = Self::default(); + for (key, value) in header { + if key.to_lowercase() == content_encoding_key { + compress = value.parse::().unwrap_or_default(); + break; + } + } + compress + } + + /// Decodes data based on the compression type. + /// + /// This function decodes the compressed data using the corresponding compression algorithm + /// (Gzip, Deflate, or Brotli) depending on the `Compress` enum value. + /// + /// # Arguments + /// - `data` - A vector of bytes containing the compressed data. + /// - `buffer_size` - The buffer size to use during decompression. + /// + /// # Returns + /// - A `Vec` containing the decompressed data. + pub fn decode(&self, data: &Vec, buffer_size: usize) -> Vec { + match self { + Self::Gzip => gzip::decode::decode(data, buffer_size), + Self::Deflate => deflate::decode::decode(data, buffer_size), + Self::Br => brotli::decode::decode(data, buffer_size), + Self::Unknown => data.clone(), + } + } +} diff --git a/src/compress/mod.rs b/src/compress/mod.rs new file mode 100644 index 0000000..2a13138 --- /dev/null +++ b/src/compress/mod.rs @@ -0,0 +1,6 @@ +pub mod brotli; +pub mod constant; +pub mod deflate; +pub mod gzip; +pub mod r#impl; +pub mod r#type; diff --git a/src/compress/type.rs b/src/compress/type.rs new file mode 100644 index 0000000..ccf71dd --- /dev/null +++ b/src/compress/type.rs @@ -0,0 +1,7 @@ +#[derive(Debug, PartialEq, Eq)] +pub enum Compress { + Gzip, + Deflate, + Br, + Unknown, +} diff --git a/src/constant/mod.rs b/src/constant/mod.rs index 642d416..702ece4 100644 --- a/src/constant/mod.rs +++ b/src/constant/mod.rs @@ -1,3 +1,2 @@ pub mod common; -pub mod http; pub mod request; diff --git a/src/content_type/impl.rs b/src/content_type/impl.rs index ec7207f..0fecb6c 100644 --- a/src/content_type/impl.rs +++ b/src/content_type/impl.rs @@ -1,5 +1,5 @@ use super::r#type::ContentType; -use crate::constant::http::{ +use crate::request::constant::{ APPLICATION_JSON, APPLICATION_XML, FORM_URLENCODED, TEXT_HTML, TEXT_PLAIN, }; use serde::Serialize; @@ -123,12 +123,12 @@ impl ContentType { data: &T, ) -> String { match self { - ContentType::ApplicationJson => ContentType::get_application_json(data), - ContentType::ApplicationXml => ContentType::get_application_xml(data), - ContentType::TextPlain => ContentType::get_text_plain(data), - ContentType::TextHtml => ContentType::get_text_html(data), - ContentType::FormUrlEncoded => ContentType::get_form_url_encoded(data), - ContentType::Unknown => ContentType::get_binary(data), + Self::ApplicationJson => Self::get_application_json(data), + Self::ApplicationXml => Self::get_application_xml(data), + Self::TextPlain => Self::get_text_plain(data), + Self::TextHtml => Self::get_text_html(data), + Self::FormUrlEncoded => Self::get_form_url_encoded(data), + Self::Unknown => Self::get_binary(data), } } } @@ -136,37 +136,19 @@ impl ContentType { impl FromStr for ContentType { type Err = (); - /// Parses a string to convert it into a `ContentType` enum variant. - /// - /// This implementation compares the input string (case-insensitive) with predefined content - /// types and returns the corresponding `ContentType` variant. - /// - /// # Parameters - /// - `data`: The string representing the content type to be parsed. - /// - /// # Returns - /// - A `Result` containing the matching `ContentType` variant if the string matches a known - /// content type, or `ContentType::Unknown` if the string does not match any predefined content - /// type. fn from_str(data: &str) -> Result { match data.to_lowercase().as_str() { - _data if _data == APPLICATION_JSON => Ok(ContentType::ApplicationJson), - _data if _data == APPLICATION_XML => Ok(ContentType::ApplicationXml), - _data if _data == TEXT_PLAIN => Ok(ContentType::TextPlain), - _data if _data == TEXT_HTML => Ok(ContentType::TextHtml), - _data if _data == FORM_URLENCODED => Ok(ContentType::FormUrlEncoded), - _ => Ok(ContentType::Unknown), + _data if _data == APPLICATION_JSON => Ok(Self::ApplicationJson), + _data if _data == APPLICATION_XML => Ok(Self::ApplicationXml), + _data if _data == TEXT_PLAIN => Ok(Self::TextPlain), + _data if _data == TEXT_HTML => Ok(Self::TextHtml), + _data if _data == FORM_URLENCODED => Ok(Self::FormUrlEncoded), + _ => Ok(Self::Unknown), } } } impl Default for ContentType { - /// Returns the default `ContentType`, which is `ContentType::Unknown`. - /// - /// This is used when no specific content type is provided or when the content type is not recognized. - /// - /// # Returns - /// - The `ContentType::Unknown` variant. fn default() -> Self { Self::Unknown } diff --git a/src/content_type/type.rs b/src/content_type/type.rs index 53e3dce..da1182c 100644 --- a/src/content_type/type.rs +++ b/src/content_type/type.rs @@ -1,6 +1,6 @@ /// Represents different types of HTTP content types, such as JSON, XML, plain text, HTML, /// form URL encoded, and an unknown type. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub enum ContentType { /// Represents the `application/json` content type. ApplicationJson, diff --git a/src/http_url/impl.rs b/src/http_url/impl.rs index 423fb60..49f3431 100644 --- a/src/http_url/impl.rs +++ b/src/http_url/impl.rs @@ -1,14 +1,7 @@ use super::r#type::HttpUrl; -use crate::{protocol::r#type::Protocol, request::error::Error}; +use crate::{protocol::r#type::Protocol, request::error::r#type::Error}; use url::Url as UrlParser; -/// Default implementation for `HttpUrl`. -/// -/// This implementation provides the default values for a `HttpUrl` instance. All fields -/// are initialized to `None` to indicate that no URL components are set by default. -/// -/// # Returns -/// Returns a new `HttpUrl` instance with all fields set to `None`. impl Default for HttpUrl { fn default() -> Self { HttpUrl { @@ -36,22 +29,19 @@ impl HttpUrl { /// Returns a `Result` containing either a `HttpUrl` instance populated with the /// parsed components or an `Error::InvalidUrl` if the parsing fails. pub fn parse(url_str: &str) -> Result { - if let Ok(parsed_url) = UrlParser::parse(url_str) { - let res: HttpUrl = HttpUrl { - protocol: parsed_url - .scheme() - .to_string() - .parse::() - .unwrap_or_default(), - host: parsed_url.host_str().map(|h| h.to_string()), - port: parsed_url.port(), - path: Some(parsed_url.path().to_string()), - query: parsed_url.query().map(|q| q.to_string()), - fragment: parsed_url.fragment().map(|f| f.to_string()), - }; - Ok(res) - } else { - Err(Error::InvalidUrl) - } + let parsed_url: UrlParser = UrlParser::parse(url_str).map_err(|_| Error::InvalidUrl)?; + let res: Self = Self { + protocol: parsed_url + .scheme() + .to_string() + .parse::() + .unwrap_or_default(), + host: parsed_url.host_str().map(|h| h.to_string()), + port: parsed_url.port(), + path: Some(parsed_url.path().to_string()), + query: parsed_url.query().map(|q| q.to_string()), + fragment: parsed_url.fragment().map(|f| f.to_string()), + }; + Ok(res) } } diff --git a/src/http_url/type.rs b/src/http_url/type.rs index 73d662d..2dd04f2 100644 --- a/src/http_url/type.rs +++ b/src/http_url/type.rs @@ -16,7 +16,7 @@ use crate::protocol::r#type::Protocol; /// /// This struct is primarily used for holding the components of a URL after parsing, allowing /// for easy manipulation and access to the individual components. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct HttpUrl { pub protocol: Protocol, pub host: Option, diff --git a/src/http_version/impl.rs b/src/http_version/impl.rs index 7d23723..b1b309b 100644 --- a/src/http_version/impl.rs +++ b/src/http_version/impl.rs @@ -1,38 +1,19 @@ use super::r#type::HttpVersion; -use crate::constant::http::{HTTP_VERSION_1_1, HTTP_VERSION_2, UNKNOWN_HTTP_VERSION}; -use std::fmt; +use crate::request::constant::{HTTP_VERSION_1_1, HTTP_VERSION_2, UNKNOWN_HTTP_VERSION}; +use std::fmt::{self, Display}; impl Default for HttpVersion { - /// Provides the default value for `HttpVersion`. - /// - /// This method initializes a `HttpVersion` instance with the default value, which is - /// `HttpVersion::HTTP1_1`. This is typically used when a `HttpVersion` instance is created - /// and no specific version is provided, falling back to HTTP/1.1 as the default. - /// - /// # Returns - /// Returns the default `HttpVersion::HTTP1_1`. fn default() -> Self { Self::HTTP1_1 } } -impl fmt::Display for HttpVersion { - /// Formats the `HttpVersion` instance as a string. - /// - /// This method converts the `HttpVersion` instance into its corresponding string representation, - /// which can be useful for displaying or logging the HTTP version. The version is returned as a - /// human-readable string based on the variant of the `HttpVersion`. - /// - /// # Parameters - /// - `f`: The formatter to write the output to. - /// - /// # Returns - /// Returns a `fmt::Result`, indicating the success or failure of the formatting operation. +impl Display for HttpVersion { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let version_str = match self { - HttpVersion::HTTP1_1 => HTTP_VERSION_1_1, - HttpVersion::HTTP2 => HTTP_VERSION_2, - HttpVersion::Unknown(_) => UNKNOWN_HTTP_VERSION, + Self::HTTP1_1 => HTTP_VERSION_1_1, + Self::HTTP2 => HTTP_VERSION_2, + Self::Unknown(_) => UNKNOWN_HTTP_VERSION, }; write!(f, "{}", version_str) } diff --git a/src/http_version/type.rs b/src/http_version/type.rs index a005f52..0c4fa1f 100644 --- a/src/http_version/type.rs +++ b/src/http_version/type.rs @@ -7,13 +7,7 @@ /// The variants include: /// - `HTTP1_1`: Represents HTTP version 1.1. /// - `HTTP2`: Represents HTTP version 2.0. -/// -/// # Derives -/// The enum derives the following traits: -/// - `Debug`: Allows for formatting the enum for debugging purposes. -/// - `PartialEq`: Allows for comparing instances of `HttpVersion` for equality. -/// - `Clone`: Allows for creating a copy of `HttpVersion` instances. -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, Eq)] pub enum HttpVersion { /// HTTP version 1.1 HTTP1_1, diff --git a/src/lib.rs b/src/lib.rs index 2ee698f..1bf1112 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,10 @@ pub(crate) mod body; +#[cfg(test)] +mod cfg; +pub(crate) mod compress; pub(crate) mod constant; pub(crate) mod content_type; pub(crate) mod global_trait; -pub(crate) mod header; pub(crate) mod http_url; pub(crate) mod http_version; pub(crate) mod methods; @@ -13,7 +15,6 @@ pub(crate) mod status_code; pub(crate) mod utils; pub use request::{ - error::Error, http_request::r#type::HttpRequest, - http_request_builder::r#type::HttpRequestBuilder, + error::r#type::Error, request::r#type::Request, request_builder::r#type::RequestBuilder, }; -pub use response::r#trait::HttpResponse; +pub use response::r#trait::Response; diff --git a/src/methods/constant.rs b/src/methods/constant.rs new file mode 100644 index 0000000..15c09c9 --- /dev/null +++ b/src/methods/constant.rs @@ -0,0 +1,2 @@ +pub static GET: &str = "GET"; +pub static POST: &str = "POST"; diff --git a/src/methods/impl.rs b/src/methods/impl.rs index 46ed967..3fe1d15 100644 --- a/src/methods/impl.rs +++ b/src/methods/impl.rs @@ -1,49 +1,44 @@ use std::fmt::{self, Display}; +use crate::methods::constant::{GET, POST}; + use super::r#type::Methods; -/// Implements the default value for `Methods`. -/// -/// The default value is `Methods::GET`, which serves as the default HTTP request method. impl Default for Methods { fn default() -> Self { - Methods::GET + Self::GET } } /// Provides utility methods for the `Methods` type. impl Methods { - /// Creates a new instance of `Methods` with the default value of `Methods::GET`. + /// Creates a new instance of `Methods` with the default value of `Self::GET`. /// /// This is a shorthand for using the `default` method. pub fn new() -> Self { - Methods::default() + Self::default() } /// Checks if the current method is `GET`. /// /// Returns `true` if the method is `GET`, otherwise returns `false`. pub fn is_get(&self) -> bool { - self.to_owned() == Methods::GET.to_owned() + self.to_owned() == Self::GET.to_owned() } /// Checks if the current method is `POST`. /// /// Returns `true` if the method is `POST`, otherwise returns `false`. pub fn is_post(&self) -> bool { - self.to_owned() == Methods::POST.to_owned() + self.to_owned() == Self::POST.to_owned() } } -/// Implements the `Display` trait for `Methods`. -/// -/// Formats the `Methods` enum as a string, returning `"GET"` for `Methods::GET` -/// and `"POST"` for `Methods::POST`. impl Display for Methods { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let res: &str = match self { - Methods::GET => "GET", - Methods::POST => "POST", + Self::GET => GET, + Self::POST => POST, }; write!(f, "{}", res) } diff --git a/src/methods/mod.rs b/src/methods/mod.rs index 6297e83..5c7188f 100644 --- a/src/methods/mod.rs +++ b/src/methods/mod.rs @@ -1,2 +1,3 @@ +pub mod constant; pub mod r#impl; pub mod r#type; diff --git a/src/methods/type.rs b/src/methods/type.rs index e1ab5d6..2dbed0c 100644 --- a/src/methods/type.rs +++ b/src/methods/type.rs @@ -1,11 +1,7 @@ /// Defines the `Methods` enum, representing HTTP request methods. /// /// The `Methods` enum includes commonly used HTTP methods such as `GET` and `POST`. -/// It derives the following traits: -/// - `Debug`: Enables formatting the enum with the `{:?}` formatter for debugging purposes. -/// - `Clone`: Allows creating a duplicate of a `Methods` value. -/// - `PartialEq`: Enables equality comparison between `Methods` values. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum Methods { /// Represents the HTTP `GET` method. GET, diff --git a/src/protocol/impl.rs b/src/protocol/impl.rs index f50c70b..a6304eb 100644 --- a/src/protocol/impl.rs +++ b/src/protocol/impl.rs @@ -1,25 +1,25 @@ +use crate::request::constant::{HTTP, HTTPS}; + use super::r#type::Protocol; use std::{ fmt::{self, Display}, str::FromStr, }; -/// Implements the default value for `Protocol`. -/// -/// The default value is `Protocol::HTTP`. + impl Default for Protocol { fn default() -> Self { - Protocol::HTTP + Self::HTTP } } /// Provides utility methods for the `Protocol` type. impl Protocol { - /// Creates a new instance of `Protocol` with the default value of `Protocol::HTTP`. + /// Creates a new instance of `Protocol` with the default value of `Self::HTTP`. /// /// This is a shorthand for using the `default` method. #[allow(dead_code)] pub fn new() -> Self { - Protocol::default() + Self::default() } /// Checks if the current protocol is `HTTP`. @@ -27,40 +27,37 @@ impl Protocol { /// Returns `true` if the protocol is `HTTP`, otherwise returns `false`. #[allow(dead_code)] pub fn is_http(&self) -> bool { - self.to_owned() == Protocol::HTTP.to_owned() + self.to_owned() == Self::HTTP.to_owned() } /// Checks if the current protocol is `HTTPS`. /// /// Returns `true` if the protocol is `HTTPS`, otherwise returns `false`. pub fn is_https(&self) -> bool { - self.to_owned() == Protocol::HTTPS.to_owned() + self.to_owned() == Self::HTTPS.to_owned() } /// Returns the default port associated with the protocol. /// - /// - Returns `80` for `Protocol::HTTP`. - /// - Returns `443` for `Protocol::HTTPS`. + /// - Returns `80` for `Self::HTTP`. + /// - Returns `443` for `Self::HTTPS`. pub fn get_port(&self) -> u16 { match self { - Protocol::HTTP => 80, - Protocol::HTTPS => 443, - Protocol::Unknown(_) => 80, + Self::HTTP => 80, + Self::HTTPS => 443, + Self::Unknown(_) => 80, } } } -/// Implements the `Display` trait for `Protocol`. -/// -/// Formats the `Protocol` enum as a lowercase string, returning: -/// - `"http"` for `Protocol::HTTP`. -/// - `"https"` for `Protocol::HTTPS`. impl Display for Protocol { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let http: String = HTTP.to_lowercase(); + let https: String = HTTPS.to_lowercase(); let res: &str = match self { - Protocol::HTTP => "http", - Protocol::HTTPS => "https", - Protocol::Unknown(protocol) => protocol, + Self::HTTP => http.as_str(), + Self::HTTPS => https.as_str(), + Self::Unknown(protocol) => protocol, }; write!(f, "{}", res) } @@ -69,27 +66,11 @@ impl Display for Protocol { impl FromStr for Protocol { type Err = &'static str; - /// Parses a string into a `Protocol` variant. - /// - /// This method attempts to convert a string into one of the `Protocol` variants: - /// - "http" will be converted to `Protocol::HTTP`. - /// - "https" will be converted to `Protocol::HTTPS`. - /// - /// If the string doesn't match either of these values, it returns an error. - /// - /// # Parameters - /// - `s`: A string slice representing the protocol to be parsed. - /// - /// # Returns - /// A `Result` that is either: - /// - `Ok(Protocol::HTTP)` if the string is "http". - /// - `Ok(Protocol::HTTPS)` if the string is "https". - /// - `Err("Invalid protocol")` if the string doesn't match either value. - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "http" => Ok(Protocol::HTTP), - "https" => Ok(Protocol::HTTPS), - _ => Ok(Protocol::Unknown(s.to_string())), + fn from_str(data: &str) -> Result { + match data.to_lowercase().as_str() { + _data if _data == HTTP.to_lowercase() => Ok(Self::HTTP), + _data if _data == HTTPS.to_lowercase() => Ok(Self::HTTPS), + _ => Ok(Self::Unknown(data.to_string())), } } } diff --git a/src/protocol/type.rs b/src/protocol/type.rs index c18f196..d70625d 100644 --- a/src/protocol/type.rs +++ b/src/protocol/type.rs @@ -3,12 +3,7 @@ /// The `Protocol` enum includes: /// - `HTTP`: Represents the HTTP protocol. /// - `HTTPS`: Represents the HTTPS protocol. -/// -/// It derives the following traits: -/// - `Debug`: Enables formatting the enum with the `{:?}` formatter for debugging purposes. -/// - `Clone`: Allows creating a duplicate of a `Protocol` value. -/// - `PartialEq`: Enables equality comparison between `Protocol` values. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum Protocol { /// Represents the HTTP protocol. HTTP, diff --git a/src/request/config/impl.rs b/src/request/config/impl.rs index ca946cb..c31f13b 100644 --- a/src/request/config/impl.rs +++ b/src/request/config/impl.rs @@ -5,24 +5,8 @@ use crate::{ }; impl Default for Config { - /// Provides the default configuration for `Config`. - /// - /// This method initializes a `Config` instance with default values: - /// - `timeout`: Set to the constant `DEFAULT_TIMEOUT`, which represents the default timeout duration. - /// - `url_obj`: Initialized with the default value of `HttpUrl`. This represents the URL used in the request. - /// - `redirect`: Set to `false` by default, meaning that HTTP redirects are disabled unless explicitly enabled. - /// - `max_redirect_times`: Set to `8` by default, which limits the maximum number of redirects that can be followed. - /// - `redirect_times`: Set to `0`, indicating that no redirects have been followed initially. - /// - `http_version`: Set to the default value of `HttpVersion`, which defines the default HTTP protocol version used in the request. - /// - `buffer`: Set to `1024`, defining the default buffer size (in bytes) for reading the HTTP response. - /// - /// # Returns - /// - /// Returns a `Config` instance initialized with the default settings as described above. - /// The default configuration is suitable for most typical HTTP requests, but can be customized - /// as needed by modifying individual fields after the instance is created. fn default() -> Self { - Config { + Self { timeout: DEFAULT_TIMEOUT, url_obj: HttpUrl::default(), redirect: false, @@ -30,6 +14,7 @@ impl Default for Config { redirect_times: 0, http_version: HttpVersion::default(), buffer: 1024, + decode: true, } } } diff --git a/src/request/config/type.rs b/src/request/config/type.rs index 5175a71..4375f74 100644 --- a/src/request/config/type.rs +++ b/src/request/config/type.rs @@ -45,7 +45,7 @@ use crate::{http_url::r#type::HttpUrl, http_version::r#type::HttpVersion}; /// /// - Adjust the `buffer` size depending on your application’s memory usage and the size of the responses /// you expect to receive. A larger buffer can help improve performance when handling large responses. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Config { /// The timeout duration for the request in milliseconds. pub timeout: u64, @@ -65,6 +65,9 @@ pub struct Config { /// The type of this field is `HttpVersion`. pub http_version: HttpVersion, - /// The buffer size for reading the HTTP response. + /// The buffer size for reading the HTTP response and decode. pub buffer: usize, + + /// Auto decode response data + pub decode: bool, } diff --git a/src/constant/http.rs b/src/request/constant.rs similarity index 90% rename from src/constant/http.rs rename to src/request/constant.rs index 3692f23..ff3d460 100644 --- a/src/constant/http.rs +++ b/src/request/constant.rs @@ -19,6 +19,9 @@ pub static CONTENT_LENGTH: &str = "Content-Length"; /// The HTTP header field name `Content-Type`, used to specify the media type of the resource or the data being sent in an HTTP request or response. pub static CONTENT_TYPE: &str = "Content-Type"; +/// The HTTP header name used to indicate the content encoding of the response. +pub static CONTENT_ENCODING: &str = "Content-Encoding"; + /// The HTTP header field "Accept". pub static ACCEPT: &str = "Accept"; @@ -65,3 +68,9 @@ pub static FORM_URLENCODED: &str = "application/x-www-form-urlencoded"; /// Query symbols pub static QUERY_SYMBOL: &str = "?"; + +/// A constant representing the "HTTP" protocol. +pub static HTTP: &str = "HTTP"; + +/// A constant representing the "HTTPS" protocol. +pub static HTTPS: &str = "HTTPS"; diff --git a/src/request/error.rs b/src/request/error.rs deleted file mode 100644 index cd52750..0000000 --- a/src/request/error.rs +++ /dev/null @@ -1,69 +0,0 @@ -use std::{ - error::Error as StdError, - fmt::{self}, -}; - -/// Represents different types of errors that can occur in the application. -/// -/// The `Error` enum defines various error types related to HTTP requests, network connections, and TLS operations. -/// Each variant corresponds to a specific error that can occur during the execution of the application. -/// -/// # Variants -/// - `InvalidUrl`: Indicates that the provided URL is invalid. -/// - `TcpStreamConnectError`: Represents an error that occurred while attempting to connect a TCP stream. -/// - `RequestError`: A general error related to making a request. -/// - `MethodsNotSupport`: Indicates that the requested HTTP method is not supported. -/// - `ReadConnectionError`: An error that occurred while reading from the connection. -/// - `TlsConnectorBuildError`: Indicates an error during the construction of the TLS connector. -/// - `SetReadTimeoutError`: Occurs when setting the read timeout fails. -/// - `TlsStreamConnectError`: Represents an error that occurred while establishing a TLS stream connection. -/// - `MaxRedirectTimes`: Occurs when the maximum number of redirects is exceeded. -/// - `RedirectUrlDeadLoop`: Indicates that a redirect URL has resulted in a dead loop. -/// - `RedirectInvalidUrl`: Occurs when a redirect URL is invalid. -#[derive(Debug)] -pub enum Error { - InvalidUrl, - TcpStreamConnectError, - RequestError, - MethodsNotSupport, - ReadConnectionError, - TlsConnectorBuildError, - SetReadTimeoutError, - SetWriteTimeoutError, - TlsStreamConnectError, - MaxRedirectTimes, - RedirectUrlDeadLoop, - RedirectInvalidUrl, -} - -impl StdError for Error {} - -impl fmt::Display for Error { - /// Formats the `Error` enum into a human-readable string. - /// - /// This method implements the `fmt::Display` trait for the `Error` enum, allowing it to be - /// formatted into a string representation. Each variant is matched and a corresponding - /// error message is returned for display. - /// - /// # Parameters - /// - `f`: A mutable reference to the `fmt::Formatter` that handles the formatting of the error. - /// - /// # Returns - /// A `fmt::Result` which indicates whether the formatting was successful. - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Error::InvalidUrl => write!(f, "Invalid URL"), - Error::TcpStreamConnectError => write!(f, "TCP Stream Connection Error"), - Error::RequestError => write!(f, "Request Error"), - Error::MethodsNotSupport => write!(f, "Unsupported HTTP Method"), - Error::ReadConnectionError => write!(f, "Connection Read Error"), - Error::TlsConnectorBuildError => write!(f, "TLS Connector Build Error"), - Error::SetReadTimeoutError => write!(f, "Failed to Set Read Timeout"), - Error::SetWriteTimeoutError => write!(f, "Failed to Set Write Timeout"), - Error::TlsStreamConnectError => write!(f, "TLS Stream Connection Error"), - Error::MaxRedirectTimes => write!(f, "Max Redirect Times"), - Error::RedirectUrlDeadLoop => write!(f, "Redirect URL Dead Loop"), - Error::RedirectInvalidUrl => write!(f, "Redirect Invalid Url"), - } - } -} diff --git a/src/request/error/impl.rs b/src/request/error/impl.rs new file mode 100644 index 0000000..aa2d755 --- /dev/null +++ b/src/request/error/impl.rs @@ -0,0 +1,28 @@ +use std::{ + error::Error as StdError, + fmt::{self, Display}, +}; + +use super::r#type::Error; + +impl StdError for Error {} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::InvalidUrl => write!(f, "Invalid URL"), + Error::TcpStreamConnectError => write!(f, "TCP Stream Connection Error"), + Error::RequestError => write!(f, "Request Error"), + Error::MethodsNotSupport => write!(f, "Unsupported HTTP Method"), + Error::ReadConnectionError => write!(f, "Connection Read Error"), + Error::TlsConnectorBuildError => write!(f, "TLS Connector Build Error"), + Error::SetReadTimeoutError => write!(f, "Failed to Set Read Timeout"), + Error::SetWriteTimeoutError => write!(f, "Failed to Set Write Timeout"), + Error::TlsStreamConnectError => write!(f, "TLS Stream Connection Error"), + Error::MaxRedirectTimes => write!(f, "Max Redirect Times"), + Error::RedirectUrlDeadLoop => write!(f, "Redirect URL Dead Loop"), + Error::RedirectInvalidUrl => write!(f, "Redirect Invalid Url"), + Error::NeedOpenRedirect => write!(f, "Need Open Redirect"), + } + } +} diff --git a/src/request/http_request/mod.rs b/src/request/error/mod.rs similarity index 100% rename from src/request/http_request/mod.rs rename to src/request/error/mod.rs diff --git a/src/request/error/type.rs b/src/request/error/type.rs new file mode 100644 index 0000000..f3523d9 --- /dev/null +++ b/src/request/error/type.rs @@ -0,0 +1,34 @@ +/// Represents different types of errors that can occur in the application. +/// +/// The `Error` enum defines various error types related to HTTP requests, network connections, and TLS operations. +/// Each variant corresponds to a specific error that can occur during the execution of the application. +/// +/// # Variants +/// - `InvalidUrl`: Indicates that the provided URL is invalid. +/// - `TcpStreamConnectError`: Represents an error that occurred while attempting to connect a TCP stream. +/// - `RequestError`: A general error related to making a request. +/// - `MethodsNotSupport`: Indicates that the requested HTTP method is not supported. +/// - `ReadConnectionError`: An error that occurred while reading from the connection. +/// - `TlsConnectorBuildError`: Indicates an error during the construction of the TLS connector. +/// - `SetReadTimeoutError`: Occurs when setting the read timeout fails. +/// - `TlsStreamConnectError`: Represents an error that occurred while establishing a TLS stream connection. +/// - `MaxRedirectTimes`: Occurs when the maximum number of redirects is exceeded. +/// - `RedirectUrlDeadLoop`: Indicates that a redirect URL has resulted in a dead loop. +/// - `RedirectInvalidUrl`: Occurs when a redirect URL is invalid. +/// - `NeedOpenRedirect`: A URL need open redirect +#[derive(Debug)] +pub enum Error { + InvalidUrl, + TcpStreamConnectError, + RequestError, + MethodsNotSupport, + ReadConnectionError, + TlsConnectorBuildError, + SetReadTimeoutError, + SetWriteTimeoutError, + TlsStreamConnectError, + MaxRedirectTimes, + RedirectUrlDeadLoop, + RedirectInvalidUrl, + NeedOpenRedirect, +} diff --git a/src/header/mod.rs b/src/request/header/mod.rs similarity index 100% rename from src/header/mod.rs rename to src/request/header/mod.rs diff --git a/src/header/type.rs b/src/request/header/type.rs similarity index 100% rename from src/header/type.rs rename to src/request/header/type.rs diff --git a/src/request/http_request_builder/type.rs b/src/request/http_request_builder/type.rs deleted file mode 100644 index 8cb56e2..0000000 --- a/src/request/http_request_builder/type.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::request::http_request::r#type::HttpRequest; - -/// Builder pattern for constructing `HttpRequest` instances. -/// -/// The `HttpRequestBuilder` struct facilitates the creation of `HttpRequest` objects -/// through a series of method calls. It allows for flexible and clear configuration of -/// an HTTP request's components such as method, URL, headers, and body. -/// -/// # Fields -/// - `http_request`: A temporary `HttpRequest` instance used to accumulate changes during -/// the construction process. It holds the current state of the builder. -/// - `builder`: A finalized `HttpRequest` instance that holds the result after the -/// builder process has been completed. It is returned when the builder is finalized. -/// -/// # Traits Implemented -/// - `Debug`: Enables the ability to format and print the `HttpRequestBuilder` for debugging purposes. -/// - `Clone`: Allows for cloning of the `HttpRequestBuilder` and its internal components. -/// - `PartialEq`: Provides equality comparison between two `HttpRequestBuilder` instances. -/// -/// This builder simplifies the creation of `HttpRequest` objects, ensuring thread-safety -/// and immutability of shared references, while providing a fluent API for constructing -/// HTTP requests with various configurations. -#[derive(Debug, Clone, PartialEq)] -pub struct HttpRequestBuilder { - pub(crate) http_request: HttpRequest, - pub(crate) builder: HttpRequest, -} diff --git a/src/request/mod.rs b/src/request/mod.rs index 1aa6ee6..55f4752 100644 --- a/src/request/mod.rs +++ b/src/request/mod.rs @@ -1,7 +1,7 @@ -#[cfg(test)] -mod cfg; pub mod config; +pub mod constant; pub mod error; -pub mod http_request; -pub mod http_request_builder; +pub mod header; +pub mod request; +pub mod request_builder; pub mod tmp; diff --git a/src/request/http_request/impl.rs b/src/request/request/impl.rs similarity index 96% rename from src/request/http_request/impl.rs rename to src/request/request/impl.rs index b2f60ad..de1285f 100644 --- a/src/request/http_request/impl.rs +++ b/src/request/request/impl.rs @@ -1,28 +1,29 @@ -use super::r#type::HttpRequest; +use super::r#type::Request; use crate::{ body::r#type::Body, - constant::{ - common::APP_NAME, - http::{ - ACCEPT, ACCEPT_VALUE, CONTENT_TYPE, HTTP_BR, HTTP_BR_BYTES, HTTP_DOUBLE_BR_BYTES, - QUERY_SYMBOL, USER_AGENT, - }, - }, + constant::common::APP_NAME, content_type::r#type::ContentType, http_url::r#type::HttpUrl, methods::r#type::Methods, protocol::r#type::Protocol, - request::{config::r#type::Config, error::Error, tmp::r#type::Tmp}, + request::{ + config::r#type::Config, + constant::{ + ACCEPT, ACCEPT_VALUE, CONTENT_TYPE, HTTP_BR, HTTP_BR_BYTES, HTTP_DOUBLE_BR_BYTES, + QUERY_SYMBOL, USER_AGENT, + }, + error::r#type::Error, + header::r#type::Header, + tmp::r#type::Tmp, + }, response::{ - http_response_binary::r#type::HttpResponseBinary, r#trait::HttpResponse, - r#type::BoxHttpResponse, + r#trait::Response, r#type::BoxHttpResponse, response_binary::r#type::HttpResponseBinary, }, utils::vec::case_insensitive_match, }; use crate::{ - constant::http::{CONTENT_LENGTH, DEFAULT_HTTP_PATH, HOST, LOCATION}, global_trait::r#trait::ReadWrite, - header::r#type::Header, + request::constant::{CONTENT_LENGTH, DEFAULT_HTTP_PATH, HOST, LOCATION}, }; use native_tls::{TlsConnector, TlsStream}; use std::{ @@ -33,13 +34,13 @@ use std::{ time::Duration, }; -/// Implements methods for the `HttpRequest` struct. +/// Implements methods for the `Request` struct. /// /// These methods provide functionality for managing HTTP requests, including: /// - Retrieving or setting HTTP attributes (e.g., URL, headers, protocol). /// - Constructing and sending HTTP GET or POST requests. /// - Parsing responses and handling redirects. -impl HttpRequest { +impl Request { /// Returns the protocol of the HTTP request. fn get_protocol(&self) -> Protocol { self.config.url_obj.protocol.clone() @@ -341,8 +342,11 @@ impl HttpRequest { break 'read_loop; } } - self.response = ::from(&response_bytes); + self.response = ::from(&response_bytes); if !self.config.redirect || redirect_url.is_none() { + if self.config.decode { + self.response = self.response.decode(self.config.buffer); + } return Ok(Box::new(self.response.clone())); } let url: String = @@ -438,11 +442,14 @@ impl HttpRequest { /// /// Returns `Ok(HttpResponseBinary)` if the redirection is successful, or `Err(Error)` otherwise. fn handle_redirect(&mut self, url: String) -> Result { + if !self.config.redirect { + return Err(Error::NeedOpenRedirect); + } if self.tmp.visit_url.contains(&url) { return Err(Error::RedirectUrlDeadLoop); } self.tmp.visit_url.insert(url.clone()); - if self.config.redirect && self.config.redirect_times >= self.config.max_redirect_times { + if self.config.redirect_times >= self.config.max_redirect_times { return Err(Error::MaxRedirectTimes); } self.config.redirect_times = self.config.redirect_times + 1; @@ -545,10 +552,9 @@ impl HttpRequest { } } -/// Default implementation for `HttpRequest`. -impl Default for HttpRequest { - fn default() -> HttpRequest { - HttpRequest { +impl Default for Request { + fn default() -> Self { + Self { methods: Arc::new(Methods::new()), url: Arc::new(String::new()), header: Arc::new(HashMap::new()), diff --git a/src/request/http_request_builder/mod.rs b/src/request/request/mod.rs similarity index 100% rename from src/request/http_request_builder/mod.rs rename to src/request/request/mod.rs diff --git a/src/request/http_request/type.rs b/src/request/request/type.rs similarity index 80% rename from src/request/http_request/type.rs rename to src/request/request/type.rs index 866d9f1..34d42a6 100644 --- a/src/request/http_request/type.rs +++ b/src/request/request/type.rs @@ -1,16 +1,15 @@ use crate::{ body::r#type::Body, - header::r#type::Header, methods::r#type::Methods, - request::{config::r#type::Config, tmp::r#type::Tmp}, - response::http_response_binary::r#type::HttpResponseBinary, + request::{config::r#type::Config, header::r#type::Header, tmp::r#type::Tmp}, + response::response_binary::r#type::HttpResponseBinary, }; use std::sync::Arc; /// Represents an HTTP request, encapsulating various components such as the method, URL, protocol, /// headers, body, and additional metadata. -#[derive(Debug, Clone, PartialEq)] -pub struct HttpRequest { +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Request { /// The HTTP method of the request (e.g., GET, POST, etc.). pub(crate) methods: Arc, diff --git a/src/request/http_request_builder/impl.rs b/src/request/request_builder/impl.rs similarity index 75% rename from src/request/http_request_builder/impl.rs rename to src/request/request_builder/impl.rs index a266ef8..d1f3e77 100644 --- a/src/request/http_request_builder/impl.rs +++ b/src/request/request_builder/impl.rs @@ -1,56 +1,32 @@ use std::sync::Arc; -use super::r#type::HttpRequestBuilder; +use super::r#type::RequestBuilder; use crate::{ body::r#type::{Body, BodyBinary, BodyJson, BodyText}, - header::r#type::Header, http_version::r#type::HttpVersion, methods::r#type::Methods, - request::http_request::r#type::HttpRequest, + request::{header::r#type::Header, request::r#type::Request}, }; -/// Provides a builder pattern implementation for constructing `HttpRequest` instances. -/// -/// The `HttpRequestBuilder` struct is used to create and configure `HttpRequest` objects -/// through a series of method calls, enabling a flexible and clear way to construct -/// requests. -/// -/// # Traits Implemented -/// - `Default`: Provides a default instance of the builder, initializing all fields -/// with default values. -/// -/// # Methods -/// - `new`: Creates a new instance of the builder with default values. -/// - `methods`: Sets the HTTP method for the request (e.g., GET, POST). -/// - `url`: Sets the target URL of the request. -/// - `headers`: Updates the headers of the request. Existing headers may be merged with -/// the provided ones. -/// - `body`: Updates the body of the request. Existing body data may be merged with -/// the provided data. -/// - `builder`: Finalizes the configuration and returns a fully constructed `HttpRequest` -/// instance. Resets the builder's temporary state for subsequent use. -/// -/// This builder simplifies the construction of `HttpRequest` objects while maintaining -/// thread safety and ensuring immutability for shared references where applicable. -impl Default for HttpRequestBuilder { - fn default() -> HttpRequestBuilder { - HttpRequestBuilder { - http_request: HttpRequest::default(), - builder: HttpRequest::default(), +impl Default for RequestBuilder { + fn default() -> Self { + Self { + http_request: Request::default(), + builder: Request::default(), } } } -impl HttpRequestBuilder { +impl RequestBuilder { /// Creates a new instance of the builder with default values. /// - /// This method initializes the `HttpRequestBuilder` with default values for all + /// This method initializes the `RequestBuilder` with default values for all /// fields. /// /// # Returns - /// Returns a new instance of `HttpRequestBuilder`. + /// Returns a new instance of `RequestBuilder`. pub fn new() -> Self { - HttpRequestBuilder::default() + Self::default() } /// Sets the HTTP method for the request. @@ -62,7 +38,7 @@ impl HttpRequestBuilder { /// - `methods`: The HTTP method to be set for the request. /// /// # Returns - /// Returns a mutable reference to the `HttpRequestBuilder` to allow method chaining. + /// Returns a mutable reference to the `RequestBuilder` to allow method chaining. pub fn post(&mut self, url: &str) -> &mut Self { self.http_request.methods = Arc::new(Methods::POST); self.url(url); @@ -78,7 +54,7 @@ impl HttpRequestBuilder { /// - `methods`: The HTTP method to be set for the request. /// /// # Returns - /// Returns a mutable reference to the `HttpRequestBuilder` to allow method chaining. + /// Returns a mutable reference to the `RequestBuilder` to allow method chaining. pub fn get(&mut self, url: &str) -> &mut Self { self.http_request.methods = Arc::new(Methods::GET); self.url(url); @@ -93,7 +69,7 @@ impl HttpRequestBuilder { /// - `url`: The target URL of the request. /// /// # Returns - /// Returns a mutable reference to the `HttpRequestBuilder` to allow method chaining. + /// Returns a mutable reference to the `RequestBuilder` to allow method chaining. fn url(&mut self, url: &str) -> &mut Self { self.http_request.url = Arc::new(url.to_owned()); self @@ -136,7 +112,7 @@ impl HttpRequestBuilder { /// - `header`: The headers to be set for the request. /// /// # Returns - /// Returns a mutable reference to the `HttpRequestBuilder` to allow method chaining. + /// Returns a mutable reference to the `RequestBuilder` to allow method chaining. pub fn headers(&mut self, header: Header) -> &mut Self { if let Some(tmp_header) = Arc::get_mut(&mut self.http_request.header) { for (key, value) in header { @@ -155,7 +131,7 @@ impl HttpRequestBuilder { /// - `body`: The JSON body data to be set for the request. /// /// # Returns - /// Returns a mutable reference to the `HttpRequestBuilder` to allow method chaining. + /// Returns a mutable reference to the `RequestBuilder` to allow method chaining. pub fn json(&mut self, body: BodyJson) -> &mut Self { self.http_request.body = Arc::new(Body::Json(body)); self @@ -170,7 +146,7 @@ impl HttpRequestBuilder { /// - `body`: The text body data to be set for the request. /// /// # Returns - /// Returns a mutable reference to the `HttpRequestBuilder` to allow method chaining. + /// Returns a mutable reference to the `RequestBuilder` to allow method chaining. pub fn text(&mut self, body: BodyText) -> &mut Self { self.http_request.body = Arc::new(Body::Text(body)); self @@ -211,7 +187,7 @@ impl HttpRequestBuilder { /// connection timeout. /// /// # Returns - /// Returns a mutable reference to the `HttpRequestBuilder` to allow method chaining. + /// Returns a mutable reference to the `RequestBuilder` to allow method chaining. pub fn timeout(&mut self, timeout: u64) -> &mut Self { self.http_request.config.timeout = timeout; self @@ -273,17 +249,41 @@ impl HttpRequestBuilder { self } - /// Finalizes the builder and returns a fully constructed `HttpRequest` instance. + /// Enables automatic response decoding. + /// + /// When enabled, the response body will be automatically decompressed if it is encoded + /// using a supported compression format (e.g., `gzip`, `deflate`, `br`). + /// + /// # Returns + /// A mutable reference to the current instance, allowing for method chaining. + pub fn decode(&mut self) -> &mut Self { + self.http_request.config.decode = true; + self + } + + /// Disables automatic response decoding. + /// + /// When disabled, the response body will not be automatically decompressed, + /// and the raw encoded data will be returned as-is. + /// + /// # Returns + /// A mutable reference to the current instance, allowing for method chaining. + pub fn undecode(&mut self) -> &mut Self { + self.http_request.config.decode = false; + self + } + + /// Finalizes the builder and returns a fully constructed `Request` instance. /// /// This method takes the current configuration stored in `http_request`, creates a new - /// `HttpRequest` instance with the configuration, and resets the builder's temporary + /// `Request` instance with the configuration, and resets the builder's temporary /// state for further use. /// /// # Returns - /// Returns a fully constructed `HttpRequest` instance based on the current builder state. - pub fn builder(&mut self) -> HttpRequest { + /// Returns a fully constructed `Request` instance based on the current builder state. + pub fn builder(&mut self) -> Request { self.builder = self.http_request.clone(); - self.http_request = HttpRequest::default(); + self.http_request = Request::default(); self.builder.clone() } } diff --git a/src/response/http_response_binary/mod.rs b/src/request/request_builder/mod.rs similarity index 100% rename from src/response/http_response_binary/mod.rs rename to src/request/request_builder/mod.rs diff --git a/src/request/request_builder/type.rs b/src/request/request_builder/type.rs new file mode 100644 index 0000000..58ce92f --- /dev/null +++ b/src/request/request_builder/type.rs @@ -0,0 +1,22 @@ +use crate::request::request::r#type::Request; + +/// Builder pattern for constructing `Request` instances. +/// +/// The `RequestBuilder` struct facilitates the creation of `Request` objects +/// through a series of method calls. It allows for flexible and clear configuration of +/// an HTTP request's components such as method, URL, headers, and body. +/// +/// # Fields +/// - `http_request`: A temporary `Request` instance used to accumulate changes during +/// the construction process. It holds the current state of the builder. +/// - `builder`: A finalized `Request` instance that holds the result after the +/// builder process has been completed. It is returned when the builder is finalized. +/// +/// This builder simplifies the creation of `Request` objects, ensuring thread-safety +/// and immutability of shared references, while providing a fluent API for constructing +/// HTTP requests with various configurations. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct RequestBuilder { + pub(crate) http_request: Request, + pub(crate) builder: Request, +} diff --git a/src/request/tmp/impl.rs b/src/request/tmp/impl.rs index bfde70b..cf11ab3 100644 --- a/src/request/tmp/impl.rs +++ b/src/request/tmp/impl.rs @@ -2,18 +2,8 @@ use super::r#type::Tmp; use std::collections::HashSet; impl Default for Tmp { - /// Provides the default value for `Tmp`. - /// - /// This method initializes a `Tmp` instance with default values. Specifically, it sets - /// `visit_url` to an empty `HashSet`, which is used to store visited URLs. This can be - /// useful for tracking URLs that have already been visited in the context of HTTP requests - /// or other network-related operations. - /// - /// # Returns - /// Returns a `Tmp` instance with a default state, where: - /// - `visit_url` is an empty `HashSet` of URLs. fn default() -> Self { - Tmp { + Self { visit_url: HashSet::new(), } } diff --git a/src/request/tmp/type.rs b/src/request/tmp/type.rs index 25448cf..e498381 100644 --- a/src/request/tmp/type.rs +++ b/src/request/tmp/type.rs @@ -1,17 +1,12 @@ use std::collections::HashSet; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] /// Represents a structure that stores visited URLs. /// /// The `Tmp` struct is used to track the URLs that have been visited. It contains a single field, /// `visit_url`, which is a `HashSet` of strings representing the visited URLs. The use of a `HashSet` /// ensures that each URL is stored only once, even if it is added multiple times. /// -/// The struct derives the following traits: -/// - `Debug`: Allows for formatting the struct for debugging purposes. -/// - `Clone`: Enables creating a copy of `Tmp` instances. -/// - `PartialEq`: Allows for comparing `Tmp` instances for equality. -/// /// # Fields /// - `visit_url`: A `HashSet` that stores the URLs that have been visited. This ensures /// that each URL is unique within the set. diff --git a/src/response/http_response_text/impl.rs b/src/response/http_response_text/impl.rs deleted file mode 100644 index 9452b30..0000000 --- a/src/response/http_response_text/impl.rs +++ /dev/null @@ -1,64 +0,0 @@ -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/mod.rs b/src/response/mod.rs index db5bf49..60ca578 100644 --- a/src/response/mod.rs +++ b/src/response/mod.rs @@ -1,4 +1,5 @@ -pub mod http_response_binary; -pub mod http_response_text; +pub mod response_binary; +pub mod response_header; +pub mod response_text; pub mod r#trait; pub mod r#type; diff --git a/src/response/http_response_binary/impl.rs b/src/response/response_binary/impl.rs similarity index 60% rename from src/response/http_response_binary/impl.rs rename to src/response/response_binary/impl.rs index 40f2870..53f3bac 100644 --- a/src/response/http_response_binary/impl.rs +++ b/src/response/response_binary/impl.rs @@ -1,17 +1,16 @@ use super::r#type::HttpResponseBinary; use crate::{ - constant::{ - common::{BR_BYTES, COLON_SPACE_BYTES}, - http::HTTP_BR_BYTES, - }, + compress::r#type::Compress, + constant::common::{BR_BYTES, COLON_SPACE_BYTES}, http_version::r#type::HttpVersion, - response::{http_response_text::r#type::HttpResponseText, r#trait::HttpResponse}, + request::constant::HTTP_BR_BYTES, + response::{r#trait::Response, response_text::r#type::HttpResponseText}, status_code::r#type::StatusCode, utils::vec::{split_multi_byte, split_whitespace}, }; use std::{collections::HashMap, vec::IntoIter}; -/// Implements the `HttpResponse` trait for `HttpResponseBinary`. +/// Implements the `Response` trait for `HttpResponseBinary`. /// /// This implementation specifies the associated types for binary and text representations /// of HTTP responses, enabling seamless conversion and handling of HTTP response data. @@ -19,25 +18,10 @@ use std::{collections::HashMap, vec::IntoIter}; /// # 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 { +impl Response for HttpResponseBinary { type OutputText = HttpResponseText; type OutputBinary = HttpResponseBinary; - /// Parses a raw HTTP response from a byte slice and constructs an `HttpResponseBinary` instance. - /// - /// 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 - /// - `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 format is malformed and required components - /// such as the status line cannot be parsed. fn from(response: &[u8]) -> Self where Self: Sized, @@ -84,26 +68,10 @@ impl HttpResponse for HttpResponseBinary { } } - /// Returns a clone of the binary representation of the HTTP response. - /// - /// 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. - /// - /// 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(); @@ -115,16 +83,23 @@ impl HttpResponse for HttpResponseBinary { body, } } + + fn decode(&self, buffer_size: usize) -> HttpResponseBinary { + let http_response: HttpResponseBinary = self.clone(); + let body: Vec = Compress::from(&self.headers).decode(&self.body, buffer_size); + HttpResponseBinary { + http_version: http_response.http_version, + status_code: http_response.status_code, + status_text: http_response.status_text, + headers: http_response.headers, + body, + } + } } -/// Default implementation for `HttpResponseBinary`. -/// -/// This implementation provides default values for an `HttpResponseBinary` instance, setting the HTTP -/// version to the default version, the status code to `StatusCode::Unknown`, and initializing the -/// headers and body to empty collections. impl Default for HttpResponseBinary { fn default() -> Self { - HttpResponseBinary { + Self { http_version: HttpVersion::Unknown(String::new()).to_string(), status_code: StatusCode::Unknown.code(), status_text: StatusCode::Unknown.to_string(), diff --git a/src/response/http_response_text/mod.rs b/src/response/response_binary/mod.rs similarity index 100% rename from src/response/http_response_text/mod.rs rename to src/response/response_binary/mod.rs diff --git a/src/response/http_response_binary/type.rs b/src/response/response_binary/type.rs similarity index 97% rename from src/response/http_response_binary/type.rs rename to src/response/response_binary/type.rs index 9045f9b..7857bcc 100644 --- a/src/response/http_response_binary/type.rs +++ b/src/response/response_binary/type.rs @@ -13,7 +13,7 @@ use std::collections::HashMap; /// - `headers`: A `HashMap` containing the headers of the response, where each key is the header name /// (e.g., "Content-Type"), and the value is the corresponding header value. /// - `body`: A `Vec` representing the body of the HTTP response, which contains the content being returned. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct HttpResponseBinary { /// The HTTP version of the response (e.g., "HTTP/1.1"). pub http_version: String, diff --git a/src/response/response_header/mod.rs b/src/response/response_header/mod.rs new file mode 100644 index 0000000..6e146ba --- /dev/null +++ b/src/response/response_header/mod.rs @@ -0,0 +1 @@ +pub mod r#type; diff --git a/src/response/response_header/type.rs b/src/response/response_header/type.rs new file mode 100644 index 0000000..f84e9d2 --- /dev/null +++ b/src/response/response_header/type.rs @@ -0,0 +1,6 @@ +use std::collections::HashMap; + +/// A type alias for a `HashMap`, representing the headers of an HTTP request or response. +/// This structure stores key-value pairs, where each key is the name of an HTTP header (e.g., `Content-Type`, `Host`), +/// and the value is the corresponding header value (e.g., `application/json`, `example.com`). +pub type Header = HashMap; diff --git a/src/response/response_text/impl.rs b/src/response/response_text/impl.rs new file mode 100644 index 0000000..05d67c4 --- /dev/null +++ b/src/response/response_text/impl.rs @@ -0,0 +1,69 @@ +use std::collections::HashMap; + +use super::r#type::HttpResponseText; +use crate::{ + compress::r#type::Compress, + http_version::r#type::HttpVersion, + response::{r#trait::Response, response_binary::r#type::HttpResponseBinary}, + status_code::r#type::StatusCode, +}; + +/// Implements the `Response` 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 Response for HttpResponseText { + type OutputText = HttpResponseText; + type OutputBinary = HttpResponseBinary; + + fn from(response: &[u8]) -> Self::OutputText + where + Self: Sized, + { + ::from(response).text() + } + + fn text(&self) -> Self::OutputText { + self.clone() + } + + 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(), + } + } + + fn decode(&self, buffer_size: usize) -> HttpResponseBinary { + let http_response: HttpResponseText = self.clone(); + let tmp_body: Vec = self.body.as_bytes().to_vec(); + let body: Vec = Compress::from(&self.headers).decode(&tmp_body, buffer_size); + HttpResponseBinary { + http_version: http_response.http_version, + status_code: http_response.status_code, + status_text: http_response.status_text, + headers: http_response.headers, + body, + } + } +} + +impl Default for HttpResponseText { + fn default() -> Self { + Self { + http_version: HttpVersion::Unknown(String::new()).to_string(), + status_code: StatusCode::Unknown.code(), + status_text: StatusCode::Unknown.to_string(), + headers: HashMap::new(), + body: String::new(), + } + } +} diff --git a/src/response/response_text/mod.rs b/src/response/response_text/mod.rs new file mode 100644 index 0000000..6297e83 --- /dev/null +++ b/src/response/response_text/mod.rs @@ -0,0 +1,2 @@ +pub mod r#impl; +pub mod r#type; diff --git a/src/response/http_response_text/type.rs b/src/response/response_text/type.rs similarity index 97% rename from src/response/http_response_text/type.rs rename to src/response/response_text/type.rs index fe99282..e636397 100644 --- a/src/response/http_response_text/type.rs +++ b/src/response/response_text/type.rs @@ -13,7 +13,7 @@ use std::collections::HashMap; /// - `headers`: A `HashMap` containing the headers of the response, where each key is the header name /// (e.g., "Content-Type"), and the value is the corresponding header value. /// - `body`: A `Vec` representing the body of the HTTP response, which contains the content being returned. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct HttpResponseText { /// The HTTP version of the response (e.g., "HTTP/1.1"). pub http_version: String, diff --git a/src/response/trait.rs b/src/response/trait.rs index ba694d6..45eef97 100644 --- a/src/response/trait.rs +++ b/src/response/trait.rs @@ -9,7 +9,7 @@ /// # Associated Types /// - `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 { +pub trait Response { type OutputText; type OutputBinary; @@ -42,4 +42,16 @@ pub trait HttpResponse { fn from(response: &[u8]) -> Self where Self: Sized; + + /// Decodes the data using a specified buffer size. + /// + /// This method takes a buffer size as input and performs the decoding process. + /// It returns the decoded output in the form of `Self::OutputBinary`. + /// + /// # Parameters + /// - `buffer_size`: The buffer size to be used during decoding. + /// + /// # Returns + /// Returns the decoded data as `Self::OutputBinary`. The exact type of `OutputBinary` depends on the implementation of the `Self` type. + fn decode(&self, buffer_size: usize) -> Self::OutputBinary; } diff --git a/src/response/type.rs b/src/response/type.rs index 3cdae23..f9dd1c2 100644 --- a/src/response/type.rs +++ b/src/response/type.rs @@ -1,13 +1,11 @@ -use super::{ - http_response_binary::r#type::HttpResponseBinary, http_response_text::r#type::HttpResponseText, -}; -use crate::HttpResponse; +use super::{response_binary::r#type::HttpResponseBinary, response_text::r#type::HttpResponseText}; +use crate::Response; -/// A type alias for a boxed dynamic trait object implementing the `HttpResponse` trait. +/// A type alias for a boxed dynamic trait object implementing the `Response` trait. /// /// This alias defines a `Response` as a `Box` containing any type that implements the -/// `HttpResponse` trait, with associated types `OutputText` set to `HttpResponseText` +/// `Response` 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>; + Box>; diff --git a/src/status_code/impl.rs b/src/status_code/impl.rs index f0e91ba..5500d0a 100644 --- a/src/status_code/impl.rs +++ b/src/status_code/impl.rs @@ -28,62 +28,53 @@ impl StatusCode { /// /// This method returns the corresponding HTTP numeric status code based on the `StatusCode` variant. /// For example: - /// - `StatusCode::Ok` returns 200. - /// - `StatusCode::BadRequest` returns 400. - /// - `StatusCode::Unknown` returns 0 (the default for unrecognized status codes). + /// - `Self::Ok` returns 200. + /// - `Self::BadRequest` returns 400. + /// - `Self::Unknown` returns 0 (the default for unrecognized status codes). /// /// # Parameters /// - `&self`: A reference to the `StatusCode` enum instance. This represents the specific variant of the `StatusCode` enum that the method is called on. /// /// # Return Value /// - `u16`: The numeric HTTP status code associated with the `StatusCode` variant. For example: - /// - `StatusCode::Ok` returns `200`. - /// - `StatusCode::BadRequest` returns `400`. - /// - `StatusCode::Unknown` returns `0`. + /// - `Self::Ok` returns `200`. + /// - `Self::BadRequest` returns `400`. + /// - `Self::Unknown` returns `0`. pub fn code(&self) -> u16 { match self { - StatusCode::Ok => 200, - StatusCode::Created => 201, - StatusCode::NoContent => 204, - StatusCode::BadRequest => 400, - StatusCode::Unauthorized => 401, - StatusCode::Forbidden => 403, - StatusCode::NotFound => 404, - StatusCode::InternalServerError => 500, - StatusCode::NotImplemented => 501, - StatusCode::BadGateway => 502, - StatusCode::Unknown => 0, + Self::Ok => 200, + Self::Created => 201, + Self::NoContent => 204, + Self::BadRequest => 400, + Self::Unauthorized => 401, + Self::Forbidden => 403, + Self::NotFound => 404, + Self::InternalServerError => 500, + Self::NotImplemented => 501, + Self::BadGateway => 502, + Self::Unknown => 0, } } + + pub fn same(&self, code_str: &str) -> bool { + self.code().to_string() == code_str || self.to_string() == code_str + } } impl Display for StatusCode { - /// Formats the `StatusCode` as a human-readable string, such as "OK" or "Not Found". - /// - /// This method formats the `StatusCode` variant into a string that can be easily displayed. - /// For example: - /// - `StatusCode::Ok` formats to `"OK"`. - /// - `StatusCode::BadRequest` formats to `"Bad Request"`. - /// - /// # Parameters - /// - `&self`: A reference to the `StatusCode` enum instance, representing the specific status code variant. - /// - `f`: A mutable reference to the `fmt::Formatter` that is responsible for formatting the output. - /// - /// # Return Value - /// - `fmt::Result`: A result that indicates whether the formatting was successful. The result is `Ok(())` if the formatting was successful, or an error if it failed. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let res: &str = match self { - StatusCode::Ok => "OK", - StatusCode::Created => "Created", - StatusCode::NoContent => "No Content", - StatusCode::BadRequest => "Bad Request", - StatusCode::Unauthorized => "Unauthorized", - StatusCode::Forbidden => "Forbidden", - StatusCode::NotFound => "Not Found", - StatusCode::InternalServerError => "Internal Server Error", - StatusCode::NotImplemented => "Not Implemented", - StatusCode::BadGateway => "Bad Gateway", - StatusCode::Unknown => "Unknown", + Self::Ok => "OK", + Self::Created => "Created", + Self::NoContent => "No Content", + Self::BadRequest => "Bad Request", + Self::Unauthorized => "Unauthorized", + Self::Forbidden => "Forbidden", + Self::NotFound => "Not Found", + Self::InternalServerError => "Internal Server Error", + Self::NotImplemented => "Not Implemented", + Self::BadGateway => "Bad Gateway", + Self::Unknown => "Unknown", }; write!(f, "{}", res) } @@ -92,50 +83,25 @@ impl Display for StatusCode { impl FromStr for StatusCode { type Err = (); - /// Converts a string representation of an HTTP status code (either numeric or textual) - /// into the corresponding `StatusCode` enum variant. - /// - /// This method allows parsing of both numeric status codes (e.g., "200", "404") and their - /// corresponding textual representations (e.g., "OK", "Not Found") into the `StatusCode` enum. - /// - /// # Parameters - /// - `code_str`: A string slice (`&str`) representing the status code. This can be either numeric (e.g., "200") or textual (e.g., "OK"). - /// - /// # Return Value - /// - `Result`: Returns a `Result`: - /// - `Ok(StatusCode::Ok)` for "200" or "OK". - /// - `Ok(StatusCode::BadRequest)` for "400" or "Bad Request". - /// - `Ok(StatusCode::NotFound)` for "404" or "Not Found". - /// - `Ok(StatusCode::Unknown)` if the string is not a recognized status code. fn from_str(code_str: &str) -> Result { match code_str { - "200" | "OK" => Ok(StatusCode::Ok), - "201" | "Created" => Ok(StatusCode::Created), - "204" | "No Content" => Ok(StatusCode::NoContent), - "400" | "Bad Request" => Ok(StatusCode::BadRequest), - "401" | "Unauthorized" => Ok(StatusCode::Unauthorized), - "403" | "Forbidden" => Ok(StatusCode::Forbidden), - "404" | "Not Found" => Ok(StatusCode::NotFound), - "500" | "Internal Server Error" => Ok(StatusCode::InternalServerError), - "501" | "Not Implemented" => Ok(StatusCode::NotImplemented), - "502" | "Bad Gateway" => Ok(StatusCode::BadGateway), - _ => Ok(StatusCode::Unknown), + _code_str if Self::Ok.same(_code_str) => Ok(Self::Ok), + _code_str if Self::Created.same(_code_str) => Ok(Self::Created), + _code_str if Self::NoContent.same(_code_str) => Ok(Self::NoContent), + _code_str if Self::BadRequest.same(_code_str) => Ok(Self::BadRequest), + _code_str if Self::Unauthorized.same(_code_str) => Ok(Self::Unauthorized), + _code_str if Self::Forbidden.same(_code_str) => Ok(Self::Forbidden), + _code_str if Self::NotFound.same(_code_str) => Ok(Self::NotFound), + _code_str if Self::InternalServerError.same(_code_str) => Ok(Self::InternalServerError), + _code_str if Self::NotImplemented.same(_code_str) => Ok(Self::NotImplemented), + _code_str if Self::BadGateway.same(_code_str) => Ok(Self::BadGateway), + _ => Ok(Self::Unknown), } } } impl Default for StatusCode { - /// Returns the default status code, which is `StatusCode::Ok` (HTTP 200). - /// - /// This method provides a default status code, typically used when no specific status code is set. - /// It returns `StatusCode::Ok`, which corresponds to HTTP status code 200 (OK). - /// - /// # Parameters - /// - None - /// - /// # Return Value - /// - `StatusCode::Ok`: The default HTTP status code, which is 200 (OK). fn default() -> Self { - StatusCode::Ok + Self::Ok } }