33using Microsoft . AspNetCore . Builder ;
44using Microsoft . AspNetCore . Http ;
55using Microsoft . AspNetCore . Routing ;
6+ using Microsoft . AspNetCore . WebUtilities ;
67using Microsoft . Net . Http . Headers ;
78using System ;
89using System . Collections . Generic ;
910using System . IO ;
1011using System . Linq ;
1112using System . Net . Http ;
13+ using System . Net . WebSockets ;
1214using System . Security . Authentication ;
1315using System . Text . Json ;
1416using System . Threading . Tasks ;
@@ -46,42 +48,42 @@ public static class EndpointRouteBuilder
4648 /// Maps the <see cref="ElevenLabsClient"/> endpoints.
4749 /// </summary>
4850 /// <param name="endpoints"><see cref="IEndpointRouteBuilder"/>.</param>
49- /// <param name="elevenLabsClient "><see cref="ElevenLabsClient"/>.</param>
51+ /// <param name="client "><see cref="ElevenLabsClient"/>.</param>
5052 /// <param name="authenticationFilter"><see cref="IAuthenticationFilter"/>.</param>
5153 /// <param name="routePrefix">Optional, custom route prefix. i.e. '/elevenlabs'.</param>
52- public static void MapElevenLabsEndpoints ( this IEndpointRouteBuilder endpoints , ElevenLabsClient elevenLabsClient , IAuthenticationFilter authenticationFilter , string routePrefix = "" )
54+ public static void MapElevenLabsEndpoints ( this IEndpointRouteBuilder endpoints , ElevenLabsClient client , IAuthenticationFilter authenticationFilter , string routePrefix = "" )
5355 {
54- endpoints . Map ( $ "{ routePrefix } { elevenLabsClient . ElevenLabsClientSettings . BaseRequest } {{**endpoint}}", HandleRequest ) ;
56+ endpoints . Map ( $ "{ routePrefix } { client . Settings . BaseRequest } {{**endpoint}}", HandleRequest ) ;
57+ return ;
5558
5659 async Task HandleRequest ( HttpContext httpContext , string endpoint )
5760 {
5861 try
5962 {
60- #pragma warning disable CS0618 // Type or member is obsolete
61- // ReSharper disable once MethodHasAsyncOverload
62- authenticationFilter . ValidateAuthentication ( httpContext . Request . Headers ) ;
63- #pragma warning restore CS0618 // Type or member is obsolete
64- await authenticationFilter . ValidateAuthenticationAsync ( httpContext . Request . Headers ) ;
65-
63+ await authenticationFilter . ValidateAuthenticationAsync ( httpContext . Request . Headers ) . ConfigureAwait ( false ) ;
6664 var method = new HttpMethod ( httpContext . Request . Method ) ;
67- var uri = new Uri ( string . Format (
68- elevenLabsClient . ElevenLabsClientSettings . BaseRequestUrlFormat ,
69- $ "{ endpoint } { httpContext . Request . QueryString } "
70- ) ) ;
71- using var request = new HttpRequestMessage ( method , uri ) ;
72- request . Content = new StreamContent ( httpContext . Request . Body ) ;
65+ var originalQuery = QueryHelpers . ParseQuery ( httpContext . Request . QueryString . Value ?? "" ) ;
66+ var modifiedQuery = new Dictionary < string , string > ( originalQuery . Count ) ;
7367
74- if ( httpContext . Request . Body . CanSeek )
68+ foreach ( var pair in originalQuery )
7569 {
76- httpContext . Request . Body . Position = 0 ;
70+ modifiedQuery [ pair . Key ] = pair . Value . FirstOrDefault ( ) ;
7771 }
7872
73+ var uri = new Uri ( string . Format (
74+ client . Settings . BaseRequestUrlFormat ,
75+ QueryHelpers . AddQueryString ( endpoint , modifiedQuery )
76+ ) ) ;
77+
78+ using var request = new HttpRequestMessage ( method , uri ) ;
79+ request . Content = new StreamContent ( httpContext . Request . Body ) ;
80+
7981 if ( httpContext . Request . ContentType != null )
8082 {
8183 request . Content . Headers . ContentType = System . Net . Http . Headers . MediaTypeHeaderValue . Parse ( httpContext . Request . ContentType ) ;
8284 }
8385
84- var proxyResponse = await elevenLabsClient . Client . SendAsync ( request , HttpCompletionOption . ResponseHeadersRead ) ;
86+ var proxyResponse = await client . Client . SendAsync ( request , HttpCompletionOption . ResponseHeadersRead , httpContext . RequestAborted ) . ConfigureAwait ( false ) ;
8587 httpContext . Response . StatusCode = ( int ) proxyResponse . StatusCode ;
8688
8789 foreach ( var ( key , value ) in proxyResponse . Headers )
@@ -101,32 +103,37 @@ async Task HandleRequest(HttpContext httpContext, string endpoint)
101103
102104 if ( httpContext . Response . ContentType . Equals ( streamingContent ) )
103105 {
104- using var reader = new StreamReader ( await request . Content . ReadAsStreamAsync ( ) ) ;
105- var stream = await proxyResponse . Content . ReadAsStreamAsync ( ) ;
106- await WriteServerStreamEventsAsync ( httpContext , stream ) ;
106+ var stream = await proxyResponse . Content . ReadAsStreamAsync ( ) . ConfigureAwait ( false ) ;
107+ await WriteServerStreamEventsAsync ( httpContext , stream ) . ConfigureAwait ( false ) ;
107108 }
108109 else
109110 {
110- await proxyResponse . Content . CopyToAsync ( httpContext . Response . Body ) ;
111+ await proxyResponse . Content . CopyToAsync ( httpContext . Response . Body , httpContext . RequestAborted ) . ConfigureAwait ( false ) ;
111112 }
112113 }
113114 catch ( AuthenticationException authenticationException )
114115 {
115116 httpContext . Response . StatusCode = StatusCodes . Status401Unauthorized ;
116- await httpContext . Response . WriteAsync ( authenticationException . Message ) ;
117+ await httpContext . Response . WriteAsync ( authenticationException . Message ) . ConfigureAwait ( false ) ;
118+ }
119+ catch ( WebSocketException )
120+ {
121+ // ignore
122+ throw ;
117123 }
118124 catch ( Exception e )
119125 {
126+ if ( httpContext . Response . HasStarted ) { throw ; }
120127 httpContext . Response . StatusCode = StatusCodes . Status500InternalServerError ;
121- var response = JsonSerializer . Serialize ( new { error = new { message = e . Message , stackTrace = e . StackTrace } } ) ;
122- await httpContext . Response . WriteAsync ( response ) ;
128+ var response = JsonSerializer . Serialize ( new { error = new { e . Message , e . StackTrace } } ) ;
129+ await httpContext . Response . WriteAsync ( response ) . ConfigureAwait ( false ) ;
123130 }
124131
125132 static async Task WriteServerStreamEventsAsync ( HttpContext httpContext , Stream contentStream )
126133 {
127134 var responseStream = httpContext . Response . Body ;
128- await contentStream . CopyToAsync ( responseStream , httpContext . RequestAborted ) ;
129- await responseStream . FlushAsync ( httpContext . RequestAborted ) ;
135+ await contentStream . CopyToAsync ( responseStream , httpContext . RequestAborted ) . ConfigureAwait ( false ) ;
136+ await responseStream . FlushAsync ( httpContext . RequestAborted ) . ConfigureAwait ( false ) ;
130137 }
131138 }
132139 }
0 commit comments