Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TryFrom<http::Method> for MethodFilter #1130

Merged
merged 7 commits into from
Jul 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions axum/CHANGELOG.md
Expand Up @@ -16,7 +16,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`/foo/`). That is no longer supported and such requests will now be sent to
the fallback. Consider using `axum_extra::routing::RouterExt::route_with_tsr`
if you want the old behavior ([#1119])
- **added** Implement `TryFrom<http:: Method>` for `MethodFilter` and use new `NoMatchingMethodFilter` error in case of failure ([#1130])
davidpdrsn marked this conversation as resolved.
Show resolved Hide resolved

[#1130]: https://github.com/tokio-rs/axum/pull/1130
[#1077]: https://github.com/tokio-rs/axum/pull/1077
[#1102]: https://github.com/tokio-rs/axum/pull/1102
[#1119]: https://github.com/tokio-rs/axum/pull/1119
Expand Down
97 changes: 97 additions & 0 deletions axum/src/routing/method_filter.rs
@@ -1,4 +1,9 @@
use bitflags::bitflags;
use http::Method;
use std::{
fmt,
fmt::{Debug, Formatter},
};

bitflags! {
/// A filter that matches one or more HTTP methods.
Expand All @@ -21,3 +26,95 @@ bitflags! {
const TRACE = 0b100000000;
}
}

/// Error type used when converting a [`Method`] to a [`MethodFilter`] fails.
#[derive(Debug)]
pub struct NoMatchingMethodFilter {
davidpdrsn marked this conversation as resolved.
Show resolved Hide resolved
method: Method,
}

impl NoMatchingMethodFilter {
/// Get the [`Method`] that couldn't be converted to a [`MethodFilter`].
pub fn method(&self) -> &Method {
&self.method
}
}

impl fmt::Display for NoMatchingMethodFilter {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "no `MethodFilter` for `{}`", self.method.as_str())
}
}

impl std::error::Error for NoMatchingMethodFilter {}

impl TryFrom<Method> for MethodFilter {
type Error = NoMatchingMethodFilter;

fn try_from(m: Method) -> Result<Self, NoMatchingMethodFilter> {
match m {
Method::DELETE => Ok(MethodFilter::DELETE),
Method::GET => Ok(MethodFilter::GET),
Method::HEAD => Ok(MethodFilter::HEAD),
Method::OPTIONS => Ok(MethodFilter::OPTIONS),
Method::PATCH => Ok(MethodFilter::PATCH),
Method::POST => Ok(MethodFilter::POST),
Method::PUT => Ok(MethodFilter::PUT),
Method::TRACE => Ok(MethodFilter::TRACE),
other => Err(NoMatchingMethodFilter { method: other }),
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn from_http_method() {
assert_eq!(
MethodFilter::try_from(Method::DELETE).unwrap(),
MethodFilter::DELETE
);

assert_eq!(
MethodFilter::try_from(Method::GET).unwrap(),
MethodFilter::GET
);

assert_eq!(
MethodFilter::try_from(Method::HEAD).unwrap(),
MethodFilter::HEAD
);

assert_eq!(
MethodFilter::try_from(Method::OPTIONS).unwrap(),
MethodFilter::OPTIONS
);

assert_eq!(
MethodFilter::try_from(Method::PATCH).unwrap(),
MethodFilter::PATCH
);

assert_eq!(
MethodFilter::try_from(Method::POST).unwrap(),
MethodFilter::POST
);

assert_eq!(
MethodFilter::try_from(Method::PUT).unwrap(),
MethodFilter::PUT
);

assert_eq!(
MethodFilter::try_from(Method::TRACE).unwrap(),
MethodFilter::TRACE
);

assert!(MethodFilter::try_from(http::Method::CONNECT)
.unwrap_err()
.to_string()
.contains("CONNECT"));
}
}