@@ -6,6 +6,16 @@ use url::Url;
66
77use crate :: error:: TrustedServerError ;
88
9+ /// Returns the default port for the given scheme (443 for HTTPS, 80 for HTTP).
10+ #[ inline]
11+ fn default_port_for_scheme ( scheme : & str ) -> u16 {
12+ if scheme. eq_ignore_ascii_case ( "https" ) {
13+ 443
14+ } else {
15+ 80
16+ }
17+ }
18+
919/// Compute the Host header value for a backend request.
1020///
1121/// For standard ports (443 for HTTPS, 80 for HTTP), returns just the hostname.
@@ -16,9 +26,7 @@ use crate::error::TrustedServerError;
1626/// would generate URLs without the port when the Host header didn't include it.
1727#[ inline]
1828fn compute_host_header ( scheme : & str , host : & str , port : u16 ) -> String {
19- let is_https = scheme. eq_ignore_ascii_case ( "https" ) ;
20- let default_port = if is_https { 443 } else { 80 } ;
21- if port != default_port {
29+ if port != default_port_for_scheme ( scheme) {
2230 format ! ( "{}:{}" , host, port)
2331 } else {
2432 host. to_string ( )
@@ -37,6 +45,11 @@ fn compute_host_header(scheme: &str, host: &str, port: u16) -> String {
3745/// * `host` - The hostname
3846/// * `port` - Optional port number
3947/// * `certificate_check` - If true, enables TLS certificate verification (default for production)
48+ ///
49+ /// # Errors
50+ ///
51+ /// Returns an error if the host is empty or if backend creation fails
52+ /// (except for `NameInUse` which reuses the existing backend).
4053pub fn ensure_origin_backend (
4154 scheme : & str ,
4255 host : & str ,
@@ -49,12 +62,7 @@ pub fn ensure_origin_backend(
4962 } ) ) ;
5063 }
5164
52- let is_https = scheme. eq_ignore_ascii_case ( "https" ) ;
53- let target_port = match ( port, is_https) {
54- ( Some ( p) , _) => p,
55- ( None , true ) => 443 ,
56- ( None , false ) => 80 ,
57- } ;
65+ let target_port = port. unwrap_or_else ( || default_port_for_scheme ( scheme) ) ;
5866
5967 let host_with_port = format ! ( "{}:{}" , host, target_port) ;
6068
@@ -115,6 +123,13 @@ pub fn ensure_origin_backend(
115123 }
116124}
117125
126+ /// Ensures a dynamic backend exists for the given origin URL.
127+ ///
128+ /// Parses the URL and delegates to [`ensure_origin_backend`] to create or reuse a backend.
129+ ///
130+ /// # Errors
131+ ///
132+ /// Returns an error if the URL cannot be parsed or lacks a host, or if backend creation fails.
118133pub fn ensure_backend_from_url (
119134 origin_url : & str ,
120135 certificate_check : bool ,
@@ -141,83 +156,97 @@ mod tests {
141156 // Tests for compute_host_header - the fix for port preservation in Host header
142157 #[ test]
143158 fn host_header_includes_port_for_non_standard_https ( ) {
144- // Non-standard port 9443 should be included in Host header
145159 assert_eq ! (
146160 compute_host_header( "https" , "cdn.example.com" , 9443 ) ,
147- "cdn.example.com:9443"
161+ "cdn.example.com:9443" ,
162+ "should include non-standard HTTPS port 9443 in Host header"
148163 ) ;
149164 assert_eq ! (
150165 compute_host_header( "https" , "cdn.example.com" , 8443 ) ,
151- "cdn.example.com:8443"
166+ "cdn.example.com:8443" ,
167+ "should include non-standard HTTPS port 8443 in Host header"
152168 ) ;
153169 }
154170
155171 #[ test]
156172 fn host_header_excludes_port_for_standard_https ( ) {
157- // Standard port 443 should NOT be included
158173 assert_eq ! (
159174 compute_host_header( "https" , "cdn.example.com" , 443 ) ,
160- "cdn.example.com"
175+ "cdn.example.com" ,
176+ "should omit standard HTTPS port 443 from Host header"
161177 ) ;
162178 }
163179
164180 #[ test]
165181 fn host_header_includes_port_for_non_standard_http ( ) {
166- // Non-standard port 8080 should be included
167182 assert_eq ! (
168183 compute_host_header( "http" , "cdn.example.com" , 8080 ) ,
169- "cdn.example.com:8080"
184+ "cdn.example.com:8080" ,
185+ "should include non-standard HTTP port 8080 in Host header"
170186 ) ;
171187 }
172188
173189 #[ test]
174190 fn host_header_excludes_port_for_standard_http ( ) {
175- // Standard port 80 should NOT be included
176191 assert_eq ! (
177192 compute_host_header( "http" , "cdn.example.com" , 80 ) ,
178- "cdn.example.com"
193+ "cdn.example.com" ,
194+ "should omit standard HTTP port 80 from Host header"
179195 ) ;
180196 }
181197
182198 #[ test]
183199 fn returns_name_for_https_with_cert_check ( ) {
184- let name = ensure_origin_backend ( "https" , "origin.example.com" , None , true ) . unwrap ( ) ;
200+ let name = ensure_origin_backend ( "https" , "origin.example.com" , None , true )
201+ . expect ( "should create backend for valid HTTPS origin" ) ;
185202 assert_eq ! ( name, "backend_https_origin_example_com_443" ) ;
186203 }
187204
188205 #[ test]
189206 fn returns_name_for_https_without_cert_check ( ) {
190- let name = ensure_origin_backend ( "https" , "origin.example.com" , None , false ) . unwrap ( ) ;
207+ let name = ensure_origin_backend ( "https" , "origin.example.com" , None , false )
208+ . expect ( "should create backend with cert check disabled" ) ;
191209 assert_eq ! ( name, "backend_https_origin_example_com_443_nocert" ) ;
192210 }
193211
194212 #[ test]
195213 fn returns_name_for_http_with_port_and_sanitizes ( ) {
196- let name = ensure_origin_backend ( "http" , "api.test-site.org" , Some ( 8080 ) , true ) . unwrap ( ) ;
214+ let name = ensure_origin_backend ( "http" , "api.test-site.org" , Some ( 8080 ) , true )
215+ . expect ( "should create backend for HTTP origin with explicit port" ) ;
197216 assert_eq ! ( name, "backend_http_api_test-site_org_8080" ) ;
198- // Explicitly check that ':' was replaced with '_'
199- assert ! ( name. ends_with( "_8080" ) ) ;
217+ assert ! (
218+ name. ends_with( "_8080" ) ,
219+ "should sanitize ':' to '_' in backend name"
220+ ) ;
200221 }
201222
202223 #[ test]
203224 fn returns_name_for_http_without_port_defaults_to_80 ( ) {
204- let name = ensure_origin_backend ( "http" , "example.org" , None , true ) . unwrap ( ) ;
225+ let name = ensure_origin_backend ( "http" , "example.org" , None , true )
226+ . expect ( "should create backend defaulting to port 80 for HTTP" ) ;
205227 assert_eq ! ( name, "backend_http_example_org_80" ) ;
206228 }
207229
208230 #[ test]
209231 fn error_on_missing_host ( ) {
210- let err = ensure_origin_backend ( "https" , "" , None , true )
211- . err ( )
212- . unwrap ( ) ;
232+ let err =
233+ ensure_origin_backend ( "https" , "" , None , true ) . expect_err ( "should reject empty host" ) ;
213234 let msg = err. to_string ( ) ;
214- assert ! ( msg. contains( "missing host" ) ) ;
235+ assert ! (
236+ msg. contains( "missing host" ) ,
237+ "should report missing host in error message"
238+ ) ;
215239 }
216240
217241 #[ test]
218242 fn second_call_reuses_existing_backend ( ) {
219- let first = ensure_origin_backend ( "https" , "reuse.example.com" , None , true ) . unwrap ( ) ;
220- let second = ensure_origin_backend ( "https" , "reuse.example.com" , None , true ) . unwrap ( ) ;
221- assert_eq ! ( first, second) ;
243+ let first = ensure_origin_backend ( "https" , "reuse.example.com" , None , true )
244+ . expect ( "should create backend on first call" ) ;
245+ let second = ensure_origin_backend ( "https" , "reuse.example.com" , None , true )
246+ . expect ( "should reuse backend on second call" ) ;
247+ assert_eq ! (
248+ first, second,
249+ "should return same backend name on repeat call"
250+ ) ;
222251 }
223252}
0 commit comments