use crate::{
AuthorityInputExt, Protocol, ProtocolInputExt, TransportProtocolInputExt,
address::{HostWithOptPort, HostWithPort},
transport::TransportProtocol,
};
use rama_core::{Fork, extensions::Extensions, extensions::ExtensionsRef};
#[cfg(feature = "http")]
use crate::{
HttpVersionInputExt, TargetHttpVersionInputExt,
http::{HttpRequestVersion, TargetHttpVersion, Version},
};
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct ConnectRequest {
pub authority: HostWithPort,
pub extensions: Extensions,
pub application_protocol: Option<Protocol>,
pub transport_protocol: Option<TransportProtocol>,
}
impl ConnectRequest {
#[must_use]
pub fn new(authority: HostWithPort) -> Self {
Self {
authority,
extensions: Extensions::new(),
application_protocol: None,
transport_protocol: None,
}
}
#[must_use]
pub const fn new_with_extensions(authority: HostWithPort, extensions: Extensions) -> Self {
Self {
authority,
extensions,
application_protocol: None,
transport_protocol: None,
}
}
rama_utils::macros::generate_set_and_with! {
pub fn application_protocol(mut self, protocol: Option<Protocol>) -> Self {
self.application_protocol = protocol;
self
}
}
rama_utils::macros::generate_set_and_with! {
pub fn transport_protocol(mut self, protocol: Option<TransportProtocol>) -> Self {
self.transport_protocol = protocol;
self
}
}
}
impl Fork for ConnectRequest {
fn fork(&self) -> Self {
Self {
authority: self.authority.clone(),
extensions: self.extensions.fork(),
application_protocol: self.application_protocol.clone(),
transport_protocol: self.transport_protocol,
}
}
}
impl ExtensionsRef for ConnectRequest {
fn extensions(&self) -> &Extensions {
&self.extensions
}
}
impl AuthorityInputExt for ConnectRequest {
fn authority(&self) -> Option<HostWithOptPort> {
Some(self.authority.clone().into())
}
}
impl ProtocolInputExt for ConnectRequest {
fn protocol(&self) -> Option<&Protocol> {
self.application_protocol.as_ref()
}
}
impl TransportProtocolInputExt for ConnectRequest {
fn transport_protocol(&self) -> Option<TransportProtocol> {
self.transport_protocol
}
}
#[cfg(feature = "http")]
impl TargetHttpVersionInputExt for ConnectRequest {
fn target_http_version(&self) -> Option<Version> {
self.extensions
.get_ref::<TargetHttpVersion>()
.map(|target| target.0)
}
}
#[cfg(feature = "http")]
impl HttpVersionInputExt for ConnectRequest {
fn http_version(&self) -> Option<Version> {
self.extensions
.get_ref::<HttpRequestVersion>()
.map(|version| version.0)
}
}
#[cfg(test)]
mod tests {
use rama_core::extensions::Extension;
use super::*;
#[derive(Debug, Extension)]
struct AttemptMarker;
#[test]
fn fork_isolates_attempt_extensions() {
let request = ConnectRequest::new(HostWithPort::example_domain_https());
let attempt = request.fork();
attempt.extensions.insert(AttemptMarker);
assert!(!request.extensions.contains::<AttemptMarker>());
assert!(attempt.extensions.contains::<AttemptMarker>());
}
#[cfg(feature = "http")]
#[test]
fn target_http_version_comes_from_extension() {
let request = ConnectRequest::new(HostWithPort::example_domain_https());
assert_eq!(request.target_http_version(), None);
request
.extensions
.insert(TargetHttpVersion(Version::HTTP_2));
assert_eq!(request.target_http_version(), Some(Version::HTTP_2));
}
#[cfg(feature = "http")]
#[test]
fn request_http_version_is_not_a_target_requirement() {
let request = ConnectRequest::new(HostWithPort::example_domain_https());
request
.extensions
.insert(HttpRequestVersion(Version::HTTP_2));
assert_eq!(request.http_version(), Some(Version::HTTP_2));
assert_eq!(request.target_http_version(), None);
}
}