Return rejection if WebSocket request couldn't be upgraded (#1135)

* Return rejection if `WebSocket` request couldn't be upgraded

* make rejection about connection upgrades

* changelog links
This commit is contained in:
David Pedersen 2022-07-11 14:33:55 +02:00 committed by GitHub
parent 8c9998eab7
commit 92dbbd3182
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 7 deletions

View file

@ -16,6 +16,10 @@ 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])
- **fixed:** If `WebSocketUpgrade` cannot upgrade the connection it will return a
`WebSocketUpgradeRejection::ConnectionNotUpgradable` rejection ([#1135])
- **changed:** `WebSocketUpgradeRejection` has a new variant `ConnectionNotUpgradable`
variant ([#1135])
- **added** Implement `TryFrom<http:: Method>` for `MethodFilter` and use new `NoMatchingMethodFilter` error in case of failure ([#1130])
- **added:** Support running extractors from `middleware::from_fn` functions ([#1088])
- **added:** Added `debug_handler` which is an attribute macro that improves
@ -27,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#1102]: https://github.com/tokio-rs/axum/pull/1102
[#1119]: https://github.com/tokio-rs/axum/pull/1119
[#1130]: https://github.com/tokio-rs/axum/pull/1130
[#1135]: https://github.com/tokio-rs/axum/pull/1135
[#924]: https://github.com/tokio-rs/axum/pull/924
# 0.5.10 (28. June, 2022)

View file

@ -267,14 +267,15 @@ where
return Err(InvalidWebSocketVersionHeader.into());
}
let sec_websocket_key =
if let Some(key) = req.headers_mut().remove(header::SEC_WEBSOCKET_KEY) {
key
} else {
return Err(WebSocketKeyHeaderMissing.into());
};
let sec_websocket_key = req
.headers_mut()
.remove(header::SEC_WEBSOCKET_KEY)
.ok_or(WebSocketKeyHeaderMissing)?;
let on_upgrade = req.extensions_mut().remove::<OnUpgrade>().unwrap();
let on_upgrade = req
.extensions_mut()
.remove::<OnUpgrade>()
.ok_or(ConnectionNotUpgradable)?;
let sec_websocket_protocol = req.headers().get(header::SEC_WEBSOCKET_PROTOCOL).cloned();
@ -564,6 +565,20 @@ pub mod rejection {
pub struct WebSocketKeyHeaderMissing;
}
define_rejection! {
#[status = UPGRADE_REQUIRED]
#[body = "WebSocket request couldn't be upgraded since no upgrade state was present"]
/// Rejection type for [`WebSocketUpgrade`](super::WebSocketUpgrade).
///
/// This rejection is returned if the connection cannot be upgraded for example if the
/// request is HTTP/1.0.
///
/// See [MDN] for more details about connection upgrades.
///
/// [MDN]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Upgrade
pub struct ConnectionNotUpgradable;
}
composite_rejection! {
/// Rejection used for [`WebSocketUpgrade`](super::WebSocketUpgrade).
///
@ -575,6 +590,7 @@ pub mod rejection {
InvalidUpgradeHeader,
InvalidWebSocketVersionHeader,
WebSocketKeyHeaderMissing,
ConnectionNotUpgradable,
}
}
}
@ -640,3 +656,37 @@ pub mod close_code {
/// action.
pub const AGAIN: u16 = 1013;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{body::Body, routing::get};
use http::{Request, Version};
use tower::ServiceExt;
#[tokio::test]
async fn rejects_http_1_0_requests() {
let svc = get(|ws: Result<WebSocketUpgrade, WebSocketUpgradeRejection>| {
let rejection = ws.unwrap_err();
assert!(matches!(
rejection,
WebSocketUpgradeRejection::ConnectionNotUpgradable(_)
));
std::future::ready(())
});
let req = Request::builder()
.version(Version::HTTP_10)
.method(Method::GET)
.header("upgrade", "websocket")
.header("connection", "Upgrade")
.header("sec-websocket-key", "6D69KGBOr4Re+Nj6zx9aQA==")
.header("sec-websocket-version", "13")
.body(Body::empty())
.unwrap();
let res = svc.oneshot(req).await.unwrap();
assert_eq!(res.status(), StatusCode::OK);
}
}