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}