http_kit/
request.rs

1//! HTTP request implementation.
2//!
3//! This module provides the [`Request`] type representing an HTTP request with methods to:
4//!
5//! - Create requests for different HTTP methods (GET, POST, PUT, DELETE)
6//! - Manipulate request headers and body
7//! - Access and modify extensions for storing custom data
8//! - Perform conversions between body formats (JSON, form-data, files)
9//! - Handle request metadata like URI, method, version, and headers
10//!
11//! The module integrates with common serialization formats and provides convenience
12//! methods for handling request data in various formats while maintaining type safety.
13//!
14//! # Features
15//!
16//! The following feature gates are available:
17//!
18//! - `json` - Enables JSON serialization/deserialization support via serde_json
19//! - `form` - Enables form data handling via serde_urlencoded
20//! - `fs` - Enables file upload support with MIME type detection
21//! - `mime` - Enables MIME type parsing and manipulation
22//!
23//! # Examples
24//!
25//! ## Creating Basic Requests
26//!
27//! ```rust
28//! use http_kit::Request;
29//!
30//! // GET request
31//! let get_req = Request::get("https://api.example.com/users");
32//!
33//! // POST request with headers
34//! let post_req = Request::post("https://api.example.com/users")
35//!     .header(http::header::CONTENT_TYPE, "application/json")
36//!     .header(http::header::USER_AGENT, "http-kit/1.0");
37//! ```
38//!
39//! ## Working with Request Bodies
40//!
41//! ```rust
42//! # #[cfg(feature = "json")]
43//! # {
44//! use http_kit::Request;
45//! use serde::Serialize;
46//!
47//! #[derive(Serialize)]
48//! struct User { name: String, email: String }
49//!
50//! let user = User {
51//!     name: "Alice".to_string(),
52//!     email: "alice@example.com".to_string(),
53//! };
54//!
55//! let request = Request::post("https://api.example.com/users")
56//!     .json(&user)?;
57//! # }
58//! # Ok::<(), serde_json::Error>(())
59//! ```
60//!
61use crate::{body::BodyFrozen, Body, BodyError};
62use bytes::Bytes;
63use bytestr::ByteStr;
64use core::fmt::Debug;
65use http::{
66    header::{GetAll, HeaderName},
67    Extensions, HeaderMap, HeaderValue, Method, Uri, Version,
68};
69
70type RequestParts = http::request::Parts;
71
72/// An HTTP request with headers, body, and metadata.
73///
74/// `Request` represents an HTTP request that can be constructed, modified, and processed.
75/// It provides methods for working with all aspects of HTTP requests including:
76///
77/// - **HTTP method** (GET, POST, PUT, DELETE, etc.)
78/// - **URI/URL** for the request target
79/// - **Headers** for metadata like content type, authorization, etc.
80/// - **Body** for request payload data
81/// - **Extensions** for storing custom application data
82/// - **HTTP version** information
83///
84/// The request type integrates with the body system to provide convenient methods
85/// for handling different content types like JSON, form data, and files.
86///
87/// # Examples
88///
89/// ## Basic Request Creation
90///
91/// ```rust
92/// use http_kit::Request;
93/// use http::{Method, Uri};
94///
95/// // Using convenience methods
96/// let get_req = Request::get("/api/users");
97/// let post_req = Request::post("/api/users");
98///
99/// // Using the general constructor
100/// let put_req = Request::new(Method::PUT, "/api/users/123");
101/// ```
102///
103/// ## Working with Headers
104///
105/// ```rust
106/// use http_kit::Request;
107///
108/// let mut request = Request::get("/api/data")
109///     .header(http::header::ACCEPT, "application/json")
110///     .header(http::header::USER_AGENT, "MyApp/1.0");
111///
112/// // Access headers
113/// if let Some(accept) = request.get_header(http::header::ACCEPT) {
114///     println!("Accept header: {:?}", accept);
115/// }
116/// ```
117///
118/// ## Request Body Handling
119///
120/// ```rust
121/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
122/// use http_kit::Request;
123///
124/// let mut request = Request::post("/api/echo");
125/// request.replace_body("Hello, server!");
126///
127/// // Take body for processing
128/// let body = request.take_body()?;
129/// let data = body.into_bytes().await?;
130/// # Ok(())
131/// # }
132/// ```
133#[derive(Debug)]
134pub struct Request {
135    parts: RequestParts,
136    body: Body,
137}
138
139impl From<http::Request<Body>> for Request {
140    fn from(request: http::Request<Body>) -> Self {
141        let (parts, body) = request.into_parts();
142        Self { parts, body }
143    }
144}
145
146impl From<Request> for http::Request<Body> {
147    fn from(request: Request) -> Self {
148        Self::from_parts(request.parts, request.body)
149    }
150}
151
152impl Request {
153    /// Creates a new HTTP request with the specified method and URI.
154    ///
155    /// This is the general-purpose constructor for creating requests. For common
156    /// HTTP methods, consider using the convenience methods like [`Request::get`],
157    /// [`Request::post`], etc.
158    ///
159    /// # Arguments
160    ///
161    /// * `method` - The HTTP method (GET, POST, PUT, DELETE, etc.)
162    /// * `uri` - The request URI/URL
163    ///
164    /// # Panics
165    ///
166    /// Panics if the URI cannot be parsed into a valid `Uri`.
167    ///
168    /// # Examples
169    ///
170    /// ```rust
171    /// use http_kit::Request;
172    /// use http::Method;
173    ///
174    /// let request = Request::new(Method::PATCH, "/api/users/123");
175    /// assert_eq!(request.method(), &Method::PATCH);
176    /// ```
177    pub fn new<U>(method: Method, uri: U) -> Self
178    where
179        U: TryInto<Uri>,
180        U::Error: Debug,
181    {
182        http::Request::builder()
183            .method(method)
184            .uri(uri.try_into().unwrap())
185            .body(Body::empty())
186            .unwrap()
187            .into()
188    }
189
190    /// Creates a new GET request with the specified URI.
191    ///
192    /// This is a convenience method for creating GET requests, which are commonly
193    /// used for retrieving data from servers.
194    ///
195    /// # Arguments
196    ///
197    /// * `uri` - The request URI/URL
198    ///
199    /// # Examples
200    ///
201    /// ```rust
202    /// use http_kit::Request;
203    ///
204    /// let request = Request::get("/api/users");
205    /// assert_eq!(request.method(), &http::Method::GET);
206    /// assert_eq!(request.uri().path(), "/api/users");
207    /// ```
208    pub fn get<U>(uri: U) -> Self
209    where
210        U: TryInto<Uri>,
211        U::Error: Debug,
212    {
213        Self::new(Method::GET, uri)
214    }
215
216    /// Creates a new POST request with the specified URI.
217    ///
218    /// This is a convenience method for creating POST requests, which are commonly
219    /// used for submitting data to servers, creating resources, or triggering actions.
220    ///
221    /// # Arguments
222    ///
223    /// * `uri` - The request URI/URL
224    ///
225    /// # Examples
226    ///
227    /// ```rust
228    /// use http_kit::Request;
229    ///
230    /// let request = Request::post("/api/users");
231    /// assert_eq!(request.method(), &http::Method::POST);
232    /// ```
233    pub fn post<U>(uri: U) -> Self
234    where
235        U: TryInto<Uri>,
236        U::Error: Debug,
237    {
238        Self::new(Method::POST, uri)
239    }
240
241    /// Creates a new PUT request with the specified URI.
242    ///
243    /// This is a convenience method for creating PUT requests, which are commonly
244    /// used for updating or replacing resources on the server.
245    ///
246    /// # Arguments
247    ///
248    /// * `uri` - The request URI/URL
249    ///
250    /// # Examples
251    ///
252    /// ```rust
253    /// use http_kit::Request;
254    ///
255    /// let request = Request::put("/api/users/123");
256    /// assert_eq!(request.method(), &http::Method::PUT);
257    /// ```
258    pub fn put<U>(uri: U) -> Self
259    where
260        U: TryInto<Uri>,
261        U::Error: Debug,
262    {
263        Self::new(Method::PUT, uri)
264    }
265
266    /// Creates a new DELETE request with the specified URI.
267    ///
268    /// This is a convenience method for creating DELETE requests, which are commonly
269    /// used for removing resources from the server.
270    ///
271    /// # Arguments
272    ///
273    /// * `uri` - The request URI/URL
274    ///
275    /// # Examples
276    ///
277    /// ```rust
278    /// use http_kit::Request;
279    ///
280    /// let request = Request::delete("/api/users/123");
281    /// assert_eq!(request.method(), &http::Method::DELETE);
282    /// ```
283    pub fn delete<U>(uri: U) -> Self
284    where
285        U: TryInto<Uri>,
286        U::Error: Debug,
287    {
288        Self::new(Method::DELETE, uri)
289    }
290    /// Returns a reference to the request parts.
291    ///
292    /// The request parts contain all the HTTP metadata including method, URI,
293    /// version, headers, and extensions, but not the body.
294    ///
295    /// # Examples
296    ///
297    /// ```rust
298    /// use http_kit::Request;
299    ///
300    /// let request = Request::get("/api/users");
301    /// let parts = request.parts();
302    /// println!("Method: {}, URI: {}", parts.method, parts.uri);
303    /// ```
304    pub const fn parts(&self) -> &RequestParts {
305        &self.parts
306    }
307
308    /// Returns a mutable reference to the request parts.
309    ///
310    /// This allows modification of the HTTP metadata including method, URI,
311    /// version, headers, and extensions.
312    ///
313    /// # Examples
314    ///
315    /// ```rust
316    /// use http_kit::Request;
317    /// use http::Method;
318    ///
319    /// let mut request = Request::get("/api/users");
320    /// request.parts_mut().method = Method::POST;
321    /// assert_eq!(request.method(), &Method::POST);
322    /// ```
323    pub fn parts_mut(&mut self) -> &mut RequestParts {
324        &mut self.parts
325    }
326
327    /// Returns a reference to the HTTP method.
328    ///
329    /// # Examples
330    ///
331    /// ```rust
332    /// use http_kit::Request;
333    /// use http::Method;
334    ///
335    /// let request = Request::post("/api/data");
336    /// assert_eq!(request.method(), &Method::POST);
337    /// ```
338    pub const fn method(&self) -> &Method {
339        &self.parts.method
340    }
341
342    /// Returns a mutable reference to the HTTP method.
343    ///
344    /// # Examples
345    ///
346    /// ```rust
347    /// use http_kit::Request;
348    /// use http::Method;
349    ///
350    /// let mut request = Request::get("/api/users");
351    /// *request.method_mut() = Method::POST;
352    /// assert_eq!(request.method(), &Method::POST);
353    /// ```
354    pub fn method_mut(&mut self) -> &mut Method {
355        &mut self.parts.method
356    }
357
358    /// Sets the HTTP method for this request.
359    ///
360    /// # Arguments
361    ///
362    /// * `method` - The new HTTP method
363    ///
364    /// # Examples
365    ///
366    /// ```rust
367    /// use http_kit::Request;
368    /// use http::Method;
369    ///
370    /// let mut request = Request::get("/api/users");
371    /// request.set_method(Method::PUT);
372    /// assert_eq!(request.method(), &Method::PUT);
373    /// ```
374    pub fn set_method(&mut self, method: Method) {
375        *self.method_mut() = method;
376    }
377
378    /// Returns a reference to the request URI.
379    ///
380    /// # Examples
381    ///
382    /// ```rust
383    /// use http_kit::Request;
384    ///
385    /// let request = Request::get("/api/users?page=1");
386    /// assert_eq!(request.uri().path(), "/api/users");
387    /// assert_eq!(request.uri().query(), Some("page=1"));
388    /// ```
389    pub const fn uri(&self) -> &Uri {
390        &self.parts.uri
391    }
392
393    /// Returns a mutable reference to the request URI.
394    ///
395    /// # Examples
396    ///
397    /// ```rust
398    /// use http_kit::Request;
399    ///
400    /// let mut request = Request::get("/api/users");
401    /// *request.uri_mut() = "/api/posts".parse().unwrap();
402    /// assert_eq!(request.uri().path(), "/api/posts");
403    /// ```
404    pub fn uri_mut(&mut self) -> &mut Uri {
405        &mut self.parts.uri
406    }
407
408    /// Sets the request URI.
409    ///
410    /// # Arguments
411    ///
412    /// * `uri` - The new URI for the request
413    ///
414    /// # Examples
415    ///
416    /// ```rust
417    /// use http_kit::Request;
418    ///
419    /// let mut request = Request::get("/api/users");
420    /// request.set_uri("/api/posts".parse().unwrap());
421    /// assert_eq!(request.uri().path(), "/api/posts");
422    /// ```
423    pub fn set_uri(&mut self, uri: Uri) {
424        *self.uri_mut() = uri;
425    }
426    /// Returns the HTTP version for this request.
427    ///
428    /// # Examples
429    ///
430    /// ```rust
431    /// use http_kit::Request;
432    /// use http::Version;
433    ///
434    /// let request = Request::get("/api/users");
435    /// // Default version is typically HTTP/1.1
436    /// assert_eq!(request.version(), Version::HTTP_11);
437    /// ```
438    pub const fn version(&self) -> Version {
439        self.parts.version
440    }
441
442    /// Returns a mutable reference to the HTTP version.
443    ///
444    /// # Examples
445    ///
446    /// ```rust
447    /// use http_kit::Request;
448    /// use http::Version;
449    ///
450    /// let mut request = Request::get("/api/users");
451    /// *request.version_mut() = Version::HTTP_2;
452    /// assert_eq!(request.version(), Version::HTTP_2);
453    /// ```
454    pub fn version_mut(&mut self) -> &mut Version {
455        &mut self.parts.version
456    }
457    /// Sets the HTTP version for this request.
458    ///
459    /// # Arguments
460    ///
461    /// * `version` - The HTTP version to use
462    ///
463    /// # Examples
464    ///
465    /// ```rust
466    /// use http_kit::Request;
467    /// use http::Version;
468    ///
469    /// let mut request = Request::get("/api/users");
470    /// request.set_version(Version::HTTP_2);
471    /// assert_eq!(request.version(), Version::HTTP_2);
472    /// ```
473    pub fn set_version(&mut self, version: Version) {
474        *self.version_mut() = version;
475    }
476
477    /// Sets an HTTP header and returns the modified request.
478    ///
479    /// This is a builder-style method that allows method chaining. If you need to
480    /// modify an existing request, use [`insert_header`] instead.
481    ///
482    /// # Arguments
483    ///
484    /// * `name` - The header name
485    /// * `value` - The header value
486    ///
487    /// # Examples
488    ///
489    /// ```rust
490    /// use http_kit::Request;
491    ///
492    /// let request = Request::get("/api/users")
493    ///     .header(http::header::ACCEPT, "application/json")
494    ///     .header(http::header::USER_AGENT, "MyApp/1.0");
495    /// ```
496    ///
497    /// [`insert_header`]: Request::insert_header
498    pub fn header<V>(mut self, name: HeaderName, value: V) -> Self
499    where
500        V: TryInto<HeaderValue>,
501        V::Error: Debug,
502    {
503        self.insert_header(name, value.try_into().unwrap());
504        self
505    }
506
507    /// Returns a reference to the HTTP headers.
508    ///
509    /// # Examples
510    ///
511    /// ```rust
512    /// use http_kit::Request;
513    ///
514    /// let request = Request::get("/api/users")
515    ///     .header(http::header::ACCEPT, "application/json");
516    ///
517    /// let headers = request.headers();
518    /// assert!(headers.contains_key(http::header::ACCEPT));
519    /// ```
520    pub const fn headers(&self) -> &HeaderMap {
521        &self.parts.headers
522    }
523
524    /// Returns a mutable reference to the HTTP headers.
525    ///
526    /// This allows direct manipulation of the header map.
527    ///
528    /// # Examples
529    ///
530    /// ```rust
531    /// use http_kit::Request;
532    ///
533    /// let mut request = Request::get("/api/users");
534    /// request.headers_mut().insert(
535    ///     http::header::ACCEPT,
536    ///     "application/json".parse().unwrap()
537    /// );
538    /// ```
539    pub fn headers_mut(&mut self) -> &mut HeaderMap {
540        &mut self.parts.headers
541    }
542
543    /// Returns the first value for the given header name.
544    ///
545    /// If the header has multiple values, only the first one is returned.
546    /// Returns `None` if the header is not present.
547    ///
548    /// # Arguments
549    ///
550    /// * `name` - The header name to look up
551    ///
552    /// # Examples
553    ///
554    /// ```rust
555    /// use http_kit::Request;
556    ///
557    /// let request = Request::get("/api/users")
558    ///     .header(http::header::ACCEPT, "application/json");
559    ///
560    /// if let Some(accept) = request.get_header(http::header::ACCEPT) {
561    ///     assert_eq!(accept, "application/json");
562    /// }
563    /// ```
564    pub fn get_header(&self, name: HeaderName) -> Option<&HeaderValue> {
565        self.headers().get(name)
566    }
567
568    /// Returns an iterator over all values for a header name.
569    ///
570    /// This method retrieves all values for a specific header, unlike [`get_header`]
571    /// which only returns the first value. This is useful for headers that can
572    /// have multiple values like `Accept` or `Set-Cookie`.
573    ///
574    /// # Arguments
575    ///
576    /// * `name` - The header name to get values for
577    ///
578    /// # Examples
579    ///
580    /// ```rust
581    /// use http_kit::Request;
582    ///
583    /// let mut request = Request::get("/api/users");
584    /// request.append_header(http::header::ACCEPT, "text/html".parse().unwrap());
585    /// request.append_header(http::header::ACCEPT, "application/json".parse().unwrap());
586    ///
587    /// // Iterate over all Accept header values
588    /// for accept in request.get_headers(http::header::ACCEPT) {
589    ///     println!("Accept: {}", accept.to_str().unwrap());
590    /// }
591    /// ```
592    ///
593    /// [`get_header`]: Request::get_header
594    pub fn get_headers(&self, name: HeaderName) -> GetAll<'_, HeaderValue> {
595        self.headers().get_all(name)
596    }
597
598    /// Appends a header value without removing existing values.
599    ///
600    /// If a header with the same name already exists, the new value is added
601    /// alongside the existing values rather than replacing them.
602    ///
603    /// # Arguments
604    ///
605    /// * `name` - The header name
606    /// * `value` - The header value to append
607    ///
608    /// # Examples
609    ///
610    /// ```rust
611    /// use http_kit::Request;
612    ///
613    /// let mut request = Request::get("/api/users");
614    /// request.append_header(http::header::ACCEPT, "application/json".parse().unwrap());
615    /// request.append_header(http::header::ACCEPT, "text/html".parse().unwrap());
616    /// // Now the Accept header has both values
617    /// ```
618    pub fn append_header(&mut self, name: HeaderName, value: HeaderValue) {
619        self.headers_mut().append(name, value);
620    }
621
622    /// Inserts a header value, replacing any existing values.
623    ///
624    /// If a header with the same name already exists, it is completely replaced
625    /// with the new value.
626    ///
627    /// # Arguments
628    ///
629    /// * `name` - The header name
630    /// * `value` - The header value
631    ///
632    /// # Returns
633    ///
634    /// Returns the previous header value if one existed.
635    ///
636    /// # Examples
637    ///
638    /// ```rust
639    /// use http_kit::Request;
640    ///
641    /// let mut request = Request::get("/api/users");
642    /// let old_value = request.insert_header(
643    ///     http::header::USER_AGENT,
644    ///     "MyApp/1.0".parse().unwrap()
645    /// );
646    /// assert!(old_value.is_none());
647    ///
648    /// let old_value = request.insert_header(
649    ///     http::header::USER_AGENT,
650    ///     "MyApp/2.0".parse().unwrap()
651    /// );
652    /// assert!(old_value.is_some());
653    /// ```
654    pub fn insert_header(&mut self, name: HeaderName, value: HeaderValue) -> Option<HeaderValue> {
655        self.headers_mut().insert(name, value)
656    }
657
658    /// Returns a reference to the request extensions.
659    ///
660    /// Extensions provide a type-safe way to store additional data associated
661    /// with the request that doesn't fit into standard HTTP fields.
662    ///
663    /// # Examples
664    ///
665    /// ```rust
666    /// use http_kit::Request;
667    ///
668    /// let request = Request::get("/api/users");
669    /// let extensions = request.extensions();
670    /// // Check if a specific type is stored
671    /// let user_id: Option<&u32> = extensions.get();
672    /// ```
673    pub const fn extensions(&self) -> &Extensions {
674        &self.parts.extensions
675    }
676
677    /// Returns a mutable reference to the request extensions.
678    ///
679    /// This allows modification of the extensions map.
680    ///
681    /// # Examples
682    ///
683    /// ```rust
684    /// use http_kit::Request;
685    ///
686    /// let mut request = Request::get("/api/users");
687    /// request.extensions_mut().insert(42u32);
688    /// ```
689    pub fn extensions_mut(&mut self) -> &mut Extensions {
690        &mut self.parts.extensions
691    }
692
693    /// Returns a reference to an extension of the specified type.
694    ///
695    /// # Type Parameters
696    ///
697    /// * `T` - The type to retrieve from extensions
698    ///
699    /// # Examples
700    ///
701    /// ```rust
702    /// use http_kit::Request;
703    ///
704    /// let mut request = Request::get("/api/users");
705    /// request.insert_extension(42u32);
706    ///
707    /// if let Some(value) = request.get_extension::<u32>() {
708    ///     assert_eq!(*value, 42);
709    /// }
710    /// ```
711    pub fn get_extension<T: Send + Sync + 'static>(&self) -> Option<&T> {
712        self.extensions().get()
713    }
714
715    /// Returns a mutable reference to an extension of the specified type.
716    ///
717    /// # Type Parameters
718    ///
719    /// * `T` - The type to retrieve from extensions
720    ///
721    /// # Examples
722    ///
723    /// ```rust
724    /// use http_kit::Request;
725    ///
726    /// let mut request = Request::get("/api/users");
727    /// request.insert_extension(42u32);
728    ///
729    /// if let Some(value) = request.get_mut_extension::<u32>() {
730    ///     *value = 100;
731    /// }
732    /// ```
733    pub fn get_mut_extension<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
734        self.extensions_mut().get_mut()
735    }
736
737    /// Removes and returns an extension of the specified type.
738    ///
739    /// # Type Parameters
740    ///
741    /// * `T` - The type to remove from extensions
742    ///
743    /// # Returns
744    ///
745    /// Returns the removed value if it existed, or `None` if it wasn't present.
746    ///
747    /// # Examples
748    ///
749    /// ```rust
750    /// use http_kit::Request;
751    ///
752    /// let mut request = Request::get("/api/users");
753    /// request.insert_extension(42u32);
754    ///
755    /// let removed = request.remove_extension::<u32>();
756    /// assert_eq!(removed, Some(42));
757    ///
758    /// let removed_again = request.remove_extension::<u32>();
759    /// assert_eq!(removed_again, None);
760    /// ```
761    pub fn remove_extension<T: Send + Sync + 'static>(&mut self) -> Option<T> {
762        self.extensions_mut().remove()
763    }
764
765    /// Inserts an extension value, returning any previous value of the same type.
766    ///
767    /// # Type Parameters
768    ///
769    /// * `T` - The type to insert into extensions
770    ///
771    /// # Arguments
772    ///
773    /// * `extension` - The value to insert
774    ///
775    /// # Returns
776    ///
777    /// Returns the previous value of the same type if one existed.
778    ///
779    /// # Examples
780    ///
781    /// ```rust
782    /// use http_kit::Request;
783    ///
784    /// let mut request = Request::get("/api/users");
785    ///
786    /// let old_value = request.insert_extension(42u32);
787    /// assert_eq!(old_value, None);
788    ///
789    /// let old_value = request.insert_extension(100u32);
790    /// assert_eq!(old_value, Some(42));
791    /// ```
792    pub fn insert_extension<T: Send + Sync + Clone + 'static>(
793        &mut self,
794        extension: T,
795    ) -> Option<T> {
796        self.extensions_mut().insert(extension)
797    }
798
799    /// Takes the request body, leaving a frozen (unusable) body in its place.
800    ///
801    /// This method extracts the body from the request while ensuring it cannot
802    /// be accessed again. This is useful when you need to consume the body
803    /// for processing while preventing accidental double-consumption.
804    ///
805    /// # Errors
806    ///
807    /// Returns `BodyFrozen` if the body has already been taken.
808    ///
809    /// # Examples
810    ///
811    /// ```rust
812    /// use http_kit::Request;
813    ///
814    /// let mut request = Request::post("/api/data");
815    /// request.replace_body("Hello, world!");
816    ///
817    /// let body = request.take_body()?;
818    /// // request.take_body() would now return an error
819    /// # Ok::<(), http_kit::BodyError>(())
820    /// ```
821    pub fn take_body(&mut self) -> Result<Body, BodyFrozen> {
822        self.body.take()
823    }
824
825    /// Replaces the request body and returns the previous body.
826    ///
827    /// This method swaps the current body with a new one, returning the
828    /// original body. This is useful for body transformations or when
829    /// you need to temporarily substitute the body content.
830    ///
831    /// # Arguments
832    ///
833    /// * `body` - The new body to set (anything convertible to `Body`)
834    ///
835    /// # Examples
836    ///
837    /// ```rust
838    /// use http_kit::Request;
839    ///
840    /// let mut request = Request::post("/api/data");
841    /// request.replace_body("Original content");
842    ///
843    /// let old_body = request.replace_body("New content");
844    /// // old_body contains "Original content"
845    /// // request now contains "New content"
846    /// ```
847    pub fn replace_body(&mut self, body: impl Into<Body>) -> Body {
848        self.body.replace(body.into())
849    }
850
851    /// Swaps the request body with another body.
852    ///
853    /// This method exchanges the contents of the request body with another body,
854    /// provided that the request body is not frozen.
855    ///
856    /// # Arguments
857    ///
858    /// * `body` - The body to swap with
859    ///
860    /// # Errors
861    ///
862    /// Returns `BodyFrozen` if the request body has been frozen/consumed.
863    ///
864    /// # Examples
865    ///
866    /// ```rust
867    /// use http_kit::{Request, Body};
868    ///
869    /// let mut request = Request::post("/api/data");
870    /// request.replace_body("Request content");
871    ///
872    /// let mut other_body = Body::from_bytes("Other content");
873    /// request.swap_body(&mut other_body)?;
874    ///
875    /// // Now request contains "Other content"
876    /// // and other_body contains "Request content"
877    /// # Ok::<(), http_kit::BodyError>(())
878    /// ```
879    pub fn swap_body(&mut self, body: &mut Body) -> Result<(), BodyFrozen> {
880        self.body.swap(body)
881    }
882
883    /// Transforms the request body using the provided function.
884    ///
885    /// This method allows you to apply a transformation to the request body
886    /// in a functional style, returning a new request with the transformed body.
887    ///
888    /// # Arguments
889    ///
890    /// * `f` - A function that takes the current body and returns a new body
891    ///
892    /// # Examples
893    ///
894    /// ```rust
895    /// use http_kit::{Request, Body};
896    ///
897    /// let request = Request::post("/api/data")
898    ///     .map_body(|body| {
899    ///         // Transform empty body to contain JSON
900    ///         Body::from_bytes(r#"{"message": "Hello"}"#)
901    ///     });
902    /// ```
903    pub fn map_body<F>(mut self, f: F) -> Self
904    where
905        F: FnOnce(Body) -> Body,
906    {
907        self.body = f(self.body);
908        self
909    }
910
911    /// Sets the body from a JSON-serializable value.
912    ///
913    /// This method serializes the provided value to JSON and sets it as the request body.
914    /// It also automatically sets the `Content-Type` header to `application/json`.
915    ///
916    /// # Arguments
917    ///
918    /// * `value` - Any value that implements `serde::Serialize`
919    ///
920    /// # Errors
921    ///
922    /// Returns `serde_json::Error` if JSON serialization fails.
923    ///
924    /// # Examples
925    ///
926    /// ```rust
927    /// # #[cfg(feature = "json")]
928    /// # {
929    /// use http_kit::Request;
930    /// use serde::Serialize;
931    ///
932    /// #[derive(Serialize)]
933    /// struct User { name: String, age: u32 }
934    ///
935    /// let user = User { name: "Alice".to_string(), age: 30 };
936    /// let request = Request::post("/api/users").json(&user)?;
937    /// # }
938    /// # Ok::<(), serde_json::Error>(())
939    /// ```
940    #[cfg(feature = "json")]
941    pub fn json<T: serde::Serialize>(mut self, value: T) -> Result<Self, serde_json::Error> {
942        use http::header;
943
944        self.insert_header(
945            header::CONTENT_TYPE,
946            HeaderValue::from_static("application/json"),
947        );
948        self.replace_body(Body::from_json(value)?);
949        Ok(self)
950    }
951
952    /// Sets the body from a form-serializable value.
953    ///
954    /// This method serializes the provided value to URL-encoded form data and sets it
955    /// as the request body. It also automatically sets the `Content-Type` header to
956    /// `application/x-www-form-urlencoded`.
957    ///
958    /// # Arguments
959    ///
960    /// * `value` - Any value that implements `serde::Serialize`
961    ///
962    /// # Errors
963    ///
964    /// Returns `serde_urlencoded::ser::Error` if form serialization fails.
965    ///
966    /// # Examples
967    ///
968    /// ```rust
969    /// # #[cfg(feature = "form")]
970    /// # {
971    /// use http_kit::Request;
972    /// use serde::Serialize;
973    ///
974    /// #[derive(Serialize)]
975    /// struct LoginForm { username: String, password: String }
976    ///
977    /// let form = LoginForm {
978    ///     username: "alice".to_string(),
979    ///     password: "secret".to_string(),
980    /// };
981    /// let request = Request::post("/login").form(&form)?;
982    /// # }
983    /// # Ok::<(), serde_urlencoded::ser::Error>(())
984    /// ```
985    #[cfg(feature = "form")]
986    pub fn form<T: serde::Serialize>(
987        mut self,
988        value: T,
989    ) -> Result<Self, serde_urlencoded::ser::Error> {
990        use http::header;
991
992        self.insert_header(
993            header::CONTENT_TYPE,
994            HeaderValue::from_static("application/x-www-form-urlencoded"),
995        );
996        self.replace_body(Body::from_form(value)?);
997        Ok(self)
998    }
999
1000    /// Sets the body from a file, streaming its contents.
1001    ///
1002    /// This method opens the specified file and streams its contents as the request body.
1003    /// It automatically detects the MIME type based on the file extension and sets the
1004    /// appropriate `Content-Type` header.
1005    ///
1006    /// # Arguments
1007    ///
1008    /// * `path` - Path to the file to read
1009    ///
1010    /// # Errors
1011    ///
1012    /// Returns `io::Error` if the file cannot be opened or read.
1013    ///
1014    /// # Examples
1015    ///
1016    /// ```rust,no_run
1017    /// # #[cfg(feature = "fs")]
1018    /// # {
1019    /// use http_kit::Request;
1020    ///
1021    /// # async fn example() -> Result<(), std::io::Error> {
1022    /// let request = Request::post("/upload").file("document.pdf").await?;
1023    /// // Content-Type will be automatically set based on .pdf extension
1024    /// # Ok(())
1025    /// # }
1026    /// # }
1027    /// ```
1028    #[cfg(feature = "fs")]
1029    pub async fn file(
1030        mut self,
1031        path: impl AsRef<core::path::Path>,
1032    ) -> Result<Self, core::io::Error> {
1033        use core::os::unix::ffi::OsStrExt;
1034
1035        let path = path.as_ref();
1036        let extension = path.extension().unwrap_or_default().as_bytes();
1037        let mime = crate::mime_guess::guess(extension).unwrap_or("application/octet-stream");
1038        self.replace_body(Body::from_file(path).await?);
1039        self.insert_header(http::header::CONTENT_TYPE, HeaderValue::from_static(mime));
1040        Ok(self)
1041    }
1042
1043    /// Consumes the request body and returns its data as bytes.
1044    ///
1045    /// This method takes the request body and reads all its data into memory,
1046    /// returning it as a `Bytes` object. The body becomes unavailable after this call.
1047    ///
1048    /// # Errors
1049    ///
1050    /// Returns `BodyError` if:
1051    /// - The body has already been consumed
1052    /// - An I/O error occurs while reading streaming data
1053    ///
1054    /// # Examples
1055    ///
1056    /// ```rust
1057    /// use http_kit::Request;
1058    ///
1059    /// # async fn example() -> Result<(), http_kit::BodyError> {
1060    /// let mut request = Request::post("/api/data");
1061    /// request.replace_body("Hello, world!");
1062    ///
1063    /// let bytes = request.into_bytes().await?;
1064    /// assert_eq!(bytes, "Hello, world!");
1065    /// # Ok(())
1066    /// # }
1067    /// ```
1068    pub async fn into_bytes(&mut self) -> Result<Bytes, BodyError> {
1069        self.take_body()?.into_bytes().await
1070    }
1071
1072    /// Consumes the request body and returns its data as a UTF-8 string.
1073    ///
1074    /// This method takes the request body, reads all its data into memory,
1075    /// and converts it to a UTF-8 string. The body becomes unavailable after this call.
1076    ///
1077    /// # Errors
1078    ///
1079    /// Returns `BodyError` if:
1080    /// - The body has already been consumed
1081    /// - An I/O error occurs while reading streaming data
1082    /// - The body contains invalid UTF-8 sequences
1083    ///
1084    /// # Examples
1085    ///
1086    /// ```rust
1087    /// use http_kit::Request;
1088    ///
1089    /// # async fn example() -> Result<(), http_kit::BodyError> {
1090    /// let mut request = Request::post("/api/echo");
1091    /// request.replace_body("Hello, world!");
1092    ///
1093    /// let text = request.into_string().await?;
1094    /// assert_eq!(text, "Hello, world!");
1095    /// # Ok(())
1096    /// # }
1097    /// ```
1098    pub async fn into_string(&mut self) -> Result<ByteStr, BodyError> {
1099        self.take_body()?.into_string().await
1100    }
1101
1102    /// Deserializes the request body as JSON into the specified type.
1103    ///
1104    /// This method reads the request body and attempts to deserialize it as JSON.
1105    /// It validates that the `Content-Type` header is `application/json` before
1106    /// attempting deserialization, making it safe for API endpoints.
1107    ///
1108    /// The deserialization is performed with zero-copy when possible by working
1109    /// directly with the buffered byte data.
1110    ///
1111    /// # Errors
1112    ///
1113    /// Returns `crate::Error` if:
1114    /// - The `Content-Type` header is not `application/json`
1115    /// - The body has already been consumed
1116    /// - The JSON is malformed or doesn't match the target type
1117    ///
1118    /// # Examples
1119    ///
1120    /// ```rust
1121    /// # #[cfg(feature = "json")]
1122    /// # {
1123    /// use http_kit::Request;
1124    /// use serde::Deserialize;
1125    ///
1126    /// #[derive(Deserialize)]
1127    /// struct User { name: String, age: u32 }
1128    ///
1129    /// # async fn example() -> Result<(), http_kit::Error> {
1130    /// let json_data = r#"{"name": "Alice", "age": 30}"#;
1131    /// let mut request = Request::post("/api/users")
1132    ///     .header(http::header::CONTENT_TYPE, "application/json");
1133    /// request.replace_body(json_data);
1134    ///
1135    /// let user: User = request.into_json().await?;
1136    /// assert_eq!(user.name, "Alice");
1137    /// # Ok(())
1138    /// # }
1139    /// # }
1140    /// ```
1141    #[cfg(feature = "json")]
1142    pub async fn into_json<'a, T>(&'a mut self) -> Result<T, crate::Error>
1143    where
1144        T: serde::Deserialize<'a>,
1145    {
1146        use crate::ResultExt;
1147
1148        assert_content_type!("application/json", self.headers());
1149
1150        serde_json::from_slice(self.body.as_bytes().await?).status(crate::StatusCode::BAD_REQUEST)
1151    }
1152
1153    /// Deserializes the request body as URL-encoded form data into the specified type.
1154    ///
1155    /// This method reads the request body and attempts to deserialize it as
1156    /// `application/x-www-form-urlencoded` data. It validates that the `Content-Type`
1157    /// header matches before attempting deserialization.
1158    ///
1159    /// The deserialization is performed with zero-copy when possible by working
1160    /// directly with the buffered byte data.
1161    ///
1162    /// # Errors
1163    ///
1164    /// Returns `crate::Error` if:
1165    /// - The `Content-Type` header is not `application/x-www-form-urlencoded`
1166    /// - The body has already been consumed
1167    /// - The form data is malformed or doesn't match the target type
1168    ///
1169    /// # Examples
1170    ///
1171    /// ```rust
1172    /// # #[cfg(feature = "form")]
1173    /// # {
1174    /// use http_kit::Request;
1175    /// use serde::Deserialize;
1176    ///
1177    /// #[derive(Deserialize)]
1178    /// struct LoginForm { username: String, password: String }
1179    ///
1180    /// # async fn example() -> Result<(), http_kit::Error> {
1181    /// let form_data = "username=alice&password=secret";
1182    /// let mut request = Request::post("/login")
1183    ///     .header(http::header::CONTENT_TYPE, "application/x-www-form-urlencoded");
1184    /// request.replace_body(form_data);
1185    ///
1186    /// let form: LoginForm = request.into_form().await?;
1187    /// assert_eq!(form.username, "alice");
1188    /// # Ok(())
1189    /// # }
1190    /// # }
1191    /// ```
1192    #[cfg(feature = "form")]
1193    pub async fn into_form<'a, T>(&'a mut self) -> Result<T, crate::Error>
1194    where
1195        T: serde::Deserialize<'a>,
1196    {
1197        use crate::ResultExt;
1198
1199        assert_content_type!("application/x-www-form-urlencoded", self.headers());
1200
1201        serde_urlencoded::from_bytes(self.body.as_bytes().await?)
1202            .status(crate::StatusCode::BAD_REQUEST)
1203    }
1204    /// Sets the MIME type for the request.
1205    ///
1206    /// This method sets the `Content-Type` header using a parsed MIME type,
1207    /// providing type safety and validation for content types.
1208    ///
1209    /// # Arguments
1210    ///
1211    /// * `mime` - The MIME type to set
1212    ///
1213    /// # Examples
1214    ///
1215    /// ```rust
1216    /// # #[cfg(feature = "mime")]
1217    /// # {
1218    /// use http_kit::Request;
1219    /// use mime;
1220    ///
1221    /// let request = Request::post("/api/data")
1222    ///     .mime(mime::APPLICATION_JSON);
1223    /// # }
1224    /// ```
1225    #[cfg(feature = "mime")]
1226    pub fn mime(mut self, mime: mime::Mime) -> Self {
1227        self.insert_header(
1228            http::header::CONTENT_TYPE,
1229            http::HeaderValue::from_str(mime.as_ref()).unwrap(),
1230        );
1231        self
1232    }
1233
1234    /// Parses the `Content-Type` header and returns a MIME type.
1235    ///
1236    /// This method attempts to parse the `Content-Type` header value as a MIME type,
1237    /// providing structured access to content type information.
1238    ///
1239    /// # Returns
1240    ///
1241    /// Returns `Some(mime::Mime)` if the header exists and can be parsed,
1242    /// or `None` if the header is missing or invalid.
1243    ///
1244    /// # Examples
1245    ///
1246    /// ```rust
1247    /// # #[cfg(feature = "mime")]
1248    /// # {
1249    /// use http_kit::Request;
1250    /// use mime;
1251    ///
1252    /// let request = Request::post("/api/data")
1253    ///     .header(http::header::CONTENT_TYPE, "application/json; charset=utf-8");
1254    ///
1255    /// if let Some(mime_type) = request.get_mime() {
1256    ///     assert_eq!(mime_type.type_(), mime::APPLICATION);
1257    ///     assert_eq!(mime_type.subtype(), mime::JSON);
1258    /// }
1259    /// # }
1260    /// ```
1261    #[cfg(feature = "mime")]
1262    pub fn get_mime(&self) -> Option<mime::Mime> {
1263        core::str::from_utf8(self.get_header(http::header::CONTENT_TYPE)?.as_bytes())
1264            .ok()?
1265            .parse()
1266            .ok()
1267    }
1268}