diff --git a/src/RestSharp/Extensions/HttpResponseExtensions.cs b/src/RestSharp/Extensions/HttpResponseExtensions.cs new file mode 100644 index 000000000..53b873e6c --- /dev/null +++ b/src/RestSharp/Extensions/HttpResponseExtensions.cs @@ -0,0 +1,27 @@ +// Copyright (c) .NET Foundation and Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace RestSharp.Extensions; + +public static class HttpResponseExtensions { + internal static Exception? MaybeException(this HttpResponseMessage httpResponse) + => httpResponse.IsSuccessStatusCode + ? null +#if NETSTANDARD + : new HttpRequestException($"Request failed with status code {httpResponse.StatusCode}"); +#else + : new HttpRequestException($"Request failed with status code {httpResponse.StatusCode}", null, httpResponse.StatusCode); +#endif +} diff --git a/src/RestSharp/Response/RestResponse.cs b/src/RestSharp/Response/RestResponse.cs index 503d2c7f2..a9225ec23 100644 --- a/src/RestSharp/Response/RestResponse.cs +++ b/src/RestSharp/Response/RestResponse.cs @@ -89,7 +89,7 @@ async Task GetDefaultResponse() { ContentLength = httpResponse.Content.Headers.ContentLength, ContentType = httpResponse.Content.Headers.ContentType?.MediaType, ResponseStatus = calculateResponseStatus(httpResponse), - ErrorException = MaybeException(), + ErrorException = httpResponse.MaybeException(), ResponseUri = httpResponse.RequestMessage!.RequestUri, Server = httpResponse.Headers.Server.ToString(), StatusCode = httpResponse.StatusCode, @@ -102,15 +102,6 @@ async Task GetDefaultResponse() { RootElement = request.RootElement }; - Exception? MaybeException() - => httpResponse.IsSuccessStatusCode - ? null -#if NETSTANDARD - : new HttpRequestException($"Request failed with status code {httpResponse.StatusCode}"); -#else - : new HttpRequestException($"Request failed with status code {httpResponse.StatusCode}", null, httpResponse.StatusCode); -#endif - Task ReadResponse() => httpResponse.ReadResponse(cancellationToken); async Task ReadAndConvertResponse() { diff --git a/src/RestSharp/RestClient.Async.cs b/src/RestSharp/RestClient.Async.cs index 7a353e550..0a57d189f 100644 --- a/src/RestSharp/RestClient.Async.cs +++ b/src/RestSharp/RestClient.Async.cs @@ -50,8 +50,7 @@ async Task ExecuteInternal(RestRequest request, CancellationTo using var requestContent = new RequestContent(this, request); - if (Authenticator != null) - await Authenticator.Authenticate(this, request).ConfigureAwait(false); + if (Authenticator != null) await Authenticator.Authenticate(this, request).ConfigureAwait(false); var httpMethod = AsHttpMethod(request.Method); var url = BuildUri(request); @@ -61,7 +60,8 @@ async Task ExecuteInternal(RestRequest request, CancellationTo using var timeoutCts = new CancellationTokenSource(request.Timeout > 0 ? request.Timeout : int.MaxValue); using var cts = CancellationTokenSource.CreateLinkedTokenSource(timeoutCts.Token, cancellationToken); - var ct = cts.Token; + + var ct = cts.Token; try { var headers = new RequestHeaders() @@ -70,13 +70,11 @@ async Task ExecuteInternal(RestRequest request, CancellationTo .AddAcceptHeader(AcceptedContentTypes); message.AddHeaders(headers); - if (request.OnBeforeRequest != null) - await request.OnBeforeRequest(message).ConfigureAwait(false); + if (request.OnBeforeRequest != null) await request.OnBeforeRequest(message).ConfigureAwait(false); var responseMessage = await HttpClient.SendAsync(message, request.CompletionOption, ct).ConfigureAwait(false); - if (request.OnAfterRequest != null) - await request.OnAfterRequest(responseMessage).ConfigureAwait(false); + if (request.OnAfterRequest != null) await request.OnAfterRequest(responseMessage).ConfigureAwait(false); return new InternalResponse(responseMessage, url, null, timeoutCts.Token); } @@ -99,8 +97,10 @@ record InternalResponse(HttpResponseMessage? ResponseMessage, Uri Url, Exception request.CompletionOption = HttpCompletionOption.ResponseHeadersRead; var response = await ExecuteInternal(request, cancellationToken).ConfigureAwait(false); - if (response.Exception != null) { - return Options.ThrowOnAnyError ? throw response.Exception : null; + var exception = response.Exception ?? response.ResponseMessage?.MaybeException(); + + if (exception != null) { + return Options.ThrowOnAnyError ? throw exception : null; } if (response.ResponseMessage == null) return null; @@ -141,7 +141,7 @@ static HttpMethod AsHttpMethod(Method method) #if NETSTANDARD Method.Patch => new HttpMethod("PATCH"), #else - Method.Patch => HttpMethod.Patch, + Method.Patch => HttpMethod.Patch, #endif Method.Merge => new HttpMethod("MERGE"), Method.Copy => new HttpMethod("COPY"), @@ -157,11 +157,11 @@ public static RestResponse ThrowIfError(this RestResponse response) { return response; } - + public static RestResponse ThrowIfError(this RestResponse response) { var exception = response.GetException(); if (exception != null) throw exception; return response; } -} \ No newline at end of file +} diff --git a/test/RestSharp.Tests.Integrated/DownloadFileTests.cs b/test/RestSharp.Tests.Integrated/DownloadFileTests.cs index fe7a2fde3..aa30a158e 100644 --- a/test/RestSharp.Tests.Integrated/DownloadFileTests.cs +++ b/test/RestSharp.Tests.Integrated/DownloadFileTests.cs @@ -7,7 +7,8 @@ namespace RestSharp.Tests.Integrated; public sealed class DownloadFileTests : IDisposable { public DownloadFileTests() { _server = HttpServerFixture.StartServer("Assets/Koala.jpg", FileHandler); - _client = new RestClient(_server.Url); + var options = new RestClientOptions(_server.Url) { ThrowOnAnyError = true }; + _client = new RestClient(options); } public void Dispose() => _server.Dispose(); @@ -46,6 +47,13 @@ public async Task AdvancedResponseWriter_without_ResponseWriter_reads_stream() { Assert.True(string.Compare("JFIF", tag, StringComparison.Ordinal) == 0); } + [Fact] + public async Task Handles_File_Download_Failure() { + var request = new RestRequest("Assets/Koala1.jpg"); + var task = () => _client.DownloadDataAsync(request); + await task.Should().ThrowAsync().WithMessage("Request failed with status code NotFound"); + } + [Fact] public async Task Handles_Binary_File_Download() { var request = new RestRequest("Assets/Koala.jpg"); @@ -76,4 +84,4 @@ public async Task Writes_Response_To_Stream() { Assert.Equal(expected, fromTemp); } -} \ No newline at end of file +}