@@ -912,6 +912,32 @@ impl<ReqBody, E> MethodRouter<ReqBody, E> {
912912 S : Service < Request < ReqBody > , Response = Response , Error = E > + Clone + Send + ' static ,
913913 S :: Future : Send + ' static ,
914914 {
915+ macro_rules! set_service {
916+ (
917+ $filter: ident,
918+ $svc: ident,
919+ $allow_header: ident,
920+ [
921+ $(
922+ ( $out: ident, $variant: ident, [ $( $method: literal) ,+] )
923+ ) ,+
924+ $( , ) ?
925+ ]
926+ ) => {
927+ $(
928+ if $filter. contains( MethodFilter :: $variant) {
929+ if $out. is_some( ) {
930+ panic!( "Overlapping method route. Cannot add two method routes that both handle `{}`" , stringify!( $variant) )
931+ }
932+ $out = $svc. clone( ) ;
933+ $(
934+ append_allow_header( & mut $allow_header, $method) ;
935+ ) +
936+ }
937+ ) +
938+ }
939+ }
940+
915941 // written with a pattern match like this to ensure we update all fields
916942 let Self {
917943 mut get,
@@ -927,39 +953,21 @@ impl<ReqBody, E> MethodRouter<ReqBody, E> {
927953 _request_body : _,
928954 } = self ;
929955 let svc = Some ( Route :: new ( svc) ) ;
930- if filter. contains ( MethodFilter :: GET ) {
931- get = svc. clone ( ) ;
932- append_allow_header ( & mut allow_header, "GET" ) ;
933- append_allow_header ( & mut allow_header, "HEAD" ) ;
934- }
935- if filter. contains ( MethodFilter :: HEAD ) {
936- append_allow_header ( & mut allow_header, "HEAD" ) ;
937- head = svc. clone ( ) ;
938- }
939- if filter. contains ( MethodFilter :: DELETE ) {
940- append_allow_header ( & mut allow_header, "DELETE" ) ;
941- delete = svc. clone ( ) ;
942- }
943- if filter. contains ( MethodFilter :: OPTIONS ) {
944- append_allow_header ( & mut allow_header, "OPTIONS" ) ;
945- options = svc. clone ( ) ;
946- }
947- if filter. contains ( MethodFilter :: PATCH ) {
948- append_allow_header ( & mut allow_header, "PATCH" ) ;
949- patch = svc. clone ( ) ;
950- }
951- if filter. contains ( MethodFilter :: POST ) {
952- append_allow_header ( & mut allow_header, "POST" ) ;
953- post = svc. clone ( ) ;
954- }
955- if filter. contains ( MethodFilter :: PUT ) {
956- append_allow_header ( & mut allow_header, "PUT" ) ;
957- put = svc. clone ( ) ;
958- }
959- if filter. contains ( MethodFilter :: TRACE ) {
960- append_allow_header ( & mut allow_header, "TRACE" ) ;
961- trace = svc;
962- }
956+ set_service ! (
957+ filter,
958+ svc,
959+ allow_header,
960+ [
961+ ( get, GET , [ "GET" , "HEAD" ] ) ,
962+ ( head, HEAD , [ "HEAD" ] ) ,
963+ ( delete, DELETE , [ "DELETE" ] ) ,
964+ ( options, OPTIONS , [ "OPTIONS" ] ) ,
965+ ( patch, PATCH , [ "PATCH" ] ) ,
966+ ( post, POST , [ "POST" ] ) ,
967+ ( put, PUT , [ "PUT" ] ) ,
968+ ( trace, TRACE , [ "TRACE" ] ) ,
969+ ]
970+ ) ;
963971 Self {
964972 get,
965973 head,
@@ -1294,6 +1302,32 @@ mod tests {
12941302 assert_eq ! ( headers[ ALLOW ] , "GET,POST" ) ;
12951303 }
12961304
1305+ #[ tokio:: test]
1306+ #[ should_panic(
1307+ expected = "Overlapping method route. Cannot add two method routes that both handle `GET`"
1308+ ) ]
1309+ async fn handler_overlaps ( ) {
1310+ let _: MethodRouter = get ( ok) . get ( ok) ;
1311+ }
1312+
1313+ #[ tokio:: test]
1314+ #[ should_panic(
1315+ expected = "Overlapping method route. Cannot add two method routes that both handle `POST`"
1316+ ) ]
1317+ async fn service_overlaps ( ) {
1318+ let _: MethodRouter = post_service ( ok. into_service ( ) ) . post_service ( ok. into_service ( ) ) ;
1319+ }
1320+
1321+ #[ tokio:: test]
1322+ async fn get_head_does_not_overlap ( ) {
1323+ let _: MethodRouter = get ( ok) . head ( ok) ;
1324+ }
1325+
1326+ #[ tokio:: test]
1327+ async fn head_get_does_not_overlap ( ) {
1328+ let _: MethodRouter = head ( ok) . get ( ok) ;
1329+ }
1330+
12971331 async fn call < S > ( method : Method , svc : & mut S ) -> ( StatusCode , HeaderMap , String )
12981332 where
12991333 S : Service < Request < Body > , Response = Response , Error = Infallible > ,
0 commit comments