11using System ;
22using System . Collections . Generic ;
3+ using System . Globalization ;
34using System . IO ;
5+ using System . Linq ;
46using System . Net ;
57using System . Net . Http ;
68using System . Net . Http . Headers ;
@@ -18,6 +20,7 @@ internal sealed class RequestHandler : IRequestHandler
1820{
1921 private static readonly Encoding Utf8 = new UTF8Encoding ( false ) ;
2022 private static readonly Type RawJsonType = typeof ( RawJson ) ;
23+ private static readonly Type ErrorResponseType = typeof ( ErrorResponse ) ;
2124 private static readonly byte [ ] EventPrefix = "data:"u8 . ToArray ( ) ;
2225
2326 internal static readonly JsonSerializerOptions DefaultSerializerOptions = CreateSerializerOptions ( ) ;
@@ -68,7 +71,8 @@ private static JsonSerializerOptions CreateSerializerOptions()
6871 . SendAsync ( request , HttpCompletionOption . ResponseContentRead , cancellationToken )
6972 . ConfigureAwait ( false ) ;
7073
71- response . EnsureSuccessStatusCode ( ) ;
74+ if ( ! response . IsSuccessStatusCode )
75+ await ThrowResponseError ( response , cancellationToken ) . ConfigureAwait ( false ) ;
7276
7377 return await ParseResponse ( response , returnType , serializerOptions , allowNullResponse , cancellationToken )
7478 . ConfigureAwait ( false ) ;
@@ -90,15 +94,13 @@ private static JsonSerializerOptions CreateSerializerOptions()
9094 return null ;
9195 }
9296
93- try
94- {
95- response . EnsureSuccessStatusCode ( ) ;
97+ if ( response . IsSuccessStatusCode )
9698 return new HttpStreamedResult ( response ) ;
97- }
98- catch
99+
100+ using ( response )
99101 {
100- response . Dispose ( ) ;
101- throw ;
102+ await ThrowResponseError ( response , cancellationToken ) . ConfigureAwait ( false ) ;
103+ return null ;
102104 }
103105 }
104106
@@ -116,7 +118,8 @@ public async IAsyncEnumerable<object> GetEvents(
116118 . SendAsync ( request , HttpCompletionOption . ResponseContentRead , cancellationToken )
117119 . ConfigureAwait ( false ) ;
118120
119- response . EnsureSuccessStatusCode ( ) ;
121+ if ( ! response . IsSuccessStatusCode )
122+ await ThrowResponseError ( response , cancellationToken ) . ConfigureAwait ( false ) ;
120123
121124 var responseStream = await response . Content . ReadAsStreamAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
122125 await using var responseStreamScope = responseStream . ConfigureAwait ( false ) ;
@@ -151,7 +154,8 @@ public async IAsyncEnumerable<object> GetEvents(
151154 . SendAsync ( request , HttpCompletionOption . ResponseContentRead , cancellationToken )
152155 . ConfigureAwait ( false ) ;
153156
154- response . EnsureSuccessStatusCode ( ) ;
157+ if ( ! response . IsSuccessStatusCode )
158+ await ThrowResponseError ( response , cancellationToken ) . ConfigureAwait ( false ) ;
155159
156160 return returnType != null
157161 ? await ParseResponse ( response , returnType , serializerOptions , allowNullResponse , cancellationToken )
@@ -195,8 +199,62 @@ HttpContent GetContent()
195199 return result ;
196200 }
197201
198- private static InvalidDataException InvalidResponse ( )
202+ private static async ValueTask ThrowResponseError (
203+ HttpResponseMessage response , CancellationToken cancellationToken )
204+ {
205+ if ( response . Content . Headers . ContentType ? . MediaType != ContentTypes . Json )
206+ {
207+ throw CreateException ( response ) ;
208+ }
209+
210+ var errorResponse = ( ErrorResponse ? ) await ParseResponse (
211+ response , ErrorResponseType , DefaultSerializerOptions , true , cancellationToken )
212+ . ConfigureAwait ( false ) ;
213+
214+ throw CreateException ( response , errorResponse ? . Error ? . Message , errorResponse ? . Error ? . Parameter ) ;
215+ }
216+
217+ private static PlayerClientException CreateException (
218+ HttpResponseMessage message ,
219+ string ? serverMessage = null ,
220+ string ? parameterName = null )
221+ {
222+ var messageBuilder = new StringBuilder ( 120 ) ;
223+
224+ messageBuilder . Append (
225+ CultureInfo . InvariantCulture ,
226+ $ "Response status code does not indicate success: { ( int ) message . StatusCode } ") ;
227+
228+ if ( message . ReasonPhrase != null )
229+ {
230+ messageBuilder . Append ( $ " ({ message . ReasonPhrase } )") ;
231+ }
232+
233+ messageBuilder . Append ( '.' ) ;
234+
235+ if ( serverMessage != null )
236+ {
237+ messageBuilder . Append ( " Server error: " ) . Append ( serverMessage ) ;
238+
239+ if ( ! serverMessage . EndsWith ( '.' ) )
240+ messageBuilder . Append ( '.' ) ;
241+ }
242+
243+ if ( parameterName != null )
244+ {
245+ messageBuilder . Append ( $ " Parameter name: { parameterName } .") ;
246+ }
247+
248+ return new PlayerClientException (
249+ messageBuilder . ToString ( ) ,
250+ HttpRequestError . Unknown ,
251+ message . StatusCode ,
252+ serverMessage ,
253+ parameterName ) ;
254+ }
255+
256+ private static PlayerClientException InvalidResponse ( )
199257 {
200- return new InvalidDataException ( "Invalid response: expected JSON object." ) ;
258+ return new PlayerClientException ( "Invalid response: expected JSON object." , HttpRequestError . InvalidResponse ) ;
201259 }
202260}
0 commit comments