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

Ensure we include the port when parsing authority #2242

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions axum/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

# Unreleased

- **fixed:** Include port number when parsing authority ([#2242])
- **change:** Avoid cloning `Arc` during deserialization of `Path`
- **added:** `axum::serve::Serve::tcp_nodelay` and `axum::serve::WithGracefulShutdown::tcp_nodelay` ([#2653])
- **added:** `Router::has_routes` function ([#2790])
- **change:** Update tokio-tungstenite to 0.23 ([#2841])
- **added:** `Serve::local_addr` and `WithGracefulShutdown::local_addr` functions ([#2881])

[#2242]: https://github.com/tokio-rs/axum/pull/2242
[#2653]: https://github.com/tokio-rs/axum/pull/2653
[#2790]: https://github.com/tokio-rs/axum/pull/2790
[#2841]: https://github.com/tokio-rs/axum/pull/2841
Expand Down
33 changes: 25 additions & 8 deletions axum/src/extract/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@ use async_trait::async_trait;
use http::{
header::{HeaderMap, FORWARDED},
request::Parts,
uri::Authority,
};

const X_FORWARDED_HOST_HEADER_KEY: &str = "X-Forwarded-Host";

/// Extractor that resolves the hostname of the request.
/// Extractor that resolves the host of the request.
///
/// Hostname is resolved through the following, in order:
/// Host is resolved through the following, in order:
/// - `Forwarded` header
/// - `X-Forwarded-Host` header
/// - `Host` header
/// - request target / URI
/// - Authority of the request URI
///
/// See https://www.rfc-editor.org/rfc/rfc9110.html#name-host-and-authority for the definition of
jplatte marked this conversation as resolved.
Show resolved Hide resolved
/// host.
///
/// Note that user agents can set `X-Forwarded-Host` and `Host` headers to arbitrary values so make
/// sure to validate them to avoid security issues.
Expand Down Expand Up @@ -51,8 +55,8 @@ where
return Ok(Host(host.to_owned()));
}

if let Some(host) = parts.uri.host() {
return Ok(Host(host.to_owned()));
if let Some(authority) = parts.uri.authority() {
return Ok(Host(parse_authority(authority).to_owned()));
}

Err(HostRejection::FailedToResolveHost(FailedToResolveHost))
Expand All @@ -76,11 +80,18 @@ fn parse_forwarded(headers: &HeaderMap) -> Option<&str> {
})
}

fn parse_authority(auth: &Authority) -> &str {
auth.as_str()
.rsplit('@')
.next()
.expect("split always has at least 1 item")
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{routing::get, test_helpers::TestClient, Router};
use http::header::HeaderName;
use http::{header::HeaderName, Request};

fn test_client() -> TestClient {
async fn host_as_body(Host(host): Host) -> String {
Expand Down Expand Up @@ -130,8 +141,14 @@ mod tests {

#[crate::test]
async fn uri_host() {
let host = test_client().get("/").await.text().await;
assert!(host.contains("127.0.0.1"));
let mut parts = Request::new(()).into_parts().0;
parts.uri = "https://127.0.0.1:1234/image.jpg".parse().unwrap();
let host = Host::from_request_parts(&mut parts, &()).await.unwrap();
assert_eq!(host.0, "127.0.0.1:1234");

parts.uri = "http://cool:user@[::1]:456/file.txt".parse().unwrap();
let host = Host::from_request_parts(&mut parts, &()).await.unwrap();
assert_eq!(host.0, "[::1]:456");
Comment on lines +144 to +151
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you completely rewrite this example to not use the test client?

}

#[test]
Expand Down
Loading