150 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| //! The HTTP request method
 | |
| use std::fmt;
 | |
| use std::str::FromStr;
 | |
| 
 | |
| 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 = ();
 | |
|     fn from_str(s: &str) -> Result<Method, ()> {
 | |
|         if s == "" {
 | |
|             Err(())
 | |
|         } 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));
 | |
|     }
 | |
| }
 |