mirror of https://github.com/fafhrd91/actix-web
Handle repeated HTTP Method edge case
Refactor code to detect when the same HTTP method is specified more than once. eg. `#[route("/multi", method = "GET", method = "GET")]` and return a compile time error.
This commit is contained in:
parent
90a6b47927
commit
8bb205846d
|
@ -1,5 +1,7 @@
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||||
use quote::{format_ident, quote, ToTokens, TokenStreamExt};
|
use quote::{format_ident, quote, ToTokens, TokenStreamExt};
|
||||||
|
@ -17,7 +19,7 @@ impl ToTokens for ResourceType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum GuardType {
|
pub enum GuardType {
|
||||||
Get,
|
Get,
|
||||||
Post,
|
Post,
|
||||||
|
@ -59,7 +61,7 @@ struct Args {
|
||||||
path: syn::LitStr,
|
path: syn::LitStr,
|
||||||
guards: Vec<Ident>,
|
guards: Vec<Ident>,
|
||||||
wrappers: Vec<syn::Type>,
|
wrappers: Vec<syn::Type>,
|
||||||
methods: Vec<GuardType>,
|
methods: HashSet<GuardType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Args {
|
impl Args {
|
||||||
|
@ -67,7 +69,7 @@ impl Args {
|
||||||
let mut path = None;
|
let mut path = None;
|
||||||
let mut guards = Vec::new();
|
let mut guards = Vec::new();
|
||||||
let mut wrappers = Vec::new();
|
let mut wrappers = Vec::new();
|
||||||
let mut methods = Vec::new();
|
let mut methods = HashSet::new();
|
||||||
for arg in args {
|
for arg in args {
|
||||||
match arg {
|
match arg {
|
||||||
NestedMeta::Lit(syn::Lit::Str(lit)) => match path {
|
NestedMeta::Lit(syn::Lit::Str(lit)) => match path {
|
||||||
|
@ -102,26 +104,38 @@ impl Args {
|
||||||
}
|
}
|
||||||
} else if nv.path.is_ident("method") {
|
} else if nv.path.is_ident("method") {
|
||||||
if let syn::Lit::Str(ref lit) = nv.lit {
|
if let syn::Lit::Str(ref lit) = nv.lit {
|
||||||
|
let guard_type: Option<GuardType> =
|
||||||
match lit.value().as_str() {
|
match lit.value().as_str() {
|
||||||
"CONNECT" => methods.push(GuardType::Connect),
|
"CONNECT" => Some(GuardType::Connect),
|
||||||
"DELETE" => methods.push(GuardType::Delete),
|
"DELETE" => Some(GuardType::Delete),
|
||||||
"GET" => methods.push(GuardType::Get),
|
"GET" => Some(GuardType::Get),
|
||||||
"HEAD" => methods.push(GuardType::Head),
|
"HEAD" => Some(GuardType::Head),
|
||||||
"OPTIONS" => methods.push(GuardType::Options),
|
"OPTIONS" => Some(GuardType::Options),
|
||||||
"PATCH" => methods.push(GuardType::Patch),
|
"PATCH" => Some(GuardType::Patch),
|
||||||
"POST" => methods.push(GuardType::Post),
|
"POST" => Some(GuardType::Post),
|
||||||
"PUT" => methods.push(GuardType::Put),
|
"PUT" => Some(GuardType::Put),
|
||||||
"TRACE" => methods.push(GuardType::Trace),
|
"TRACE" => Some(GuardType::Trace),
|
||||||
_ => {
|
_ => None,
|
||||||
|
};
|
||||||
|
if let Some(guard) = guard_type {
|
||||||
|
if !methods.insert(guard) {
|
||||||
|
return Err(syn::Error::new_spanned(
|
||||||
|
&nv.lit,
|
||||||
|
&format!(
|
||||||
|
"HTTP Method defined more than once: `{}`",
|
||||||
|
lit.value()
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
return Err(syn::Error::new_spanned(
|
return Err(syn::Error::new_spanned(
|
||||||
&nv.lit,
|
&nv.lit,
|
||||||
&format!(
|
&format!(
|
||||||
"Unexpected HTTP Method: `{}`",
|
"Unexpected HTTP Method: `{}`",
|
||||||
lit.value()
|
lit.value()
|
||||||
),
|
),
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
return Err(syn::Error::new_spanned(
|
return Err(syn::Error::new_spanned(
|
||||||
nv.lit,
|
nv.lit,
|
||||||
|
@ -246,6 +260,7 @@ impl ToTokens for Route {
|
||||||
resource_type,
|
resource_type,
|
||||||
} = self;
|
} = self;
|
||||||
let resource_name = name.to_string();
|
let resource_name = name.to_string();
|
||||||
|
let methods = methods.iter();
|
||||||
|
|
||||||
let guard_gen = if guard == &GuardType::Multi {
|
let guard_gen = if guard == &GuardType::Multi {
|
||||||
quote! {
|
quote! {
|
||||||
|
|
Loading…
Reference in New Issue