11using System . Net ;
22using System . Text ;
3+ using Akka . Actor ;
34using TurboHTTP . Protocol . Semantics ;
4- using Encoder = TurboHTTP . Protocol . Http11 . Encoder ;
5+ using TurboHTTP . Protocol . Syntax . Http11 . Client ;
6+ using TurboHTTP . Protocol . Syntax . Http11 . Options ;
57
68namespace TurboHTTP . Tests . Security ;
79
810public sealed class UriRedirectSpec
911{
10- private static string EncodeHttp11 ( HttpRequestMessage request , bool absoluteForm = false , int bufferSize = 16384 )
12+ private static readonly Http11ClientEncoder Encoder = new ( Http11ClientEncoderOptions . Default ) ;
13+
14+ private static string EncodeHttp11 ( HttpRequestMessage request , int bufferSize = 16384 )
1115 {
12- var buffer = new Memory < byte > ( new byte [ bufferSize ] ) ;
13- var span = buffer . Span ;
14- var written = Encoder . Encode ( request , ref span , absoluteForm ) ;
15- return Encoding . ASCII . GetString ( buffer . Span [ ..written ] ) ;
16+ var buffer = new byte [ bufferSize ] ;
17+ var written = Encoder . Encode ( buffer , request , ActorRefs . Nobody ) ;
18+ return Encoding . ASCII . GetString ( buffer , 0 , written ) ;
1619 }
1720
1821 private static HttpResponseMessage RedirectResponse ( HttpStatusCode status , string location )
@@ -25,35 +28,25 @@ private static HttpResponseMessage RedirectResponse(HttpStatusCode status, strin
2528 [ Fact ( Timeout = 5000 ) ]
2629 public void Uri_should_normalize_backslash_when_path_contains_backslash ( )
2730 {
28- // Attack: Backslash path traversal on Windows (e.g., ..\..\etc\passwd)
29- // .NET Uri normalizes backslashes to forward slashes on Windows
3031 const string uriString = "https://example.com/api\\ ..\\ sensitive" ;
3132
32- // On Windows, Uri may normalize backslashes — test the actual behavior
3333 if ( OperatingSystem . IsWindows ( ) )
3434 {
3535 var uri = new Uri ( uriString ) ;
36- // Backslash should be converted to forward slash
3736 Assert . DoesNotContain ( "\\ " , uri . AbsolutePath ) ;
3837 }
3938 }
4039
4140 [ Fact ( Timeout = 5000 ) ]
4241 public void Http11Encoder_should_encode_extremely_long_uri_when_uri_exceeds_standard_size ( )
4342 {
44- // Attack: Resource exhaustion via extremely long URIs
45- var longPath = string . Concat ( Enumerable . Repeat ( "segment/" , 400 ) ) ; // ~3200 chars
43+ var longPath = string . Concat ( Enumerable . Repeat ( "segment/" , 400 ) ) ;
4644 var longUri = $ "https://example.com/{ longPath } query=value";
4745
4846 var request = new HttpRequestMessage ( HttpMethod . Get , longUri ) ;
4947
50- // Use a larger buffer to accommodate the long URI
51- const int bufferSize = 32768 ; // 32 KB
52- var buffer = new Memory < byte > ( new byte [ bufferSize ] ) ;
53- var span = buffer . Span ;
54-
55- // Should encode without throwing
56- var written = Encoder . Encode ( request , ref span ) ;
48+ const int bufferSize = 32768 ;
49+ var written = Encoder . Encode ( new byte [ bufferSize ] , request , ActorRefs . Nobody ) ;
5750
5851 Assert . True ( written > 0 ) ;
5952 Assert . True ( written < bufferSize ) ;
@@ -62,17 +55,13 @@ public void Http11Encoder_should_encode_extremely_long_uri_when_uri_exceeds_stan
6255 [ Fact ( Timeout = 5000 ) ]
6356 public void Http11Encoder_should_encode_long_query_string_when_query_parameters_very_large ( )
6457 {
65- // Attack: Query string DoS via extremely long parameter values
6658 var longQueryValue = string . Concat ( Enumerable . Repeat ( "x" , 4096 ) ) ;
6759 var uri = $ "https://example.com/endpoint?data={ longQueryValue } ";
6860
6961 var request = new HttpRequestMessage ( HttpMethod . Get , uri ) ;
7062
7163 const int bufferSize = 32768 ;
72- var buffer = new Memory < byte > ( new byte [ bufferSize ] ) ;
73- var span = buffer . Span ;
74-
75- var written = Encoder . Encode ( request , ref span ) ;
64+ var written = Encoder . Encode ( new byte [ bufferSize ] , request , ActorRefs . Nobody ) ;
7665
7766 Assert . True ( written > 0 ) ;
7867 Assert . True ( written < bufferSize ) ;
@@ -81,19 +70,15 @@ public void Http11Encoder_should_encode_long_query_string_when_query_parameters_
8170 [ Fact ( Timeout = 5000 ) ]
8271 public void RedirectHandler_should_strip_userinfo_in_location_when_location_contains_credentials ( )
8372 {
84- // Attack: Location header with embedded credentials
85- // https://user:password@evil.com/phishing
8673 var original = new HttpRequestMessage ( HttpMethod . Get , "https://trusted.com/page" ) ;
8774 var response = RedirectResponse ( HttpStatusCode . Found , "https://admin:secret@attacker.com/" ) ;
8875
8976 var handler = new RedirectHandler ( ) ;
9077 var redirect = handler . BuildRedirectRequest ( original , response ) ;
9178
92- // The redirect URI will contain userinfo in the Uri object, but encoders strip it
9379 Assert . NotNull ( redirect . RequestUri ) ;
9480
95- // If we encode the redirect request, userinfo should not appear
96- var encoded = EncodeHttp11 ( redirect , absoluteForm : true ) ;
81+ var encoded = EncodeHttp11 ( redirect ) ;
9782 Assert . DoesNotContain ( "admin" , encoded ) ;
9883 Assert . DoesNotContain ( "secret" , encoded ) ;
9984 Assert . DoesNotContain ( "@" , encoded ) ;
0 commit comments