httparse is a http1 stateless push parser. This not only speeds up parsing right now with sync io, but will also be useful for when we get async io, since it's push based instead of pull. BREAKING CHANGE: Several public functions and types in the `http` module have been removed. They have been replaced with 2 methods that handle all of the http1 parsing.
		
			
				
	
	
		
			151 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| //! The HTTP request method
 | |
| use std::fmt;
 | |
| use std::str::FromStr;
 | |
| 
 | |
| use error::HttpError;
 | |
| use self::Method::{Options, Get, Post, Put, Delete, Head, Trace, Connect, Patch,
 | |
|                    Extension};
 | |
| 
 | |
| /// The Request Method (VERB)
 | |
| ///
 | |
| /// Currently includes 8 variants representing the 8 methods defined in
 | |
| /// [RFC 7230](https://tools.ietf.org/html/rfc7231#section-4.1), plus PATCH,
 | |
| /// and an Extension variant for all extensions.
 | |
| ///
 | |
| /// It may make sense to grow this to include all variants currently
 | |
| /// registered with IANA, if they are at all common to use.
 | |
| #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 | |
| pub enum Method {
 | |
|     /// OPTIONS
 | |
|     Options,
 | |
|     /// GET
 | |
|     Get,
 | |
|     /// POST
 | |
|     Post,
 | |
|     /// PUT
 | |
|     Put,
 | |
|     /// DELETE
 | |
|     Delete,
 | |
|     /// HEAD
 | |
|     Head,
 | |
|     /// TRACE
 | |
|     Trace,
 | |
|     /// CONNECT
 | |
|     Connect,
 | |
|     /// PATCH
 | |
|     Patch,
 | |
|     /// Method extentions. An example would be `let m = Extension("FOO".to_string())`.
 | |
|     Extension(String)
 | |
| }
 | |
| 
 | |
| impl Method {
 | |
|     /// Whether a method is considered "safe", meaning the request is
 | |
|     /// essentially read-only.
 | |
|     ///
 | |
|     /// See [the spec](https://tools.ietf.org/html/rfc7231#section-4.2.1)
 | |
|     /// for more words.
 | |
|     pub fn safe(&self) -> bool {
 | |
|         match *self {
 | |
|             Get | Head | Options | Trace => true,
 | |
|             _ => false
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Whether a method is considered "idempotent", meaning the request has
 | |
|     /// the same result is executed multiple times.
 | |
|     ///
 | |
|     /// See [the spec](https://tools.ietf.org/html/rfc7231#section-4.2.2) for
 | |
|     /// more words.
 | |
|     pub fn idempotent(&self) -> bool {
 | |
|         if self.safe() {
 | |
|             true
 | |
|         } else {
 | |
|             match *self {
 | |
|                 Put | Delete => true,
 | |
|                 _ => false
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl FromStr for Method {
 | |
|     type Err = HttpError;
 | |
|     fn from_str(s: &str) -> Result<Method, HttpError> {
 | |
|         if s == "" {
 | |
|             Err(HttpError::HttpMethodError)
 | |
|         } else {
 | |
|             Ok(match s {
 | |
|                 "OPTIONS" => Options,
 | |
|                 "GET" => Get,
 | |
|                 "POST" => Post,
 | |
|                 "PUT" => Put,
 | |
|                 "DELETE" => Delete,
 | |
|                 "HEAD" => Head,
 | |
|                 "TRACE" => Trace,
 | |
|                 "CONNECT" => Connect,
 | |
|                 "PATCH" => Patch,
 | |
|                 _ => Extension(s.to_string())
 | |
|             })
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl fmt::Display for Method {
 | |
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 | |
|         fmt.write_str(match *self {
 | |
|             Options => "OPTIONS",
 | |
|             Get => "GET",
 | |
|             Post => "POST",
 | |
|             Put => "PUT",
 | |
|             Delete => "DELETE",
 | |
|             Head => "HEAD",
 | |
|             Trace => "TRACE",
 | |
|             Connect => "CONNECT",
 | |
|             Patch => "PATCH",
 | |
|             Extension(ref s) => s.as_slice()
 | |
|         })
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[cfg(test)]
 | |
| mod tests {
 | |
|     use std::collections::HashMap;
 | |
|     use std::str::FromStr;
 | |
|     use super::Method;
 | |
|     use super::Method::{Get, Post, Put, Extension};
 | |
| 
 | |
|     #[test]
 | |
|     fn test_safe() {
 | |
|         assert_eq!(true, Get.safe());
 | |
|         assert_eq!(false, Post.safe());
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn test_idempotent() {
 | |
|         assert_eq!(true, Get.idempotent());
 | |
|         assert_eq!(true, Put.idempotent());
 | |
|         assert_eq!(false, Post.idempotent());
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn test_from_str() {
 | |
|         assert_eq!(Ok(Get), FromStr::from_str("GET"));
 | |
|         assert_eq!(Ok(Extension("MOVE".to_string())),
 | |
|                    FromStr::from_str("MOVE"));
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn test_fmt() {
 | |
|         assert_eq!("GET".to_string(), format!("{}", Get));
 | |
|         assert_eq!("MOVE".to_string(),
 | |
|                    format!("{}", Extension("MOVE".to_string())));
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn test_hashable() {
 | |
|         let mut counter: HashMap<Method,usize> = HashMap::new();
 | |
|         counter.insert(Get, 1);
 | |
|         assert_eq!(Some(&1), counter.get(&Get));
 | |
|     }
 | |
| }
 |