diff --git a/server/src/server.rs b/server/src/server.rs index 85135a531c..c844bbba54 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -34,6 +34,7 @@ use std::time::Duration; use crate::future::{ConnectionGuard, ServerHandle, StopHandle}; use crate::logger::{Logger, TransportProtocol}; +use crate::transport::http::fetch_authority; use crate::transport::{http, ws}; use futures_util::future::{self, Either, FutureExt}; @@ -44,7 +45,7 @@ use jsonrpsee_core::id_providers::RandomIntegerIdProvider; use jsonrpsee_core::server::{AllowHosts, Authority, AuthorityError, Methods, WhitelistedHosts}; use jsonrpsee_core::traits::IdProvider; -use jsonrpsee_core::{http_helpers, Error, TEN_MB_SIZE_BYTES}; +use jsonrpsee_core::{Error, TEN_MB_SIZE_BYTES}; use soketto::handshake::http::is_upgrade_request; use tokio::net::{TcpListener, TcpStream, ToSocketAddrs}; @@ -651,16 +652,11 @@ impl hyper::service::Service> for TowerSe fn call(&mut self, request: hyper::Request) -> Self::Future { tracing::trace!("{:?}", request); - let host = match http_helpers::read_header_value(request.headers(), hyper::header::HOST) { - Some(host) => host, - None if request.version() == hyper::Version::HTTP_2 => match request.uri().host() { - Some(host) => host, - None => return async move { Ok(http::response::malformed()) }.boxed(), - }, - None => return async move { Ok(http::response::malformed()) }.boxed(), + let Some(authority) = fetch_authority(&request) else { + return async { Ok(http::response::malformed()) }.boxed(); }; - if let Err(e) = self.inner.allow_hosts.verify(host) { + if let Err(e) = self.inner.allow_hosts.verify(authority) { tracing::debug!("Denied request: {}", e); return async { Ok(http::response::host_not_allowed()) }.boxed(); } diff --git a/server/src/transport/http.rs b/server/src/transport/http.rs index 3426a01060..b9bb87c75e 100644 --- a/server/src/transport/http.rs +++ b/server/src/transport/http.rs @@ -9,7 +9,7 @@ use futures_util::future::Either; use futures_util::stream::{FuturesOrdered, StreamExt}; use hyper::Method; use jsonrpsee_core::error::GenericTransportError; -use jsonrpsee_core::http_helpers::read_body; +use jsonrpsee_core::http_helpers::{self, read_body}; use jsonrpsee_core::server::helpers::{ batch_response_error, prepare_error, BatchResponseBuilder, MethodResponse, MethodResponseResult, }; @@ -50,6 +50,20 @@ pub(crate) async fn reject_connection(socket: tokio::net::TcpStream) { } } +/// The `Authority` can be sent by the client in the `Host header` or in the `URI` +/// such that we must check both. +pub(crate) fn fetch_authority(request: &hyper::Request) -> Option<&str> { + let host_header = http_helpers::read_header_value(request.headers(), hyper::header::HOST); + let uri = request.uri().authority(); + + match (host_header, uri) { + (Some(a1), Some(a2)) if a1 == a2.as_str() => Some(a1), + (Some(a), None) => Some(a), + (None, Some(a)) => Some(a.as_str()), + _ => None, + } +} + #[derive(Debug)] pub(crate) struct ProcessValidatedRequest<'a, L: Logger> { pub(crate) request: hyper::Request,