@@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Web
1515 public static class CaseHandlingUriBuilder
1616 {
1717 private static readonly Uri FallbackBaseUri = new ( "http://localhost/" ) ;
18- private static readonly SpanAction < char , ( bool LowerInvariant , string Host , string PathBase , string Path , string Query ) > InitializeAbsoluteUriStringSpanAction = new ( InitializeAbsoluteUriString ) ;
18+ private static readonly SpanAction < char , ( bool LowerInvariant , string Scheme , string Host , string PathBase , string Path , string Query ) > InitializeAbsoluteUriStringSpanAction = new ( InitializeAbsoluteUriString ) ;
1919
2020 /// <summary>
2121 /// Provides Uri case handling options.
@@ -50,30 +50,54 @@ public static string BuildRelative(
5050 // Take any potential performance hit vs concatination for code reading sanity.
5151 => BuildAbsolute ( handling , default , pathBase , path , query ) ;
5252
53+ /// <summary>
54+ /// Combines the given URI components into a string that is properly encoded for use in HTTP headers.
55+ /// Note that unicode in the HostString will be encoded as punycode and the scheme is not included
56+ /// in the result.
57+ /// </summary>
58+ /// <param name="handling">Determines case handling for the result. <paramref name="query"/> is always converted to invariant lowercase.</param>
59+ /// <param name="host">The host portion of the uri normally included in the Host header. This may include the port.</param>
60+ /// <param name="pathBase">The first portion of the request path associated with application root.</param>
61+ /// <param name="path">The portion of the request path that identifies the requested resource.</param>
62+ /// <param name="query">The query, if any.</param>
63+ /// <returns>The combined URI components, properly encoded for use in HTTP headers.</returns>
64+ public static string BuildAbsolute (
65+ CaseHandling handling ,
66+ HostString host ,
67+ PathString pathBase = default ,
68+ PathString path = default ,
69+ QueryString query = default )
70+ => BuildAbsolute ( handling , string . Empty , host , pathBase , path , query ) ;
71+
5372 /// <summary>
5473 /// Combines the given URI components into a string that is properly encoded for use in HTTP headers.
5574 /// Note that unicode in the HostString will be encoded as punycode.
5675 /// </summary>
5776 /// <param name="handling">Determines case handling for the result. <paramref name="query"/> is always converted to invariant lowercase.</param>
77+ /// <param name="scheme">http, https, etc.</param>
5878 /// <param name="host">The host portion of the uri normally included in the Host header. This may include the port.</param>
5979 /// <param name="pathBase">The first portion of the request path associated with application root.</param>
6080 /// <param name="path">The portion of the request path that identifies the requested resource.</param>
6181 /// <param name="query">The query, if any.</param>
6282 /// <returns>The combined URI components, properly encoded for use in HTTP headers.</returns>
6383 public static string BuildAbsolute (
6484 CaseHandling handling ,
85+ string scheme ,
6586 HostString host ,
6687 PathString pathBase = default ,
6788 PathString path = default ,
6889 QueryString query = default )
6990 {
91+ Guard . NotNull ( scheme , nameof ( scheme ) ) ;
92+
7093 string hostText = host . ToUriComponent ( ) ;
7194 string pathBaseText = pathBase . ToUriComponent ( ) ;
7295 string pathText = path . ToUriComponent ( ) ;
7396 string queryText = query . ToUriComponent ( ) ;
7497
7598 // PERF: Calculate string length to allocate correct buffer size for string.Create.
7699 int length =
100+ ( scheme . Length > 0 ? scheme . Length + Uri . SchemeDelimiter . Length : 0 ) +
77101 hostText . Length +
78102 pathBaseText . Length +
79103 pathText . Length +
@@ -95,7 +119,10 @@ public static string BuildAbsolute(
95119 length -- ;
96120 }
97121
98- return string . Create ( length , ( handling == CaseHandling . LowerInvariant , hostText , pathBaseText , pathText , queryText ) , InitializeAbsoluteUriStringSpanAction ) ;
122+ return string . Create (
123+ length ,
124+ ( handling == CaseHandling . LowerInvariant , scheme , hostText , pathBaseText , pathText , queryText ) ,
125+ InitializeAbsoluteUriStringSpanAction ) ;
99126 }
100127
101128 /// <summary>
@@ -122,6 +149,7 @@ public static string Encode(CaseHandling handling, Uri uri)
122149 {
123150 return BuildAbsolute (
124151 handling ,
152+ scheme : uri . Scheme ,
125153 host : HostString . FromUriComponent ( uri ) ,
126154 pathBase : PathString . FromUriComponent ( uri ) ,
127155 query : QueryString . FromUriComponent ( uri ) ) ;
@@ -167,7 +195,7 @@ private static int CopyTextToBufferLowerInvariant(Span<char> buffer, int index,
167195 /// </summary>
168196 /// <param name="buffer">The URI <see cref="string"/>'s <see cref="char"/> buffer.</param>
169197 /// <param name="uriParts">The URI parts.</param>
170- private static void InitializeAbsoluteUriString ( Span < char > buffer , ( bool Lower , string Host , string PathBase , string Path , string Query ) uriParts )
198+ private static void InitializeAbsoluteUriString ( Span < char > buffer , ( bool Lower , string Scheme , string Host , string PathBase , string Path , string Query ) uriParts )
171199 {
172200 int index = 0 ;
173201 ReadOnlySpan < char > pathBaseSpan = uriParts . PathBase . AsSpan ( ) ;
@@ -180,6 +208,12 @@ private static void InitializeAbsoluteUriString(Span<char> buffer, (bool Lower,
180208 pathBaseSpan = pathBaseSpan . Slice ( 0 , pathBaseSpan . Length - 1 ) ;
181209 }
182210
211+ if ( uriParts . Scheme . Length > 0 )
212+ {
213+ index = CopyTextToBuffer ( buffer , index , uriParts . Scheme . AsSpan ( ) ) ;
214+ index = CopyTextToBuffer ( buffer , index , Uri . SchemeDelimiter . AsSpan ( ) ) ;
215+ }
216+
183217 if ( uriParts . Lower )
184218 {
185219 index = CopyTextToBufferLowerInvariant ( buffer , index , uriParts . Host . AsSpan ( ) ) ;
0 commit comments