feat: Add support for form-encoded POST bodies
This commit is contained in:
		
							parent
							
								
									d3a47d3b1c
								
							
						
					
					
						commit
						aedfd7c7ac
					
				
					 1 changed files with 57 additions and 8 deletions
				
			
		
							
								
								
									
										65
									
								
								src/lib.rs
									
										
									
									
									
								
							
							
						
						
									
										65
									
								
								src/lib.rs
									
										
									
									
									
								
							|  | @ -43,7 +43,7 @@ extern crate curl; | ||||||
| #[cfg(feature = "json")] extern crate serde; | #[cfg(feature = "json")] extern crate serde; | ||||||
| #[cfg(feature = "json")] extern crate serde_json; | #[cfg(feature = "json")] extern crate serde_json; | ||||||
| 
 | 
 | ||||||
| use curl::easy::{Easy, List, ReadError}; | use curl::easy::{Easy, Form, List, ReadError}; | ||||||
| use std::collections::HashMap; | use std::collections::HashMap; | ||||||
| use std::io::Write; | use std::io::Write; | ||||||
| use std::string::{FromUtf8Error, ToString}; | use std::string::{FromUtf8Error, ToString}; | ||||||
|  | @ -74,12 +74,15 @@ pub struct Request<'a> { | ||||||
| 
 | 
 | ||||||
| enum Body<'a> { | enum Body<'a> { | ||||||
|     NoBody, |     NoBody, | ||||||
|     #[cfg(feature = "json")] |     Form(Form), | ||||||
|     Json(Vec<u8>), | 
 | ||||||
|     Bytes { |     Bytes { | ||||||
|         content_type: &'a str, |         content_type: &'a str, | ||||||
|         data: &'a [u8], |         data: &'a [u8], | ||||||
|     } |     }, | ||||||
|  | 
 | ||||||
|  |     #[cfg(feature = "json")] | ||||||
|  |     Json(Vec<u8>), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// HTTP responses structure containing response data and headers.
 | /// HTTP responses structure containing response data and headers.
 | ||||||
|  | @ -133,6 +136,41 @@ impl <'a> Request<'a> { | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Add a form-encoded body to a request using the `curl::Form`
 | ||||||
|  |     /// type.
 | ||||||
|  |     ///
 | ||||||
|  |     /// ```rust
 | ||||||
|  |     /// # extern crate curl;
 | ||||||
|  |     /// # extern crate serde_json;
 | ||||||
|  |     /// # use crimp::*;
 | ||||||
|  |     /// # use serde_json::{Value, json};
 | ||||||
|  |     /// use curl::easy::Form;
 | ||||||
|  |     ///
 | ||||||
|  |     /// let mut form = Form::new();
 | ||||||
|  |     /// form.part("some-name")
 | ||||||
|  |     ///     .contents("some-data".as_bytes())
 | ||||||
|  |     ///     .add().unwrap();
 | ||||||
|  |     ///
 | ||||||
|  |     /// let response = Request::new(Method::Post, "https://httpbin.org/post")
 | ||||||
|  |     ///     .user_agent("crimp test suite").unwrap()
 | ||||||
|  |     ///     .form(form)
 | ||||||
|  |     ///     .send().unwrap();
 | ||||||
|  |     /// #
 | ||||||
|  |     /// # assert_eq!(200, response.status, "form POST should succeed");
 | ||||||
|  |     /// # assert_eq!(
 | ||||||
|  |     /// #     response.as_json::<Value>().unwrap().body.get("form").unwrap(),
 | ||||||
|  |     /// #     &json!({"some-name": "some-data"}),
 | ||||||
|  |     /// #     "posted form data should match",
 | ||||||
|  |     /// # );
 | ||||||
|  |     /// ```
 | ||||||
|  |     ///
 | ||||||
|  |     /// See the documentation of `curl::easy::Form` for details on how
 | ||||||
|  |     /// to construct a form body.
 | ||||||
|  |     pub fn form(mut self, form: Form) -> Self { | ||||||
|  |         self.body = Body::Form(form); | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /// Add a JSON-encoded body from a serializable type.
 |     /// Add a JSON-encoded body from a serializable type.
 | ||||||
|     #[cfg(feature = "json")] |     #[cfg(feature = "json")] | ||||||
|     pub fn json<T: Serialize>(mut self, body: &T) -> Result<Self, serde_json::Error> { |     pub fn json<T: Serialize>(mut self, body: &T) -> Result<Self, serde_json::Error> { | ||||||
|  | @ -159,8 +197,16 @@ impl <'a> Request<'a> { | ||||||
|         let mut headers = HashMap::new(); |         let mut headers = HashMap::new(); | ||||||
|         let mut body = vec![]; |         let mut body = vec![]; | ||||||
| 
 | 
 | ||||||
|  |         // Submit a form value to cURL if it is set and proceed
 | ||||||
|  |         // pretending that there is no body, as the handling of this
 | ||||||
|  |         // type of body happens under-the-hood.
 | ||||||
|  |         if let Body::Form(form) = self.body { | ||||||
|  |             self.handle.httppost(form)?; | ||||||
|  |             self.body = Body::NoBody; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         // Optionally set content type if a body payload is configured
 |         // Optionally set content type if a body payload is configured
 | ||||||
|         // and configure the expected body size.
 |         // and configure the expected body size (or form payload).
 | ||||||
|          match self.body { |          match self.body { | ||||||
|             Body::Bytes { content_type, data } => { |             Body::Bytes { content_type, data } => { | ||||||
|                 self.handle.post_field_size(data.len() as u64)?; |                 self.handle.post_field_size(data.len() as u64)?; | ||||||
|  | @ -173,7 +219,9 @@ impl <'a> Request<'a> { | ||||||
|                 self.headers.append("Content-Type: application/json")?; |                 self.headers.append("Content-Type: application/json")?; | ||||||
|             }, |             }, | ||||||
| 
 | 
 | ||||||
|             Body::NoBody => (), |              // Do not set content-type header at all if there is no
 | ||||||
|  |              // body, or if the form handler was invoked above.
 | ||||||
|  |              _ => (), | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         // Configure headers on the request:
 |         // Configure headers on the request:
 | ||||||
|  | @ -200,8 +248,9 @@ impl <'a> Request<'a> { | ||||||
|                         .map_err(|_| ReadError::Abort) |                         .map_err(|_| ReadError::Abort) | ||||||
|                 })?, |                 })?, | ||||||
| 
 | 
 | ||||||
|                 // Do nothing if there is no body ...
 |                 // Do nothing if there is no body or if the body is a
 | ||||||
|                 Body::NoBody => (), |                 // form.
 | ||||||
|  |                 _ => (), | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|             // Read one header per invocation. Request processing is
 |             // Read one header per invocation. Request processing is
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue